📄 pixman-region.c
字号:
pixman_coalesce ( pixman_region16_t * region, /* Region to coalesce */ int prevStart, /* Index of start of previous band */ int curStart) /* Index of start of current band */{ pixman_box16_t * pPrevBox; /* Current box in previous band */ pixman_box16_t * pCurBox; /* Current box in current band */ int numRects; /* Number rectangles in both bands */ int y2; /* Bottom of current band */ /* * Figure out how many rectangles are in the band. */ numRects = curStart - prevStart; assert(numRects == region->data->numRects - curStart); if (!numRects) return curStart; /* * The bands may only be coalesced if the bottom of the previous * matches the top scanline of the current. */ pPrevBox = PIXREGION_BOX(region, prevStart); pCurBox = PIXREGION_BOX(region, curStart); if (pPrevBox->y2 != pCurBox->y1) return curStart; /* * Make sure the bands have boxes in the same places. This * assumes that boxes have been added in such a way that they * cover the most area possible. I.e. two boxes in a band must * have some horizontal space between them. */ y2 = pCurBox->y2; do { if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) { return (curStart); } pPrevBox++; pCurBox++; numRects--; } while (numRects); /* * The bands may be merged, so set the bottom y of each box * in the previous band to the bottom y of the current band. */ numRects = curStart - prevStart; region->data->numRects -= numRects; do { pPrevBox--; pPrevBox->y2 = y2; numRects--; } while (numRects); return prevStart;}/* Quicky macro to avoid trivial reject procedure calls to pixman_coalesce */#define Coalesce(newReg, prevBand, curBand) \ if (curBand - prevBand == newReg->data->numRects - curBand) { \ prevBand = pixman_coalesce(newReg, prevBand, curBand); \ } else { \ prevBand = curBand; \ }/*- *----------------------------------------------------------------------- * pixman_region_appendNonO -- * Handle a non-overlapping band for the union and subtract operations. * Just adds the (top/bottom-clipped) rectangles into the region. * Doesn't have to check for subsumption or anything. * * Results: * None. * * Side Effects: * region->data->numRects is incremented and the rectangles overwritten * with the rectangles we're passed. * *----------------------------------------------------------------------- */static inline pixman_bool_tpixman_region_appendNonO ( pixman_region16_t * region, pixman_box16_t * r, pixman_box16_t * rEnd, int y1, int y2){ pixman_box16_t * pNextRect; int newRects; newRects = rEnd - r; assert(y1 < y2); assert(newRects != 0); /* Make sure we have enough space for all rectangles to be added */ RECTALLOC(region, newRects); pNextRect = PIXREGION_TOP(region); region->data->numRects += newRects; do { assert(r->x1 < r->x2); ADDRECT(pNextRect, r->x1, y1, r->x2, y2); r++; } while (r != rEnd); return TRUE;}#define FindBand(r, rBandEnd, rEnd, ry1) \{ \ ry1 = r->y1; \ rBandEnd = r+1; \ while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \ rBandEnd++; \ } \}#define AppendRegions(newReg, r, rEnd) \{ \ int newRects; \ if ((newRects = rEnd - r)) { \ RECTALLOC(newReg, newRects); \ memmove((char *)PIXREGION_TOP(newReg),(char *)r, \ newRects * sizeof(pixman_box16_t)); \ newReg->data->numRects += newRects; \ } \}/*- *----------------------------------------------------------------------- * pixman_op -- * Apply an operation to two regions. Called by pixman_region_union, pixman_region_inverse, * pixman_region_subtract, pixman_region_intersect.... Both regions MUST have at least one * rectangle, and cannot be the same object. * * Results: * TRUE if successful. * * Side Effects: * The new region is overwritten. * pOverlap set to TRUE if overlapFunc ever returns TRUE. * * Notes: * The idea behind this function is to view the two regions as sets. * Together they cover a rectangle of area that this function divides * into horizontal bands where points are covered only by one region * or by both. For the first case, the nonOverlapFunc is called with * each the band and the band's upper and lower extents. For the * second, the overlapFunc is called to process the entire band. It * is responsible for clipping the rectangles in the band, though * this function provides the boundaries. * At the end of each band, the new region is coalesced, if possible, * to reduce the number of rectangles in the region. * *----------------------------------------------------------------------- */typedef pixman_bool_t (*OverlapProcPtr)( 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);static pixman_bool_tpixman_op( pixman_region16_t *newReg, /* Place to store result */ pixman_region16_t * reg1, /* First region in operation */ pixman_region16_t * reg2, /* 2d region in operation */ OverlapProcPtr overlapFunc, /* Function to call for over- * lapping bands */ int appendNon1, /* Append non-overlapping bands */ /* in region 1 ? */ int appendNon2, /* Append non-overlapping bands */ /* in region 2 ? */ int *pOverlap){ pixman_box16_t * r1; /* Pointer into first region */ pixman_box16_t * r2; /* Pointer into 2d region */ pixman_box16_t * r1End; /* End of 1st region */ pixman_box16_t * r2End; /* End of 2d region */ short ybot; /* Bottom of intersection */ short ytop; /* Top of intersection */ pixman_region16_data_t * oldData; /* Old data for newReg */ int prevBand; /* Index of start of * previous band in newReg */ int curBand; /* Index of start of current * band in newReg */ pixman_box16_t * r1BandEnd; /* End of current band in r1 */ pixman_box16_t * r2BandEnd; /* End of current band in r2 */ short top; /* Top of non-overlapping band */ short bot; /* Bottom of non-overlapping band*/ int r1y1; /* Temps for r1->y1 and r2->y1 */ int r2y1; int newSize; int numRects; /* * Break any region computed from a broken region */ if (PIXREGION_NAR (reg1) || PIXREGION_NAR(reg2)) return pixman_break (newReg); /* * Initialization: * set r1, r2, r1End and r2End appropriately, save the rectangles * of the destination region until the end in case it's one of * the two source regions, then mark the "new" region empty, allocating * another array of rectangles for it to use. */ r1 = PIXREGION_RECTS(reg1); newSize = PIXREGION_NUM_RECTS(reg1); r1End = r1 + newSize; numRects = PIXREGION_NUM_RECTS(reg2); r2 = PIXREGION_RECTS(reg2); r2End = r2 + numRects; assert(r1 != r1End); assert(r2 != r2End); oldData = (pixman_region16_data_t *)NULL; if (((newReg == reg1) && (newSize > 1)) || ((newReg == reg2) && (numRects > 1))) { oldData = newReg->data; newReg->data = pixman_region_emptyData; } /* guess at new size */ if (numRects > newSize) newSize = numRects; newSize <<= 1; if (!newReg->data) newReg->data = pixman_region_emptyData; else if (newReg->data->size) newReg->data->numRects = 0; if (newSize > newReg->data->size) { if (!pixman_rect_alloc(newReg, newSize)) { if (oldData) free (oldData); return FALSE; } } /* * Initialize ybot. * In the upcoming loop, ybot and ytop serve different functions depending * on whether the band being handled is an overlapping or non-overlapping * band. * In the case of a non-overlapping band (only one of the regions * has points in the band), ybot is the bottom of the most recent * intersection and thus clips the top of the rectangles in that band. * ytop is the top of the next intersection between the two regions and * serves to clip the bottom of the rectangles in the current band. * For an overlapping band (where the two regions intersect), ytop clips * the top of the rectangles of both regions and ybot clips the bottoms. */ ybot = MIN(r1->y1, r2->y1); /* * prevBand serves to mark the start of the previous band so rectangles * can be coalesced into larger rectangles. qv. pixman_coalesce, above. * In the beginning, there is no previous band, so prevBand == curBand * (curBand is set later on, of course, but the first band will always * start at index 0). prevBand and curBand must be indices because of * the possible expansion, and resultant moving, of the new region's * array of rectangles. */ prevBand = 0; do { /* * This algorithm proceeds one source-band (as opposed to a * destination band, which is determined by where the two regions * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the * rectangle after the last one in the current band for their * respective regions. */ assert(r1 != r1End); assert(r2 != r2End); FindBand(r1, r1BandEnd, r1End, r1y1); FindBand(r2, r2BandEnd, r2End, r2y1); /* * First handle the band that doesn't intersect, if any. * * Note that attention is restricted to one band in the * non-intersecting region at once, so if a region has n * bands between the current position and the next place it overlaps * the other, this entire loop will be passed through n times. */ if (r1y1 < r2y1) { if (appendNon1) { top = MAX(r1y1, ybot); bot = MIN(r1->y2, r2y1); if (top != bot) { curBand = newReg->data->numRects; pixman_region_appendNonO(newReg, r1, r1BandEnd, top, bot); Coalesce(newReg, prevBand, curBand); } } ytop = r2y1; } else if (r2y1 < r1y1) { if (appendNon2) { top = MAX(r2y1, ybot); bot = MIN(r2->y2, r1y1); if (top != bot) { curBand = newReg->data->numRects; pixman_region_appendNonO(newReg, r2, r2BandEnd, top, bot); Coalesce(newReg, prevBand, curBand); } } ytop = r1y1; } else { ytop = r1y1; } /* * Now see if we've hit an intersecting band. The two bands only * intersect if ybot > ytop */ ybot = MIN(r1->y2, r2->y2); if (ybot > ytop) { curBand = newReg->data->numRects; (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, pOverlap); Coalesce(newReg, prevBand, curBand); } /* * If we've finished with a band (y2 == ybot) we skip forward * in the region to the next band. */ if (r1->y2 == ybot) r1 = r1BandEnd; if (r2->y2 == ybot) r2 = r2BandEnd; } while (r1 != r1End && r2 != r2End); /* * Deal with whichever region (if any) still has rectangles left. * * We only need to worry about banding and coalescing for the very first * band left. After that, we can just group all remaining boxes, * regardless of how many bands, into one final append to the list. */ if ((r1 != r1End) && appendNon1) { /* Do first nonOverlap1Func call, which may be able to coalesce */ FindBand(r1, r1BandEnd, r1End, r1y1); curBand = newReg->data->numRects; pixman_region_appendNonO(newReg, r1, r1BandEnd, MAX(r1y1, ybot), r1->y2); Coalesce(newReg, prevBand, curBand); /* Just append the rest of the boxes */ AppendRegions(newReg, r1BandEnd, r1End); } else if ((r2 != r2End) && appendNon2) { /* Do first nonOverlap2Func call, which may be able to coalesce */ FindBand(r2, r2BandEnd, r2End, r2y1); curBand = newReg->data->numRects; pixman_region_appendNonO(newReg, r2, r2BandEnd, MAX(r2y1, ybot), r2->y2); Coalesce(newReg, prevBand, curBand); /* Append rest of boxes */ AppendRegions(newReg, r2BandEnd, r2End); } if (oldData) free(oldData); if (!(numRects = newReg->data->numRects)) { freeData(newReg); newReg->data = pixman_region_emptyData; } else if (numRects == 1) { newReg->extents = *PIXREGION_BOXPTR(newReg); freeData(newReg); newReg->data = (pixman_region16_data_t *)NULL; } else { DOWNSIZE(newReg, numRects); } return TRUE;}/*- *----------------------------------------------------------------------- * pixman_set_extents -- * Reset the extents of a region to what they should be. Called by * pixman_region_subtract and pixman_region_intersect as they can't figure it out along the * way or do so easily, as pixman_region_union can. * * Results: * None. * * Side Effects: * The region's 'extents' structure is overwritten. * *----------------------------------------------------------------------- */static voidpixman_set_extents (pixman_region16_t *region){ pixman_box16_t *box, *boxEnd; if (!region->data) return; if (!region->data->size) { region->extents.x2 = region->extents.x1; region->extents.y2 = region->extents.y1; return; } box = PIXREGION_BOXPTR(region); boxEnd = PIXREGION_END(region); /* * Since box is the first rectangle in the region, it must have the * smallest y1 and since boxEnd is the last rectangle in the region, * it must have the largest y2, because of banding. Initialize x1 and * x2 from box and boxEnd, resp., as good things to initialize them * to... */ region->extents.x1 = box->x1; region->extents.y1 = box->y1; region->extents.x2 = boxEnd->x2; region->extents.y2 = boxEnd->y2; assert(region->extents.y1 < region->extents.y2); while (box <= boxEnd) { if (box->x1 < region->extents.x1) region->extents.x1 = box->x1; if (box->x2 > region->extents.x2) region->extents.x2 = box->x2; box++; }; assert(region->extents.x1 < region->extents.x2);}/*====================================================================== * Region Intersection *====================================================================*//*- *----------------------------------------------------------------------- * pixman_region_intersectO -- * Handle an overlapping band for pixman_region_intersect. * * Results: * TRUE if successful. * * Side Effects: * Rectangles may be added to the region. * *----------------------------------------------------------------------- */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -