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