Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygengraphicspath.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, ®ion); 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
1.7.6.1
|