Author: tkreuzer Date: Tue Nov 4 20:20:45 2014 New Revision: 65252
URL: http://svn.reactos.org/svn/reactos?rev=65252&view=rev Log: [WIN32K] - Fix completely broken REGION_CropAndOffsetRegion - Make sure iType is correctly set in NtGdiGetRegionData
Modified: trunk/reactos/win32ss/gdi/ntgdi/region.c
Modified: trunk/reactos/win32ss/gdi/ntgdi/region.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/gdi/ntgdi/region.c?... ============================================================================== --- trunk/reactos/win32ss/gdi/ntgdi/region.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/gdi/ntgdi/region.c [iso-8859-1] Tue Nov 4 20:20:45 2014 @@ -577,7 +577,7 @@ pReg->rdh.iType = RDH_RECTANGLES; }
-// FIXME: This seems to be wrong +// FIXME: This function needs review and testing /*********************************************************************** * REGION_CropAndOffsetRegion */ @@ -649,82 +649,106 @@ else // Region box and clipping rect appear to intersect { PRECTL lpr, rpr; - ULONG i, j, clipa, clipb; - INT left = rgnSrc->rdh.rcBound.right + off->x; - INT right = rgnSrc->rdh.rcBound.left + off->x; - - for (clipa = 0; (rgnSrc->Buffer + clipa)->bottom <= rect->top; clipa++) - // Region and rect intersect so we stop before clipa > rgnSrc->rdh.nCount - ; // skip bands above the clipping rectangle - + ULONG i, j, clipa, clipb, nRgnSize; + INT left = MAXLONG; + INT right = MINLONG; + INT top = MAXLONG; + INT bottom = MINLONG; + + /* Skip all rects that are completely above our intersect rect */ + for (clipa = 0; clipa < rgnSrc->rdh.nCount; clipa++) + { + /* bottom is exclusive, so break when we go above it */ + if (rgnSrc->Buffer[clipa].bottom > rect->top) break; + } + + /* Bail out, if there is nothing left */ + if (clipa == rgnSrc->rdh.nCount) goto empty; + + /* Find the last rect that is still within the intersect rect (exclusive) */ for (clipb = clipa; clipb < rgnSrc->rdh.nCount; clipb++) - if ((rgnSrc->Buffer + clipb)->top >= rect->bottom) - break; // and below it + { + /* bottom is exclusive, so stop, when we start at that y pos */ + if (rgnSrc->Buffer[clipb].top >= rect->bottom) break; + } + + /* Bail out, if there is nothing left */ + if (clipb == clipa) goto empty;
// clipa - index of the first rect in the first intersecting band - // clipb - index of the last rect in the last intersecting band - - if ((rgnDst != rgnSrc) && (rgnDst->rdh.nCount < (i = (clipb - clipa)))) + // clipb - index of the last rect in the last intersecting band plus 1 + + /* Check if the buffer in the dest region is large enough, + otherwise allocate a new one */ + nRgnSize = (clipb - clipa) * sizeof(RECT); + if ((rgnDst != rgnSrc) && (rgnDst->rdh.nRgnSize < nRgnSize)) { PRECTL temp; - temp = ExAllocatePoolWithTag(PagedPool, i * sizeof(RECT), TAG_REGION); + temp = ExAllocatePoolWithTag(PagedPool, nRgnSize, TAG_REGION); if (!temp) return ERROR;
- if (rgnDst->Buffer && rgnDst->Buffer != &rgnDst->rdh.rcBound) - ExFreePoolWithTag(rgnDst->Buffer, TAG_REGION); // free the old buffer + /* Free the old buffer */ + if (rgnDst->Buffer && (rgnDst->Buffer != &rgnDst->rdh.rcBound)) + ExFreePoolWithTag(rgnDst->Buffer, TAG_REGION); + rgnDst->Buffer = temp; - rgnDst->rdh.nCount = i; - rgnDst->rdh.nRgnSize = i * sizeof(RECT); - } - + rgnDst->rdh.nCount = 0; + rgnDst->rdh.nRgnSize = nRgnSize; + rgnDst->rdh.iType = RDH_RECTANGLES; + } + + /* Loop all rects within the intersect rect from the y perspective */ for (i = clipa, j = 0; i < clipb ; i++) { // i - src index, j - dst index, j is always <= i for obvious reasons
- lpr = rgnSrc->Buffer + i; - - if (lpr->left < rect->right && lpr->right > rect->left) + lpr = &rgnSrc->Buffer[i]; + + /* Make sure the source rect is not retarded */ + ASSERT(lpr->bottom > rect->top); + ASSERT(lpr->right > rect->left); + + /* We already checked above, this should hold true */ + ASSERT(lpr->bottom > rect->top); + ASSERT(lpr->top < rect->bottom); + + /* Check if this rect is really inside the intersect rect */ + if ((lpr->left < rect->right) && (lpr->right > rect->left)) { - rpr = rgnDst->Buffer + j; - - rpr->top = lpr->top + off->y; - rpr->bottom = lpr->bottom + off->y; - rpr->left = ((lpr->left > rect->left) ? lpr->left : rect->left) + off->x; - rpr->right = ((lpr->right < rect->right) ? lpr->right : rect->right) + off->x; - + rpr = &rgnDst->Buffer[j]; + + /* Crop the rect with the intersect rect and add offset */ + rpr->top = max(lpr->top, rect->top) + off->y; + rpr->bottom = min(lpr->bottom, rect->bottom) + off->y; + rpr->left = max(lpr->left, rect->left) + off->x; + rpr->right = min(lpr->right, rect->right) + off->y; + + /* Make sure the resulting rect is not retarded */ + ASSERT(lpr->bottom > rect->top); + ASSERT(lpr->right > rect->left); + + /* Track new bounds */ if (rpr->left < left) left = rpr->left; if (rpr->right > right) right = rpr->right; - + if (rpr->top < top) top = rpr->top; + if (rpr->bottom > bottom) bottom = rpr->bottom; + + /* Next target rect */ j++; } }
if (j == 0) goto empty;
+ /* Update the bounds rect */ rgnDst->rdh.rcBound.left = left; rgnDst->rdh.rcBound.right = right; - - left = rect->top + off->y; - right = rect->bottom + off->y; - - rgnDst->rdh.nCount = j--; - for (i = 0; i <= j; i++) // Fixup top band - if ((rgnDst->Buffer + i)->top < left) - (rgnDst->Buffer + i)->top = left; - else - break; - - for (i = j; i > 0; i--) // Fixup bottom band - if ((rgnDst->Buffer + i)->bottom > right) - (rgnDst->Buffer + i)->bottom = right; - else - break; - - rgnDst->rdh.rcBound.top = (rgnDst->Buffer)->top; - rgnDst->rdh.rcBound.bottom = (rgnDst->Buffer + j)->bottom; - - rgnDst->rdh.iType = RDH_RECTANGLES; + rgnDst->rdh.rcBound.top = top; + rgnDst->rdh.rcBound.bottom = bottom; + + /* Set new rect count */ + rgnDst->rdh.nCount = j; }
return REGION_Complexity(rgnDst); @@ -732,15 +756,9 @@ empty: if (!rgnDst->Buffer) { - rgnDst->Buffer = ExAllocatePoolWithTag(PagedPool, RGN_DEFAULT_RECTS * sizeof(RECT), TAG_REGION); - if (rgnDst->Buffer) - { - rgnDst->rdh.nCount = RGN_DEFAULT_RECTS; - rgnDst->rdh.nRgnSize = RGN_DEFAULT_RECTS * sizeof(RECT); - } - else - return ERROR; - } + rgnDst->Buffer = &rgnDst->rdh.rcBound; + } + EMPTY_REGION(rgnDst); return NULLREGION; } @@ -4004,6 +4022,7 @@ ProbeForWrite(lpRgnData, cjSize, sizeof(ULONG)); RtlCopyMemory(lpRgnData, &prgn->rdh, sizeof(RGNDATAHEADER)); RtlCopyMemory(lpRgnData->Buffer, prgn->Buffer, cjRects); + lpRgnData->rdh.iType = RDH_RECTANGLES; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {