103b705cfSriastradh/*
203b705cfSriastradh * Copyright © 1998 Keith Packard
303b705cfSriastradh * Copyright © 2012 Intel Corporation
403b705cfSriastradh *
503b705cfSriastradh * Permission to use, copy, modify, distribute, and sell this software and its
603b705cfSriastradh * documentation for any purpose is hereby granted without fee, provided that
703b705cfSriastradh * the above copyright notice appear in all copies and that both that
803b705cfSriastradh * copyright notice and this permission notice appear in supporting
903b705cfSriastradh * documentation, and that the name of Keith Packard not be used in
1003b705cfSriastradh * advertising or publicity pertaining to distribution of the software without
1103b705cfSriastradh * specific, written prior permission.  Keith Packard makes no
1203b705cfSriastradh * representations about the suitability of this software for any purpose.  It
1303b705cfSriastradh * is provided "as is" without express or implied warranty.
1403b705cfSriastradh *
1503b705cfSriastradh * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1603b705cfSriastradh * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1703b705cfSriastradh * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1803b705cfSriastradh * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1903b705cfSriastradh * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
2003b705cfSriastradh * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2103b705cfSriastradh * PERFORMANCE OF THIS SOFTWARE.
2203b705cfSriastradh */
2303b705cfSriastradh
2403b705cfSriastradh#include <stdlib.h>
2503b705cfSriastradh
2603b705cfSriastradh#include "fb.h"
2703b705cfSriastradh
2803b705cfSriastradhstatic Bool region_grow(RegionPtr region)
2903b705cfSriastradh{
3003b705cfSriastradh	RegDataPtr data;
3103b705cfSriastradh	int n;
3203b705cfSriastradh
3303b705cfSriastradh	n = 16;
3403b705cfSriastradh	if (!region->data) {
3503b705cfSriastradh		region->data = malloc(RegionSizeof(n));
3603b705cfSriastradh		if (!region->data)
3703b705cfSriastradh			return RegionBreak(region);
3803b705cfSriastradh		region->data->numRects = 1;
3903b705cfSriastradh		*RegionBoxptr(region) = region->extents;
4003b705cfSriastradh	} else if (!region->data->size) {
4103b705cfSriastradh		region->data = malloc(RegionSizeof(n));
4203b705cfSriastradh		if (!region->data)
4303b705cfSriastradh			return RegionBreak(region);
4403b705cfSriastradh		region->data->numRects = 0;
4503b705cfSriastradh	} else {
4603b705cfSriastradh		n = 2 * region->data->numRects;
4703b705cfSriastradh		data = (RegDataPtr) realloc(region->data, RegionSizeof(n));
4803b705cfSriastradh		if (!data)
4903b705cfSriastradh			return RegionBreak(region);
5003b705cfSriastradh		region->data = data;
5103b705cfSriastradh	}
5203b705cfSriastradh	region->data->size = n;
5303b705cfSriastradh	return TRUE;
5403b705cfSriastradh}
5503b705cfSriastradh
5603b705cfSriastradhstatic inline void add(RegionPtr region,
5703b705cfSriastradh		       int16_t x1, int16_t y1, int16_t x2, int16_t y2)
5803b705cfSriastradh{
5903b705cfSriastradh	BoxPtr r;
6003b705cfSriastradh
6103b705cfSriastradh	if (region->data->numRects == region->data->size &&
6203b705cfSriastradh	    !region_grow(region))
6303b705cfSriastradh		return;
6403b705cfSriastradh
6503b705cfSriastradh	r = RegionBoxptr(region) + region->data->numRects++;
6603b705cfSriastradh	r->x1 = x1; r->y1 = y1;
6703b705cfSriastradh	r->x2 = x2; r->y2 = y2;
6803b705cfSriastradh
6903b705cfSriastradh	DBG(("%s[%ld/%ld]: (%d, %d), (%d, %d)\n",
7003b705cfSriastradh	     __FUNCTION__,
7103b705cfSriastradh	     (long)region->data->numRects, (long)region->data->size,
7203b705cfSriastradh	     x1, y1, x2, y2));
7303b705cfSriastradh
7403b705cfSriastradh	if (x1 < region->extents.x1)
7503b705cfSriastradh		region->extents.x1 = x1;
7603b705cfSriastradh	if (x2 > region->extents.x2)
7703b705cfSriastradh		region->extents.x2 = x2;
7803b705cfSriastradh}
7903b705cfSriastradh
8003b705cfSriastradh#define MASK_0 (FB_ALLONES & ~FbScrRight(FB_ALLONES, 1))
8103b705cfSriastradh
8203b705cfSriastradh/* Convert bitmap clip mask into clipping region.
8303b705cfSriastradh * First, goes through each line and makes boxes by noting the transitions
8403b705cfSriastradh * from 0 to 1 and 1 to 0.
8503b705cfSriastradh * Then it coalesces the current line with the previous if they have boxes
8603b705cfSriastradh * at the same X coordinates.
8703b705cfSriastradh */
8803b705cfSriastradhRegionPtr
8903b705cfSriastradhfbBitmapToRegion(PixmapPtr pixmap)
9003b705cfSriastradh{
9103b705cfSriastradh	FbBits maskw;
9203b705cfSriastradh	register RegionPtr region;
9303b705cfSriastradh	const FbBits *bits, *line, *end;
9403b705cfSriastradh	int width, y1, y2, base, x1;
9503b705cfSriastradh	int stride, i;
9603b705cfSriastradh
9703b705cfSriastradh	DBG(("%s bitmap=%dx%d\n", __FUNCTION__,
9803b705cfSriastradh	     pixmap->drawable.width, pixmap->drawable.height));
9903b705cfSriastradh
10003b705cfSriastradh	region = RegionCreate(NULL, 1);
10103b705cfSriastradh	if (!region)
10203b705cfSriastradh		return NullRegion;
10303b705cfSriastradh
10403b705cfSriastradh	line = (FbBits *) pixmap->devPrivate.ptr;
10503b705cfSriastradh	stride = pixmap->devKind >> (FB_SHIFT - 3);
10603b705cfSriastradh
10703b705cfSriastradh	width = pixmap->drawable.width;
10803b705cfSriastradh	maskw = 0;
10903b705cfSriastradh	if (width & 7)
11003b705cfSriastradh		maskw = FB_ALLONES & ~FbScrRight(FB_ALLONES, width & FB_MASK);
11103b705cfSriastradh	region->extents.x1 = width;
11203b705cfSriastradh	region->extents.x2 = 0;
11303b705cfSriastradh	y2 = 0;
11403b705cfSriastradh	while (y2 < pixmap->drawable.height) {
11503b705cfSriastradh		y1 = y2++;
11603b705cfSriastradh		bits = line;
11703b705cfSriastradh		line += stride;
11803b705cfSriastradh		while (y2 < pixmap->drawable.height &&
11903b705cfSriastradh		       memcmp(bits, line, width >> 3) == 0 &&
12003b705cfSriastradh		       (maskw == 0 || (bits[width >> FB_SHIFT] & maskw) == (line[width >> FB_SHIFT] & maskw)))
12103b705cfSriastradh			line += stride, y2++;
12203b705cfSriastradh
12303b705cfSriastradh		if (READ(bits) & MASK_0)
12403b705cfSriastradh			x1 = 0;
12503b705cfSriastradh		else
12603b705cfSriastradh			x1 = -1;
12703b705cfSriastradh
12803b705cfSriastradh		/* Process all words which are fully in the pixmap */
12903b705cfSriastradh		end = bits + (width >> FB_SHIFT);
13003b705cfSriastradh		for (base = 0; bits < end; base += FB_UNIT) {
13103b705cfSriastradh			FbBits w = READ(bits++);
13203b705cfSriastradh			if (x1 < 0) {
13303b705cfSriastradh				if (!w)
13403b705cfSriastradh					continue;
13503b705cfSriastradh			} else {
13603b705cfSriastradh				if (!~w)
13703b705cfSriastradh					continue;
13803b705cfSriastradh			}
13903b705cfSriastradh			for (i = 0; i < FB_UNIT; i++) {
14003b705cfSriastradh				if (w & MASK_0) {
14103b705cfSriastradh					if (x1 < 0)
14203b705cfSriastradh						x1 = base + i;
14303b705cfSriastradh				} else {
14403b705cfSriastradh					if (x1 >= 0) {
14503b705cfSriastradh						add(region, x1, y1, base + i, y2);
14603b705cfSriastradh						x1 = -1;
14703b705cfSriastradh					}
14803b705cfSriastradh				}
14903b705cfSriastradh				w = FbScrLeft(w, 1);
15003b705cfSriastradh			}
15103b705cfSriastradh		}
15203b705cfSriastradh		if (width & FB_MASK) {
15303b705cfSriastradh			FbBits w = READ(bits++);
15403b705cfSriastradh			for (i = 0; i < (width & FB_MASK); i++) {
15503b705cfSriastradh				if (w & MASK_0) {
15603b705cfSriastradh					if (x1 < 0)
15703b705cfSriastradh						x1 = base + i;
15803b705cfSriastradh				} else {
15903b705cfSriastradh					if (x1 >= 0) {
16003b705cfSriastradh						add(region, x1, y1, base + i, y2);
16103b705cfSriastradh						x1 = -1;
16203b705cfSriastradh					}
16303b705cfSriastradh				}
16403b705cfSriastradh				w = FbScrLeft(w, 1);
16503b705cfSriastradh			}
16603b705cfSriastradh		}
16703b705cfSriastradh		if (x1 >= 0)
16803b705cfSriastradh			add(region, x1, y1, width, y2);
16903b705cfSriastradh	}
17003b705cfSriastradh
17103b705cfSriastradh	if (region->data->numRects) {
17203b705cfSriastradh		region->extents.y1 = RegionBoxptr(region)->y1;
17303b705cfSriastradh		region->extents.y2 = RegionEnd(region)->y2;
17403b705cfSriastradh		if (region->data->numRects == 1) {
17503b705cfSriastradh			free(region->data);
17603b705cfSriastradh			region->data = NULL;
17703b705cfSriastradh		}
17803b705cfSriastradh	} else
17903b705cfSriastradh		region->extents.x1 = region->extents.x2 = 0;
18003b705cfSriastradh
18142542f5fSchristos	DBG(("%s: region extents=(%d, %d), (%d, %d) x %d\n",
18203b705cfSriastradh	     __FUNCTION__,
18303b705cfSriastradh	     region->extents.x1, region->extents.y1,
18403b705cfSriastradh	     region->extents.x2, region->extents.y2,
18542542f5fSchristos	     region_num_rects(region)));
18603b705cfSriastradh
18703b705cfSriastradh	return region;
18803b705cfSriastradh}
189