ReactOS 0.4.16-dev-1946-g52006dd
path.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/path.c
5 * PURPOSE: Graphics paths (BeginPath, EndPath etc.)
6 * PROGRAMMER: Copyright 1997, 1998 Martin Boehme
7 * 1999 Huw D M Davies
8 * 2005 Dmitry Timoshkov
9 * 2018 Katayama Hirofumi MZ
10 */
11
12#include <win32k.h>
13#include <suppress.h>
14
16
17#ifdef _MSC_VER
18#pragma warning(disable:4244)
19#endif
20
21#define NUM_ENTRIES_INITIAL 16 /* Initial size of points / flags arrays */
22
23#define GROW_FACTOR_NUMER 2 /* Numerator of grow factor for the array */
24#define GROW_FACTOR_DENOM 1 /* Denominator of grow factor */
25
26#if DBG
27static int PathCount = 0;
28#endif
29
30/***********************************************************************
31 * Internal functions
32 */
33
36{
38
39 if (!pPath)
40 {
42 return NULL;
43 }
44
45 TRACE("CreatePath p 0x%p\n", pPath);
46 // Path handles are shared. Also due to recursion with in the same thread.
47 GDIOBJ_vUnlockObject((POBJ)pPath); // Unlock
48 pPath = PATH_LockPath(pPath->BaseObject.hHmgr); // Share Lock.
49
50 /* Make sure that path is empty */
51 PATH_EmptyPath(pPath);
52
54
56
58 RtlZeroMemory( pPath->pPoints, count * sizeof(POINT));
60 RtlZeroMemory( pPath->pFlags, count * sizeof(BYTE));
61
62 /* Initialize variables for new path */
63 pPath->numEntriesUsed = 0;
64 pPath->newStroke = TRUE;
65 pPath->state = PATH_Open;
66 pPath->pos.x = pPath->pos.y = 0;
67#if DBG
68 PathCount++;
69 TRACE("Create Path %d\n",PathCount);
70#endif
71 return pPath;
72}
73
74/* PATH_DestroyGdiPath
75 *
76 * Destroys a GdiPath structure (frees the memory in the arrays).
77 */
78VOID
81{
82 ASSERT(pPath != NULL);
83
84 if (pPath->pPoints) ExFreePoolWithTag(pPath->pPoints, TAG_PATH);
85 if (pPath->pFlags) ExFreePoolWithTag(pPath->pFlags, TAG_PATH);
86}
87
88BOOL
91{
92 PPATH pPath;
93 if (!hPath) return FALSE;
94 pPath = PATH_LockPath(hPath);
95 if (!pPath) return FALSE;
98#if DBG
99 PathCount--;
100 TRACE("Delete Path %d\n",PathCount);
101#endif
102 return TRUE;
103}
104
105
106VOID
109{
110 ASSERT(pPath->state == PATH_Open);
111
112 // FIXME: Shouldn't we draw a line to the beginning of the figure?
113 // Set PT_CLOSEFIGURE on the last entry and start a new stroke
114 if (pPath->numEntriesUsed)
115 {
116 pPath->pFlags[pPath->numEntriesUsed - 1] |= PT_CLOSEFIGURE;
117 pPath->newStroke = TRUE;
118 }
119}
120
121/* MSDN: This fails if the device coordinates exceed 27 bits, or if the converted
122 logical coordinates exceed 32 bits. */
123BOOL
126 PDC pdc,
127 PPOINT ppt,
128 INT count)
129{
130 XFORMOBJ xo;
131
132 XFORMOBJ_vInit(&xo, &pdc->pdcattr->mxDeviceToWorld);
133 return XFORMOBJ_bApplyXform(&xo, XF_LTOL, count, (PPOINTL)ppt, (PPOINTL)ppt);
134}
135
136/* PATH_InitGdiPath
137 *
138 * Initializes the GdiPath structure.
139 */
140VOID
143 PPATH pPath)
144{
145 ASSERT(pPath != NULL);
146
147 pPath->state = PATH_Null;
148 pPath->pPoints = NULL;
149 pPath->pFlags = NULL;
150 pPath->numEntriesUsed = 0;
151 pPath->numEntriesAllocated = 0;
152}
153
154/* PATH_AssignGdiPath
155 *
156 * Copies the GdiPath structure "pPathSrc" to "pPathDest". A deep copy is
157 * performed, i.e. the contents of the pPoints and pFlags arrays are copied,
158 * not just the pointers. Since this means that the arrays in pPathDest may
159 * need to be resized, pPathDest should have been initialized using
160 * PATH_InitGdiPath (in C++, this function would be an assignment operator,
161 * not a copy constructor).
162 * Returns TRUE if successful, else FALSE.
163 */
164BOOL
167 PPATH pPathDest,
168 const PPATH pPathSrc)
169{
170 ASSERT(pPathDest != NULL && pPathSrc != NULL);
171
172 /* Make sure destination arrays are big enough */
173 if (!PATH_ReserveEntries(pPathDest, pPathSrc->numEntriesUsed))
174 return FALSE;
175
176 /* Perform the copy operation */
177 memcpy(pPathDest->pPoints, pPathSrc->pPoints, sizeof(POINT)*pPathSrc->numEntriesUsed);
178 memcpy(pPathDest->pFlags, pPathSrc->pFlags, sizeof(BYTE)*pPathSrc->numEntriesUsed);
179
180 pPathDest->pos = pPathSrc->pos;
181 pPathDest->state = pPathSrc->state;
182 pPathDest->numEntriesUsed = pPathSrc->numEntriesUsed;
183 pPathDest->newStroke = pPathSrc->newStroke;
184 return TRUE;
185}
186
188{
189 PPATH pdstPath, psrcPath = PATH_LockPath(src->dclevel.hPath);
190 TRACE("PATH_SavePath\n");
191 if (psrcPath)
192 {
193 TRACE("PATH_SavePath 1\n");
194
195 pdstPath = PATH_CreatePath(psrcPath->numEntriesAllocated);
196
197 dst->dclevel.flPath = src->dclevel.flPath;
198
199 dst->dclevel.hPath = pdstPath->BaseObject.hHmgr;
200
201 PATH_AssignGdiPath(pdstPath, psrcPath);
202
203 PATH_UnlockPath(pdstPath);
204 PATH_UnlockPath(psrcPath);
205 }
206 return TRUE;
207}
208
210{
211 TRACE("PATH_RestorePath\n");
212
213 if (dst->dclevel.hPath == NULL)
214 {
215 PPATH pdstPath, psrcPath = PATH_LockPath(src->dclevel.hPath);
216 TRACE("PATH_RestorePath 1\n");
217 pdstPath = PATH_CreatePath(psrcPath->numEntriesAllocated);
218 dst->dclevel.flPath = src->dclevel.flPath;
219 dst->dclevel.hPath = pdstPath->BaseObject.hHmgr;
220
221 PATH_AssignGdiPath(pdstPath, psrcPath);
222
223 PATH_UnlockPath(pdstPath);
224 PATH_UnlockPath(psrcPath);
225 }
226 else
227 {
228 PPATH pdstPath, psrcPath = PATH_LockPath(src->dclevel.hPath);
229 pdstPath = PATH_LockPath(dst->dclevel.hPath);
230 TRACE("PATH_RestorePath 2\n");
231 dst->dclevel.flPath = src->dclevel.flPath & (DCPATH_CLOCKWISE|DCPATH_ACTIVE);
232 PATH_AssignGdiPath(pdstPath, psrcPath);
233
234 PATH_UnlockPath(pdstPath);
235 PATH_UnlockPath(psrcPath);
236 }
237 return TRUE;
238}
239
240/* PATH_EmptyPath
241 *
242 * Removes all entries from the path and sets the path state to PATH_Null.
243 */
244VOID
247{
248 ASSERT(pPath != NULL);
249
250 pPath->state = PATH_Null;
251 pPath->numEntriesUsed = 0;
252}
253
254/* PATH_AddEntry
255 *
256 * Adds an entry to the path. For "flags", pass either PT_MOVETO, PT_LINETO
257 * or PT_BEZIERTO, optionally ORed with PT_CLOSEFIGURE. Returns TRUE if
258 * successful, FALSE otherwise (e.g. if not enough memory was available).
259 */
260BOOL
263 PPATH pPath,
264 const POINT *pPoint,
265 BYTE flags)
266{
267 ASSERT(pPath != NULL);
268
269 /* FIXME: If newStroke is true, perhaps we want to check that we're
270 * getting a PT_MOVETO
271 */
272 TRACE("(%d,%d) - %d\n", pPoint->x, pPoint->y, flags);
273
274 /* Reserve enough memory for an extra path entry */
275 if (!PATH_ReserveEntries(pPath, pPath->numEntriesUsed + 1))
276 return FALSE;
277
278 /* Store information in path entry */
279 pPath->pPoints[pPath->numEntriesUsed] = *pPoint;
280 pPath->pFlags[pPath->numEntriesUsed] = flags;
281
282 /* Increment entry count */
283 pPath->numEntriesUsed++;
284
285 return TRUE;
286}
287
288/* PATH_ReserveEntries
289 *
290 * Ensures that at least "numEntries" entries (for points and flags) have
291 * been allocated; allocates larger arrays and copies the existing entries
292 * to those arrays, if necessary. Returns TRUE if successful, else FALSE.
293 */
294BOOL
297 PPATH pPath,
298 INT numEntries)
299{
300 INT numEntriesToAllocate;
301 POINT *pPointsNew;
302 BYTE *pFlagsNew;
303
304 ASSERT(pPath != NULL);
305 ASSERT(numEntries >= 0);
306
307 /* Do we have to allocate more memory? */
308 if (numEntries > pPath->numEntriesAllocated)
309 {
310 /* Find number of entries to allocate. We let the size of the array
311 * grow exponentially, since that will guarantee linear time
312 * complexity. */
313 if (pPath->numEntriesAllocated)
314 {
315 numEntriesToAllocate = pPath->numEntriesAllocated;
316 while (numEntriesToAllocate < numEntries)
317 numEntriesToAllocate = numEntriesToAllocate * GROW_FACTOR_NUMER / GROW_FACTOR_DENOM;
318 }
319 else
320 numEntriesToAllocate = numEntries;
321
322 /* Allocate new arrays */
323 pPointsNew = (POINT *)ExAllocatePoolWithTag(PagedPool, numEntriesToAllocate * sizeof(POINT), TAG_PATH);
324 if (!pPointsNew)
325 return FALSE;
326
327 pFlagsNew = (BYTE *)ExAllocatePoolWithTag(PagedPool, numEntriesToAllocate * sizeof(BYTE), TAG_PATH);
328 if (!pFlagsNew)
329 {
330 ExFreePoolWithTag(pPointsNew, TAG_PATH);
331 return FALSE;
332 }
333
334 /* Copy old arrays to new arrays and discard old arrays */
335 if (pPath->pPoints)
336 {
337 ASSERT(pPath->pFlags);
338
339 memcpy(pPointsNew, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
340 memcpy(pFlagsNew, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
341
344 }
345
346 pPath->pPoints = pPointsNew;
347 pPath->pFlags = pFlagsNew;
348 pPath->numEntriesAllocated = numEntriesToAllocate;
349 }
350
351 return TRUE;
352}
353
354/* PATH_ScaleNormalizedPoint
355 *
356 * Scales a normalized point (x, y) with respect to the box whose corners are
357 * passed in "corners". The point is stored in "*pPoint". The normalized
358 * coordinates (-1.0, -1.0) correspond to corners[0], the coordinates
359 * (1.0, 1.0) correspond to corners[1].
360 */
361static
364 POINT corners[],
365 FLOATL x,
366 FLOATL y,
367 POINT *pPoint)
368{
369 FLOATOBJ tmp;
370
371 ASSERT(corners);
372 ASSERT(pPoint);
373
374 /* pPoint->x = (double)corners[0].x + (double)(corners[1].x - corners[0].x) * 0.5 * (x + 1.0); */
375 FLOATOBJ_SetFloat(&tmp, x);
376 FLOATOBJ_Add(&tmp, (FLOATOBJ*)&gef1);
377 FLOATOBJ_Div(&tmp, (FLOATOBJ*)&gef2);
378 FLOATOBJ_MulLong(&tmp, corners[1].x - corners[0].x);
379 FLOATOBJ_AddLong(&tmp, corners[0].x);
380 if (!FLOATOBJ_bConvertToLong(&tmp, &pPoint->x))
381 return FALSE;
382
383 /* pPoint->y = (double)corners[0].y + (double)(corners[1].y - corners[0].y) * 0.5 * (y + 1.0); */
384 FLOATOBJ_SetFloat(&tmp, y);
385 FLOATOBJ_Add(&tmp, (FLOATOBJ*)&gef1);
386 FLOATOBJ_Div(&tmp, (FLOATOBJ*)&gef2);
387 FLOATOBJ_MulLong(&tmp, corners[1].y - corners[0].y);
388 FLOATOBJ_AddLong(&tmp, corners[0].y);
389 if (!FLOATOBJ_bConvertToLong(&tmp, &pPoint->y))
390 return FALSE;
391 return TRUE;
392}
393
394/* PATH_NormalizePoint
395 *
396 * Normalizes a point with respect to the box whose corners are passed in
397 * corners. The normalized coordinates are stored in *pX and *pY.
398 */
399static
400VOID
402 POINTL corners[],
403 const POINTL *pPoint,
404 FLOATL *pX,
405 FLOATL *pY)
406{
407 FLOATOBJ tmp;
408
409 ASSERT(corners);
410 ASSERT(pPoint);
411 ASSERT(pX);
412 ASSERT(pY);
413
414 /* *pX = (float)(pPoint->x - corners[0].x) / (float)(corners[1].x - corners[0].x) * 2.0 - 1.0; */
415 FLOATOBJ_SetLong(&tmp, (pPoint->x - corners[0].x) * 2);
416 FLOATOBJ_DivLong(&tmp, corners[1].x - corners[0].x);
417 FLOATOBJ_Sub(&tmp, (PFLOATOBJ)&gef1);
418 *pX = FLOATOBJ_GetFloat(&tmp);
419
420 /* *pY = (float)(pPoint->y - corners[0].y) / (float)(corners[1].y - corners[0].y) * 2.0 - 1.0; */
421 FLOATOBJ_SetLong(&tmp, (pPoint->y - corners[0].y) * 2);
422 FLOATOBJ_DivLong(&tmp, corners[1].y - corners[0].y);
423 FLOATOBJ_Sub(&tmp, (PFLOATOBJ)&gef1);
424 *pY = FLOATOBJ_GetFloat(&tmp);
425}
426
427/* PATH_CheckCorners
428 *
429 * Helper function for PATH_RoundRect() and PATH_Rectangle()
430 */
431static
432BOOL
434 DC *dc,
435 RECTL* rect,
436 INT x1,
437 INT y1,
438 INT x2,
439 INT y2)
440{
441 PDC_ATTR pdcattr = dc->pdcattr;
442
443 /* Convert points to device coordinates */
445 IntLPtoDP(dc, (PPOINT)rect, 2);
446
447 /* Make sure first corner is top left and second corner is bottom right */
449
450 /* In GM_COMPATIBLE, don't include bottom and right edges */
451 if (pdcattr->iGraphicsMode == GM_COMPATIBLE)
452 {
453 if (rect->left == rect->right) return FALSE;
454 if (rect->top == rect->bottom) return FALSE;
455 rect->right--;
456 rect->bottom--;
457 }
458 return TRUE;
459}
460
461/* add a number of points, converting them to device coords */
462/* return a pointer to the first type byte so it can be fixed up if necessary */
465{
466 BYTE *ret;
467
468 if (!PATH_ReserveEntries( path, path->numEntriesUsed + count )) return NULL;
469
470 ret = &path->pFlags[path->numEntriesUsed];
471 memcpy( &path->pPoints[path->numEntriesUsed], points, count * sizeof(*points) );
472 IntLPtoDP( dc, &path->pPoints[path->numEntriesUsed], count );
473 memset( ret, type, count );
474 path->numEntriesUsed += count;
475 return ret;
476}
477
478/* add a number of points that are already in device coords */
479/* return a pointer to the first type byte so it can be fixed up if necessary */
481{
482 BYTE *ret;
483
484 if (!PATH_ReserveEntries( path, path->numEntriesUsed + count )) return NULL;
485
486 ret = &path->pFlags[path->numEntriesUsed];
487 memcpy( &path->pPoints[path->numEntriesUsed], points, count * sizeof(*points) );
488 memset( ret, type, count );
489 path->numEntriesUsed += count;
490 return ret;
491}
492
493/* reverse the order of an array of points */
495{
496 UINT i;
497 for (i = 0; i < count / 2; i++)
498 {
499 POINT pt = points[i];
500 points[i] = points[count - i - 1];
501 points[count - i - 1] = pt;
502 }
503}
504
505/* start a new path stroke if necessary */
507{
508 if (!path->newStroke && path->numEntriesUsed &&
509 !(path->pFlags[path->numEntriesUsed - 1] & PT_CLOSEFIGURE) &&
510 path->pPoints[path->numEntriesUsed - 1].x == path->pos.x &&
511 path->pPoints[path->numEntriesUsed - 1].y == path->pos.y)
512 return TRUE;
513
514 path->newStroke = FALSE;
515 return add_points( path, &path->pos, 1, PT_MOVETO ) != NULL;
516}
517
518/* set current position to the last point that was added to the path */
520{
521 ASSERT(path->numEntriesUsed);
522 path->pos = path->pPoints[path->numEntriesUsed - 1];
523}
524
525/* close the current figure */
526static void close_figure( PPATH path )
527{
528 ASSERT(path->numEntriesUsed);
529 path->pFlags[path->numEntriesUsed - 1] |= PT_CLOSEFIGURE;
530}
531
532/* add a number of points, starting a new stroke if necessary */
535{
536 if (!start_new_stroke( path )) return FALSE;
537 if (!add_log_points( dc, path, points, count, type )) return FALSE;
539
540 TRACE("ALPNS : Pos X %d Y %d\n",path->pos.x, path->pos.y);
541 IntGdiMoveToEx(dc, path->pos.x, path->pos.y, NULL);
542
543 return TRUE;
544}
545
546/* PATH_MoveTo
547 *
548 * Should be called when a MoveTo is performed on a DC that has an
549 * open path. This starts a new stroke. Returns TRUE if successful, else
550 * FALSE.
551 */
552BOOL
555 PDC dc,
556 PPATH pPath)
557{
558 if (!pPath) return FALSE;
559
560 // GDI32 : Signal from user space of a change in position.
561 if (dc->pdcattr->ulDirty_ & DIRTY_STYLESTATE)
562 {
563 TRACE("MoveTo has changed\n");
564 pPath->newStroke = TRUE;
565 // Set position and clear the signal flag.
567 IntLPtoDP( dc, &pPath->pos, 1 );
568 return TRUE;
569 }
570
571 return FALSE;
572}
573
574/* PATH_LineTo
575 *
576 * Should be called when a LineTo is performed on a DC that has an
577 * open path. This adds a PT_LINETO entry to the path (and possibly
578 * a PT_MOVETO entry, if this is the first LineTo in a stroke).
579 * Returns TRUE if successful, else FALSE.
580 */
581BOOL
584 PDC dc,
585 INT x,
586 INT y)
587{
588 BOOL Ret;
589 PPATH pPath;
590 POINT point, pointCurPos;
591
592 pPath = PATH_LockPath(dc->dclevel.hPath);
593 if (!pPath) return FALSE;
594
595 point.x = x;
596 point.y = y;
597
598 // Coalesce a MoveTo point.
599 if ( !PATH_MoveTo(dc, pPath) )
600 {
601 /* Add a PT_MOVETO if necessary */
602 if (pPath->newStroke)
603 {
604 TRACE("Line To : New Stroke\n");
605 pPath->newStroke = FALSE;
606 IntGetCurrentPositionEx(dc, &pointCurPos);
607 CoordLPtoDP(dc, &pointCurPos);
608 if (!PATH_AddEntry(pPath, &pointCurPos, PT_MOVETO))
609 {
610 PATH_UnlockPath(pPath);
611 return FALSE;
612 }
613 }
614 }
615 Ret = add_log_points_new_stroke( dc, pPath, &point, 1, PT_LINETO );
616 PATH_UnlockPath(pPath);
617 return Ret;
618}
619
620/* PATH_Rectangle
621 *
622 * Should be called when a call to Rectangle is performed on a DC that has
623 * an open path. Returns TRUE if successful, else FALSE.
624 */
625BOOL
628 PDC dc,
629 INT x1,
630 INT y1,
631 INT x2,
632 INT y2)
633{
634 PPATH pPath;
635 RECTL rect;
636 POINTL points[4];
637 BYTE *type;
638
639 pPath = PATH_LockPath(dc->dclevel.hPath);
640 if (!pPath) return FALSE;
641
642 if (!PATH_CheckRect(dc, &rect, x1, y1, x2, y2))
643 {
644 PATH_UnlockPath(pPath);
645 return TRUE;
646 }
647
648 points[0].x = rect.right; points[0].y = rect.top;
649 points[1].x = rect.left; points[1].y = rect.top;
650 points[2].x = rect.left; points[2].y = rect.bottom;
651 points[3].x = rect.right; points[3].y = rect.bottom;
652
653 if (dc->dclevel.flPath & DCPATH_CLOCKWISE) reverse_points(points, 4 );
654
655 if (!(type = add_points( pPath, points, 4, PT_LINETO )))
656 {
657 PATH_UnlockPath(pPath);
658 return FALSE;
659 }
660 type[0] = PT_MOVETO;
661
662 /* Close the rectangle figure */
663 IntGdiCloseFigure(pPath) ;
664 PATH_UnlockPath(pPath);
665 return TRUE;
666}
667
668/* PATH_RoundRect
669 *
670 * Should be called when a call to RoundRect is performed on a DC that has
671 * an open path. Returns TRUE if successful, else FALSE.
672 *
673 */
674BOOL
676 DC *dc,
677 INT x1,
678 INT y1,
679 INT x2,
680 INT y2,
681 INT ell_width,
682 INT ell_height)
683{
684 PPATH pPath;
685 RECTL rect, ellipse;
686 POINT points[16];
687 BYTE *type;
689
690 if (!ell_width || !ell_height) return PATH_Rectangle( dc, x1, y1, x2, y2 );
691
692 pPath = PATH_LockPath(dc->dclevel.hPath);
693 if (!pPath) return FALSE;
694
695 if (!PATH_CheckRect(dc, &rect, x1, y1, x2, y2))
696 {
697 PATH_UnlockPath(pPath);
698 return TRUE;
699 }
700
701 RECTL_vSetRect(&ellipse, 0, 0, ell_width, ell_height);
702 IntLPtoDP( dc, (PPOINT)&ellipse, 2 );
703 RECTL_vMakeWellOrdered(&ellipse);
704 ell_width = min(RECTL_lGetWidth(&ellipse), RECTL_lGetWidth(&rect));
705 ell_height = min(RECTL_lGetHeight(&ellipse), RECTL_lGetHeight(&rect));
706
707 /*
708 * See here to understand what's happening
709 * https://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves
710 */
711 xOffset = EngMulDiv(ell_width, 44771525, 200000000); /* w * (1 - 0.5522847) / 2 */
712 yOffset = EngMulDiv(ell_height, 44771525, 200000000); /* h * (1 - 0.5522847) / 2 */
713 TRACE("xOffset %d, yOffset %d, Rect WxH: %dx%d.\n",
715
716 /*
717 * Get half width & height.
718 * Do not use integer division, we need the rounding made by EngMulDiv.
719 */
720 ell_width = EngMulDiv(ell_width, 1, 2);
721 ell_height = EngMulDiv(ell_height, 1, 2);
722
723 /* starting point */
724 points[0].x = rect.right;
725 points[0].y = rect.top + ell_height;
726 /* first curve */
727 points[1].x = rect.right;
728 points[1].y = rect.top + yOffset;
729 points[2].x = rect.right - xOffset;
730 points[2].y = rect.top;
731 points[3].x = rect.right - ell_width;
732 points[3].y = rect.top;
733 /* horizontal line */
734 points[4].x = rect.left + ell_width;
735 points[4].y = rect.top;
736 /* second curve */
737 points[5].x = rect.left + xOffset;
738 points[5].y = rect.top;
739 points[6].x = rect.left;
740 points[6].y = rect.top + yOffset;
741 points[7].x = rect.left;
742 points[7].y = rect.top + ell_height;
743 /* vertical line */
744 points[8].x = rect.left;
745 points[8].y = rect.bottom - ell_height;
746 /* third curve */
747 points[9].x = rect.left;
748 points[9].y = rect.bottom - yOffset;
749 points[10].x = rect.left + xOffset;
750 points[10].y = rect.bottom;
751 points[11].x = rect.left + ell_width;
752 points[11].y = rect.bottom;
753 /* horizontal line */
754 points[12].x = rect.right - ell_width;
755 points[12].y = rect.bottom;
756 /* fourth curve */
757 points[13].x = rect.right - xOffset;
758 points[13].y = rect.bottom;
759 points[14].x = rect.right;
760 points[14].y = rect.bottom - yOffset;
761 points[15].x = rect.right;
762 points[15].y = rect.bottom - ell_height;
763
764 if (dc->dclevel.flPath & DCPATH_CLOCKWISE) reverse_points( points, 16 );
765 if (!(type = add_points( pPath, points, 16, PT_BEZIERTO )))
766 {
767 PATH_UnlockPath(pPath);
768 return FALSE;
769 }
770 type[0] = PT_MOVETO;
771 type[4] = type[8] = type[12] = PT_LINETO;
772
773 IntGdiCloseFigure(pPath);
774 PATH_UnlockPath(pPath);
775 return TRUE;
776}
777
778/* PATH_Ellipse
779 *
780 */
781BOOL
783 PDC dc,
784 INT x1,
785 INT y1,
786 INT x2,
787 INT y2)
788{
789 PPATH pPath;
790 POINT points[13];
791 RECTL rect;
792 BYTE *type;
793 LONG xRadius, yRadius, xOffset, yOffset;
795
796 TRACE("PATH_Ellipse: %p -> (%d, %d) - (%d, %d)\n",
797 dc, x1, y1, x2, y2);
798
799 if (!PATH_CheckRect(dc, &rect, x1, y1, x2, y2))
800 {
801 return TRUE;
802 }
803
804 xRadius = RECTL_lGetWidth(&rect) / 2;
805 yRadius = RECTL_lGetHeight(&rect) / 2;
806
807 /* Get the four points which box our ellipse */
808 left.x = rect.left; left.y = rect.top + yRadius;
809 top.x = rect.left + xRadius; top.y = rect.top;
810 right.x = rect.right; right.y = rect.bottom - yRadius;
811 bottom.x = rect.right - xRadius; bottom.y = rect.bottom;
812
813 /*
814 * See here to understand what's happening
815 * https://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves
816 */
817 xOffset = EngMulDiv(RECTL_lGetWidth(&rect), 55428475, 200000000); /* w * 0.55428475 / 2 */
818 yOffset = EngMulDiv(RECTL_lGetHeight(&rect), 55428475, 200000000); /* h * 0.55428475 / 2 */
819 TRACE("xOffset %d, yOffset %d, Rect WxH: %dx%d.\n",
821
822 pPath = PATH_LockPath(dc->dclevel.hPath);
823 if (!pPath)
824 return FALSE;
825
826 /* Starting point: Right */
827 points[0] = right;
828
829 /* first curve - going up, left */
830 points[1] = right;
831 points[1].y -= yOffset;
832 points[2] = top;
833 points[2].x += xOffset;
834
835 /* top */
836 points[3] = top;
837
838 /* second curve - going left, down*/
839 points[4] = top;
840 points[4].x -= xOffset;
841 points[5] = left;
842 points[5].y -= yOffset;
843
844 /* Left */
845 points[6] = left;
846
847 /* Third curve - going down, right */
848 points[7] = left;
849 points[7].y += yOffset;
850 points[8] = bottom;
851 points[8].x -= xOffset;
852
853 /* bottom */
854 points[9] = bottom;
855
856 /* Fourth curve - Going right, up */
857 points[10] = bottom;
858 points[10].x += xOffset;
859 points[11] = right;
860 points[11].y += yOffset;
861
862 /* Back to starting point */
863 points[12] = right;
864
865 if (dc->dclevel.flPath & DCPATH_CLOCKWISE) reverse_points( points, 13 );
866 if (!(type = add_points( pPath, points, 13, PT_BEZIERTO )))
867 {
868 ERR("PATH_Ellipse No add\n");
869 PATH_UnlockPath(pPath);
870 return FALSE;
871 }
872 type[0] = PT_MOVETO;
873
874 IntGdiCloseFigure(pPath);
875 PATH_UnlockPath(pPath);
876 return TRUE;
877}
878
879/* PATH_DoArcPart
880 *
881 * Creates a Bezier spline that corresponds to part of an arc and appends the
882 * corresponding points to the path. The start and end angles are passed in
883 * "angleStart" and "angleEnd"; these angles should span a quarter circle
884 * at most. If "startEntryType" is non-zero, an entry of that type for the first
885 * control point is added to the path; otherwise, it is assumed that the current
886 * position is equal to the first control point.
887 */
888static
889BOOL
891 PPATH pPath,
892 POINT corners[],
893 double angleStart,
894 double angleEnd,
895 BYTE startEntryType)
896{
897 double halfAngle, a;
898 float xNorm[4], yNorm[4];
899 POINT points[4];
900 BYTE *type;
901 int i, start;
902
903 ASSERT(fabs(angleEnd - angleStart) <= M_PI_2);
904
905 /* FIXME: Is there an easier way of computing this? */
906
907 /* Compute control points */
908 halfAngle = (angleEnd - angleStart) / 2.0;
909 if (fabs(halfAngle) > 1e-8)
910 {
911 a = 4.0 / 3.0 * (1 - cos(halfAngle)) / sin(halfAngle);
912 xNorm[0] = cos(angleStart);
913 yNorm[0] = sin(angleStart);
914 xNorm[1] = xNorm[0] - a * yNorm[0];
915 yNorm[1] = yNorm[0] + a * xNorm[0];
916 xNorm[3] = cos(angleEnd);
917 yNorm[3] = sin(angleEnd);
918 xNorm[2] = xNorm[3] + a * yNorm[3];
919 yNorm[2] = yNorm[3] - a * xNorm[3];
920 }
921 else
922 for (i = 0; i < 4; i++)
923 {
924 xNorm[i] = cos(angleStart);
925 yNorm[i] = sin(angleStart);
926 }
927
928 /* Add starting point to path if desired */
929 start = !startEntryType;
930
931 /* Add remaining control points */
932 for (i = start; i < 4; i++)
933 {
934 if (!PATH_ScaleNormalizedPoint(corners, *(FLOATL*)&xNorm[i], *(FLOATL*)&yNorm[i], &points[i]))
935 return FALSE;
936 }
937 if (!(type = add_points( pPath, points + start, 4 - start, PT_BEZIERTO ))) return FALSE;
938 if (!start) type[0] = startEntryType;
939
940 return TRUE;
941}
942
943/* PATH_Arc
944 *
945 * Should be called when a call to Arc is performed on a DC that has
946 * an open path. This adds up to five Bezier splines representing the arc
947 * to the path. When 'lines' is 1, we add 1 extra line to get a chord,
948 * when 'lines' is 2, we add 2 extra lines to get a pie, and when 'lines' is
949 * -1 we add 1 extra line from the current DC position to the starting position
950 * of the arc before drawing the arc itself (arcto). Returns TRUE if successful,
951 * else FALSE.
952 */
953BOOL
956 PDC dc,
957 INT x1,
958 INT y1,
959 INT x2,
960 INT y2,
961 INT xStart,
962 INT yStart,
963 INT xEnd,
964 INT yEnd,
966 INT lines)
967{
968 double angleStart, angleEnd, angleStartQuadrant, angleEndQuadrant = 0.0;
969 /* Initialize angleEndQuadrant to silence gcc's warning */
970 FLOATL x, y;
971 POINT corners[2], pointStart, pointEnd;
972 POINT centre, pointCurPos;
973 BOOL start, end, Ret = TRUE;
974 INT temp;
975 BOOL clockwise;
976 PPATH pPath;
977
978 /* FIXME: This function should check for all possible error returns */
979 /* FIXME: Do we have to respect newStroke? */
980
981 ASSERT(dc);
982
983 pPath = PATH_LockPath(dc->dclevel.hPath);
984 if (!pPath) return FALSE;
985
986 if (direction)
987 clockwise = ((direction == AD_CLOCKWISE) !=0 );
988 else
989 clockwise = ((dc->dclevel.flPath & DCPATH_CLOCKWISE) != 0);
990
991 /* Check for zero height / width */
992 /* FIXME: Only in GM_COMPATIBLE? */
993 if (x1 == x2 || y1 == y2)
994 {
995 Ret = TRUE;
996 goto ArcExit;
997 }
998 /* Convert points to device coordinates */
999 corners[0].x = x1; corners[0].y = y1;
1000 corners[1].x = x2; corners[1].y = y2;
1001 pointStart.x = xStart; pointStart.y = yStart;
1002 pointEnd.x = xEnd; pointEnd.y = yEnd;
1003 INTERNAL_LPTODP(dc, corners, 2);
1004 INTERNAL_LPTODP(dc, &pointStart, 1);
1005 INTERNAL_LPTODP(dc, &pointEnd, 1);
1006
1007 /* Make sure first corner is top left and second corner is bottom right */
1008 if (corners[0].x > corners[1].x)
1009 {
1010 temp = corners[0].x;
1011 corners[0].x = corners[1].x;
1012 corners[1].x = temp;
1013 }
1014 if (corners[0].y > corners[1].y)
1015 {
1016 temp = corners[0].y;
1017 corners[0].y = corners[1].y;
1018 corners[1].y = temp;
1019 }
1020
1021 /* Compute start and end angle */
1022 PATH_NormalizePoint(corners, &pointStart, &x, &y);
1023 angleStart = atan2(*(FLOAT*)&y, *(FLOAT*)&x);
1024 PATH_NormalizePoint(corners, &pointEnd, &x, &y);
1025 angleEnd = atan2(*(FLOAT*)&y, *(FLOAT*)&x);
1026
1027 /* Make sure the end angle is "on the right side" of the start angle */
1028 if (clockwise)
1029 {
1030 if (angleEnd <= angleStart)
1031 {
1032 angleEnd += 2 * M_PI;
1033 ASSERT(angleEnd >= angleStart);
1034 }
1035 }
1036 else
1037 {
1038 if (angleEnd >= angleStart)
1039 {
1040 angleEnd -= 2 * M_PI;
1041 ASSERT(angleEnd <= angleStart);
1042 }
1043 }
1044
1045 /* In GM_COMPATIBLE, don't include bottom and right edges */
1046 if (dc->pdcattr->iGraphicsMode == GM_COMPATIBLE)
1047 {
1048 corners[1].x--;
1049 corners[1].y--;
1050 }
1051
1052 /* arcto: Add a PT_MOVETO only if this is the first entry in a stroke */
1053 if (lines == GdiTypeArcTo && pPath->newStroke) // -1
1054 {
1055 pPath->newStroke = FALSE;
1056 IntGetCurrentPositionEx(dc, &pointCurPos);
1057 CoordLPtoDP(dc, &pointCurPos);
1058 if (!PATH_AddEntry(pPath, &pointCurPos, PT_MOVETO))
1059 {
1060 Ret = FALSE;
1061 goto ArcExit;
1062 }
1063 }
1064
1065 /* Add the arc to the path with one Bezier spline per quadrant that the
1066 * arc spans */
1067 start = TRUE;
1068 end = FALSE;
1069 do
1070 {
1071 /* Determine the start and end angles for this quadrant */
1072 if (start)
1073 {
1074 angleStartQuadrant = angleStart;
1075 if (clockwise)
1076 angleEndQuadrant = (floor(angleStart / M_PI_2) + 1.0) * M_PI_2;
1077 else
1078 angleEndQuadrant = (ceil(angleStart / M_PI_2) - 1.0) * M_PI_2;
1079 }
1080 else
1081 {
1082 angleStartQuadrant = angleEndQuadrant;
1083 if (clockwise)
1084 angleEndQuadrant += M_PI_2;
1085 else
1086 angleEndQuadrant -= M_PI_2;
1087 }
1088
1089 /* Have we reached the last part of the arc? */
1090 if ((clockwise && angleEnd < angleEndQuadrant) ||
1091 (!clockwise && angleEnd > angleEndQuadrant))
1092 {
1093 /* Adjust the end angle for this quadrant */
1094 angleEndQuadrant = angleEnd;
1095 end = TRUE;
1096 }
1097
1098 /* Add the Bezier spline to the path */
1099 PATH_DoArcPart(pPath,
1100 corners,
1101 angleStartQuadrant,
1102 angleEndQuadrant,
1103 start ? (lines == GdiTypeArcTo ? PT_LINETO : PT_MOVETO) : FALSE); // -1
1104 start = FALSE;
1105 }
1106 while (!end);
1107
1108 if (lines == GdiTypeArcTo)
1109 {
1110 update_current_pos( pPath );
1111 }
1112 else /* chord: close figure. pie: add line and close figure */
1113 if (lines == GdiTypeChord) // 1
1114 {
1115 IntGdiCloseFigure(pPath);
1116 }
1117 else if (lines == GdiTypePie) // 2
1118 {
1119 centre.x = (corners[0].x + corners[1].x) / 2;
1120 centre.y = (corners[0].y + corners[1].y) / 2;
1121 if (!PATH_AddEntry(pPath, &centre, PT_LINETO | PT_CLOSEFIGURE))
1122 Ret = FALSE;
1123 }
1124ArcExit:
1125 PATH_UnlockPath(pPath);
1126 return Ret;
1127}
1128
1129BOOL
1132 PDC dc,
1133 const POINT *pts,
1134 DWORD cbPoints)
1135{
1136 PPATH pPath;
1137 BOOL ret;
1138
1139 ASSERT(dc);
1140 ASSERT(pts);
1141 ASSERT(cbPoints);
1142
1143 pPath = PATH_LockPath(dc->dclevel.hPath);
1144 if (!pPath) return FALSE;
1145
1146 ret = add_log_points_new_stroke( dc, pPath, pts, cbPoints, PT_BEZIERTO );
1147
1148 PATH_UnlockPath(pPath);
1149 return ret;
1150}
1151
1152BOOL
1155 PDC dc,
1156 const POINT *pts,
1157 DWORD cbPoints)
1158{
1159 PPATH pPath;
1160 BYTE *type;
1161
1162 ASSERT(dc);
1163 ASSERT(pts);
1164 ASSERT(cbPoints);
1165
1166 pPath = PATH_LockPath(dc->dclevel.hPath);
1167 if (!pPath) return FALSE;
1168
1169 type = add_log_points( dc, pPath, pts, cbPoints, PT_BEZIERTO );
1170 if (!type) return FALSE;
1171
1172 type[0] = PT_MOVETO;
1173
1174 PATH_UnlockPath(pPath);
1175 return TRUE;
1176}
1177
1178BOOL
1181 PDC dc,
1182 const POINT *pts,
1183 const BYTE *types,
1184 DWORD cbPoints)
1185{
1186 PPATH pPath;
1187 POINT orig_pos, cur_pos;
1188 ULONG i, lastmove = 0;
1189
1190 pPath = PATH_LockPath(dc->dclevel.hPath);
1191 if (!pPath) return FALSE;
1192
1193 if (pPath->state != PATH_Open)
1194 {
1195 PATH_UnlockPath(pPath);
1196 return FALSE;
1197 }
1198
1199 for (i = 0; i < pPath->numEntriesUsed; i++) if (pPath->pFlags[i] == PT_MOVETO) lastmove = i;
1200 orig_pos = pPath->pos;
1201
1202 IntGetCurrentPositionEx(dc, &cur_pos);
1203
1204 TRACE("PPD : Current pos X %d Y %d\n",pPath->pos.x, pPath->pos.y);
1205 TRACE("PPD : last %d pos X %d Y %d\n",lastmove, pPath->pPoints[lastmove].x, pPath->pPoints[lastmove].y);
1206
1207
1208 for(i = 0; i < cbPoints; i++)
1209 {
1210 switch (types[i])
1211 {
1212 case PT_MOVETO:
1213 pPath->newStroke = TRUE;
1214 pPath->pos = pts[i];
1215 IntLPtoDP( dc, &pPath->pos, 1);
1216 lastmove = pPath->numEntriesUsed;
1217 break;
1218 case PT_LINETO:
1220 if (!add_log_points_new_stroke( dc, pPath, &pts[i], 1, PT_LINETO ))
1221 {
1222 PATH_UnlockPath(pPath);
1223 return FALSE;
1224 }
1225 break;
1226 case PT_BEZIERTO:
1227 if ((i + 2 < cbPoints) && (types[i + 1] == PT_BEZIERTO) &&
1228 (types[i + 2] & ~PT_CLOSEFIGURE) == PT_BEZIERTO)
1229 {
1230 if (!add_log_points_new_stroke( dc, pPath, &pts[i], 3, PT_BEZIERTO ))
1231 {
1232 PATH_UnlockPath(pPath);
1233 return FALSE;
1234 }
1235 i += 2;
1236 break;
1237 }
1238 /* fall through */
1239 default:
1240 /* restore original position */
1241 pPath->pos = orig_pos;
1242
1243 TRACE("PPD Bad : pos X %d Y %d\n",pPath->pos.x, pPath->pos.y);
1244
1245 IntGdiMoveToEx(dc, cur_pos.x, cur_pos.y, NULL);
1246
1247 PATH_UnlockPath(pPath);
1248 return FALSE;
1249 }
1250
1251 if (types[i] & PT_CLOSEFIGURE)
1252 {
1253 close_figure( pPath );
1254 pPath->pos = pPath->pPoints[lastmove];
1255 TRACE("PPD close : pos X %d Y %d\n",pPath->pos.x, pPath->pos.y);
1256 }
1257 }
1258 PATH_UnlockPath(pPath);
1259 return TRUE;
1260}
1261
1262BOOL
1265 PDC dc,
1266 const POINT *pts,
1267 DWORD cbPoints)
1268{
1269 PPATH pPath;
1270 BOOL ret;
1271
1272 ASSERT(dc);
1273 ASSERT(pts);
1274 ASSERT(cbPoints);
1275
1276 if (cbPoints < 1) return FALSE;
1277
1278 pPath = PATH_LockPath(dc->dclevel.hPath);
1279 if (!pPath) return FALSE;
1280
1281 ret = add_log_points_new_stroke( dc, pPath, pts, cbPoints, PT_LINETO );
1282 PATH_UnlockPath(pPath);
1283 return ret;
1284}
1285
1286BOOL
1289 PDC dc,
1290 const POINT* pts,
1291 const INT* counts,
1292 UINT polygons)
1293{
1294 UINT poly, count;
1295 BYTE *type;
1296 PPATH pPath;
1297
1298 ASSERT(dc);
1299 ASSERT(pts);
1300 ASSERT(counts);
1301 ASSERT(polygons);
1302
1303 if (!polygons) return FALSE;
1304
1305 pPath = PATH_LockPath(dc->dclevel.hPath);
1306 if (!pPath) return FALSE;
1307
1308
1309 for (poly = count = 0; poly < polygons; poly++)
1310 {
1311 if (counts[poly] < 2)
1312 {
1313 PATH_UnlockPath(pPath);
1314 return FALSE;
1315 }
1316 count += counts[poly];
1317 }
1318
1319 type = add_log_points( dc, pPath, pts, count, PT_LINETO );
1320 if (!type)
1321 {
1322 PATH_UnlockPath(pPath);
1323 return FALSE;
1324 }
1325
1326 /* make the first point of each polyline a PT_MOVETO, and close the last one */
1327 for (poly = 0; poly < polygons; type += counts[poly++])
1328 {
1329 type[0] = PT_MOVETO;
1330 type[counts[poly] - 1] = PT_LINETO | PT_CLOSEFIGURE;
1331 }
1332 PATH_UnlockPath(pPath);
1333 return TRUE;
1334}
1335
1336BOOL
1339 PDC dc,
1340 const POINT* pts,
1341 const DWORD* counts,
1342 DWORD polylines)
1343{
1344 POINT pt;
1345 ULONG poly, point, i;
1346 PPATH pPath;
1347
1348 ASSERT(dc);
1349 ASSERT(pts);
1350 ASSERT(counts);
1351 ASSERT(polylines);
1352
1353 pPath = PATH_LockPath(dc->dclevel.hPath);
1354 if (!pPath)
1355 {
1356 return FALSE;
1357 }
1358
1359 for (i = 0, poly = 0; poly < polylines; poly++)
1360 {
1361 for (point = 0; point < counts[poly]; point++, i++)
1362 {
1363 pt = pts[i];
1364 CoordLPtoDP(dc, &pt);
1365 PATH_AddEntry(pPath, &pt, (point == 0) ? PT_MOVETO : PT_LINETO);
1366 }
1367 }
1368 TRACE("PATH_PolyPolyline end count %d\n",pPath->numEntriesUsed);
1369 PATH_UnlockPath(pPath);
1370 return TRUE;
1371}
1372
1373/* PATH_AddFlatBezier
1374 *
1375 */
1376BOOL
1379 PPATH pPath,
1380 POINT *pt,
1381 BOOL closed)
1382{
1383 POINT *pts;
1384 BOOL ret = FALSE;
1385 INT no, i;
1386
1387 pts = GDI_Bezier(pt, 4, &no);
1388 if (!pts) return FALSE;
1389
1390 for (i = 1; i < no; i++)
1391 {
1392 if (!(ret = PATH_AddEntry(pPath, &pts[i], (i == no - 1 && closed) ? PT_LINETO | PT_CLOSEFIGURE : PT_LINETO)))
1393 break;
1394 }
1395
1397 return ret;
1398}
1399
1400/* PATH_FlattenPath
1401 *
1402 * Replaces Beziers with line segments
1403 *
1404 */
1405PPATH
1408{
1409 PPATH newPath;
1410 INT srcpt;
1411 TRACE("PATH_FlattenPath\n");
1412 if (!(newPath = PATH_CreatePath(pPath->numEntriesUsed))) return NULL;
1413
1414 for (srcpt = 0; srcpt < pPath->numEntriesUsed; srcpt++)
1415 {
1416 switch(pPath->pFlags[srcpt] & ~PT_CLOSEFIGURE)
1417 {
1418 case PT_MOVETO:
1419 case PT_LINETO:
1420 if (!PATH_AddEntry(newPath, &pPath->pPoints[srcpt], pPath->pFlags[srcpt]))
1421 {
1422 PATH_UnlockPath(newPath);
1423 PATH_Delete(newPath->BaseObject.hHmgr);
1424 return NULL;
1425 }
1426 break;
1427 case PT_BEZIERTO:
1428 if(!PATH_AddFlatBezier(newPath, &pPath->pPoints[srcpt - 1], pPath->pFlags[srcpt + 2] & PT_CLOSEFIGURE))
1429 {
1430 PATH_UnlockPath(newPath);
1431 PATH_Delete(newPath->BaseObject.hHmgr);
1432 return NULL;
1433 }
1434 srcpt += 2;
1435 break;
1436 }
1437 }
1438 TRACE("PATH_FlattenPath good\n");
1439 newPath->state = pPath->state;
1440 return newPath;
1441}
1442
1443/* PATH_PathToRegion
1444 *
1445 * Fills Rgn from the specified path using the specified polygon
1446 * filling mode. The path is left unchanged.
1447 */
1448BOOL
1451 PPATH pPath,
1452 INT Mode,
1453 PREGION Rgn)
1454{
1455 int i, pos, polygons;
1456 PULONG counts;
1457 int Ret;
1458
1459 if (!pPath->numEntriesUsed) return FALSE;
1460
1461 counts = ExAllocatePoolWithTag(PagedPool, (pPath->numEntriesUsed / 2) * sizeof(*counts), TAG_PATH);
1462 if (!counts)
1463 {
1464 ERR("Failed to allocate %lu strokes\n", (pPath->numEntriesUsed / 2) * sizeof(*counts));
1466 return FALSE;
1467 }
1468
1469 pos = polygons = 0;
1470 ASSERT( pPath->pFlags[0] == PT_MOVETO );
1471 for (i = 1; i < pPath->numEntriesUsed; i++)
1472 {
1473 if (pPath->pFlags[i] != PT_MOVETO) continue;
1474 counts[polygons++] = i - pos;
1475 pos = i;
1476 }
1477 if (i > pos + 1) counts[polygons++] = i - pos;
1478
1479 ASSERT( polygons <= pPath->numEntriesUsed / 2 );
1480
1481 /* Fill the region with the strokes */
1482 Ret = REGION_SetPolyPolygonRgn(Rgn,
1483 pPath->pPoints,
1484 counts,
1485 polygons,
1486 Mode);
1487 if (!Ret)
1488 {
1489 ERR("REGION_SetPolyPolygonRgn failed\n");
1490 }
1491
1492 ExFreePoolWithTag(counts, TAG_PATH);
1493
1494 /* Success! */
1495 return Ret;
1496}
1497
1498/* PATH_FillPath
1499 *
1500 * You can play with this as long as you like, but if you break Area.exe the purge will Begain on Path!!!
1501 *
1502 */
1503BOOL
1506 PDC dc,
1507 PPATH pPath)
1508{
1509 return PATH_FillPathEx(dc, pPath, NULL);
1510}
1511
1512BOOL
1515 PDC dc,
1516 PPATH pPath,
1517 PBRUSH pbrFill)
1518{
1519 INT mapMode, graphicsMode;
1520 SIZE ptViewportExt, ptWindowExt;
1521 POINTL ptViewportOrg, ptWindowOrg;
1522 XFORML xform;
1523 PREGION Rgn;
1524 PDC_ATTR pdcattr = dc->pdcattr;
1525
1526 /* Allocate a temporary region */
1527 Rgn = IntSysCreateRectpRgn(0, 0, 0, 0);
1528 if (!Rgn)
1529 {
1531 return FALSE;
1532 }
1533
1534 if (!PATH_PathToRegion(pPath, pdcattr->jFillMode, Rgn))
1535 {
1536 TRACE("PFP : Fail P2R\n");
1537 /* EngSetLastError ? */
1538 REGION_Delete(Rgn);
1539 return FALSE;
1540 }
1541
1542 /* Since PaintRgn interprets the region as being in logical coordinates
1543 * but the points we store for the path are already in device
1544 * coordinates, we have to set the mapping mode to MM_TEXT temporarily.
1545 * Using SaveDC to save information about the mapping mode / world
1546 * transform would be easier but would require more overhead, especially
1547 * now that SaveDC saves the current path.
1548 */
1549
1550 /* Save the information about the old mapping mode */
1551 mapMode = pdcattr->iMapMode;
1552 ptViewportExt = pdcattr->szlViewportExt;
1553 ptViewportOrg = pdcattr->ptlViewportOrg;
1554 ptWindowExt = pdcattr->szlWindowExt;
1555 ptWindowOrg = pdcattr->ptlWindowOrg;
1556
1557 /* Save world transform
1558 * NB: The Windows documentation on world transforms would lead one to
1559 * believe that this has to be done only in GM_ADVANCED; however, my
1560 * tests show that resetting the graphics mode to GM_COMPATIBLE does
1561 * not reset the world transform.
1562 */
1563 MatrixS2XForm(&xform, &dc->pdcattr->mxWorldToPage);
1564
1565 /* Set MM_TEXT */
1567 pdcattr->ptlViewportOrg.x = 0;
1568 pdcattr->ptlViewportOrg.y = 0;
1569 pdcattr->ptlWindowOrg.x = 0;
1570 pdcattr->ptlWindowOrg.y = 0;
1571
1572 graphicsMode = pdcattr->iGraphicsMode;
1573 pdcattr->iGraphicsMode = GM_ADVANCED;
1575 pdcattr->iGraphicsMode = graphicsMode;
1576
1577 /* Paint the region */
1578 IntGdiFillRgn(dc, Rgn, pbrFill);
1579 REGION_Delete(Rgn);
1580 /* Restore the old mapping mode */
1581 IntGdiSetMapMode(dc, mapMode);
1582 pdcattr->szlViewportExt = ptViewportExt;
1583 pdcattr->ptlViewportOrg = ptViewportOrg;
1584 pdcattr->szlWindowExt = ptWindowExt;
1585 pdcattr->ptlWindowOrg = ptWindowOrg;
1586
1587 /* Go to GM_ADVANCED temporarily to restore the world transform */
1588 graphicsMode = pdcattr->iGraphicsMode;
1589 pdcattr->iGraphicsMode = GM_ADVANCED;
1591 pdcattr->iGraphicsMode = graphicsMode;
1592 return TRUE;
1593}
1594
1595BOOL
1598 DC *dc,
1599 PPATH pPath)
1600{
1601 BOOL ret = FALSE;
1602 INT nLinePts, nAlloc, jOldFillMode, i = 0;
1603 POINT *pLinePts = NULL;
1604 POINT ptViewportOrg, ptWindowOrg;
1605 SIZE szViewportExt, szWindowExt;
1606 DWORD mapMode, graphicsMode;
1607 XFORM xform;
1608 PDC_ATTR pdcattr = dc->pdcattr;
1609 PBRUSH pbrLine;
1610 PPATH pNewPath;
1611
1612 TRACE("Enter %s\n", __FUNCTION__);
1613
1614 pbrLine = dc->dclevel.pbrLine;
1615 if (IntIsEffectiveWidePen(pbrLine))
1616 {
1617 pNewPath = PATH_WidenPathEx(dc, pPath);
1618 if (pNewPath)
1619 {
1620 /* Fill the path with the WINDING fill mode */
1621 jOldFillMode = pdcattr->jFillMode;
1622 pdcattr->jFillMode = WINDING;
1623 PATH_FillPathEx(dc, pNewPath, pbrLine);
1624 pdcattr->jFillMode = jOldFillMode;
1625
1626 PATH_Delete(pNewPath->BaseObject.hHmgr);
1627 return TRUE;
1628 }
1629 }
1630
1631 /* Save the mapping mode info */
1632 mapMode = pdcattr->iMapMode;
1633
1634 szViewportExt = *DC_pszlViewportExt(dc);
1635 ptViewportOrg = dc->pdcattr->ptlViewportOrg;
1636 szWindowExt = dc->pdcattr->szlWindowExt;
1637 ptWindowOrg = dc->pdcattr->ptlWindowOrg;
1638
1639 MatrixS2XForm(&xform, &dc->pdcattr->mxWorldToPage);
1640
1641 /* Set MM_TEXT */
1642 pdcattr->iMapMode = MM_TEXT;
1643 pdcattr->ptlViewportOrg.x = 0;
1644 pdcattr->ptlViewportOrg.y = 0;
1645 pdcattr->ptlWindowOrg.x = 0;
1646 pdcattr->ptlWindowOrg.y = 0;
1647 graphicsMode = pdcattr->iGraphicsMode;
1648 pdcattr->iGraphicsMode = GM_ADVANCED;
1650 pdcattr->iGraphicsMode = graphicsMode;
1651
1652 /* Allocate enough memory for the worst case without beziers (one PT_MOVETO
1653 * and the rest PT_LINETO with PT_CLOSEFIGURE at the end) plus some buffer
1654 * space in case we get one to keep the number of reallocations small. */
1655 nAlloc = pPath->numEntriesUsed + 1 + 300;
1656 pLinePts = ExAllocatePoolWithTag(PagedPool, nAlloc * sizeof(POINT), TAG_PATH);
1657 if (!pLinePts)
1658 {
1659 ERR("Can't allocate pool!\n");
1661 goto end;
1662 }
1663 nLinePts = 0;
1664
1665 for (i = 0; i < pPath->numEntriesUsed; i++)
1666 {
1667 if ((i == 0 || (pPath->pFlags[i - 1] & PT_CLOSEFIGURE))
1668 && (pPath->pFlags[i] != PT_MOVETO))
1669 {
1670 ERR("Expected PT_MOVETO %s, got path flag %d\n",
1671 i == 0 ? "as first point" : "after PT_CLOSEFIGURE",
1672 (INT)pPath->pFlags[i]);
1673 goto end;
1674 }
1675
1676 switch(pPath->pFlags[i])
1677 {
1678 case PT_MOVETO:
1679 TRACE("Got PT_MOVETO (%ld, %ld)\n",
1680 pPath->pPoints[i].x, pPath->pPoints[i].y);
1681 if (nLinePts >= 2) IntGdiPolyline(dc, pLinePts, nLinePts);
1682 nLinePts = 0;
1683 pLinePts[nLinePts++] = pPath->pPoints[i];
1684 break;
1685 case PT_LINETO:
1686 case (PT_LINETO | PT_CLOSEFIGURE):
1687 TRACE("Got PT_LINETO (%ld, %ld)\n",
1688 pPath->pPoints[i].x, pPath->pPoints[i].y);
1689 pLinePts[nLinePts++] = pPath->pPoints[i];
1690 break;
1691 case PT_BEZIERTO:
1692 TRACE("Got PT_BEZIERTO\n");
1693 if (pPath->pFlags[i + 1] != PT_BEZIERTO ||
1694 (pPath->pFlags[i + 2] & ~PT_CLOSEFIGURE) != PT_BEZIERTO)
1695 {
1696 ERR("Path didn't contain 3 successive PT_BEZIERTOs\n");
1697 ret = FALSE;
1698 goto end;
1699 }
1700 else
1701 {
1702 INT nBzrPts, nMinAlloc;
1703 POINT *pBzrPts = GDI_Bezier(&pPath->pPoints[i - 1], 4, &nBzrPts);
1704 /* Make sure we have allocated enough memory for the lines of
1705 * this bezier and the rest of the path, assuming we won't get
1706 * another one (since we won't reallocate again then). */
1707 nMinAlloc = nLinePts + (pPath->numEntriesUsed - i) + nBzrPts;
1708 if (nAlloc < nMinAlloc)
1709 {
1710 // Reallocate memory
1711
1712 POINT *Realloc = NULL;
1713 nAlloc = nMinAlloc * 2;
1714
1716 nAlloc * sizeof(POINT),
1717 TAG_PATH);
1718
1719 if (!Realloc)
1720 {
1721 ERR("Can't allocate pool!\n");
1722 ExFreePoolWithTag(pBzrPts, TAG_BEZIER);
1723 goto end;
1724 }
1725
1726 memcpy(Realloc, pLinePts, nLinePts * sizeof(POINT));
1727 ExFreePoolWithTag(pLinePts, TAG_PATH);
1728 pLinePts = Realloc;
1729 }
1730 memcpy(&pLinePts[nLinePts], &pBzrPts[1], (nBzrPts - 1) * sizeof(POINT));
1731 nLinePts += nBzrPts - 1;
1732 ExFreePoolWithTag(pBzrPts, TAG_BEZIER);
1733 i += 2;
1734 }
1735 break;
1736 default:
1737 ERR("Got path flag %d (not supported)\n", (INT)pPath->pFlags[i]);
1738 goto end;
1739 }
1740
1741 if (pPath->pFlags[i] & PT_CLOSEFIGURE)
1742 {
1743 pLinePts[nLinePts++] = pLinePts[0];
1744 }
1745 }
1746 if (nLinePts >= 2)
1747 IntGdiPolyline(dc, pLinePts, nLinePts);
1748
1749 ret = TRUE;
1750
1751end:
1752 if (pLinePts) ExFreePoolWithTag(pLinePts, TAG_PATH);
1753
1754 /* Restore the old mapping mode */
1755 pdcattr->iMapMode = mapMode;
1756 pdcattr->szlWindowExt.cx = szWindowExt.cx;
1757 pdcattr->szlWindowExt.cy = szWindowExt.cy;
1758 pdcattr->ptlWindowOrg.x = ptWindowOrg.x;
1759 pdcattr->ptlWindowOrg.y = ptWindowOrg.y;
1760
1761 pdcattr->szlViewportExt.cx = szViewportExt.cx;
1762 pdcattr->szlViewportExt.cy = szViewportExt.cy;
1763 pdcattr->ptlViewportOrg.x = ptViewportOrg.x;
1764 pdcattr->ptlViewportOrg.y = ptViewportOrg.y;
1765
1766 /* Restore the world transform */
1767 XForm2MatrixS(&dc->pdcattr->mxWorldToPage, &xform);
1768
1769 /* If we've moved the current point then get its new position
1770 which will be in device (MM_TEXT) co-ords, convert it to
1771 logical co-ords and re-set it. This basically updates
1772 dc->CurPosX|Y so that their values are in the correct mapping
1773 mode.
1774 */
1775 if (i > 0)
1776 {
1777 POINT pt;
1779 IntDPtoLP(dc, &pt, 1);
1780 IntGdiMoveToEx(dc, pt.x, pt.y, NULL);
1781 }
1782 TRACE("Leave %s, ret=%d\n", __FUNCTION__, ret);
1783 return ret;
1784}
1785
1786#define round(x) ((int)((x)>0?(x)+0.5:(x)-0.5))
1787
1789IntGdiWidenPath(PPATH pPath, UINT penWidth, UINT penStyle, FLOAT eMiterLimit)
1790{
1791 INT i, j, numStrokes, numOldStrokes, penWidthIn, penWidthOut;
1792 PPATH flat_path, pNewPath = NULL, *pStrokes = NULL, *pOldStrokes, pUpPath, pDownPath;
1793 BYTE *type;
1794 DWORD joint, endcap;
1795 KFLOATING_SAVE fpsave;
1796
1797 endcap = (PS_ENDCAP_MASK & penStyle);
1798 joint = (PS_JOIN_MASK & penStyle);
1799
1800 if (!(flat_path = PATH_FlattenPath(pPath)))
1801 {
1802 ERR("PATH_FlattenPath\n");
1803 return NULL;
1804 }
1805
1806 penWidthIn = penWidth / 2;
1807 penWidthOut = penWidth / 2;
1808 if (penWidthIn + penWidthOut < penWidth)
1809 penWidthOut++;
1810
1811 numStrokes = 0;
1812
1813 for (i = 0, j = 0; i < flat_path->numEntriesUsed; i++, j++)
1814 {
1815 POINT point;
1816 if ((i == 0 || (flat_path->pFlags[i - 1] & PT_CLOSEFIGURE)) &&
1817 (flat_path->pFlags[i] != PT_MOVETO))
1818 {
1819 ERR("Expected PT_MOVETO %s, got path flag %c\n",
1820 i == 0 ? "as first point" : "after PT_CLOSEFIGURE",
1821 flat_path->pFlags[i]);
1822 goto Exit;
1823 }
1824 switch(flat_path->pFlags[i])
1825 {
1826 case PT_MOVETO:
1827 if (numStrokes > 0)
1828 {
1829 pStrokes[numStrokes - 1]->state = PATH_Closed;
1830 }
1831 numOldStrokes = numStrokes;
1832 numStrokes++;
1833 j = 0;
1834 if (numStrokes == 1)
1835 pStrokes = ExAllocatePoolWithTag(PagedPool, sizeof(*pStrokes), TAG_PATH);
1836 else
1837 {
1838 pOldStrokes = pStrokes; // Save old pointer.
1839 pStrokes = ExAllocatePoolWithTag(PagedPool, numStrokes * sizeof(*pStrokes), TAG_PATH);
1840 if (!pStrokes)
1841 {
1842 ExFreePoolWithTag(pOldStrokes, TAG_PATH);
1843 goto Exit;
1844 }
1845 RtlCopyMemory(pStrokes, pOldStrokes, numOldStrokes * sizeof(PPATH));
1846 ExFreePoolWithTag(pOldStrokes, TAG_PATH); // Free old pointer.
1847 }
1848 if (!pStrokes)
1849 {
1850 goto Exit;
1851 }
1852 pStrokes[numStrokes - 1] = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
1853 if (!pStrokes[numStrokes - 1])
1854 {
1855 ASSERT(FALSE); // FIXME
1856 }
1857 PATH_InitGdiPath(pStrokes[numStrokes - 1]);
1858 pStrokes[numStrokes - 1]->state = PATH_Open;
1859 case PT_LINETO:
1860 case (PT_LINETO | PT_CLOSEFIGURE):
1861 point.x = flat_path->pPoints[i].x;
1862 point.y = flat_path->pPoints[i].y;
1863 PATH_AddEntry(pStrokes[numStrokes - 1], &point, flat_path->pFlags[i]);
1864 break;
1865 case PT_BEZIERTO:
1866 /* Should never happen because of the FlattenPath call */
1867 ERR("Should never happen\n");
1868 break;
1869 default:
1870 ERR("Got path flag %c\n", flat_path->pFlags[i]);
1871 goto Exit;
1872 }
1873 }
1874
1875 pNewPath = PATH_CreatePath( flat_path->numEntriesUsed );
1876 if (pNewPath == NULL)
1877 {
1878 ERR("PATH_CreatePath\n");
1879 goto Exit;
1880 }
1881
1882 KeSaveFloatingPointState(&fpsave);
1883
1884 for (i = 0; i < numStrokes; i++)
1885 {
1886 pUpPath = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
1887 PATH_InitGdiPath(pUpPath);
1888 pUpPath->state = PATH_Open;
1889 pDownPath = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
1890 PATH_InitGdiPath(pDownPath);
1891 pDownPath->state = PATH_Open;
1892
1893 for (j = 0; j < pStrokes[i]->numEntriesUsed; j++)
1894 {
1895 /* Beginning or end of the path if not closed */
1896 if ((!(pStrokes[i]->pFlags[pStrokes[i]->numEntriesUsed - 1] & PT_CLOSEFIGURE)) && (j == 0 || j == pStrokes[i]->numEntriesUsed - 1))
1897 {
1898 /* Compute segment angle */
1899 INT xo, yo, xa, ya;
1900 double theta;
1901 POINT pt;
1902 POINT corners[2];
1903 if (j == 0)
1904 {
1905 xo = pStrokes[i]->pPoints[j].x;
1906 yo = pStrokes[i]->pPoints[j].y;
1907 xa = pStrokes[i]->pPoints[1].x;
1908 ya = pStrokes[i]->pPoints[1].y;
1909 }
1910 else
1911 {
1912 xa = pStrokes[i]->pPoints[j - 1].x;
1913 ya = pStrokes[i]->pPoints[j - 1].y;
1914 xo = pStrokes[i]->pPoints[j].x;
1915 yo = pStrokes[i]->pPoints[j].y;
1916 }
1917 theta = atan2(ya - yo, xa - xo);
1918 switch(endcap)
1919 {
1920 case PS_ENDCAP_SQUARE :
1921 pt.x = xo + round(sqrt(2) * penWidthOut * cos(M_PI_4 + theta));
1922 pt.y = yo + round(sqrt(2) * penWidthOut * sin(M_PI_4 + theta));
1923 PATH_AddEntry(pUpPath, &pt, (j == 0 ? PT_MOVETO : PT_LINETO));
1924 pt.x = xo + round(sqrt(2) * penWidthIn * cos(- M_PI_4 + theta));
1925 pt.y = yo + round(sqrt(2) * penWidthIn * sin(- M_PI_4 + theta));
1926 PATH_AddEntry(pUpPath, &pt, PT_LINETO);
1927 break;
1928 case PS_ENDCAP_FLAT :
1929 pt.x = xo + round(penWidthOut * cos(theta + M_PI_2));
1930 pt.y = yo + round(penWidthOut * sin(theta + M_PI_2));
1931 PATH_AddEntry(pUpPath, &pt, (j == 0 ? PT_MOVETO : PT_LINETO));
1932 pt.x = xo - round(penWidthIn * cos(theta + M_PI_2));
1933 pt.y = yo - round(penWidthIn * sin(theta + M_PI_2));
1934 PATH_AddEntry(pUpPath, &pt, PT_LINETO);
1935 break;
1936 case PS_ENDCAP_ROUND :
1937 default :
1938 corners[0].x = xo - penWidthIn;
1939 corners[0].y = yo - penWidthIn;
1940 corners[1].x = xo + penWidthOut;
1941 corners[1].y = yo + penWidthOut;
1942 PATH_DoArcPart(pUpPath , corners, theta + M_PI_2 , theta + 3 * M_PI_4, (j == 0 ? PT_MOVETO : FALSE));
1943 PATH_DoArcPart(pUpPath , corners, theta + 3 * M_PI_4 , theta + M_PI, FALSE);
1944 PATH_DoArcPart(pUpPath , corners, theta + M_PI, theta + 5 * M_PI_4, FALSE);
1945 PATH_DoArcPart(pUpPath , corners, theta + 5 * M_PI_4 , theta + 3 * M_PI_2, FALSE);
1946 break;
1947 }
1948 }
1949 /* Corpse of the path */
1950 else
1951 {
1952 /* Compute angle */
1953 INT previous, next;
1954 double xa, ya, xb, yb, xo, yo;
1955 double alpha, theta, miterWidth;
1956 DWORD _joint = joint;
1957 POINT pt;
1958 PPATH pInsidePath, pOutsidePath;
1959 if (j > 0 && j < pStrokes[i]->numEntriesUsed - 1)
1960 {
1961 previous = j - 1;
1962 next = j + 1;
1963 }
1964 else if (j == 0)
1965 {
1966 previous = pStrokes[i]->numEntriesUsed - 1;
1967 next = j + 1;
1968 }
1969 else
1970 {
1971 previous = j - 1;
1972 next = 0;
1973 }
1974 xo = pStrokes[i]->pPoints[j].x;
1975 yo = pStrokes[i]->pPoints[j].y;
1976 xa = pStrokes[i]->pPoints[previous].x;
1977 ya = pStrokes[i]->pPoints[previous].y;
1978 xb = pStrokes[i]->pPoints[next].x;
1979 yb = pStrokes[i]->pPoints[next].y;
1980 theta = atan2(yo - ya, xo - xa);
1981 alpha = atan2(yb - yo, xb - xo) - theta;
1982 if (alpha > 0) alpha -= M_PI;
1983 else alpha += M_PI;
1984 if (_joint == PS_JOIN_MITER && eMiterLimit < fabs(1 / sin(alpha / 2)))
1985 {
1986 _joint = PS_JOIN_BEVEL;
1987 }
1988 if (alpha > 0)
1989 {
1990 pInsidePath = pUpPath;
1991 pOutsidePath = pDownPath;
1992 }
1993 else if (alpha < 0)
1994 {
1995 pInsidePath = pDownPath;
1996 pOutsidePath = pUpPath;
1997 }
1998 else
1999 {
2000 continue;
2001 }
2002 /* Inside angle points */
2003 if (alpha > 0)
2004 {
2005 pt.x = xo - round(penWidthIn * cos(theta + M_PI_2));
2006 pt.y = yo - round(penWidthIn * sin(theta + M_PI_2));
2007 }
2008 else
2009 {
2010 pt.x = xo + round(penWidthIn * cos(theta + M_PI_2));
2011 pt.y = yo + round(penWidthIn * sin(theta + M_PI_2));
2012 }
2013 PATH_AddEntry(pInsidePath, &pt, PT_LINETO);
2014 if (alpha > 0)
2015 {
2016 pt.x = xo + round(penWidthIn * cos(M_PI_2 + alpha + theta));
2017 pt.y = yo + round(penWidthIn * sin(M_PI_2 + alpha + theta));
2018 }
2019 else
2020 {
2021 pt.x = xo - round(penWidthIn * cos(M_PI_2 + alpha + theta));
2022 pt.y = yo - round(penWidthIn * sin(M_PI_2 + alpha + theta));
2023 }
2024 PATH_AddEntry(pInsidePath, &pt, PT_LINETO);
2025 /* Outside angle point */
2026 switch(_joint)
2027 {
2028 case PS_JOIN_MITER :
2029 miterWidth = fabs(penWidthOut / cos(M_PI_2 - fabs(alpha) / 2));
2030 pt.x = xo + round(miterWidth * cos(theta + alpha / 2));
2031 pt.y = yo + round(miterWidth * sin(theta + alpha / 2));
2032 PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
2033 break;
2034 case PS_JOIN_BEVEL :
2035 if (alpha > 0)
2036 {
2037 pt.x = xo + round(penWidthOut * cos(theta + M_PI_2));
2038 pt.y = yo + round(penWidthOut * sin(theta + M_PI_2));
2039 }
2040 else
2041 {
2042 pt.x = xo - round(penWidthOut * cos(theta + M_PI_2));
2043 pt.y = yo - round(penWidthOut * sin(theta + M_PI_2));
2044 }
2045 PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
2046 if (alpha > 0)
2047 {
2048 pt.x = xo - round(penWidthOut * cos(M_PI_2 + alpha + theta));
2049 pt.y = yo - round(penWidthOut * sin(M_PI_2 + alpha + theta));
2050 }
2051 else
2052 {
2053 pt.x = xo + round(penWidthOut * cos(M_PI_2 + alpha + theta));
2054 pt.y = yo + round(penWidthOut * sin(M_PI_2 + alpha + theta));
2055 }
2056 PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
2057 break;
2058 case PS_JOIN_ROUND :
2059 default :
2060 if (alpha > 0)
2061 {
2062 pt.x = xo + round(penWidthOut * cos(theta + M_PI_2));
2063 pt.y = yo + round(penWidthOut * sin(theta + M_PI_2));
2064 }
2065 else
2066 {
2067 pt.x = xo - round(penWidthOut * cos(theta + M_PI_2));
2068 pt.y = yo - round(penWidthOut * sin(theta + M_PI_2));
2069 }
2070 PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
2071 pt.x = xo + round(penWidthOut * cos(theta + alpha / 2));
2072 pt.y = yo + round(penWidthOut * sin(theta + alpha / 2));
2073 PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
2074 if (alpha > 0)
2075 {
2076 pt.x = xo - round(penWidthOut * cos(M_PI_2 + alpha + theta));
2077 pt.y = yo - round(penWidthOut * sin(M_PI_2 + alpha + theta));
2078 }
2079 else
2080 {
2081 pt.x = xo + round(penWidthOut * cos(M_PI_2 + alpha + theta));
2082 pt.y = yo + round(penWidthOut * sin(M_PI_2 + alpha + theta));
2083 }
2084 PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
2085 break;
2086 }
2087 }
2088 }
2089 type = add_points( pNewPath, pUpPath->pPoints, pUpPath->numEntriesUsed, PT_LINETO );
2090 type[0] = PT_MOVETO;
2091 reverse_points( pDownPath->pPoints, pDownPath->numEntriesUsed );
2092 type = add_points( pNewPath, pDownPath->pPoints, pDownPath->numEntriesUsed, PT_LINETO );
2093 if (pStrokes[i]->pFlags[pStrokes[i]->numEntriesUsed - 1] & PT_CLOSEFIGURE) type[0] = PT_MOVETO;
2094
2095 PATH_DestroyGdiPath(pStrokes[i]);
2096 ExFreePoolWithTag(pStrokes[i], TAG_PATH);
2097 PATH_DestroyGdiPath(pUpPath);
2098 ExFreePoolWithTag(pUpPath, TAG_PATH);
2099 PATH_DestroyGdiPath(pDownPath);
2100 ExFreePoolWithTag(pDownPath, TAG_PATH);
2101 }
2102
2103 pNewPath->state = PATH_Closed;
2104 PATH_UnlockPath(pNewPath);
2105
2107
2108Exit:
2109 if (pStrokes) ExFreePoolWithTag(pStrokes, TAG_PATH);
2110 HPATH hpathToDelete = flat_path->BaseObject.hHmgr;
2111 PATH_UnlockPath(flat_path);
2112 PATH_Delete(hpathToDelete);
2113
2114 return pNewPath;
2115}
2116
2117static
2118PPATH
2121{
2122 PPATH pPath, pNewPath;
2123
2124 pPath = PATH_LockPath(dc->dclevel.hPath);
2125 if (!pPath)
2126 {
2128 return NULL;
2129 }
2130
2131 pNewPath = PATH_WidenPathEx(dc, pPath);
2132 PATH_UnlockPath(pPath);
2133 return pNewPath;
2134}
2135
2136PPATH
2139{
2140 INT size;
2141 UINT penWidth, penStyle;
2142 DWORD obj_type;
2143 LPEXTLOGPEN elp;
2144 PDC_ATTR pdcattr = dc->pdcattr;
2145
2146 if (pPath->state != PATH_Closed)
2147 {
2148 TRACE("PWP 1\n");
2150 return NULL;
2151 }
2152
2153 size = GreGetObject(pdcattr->hpen, 0, NULL);
2154 if (!size)
2155 {
2156 TRACE("PWP 2\n");
2158 return NULL;
2159 }
2160
2162 if (elp == NULL)
2163 {
2164 TRACE("PWP 3\n");
2166 return NULL;
2167 }
2168
2169 GreGetObject(pdcattr->hpen, size, elp);
2170
2171 obj_type = GDI_HANDLE_GET_TYPE(pdcattr->hpen);
2172 if (obj_type == GDI_OBJECT_TYPE_PEN)
2173 {
2174 penStyle = ((LOGPEN*)elp)->lopnStyle;
2175 }
2176 else if (obj_type == GDI_OBJECT_TYPE_EXTPEN)
2177 {
2178 penStyle = elp->elpPenStyle;
2179 }
2180 else
2181 {
2182 TRACE("PWP 4\n");
2185 return NULL;
2186 }
2187
2188 penWidth = elp->elpWidth;
2190
2191 /* The function cannot apply to cosmetic pens */
2192 if (obj_type == GDI_OBJECT_TYPE_EXTPEN &&
2193 (PS_TYPE_MASK & penStyle) == PS_COSMETIC)
2194 {
2195 TRACE("PWP 5\n");
2197 return FALSE;
2198 }
2199
2200 return IntGdiWidenPath(pPath, penWidth, penStyle, dc->dclevel.laPath.eMiterLimit);
2201}
2202
2204{
2205 return (f.fract >= 0x8000) ? (f.value + 1) : f.value;
2206}
2207
2208/**********************************************************************
2209 * PATH_BezierTo
2210 *
2211 * Internally used by PATH_add_outline
2212 */
2213static
2214VOID
2217 PPATH pPath,
2218 POINT *lppt,
2219 INT n)
2220{
2221 if (n < 2) return;
2222
2223 if (n == 2)
2224 {
2225 PATH_AddEntry(pPath, &lppt[1], PT_LINETO);
2226 }
2227 else if (n == 3)
2228 {
2229 add_points( pPath, lppt, 3, PT_BEZIERTO );
2230 }
2231 else
2232 {
2233 POINT pt[3];
2234 INT i = 0;
2235
2236 pt[2] = lppt[0];
2237 n--;
2238
2239 while (n > 2)
2240 {
2241 pt[0] = pt[2];
2242 pt[1] = lppt[i + 1];
2243 pt[2].x = (lppt[i + 2].x + lppt[i + 1].x) / 2;
2244 pt[2].y = (lppt[i + 2].y + lppt[i + 1].y) / 2;
2245 add_points( pPath, pt, 3, PT_BEZIERTO );
2246 n--;
2247 i++;
2248 }
2249
2250 pt[0] = pt[2];
2251 pt[1] = lppt[i + 1];
2252 pt[2] = lppt[i + 2];
2253 add_points( pPath, pt, 3, PT_BEZIERTO );
2254 }
2255}
2256
2257static
2258BOOL
2261 PDC dc,
2262 PPATH pPath,
2263 INT x,
2264 INT y,
2266 DWORD size)
2267{
2269 POINT pt;
2270 BOOL bResult = FALSE;
2271
2272 start = header;
2273
2274 while ((char *)header < (char *)start + size)
2275 {
2276 TTPOLYCURVE *curve;
2277
2278 if (header->dwType != TT_POLYGON_TYPE)
2279 {
2280 ERR("Unknown header type %lu\n", header->dwType);
2281 goto cleanup;
2282 }
2283
2284 pt.x = x + int_from_fixed(header->pfxStart.x);
2285 pt.y = y - int_from_fixed(header->pfxStart.y);
2286 PATH_AddEntry(pPath, &pt, PT_MOVETO);
2287
2288 curve = (TTPOLYCURVE *)(header + 1);
2289
2290 while ((char *)curve < (char *)header + header->cb)
2291 {
2292 TRACE("curve->wType %d\n", curve->wType);
2293
2294 switch(curve->wType)
2295 {
2296 case TT_PRIM_LINE:
2297 {
2298 WORD i;
2299
2300 for (i = 0; i < curve->cpfx; i++)
2301 {
2302 pt.x = x + int_from_fixed(curve->apfx[i].x);
2303 pt.y = y - int_from_fixed(curve->apfx[i].y);
2304 PATH_AddEntry(pPath, &pt, PT_LINETO);
2305 }
2306 break;
2307 }
2308
2309 case TT_PRIM_QSPLINE:
2310 case TT_PRIM_CSPLINE:
2311 {
2312 WORD i;
2313 POINTFX ptfx;
2314 POINT *pts = ExAllocatePoolWithTag(PagedPool, (curve->cpfx + 1) * sizeof(POINT), TAG_PATH);
2315
2316 if (!pts) goto cleanup;
2317
2318 ptfx = *(POINTFX *)((char *)curve - sizeof(POINTFX));
2319
2320 pts[0].x = x + int_from_fixed(ptfx.x);
2321 pts[0].y = y - int_from_fixed(ptfx.y);
2322
2323 for (i = 0; i < curve->cpfx; i++)
2324 {
2325 pts[i + 1].x = x + int_from_fixed(curve->apfx[i].x);
2326 pts[i + 1].y = y - int_from_fixed(curve->apfx[i].y);
2327 }
2328
2329 PATH_BezierTo(pPath, pts, curve->cpfx + 1);
2330
2332 break;
2333 }
2334
2335 default:
2336 ERR("Unknown curve type %04x\n", curve->wType);
2337 goto cleanup;
2338 }
2339
2340 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
2341 }
2342 header = (TTPOLYGONHEADER *)((char *)header + header->cb);
2343 }
2344
2345 bResult = TRUE;
2346
2347cleanup:
2348 IntGdiCloseFigure(pPath);
2349 return bResult;
2350}
2351
2352/**********************************************************************
2353 * PATH_ExtTextOut
2354 */
2355BOOL
2358 PDC dc,
2359 INT x,
2360 INT y,
2361 UINT flags,
2362 const RECTL *lprc,
2363 LPCWSTR str,
2364 UINT count,
2365 const INT *dx)
2366{
2367 PPATH pPath;
2368 unsigned int idx, ggo_flags = GGO_NATIVE;
2369 POINT offset = {0, 0};
2370
2371 pPath = PATH_LockPath(dc->dclevel.hPath);
2372 if (!pPath)
2373 {
2374 return FALSE;
2375 }
2376
2377 if (pPath->state != PATH_Open)
2378 {
2379 ERR("PATH_ExtTextOut not open\n");
2380 return FALSE;
2381 }
2382
2383 if (!count) return TRUE;
2384 if (flags & ETO_GLYPH_INDEX) ggo_flags |= GGO_GLYPH_INDEX;
2385
2386 for (idx = 0; idx < count; idx++)
2387 {
2388 MAT2 identity = { {0, 1}, {0, 0}, {0, 0}, {0, 1} };
2389 GLYPHMETRICS gm;
2390 DWORD dwSize;
2391 void *outline;
2392
2394 str[idx],
2395 ggo_flags,
2396 &gm,
2397 0,
2398 NULL,
2399 &identity,
2400 TRUE);
2401 if (dwSize == GDI_ERROR)
2402 {
2403 // With default DC font,,, bitmap font?
2404 // ExtTextOut on a path with bitmap font selected shouldn't fail.
2405 // This just leads to empty path generated.
2406 // Ref : test_emf_ExtTextOut_on_path
2407 continue;
2408 }
2409
2410 /* Add outline only if char is printable */
2411 if (dwSize)
2412 {
2414 if (!outline)
2415 {
2416 PATH_UnlockPath(pPath);
2417 return FALSE;
2418 }
2419
2421 str[idx],
2422 ggo_flags,
2423 &gm,
2424 dwSize,
2425 outline,
2426 &identity,
2427 TRUE);
2428
2429 PATH_add_outline(dc, pPath, x + offset.x, y + offset.y, outline, dwSize);
2430
2432 }
2433
2434 if (dx)
2435 {
2436 if (flags & ETO_PDY)
2437 {
2438 offset.x += dx[idx * 2];
2439 offset.y += dx[idx * 2 + 1];
2440 }
2441 else
2442 offset.x += dx[idx];
2443 }
2444 else
2445 {
2446 offset.x += gm.gmCellIncX;
2447 offset.y += gm.gmCellIncY;
2448 }
2449 }
2450 PATH_UnlockPath(pPath);
2451 return TRUE;
2452}
2453
2454
2455/***********************************************************************
2456 * Exported functions
2457 */
2458
2459BOOL
2462{
2463 PDC dc = DC_LockDc(hDC);
2464 if (!dc)
2465 {
2467 return FALSE;
2468 }
2469
2470 if (!dc->dclevel.hPath)
2471 {
2472 DC_UnlockDc(dc);
2473 return TRUE;
2474 }
2475
2476 if (!PATH_Delete(dc->dclevel.hPath))
2477 {
2478 DC_UnlockDc(dc);
2479 return FALSE;
2480 }
2481
2482 dc->dclevel.hPath = 0;
2483 dc->dclevel.flPath &= ~DCPATH_ACTIVE;
2484
2485 DC_UnlockDc(dc);
2486 return TRUE;
2487}
2488
2489BOOL
2492{
2493 PPATH pPath;
2494 PDC dc;
2495
2496 dc = DC_LockDc(hDC);
2497 if (!dc)
2498 {
2500 return FALSE;
2501 }
2502
2503 /* If path is already open, do nothing. Check if not Save DC state */
2504 if ((dc->dclevel.flPath & DCPATH_ACTIVE) && !(dc->dclevel.flPath & DCPATH_SAVE))
2505 {
2506 DC_UnlockDc(dc);
2507 return TRUE;
2508 }
2509
2510 if (dc->dclevel.hPath)
2511 {
2512 TRACE("BeginPath 1 0x%p\n", dc->dclevel.hPath);
2513 if (!(dc->dclevel.flPath & DCPATH_SAVE))
2514 {
2515 // Remove previous handle.
2516 if (!PATH_Delete(dc->dclevel.hPath))
2517 {
2518 DC_UnlockDc(dc);
2519 return FALSE;
2520 }
2521 }
2522 else
2523 {
2524 // Clear flags and Handle.
2525 dc->dclevel.flPath &= ~(DCPATH_SAVE | DCPATH_ACTIVE);
2526 dc->dclevel.hPath = NULL;
2527 }
2528 }
2530 dc->dclevel.flPath |= DCPATH_ACTIVE; // Set active ASAP!
2531 dc->dclevel.hPath = pPath->BaseObject.hHmgr;
2532 IntGetCurrentPositionEx(dc, &pPath->pos);
2533 IntLPtoDP( dc, &pPath->pos, 1 );
2534 TRACE("BP : Current pos X %d Y %d\n",pPath->pos.x, pPath->pos.y);
2535 PATH_UnlockPath(pPath);
2536 DC_UnlockDc(dc);
2537
2538 if (!pPath)
2539 {
2540 return FALSE;
2541 }
2542 return TRUE;
2543}
2544
2545BOOL
2548{
2549 BOOL Ret = FALSE; // Default to failure
2550 PDC pDc;
2551 PPATH pPath;
2552
2553 TRACE("Enter %s\n", __FUNCTION__);
2554
2555 pDc = DC_LockDc(hDC);
2556 if (!pDc)
2557 {
2559 return FALSE;
2560 }
2561
2562 pPath = PATH_LockPath(pDc->dclevel.hPath);
2563 if (!pPath)
2564 {
2565 DC_UnlockDc(pDc);
2566 return FALSE;
2567 }
2568
2569 if (pPath->state == PATH_Open)
2570 {
2571 IntGdiCloseFigure(pPath);
2572 Ret = TRUE;
2573 }
2574 else
2575 {
2577 }
2578
2579 PATH_UnlockPath(pPath);
2580 DC_UnlockDc(pDc);
2581 return Ret;
2582}
2583
2584BOOL
2587{
2588 BOOL ret = TRUE;
2589 PPATH pPath;
2590 PDC dc;
2591
2592 dc = DC_LockDc(hDC);
2593 if (!dc)
2594 {
2596 return FALSE;
2597 }
2598
2599 pPath = PATH_LockPath(dc->dclevel.hPath);
2600 if (!pPath)
2601 {
2602 DC_UnlockDc(dc);
2603 return FALSE;
2604 }
2605
2606 /* Check that path is currently being constructed */
2607 if ((pPath->state != PATH_Open) || !(dc->dclevel.flPath & DCPATH_ACTIVE))
2608 {
2609 TRACE("EndPath ERROR! 0x%p\n", dc->dclevel.hPath);
2611 ret = FALSE;
2612 }
2613 /* Set flag to indicate that path is finished */
2614 else
2615 {
2616 TRACE("EndPath 0x%p\n", dc->dclevel.hPath);
2617 pPath->state = PATH_Closed;
2618 dc->dclevel.flPath &= ~DCPATH_ACTIVE;
2619 }
2620
2621 PATH_UnlockPath(pPath);
2622 DC_UnlockDc(dc);
2623 return ret;
2624}
2625
2626BOOL
2629{
2630 BOOL ret = FALSE;
2631 PPATH pPath, pNewPath;
2632 PDC_ATTR pdcattr;
2633 PDC dc;
2634
2635 dc = DC_LockDc(hDC);
2636 if (!dc)
2637 {
2639 return FALSE;
2640 }
2641
2642 pPath = PATH_LockPath(dc->dclevel.hPath);
2643 if (!pPath)
2644 {
2645 DC_UnlockDc(dc);
2646 return FALSE;
2647 }
2648
2650
2651 pdcattr = dc->pdcattr;
2652
2653 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
2655
2656 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
2658
2659 pNewPath = PATH_FlattenPath(pPath);
2660
2661 if (pNewPath->state != PATH_Closed)
2662 {
2664 }
2665 else if (pNewPath->numEntriesUsed)
2666 {
2667 ret = PATH_FillPath(dc, pNewPath);
2668 }
2669 else ret = TRUE;
2670
2671 PATH_UnlockPath(pNewPath);
2672 PATH_Delete(pNewPath->BaseObject.hHmgr);
2673
2674 PATH_UnlockPath(pPath);
2676 dc->dclevel.hPath = 0;
2677 dc->dclevel.flPath &= ~DCPATH_ACTIVE;
2678
2680 DC_UnlockDc(dc);
2681 return ret;
2682}
2683
2684BOOL
2687{
2688 BOOL Ret = FALSE;
2689 DC *pDc;
2690 PPATH pPath, pNewPath = NULL;
2691
2692 TRACE("Enter %s\n", __FUNCTION__);
2693
2694 pDc = DC_LockDc(hDC);
2695 if (!pDc)
2696 {
2698 return FALSE;
2699 }
2700
2701 pPath = PATH_LockPath(pDc->dclevel.hPath);
2702 if (!pPath)
2703 {
2705 DC_UnlockDc(pDc);
2706 return FALSE;
2707 }
2708
2709 if (pPath->state == PATH_Closed)
2710 {
2711 pNewPath = PATH_FlattenPath(pPath);
2712 }
2713
2714 PATH_UnlockPath(pPath);
2715
2716 if (pNewPath)
2717 {
2718 PATH_Delete(pDc->dclevel.hPath);
2719 pDc->dclevel.hPath = pNewPath->BaseObject.hHmgr;
2720 PATH_UnlockPath(pNewPath);
2721 Ret = TRUE;
2722 }
2723
2724 DC_UnlockDc(pDc);
2725 return Ret;
2726}
2727
2729BOOL
2731NtGdiGetMiterLimit(
2732 _In_ HDC hdc,
2734{
2735 DC *pDc;
2736 BOOL bResult = TRUE;
2737
2738 if (!(pDc = DC_LockDc(hdc)))
2739 {
2741 return FALSE;
2742 }
2743
2744 _SEH2_TRY
2745 {
2746 ProbeForWrite(pdwOut, sizeof(DWORD), 1);
2747 *pdwOut = pDc->dclevel.laPath.eMiterLimit;
2748 }
2750 {
2752 bResult = FALSE;
2753 }
2754 _SEH2_END;
2755
2756 DC_UnlockDc(pDc);
2757 return bResult;
2758
2759}
2760
2761INT
2764 HDC hDC,
2765 LPPOINT Points,
2766 LPBYTE Types,
2767 INT nSize)
2768{
2769 INT ret = -1;
2770 PPATH pPath;
2771 DC *dc;
2772
2773 _SEH2_TRY
2774 {
2775 ProbeForWrite(Points, nSize * sizeof(*Points), sizeof(ULONG));
2777 }
2779 {
2781 _SEH2_YIELD(return -1);
2782 }
2783 _SEH2_END
2784
2785 dc = DC_LockDc(hDC);
2786 TRACE("NtGdiGetPath start\n");
2787 if (!dc)
2788 {
2789 ERR("Can't lock dc!\n");
2791 return -1;
2792 }
2793
2794 pPath = PATH_LockPath(dc->dclevel.hPath);
2795 if (!pPath)
2796 {
2797 DC_UnlockDc(dc);
2798 return -1;
2799 }
2800
2801 if (pPath->state != PATH_Closed)
2802 {
2804 goto done;
2805 }
2806
2807 if (nSize == 0)
2808 {
2809 ret = pPath->numEntriesUsed;
2810 }
2811 else if (nSize < pPath->numEntriesUsed)
2812 {
2814 goto done;
2815 }
2816 else
2817 {
2818 _SEH2_TRY
2819 {
2820 memcpy(Points, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
2821 memcpy(Types, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
2822
2823 /* Convert the points to logical coordinates */
2824 if (!GdiPathDPtoLP(dc, Points, pPath->numEntriesUsed))
2825 {
2828 }
2829
2830 ret = pPath->numEntriesUsed;
2831 }
2833 {
2835 }
2836 _SEH2_END
2837 }
2838
2839done:
2840 TRACE("NtGdiGetPath exit %d\n",ret);
2841 PATH_UnlockPath(pPath);
2842 DC_UnlockDc(dc);
2843 return ret;
2844}
2845
2846HRGN
2849{
2850 PPATH pPath, pNewPath;
2851 HRGN hrgnRval = 0;
2852 int Ret;
2853 PREGION Rgn;
2854 DC *pDc;
2855 PDC_ATTR pdcattr;
2856
2857 TRACE("Enter %s\n", __FUNCTION__);
2858
2859 pDc = DC_LockDc(hDC);
2860 if (!pDc)
2861 {
2862 ERR("Failed to lock DC %p\n", hDC);
2864 return NULL;
2865 }
2866
2867 pdcattr = pDc->pdcattr;
2868
2869 pPath = PATH_LockPath(pDc->dclevel.hPath);
2870 if (!pPath)
2871 {
2872 ERR("Failed to lock DC path %p\n", pDc->dclevel.hPath);
2873 DC_UnlockDc(pDc);
2874 return NULL;
2875 }
2876
2877 if (pPath->state != PATH_Closed)
2878 {
2879 // FIXME: Check that setlasterror is being called correctly
2880 ERR("Path is not closed!\n");
2882 }
2883 else
2884 {
2885 /* Create the region and fill it with the path strokes */
2887 if (!Rgn)
2888 {
2889 ERR("Failed to allocate a region\n");
2890 PATH_UnlockPath(pPath);
2891 DC_UnlockDc(pDc);
2892 return NULL;
2893 }
2894 hrgnRval = Rgn->BaseObject.hHmgr;
2895
2896 pNewPath = PATH_FlattenPath(pPath);
2897 if (pNewPath == NULL)
2898 {
2899 ERR("Failed to flatten path %p\n", pDc->dclevel.hPath);
2900 REGION_Delete(Rgn);
2901 PATH_UnlockPath(pPath);
2902 DC_UnlockDc(pDc);
2903 return NULL;
2904 }
2905
2906 Ret = PATH_PathToRegion(pNewPath, pdcattr->jFillMode, Rgn);
2907
2908 PATH_UnlockPath(pNewPath);
2909 PATH_Delete(pNewPath->BaseObject.hHmgr);
2910
2911 if (!Ret)
2912 {
2913 ERR("PATH_PathToRegion failed\n");
2914 REGION_Delete(Rgn);
2915 hrgnRval = NULL;
2916 }
2917 else
2918 REGION_UnlockRgn(Rgn);
2919 }
2920
2921 PATH_UnlockPath(pPath);
2922 PATH_Delete(pDc->dclevel.hPath);
2923 pDc->dclevel.hPath = NULL;
2924 pDc->dclevel.flPath &= ~DCPATH_ACTIVE;
2925
2926 DC_UnlockDc(pDc);
2927 return hrgnRval;
2928}
2929
2930BOOL
2933 IN HDC hdc,
2934 IN DWORD dwNew,
2936{
2937 DC *pDc;
2938 gxf_long worker, worker1;
2939 BOOL bResult = TRUE;
2940
2941 if (!(pDc = DC_LockDc(hdc)))
2942 {
2944 return FALSE;
2945 }
2946
2947 worker.l = dwNew;
2948 worker1.f = pDc->dclevel.laPath.eMiterLimit;
2949 pDc->dclevel.laPath.eMiterLimit = worker.f;
2950
2951 if (pdwOut)
2952 {
2953 _SEH2_TRY
2954 {
2955 ProbeForWrite(pdwOut, sizeof(DWORD), 1);
2956 *pdwOut = worker1.l;
2957 }
2959 {
2961 bResult = FALSE;
2962 }
2963 _SEH2_END;
2964 }
2965
2966 DC_UnlockDc(pDc);
2967 return bResult;
2968}
2969
2970BOOL
2973{
2974 DC *pDc;
2975 PDC_ATTR pdcattr;
2976 PPATH pPath, pNewPath;
2977 BOOL bRet = FALSE;
2978
2979 TRACE("Enter %s\n", __FUNCTION__);
2980
2981 if (!(pDc = DC_LockDc(hDC)))
2982 {
2984 return FALSE;
2985 }
2986 pPath = PATH_LockPath(pDc->dclevel.hPath);
2987 if (!pPath)
2988 {
2989 DC_UnlockDc(pDc);
2990 return FALSE;
2991 }
2992
2994
2995 pdcattr = pDc->pdcattr;
2996
2997 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
2999
3000 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
3002
3003 pNewPath = PATH_FlattenPath(pPath);
3004
3005 if (pNewPath->state != PATH_Closed)
3006 {
3008 }
3009 else if (pNewPath->numEntriesUsed)
3010 {
3011 bRet = PATH_FillPath(pDc, pNewPath);
3012 if (bRet) bRet = PATH_StrokePath(pDc, pNewPath);
3013 }
3014 else bRet = TRUE;
3015
3016 PATH_UnlockPath(pNewPath);
3017 PATH_Delete(pNewPath->BaseObject.hHmgr);
3018
3019 PATH_UnlockPath(pPath);
3021 pDc->dclevel.hPath = 0;
3022 pDc->dclevel.flPath &= ~DCPATH_ACTIVE;
3023
3024 DC_vFinishBlit(pDc, NULL);
3025 DC_UnlockDc(pDc);
3026 return bRet;
3027}
3028
3029BOOL
3032{
3033 DC *pDc;
3034 PDC_ATTR pdcattr;
3035 PPATH pPath, pNewPath;
3036 BOOL bRet = FALSE;
3037
3038 TRACE("Enter %s\n", __FUNCTION__);
3039
3040 if (!(pDc = DC_LockDc(hDC)))
3041 {
3043 return FALSE;
3044 }
3045
3046 pPath = PATH_LockPath(pDc->dclevel.hPath);
3047 if (!pPath)
3048 {
3049 DC_UnlockDc(pDc);
3050 return FALSE;
3051 }
3052
3054
3055 pdcattr = pDc->pdcattr;
3056
3057 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
3059
3060 pNewPath = PATH_FlattenPath(pPath);
3061
3062 if (pNewPath->state != PATH_Closed)
3063 {
3065 }
3066 else bRet = PATH_StrokePath(pDc, pNewPath);
3067
3068 PATH_UnlockPath(pNewPath);
3069 PATH_Delete(pNewPath->BaseObject.hHmgr);
3070
3071 DC_vFinishBlit(pDc, NULL);
3072
3073 PATH_UnlockPath(pPath);
3075 pDc->dclevel.hPath = 0;
3076 pDc->dclevel.flPath &= ~DCPATH_ACTIVE;
3077
3078 DC_UnlockDc(pDc);
3079 return bRet;
3080}
3081
3082BOOL
3085{
3086 PPATH pPath;
3087 BOOL Ret = FALSE;
3088 PDC pdc = DC_LockDc(hDC);
3089 TRACE("NtGdiWidenPat Enter\n");
3090 if (!pdc)
3091 {
3093 return FALSE;
3094 }
3095
3096 pPath = PATH_WidenPath(pdc);
3097 if (pPath)
3098 {
3099 TRACE("WindenPath New Path\n");
3100 PATH_Delete(pdc->dclevel.hPath);
3101 pdc->dclevel.hPath = pPath->BaseObject.hHmgr;
3102 Ret = TRUE;
3103 }
3104 DC_UnlockDc(pdc);
3105 TRACE("NtGdiWidenPat Ret %d\n",Ret);
3106 return Ret;
3107}
3108
3109/* EOF */
static HDC hDC
Definition: 3dtext.c:33
unsigned char BOOLEAN
_STLP_DECLSPEC complex< float > _STLP_CALL cos(const complex< float > &)
_STLP_DECLSPEC complex< float > _STLP_CALL sin(const complex< float > &)
_STLP_DECLSPEC complex< float > _STLP_CALL sqrt(const complex< float > &)
Definition: complex.cpp:188
valarray< _Tp > atan2(const valarray< _Tp > &__x, const valarray< _Tp > &__y)
Definition: _valarray.h:928
char ACPI_OBJECT_TYPE * Types
Definition: acdebug.h:354
int yOffset
Definition: appswitch.c:58
int xOffset
Definition: appswitch.c:58
#define WINDING
Definition: constants.h:279
#define ERR(fmt,...)
Definition: precomp.h:57
POINT * GDI_Bezier(const POINT *Points, INT count, INT *nPtsOut)
Definition: bezier.c:189
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:106
HGDIOBJ hHmgr(VOID)
Definition: baseobj.hpp:95
#define CoordLPtoDP(pdc, ppt)
Definition: coord.h:187
static BOOLEAN INTERNAL_LPTODP(DC *dc, LPPOINT points, UINT count)
Definition: coord.h:47
#define XForm2MatrixS(m, x)
Definition: coord.h:199
#define MatrixS2XForm(x, m)
Definition: coord.h:200
FORCEINLINE PSIZEL DC_pszlViewportExt(PDC pdc)
Definition: coord.h:111
static BOOLEAN IntDPtoLP(DC *pdc, PPOINTL ppt, UINT count)
Definition: coord.h:192
static BOOLEAN IntLPtoDP(DC *pdc, PPOINTL ppt, UINT count)
Definition: coord.h:182
#define M_PI_4
HDC dc
Definition: cylfrac.c:34
VOID FASTCALL DC_vPrepareDCsForBlit(PDC pdcDest, const RECT *rcDest, PDC pdcSrc, const RECT *rcSrc)
Definition: dclife.c:505
VOID FASTCALL DC_vUpdateLineBrush(PDC pdc)
Definition: dcobjs.c:62
VOID FASTCALL DC_vFinishBlit(PDC pdc1, PDC pdc2)
Definition: dclife.c:614
FORCEINLINE VOID DC_UnlockDc(PDC pdc)
Definition: dc.h:238
VOID FASTCALL DC_vUpdateFillBrush(PDC pdc)
Definition: dcobjs.c:16
FORCEINLINE PDC DC_LockDc(HDC hdc)
Definition: dc.h:220
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
unsigned int idx
Definition: utils.c:41
#define APIENTRY
Definition: api.h:79
static WCHAR no[MAX_STRING_RESOURCE_LEN]
Definition: object.c:2340
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define ERROR_INVALID_HANDLE
Definition: compat.h:98
static void cleanup(void)
Definition: main.c:1335
#define pt(x, y)
Definition: drawing.c:79
return ret
Definition: mutex.c:146
#define __FUNCTION__
Definition: types.h:116
POINTL point
Definition: edittest.c:50
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define PagedPool
Definition: env_spec_w32.h:308
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
static const FLOATOBJ gef1
Definition: floatobj.h:114
static const FLOATOBJ gef2
Definition: floatobj.h:115
#define FLOATOBJ_bConvertToLong(pf, pl)
Definition: floatobj.h:102
ULONG FASTCALL ftGdiGetGlyphOutline(PDC dc, WCHAR wch, UINT iFormat, LPGLYPHMETRICS pgm, ULONG cjBuf, PVOID pvBuf, const MAT2 *pmat2, BOOL bIgnoreRotation)
Definition: freetype.c:4626
#define GDI_HANDLE_GET_TYPE(h)
Definition: gdi.h:31
#define GDI_OBJECT_TYPE_EXTPEN
Definition: gdi.h:55
#define GDI_OBJECT_TYPE_PEN
Definition: gdi.h:54
GLuint start
Definition: gl.h:1545
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLclampf GLclampf GLclampf alpha
Definition: gl.h:1740
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLuint GLuint end
Definition: gl.h:1545
GLdouble n
Definition: glext.h:7729
GLenum src
Definition: glext.h:6340
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
GLdouble GLdouble GLdouble GLdouble top
Definition: glext.h:10859
GLdouble GLdouble right
Definition: glext.h:10859
GLfloat f
Definition: glext.h:7540
GLint left
Definition: glext.h:7726
GLenum GLenum dst
Definition: glext.h:6340
GLbitfield flags
Definition: glext.h:7161
GLint GLint bottom
Definition: glext.h:7726
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
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
_In_ ULONG Mode
Definition: hubbusif.h:303
_Check_return_ _CRT_JIT_INTRINSIC double __cdecl fabs(_In_ double x)
Definition: fabs.c:17
_Check_return_ _CRTIMP double __cdecl floor(_In_ double x)
_Check_return_ _CRTIMP double __cdecl ceil(_In_ double x)
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
BOOL FASTCALL IntGdiPolyline(DC *dc, LPPOINT pt, int Count)
Definition: line.c:327
BOOL FASTCALL IntGdiMoveToEx(DC *dc, int X, int Y, LPPOINT Point)
Definition: line.c:80
#define e
Definition: ke_i.h:82
#define a
Definition: ke_i.h:78
#define KeSaveFloatingPointState(x)
Definition: kmixer.h:32
#define KeRestoreFloatingPointState(x)
Definition: kmixer.h:33
GLint dx
Definition: linetemp.h:97
#define M_PI
Definition: macros.h:263
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
void * Realloc(void *, size_t)
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:56
HDC hdc
Definition: main.c:9
static HDC
Definition: imagelist.c:88
#define M_PI_2
Definition: port.h:185
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
direction
Definition: netio.c:882
#define _Success_(c)
Definition: no_sal2.h:84
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define FASTCALL
Definition: nt_native.h:50
int APIENTRY IntGdiSetMapMode(PDC dc, int MapMode)
Definition: coord.c:828
BOOL NTAPI GreModifyWorldTransform(PDC pdc, const XFORML *pxform, DWORD dwMode)
Definition: coord.c:461
_Out_ PDWORD pdwOut
Definition: ntgdi.h:1813
__kernel_entry W32KAPI BOOL APIENTRY NtGdiEndPath(_In_ HDC hdc)
__kernel_entry W32KAPI INT APIENTRY NtGdiGetPath(_In_ HDC hdc, _Out_writes_opt_(cptBuf) LPPOINT pptlBuf, _Out_writes_opt_(cptBuf) LPBYTE pjTypes, _In_ INT cptBuf)
__kernel_entry W32KAPI BOOL APIENTRY NtGdiCloseFigure(_In_ HDC hdc)
__kernel_entry W32KAPI BOOL APIENTRY NtGdiFlattenPath(_In_ HDC hdc)
__kernel_entry W32KAPI HRGN APIENTRY NtGdiPathToRegion(_In_ HDC hdc)
__kernel_entry W32KAPI BOOL APIENTRY NtGdiStrokePath(_In_ HDC hdc)
__kernel_entry W32KAPI BOOL APIENTRY NtGdiAbortPath(_In_ HDC hdc)
__kernel_entry W32KAPI BOOL APIENTRY NtGdiWidenPath(_In_ HDC hdc)
__kernel_entry W32KAPI BOOL APIENTRY NtGdiFillPath(_In_ HDC hdc)
__kernel_entry W32KAPI BOOL APIENTRY NtGdiSetMiterLimit(_In_ HDC hdc, _In_ DWORD dwNew, _Inout_opt_ PDWORD pdwOut)
__kernel_entry W32KAPI BOOL APIENTRY NtGdiBeginPath(_In_ HDC hdc)
__kernel_entry W32KAPI BOOL APIENTRY NtGdiStrokeAndFillPath(_In_ HDC hdc)
#define DIRTY_FILL
Definition: ntgdihdl.h:123
#define DC_PEN_DIRTY
Definition: ntgdihdl.h:136
#define DIRTY_LINE
Definition: ntgdihdl.h:124
#define DIRTY_STYLESTATE
Definition: ntgdihdl.h:133
#define DC_BRUSH_DIRTY
Definition: ntgdihdl.h:135
@ GdiTypeChord
Definition: ntgdityp.h:22
@ GdiTypeArcTo
Definition: ntgdityp.h:21
@ GdiTypePie
Definition: ntgdityp.h:23
#define MWT_SET
Definition: ntgdityp.h:180
#define PATH_AllocPathWithHandle()
Definition: path.h:69
#define PATH_UnlockPath(pPath)
Definition: path.h:71
@ PATH_Null
Definition: path.h:18
@ PATH_Open
Definition: path.h:19
@ PATH_Closed
Definition: path.h:20
@ DCPATH_SAVE
Definition: path.h:7
@ DCPATH_CLOCKWISE
Definition: path.h:8
@ DCPATH_ACTIVE
Definition: path.h:6
#define PATH_LockPath(hPath)
Definition: path.h:70
DWORD * PDWORD
Definition: pedump.c:68
long LONG
Definition: pedump.c:60
#define IntIsEffectiveWidePen(pbrLine)
Definition: pen.h:33
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:181
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:82
#define _SEH2_END
Definition: pseh2_64.h:171
#define _SEH2_TRY
Definition: pseh2_64.h:71
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:184
#define _SEH2_LEAVE
Definition: pseh2_64.h:183
static unsigned __int64 next
Definition: rand_nt.c:6
const WCHAR * str
static calc_node_t temp
Definition: rpn_ieee.c:38
#define memset(x, y, z)
Definition: compat.h:39
static void Exit(void)
Definition: sock.c:1330
#define TRACE(s)
Definition: solgame.cpp:4
& rect
Definition: startmenu.cpp:1413
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
Definition: polytest.cpp:41
Definition: types.h:101
HANDLE hpen
Definition: ntgdihdl.h:296
SIZEL szlViewportExt
Definition: ntgdihdl.h:344
INT iMapMode
Definition: ntgdihdl.h:338
INT iGraphicsMode
Definition: ntgdihdl.h:306
POINTL ptlViewportOrg
Definition: ntgdihdl.h:343
POINTL ptlWindowOrg
Definition: ntgdihdl.h:341
ULONG ulDirty_
Definition: ntgdihdl.h:294
BYTE jFillMode
Definition: ntgdihdl.h:309
SIZEL szlWindowExt
Definition: ntgdihdl.h:342
short gmCellIncX
Definition: wingdi.h:2891
short gmCellIncY
Definition: wingdi.h:2892
Definition: wingdi.h:2918
Definition: path.h:35
BOOL newStroke
Definition: path.h:57
POINT pos
Definition: path.h:58
BASEOBJECT BaseObject
Definition: path.h:36
FLONG state
Definition: path.h:52
BYTE * pFlags
Definition: path.h:54
int numEntriesUsed
Definition: path.h:55
POINT * pPoints
Definition: path.h:53
int numEntriesAllocated
Definition: path.h:56
LONG y
Definition: windef.h:124
LONG x
Definition: windef.h:123
Definition: region.h:8
BASEOBJECT BaseObject
Definition: region.h:11
LONG cx
Definition: kdterminal.h:27
LONG cy
Definition: kdterminal.h:28
Definition: mesh.c:5330
DWORD elpWidth
Definition: wingdi.h:2389
DWORD elpPenStyle
Definition: wingdi.h:2388
FIXED y
Definition: wingdi.h:3155
FIXED x
Definition: wingdi.h:3154
long y
Definition: polytest.cpp:48
long x
Definition: polytest.cpp:48
POINTFX apfx[1]
Definition: wingdi.h:3160
Definition: cmds.c:130
#define max(a, b)
Definition: svc.c:63
eMaj lines
Definition: tritemp.h:206
uint32_t * PULONG
Definition: typedefs.h:59
unsigned char * LPBYTE
Definition: typedefs.h:53
float FLOAT
Definition: typedefs.h:69
int32_t INT
Definition: typedefs.h:58
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
ULONG l
Definition: ntgdityp.h:427
FLOAT f
Definition: ntgdityp.h:426
VOID FASTCALL SetLastNtError(_In_ NTSTATUS Status)
Definition: error.c:31
BOOL IntGdiFillRgn(_In_ PDC pdc, _In_ PREGION prgn, _In_opt_ PBRUSH pbrFill)
Definition: bitblt.c:1192
INT NTAPI GreGetObject(IN HGDIOBJ hobj, IN INT cbCount, OUT PVOID pvBuffer)
Definition: gdiobj.c:1277
VOID NTAPI GDIOBJ_vUnlockObject(POBJ pobj)
Definition: gdiobj.c:887
VOID NTAPI GDIOBJ_vDeleteObject(POBJ pobj)
Definition: gdiobj.c:1118
VOID FASTCALL IntGetCurrentPositionEx(PDC dc, LPPOINT pt)
Definition: line.c:130
static BYTE * add_log_points(DC *dc, PPATH path, const POINT *points, DWORD count, BYTE type)
Definition: path.c:463
#define NUM_ENTRIES_INITIAL
Definition: path.c:21
BOOL FASTCALL PATH_AssignGdiPath(PPATH pPathDest, const PPATH pPathSrc)
Definition: path.c:166
BOOL PATH_RestorePath(DC *dst, DC *src)
Definition: path.c:209
BOOL FASTCALL PATH_PolyBezierTo(PDC dc, const POINT *pts, DWORD cbPoints)
Definition: path.c:1131
static BOOLEAN PATH_ScaleNormalizedPoint(POINT corners[], FLOATL x, FLOATL y, POINT *pPoint)
Definition: path.c:363
BOOL FASTCALL PATH_PolyPolygon(PDC dc, const POINT *pts, const INT *counts, UINT polygons)
Definition: path.c:1288
BOOL FASTCALL PATH_PolyBezier(PDC dc, const POINT *pts, DWORD cbPoints)
Definition: path.c:1154
BOOL PATH_RoundRect(DC *dc, INT x1, INT y1, INT x2, INT y2, INT ell_width, INT ell_height)
Definition: path.c:675
PPATH FASTCALL IntGdiWidenPath(PPATH pPath, UINT penWidth, UINT penStyle, FLOAT eMiterLimit)
Definition: path.c:1789
BOOL FASTCALL PATH_PathToRegion(PPATH pPath, INT Mode, PREGION Rgn)
Definition: path.c:1450
BOOL FASTCALL PATH_Rectangle(PDC dc, INT x1, INT y1, INT x2, INT y2)
Definition: path.c:627
BOOL FASTCALL PATH_Delete(HPATH hPath)
Definition: path.c:90
static void update_current_pos(PPATH path)
Definition: path.c:519
static BOOL PATH_CheckRect(DC *dc, RECTL *rect, INT x1, INT y1, INT x2, INT y2)
Definition: path.c:433
#define GROW_FACTOR_DENOM
Definition: path.c:24
BOOL FASTCALL PATH_FillPathEx(PDC dc, PPATH pPath, PBRUSH pbrFill)
Definition: path.c:1514
VOID FASTCALL PATH_DestroyGdiPath(PPATH pPath)
Definition: path.c:80
BOOL FASTCALL PATH_ReserveEntries(PPATH pPath, INT numEntries)
Definition: path.c:296
static void close_figure(PPATH path)
Definition: path.c:526
VOID FASTCALL IntGdiCloseFigure(PPATH pPath)
Definition: path.c:108
VOID FASTCALL PATH_InitGdiPath(PPATH pPath)
Definition: path.c:142
BOOL PATH_Ellipse(PDC dc, INT x1, INT y1, INT x2, INT y2)
Definition: path.c:782
#define round(x)
Definition: path.c:1786
static BOOL PATH_DoArcPart(PPATH pPath, POINT corners[], double angleStart, double angleEnd, BYTE startEntryType)
Definition: path.c:890
BOOL FASTCALL PATH_PolylineTo(PDC dc, const POINT *pts, DWORD cbPoints)
Definition: path.c:1264
BOOL FASTCALL GdiPathDPtoLP(PDC pdc, PPOINT ppt, INT count)
Definition: path.c:125
BOOL FASTCALL PATH_LineTo(PDC dc, INT x, INT y)
Definition: path.c:583
static VOID FASTCALL PATH_BezierTo(PPATH pPath, POINT *lppt, INT n)
Definition: path.c:2216
static VOID PATH_NormalizePoint(POINTL corners[], const POINTL *pPoint, FLOATL *pX, FLOATL *pY)
Definition: path.c:401
BOOL FASTCALL PATH_FillPath(PDC dc, PPATH pPath)
Definition: path.c:1505
BOOL FASTCALL PATH_ExtTextOut(PDC dc, INT x, INT y, UINT flags, const RECTL *lprc, LPCWSTR str, UINT count, const INT *dx)
Definition: path.c:2357
PPATH FASTCALL PATH_FlattenPath(PPATH pPath)
Definition: path.c:1407
BOOL FASTCALL PATH_StrokePath(DC *dc, PPATH pPath)
Definition: path.c:1597
BOOL FASTCALL PATH_AddEntry(PPATH pPath, const POINT *pPoint, BYTE flags)
Definition: path.c:262
VOID FASTCALL PATH_EmptyPath(PPATH pPath)
Definition: path.c:246
BOOL FASTCALL PATH_PolyPolyline(PDC dc, const POINT *pts, const DWORD *counts, DWORD polylines)
Definition: path.c:1338
#define GROW_FACTOR_NUMER
Definition: path.c:23
static BOOL add_log_points_new_stroke(DC *dc, PPATH path, const POINT *points, DWORD count, BYTE type)
Definition: path.c:533
PPATH FASTCALL PATH_CreatePath(int count)
Definition: path.c:35
static BYTE * add_points(PPATH path, const POINT *points, DWORD count, BYTE type)
Definition: path.c:480
BOOL FASTCALL PATH_PolyDraw(PDC dc, const POINT *pts, const BYTE *types, DWORD cbPoints)
Definition: path.c:1180
BOOL FASTCALL PATH_AddFlatBezier(PPATH pPath, POINT *pt, BOOL closed)
Definition: path.c:1378
static void reverse_points(POINT *points, UINT count)
Definition: path.c:494
static BOOL start_new_stroke(PPATH path)
Definition: path.c:506
static INT int_from_fixed(FIXED f)
Definition: path.c:2203
BOOL FASTCALL PATH_Arc(PDC dc, INT x1, INT y1, INT x2, INT y2, INT xStart, INT yStart, INT xEnd, INT yEnd, INT direction, INT lines)
Definition: path.c:955
PPATH FASTCALL PATH_WidenPathEx(DC *dc, PPATH pPath)
Definition: path.c:2138
BOOL FASTCALL PATH_MoveTo(PDC dc, PPATH pPath)
Definition: path.c:554
static BOOL FASTCALL PATH_add_outline(PDC dc, PPATH pPath, INT x, INT y, TTPOLYGONHEADER *header, DWORD size)
Definition: path.c:2260
static PPATH FASTCALL PATH_WidenPath(DC *dc)
Definition: path.c:2120
BOOL PATH_SavePath(DC *dst, DC *src)
Definition: path.c:187
VOID FASTCALL RECTL_vMakeWellOrdered(_Inout_ RECTL *prcl)
Definition: rect.c:81
FORCEINLINE LONG RECTL_lGetWidth(_In_ const RECTL *prcl)
Definition: rect.h:93
FORCEINLINE VOID RECTL_vSetRect(_Out_ RECTL *prcl, _In_ LONG left, _In_ LONG top, _In_ LONG right, _In_ LONG bottom)
Definition: rect.h:5
FORCEINLINE LONG RECTL_lGetHeight(_In_ const RECTL *prcl)
Definition: rect.h:86
VOID FASTCALL REGION_Delete(PREGION pRgn)
Definition: region.c:2449
BOOL FASTCALL REGION_SetPolyPolygonRgn(_Inout_ PREGION prgn, _In_ const POINT *ppt, _In_ const ULONG *pcPoints, _In_ ULONG cPolygons, _In_ INT iMode)
Definition: region.c:3254
VOID FASTCALL REGION_UnlockRgn(_In_ PREGION prgn)
Definition: region.c:2373
PREGION FASTCALL IntSysCreateRectpRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
Definition: region.c:2407
PREGION FASTCALL REGION_AllocUserRgnWithHandle(INT nRgn)
Definition: region.c:2294
#define TAG_PATH
Definition: tags.h:25
#define TAG_BEZIER
Definition: tags.h:13
*nSize LPSTR _Inout_ LPDWORD nSize
Definition: winbase.h:1834
#define FLOATOBJ_Div(pf, pf1)
Definition: winddi.h:2827
#define FLOATOBJ_DivLong(pf, l)
Definition: winddi.h:2829
FLOAT * PFLOATOBJ
Definition: winddi.h:677
#define XF_LTOL
Definition: winddi.h:3109
#define FLOATOBJ_Sub(pf, pf1)
Definition: winddi.h:2821
FLOAT FLOATL
Definition: winddi.h:114
FLOAT FLOATOBJ
Definition: winddi.h:677
#define FLOATOBJ_Add(pf, pf1)
Definition: winddi.h:2818
#define FLOATOBJ_MulLong(pf, l)
Definition: winddi.h:2826
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3708
ENGAPI INT APIENTRY EngMulDiv(_In_ INT a, _In_ INT b, _In_ INT c)
Definition: math.c:26
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG y1
Definition: winddi.h:3709
#define FLOATOBJ_SetFloat(pf, f)
Definition: winddi.h:2814
_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
ENGAPI VOID APIENTRY EngSetLastError(_In_ ULONG iError)
Definition: error.c:22
#define FLOATOBJ_GetFloat(pf)
Definition: winddi.h:2816
#define FLOATOBJ_SetLong(pf, l)
Definition: winddi.h:2815
#define FLOATOBJ_AddLong(pf, l)
Definition: winddi.h:2820
#define ERROR_CAN_NOT_COMPLETE
Definition: winerror.h:906
#define ERROR_ARITHMETIC_OVERFLOW
Definition: winerror.h:623
#define GM_COMPATIBLE
Definition: wingdi.h:864
#define PS_JOIN_BEVEL
Definition: wingdi.h:597
#define GM_ADVANCED
Definition: wingdi.h:865
#define PS_ENDCAP_SQUARE
Definition: wingdi.h:595
struct tagPOINTFX POINTFX
#define PS_JOIN_ROUND
Definition: wingdi.h:599
#define PS_COSMETIC
Definition: wingdi.h:584
#define TT_PRIM_CSPLINE
Definition: wingdi.h:1321
#define PS_ENDCAP_ROUND
Definition: wingdi.h:594
#define TT_POLYGON_TYPE
Definition: wingdi.h:1318
#define PT_LINETO
Definition: wingdi.h:885
#define TT_PRIM_QSPLINE
Definition: wingdi.h:1320
#define PS_JOIN_MASK
Definition: wingdi.h:600
#define GGO_GLYPH_INDEX
Definition: wingdi.h:855
#define GDI_ERROR
Definition: wingdi.h:1309
#define PT_CLOSEFIGURE
Definition: wingdi.h:887
#define MM_TEXT
Definition: wingdi.h:873
#define PT_MOVETO
Definition: wingdi.h:884
#define MWT_IDENTITY
Definition: wingdi.h:944
#define ETO_PDY
Definition: wingdi.h:657
#define PT_BEZIERTO
Definition: wingdi.h:886
#define GGO_NATIVE
Definition: wingdi.h:850
#define TT_PRIM_LINE
Definition: wingdi.h:1319
#define AD_CLOCKWISE
Definition: wingdi.h:668
#define PS_JOIN_MITER
Definition: wingdi.h:598
#define PS_ENDCAP_MASK
Definition: wingdi.h:602
#define PS_TYPE_MASK
Definition: wingdi.h:603
#define PS_ENDCAP_FLAT
Definition: wingdi.h:596
_In_ int _Inout_ LPRECT lprc
Definition: winuser.h:4568
#define XFORMOBJ_vInit
Definition: xformobj.h:12
#define XFORMOBJ_bApplyXform
Definition: xformobj.h:11
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
unsigned char BYTE
Definition: xxhash.c:193