ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

region.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Google (Lei Zhang)
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00017  */
00018 
00019 #include <stdarg.h>
00020 
00021 #include "windef.h"
00022 #include "winbase.h"
00023 #include "wingdi.h"
00024 
00025 #include "objbase.h"
00026 
00027 #include "gdiplus.h"
00028 #include "gdiplus_private.h"
00029 #include "wine/debug.h"
00030 
00031 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
00032 
00033 /**********************************************************
00034  *
00035  * Data returned by GdipGetRegionData looks something like this:
00036  *
00037  * struct region_data_header
00038  * {
00039  *   DWORD size;     size in bytes of the data - 8.
00040  *   DWORD magic1;   probably a checksum.
00041  *   DWORD magic2;   always seems to be 0xdbc01001 - version?
00042  *   DWORD num_ops;  number of combining ops * 2
00043  * };
00044  *
00045  * Then follows a sequence of combining ops and region elements.
00046  *
00047  * A region element is either a RECTF or some path data.
00048  *
00049  * Combining ops are just stored as their CombineMode value.
00050  *
00051  * Each RECTF is preceded by the DWORD 0x10000000.  An empty rect is
00052  * stored as 0x10000002 (with no following RECTF) and an infinite rect
00053  * is stored as 0x10000003 (again with no following RECTF).
00054  *
00055  * Path data is preceded by the DWORD 0x10000001.  Then follows a
00056  * DWORD size and then size bytes of data.
00057  *
00058  * The combining ops are stored in the reverse order to the region
00059  * elements and in the reverse order to which the region was
00060  * constructed.
00061  *
00062  * When two or more complex regions (ie those with more than one
00063  * element) are combined, the combining op for the two regions comes
00064  * first, then the combining ops for the region elements in region 1,
00065  * followed by the region elements for region 1, then follows the
00066  * combining ops for region 2 and finally region 2's region elements.
00067  * Presumably you're supposed to use the 0x1000000x header to find the
00068  * end of the op list (the count of the elements in each region is not
00069  * stored).
00070  *
00071  * When a simple region (1 element) is combined, it's treated as if a
00072  * single rect/path is being combined.
00073  *
00074  */
00075 
00076 #define FLAGS_NOFLAGS   0x0
00077 #define FLAGS_INTPATH   0x4000
00078 
00079 /* Header size as far as header->size is concerned. This doesn't include
00080  * header->size or header->checksum
00081  */
00082 static const INT sizeheader_size = sizeof(DWORD) * 2;
00083 
00084 typedef struct packed_point
00085 {
00086     short X;
00087     short Y;
00088 } packed_point;
00089 
00090 /* Everything is measured in DWORDS; round up if there's a remainder */
00091 static inline INT get_pathtypes_size(const GpPath* path)
00092 {
00093     INT needed = path->pathdata.Count / sizeof(DWORD);
00094 
00095     if (path->pathdata.Count % sizeof(DWORD) > 0)
00096         needed++;
00097 
00098     return needed * sizeof(DWORD);
00099 }
00100 
00101 static inline INT get_element_size(const region_element* element)
00102 {
00103     INT needed = sizeof(DWORD); /* DWORD for the type */
00104     switch(element->type)
00105     {
00106         case RegionDataRect:
00107             return needed + sizeof(GpRect);
00108         case RegionDataPath:
00109              needed += element->elementdata.pathdata.pathheader.size;
00110              needed += sizeof(DWORD); /* Extra DWORD for pathheader.size */
00111              return needed;
00112         case RegionDataEmptyRect:
00113         case RegionDataInfiniteRect:
00114             return needed;
00115         default:
00116             needed += get_element_size(element->elementdata.combine.left);
00117             needed += get_element_size(element->elementdata.combine.right);
00118             return needed;
00119     }
00120 
00121     return 0;
00122 }
00123 
00124 /* Does not check parameters, caller must do that */
00125 static inline GpStatus init_region(GpRegion* region, const RegionType type)
00126 {
00127     region->node.type       = type;
00128     region->header.checksum = 0xdeadbeef;
00129     region->header.magic    = VERSION_MAGIC;
00130     region->header.num_children  = 0;
00131     region->header.size     = sizeheader_size + get_element_size(&region->node);
00132 
00133     return Ok;
00134 }
00135 
00136 static inline GpStatus clone_element(const region_element* element,
00137         region_element** element2)
00138 {
00139     GpStatus stat;
00140 
00141     /* root node is allocated with GpRegion */
00142     if(!*element2){
00143         *element2 = GdipAlloc(sizeof(region_element));
00144         if (!*element2)
00145             return OutOfMemory;
00146     }
00147 
00148     (*element2)->type = element->type;
00149 
00150     switch (element->type)
00151     {
00152         case RegionDataRect:
00153             (*element2)->elementdata.rect = element->elementdata.rect;
00154             break;
00155         case RegionDataEmptyRect:
00156         case RegionDataInfiniteRect:
00157             break;
00158         case RegionDataPath:
00159             (*element2)->elementdata.pathdata.pathheader = element->elementdata.pathdata.pathheader;
00160             stat = GdipClonePath(element->elementdata.pathdata.path,
00161                     &(*element2)->elementdata.pathdata.path);
00162             if (stat != Ok) goto clone_out;
00163             break;
00164         default:
00165             (*element2)->elementdata.combine.left  = NULL;
00166             (*element2)->elementdata.combine.right = NULL;
00167 
00168             stat = clone_element(element->elementdata.combine.left,
00169                     &(*element2)->elementdata.combine.left);
00170             if (stat != Ok) goto clone_out;
00171             stat = clone_element(element->elementdata.combine.right,
00172                     &(*element2)->elementdata.combine.right);
00173             if (stat != Ok) goto clone_out;
00174             break;
00175     }
00176 
00177     return Ok;
00178 
00179 clone_out:
00180     delete_element(*element2);
00181     *element2 = NULL;
00182     return stat;
00183 }
00184 
00185 /* Common code for CombineRegion*
00186  * All the caller has to do is get its format into an element
00187  */
00188 static inline void fuse_region(GpRegion* region, region_element* left,
00189         region_element* right, const CombineMode mode)
00190 {
00191     region->node.type = mode;
00192     region->node.elementdata.combine.left = left;
00193     region->node.elementdata.combine.right = right;
00194 
00195     region->header.size = sizeheader_size + get_element_size(&region->node);
00196     region->header.num_children += 2;
00197 }
00198 
00199 /*****************************************************************************
00200  * GdipCloneRegion [GDIPLUS.@]
00201  *
00202  * Creates a deep copy of the region
00203  *
00204  * PARAMS
00205  *  region  [I] source region
00206  *  clone   [O] resulting clone
00207  *
00208  * RETURNS
00209  *  SUCCESS: Ok
00210  *  FAILURE: InvalidParameter or OutOfMemory
00211  */
00212 GpStatus WINGDIPAPI GdipCloneRegion(GpRegion *region, GpRegion **clone)
00213 {
00214     region_element *element;
00215 
00216     TRACE("%p %p\n", region, clone);
00217 
00218     if (!(region && clone))
00219         return InvalidParameter;
00220 
00221     *clone = GdipAlloc(sizeof(GpRegion));
00222     if (!*clone)
00223         return OutOfMemory;
00224     element = &(*clone)->node;
00225 
00226     (*clone)->header = region->header;
00227     return clone_element(&region->node, &element);
00228 }
00229 
00230 /*****************************************************************************
00231  * GdipCombineRegionPath [GDIPLUS.@]
00232  */
00233 GpStatus WINGDIPAPI GdipCombineRegionPath(GpRegion *region, GpPath *path, CombineMode mode)
00234 {
00235     GpRegion *path_region;
00236     region_element *left, *right = NULL;
00237     GpStatus stat;
00238 
00239     TRACE("%p %p %d\n", region, path, mode);
00240 
00241     if (!(region && path))
00242         return InvalidParameter;
00243 
00244     stat = GdipCreateRegionPath(path, &path_region);
00245     if (stat != Ok)
00246         return stat;
00247 
00248     /* simply replace region data */
00249     if(mode == CombineModeReplace){
00250         delete_element(&region->node);
00251         memcpy(region, path_region, sizeof(GpRegion));
00252         GdipFree(path_region);
00253         return Ok;
00254     }
00255 
00256     left = GdipAlloc(sizeof(region_element));
00257     if (!left)
00258         goto out;
00259     *left = region->node;
00260 
00261     stat = clone_element(&path_region->node, &right);
00262     if (stat != Ok)
00263         goto out;
00264 
00265     fuse_region(region, left, right, mode);
00266 
00267     GdipDeleteRegion(path_region);
00268     return Ok;
00269 
00270 out:
00271     GdipFree(left);
00272     GdipDeleteRegion(path_region);
00273     return stat;
00274 }
00275 
00276 /*****************************************************************************
00277  * GdipCombineRegionRect [GDIPLUS.@]
00278  */
00279 GpStatus WINGDIPAPI GdipCombineRegionRect(GpRegion *region,
00280         GDIPCONST GpRectF *rect, CombineMode mode)
00281 {
00282     GpRegion *rect_region;
00283     region_element *left, *right = NULL;
00284     GpStatus stat;
00285 
00286     TRACE("%p %p %d\n", region, rect, mode);
00287 
00288     if (!(region && rect))
00289         return InvalidParameter;
00290 
00291     stat = GdipCreateRegionRect(rect, &rect_region);
00292     if (stat != Ok)
00293         return stat;
00294 
00295     /* simply replace region data */
00296     if(mode == CombineModeReplace){
00297         delete_element(&region->node);
00298         memcpy(region, rect_region, sizeof(GpRegion));
00299         GdipFree(rect_region);
00300         return Ok;
00301     }
00302 
00303     left = GdipAlloc(sizeof(region_element));
00304     if (!left)
00305         goto out;
00306     memcpy(left, &region->node, sizeof(region_element));
00307 
00308     stat = clone_element(&rect_region->node, &right);
00309     if (stat != Ok)
00310         goto out;
00311 
00312     fuse_region(region, left, right, mode);
00313 
00314     GdipDeleteRegion(rect_region);
00315     return Ok;
00316 
00317 out:
00318     GdipFree(left);
00319     GdipDeleteRegion(rect_region);
00320     return stat;
00321 }
00322 
00323 /*****************************************************************************
00324  * GdipCombineRegionRectI [GDIPLUS.@]
00325  */
00326 GpStatus WINGDIPAPI GdipCombineRegionRectI(GpRegion *region,
00327         GDIPCONST GpRect *rect, CombineMode mode)
00328 {
00329     GpRectF rectf;
00330 
00331     TRACE("%p %p %d\n", region, rect, mode);
00332 
00333     if (!rect)
00334         return InvalidParameter;
00335 
00336     rectf.X = (REAL)rect->X;
00337     rectf.Y = (REAL)rect->Y;
00338     rectf.Height = (REAL)rect->Height;
00339     rectf.Width = (REAL)rect->Width;
00340 
00341     return GdipCombineRegionRect(region, &rectf, mode);
00342 }
00343 
00344 /*****************************************************************************
00345  * GdipCombineRegionRegion [GDIPLUS.@]
00346  */
00347 GpStatus WINGDIPAPI GdipCombineRegionRegion(GpRegion *region1,
00348         GpRegion *region2, CombineMode mode)
00349 {
00350     region_element *left, *right = NULL;
00351     GpStatus stat;
00352     GpRegion *reg2copy;
00353 
00354     TRACE("%p %p %d\n", region1, region2, mode);
00355 
00356     if(!(region1 && region2))
00357         return InvalidParameter;
00358 
00359     /* simply replace region data */
00360     if(mode == CombineModeReplace){
00361         stat = GdipCloneRegion(region2, &reg2copy);
00362         if(stat != Ok)  return stat;
00363 
00364         delete_element(&region1->node);
00365         memcpy(region1, reg2copy, sizeof(GpRegion));
00366         GdipFree(reg2copy);
00367         return Ok;
00368     }
00369 
00370     left  = GdipAlloc(sizeof(region_element));
00371     if (!left)
00372         return OutOfMemory;
00373 
00374     *left = region1->node;
00375     stat = clone_element(&region2->node, &right);
00376     if (stat != Ok)
00377     {
00378         GdipFree(left);
00379         return OutOfMemory;
00380     }
00381 
00382     fuse_region(region1, left, right, mode);
00383     region1->header.num_children += region2->header.num_children;
00384 
00385     return Ok;
00386 }
00387 
00388 /*****************************************************************************
00389  * GdipCreateRegion [GDIPLUS.@]
00390  */
00391 GpStatus WINGDIPAPI GdipCreateRegion(GpRegion **region)
00392 {
00393     TRACE("%p\n", region);
00394 
00395     if(!region)
00396         return InvalidParameter;
00397 
00398     *region = GdipAlloc(sizeof(GpRegion));
00399     if(!*region)
00400         return OutOfMemory;
00401 
00402     return init_region(*region, RegionDataInfiniteRect);
00403 }
00404 
00405 /*****************************************************************************
00406  * GdipCreateRegionPath [GDIPLUS.@]
00407  *
00408  * Creates a GpRegion from a GpPath
00409  *
00410  * PARAMS
00411  *  path    [I] path to base the region on
00412  *  region  [O] pointer to the newly allocated region
00413  *
00414  * RETURNS
00415  *  SUCCESS: Ok
00416  *  FAILURE: InvalidParameter
00417  *
00418  * NOTES
00419  *  If a path has no floating point points, its points will be stored as shorts
00420  *  (INTPATH)
00421  *
00422  *  If a path is empty, it is considered to be an INTPATH
00423  */
00424 GpStatus WINGDIPAPI GdipCreateRegionPath(GpPath *path, GpRegion **region)
00425 {
00426     region_element* element;
00427     GpPoint  *pointsi;
00428     GpPointF *pointsf;
00429 
00430     GpStatus stat;
00431     DWORD flags = FLAGS_INTPATH;
00432     INT count, i;
00433 
00434     TRACE("%p, %p\n", path, region);
00435 
00436     if (!(path && region))
00437         return InvalidParameter;
00438 
00439     *region = GdipAlloc(sizeof(GpRegion));
00440     if(!*region)
00441         return OutOfMemory;
00442     stat = init_region(*region, RegionDataPath);
00443     if (stat != Ok)
00444     {
00445         GdipDeleteRegion(*region);
00446         return stat;
00447     }
00448     element = &(*region)->node;
00449     count = path->pathdata.Count;
00450 
00451     /* Test to see if the path is an Integer path */
00452     if (count)
00453     {
00454         pointsi = GdipAlloc(sizeof(GpPoint) * count);
00455         pointsf = GdipAlloc(sizeof(GpPointF) * count);
00456         if (!(pointsi && pointsf))
00457         {
00458             GdipFree(pointsi);
00459             GdipFree(pointsf);
00460             GdipDeleteRegion(*region);
00461             return OutOfMemory;
00462         }
00463 
00464         stat = GdipGetPathPointsI(path, pointsi, count);
00465         if (stat != Ok)
00466         {
00467             GdipDeleteRegion(*region);
00468             return stat;
00469         }
00470         stat = GdipGetPathPoints(path, pointsf, count);
00471         if (stat != Ok)
00472         {
00473             GdipDeleteRegion(*region);
00474             return stat;
00475         }
00476 
00477         for (i = 0; i < count; i++)
00478         {
00479             if (!(pointsi[i].X == pointsf[i].X &&
00480                   pointsi[i].Y == pointsf[i].Y ))
00481             {
00482                 flags = FLAGS_NOFLAGS;
00483                 break;
00484             }
00485         }
00486         GdipFree(pointsi);
00487         GdipFree(pointsf);
00488     }
00489 
00490     stat = GdipClonePath(path, &element->elementdata.pathdata.path);
00491     if (stat != Ok)
00492     {
00493         GdipDeleteRegion(*region);
00494         return stat;
00495     }
00496 
00497     /* 3 for headers, once again size doesn't count itself */
00498     element->elementdata.pathdata.pathheader.size = ((sizeof(DWORD) * 3));
00499     switch(flags)
00500     {
00501         /* Floats, sent out as floats */
00502         case FLAGS_NOFLAGS:
00503             element->elementdata.pathdata.pathheader.size +=
00504                 (sizeof(DWORD) * count * 2);
00505             break;
00506         /* INTs, sent out as packed shorts */
00507         case FLAGS_INTPATH:
00508             element->elementdata.pathdata.pathheader.size +=
00509                 (sizeof(DWORD) * count);
00510             break;
00511         default:
00512             FIXME("Unhandled flags (%08x). Expect wrong results.\n", flags);
00513     }
00514     element->elementdata.pathdata.pathheader.size += get_pathtypes_size(path);
00515     element->elementdata.pathdata.pathheader.magic = VERSION_MAGIC;
00516     element->elementdata.pathdata.pathheader.count = count;
00517     element->elementdata.pathdata.pathheader.flags = flags;
00518     (*region)->header.size = sizeheader_size + get_element_size(element);
00519 
00520     return Ok;
00521 }
00522 
00523 /*****************************************************************************
00524  * GdipCreateRegionRect [GDIPLUS.@]
00525  */
00526 GpStatus WINGDIPAPI GdipCreateRegionRect(GDIPCONST GpRectF *rect,
00527         GpRegion **region)
00528 {
00529     GpStatus stat;
00530 
00531     TRACE("%p, %p\n", rect, region);
00532 
00533     if (!(rect && region))
00534         return InvalidParameter;
00535 
00536     *region = GdipAlloc(sizeof(GpRegion));
00537     stat = init_region(*region, RegionDataRect);
00538     if(stat != Ok)
00539     {
00540         GdipDeleteRegion(*region);
00541         return stat;
00542     }
00543 
00544     (*region)->node.elementdata.rect.X = rect->X;
00545     (*region)->node.elementdata.rect.Y = rect->Y;
00546     (*region)->node.elementdata.rect.Width = rect->Width;
00547     (*region)->node.elementdata.rect.Height = rect->Height;
00548 
00549     return Ok;
00550 }
00551 
00552 /*****************************************************************************
00553  * GdipCreateRegionRectI [GDIPLUS.@]
00554  */
00555 GpStatus WINGDIPAPI GdipCreateRegionRectI(GDIPCONST GpRect *rect,
00556         GpRegion **region)
00557 {
00558     GpRectF rectf;
00559 
00560     TRACE("%p, %p\n", rect, region);
00561 
00562     rectf.X = (REAL)rect->X;
00563     rectf.Y = (REAL)rect->Y;
00564     rectf.Width = (REAL)rect->Width;
00565     rectf.Height = (REAL)rect->Height;
00566 
00567     return GdipCreateRegionRect(&rectf, region);
00568 }
00569 
00570 GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRegion **region)
00571 {
00572     FIXME("(%p, %d, %p): stub\n", data, size, region);
00573 
00574     *region = NULL;
00575     return NotImplemented;
00576 }
00577 
00578 
00579 /******************************************************************************
00580  * GdipCreateRegionHrgn [GDIPLUS.@]
00581  */
00582 GpStatus WINGDIPAPI GdipCreateRegionHrgn(HRGN hrgn, GpRegion **region)
00583 {
00584     DWORD size;
00585     LPRGNDATA buf;
00586     LPRECT rect;
00587     GpStatus stat;
00588     GpPath* path;
00589     GpRegion* local;
00590     int i;
00591 
00592     TRACE("(%p, %p)\n", hrgn, region);
00593 
00594     if(!region || !(size = GetRegionData(hrgn, 0, NULL)))
00595         return InvalidParameter;
00596 
00597     buf = GdipAlloc(size);
00598     if(!buf)
00599         return OutOfMemory;
00600 
00601     if(!GetRegionData(hrgn, size, buf)){
00602         GdipFree(buf);
00603         return GenericError;
00604     }
00605 
00606     if(buf->rdh.nCount == 0){
00607         if((stat = GdipCreateRegion(&local)) != Ok){
00608             GdipFree(buf);
00609             return stat;
00610         }
00611         if((stat = GdipSetEmpty(local)) != Ok){
00612             GdipFree(buf);
00613             GdipDeleteRegion(local);
00614             return stat;
00615         }
00616         *region = local;
00617         GdipFree(buf);
00618         return Ok;
00619     }
00620 
00621     if((stat = GdipCreatePath(FillModeAlternate, &path)) != Ok){
00622         GdipFree(buf);
00623         return stat;
00624     }
00625 
00626     rect = (LPRECT)buf->Buffer;
00627     for(i = 0; i < buf->rdh.nCount; i++){
00628         if((stat = GdipAddPathRectangle(path, (REAL)rect->left, (REAL)rect->top,
00629                         (REAL)(rect->right - rect->left), (REAL)(rect->bottom - rect->top))) != Ok){
00630             GdipFree(buf);
00631             GdipDeletePath(path);
00632             return stat;
00633         }
00634         rect++;
00635     }
00636 
00637     stat = GdipCreateRegionPath(path, region);
00638 
00639     GdipFree(buf);
00640     GdipDeletePath(path);
00641     return stat;
00642 }
00643 
00644 /*****************************************************************************
00645  * GdipDeleteRegion [GDIPLUS.@]
00646  */
00647 GpStatus WINGDIPAPI GdipDeleteRegion(GpRegion *region)
00648 {
00649     TRACE("%p\n", region);
00650 
00651     if (!region)
00652         return InvalidParameter;
00653 
00654     delete_element(&region->node);
00655     GdipFree(region);
00656 
00657     return Ok;
00658 }
00659 
00660 /*****************************************************************************
00661  * GdipGetRegionBounds [GDIPLUS.@]
00662  */
00663 GpStatus WINGDIPAPI GdipGetRegionBounds(GpRegion *region, GpGraphics *graphics, GpRectF *rect)
00664 {
00665     HRGN hrgn;
00666     RECT r;
00667     GpStatus status;
00668 
00669     TRACE("(%p, %p, %p)\n", region, graphics, rect);
00670 
00671     if(!region || !graphics || !rect)
00672         return InvalidParameter;
00673 
00674     /* Contrary to MSDN, native ignores the graphics transform. */
00675     status = GdipGetRegionHRgn(region, NULL, &hrgn);
00676     if(status != Ok)
00677         return status;
00678 
00679     /* infinite */
00680     if(!hrgn){
00681         rect->X = rect->Y = -(REAL)(1 << 22);
00682         rect->Width = rect->Height = (REAL)(1 << 23);
00683         return Ok;
00684     }
00685 
00686     if(GetRgnBox(hrgn, &r)){
00687         rect->X = r.left;
00688         rect->Y = r.top;
00689         rect->Width  = r.right  - r.left;
00690         rect->Height = r.bottom - r.top;
00691     }
00692     else
00693         status = GenericError;
00694 
00695     DeleteObject(hrgn);
00696 
00697     return status;
00698 }
00699 
00700 /*****************************************************************************
00701  * GdipGetRegionBoundsI [GDIPLUS.@]
00702  */
00703 GpStatus WINGDIPAPI GdipGetRegionBoundsI(GpRegion *region, GpGraphics *graphics, GpRect *rect)
00704 {
00705     GpRectF rectf;
00706     GpStatus status;
00707 
00708     TRACE("(%p, %p, %p)\n", region, graphics, rect);
00709 
00710     if(!rect)
00711         return InvalidParameter;
00712 
00713     status = GdipGetRegionBounds(region, graphics, &rectf);
00714     if(status == Ok){
00715         rect->X = roundr(rectf.X);
00716         rect->Y = roundr(rectf.X);
00717         rect->Width  = roundr(rectf.Width);
00718         rect->Height = roundr(rectf.Height);
00719     }
00720 
00721     return status;
00722 }
00723 
00724 static inline void write_dword(DWORD* location, INT* offset, const DWORD write)
00725 {
00726     location[*offset] = write;
00727     (*offset)++;
00728 }
00729 
00730 static inline void write_float(DWORD* location, INT* offset, const FLOAT write)
00731 {
00732     ((FLOAT*)location)[*offset] = write;
00733     (*offset)++;
00734 }
00735 
00736 static inline void write_packed_point(DWORD* location, INT* offset,
00737         const GpPointF* write)
00738 {
00739     packed_point point;
00740 
00741     point.X = write->X;
00742     point.Y = write->Y;
00743     memcpy(location + *offset, &point, sizeof(packed_point));
00744     (*offset)++;
00745 }
00746 
00747 static inline void write_path_types(DWORD* location, INT* offset,
00748         const GpPath* path)
00749 {
00750     memcpy(location + *offset, path->pathdata.Types, path->pathdata.Count);
00751 
00752     /* The unwritten parts of the DWORD (if any) must be cleared */
00753     if (path->pathdata.Count % sizeof(DWORD))
00754         ZeroMemory(((BYTE*)location) + (*offset * sizeof(DWORD)) +
00755                 path->pathdata.Count,
00756                 sizeof(DWORD) - path->pathdata.Count % sizeof(DWORD));
00757     *offset += (get_pathtypes_size(path) / sizeof(DWORD));
00758 }
00759 
00760 static void write_element(const region_element* element, DWORD *buffer,
00761         INT* filled)
00762 {
00763     write_dword(buffer, filled, element->type);
00764     switch (element->type)
00765     {
00766         case CombineModeReplace:
00767         case CombineModeIntersect:
00768         case CombineModeUnion:
00769         case CombineModeXor:
00770         case CombineModeExclude:
00771         case CombineModeComplement:
00772             write_element(element->elementdata.combine.left, buffer, filled);
00773             write_element(element->elementdata.combine.right, buffer, filled);
00774             break;
00775         case RegionDataRect:
00776             write_float(buffer, filled, element->elementdata.rect.X);
00777             write_float(buffer, filled, element->elementdata.rect.Y);
00778             write_float(buffer, filled, element->elementdata.rect.Width);
00779             write_float(buffer, filled, element->elementdata.rect.Height);
00780             break;
00781         case RegionDataPath:
00782         {
00783             INT i;
00784             const GpPath* path = element->elementdata.pathdata.path;
00785 
00786             memcpy(buffer + *filled, &element->elementdata.pathdata.pathheader,
00787                     sizeof(element->elementdata.pathdata.pathheader));
00788             *filled += sizeof(element->elementdata.pathdata.pathheader) / sizeof(DWORD);
00789             switch (element->elementdata.pathdata.pathheader.flags)
00790             {
00791                 case FLAGS_NOFLAGS:
00792                     for (i = 0; i < path->pathdata.Count; i++)
00793                     {
00794                         write_float(buffer, filled, path->pathdata.Points[i].X);
00795                         write_float(buffer, filled, path->pathdata.Points[i].Y);
00796                     }
00797                     break;
00798                 case FLAGS_INTPATH:
00799                     for (i = 0; i < path->pathdata.Count; i++)
00800                     {
00801                         write_packed_point(buffer, filled,
00802                                 &path->pathdata.Points[i]);
00803                     }
00804             }
00805             write_path_types(buffer, filled, path);
00806             break;
00807         }
00808         case RegionDataEmptyRect:
00809         case RegionDataInfiniteRect:
00810             break;
00811     }
00812 }
00813 
00814 /*****************************************************************************
00815  * GdipGetRegionData [GDIPLUS.@]
00816  *
00817  * Returns the header, followed by combining ops and region elements.
00818  *
00819  * PARAMS
00820  *  region  [I] region to retrieve from
00821  *  buffer  [O] buffer to hold the resulting data
00822  *  size    [I] size of the buffer
00823  *  needed  [O] (optional) how much data was written
00824  *
00825  * RETURNS
00826  *  SUCCESS: Ok
00827  *  FAILURE: InvalidParameter
00828  *
00829  * NOTES
00830  *  The header contains the size, a checksum, a version string, and the number
00831  *  of children. The size does not count itself or the checksum.
00832  *  Version is always something like 0xdbc01001 or 0xdbc01002
00833  *
00834  *  An element is a RECT, or PATH; Combining ops are stored as their
00835  *  CombineMode value. Special regions (infinite, empty) emit just their
00836  *  op-code; GpRectFs emit their code followed by their points; GpPaths emit
00837  *  their code followed by a second header for the path followed by the actual
00838  *  path data. Followed by the flags for each point. The pathheader contains
00839  *  the size of the data to follow, a version number again, followed by a count
00840  *  of how many points, and any special flags which may apply. 0x4000 means its
00841  *  a path of shorts instead of FLOAT.
00842  *
00843  *  Combining Ops are stored in reverse order from when they were constructed;
00844  *  the output is a tree where the left side combining area is always taken
00845  *  first.
00846  */
00847 GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
00848         UINT *needed)
00849 {
00850     INT filled = 0;
00851 
00852     TRACE("%p, %p, %d, %p\n", region, buffer, size, needed);
00853 
00854     if (!(region && buffer && size))
00855         return InvalidParameter;
00856 
00857     memcpy(buffer, &region->header, sizeof(region->header));
00858     filled += sizeof(region->header) / sizeof(DWORD);
00859     /* With few exceptions, everything written is DWORD aligned,
00860      * so use that as our base */
00861     write_element(&region->node, (DWORD*)buffer, &filled);
00862 
00863     if (needed)
00864         *needed = filled * sizeof(DWORD);
00865 
00866     return Ok;
00867 }
00868 
00869 /*****************************************************************************
00870  * GdipGetRegionDataSize [GDIPLUS.@]
00871  */
00872 GpStatus WINGDIPAPI GdipGetRegionDataSize(GpRegion *region, UINT *needed)
00873 {
00874     TRACE("%p, %p\n", region, needed);
00875 
00876     if (!(region && needed))
00877         return InvalidParameter;
00878 
00879     /* header.size doesn't count header.size and header.checksum */
00880     *needed = region->header.size + sizeof(DWORD) * 2;
00881 
00882     return Ok;
00883 }
00884 
00885 static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn)
00886 {
00887     HDC new_hdc=NULL;
00888     GpGraphics *new_graphics=NULL;
00889     GpStatus stat;
00890     INT save_state;
00891 
00892     if (!graphics)
00893     {
00894         new_hdc = GetDC(0);
00895         if (!new_hdc)
00896             return OutOfMemory;
00897 
00898         stat = GdipCreateFromHDC(new_hdc, &new_graphics);
00899         graphics = new_graphics;
00900         if (stat != Ok)
00901         {
00902             ReleaseDC(0, new_hdc);
00903             return stat;
00904         }
00905     }
00906     else if (!graphics->hdc)
00907     {
00908         graphics->hdc = new_hdc = GetDC(0);
00909         if (!new_hdc)
00910             return OutOfMemory;
00911     }
00912 
00913     save_state = SaveDC(graphics->hdc);
00914     EndPath(graphics->hdc);
00915 
00916     SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE
00917                                                                     : WINDING));
00918 
00919     stat = trace_path(graphics, path);
00920     if (stat == Ok)
00921     {
00922         *hrgn = PathToRegion(graphics->hdc);
00923         stat = *hrgn ? Ok : OutOfMemory;
00924     }
00925 
00926     RestoreDC(graphics->hdc, save_state);
00927     if (new_hdc)
00928     {
00929         ReleaseDC(0, new_hdc);
00930         if (new_graphics)
00931             GdipDeleteGraphics(new_graphics);
00932         else
00933             graphics->hdc = NULL;
00934     }
00935 
00936     return stat;
00937 }
00938 
00939 static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *graphics, HRGN *hrgn)
00940 {
00941     switch (element->type)
00942     {
00943         case RegionDataInfiniteRect:
00944             *hrgn = NULL;
00945             return Ok;
00946         case RegionDataEmptyRect:
00947             *hrgn = CreateRectRgn(0, 0, 0, 0);
00948             return *hrgn ? Ok : OutOfMemory;
00949         case RegionDataPath:
00950             return get_path_hrgn(element->elementdata.pathdata.path, graphics, hrgn);
00951         case RegionDataRect:
00952         {
00953             GpPath* path;
00954             GpStatus stat;
00955             GpRectF* rc = &element->elementdata.rect;
00956 
00957             stat = GdipCreatePath(FillModeAlternate, &path);
00958             if (stat != Ok)
00959                 return stat;
00960             stat = GdipAddPathRectangle(path, rc->X, rc->Y, rc->Width, rc->Height);
00961 
00962             if (stat == Ok)
00963                 stat = get_path_hrgn(path, graphics, hrgn);
00964 
00965             GdipDeletePath(path);
00966 
00967             return stat;
00968         }
00969         case CombineModeIntersect:
00970         case CombineModeUnion:
00971         case CombineModeXor:
00972         case CombineModeExclude:
00973         case CombineModeComplement:
00974         {
00975             HRGN left, right;
00976             GpStatus stat;
00977             int ret;
00978 
00979             stat = get_region_hrgn(element->elementdata.combine.left, graphics, &left);
00980             if (stat != Ok)
00981             {
00982                 *hrgn = NULL;
00983                 return stat;
00984             }
00985 
00986             if (left == NULL)
00987             {
00988                 /* existing region is infinite */
00989                 switch (element->type)
00990                 {
00991                     case CombineModeIntersect:
00992                         return get_region_hrgn(element->elementdata.combine.right, graphics, hrgn);
00993                     case CombineModeXor: case CombineModeExclude:
00994                         FIXME("cannot exclude from an infinite region\n");
00995                         /* fall-through */
00996                     case CombineModeUnion: case CombineModeComplement:
00997                         *hrgn = NULL;
00998                         return Ok;
00999                 }
01000             }
01001 
01002             stat = get_region_hrgn(element->elementdata.combine.right, graphics, &right);
01003             if (stat != Ok)
01004             {
01005                 DeleteObject(left);
01006                 *hrgn = NULL;
01007                 return stat;
01008             }
01009 
01010             if (right == NULL)
01011             {
01012                 /* new region is infinite */
01013                 switch (element->type)
01014                 {
01015                     case CombineModeIntersect:
01016                         *hrgn = left;
01017                         return Ok;
01018                     case CombineModeXor: case CombineModeComplement:
01019                         FIXME("cannot exclude from an infinite region\n");
01020                         /* fall-through */
01021                     case CombineModeUnion: case CombineModeExclude:
01022                         DeleteObject(left);
01023                         *hrgn = NULL;
01024                         return Ok;
01025                 }
01026             }
01027 
01028             switch (element->type)
01029             {
01030                 case CombineModeIntersect:
01031                     ret = CombineRgn(left, left, right, RGN_AND);
01032                     break;
01033                 case CombineModeUnion:
01034                     ret = CombineRgn(left, left, right, RGN_OR);
01035                     break;
01036                 case CombineModeXor:
01037                     ret = CombineRgn(left, left, right, RGN_XOR);
01038                     break;
01039                 case CombineModeExclude:
01040                     ret = CombineRgn(left, left, right, RGN_DIFF);
01041                     break;
01042                 case CombineModeComplement:
01043                     ret = CombineRgn(left, right, left, RGN_DIFF);
01044                     break;
01045                 default:
01046                     ret = ERROR;
01047             }
01048 
01049             DeleteObject(right);
01050 
01051             if (ret == ERROR)
01052             {
01053                 DeleteObject(left);
01054                 *hrgn = NULL;
01055                 return GenericError;
01056             }
01057 
01058             *hrgn = left;
01059             return Ok;
01060         }
01061         default:
01062             FIXME("GdipGetRegionHRgn unimplemented for region type=%x\n", element->type);
01063             *hrgn = NULL;
01064             return NotImplemented;
01065     }
01066 }
01067 
01068 /*****************************************************************************
01069  * GdipGetRegionHRgn [GDIPLUS.@]
01070  */
01071 GpStatus WINGDIPAPI GdipGetRegionHRgn(GpRegion *region, GpGraphics *graphics, HRGN *hrgn)
01072 {
01073     TRACE("(%p, %p, %p)\n", region, graphics, hrgn);
01074 
01075     if (!region || !hrgn)
01076         return InvalidParameter;
01077 
01078     return get_region_hrgn(&region->node, graphics, hrgn);
01079 }
01080 
01081 GpStatus WINGDIPAPI GdipIsEmptyRegion(GpRegion *region, GpGraphics *graphics, BOOL *res)
01082 {
01083     TRACE("(%p, %p, %p)\n", region, graphics, res);
01084 
01085     if(!region || !graphics || !res)
01086         return InvalidParameter;
01087 
01088     *res = (region->node.type == RegionDataEmptyRect);
01089 
01090     return Ok;
01091 }
01092 
01093 /*****************************************************************************
01094  * GdipIsEqualRegion [GDIPLUS.@]
01095  */
01096 GpStatus WINGDIPAPI GdipIsEqualRegion(GpRegion *region, GpRegion *region2, GpGraphics *graphics,
01097                                       BOOL *res)
01098 {
01099     HRGN hrgn1, hrgn2;
01100     GpStatus stat;
01101 
01102     TRACE("(%p, %p, %p, %p)\n", region, region2, graphics, res);
01103 
01104     if(!region || !region2 || !graphics || !res)
01105         return InvalidParameter;
01106 
01107     stat = GdipGetRegionHRgn(region, graphics, &hrgn1);
01108     if(stat != Ok)
01109         return stat;
01110     stat = GdipGetRegionHRgn(region2, graphics, &hrgn2);
01111     if(stat != Ok){
01112         DeleteObject(hrgn1);
01113         return stat;
01114     }
01115 
01116     *res = EqualRgn(hrgn1, hrgn2);
01117 
01118     /* one of GpRegions is infinite */
01119     if(*res == ERROR)
01120         *res = (!hrgn1 && !hrgn2);
01121 
01122     DeleteObject(hrgn1);
01123     DeleteObject(hrgn2);
01124 
01125     return Ok;
01126 }
01127 
01128 /*****************************************************************************
01129  * GdipIsInfiniteRegion [GDIPLUS.@]
01130  */
01131 GpStatus WINGDIPAPI GdipIsInfiniteRegion(GpRegion *region, GpGraphics *graphics, BOOL *res)
01132 {
01133     /* I think graphics is ignored here */
01134     TRACE("(%p, %p, %p)\n", region, graphics, res);
01135 
01136     if(!region || !graphics || !res)
01137         return InvalidParameter;
01138 
01139     *res = (region->node.type == RegionDataInfiniteRect);
01140 
01141     return Ok;
01142 }
01143 
01144 /*****************************************************************************
01145  * GdipIsVisibleRegionRect [GDIPLUS.@]
01146  */
01147 GpStatus WINGDIPAPI GdipIsVisibleRegionRect(GpRegion* region, REAL x, REAL y, REAL w, REAL h, GpGraphics *graphics, BOOL *res)
01148 {
01149     HRGN hrgn;
01150     GpStatus stat;
01151     RECT rect;
01152 
01153     TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %p, %p)\n", region, x, y, w, h, graphics, res);
01154 
01155     if(!region || !res)
01156         return InvalidParameter;
01157 
01158     if((stat = GdipGetRegionHRgn(region, NULL, &hrgn)) != Ok)
01159         return stat;
01160 
01161     /* infinite */
01162     if(!hrgn){
01163         *res = TRUE;
01164         return Ok;
01165     }
01166 
01167     rect.left = ceilr(x);
01168     rect.top = ceilr(y);
01169     rect.right = ceilr(x + w);
01170     rect.bottom = ceilr(y + h);
01171 
01172     *res = RectInRegion(hrgn, &rect);
01173 
01174     DeleteObject(hrgn);
01175 
01176     return Ok;
01177 }
01178 
01179 /*****************************************************************************
01180  * GdipIsVisibleRegionRectI [GDIPLUS.@]
01181  */
01182 GpStatus WINGDIPAPI GdipIsVisibleRegionRectI(GpRegion* region, INT x, INT y, INT w, INT h, GpGraphics *graphics, BOOL *res)
01183 {
01184     TRACE("(%p, %d, %d, %d, %d, %p, %p)\n", region, x, y, w, h, graphics, res);
01185     if(!region || !res)
01186         return InvalidParameter;
01187 
01188     return GdipIsVisibleRegionRect(region, (REAL)x, (REAL)y, (REAL)w, (REAL)h, graphics, res);
01189 }
01190 
01191 /*****************************************************************************
01192  * GdipIsVisibleRegionPoint [GDIPLUS.@]
01193  */
01194 GpStatus WINGDIPAPI GdipIsVisibleRegionPoint(GpRegion* region, REAL x, REAL y, GpGraphics *graphics, BOOL *res)
01195 {
01196     HRGN hrgn;
01197     GpStatus stat;
01198 
01199     TRACE("(%p, %.2f, %.2f, %p, %p)\n", region, x, y, graphics, res);
01200 
01201     if(!region || !res)
01202         return InvalidParameter;
01203 
01204     if((stat = GdipGetRegionHRgn(region, NULL, &hrgn)) != Ok)
01205         return stat;
01206 
01207     /* infinite */
01208     if(!hrgn){
01209         *res = TRUE;
01210         return Ok;
01211     }
01212 
01213     *res = PtInRegion(hrgn, roundr(x), roundr(y));
01214 
01215     DeleteObject(hrgn);
01216 
01217     return Ok;
01218 }
01219 
01220 /*****************************************************************************
01221  * GdipIsVisibleRegionPointI [GDIPLUS.@]
01222  */
01223 GpStatus WINGDIPAPI GdipIsVisibleRegionPointI(GpRegion* region, INT x, INT y, GpGraphics *graphics, BOOL *res)
01224 {
01225     TRACE("(%p, %d, %d, %p, %p)\n", region, x, y, graphics, res);
01226 
01227     return GdipIsVisibleRegionPoint(region, (REAL)x, (REAL)y, graphics, res);
01228 }
01229 
01230 /*****************************************************************************
01231  * GdipSetEmpty [GDIPLUS.@]
01232  */
01233 GpStatus WINGDIPAPI GdipSetEmpty(GpRegion *region)
01234 {
01235     GpStatus stat;
01236 
01237     TRACE("%p\n", region);
01238 
01239     if (!region)
01240         return InvalidParameter;
01241 
01242     delete_element(&region->node);
01243     stat = init_region(region, RegionDataEmptyRect);
01244 
01245     return stat;
01246 }
01247 
01248 GpStatus WINGDIPAPI GdipSetInfinite(GpRegion *region)
01249 {
01250     GpStatus stat;
01251 
01252     TRACE("%p\n", region);
01253 
01254     if (!region)
01255         return InvalidParameter;
01256 
01257     delete_element(&region->node);
01258     stat = init_region(region, RegionDataInfiniteRect);
01259 
01260     return stat;
01261 }
01262 
01263 /* Transforms GpRegion elements with given matrix */
01264 static GpStatus transform_region_element(region_element* element, GpMatrix *matrix)
01265 {
01266     GpStatus stat;
01267 
01268     switch(element->type)
01269     {
01270         case RegionDataEmptyRect:
01271         case RegionDataInfiniteRect:
01272             return Ok;
01273         case RegionDataRect:
01274         {
01275             /* We can't transform a rectangle, so convert it to a path. */
01276             GpRegion *new_region;
01277             GpPath *path;
01278 
01279             stat = GdipCreatePath(FillModeAlternate, &path);
01280             if (stat == Ok)
01281             {
01282                 stat = GdipAddPathRectangle(path,
01283                     element->elementdata.rect.X, element->elementdata.rect.Y,
01284                     element->elementdata.rect.Width, element->elementdata.rect.Height);
01285 
01286                 if (stat == Ok)
01287                     stat = GdipCreateRegionPath(path, &new_region);
01288 
01289                 GdipDeletePath(path);
01290             }
01291 
01292             if (stat == Ok)
01293             {
01294                 /* Steal the element from the created region. */
01295                 memcpy(element, &new_region->node, sizeof(region_element));
01296                 HeapFree(GetProcessHeap(), 0, new_region);
01297             }
01298             else
01299                 return stat;
01300         }
01301         /* Fall-through to do the actual conversion. */
01302         case RegionDataPath:
01303             stat = GdipTransformMatrixPoints(matrix,
01304                 element->elementdata.pathdata.path->pathdata.Points,
01305                 element->elementdata.pathdata.path->pathdata.Count);
01306             return stat;
01307         default:
01308             stat = transform_region_element(element->elementdata.combine.left, matrix);
01309             if (stat == Ok)
01310                 stat = transform_region_element(element->elementdata.combine.right, matrix);
01311             return stat;
01312     }
01313 }
01314 
01315 GpStatus WINGDIPAPI GdipTransformRegion(GpRegion *region, GpMatrix *matrix)
01316 {
01317     TRACE("(%p, %p)\n", region, matrix);
01318 
01319     if (!region || !matrix)
01320         return InvalidParameter;
01321 
01322     return transform_region_element(&region->node, matrix);
01323 }
01324 
01325 /* Translates GpRegion elements with specified offsets */
01326 static void translate_region_element(region_element* element, REAL dx, REAL dy)
01327 {
01328     INT i;
01329 
01330     switch(element->type)
01331     {
01332         case RegionDataEmptyRect:
01333         case RegionDataInfiniteRect:
01334             return;
01335         case RegionDataRect:
01336             element->elementdata.rect.X += dx;
01337             element->elementdata.rect.Y += dy;
01338             return;
01339         case RegionDataPath:
01340             for(i = 0; i < element->elementdata.pathdata.path->pathdata.Count; i++){
01341                 element->elementdata.pathdata.path->pathdata.Points[i].X += dx;
01342                 element->elementdata.pathdata.path->pathdata.Points[i].Y += dy;
01343             }
01344             return;
01345         default:
01346             translate_region_element(element->elementdata.combine.left,  dx, dy);
01347             translate_region_element(element->elementdata.combine.right, dx, dy);
01348             return;
01349     }
01350 }
01351 
01352 /*****************************************************************************
01353  * GdipTranslateRegion [GDIPLUS.@]
01354  */
01355 GpStatus WINGDIPAPI GdipTranslateRegion(GpRegion *region, REAL dx, REAL dy)
01356 {
01357     TRACE("(%p, %f, %f)\n", region, dx, dy);
01358 
01359     if(!region)
01360         return InvalidParameter;
01361 
01362     translate_region_element(&region->node, dx, dy);
01363 
01364     return Ok;
01365 }
01366 
01367 /*****************************************************************************
01368  * GdipTranslateRegionI [GDIPLUS.@]
01369  */
01370 GpStatus WINGDIPAPI GdipTranslateRegionI(GpRegion *region, INT dx, INT dy)
01371 {
01372     TRACE("(%p, %d, %d)\n", region, dx, dy);
01373 
01374     return GdipTranslateRegion(region, (REAL)dx, (REAL)dy);
01375 }
01376 
01377 static GpStatus get_region_scans_data(GpRegion *region, GpMatrix *matrix, LPRGNDATA *data)
01378 {
01379     GpRegion *region_copy;
01380     GpStatus stat;
01381     HRGN hrgn;
01382     DWORD data_size;
01383 
01384     stat = GdipCloneRegion(region, &region_copy);
01385 
01386     if (stat == Ok)
01387     {
01388         stat = GdipTransformRegion(region_copy, matrix);
01389 
01390         if (stat == Ok)
01391             stat = GdipGetRegionHRgn(region_copy, NULL, &hrgn);
01392 
01393         if (stat == Ok)
01394         {
01395             if (hrgn)
01396             {
01397                 data_size = GetRegionData(hrgn, 0, NULL);
01398 
01399                 *data = GdipAlloc(data_size);
01400 
01401                 if (*data)
01402                     GetRegionData(hrgn, data_size, *data);
01403                 else
01404                     stat = OutOfMemory;
01405 
01406                 DeleteObject(hrgn);
01407             }
01408             else
01409             {
01410                 data_size = sizeof(RGNDATAHEADER) + sizeof(RECT);
01411 
01412                 *data = GdipAlloc(data_size);
01413 
01414                 if (*data)
01415                 {
01416                     (*data)->rdh.dwSize = sizeof(RGNDATAHEADER);
01417                     (*data)->rdh.iType = RDH_RECTANGLES;
01418                     (*data)->rdh.nCount = 1;
01419                     (*data)->rdh.nRgnSize = sizeof(RECT);
01420                     (*data)->rdh.rcBound.left = (*data)->rdh.rcBound.top = -0x400000;
01421                     (*data)->rdh.rcBound.right = (*data)->rdh.rcBound.bottom = 0x400000;
01422 
01423                     memcpy((*data)->Buffer, &(*data)->rdh.rcBound, sizeof(RECT));
01424                 }
01425                 else
01426                     stat = OutOfMemory;
01427             }
01428         }
01429 
01430         GdipDeleteRegion(region_copy);
01431     }
01432 
01433     return stat;
01434 }
01435 
01436 GpStatus WINGDIPAPI GdipGetRegionScansCount(GpRegion *region, UINT *count, GpMatrix *matrix)
01437 {
01438     GpStatus stat;
01439     LPRGNDATA data;
01440 
01441     TRACE("(%p, %p, %p)\n", region, count, matrix);
01442 
01443     if (!region || !count || !matrix)
01444         return InvalidParameter;
01445 
01446     stat = get_region_scans_data(region, matrix, &data);
01447 
01448     if (stat == Ok)
01449     {
01450         *count = data->rdh.nCount;
01451         GdipFree(data);
01452     }
01453 
01454     return stat;
01455 }
01456 
01457 GpStatus WINGDIPAPI GdipGetRegionScansI(GpRegion *region, GpRect *scans, INT *count, GpMatrix *matrix)
01458 {
01459     GpStatus stat;
01460     INT i;
01461     LPRGNDATA data;
01462     RECT *rects;
01463 
01464     if (!region || !count || !matrix)
01465         return InvalidParameter;
01466 
01467     stat = get_region_scans_data(region, matrix, &data);
01468 
01469     if (stat == Ok)
01470     {
01471         *count = data->rdh.nCount;
01472         rects = (RECT*)data->Buffer;
01473 
01474         if (scans)
01475         {
01476             for (i=0; i<data->rdh.nCount; i++)
01477             {
01478                 scans[i].X = rects[i].left;
01479                 scans[i].Y = rects[i].top;
01480                 scans[i].Width = rects[i].right - rects[i].left;
01481                 scans[i].Height = rects[i].bottom - rects[i].top;
01482             }
01483         }
01484 
01485         GdipFree(data);
01486     }
01487 
01488     return Ok;
01489 }
01490 
01491 GpStatus WINGDIPAPI GdipGetRegionScans(GpRegion *region, GpRectF *scans, INT *count, GpMatrix *matrix)
01492 {
01493     GpStatus stat;
01494     INT i;
01495     LPRGNDATA data;
01496     RECT *rects;
01497 
01498     if (!region || !count || !matrix)
01499         return InvalidParameter;
01500 
01501     stat = get_region_scans_data(region, matrix, &data);
01502 
01503     if (stat == Ok)
01504     {
01505         *count = data->rdh.nCount;
01506         rects = (RECT*)data->Buffer;
01507 
01508         if (scans)
01509         {
01510             for (i=0; i<data->rdh.nCount; i++)
01511             {
01512                 scans[i].X = rects[i].left;
01513                 scans[i].Y = rects[i].top;
01514                 scans[i].Width = rects[i].right - rects[i].left;
01515                 scans[i].Height = rects[i].bottom - rects[i].top;
01516             }
01517         }
01518 
01519         GdipFree(data);
01520     }
01521 
01522     return Ok;
01523 }

Generated on Sat May 26 2012 04:22:11 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.