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