[WIN32K]
[reactos.git] / 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 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 DC_vPrepareDCsForBlit(dc, dc->rosdc.CombinedClip->rclBounds,
251 NULL, dc->rosdc.CombinedClip->rclBounds);
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 DC_vFinishBlit(dc, NULL);
299
300 return Ret;
301 }
302
303 BOOL FASTCALL
304 IntGdiPolylineTo(DC *dc,
305 LPPOINT pt,
306 DWORD Count)
307 {
308 BOOL ret = FALSE; // default to failure
309 PDC_ATTR pdcattr = dc->pdcattr;
310
311 if (PATH_IsPathOpen(dc->dclevel))
312 {
313 ret = PATH_PolylineTo(dc, pt, Count);
314 }
315 else /* do it using Polyline */
316 {
317 POINT *pts = ExAllocatePoolWithTag(PagedPool,
318 sizeof(POINT) * (Count + 1),
319 TAG_SHAPE);
320 if ( pts )
321 {
322 pts[0].x = pdcattr->ptlCurrent.x;
323 pts[0].y = pdcattr->ptlCurrent.y;
324 memcpy( pts + 1, pt, sizeof(POINT) * Count);
325 ret = IntGdiPolyline(dc, pts, Count + 1);
326 ExFreePoolWithTag(pts, TAG_SHAPE);
327 }
328 }
329 if ( ret )
330 {
331 pdcattr->ptlCurrent.x = pt[Count-1].x;
332 pdcattr->ptlCurrent.y = pt[Count-1].y;
333 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
334 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
335 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
336 }
337
338 return ret;
339 }
340
341
342 BOOL FASTCALL
343 IntGdiPolyPolyline(DC *dc,
344 LPPOINT pt,
345 PULONG PolyPoints,
346 DWORD Count)
347 {
348 int i;
349 LPPOINT pts;
350 PULONG pc;
351 BOOL ret = FALSE; // default to failure
352 pts = pt;
353 pc = PolyPoints;
354
355 if (PATH_IsPathOpen(dc->dclevel))
356 return PATH_PolyPolyline( dc, pt, PolyPoints, Count );
357
358 for (i = 0; i < Count; i++)
359 {
360 ret = IntGdiPolyline ( dc, pts, *pc );
361 if (ret == FALSE)
362 {
363 return ret;
364 }
365 pts+=*pc++;
366 }
367
368 return ret;
369 }
370
371 /******************************************************************************/
372
373 BOOL
374 APIENTRY
375 NtGdiLineTo(HDC hDC,
376 int XEnd,
377 int YEnd)
378 {
379 DC *dc;
380 BOOL Ret;
381 RECT rcLockRect ;
382
383 dc = DC_LockDc(hDC);
384 if (!dc)
385 {
386 SetLastWin32Error(ERROR_INVALID_HANDLE);
387 return FALSE;
388 }
389 if (dc->dctype == DC_TYPE_INFO)
390 {
391 DC_UnlockDc(dc);
392 /* Yes, Windows really returns TRUE in this case */
393 return TRUE;
394 }
395
396 rcLockRect.left = dc->pdcattr->ptlCurrent.x;
397 rcLockRect.top = dc->pdcattr->ptlCurrent.y;
398 rcLockRect.right = XEnd;
399 rcLockRect.bottom = YEnd;
400
401 IntLPtoDP(dc, &rcLockRect, 2);
402
403 /* The DCOrg is in device coordinates */
404 rcLockRect.left += dc->ptlDCOrig.x;
405 rcLockRect.top += dc->ptlDCOrig.y;
406 rcLockRect.right += dc->ptlDCOrig.x;
407 rcLockRect.bottom += dc->ptlDCOrig.y;
408
409 DC_vPrepareDCsForBlit(dc, rcLockRect, NULL, rcLockRect);
410
411 if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
412 DC_vUpdateLineBrush(dc);
413
414 Ret = IntGdiLineTo(dc, XEnd, YEnd);
415
416 DC_vFinishBlit(dc, NULL);
417
418 DC_UnlockDc(dc);
419 return Ret;
420 }
421
422 BOOL
423 APIENTRY
424 NtGdiPolyDraw(
425 IN HDC hdc,
426 IN LPPOINT lppt,
427 IN LPBYTE lpbTypes,
428 IN ULONG cCount)
429 {
430 PDC dc;
431 PPATH pPath;
432 BOOL result = FALSE;
433 POINT lastmove;
434 unsigned int i;
435 PDC_ATTR pdcattr;
436
437 dc = DC_LockDc(hdc);
438 if (!dc) return FALSE;
439 pdcattr = dc->pdcattr;
440
441 _SEH2_TRY
442 {
443 ProbeArrayForRead(lppt, sizeof(POINT), cCount, sizeof(LONG));
444 ProbeArrayForRead(lpbTypes, sizeof(BYTE), cCount, sizeof(BYTE));
445
446 /* check for each bezierto if there are two more points */
447 for ( i = 0; i < cCount; i++ )
448 {
449 if ( lpbTypes[i] != PT_MOVETO &&
450 lpbTypes[i] & PT_BEZIERTO )
451 {
452 if ( cCount < i+3 ) _SEH2_LEAVE;
453 else i += 2;
454 }
455 }
456
457 /* if no moveto occurs, we will close the figure here */
458 lastmove.x = pdcattr->ptlCurrent.x;
459 lastmove.y = pdcattr->ptlCurrent.y;
460
461 /* now let's draw */
462 for ( i = 0; i < cCount; i++ )
463 {
464 if ( lpbTypes[i] == PT_MOVETO )
465 {
466 IntGdiMoveToEx( dc, lppt[i].x, lppt[i].y, NULL, FALSE );
467 lastmove.x = pdcattr->ptlCurrent.x;
468 lastmove.y = pdcattr->ptlCurrent.y;
469 }
470 else if ( lpbTypes[i] & PT_LINETO )
471 IntGdiLineTo( dc, lppt[i].x, lppt[i].y );
472 else if ( lpbTypes[i] & PT_BEZIERTO )
473 {
474 POINT pts[4];
475 pts[0].x = pdcattr->ptlCurrent.x;
476 pts[0].y = pdcattr->ptlCurrent.y;
477 RtlCopyMemory(pts + 1, &lppt[i], sizeof(POINT) * 3);
478 IntGdiPolyBezier(dc, pts, 4);
479 i += 2;
480 }
481 else _SEH2_LEAVE;
482
483 if ( lpbTypes[i] & PT_CLOSEFIGURE )
484 {
485 if ( PATH_IsPathOpen(dc->dclevel) )
486 {
487 pPath = PATH_LockPath( dc->dclevel.hPath );
488 if (pPath)
489 {
490 IntGdiCloseFigure( pPath );
491 PATH_UnlockPath( pPath );
492 }
493 }
494 else IntGdiLineTo( dc, lastmove.x, lastmove.y );
495 }
496 }
497
498 result = TRUE;
499 }
500 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
501 {
502 SetLastNtError(_SEH2_GetExceptionCode());
503 }
504 _SEH2_END;
505
506 DC_UnlockDc(dc);
507
508 return result;
509 }
510
511 /*
512 * @unimplemented
513 */
514 BOOL
515 APIENTRY
516 NtGdiMoveTo(
517 IN HDC hdc,
518 IN INT x,
519 IN INT y,
520 OUT OPTIONAL LPPOINT pptOut)
521 {
522 UNIMPLEMENTED;
523 return FALSE;
524 }
525
526 /* EOF */