xf86-video-intel/src/sna/fb/fbbitmap.c

189 lines
5.0 KiB
C

/*
* Copyright © 1998 Keith Packard
* Copyright © 2012 Intel Corporation
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include "fb.h"
static Bool region_grow(RegionPtr region)
{
RegDataPtr data;
int n;
n = 16;
if (!region->data) {
region->data = malloc(RegionSizeof(n));
if (!region->data)
return RegionBreak(region);
region->data->numRects = 1;
*RegionBoxptr(region) = region->extents;
} else if (!region->data->size) {
region->data = malloc(RegionSizeof(n));
if (!region->data)
return RegionBreak(region);
region->data->numRects = 0;
} else {
n = 2 * region->data->numRects;
data = (RegDataPtr) realloc(region->data, RegionSizeof(n));
if (!data)
return RegionBreak(region);
region->data = data;
}
region->data->size = n;
return TRUE;
}
static inline void add(RegionPtr region,
int16_t x1, int16_t y1, int16_t x2, int16_t y2)
{
BoxPtr r;
if (region->data->numRects == region->data->size &&
!region_grow(region))
return;
r = RegionBoxptr(region) + region->data->numRects++;
r->x1 = x1; r->y1 = y1;
r->x2 = x2; r->y2 = y2;
DBG(("%s[%ld/%ld]: (%d, %d), (%d, %d)\n",
__FUNCTION__,
(long)region->data->numRects, (long)region->data->size,
x1, y1, x2, y2));
if (x1 < region->extents.x1)
region->extents.x1 = x1;
if (x2 > region->extents.x2)
region->extents.x2 = x2;
}
#define MASK_0 (FB_ALLONES & ~FbScrRight(FB_ALLONES, 1))
/* Convert bitmap clip mask into clipping region.
* First, goes through each line and makes boxes by noting the transitions
* from 0 to 1 and 1 to 0.
* Then it coalesces the current line with the previous if they have boxes
* at the same X coordinates.
*/
RegionPtr
fbBitmapToRegion(PixmapPtr pixmap)
{
FbBits maskw;
register RegionPtr region;
const FbBits *bits, *line, *end;
int width, y1, y2, base, x1;
int stride, i;
DBG(("%s bitmap=%dx%d\n", __FUNCTION__,
pixmap->drawable.width, pixmap->drawable.height));
region = RegionCreate(NULL, 1);
if (!region)
return NullRegion;
line = (FbBits *) pixmap->devPrivate.ptr;
stride = pixmap->devKind >> (FB_SHIFT - 3);
width = pixmap->drawable.width;
maskw = 0;
if (width & 7)
maskw = FB_ALLONES & ~FbScrRight(FB_ALLONES, width & FB_MASK);
region->extents.x1 = width;
region->extents.x2 = 0;
y2 = 0;
while (y2 < pixmap->drawable.height) {
y1 = y2++;
bits = line;
line += stride;
while (y2 < pixmap->drawable.height &&
memcmp(bits, line, width >> 3) == 0 &&
(maskw == 0 || (bits[width >> FB_SHIFT] & maskw) == (line[width >> FB_SHIFT] & maskw)))
line += stride, y2++;
if (READ(bits) & MASK_0)
x1 = 0;
else
x1 = -1;
/* Process all words which are fully in the pixmap */
end = bits + (width >> FB_SHIFT);
for (base = 0; bits < end; base += FB_UNIT) {
FbBits w = READ(bits++);
if (x1 < 0) {
if (!w)
continue;
} else {
if (!~w)
continue;
}
for (i = 0; i < FB_UNIT; i++) {
if (w & MASK_0) {
if (x1 < 0)
x1 = base + i;
} else {
if (x1 >= 0) {
add(region, x1, y1, base + i, y2);
x1 = -1;
}
}
w = FbScrLeft(w, 1);
}
}
if (width & FB_MASK) {
FbBits w = READ(bits++);
for (i = 0; i < (width & FB_MASK); i++) {
if (w & MASK_0) {
if (x1 < 0)
x1 = base + i;
} else {
if (x1 >= 0) {
add(region, x1, y1, base + i, y2);
x1 = -1;
}
}
w = FbScrLeft(w, 1);
}
}
if (x1 >= 0)
add(region, x1, y1, width, y2);
}
if (region->data->numRects) {
region->extents.y1 = RegionBoxptr(region)->y1;
region->extents.y2 = RegionEnd(region)->y2;
if (region->data->numRects == 1) {
free(region->data);
region->data = NULL;
}
} else
region->extents.x1 = region->extents.x2 = 0;
DBG(("%s: region extents=(%d, %d), (%d, %d) x %ld\n",
__FUNCTION__,
region->extents.x1, region->extents.y1,
region->extents.x2, region->extents.y2,
(long)RegionNumRects(region)));
return region;
}