/* * 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 #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 %d\n", __FUNCTION__, region->extents.x1, region->extents.y1, region->extents.x2, region->extents.y2, region_num_rects(region))); return region; }