Blame libfreerdp/codec/region.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2014 Thincast Technologies GmbH
Packit Service fa4841
 * Copyright 2014 Hardening <contact@hardening-consulting.com>
Packit Service fa4841
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
Packit Service fa4841
 * Copyright 2017 Thincast Technologies GmbH
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 * http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#include <assert.h>
Packit Service fa4841
#include <winpr/memory.h>
Packit Service fa4841
#include <freerdp/log.h>
Packit Service fa4841
#include <freerdp/codec/region.h>
Packit Service fa4841
Packit Service fa4841
#define TAG FREERDP_TAG("codec")
Packit Service fa4841
Packit Service fa4841
/*
Packit Service fa4841
 * The functions in this file implement the Region abstraction largely inspired from
Packit Service fa4841
 * pixman library. The following comment is taken from the pixman code.
Packit Service fa4841
 *
Packit Service fa4841
 * A Region is simply a set of disjoint(non-overlapping) rectangles, plus an
Packit Service fa4841
 * "extent" rectangle which is the smallest single rectangle that contains all
Packit Service fa4841
 * the non-overlapping rectangles.
Packit Service fa4841
 *
Packit Service fa4841
 * A Region is implemented as a "y-x-banded" array of rectangles.  This array
Packit Service fa4841
 * imposes two degrees of order.  First, all rectangles are sorted by top side
Packit Service fa4841
 * y coordinate first (y1), and then by left side x coordinate (x1).
Packit Service fa4841
 *
Packit Service fa4841
 * Furthermore, the rectangles are grouped into "bands".  Each rectangle in a
Packit Service fa4841
 * band has the same top y coordinate (y1), and each has the same bottom y
Packit Service fa4841
 * coordinate (y2).  Thus all rectangles in a band differ only in their left
Packit Service fa4841
 * and right side (x1 and x2).  Bands are implicit in the array of rectangles:
Packit Service fa4841
 * there is no separate list of band start pointers.
Packit Service fa4841
 *
Packit Service fa4841
 * The y-x band representation does not minimize rectangles.  In particular,
Packit Service fa4841
 * if a rectangle vertically crosses a band (the rectangle has scanlines in
Packit Service fa4841
 * the y1 to y2 area spanned by the band), then the rectangle may be broken
Packit Service fa4841
 * down into two or more smaller rectangles stacked one atop the other.
Packit Service fa4841
 *
Packit Service fa4841
 *  -----------                             -----------
Packit Service fa4841
 *  |         |                             |         |             band 0
Packit Service fa4841
 *  |         |  --------                   -----------  --------
Packit Service fa4841
 *  |         |  |      |  in y-x banded    |         |  |      |   band 1
Packit Service fa4841
 *  |         |  |      |  form is          |         |  |      |
Packit Service fa4841
 *  -----------  |      |                   -----------  --------
Packit Service fa4841
 *               |      |                                |      |   band 2
Packit Service fa4841
 *               --------                                --------
Packit Service fa4841
 *
Packit Service fa4841
 * An added constraint on the rectangles is that they must cover as much
Packit Service fa4841
 * horizontal area as possible: no two rectangles within a band are allowed
Packit Service fa4841
 * to touch.
Packit Service fa4841
 *
Packit Service fa4841
 * Whenever possible, bands will be merged together to cover a greater vertical
Packit Service fa4841
 * distance (and thus reduce the number of rectangles). Two bands can be merged
Packit Service fa4841
 * only if the bottom of one touches the top of the other and they have
Packit Service fa4841
 * rectangles in the same places (of the same width, of course).
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
struct _REGION16_DATA
Packit Service fa4841
{
Packit Service fa4841
	long size;
Packit Service fa4841
	long nbRects;
Packit Service fa4841
};
Packit Service fa4841
Packit Service fa4841
static REGION16_DATA empty_region = { 0, 0 };
Packit Service fa4841
Packit Service fa4841
void region16_init(REGION16* region)
Packit Service fa4841
{
Packit Service fa4841
	assert(region);
Packit Service fa4841
	ZeroMemory(region, sizeof(REGION16));
Packit Service fa4841
	region->data = &empty_region;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
int region16_n_rects(const REGION16* region)
Packit Service fa4841
{
Packit Service fa4841
	assert(region);
Packit Service fa4841
	assert(region->data);
Packit Service fa4841
	return region->data->nbRects;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
const RECTANGLE_16* region16_rects(const REGION16* region, UINT32* nbRects)
Packit Service fa4841
{
Packit Service fa4841
	REGION16_DATA* data;
Packit Service fa4841
Packit Service fa4841
	if (nbRects)
Packit Service fa4841
		*nbRects = 0;
Packit Service fa4841
Packit Service fa4841
	if (!region)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	data = region->data;
Packit Service fa4841
Packit Service fa4841
	if (!data)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	if (nbRects)
Packit Service fa4841
		*nbRects = data->nbRects;
Packit Service fa4841
Packit Service fa4841
	return (RECTANGLE_16*)(data + 1);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static INLINE RECTANGLE_16* region16_rects_noconst(REGION16* region)
Packit Service fa4841
{
Packit Service fa4841
	REGION16_DATA* data;
Packit Service fa4841
	data = region->data;
Packit Service fa4841
Packit Service fa4841
	if (!data)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	return (RECTANGLE_16*)(&data[1]);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
const RECTANGLE_16* region16_extents(const REGION16* region)
Packit Service fa4841
{
Packit Service fa4841
	if (!region)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	return &region->extents;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static RECTANGLE_16* region16_extents_noconst(REGION16* region)
Packit Service fa4841
{
Packit Service fa4841
	if (!region)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	return &region->extents;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL rectangle_is_empty(const RECTANGLE_16* rect)
Packit Service fa4841
{
Packit Service fa4841
	/* A rectangle with width = 0 or height = 0 should be regarded
Packit Service fa4841
	 * as empty.
Packit Service fa4841
	 */
Packit Service fa4841
	return ((rect->left == rect->right) || (rect->top == rect->bottom)) ? TRUE : FALSE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL region16_is_empty(const REGION16* region)
Packit Service fa4841
{
Packit Service fa4841
	assert(region);
Packit Service fa4841
	assert(region->data);
Packit Service fa4841
	return (region->data->nbRects == 0);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL rectangles_equal(const RECTANGLE_16* r1, const RECTANGLE_16* r2)
Packit Service fa4841
{
Packit Service fa4841
	return ((r1->left == r2->left) && (r1->top == r2->top) && (r1->right == r2->right) &&
Packit Service fa4841
	        (r1->bottom == r2->bottom))
Packit Service fa4841
	           ? TRUE
Packit Service fa4841
	           : FALSE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL rectangles_intersects(const RECTANGLE_16* r1, const RECTANGLE_16* r2)
Packit Service fa4841
{
Packit Service fa4841
	RECTANGLE_16 tmp;
Packit Service fa4841
	return rectangles_intersection(r1, r2, &tmp);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL rectangles_intersection(const RECTANGLE_16* r1, const RECTANGLE_16* r2, RECTANGLE_16* dst)
Packit Service fa4841
{
Packit Service fa4841
	dst->left = MAX(r1->left, r2->left);
Packit Service fa4841
	dst->right = MIN(r1->right, r2->right);
Packit Service fa4841
	dst->top = MAX(r1->top, r2->top);
Packit Service fa4841
	dst->bottom = MIN(r1->bottom, r2->bottom);
Packit Service fa4841
	return (dst->left < dst->right) && (dst->top < dst->bottom);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void region16_clear(REGION16* region)
Packit Service fa4841
{
Packit Service fa4841
	assert(region);
Packit Service fa4841
	assert(region->data);
Packit Service fa4841
Packit Service fa4841
	if ((region->data->size > 0) && (region->data != &empty_region))
Packit Service fa4841
		free(region->data);
Packit Service fa4841
Packit Service fa4841
	region->data = &empty_region;
Packit Service fa4841
	ZeroMemory(&region->extents, sizeof(region->extents));
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static INLINE REGION16_DATA* allocateRegion(long nbItems)
Packit Service fa4841
{
Packit Service fa4841
	long allocSize = sizeof(REGION16_DATA) + (nbItems * sizeof(RECTANGLE_16));
Packit Service fa4841
	REGION16_DATA* ret = (REGION16_DATA*)malloc(allocSize);
Packit Service fa4841
Packit Service fa4841
	if (!ret)
Packit Service fa4841
		return ret;
Packit Service fa4841
Packit Service fa4841
	ret->size = allocSize;
Packit Service fa4841
	ret->nbRects = nbItems;
Packit Service fa4841
	return ret;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL region16_copy(REGION16* dst, const REGION16* src)
Packit Service fa4841
{
Packit Service fa4841
	assert(dst);
Packit Service fa4841
	assert(dst->data);
Packit Service fa4841
	assert(src);
Packit Service fa4841
	assert(src->data);
Packit Service fa4841
Packit Service fa4841
	if (dst == src)
Packit Service fa4841
		return TRUE;
Packit Service fa4841
Packit Service fa4841
	dst->extents = src->extents;
Packit Service fa4841
Packit Service fa4841
	if ((dst->data->size > 0) && (dst->data != &empty_region))
Packit Service fa4841
		free(dst->data);
Packit Service fa4841
Packit Service fa4841
	if (src->data->size == 0)
Packit Service fa4841
		dst->data = &empty_region;
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		dst->data = allocateRegion(src->data->nbRects);
Packit Service fa4841
Packit Service fa4841
		if (!dst->data)
Packit Service fa4841
			return FALSE;
Packit Service fa4841
Packit Service fa4841
		CopyMemory(dst->data, src->data, src->data->size);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void region16_print(const REGION16* region)
Packit Service fa4841
{
Packit Service fa4841
	const RECTANGLE_16* rects;
Packit Service fa4841
	UINT32 nbRects, i;
Packit Service fa4841
	int currentBandY = -1;
Packit Service fa4841
	rects = region16_rects(region, &nbRects);
Packit Service fa4841
	WLog_DBG(TAG, "nrects=%" PRIu32 "", nbRects);
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < nbRects; i++, rects++)
Packit Service fa4841
	{
Packit Service fa4841
		if (rects->top != currentBandY)
Packit Service fa4841
		{
Packit Service fa4841
			currentBandY = rects->top;
Packit Service fa4841
			WLog_DBG(TAG, "band %d: ", currentBandY);
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		WLog_DBG(TAG, "(%" PRIu16 ",%" PRIu16 "-%" PRIu16 ",%" PRIu16 ")", rects->left, rects->top,
Packit Service fa4841
		         rects->right, rects->bottom);
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void region16_copy_band_with_union(RECTANGLE_16* dst, const RECTANGLE_16* src,
Packit Service fa4841
                                          const RECTANGLE_16* end, UINT16 newTop, UINT16 newBottom,
Packit Service fa4841
                                          const RECTANGLE_16* unionRect, UINT32* dstCounter,
Packit Service fa4841
                                          const RECTANGLE_16** srcPtr, RECTANGLE_16** dstPtr)
Packit Service fa4841
{
Packit Service fa4841
	UINT16 refY = src->top;
Packit Service fa4841
	const RECTANGLE_16 *startOverlap, *endOverlap;
Packit Service fa4841
Packit Service fa4841
	/* merges a band with the given rect
Packit Service fa4841
	 * Input:
Packit Service fa4841
	 *                   unionRect
Packit Service fa4841
	 *               |               |
Packit Service fa4841
	 *               |               |
Packit Service fa4841
	 * ==============+===============+================================
Packit Service fa4841
	 *   |Item1|  |Item2| |Item3|  |Item4|    |Item5|            Band
Packit Service fa4841
	 * ==============+===============+================================
Packit Service fa4841
	 *    before     |    overlap    |          after
Packit Service fa4841
	 *
Packit Service fa4841
	 * Resulting band:
Packit Service fa4841
	 *   +-----+  +----------------------+    +-----+
Packit Service fa4841
	 *   |Item1|  |      Item2           |    |Item3|
Packit Service fa4841
	 *   +-----+  +----------------------+    +-----+
Packit Service fa4841
	 *
Packit Service fa4841
	 *  We first copy as-is items that are before Item2, the first overlapping
Packit Service fa4841
	 *  item.
Packit Service fa4841
	 *  Then we find the last one that overlap unionRect to agregate Item2, Item3
Packit Service fa4841
	 *  and Item4 to create Item2.
Packit Service fa4841
	 *  Finally Item5 is copied as Item3.
Packit Service fa4841
	 *
Packit Service fa4841
	 *  When no unionRect is provided, we skip the two first steps to just copy items
Packit Service fa4841
	 */
Packit Service fa4841
Packit Service fa4841
	if (unionRect)
Packit Service fa4841
	{
Packit Service fa4841
		/* items before unionRect */
Packit Service fa4841
		while ((src < end) && (src->top == refY) && (src->right < unionRect->left))
Packit Service fa4841
		{
Packit Service fa4841
			dst->top = newTop;
Packit Service fa4841
			dst->bottom = newBottom;
Packit Service fa4841
			dst->right = src->right;
Packit Service fa4841
			dst->left = src->left;
Packit Service fa4841
			src++;
Packit Service fa4841
			dst++;
Packit Service fa4841
			*dstCounter += 1;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		/* treat items overlapping with unionRect */
Packit Service fa4841
		startOverlap = unionRect;
Packit Service fa4841
		endOverlap = unionRect;
Packit Service fa4841
Packit Service fa4841
		if ((src < end) && (src->top == refY) && (src->left < unionRect->left))
Packit Service fa4841
			startOverlap = src;
Packit Service fa4841
Packit Service fa4841
		while ((src < end) && (src->top == refY) && (src->right < unionRect->right))
Packit Service fa4841
		{
Packit Service fa4841
			src++;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if ((src < end) && (src->top == refY) && (src->left < unionRect->right))
Packit Service fa4841
		{
Packit Service fa4841
			endOverlap = src;
Packit Service fa4841
			src++;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		dst->bottom = newBottom;
Packit Service fa4841
		dst->top = newTop;
Packit Service fa4841
		dst->left = startOverlap->left;
Packit Service fa4841
		dst->right = endOverlap->right;
Packit Service fa4841
		dst++;
Packit Service fa4841
		*dstCounter += 1;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* treat remaining items on the same band */
Packit Service fa4841
	while ((src < end) && (src->top == refY))
Packit Service fa4841
	{
Packit Service fa4841
		dst->top = newTop;
Packit Service fa4841
		dst->bottom = newBottom;
Packit Service fa4841
		dst->right = src->right;
Packit Service fa4841
		dst->left = src->left;
Packit Service fa4841
		src++;
Packit Service fa4841
		dst++;
Packit Service fa4841
		*dstCounter += 1;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (srcPtr)
Packit Service fa4841
		*srcPtr = src;
Packit Service fa4841
Packit Service fa4841
	*dstPtr = dst;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static RECTANGLE_16* next_band(RECTANGLE_16* band1, RECTANGLE_16* endPtr, int* nbItems)
Packit Service fa4841
{
Packit Service fa4841
	UINT16 refY = band1->top;
Packit Service fa4841
	*nbItems = 0;
Packit Service fa4841
Packit Service fa4841
	while ((band1 < endPtr) && (band1->top == refY))
Packit Service fa4841
	{
Packit Service fa4841
		band1++;
Packit Service fa4841
		*nbItems += 1;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return band1;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL band_match(const RECTANGLE_16* band1, const RECTANGLE_16* band2, RECTANGLE_16* endPtr)
Packit Service fa4841
{
Packit Service fa4841
	int refBand2 = band2->top;
Packit Service fa4841
	const RECTANGLE_16* band2Start = band2;
Packit Service fa4841
Packit Service fa4841
	while ((band1 < band2Start) && (band2 < endPtr) && (band2->top == refBand2))
Packit Service fa4841
	{
Packit Service fa4841
		if ((band1->left != band2->left) || (band1->right != band2->right))
Packit Service fa4841
			return FALSE;
Packit Service fa4841
Packit Service fa4841
		band1++;
Packit Service fa4841
		band2++;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (band1 != band2Start)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	return (band2 == endPtr) || (band2->top != refBand2);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/** compute if the rectangle is fully included in the band
Packit Service fa4841
 * @param band a pointer on the beginning of the band
Packit Service fa4841
 * @param endPtr end of the region
Packit Service fa4841
 * @param rect the rectangle to test
Packit Service fa4841
 * @return if rect is fully included in an item of the band
Packit Service fa4841
 */
Packit Service fa4841
static BOOL rectangle_contained_in_band(const RECTANGLE_16* band, const RECTANGLE_16* endPtr,
Packit Service fa4841
                                        const RECTANGLE_16* rect)
Packit Service fa4841
{
Packit Service fa4841
	UINT16 refY = band->top;
Packit Service fa4841
Packit Service fa4841
	if ((band->top > rect->top) || (rect->bottom > band->bottom))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* note: as the band is sorted from left to right, once we've seen an item
Packit Service fa4841
	 * 		that is after rect->left we're sure that the result is False.
Packit Service fa4841
	 */
Packit Service fa4841
	while ((band < endPtr) && (band->top == refY) && (band->left <= rect->left))
Packit Service fa4841
	{
Packit Service fa4841
		if (rect->right <= band->right)
Packit Service fa4841
			return TRUE;
Packit Service fa4841
Packit Service fa4841
		band++;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return FALSE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL region16_simplify_bands(REGION16* region)
Packit Service fa4841
{
Packit Service fa4841
	/** Simplify consecutive bands that touch and have the same items
Packit Service fa4841
	 *
Packit Service fa4841
	 *  ====================          ====================
Packit Service fa4841
	 *     | 1 |  | 2   |               |   |  |     |
Packit Service fa4841
	 *  ====================            |   |  |     |
Packit Service fa4841
	 *     | 1 |  | 2   |	   ====>    | 1 |  |  2  |
Packit Service fa4841
	 *  ====================            |   |  |     |
Packit Service fa4841
	 *     | 1 |  | 2   |               |   |  |     |
Packit Service fa4841
	 *  ====================          ====================
Packit Service fa4841
	 *
Packit Service fa4841
	 */
Packit Service fa4841
	RECTANGLE_16 *band1, *band2, *endPtr, *endBand, *tmp;
Packit Service fa4841
	int nbRects, finalNbRects;
Packit Service fa4841
	int bandItems, toMove;
Packit Service fa4841
	finalNbRects = nbRects = region16_n_rects(region);
Packit Service fa4841
Packit Service fa4841
	if (nbRects < 2)
Packit Service fa4841
		return TRUE;
Packit Service fa4841
Packit Service fa4841
	band1 = region16_rects_noconst(region);
Packit Service fa4841
	endPtr = band1 + nbRects;
Packit Service fa4841
Packit Service fa4841
	do
Packit Service fa4841
	{
Packit Service fa4841
		band2 = next_band(band1, endPtr, &bandItems);
Packit Service fa4841
Packit Service fa4841
		if (band2 == endPtr)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		if ((band1->bottom == band2->top) && band_match(band1, band2, endPtr))
Packit Service fa4841
		{
Packit Service fa4841
			/* adjust the bottom of band1 items */
Packit Service fa4841
			tmp = band1;
Packit Service fa4841
Packit Service fa4841
			while (tmp < band2)
Packit Service fa4841
			{
Packit Service fa4841
				tmp->bottom = band2->bottom;
Packit Service fa4841
				tmp++;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			/* override band2, we don't move band1 pointer as the band after band2
Packit Service fa4841
			 * may be merged too */
Packit Service fa4841
			endBand = band2 + bandItems;
Packit Service fa4841
			toMove = (endPtr - endBand) * sizeof(RECTANGLE_16);
Packit Service fa4841
Packit Service fa4841
			if (toMove)
Packit Service fa4841
				MoveMemory(band2, endBand, toMove);
Packit Service fa4841
Packit Service fa4841
			finalNbRects -= bandItems;
Packit Service fa4841
			endPtr -= bandItems;
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
		{
Packit Service fa4841
			band1 = band2;
Packit Service fa4841
		}
Packit Service fa4841
	} while (TRUE);
Packit Service fa4841
Packit Service fa4841
	if (finalNbRects != nbRects)
Packit Service fa4841
	{
Packit Service fa4841
		REGION16_DATA* data;
Packit Service fa4841
		size_t allocSize = sizeof(REGION16_DATA) + (finalNbRects * sizeof(RECTANGLE_16));
Packit Service fa4841
		data = realloc(region->data, allocSize);
Packit Service fa4841
		if (!data)
Packit Service fa4841
			free(region->data);
Packit Service fa4841
		region->data = data;
Packit Service fa4841
Packit Service fa4841
		if (!region->data)
Packit Service fa4841
		{
Packit Service fa4841
			region->data = &empty_region;
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		region->data->nbRects = finalNbRects;
Packit Service fa4841
		region->data->size = allocSize;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL region16_union_rect(REGION16* dst, const REGION16* src, const RECTANGLE_16* rect)
Packit Service fa4841
{
Packit Service fa4841
	const RECTANGLE_16* srcExtents;
Packit Service fa4841
	RECTANGLE_16* dstExtents;
Packit Service fa4841
	const RECTANGLE_16 *currentBand, *endSrcRect, *nextBand;
Packit Service fa4841
	REGION16_DATA* newItems = NULL;
Packit Service fa4841
	REGION16_DATA* tmpItems = NULL;
Packit Service fa4841
	RECTANGLE_16* dstRect = NULL;
Packit Service fa4841
	UINT32 usedRects, srcNbRects;
Packit Service fa4841
	UINT16 topInterBand;
Packit Service fa4841
	assert(src);
Packit Service fa4841
	assert(src->data);
Packit Service fa4841
	assert(dst);
Packit Service fa4841
	srcExtents = region16_extents(src);
Packit Service fa4841
	dstExtents = region16_extents_noconst(dst);
Packit Service fa4841
Packit Service fa4841
	if (!region16_n_rects(src))
Packit Service fa4841
	{
Packit Service fa4841
		/* source is empty, so the union is rect */
Packit Service fa4841
		dst->extents = *rect;
Packit Service fa4841
		dst->data = allocateRegion(1);
Packit Service fa4841
Packit Service fa4841
		if (!dst->data)
Packit Service fa4841
			return FALSE;
Packit Service fa4841
Packit Service fa4841
		dstRect = region16_rects_noconst(dst);
Packit Service fa4841
		dstRect->top = rect->top;
Packit Service fa4841
		dstRect->left = rect->left;
Packit Service fa4841
		dstRect->right = rect->right;
Packit Service fa4841
		dstRect->bottom = rect->bottom;
Packit Service fa4841
		return TRUE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	newItems = allocateRegion((1 + region16_n_rects(src)) * 4);
Packit Service fa4841
Packit Service fa4841
	if (!newItems)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	dstRect = (RECTANGLE_16*)(&newItems[1]);
Packit Service fa4841
	usedRects = 0;
Packit Service fa4841
Packit Service fa4841
	/* adds the piece of rect that is on the top of src */
Packit Service fa4841
	if (rect->top < srcExtents->top)
Packit Service fa4841
	{
Packit Service fa4841
		dstRect->top = rect->top;
Packit Service fa4841
		dstRect->left = rect->left;
Packit Service fa4841
		dstRect->right = rect->right;
Packit Service fa4841
		dstRect->bottom = MIN(srcExtents->top, rect->bottom);
Packit Service fa4841
		usedRects++;
Packit Service fa4841
		dstRect++;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* treat possibly overlapping region */
Packit Service fa4841
	currentBand = region16_rects(src, &srcNbRects);
Packit Service fa4841
	endSrcRect = currentBand + srcNbRects;
Packit Service fa4841
Packit Service fa4841
	while (currentBand < endSrcRect)
Packit Service fa4841
	{
Packit Service fa4841
		if ((currentBand->bottom <= rect->top) || (rect->bottom <= currentBand->top) ||
Packit Service fa4841
		    rectangle_contained_in_band(currentBand, endSrcRect, rect))
Packit Service fa4841
		{
Packit Service fa4841
			/* no overlap between rect and the band, rect is totally below or totally above
Packit Service fa4841
			 * the current band, or rect is already covered by an item of the band.
Packit Service fa4841
			 * let's copy all the rectangles from this band
Packit Service fa4841
			            +----+
Packit Service fa4841
			            |    |   rect (case 1)
Packit Service fa4841
			            +----+
Packit Service fa4841
Packit Service fa4841
			   =================
Packit Service fa4841
			band of srcRect
Packit Service fa4841
			 =================
Packit Service fa4841
			        +----+
Packit Service fa4841
			        |    |   rect (case 2)
Packit Service fa4841
			        +----+
Packit Service fa4841
			*/
Packit Service fa4841
			region16_copy_band_with_union(dstRect, currentBand, endSrcRect, currentBand->top,
Packit Service fa4841
			                              currentBand->bottom, NULL, &usedRects, &nextBand,
Packit Service fa4841
			                              &dstRect);
Packit Service fa4841
			topInterBand = rect->top;
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
		{
Packit Service fa4841
			/* rect overlaps the band:
Packit Service fa4841
			           |    |  |    |
Packit Service fa4841
			====^=================|    |==|    |=========================== band
Packit Service fa4841
			|   top split     |    |  |    |
Packit Service fa4841
			v                 | 1  |  | 2  |
Packit Service fa4841
			^                 |    |  |    |  +----+   +----+
Packit Service fa4841
			|   merge zone    |    |  |    |  |    |   | 4  |
Packit Service fa4841
			v                 +----+  |    |  |    |   +----+
Packit Service fa4841
			^                         |    |  | 3  |
Packit Service fa4841
			|   bottom split          |    |  |    |
Packit Service fa4841
			====v=========================|    |==|    |===================
Packit Service fa4841
			           |    |  |    |
Packit Service fa4841
Packit Service fa4841
			 possible cases:
Packit Service fa4841
			 1) no top split, merge zone then a bottom split. The band will be splitted
Packit Service fa4841
			  in two
Packit Service fa4841
			 2) not band split, only the merge zone, band merged with rect but not splitted
Packit Service fa4841
			 3) a top split, the merge zone and no bottom split. The band will be split
Packit Service fa4841
			 in two
Packit Service fa4841
			 4) a top split, the merge zone and also a bottom split. The band will be
Packit Service fa4841
			 splitted in 3, but the coalesce algorithm may merge the created bands
Packit Service fa4841
			 */
Packit Service fa4841
			UINT16 mergeTop = currentBand->top;
Packit Service fa4841
			UINT16 mergeBottom = currentBand->bottom;
Packit Service fa4841
Packit Service fa4841
			/* test if we need a top split, case 3 and 4 */
Packit Service fa4841
			if (rect->top > currentBand->top)
Packit Service fa4841
			{
Packit Service fa4841
				region16_copy_band_with_union(dstRect, currentBand, endSrcRect, currentBand->top,
Packit Service fa4841
				                              rect->top, NULL, &usedRects, &nextBand, &dstRect);
Packit Service fa4841
				mergeTop = rect->top;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			/* do the merge zone (all cases) */
Packit Service fa4841
			if (rect->bottom < currentBand->bottom)
Packit Service fa4841
				mergeBottom = rect->bottom;
Packit Service fa4841
Packit Service fa4841
			region16_copy_band_with_union(dstRect, currentBand, endSrcRect, mergeTop, mergeBottom,
Packit Service fa4841
			                              rect, &usedRects, &nextBand, &dstRect);
Packit Service fa4841
Packit Service fa4841
			/* test if we need a bottom split, case 1 and 4 */
Packit Service fa4841
			if (rect->bottom < currentBand->bottom)
Packit Service fa4841
			{
Packit Service fa4841
				region16_copy_band_with_union(dstRect, currentBand, endSrcRect, mergeBottom,
Packit Service fa4841
				                              currentBand->bottom, NULL, &usedRects, &nextBand,
Packit Service fa4841
				                              &dstRect);
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			topInterBand = currentBand->bottom;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		/* test if a piece of rect should be inserted as a new band between
Packit Service fa4841
		 * the current band and the next one. band n and n+1 shouldn't touch.
Packit Service fa4841
		 *
Packit Service fa4841
		 * ==============================================================
Packit Service fa4841
		 *                                                        band n
Packit Service fa4841
		 *            +------+                    +------+
Packit Service fa4841
		 * ===========| rect |====================|      |===============
Packit Service fa4841
		 *            |      |    +------+        |      |
Packit Service fa4841
		 *            +------+    | rect |        | rect |
Packit Service fa4841
		 *                        +------+        |      |
Packit Service fa4841
		 * =======================================|      |================
Packit Service fa4841
		 *                                        +------+         band n+1
Packit Service fa4841
		 * ===============================================================
Packit Service fa4841
		 *
Packit Service fa4841
		 */
Packit Service fa4841
		if ((nextBand < endSrcRect) && (nextBand->top != currentBand->bottom) &&
Packit Service fa4841
		    (rect->bottom > currentBand->bottom) && (rect->top < nextBand->top))
Packit Service fa4841
		{
Packit Service fa4841
			dstRect->right = rect->right;
Packit Service fa4841
			dstRect->left = rect->left;
Packit Service fa4841
			dstRect->top = topInterBand;
Packit Service fa4841
			dstRect->bottom = MIN(nextBand->top, rect->bottom);
Packit Service fa4841
			dstRect++;
Packit Service fa4841
			usedRects++;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		currentBand = nextBand;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* adds the piece of rect that is below src */
Packit Service fa4841
	if (srcExtents->bottom < rect->bottom)
Packit Service fa4841
	{
Packit Service fa4841
		dstRect->top = MAX(srcExtents->bottom, rect->top);
Packit Service fa4841
		dstRect->left = rect->left;
Packit Service fa4841
		dstRect->right = rect->right;
Packit Service fa4841
		dstRect->bottom = rect->bottom;
Packit Service fa4841
		usedRects++;
Packit Service fa4841
		dstRect++;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if ((src == dst) && (src->data->size > 0) && (src->data != &empty_region))
Packit Service fa4841
		free(src->data);
Packit Service fa4841
Packit Service fa4841
	dstExtents->top = MIN(rect->top, srcExtents->top);
Packit Service fa4841
	dstExtents->left = MIN(rect->left, srcExtents->left);
Packit Service fa4841
	dstExtents->bottom = MAX(rect->bottom, srcExtents->bottom);
Packit Service fa4841
	dstExtents->right = MAX(rect->right, srcExtents->right);
Packit Service fa4841
	newItems->size = sizeof(REGION16_DATA) + (usedRects * sizeof(RECTANGLE_16));
Packit Service fa4841
	tmpItems = realloc(newItems, newItems->size);
Packit Service fa4841
	if (!tmpItems)
Packit Service fa4841
		free(newItems);
Packit Service fa4841
	newItems = tmpItems;
Packit Service fa4841
	dst->data = newItems;
Packit Service fa4841
Packit Service fa4841
	if (!dst->data)
Packit Service fa4841
	{
Packit Service fa4841
		free(newItems);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	dst->data->nbRects = usedRects;
Packit Service fa4841
	return region16_simplify_bands(dst);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL region16_intersects_rect(const REGION16* src, const RECTANGLE_16* arg2)
Packit Service fa4841
{
Packit Service fa4841
	const RECTANGLE_16 *rect, *endPtr, *srcExtents;
Packit Service fa4841
	UINT32 nbRects;
Packit Service fa4841
Packit Service fa4841
	if (!src || !src->data || !arg2)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	rect = region16_rects(src, &nbRects);
Packit Service fa4841
Packit Service fa4841
	if (!nbRects)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	srcExtents = region16_extents(src);
Packit Service fa4841
Packit Service fa4841
	if (nbRects == 1)
Packit Service fa4841
		return rectangles_intersects(srcExtents, arg2);
Packit Service fa4841
Packit Service fa4841
	if (!rectangles_intersects(srcExtents, arg2))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	for (endPtr = rect + nbRects; (rect < endPtr) && (arg2->bottom > rect->top); rect++)
Packit Service fa4841
	{
Packit Service fa4841
		if (rectangles_intersects(rect, arg2))
Packit Service fa4841
			return TRUE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return FALSE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL region16_intersect_rect(REGION16* dst, const REGION16* src, const RECTANGLE_16* rect)
Packit Service fa4841
{
Packit Service fa4841
	REGION16_DATA* newItems;
Packit Service fa4841
	const RECTANGLE_16 *srcPtr, *endPtr, *srcExtents;
Packit Service fa4841
	RECTANGLE_16* dstPtr;
Packit Service fa4841
	UINT32 nbRects, usedRects;
Packit Service fa4841
	RECTANGLE_16 common, newExtents;
Packit Service fa4841
	assert(src);
Packit Service fa4841
	assert(src->data);
Packit Service fa4841
	srcPtr = region16_rects(src, &nbRects);
Packit Service fa4841
Packit Service fa4841
	if (!nbRects)
Packit Service fa4841
	{
Packit Service fa4841
		region16_clear(dst);
Packit Service fa4841
		return TRUE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	srcExtents = region16_extents(src);
Packit Service fa4841
Packit Service fa4841
	if (nbRects == 1)
Packit Service fa4841
	{
Packit Service fa4841
		BOOL intersects = rectangles_intersection(srcExtents, rect, &common);
Packit Service fa4841
		region16_clear(dst);
Packit Service fa4841
Packit Service fa4841
		if (intersects)
Packit Service fa4841
			return region16_union_rect(dst, dst, &common);
Packit Service fa4841
Packit Service fa4841
		return TRUE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	newItems = allocateRegion(nbRects);
Packit Service fa4841
Packit Service fa4841
	if (!newItems)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	dstPtr = (RECTANGLE_16*)(&newItems[1]);
Packit Service fa4841
	usedRects = 0;
Packit Service fa4841
	ZeroMemory(&newExtents, sizeof(newExtents));
Packit Service fa4841
Packit Service fa4841
	/* accumulate intersecting rectangles, the final region16_simplify_bands() will
Packit Service fa4841
	 * do all the bad job to recreate correct rectangles
Packit Service fa4841
	 */
Packit Service fa4841
	for (endPtr = srcPtr + nbRects; (srcPtr < endPtr) && (rect->bottom > srcPtr->top); srcPtr++)
Packit Service fa4841
	{
Packit Service fa4841
		if (rectangles_intersection(srcPtr, rect, &common))
Packit Service fa4841
		{
Packit Service fa4841
			*dstPtr = common;
Packit Service fa4841
			usedRects++;
Packit Service fa4841
			dstPtr++;
Packit Service fa4841
Packit Service fa4841
			if (rectangle_is_empty(&newExtents))
Packit Service fa4841
			{
Packit Service fa4841
				/* Check if the existing newExtents is empty. If it is empty, use
Packit Service fa4841
				 * new common directly. We do not need to check common rectangle
Packit Service fa4841
				 * because the rectangles_intersection() ensures that it is not empty.
Packit Service fa4841
				 */
Packit Service fa4841
				newExtents = common;
Packit Service fa4841
			}
Packit Service fa4841
			else
Packit Service fa4841
			{
Packit Service fa4841
				newExtents.top = MIN(common.top, newExtents.top);
Packit Service fa4841
				newExtents.left = MIN(common.left, newExtents.left);
Packit Service fa4841
				newExtents.bottom = MAX(common.bottom, newExtents.bottom);
Packit Service fa4841
				newExtents.right = MAX(common.right, newExtents.right);
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	newItems->nbRects = usedRects;
Packit Service fa4841
	newItems->size = sizeof(REGION16_DATA) + (usedRects * sizeof(RECTANGLE_16));
Packit Service fa4841
Packit Service fa4841
	if ((dst->data->size > 0) && (dst->data != &empty_region))
Packit Service fa4841
		free(dst->data);
Packit Service fa4841
Packit Service fa4841
	dst->data = realloc(newItems, newItems->size);
Packit Service fa4841
Packit Service fa4841
	if (!dst->data)
Packit Service fa4841
	{
Packit Service fa4841
		free(newItems);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	dst->extents = newExtents;
Packit Service fa4841
	return region16_simplify_bands(dst);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void region16_uninit(REGION16* region)
Packit Service fa4841
{
Packit Service fa4841
	assert(region);
Packit Service fa4841
Packit Service fa4841
	if (region->data)
Packit Service fa4841
	{
Packit Service fa4841
		if ((region->data->size > 0) && (region->data != &empty_region))
Packit Service fa4841
			free(region->data);
Packit Service fa4841
Packit Service fa4841
		region->data = NULL;
Packit Service fa4841
	}
Packit Service fa4841
}