Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenregion.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(®ion->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(®ion->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(®ion->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(®ion->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(®ion->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, ®ion->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, ®2copy); 00362 if(stat != Ok) return stat; 00363 00364 delete_element(®ion1->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(®ion2->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(®ion->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, ®ion->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(®ion->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(®ion->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(®ion->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(®ion->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(®ion->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(®ion->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, ®ion_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
1.7.6.1
|