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

graphicspath.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 Google (Evan Stade)
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 
00020 #include <stdarg.h>
00021 #include <math.h>
00022 
00023 #include "windef.h"
00024 #include "winbase.h"
00025 #include "winuser.h"
00026 #include "wingdi.h"
00027 
00028 #include "objbase.h"
00029 
00030 #include "gdiplus.h"
00031 #include "gdiplus_private.h"
00032 #include "wine/debug.h"
00033 
00034 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
00035 
00036 typedef struct path_list_node_t path_list_node_t;
00037 struct path_list_node_t {
00038     GpPointF pt;
00039     BYTE type; /* PathPointTypeStart or PathPointTypeLine */
00040     path_list_node_t *next;
00041 };
00042 
00043 /* init list */
00044 static BOOL init_path_list(path_list_node_t **node, REAL x, REAL y)
00045 {
00046     *node = GdipAlloc(sizeof(path_list_node_t));
00047     if(!*node)
00048         return FALSE;
00049 
00050     (*node)->pt.X = x;
00051     (*node)->pt.Y = y;
00052     (*node)->type = PathPointTypeStart;
00053     (*node)->next = NULL;
00054 
00055     return TRUE;
00056 }
00057 
00058 /* free all nodes including argument */
00059 static void free_path_list(path_list_node_t *node)
00060 {
00061     path_list_node_t *n = node;
00062 
00063     while(n){
00064         n = n->next;
00065         GdipFree(node);
00066         node = n;
00067     }
00068 }
00069 
00070 /* Add a node after 'node' */
00071 /*
00072  * Returns
00073  *  pointer on success
00074  *  NULL    on allocation problems
00075  */
00076 static path_list_node_t* add_path_list_node(path_list_node_t *node, REAL x, REAL y, BOOL type)
00077 {
00078     path_list_node_t *new;
00079 
00080     new = GdipAlloc(sizeof(path_list_node_t));
00081     if(!new)
00082         return NULL;
00083 
00084     new->pt.X  = x;
00085     new->pt.Y  = y;
00086     new->type  = type;
00087     new->next  = node->next;
00088     node->next = new;
00089 
00090     return new;
00091 }
00092 
00093 /* returns element count */
00094 static INT path_list_count(path_list_node_t *node)
00095 {
00096     INT count = 1;
00097 
00098     while((node = node->next))
00099         ++count;
00100 
00101     return count;
00102 }
00103 
00104 /* GdipFlattenPath helper */
00105 /*
00106  * Used to recursively flatten single Bezier curve
00107  * Parameters:
00108  *  - start   : pointer to start point node;
00109  *  - (x2, y2): first control point;
00110  *  - (x3, y3): second control point;
00111  *  - end     : pointer to end point node
00112  *  - flatness: admissible error of linear approximation.
00113  *
00114  * Return value:
00115  *  TRUE : success
00116  *  FALSE: out of memory
00117  *
00118  * TODO: used quality criteria should be revised to match native as
00119  *       closer as possible.
00120  */
00121 static BOOL flatten_bezier(path_list_node_t *start, REAL x2, REAL y2, REAL x3, REAL y3,
00122                            path_list_node_t *end, REAL flatness)
00123 {
00124     /* this 5 middle points with start/end define to half-curves */
00125     GpPointF mp[5];
00126     GpPointF pt, pt_st;
00127     path_list_node_t *node;
00128 
00129     /* calculate bezier curve middle points == new control points */
00130     mp[0].X = (start->pt.X + x2) / 2.0;
00131     mp[0].Y = (start->pt.Y + y2) / 2.0;
00132     /* middle point between control points */
00133     pt.X = (x2 + x3) / 2.0;
00134     pt.Y = (y2 + y3) / 2.0;
00135     mp[1].X = (mp[0].X + pt.X) / 2.0;
00136     mp[1].Y = (mp[0].Y + pt.Y) / 2.0;
00137     mp[4].X = (end->pt.X + x3) / 2.0;
00138     mp[4].Y = (end->pt.Y + y3) / 2.0;
00139     mp[3].X = (mp[4].X + pt.X) / 2.0;
00140     mp[3].Y = (mp[4].Y + pt.Y) / 2.0;
00141 
00142     mp[2].X = (mp[1].X + mp[3].X) / 2.0;
00143     mp[2].Y = (mp[1].Y + mp[3].Y) / 2.0;
00144 
00145     pt = end->pt;
00146     pt_st = start->pt;
00147     /* check flatness as a half of distance between middle point and a linearized path */
00148     if(fabs(((pt.Y - pt_st.Y)*mp[2].X + (pt_st.X - pt.X)*mp[2].Y +
00149         (pt_st.Y*pt.X - pt_st.X*pt.Y))) <=
00150         (0.5 * flatness*sqrtf((powf(pt.Y - pt_st.Y, 2.0) + powf(pt_st.X - pt.X, 2.0))))){
00151         return TRUE;
00152     }
00153     else
00154         /* add a middle point */
00155         if(!(node = add_path_list_node(start, mp[2].X, mp[2].Y, PathPointTypeLine)))
00156             return FALSE;
00157 
00158     /* do the same with halfs */
00159     flatten_bezier(start, mp[0].X, mp[0].Y, mp[1].X, mp[1].Y, node, flatness);
00160     flatten_bezier(node,  mp[3].X, mp[3].Y, mp[4].X, mp[4].Y, end,  flatness);
00161 
00162     return TRUE;
00163 }
00164 
00165 GpStatus WINGDIPAPI GdipAddPathArc(GpPath *path, REAL x1, REAL y1, REAL x2,
00166     REAL y2, REAL startAngle, REAL sweepAngle)
00167 {
00168     INT count, old_count, i;
00169 
00170     TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n",
00171           path, x1, y1, x2, y2, startAngle, sweepAngle);
00172 
00173     if(!path)
00174         return InvalidParameter;
00175 
00176     count = arc2polybezier(NULL, x1, y1, x2, y2, startAngle, sweepAngle);
00177 
00178     if(count == 0)
00179         return Ok;
00180     if(!lengthen_path(path, count))
00181         return OutOfMemory;
00182 
00183     old_count = path->pathdata.Count;
00184     arc2polybezier(&path->pathdata.Points[old_count], x1, y1, x2, y2,
00185                    startAngle, sweepAngle);
00186 
00187     for(i = 0; i < count; i++){
00188         path->pathdata.Types[old_count + i] = PathPointTypeBezier;
00189     }
00190 
00191     path->pathdata.Types[old_count] =
00192         (path->newfigure ? PathPointTypeStart : PathPointTypeLine);
00193     path->newfigure = FALSE;
00194     path->pathdata.Count += count;
00195 
00196     return Ok;
00197 }
00198 
00199 GpStatus WINGDIPAPI GdipAddPathArcI(GpPath *path, INT x1, INT y1, INT x2,
00200    INT y2, REAL startAngle, REAL sweepAngle)
00201 {
00202     TRACE("(%p, %d, %d, %d, %d, %.2f, %.2f)\n",
00203           path, x1, y1, x2, y2, startAngle, sweepAngle);
00204 
00205     return GdipAddPathArc(path,(REAL)x1,(REAL)y1,(REAL)x2,(REAL)y2,startAngle,sweepAngle);
00206 }
00207 
00208 GpStatus WINGDIPAPI GdipAddPathBezier(GpPath *path, REAL x1, REAL y1, REAL x2,
00209     REAL y2, REAL x3, REAL y3, REAL x4, REAL y4)
00210 {
00211     INT old_count;
00212 
00213     TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n",
00214           path, x1, y1, x2, y2, x3, y3, x4, y4);
00215 
00216     if(!path)
00217         return InvalidParameter;
00218 
00219     if(!lengthen_path(path, 4))
00220         return OutOfMemory;
00221 
00222     old_count = path->pathdata.Count;
00223 
00224     path->pathdata.Points[old_count].X = x1;
00225     path->pathdata.Points[old_count].Y = y1;
00226     path->pathdata.Points[old_count + 1].X = x2;
00227     path->pathdata.Points[old_count + 1].Y = y2;
00228     path->pathdata.Points[old_count + 2].X = x3;
00229     path->pathdata.Points[old_count + 2].Y = y3;
00230     path->pathdata.Points[old_count + 3].X = x4;
00231     path->pathdata.Points[old_count + 3].Y = y4;
00232 
00233     path->pathdata.Types[old_count] =
00234         (path->newfigure ? PathPointTypeStart : PathPointTypeLine);
00235     path->pathdata.Types[old_count + 1] = PathPointTypeBezier;
00236     path->pathdata.Types[old_count + 2] = PathPointTypeBezier;
00237     path->pathdata.Types[old_count + 3] = PathPointTypeBezier;
00238 
00239     path->newfigure = FALSE;
00240     path->pathdata.Count += 4;
00241 
00242     return Ok;
00243 }
00244 
00245 GpStatus WINGDIPAPI GdipAddPathBezierI(GpPath *path, INT x1, INT y1, INT x2,
00246     INT y2, INT x3, INT y3, INT x4, INT y4)
00247 {
00248     TRACE("(%p, %d, %d, %d, %d, %d, %d, %d, %d)\n",
00249           path, x1, y1, x2, y2, x3, y3, x4, y4);
00250 
00251     return GdipAddPathBezier(path,(REAL)x1,(REAL)y1,(REAL)x2,(REAL)y2,(REAL)x3,(REAL)y3,
00252                                   (REAL)x4,(REAL)y4);
00253 }
00254 
00255 GpStatus WINGDIPAPI GdipAddPathBeziers(GpPath *path, GDIPCONST GpPointF *points,
00256     INT count)
00257 {
00258     INT i, old_count;
00259 
00260     TRACE("(%p, %p, %d)\n", path, points, count);
00261 
00262     if(!path || !points || ((count - 1) % 3))
00263         return InvalidParameter;
00264 
00265     if(!lengthen_path(path, count))
00266         return OutOfMemory;
00267 
00268     old_count = path->pathdata.Count;
00269 
00270     for(i = 0; i < count; i++){
00271         path->pathdata.Points[old_count + i].X = points[i].X;
00272         path->pathdata.Points[old_count + i].Y = points[i].Y;
00273         path->pathdata.Types[old_count + i] = PathPointTypeBezier;
00274     }
00275 
00276     path->pathdata.Types[old_count] =
00277         (path->newfigure ? PathPointTypeStart : PathPointTypeLine);
00278     path->newfigure = FALSE;
00279     path->pathdata.Count += count;
00280 
00281     return Ok;
00282 }
00283 
00284 GpStatus WINGDIPAPI GdipAddPathBeziersI(GpPath *path, GDIPCONST GpPoint *points,
00285     INT count)
00286 {
00287     GpPointF *ptsF;
00288     GpStatus ret;
00289     INT i;
00290 
00291     TRACE("(%p, %p, %d)\n", path, points, count);
00292 
00293     if(!points || ((count - 1) % 3))
00294         return InvalidParameter;
00295 
00296     ptsF = GdipAlloc(sizeof(GpPointF) * count);
00297     if(!ptsF)
00298         return OutOfMemory;
00299 
00300     for(i = 0; i < count; i++){
00301         ptsF[i].X = (REAL)points[i].X;
00302         ptsF[i].Y = (REAL)points[i].Y;
00303     }
00304 
00305     ret = GdipAddPathBeziers(path, ptsF, count);
00306     GdipFree(ptsF);
00307 
00308     return ret;
00309 }
00310 
00311 GpStatus WINGDIPAPI GdipAddPathClosedCurve(GpPath *path, GDIPCONST GpPointF *points,
00312     INT count)
00313 {
00314     TRACE("(%p, %p, %d)\n", path, points, count);
00315 
00316     return GdipAddPathClosedCurve2(path, points, count, 1.0);
00317 }
00318 
00319 GpStatus WINGDIPAPI GdipAddPathClosedCurveI(GpPath *path, GDIPCONST GpPoint *points,
00320     INT count)
00321 {
00322     TRACE("(%p, %p, %d)\n", path, points, count);
00323 
00324     return GdipAddPathClosedCurve2I(path, points, count, 1.0);
00325 }
00326 
00327 GpStatus WINGDIPAPI GdipAddPathClosedCurve2(GpPath *path, GDIPCONST GpPointF *points,
00328     INT count, REAL tension)
00329 {
00330     INT i, len_pt = (count + 1)*3-2;
00331     GpPointF *pt;
00332     GpPointF *pts;
00333     REAL x1, x2, y1, y2;
00334     GpStatus stat;
00335 
00336     TRACE("(%p, %p, %d, %.2f)\n", path, points, count, tension);
00337 
00338     if(!path || !points || count <= 1)
00339         return InvalidParameter;
00340 
00341     pt = GdipAlloc(len_pt * sizeof(GpPointF));
00342     pts = GdipAlloc((count + 1)*sizeof(GpPointF));
00343     if(!pt || !pts){
00344         GdipFree(pt);
00345         GdipFree(pts);
00346         return OutOfMemory;
00347     }
00348 
00349     /* copy source points to extend with the last one */
00350     memcpy(pts, points, sizeof(GpPointF)*count);
00351     pts[count] = pts[0];
00352 
00353     tension = tension * TENSION_CONST;
00354 
00355     for(i = 0; i < count-1; i++){
00356         calc_curve_bezier(&(pts[i]), tension, &x1, &y1, &x2, &y2);
00357 
00358         pt[3*i+2].X = x1;
00359         pt[3*i+2].Y = y1;
00360         pt[3*i+3].X = pts[i+1].X;
00361         pt[3*i+3].Y = pts[i+1].Y;
00362         pt[3*i+4].X = x2;
00363         pt[3*i+4].Y = y2;
00364     }
00365 
00366     /* points [len_pt-2] and [0] are calculated
00367        separately to connect splines properly */
00368     pts[0] = points[count-1];
00369     pts[1] = points[0]; /* equals to start and end of a resulting path */
00370     pts[2] = points[1];
00371 
00372     calc_curve_bezier(pts, tension, &x1, &y1, &x2, &y2);
00373     pt[len_pt-2].X = x1;
00374     pt[len_pt-2].Y = y1;
00375     pt[0].X = pts[1].X;
00376     pt[0].Y = pts[1].Y;
00377     pt[1].X = x2;
00378     pt[1].Y = y2;
00379     /* close path */
00380     pt[len_pt-1].X = pt[0].X;
00381     pt[len_pt-1].Y = pt[0].Y;
00382 
00383     stat = GdipAddPathBeziers(path, pt, len_pt);
00384 
00385     /* close figure */
00386     if(stat == Ok){
00387         path->pathdata.Types[path->pathdata.Count - 1] |= PathPointTypeCloseSubpath;
00388         path->newfigure = TRUE;
00389     }
00390 
00391     GdipFree(pts);
00392     GdipFree(pt);
00393 
00394     return stat;
00395 }
00396 
00397 GpStatus WINGDIPAPI GdipAddPathClosedCurve2I(GpPath *path, GDIPCONST GpPoint *points,
00398     INT count, REAL tension)
00399 {
00400     GpPointF *ptf;
00401     INT i;
00402     GpStatus stat;
00403 
00404     TRACE("(%p, %p, %d, %.2f)\n", path, points, count, tension);
00405 
00406     if(!path || !points || count <= 1)
00407         return InvalidParameter;
00408 
00409     ptf = GdipAlloc(sizeof(GpPointF)*count);
00410     if(!ptf)
00411         return OutOfMemory;
00412 
00413     for(i = 0; i < count; i++){
00414         ptf[i].X = (REAL)points[i].X;
00415         ptf[i].Y = (REAL)points[i].Y;
00416     }
00417 
00418     stat = GdipAddPathClosedCurve2(path, ptf, count, tension);
00419 
00420     GdipFree(ptf);
00421 
00422     return stat;
00423 }
00424 
00425 GpStatus WINGDIPAPI GdipAddPathCurve(GpPath *path, GDIPCONST GpPointF *points, INT count)
00426 {
00427     TRACE("(%p, %p, %d)\n", path, points, count);
00428 
00429     if(!path || !points || count <= 1)
00430         return InvalidParameter;
00431 
00432     return GdipAddPathCurve2(path, points, count, 1.0);
00433 }
00434 
00435 GpStatus WINGDIPAPI GdipAddPathCurveI(GpPath *path, GDIPCONST GpPoint *points, INT count)
00436 {
00437     TRACE("(%p, %p, %d)\n", path, points, count);
00438 
00439     if(!path || !points || count <= 1)
00440         return InvalidParameter;
00441 
00442     return GdipAddPathCurve2I(path, points, count, 1.0);
00443 }
00444 
00445 GpStatus WINGDIPAPI GdipAddPathCurve2(GpPath *path, GDIPCONST GpPointF *points, INT count,
00446     REAL tension)
00447 {
00448     INT i, len_pt = count*3-2;
00449     GpPointF *pt;
00450     REAL x1, x2, y1, y2;
00451     GpStatus stat;
00452 
00453     TRACE("(%p, %p, %d, %.2f)\n", path, points, count, tension);
00454 
00455     if(!path || !points || count <= 1)
00456         return InvalidParameter;
00457 
00458     pt = GdipAlloc(len_pt * sizeof(GpPointF));
00459     if(!pt)
00460         return OutOfMemory;
00461 
00462     tension = tension * TENSION_CONST;
00463 
00464     calc_curve_bezier_endp(points[0].X, points[0].Y, points[1].X, points[1].Y,
00465         tension, &x1, &y1);
00466 
00467     pt[0].X = points[0].X;
00468     pt[0].Y = points[0].Y;
00469     pt[1].X = x1;
00470     pt[1].Y = y1;
00471 
00472     for(i = 0; i < count-2; i++){
00473         calc_curve_bezier(&(points[i]), tension, &x1, &y1, &x2, &y2);
00474 
00475         pt[3*i+2].X = x1;
00476         pt[3*i+2].Y = y1;
00477         pt[3*i+3].X = points[i+1].X;
00478         pt[3*i+3].Y = points[i+1].Y;
00479         pt[3*i+4].X = x2;
00480         pt[3*i+4].Y = y2;
00481     }
00482 
00483     calc_curve_bezier_endp(points[count-1].X, points[count-1].Y,
00484         points[count-2].X, points[count-2].Y, tension, &x1, &y1);
00485 
00486     pt[len_pt-2].X = x1;
00487     pt[len_pt-2].Y = y1;
00488     pt[len_pt-1].X = points[count-1].X;
00489     pt[len_pt-1].Y = points[count-1].Y;
00490 
00491     stat = GdipAddPathBeziers(path, pt, len_pt);
00492 
00493     GdipFree(pt);
00494 
00495     return stat;
00496 }
00497 
00498 GpStatus WINGDIPAPI GdipAddPathCurve2I(GpPath *path, GDIPCONST GpPoint *points,
00499     INT count, REAL tension)
00500 {
00501     GpPointF *ptf;
00502     INT i;
00503     GpStatus stat;
00504 
00505     TRACE("(%p, %p, %d, %.2f)\n", path, points, count, tension);
00506 
00507     if(!path || !points || count <= 1)
00508         return InvalidParameter;
00509 
00510     ptf = GdipAlloc(sizeof(GpPointF)*count);
00511     if(!ptf)
00512         return OutOfMemory;
00513 
00514     for(i = 0; i < count; i++){
00515         ptf[i].X = (REAL)points[i].X;
00516         ptf[i].Y = (REAL)points[i].Y;
00517     }
00518 
00519     stat = GdipAddPathCurve2(path, ptf, count, tension);
00520 
00521     GdipFree(ptf);
00522 
00523     return stat;
00524 }
00525 
00526 GpStatus WINGDIPAPI GdipAddPathCurve3(GpPath *path, GDIPCONST GpPointF *points,
00527     INT count, INT offset, INT nseg, REAL tension)
00528 {
00529     TRACE("(%p, %p, %d, %d, %d, %.2f)\n", path, points, count, offset, nseg, tension);
00530 
00531     if(!path || !points || offset + 1 >= count || count - offset < nseg + 1)
00532         return InvalidParameter;
00533 
00534     return GdipAddPathCurve2(path, &points[offset], nseg + 1, tension);
00535 }
00536 
00537 GpStatus WINGDIPAPI GdipAddPathCurve3I(GpPath *path, GDIPCONST GpPoint *points,
00538     INT count, INT offset, INT nseg, REAL tension)
00539 {
00540     TRACE("(%p, %p, %d, %d, %d, %.2f)\n", path, points, count, offset, nseg, tension);
00541 
00542     if(!path || !points || offset + 1 >= count || count - offset < nseg + 1)
00543         return InvalidParameter;
00544 
00545     return GdipAddPathCurve2I(path, &points[offset], nseg + 1, tension);
00546 }
00547 
00548 GpStatus WINGDIPAPI GdipAddPathEllipse(GpPath *path, REAL x, REAL y, REAL width,
00549     REAL height)
00550 {
00551     INT old_count, numpts;
00552 
00553     TRACE("(%p, %.2f, %.2f, %.2f, %.2f)\n", path, x, y, width, height);
00554 
00555     if(!path)
00556         return InvalidParameter;
00557 
00558     if(!lengthen_path(path, MAX_ARC_PTS))
00559         return OutOfMemory;
00560 
00561     old_count = path->pathdata.Count;
00562     if((numpts = arc2polybezier(&path->pathdata.Points[old_count],  x, y, width,
00563                                height, 0.0, 360.0)) != MAX_ARC_PTS){
00564         ERR("expected %d points but got %d\n", MAX_ARC_PTS, numpts);
00565         return GenericError;
00566     }
00567 
00568     memset(&path->pathdata.Types[old_count + 1], PathPointTypeBezier,
00569            MAX_ARC_PTS - 1);
00570 
00571     /* An ellipse is an intrinsic figure (always is its own subpath). */
00572     path->pathdata.Types[old_count] = PathPointTypeStart;
00573     path->pathdata.Types[old_count + MAX_ARC_PTS - 1] |= PathPointTypeCloseSubpath;
00574     path->newfigure = TRUE;
00575     path->pathdata.Count += MAX_ARC_PTS;
00576 
00577     return Ok;
00578 }
00579 
00580 GpStatus WINGDIPAPI GdipAddPathEllipseI(GpPath *path, INT x, INT y, INT width,
00581     INT height)
00582 {
00583     TRACE("(%p, %d, %d, %d, %d)\n", path, x, y, width, height);
00584 
00585     return GdipAddPathEllipse(path,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
00586 }
00587 
00588 GpStatus WINGDIPAPI GdipAddPathLine2(GpPath *path, GDIPCONST GpPointF *points,
00589     INT count)
00590 {
00591     INT i, old_count;
00592 
00593     TRACE("(%p, %p, %d)\n", path, points, count);
00594 
00595     if(!path || !points)
00596         return InvalidParameter;
00597 
00598     if(!lengthen_path(path, count))
00599         return OutOfMemory;
00600 
00601     old_count = path->pathdata.Count;
00602 
00603     for(i = 0; i < count; i++){
00604         path->pathdata.Points[old_count + i].X = points[i].X;
00605         path->pathdata.Points[old_count + i].Y = points[i].Y;
00606         path->pathdata.Types[old_count + i] = PathPointTypeLine;
00607     }
00608 
00609     if(path->newfigure){
00610         path->pathdata.Types[old_count] = PathPointTypeStart;
00611         path->newfigure = FALSE;
00612     }
00613 
00614     path->pathdata.Count += count;
00615 
00616     return Ok;
00617 }
00618 
00619 GpStatus WINGDIPAPI GdipAddPathLine2I(GpPath *path, GDIPCONST GpPoint *points, INT count)
00620 {
00621     GpPointF *pointsF;
00622     INT i;
00623     GpStatus stat;
00624 
00625     TRACE("(%p, %p, %d)\n", path, points, count);
00626 
00627     if(count <= 0)
00628         return InvalidParameter;
00629 
00630     pointsF = GdipAlloc(sizeof(GpPointF) * count);
00631     if(!pointsF)    return OutOfMemory;
00632 
00633     for(i = 0;i < count; i++){
00634         pointsF[i].X = (REAL)points[i].X;
00635         pointsF[i].Y = (REAL)points[i].Y;
00636     }
00637 
00638     stat = GdipAddPathLine2(path, pointsF, count);
00639 
00640     GdipFree(pointsF);
00641 
00642     return stat;
00643 }
00644 
00645 GpStatus WINGDIPAPI GdipAddPathLine(GpPath *path, REAL x1, REAL y1, REAL x2, REAL y2)
00646 {
00647     INT old_count;
00648 
00649     TRACE("(%p, %.2f, %.2f, %.2f, %.2f)\n", path, x1, y1, x2, y2);
00650 
00651     if(!path)
00652         return InvalidParameter;
00653 
00654     if(!lengthen_path(path, 2))
00655         return OutOfMemory;
00656 
00657     old_count = path->pathdata.Count;
00658 
00659     path->pathdata.Points[old_count].X = x1;
00660     path->pathdata.Points[old_count].Y = y1;
00661     path->pathdata.Points[old_count + 1].X = x2;
00662     path->pathdata.Points[old_count + 1].Y = y2;
00663 
00664     path->pathdata.Types[old_count] =
00665         (path->newfigure ? PathPointTypeStart : PathPointTypeLine);
00666     path->pathdata.Types[old_count + 1] = PathPointTypeLine;
00667 
00668     path->newfigure = FALSE;
00669     path->pathdata.Count += 2;
00670 
00671     return Ok;
00672 }
00673 
00674 GpStatus WINGDIPAPI GdipAddPathLineI(GpPath *path, INT x1, INT y1, INT x2, INT y2)
00675 {
00676     TRACE("(%p, %d, %d, %d, %d)\n", path, x1, y1, x2, y2);
00677 
00678     return GdipAddPathLine(path, (REAL)x1, (REAL)y1, (REAL)x2, (REAL)y2);
00679 }
00680 
00681 GpStatus WINGDIPAPI GdipAddPathPath(GpPath *path, GDIPCONST GpPath* addingPath,
00682     BOOL connect)
00683 {
00684     INT old_count, count;
00685 
00686     TRACE("(%p, %p, %d)\n", path, addingPath, connect);
00687 
00688     if(!path || !addingPath)
00689         return InvalidParameter;
00690 
00691     old_count = path->pathdata.Count;
00692     count = addingPath->pathdata.Count;
00693 
00694     if(!lengthen_path(path, count))
00695         return OutOfMemory;
00696 
00697     memcpy(&path->pathdata.Points[old_count], addingPath->pathdata.Points,
00698            count * sizeof(GpPointF));
00699     memcpy(&path->pathdata.Types[old_count], addingPath->pathdata.Types, count);
00700 
00701     if(path->newfigure || !connect)
00702         path->pathdata.Types[old_count] = PathPointTypeStart;
00703     else
00704         path->pathdata.Types[old_count] = PathPointTypeLine;
00705 
00706     path->newfigure = FALSE;
00707     path->pathdata.Count += count;
00708 
00709     return Ok;
00710 }
00711 
00712 GpStatus WINGDIPAPI GdipAddPathPie(GpPath *path, REAL x, REAL y, REAL width, REAL height,
00713     REAL startAngle, REAL sweepAngle)
00714 {
00715     GpPointF *ptf;
00716     GpStatus status;
00717     INT i, count;
00718 
00719     TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n",
00720           path, x, y, width, height, startAngle, sweepAngle);
00721 
00722     if(!path)
00723         return InvalidParameter;
00724 
00725     /* on zero width/height only start point added */
00726     if(width <= 1e-7 || height <= 1e-7){
00727         if(!lengthen_path(path, 1))
00728             return OutOfMemory;
00729         path->pathdata.Points[0].X = x + width  / 2.0;
00730         path->pathdata.Points[0].Y = y + height / 2.0;
00731         path->pathdata.Types[0] = PathPointTypeStart | PathPointTypeCloseSubpath;
00732         path->pathdata.Count = 1;
00733         return InvalidParameter;
00734     }
00735 
00736     count = arc2polybezier(NULL, x, y, width, height, startAngle, sweepAngle);
00737 
00738     if(count == 0)
00739         return Ok;
00740 
00741     ptf = GdipAlloc(sizeof(GpPointF)*count);
00742     if(!ptf)
00743         return OutOfMemory;
00744 
00745     arc2polybezier(ptf, x, y, width, height, startAngle, sweepAngle);
00746 
00747     status = GdipAddPathLine(path, x + width/2, y + height/2, ptf[0].X, ptf[0].Y);
00748     if(status != Ok){
00749         GdipFree(ptf);
00750         return status;
00751     }
00752     /* one spline is already added as a line endpoint */
00753     if(!lengthen_path(path, count - 1)){
00754         GdipFree(ptf);
00755         return OutOfMemory;
00756     }
00757 
00758     memcpy(&(path->pathdata.Points[path->pathdata.Count]), &(ptf[1]),sizeof(GpPointF)*(count-1));
00759     for(i = 0; i < count-1; i++)
00760         path->pathdata.Types[path->pathdata.Count+i] = PathPointTypeBezier;
00761 
00762     path->pathdata.Count += count-1;
00763 
00764     GdipClosePathFigure(path);
00765 
00766     GdipFree(ptf);
00767 
00768     return status;
00769 }
00770 
00771 GpStatus WINGDIPAPI GdipAddPathPieI(GpPath *path, INT x, INT y, INT width, INT height,
00772     REAL startAngle, REAL sweepAngle)
00773 {
00774     TRACE("(%p, %d, %d, %d, %d, %.2f, %.2f)\n",
00775           path, x, y, width, height, startAngle, sweepAngle);
00776 
00777     return GdipAddPathPie(path, (REAL)x, (REAL)y, (REAL)width, (REAL)height, startAngle, sweepAngle);
00778 }
00779 
00780 GpStatus WINGDIPAPI GdipAddPathPolygon(GpPath *path, GDIPCONST GpPointF *points, INT count)
00781 {
00782     INT old_count;
00783 
00784     TRACE("(%p, %p, %d)\n", path, points, count);
00785 
00786     if(!path || !points || count < 3)
00787         return InvalidParameter;
00788 
00789     if(!lengthen_path(path, count))
00790         return OutOfMemory;
00791 
00792     old_count = path->pathdata.Count;
00793 
00794     memcpy(&path->pathdata.Points[old_count], points, count*sizeof(GpPointF));
00795     memset(&path->pathdata.Types[old_count + 1], PathPointTypeLine, count - 1);
00796 
00797     /* A polygon is an intrinsic figure */
00798     path->pathdata.Types[old_count] = PathPointTypeStart;
00799     path->pathdata.Types[old_count + count - 1] |= PathPointTypeCloseSubpath;
00800     path->newfigure = TRUE;
00801     path->pathdata.Count += count;
00802 
00803     return Ok;
00804 }
00805 
00806 GpStatus WINGDIPAPI GdipAddPathPolygonI(GpPath *path, GDIPCONST GpPoint *points, INT count)
00807 {
00808     GpPointF *ptf;
00809     GpStatus status;
00810     INT i;
00811 
00812     TRACE("(%p, %p, %d)\n", path, points, count);
00813 
00814     if(!points || count < 3)
00815         return InvalidParameter;
00816 
00817     ptf = GdipAlloc(sizeof(GpPointF) * count);
00818     if(!ptf)
00819         return OutOfMemory;
00820 
00821     for(i = 0; i < count; i++){
00822         ptf[i].X = (REAL)points[i].X;
00823         ptf[i].Y = (REAL)points[i].Y;
00824     }
00825 
00826     status = GdipAddPathPolygon(path, ptf, count);
00827 
00828     GdipFree(ptf);
00829 
00830     return status;
00831 }
00832 
00833 static float fromfixedpoint(const FIXED v)
00834 {
00835     float f = ((float)v.fract) / (1<<(sizeof(v.fract)*8));
00836     f += v.value;
00837     return f;
00838 }
00839 
00840 struct format_string_args
00841 {
00842     GpPath *path;
00843     UINT maxY;
00844 };
00845 
00846 static GpStatus format_string_callback(HDC dc,
00847     GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
00848     GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
00849     INT lineno, const RectF *bounds, INT *underlined_indexes,
00850     INT underlined_index_count, void *priv)
00851 {
00852     static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
00853     struct format_string_args *args = priv;
00854     GpPath *path = args->path;
00855     GpStatus status = Ok;
00856     float x = bounds->X;
00857     float y = bounds->Y;
00858     int i;
00859 
00860     if (underlined_index_count)
00861         FIXME("hotkey underlines not drawn yet\n");
00862 
00863     for (i = index; i < length; ++i)
00864     {
00865         GLYPHMETRICS gm;
00866         TTPOLYGONHEADER *ph = NULL;
00867         char *start;
00868         DWORD len, ofs = 0;
00869         UINT bb_end;
00870         len = GetGlyphOutlineW(dc, string[i], GGO_BEZIER, &gm, 0, NULL, &identity);
00871         if (len == GDI_ERROR)
00872         {
00873             status = GenericError;
00874             break;
00875         }
00876         ph = GdipAlloc(len);
00877         start = (char *)ph;
00878         if (!ph || !lengthen_path(path, len / sizeof(POINTFX)))
00879         {
00880             status = OutOfMemory;
00881             break;
00882         }
00883         GetGlyphOutlineW(dc, string[i], GGO_BEZIER, &gm, len, start, &identity);
00884         bb_end = gm.gmBlackBoxY + gm.gmptGlyphOrigin.y;
00885         if (bb_end + y > args->maxY)
00886             args->maxY = bb_end + y;
00887 
00888         ofs = 0;
00889         while (ofs < len)
00890         {
00891             DWORD ofs_start = ofs;
00892             ph = (TTPOLYGONHEADER*)&start[ofs];
00893             path->pathdata.Types[path->pathdata.Count] = PathPointTypeStart;
00894             path->pathdata.Points[path->pathdata.Count].X = x + fromfixedpoint(ph->pfxStart.x);
00895             path->pathdata.Points[path->pathdata.Count++].Y = y + bb_end - fromfixedpoint(ph->pfxStart.y);
00896             TRACE("Starting at count %i with pos %f, %f)\n", path->pathdata.Count, x, y);
00897             ofs += sizeof(*ph);
00898             while (ofs - ofs_start < ph->cb)
00899             {
00900                 TTPOLYCURVE *curve = (TTPOLYCURVE*)&start[ofs];
00901                 int j;
00902                 ofs += sizeof(TTPOLYCURVE) + (curve->cpfx - 1) * sizeof(POINTFX);
00903 
00904                 switch (curve->wType)
00905                 {
00906                 case TT_PRIM_LINE:
00907                     for (j = 0; j < curve->cpfx; ++j)
00908                     {
00909                         path->pathdata.Types[path->pathdata.Count] = PathPointTypeLine;
00910                         path->pathdata.Points[path->pathdata.Count].X = x + fromfixedpoint(curve->apfx[j].x);
00911                         path->pathdata.Points[path->pathdata.Count++].Y = y + bb_end - fromfixedpoint(curve->apfx[j].y);
00912                     }
00913                     break;
00914                 case TT_PRIM_CSPLINE:
00915                     for (j = 0; j < curve->cpfx; ++j)
00916                     {
00917                         path->pathdata.Types[path->pathdata.Count] = PathPointTypeBezier;
00918                         path->pathdata.Points[path->pathdata.Count].X = x + fromfixedpoint(curve->apfx[j].x);
00919                         path->pathdata.Points[path->pathdata.Count++].Y = y + bb_end - fromfixedpoint(curve->apfx[j].y);
00920                     }
00921                     break;
00922                 default:
00923                     ERR("Unhandled type: %u\n", curve->wType);
00924                     status = GenericError;
00925                 }
00926             }
00927             path->pathdata.Types[path->pathdata.Count - 1] |= PathPointTypeCloseSubpath;
00928         }
00929         path->newfigure = TRUE;
00930         x += gm.gmCellIncX;
00931         y += gm.gmCellIncY;
00932 
00933         GdipFree(ph);
00934         if (status != Ok)
00935             break;
00936     }
00937 
00938     return status;
00939 }
00940 
00941 GpStatus WINGDIPAPI GdipAddPathString(GpPath* path, GDIPCONST WCHAR* string, INT length, GDIPCONST GpFontFamily* family, INT style, REAL emSize, GDIPCONST RectF* layoutRect, GDIPCONST GpStringFormat* format)
00942 {
00943     GpFont *font;
00944     GpStatus status;
00945     LOGFONTW lfw;
00946     HANDLE hfont;
00947     HDC dc;
00948     GpPath *backup;
00949     struct format_string_args args;
00950     int i;
00951 
00952     FIXME("(%p, %s, %d, %p, %d, %f, %p, %p): stub\n", path, debugstr_w(string), length, family, style, emSize, layoutRect, format);
00953     if (!path || !string || !family || !emSize || !layoutRect || !format)
00954         return InvalidParameter;
00955 
00956     status = GdipCreateFont(family, emSize, style, UnitPixel, &font);
00957     if (status != Ok)
00958         return status;
00959 
00960     status = GdipGetLogFontW((GpFont *)font, NULL, &lfw);
00961     if (status != Ok) return status;
00962     hfont = CreateFontIndirectW(&lfw);
00963     if (!hfont)
00964     {
00965         WARN("Failed to create font\n");
00966         return GenericError;
00967     }
00968 
00969     if ((status = GdipClonePath(path, &backup)) != Ok)
00970     {
00971         DeleteObject(hfont);
00972         return status;
00973     }
00974 
00975     dc = CreateCompatibleDC(0);
00976     SelectObject(dc, hfont);
00977 
00978     args.path = path;
00979     args.maxY = 0;
00980     status = gdip_format_string(dc, string, length, NULL, layoutRect, format, format_string_callback, &args);
00981 
00982     DeleteDC(dc);
00983     DeleteObject(hfont);
00984 
00985     if (status != Ok) /* free backup */
00986     {
00987         GdipFree(path->pathdata.Points);
00988         GdipFree(path->pathdata.Types);
00989         *path = *backup;
00990         GdipFree(backup);
00991         return status;
00992     }
00993     if (format && format->vertalign == StringAlignmentCenter && layoutRect->Y + args.maxY < layoutRect->Height)
00994     {
00995         float inc = layoutRect->Height - args.maxY - layoutRect->Y;
00996         inc /= 2;
00997         for (i = backup->pathdata.Count; i < path->pathdata.Count; ++i)
00998             path->pathdata.Points[i].Y += inc;
00999     } else if (format && format->vertalign == StringAlignmentFar) {
01000         float inc = layoutRect->Height - args.maxY - layoutRect->Y;
01001         for (i = backup->pathdata.Count; i < path->pathdata.Count; ++i)
01002             path->pathdata.Points[i].Y += inc;
01003     }
01004     GdipDeletePath(backup);
01005     return status;
01006 }
01007 
01008 GpStatus WINGDIPAPI GdipAddPathStringI(GpPath* path, GDIPCONST WCHAR* string, INT length, GDIPCONST GpFontFamily* family, INT style, REAL emSize, GDIPCONST Rect* layoutRect, GDIPCONST GpStringFormat* format)
01009 {
01010     if (layoutRect)
01011     {
01012         RectF layoutRectF = {
01013             (REAL)layoutRect->X,
01014             (REAL)layoutRect->Y,
01015             (REAL)layoutRect->Width,
01016             (REAL)layoutRect->Height
01017         };
01018         return GdipAddPathString(path, string, length, family, style, emSize, &layoutRectF, format);
01019     }
01020     return InvalidParameter;
01021 }
01022 
01023 GpStatus WINGDIPAPI GdipClonePath(GpPath* path, GpPath **clone)
01024 {
01025     TRACE("(%p, %p)\n", path, clone);
01026 
01027     if(!path || !clone)
01028         return InvalidParameter;
01029 
01030     *clone = GdipAlloc(sizeof(GpPath));
01031     if(!*clone) return OutOfMemory;
01032 
01033     **clone = *path;
01034 
01035     (*clone)->pathdata.Points = GdipAlloc(path->datalen * sizeof(PointF));
01036     (*clone)->pathdata.Types = GdipAlloc(path->datalen);
01037     if(!(*clone)->pathdata.Points || !(*clone)->pathdata.Types){
01038         GdipFree(*clone);
01039         GdipFree((*clone)->pathdata.Points);
01040         GdipFree((*clone)->pathdata.Types);
01041         return OutOfMemory;
01042     }
01043 
01044     memcpy((*clone)->pathdata.Points, path->pathdata.Points,
01045            path->datalen * sizeof(PointF));
01046     memcpy((*clone)->pathdata.Types, path->pathdata.Types, path->datalen);
01047 
01048     return Ok;
01049 }
01050 
01051 GpStatus WINGDIPAPI GdipClosePathFigure(GpPath* path)
01052 {
01053     TRACE("(%p)\n", path);
01054 
01055     if(!path)
01056         return InvalidParameter;
01057 
01058     if(path->pathdata.Count > 0){
01059         path->pathdata.Types[path->pathdata.Count - 1] |= PathPointTypeCloseSubpath;
01060         path->newfigure = TRUE;
01061     }
01062 
01063     return Ok;
01064 }
01065 
01066 GpStatus WINGDIPAPI GdipClosePathFigures(GpPath* path)
01067 {
01068     INT i;
01069 
01070     TRACE("(%p)\n", path);
01071 
01072     if(!path)
01073         return InvalidParameter;
01074 
01075     for(i = 1; i < path->pathdata.Count; i++){
01076         if(path->pathdata.Types[i] == PathPointTypeStart)
01077             path->pathdata.Types[i-1] |= PathPointTypeCloseSubpath;
01078     }
01079 
01080     path->newfigure = TRUE;
01081 
01082     return Ok;
01083 }
01084 
01085 GpStatus WINGDIPAPI GdipCreatePath(GpFillMode fill, GpPath **path)
01086 {
01087     TRACE("(%d, %p)\n", fill, path);
01088 
01089     if(!path)
01090         return InvalidParameter;
01091 
01092     *path = GdipAlloc(sizeof(GpPath));
01093     if(!*path)  return OutOfMemory;
01094 
01095     (*path)->fill = fill;
01096     (*path)->newfigure = TRUE;
01097 
01098     return Ok;
01099 }
01100 
01101 GpStatus WINGDIPAPI GdipCreatePath2(GDIPCONST GpPointF* points,
01102     GDIPCONST BYTE* types, INT count, GpFillMode fill, GpPath **path)
01103 {
01104     TRACE("(%p, %p, %d, %d, %p)\n", points, types, count, fill, path);
01105 
01106     if(!path)
01107         return InvalidParameter;
01108 
01109     *path = GdipAlloc(sizeof(GpPath));
01110     if(!*path)  return OutOfMemory;
01111 
01112     (*path)->pathdata.Points = GdipAlloc(count * sizeof(PointF));
01113     (*path)->pathdata.Types = GdipAlloc(count);
01114 
01115     if(!(*path)->pathdata.Points || !(*path)->pathdata.Types){
01116         GdipFree((*path)->pathdata.Points);
01117         GdipFree((*path)->pathdata.Types);
01118         GdipFree(*path);
01119         return OutOfMemory;
01120     }
01121 
01122     memcpy((*path)->pathdata.Points, points, count * sizeof(PointF));
01123     memcpy((*path)->pathdata.Types, types, count);
01124     (*path)->pathdata.Count = count;
01125     (*path)->datalen = count;
01126 
01127     (*path)->fill = fill;
01128     (*path)->newfigure = TRUE;
01129 
01130     return Ok;
01131 }
01132 
01133 GpStatus WINGDIPAPI GdipCreatePath2I(GDIPCONST GpPoint* points,
01134     GDIPCONST BYTE* types, INT count, GpFillMode fill, GpPath **path)
01135 {
01136     GpPointF *ptF;
01137     GpStatus ret;
01138     INT i;
01139 
01140     TRACE("(%p, %p, %d, %d, %p)\n", points, types, count, fill, path);
01141 
01142     ptF = GdipAlloc(sizeof(GpPointF)*count);
01143 
01144     for(i = 0;i < count; i++){
01145         ptF[i].X = (REAL)points[i].X;
01146         ptF[i].Y = (REAL)points[i].Y;
01147     }
01148 
01149     ret = GdipCreatePath2(ptF, types, count, fill, path);
01150 
01151     GdipFree(ptF);
01152 
01153     return ret;
01154 }
01155 
01156 GpStatus WINGDIPAPI GdipDeletePath(GpPath *path)
01157 {
01158     TRACE("(%p)\n", path);
01159 
01160     if(!path)
01161         return InvalidParameter;
01162 
01163     GdipFree(path->pathdata.Points);
01164     GdipFree(path->pathdata.Types);
01165     GdipFree(path);
01166 
01167     return Ok;
01168 }
01169 
01170 GpStatus WINGDIPAPI GdipFlattenPath(GpPath *path, GpMatrix* matrix, REAL flatness)
01171 {
01172     path_list_node_t *list, *node;
01173     GpPointF pt;
01174     INT i = 1;
01175     INT startidx = 0;
01176 
01177     TRACE("(%p, %p, %.2f)\n", path, matrix, flatness);
01178 
01179     if(!path)
01180         return InvalidParameter;
01181 
01182     if(matrix){
01183         WARN("transformation not supported yet!\n");
01184         return NotImplemented;
01185     }
01186 
01187     if(path->pathdata.Count == 0)
01188         return Ok;
01189 
01190     pt = path->pathdata.Points[0];
01191     if(!init_path_list(&list, pt.X, pt.Y))
01192         return OutOfMemory;
01193 
01194     node = list;
01195 
01196     while(i < path->pathdata.Count){
01197 
01198         BYTE type = path->pathdata.Types[i] & PathPointTypePathTypeMask;
01199         path_list_node_t *start;
01200 
01201         pt = path->pathdata.Points[i];
01202 
01203         /* save last start point index */
01204         if(type == PathPointTypeStart)
01205             startidx = i;
01206 
01207         /* always add line points and start points */
01208         if((type == PathPointTypeStart) || (type == PathPointTypeLine)){
01209             if(!add_path_list_node(node, pt.X, pt.Y, path->pathdata.Types[i]))
01210                 goto memout;
01211 
01212             node = node->next;
01213             ++i;
01214             continue;
01215         }
01216 
01217         /* Bezier curve */
01218 
01219         /* test for closed figure */
01220         if(path->pathdata.Types[i+1] & PathPointTypeCloseSubpath){
01221             pt = path->pathdata.Points[startidx];
01222             ++i;
01223         }
01224         else
01225         {
01226             i += 2;
01227             pt = path->pathdata.Points[i];
01228         };
01229 
01230         start = node;
01231         /* add Bezier end point */
01232         type = (path->pathdata.Types[i] & ~PathPointTypePathTypeMask) | PathPointTypeLine;
01233         if(!add_path_list_node(node, pt.X, pt.Y, type))
01234             goto memout;
01235         node = node->next;
01236 
01237         /* flatten curve */
01238         if(!flatten_bezier(start, path->pathdata.Points[i-2].X, path->pathdata.Points[i-2].Y,
01239                                   path->pathdata.Points[i-1].X, path->pathdata.Points[i-1].Y,
01240                            node, flatness))
01241             goto memout;
01242 
01243         ++i;
01244     }/* while */
01245 
01246     /* store path data back */
01247     i = path_list_count(list);
01248     if(!lengthen_path(path, i))
01249         goto memout;
01250     path->pathdata.Count = i;
01251 
01252     node = list;
01253     for(i = 0; i < path->pathdata.Count; i++){
01254         path->pathdata.Points[i] = node->pt;
01255         path->pathdata.Types[i]  = node->type;
01256         node = node->next;
01257     }
01258 
01259     free_path_list(list);
01260     return Ok;
01261 
01262 memout:
01263     free_path_list(list);
01264     return OutOfMemory;
01265 }
01266 
01267 GpStatus WINGDIPAPI GdipGetPathData(GpPath *path, GpPathData* pathData)
01268 {
01269     TRACE("(%p, %p)\n", path, pathData);
01270 
01271     if(!path || !pathData)
01272         return InvalidParameter;
01273 
01274     /* Only copy data. pathData allocation/freeing controlled by wrapper class.
01275        Assumed that pathData is enough wide to get all data - controlled by wrapper too. */
01276     memcpy(pathData->Points, path->pathdata.Points, sizeof(PointF) * pathData->Count);
01277     memcpy(pathData->Types , path->pathdata.Types , pathData->Count);
01278 
01279     return Ok;
01280 }
01281 
01282 GpStatus WINGDIPAPI GdipGetPathFillMode(GpPath *path, GpFillMode *fillmode)
01283 {
01284     TRACE("(%p, %p)\n", path, fillmode);
01285 
01286     if(!path || !fillmode)
01287         return InvalidParameter;
01288 
01289     *fillmode = path->fill;
01290 
01291     return Ok;
01292 }
01293 
01294 GpStatus WINGDIPAPI GdipGetPathLastPoint(GpPath* path, GpPointF* lastPoint)
01295 {
01296     INT count;
01297 
01298     TRACE("(%p, %p)\n", path, lastPoint);
01299 
01300     if(!path || !lastPoint)
01301         return InvalidParameter;
01302 
01303     count = path->pathdata.Count;
01304     if(count > 0)
01305         *lastPoint = path->pathdata.Points[count-1];
01306 
01307     return Ok;
01308 }
01309 
01310 GpStatus WINGDIPAPI GdipGetPathPoints(GpPath *path, GpPointF* points, INT count)
01311 {
01312     TRACE("(%p, %p, %d)\n", path, points, count);
01313 
01314     if(!path)
01315         return InvalidParameter;
01316 
01317     if(count < path->pathdata.Count)
01318         return InsufficientBuffer;
01319 
01320     memcpy(points, path->pathdata.Points, path->pathdata.Count * sizeof(GpPointF));
01321 
01322     return Ok;
01323 }
01324 
01325 GpStatus WINGDIPAPI GdipGetPathPointsI(GpPath *path, GpPoint* points, INT count)
01326 {
01327     GpStatus ret;
01328     GpPointF *ptf;
01329     INT i;
01330 
01331     TRACE("(%p, %p, %d)\n", path, points, count);
01332 
01333     if(count <= 0)
01334         return InvalidParameter;
01335 
01336     ptf = GdipAlloc(sizeof(GpPointF)*count);
01337     if(!ptf)    return OutOfMemory;
01338 
01339     ret = GdipGetPathPoints(path,ptf,count);
01340     if(ret == Ok)
01341         for(i = 0;i < count;i++){
01342             points[i].X = roundr(ptf[i].X);
01343             points[i].Y = roundr(ptf[i].Y);
01344         };
01345     GdipFree(ptf);
01346 
01347     return ret;
01348 }
01349 
01350 GpStatus WINGDIPAPI GdipGetPathTypes(GpPath *path, BYTE* types, INT count)
01351 {
01352     TRACE("(%p, %p, %d)\n", path, types, count);
01353 
01354     if(!path)
01355         return InvalidParameter;
01356 
01357     if(count < path->pathdata.Count)
01358         return InsufficientBuffer;
01359 
01360     memcpy(types, path->pathdata.Types, path->pathdata.Count);
01361 
01362     return Ok;
01363 }
01364 
01365 /* Windows expands the bounding box to the maximum possible bounding box
01366  * for a given pen.  For example, if a line join can extend past the point
01367  * it's joining by x units, the bounding box is extended by x units in every
01368  * direction (even though this is too conservative for most cases). */
01369 GpStatus WINGDIPAPI GdipGetPathWorldBounds(GpPath* path, GpRectF* bounds,
01370     GDIPCONST GpMatrix *matrix, GDIPCONST GpPen *pen)
01371 {
01372     GpPointF * points, temp_pts[4];
01373     INT count, i;
01374     REAL path_width = 1.0, width, height, temp, low_x, low_y, high_x, high_y;
01375 
01376     TRACE("(%p, %p, %p, %p)\n", path, bounds, matrix, pen);
01377 
01378     /* Matrix and pen can be null. */
01379     if(!path || !bounds)
01380         return InvalidParameter;
01381 
01382     /* If path is empty just return. */
01383     count = path->pathdata.Count;
01384     if(count == 0){
01385         bounds->X = bounds->Y = bounds->Width = bounds->Height = 0.0;
01386         return Ok;
01387     }
01388 
01389     points = path->pathdata.Points;
01390 
01391     low_x = high_x = points[0].X;
01392     low_y = high_y = points[0].Y;
01393 
01394     for(i = 1; i < count; i++){
01395         low_x = min(low_x, points[i].X);
01396         low_y = min(low_y, points[i].Y);
01397         high_x = max(high_x, points[i].X);
01398         high_y = max(high_y, points[i].Y);
01399     }
01400 
01401     width = high_x - low_x;
01402     height = high_y - low_y;
01403 
01404     /* This looks unusual but it's the only way I can imitate windows. */
01405     if(matrix){
01406         temp_pts[0].X = low_x;
01407         temp_pts[0].Y = low_y;
01408         temp_pts[1].X = low_x;
01409         temp_pts[1].Y = high_y;
01410         temp_pts[2].X = high_x;
01411         temp_pts[2].Y = high_y;
01412         temp_pts[3].X = high_x;
01413         temp_pts[3].Y = low_y;
01414 
01415         GdipTransformMatrixPoints((GpMatrix*)matrix, temp_pts, 4);
01416         low_x = temp_pts[0].X;
01417         low_y = temp_pts[0].Y;
01418 
01419         for(i = 1; i < 4; i++){
01420             low_x = min(low_x, temp_pts[i].X);
01421             low_y = min(low_y, temp_pts[i].Y);
01422         }
01423 
01424         temp = width;
01425         width = height * fabs(matrix->matrix[2]) + width * fabs(matrix->matrix[0]);
01426         height = height * fabs(matrix->matrix[3]) + temp * fabs(matrix->matrix[1]);
01427     }
01428 
01429     if(pen){
01430         path_width = pen->width / 2.0;
01431 
01432         if(count > 2)
01433             path_width = max(path_width,  pen->width * pen->miterlimit / 2.0);
01434         /* FIXME: this should probably also check for the startcap */
01435         if(pen->endcap & LineCapNoAnchor)
01436             path_width = max(path_width,  pen->width * 2.2);
01437 
01438         low_x -= path_width;
01439         low_y -= path_width;
01440         width += 2.0 * path_width;
01441         height += 2.0 * path_width;
01442     }
01443 
01444     bounds->X = low_x;
01445     bounds->Y = low_y;
01446     bounds->Width = width;
01447     bounds->Height = height;
01448 
01449     return Ok;
01450 }
01451 
01452 GpStatus WINGDIPAPI GdipGetPathWorldBoundsI(GpPath* path, GpRect* bounds,
01453     GDIPCONST GpMatrix *matrix, GDIPCONST GpPen *pen)
01454 {
01455     GpStatus ret;
01456     GpRectF boundsF;
01457 
01458     TRACE("(%p, %p, %p, %p)\n", path, bounds, matrix, pen);
01459 
01460     ret = GdipGetPathWorldBounds(path,&boundsF,matrix,pen);
01461 
01462     if(ret == Ok){
01463         bounds->X      = roundr(boundsF.X);
01464         bounds->Y      = roundr(boundsF.Y);
01465         bounds->Width  = roundr(boundsF.Width);
01466         bounds->Height = roundr(boundsF.Height);
01467     }
01468 
01469     return ret;
01470 }
01471 
01472 GpStatus WINGDIPAPI GdipGetPointCount(GpPath *path, INT *count)
01473 {
01474     TRACE("(%p, %p)\n", path, count);
01475 
01476     if(!path)
01477         return InvalidParameter;
01478 
01479     *count = path->pathdata.Count;
01480 
01481     return Ok;
01482 }
01483 
01484 GpStatus WINGDIPAPI GdipReversePath(GpPath* path)
01485 {
01486     INT i, count;
01487     INT start = 0; /* position in reversed path */
01488     GpPathData revpath;
01489 
01490     TRACE("(%p)\n", path);
01491 
01492     if(!path)
01493         return InvalidParameter;
01494 
01495     count = path->pathdata.Count;
01496 
01497     if(count == 0) return Ok;
01498 
01499     revpath.Points = GdipAlloc(sizeof(GpPointF)*count);
01500     revpath.Types  = GdipAlloc(sizeof(BYTE)*count);
01501     revpath.Count  = count;
01502     if(!revpath.Points || !revpath.Types){
01503         GdipFree(revpath.Points);
01504         GdipFree(revpath.Types);
01505         return OutOfMemory;
01506     }
01507 
01508     for(i = 0; i < count; i++){
01509 
01510         /* find next start point */
01511         if(path->pathdata.Types[count-i-1] == PathPointTypeStart){
01512             INT j;
01513             for(j = start; j <= i; j++){
01514                 revpath.Points[j] = path->pathdata.Points[count-j-1];
01515                 revpath.Types[j] = path->pathdata.Types[count-j-1];
01516             }
01517             /* mark start point */
01518             revpath.Types[start] = PathPointTypeStart;
01519             /* set 'figure' endpoint type */
01520             if(i-start > 1){
01521                 revpath.Types[i] = path->pathdata.Types[count-start-1] & ~PathPointTypePathTypeMask;
01522                 revpath.Types[i] |= revpath.Types[i-1];
01523             }
01524             else
01525                 revpath.Types[i] = path->pathdata.Types[start];
01526 
01527             start = i+1;
01528         }
01529     }
01530 
01531     memcpy(path->pathdata.Points, revpath.Points, sizeof(GpPointF)*count);
01532     memcpy(path->pathdata.Types,  revpath.Types,  sizeof(BYTE)*count);
01533 
01534     GdipFree(revpath.Points);
01535     GdipFree(revpath.Types);
01536 
01537     return Ok;
01538 }
01539 
01540 GpStatus WINGDIPAPI GdipIsOutlineVisiblePathPointI(GpPath* path, INT x, INT y,
01541     GpPen *pen, GpGraphics *graphics, BOOL *result)
01542 {
01543     TRACE("(%p, %d, %d, %p, %p, %p)\n", path, x, y, pen, graphics, result);
01544 
01545     return GdipIsOutlineVisiblePathPoint(path, x, y, pen, graphics, result);
01546 }
01547 
01548 GpStatus WINGDIPAPI GdipIsOutlineVisiblePathPoint(GpPath* path, REAL x, REAL y,
01549     GpPen *pen, GpGraphics *graphics, BOOL *result)
01550 {
01551     static int calls;
01552 
01553     TRACE("(%p,%0.2f,%0.2f,%p,%p,%p)\n", path, x, y, pen, graphics, result);
01554 
01555     if(!path || !pen)
01556         return InvalidParameter;
01557 
01558     if(!(calls++))
01559         FIXME("not implemented\n");
01560 
01561     return NotImplemented;
01562 }
01563 
01564 GpStatus WINGDIPAPI GdipIsVisiblePathPointI(GpPath* path, INT x, INT y, GpGraphics *graphics, BOOL *result)
01565 {
01566     TRACE("(%p, %d, %d, %p, %p)\n", path, x, y, graphics, result);
01567 
01568     return GdipIsVisiblePathPoint(path, x, y, graphics, result);
01569 }
01570 
01571 /*****************************************************************************
01572  * GdipIsVisiblePathPoint [GDIPLUS.@]
01573  */
01574 GpStatus WINGDIPAPI GdipIsVisiblePathPoint(GpPath* path, REAL x, REAL y, GpGraphics *graphics, BOOL *result)
01575 {
01576     GpRegion *region;
01577     HRGN hrgn;
01578     GpStatus status;
01579 
01580     if(!path || !result) return InvalidParameter;
01581 
01582     status = GdipCreateRegionPath(path, &region);
01583     if(status != Ok)
01584         return status;
01585 
01586     status = GdipGetRegionHRgn(region, graphics, &hrgn);
01587     if(status != Ok){
01588         GdipDeleteRegion(region);
01589         return status;
01590     }
01591 
01592     *result = PtInRegion(hrgn, roundr(x), roundr(y));
01593 
01594     DeleteObject(hrgn);
01595     GdipDeleteRegion(region);
01596 
01597     return Ok;
01598 }
01599 
01600 GpStatus WINGDIPAPI GdipStartPathFigure(GpPath *path)
01601 {
01602     TRACE("(%p)\n", path);
01603 
01604     if(!path)
01605         return InvalidParameter;
01606 
01607     path->newfigure = TRUE;
01608 
01609     return Ok;
01610 }
01611 
01612 GpStatus WINGDIPAPI GdipResetPath(GpPath *path)
01613 {
01614     TRACE("(%p)\n", path);
01615 
01616     if(!path)
01617         return InvalidParameter;
01618 
01619     path->pathdata.Count = 0;
01620     path->newfigure = TRUE;
01621     path->fill = FillModeAlternate;
01622 
01623     return Ok;
01624 }
01625 
01626 GpStatus WINGDIPAPI GdipSetPathFillMode(GpPath *path, GpFillMode fill)
01627 {
01628     TRACE("(%p, %d)\n", path, fill);
01629 
01630     if(!path)
01631         return InvalidParameter;
01632 
01633     path->fill = fill;
01634 
01635     return Ok;
01636 }
01637 
01638 GpStatus WINGDIPAPI GdipTransformPath(GpPath *path, GpMatrix *matrix)
01639 {
01640     TRACE("(%p, %p)\n", path, matrix);
01641 
01642     if(!path)
01643         return InvalidParameter;
01644 
01645     if(path->pathdata.Count == 0)
01646         return Ok;
01647 
01648     return GdipTransformMatrixPoints(matrix, path->pathdata.Points,
01649                                      path->pathdata.Count);
01650 }
01651 
01652 GpStatus WINGDIPAPI GdipWarpPath(GpPath *path, GpMatrix* matrix,
01653     GDIPCONST GpPointF *points, INT count, REAL x, REAL y, REAL width,
01654     REAL height, WarpMode warpmode, REAL flatness)
01655 {
01656     FIXME("(%p,%p,%p,%i,%0.2f,%0.2f,%0.2f,%0.2f,%i,%0.2f)\n", path, matrix,
01657         points, count, x, y, width, height, warpmode, flatness);
01658 
01659     return NotImplemented;
01660 }
01661 
01662 static void add_bevel_point(const GpPointF *endpoint, const GpPointF *nextpoint,
01663     GpPen *pen, int right_side, path_list_node_t **last_point)
01664 {
01665     REAL segment_dy = nextpoint->Y-endpoint->Y;
01666     REAL segment_dx = nextpoint->X-endpoint->X;
01667     REAL segment_length = sqrtf(segment_dy*segment_dy + segment_dx*segment_dx);
01668     REAL distance = pen->width/2.0;
01669     REAL bevel_dx, bevel_dy;
01670 
01671     if (right_side)
01672     {
01673         bevel_dx = -distance * segment_dy / segment_length;
01674         bevel_dy = distance * segment_dx / segment_length;
01675     }
01676     else
01677     {
01678         bevel_dx = distance * segment_dy / segment_length;
01679         bevel_dy = -distance * segment_dx / segment_length;
01680     }
01681 
01682     *last_point = add_path_list_node(*last_point, endpoint->X + bevel_dx,
01683         endpoint->Y + bevel_dy, PathPointTypeLine);
01684 }
01685 
01686 static void widen_joint(const GpPointF *p1, const GpPointF *p2, const GpPointF *p3,
01687     GpPen* pen, path_list_node_t **last_point)
01688 {
01689     switch (pen->join)
01690     {
01691     default:
01692     case LineJoinBevel:
01693         add_bevel_point(p2, p1, pen, 1, last_point);
01694         add_bevel_point(p2, p3, pen, 0, last_point);
01695         break;
01696     }
01697 }
01698 
01699 static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint,
01700     GpPen *pen, GpLineCap cap, GpCustomLineCap *custom, int add_first_points,
01701     int add_last_point, path_list_node_t **last_point)
01702 {
01703     switch (cap)
01704     {
01705     default:
01706     case LineCapFlat:
01707         if (add_first_points)
01708             add_bevel_point(endpoint, nextpoint, pen, 1, last_point);
01709         if (add_last_point)
01710             add_bevel_point(endpoint, nextpoint, pen, 0, last_point);
01711         break;
01712     }
01713 }
01714 
01715 static void widen_open_figure(GpPath *path, GpPen *pen, int start, int end,
01716     path_list_node_t **last_point)
01717 {
01718     int i;
01719 
01720     if (end <= start)
01721         return;
01722 
01723     widen_cap(&path->pathdata.Points[start], &path->pathdata.Points[start+1],
01724         pen, pen->startcap, pen->customstart, FALSE, TRUE, last_point);
01725 
01726     (*last_point)->type = PathPointTypeStart;
01727 
01728     for (i=start+1; i<end; i++)
01729         widen_joint(&path->pathdata.Points[i-1], &path->pathdata.Points[i],
01730             &path->pathdata.Points[i+1], pen, last_point);
01731 
01732     widen_cap(&path->pathdata.Points[end], &path->pathdata.Points[end-1],
01733         pen, pen->endcap, pen->customend, TRUE, TRUE, last_point);
01734 
01735     for (i=end-1; i>start; i--)
01736         widen_joint(&path->pathdata.Points[i+1], &path->pathdata.Points[i],
01737             &path->pathdata.Points[i-1], pen, last_point);
01738 
01739     widen_cap(&path->pathdata.Points[start], &path->pathdata.Points[start+1],
01740         pen, pen->startcap, pen->customstart, TRUE, FALSE, last_point);
01741 
01742     (*last_point)->type |= PathPointTypeCloseSubpath;
01743 }
01744 
01745 static void widen_closed_figure(GpPath *path, GpPen *pen, int start, int end,
01746     path_list_node_t **last_point)
01747 {
01748     int i;
01749     path_list_node_t *prev_point;
01750 
01751     if (end <= start+1)
01752         return;
01753 
01754     /* left outline */
01755     prev_point = *last_point;
01756 
01757     widen_joint(&path->pathdata.Points[end], &path->pathdata.Points[start],
01758         &path->pathdata.Points[start+1], pen, last_point);
01759 
01760     for (i=start+1; i<end; i++)
01761         widen_joint(&path->pathdata.Points[i-1], &path->pathdata.Points[i],
01762             &path->pathdata.Points[i+1], pen, last_point);
01763 
01764     widen_joint(&path->pathdata.Points[end-1], &path->pathdata.Points[end],
01765         &path->pathdata.Points[start], pen, last_point);
01766 
01767     prev_point->next->type = PathPointTypeStart;
01768     (*last_point)->type |= PathPointTypeCloseSubpath;
01769 
01770     /* right outline */
01771     prev_point = *last_point;
01772 
01773     widen_joint(&path->pathdata.Points[start], &path->pathdata.Points[end],
01774         &path->pathdata.Points[end-1], pen, last_point);
01775 
01776     for (i=end-1; i>start; i--)
01777         widen_joint(&path->pathdata.Points[i+1], &path->pathdata.Points[i],
01778             &path->pathdata.Points[i-1], pen, last_point);
01779 
01780     widen_joint(&path->pathdata.Points[start+1], &path->pathdata.Points[start],
01781         &path->pathdata.Points[end], pen, last_point);
01782 
01783     prev_point->next->type = PathPointTypeStart;
01784     (*last_point)->type |= PathPointTypeCloseSubpath;
01785 }
01786 
01787 GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
01788     REAL flatness)
01789 {
01790     GpPath *flat_path=NULL;
01791     GpStatus status;
01792     path_list_node_t *points=NULL, *last_point=NULL;
01793     int i, subpath_start=0, new_length;
01794     BYTE type;
01795 
01796     TRACE("(%p,%p,%p,%0.2f)\n", path, pen, matrix, flatness);
01797 
01798     if (!path || !pen)
01799         return InvalidParameter;
01800 
01801     if (path->pathdata.Count <= 1)
01802         return OutOfMemory;
01803 
01804     status = GdipClonePath(path, &flat_path);
01805 
01806     if (status == Ok)
01807         status = GdipFlattenPath(flat_path, matrix, flatness);
01808 
01809     if (status == Ok && !init_path_list(&points, 314.0, 22.0))
01810         status = OutOfMemory;
01811 
01812     if (status == Ok)
01813     {
01814         last_point = points;
01815 
01816         if (pen->endcap != LineCapFlat)
01817             FIXME("unimplemented end cap %x\n", pen->endcap);
01818 
01819         if (pen->startcap != LineCapFlat)
01820             FIXME("unimplemented start cap %x\n", pen->startcap);
01821 
01822         if (pen->dashcap != DashCapFlat)
01823             FIXME("unimplemented dash cap %d\n", pen->dashcap);
01824 
01825         if (pen->join != LineJoinBevel)
01826             FIXME("unimplemented line join %d\n", pen->join);
01827 
01828         if (pen->dash != DashStyleSolid)
01829             FIXME("unimplemented dash style %d\n", pen->dash);
01830 
01831         if (pen->align != PenAlignmentCenter)
01832             FIXME("unimplemented pen alignment %d\n", pen->align);
01833 
01834         for (i=0; i < flat_path->pathdata.Count; i++)
01835         {
01836             type = flat_path->pathdata.Types[i];
01837 
01838             if ((type&PathPointTypePathTypeMask) == PathPointTypeStart)
01839                 subpath_start = i;
01840 
01841             if ((type&PathPointTypeCloseSubpath) == PathPointTypeCloseSubpath)
01842             {
01843                 widen_closed_figure(flat_path, pen, subpath_start, i, &last_point);
01844             }
01845             else if (i == flat_path->pathdata.Count-1 ||
01846                 (flat_path->pathdata.Types[i+1]&PathPointTypePathTypeMask) == PathPointTypeStart)
01847             {
01848                 widen_open_figure(flat_path, pen, subpath_start, i, &last_point);
01849             }
01850         }
01851 
01852         new_length = path_list_count(points)-1;
01853 
01854         if (!lengthen_path(path, new_length))
01855             status = OutOfMemory;
01856     }
01857 
01858     if (status == Ok)
01859     {
01860         path->pathdata.Count = new_length;
01861 
01862         last_point = points->next;
01863         for (i = 0; i < new_length; i++)
01864         {
01865             path->pathdata.Points[i] = last_point->pt;
01866             path->pathdata.Types[i] = last_point->type;
01867             last_point = last_point->next;
01868         }
01869 
01870         path->fill = FillModeWinding;
01871     }
01872 
01873     free_path_list(points);
01874 
01875     GdipDeletePath(flat_path);
01876 
01877     return status;
01878 }
01879 
01880 GpStatus WINGDIPAPI GdipAddPathRectangle(GpPath *path, REAL x, REAL y,
01881     REAL width, REAL height)
01882 {
01883     GpPath *backup;
01884     GpPointF ptf[2];
01885     GpStatus retstat;
01886     BOOL old_new;
01887 
01888     TRACE("(%p, %.2f, %.2f, %.2f, %.2f)\n", path, x, y, width, height);
01889 
01890     if(!path)
01891         return InvalidParameter;
01892 
01893     /* make a backup copy of path data */
01894     if((retstat = GdipClonePath(path, &backup)) != Ok)
01895         return retstat;
01896 
01897     /* rectangle should start as new path */
01898     old_new = path->newfigure;
01899     path->newfigure = TRUE;
01900     if((retstat = GdipAddPathLine(path,x,y,x+width,y)) != Ok){
01901         path->newfigure = old_new;
01902         goto fail;
01903     }
01904 
01905     ptf[0].X = x+width;
01906     ptf[0].Y = y+height;
01907     ptf[1].X = x;
01908     ptf[1].Y = y+height;
01909 
01910     if((retstat = GdipAddPathLine2(path, ptf, 2)) != Ok)  goto fail;
01911     path->pathdata.Types[path->pathdata.Count-1] |= PathPointTypeCloseSubpath;
01912 
01913     /* free backup */
01914     GdipDeletePath(backup);
01915     return Ok;
01916 
01917 fail:
01918     /* reverting */
01919     GdipFree(path->pathdata.Points);
01920     GdipFree(path->pathdata.Types);
01921     memcpy(path, backup, sizeof(*path));
01922     GdipFree(backup);
01923 
01924     return retstat;
01925 }
01926 
01927 GpStatus WINGDIPAPI GdipAddPathRectangleI(GpPath *path, INT x, INT y,
01928     INT width, INT height)
01929 {
01930     TRACE("(%p, %d, %d, %d, %d)\n", path, x, y, width, height);
01931 
01932     return GdipAddPathRectangle(path,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
01933 }
01934 
01935 GpStatus WINGDIPAPI GdipAddPathRectangles(GpPath *path, GDIPCONST GpRectF *rects, INT count)
01936 {
01937     GpPath *backup;
01938     GpStatus retstat;
01939     INT i;
01940 
01941     TRACE("(%p, %p, %d)\n", path, rects, count);
01942 
01943     /* count == 0 - verified condition  */
01944     if(!path || !rects || count == 0)
01945         return InvalidParameter;
01946 
01947     if(count < 0)
01948         return OutOfMemory;
01949 
01950     /* make a backup copy */
01951     if((retstat = GdipClonePath(path, &backup)) != Ok)
01952         return retstat;
01953 
01954     for(i = 0; i < count; i++){
01955         if((retstat = GdipAddPathRectangle(path,rects[i].X,rects[i].Y,rects[i].Width,rects[i].Height)) != Ok)
01956             goto fail;
01957     }
01958 
01959     /* free backup */
01960     GdipDeletePath(backup);
01961     return Ok;
01962 
01963 fail:
01964     /* reverting */
01965     GdipFree(path->pathdata.Points);
01966     GdipFree(path->pathdata.Types);
01967     memcpy(path, backup, sizeof(*path));
01968     GdipFree(backup);
01969 
01970     return retstat;
01971 }
01972 
01973 GpStatus WINGDIPAPI GdipAddPathRectanglesI(GpPath *path, GDIPCONST GpRect *rects, INT count)
01974 {
01975     GpRectF *rectsF;
01976     GpStatus retstat;
01977     INT i;
01978 
01979     TRACE("(%p, %p, %d)\n", path, rects, count);
01980 
01981     if(!rects || count == 0)
01982         return InvalidParameter;
01983 
01984     if(count < 0)
01985         return OutOfMemory;
01986 
01987     rectsF = GdipAlloc(sizeof(GpRectF)*count);
01988 
01989     for(i = 0;i < count;i++){
01990         rectsF[i].X      = (REAL)rects[i].X;
01991         rectsF[i].Y      = (REAL)rects[i].Y;
01992         rectsF[i].Width  = (REAL)rects[i].Width;
01993         rectsF[i].Height = (REAL)rects[i].Height;
01994     }
01995 
01996     retstat = GdipAddPathRectangles(path, rectsF, count);
01997     GdipFree(rectsF);
01998 
01999     return retstat;
02000 }
02001 
02002 GpStatus WINGDIPAPI GdipSetPathMarker(GpPath* path)
02003 {
02004     INT count;
02005 
02006     TRACE("(%p)\n", path);
02007 
02008     if(!path)
02009         return InvalidParameter;
02010 
02011     count = path->pathdata.Count;
02012 
02013     /* set marker flag */
02014     if(count > 0)
02015         path->pathdata.Types[count-1] |= PathPointTypePathMarker;
02016 
02017     return Ok;
02018 }
02019 
02020 GpStatus WINGDIPAPI GdipClearPathMarkers(GpPath* path)
02021 {
02022     INT count;
02023     INT i;
02024 
02025     TRACE("(%p)\n", path);
02026 
02027     if(!path)
02028         return InvalidParameter;
02029 
02030     count = path->pathdata.Count;
02031 
02032     for(i = 0; i < count - 1; i++){
02033         path->pathdata.Types[i] &= ~PathPointTypePathMarker;
02034     }
02035 
02036     return Ok;
02037 }
02038 
02039 GpStatus WINGDIPAPI GdipWindingModeOutline(GpPath *path, GpMatrix *matrix, REAL flatness)
02040 {
02041    FIXME("stub: %p, %p, %.2f\n", path, matrix, flatness);
02042    return NotImplemented;
02043 }

Generated on Sun May 27 2012 04:23:36 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.