72f27c2079bcdad52d5c4d9a2157ef4fb89b9517
[reactos.git] / win32ss / gdi / eng / pathobj.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS win32 subsystem
4 * PURPOSE: PATHOBJ service routines
5 * FILE: win32ss/gdi/eng/pathobj.c
6 * PROGRAMERS: Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <win32k.h>
12 #undef XFORMOBJ
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* TYPES *********************************************************************/
18
19 /* extended PATHDATA */
20 typedef struct _EXTPATHDATA
21 {
22 PATHDATA pd;
23 struct _EXTPATHDATA *ppdNext;
24 } EXTPATHDATA, *PEXTPATHDATA;
25
26 /* extended PATHOBJ */
27 typedef struct _EXTPATHOBJ
28 {
29 PATHOBJ po;
30 PEXTPATHDATA ppdFirst;
31 PEXTPATHDATA ppdLast;
32 PEXTPATHDATA ppdCurrent;
33 } EXTPATHOBJ, *PEXTPATHOBJ;
34
35 /* FUNCTIONS *****************************************************************/
36
37 /* FIXME: set last error */
38 /* FIXME: PATHOBJ_vEnumStartClipLines and PATHOBJ_bEnumClipLines */
39
40 /*
41 * @implemented
42 */
43 PATHOBJ*
44 APIENTRY
45 EngCreatePath(VOID)
46 {
47 PEXTPATHOBJ pPathObj;
48 const ULONG size = sizeof(EXTPATHOBJ);
49
50 pPathObj = ExAllocatePoolWithTag(PagedPool, size, GDITAG_PATHOBJ);
51 if (pPathObj == NULL)
52 {
53 return NULL;
54 }
55
56 RtlZeroMemory(pPathObj, size);
57 return &pPathObj->po;
58 }
59
60 /*
61 * @implemented
62 */
63 VOID
64 APIENTRY
65 EngDeletePath(IN PATHOBJ *ppo)
66 {
67 PEXTPATHOBJ pPathObj;
68 PEXTPATHDATA ppd, ppdNext;
69
70 pPathObj = (PEXTPATHOBJ)ppo;
71 if (pPathObj == NULL)
72 return;
73
74 for (ppd = pPathObj->ppdFirst; ppd; ppd = ppdNext)
75 {
76 ppdNext = ppd->ppdNext;
77 ExFreePoolWithTag(ppd, GDITAG_PATHOBJ);
78 }
79 ExFreePoolWithTag(pPathObj, GDITAG_PATHOBJ);
80 }
81
82 /*
83 * @implemented
84 */
85 BOOL
86 APIENTRY
87 PATHOBJ_bCloseFigure(IN PATHOBJ *ppo)
88 {
89 PEXTPATHDATA ppd;
90 PEXTPATHOBJ pPathObj = (PEXTPATHOBJ)ppo;
91 if (pPathObj == NULL)
92 return FALSE;
93
94 ppd = pPathObj->ppdLast;
95 if (ppd == NULL)
96 return FALSE;
97
98 ppd->pd.flags |= PD_CLOSEFIGURE | PD_ENDSUBPATH;
99 return TRUE;
100 }
101
102 /*
103 * @implemented
104 */
105 VOID
106 APIENTRY
107 PATHOBJ_vEnumStart(IN PATHOBJ *ppo)
108 {
109 PEXTPATHOBJ pPathObj = (PEXTPATHOBJ)ppo;
110 if (pPathObj == NULL)
111 return;
112
113 pPathObj->ppdCurrent = pPathObj->ppdFirst;
114 }
115
116 /*
117 * @implemented
118 */
119 BOOL
120 APIENTRY
121 PATHOBJ_bEnum(
122 IN PATHOBJ *ppo,
123 OUT PATHDATA *ppd)
124 {
125 PEXTPATHOBJ pPathObj = (PEXTPATHOBJ)ppo;
126 if (pPathObj == NULL || pPathObj->ppdCurrent == NULL)
127 return FALSE;
128
129 *ppd = pPathObj->ppdCurrent->pd;
130
131 pPathObj->ppdCurrent = pPathObj->ppdCurrent->ppdNext;
132 return (pPathObj->ppdCurrent != NULL);
133 }
134
135 /*
136 * @implemented
137 */
138 BOOL
139 APIENTRY
140 PATHOBJ_bMoveTo(
141 IN PATHOBJ *ppo,
142 IN POINTFIX ptfx)
143 {
144 PEXTPATHOBJ pPathObj;
145 PEXTPATHDATA ppd, ppdLast;
146
147 pPathObj = (PEXTPATHOBJ)ppo;
148 if (pPathObj == NULL)
149 return FALSE;
150
151 /* allocate a subpath data */
152 ppd = ExAllocatePoolWithTag(PagedPool, sizeof(EXTPATHDATA), GDITAG_PATHOBJ);
153 if (ppd == NULL)
154 return FALSE;
155
156 RtlZeroMemory(ppd, sizeof(EXTPATHDATA));
157
158 /* add the first point to the subpath */
159 ppd->pd.flags = PD_BEGINSUBPATH;
160 ppd->pd.count = 1;
161 ppd->pd.pptfx = ExAllocatePoolWithTag(PagedPool, sizeof(POINTFIX), GDITAG_PATHOBJ);
162 if (ppd->pd.pptfx == NULL)
163 {
164 ExFreePoolWithTag(ppd, GDITAG_PATHOBJ);
165 return FALSE;
166 }
167 ppd->pd.pptfx[0] = ptfx;
168
169 ppdLast = pPathObj->ppdLast;
170 if (ppdLast)
171 {
172 /* end the last subpath */
173 ppdLast->pd.flags |= PD_ENDSUBPATH;
174
175 /* add the subpath to the last */
176 ppdLast->ppdNext = ppd;
177 pPathObj->ppdLast = ppd;
178 }
179 else
180 {
181 /* add the subpath */
182 pPathObj->ppdLast = pPathObj->ppdFirst = ppd;
183 }
184
185 pPathObj->po.cCurves++;
186
187 return TRUE;
188 }
189
190 /*
191 * @implemented
192 */
193 BOOL
194 APIENTRY
195 PATHOBJ_bPolyLineTo(
196 IN PATHOBJ *ppo,
197 IN POINTFIX *pptfx,
198 IN ULONG cptfx)
199 {
200 PEXTPATHOBJ pPathObj;
201 PEXTPATHDATA ppd, ppdLast;
202 PPOINTFIX pptfxNew, pptfxOld;
203 ULONG size;
204
205 pPathObj = (PEXTPATHOBJ)ppo;
206 if (pPathObj == NULL || pptfx == NULL || cptfx == 0)
207 return FALSE;
208
209 ppdLast = pPathObj->ppdLast;
210 if (ppdLast == NULL)
211 {
212 /* allocate a subpath data */
213 ppd = ExAllocatePoolWithTag(PagedPool, sizeof(EXTPATHDATA), GDITAG_PATHOBJ);
214 if (ppd == NULL)
215 return FALSE;
216
217 /* store data */
218 RtlZeroMemory(ppd, sizeof(EXTPATHDATA));
219 ppd->pd.flags = PD_BEGINSUBPATH;
220
221 size = cptfx * sizeof(POINTFIX);
222 pptfxNew = ExAllocatePoolWithTag(PagedPool, size, GDITAG_PATHOBJ);
223 if (pptfxNew == NULL)
224 {
225 ExFreePoolWithTag(ppd, GDITAG_PATHOBJ);
226 return FALSE;
227 }
228 RtlCopyMemory(pptfxNew, pptfx, size);
229 ppd->pd.pptfx = pptfxNew;
230 ppd->pd.count = cptfx;
231
232 /* set the subpath */
233 pPathObj->ppdLast = pPathObj->ppdFirst = ppd;
234
235 pPathObj->po.cCurves++;
236 }
237 else if (ppdLast->pd.flags & (PD_BEZIERS | PD_ENDSUBPATH))
238 {
239 /* allocate a subpath data */
240 ppd = ExAllocatePoolWithTag(PagedPool, sizeof(EXTPATHDATA), GDITAG_PATHOBJ);
241 if (ppd == NULL)
242 return FALSE;
243
244 /* store data */
245 RtlZeroMemory(ppd, sizeof(EXTPATHDATA));
246 ppd->pd.flags = 0;
247 ppd->pd.count = cptfx;
248
249 size = cptfx * sizeof(POINTFIX);
250 pptfxNew = ExAllocatePoolWithTag(PagedPool, size, GDITAG_PATHOBJ);
251 if (pptfxNew == NULL)
252 {
253 ExFreePoolWithTag(ppd, GDITAG_PATHOBJ);
254 return FALSE;
255 }
256 RtlCopyMemory(pptfxNew, pptfx, size);
257 ppd->pd.pptfx = pptfxNew;
258
259 /* add to last */
260 ppdLast->ppdNext = ppd;
261 pPathObj->ppdLast = ppd;
262
263 pPathObj->po.cCurves++;
264 }
265 else
266 {
267 /* concatenate ppdLast->pd.pptfx and pptfx */
268 size = (ppdLast->pd.count + cptfx) * sizeof(POINTFIX);
269 pptfxNew = ExAllocatePoolWithTag(PagedPool, size, GDITAG_PATHOBJ);
270 if (pptfxNew == NULL)
271 return FALSE;
272
273 size = ppdLast->pd.count * sizeof(POINTFIX);
274 RtlCopyMemory(&pptfxNew[0], ppdLast->pd.pptfx, size);
275 size = cptfx * sizeof(POINTFIX);
276 RtlCopyMemory(&pptfxNew[ppdLast->pd.count], pptfx, size);
277
278 pptfxOld = ppdLast->pd.pptfx;
279 ppdLast->pd.pptfx = pptfxNew;
280 ppdLast->pd.count += cptfx;
281 ExFreePoolWithTag(pptfxOld, GDITAG_PATHOBJ);
282 }
283
284 return TRUE;
285 }
286
287 /*
288 * @implemented
289 */
290 BOOL
291 APIENTRY
292 PATHOBJ_bPolyBezierTo(
293 IN PATHOBJ *ppo,
294 IN POINTFIX *pptfx,
295 IN ULONG cptfx)
296 {
297 PEXTPATHOBJ pPathObj;
298 PEXTPATHDATA ppd, ppdLast;
299 PPOINTFIX pptfxNew, pptfxOld;
300 ULONG size;
301
302 pPathObj = (PEXTPATHOBJ)ppo;
303 if (pPathObj == NULL || pptfx == NULL || cptfx == 0)
304 return FALSE;
305
306 ppdLast = pPathObj->ppdLast;
307 if (ppdLast == NULL)
308 {
309 /* allocate a subpath data */
310 ppd = ExAllocatePoolWithTag(PagedPool, sizeof(EXTPATHDATA), GDITAG_PATHOBJ);
311 if (ppd == NULL)
312 return FALSE;
313
314 /* store data */
315 RtlZeroMemory(ppd, sizeof(EXTPATHDATA));
316 ppd->pd.flags = PD_BEGINSUBPATH | PD_BEZIERS;
317
318 size = cptfx * sizeof(POINTFIX);
319 pptfxNew = ExAllocatePoolWithTag(PagedPool, size, GDITAG_PATHOBJ);
320 if (pptfxNew == NULL)
321 {
322 ExFreePoolWithTag(ppd, GDITAG_PATHOBJ);
323 return FALSE;
324 }
325 RtlCopyMemory(pptfxNew, pptfx, size);
326 ppd->pd.pptfx = pptfxNew;
327 ppd->pd.count = cptfx;
328
329 /* set the subpath */
330 pPathObj->ppdLast = pPathObj->ppdFirst = ppd;
331
332 pPathObj->po.cCurves++;
333 }
334 else if (!(ppdLast->pd.flags & PD_BEZIERS) || (ppdLast->pd.flags & PD_ENDSUBPATH))
335 {
336 /* allocate a subpath data */
337 ppd = ExAllocatePoolWithTag(PagedPool, sizeof(EXTPATHDATA), GDITAG_PATHOBJ);
338 if (ppd == NULL)
339 return FALSE;
340
341 /* store data */
342 RtlZeroMemory(ppd, sizeof(EXTPATHDATA));
343 ppd->pd.flags = PD_BEZIERS;
344 ppd->pd.count = cptfx;
345
346 size = cptfx * sizeof(POINTFIX);
347 pptfxNew = ExAllocatePoolWithTag(PagedPool, size, GDITAG_PATHOBJ);
348 if (pptfxNew == NULL)
349 {
350 ExFreePoolWithTag(ppd, GDITAG_PATHOBJ);
351 return FALSE;
352 }
353 RtlCopyMemory(pptfxNew, pptfx, size);
354 ppd->pd.pptfx = pptfxNew;
355
356 /* add to last */
357 ppdLast->ppdNext = ppd;
358 pPathObj->ppdLast = ppd;
359
360 pPathObj->po.cCurves++;
361 }
362 else
363 {
364 /* concatenate ppdLast->pd.pptfx and pptfx */
365 size = (ppdLast->pd.count + cptfx) * sizeof(POINTFIX);
366 pptfxNew = ExAllocatePoolWithTag(PagedPool, size, GDITAG_PATHOBJ);
367 if (pptfxNew == NULL)
368 return FALSE;
369
370 size = ppdLast->pd.count * sizeof(POINTFIX);
371 RtlCopyMemory(&pptfxNew[0], ppdLast->pd.pptfx, size);
372 size = cptfx * sizeof(POINTFIX);
373 RtlCopyMemory(&pptfxNew[ppdLast->pd.count], pptfx, size);
374
375 pptfxOld = ppdLast->pd.pptfx;
376 ppdLast->pd.pptfx = pptfxNew;
377 ppdLast->pd.count += cptfx;
378 ExFreePoolWithTag(pptfxOld, GDITAG_PATHOBJ);
379 }
380
381 pPathObj->po.fl |= PO_BEZIERS;
382
383 return TRUE;
384 }
385
386 VOID
387 APIENTRY
388 PATHOBJ_vEnumStartClipLines(
389 IN PATHOBJ *ppo,
390 IN CLIPOBJ *pco,
391 IN SURFOBJ *pso,
392 IN LINEATTRS *pla)
393 {
394 UNIMPLEMENTED;
395 }
396
397 BOOL
398 APIENTRY
399 PATHOBJ_bEnumClipLines(
400 IN PATHOBJ *ppo,
401 IN ULONG cb,
402 OUT CLIPLINE *pcl)
403 {
404 UNIMPLEMENTED;
405 return FALSE;
406 }
407
408 /*
409 * @implemented
410 */
411 VOID
412 APIENTRY
413 PATHOBJ_vGetBounds(
414 IN PATHOBJ *ppo,
415 OUT PRECTFX prectfx)
416 {
417 FIX xLeft, yTop, xRight, yBottom;
418 PEXTPATHOBJ pPathObj;
419 PEXTPATHDATA ppd, ppdNext;
420 ULONG i;
421
422 pPathObj = (PEXTPATHOBJ)ppo;
423 if (pPathObj == NULL || prectfx == NULL)
424 return;
425
426 yTop = xLeft = MAXLONG;
427 yBottom = xRight = MINLONG;
428
429 for (ppd = pPathObj->ppdFirst; ppd; ppd = ppdNext)
430 {
431 ppdNext = ppd->ppdNext;
432 for (i = 0; i < ppd->pd.count; ++i)
433 {
434 PPOINTFIX pptfx = &ppd->pd.pptfx[i];
435 if (pptfx->x < xLeft)
436 xLeft = pptfx->x;
437 if (pptfx->x > xRight)
438 xRight = pptfx->x;
439 if (pptfx->y < yTop)
440 yTop = pptfx->y;
441 if (pptfx->y > yBottom)
442 yBottom = pptfx->y;
443 }
444 }
445
446 if (xLeft <= xRight && yTop <= yBottom)
447 {
448 prectfx->xLeft = xLeft;
449 prectfx->yTop = yTop;
450 prectfx->xRight = xRight + 1;
451 prectfx->yBottom = yBottom + 1;
452 }
453 else
454 {
455 RtlZeroMemory(prectfx, sizeof(*prectfx));
456 }
457 }
458
459 /* EOF */