Merge from amd64 branch:
[reactos.git] / reactos / subsystems / win32 / win32k / objects / line.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <w32k.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 // Some code from the WINE project source (www.winehq.com)
26
27 // Should use Fx in Point
28 //
29 BOOL FASTCALL
30 IntGdiMoveToEx(DC *dc,
31 int X,
32 int Y,
33 LPPOINT Point)
34 {
35 BOOL PathIsOpen;
36 PDC_ATTR pdcattr = dc->pdcattr;
37 if ( Point )
38 {
39 if ( pdcattr->ulDirty_ & DIRTY_PTLCURRENT ) // Double hit!
40 {
41 Point->x = pdcattr->ptfxCurrent.x; // ret prev before change.
42 Point->y = pdcattr->ptfxCurrent.y;
43 IntDPtoLP ( dc, Point, 1); // reconvert back.
44 }
45 else
46 {
47 Point->x = pdcattr->ptlCurrent.x;
48 Point->y = pdcattr->ptlCurrent.y;
49 }
50 }
51 pdcattr->ptlCurrent.x = X;
52 pdcattr->ptlCurrent.y = Y;
53 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
54 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
55 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
56
57 PathIsOpen = PATH_IsPathOpen(dc->dclevel);
58
59 if ( PathIsOpen )
60 return PATH_MoveTo ( dc );
61
62 return TRUE;
63 }
64
65 // Should use Fx in pt
66 //
67 VOID FASTCALL
68 IntGetCurrentPositionEx(PDC dc, LPPOINT pt)
69 {
70 PDC_ATTR pdcattr = dc->pdcattr;
71
72 if ( pt )
73 {
74 if (pdcattr->ulDirty_ & DIRTY_PTFXCURRENT)
75 {
76 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
77 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
78 pdcattr->ulDirty_ &= ~(DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
79 }
80 pt->x = pdcattr->ptlCurrent.x;
81 pt->y = pdcattr->ptlCurrent.y;
82 }
83 }
84
85 BOOL FASTCALL
86 IntGdiLineTo(DC *dc,
87 int XEnd,
88 int YEnd)
89 {
90 SURFACE *psurf;
91 BOOL Ret = TRUE;
92 PBRUSH pbrLine;
93 RECTL Bounds;
94 POINT Points[2];
95 PDC_ATTR pdcattr = dc->pdcattr;
96
97 if (PATH_IsPathOpen(dc->dclevel))
98 {
99 Ret = PATH_LineTo(dc, XEnd, YEnd);
100 if (Ret)
101 {
102 // FIXME - PATH_LineTo should maybe do this? No
103 pdcattr->ptlCurrent.x = XEnd;
104 pdcattr->ptlCurrent.y = YEnd;
105 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
106 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
107 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
108 }
109 return Ret;
110 }
111 else
112 {
113 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
114 DC_vUpdateLineBrush(dc);
115
116 psurf = dc->dclevel.pSurface;
117 if (NULL == psurf)
118 {
119 SetLastWin32Error(ERROR_INVALID_HANDLE);
120 return FALSE;
121 }
122
123 Points[0].x = pdcattr->ptlCurrent.x;
124 Points[0].y = pdcattr->ptlCurrent.y;
125 Points[1].x = XEnd;
126 Points[1].y = YEnd;
127
128 IntLPtoDP(dc, Points, 2);
129
130 /* The DCOrg is in device coordinates */
131 Points[0].x += dc->ptlDCOrig.x;
132 Points[0].y += dc->ptlDCOrig.y;
133 Points[1].x += dc->ptlDCOrig.x;
134 Points[1].y += dc->ptlDCOrig.y;
135
136 Bounds.left = min(Points[0].x, Points[1].x);
137 Bounds.top = min(Points[0].y, Points[1].y);
138 Bounds.right = max(Points[0].x, Points[1].x);
139 Bounds.bottom = max(Points[0].y, Points[1].y);
140
141 /* get BRUSH from current pen. */
142 pbrLine = dc->dclevel.pbrLine;
143 ASSERT(pbrLine);
144
145 if (!(pbrLine->flAttrs & GDIBRUSH_IS_NULL))
146 {
147 Ret = IntEngLineTo(&psurf->SurfObj,
148 dc->rosdc.CombinedClip,
149 &dc->eboLine.BrushObject,
150 Points[0].x, Points[0].y,
151 Points[1].x, Points[1].y,
152 &Bounds,
153 ROP2_TO_MIX(pdcattr->jROP2));
154 }
155
156 }
157
158 if (Ret)
159 {
160 pdcattr->ptlCurrent.x = XEnd;
161 pdcattr->ptlCurrent.y = YEnd;
162 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
163 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
164 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
165 }
166
167 return Ret;
168 }
169
170 BOOL FASTCALL
171 IntGdiPolyBezier(DC *dc,
172 LPPOINT pt,
173 DWORD Count)
174 {
175 BOOL ret = FALSE; // default to FAILURE
176
177 if ( PATH_IsPathOpen(dc->dclevel) )
178 {
179 return PATH_PolyBezier ( dc, pt, Count );
180 }
181
182 /* We'll convert it into line segments and draw them using Polyline */
183 {
184 POINT *Pts;
185 INT nOut;
186
187 Pts = GDI_Bezier ( pt, Count, &nOut );
188 if ( Pts )
189 {
190 ret = IntGdiPolyline(dc, Pts, nOut);
191 ExFreePoolWithTag(Pts, TAG_BEZIER);
192 }
193 }
194
195 return ret;
196 }
197
198 BOOL FASTCALL
199 IntGdiPolyBezierTo(DC *dc,
200 LPPOINT pt,
201 DWORD Count)
202 {
203 BOOL ret = FALSE; // default to failure
204 PDC_ATTR pdcattr = dc->pdcattr;
205
206 if ( PATH_IsPathOpen(dc->dclevel) )
207 ret = PATH_PolyBezierTo ( dc, pt, Count );
208 else /* We'll do it using PolyBezier */
209 {
210 POINT *npt;
211 npt = ExAllocatePoolWithTag(PagedPool,
212 sizeof(POINT) * (Count + 1),
213 TAG_BEZIER);
214 if ( npt )
215 {
216 npt[0].x = pdcattr->ptlCurrent.x;
217 npt[0].y = pdcattr->ptlCurrent.y;
218 memcpy(npt + 1, pt, sizeof(POINT) * Count);
219 ret = IntGdiPolyBezier(dc, npt, Count+1);
220 ExFreePoolWithTag(npt, TAG_BEZIER);
221 }
222 }
223 if ( ret )
224 {
225 pdcattr->ptlCurrent.x = pt[Count-1].x;
226 pdcattr->ptlCurrent.y = pt[Count-1].y;
227 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
228 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
229 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
230 }
231
232 return ret;
233 }
234
235 BOOL FASTCALL
236 IntGdiPolyline(DC *dc,
237 LPPOINT pt,
238 int Count)
239 {
240 SURFACE *psurf;
241 BRUSH *pbrLine;
242 LPPOINT Points;
243 BOOL Ret = TRUE;
244 LONG i;
245 PDC_ATTR pdcattr = dc->pdcattr;
246
247 if (PATH_IsPathOpen(dc->dclevel))
248 return PATH_Polyline(dc, pt, Count);
249
250 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
251 DC_vUpdateFillBrush(dc);
252
253 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
254 DC_vUpdateLineBrush(dc);
255
256 /* Get BRUSHOBJ from current pen. */
257 pbrLine = dc->dclevel.pbrLine;
258 ASSERT(pbrLine);
259
260 if (!(pbrLine->flAttrs & GDIBRUSH_IS_NULL))
261 {
262 Points = EngAllocMem(0, Count * sizeof(POINT), TAG_COORD);
263 if (Points != NULL)
264 {
265 psurf = dc->dclevel.pSurface;
266 /* FIXME - psurf can be NULL!!!!
267 Don't assert but handle this case gracefully! */
268 ASSERT(psurf);
269
270 RtlCopyMemory(Points, pt, Count * sizeof(POINT));
271 IntLPtoDP(dc, Points, Count);
272
273 /* Offset the array of points by the DC origin */
274 for (i = 0; i < Count; i++)
275 {
276 Points[i].x += dc->ptlDCOrig.x;
277 Points[i].y += dc->ptlDCOrig.y;
278 }
279
280 Ret = IntEngPolyline(&psurf->SurfObj,
281 dc->rosdc.CombinedClip,
282 &dc->eboLine.BrushObject,
283 Points,
284 Count,
285 ROP2_TO_MIX(pdcattr->jROP2));
286
287 EngFreeMem(Points);
288 }
289 else
290 {
291 Ret = FALSE;
292 }
293 }
294
295 return Ret;
296 }
297
298 BOOL FASTCALL
299 IntGdiPolylineTo(DC *dc,
300 LPPOINT pt,
301 DWORD Count)
302 {
303 BOOL ret = FALSE; // default to failure
304 PDC_ATTR pdcattr = dc->pdcattr;
305
306 if (PATH_IsPathOpen(dc->dclevel))
307 {
308 ret = PATH_PolylineTo(dc, pt, Count);
309 }
310 else /* do it using Polyline */
311 {
312 POINT *pts = ExAllocatePoolWithTag(PagedPool,
313 sizeof(POINT) * (Count + 1),
314 TAG_SHAPE);
315 if ( pts )
316 {
317 pts[0].x = pdcattr->ptlCurrent.x;
318 pts[0].y = pdcattr->ptlCurrent.y;
319 memcpy( pts + 1, pt, sizeof(POINT) * Count);
320 ret = IntGdiPolyline(dc, pts, Count + 1);
321 ExFreePoolWithTag(pts, TAG_SHAPE);
322 }
323 }
324 if ( ret )
325 {
326 pdcattr->ptlCurrent.x = pt[Count-1].x;
327 pdcattr->ptlCurrent.y = pt[Count-1].y;
328 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
329 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
330 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
331 }
332
333 return ret;
334 }
335
336
337 BOOL FASTCALL
338 IntGdiPolyPolyline(DC *dc,
339 LPPOINT pt,
340 PULONG PolyPoints,
341 DWORD Count)
342 {
343 int i;
344 LPPOINT pts;
345 PULONG pc;
346 BOOL ret = FALSE; // default to failure
347 pts = pt;
348 pc = PolyPoints;
349
350 if (PATH_IsPathOpen(dc->dclevel))
351 return PATH_PolyPolyline( dc, pt, PolyPoints, Count );
352
353 for (i = 0; i < Count; i++)
354 {
355 ret = IntGdiPolyline ( dc, pts, *pc );
356 if (ret == FALSE)
357 {
358 return ret;
359 }
360 pts+=*pc++;
361 }
362
363 return ret;
364 }
365
366 /******************************************************************************/
367
368 BOOL
369 APIENTRY
370 NtGdiLineTo(HDC hDC,
371 int XEnd,
372 int YEnd)
373 {
374 DC *dc;
375 BOOL Ret;
376
377 dc = DC_LockDc(hDC);
378 if (!dc)
379 {
380 SetLastWin32Error(ERROR_INVALID_HANDLE);
381 return FALSE;
382 }
383 if (dc->dctype == DC_TYPE_INFO)
384 {
385 DC_UnlockDc(dc);
386 /* Yes, Windows really returns TRUE in this case */
387 return TRUE;
388 }
389
390 Ret = IntGdiLineTo(dc, XEnd, YEnd);
391
392 DC_UnlockDc(dc);
393 return Ret;
394 }
395
396 BOOL
397 APIENTRY
398 NtGdiPolyDraw(
399 IN HDC hdc,
400 IN LPPOINT lppt,
401 IN LPBYTE lpbTypes,
402 IN ULONG cCount)
403 {
404 PDC dc;
405 PPATH pPath;
406 BOOL result = FALSE;
407 POINT lastmove;
408 unsigned int i;
409 PDC_ATTR pdcattr;
410
411 dc = DC_LockDc(hdc);
412 if (!dc) return FALSE;
413 pdcattr = dc->pdcattr;
414
415 _SEH2_TRY
416 {
417 ProbeArrayForRead(lppt, sizeof(POINT), cCount, sizeof(LONG));
418 ProbeArrayForRead(lpbTypes, sizeof(BYTE), cCount, sizeof(BYTE));
419
420 /* check for each bezierto if there are two more points */
421 for ( i = 0; i < cCount; i++ )
422 {
423 if ( lpbTypes[i] != PT_MOVETO &&
424 lpbTypes[i] & PT_BEZIERTO )
425 {
426 if ( cCount < i+3 ) _SEH2_LEAVE;
427 else i += 2;
428 }
429 }
430
431 /* if no moveto occurs, we will close the figure here */
432 lastmove.x = pdcattr->ptlCurrent.x;
433 lastmove.y = pdcattr->ptlCurrent.y;
434
435 /* now let's draw */
436 for ( i = 0; i < cCount; i++ )
437 {
438 if ( lpbTypes[i] == PT_MOVETO )
439 {
440 IntGdiMoveToEx( dc, lppt[i].x, lppt[i].y, NULL );
441 lastmove.x = pdcattr->ptlCurrent.x;
442 lastmove.y = pdcattr->ptlCurrent.y;
443 }
444 else if ( lpbTypes[i] & PT_LINETO )
445 IntGdiLineTo( dc, lppt[i].x, lppt[i].y );
446 else if ( lpbTypes[i] & PT_BEZIERTO )
447 {
448 POINT pts[4];
449 pts[0].x = pdcattr->ptlCurrent.x;
450 pts[0].y = pdcattr->ptlCurrent.y;
451 RtlCopyMemory(pts + 1, &lppt[i], sizeof(POINT) * 3);
452 IntGdiPolyBezier(dc, pts, 4);
453 i += 2;
454 }
455 else _SEH2_LEAVE;
456
457 if ( lpbTypes[i] & PT_CLOSEFIGURE )
458 {
459 if ( PATH_IsPathOpen(dc->dclevel) )
460 {
461 pPath = PATH_LockPath( dc->dclevel.hPath );
462 if (pPath)
463 {
464 IntGdiCloseFigure( pPath );
465 PATH_UnlockPath( pPath );
466 }
467 }
468 else IntGdiLineTo( dc, lastmove.x, lastmove.y );
469 }
470 }
471
472 result = TRUE;
473 }
474 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
475 {
476 SetLastNtError(_SEH2_GetExceptionCode());
477 }
478 _SEH2_END;
479
480 DC_UnlockDc(dc);
481
482 return result;
483 }
484
485 /*
486 * @unimplemented
487 */
488 BOOL
489 APIENTRY
490 NtGdiMoveTo(
491 IN HDC hdc,
492 IN INT x,
493 IN INT y,
494 OUT OPTIONAL LPPOINT pptOut)
495 {
496 UNIMPLEMENTED;
497 return FALSE;
498 }
499
500 /* EOF */