📄 pixman-region.c
字号:
ExchangeRects(0, j); /* Recurse */ if (numRects-j-1 > 1) QuickSortRects(&rects[j+1], numRects-j-1); numRects = j; } while (numRects > 1);}/*- *----------------------------------------------------------------------- * pixman_region_validate -- * * Take a ``region'' which is a non-y-x-banded random collection of * rectangles, and compute a nice region which is the union of all the * rectangles. * * Results: * TRUE if successful. * * Side Effects: * The passed-in ``region'' may be modified. * pOverlap set to TRUE if any retangles overlapped, * else FALSE; * * Strategy: * Step 1. Sort the rectangles into ascending order with primary key y1 * and secondary key x1. * * Step 2. Split the rectangles into the minimum number of proper y-x * banded regions. This may require horizontally merging * rectangles, and vertically coalescing bands. With any luck, * this step in an identity transformation (ala the Box widget), * or a coalescing into 1 box (ala Menus). * * Step 3. Merge the separate regions down to a single region by calling * pixman_region_union. Maximize the work each pixman_region_union call does by using * a binary merge. * *----------------------------------------------------------------------- */pixman_bool_tpixman_region_validate(pixman_region16_t * badreg, int *pOverlap){ /* Descriptor for regions under construction in Step 2. */ typedef struct { pixman_region16_t reg; int prevBand; int curBand; } RegionInfo; int numRects; /* Original numRects for badreg */ RegionInfo *ri; /* Array of current regions */ int numRI; /* Number of entries used in ri */ int sizeRI; /* Number of entries available in ri */ int i; /* Index into rects */ int j; /* Index into ri */ RegionInfo *rit; /* &ri[j] */ pixman_region16_t * reg; /* ri[j].reg */ pixman_box16_t * box; /* Current box in rects */ pixman_box16_t * riBox; /* Last box in ri[j].reg */ pixman_region16_t * hreg; /* ri[j_half].reg */ pixman_bool_t ret = TRUE; *pOverlap = FALSE; if (!badreg->data) { good(badreg); return TRUE; } numRects = badreg->data->numRects; if (!numRects) { if (PIXREGION_NAR(badreg)) return FALSE; good(badreg); return TRUE; } if (badreg->extents.x1 < badreg->extents.x2) { if ((numRects) == 1) { freeData(badreg); badreg->data = (pixman_region16_data_t *) NULL; } else { DOWNSIZE(badreg, numRects); } good(badreg); return TRUE; } /* Step 1: Sort the rects array into ascending (y1, x1) order */ QuickSortRects(PIXREGION_BOXPTR(badreg), numRects); /* Step 2: Scatter the sorted array into the minimum number of regions */ /* Set up the first region to be the first rectangle in badreg */ /* Note that step 2 code will never overflow the ri[0].reg rects array */ ri = (RegionInfo *) pixman_malloc_ab (4, sizeof(RegionInfo)); if (!ri) return pixman_break (badreg); sizeRI = 4; numRI = 1; ri[0].prevBand = 0; ri[0].curBand = 0; ri[0].reg = *badreg; box = PIXREGION_BOXPTR(&ri[0].reg); ri[0].reg.extents = *box; ri[0].reg.data->numRects = 1; badreg->extents = *pixman_region_emptyBox; badreg->data = pixman_region_emptyData; /* Now scatter rectangles into the minimum set of valid regions. If the next rectangle to be added to a region would force an existing rectangle in the region to be split up in order to maintain y-x banding, just forget it. Try the next region. If it doesn't fit cleanly into any region, make a new one. */ for (i = numRects; --i > 0;) { box++; /* Look for a region to append box to */ for (j = numRI, rit = ri; --j >= 0; rit++) { reg = &rit->reg; riBox = PIXREGION_END(reg); if (box->y1 == riBox->y1 && box->y2 == riBox->y2) { /* box is in same band as riBox. Merge or append it */ if (box->x1 <= riBox->x2) { /* Merge it with riBox */ if (box->x1 < riBox->x2) *pOverlap = TRUE; if (box->x2 > riBox->x2) riBox->x2 = box->x2; } else { RECTALLOC_BAIL(reg, 1, bail); *PIXREGION_TOP(reg) = *box; reg->data->numRects++; } goto NextRect; /* So sue me */ } else if (box->y1 >= riBox->y2) { /* Put box into new band */ if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; if (reg->extents.x1 > box->x1) reg->extents.x1 = box->x1; Coalesce(reg, rit->prevBand, rit->curBand); rit->curBand = reg->data->numRects; RECTALLOC_BAIL(reg, 1, bail); *PIXREGION_TOP(reg) = *box; reg->data->numRects++; goto NextRect; } /* Well, this region was inappropriate. Try the next one. */ } /* for j */ /* Uh-oh. No regions were appropriate. Create a new one. */ if (sizeRI == numRI) { size_t data_size; /* Oops, allocate space for new region information */ sizeRI <<= 1; data_size = sizeRI * sizeof(RegionInfo); if (data_size / sizeRI != sizeof(RegionInfo)) goto bail; rit = (RegionInfo *) realloc(ri, data_size); if (!rit) goto bail; ri = rit; rit = &ri[numRI]; } numRI++; rit->prevBand = 0; rit->curBand = 0; rit->reg.extents = *box; rit->reg.data = (pixman_region16_data_t *)NULL; if (!pixman_rect_alloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */ goto bail;NextRect: ; } /* for i */ /* Make a final pass over each region in order to Coalesce and set extents.x2 and extents.y2 */ for (j = numRI, rit = ri; --j >= 0; rit++) { reg = &rit->reg; riBox = PIXREGION_END(reg); reg->extents.y2 = riBox->y2; if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; Coalesce(reg, rit->prevBand, rit->curBand); if (reg->data->numRects == 1) /* keep unions happy below */ { freeData(reg); reg->data = (pixman_region16_data_t *)NULL; } } /* Step 3: Union all regions into a single region */ while (numRI > 1) { int half = numRI/2; for (j = numRI & 1; j < (half + (numRI & 1)); j++) { reg = &ri[j].reg; hreg = &ri[j+half].reg; if (!pixman_op(reg, reg, hreg, pixman_region_unionO, TRUE, TRUE, pOverlap)) ret = FALSE; if (hreg->extents.x1 < reg->extents.x1) reg->extents.x1 = hreg->extents.x1; if (hreg->extents.y1 < reg->extents.y1) reg->extents.y1 = hreg->extents.y1; if (hreg->extents.x2 > reg->extents.x2) reg->extents.x2 = hreg->extents.x2; if (hreg->extents.y2 > reg->extents.y2) reg->extents.y2 = hreg->extents.y2; freeData(hreg); } numRI -= half; if (!ret) goto bail; } *badreg = ri[0].reg; free(ri); good(badreg); return ret;bail: for (i = 0; i < numRI; i++) freeData(&ri[i].reg); free (ri); return pixman_break (badreg);}/*====================================================================== * Region Subtraction *====================================================================*//*- *----------------------------------------------------------------------- * pixman_region_subtractO -- * Overlapping band subtraction. x1 is the left-most point not yet * checked. * * Results: * TRUE if successful. * * Side Effects: * region may have rectangles added to it. * *----------------------------------------------------------------------- *//*ARGSUSED*/static pixman_bool_tpixman_region_subtractO ( pixman_region16_t * region, pixman_box16_t * r1, pixman_box16_t * r1End, pixman_box16_t * r2, pixman_box16_t * r2End, short y1, short y2, int *pOverlap){ pixman_box16_t * pNextRect; int x1; x1 = r1->x1; assert(y1<y2); assert(r1 != r1End && r2 != r2End); pNextRect = PIXREGION_TOP(region); do { if (r2->x2 <= x1) { /* * Subtrahend entirely to left of minuend: go to next subtrahend. */ r2++; } else if (r2->x1 <= x1) { /* * Subtrahend preceeds minuend: nuke left edge of minuend. */ x1 = r2->x2; if (x1 >= r1->x2) { /* * Minuend completely covered: advance to next minuend and * reset left fence to edge of new minuend. */ r1++; if (r1 != r1End) x1 = r1->x1; } else { /* * Subtrahend now used up since it doesn't extend beyond * minuend */ r2++; } } else if (r2->x1 < r1->x2) { /* * Left part of subtrahend covers part of minuend: add uncovered * part of minuend to region and skip to next subtrahend. */ assert(x1<r2->x1); NEWRECT(region, pNextRect, x1, y1, r2->x1, y2); x1 = r2->x2; if (x1 >= r1->x2) { /* * Minuend used up: advance to new... */ r1++; if (r1 != r1End) x1 = r1->x1; } else { /* * Subtrahend used up */ r2++; } } else { /* * Minuend used up: add any remaining piece before advancing. */ if (r1->x2 > x1) NEWRECT(region, pNextRect, x1, y1, r1->x2, y2); r1++; if (r1 != r1End) x1 = r1->x1; } } while ((r1 != r1End) && (r2 != r2End)); /* * Add remaining minuend rectangles to region. */ while (r1 != r1End) { assert(x1<r1->x2); NEWRECT(region, pNextRect, x1, y1, r1->x2, y2); r1++; if (r1 != r1End) x1 = r1->x1; } return TRUE;}/*- *----------------------------------------------------------------------- * pixman_region_subtract -- * Subtract regS from regM and leave the result in regD. * S stands for subtrahend, M for minuend and D for difference. * * Results: * TRUE if successful. * * Side Effects: * regD is overwritten. * *----------------------------------------------------------------------- */pixman_bool_tpixman_region_subtract(pixman_region16_t * regD, pixman_region16_t * regM, pixman_region16_t * regS){ int overlap; /* result ignored */ good(regM); good(regS); good(regD); /* check for trivial rejects */ if (PIXREGION_NIL(regM) || PIXREGION_NIL(regS) || !EXTENTCHECK(®M->extents, ®S->extents)) { if (PIXREGION_NAR (regS)) return pixman_break (regD); return pixman_region_copy(regD, regM); } else if (regM == regS) { freeData(regD); regD->extents.x2 = regD->extents.x1; regD->extents.y2 = regD->extents.y1; regD->data = pixman_region_emptyData; return TRUE; } /* Add those rectangles in region 1 that aren't in region 2, do yucky substraction for overlaps, and just throw away rectangles in region 2 that aren't in region 1 */ if (!pixman_op(regD, regM, regS, pixman_region_subtractO, TRUE, FALSE, &overlap)) return FALSE; /* * Can't alter RegD's extents before we call pixman_op because * it might be one of the source regions and pixman_op depends * on the extents of those regions being unaltered. Besides, this * way there's no checking against rectangles that will be nuked * due to coalescing, so we have to examine fewer rectangles. */ pixman_set_extents(regD); good(regD); return TRUE;}/*====================================================================== * Region Inversion *====================================================================*//*- *----------------------------------------------------------------------- * pixman_region_inverse -- * Take a region and a box and return a region that is everything * in the box but not in the region. The careful reader will note * that this is the same as subtracting the region from the box... * * Results: * TRUE. * * Side Effects: * newReg is overwritten. * *----------------------------------------------------------------------- */pixman_bool_tpixman_region_inverse(pixman_region16_t * newReg, /* Destination region */ pixman_region16_t * reg1, /* Region to invert */ pixman_box16_t * invRect) /* Bounding box for inversion */{ pixman_region16_t invReg; /* Quick and dirty region made from the * bounding box */ int overlap; /* result ignored */ good(reg1); good(newReg); /* check for trivial rejects */ if (PIXREGION_NIL(reg1) || !EXTENTCHECK(invRect, ®1->extents)) { if (PIXREGION_NAR(reg1)) return pixman_break (newReg); newReg->extents = *invRect;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -