ReactOS 0.4.17-dev-218-g5635d24
graphicspath.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2007 Google (Evan Stade)
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 *
18 */
19
20#include <stdarg.h>
21#include <math.h>
22
23#include "windef.h"
24#include "winbase.h"
25#include "winuser.h"
26#include "wingdi.h"
27
28#include "objbase.h"
29
30#include "gdiplus.h"
31#include "gdiplus_private.h"
32#include "wine/debug.h"
33
35
36#define SQRT3 1.73205080757
37
41 BYTE type; /* PathPointTypeStart or PathPointTypeLine */
43};
44
45/* init list */
47{
48 *node = calloc(1, sizeof(path_list_node_t));
49 if(!*node)
50 return FALSE;
51
52 (*node)->pt.X = x;
53 (*node)->pt.Y = y;
54 (*node)->type = PathPointTypeStart;
55 (*node)->next = NULL;
56
57 return TRUE;
58}
59
60/* free all nodes including argument */
62{
64
65 while(n){
66 n = n->next;
67 free(node);
68 node = n;
69 }
70}
71
72/* Add a node after 'node' */
73/*
74 * Returns
75 * pointer on success
76 * NULL on allocation problems
77 */
79{
81
82 new = calloc(1, sizeof(path_list_node_t));
83 if(!new)
84 return NULL;
85
86 new->pt.X = x;
87 new->pt.Y = y;
88 new->type = type;
89 new->next = node->next;
90 node->next = new;
91
92 return new;
93}
94
95/* returns element count */
97{
98 INT count = 0;
99
100 while(node)
101 {
102 ++count;
103 node = node->next;
104 }
105
106 return count;
107}
108
110{
112 GpPointF *Points;
113 BYTE *Types;
114
115 if (count == 0)
116 {
117 path->pathdata.Count = count;
118 return TRUE;
119 }
120
121 Points = calloc(count, sizeof(GpPointF));
122 Types = calloc(1, count);
123
124 if (!Points || !Types)
125 {
126 free(Points);
127 free(Types);
128 return FALSE;
129 }
130
131 for(i = 0; i < count; i++){
132 Points[i] = node->pt;
133 Types[i] = node->type;
134 node = node->next;
135 }
136
137 free(path->pathdata.Points);
138 free(path->pathdata.Types);
139
140 path->pathdata.Points = Points;
141 path->pathdata.Types = Types;
142 path->pathdata.Count = count;
143 path->datalen = count;
144
145 return TRUE;
146}
147
149{
156 struct list entry;
157};
158
160{
161 struct flatten_bezier_job *job = malloc(sizeof(struct flatten_bezier_job));
162 if (!job)
163 return FALSE;
164
165 job->start = start;
166 job->x2 = x2;
167 job->y2 = y2;
168 job->x3 = x3;
169 job->y3 = y3;
170 job->end = end;
171
172 list_add_after(jobs, &job->entry);
173 return TRUE;
174}
175
176/* GdipFlattenPath helper */
177/*
178 * Used to recursively flatten single Bezier curve
179 * Parameters:
180 * - start : pointer to start point node;
181 * - (x2, y2): first control point;
182 * - (x3, y3): second control point;
183 * - end : pointer to end point node
184 * - flatness: admissible error of linear approximation.
185 *
186 * Return value:
187 * TRUE : success
188 * FALSE: out of memory
189 *
190 * TODO: used quality criteria should be revised to match native as
191 * closer as possible.
192 */
194 path_list_node_t *end, REAL flatness)
195{
196 /* this 5 middle points with start/end define to half-curves */
197 GpPointF mp[5];
198 GpPointF pt, pt_st;
200 REAL area_triangle, distance_start_end;
201 BOOL ret = TRUE;
202 struct list jobs;
204
205 list_init( &jobs );
206 flatten_bezier_add(&jobs, start, x2, y2, x3, y3, end);
208 {
209 start = current->start;
210 x2 = current->x2;
211 y2 = current->y2;
212 x3 = current->x3;
213 y3 = current->y3;
214 end = current->end;
215
216 /* middle point between control points */
217 pt.X = (x2 + x3) / 2.0;
218 pt.Y = (y2 + y3) / 2.0;
219
220 /* calculate bezier curve middle points == new control points */
221 mp[0].X = (start->pt.X + x2) / 2.0;
222 mp[0].Y = (start->pt.Y + y2) / 2.0;
223 mp[1].X = (mp[0].X + pt.X) / 2.0;
224 mp[1].Y = (mp[0].Y + pt.Y) / 2.0;
225 mp[4].X = (end->pt.X + x3) / 2.0;
226 mp[4].Y = (end->pt.Y + y3) / 2.0;
227 mp[3].X = (mp[4].X + pt.X) / 2.0;
228 mp[3].Y = (mp[4].Y + pt.Y) / 2.0;
229
230 /* middle point between new control points */
231 mp[2].X = (mp[1].X + mp[3].X) / 2.0;
232 mp[2].Y = (mp[1].Y + mp[3].Y) / 2.0;
233
234 pt = end->pt;
235 pt_st = start->pt;
236
237 /* Test for closely spaced points that don't need to be flattened
238 * Also avoids limited-precision errors in flatness check
239 */
240 if((fabs(pt.X - mp[2].X) + fabs(pt.Y - mp[2].Y) +
241 fabs(pt_st.X - mp[2].X) + fabs(pt_st.Y - mp[2].Y) ) <= flatness * 0.5)
242 continue;
243
244 /* check flatness as a half of distance between middle point and a linearized path
245 * formula for distance point from line for point (x0, y0) and line (x1, y1) (x2, y2)
246 * is defined as (area_triangle / distance_start_end):
247 * | (x2 - x1) * (y1 - y0) - (x1 - x0) * (y2 - y1) / sqrt( (x2 - x1)^2 + (y2 - y1)^2 ) |
248 * Here rearranged to avoid division and simplified:
249 * x0(y2 - y1) + y0(x1 - x2) + (x2*y1 - x1*y2)
250 */
251 area_triangle = (pt.Y - pt_st.Y)*mp[2].X + (pt_st.X - pt.X)*mp[2].Y + (pt_st.Y*pt.X - pt_st.X*pt.Y);
252 distance_start_end = hypotf(pt.Y - pt_st.Y, pt_st.X - pt.X);
253 if(fabs(area_triangle) <= (0.5 * flatness * distance_start_end)){
254 continue;
255 }
256 else
257 /* add a middle point */
258 if(!(node = add_path_list_node(start, mp[2].X, mp[2].Y, PathPointTypeLine)))
259 {
260 ret = FALSE;
261 break;
262 };
263
264 /* do the same with halves */
265 if (!flatten_bezier_add(&current->entry, node, mp[3].X, mp[3].Y, mp[4].X, mp[4].Y, end))
266 break;
267 if (!flatten_bezier_add(&current->entry, start, mp[0].X, mp[0].Y, mp[1].X, mp[1].Y, node))
268 break;
269 }
270
271 /* Cleanup */
273 {
274 list_remove(&current->entry);
275 free(current);
276 }
277
278 return ret;
279}
280
281/* GdipAddPath* helper
282 *
283 * Several GdipAddPath functions are expected to add onto an open figure.
284 * So if the first point being added is an exact match to the last point
285 * of the existing line, that point should not be added.
286 *
287 * Parameters:
288 * path : path to which points should be added
289 * points : array of points to add
290 * count : number of points to add (at least 1)
291 * type : type of the points being added
292 *
293 * Return value:
294 * OutOfMemory : out of memory, could not lengthen path
295 * Ok : success
296 */
298{
299 INT insert_index = path->pathdata.Count;
300 BYTE first_point_type = (path->newfigure ? PathPointTypeStart : PathPointTypeLine);
301
302 if(!path->newfigure &&
303 path->pathdata.Points[insert_index-1].X == points[0].X &&
304 path->pathdata.Points[insert_index-1].Y == points[0].Y)
305 {
306 points++;
307 count--;
308 first_point_type = type;
309 }
310
311 if(!count)
312 return Ok;
313
315 return OutOfMemory;
316
317 memcpy(path->pathdata.Points + insert_index, points, sizeof(GpPointF)*count);
318 path->pathdata.Types[insert_index] = first_point_type;
319 memset(path->pathdata.Types + insert_index + 1, type, count - 1);
320
321 path->newfigure = FALSE;
322 path->pathdata.Count += count;
323
324 return Ok;
325}
326
327/*******************************************************************************
328 * GdipAddPathArc [GDIPLUS.1]
329 *
330 * Add an elliptical arc to the given path.
331 *
332 * PARAMS
333 * path [I/O] Path that the arc is appended to
334 * x [I] X coordinate of the boundary rectangle
335 * y [I] Y coordinate of the boundary rectangle
336 * width [I] Width of the boundary rectangle
337 * height [I] Height of the boundary rectangle
338 * startAngle [I] Starting angle of the arc, clockwise
339 * sweepAngle [I] Angle of the arc, clockwise
340 *
341 * RETURNS
342 * InvalidParameter If the given path is invalid
343 * OutOfMemory If memory allocation fails, i.e. the path cannot be lengthened
344 * Ok If everything works out as expected
345 *
346 * NOTES
347 * This functions takes the newfigure value of the given path into account,
348 * i.e. the arc is connected to the end of the given path if it was set to
349 * FALSE, otherwise the arc's first point gets the PathPointTypeStart value.
350 * In both cases, the value of newfigure of the given path is FALSE
351 * afterwards.
352 */
354 REAL height, REAL startAngle, REAL sweepAngle)
355{
358 INT count;
359
360 TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n",
361 path, x, y, width, height, startAngle, sweepAngle);
362
363 if(!path || width <= 0.0f || height <= 0.0f)
364 return InvalidParameter;
365
366 count = arc2polybezier(NULL, x, y, width, height, startAngle, sweepAngle);
367 if(count == 0)
368 return Ok;
369
370 points = malloc(sizeof(GpPointF) * count);
371 if(!points)
372 return OutOfMemory;
373
374 arc2polybezier(points, x, y, width, height, startAngle, sweepAngle);
375
377
378 free(points);
379 return status;
380}
381
382/*******************************************************************************
383 * GdipAddPathArcI [GDUPLUS.2]
384 *
385 * See GdipAddPathArc
386 */
388 INT y2, REAL startAngle, REAL sweepAngle)
389{
390 TRACE("(%p, %d, %d, %d, %d, %.2f, %.2f)\n",
391 path, x1, y1, x2, y2, startAngle, sweepAngle);
392
393 return GdipAddPathArc(path,(REAL)x1,(REAL)y1,(REAL)x2,(REAL)y2,startAngle,sweepAngle);
394}
395
398{
399 PointF points[4];
400
401 TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n",
402 path, x1, y1, x2, y2, x3, y3, x4, y4);
403
404 if(!path)
405 return InvalidParameter;
406
407 points[0].X = x1;
408 points[0].Y = y1;
409 points[1].X = x2;
410 points[1].Y = y2;
411 points[2].X = x3;
412 points[2].Y = y3;
413 points[3].X = x4;
414 points[3].Y = y4;
415
417}
418
420 INT y2, INT x3, INT y3, INT x4, INT y4)
421{
422 TRACE("(%p, %d, %d, %d, %d, %d, %d, %d, %d)\n",
423 path, x1, y1, x2, y2, x3, y3, x4, y4);
424
426 (REAL)x4,(REAL)y4);
427}
428
430 INT count)
431{
432 TRACE("(%p, %p, %d)\n", path, points, count);
433
434 if(!path || !points || ((count - 1) % 3))
435 return InvalidParameter;
436
438}
439
441 INT count)
442{
443 GpPointF *ptsF;
445 INT i;
446
447 TRACE("(%p, %p, %d)\n", path, points, count);
448
449 if(!points || ((count - 1) % 3))
450 return InvalidParameter;
451
452 ptsF = malloc(sizeof(GpPointF) * count);
453 if(!ptsF)
454 return OutOfMemory;
455
456 for(i = 0; i < count; i++){
457 ptsF[i].X = (REAL)points[i].X;
458 ptsF[i].Y = (REAL)points[i].Y;
459 }
460
462 free(ptsF);
463
464 return ret;
465}
466
468 INT count)
469{
470 TRACE("(%p, %p, %d)\n", path, points, count);
471
473}
474
476 INT count)
477{
478 TRACE("(%p, %p, %d)\n", path, points, count);
479
481}
482
484 INT count, REAL tension)
485{
486 INT i, len_pt = (count + 1)*3-2;
487 GpPointF *pt;
488 GpPointF *pts;
489 REAL x1, x2, y1, y2;
491
492 TRACE("(%p, %p, %d, %.2f)\n", path, points, count, tension);
493
494 if(!path || !points || count <= 1)
495 return InvalidParameter;
496
497 pt = malloc(len_pt * sizeof(GpPointF));
498 pts = malloc((count + 1) * sizeof(GpPointF));
499 if(!pt || !pts){
500 free(pt);
501 free(pts);
502 return OutOfMemory;
503 }
504
505 /* copy source points to extend with the last one */
506 memcpy(pts, points, sizeof(GpPointF)*count);
507 pts[count] = pts[0];
508
509 tension = tension * TENSION_CONST;
510
511 for(i = 0; i < count-1; i++){
512 calc_curve_bezier(&(pts[i]), tension, &x1, &y1, &x2, &y2);
513
514 pt[3*i+2].X = x1;
515 pt[3*i+2].Y = y1;
516 pt[3*i+3].X = pts[i+1].X;
517 pt[3*i+3].Y = pts[i+1].Y;
518 pt[3*i+4].X = x2;
519 pt[3*i+4].Y = y2;
520 }
521
522 /* points [len_pt-2] and [0] are calculated
523 separately to connect splines properly */
524 pts[0] = points[count-1];
525 pts[1] = points[0]; /* equals to start and end of a resulting path */
526 pts[2] = points[1];
527
528 calc_curve_bezier(pts, tension, &x1, &y1, &x2, &y2);
529 pt[len_pt-2].X = x1;
530 pt[len_pt-2].Y = y1;
531 pt[0].X = pts[1].X;
532 pt[0].Y = pts[1].Y;
533 pt[1].X = x2;
534 pt[1].Y = y2;
535 /* close path */
536 pt[len_pt-1].X = pt[0].X;
537 pt[len_pt-1].Y = pt[0].Y;
538
540
541 /* close figure */
542 if(stat == Ok){
543 path->pathdata.Types[path->pathdata.Count - 1] |= PathPointTypeCloseSubpath;
544 path->newfigure = TRUE;
545 }
546
547 free(pts);
548 free(pt);
549
550 return stat;
551}
552
554 INT count, REAL tension)
555{
556 GpPointF *ptf;
557 INT i;
559
560 TRACE("(%p, %p, %d, %.2f)\n", path, points, count, tension);
561
562 if(!path || !points || count <= 1)
563 return InvalidParameter;
564
565 ptf = malloc(sizeof(GpPointF) * count);
566 if(!ptf)
567 return OutOfMemory;
568
569 for(i = 0; i < count; i++){
570 ptf[i].X = (REAL)points[i].X;
571 ptf[i].Y = (REAL)points[i].Y;
572 }
573
574 stat = GdipAddPathClosedCurve2(path, ptf, count, tension);
575
576 free(ptf);
577
578 return stat;
579}
580
582{
583 TRACE("(%p, %p, %d)\n", path, points, count);
584
585 return GdipAddPathCurve3(path, points, count, 0, count - 1, 0.5);
586}
587
589{
590 TRACE("(%p, %p, %d)\n", path, points, count);
591
592 return GdipAddPathCurve3I(path, points, count, 0, count - 1, 0.5);
593}
594
596 INT count, INT offset, INT nseg, REAL tension)
597{
598 INT i, len_pt = nseg * 3 + 1;
599 GpPointF *pt;
600 REAL x1, x2, y1, y2;
602 TRACE("(%p, %p, %d, %d, %d, %.2f)\n", path, points, count, offset, nseg, tension);
603
604 if(!path || !points || offset + 1 >= count || count - offset < nseg + 1 || nseg < 1)
605 return InvalidParameter;
606
607 pt = calloc(len_pt, sizeof(GpPointF));
608 if(!pt)
609 return OutOfMemory;
610
611 tension = tension * TENSION_CONST;
612
613 pt[0].X = points[offset].X;
614 pt[0].Y = points[offset].Y;
615 if (offset > 0)
616 {
617 calc_curve_bezier(&(points[offset - 1]), tension, &x1, &y1, &x2, &y2);
618 pt[1].X = x2;
619 pt[1].Y = y2;
620 }
621 else
622 {
624 points[offset + 1].X, points[offset + 1].Y, tension, &x1, &y1);
625 pt[1].X = x1;
626 pt[1].Y = y1;
627 }
628
629 for (i = 0; i < nseg - 1; i++){
630 calc_curve_bezier(&(points[offset + i]), tension, &x1, &y1, &x2, &y2);
631
632 pt[3*i+2].X = x1;
633 pt[3*i+2].Y = y1;
634 pt[3*i+3].X = points[offset + i + 1].X;
635 pt[3*i+3].Y = points[offset + i + 1].Y;
636 pt[3*i+4].X = x2;
637 pt[3*i+4].Y = y2;
638 }
639
640 if (offset + nseg + 1 < count)
641 /* If there are one more point in points table then use it for curve calculation */
642 calc_curve_bezier(&(points[offset + nseg - 1]), tension, &x1, &y1, &x2, &y2);
643 else
645 points[offset + nseg - 1].X, points[offset + nseg - 1].Y, tension, &x1, &y1);
646
647 pt[len_pt-2].X = x1;
648 pt[len_pt-2].Y = y1;
649 pt[len_pt-1].X = points[offset + nseg].X;
650 pt[len_pt-1].Y = points[offset + nseg].Y;
651
653
654 free(pt);
655
656 return stat;
657}
658
660 INT count, REAL tension)
661{
662 TRACE("(%p, %p, %d, %.2f)\n", path, points, count, tension);
663
664 return GdipAddPathCurve3I(path, points, count, 0, count - 1, tension);
665}
666
668 REAL tension)
669{
670 TRACE("(%p, %p, %d, %.2f)\n", path, points, count, tension);
671
672 return GdipAddPathCurve3(path, points, count, 0, count - 1, tension);
673}
674
676 INT count, INT offset, INT nseg, REAL tension)
677{
678 GpPointF *ptf;
679 INT i;
681
682 TRACE("(%p, %p, %d, %d, %d, %.2f)\n", path, points, count, offset, nseg, tension);
683
684 if(!path || !points || offset + 1 >= count || count - offset < nseg + 1 || nseg < 1)
685 return InvalidParameter;
686
687 ptf = malloc(sizeof(GpPointF) * count);
688 if(!ptf)
689 return OutOfMemory;
690
691 for(i = 0; i < count; i++) {
692 ptf[i].X = (REAL)points[i].X;
693 ptf[i].Y = (REAL)points[i].Y;
694 }
695
696 stat = GdipAddPathCurve3(path, ptf, count, offset, nseg, tension);
697
698 free(ptf);
699
700 return stat;
701}
702
704 REAL height)
705{
706 INT old_count, numpts;
707
708 TRACE("(%p, %.2f, %.2f, %.2f, %.2f)\n", path, x, y, width, height);
709
710 if(!path)
711 return InvalidParameter;
712
714 return OutOfMemory;
715
716 old_count = path->pathdata.Count;
717 if((numpts = arc2polybezier(&path->pathdata.Points[old_count], x, y, width,
718 height, 0.0, 360.0)) != MAX_ARC_PTS){
719 ERR("expected %d points but got %d\n", MAX_ARC_PTS, numpts);
720 return GenericError;
721 }
722
723 memset(&path->pathdata.Types[old_count + 1], PathPointTypeBezier,
724 MAX_ARC_PTS - 1);
725
726 /* An ellipse is an intrinsic figure (always is its own subpath). */
727 path->pathdata.Types[old_count] = PathPointTypeStart;
728 path->pathdata.Types[old_count + MAX_ARC_PTS - 1] |= PathPointTypeCloseSubpath;
729 path->newfigure = TRUE;
730 path->pathdata.Count += MAX_ARC_PTS;
731
732 return Ok;
733}
734
736 INT height)
737{
738 TRACE("(%p, %d, %d, %d, %d)\n", path, x, y, width, height);
739
741}
742
744 INT count)
745{
746 TRACE("(%p, %p, %d)\n", path, points, count);
747
748 if(!path || !points || count < 1)
749 return InvalidParameter;
750
752}
753
755{
756 GpPointF *pointsF;
757 INT i;
759
760 TRACE("(%p, %p, %d)\n", path, points, count);
761
762 if(count <= 0)
763 return InvalidParameter;
764
765 pointsF = malloc(sizeof(GpPointF) * count);
766 if(!pointsF) return OutOfMemory;
767
768 for(i = 0;i < count; i++){
769 pointsF[i].X = (REAL)points[i].X;
770 pointsF[i].Y = (REAL)points[i].Y;
771 }
772
773 stat = GdipAddPathLine2(path, pointsF, count);
774
775 free(pointsF);
776
777 return stat;
778}
779
780/*************************************************************************
781 * GdipAddPathLine [GDIPLUS.21]
782 *
783 * Add two points to the given path.
784 *
785 * PARAMS
786 * path [I/O] Path that the line is appended to
787 * x1 [I] X coordinate of the first point of the line
788 * y1 [I] Y coordinate of the first point of the line
789 * x2 [I] X coordinate of the second point of the line
790 * y2 [I] Y coordinate of the second point of the line
791 *
792 * RETURNS
793 * InvalidParameter If the first parameter is not a valid path
794 * OutOfMemory If the path cannot be lengthened, i.e. memory allocation fails
795 * Ok If everything works out as expected
796 *
797 * NOTES
798 * This functions takes the newfigure value of the given path into account,
799 * i.e. the two new points are connected to the end of the given path if it
800 * was set to FALSE, otherwise the first point is given the PathPointTypeStart
801 * value. In both cases, the value of newfigure of the given path is FALSE
802 * afterwards.
803 */
805{
806 PointF points[2];
807
808 TRACE("(%p, %.2f, %.2f, %.2f, %.2f)\n", path, x1, y1, x2, y2);
809
810 if(!path)
811 return InvalidParameter;
812
813 points[0].X = x1;
814 points[0].Y = y1;
815 points[1].X = x2;
816 points[1].Y = y2;
817
819}
820
821/*************************************************************************
822 * GdipAddPathLineI [GDIPLUS.21]
823 *
824 * See GdipAddPathLine
825 */
827{
828 TRACE("(%p, %d, %d, %d, %d)\n", path, x1, y1, x2, y2);
829
830 return GdipAddPathLine(path, (REAL)x1, (REAL)y1, (REAL)x2, (REAL)y2);
831}
832
835{
836 INT old_count, count;
837
838 TRACE("(%p, %p, %d)\n", path, addingPath, connect);
839
840 if(!path || !addingPath)
841 return InvalidParameter;
842
843 old_count = path->pathdata.Count;
844 count = addingPath->pathdata.Count;
845
847 return OutOfMemory;
848
849 memcpy(&path->pathdata.Points[old_count], addingPath->pathdata.Points,
850 count * sizeof(GpPointF));
851 memcpy(&path->pathdata.Types[old_count], addingPath->pathdata.Types, count);
852
853 if(path->newfigure || !connect)
854 path->pathdata.Types[old_count] = PathPointTypeStart;
855 else
856 path->pathdata.Types[old_count] = PathPointTypeLine;
857
858 path->newfigure = FALSE;
859 path->pathdata.Count += count;
860
861 return Ok;
862}
863
865 REAL startAngle, REAL sweepAngle)
866{
867 GpPointF *ptf;
869 INT i, count;
870
871 TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n",
872 path, x, y, width, height, startAngle, sweepAngle);
873
874 if(!path)
875 return InvalidParameter;
876
877 /* on zero width/height only start point added */
878 if(width <= 1e-7 || height <= 1e-7){
879 if(!lengthen_path(path, 1))
880 return OutOfMemory;
881 path->pathdata.Points[0].X = x + width / 2.0;
882 path->pathdata.Points[0].Y = y + height / 2.0;
884 path->pathdata.Count = 1;
885 return InvalidParameter;
886 }
887
888 count = arc2polybezier(NULL, x, y, width, height, startAngle, sweepAngle);
889
890 if(count == 0)
891 return Ok;
892
893 ptf = malloc(sizeof(GpPointF) * count);
894 if(!ptf)
895 return OutOfMemory;
896
897 arc2polybezier(ptf, x, y, width, height, startAngle, sweepAngle);
898
899 status = GdipAddPathLine(path, x + width/2, y + height/2, ptf[0].X, ptf[0].Y);
900 if(status != Ok){
901 free(ptf);
902 return status;
903 }
904 /* one spline is already added as a line endpoint */
905 if(!lengthen_path(path, count - 1)){
906 free(ptf);
907 return OutOfMemory;
908 }
909
910 memcpy(&(path->pathdata.Points[path->pathdata.Count]), &(ptf[1]),sizeof(GpPointF)*(count-1));
911 for(i = 0; i < count-1; i++)
912 path->pathdata.Types[path->pathdata.Count+i] = PathPointTypeBezier;
913
914 path->pathdata.Count += count-1;
915
917
918 free(ptf);
919
920 return status;
921}
922
924 REAL startAngle, REAL sweepAngle)
925{
926 TRACE("(%p, %d, %d, %d, %d, %.2f, %.2f)\n",
927 path, x, y, width, height, startAngle, sweepAngle);
928
929 return GdipAddPathPie(path, (REAL)x, (REAL)y, (REAL)width, (REAL)height, startAngle, sweepAngle);
930}
931
933{
934 INT old_count;
935
936 TRACE("(%p, %p, %d)\n", path, points, count);
937
938 if(!path || !points || count < 3)
939 return InvalidParameter;
940
942 return OutOfMemory;
943
944 old_count = path->pathdata.Count;
945
946 memcpy(&path->pathdata.Points[old_count], points, count*sizeof(GpPointF));
947 memset(&path->pathdata.Types[old_count + 1], PathPointTypeLine, count - 1);
948
949 /* A polygon is an intrinsic figure */
950 path->pathdata.Types[old_count] = PathPointTypeStart;
951 path->pathdata.Types[old_count + count - 1] |= PathPointTypeCloseSubpath;
952 path->newfigure = TRUE;
953 path->pathdata.Count += count;
954
955 return Ok;
956}
957
959{
960 GpPointF *ptf;
962 INT i;
963
964 TRACE("(%p, %p, %d)\n", path, points, count);
965
966 if(!points || count < 3)
967 return InvalidParameter;
968
969 ptf = malloc(sizeof(GpPointF) * count);
970 if(!ptf)
971 return OutOfMemory;
972
973 for(i = 0; i < count; i++){
974 ptf[i].X = (REAL)points[i].X;
975 ptf[i].Y = (REAL)points[i].Y;
976 }
977
979
980 free(ptf);
981
982 return status;
983}
984
985static float fromfixedpoint(const FIXED v)
986{
987 float f = ((float)v.fract) / (1<<(sizeof(v.fract)*8));
988 f += v.value;
989 return f;
990}
991
993{
995 float maxY;
996 float scale;
997 float ascent;
998};
999
1001{
1002 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
1003 struct format_string_args *args = info->user_data;
1004 struct gdip_font_link_section *section = LIST_ENTRY(list_head(&info->font_link_info.sections), struct gdip_font_link_section, entry);
1005 HFONT hfont = NULL, oldhfont = NULL;
1006 int section_start = -1;
1007 GpPath *path = args->path;
1008 GpStatus status = Ok;
1009 float x = info->rect->X + (info->bounds->X - info->rect->X) * args->scale;
1010 float y = info->rect->Y + (info->bounds->Y - info->rect->Y) * args->scale;
1011 int i;
1012
1013 if (info->underlined_index_count)
1014 FIXME("hotkey underlines not drawn yet\n");
1015
1016 if (y + info->bounds->Height * args->scale > args->maxY)
1017 args->maxY = y + info->bounds->Height * args->scale;
1018
1019 for (i = info->index; i < info->length + info->index; ++i)
1020 {
1021 GLYPHMETRICS gm;
1022 TTPOLYGONHEADER *ph = NULL, *origph;
1023 char *start;
1024 DWORD len, ofs = 0;
1025
1026 while (i >= section->end)
1027 section = LIST_ENTRY(list_next(&info->font_link_info.sections, &section->entry), struct gdip_font_link_section, entry);
1028
1029 if (section_start != section->start)
1030 {
1031 if (hfont)
1032 {
1033 SelectObject(info->hdc, oldhfont);
1035 }
1036 get_font_hfont(info->graphics, section->font, NULL, &hfont, NULL, NULL);
1037 oldhfont = SelectObject(info->hdc, hfont);
1038 section_start = section->start;
1039 }
1040
1041 len = GetGlyphOutlineW(info->hdc, info->string[i], GGO_BEZIER, &gm, 0, NULL, &identity);
1042 if (len == GDI_ERROR)
1043 {
1045 break;
1046 }
1047 origph = ph = calloc(1, len);
1048 start = (char *)ph;
1049 if (!ph || !lengthen_path(path, len / sizeof(POINTFX)))
1050 {
1051 free(ph);
1053 break;
1054 }
1055 GetGlyphOutlineW(info->hdc, info->string[i], GGO_BEZIER, &gm, len, start, &identity);
1056
1057 ofs = 0;
1058 while (ofs < len)
1059 {
1060 DWORD ofs_start = ofs;
1061 ph = (TTPOLYGONHEADER*)&start[ofs];
1062 path->pathdata.Types[path->pathdata.Count] = PathPointTypeStart;
1063 path->pathdata.Points[path->pathdata.Count].X = x + fromfixedpoint(ph->pfxStart.x) * args->scale;
1064 path->pathdata.Points[path->pathdata.Count++].Y = y + args->ascent - fromfixedpoint(ph->pfxStart.y) * args->scale;
1065 TRACE("Starting at count %i with pos %f, %f)\n", path->pathdata.Count, x, y);
1066 ofs += sizeof(*ph);
1067 while (ofs - ofs_start < ph->cb)
1068 {
1069 TTPOLYCURVE *curve = (TTPOLYCURVE*)&start[ofs];
1070 int j;
1071 ofs += sizeof(TTPOLYCURVE) + (curve->cpfx - 1) * sizeof(POINTFX);
1072
1073 switch (curve->wType)
1074 {
1075 case TT_PRIM_LINE:
1076 for (j = 0; j < curve->cpfx; ++j)
1077 {
1078 path->pathdata.Types[path->pathdata.Count] = PathPointTypeLine;
1079 path->pathdata.Points[path->pathdata.Count].X = x + fromfixedpoint(curve->apfx[j].x) * args->scale;
1080 path->pathdata.Points[path->pathdata.Count++].Y = y + args->ascent - fromfixedpoint(curve->apfx[j].y) * args->scale;
1081 }
1082 break;
1083 case TT_PRIM_CSPLINE:
1084 for (j = 0; j < curve->cpfx; ++j)
1085 {
1086 path->pathdata.Types[path->pathdata.Count] = PathPointTypeBezier;
1087 path->pathdata.Points[path->pathdata.Count].X = x + fromfixedpoint(curve->apfx[j].x) * args->scale;
1088 path->pathdata.Points[path->pathdata.Count++].Y = y + args->ascent - fromfixedpoint(curve->apfx[j].y) * args->scale;
1089 }
1090 break;
1091 default:
1092 ERR("Unhandled type: %u\n", curve->wType);
1094 }
1095 }
1096 path->pathdata.Types[path->pathdata.Count - 1] |= PathPointTypeCloseSubpath;
1097 }
1098 path->newfigure = TRUE;
1099 x += gm.gmCellIncX * args->scale;
1100 y += gm.gmCellIncY * args->scale;
1101
1102 free(origph);
1103 if (status != Ok)
1104 break;
1105 }
1106
1107 if (hfont)
1108 {
1109 SelectObject(info->hdc, oldhfont);
1111 }
1112
1113 return status;
1114}
1115
1117{
1118 GpFont *font;
1120 LOGFONTW lfw;
1121 HANDLE hfont;
1122 HDC dc;
1123 GpGraphics *graphics;
1124 GpPath *backup;
1125 struct format_string_args args;
1126 int i;
1127 UINT16 native_height;
1128 RectF scaled_layout_rect;
1129 TEXTMETRICW textmetric;
1130
1131 TRACE("(%p, %s, %d, %p, %d, %f, %p, %p)\n", path, debugstr_w(string), length, family, style, emSize, layoutRect, format);
1132 if (!path || !string || !family || !emSize || !layoutRect)
1133 return InvalidParameter;
1134
1135 if (!format)
1137
1138 status = GdipGetEmHeight(family, style, &native_height);
1139 if (status != Ok)
1140 return status;
1141
1142 scaled_layout_rect.X = layoutRect->X;
1143 scaled_layout_rect.Y = layoutRect->Y;
1144 scaled_layout_rect.Width = layoutRect->Width * native_height / emSize;
1145 scaled_layout_rect.Height = layoutRect->Height * native_height / emSize;
1146
1147 if ((status = GdipClonePath(path, &backup)) != Ok)
1148 return status;
1149
1151 status = GdipCreateFromHDC(dc, &graphics);
1152 if (status != Ok)
1153 {
1154 DeleteDC(dc);
1156 return status;
1157 }
1158
1159 status = GdipCreateFont(family, native_height, style, UnitPixel, &font);
1160 if (status != Ok)
1161 {
1162 GdipDeleteGraphics(graphics);
1163 DeleteDC(dc);
1165 return status;
1166 }
1167
1168 get_log_fontW(font, graphics, &lfw);
1169
1170 hfont = CreateFontIndirectW(&lfw);
1171 if (!hfont)
1172 {
1173 WARN("Failed to create font\n");
1174 DeleteDC(dc);
1177 return GenericError;
1178 }
1179
1181
1182 GetTextMetricsW(dc, &textmetric);
1183
1184 args.path = path;
1185 args.maxY = 0;
1186 args.scale = emSize / native_height;
1187 args.ascent = textmetric.tmAscent * args.scale;
1188 status = gdip_format_string(graphics, dc, string, length, font, &scaled_layout_rect,
1190
1191 DeleteDC(dc);
1194 GdipDeleteGraphics(graphics);
1195
1196 if (status != Ok) /* free backup */
1197 {
1198 free(path->pathdata.Points);
1199 free(path->pathdata.Types);
1200 *path = *backup;
1201 free(backup);
1202 return status;
1203 }
1204 if (format->line_align == StringAlignmentCenter && layoutRect->Y + args.maxY < layoutRect->Height)
1205 {
1206 float inc = layoutRect->Height + layoutRect->Y - args.maxY;
1207 inc /= 2;
1208 for (i = backup->pathdata.Count; i < path->pathdata.Count; ++i)
1209 path->pathdata.Points[i].Y += inc;
1210 } else if (format->line_align == StringAlignmentFar) {
1211 float inc = layoutRect->Height + layoutRect->Y - args.maxY;
1212 for (i = backup->pathdata.Count; i < path->pathdata.Count; ++i)
1213 path->pathdata.Points[i].Y += inc;
1214 }
1216 return status;
1217}
1218
1220 INT style, REAL emSize, GDIPCONST Rect* layoutRect, GDIPCONST GpStringFormat* format)
1221{
1222 RectF rect;
1223
1224 if (!layoutRect)
1225 return InvalidParameter;
1226
1227 set_rect(&rect, layoutRect->X, layoutRect->Y, layoutRect->Width, layoutRect->Height);
1228 return GdipAddPathString(path, string, length, family, style, emSize, &rect, format);
1229}
1230
1231/*************************************************************************
1232 * GdipClonePath [GDIPLUS.53]
1233 *
1234 * Duplicate the given path in memory.
1235 *
1236 * PARAMS
1237 * path [I] The path to be duplicated
1238 * clone [O] Pointer to the new path
1239 *
1240 * RETURNS
1241 * InvalidParameter If the input path is invalid
1242 * OutOfMemory If allocation of needed memory fails
1243 * Ok If everything works out as expected
1244 */
1246{
1247 TRACE("(%p, %p)\n", path, clone);
1248
1249 if(!path || !clone)
1250 return InvalidParameter;
1251
1252 if (path->pathdata.Count)
1253 return GdipCreatePath2(path->pathdata.Points, path->pathdata.Types, path->pathdata.Count,
1254 path->fill, clone);
1255 else
1256 {
1257 *clone = calloc(1, sizeof(GpPath));
1258 if(!*clone) return OutOfMemory;
1259 }
1260
1261 return Ok;
1262}
1263
1265{
1266 TRACE("(%p)\n", path);
1267
1268 if(!path)
1269 return InvalidParameter;
1270
1271 if(path->pathdata.Count > 0){
1272 path->pathdata.Types[path->pathdata.Count - 1] |= PathPointTypeCloseSubpath;
1273 path->newfigure = TRUE;
1274 }
1275
1276 return Ok;
1277}
1278
1280{
1281 INT i;
1282
1283 TRACE("(%p)\n", path);
1284
1285 if(!path)
1286 return InvalidParameter;
1287
1288 for(i = 1; i < path->pathdata.Count; i++){
1289 if(path->pathdata.Types[i] == PathPointTypeStart)
1290 path->pathdata.Types[i-1] |= PathPointTypeCloseSubpath;
1291 }
1292
1293 path->newfigure = TRUE;
1294
1295 return Ok;
1296}
1297
1299{
1300 TRACE("(%d, %p)\n", fill, path);
1301
1302 if(!path)
1303 return InvalidParameter;
1304
1305 *path = calloc(1, sizeof(GpPath));
1306 if(!*path) return OutOfMemory;
1307
1308 (*path)->fill = fill;
1309 (*path)->newfigure = TRUE;
1310
1311 return Ok;
1312}
1313
1316{
1317 int i;
1318
1319 TRACE("(%p, %p, %d, %d, %p)\n", points, types, count, fill, path);
1320
1321 if(!points || !types || !path)
1322 return InvalidParameter;
1323
1324 if(count <= 0) {
1325 *path = NULL;
1326 return OutOfMemory;
1327 }
1328
1329 *path = calloc(1, sizeof(GpPath));
1330 if(!*path) return OutOfMemory;
1331
1333 count = 0;
1334
1335 for(i = 1; i < count; i++) {
1337 if(i+2 < count &&
1340 i += 2;
1341 else {
1342 count = 0;
1343 break;
1344 }
1345 }
1346 }
1347
1348 (*path)->pathdata.Points = malloc(count * sizeof(PointF));
1349 (*path)->pathdata.Types = malloc(count);
1350
1351 if(!(*path)->pathdata.Points || !(*path)->pathdata.Types){
1352 free((*path)->pathdata.Points);
1353 free((*path)->pathdata.Types);
1354 free(*path);
1355 return OutOfMemory;
1356 }
1357
1358 memcpy((*path)->pathdata.Points, points, count * sizeof(PointF));
1359 memcpy((*path)->pathdata.Types, types, count);
1360 if(count > 0)
1361 (*path)->pathdata.Types[0] = PathPointTypeStart;
1362 (*path)->pathdata.Count = count;
1363 (*path)->datalen = count;
1364
1365 (*path)->fill = fill;
1366 (*path)->newfigure = TRUE;
1367
1368 return Ok;
1369}
1370
1373{
1374 GpPointF *ptF;
1375 GpStatus ret;
1376 INT i;
1377
1378 TRACE("(%p, %p, %d, %d, %p)\n", points, types, count, fill, path);
1379
1380 ptF = malloc(sizeof(GpPointF) * count);
1381
1382 for(i = 0;i < count; i++){
1383 ptF[i].X = (REAL)points[i].X;
1384 ptF[i].Y = (REAL)points[i].Y;
1385 }
1386
1388
1389 free(ptF);
1390
1391 return ret;
1392}
1393
1395{
1396 TRACE("(%p)\n", path);
1397
1398 if(!path)
1399 return InvalidParameter;
1400
1401 free(path->pathdata.Points);
1402 free(path->pathdata.Types);
1403 free(path);
1404
1405 return Ok;
1406}
1407
1409{
1411 GpPointF pt;
1412 INT i = 1;
1413 INT startidx = 0;
1414 GpStatus stat;
1415
1416 TRACE("(%p, %p, %.2f)\n", path, matrix, flatness);
1417
1418 if(!path)
1419 return InvalidParameter;
1420
1421 if(path->pathdata.Count == 0)
1422 return Ok;
1423
1425 if(stat != Ok)
1426 return stat;
1427
1428 pt = path->pathdata.Points[0];
1429 if(!init_path_list(&list, pt.X, pt.Y))
1430 return OutOfMemory;
1431
1432 node = list;
1433
1434 while(i < path->pathdata.Count){
1435
1436 BYTE type = path->pathdata.Types[i] & PathPointTypePathTypeMask;
1438
1439 pt = path->pathdata.Points[i];
1440
1441 /* save last start point index */
1443 startidx = i;
1444
1445 /* always add line points and start points */
1447 if(!add_path_list_node(node, pt.X, pt.Y, path->pathdata.Types[i]))
1448 goto memout;
1449
1450 node = node->next;
1451 ++i;
1452 continue;
1453 }
1454
1455 /* Bezier curve */
1456
1457 /* test for closed figure */
1458 if(path->pathdata.Types[i+1] & PathPointTypeCloseSubpath){
1459 pt = path->pathdata.Points[startidx];
1460 ++i;
1461 }
1462 else
1463 {
1464 i += 2;
1465 pt = path->pathdata.Points[i];
1466 };
1467
1468 start = node;
1469 /* add Bezier end point */
1470 type = (path->pathdata.Types[i] & ~PathPointTypePathTypeMask) | PathPointTypeLine;
1471 if(!add_path_list_node(node, pt.X, pt.Y, type))
1472 goto memout;
1473 node = node->next;
1474
1475 /* flatten curve */
1476 if(!flatten_bezier(start, path->pathdata.Points[i-2].X, path->pathdata.Points[i-2].Y,
1477 path->pathdata.Points[i-1].X, path->pathdata.Points[i-1].Y,
1478 node, flatness))
1479 goto memout;
1480
1481 ++i;
1482 }/* while */
1483
1484 if (!path_list_to_path(list, path)) goto memout;
1486 return Ok;
1487
1488memout:
1490 return OutOfMemory;
1491}
1492
1494{
1495 TRACE("(%p, %p)\n", path, pathData);
1496
1497 if(!path || !pathData)
1498 return InvalidParameter;
1499
1500 /* Only copy data. pathData allocation/freeing controlled by wrapper class.
1501 Assumed that pathData is enough wide to get all data - controlled by wrapper too. */
1502 memcpy(pathData->Points, path->pathdata.Points, sizeof(PointF) * pathData->Count);
1503 memcpy(pathData->Types , path->pathdata.Types , pathData->Count);
1504
1505 return Ok;
1506}
1507
1509{
1510 TRACE("(%p, %p)\n", path, fillmode);
1511
1512 if(!path || !fillmode)
1513 return InvalidParameter;
1514
1515 *fillmode = path->fill;
1516
1517 return Ok;
1518}
1519
1521{
1522 INT count;
1523
1524 TRACE("(%p, %p)\n", path, lastPoint);
1525
1526 if(!path || !lastPoint)
1527 return InvalidParameter;
1528
1529 count = path->pathdata.Count;
1530 if(count > 0)
1531 *lastPoint = path->pathdata.Points[count-1];
1532
1533 return Ok;
1534}
1535
1537{
1538 TRACE("(%p, %p, %d)\n", path, points, count);
1539
1540 if(!path)
1541 return InvalidParameter;
1542
1543 if(count < path->pathdata.Count)
1544 return InsufficientBuffer;
1545
1546 memcpy(points, path->pathdata.Points, path->pathdata.Count * sizeof(GpPointF));
1547
1548 return Ok;
1549}
1550
1552{
1553 GpStatus ret;
1554 GpPointF *ptf;
1555 INT i;
1556
1557 TRACE("(%p, %p, %d)\n", path, points, count);
1558
1559 if(count <= 0)
1560 return InvalidParameter;
1561
1562 ptf = malloc(sizeof(GpPointF) * count);
1563 if(!ptf) return OutOfMemory;
1564
1566 if(ret == Ok)
1567 for(i = 0;i < count;i++){
1568 points[i].X = gdip_round(ptf[i].X);
1569 points[i].Y = gdip_round(ptf[i].Y);
1570 };
1571 free(ptf);
1572
1573 return ret;
1574}
1575
1577{
1578 TRACE("(%p, %p, %d)\n", path, types, count);
1579
1580 if(!path)
1581 return InvalidParameter;
1582
1583 if(count < path->pathdata.Count)
1584 return InsufficientBuffer;
1585
1586 memcpy(types, path->pathdata.Types, path->pathdata.Count);
1587
1588 return Ok;
1589}
1590
1591/* Windows expands the bounding box to the maximum possible bounding box
1592 * for a given pen. For example, if a line join can extend past the point
1593 * it's joining by x units, the bounding box is extended by x units in every
1594 * direction (even though this is too conservative for most cases). */
1597{
1598 GpPointF * points, temp_pts[4];
1599 INT count, i;
1600 REAL path_width = 1.0, width, height, temp, low_x, low_y, high_x, high_y;
1601
1602 TRACE("(%p, %p, %s, %p)\n", path, bounds, debugstr_matrix(matrix), pen);
1603
1604 /* Matrix and pen can be null. */
1605 if(!path || !bounds)
1606 return InvalidParameter;
1607
1608 /* If path is empty just return. */
1609 count = path->pathdata.Count;
1610 if(count == 0){
1611 bounds->X = bounds->Y = bounds->Width = bounds->Height = 0.0;
1612 return Ok;
1613 }
1614
1615 points = path->pathdata.Points;
1616
1617 low_x = high_x = points[0].X;
1618 low_y = high_y = points[0].Y;
1619
1620 for(i = 1; i < count; i++){
1621 low_x = min(low_x, points[i].X);
1622 low_y = min(low_y, points[i].Y);
1623 high_x = max(high_x, points[i].X);
1624 high_y = max(high_y, points[i].Y);
1625 }
1626
1627 width = high_x - low_x;
1628 height = high_y - low_y;
1629
1630 /* This looks unusual but it's the only way I can imitate windows. */
1631 if(matrix){
1632 temp_pts[0].X = low_x;
1633 temp_pts[0].Y = low_y;
1634 temp_pts[1].X = low_x;
1635 temp_pts[1].Y = high_y;
1636 temp_pts[2].X = high_x;
1637 temp_pts[2].Y = high_y;
1638 temp_pts[3].X = high_x;
1639 temp_pts[3].Y = low_y;
1640
1642 low_x = temp_pts[0].X;
1643 low_y = temp_pts[0].Y;
1644
1645 for(i = 1; i < 4; i++){
1646 low_x = min(low_x, temp_pts[i].X);
1647 low_y = min(low_y, temp_pts[i].Y);
1648 }
1649
1650 temp = width;
1651 width = height * fabs(matrix->matrix[2]) + width * fabs(matrix->matrix[0]);
1652 height = height * fabs(matrix->matrix[3]) + temp * fabs(matrix->matrix[1]);
1653 }
1654
1655 if(pen){
1656 path_width = pen->width / 2.0;
1657
1658 if(count > 2)
1659 path_width = max(path_width, pen->width * pen->miterlimit / 2.0);
1660 /* FIXME: this should probably also check for the startcap */
1661 if(pen->endcap & LineCapNoAnchor)
1662 path_width = max(path_width, pen->width * 2.2);
1663
1664 low_x -= path_width;
1665 low_y -= path_width;
1666 width += 2.0 * path_width;
1667 height += 2.0 * path_width;
1668 }
1669
1670 bounds->X = low_x;
1671 bounds->Y = low_y;
1672 bounds->Width = width;
1673 bounds->Height = height;
1674
1675 return Ok;
1676}
1677
1680{
1681 GpStatus ret;
1682 GpRectF boundsF;
1683
1684 TRACE("(%p, %p, %s, %p)\n", path, bounds, debugstr_matrix(matrix), pen);
1685
1686 ret = GdipGetPathWorldBounds(path,&boundsF,matrix,pen);
1687
1688 if(ret == Ok){
1689 bounds->X = gdip_round(boundsF.X);
1690 bounds->Y = gdip_round(boundsF.Y);
1691 bounds->Width = gdip_round(boundsF.Width);
1692 bounds->Height = gdip_round(boundsF.Height);
1693 }
1694
1695 return ret;
1696}
1697
1699{
1700 TRACE("(%p, %p)\n", path, count);
1701
1702 if(!path)
1703 return InvalidParameter;
1704
1705 *count = path->pathdata.Count;
1706
1707 return Ok;
1708}
1709
1711{
1712 INT i, count;
1713 INT start = 0; /* position in reversed path */
1714 GpPathData revpath;
1715
1716 TRACE("(%p)\n", path);
1717
1718 if(!path)
1719 return InvalidParameter;
1720
1721 count = path->pathdata.Count;
1722
1723 if(count == 0) return Ok;
1724
1725 revpath.Points = calloc(count, sizeof(GpPointF));
1726 revpath.Types = calloc(count, sizeof(BYTE));
1727 revpath.Count = count;
1728 if(!revpath.Points || !revpath.Types){
1729 free(revpath.Points);
1730 free(revpath.Types);
1731 return OutOfMemory;
1732 }
1733
1734 for(i = 0; i < count; i++){
1735
1736 /* find next start point */
1737 if(path->pathdata.Types[count-i-1] == PathPointTypeStart){
1738 INT j;
1739 for(j = start; j <= i; j++){
1740 revpath.Points[j] = path->pathdata.Points[count-j-1];
1741 revpath.Types[j] = path->pathdata.Types[count-j-1];
1742 }
1743 /* mark start point */
1744 revpath.Types[start] = PathPointTypeStart;
1745 /* set 'figure' endpoint type */
1746 if(i-start > 1){
1747 revpath.Types[i] = path->pathdata.Types[count-start-1] & ~PathPointTypePathTypeMask;
1748 revpath.Types[i] |= revpath.Types[i-1];
1749 }
1750 else
1751 revpath.Types[i] = path->pathdata.Types[start];
1752
1753 start = i+1;
1754 }
1755 }
1756
1757 memcpy(path->pathdata.Points, revpath.Points, sizeof(GpPointF)*count);
1758 memcpy(path->pathdata.Types, revpath.Types, sizeof(BYTE)*count);
1759
1760 free(revpath.Points);
1761 free(revpath.Types);
1762
1763 return Ok;
1764}
1765
1767 GpPen *pen, GpGraphics *graphics, BOOL *result)
1768{
1769 TRACE("(%p, %d, %d, %p, %p, %p)\n", path, x, y, pen, graphics, result);
1770
1771 return GdipIsOutlineVisiblePathPoint(path, x, y, pen, graphics, result);
1772}
1773
1775 GpPen *pen, GpGraphics *graphics, BOOL *result)
1776{
1777 GpStatus stat;
1778 GpPath *wide_path;
1779 GpPointF pt = {x, y};
1781
1782 TRACE("(%p, %0.2f, %0.2f, %p, %p, %p)\n", path, x, y, pen, graphics, result);
1783
1784 if(!path || !pen)
1785 return InvalidParameter;
1786
1787 stat = GdipClonePath(path, &wide_path);
1788
1789 if (stat != Ok)
1790 return stat;
1791
1792 if (pen->unit == UnitPixel && graphics != NULL)
1793 {
1795
1796 if (stat == Ok)
1799 if (stat == Ok)
1801 }
1802
1803 if (stat == Ok)
1804 stat = GdipWidenPath(wide_path, pen, transform, 0.25f);
1805
1806 if (stat == Ok)
1807 stat = GdipIsVisiblePathPoint(wide_path, pt.X, pt.Y, graphics, result);
1808
1810
1811 GdipDeletePath(wide_path);
1812
1813 return stat;
1814}
1815
1817{
1818 TRACE("(%p, %d, %d, %p, %p)\n", path, x, y, graphics, result);
1819
1820 return GdipIsVisiblePathPoint(path, x, y, graphics, result);
1821}
1822
1823/*****************************************************************************
1824 * GdipIsVisiblePathPoint [GDIPLUS.@]
1825 */
1827{
1828 GpRegion *region;
1829 HRGN hrgn;
1831
1832 if(!path || !result) return InvalidParameter;
1833
1834 status = GdipCreateRegionPath(path, &region);
1835 if(status != Ok)
1836 return status;
1837
1838 status = GdipGetRegionHRgn(region, NULL, &hrgn);
1839 if(status != Ok){
1840 GdipDeleteRegion(region);
1841 return status;
1842 }
1843
1845
1847 GdipDeleteRegion(region);
1848
1849 return Ok;
1850}
1851
1853{
1854 TRACE("(%p)\n", path);
1855
1856 if(!path)
1857 return InvalidParameter;
1858
1859 path->newfigure = TRUE;
1860
1861 return Ok;
1862}
1863
1865{
1866 TRACE("(%p)\n", path);
1867
1868 if(!path)
1869 return InvalidParameter;
1870
1871 path->pathdata.Count = 0;
1872 path->newfigure = TRUE;
1873 path->fill = FillModeAlternate;
1874
1875 return Ok;
1876}
1877
1879{
1880 TRACE("(%p, %d)\n", path, fill);
1881
1882 if(!path)
1883 return InvalidParameter;
1884
1885 path->fill = fill;
1886
1887 return Ok;
1888}
1889
1891{
1892 TRACE("(%p, %s)\n", path, debugstr_matrix(matrix));
1893
1894 if(!path)
1895 return InvalidParameter;
1896
1897 if(path->pathdata.Count == 0 || !matrix)
1898 return Ok;
1899
1900 return GdipTransformMatrixPoints(matrix, path->pathdata.Points,
1901 path->pathdata.Count);
1902}
1903
1906 REAL height, WarpMode warpmode, REAL flatness)
1907{
1908 FIXME("(%p,%s,%p,%i,%0.2f,%0.2f,%0.2f,%0.2f,%i,%0.2f)\n", path, debugstr_matrix(matrix),
1909 points, count, x, y, width, height, warpmode, flatness);
1910
1911 return NotImplemented;
1912}
1913
1914static void add_bevel_point(const GpPointF *endpoint, const GpPointF *nextpoint,
1915 REAL pen_width, int right_side, path_list_node_t **last_point)
1916{
1917 REAL segment_dy = nextpoint->Y-endpoint->Y;
1918 REAL segment_dx = nextpoint->X-endpoint->X;
1919 REAL segment_length = hypotf(segment_dy, segment_dx);
1920 REAL distance = pen_width / 2.0;
1921 REAL bevel_dx, bevel_dy;
1922
1923 if (segment_length == 0.0)
1924 {
1925 *last_point = add_path_list_node(*last_point, endpoint->X,
1927 return;
1928 }
1929
1930 if (right_side)
1931 {
1932 bevel_dx = -distance * segment_dy / segment_length;
1933 bevel_dy = distance * segment_dx / segment_length;
1934 }
1935 else
1936 {
1937 bevel_dx = distance * segment_dy / segment_length;
1938 bevel_dy = -distance * segment_dx / segment_length;
1939 }
1940
1941 *last_point = add_path_list_node(*last_point, endpoint->X + bevel_dx,
1942 endpoint->Y + bevel_dy, PathPointTypeLine);
1943}
1944
1945static void widen_joint(const GpPointF *p1, const GpPointF *p2, const GpPointF *p3,
1946 GpPen* pen, REAL pen_width, path_list_node_t **last_point)
1947{
1948 switch (pen->join)
1949 {
1950 case LineJoinMiter:
1952 if ((p2->X - p1->X) * (p3->Y - p1->Y) > (p2->Y - p1->Y) * (p3->X - p1->X))
1953 {
1954 float distance = pen_width / 2.0;
1955 float length_0 = hypotf(p2->X - p1->X, p2->Y - p1->Y);
1956 float length_1 = hypotf(p3->X - p2->X, p3->Y - p2->Y);
1957 float dx0 = distance * (p2->X - p1->X) / length_0;
1958 float dy0 = distance * (p2->Y - p1->Y) / length_0;
1959 float dx1 = distance * (p3->X - p2->X) / length_1;
1960 float dy1 = distance * (p3->Y - p2->Y) / length_1;
1961 float det = (dy0*dx1 - dx0*dy1);
1962 float dx = (dx0*dx1*(dx0-dx1) + dy0*dy0*dx1 - dy1*dy1*dx0)/det;
1963 float dy = (dy0*dy1*(dy0-dy1) + dx0*dx0*dy1 - dx1*dx1*dy0)/det;
1964 if (dx*dx + dy*dy < pen->miterlimit*pen->miterlimit * distance*distance)
1965 {
1966 *last_point = add_path_list_node(*last_point, p2->X + dx,
1967 p2->Y + dy, PathPointTypeLine);
1968 break;
1969 }
1970 else if (pen->join == LineJoinMiter)
1971 {
1972 static int once;
1973 if (!once++)
1974 FIXME("should add a clipped corner\n");
1975 }
1976 /* else fall-through */
1977 }
1978 /* else fall-through */
1979 default:
1980 case LineJoinBevel:
1981 add_bevel_point(p2, p1, pen_width, 1, last_point);
1982 add_bevel_point(p2, p3, pen_width, 0, last_point);
1983 break;
1984 }
1985}
1986
1987static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint,
1988 REAL pen_width, GpLineCap cap, GpCustomLineCap* custom_cap, int add_first_points,
1989 int add_last_point, path_list_node_t **last_point)
1990{
1991 switch (cap)
1992 {
1993 default:
1994 case LineCapFlat:
1995 if (add_first_points)
1996 add_bevel_point(endpoint, nextpoint, pen_width, 1, last_point);
1997 if (add_last_point)
1998 add_bevel_point(endpoint, nextpoint, pen_width, 0, last_point);
1999 break;
2000 case LineCapSquare:
2001 case LineCapCustom:
2002 case LineCapArrowAnchor:
2003 {
2004 REAL segment_dy = nextpoint->Y-endpoint->Y;
2005 REAL segment_dx = nextpoint->X-endpoint->X;
2006 REAL segment_length = hypotf(segment_dy, segment_dx);
2007 REAL distance = pen_width / 2.0;
2008 REAL bevel_dx, bevel_dy;
2009 REAL extend_dx, extend_dy;
2010
2011 extend_dx = distance * segment_dx / segment_length;
2012 extend_dy = distance * segment_dy / segment_length;
2013
2014 bevel_dx = -extend_dy;
2015 bevel_dy = extend_dx;
2016
2017 if (cap == LineCapCustom)
2018 {
2019 extend_dx = -2.0 * custom_cap->inset * extend_dx;
2020 extend_dy = -2.0 * custom_cap->inset * extend_dy;
2021 }
2022 else if (cap == LineCapArrowAnchor)
2023 {
2024 extend_dx = -3.0 * extend_dx;
2025 extend_dy = -3.0 * extend_dy;
2026 }
2027
2028 if (add_first_points)
2029 *last_point = add_path_list_node(*last_point, endpoint->X - extend_dx + bevel_dx,
2030 endpoint->Y - extend_dy + bevel_dy, PathPointTypeLine);
2031
2032 if (add_last_point)
2033 *last_point = add_path_list_node(*last_point, endpoint->X - extend_dx - bevel_dx,
2034 endpoint->Y - extend_dy - bevel_dy, PathPointTypeLine);
2035 break;
2036 }
2037 case LineCapRound:
2038 {
2039 REAL segment_dy = nextpoint->Y-endpoint->Y;
2040 REAL segment_dx = nextpoint->X-endpoint->X;
2041 REAL segment_length = hypotf(segment_dy, segment_dx);
2042 REAL distance = pen_width / 2.0;
2043 REAL dx, dy, dx2, dy2;
2044 const REAL control_point_distance = 0.5522847498307935; /* 4/3 * (sqrt(2) - 1) */
2045
2046 if (add_first_points)
2047 {
2048 dx = -distance * segment_dx / segment_length;
2049 dy = -distance * segment_dy / segment_length;
2050
2051 dx2 = dx * control_point_distance;
2052 dy2 = dy * control_point_distance;
2053
2054 /* first 90-degree arc */
2055 *last_point = add_path_list_node(*last_point, endpoint->X + dy,
2057
2058 *last_point = add_path_list_node(*last_point, endpoint->X + dy + dx2,
2059 endpoint->Y - dx + dy2, PathPointTypeBezier);
2060
2061 *last_point = add_path_list_node(*last_point, endpoint->X + dx + dy2,
2062 endpoint->Y + dy - dx2, PathPointTypeBezier);
2063
2064 /* midpoint */
2065 *last_point = add_path_list_node(*last_point, endpoint->X + dx,
2067
2068 /* second 90-degree arc */
2069 *last_point = add_path_list_node(*last_point, endpoint->X + dx - dy2,
2070 endpoint->Y + dy + dx2, PathPointTypeBezier);
2071
2072 *last_point = add_path_list_node(*last_point, endpoint->X - dy + dx2,
2073 endpoint->Y + dx + dy2, PathPointTypeBezier);
2074
2075 *last_point = add_path_list_node(*last_point, endpoint->X - dy,
2077 }
2078 else if (add_last_point)
2079 add_bevel_point(endpoint, nextpoint, pen_width, 0, last_point);
2080 break;
2081 }
2082 case LineCapTriangle:
2083 {
2084 REAL segment_dy = nextpoint->Y-endpoint->Y;
2085 REAL segment_dx = nextpoint->X-endpoint->X;
2086 REAL segment_length = hypotf(segment_dy, segment_dx);
2087 REAL distance = pen_width / 2.0;
2088 REAL dx, dy;
2089
2090 dx = distance * segment_dx / segment_length;
2091 dy = distance * segment_dy / segment_length;
2092
2093 if (add_first_points) {
2094 add_bevel_point(endpoint, nextpoint, pen_width, 1, last_point);
2095
2096 *last_point = add_path_list_node(*last_point, endpoint->X - dx,
2098 }
2099 if (add_first_points || add_last_point)
2100 add_bevel_point(endpoint, nextpoint, pen_width, 0, last_point);
2101 break;
2102 }
2103 }
2104}
2105
2106static void widen_open_figure(const GpPointF *points, int start, int end,
2107 GpPen *pen, REAL pen_width, GpLineCap start_cap, GpCustomLineCap* custom_start,
2108 GpLineCap end_cap, GpCustomLineCap* custom_end, path_list_node_t **last_point);
2109
2110static void widen_closed_figure(const GpPointF *points, int start, int end,
2111 GpPen *pen, REAL pen_width, path_list_node_t **last_point);
2112
2113static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint,
2114 GpPen *pen, REAL pen_width, GpLineCap cap, GpCustomLineCap *custom, path_list_node_t **last_point)
2115{
2116 switch (cap)
2117 {
2118 default:
2119 case LineCapNoAnchor:
2120 return;
2122 {
2123 REAL segment_dy = nextpoint->Y-endpoint->Y;
2124 REAL segment_dx = nextpoint->X-endpoint->X;
2125 REAL segment_length = hypotf(segment_dy, segment_dx);
2126 REAL distance = pen_width / sqrtf(2.0);
2127 REAL par_dx, par_dy;
2128 REAL perp_dx, perp_dy;
2129
2130 par_dx = -distance * segment_dx / segment_length;
2131 par_dy = -distance * segment_dy / segment_length;
2132
2133 perp_dx = -distance * segment_dy / segment_length;
2134 perp_dy = distance * segment_dx / segment_length;
2135
2136 *last_point = add_path_list_node(*last_point, endpoint->X - par_dx - perp_dx,
2137 endpoint->Y - par_dy - perp_dy, PathPointTypeStart);
2138 *last_point = add_path_list_node(*last_point, endpoint->X - par_dx + perp_dx,
2139 endpoint->Y - par_dy + perp_dy, PathPointTypeLine);
2140 *last_point = add_path_list_node(*last_point, endpoint->X + par_dx + perp_dx,
2141 endpoint->Y + par_dy + perp_dy, PathPointTypeLine);
2142 *last_point = add_path_list_node(*last_point, endpoint->X + par_dx - perp_dx,
2143 endpoint->Y + par_dy - perp_dy, PathPointTypeLine);
2144 break;
2145 }
2146 case LineCapRoundAnchor:
2147 {
2148 REAL segment_dy = nextpoint->Y-endpoint->Y;
2149 REAL segment_dx = nextpoint->X-endpoint->X;
2150 REAL segment_length = hypotf(segment_dy, segment_dx);
2151 REAL dx, dy, dx2, dy2;
2152 const REAL control_point_distance = 0.55228475; /* 4/3 * (sqrt(2) - 1) */
2153
2154 dx = -pen_width * segment_dx / segment_length;
2155 dy = -pen_width * segment_dy / segment_length;
2156
2157 dx2 = dx * control_point_distance;
2158 dy2 = dy * control_point_distance;
2159
2160 /* starting point */
2161 *last_point = add_path_list_node(*last_point, endpoint->X + dy,
2163
2164 /* first 90-degree arc */
2165 *last_point = add_path_list_node(*last_point, endpoint->X + dy + dx2,
2166 endpoint->Y - dx + dy2, PathPointTypeBezier);
2167 *last_point = add_path_list_node(*last_point, endpoint->X + dx + dy2,
2168 endpoint->Y + dy - dx2, PathPointTypeBezier);
2169 *last_point = add_path_list_node(*last_point, endpoint->X + dx,
2171
2172 /* second 90-degree arc */
2173 *last_point = add_path_list_node(*last_point, endpoint->X + dx - dy2,
2174 endpoint->Y + dy + dx2, PathPointTypeBezier);
2175 *last_point = add_path_list_node(*last_point, endpoint->X - dy + dx2,
2176 endpoint->Y + dx + dy2, PathPointTypeBezier);
2177 *last_point = add_path_list_node(*last_point, endpoint->X - dy,
2179
2180 /* third 90-degree arc */
2181 *last_point = add_path_list_node(*last_point, endpoint->X - dy - dx2,
2182 endpoint->Y + dx - dy2, PathPointTypeBezier);
2183 *last_point = add_path_list_node(*last_point, endpoint->X - dx - dy2,
2184 endpoint->Y - dy + dx2, PathPointTypeBezier);
2185 *last_point = add_path_list_node(*last_point, endpoint->X - dx,
2187
2188 /* fourth 90-degree arc */
2189 *last_point = add_path_list_node(*last_point, endpoint->X - dx + dy2,
2190 endpoint->Y - dy - dx2, PathPointTypeBezier);
2191 *last_point = add_path_list_node(*last_point, endpoint->X + dy - dx2,
2192 endpoint->Y - dx - dy2, PathPointTypeBezier);
2193 *last_point = add_path_list_node(*last_point, endpoint->X + dy,
2195
2196 break;
2197 }
2199 {
2200 REAL segment_dy = nextpoint->Y-endpoint->Y;
2201 REAL segment_dx = nextpoint->X-endpoint->X;
2202 REAL segment_length = hypotf(segment_dy, segment_dx);
2203 REAL par_dx, par_dy;
2204 REAL perp_dx, perp_dy;
2205
2206 par_dx = -pen_width * segment_dx / segment_length;
2207 par_dy = -pen_width * segment_dy / segment_length;
2208
2209 perp_dx = -pen_width * segment_dy / segment_length;
2210 perp_dy = pen_width * segment_dx / segment_length;
2211
2212 *last_point = add_path_list_node(*last_point, endpoint->X + par_dx,
2213 endpoint->Y + par_dy, PathPointTypeStart);
2214 *last_point = add_path_list_node(*last_point, endpoint->X - perp_dx,
2215 endpoint->Y - perp_dy, PathPointTypeLine);
2216 *last_point = add_path_list_node(*last_point, endpoint->X - par_dx,
2217 endpoint->Y - par_dy, PathPointTypeLine);
2218 *last_point = add_path_list_node(*last_point, endpoint->X + perp_dx,
2219 endpoint->Y + perp_dy, PathPointTypeLine);
2220 break;
2221 }
2222 case LineCapArrowAnchor:
2223 {
2224 REAL segment_dy = nextpoint->Y - endpoint->Y;
2225 REAL segment_dx = nextpoint->X - endpoint->X;
2226 REAL segment_length = hypotf(segment_dy, segment_dx);
2227 REAL par_dx = pen_width * segment_dx / segment_length;
2228 REAL par_dy = pen_width * segment_dy / segment_length;
2229 REAL perp_dx = -par_dy;
2230 REAL perp_dy = par_dx;
2231
2232 *last_point = add_path_list_node(*last_point, endpoint->X,
2234 *last_point = add_path_list_node(*last_point, endpoint->X + SQRT3 * par_dx - perp_dx,
2235 endpoint->Y + SQRT3 * par_dy - perp_dy, PathPointTypeLine);
2236 *last_point = add_path_list_node(*last_point, endpoint->X + SQRT3 * par_dx + perp_dx,
2237 endpoint->Y + SQRT3 * par_dy + perp_dy, PathPointTypeLine);
2238 break;
2239 }
2240 case LineCapCustom:
2241 {
2242 REAL segment_dy = nextpoint->Y - endpoint->Y;
2243 REAL segment_dx = nextpoint->X - endpoint->X;
2244 REAL segment_length = sqrtf(segment_dy * segment_dy + segment_dx * segment_dx);
2245 REAL posx, posy;
2246 REAL perp_dx, perp_dy;
2247 REAL sina, cosa;
2248 GpPointF *tmp_points;
2249
2250 if(!custom)
2251 break;
2252
2254 {
2255 GpAdjustableArrowCap *arrow = (GpAdjustableArrowCap *)custom;
2256 TRACE("GpAdjustableArrowCap middle_inset: %f height: %f width: %f\n",
2257 arrow->middle_inset, arrow->height, arrow->width);
2258 }
2259 else
2260 TRACE("GpCustomLineCap fill: %d basecap: %d inset: %f join: %d scale: %f pen_width:%f\n",
2261 custom->fill, custom->basecap, custom->inset, custom->join, custom->scale, pen_width);
2262
2263 sina = pen_width * custom->scale * segment_dx / segment_length;
2264 cosa = -pen_width * custom->scale * segment_dy / segment_length;
2265
2266 /* Coordination where cap needs to be drawn */
2267 posx = endpoint->X;
2268 posy = endpoint->Y;
2269
2270 if (!custom->fill)
2271 {
2272 tmp_points = malloc(custom->pathdata.Count * sizeof(*tmp_points));
2273 if (!tmp_points) {
2274 ERR("Out of memory\n");
2275 return;
2276 }
2277
2278 for (INT i = 0; i < custom->pathdata.Count; i++)
2279 {
2280 tmp_points[i].X = posx + custom->pathdata.Points[i].X * cosa - custom->pathdata.Points[i].Y * sina;
2281 tmp_points[i].Y = posy + custom->pathdata.Points[i].X * sina + custom->pathdata.Points[i].Y * cosa;
2282 }
2284 widen_closed_figure(tmp_points, 0, custom->pathdata.Count - 1, pen, pen_width, last_point);
2285 else
2286 widen_open_figure(tmp_points, 0, custom->pathdata.Count - 1, pen, pen_width, custom->strokeEndCap, NULL, custom->strokeStartCap, NULL, last_point);
2287 free(tmp_points);
2288 }
2289 else
2290 {
2291 for (INT i = 0; i < custom->pathdata.Count; i++)
2292 {
2293 /* rotation of CustomCap according to line */
2294 perp_dx = custom->pathdata.Points[i].X * cosa - custom->pathdata.Points[i].Y * sina;
2295 perp_dy = custom->pathdata.Points[i].X * sina + custom->pathdata.Points[i].Y * cosa;
2296 *last_point = add_path_list_node(*last_point, posx + perp_dx,
2297 posy + perp_dy, custom->pathdata.Types[i]);
2298 }
2299 }
2300 /* FIXME: The line should be adjusted by the inset value of the custom cap. */
2301 break;
2302 }
2303 }
2304
2305 (*last_point)->type |= PathPointTypeCloseSubpath;
2306}
2307
2308static void widen_open_figure(const GpPointF *points, int start, int end,
2309 GpPen *pen, REAL pen_width, GpLineCap start_cap, GpCustomLineCap* custom_start,
2310 GpLineCap end_cap, GpCustomLineCap* custom_end, path_list_node_t **last_point)
2311{
2312 int i;
2313 path_list_node_t *prev_point;
2314
2315 if (end <= start || pen_width == 0.0)
2316 return;
2317
2318 prev_point = *last_point;
2319
2321 pen_width, start_cap, custom_start, FALSE, TRUE, last_point);
2322
2323 for (i=start+1; i<end; i++)
2324 widen_joint(&points[i-1], &points[i], &points[i+1],
2325 pen, pen_width, last_point);
2326
2327 widen_cap(&points[end], &points[end-1],
2328 pen_width, end_cap, custom_end, TRUE, TRUE, last_point);
2329
2330 for (i=end-1; i>start; i--)
2331 widen_joint(&points[i+1], &points[i], &points[i-1],
2332 pen, pen_width, last_point);
2333
2335 pen_width, start_cap, custom_start, TRUE, FALSE, last_point);
2336
2337 prev_point->next->type = PathPointTypeStart;
2338 (*last_point)->type |= PathPointTypeCloseSubpath;
2339}
2340
2341static void widen_closed_figure(const GpPointF *points, int start, int end,
2342 GpPen *pen, REAL pen_width, path_list_node_t **last_point)
2343{
2344 int i;
2345 path_list_node_t *prev_point;
2346
2347 if (end <= start || pen_width == 0.0)
2348 return;
2349
2350 /* left outline */
2351 prev_point = *last_point;
2352
2354 &points[start+1], pen, pen_width, last_point);
2355
2356 for (i=start+1; i<end; i++)
2357 widen_joint(&points[i-1], &points[i],
2358 &points[i+1], pen, pen_width, last_point);
2359
2361 &points[start], pen, pen_width, last_point);
2362
2363 prev_point->next->type = PathPointTypeStart;
2364 (*last_point)->type |= PathPointTypeCloseSubpath;
2365
2366 /* right outline */
2367 prev_point = *last_point;
2368
2370 &points[end-1], pen, pen_width, last_point);
2371
2372 for (i=end-1; i>start; i--)
2373 widen_joint(&points[i+1], &points[i],
2374 &points[i-1], pen, pen_width, last_point);
2375
2377 &points[end], pen, pen_width, last_point);
2378
2379 prev_point->next->type = PathPointTypeStart;
2380 (*last_point)->type |= PathPointTypeCloseSubpath;
2381}
2382
2383static void widen_dashed_figure(GpPath *path, int start, int end, int closed,
2384 GpPen *pen, REAL pen_width, path_list_node_t **last_point)
2385{
2386 int i, j;
2387 REAL dash_pos=0.0;
2388 int dash_index=0;
2389 const REAL *dash_pattern;
2390 REAL *dash_pattern_scaled;
2391 REAL dash_pattern_scaling = max(pen->width, 1.0);
2392 int dash_count;
2393 GpPointF *tmp_points;
2394 REAL segment_dy;
2395 REAL segment_dx;
2396 REAL segment_length;
2397 REAL segment_pos;
2398 int num_tmp_points=0;
2399 int draw_start_cap=0;
2400 static const REAL dash_dot_dot[6] = { 3.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
2401
2402 if (end <= start || pen_width == 0.0)
2403 return;
2404
2405 switch (pen->dash)
2406 {
2407 case DashStyleDash:
2408 default:
2409 dash_pattern = dash_dot_dot;
2410 dash_count = 2;
2411 break;
2412 case DashStyleDot:
2413 dash_pattern = &dash_dot_dot[2];
2414 dash_count = 2;
2415 break;
2416 case DashStyleDashDot:
2417 dash_pattern = dash_dot_dot;
2418 dash_count = 4;
2419 break;
2421 dash_pattern = dash_dot_dot;
2422 dash_count = 6;
2423 break;
2424 case DashStyleCustom:
2425 dash_pattern = pen->dashes;
2426 dash_count = pen->numdashes;
2427 break;
2428 }
2429
2430 dash_pattern_scaled = malloc(dash_count * sizeof(REAL));
2431 if (!dash_pattern_scaled) return;
2432
2433 for (i = 0; i < dash_count; i++)
2434 dash_pattern_scaled[i] = dash_pattern_scaling * dash_pattern[i];
2435
2436 tmp_points = calloc(end - start + 2, sizeof(*tmp_points));
2437 if (!tmp_points) {
2438 free(dash_pattern_scaled);
2439 return; /* FIXME */
2440 }
2441
2442 if (!closed)
2443 draw_start_cap = 1;
2444
2445 for (j=start; j <= end; j++)
2446 {
2447 if (j == start)
2448 {
2449 if (closed)
2450 i = end;
2451 else
2452 continue;
2453 }
2454 else
2455 i = j-1;
2456
2457 segment_dy = path->pathdata.Points[j].Y - path->pathdata.Points[i].Y;
2458 segment_dx = path->pathdata.Points[j].X - path->pathdata.Points[i].X;
2459 segment_length = hypotf(segment_dy, segment_dx);
2460 segment_pos = 0.0;
2461
2462 while (1)
2463 {
2464 if (dash_pos == 0.0)
2465 {
2466 if ((dash_index % 2) == 0)
2467 {
2468 /* start dash */
2469 num_tmp_points = 1;
2470 tmp_points[0].X = path->pathdata.Points[i].X + segment_dx * segment_pos / segment_length;
2471 tmp_points[0].Y = path->pathdata.Points[i].Y + segment_dy * segment_pos / segment_length;
2472 }
2473 else
2474 {
2475 /* end dash */
2476 tmp_points[num_tmp_points].X = path->pathdata.Points[i].X + segment_dx * segment_pos / segment_length;
2477 tmp_points[num_tmp_points].Y = path->pathdata.Points[i].Y + segment_dy * segment_pos / segment_length;
2478
2479 widen_open_figure(tmp_points, 0, num_tmp_points, pen, pen_width,
2480 draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart,
2481 LineCapFlat, NULL, last_point);
2482 draw_start_cap = 0;
2483 num_tmp_points = 0;
2484 }
2485 }
2486
2487 if (dash_pattern_scaled[dash_index] - dash_pos > segment_length - segment_pos)
2488 {
2489 /* advance to next segment */
2490 if ((dash_index % 2) == 0)
2491 {
2492 tmp_points[num_tmp_points] = path->pathdata.Points[j];
2493 num_tmp_points++;
2494 }
2495 dash_pos += segment_length - segment_pos;
2496 break;
2497 }
2498 else
2499 {
2500 /* advance to next dash in pattern */
2501 segment_pos += dash_pattern_scaled[dash_index] - dash_pos;
2502 dash_pos = 0.0;
2503 if (++dash_index == dash_count)
2504 dash_index = 0;
2505 continue;
2506 }
2507 }
2508 }
2509
2510 if (dash_index % 2 == 0 && num_tmp_points != 0)
2511 {
2512 /* last dash overflows last segment */
2513 widen_open_figure(tmp_points, 0, num_tmp_points-1, pen, pen_width,
2514 draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart,
2515 closed ? LineCapFlat : pen->endcap, pen->customend, last_point);
2516 }
2517
2518 free(dash_pattern_scaled);
2519 free(tmp_points);
2520}
2521
2522void widen_anchors(GpPath *flat_path, GpPen *pen, REAL pen_width, path_list_node_t** last_point)
2523{
2524 BYTE *types = flat_path->pathdata.Types;
2525 int i, subpath_start=0;
2526
2527 for (i=0; i < flat_path->pathdata.Count; i++)
2528 {
2530 continue;
2531
2533 subpath_start = i;
2534
2535 if (i == flat_path->pathdata.Count-1 ||
2537 {
2538 if (pen->startcap & LineCapAnchorMask)
2539 add_anchor(&flat_path->pathdata.Points[subpath_start],
2540 &flat_path->pathdata.Points[subpath_start+1],
2541 pen, pen_width, pen->startcap, pen->customstart, last_point);
2542
2543 if (pen->endcap & LineCapAnchorMask)
2544 add_anchor(&flat_path->pathdata.Points[i],
2545 &flat_path->pathdata.Points[i-1],
2546 pen, pen_width, pen->endcap, pen->customend, last_point);
2547 }
2548 }
2549}
2550
2551GpStatus widen_flat_path_anchors(GpPath *flat_path, GpPen *pen, REAL pen_width, GpPath **anchors)
2552{
2553 GpStatus stat;
2554 path_list_node_t *points=NULL, *last_point=NULL;
2555
2556 if (!flat_path || !pen)
2557 return InvalidParameter;
2558
2559 if (init_path_list(&points, 314.0, 22.0))
2560 {
2561 last_point = points;
2562
2563 stat = GdipCreatePath(flat_path->fill, anchors);
2564 if (stat == Ok)
2565 {
2566 widen_anchors(flat_path, pen, pen_width, &last_point);
2567
2568 if (!path_list_to_path(points->next, *anchors))
2569 stat = OutOfMemory;
2570
2571 if (stat != Ok)
2572 {
2573 GdipDeletePath(*anchors);
2574 *anchors = NULL;
2575 }
2576 }
2578 }
2579 else
2580 stat = OutOfMemory;
2581
2582 /* FIXME: Apply insets to flat_path */
2583
2584 return stat;
2585}
2586
2588 REAL flatness)
2589{
2590 GpPath *flat_path=NULL;
2592 path_list_node_t *points=NULL, *last_point=NULL;
2593 int i, subpath_start=0;
2594
2595 TRACE("(%p,%p,%s,%0.2f)\n", path, pen, debugstr_matrix(matrix), flatness);
2596
2597 if (!path || !pen)
2598 return InvalidParameter;
2599
2600 if (path->pathdata.Count <= 1)
2601 return OutOfMemory;
2602
2603 status = GdipClonePath(path, &flat_path);
2604
2605 if (status == Ok)
2606 status = GdipFlattenPath(flat_path, pen->unit == UnitPixel ? matrix : NULL, flatness);
2607
2608 if (status == Ok && !init_path_list(&points, 314.0, 22.0))
2610
2611 if (status == Ok)
2612 {
2613 REAL pen_width = (pen->unit == UnitWorld) ? max(pen->width, 1.0) : pen->width;
2614 BYTE *types = flat_path->pathdata.Types;
2615
2616 last_point = points;
2617
2618 if (pen->dashcap != DashCapFlat)
2619 FIXME("unimplemented dash cap %d\n", pen->dashcap);
2620
2621 if (pen->join == LineJoinRound)
2622 FIXME("unimplemented line join %d\n", pen->join);
2623
2624 if (pen->align != PenAlignmentCenter)
2625 FIXME("unimplemented pen alignment %d\n", pen->align);
2626
2627 if (pen->compound_array_size != 0)
2628 FIXME("unimplemented pen compoundline. Solid line will be drawn instead: %d\n", pen->compound_array_size);
2629
2630 for (i=0; i < flat_path->pathdata.Count; i++)
2631 {
2633 subpath_start = i;
2634
2636 {
2637 if (pen->dash != DashStyleSolid)
2638 widen_dashed_figure(flat_path, subpath_start, i, 1, pen, pen_width, &last_point);
2639 else
2640 widen_closed_figure(flat_path->pathdata.Points, subpath_start, i, pen, pen_width, &last_point);
2641 }
2642 else if (i == flat_path->pathdata.Count-1 ||
2644 {
2645 if (pen->dash != DashStyleSolid)
2646 widen_dashed_figure(flat_path, subpath_start, i, 0, pen, pen_width, &last_point);
2647 else
2648 widen_open_figure(flat_path->pathdata.Points, subpath_start, i, pen, pen_width,
2649 pen->startcap, pen->customstart, pen->endcap, pen->customend, &last_point);
2650 }
2651 }
2652
2653 widen_anchors(flat_path, pen, fmax(pen->width, 2.0), &last_point);
2654
2655 if (!path_list_to_path(points->next, path))
2657
2658 path->fill = FillModeWinding;
2659 }
2660
2662
2663 GdipDeletePath(flat_path);
2664
2665 if (status == Ok && pen->unit != UnitPixel)
2667
2668 return status;
2669}
2670
2673{
2674 GpPath *backup;
2675 GpPointF ptf[2];
2676 GpStatus retstat;
2677 BOOL old_new;
2678
2679 TRACE("(%p, %.2f, %.2f, %.2f, %.2f)\n", path, x, y, width, height);
2680
2681 if(!path)
2682 return InvalidParameter;
2683
2684 if (width <= 0.0 || height <= 0.0)
2685 return Ok;
2686
2687 /* make a backup copy of path data */
2688 if((retstat = GdipClonePath(path, &backup)) != Ok)
2689 return retstat;
2690
2691 /* rectangle should start as new path */
2692 old_new = path->newfigure;
2693 path->newfigure = TRUE;
2694 if((retstat = GdipAddPathLine(path,x,y,x+width,y)) != Ok){
2695 path->newfigure = old_new;
2696 goto fail;
2697 }
2698
2699 ptf[0].X = x+width;
2700 ptf[0].Y = y+height;
2701 ptf[1].X = x;
2702 ptf[1].Y = y+height;
2703
2704 if((retstat = GdipAddPathLine2(path, ptf, 2)) != Ok) goto fail;
2705 path->pathdata.Types[path->pathdata.Count-1] |= PathPointTypeCloseSubpath;
2706 path->newfigure = TRUE;
2707
2708 /* free backup */
2710 return Ok;
2711
2712fail:
2713 /* reverting */
2714 free(path->pathdata.Points);
2715 free(path->pathdata.Types);
2716 memcpy(path, backup, sizeof(*path));
2717 free(backup);
2718
2719 return retstat;
2720}
2721
2724{
2725 TRACE("(%p, %d, %d, %d, %d)\n", path, x, y, width, height);
2726
2728}
2729
2731{
2732 GpPath *backup;
2733 GpStatus retstat;
2734 INT i;
2735
2736 TRACE("(%p, %p, %d)\n", path, rects, count);
2737
2738 /* count == 0 - verified condition */
2739 if(!path || !rects || count == 0)
2740 return InvalidParameter;
2741
2742 if(count < 0)
2743 return OutOfMemory;
2744
2745 /* make a backup copy */
2746 if((retstat = GdipClonePath(path, &backup)) != Ok)
2747 return retstat;
2748
2749 for(i = 0; i < count; i++){
2750 if((retstat = GdipAddPathRectangle(path,rects[i].X,rects[i].Y,rects[i].Width,rects[i].Height)) != Ok)
2751 goto fail;
2752 }
2753
2754 /* free backup */
2756 return Ok;
2757
2758fail:
2759 /* reverting */
2760 free(path->pathdata.Points);
2761 free(path->pathdata.Types);
2762 memcpy(path, backup, sizeof(*path));
2763 free(backup);
2764
2765 return retstat;
2766}
2767
2769{
2770 GpRectF *rectsF;
2771 GpStatus retstat;
2772 INT i;
2773
2774 TRACE("(%p, %p, %d)\n", path, rects, count);
2775
2776 if(!rects || count == 0)
2777 return InvalidParameter;
2778
2779 if(count < 0)
2780 return OutOfMemory;
2781
2782 rectsF = malloc(sizeof(GpRectF) * count);
2783
2784 for(i = 0;i < count;i++)
2785 set_rect(&rectsF[i], rects[i].X, rects[i].Y, rects[i].Width, rects[i].Height);
2786
2787 retstat = GdipAddPathRectangles(path, rectsF, count);
2788 free(rectsF);
2789
2790 return retstat;
2791}
2792
2794{
2795 INT count;
2796
2797 TRACE("(%p)\n", path);
2798
2799 if(!path)
2800 return InvalidParameter;
2801
2802 count = path->pathdata.Count;
2803
2804 /* set marker flag */
2805 if(count > 0)
2806 path->pathdata.Types[count-1] |= PathPointTypePathMarker;
2807
2808 return Ok;
2809}
2810
2812{
2813 INT count;
2814 INT i;
2815
2816 TRACE("(%p)\n", path);
2817
2818 if(!path)
2819 return InvalidParameter;
2820
2821 count = path->pathdata.Count;
2822
2823 for(i = 0; i < count - 1; i++){
2824 path->pathdata.Types[i] &= ~PathPointTypePathMarker;
2825 }
2826
2827 return Ok;
2828}
2829
2831{
2832 FIXME("stub: %p, %p, %.2f\n", path, matrix, flatness);
2833 return NotImplemented;
2834}
2835
2836#define FLAGS_INTPATH 0x4000
2837
2839{
2843};
2844
2845/* Test to see if the path could be stored as an array of shorts */
2847{
2848 int i;
2849
2850 if (!path->pathdata.Count) return FALSE;
2851
2852 for (i = 0; i < path->pathdata.Count; i++)
2853 {
2854 short x, y;
2855 x = gdip_round(path->pathdata.Points[i].X);
2856 y = gdip_round(path->pathdata.Points[i].Y);
2857 if (path->pathdata.Points[i].X != (REAL)x || path->pathdata.Points[i].Y != (REAL)y)
2858 return FALSE;
2859 }
2860 return TRUE;
2861}
2862
2864{
2865 struct path_header *header = data;
2866 BOOL integer_path = is_integer_path(path);
2867 DWORD i, size;
2868 BYTE *types;
2869
2870 size = sizeof(struct path_header) + path->pathdata.Count;
2871 if (integer_path)
2872 size += sizeof(short[2]) * path->pathdata.Count;
2873 else
2874 size += sizeof(float[2]) * path->pathdata.Count;
2875 size = (size + 3) & ~3;
2876
2877 if (!data) return size;
2878
2879 header->version = VERSION_MAGIC2;
2880 header->count = path->pathdata.Count;
2881 header->flags = integer_path ? FLAGS_INTPATH : 0;
2882
2883 if (integer_path)
2884 {
2885 short *points = (short*)(header + 1);
2886 for (i = 0; i < path->pathdata.Count; i++)
2887 {
2888 points[2*i] = path->pathdata.Points[i].X;
2889 points[2*i + 1] = path->pathdata.Points[i].Y;
2890 }
2891 types = (BYTE*)(points + 2*i);
2892 }
2893 else
2894 {
2895 float *points = (float*)(header + 1);
2896 for (i = 0; i < path->pathdata.Count; i++)
2897 {
2898 points[2*i] = path->pathdata.Points[i].X;
2899 points[2*i + 1] = path->pathdata.Points[i].Y;
2900 }
2901 types = (BYTE*)(points + 2*i);
2902 }
2903
2904 for (i=0; i<path->pathdata.Count; i++)
2905 types[i] = path->pathdata.Types[i];
2906 memset(types + i, 0, ((path->pathdata.Count + 3) & ~3) - path->pathdata.Count);
2907 return size;
2908}
static HFONT hfont
static HRGN hrgn
_STLP_MOVE_TO_STD_NAMESPACE void fill(_ForwardIter __first, _ForwardIter __last, const _Tp &__val)
Definition: _algobase.h:449
char ACPI_OBJECT_TYPE * Types
Definition: acdebug.h:354
unsigned short UINT16
Definition: actypes.h:129
#define stat
Definition: acwin.h:100
Arabic default style
Definition: afstyles.h:94
static long backup()
Definition: maze.c:403
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
static void list_remove(struct list_entry *entry)
Definition: list.h:90
static void list_init(struct list_entry *head)
Definition: list.h:51
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
Definition: list.h:37
RECT rect
Definition: combotst.c:67
HDC dc
Definition: cylfrac.c:34
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
float REAL
Definition: types.h:41
#define Y(I)
GpStatus WINGDIPAPI GdipDeleteFont(GpFont *font)
Definition: font.c:272
GpStatus WINGDIPAPI GdipCreateFont(GDIPCONST GpFontFamily *fontFamily, REAL emSize, INT style, Unit unit, GpFont **font)
Definition: font.c:150
GpStatus WINGDIPAPI GdipGetEmHeight(GDIPCONST GpFontFamily *family, INT style, UINT16 *EmHeight)
Definition: font.c:872
GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics)
Definition: graphics.c:2434
GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
Definition: graphics.c:2616
GpStatus WINGDIPAPI GdipAddPathCurve3(GpPath *path, GDIPCONST GpPointF *points, INT count, INT offset, INT nseg, REAL tension)
Definition: graphicspath.c:595
static BOOL flatten_bezier_add(struct list *jobs, path_list_node_t *start, REAL x2, REAL y2, REAL x3, REAL y3, path_list_node_t *end)
Definition: graphicspath.c:159
static INT path_list_count(path_list_node_t *node)
Definition: graphicspath.c:96
GpStatus WINGDIPAPI GdipGetPathWorldBoundsI(GpPath *path, GpRect *bounds, GDIPCONST GpMatrix *matrix, GDIPCONST GpPen *pen)
static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint, REAL pen_width, GpLineCap cap, GpCustomLineCap *custom_cap, int add_first_points, int add_last_point, path_list_node_t **last_point)
GpStatus WINGDIPAPI GdipClearPathMarkers(GpPath *path)
GpStatus WINGDIPAPI GdipIsOutlineVisiblePathPointI(GpPath *path, INT x, INT y, GpPen *pen, GpGraphics *graphics, BOOL *result)
GpStatus WINGDIPAPI GdipAddPathRectangleI(GpPath *path, INT x, INT y, INT width, INT height)
static void widen_dashed_figure(GpPath *path, int start, int end, int closed, GpPen *pen, REAL pen_width, path_list_node_t **last_point)
GpStatus WINGDIPAPI GdipCreatePath(GpFillMode fill, GpPath **path)
GpStatus WINGDIPAPI GdipDeletePath(GpPath *path)
static GpStatus format_string_callback(struct gdip_format_string_info *info)
GpStatus WINGDIPAPI GdipCreatePath2I(GDIPCONST GpPoint *points, GDIPCONST BYTE *types, INT count, GpFillMode fill, GpPath **path)
GpStatus WINGDIPAPI GdipAddPathPie(GpPath *path, REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
Definition: graphicspath.c:864
#define FLAGS_INTPATH
DWORD write_path_data(GpPath *path, void *data)
GpStatus WINGDIPAPI GdipAddPathEllipseI(GpPath *path, INT x, INT y, INT width, INT height)
Definition: graphicspath.c:735
GpStatus WINGDIPAPI GdipAddPathLine(GpPath *path, REAL x1, REAL y1, REAL x2, REAL y2)
Definition: graphicspath.c:804
static BOOL flatten_bezier(path_list_node_t *start, REAL x2, REAL y2, REAL x3, REAL y3, path_list_node_t *end, REAL flatness)
Definition: graphicspath.c:193
static void free_path_list(path_list_node_t *node)
Definition: graphicspath.c:61
static float fromfixedpoint(const FIXED v)
Definition: graphicspath.c:985
GpStatus WINGDIPAPI GdipAddPathRectangle(GpPath *path, REAL x, REAL y, REAL width, REAL height)
GpStatus WINGDIPAPI GdipAddPathCurve(GpPath *path, GDIPCONST GpPointF *points, INT count)
Definition: graphicspath.c:581
GpStatus WINGDIPAPI GdipIsOutlineVisiblePathPoint(GpPath *path, REAL x, REAL y, GpPen *pen, GpGraphics *graphics, BOOL *result)
GpStatus WINGDIPAPI GdipGetPathData(GpPath *path, GpPathData *pathData)
GpStatus WINGDIPAPI GdipResetPath(GpPath *path)
static void widen_closed_figure(const GpPointF *points, int start, int end, GpPen *pen, REAL pen_width, path_list_node_t **last_point)
GpStatus WINGDIPAPI GdipAddPathPieI(GpPath *path, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
Definition: graphicspath.c:923
GpStatus WINGDIPAPI GdipCreatePath2(GDIPCONST GpPointF *points, GDIPCONST BYTE *types, INT count, GpFillMode fill, GpPath **path)
static void widen_open_figure(const GpPointF *points, int start, int end, GpPen *pen, REAL pen_width, GpLineCap start_cap, GpCustomLineCap *custom_start, GpLineCap end_cap, GpCustomLineCap *custom_end, path_list_node_t **last_point)
GpStatus WINGDIPAPI GdipAddPathLine2(GpPath *path, GDIPCONST GpPointF *points, INT count)
Definition: graphicspath.c:743
GpStatus WINGDIPAPI GdipFlattenPath(GpPath *path, GpMatrix *matrix, REAL flatness)
void widen_anchors(GpPath *flat_path, GpPen *pen, REAL pen_width, path_list_node_t **last_point)
GpStatus WINGDIPAPI GdipAddPathClosedCurve2I(GpPath *path, GDIPCONST GpPoint *points, INT count, REAL tension)
Definition: graphicspath.c:553
GpStatus WINGDIPAPI GdipAddPathArcI(GpPath *path, INT x1, INT y1, INT x2, INT y2, REAL startAngle, REAL sweepAngle)
Definition: graphicspath.c:387
GpStatus WINGDIPAPI GdipAddPathStringI(GpPath *path, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFontFamily *family, INT style, REAL emSize, GDIPCONST Rect *layoutRect, GDIPCONST GpStringFormat *format)
GpStatus WINGDIPAPI GdipGetPathLastPoint(GpPath *path, GpPointF *lastPoint)
GpStatus WINGDIPAPI GdipClosePathFigure(GpPath *path)
GpStatus WINGDIPAPI GdipAddPathPolygon(GpPath *path, GDIPCONST GpPointF *points, INT count)
Definition: graphicspath.c:932
static BOOL init_path_list(path_list_node_t **node, REAL x, REAL y)
Definition: graphicspath.c:46
GpStatus widen_flat_path_anchors(GpPath *flat_path, GpPen *pen, REAL pen_width, GpPath **anchors)
GpStatus WINGDIPAPI GdipWarpPath(GpPath *path, GpMatrix *matrix, GDIPCONST GpPointF *points, INT count, REAL x, REAL y, REAL width, REAL height, WarpMode warpmode, REAL flatness)
GpStatus WINGDIPAPI GdipClonePath(GpPath *path, GpPath **clone)
static GpStatus extend_current_figure(GpPath *path, GDIPCONST PointF *points, INT count, BYTE type)
Definition: graphicspath.c:297
GpStatus WINGDIPAPI GdipAddPathCurve2I(GpPath *path, GDIPCONST GpPoint *points, INT count, REAL tension)
Definition: graphicspath.c:659
GpStatus WINGDIPAPI GdipTransformPath(GpPath *path, GpMatrix *matrix)
GpStatus WINGDIPAPI GdipAddPathCurveI(GpPath *path, GDIPCONST GpPoint *points, INT count)
Definition: graphicspath.c:588
GpStatus WINGDIPAPI GdipAddPathBezierI(GpPath *path, INT x1, INT y1, INT x2, INT y2, INT x3, INT y3, INT x4, INT y4)
Definition: graphicspath.c:419
static void widen_joint(const GpPointF *p1, const GpPointF *p2, const GpPointF *p3, GpPen *pen, REAL pen_width, path_list_node_t **last_point)
GpStatus WINGDIPAPI GdipAddPathLineI(GpPath *path, INT x1, INT y1, INT x2, INT y2)
Definition: graphicspath.c:826
GpStatus WINGDIPAPI GdipGetPathPointsI(GpPath *path, GpPoint *points, INT count)
GpStatus WINGDIPAPI GdipSetPathFillMode(GpPath *path, GpFillMode fill)
static void add_bevel_point(const GpPointF *endpoint, const GpPointF *nextpoint, REAL pen_width, int right_side, path_list_node_t **last_point)
static BOOL is_integer_path(const GpPath *path)
GpStatus WINGDIPAPI GdipAddPathPath(GpPath *path, GDIPCONST GpPath *addingPath, BOOL connect)
Definition: graphicspath.c:833
static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, GpPen *pen, REAL pen_width, GpLineCap cap, GpCustomLineCap *custom, path_list_node_t **last_point)
GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix, REAL flatness)
GpStatus WINGDIPAPI GdipAddPathBeziers(GpPath *path, GDIPCONST GpPointF *points, INT count)
Definition: graphicspath.c:429
GpStatus WINGDIPAPI GdipAddPathLine2I(GpPath *path, GDIPCONST GpPoint *points, INT count)
Definition: graphicspath.c:754
GpStatus WINGDIPAPI GdipGetPathWorldBounds(GpPath *path, GpRectF *bounds, GDIPCONST GpMatrix *matrix, GDIPCONST GpPen *pen)
GpStatus WINGDIPAPI GdipAddPathRectangles(GpPath *path, GDIPCONST GpRectF *rects, INT count)
GpStatus WINGDIPAPI GdipWindingModeOutline(GpPath *path, GpMatrix *matrix, REAL flatness)
GpStatus WINGDIPAPI GdipAddPathPolygonI(GpPath *path, GDIPCONST GpPoint *points, INT count)
Definition: graphicspath.c:958
GpStatus WINGDIPAPI GdipIsVisiblePathPoint(GpPath *path, REAL x, REAL y, GpGraphics *graphics, BOOL *result)
GpStatus WINGDIPAPI GdipAddPathCurve2(GpPath *path, GDIPCONST GpPointF *points, INT count, REAL tension)
Definition: graphicspath.c:667
GpStatus WINGDIPAPI GdipAddPathBeziersI(GpPath *path, GDIPCONST GpPoint *points, INT count)
Definition: graphicspath.c:440
GpStatus WINGDIPAPI GdipGetPointCount(GpPath *path, INT *count)
GpStatus WINGDIPAPI GdipGetPathPoints(GpPath *path, GpPointF *points, INT count)
GpStatus WINGDIPAPI GdipIsVisiblePathPointI(GpPath *path, INT x, INT y, GpGraphics *graphics, BOOL *result)
GpStatus WINGDIPAPI GdipAddPathClosedCurveI(GpPath *path, GDIPCONST GpPoint *points, INT count)
Definition: graphicspath.c:475
GpStatus WINGDIPAPI GdipAddPathBezier(GpPath *path, REAL x1, REAL y1, REAL x2, REAL y2, REAL x3, REAL y3, REAL x4, REAL y4)
Definition: graphicspath.c:396
GpStatus WINGDIPAPI GdipAddPathRectanglesI(GpPath *path, GDIPCONST GpRect *rects, INT count)
static BOOL path_list_to_path(path_list_node_t *node, GpPath *path)
Definition: graphicspath.c:109
static path_list_node_t * add_path_list_node(path_list_node_t *node, REAL x, REAL y, BOOL type)
Definition: graphicspath.c:78
GpStatus WINGDIPAPI GdipReversePath(GpPath *path)
GpStatus WINGDIPAPI GdipClosePathFigures(GpPath *path)
GpStatus WINGDIPAPI GdipGetPathTypes(GpPath *path, BYTE *types, INT count)
GpStatus WINGDIPAPI GdipStartPathFigure(GpPath *path)
GpStatus WINGDIPAPI GdipAddPathArc(GpPath *path, REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
Definition: graphicspath.c:353
#define SQRT3
Definition: graphicspath.c:36
GpStatus WINGDIPAPI GdipGetPathFillMode(GpPath *path, GpFillMode *fillmode)
GpStatus WINGDIPAPI GdipAddPathEllipse(GpPath *path, REAL x, REAL y, REAL width, REAL height)
Definition: graphicspath.c:703
GpStatus WINGDIPAPI GdipAddPathClosedCurve(GpPath *path, GDIPCONST GpPointF *points, INT count)
Definition: graphicspath.c:467
GpStatus WINGDIPAPI GdipAddPathClosedCurve2(GpPath *path, GDIPCONST GpPointF *points, INT count, REAL tension)
Definition: graphicspath.c:483
GpStatus WINGDIPAPI GdipAddPathString(GpPath *path, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFontFamily *family, INT style, REAL emSize, GDIPCONST RectF *layoutRect, GDIPCONST GpStringFormat *format)
GpStatus WINGDIPAPI GdipSetPathMarker(GpPath *path)
GpStatus WINGDIPAPI GdipAddPathCurve3I(GpPath *path, GDIPCONST GpPoint *points, INT count, INT offset, INT nseg, REAL tension)
Definition: graphicspath.c:675
GpStatus WINGDIPAPI GdipDeleteMatrix(GpMatrix *matrix)
Definition: matrix.c:156
GpStatus WINGDIPAPI GdipTransformMatrixPoints(GpMatrix *matrix, GpPointF *pts, INT count)
Definition: matrix.c:365
GpStatus WINGDIPAPI GdipCreateMatrix(GpMatrix **matrix)
Definition: matrix.c:136
GpStatus WINGDIPAPI GdipGetRegionHRgn(GpRegion *region, GpGraphics *graphics, HRGN *hrgn)
Definition: region.c:1201
GpStatus WINGDIPAPI GdipCreateRegionPath(GpPath *path, GpRegion **region)
Definition: region.c:425
GpStatus WINGDIPAPI GdipDeleteRegion(GpRegion *region)
Definition: region.c:567
static MonoProfilerRuntimeShutdownBeginCallback cb
Definition: metahost.c:118
_ACRTIMP double __cdecl fabs(double)
static float hypotf(float x, float y)
Definition: math.h:428
_ACRTIMP double __cdecl fmax(double, double)
#define pt(x, y)
Definition: drawing.c:79
return ret
Definition: mutex.c:146
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
pKey DeleteObject()
BOOL lengthen_path(GpPath *path, INT len)
Definition: gdiplus.c:415
void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1, REAL *y1, REAL *x2, REAL *y2)
Definition: gdiplus.c:389
void calc_curve_bezier_endp(REAL xend, REAL yend, REAL xadj, REAL yadj, REAL tension, REAL *x, REAL *y)
Definition: gdiplus.c:406
INT arc2polybezier(GpPointF *points, REAL left, REAL top, REAL width, REAL height, REAL start_angle, REAL sweep_angle)
Definition: gdiplus.c:223
const char * debugstr_matrix(const GpMatrix *matrix)
Definition: gdiplus.c:498
GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space, GpCoordinateSpace src_space, GpMatrix *matrix)
Definition: graphics.c:7266
static INT gdip_round(REAL x)
static void set_rect(GpRectF *rect, REAL x, REAL y, REAL width, REAL height)
#define VERSION_MAGIC2
#define TENSION_CONST
#define MAX_ARC_PTS
GpStatus gdip_format_string(GpGraphics *graphics, HDC hdc, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, int ignore_empty_clip, gdip_format_string_callback callback, void *user_data)
Definition: graphics.c:5478
const struct GpStringFormat default_drawstring_format
Definition: stringformat.c:35
void get_font_hfont(GpGraphics *graphics, GDIPCONST GpFont *font, GDIPCONST GpStringFormat *format, HFONT *hfont, LOGFONTW *lfw_return, GDIPCONST GpMatrix *matrix)
Definition: graphics.c:2385
void get_log_fontW(const GpFont *, GpGraphics *, LOGFONTW *)
Definition: graphics.c:2353
@ DashCapFlat
Definition: gdiplusenums.h:170
@ LineJoinMiter
Definition: gdiplusenums.h:105
@ LineJoinMiterClipped
Definition: gdiplusenums.h:108
@ LineJoinBevel
Definition: gdiplusenums.h:106
@ LineJoinRound
Definition: gdiplusenums.h:107
@ StringAlignmentCenter
Definition: gdiplusenums.h:264
@ StringAlignmentFar
Definition: gdiplusenums.h:265
@ CustomLineCapTypeAdjustableArrow
Definition: gdiplusenums.h:79
LineCap
Definition: gdiplusenums.h:60
@ LineCapTriangle
Definition: gdiplusenums.h:64
@ LineCapAnchorMask
Definition: gdiplusenums.h:73
@ LineCapCustom
Definition: gdiplusenums.h:72
@ LineCapArrowAnchor
Definition: gdiplusenums.h:70
@ LineCapNoAnchor
Definition: gdiplusenums.h:66
@ LineCapSquare
Definition: gdiplusenums.h:62
@ LineCapSquareAnchor
Definition: gdiplusenums.h:67
@ LineCapRound
Definition: gdiplusenums.h:63
@ LineCapRoundAnchor
Definition: gdiplusenums.h:68
@ LineCapFlat
Definition: gdiplusenums.h:61
@ LineCapDiamondAnchor
Definition: gdiplusenums.h:69
FillMode
Definition: gdiplusenums.h:54
@ FillModeAlternate
Definition: gdiplusenums.h:55
@ FillModeWinding
Definition: gdiplusenums.h:56
@ DashStyleSolid
Definition: gdiplusenums.h:177
@ DashStyleDot
Definition: gdiplusenums.h:179
@ DashStyleDashDot
Definition: gdiplusenums.h:180
@ DashStyleCustom
Definition: gdiplusenums.h:182
@ DashStyleDash
Definition: gdiplusenums.h:178
@ DashStyleDashDotDot
Definition: gdiplusenums.h:181
WarpMode
Definition: gdiplusenums.h:198
@ PenAlignmentCenter
Definition: gdiplusenums.h:154
@ UnitWorld
Definition: gdiplusenums.h:27
@ UnitPixel
Definition: gdiplusenums.h:29
@ PathPointTypePathMarker
Definition: gdiplusenums.h:88
@ PathPointTypePathTypeMask
Definition: gdiplusenums.h:86
@ PathPointTypeBezier
Definition: gdiplusenums.h:85
@ PathPointTypeLine
Definition: gdiplusenums.h:84
@ PathPointTypeCloseSubpath
Definition: gdiplusenums.h:89
@ PathPointTypeStart
Definition: gdiplusenums.h:83
@ CoordinateSpaceDevice
Definition: gdiplusenums.h:406
@ CoordinateSpaceWorld
Definition: gdiplusenums.h:404
#define GDIPCONST
Definition: gdiplusflat.h:24
#define WINGDIPAPI
Definition: gdiplusflat.h:22
Status
Definition: gdiplustypes.h:24
@ Ok
Definition: gdiplustypes.h:25
@ InvalidParameter
Definition: gdiplustypes.h:27
@ OutOfMemory
Definition: gdiplustypes.h:28
@ InsufficientBuffer
Definition: gdiplustypes.h:30
@ NotImplemented
Definition: gdiplustypes.h:31
@ GenericError
Definition: gdiplustypes.h:26
GLuint start
Definition: gl.h:1545
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
const GLdouble * v
Definition: gl.h:2040
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLuint GLuint end
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
GLint GLint GLsizei width
Definition: gl.h:1546
GLdouble n
Definition: glext.h:7729
GLuint GLenum GLenum transform
Definition: glext.h:9407
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
GLfloat f
Definition: glext.h:7540
GLsizei GLsizei GLfloat distance
Definition: glext.h:11755
GLuint GLenum matrix
Definition: glext.h:9407
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLuint64EXT * result
Definition: glext.h:11304
GLenum GLsizei len
Definition: glext.h:6722
GLenum cap
Definition: glext.h:9639
GLsizei const GLfloat * points
Definition: glext.h:8112
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
uint32_t entry
Definition: isohybrid.c:63
#define e
Definition: ke_i.h:82
#define f
Definition: ke_i.h:83
#define debugstr_w
Definition: kernel32.h:32
GLint dy
Definition: linetemp.h:97
GLint dx
Definition: linetemp.h:97
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
struct task_struct * current
Definition: linux.c:32
static HDC
Definition: imagelist.c:88
static HANDLE job
Definition: process.c:79
static float int float int float int x3
Definition: server.c:79
static float int float int float int float int x4
Definition: server.c:79
static float int float int float int float y3
Definition: server.c:79
static float int float int float int float int float y4
Definition: server.c:79
static float(__cdecl *square_half_float)(float x
#define min(a, b)
Definition: monoChain.cc:55
#define sqrtf(x)
Definition: mymath.h:59
Definition: mk_font.cpp:20
int Count
Definition: noreturn.cpp:7
short WCHAR
Definition: pedump.c:58
static unsigned __int64 next
Definition: rand_nt.c:6
#define calloc
Definition: rosglue.h:14
#define list
Definition: rosglue.h:35
static calc_node_t temp
Definition: rpn_ieee.c:38
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field)
Definition: list.h:204
__WINE_SERVER_LIST_INLINE struct list * list_next(const struct list *list, const struct list *elem)
Definition: list.h:115
__WINE_SERVER_LIST_INLINE void list_add_after(struct list *elem, struct list *to_add)
Definition: list.h:78
#define memset(x, y, z)
Definition: compat.h:39
#define TRACE(s)
Definition: solgame.cpp:4
GpPathData pathdata
CustomLineCapType type
GpLineCap strokeEndCap
GpLineCap strokeStartCap
GpPathData pathdata
GpFillMode fill
GpDashStyle dash
GpLineCap startcap
INT numdashes
REAL * dashes
GpCustomLineCap * customend
REAL miterlimit
GpLineCap endcap
GpLineJoin join
GpDashCap dashcap
GpPenAlignment align
INT compound_array_size
GpUnit unit
REAL width
GpCustomLineCap * customstart
PointF * Points
Definition: gdiplustypes.h:650
BYTE * Types
Definition: gdiplustypes.h:651
REAL Y
Definition: gdiplustypes.h:644
REAL X
Definition: gdiplustypes.h:643
REAL Height
Definition: gdiplustypes.h:659
REAL X
Definition: gdiplustypes.h:656
REAL Width
Definition: gdiplustypes.h:658
REAL Y
Definition: gdiplustypes.h:657
INT Width
Definition: gdiplustypes.h:666
INT Height
Definition: gdiplustypes.h:667
INT X
Definition: gdiplustypes.h:664
INT Y
Definition: gdiplustypes.h:665
short gmCellIncX
Definition: wingdi.h:2891
short gmCellIncY
Definition: wingdi.h:2892
Definition: wingdi.h:2918
Definition: match.c:390
Definition: nis.h:10
path_list_node_t * end
Definition: graphicspath.c:155
path_list_node_t * start
Definition: graphicspath.c:150
struct list entry
Definition: graphicspath.c:156
Definition: format.c:58
unsigned int index
Definition: notification.c:74
Definition: list.h:15
path_list_node_t * next
Definition: graphicspath.c:42
Definition: parser.c:56
Definition: stat.h:66
Definition: ps.c:97
FIXED y
Definition: wingdi.h:3155
FIXED x
Definition: wingdi.h:3154
LONG tmAscent
Definition: wingdi.h:2830
POINTFX apfx[1]
Definition: wingdi.h:3160
POINTFX pfxStart
Definition: wingdi.h:3165
Definition: cmds.c:130
#define max(a, b)
Definition: svc.c:63
#define LIST_ENTRY(type)
Definition: queue.h:175
int32_t INT
Definition: typedefs.h:58
Definition: dlist.c:348
void * next
Definition: dlist.c:360
_In_ HFONT _Out_ PUINT _Out_ PUINT Width
Definition: font.h:89
_In_ HFONT _Out_ PUINT Height
Definition: font.h:88
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3708
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG y1
Definition: winddi.h:3709
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG _In_ LONG _In_ LONG y2
Definition: winddi.h:3711
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG _In_ LONG x2
Definition: winddi.h:3710
BOOL WINAPI GetTextMetricsW(_In_ HDC, _Out_ LPTEXTMETRICW)
Definition: text.c:221
struct tagPOINTFX POINTFX
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1546
#define TT_PRIM_CSPLINE
Definition: wingdi.h:1321
struct tagTTPOLYCURVE TTPOLYCURVE
HDC WINAPI CreateCompatibleDC(_In_opt_ HDC hdc)
BOOL WINAPI PtInRegion(_In_ HRGN, _In_ int, _In_ int)
#define GDI_ERROR
Definition: wingdi.h:1309
HFONT WINAPI CreateFontIndirectW(_In_ const LOGFONTW *)
BOOL WINAPI DeleteDC(_In_ HDC)
#define TT_PRIM_LINE
Definition: wingdi.h:1319
DWORD WINAPI GetGlyphOutlineW(_In_ HDC hdc, _In_ UINT uChar, _In_ UINT fuFormat, _Out_ LPGLYPHMETRICS lpgm, _In_ DWORD cjBuffer, _Out_writes_bytes_opt_(cjBuffer) LPVOID pvBuffer, _In_ CONST MAT2 *lpmat2)
#define GGO_BEZIER
Definition: wingdi.h:851
unsigned char BYTE
Definition: xxhash.c:193