if(mode == CombineModeReplace){
delete_element(®ion->node);
memcpy(region, path_region, sizeof(GpRegion));
+ GdipFree(path_region);
return Ok;
}
out:
GdipFree(left);
- delete_element(right);
GdipDeleteRegion(path_region);
return stat;
}
if(mode == CombineModeReplace){
delete_element(®ion->node);
memcpy(region, rect_region, sizeof(GpRegion));
+ GdipFree(rect_region);
return Ok;
}
out:
GdipFree(left);
- delete_element(right);
GdipDeleteRegion(rect_region);
return stat;
}
return GdipCombineRegionRect(region, &rectf, mode);
}
+/*****************************************************************************
+ * GdipCombineRegionRegion [GDIPLUS.@]
+ */
GpStatus WINGDIPAPI GdipCombineRegionRegion(GpRegion *region1,
GpRegion *region2, CombineMode mode)
{
delete_element(®ion1->node);
memcpy(region1, reg2copy, sizeof(GpRegion));
+ GdipFree(reg2copy);
return Ok;
}
if (stat != Ok)
{
GdipFree(left);
- delete_element(right);
return OutOfMemory;
}
return Ok;
}
+/*****************************************************************************
+ * GdipCreateRegionRectI [GDIPLUS.@]
+ */
GpStatus WINGDIPAPI GdipCreateRegionRectI(GDIPCONST GpRect *rect,
GpRegion **region)
{
return NotImplemented;
}
+
+/******************************************************************************
+ * GdipCreateRegionHrgn [GDIPLUS.@]
+ */
GpStatus WINGDIPAPI GdipCreateRegionHrgn(HRGN hrgn, GpRegion **region)
{
- FIXME("(%p, %p): stub\n", hrgn, region);
+ DWORD size;
+ LPRGNDATA buf;
+ LPRECT rect;
+ GpStatus stat;
+ GpPath* path;
+ GpRegion* local;
+ int i;
- *region = NULL;
- return NotImplemented;
+ TRACE("(%p, %p)\n", hrgn, region);
+
+ if(!region || !(size = GetRegionData(hrgn, 0, NULL)))
+ return InvalidParameter;
+
+ buf = GdipAlloc(size);
+ if(!buf)
+ return OutOfMemory;
+
+ if(!GetRegionData(hrgn, size, buf)){
+ GdipFree(buf);
+ return GenericError;
+ }
+
+ if(buf->rdh.nCount == 0){
+ if((stat = GdipCreateRegion(&local)) != Ok){
+ GdipFree(buf);
+ return stat;
+ }
+ if((stat = GdipSetEmpty(local)) != Ok){
+ GdipFree(buf);
+ GdipDeleteRegion(local);
+ return stat;
+ }
+ *region = local;
+ GdipFree(buf);
+ return Ok;
+ }
+
+ if((stat = GdipCreatePath(FillModeAlternate, &path)) != Ok){
+ GdipFree(buf);
+ return stat;
+ }
+
+ rect = (LPRECT)buf->Buffer;
+ for(i = 0; i < buf->rdh.nCount; i++){
+ if((stat = GdipAddPathRectangle(path, (REAL)rect->left, (REAL)rect->top,
+ (REAL)(rect->right - rect->left), (REAL)(rect->bottom - rect->top))) != Ok){
+ GdipFree(buf);
+ GdipDeletePath(path);
+ return stat;
+ }
+ rect++;
+ }
+
+ stat = GdipCreateRegionPath(path, region);
+
+ GdipFree(buf);
+ GdipDeletePath(path);
+ return stat;
}
+/*****************************************************************************
+ * GdipDeleteRegion [GDIPLUS.@]
+ */
GpStatus WINGDIPAPI GdipDeleteRegion(GpRegion *region)
{
TRACE("%p\n", region);
return Ok;
}
+/*****************************************************************************
+ * GdipGetRegionBounds [GDIPLUS.@]
+ */
GpStatus WINGDIPAPI GdipGetRegionBounds(GpRegion *region, GpGraphics *graphics, GpRectF *rect)
{
- FIXME("(%p, %p, %p): stub\n", region, graphics, rect);
+ HRGN hrgn;
+ RECT r;
+ GpStatus status;
- return NotImplemented;
+ TRACE("(%p, %p, %p)\n", region, graphics, rect);
+
+ if(!region || !graphics || !rect)
+ return InvalidParameter;
+
+ /* Contrary to MSDN, native ignores the graphics transform. */
+ status = GdipGetRegionHRgn(region, NULL, &hrgn);
+ if(status != Ok)
+ return status;
+
+ /* infinite */
+ if(!hrgn){
+ rect->X = rect->Y = -(REAL)(1 << 22);
+ rect->Width = rect->Height = (REAL)(1 << 23);
+ return Ok;
+ }
+
+ if(!GetRgnBox(hrgn, &r)){
+ DeleteObject(hrgn);
+ return GenericError;
+ }
+
+ rect->X = r.left;
+ rect->Y = r.top;
+ rect->Width = r.right - r.left;
+ rect->Height = r.bottom - r.top;
+
+ return Ok;
}
+/*****************************************************************************
+ * GdipGetRegionBoundsI [GDIPLUS.@]
+ */
GpStatus WINGDIPAPI GdipGetRegionBoundsI(GpRegion *region, GpGraphics *graphics, GpRect *rect)
{
- FIXME("(%p, %p, %p): stub\n", region, graphics, rect);
+ GpRectF rectf;
+ GpStatus status;
- return NotImplemented;
+ TRACE("(%p, %p, %p)\n", region, graphics, rect);
+
+ if(!rect)
+ return InvalidParameter;
+
+ status = GdipGetRegionBounds(region, graphics, &rectf);
+ if(status == Ok){
+ rect->X = roundr(rectf.X);
+ rect->Y = roundr(rectf.X);
+ rect->Width = roundr(rectf.Width);
+ rect->Height = roundr(rectf.Height);
+ }
+
+ return status;
}
static inline void write_dword(DWORD* location, INT* offset, const DWORD write)
*
* RETURNS
* SUCCESS: Ok
- * FAILURE: InvalidParamter
+ * FAILURE: InvalidParameter
*
* NOTES
* The header contains the size, a checksum, a version string, and the number
return Ok;
}
+static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn)
+{
+ HDC new_hdc=NULL;
+ GpStatus stat;
+ INT save_state;
+
+ if (!graphics)
+ {
+ new_hdc = GetDC(0);
+ if (!new_hdc)
+ return OutOfMemory;
+
+ stat = GdipCreateFromHDC(new_hdc, &graphics);
+ if (stat != Ok)
+ {
+ ReleaseDC(0, new_hdc);
+ return stat;
+ }
+ }
+
+ save_state = SaveDC(graphics->hdc);
+ EndPath(graphics->hdc);
+
+ SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE
+ : WINDING));
+
+ stat = trace_path(graphics, path);
+ if (stat == Ok)
+ {
+ *hrgn = PathToRegion(graphics->hdc);
+ stat = *hrgn ? Ok : OutOfMemory;
+ }
+
+ RestoreDC(graphics->hdc, save_state);
+ if (new_hdc)
+ {
+ ReleaseDC(0, new_hdc);
+ GdipDeleteGraphics(graphics);
+ }
+
+ return stat;
+}
+
+static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *graphics, HRGN *hrgn)
+{
+ switch (element->type)
+ {
+ case RegionDataInfiniteRect:
+ *hrgn = NULL;
+ return Ok;
+ case RegionDataEmptyRect:
+ *hrgn = CreateRectRgn(0, 0, 0, 0);
+ return *hrgn ? Ok : OutOfMemory;
+ case RegionDataPath:
+ return get_path_hrgn(element->elementdata.pathdata.path, graphics, hrgn);
+ case RegionDataRect:
+ {
+ GpPath* path;
+ GpStatus stat;
+ GpRectF* rc = &element->elementdata.rect;
+
+ stat = GdipCreatePath(FillModeAlternate, &path);
+ if (stat != Ok)
+ return stat;
+ stat = GdipAddPathRectangle(path, rc->X, rc->Y, rc->Width, rc->Height);
+
+ if (stat == Ok)
+ stat = get_path_hrgn(path, graphics, hrgn);
+
+ GdipDeletePath(path);
+
+ return stat;
+ }
+ case CombineModeIntersect:
+ case CombineModeUnion:
+ case CombineModeXor:
+ case CombineModeExclude:
+ case CombineModeComplement:
+ {
+ HRGN left, right;
+ GpStatus stat;
+ int ret;
+
+ stat = get_region_hrgn(element->elementdata.combine.left, graphics, &left);
+ if (stat != Ok)
+ {
+ *hrgn = NULL;
+ return stat;
+ }
+
+ if (left == NULL)
+ {
+ /* existing region is infinite */
+ switch (element->type)
+ {
+ case CombineModeIntersect:
+ return get_region_hrgn(element->elementdata.combine.right, graphics, hrgn);
+ case CombineModeXor: case CombineModeExclude:
+ FIXME("cannot exclude from an infinite region\n");
+ /* fall-through */
+ case CombineModeUnion: case CombineModeComplement:
+ *hrgn = NULL;
+ return Ok;
+ }
+ }
+
+ stat = get_region_hrgn(element->elementdata.combine.right, graphics, &right);
+ if (stat != Ok)
+ {
+ DeleteObject(left);
+ *hrgn = NULL;
+ return stat;
+ }
+
+ if (right == NULL)
+ {
+ /* new region is infinite */
+ switch (element->type)
+ {
+ case CombineModeIntersect:
+ *hrgn = left;
+ return Ok;
+ case CombineModeXor: case CombineModeComplement:
+ FIXME("cannot exclude from an infinite region\n");
+ /* fall-through */
+ case CombineModeUnion: case CombineModeExclude:
+ DeleteObject(left);
+ *hrgn = NULL;
+ return Ok;
+ }
+ }
+
+ switch (element->type)
+ {
+ case CombineModeIntersect:
+ ret = CombineRgn(left, left, right, RGN_AND);
+ break;
+ case CombineModeUnion:
+ ret = CombineRgn(left, left, right, RGN_OR);
+ break;
+ case CombineModeXor:
+ ret = CombineRgn(left, left, right, RGN_XOR);
+ break;
+ case CombineModeExclude:
+ ret = CombineRgn(left, left, right, RGN_DIFF);
+ break;
+ case CombineModeComplement:
+ ret = CombineRgn(left, right, left, RGN_DIFF);
+ break;
+ default:
+ ret = ERROR;
+ }
+
+ DeleteObject(right);
+
+ if (ret == ERROR)
+ {
+ DeleteObject(left);
+ *hrgn = NULL;
+ return GenericError;
+ }
+
+ *hrgn = left;
+ return Ok;
+ }
+ default:
+ FIXME("GdipGetRegionHRgn unimplemented for region type=%x\n", element->type);
+ *hrgn = NULL;
+ return NotImplemented;
+ }
+}
+
/*****************************************************************************
* GdipGetRegionHRgn [GDIPLUS.@]
*/
GpStatus WINGDIPAPI GdipGetRegionHRgn(GpRegion *region, GpGraphics *graphics, HRGN *hrgn)
{
- FIXME("(%p, %p, %p): stub\n", region, graphics, hrgn);
+ TRACE("(%p, %p, %p)\n", region, graphics, hrgn);
- *hrgn = NULL;
- return NotImplemented;
+ if (!region || !hrgn)
+ return InvalidParameter;
+
+ return get_region_hrgn(®ion->node, graphics, hrgn);
}
GpStatus WINGDIPAPI GdipIsEmptyRegion(GpRegion *region, GpGraphics *graphics, BOOL *res)
return Ok;
}
+/*****************************************************************************
+ * GdipIsEqualRegion [GDIPLUS.@]
+ */
GpStatus WINGDIPAPI GdipIsEqualRegion(GpRegion *region, GpRegion *region2, GpGraphics *graphics,
BOOL *res)
{
- FIXME("(%p, %p, %p, %p): stub\n", region, region2, graphics, res);
+ HRGN hrgn1, hrgn2;
+ GpStatus stat;
- return NotImplemented;
+ TRACE("(%p, %p, %p, %p)\n", region, region2, graphics, res);
+
+ if(!region || !region2 || !graphics || !res)
+ return InvalidParameter;
+
+ stat = GdipGetRegionHRgn(region, graphics, &hrgn1);
+ if(stat != Ok)
+ return stat;
+ stat = GdipGetRegionHRgn(region2, graphics, &hrgn2);
+ if(stat != Ok){
+ DeleteObject(hrgn1);
+ return stat;
+ }
+
+ *res = EqualRgn(hrgn1, hrgn2);
+
+ /* one of GpRegions is infinite */
+ if(*res == ERROR)
+ *res = (!hrgn1 && !hrgn2);
+
+ DeleteObject(hrgn1);
+ DeleteObject(hrgn2);
+
+ return Ok;
}
/*****************************************************************************
return Ok;
}
+/*****************************************************************************
+ * GdipIsVisibleRegionRect [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipIsVisibleRegionRect(GpRegion* region, REAL x, REAL y, REAL w, REAL h, GpGraphics *graphics, BOOL *res)
+{
+ HRGN hrgn;
+ GpStatus stat;
+ RECT rect;
+
+ TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %p, %p)\n", region, x, y, w, h, graphics, res);
+
+ if(!region || !res)
+ return InvalidParameter;
+
+ if((stat = GdipGetRegionHRgn(region, NULL, &hrgn)) != Ok)
+ return stat;
+
+ /* infinite */
+ if(!hrgn){
+ *res = TRUE;
+ return Ok;
+ }
+
+ rect.left = ceilr(x);
+ rect.top = ceilr(y);
+ rect.right = ceilr(x + w);
+ rect.bottom = ceilr(y + h);
+
+ *res = RectInRegion(hrgn, &rect);
+
+ DeleteObject(hrgn);
+
+ return Ok;
+}
+
+/*****************************************************************************
+ * GdipIsVisibleRegionRectI [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipIsVisibleRegionRectI(GpRegion* region, INT x, INT y, INT w, INT h, GpGraphics *graphics, BOOL *res)
+{
+ TRACE("(%p, %d, %d, %d, %d, %p, %p)\n", region, x, y, w, h, graphics, res);
+ if(!region || !res)
+ return InvalidParameter;
+
+ return GdipIsVisibleRegionRect(region, (REAL)x, (REAL)y, (REAL)w, (REAL)h, graphics, res);
+}
+
+/*****************************************************************************
+ * GdipIsVisibleRegionPoint [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipIsVisibleRegionPoint(GpRegion* region, REAL x, REAL y, GpGraphics *graphics, BOOL *res)
+{
+ HRGN hrgn;
+ GpStatus stat;
+
+ TRACE("(%p, %.2f, %.2f, %p, %p)\n", region, x, y, graphics, res);
+
+ if(!region || !res)
+ return InvalidParameter;
+
+ if((stat = GdipGetRegionHRgn(region, NULL, &hrgn)) != Ok)
+ return stat;
+
+ /* infinite */
+ if(!hrgn){
+ *res = TRUE;
+ return Ok;
+ }
+
+ *res = PtInRegion(hrgn, roundr(x), roundr(y));
+
+ DeleteObject(hrgn);
+
+ return Ok;
+}
+
+/*****************************************************************************
+ * GdipIsVisibleRegionPointI [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipIsVisibleRegionPointI(GpRegion* region, INT x, INT y, GpGraphics *graphics, BOOL *res)
+{
+ TRACE("(%p, %d, %d, %p, %p)\n", region, x, y, graphics, res);
+
+ return GdipIsVisibleRegionPoint(region, (REAL)x, (REAL)y, graphics, res);
+}
+
/*****************************************************************************
* GdipSetEmpty [GDIPLUS.@]
*/
return NotImplemented;
}
+/* Translates GpRegion elements with specified offsets */
+static void translate_region_element(region_element* element, REAL dx, REAL dy)
+{
+ INT i;
+
+ switch(element->type)
+ {
+ case RegionDataEmptyRect:
+ case RegionDataInfiniteRect:
+ return;
+ case RegionDataRect:
+ element->elementdata.rect.X += dx;
+ element->elementdata.rect.Y += dy;
+ return;
+ case RegionDataPath:
+ for(i = 0; i < element->elementdata.pathdata.path->pathdata.Count; i++){
+ element->elementdata.pathdata.path->pathdata.Points[i].X += dx;
+ element->elementdata.pathdata.path->pathdata.Points[i].Y += dy;
+ }
+ return;
+ default:
+ translate_region_element(element->elementdata.combine.left, dx, dy);
+ translate_region_element(element->elementdata.combine.right, dx, dy);
+ return;
+ }
+}
+
+/*****************************************************************************
+ * GdipTranslateRegion [GDIPLUS.@]
+ */
GpStatus WINGDIPAPI GdipTranslateRegion(GpRegion *region, REAL dx, REAL dy)
{
- FIXME("(%p, %f, %f): stub\n", region, dx, dy);
+ TRACE("(%p, %f, %f)\n", region, dx, dy);
- return NotImplemented;
+ if(!region)
+ return InvalidParameter;
+
+ translate_region_element(®ion->node, dx, dy);
+
+ return Ok;
}
+/*****************************************************************************
+ * GdipTranslateRegionI [GDIPLUS.@]
+ */
GpStatus WINGDIPAPI GdipTranslateRegionI(GpRegion *region, INT dx, INT dy)
{
- FIXME("(%p, %d, %d): stub\n", region, dx, dy);
+ TRACE("(%p, %d, %d)\n", region, dx, dy);
+
+ return GdipTranslateRegion(region, (REAL)dx, (REAL)dy);
+}
+
+GpStatus WINGDIPAPI GdipGetRegionScansCount(GpRegion *region, UINT *count, GpMatrix *matrix)
+{
+ static int calls;
+
+ TRACE("(%p, %p, %p)\n", region, count, matrix);
+
+ if (!(calls++))
+ FIXME("not implemented\n");
return NotImplemented;
}