ReactOS  0.4.15-dev-5615-gc3644fd
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 
15 DBG_DEFAULT_CHANNEL(GdiPath);
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
27 static 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 
55  pPath->numEntriesAllocated = count;
56 
57  pPath->pPoints = (POINT *)ExAllocatePoolWithTag(PagedPool, count * sizeof(POINT), TAG_PATH);
58  RtlZeroMemory( pPath->pPoints, count * sizeof(POINT));
59  pPath->pFlags = (BYTE *)ExAllocatePoolWithTag(PagedPool, count * sizeof(BYTE), TAG_PATH);
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  */
78 VOID
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 
88 BOOL
91 {
92  PPATH pPath;
93  if (!hPath) return FALSE;
94  pPath = PATH_LockPath(hPath);
95  if (!pPath) return FALSE;
96  PATH_DestroyGdiPath(pPath);
98 #if DBG
99  PathCount--;
100  TRACE("Delete Path %d\n",PathCount);
101 #endif
102  return TRUE;
103 }
104 
105 
106 VOID
107 FASTCALL
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. */
123 BOOL
124 FASTCALL
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  */
140 VOID
141 FASTCALL
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  */
164 BOOL
165 FASTCALL
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  */
244 VOID
245 FASTCALL
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  */
260 BOOL
261 FASTCALL
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  */
294 BOOL
295 FASTCALL
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  */
361 static
362 BOOLEAN
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  */
399 static
400 VOID
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  */
431 static
432 BOOL
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 */
444  RECTL_vSetRect(rect, x1, y1, x2, y2);
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 */
464  DWORD count, BYTE type )
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 */
526 static 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 */
534  DWORD count, BYTE type )
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  */
552 BOOL
553 FASTCALL
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.
566  IntGetCurrentPositionEx(dc, &pPath->pos);
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  */
581 BOOL
582 FASTCALL
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  */
625 BOOL
626 FASTCALL
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  */
674 BOOL
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  */
781 BOOL
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  */
888 static
889 BOOL
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  */
953 BOOL
954 FASTCALL
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,
965  INT direction,
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  }
1124 ArcExit:
1125  PATH_UnlockPath(pPath);
1126  return Ret;
1127 }
1128 
1129 BOOL
1130 FASTCALL
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 
1152 BOOL
1153 FASTCALL
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 
1178 BOOL
1179 FASTCALL
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:
1219  case PT_LINETO | PT_CLOSEFIGURE:
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 
1262 BOOL
1263 FASTCALL
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 
1286 BOOL
1287 FASTCALL
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 
1336 BOOL
1337 FASTCALL
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  */
1376 BOOL
1377 FASTCALL
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  */
1405 PPATH
1406 FASTCALL
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  */
1448 BOOL
1449 FASTCALL
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  */
1503 BOOL
1504 FASTCALL
1506  PDC dc,
1507  PPATH pPath)
1508 {
1509  return PATH_FillPathEx(dc, pPath, NULL);
1510 }
1511 
1512 BOOL
1513 FASTCALL
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 
1595 BOOL
1596 FASTCALL
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 
1751 end:
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 
1789 IntGdiWidenPath(PPATH pPath, UINT penWidth, UINT penStyle, FLOAT eMiterLimit)
1790 {
1791  INT i, j, numStrokes, numOldStrokes, penWidthIn, penWidthOut;
1792  PPATH flat_path, pNewPath, *pStrokes = NULL, *pOldStrokes, pUpPath, pDownPath;
1793  BYTE *type;
1794  DWORD joint, endcap;
1795 
1796  endcap = (PS_ENDCAP_MASK & penStyle);
1797  joint = (PS_JOIN_MASK & penStyle);
1798 
1799  if (!(flat_path = PATH_FlattenPath(pPath)))
1800  {
1801  ERR("PATH_FlattenPath\n");
1802  return NULL;
1803  }
1804 
1805  penWidthIn = penWidth / 2;
1806  penWidthOut = penWidth / 2;
1807  if (penWidthIn + penWidthOut < penWidth)
1808  penWidthOut++;
1809 
1810  numStrokes = 0;
1811 
1812  for (i = 0, j = 0; i < flat_path->numEntriesUsed; i++, j++)
1813  {
1814  POINT point;
1815  if ((i == 0 || (flat_path->pFlags[i - 1] & PT_CLOSEFIGURE)) &&
1816  (flat_path->pFlags[i] != PT_MOVETO))
1817  {
1818  ERR("Expected PT_MOVETO %s, got path flag %c\n",
1819  i == 0 ? "as first point" : "after PT_CLOSEFIGURE",
1820  flat_path->pFlags[i]);
1821  if (pStrokes)
1822  ExFreePoolWithTag(pStrokes, TAG_PATH);
1823  PATH_UnlockPath(flat_path);
1824  PATH_Delete(flat_path->BaseObject.hHmgr);
1825  return NULL;
1826  }
1827  switch(flat_path->pFlags[i])
1828  {
1829  case PT_MOVETO:
1830  if (numStrokes > 0)
1831  {
1832  pStrokes[numStrokes - 1]->state = PATH_Closed;
1833  }
1834  numOldStrokes = numStrokes;
1835  numStrokes++;
1836  j = 0;
1837  if (numStrokes == 1)
1838  pStrokes = ExAllocatePoolWithTag(PagedPool, sizeof(*pStrokes), TAG_PATH);
1839  else
1840  {
1841  pOldStrokes = pStrokes; // Save old pointer.
1842  pStrokes = ExAllocatePoolWithTag(PagedPool, numStrokes * sizeof(*pStrokes), TAG_PATH);
1843  if (!pStrokes)
1844  {
1845  ExFreePoolWithTag(pOldStrokes, TAG_PATH);
1846  PATH_UnlockPath(flat_path);
1847  PATH_Delete(flat_path->BaseObject.hHmgr);
1848  return NULL;
1849  }
1850  RtlCopyMemory(pStrokes, pOldStrokes, numOldStrokes * sizeof(PPATH));
1851  ExFreePoolWithTag(pOldStrokes, TAG_PATH); // Free old pointer.
1852  }
1853  if (!pStrokes)
1854  {
1855  PATH_UnlockPath(flat_path);
1856  PATH_Delete(flat_path->BaseObject.hHmgr);
1857  return NULL;
1858  }
1859  pStrokes[numStrokes - 1] = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
1860  if (!pStrokes[numStrokes - 1])
1861  {
1862  ASSERT(FALSE); // FIXME
1863  }
1864  PATH_InitGdiPath(pStrokes[numStrokes - 1]);
1865  pStrokes[numStrokes - 1]->state = PATH_Open;
1866  case PT_LINETO:
1867  case (PT_LINETO | PT_CLOSEFIGURE):
1868  point.x = flat_path->pPoints[i].x;
1869  point.y = flat_path->pPoints[i].y;
1870  PATH_AddEntry(pStrokes[numStrokes - 1], &point, flat_path->pFlags[i]);
1871  break;
1872  case PT_BEZIERTO:
1873  /* Should never happen because of the FlattenPath call */
1874  ERR("Should never happen\n");
1875  break;
1876  default:
1877  ERR("Got path flag %c\n", flat_path->pFlags[i]);
1878  if (pStrokes)
1879  ExFreePoolWithTag(pStrokes, TAG_PATH);
1880  PATH_UnlockPath(flat_path);
1881  PATH_Delete(flat_path->BaseObject.hHmgr);
1882  return NULL;
1883  }
1884  }
1885 
1886  pNewPath = PATH_CreatePath( flat_path->numEntriesUsed );
1887 
1888  for (i = 0; i < numStrokes; i++)
1889  {
1890  pUpPath = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
1891  PATH_InitGdiPath(pUpPath);
1892  pUpPath->state = PATH_Open;
1893  pDownPath = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
1894  PATH_InitGdiPath(pDownPath);
1895  pDownPath->state = PATH_Open;
1896 
1897  for (j = 0; j < pStrokes[i]->numEntriesUsed; j++)
1898  {
1899  /* Beginning or end of the path if not closed */
1900  if ((!(pStrokes[i]->pFlags[pStrokes[i]->numEntriesUsed - 1] & PT_CLOSEFIGURE)) && (j == 0 || j == pStrokes[i]->numEntriesUsed - 1))
1901  {
1902  /* Compute segment angle */
1903  INT xo, yo, xa, ya;
1904  double theta;
1905  POINT pt;
1906  POINT corners[2];
1907  if (j == 0)
1908  {
1909  xo = pStrokes[i]->pPoints[j].x;
1910  yo = pStrokes[i]->pPoints[j].y;
1911  xa = pStrokes[i]->pPoints[1].x;
1912  ya = pStrokes[i]->pPoints[1].y;
1913  }
1914  else
1915  {
1916  xa = pStrokes[i]->pPoints[j - 1].x;
1917  ya = pStrokes[i]->pPoints[j - 1].y;
1918  xo = pStrokes[i]->pPoints[j].x;
1919  yo = pStrokes[i]->pPoints[j].y;
1920  }
1921  theta = atan2(ya - yo, xa - xo);
1922  switch(endcap)
1923  {
1924  case PS_ENDCAP_SQUARE :
1925  pt.x = xo + round(sqrt(2) * penWidthOut * cos(M_PI_4 + theta));
1926  pt.y = yo + round(sqrt(2) * penWidthOut * sin(M_PI_4 + theta));
1927  PATH_AddEntry(pUpPath, &pt, (j == 0 ? PT_MOVETO : PT_LINETO));
1928  pt.x = xo + round(sqrt(2) * penWidthIn * cos(- M_PI_4 + theta));
1929  pt.y = yo + round(sqrt(2) * penWidthIn * sin(- M_PI_4 + theta));
1930  PATH_AddEntry(pUpPath, &pt, PT_LINETO);
1931  break;
1932  case PS_ENDCAP_FLAT :
1933  pt.x = xo + round(penWidthOut * cos(theta + M_PI_2));
1934  pt.y = yo + round(penWidthOut * sin(theta + M_PI_2));
1935  PATH_AddEntry(pUpPath, &pt, (j == 0 ? PT_MOVETO : PT_LINETO));
1936  pt.x = xo - round(penWidthIn * cos(theta + M_PI_2));
1937  pt.y = yo - round(penWidthIn * sin(theta + M_PI_2));
1938  PATH_AddEntry(pUpPath, &pt, PT_LINETO);
1939  break;
1940  case PS_ENDCAP_ROUND :
1941  default :
1942  corners[0].x = xo - penWidthIn;
1943  corners[0].y = yo - penWidthIn;
1944  corners[1].x = xo + penWidthOut;
1945  corners[1].y = yo + penWidthOut;
1946  PATH_DoArcPart(pUpPath , corners, theta + M_PI_2 , theta + 3 * M_PI_4, (j == 0 ? PT_MOVETO : FALSE));
1947  PATH_DoArcPart(pUpPath , corners, theta + 3 * M_PI_4 , theta + M_PI, FALSE);
1948  PATH_DoArcPart(pUpPath , corners, theta + M_PI, theta + 5 * M_PI_4, FALSE);
1949  PATH_DoArcPart(pUpPath , corners, theta + 5 * M_PI_4 , theta + 3 * M_PI_2, FALSE);
1950  break;
1951  }
1952  }
1953  /* Corpse of the path */
1954  else
1955  {
1956  /* Compute angle */
1957  INT previous, next;
1958  double xa, ya, xb, yb, xo, yo;
1959  double alpha, theta, miterWidth;
1960  DWORD _joint = joint;
1961  POINT pt;
1962  PPATH pInsidePath, pOutsidePath;
1963  if (j > 0 && j < pStrokes[i]->numEntriesUsed - 1)
1964  {
1965  previous = j - 1;
1966  next = j + 1;
1967  }
1968  else if (j == 0)
1969  {
1970  previous = pStrokes[i]->numEntriesUsed - 1;
1971  next = j + 1;
1972  }
1973  else
1974  {
1975  previous = j - 1;
1976  next = 0;
1977  }
1978  xo = pStrokes[i]->pPoints[j].x;
1979  yo = pStrokes[i]->pPoints[j].y;
1980  xa = pStrokes[i]->pPoints[previous].x;
1981  ya = pStrokes[i]->pPoints[previous].y;
1982  xb = pStrokes[i]->pPoints[next].x;
1983  yb = pStrokes[i]->pPoints[next].y;
1984  theta = atan2(yo - ya, xo - xa);
1985  alpha = atan2(yb - yo, xb - xo) - theta;
1986  if (alpha > 0) alpha -= M_PI;
1987  else alpha += M_PI;
1988  if (_joint == PS_JOIN_MITER && eMiterLimit < fabs(1 / sin(alpha / 2)))
1989  {
1990  _joint = PS_JOIN_BEVEL;
1991  }
1992  if (alpha > 0)
1993  {
1994  pInsidePath = pUpPath;
1995  pOutsidePath = pDownPath;
1996  }
1997  else if (alpha < 0)
1998  {
1999  pInsidePath = pDownPath;
2000  pOutsidePath = pUpPath;
2001  }
2002  else
2003  {
2004  continue;
2005  }
2006  /* Inside angle points */
2007  if (alpha > 0)
2008  {
2009  pt.x = xo - round(penWidthIn * cos(theta + M_PI_2));
2010  pt.y = yo - round(penWidthIn * sin(theta + M_PI_2));
2011  }
2012  else
2013  {
2014  pt.x = xo + round(penWidthIn * cos(theta + M_PI_2));
2015  pt.y = yo + round(penWidthIn * sin(theta + M_PI_2));
2016  }
2017  PATH_AddEntry(pInsidePath, &pt, PT_LINETO);
2018  if (alpha > 0)
2019  {
2020  pt.x = xo + round(penWidthIn * cos(M_PI_2 + alpha + theta));
2021  pt.y = yo + round(penWidthIn * sin(M_PI_2 + alpha + theta));
2022  }
2023  else
2024  {
2025  pt.x = xo - round(penWidthIn * cos(M_PI_2 + alpha + theta));
2026  pt.y = yo - round(penWidthIn * sin(M_PI_2 + alpha + theta));
2027  }
2028  PATH_AddEntry(pInsidePath, &pt, PT_LINETO);
2029  /* Outside angle point */
2030  switch(_joint)
2031  {
2032  case PS_JOIN_MITER :
2033  miterWidth = fabs(penWidthOut / cos(M_PI_2 - fabs(alpha) / 2));
2034  pt.x = xo + round(miterWidth * cos(theta + alpha / 2));
2035  pt.y = yo + round(miterWidth * sin(theta + alpha / 2));
2036  PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
2037  break;
2038  case PS_JOIN_BEVEL :
2039  if (alpha > 0)
2040  {
2041  pt.x = xo + round(penWidthOut * cos(theta + M_PI_2));
2042  pt.y = yo + round(penWidthOut * sin(theta + M_PI_2));
2043  }
2044  else
2045  {
2046  pt.x = xo - round(penWidthOut * cos(theta + M_PI_2));
2047  pt.y = yo - round(penWidthOut * sin(theta + M_PI_2));
2048  }
2049  PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
2050  if (alpha > 0)
2051  {
2052  pt.x = xo - round(penWidthOut * cos(M_PI_2 + alpha + theta));
2053  pt.y = yo - round(penWidthOut * sin(M_PI_2 + alpha + theta));
2054  }
2055  else
2056  {
2057  pt.x = xo + round(penWidthOut * cos(M_PI_2 + alpha + theta));
2058  pt.y = yo + round(penWidthOut * sin(M_PI_2 + alpha + theta));
2059  }
2060  PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
2061  break;
2062  case PS_JOIN_ROUND :
2063  default :
2064  if (alpha > 0)
2065  {
2066  pt.x = xo + round(penWidthOut * cos(theta + M_PI_2));
2067  pt.y = yo + round(penWidthOut * sin(theta + M_PI_2));
2068  }
2069  else
2070  {
2071  pt.x = xo - round(penWidthOut * cos(theta + M_PI_2));
2072  pt.y = yo - round(penWidthOut * sin(theta + M_PI_2));
2073  }
2074  PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
2075  pt.x = xo + round(penWidthOut * cos(theta + alpha / 2));
2076  pt.y = yo + round(penWidthOut * sin(theta + alpha / 2));
2077  PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
2078  if (alpha > 0)
2079  {
2080  pt.x = xo - round(penWidthOut * cos(M_PI_2 + alpha + theta));
2081  pt.y = yo - round(penWidthOut * sin(M_PI_2 + alpha + theta));
2082  }
2083  else
2084  {
2085  pt.x = xo + round(penWidthOut * cos(M_PI_2 + alpha + theta));
2086  pt.y = yo + round(penWidthOut * sin(M_PI_2 + alpha + theta));
2087  }
2088  PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
2089  break;
2090  }
2091  }
2092  }
2093  type = add_points( pNewPath, pUpPath->pPoints, pUpPath->numEntriesUsed, PT_LINETO );
2094  type[0] = PT_MOVETO;
2095  reverse_points( pDownPath->pPoints, pDownPath->numEntriesUsed );
2096  type = add_points( pNewPath, pDownPath->pPoints, pDownPath->numEntriesUsed, PT_LINETO );
2097  if (pStrokes[i]->pFlags[pStrokes[i]->numEntriesUsed - 1] & PT_CLOSEFIGURE) type[0] = PT_MOVETO;
2098 
2099  PATH_DestroyGdiPath(pStrokes[i]);
2100  ExFreePoolWithTag(pStrokes[i], TAG_PATH);
2101  PATH_DestroyGdiPath(pUpPath);
2102  ExFreePoolWithTag(pUpPath, TAG_PATH);
2103  PATH_DestroyGdiPath(pDownPath);
2104  ExFreePoolWithTag(pDownPath, TAG_PATH);
2105  }
2106  if (pStrokes) ExFreePoolWithTag(pStrokes, TAG_PATH);
2107 
2108  PATH_UnlockPath(flat_path);
2109  PATH_Delete(flat_path->BaseObject.hHmgr);
2110  pNewPath->state = PATH_Closed;
2111  PATH_UnlockPath(pNewPath);
2112  return pNewPath;
2113 }
2114 
2115 static
2116 PPATH
2117 FASTCALL
2119 {
2120  PPATH pPath, pNewPath;
2121 
2122  pPath = PATH_LockPath(dc->dclevel.hPath);
2123  if (!pPath)
2124  {
2126  return NULL;
2127  }
2128 
2129  pNewPath = PATH_WidenPathEx(dc, pPath);
2130  PATH_UnlockPath(pPath);
2131  return pNewPath;
2132 }
2133 
2134 PPATH
2135 FASTCALL
2137 {
2138  INT size;
2139  UINT penWidth, penStyle;
2140  DWORD obj_type;
2141  LPEXTLOGPEN elp;
2142  PDC_ATTR pdcattr = dc->pdcattr;
2143 
2144  if (pPath->state != PATH_Closed)
2145  {
2146  TRACE("PWP 1\n");
2148  return NULL;
2149  }
2150 
2151  size = GreGetObject(pdcattr->hpen, 0, NULL);
2152  if (!size)
2153  {
2154  TRACE("PWP 2\n");
2156  return NULL;
2157  }
2158 
2160  if (elp == NULL)
2161  {
2162  TRACE("PWP 3\n");
2164  return NULL;
2165  }
2166 
2167  GreGetObject(pdcattr->hpen, size, elp);
2168 
2169  obj_type = GDI_HANDLE_GET_TYPE(pdcattr->hpen);
2170  if (obj_type == GDI_OBJECT_TYPE_PEN)
2171  {
2172  penStyle = ((LOGPEN*)elp)->lopnStyle;
2173  }
2174  else if (obj_type == GDI_OBJECT_TYPE_EXTPEN)
2175  {
2176  penStyle = elp->elpPenStyle;
2177  }
2178  else
2179  {
2180  TRACE("PWP 4\n");
2183  return NULL;
2184  }
2185 
2186  penWidth = elp->elpWidth;
2188 
2189  /* The function cannot apply to cosmetic pens */
2190  if (obj_type == GDI_OBJECT_TYPE_EXTPEN &&
2191  (PS_TYPE_MASK & penStyle) == PS_COSMETIC)
2192  {
2193  TRACE("PWP 5\n");
2195  return FALSE;
2196  }
2197 
2198  return IntGdiWidenPath(pPath, penWidth, penStyle, dc->dclevel.laPath.eMiterLimit);
2199 }
2200 
2201 static inline INT int_from_fixed(FIXED f)
2202 {
2203  return (f.fract >= 0x8000) ? (f.value + 1) : f.value;
2204 }
2205 
2206 /**********************************************************************
2207  * PATH_BezierTo
2208  *
2209  * Internally used by PATH_add_outline
2210  */
2211 static
2212 VOID
2213 FASTCALL
2215  PPATH pPath,
2216  POINT *lppt,
2217  INT n)
2218 {
2219  if (n < 2) return;
2220 
2221  if (n == 2)
2222  {
2223  PATH_AddEntry(pPath, &lppt[1], PT_LINETO);
2224  }
2225  else if (n == 3)
2226  {
2227  add_points( pPath, lppt, 3, PT_BEZIERTO );
2228  }
2229  else
2230  {
2231  POINT pt[3];
2232  INT i = 0;
2233 
2234  pt[2] = lppt[0];
2235  n--;
2236 
2237  while (n > 2)
2238  {
2239  pt[0] = pt[2];
2240  pt[1] = lppt[i + 1];
2241  pt[2].x = (lppt[i + 2].x + lppt[i + 1].x) / 2;
2242  pt[2].y = (lppt[i + 2].y + lppt[i + 1].y) / 2;
2243  add_points( pPath, pt, 3, PT_BEZIERTO );
2244  n--;
2245  i++;
2246  }
2247 
2248  pt[0] = pt[2];
2249  pt[1] = lppt[i + 1];
2250  pt[2] = lppt[i + 2];
2251  add_points( pPath, pt, 3, PT_BEZIERTO );
2252  }
2253 }
2254 
2255 static
2256 BOOL
2257 FASTCALL
2259  PDC dc,
2260  PPATH pPath,
2261  INT x,
2262  INT y,
2264  DWORD size)
2265 {
2267  POINT pt;
2268  BOOL bResult = FALSE;
2269 
2270  start = header;
2271 
2272  while ((char *)header < (char *)start + size)
2273  {
2274  TTPOLYCURVE *curve;
2275 
2276  if (header->dwType != TT_POLYGON_TYPE)
2277  {
2278  ERR("Unknown header type %lu\n", header->dwType);
2279  goto cleanup;
2280  }
2281 
2282  pt.x = x + int_from_fixed(header->pfxStart.x);
2283  pt.y = y - int_from_fixed(header->pfxStart.y);
2284  PATH_AddEntry(pPath, &pt, PT_MOVETO);
2285 
2286  curve = (TTPOLYCURVE *)(header + 1);
2287 
2288  while ((char *)curve < (char *)header + header->cb)
2289  {
2290  TRACE("curve->wType %d\n", curve->wType);
2291 
2292  switch(curve->wType)
2293  {
2294  case TT_PRIM_LINE:
2295  {
2296  WORD i;
2297 
2298  for (i = 0; i < curve->cpfx; i++)
2299  {
2300  pt.x = x + int_from_fixed(curve->apfx[i].x);
2301  pt.y = y - int_from_fixed(curve->apfx[i].y);
2302  PATH_AddEntry(pPath, &pt, PT_LINETO);
2303  }
2304  break;
2305  }
2306 
2307  case TT_PRIM_QSPLINE:
2308  case TT_PRIM_CSPLINE:
2309  {
2310  WORD i;
2311  POINTFX ptfx;
2312  POINT *pts = ExAllocatePoolWithTag(PagedPool, (curve->cpfx + 1) * sizeof(POINT), TAG_PATH);
2313 
2314  if (!pts) goto cleanup;
2315 
2316  ptfx = *(POINTFX *)((char *)curve - sizeof(POINTFX));
2317 
2318  pts[0].x = x + int_from_fixed(ptfx.x);
2319  pts[0].y = y - int_from_fixed(ptfx.y);
2320 
2321  for (i = 0; i < curve->cpfx; i++)
2322  {
2323  pts[i + 1].x = x + int_from_fixed(curve->apfx[i].x);
2324  pts[i + 1].y = y - int_from_fixed(curve->apfx[i].y);
2325  }
2326 
2327  PATH_BezierTo(pPath, pts, curve->cpfx + 1);
2328 
2330  break;
2331  }
2332 
2333  default:
2334  ERR("Unknown curve type %04x\n", curve->wType);
2335  goto cleanup;
2336  }
2337 
2338  curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
2339  }
2340  header = (TTPOLYGONHEADER *)((char *)header + header->cb);
2341  }
2342 
2343  bResult = TRUE;
2344 
2345 cleanup:
2346  IntGdiCloseFigure(pPath);
2347  return bResult;
2348 }
2349 
2350 /**********************************************************************
2351  * PATH_ExtTextOut
2352  */
2353 BOOL
2354 FASTCALL
2356  PDC dc,
2357  INT x,
2358  INT y,
2359  UINT flags,
2360  const RECTL *lprc,
2361  LPCWSTR str,
2362  UINT count,
2363  const INT *dx)
2364 {
2365  PPATH pPath;
2366  unsigned int idx, ggo_flags = GGO_NATIVE;
2367  POINT offset = {0, 0};
2368 
2369  pPath = PATH_LockPath(dc->dclevel.hPath);
2370  if (!pPath)
2371  {
2372  return FALSE;
2373  }
2374 
2375  if (pPath->state != PATH_Open)
2376  {
2377  ERR("PATH_ExtTextOut not open\n");
2378  return FALSE;
2379  }
2380 
2381  if (!count) return TRUE;
2382  if (flags & ETO_GLYPH_INDEX) ggo_flags |= GGO_GLYPH_INDEX;
2383 
2384  for (idx = 0; idx < count; idx++)
2385  {
2386  MAT2 identity = { {0, 1}, {0, 0}, {0, 0}, {0, 1} };
2387  GLYPHMETRICS gm;
2388  DWORD dwSize;
2389  void *outline;
2390 
2392  str[idx],
2393  ggo_flags,
2394  &gm,
2395  0,
2396  NULL,
2397  &identity,
2398  TRUE);
2399  if (dwSize == GDI_ERROR)
2400  {
2401  // With default DC font,,, bitmap font?
2402  // ExtTextOut on a path with bitmap font selected shouldn't fail.
2403  // This just leads to empty path generated.
2404  // Ref : test_emf_ExtTextOut_on_path
2405  continue;
2406  }
2407 
2408  /* Add outline only if char is printable */
2409  if (dwSize)
2410  {
2412  if (!outline)
2413  {
2414  PATH_UnlockPath(pPath);
2415  return FALSE;
2416  }
2417 
2419  str[idx],
2420  ggo_flags,
2421  &gm,
2422  dwSize,
2423  outline,
2424  &identity,
2425  TRUE);
2426 
2427  PATH_add_outline(dc, pPath, x + offset.x, y + offset.y, outline, dwSize);
2428 
2430  }
2431 
2432  if (dx)
2433  {
2434  if (flags & ETO_PDY)
2435  {
2436  offset.x += dx[idx * 2];
2437  offset.y += dx[idx * 2 + 1];
2438  }
2439  else
2440  offset.x += dx[idx];
2441  }
2442  else
2443  {
2444  offset.x += gm.gmCellIncX;
2445  offset.y += gm.gmCellIncY;
2446  }
2447  }
2448  PATH_UnlockPath(pPath);
2449  return TRUE;
2450 }
2451 
2452 
2453 /***********************************************************************
2454  * Exported functions
2455  */
2456 
2457 BOOL
2458 APIENTRY
2460 {
2461  PDC dc = DC_LockDc(hDC);
2462  if (!dc)
2463  {
2465  return FALSE;
2466  }
2467 
2468  if (!dc->dclevel.hPath)
2469  {
2470  DC_UnlockDc(dc);
2471  return TRUE;
2472  }
2473 
2474  if (!PATH_Delete(dc->dclevel.hPath))
2475  {
2476  DC_UnlockDc(dc);
2477  return FALSE;
2478  }
2479 
2480  dc->dclevel.hPath = 0;
2481  dc->dclevel.flPath &= ~DCPATH_ACTIVE;
2482 
2483  DC_UnlockDc(dc);
2484  return TRUE;
2485 }
2486 
2487 BOOL
2488 APIENTRY
2490 {
2491  PPATH pPath;
2492  PDC dc;
2493 
2494  dc = DC_LockDc(hDC);
2495  if (!dc)
2496  {
2498  return FALSE;
2499  }
2500 
2501  /* If path is already open, do nothing. Check if not Save DC state */
2502  if ((dc->dclevel.flPath & DCPATH_ACTIVE) && !(dc->dclevel.flPath & DCPATH_SAVE))
2503  {
2504  DC_UnlockDc(dc);
2505  return TRUE;
2506  }
2507 
2508  if (dc->dclevel.hPath)
2509  {
2510  TRACE("BeginPath 1 0x%p\n", dc->dclevel.hPath);
2511  if (!(dc->dclevel.flPath & DCPATH_SAVE))
2512  {
2513  // Remove previous handle.
2514  if (!PATH_Delete(dc->dclevel.hPath))
2515  {
2516  DC_UnlockDc(dc);
2517  return FALSE;
2518  }
2519  }
2520  else
2521  {
2522  // Clear flags and Handle.
2523  dc->dclevel.flPath &= ~(DCPATH_SAVE | DCPATH_ACTIVE);
2524  dc->dclevel.hPath = NULL;
2525  }
2526  }
2528  dc->dclevel.flPath |= DCPATH_ACTIVE; // Set active ASAP!
2529  dc->dclevel.hPath = pPath->BaseObject.hHmgr;
2530  IntGetCurrentPositionEx(dc, &pPath->pos);
2531  IntLPtoDP( dc, &pPath->pos, 1 );
2532  TRACE("BP : Current pos X %d Y %d\n",pPath->pos.x, pPath->pos.y);
2533  PATH_UnlockPath(pPath);
2534  DC_UnlockDc(dc);
2535 
2536  if (!pPath)
2537  {
2538  return FALSE;
2539  }
2540  return TRUE;
2541 }
2542 
2543 BOOL
2544 APIENTRY
2546 {
2547  BOOL Ret = FALSE; // Default to failure
2548  PDC pDc;
2549  PPATH pPath;
2550 
2551  TRACE("Enter %s\n", __FUNCTION__);
2552 
2553  pDc = DC_LockDc(hDC);
2554  if (!pDc)
2555  {
2557  return FALSE;
2558  }
2559 
2560  pPath = PATH_LockPath(pDc->dclevel.hPath);
2561  if (!pPath)
2562  {
2563  DC_UnlockDc(pDc);
2564  return FALSE;
2565  }
2566 
2567  if (pPath->state == PATH_Open)
2568  {
2569  IntGdiCloseFigure(pPath);
2570  Ret = TRUE;
2571  }
2572  else
2573  {
2575  }
2576 
2577  PATH_UnlockPath(pPath);
2578  DC_UnlockDc(pDc);
2579  return Ret;
2580 }
2581 
2582 BOOL
2583 APIENTRY
2585 {
2586  BOOL ret = TRUE;
2587  PPATH pPath;
2588  PDC dc;
2589 
2590  dc = DC_LockDc(hDC);
2591  if (!dc)
2592  {
2594  return FALSE;
2595  }
2596 
2597  pPath = PATH_LockPath(dc->dclevel.hPath);
2598  if (!pPath)
2599  {
2600  DC_UnlockDc(dc);
2601  return FALSE;
2602  }
2603 
2604  /* Check that path is currently being constructed */
2605  if ((pPath->state != PATH_Open) || !(dc->dclevel.flPath & DCPATH_ACTIVE))
2606  {
2607  TRACE("EndPath ERROR! 0x%p\n", dc->dclevel.hPath);
2609  ret = FALSE;
2610  }
2611  /* Set flag to indicate that path is finished */
2612  else
2613  {
2614  TRACE("EndPath 0x%p\n", dc->dclevel.hPath);
2615  pPath->state = PATH_Closed;
2616  dc->dclevel.flPath &= ~DCPATH_ACTIVE;
2617  }
2618 
2619  PATH_UnlockPath(pPath);
2620  DC_UnlockDc(dc);
2621  return ret;
2622 }
2623 
2624 BOOL
2625 APIENTRY
2627 {
2628  BOOL ret = FALSE;
2629  PPATH pPath, pNewPath;
2630  PDC_ATTR pdcattr;
2631  PDC dc;
2632 
2633  dc = DC_LockDc(hDC);
2634  if (!dc)
2635  {
2637  return FALSE;
2638  }
2639 
2640  pPath = PATH_LockPath(dc->dclevel.hPath);
2641  if (!pPath)
2642  {
2643  DC_UnlockDc(dc);
2644  return FALSE;
2645  }
2646 
2648 
2649  pdcattr = dc->pdcattr;
2650 
2651  if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
2653 
2654  if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
2656 
2657  pNewPath = PATH_FlattenPath(pPath);
2658 
2659  if (pNewPath->state != PATH_Closed)
2660  {
2662  }
2663  else if (pNewPath->numEntriesUsed)
2664  {
2665  ret = PATH_FillPath(dc, pNewPath);
2666  }
2667  else ret = TRUE;
2668 
2669  PATH_UnlockPath(pNewPath);
2670  PATH_Delete(pNewPath->BaseObject.hHmgr);
2671 
2672  PATH_UnlockPath(pPath);
2673  PATH_Delete(pPath->BaseObject.hHmgr);
2674  dc->dclevel.hPath = 0;
2675  dc->dclevel.flPath &= ~DCPATH_ACTIVE;
2676 
2678  DC_UnlockDc(dc);
2679  return ret;
2680 }
2681 
2682 BOOL
2683 APIENTRY
2685 {
2686  BOOL Ret = FALSE;
2687  DC *pDc;
2688  PPATH pPath, pNewPath = NULL;
2689 
2690  TRACE("Enter %s\n", __FUNCTION__);
2691 
2692  pDc = DC_LockDc(hDC);
2693  if (!pDc)
2694  {
2696  return FALSE;
2697  }
2698 
2699  pPath = PATH_LockPath(pDc->dclevel.hPath);
2700  if (!pPath)
2701  {
2703  DC_UnlockDc(pDc);
2704  return FALSE;
2705  }
2706 
2707  if (pPath->state == PATH_Closed)
2708  {
2709  pNewPath = PATH_FlattenPath(pPath);
2710  }
2711 
2712  PATH_UnlockPath(pPath);
2713 
2714  if (pNewPath)
2715  {
2716  PATH_Delete(pDc->dclevel.hPath);
2717  pDc->dclevel.hPath = pNewPath->BaseObject.hHmgr;
2718  PATH_UnlockPath(pNewPath);
2719  Ret = TRUE;
2720  }
2721 
2722  DC_UnlockDc(pDc);
2723  return Ret;
2724 }
2725 
2726 _Success_(return != FALSE)
2727 BOOL
2728 APIENTRY
2729 NtGdiGetMiterLimit(
2730  _In_ HDC hdc,
2732 {
2733  DC *pDc;
2734  BOOL bResult = TRUE;
2735 
2736  if (!(pDc = DC_LockDc(hdc)))
2737  {
2739  return FALSE;
2740  }
2741 
2742  _SEH2_TRY
2743  {
2744  ProbeForWrite(pdwOut, sizeof(DWORD), 1);
2745  *pdwOut = pDc->dclevel.laPath.eMiterLimit;
2746  }
2748  {
2750  bResult = FALSE;
2751  }
2752  _SEH2_END;
2753 
2754  DC_UnlockDc(pDc);
2755  return bResult;
2756 
2757 }
2758 
2759 INT
2760 APIENTRY
2762  HDC hDC,
2763  LPPOINT Points,
2764  LPBYTE Types,
2765  INT nSize)
2766 {
2767  INT ret = -1;
2768  PPATH pPath;
2769  DC *dc;
2770 
2771  _SEH2_TRY
2772  {
2773  ProbeForWrite(Points, nSize * sizeof(*Points), sizeof(ULONG));
2774  ProbeForWrite(Types, nSize, 1);
2775  }
2777  {
2779  _SEH2_YIELD(return -1);
2780  }
2781  _SEH2_END
2782 
2783  dc = DC_LockDc(hDC);
2784  TRACE("NtGdiGetPath start\n");
2785  if (!dc)
2786  {
2787  ERR("Can't lock dc!\n");
2789  return -1;
2790  }
2791 
2792  pPath = PATH_LockPath(dc->dclevel.hPath);
2793  if (!pPath)
2794  {
2795  DC_UnlockDc(dc);
2796  return -1;
2797  }
2798 
2799  if (pPath->state != PATH_Closed)
2800  {
2802  goto done;
2803  }
2804 
2805  if (nSize == 0)
2806  {
2807  ret = pPath->numEntriesUsed;
2808  }
2809  else if (nSize < pPath->numEntriesUsed)
2810  {
2812  goto done;
2813  }
2814  else
2815  {
2816  _SEH2_TRY
2817  {
2818  memcpy(Points, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
2819  memcpy(Types, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
2820 
2821  /* Convert the points to logical coordinates */
2822  if (!GdiPathDPtoLP(dc, Points, pPath->numEntriesUsed))
2823  {
2825  _SEH2_LEAVE;
2826  }
2827 
2828  ret = pPath->numEntriesUsed;
2829  }
2831  {
2833  }
2834  _SEH2_END
2835  }
2836 
2837 done:
2838  TRACE("NtGdiGetPath exit %d\n",ret);
2839  PATH_UnlockPath(pPath);
2840  DC_UnlockDc(dc);
2841  return ret;
2842 }
2843 
2844 HRGN
2845 APIENTRY
2847 {
2848  PPATH pPath, pNewPath;
2849  HRGN hrgnRval = 0;
2850  int Ret;
2851  PREGION Rgn;
2852  DC *pDc;
2853  PDC_ATTR pdcattr;
2854 
2855  TRACE("Enter %s\n", __FUNCTION__);
2856 
2857  pDc = DC_LockDc(hDC);
2858  if (!pDc)
2859  {
2860  ERR("Failed to lock DC %p\n", hDC);
2862  return NULL;
2863  }
2864 
2865  pdcattr = pDc->pdcattr;
2866 
2867  pPath = PATH_LockPath(pDc->dclevel.hPath);
2868  if (!pPath)
2869  {
2870  ERR("Failed to lock DC path %p\n", pDc->dclevel.hPath);
2871  DC_UnlockDc(pDc);
2872  return NULL;
2873  }
2874 
2875  if (pPath->state != PATH_Closed)
2876  {
2877  // FIXME: Check that setlasterror is being called correctly
2878  ERR("Path is not closed!\n");
2880  }
2881  else
2882  {
2883  /* Create the region and fill it with the path strokes */
2885  if (!Rgn)
2886  {
2887  ERR("Failed to allocate a region\n");
2888  PATH_UnlockPath(pPath);
2889  DC_UnlockDc(pDc);
2890  return NULL;
2891  }
2892  hrgnRval = Rgn->BaseObject.hHmgr;
2893 
2894  pNewPath = PATH_FlattenPath(pPath);
2895  if (pNewPath == NULL)
2896  {
2897  ERR("Failed to flatten path %p\n", pDc->dclevel.hPath);
2898  REGION_Delete(Rgn);
2899  PATH_UnlockPath(pPath);
2900  DC_UnlockDc(pDc);
2901  return NULL;
2902  }
2903 
2904  Ret = PATH_PathToRegion(pNewPath, pdcattr->jFillMode, Rgn);
2905 
2906  PATH_UnlockPath(pNewPath);
2907  PATH_Delete(pNewPath->BaseObject.hHmgr);
2908 
2909  if (!Ret)
2910  {
2911  ERR("PATH_PathToRegion failed\n");
2912  REGION_Delete(Rgn);
2913  hrgnRval = NULL;
2914  }
2915  else
2916  REGION_UnlockRgn(Rgn);
2917  }
2918 
2919  PATH_UnlockPath(pPath);
2920  PATH_Delete(pDc->dclevel.hPath);
2921  pDc->dclevel.hPath = NULL;
2922  pDc->dclevel.flPath &= ~DCPATH_ACTIVE;
2923 
2924  DC_UnlockDc(pDc);
2925  return hrgnRval;
2926 }
2927 
2928 BOOL
2929 APIENTRY
2931  IN HDC hdc,
2932  IN DWORD dwNew,
2934 {
2935  DC *pDc;
2936  gxf_long worker, worker1;
2937  BOOL bResult = TRUE;
2938 
2939  if (!(pDc = DC_LockDc(hdc)))
2940  {
2942  return FALSE;
2943  }
2944 
2945  worker.l = dwNew;
2946  worker1.f = pDc->dclevel.laPath.eMiterLimit;
2947  pDc->dclevel.laPath.eMiterLimit = worker.f;
2948 
2949  if (pdwOut)
2950  {
2951  _SEH2_TRY
2952  {
2953  ProbeForWrite(pdwOut, sizeof(DWORD), 1);
2954  *pdwOut = worker1.l;
2955  }
2957  {
2959  bResult = FALSE;
2960  }
2961  _SEH2_END;
2962  }
2963 
2964  DC_UnlockDc(pDc);
2965  return bResult;
2966 }
2967 
2968 BOOL
2969 APIENTRY
2971 {
2972  DC *pDc;
2973  PDC_ATTR pdcattr;
2974  PPATH pPath, pNewPath;
2975  BOOL bRet = FALSE;
2976 
2977  TRACE("Enter %s\n", __FUNCTION__);
2978 
2979  if (!(pDc = DC_LockDc(hDC)))
2980  {
2982  return FALSE;
2983  }
2984  pPath = PATH_LockPath(pDc->dclevel.hPath);
2985  if (!pPath)
2986  {
2987  DC_UnlockDc(pDc);
2988  return FALSE;
2989  }
2990 
2992 
2993  pdcattr = pDc->pdcattr;
2994 
2995  if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
2996  DC_vUpdateFillBrush(pDc);
2997 
2998  if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
2999  DC_vUpdateLineBrush(pDc);
3000 
3001  pNewPath = PATH_FlattenPath(pPath);
3002 
3003  if (pNewPath->state != PATH_Closed)
3004  {
3006  }
3007  else if (pNewPath->numEntriesUsed)
3008  {
3009  bRet = PATH_FillPath(pDc, pNewPath);
3010  if (bRet) bRet = PATH_StrokePath(pDc, pNewPath);
3011  }
3012  else bRet = TRUE;
3013 
3014  PATH_UnlockPath(pNewPath);
3015  PATH_Delete(pNewPath->BaseObject.hHmgr);
3016 
3017  PATH_UnlockPath(pPath);
3018  PATH_Delete(pPath->BaseObject.hHmgr);
3019  pDc->dclevel.hPath = 0;
3020  pDc->dclevel.flPath &= ~DCPATH_ACTIVE;
3021 
3022  DC_vFinishBlit(pDc, NULL);
3023  DC_UnlockDc(pDc);
3024  return bRet;
3025 }
3026 
3027 BOOL
3028 APIENTRY
3030 {
3031  DC *pDc;
3032  PDC_ATTR pdcattr;
3033  PPATH pPath, pNewPath;
3034  BOOL bRet = FALSE;
3035 
3036  TRACE("Enter %s\n", __FUNCTION__);
3037 
3038  if (!(pDc = DC_LockDc(hDC)))
3039  {
3041  return FALSE;
3042  }
3043 
3044  pPath = PATH_LockPath(pDc->dclevel.hPath);
3045  if (!pPath)
3046  {
3047  DC_UnlockDc(pDc);
3048  return FALSE;
3049  }
3050 
3052 
3053  pdcattr = pDc->pdcattr;
3054 
3055  if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
3056  DC_vUpdateLineBrush(pDc);
3057 
3058  pNewPath = PATH_FlattenPath(pPath);
3059 
3060  if (pNewPath->state != PATH_Closed)
3061  {
3063  }
3064  else bRet = PATH_StrokePath(pDc, pNewPath);
3065 
3066  PATH_UnlockPath(pNewPath);
3067  PATH_Delete(pNewPath->BaseObject.hHmgr);
3068 
3069  DC_vFinishBlit(pDc, NULL);
3070 
3071  PATH_UnlockPath(pPath);
3072  PATH_Delete(pPath->BaseObject.hHmgr);
3073  pDc->dclevel.hPath = 0;
3074  pDc->dclevel.flPath &= ~DCPATH_ACTIVE;
3075 
3076  DC_UnlockDc(pDc);
3077  return bRet;
3078 }
3079 
3080 BOOL
3081 APIENTRY
3083 {
3084  PPATH pPath;
3085  BOOL Ret = FALSE;
3086  PDC pdc = DC_LockDc(hDC);
3087  TRACE("NtGdiWidenPat Enter\n");
3088  if (!pdc)
3089  {
3091  return FALSE;
3092  }
3093 
3094  pPath = PATH_WidenPath(pdc);
3095  if (pPath)
3096  {
3097  TRACE("WindenPath New Path\n");
3098  PATH_Delete(pdc->dclevel.hPath);
3099  pdc->dclevel.hPath = pPath->BaseObject.hHmgr;
3100  Ret = TRUE;
3101  }
3102  DC_UnlockDc(pdc);
3103  TRACE("NtGdiWidenPat Ret %d\n",Ret);
3104  return Ret;
3105 }
3106 
3107 /* EOF */
_STLP_DECLSPEC complex< float > _STLP_CALL sqrt(const complex< float > &)
Definition: complex.cpp:188
_SEH2_TRY
Definition: create.c:4226
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG y1
Definition: winddi.h:3706
BOOL APIENTRY NtGdiStrokeAndFillPath(HDC hDC)
Definition: path.c:2970
_Success_(return !=FALSE)
Definition: path.c:2726
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define XForm2MatrixS(m, x)
Definition: coord.h:199
int numEntriesAllocated
Definition: path.h:56
_Check_return_ _CRTIMP double __cdecl ceil(_In_ double x)
FLOAT f
Definition: ntgdityp.h:426
BASEOBJECT BaseObject
Definition: region.h:11
#define M_PI_4
Definition: port.h:153
#define IN
Definition: typedefs.h:39
BOOL NTAPI GreModifyWorldTransform(PDC pdc, const XFORML *pxform, DWORD dwMode)
Definition: coord.c:461
#define max(a, b)
Definition: svc.c:63
VOID FASTCALL PATH_EmptyPath(PPATH pPath)
Definition: path.c:246
int APIENTRY IntGdiSetMapMode(PDC dc, int MapMode)
Definition: coord.c:828
BOOL FASTCALL PATH_AddEntry(PPATH pPath, const POINT *pPoint, BYTE flags)
Definition: path.c:262
ULONG l
Definition: ntgdityp.h:427
POINTL ptlViewportOrg
Definition: ntgdihdl.h:343
#define WINDING
Definition: constants.h:279
#define PS_ENDCAP_SQUARE
Definition: wingdi.h:595
valarray< _Tp > atan2(const valarray< _Tp > &__x, const valarray< _Tp > &__y)
Definition: _valarray.h:928
BOOL APIENTRY NtGdiBeginPath(HDC hDC)
Definition: path.c:2489
BOOL FASTCALL PATH_Rectangle(PDC dc, INT x1, INT y1, INT x2, INT y2)
Definition: path.c:627
_In_ int _Inout_ LPRECT lprc
Definition: winuser.h:4455
BOOL FASTCALL REGION_SetPolyPolygonRgn(_Inout_ PREGION prgn, _In_ const POINT *ppt, _In_ const ULONG *pcPoints, _In_ ULONG cPolygons, _In_ INT iMode)
Definition: region.c:3275
VOID FASTCALL DC_vUpdateLineBrush(PDC pdc)
Definition: dcobjs.c:62
FORCEINLINE PDC DC_LockDc(HDC hdc)
Definition: dc.h:220
long y
Definition: polytest.cpp:48
DWORD elpWidth
Definition: wingdi.h:1943
BOOL PATH_RestorePath(DC *dst, DC *src)
Definition: path.c:209
#define MWT_SET
Definition: ntgdityp.h:180
_In_ ULONG Mode
Definition: hubbusif.h:303
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
static BOOLEAN PATH_ScaleNormalizedPoint(POINT corners[], FLOATL x, FLOATL y, POINT *pPoint)
Definition: path.c:363
#define XFORMOBJ_bApplyXform
Definition: xformobj.h:11
static VOID FASTCALL PATH_BezierTo(PPATH pPath, POINT *lppt, INT n)
Definition: path.c:2214
long x
Definition: polytest.cpp:48
BOOL FASTCALL PATH_StrokePath(DC *dc, PPATH pPath)
Definition: path.c:1597
#define _Out_
Definition: ms_sal.h:345
#define TT_POLYGON_TYPE
Definition: wingdi.h:1318
#define TRUE
Definition: types.h:120
#define pt(x, y)
Definition: drawing.c:79
HANDLE hpen
Definition: ntgdihdl.h:296
PPATH FASTCALL PATH_WidenPathEx(DC *dc, PPATH pPath)
Definition: path.c:2136
PPATH FASTCALL PATH_CreatePath(int count)
Definition: path.c:35
#define FLOATOBJ_DivLong(pf, l)
Definition: winddi.h:2829
char ACPI_OBJECT_TYPE * Types
Definition: acdebug.h:353
GLuint GLuint GLsizei count
Definition: gl.h:1545
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3706
#define DC_PEN_DIRTY
Definition: ntgdihdl.h:136
BOOL FASTCALL PATH_MoveTo(PDC dc, PPATH pPath)
Definition: path.c:554
#define ERROR_INVALID_HANDLE
Definition: compat.h:98
INT APIENTRY NtGdiGetPath(HDC hDC, LPPOINT Points, LPBYTE Types, INT nSize)
Definition: path.c:2761
*nSize LPSTR _Inout_ LPDWORD nSize
Definition: winbase.h:2061
INT iMapMode
Definition: ntgdihdl.h:338
Definition: path.h:34
static HDC
Definition: imagelist.c:92
GLdouble n
Definition: glext.h:7729
#define round(x)
Definition: path.c:1786
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
BOOL FASTCALL PATH_PolyPolyline(PDC dc, const POINT *pts, const DWORD *counts, DWORD polylines)
Definition: path.c:1338
#define PS_JOIN_BEVEL
Definition: wingdi.h:597
static void reverse_points(POINT *points, UINT count)
Definition: path.c:494
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
#define PS_JOIN_MITER
Definition: wingdi.h:598
short gmCellIncY
Definition: wingdi.h:2446
Definition: wingdi.h:2472
BOOL APIENTRY NtGdiStrokePath(HDC hDC)
Definition: path.c:3029
_SEH2_END
Definition: create.c:4400
BOOL PATH_SavePath(DC *dst, DC *src)
Definition: path.c:187
HGDIOBJ hHmgr
Definition: gdiobj.h:40
FORCEINLINE VOID XFORMOBJ_vInit(OUT XFORMOBJ *pxo, IN MATRIX *pmx)
Definition: xformobj.h:21
BOOL PATH_Ellipse(PDC dc, INT x1, INT y1, INT x2, INT y2)
Definition: path.c:782
#define FASTCALL
Definition: nt_native.h:50
int32_t INT
Definition: typedefs.h:58
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
POINTL point
Definition: edittest.c:50
& rect
Definition: startmenu.cpp:1413
DWORD ret
Definition: path.c:47
#define FLOATOBJ_Div(pf, pf1)
Definition: winddi.h:2827
#define GDI_OBJECT_TYPE_EXTPEN
Definition: gdi.h:55
BOOL FASTCALL PATH_PolyPolygon(PDC dc, const POINT *pts, const INT *counts, UINT polygons)
Definition: path.c:1288
#define PATH_LockPath(hPath)
Definition: path.h:70
LONG y
Definition: windef.h:330
PPATH FASTCALL IntGdiWidenPath(PPATH pPath, UINT penWidth, UINT penStyle, FLOAT eMiterLimit)
Definition: path.c:1789
FLOAT * PFLOATOBJ
Definition: winddi.h:677
FIXED y
Definition: wingdi.h:2709
#define FLOATOBJ_SetFloat(pf, f)
Definition: winddi.h:2814
static void close_figure(PPATH path)
Definition: path.c:526
PREGION FASTCALL IntSysCreateRectpRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
Definition: region.c:2426
static PPATH FASTCALL PATH_WidenPath(DC *dc)
Definition: path.c:2118
unsigned char * LPBYTE
Definition: typedefs.h:53
#define FALSE
Definition: types.h:117
unsigned int BOOL
Definition: ntddk_ex.h:94
BOOL FASTCALL PATH_PolyBezierTo(PDC dc, const POINT *pts, DWORD cbPoints)
Definition: path.c:1131
long LONG
Definition: pedump.c:60
#define ERROR_CAN_NOT_COMPLETE
Definition: winerror.h:582
#define a
Definition: ke_i.h:78
#define e
Definition: ke_i.h:82
static const FLOATOBJ gef1
Definition: floatobj.h:114
Definition: path.h:18
VOID FASTCALL IntGdiCloseFigure(PPATH pPath)
Definition: path.c:108
struct tagPOINTFX POINTFX
BOOL FASTCALL PATH_PathToRegion(PPATH pPath, INT Mode, PREGION Rgn)
Definition: path.c:1450
unsigned int idx
Definition: utils.c:41
DWORD elpPenStyle
Definition: wingdi.h:1942
PPATH FASTCALL PATH_FlattenPath(PPATH pPath)
Definition: path.c:1407
#define TAG_PATH
Definition: tags.h:25
HGDIOBJ hHmgr(VOID)
Definition: baseobj.hpp:95
const WCHAR * str
#define TAG_BEZIER
Definition: tags.h:13
#define GGO_NATIVE
Definition: wingdi.h:850
#define FLOATOBJ_AddLong(pf, l)
Definition: winddi.h:2820
_STLP_DECLSPEC complex< float > _STLP_CALL cos(const complex< float > &)
POINT * pPoints
Definition: path.h:53
unsigned char BOOLEAN
BOOL FASTCALL PATH_PolyDraw(PDC dc, const POINT *pts, const BYTE *types, DWORD cbPoints)
Definition: path.c:1180
#define _In_
Definition: ms_sal.h:308
LONG cx
Definition: windef.h:334
#define FLOATOBJ_Add(pf, pf1)
Definition: winddi.h:2818
#define AD_CLOCKWISE
Definition: wingdi.h:668
GLint GLint bottom
Definition: glext.h:7726
static void update_current_pos(PPATH path)
Definition: path.c:519
BOOL APIENTRY NtGdiWidenPath(HDC hDC)
Definition: path.c:3082
FORCEINLINE LONG RECTL_lGetWidth(_In_ const RECTL *prcl)
Definition: rect.h:93
#define PATH_UnlockPath(pPath)
Definition: path.h:71
Definition: region.h:7
BOOL FASTCALL IntGdiPolyline(DC *dc, LPPOINT pt, int Count)
Definition: line.c:325
int numEntriesUsed
Definition: path.h:55
#define ERROR_ARITHMETIC_OVERFLOW
Definition: winerror.h:351
#define PS_ENDCAP_ROUND
Definition: wingdi.h:594
static BYTE * add_points(PPATH path, const POINT *points, DWORD count, BYTE type)
Definition: path.c:480
#define TT_PRIM_CSPLINE
Definition: wingdi.h:1321
#define TT_PRIM_QSPLINE
Definition: wingdi.h:1320
#define PS_COSMETIC
Definition: wingdi.h:584
BYTE * pFlags
Definition: path.h:54
ULONG ulDirty_
Definition: ntgdihdl.h:294
Definition: types.h:100
#define GDI_HANDLE_GET_TYPE(h)
Definition: gdi.h:31
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
VOID FASTCALL IntGetCurrentPositionEx(PDC dc, LPPOINT pt)
Definition: line.c:128
#define FLOATOBJ_bConvertToLong(pf, pl)
Definition: floatobj.h:102
#define XF_LTOL
Definition: winddi.h:3109
#define FLOATOBJ_MulLong(pf, l)
Definition: winddi.h:2826
eMaj lines
Definition: tritemp.h:206
#define DIRTY_STYLESTATE
Definition: ntgdihdl.h:133
GLfloat f
Definition: glext.h:7540
BOOL FASTCALL PATH_PolylineTo(PDC dc, const POINT *pts, DWORD cbPoints)
Definition: path.c:1264
POINT pos
Definition: path.h:58
#define TRACE(s)
Definition: solgame.cpp:4
Definition: polytest.cpp:40
static WCHAR no[MAX_STRING_RESOURCE_LEN]
Definition: object.c:2340
GLsizeiptr size
Definition: glext.h:5919
VOID NTAPI GDIOBJ_vDeleteObject(POBJ pobj)
Definition: gdiobj.c:1111
#define ASSERT(a)
Definition: mode.c:44
#define GDI_OBJECT_TYPE_PEN
Definition: gdi.h:54
VOID FASTCALL PATH_DestroyGdiPath(PPATH pPath)
Definition: path.c:80
FLOAT FLOATOBJ
Definition: winddi.h:677
Definition: cmds.c:130
POINTFX apfx[1]
Definition: wingdi.h:2714
BOOL APIENTRY NtGdiAbortPath(HDC hDC)
Definition: path.c:2459
GLintptr offset
Definition: glext.h:5920
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
DBG_DEFAULT_CHANNEL(GdiPath)
#define PS_JOIN_ROUND
Definition: wingdi.h:599
static BOOL add_log_points_new_stroke(DC *dc, PPATH path, const POINT *points, DWORD count, BYTE type)
Definition: path.c:533
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned long DWORD
Definition: ntddk_ex.h:95
GLint left
Definition: glext.h:7726
LONG x
Definition: windef.h:329
BOOL APIENTRY NtGdiEndPath(HDC hDC)
Definition: path.c:2584
BOOL FASTCALL PATH_LineTo(PDC dc, INT x, INT y)
Definition: path.c:583
POINT * GDI_Bezier(const POINT *Points, INT count, INT *nPtsOut)
Definition: bezier.c:189
GLdouble GLdouble right
Definition: glext.h:10859
GLbitfield flags
Definition: glext.h:7161
#define GM_COMPATIBLE
Definition: wingdi.h:864
GLuint GLuint end
Definition: gl.h:1545
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
GLsizei const GLfloat * points
Definition: glext.h:8112
VOID NTAPI GDIOBJ_vUnlockObject(POBJ pobj)
Definition: gdiobj.c:880
BOOL FASTCALL PATH_PolyBezier(PDC dc, const POINT *pts, DWORD cbPoints)
Definition: path.c:1154
#define GGO_GLYPH_INDEX
Definition: wingdi.h:855
#define DIRTY_FILL
Definition: ntgdihdl.h:123
#define M_PI
Definition: dib.cpp:249
HDC hdc
Definition: main.c:9
BYTE jFillMode
Definition: ntgdihdl.h:309
HRGN APIENTRY NtGdiPathToRegion(HDC hDC)
Definition: path.c:2846
#define MatrixS2XForm(x, m)
Definition: coord.h:200
#define FLOATOBJ_GetFloat(pf)
Definition: winddi.h:2816
#define FLOATOBJ_Sub(pf, pf1)
Definition: winddi.h:2821
SIZEL szlWindowExt
Definition: ntgdihdl.h:342
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define M_PI_2
Definition: port.h:185
static BOOL start_new_stroke(PPATH path)
Definition: path.c:506
BOOL APIENTRY NtGdiCloseFigure(HDC hDC)
Definition: path.c:2545
static BOOL PATH_CheckRect(DC *dc, RECTL *rect, INT x1, INT y1, INT x2, INT y2)
Definition: path.c:433
GLenum src
Definition: glext.h:6340
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG _In_ LONG _In_ LONG y2
Definition: winddi.h:3706
VOID FASTCALL SetLastNtError(NTSTATUS Status)
Definition: error.c:37
Definition: mesh.c:5329
#define GROW_FACTOR_DENOM
Definition: path.c:24
unsigned char BYTE
Definition: xxhash.c:193
short gmCellIncX
Definition: wingdi.h:2445
BOOL PATH_RoundRect(DC *dc, INT x1, INT y1, INT x2, INT y2, INT ell_width, INT ell_height)
Definition: path.c:675
static INT int_from_fixed(FIXED f)
Definition: path.c:2201
_Check_return_ _CRT_JIT_INTRINSIC double __cdecl fabs(_In_ double x)
Definition: fabs.c:17
static const FLOATOBJ gef2
Definition: floatobj.h:115
static BOOLEAN IntDPtoLP(DC *pdc, PPOINTL ppt, UINT count)
Definition: coord.h:192
#define ERR(fmt,...)
Definition: debug.h:110
BOOL APIENTRY NtGdiFillPath(HDC hDC)
Definition: path.c:2626
#define FLOATOBJ_SetLong(pf, l)
Definition: winddi.h:2815
FLOAT FLOATL
Definition: winddi.h:114
static HDC hDC
Definition: 3dtext.c:33
FORCEINLINE VOID RECTL_vSetRect(_Out_ RECTL *prcl, _In_ LONG left, _In_ LONG top, _In_ LONG right, _In_ LONG bottom)
Definition: rect.h:5
BOOL APIENTRY NtGdiSetMiterLimit(IN HDC hdc, IN DWORD dwNew, IN OUT OPTIONAL PDWORD pdwOut)
Definition: path.c:2930
BOOL IntGdiFillRgn(_In_ PDC pdc, _In_ PREGION prgn, _In_opt_ PBRUSH pbrFill)
Definition: bitblt.c:1186
#define PS_TYPE_MASK
Definition: wingdi.h:603
static unsigned __int64 next
Definition: rand_nt.c:6
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
FORCEINLINE VOID DC_UnlockDc(PDC pdc)
Definition: dc.h:238
static BOOL FASTCALL PATH_add_outline(PDC dc, PPATH pPath, INT x, INT y, TTPOLYGONHEADER *header, DWORD size)
Definition: path.c:2258
BOOL FASTCALL PATH_AssignGdiPath(PPATH pPathDest, const PPATH pPathSrc)
Definition: path.c:166
Definition: path.h:19
static calc_node_t temp
Definition: rpn_ieee.c:38
GLuint start
Definition: gl.h:1545
#define IntIsEffectiveWidePen(pbrLine)
Definition: pen.h:33
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:2355
GLenum GLenum dst
Definition: glext.h:6340
BOOL FASTCALL PATH_FillPathEx(PDC dc, PPATH pPath, PBRUSH pbrFill)
Definition: path.c:1514
BOOL newStroke
Definition: path.h:57
ULONG FASTCALL ftGdiGetGlyphOutline(PDC dc, WCHAR wch, UINT iFormat, LPGLYPHMETRICS pgm, ULONG cjBuf, PVOID pvBuf, LPMAT2 pmat2, BOOL bIgnoreRotation)
Definition: freetype.c:3729
#define PS_ENDCAP_FLAT
Definition: wingdi.h:596
#define PS_ENDCAP_MASK
Definition: wingdi.h:602
int xOffset
Definition: appswitch.c:59
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
#define PS_JOIN_MASK
Definition: wingdi.h:600
unsigned int * PULONG
Definition: retypes.h:1
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
FORCEINLINE PSIZEL DC_pszlViewportExt(PDC pdc)
Definition: coord.h:111
#define NULL
Definition: types.h:112
VOID FASTCALL PATH_InitGdiPath(PPATH pPath)
Definition: path.c:142
#define DC_BRUSH_DIRTY
Definition: ntgdihdl.h:135
VOID FASTCALL DC_vPrepareDCsForBlit(PDC pdcDest, const RECT *rcDest, PDC pdcSrc, const RECT *rcSrc)
Definition: dclife.c:505
ENGAPI INT APIENTRY EngMulDiv(_In_ INT a, _In_ INT b, _In_ INT c)
Definition: math.c:26
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLint dx
Definition: linetemp.h:97
DWORD * PDWORD
Definition: pedump.c:68
BOOL APIENTRY NtGdiFlattenPath(HDC hDC)
Definition: path.c:2684
BOOL FASTCALL PATH_AddFlatBezier(PPATH pPath, POINT *pt, BOOL closed)
Definition: path.c:1378
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG _In_ LONG x2
Definition: winddi.h:3706
FORCEINLINE LONG RECTL_lGetHeight(_In_ const RECTL *prcl)
Definition: rect.h:86
#define ETO_PDY
Definition: wingdi.h:657
VOID FASTCALL DC_vFinishBlit(PDC pdc1, PDC pdc2)
Definition: dclife.c:614
#define MWT_IDENTITY
Definition: wingdi.h:944
void * Realloc(void *, size_t)
#define CoordLPtoDP(pdc, ppt)
Definition: coord.h:187
#define NUM_ENTRIES_INITIAL
Definition: path.c:21
VOID FASTCALL REGION_UnlockRgn(_In_ PREGION prgn)
Definition: region.c:2392
#define PATH_AllocPathWithHandle()
Definition: path.h:69
#define MM_TEXT
Definition: wingdi.h:873
#define PT_CLOSEFIGURE
Definition: wingdi.h:887
#define OUT
Definition: typedefs.h:40
BOOL FASTCALL GdiPathDPtoLP(PDC pdc, PPOINT ppt, INT count)
Definition: path.c:125
#define GROW_FACTOR_NUMER
Definition: path.c:23
#define PT_LINETO
Definition: wingdi.h:885
GLclampf GLclampf GLclampf alpha
Definition: gl.h:1740
float FLOAT
Definition: typedefs.h:69
#define PT_MOVETO
Definition: wingdi.h:884
BOOL FASTCALL PATH_ReserveEntries(PPATH pPath, INT numEntries)
Definition: path.c:296
SIZEL szlViewportExt
Definition: ntgdihdl.h:344
unsigned int ULONG
Definition: retypes.h:1
BASEOBJECT BaseObject
Definition: path.h:36
BOOL FASTCALL IntGdiMoveToEx(DC *dc, int X, int Y, LPPOINT Point)
Definition: line.c:78
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define DIRTY_LINE
Definition: ntgdihdl.h:124
char * cleanup(char *str)
Definition: wpickclick.c:99
static const WCHAR dc[]
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
FLONG state
Definition: path.h:52
_Out_ PDWORD pdwOut
Definition: ntgdi.h:1813
static BOOL PATH_DoArcPart(PPATH pPath, POINT corners[], double angleStart, double angleEnd, BYTE startEntryType)
Definition: path.c:890
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:40
int yOffset
Definition: appswitch.c:59
_STLP_DECLSPEC complex< float > _STLP_CALL sin(const complex< float > &)
GLdouble GLdouble GLdouble GLdouble top
Definition: glext.h:10859
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:165
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:168
#define _SEH2_LEAVE
Definition: filesup.c:20
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
#define PT_BEZIERTO
Definition: wingdi.h:886
_Check_return_ _CRTIMP double __cdecl floor(_In_ double x)
static VOID PATH_NormalizePoint(POINTL corners[], const POINTL *pPoint, FLOATL *pX, FLOATL *pY)
Definition: path.c:401
PREGION FASTCALL REGION_AllocUserRgnWithHandle(INT nRgn)
Definition: region.c:2313
#define GDI_ERROR
Definition: wingdi.h:1309
#define __FUNCTION__
Definition: types.h:112
#define TT_PRIM_LINE
Definition: wingdi.h:1319
#define memset(x, y, z)
Definition: compat.h:39
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
VOID FASTCALL REGION_Delete(PREGION pRgn)
Definition: region.c:2468
LONG cy
Definition: windef.h:335
static BOOLEAN INTERNAL_LPTODP(DC *dc, LPPOINT points, UINT count)
Definition: coord.h:47
VOID FASTCALL RECTL_vMakeWellOrdered(_Inout_ RECTL *prcl)
Definition: rect.c:81
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:56
struct CFHEADER header
Definition: fdi.c:101
BOOL FASTCALL PATH_Delete(HPATH hPath)
Definition: path.c:90
ENGAPI VOID APIENTRY EngSetLastError(_In_ ULONG iError)
Definition: error.c:28
INT NTAPI GreGetObject(IN HGDIOBJ hobj, IN INT cbCount, OUT PVOID pvBuffer)
Definition: gdiobj.c:1264
#define APIENTRY
Definition: api.h:79
POINTL ptlWindowOrg
Definition: ntgdihdl.h:341
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
BOOL FASTCALL PATH_FillPath(PDC dc, PPATH pPath)
Definition: path.c:1505
FIXED x
Definition: wingdi.h:2708
VOID FASTCALL DC_vUpdateFillBrush(PDC pdc)
Definition: dcobjs.c:16
static BYTE * add_log_points(DC *dc, PPATH path, const POINT *points, DWORD count, BYTE type)
Definition: path.c:463
static BOOLEAN IntLPtoDP(DC *pdc, PPOINTL ppt, UINT count)
Definition: coord.h:182
#define GM_ADVANCED
Definition: wingdi.h:865
INT iGraphicsMode
Definition: ntgdihdl.h:306
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68