- Merge aicom-network-fixes up to r36740
[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 BitmapObj = BITMAPOBJ_LockBitmap ( dc->w.hBitmap );
119 if (NULL == BitmapObj)
120 {
121 SetLastWin32Error(ERROR_INVALID_HANDLE);
122 return FALSE;
123 }
124
125 Points[0].x = Dc_Attr->ptlCurrent.x;
126 Points[0].y = Dc_Attr->ptlCurrent.y;
127 Points[1].x = XEnd;
128 Points[1].y = YEnd;
129
130 IntLPtoDP(dc, Points, 2);
131
132 /* The DCOrg is in device coordinates */
133 Points[0].x += dc->ptlDCOrig.x;
134 Points[0].y += dc->ptlDCOrig.y;
135 Points[1].x += dc->ptlDCOrig.x;
136 Points[1].y += dc->ptlDCOrig.y;
137
138 Bounds.left = min(Points[0].x, Points[1].x);
139 Bounds.top = min(Points[0].y, Points[1].y);
140 Bounds.right = max(Points[0].x, Points[1].x);
141 Bounds.bottom = max(Points[0].y, Points[1].y);
142
143 /* get BRUSHOBJ from current pen. */
144 PenBrushObj = PENOBJ_LockPen( Dc_Attr->hpen );
145 if (!PenBrushObj)
146 {
147 /* default to BLACK_PEN */
148 PenBrushObj = PENOBJ_LockPen(NtGdiGetStockObject(BLACK_PEN));
149 ASSERT(PenBrushObj);
150 }
151
152 if (!(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
153 {
154 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
155 Ret = IntEngLineTo(&BitmapObj->SurfObj,
156 dc->CombinedClip,
157 &PenBrushInst.BrushObject,
158 Points[0].x, Points[0].y,
159 Points[1].x, Points[1].y,
160 &Bounds,
161 ROP2_TO_MIX(Dc_Attr->jROP2));
162 }
163
164 BITMAPOBJ_UnlockBitmap ( BitmapObj );
165 PENOBJ_UnlockPen( PenBrushObj );
166 }
167
168 if (Ret)
169 {
170 Dc_Attr->ptlCurrent.x = XEnd;
171 Dc_Attr->ptlCurrent.y = YEnd;
172 Dc_Attr->ptfxCurrent = Dc_Attr->ptlCurrent;
173 CoordLPtoDP(dc, &Dc_Attr->ptfxCurrent); // Update fx
174 Dc_Attr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
175 }
176
177 return Ret;
178 }
179
180 BOOL FASTCALL
181 IntGdiPolyBezier(DC *dc,
182 LPPOINT pt,
183 DWORD Count)
184 {
185 BOOL ret = FALSE; // default to FAILURE
186
187 if ( PATH_IsPathOpen(dc->DcLevel) )
188 {
189 return PATH_PolyBezier ( dc, pt, Count );
190 }
191
192 /* We'll convert it into line segments and draw them using Polyline */
193 {
194 POINT *Pts;
195 INT nOut;
196
197 Pts = GDI_Bezier ( pt, Count, &nOut );
198 if ( Pts )
199 {
200 ret = IntGdiPolyline(dc, Pts, nOut);
201 ExFreePool(Pts);
202 }
203 }
204
205 return ret;
206 }
207
208 BOOL FASTCALL
209 IntGdiPolyBezierTo(DC *dc,
210 LPPOINT pt,
211 DWORD Count)
212 {
213 BOOL ret = FALSE; // default to failure
214 PDC_ATTR Dc_Attr = dc->pDc_Attr;
215
216 if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
217 if ( PATH_IsPathOpen(dc->DcLevel) )
218 ret = PATH_PolyBezierTo ( dc, pt, Count );
219 else /* We'll do it using PolyBezier */
220 {
221 POINT *npt;
222 npt = ExAllocatePoolWithTag(PagedPool,
223 sizeof(POINT) * (Count + 1),
224 TAG_BEZIER);
225 if ( npt )
226 {
227 npt[0].x = Dc_Attr->ptlCurrent.x;
228 npt[0].y = Dc_Attr->ptlCurrent.y;
229 memcpy(npt + 1, pt, sizeof(POINT) * Count);
230 ret = IntGdiPolyBezier(dc, npt, Count+1);
231 ExFreePool(npt);
232 }
233 }
234 if ( ret )
235 {
236 Dc_Attr->ptlCurrent.x = pt[Count-1].x;
237 Dc_Attr->ptlCurrent.y = pt[Count-1].y;
238 Dc_Attr->ptfxCurrent = Dc_Attr->ptlCurrent;
239 CoordLPtoDP(dc, &Dc_Attr->ptfxCurrent); // Update fx
240 Dc_Attr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
241 }
242
243 return ret;
244 }
245
246 BOOL FASTCALL
247 IntGdiPolyline(DC *dc,
248 LPPOINT pt,
249 int Count)
250 {
251 BITMAPOBJ *BitmapObj;
252 GDIBRUSHOBJ *PenBrushObj;
253 GDIBRUSHINST PenBrushInst;
254 LPPOINT Points;
255 BOOL Ret = TRUE;
256 LONG i;
257 PDC_ATTR Dc_Attr = dc->pDc_Attr;
258
259 if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
260 if (PATH_IsPathOpen(dc->DcLevel))
261 return PATH_Polyline(dc, pt, Count);
262
263 /* Get BRUSHOBJ from current pen. */
264 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
265 /* FIXME - PenBrushObj can be NULL! Don't assert here! */
266 ASSERT(PenBrushObj);
267
268 if (!(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
269 {
270 Points = EngAllocMem(0, Count * sizeof(POINT), TAG_COORD);
271 if (Points != NULL)
272 {
273 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
274 /* FIXME - BitmapObj can be NULL!!!!
275 Don't assert but handle this case gracefully! */
276 ASSERT(BitmapObj);
277
278 RtlCopyMemory(Points, pt, Count * sizeof(POINT));
279 IntLPtoDP(dc, Points, Count);
280
281 /* Offset the array of point by the dc->w.DCOrg */
282 for (i = 0; i < Count; i++)
283 {
284 Points[i].x += dc->ptlDCOrig.x;
285 Points[i].y += dc->ptlDCOrig.y;
286 }
287
288 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
289 Ret = IntEngPolyline(&BitmapObj->SurfObj,
290 dc->CombinedClip,
291 &PenBrushInst.BrushObject,
292 Points,
293 Count,
294 ROP2_TO_MIX(Dc_Attr->jROP2));
295
296 BITMAPOBJ_UnlockBitmap(BitmapObj);
297 EngFreeMem(Points);
298 }
299 else
300 {
301 Ret = FALSE;
302 }
303 }
304
305 PENOBJ_UnlockPen(PenBrushObj);
306
307 return Ret;
308 }
309
310 BOOL FASTCALL
311 IntGdiPolylineTo(DC *dc,
312 LPPOINT pt,
313 DWORD Count)
314 {
315 BOOL ret = FALSE; // default to failure
316 PDC_ATTR Dc_Attr = dc->pDc_Attr;
317
318 if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
319 if (PATH_IsPathOpen(dc->DcLevel))
320 {
321 ret = PATH_PolylineTo(dc, pt, Count);
322 }
323 else /* do it using Polyline */
324 {
325 POINT *pts = ExAllocatePoolWithTag(PagedPool,
326 sizeof(POINT) * (Count + 1),
327 TAG_SHAPE);
328 if ( pts )
329 {
330 pts[0].x = Dc_Attr->ptlCurrent.x;
331 pts[0].y = Dc_Attr->ptlCurrent.y;
332 memcpy( pts + 1, pt, sizeof(POINT) * Count);
333 ret = IntGdiPolyline(dc, pts, Count + 1);
334 ExFreePool(pts);
335 }
336 }
337 if ( ret )
338 {
339 Dc_Attr->ptlCurrent.x = pt[Count-1].x;
340 Dc_Attr->ptlCurrent.y = pt[Count-1].y;
341 Dc_Attr->ptfxCurrent = Dc_Attr->ptlCurrent;
342 CoordLPtoDP(dc, &Dc_Attr->ptfxCurrent); // Update fx
343 Dc_Attr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
344 }
345
346 return ret;
347 }
348
349
350 BOOL FASTCALL
351 IntGdiPolyPolyline(DC *dc,
352 LPPOINT pt,
353 PULONG PolyPoints,
354 DWORD Count)
355 {
356 int i;
357 LPPOINT pts;
358 PULONG pc;
359 BOOL ret = FALSE; // default to failure
360 pts = pt;
361 pc = PolyPoints;
362
363 if (PATH_IsPathOpen(dc->DcLevel))
364 return PATH_PolyPolyline( dc, pt, PolyPoints, Count );
365
366 for (i = 0; i < Count; i++)
367 {
368 ret = IntGdiPolyline ( dc, pts, *pc );
369 if (ret == FALSE)
370 {
371 return ret;
372 }
373 pts+=*pc++;
374 }
375
376 return ret;
377 }
378
379 /******************************************************************************/
380
381 BOOL
382 STDCALL
383 NtGdiLineTo(HDC hDC,
384 int XEnd,
385 int YEnd)
386 {
387 DC *dc;
388 BOOL Ret;
389
390 dc = DC_LockDc(hDC);
391 if (!dc)
392 {
393 SetLastWin32Error(ERROR_INVALID_HANDLE);
394 return FALSE;
395 }
396 if (dc->DC_Type == DC_TYPE_INFO)
397 {
398 DC_UnlockDc(dc);
399 /* Yes, Windows really returns TRUE in this case */
400 return TRUE;
401 }
402
403 Ret = IntGdiLineTo(dc, XEnd, YEnd);
404
405 DC_UnlockDc(dc);
406 return Ret;
407 }
408
409 BOOL
410 APIENTRY
411 NtGdiPolyDraw(
412 IN HDC hdc,
413 IN LPPOINT lppt,
414 IN LPBYTE lpbTypes,
415 IN ULONG cCount)
416 {
417 PDC dc;
418 PPATH pPath;
419 BOOL result = FALSE;
420 POINT lastmove;
421 unsigned int i;
422 PDC_ATTR Dc_Attr = NULL;
423
424 dc = DC_LockDc(hdc);
425 if (!dc) return FALSE;
426 Dc_Attr = dc->pDc_Attr;
427 if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
428
429 _SEH_TRY
430 {
431 ProbeArrayForRead(lppt, sizeof(POINT), cCount, sizeof(LONG));
432 ProbeArrayForRead(lpbTypes, sizeof(BYTE), cCount, sizeof(BYTE));
433
434 /* check for each bezierto if there are two more points */
435 for ( i = 0; i < cCount; i++ )
436 {
437 if ( lpbTypes[i] != PT_MOVETO &&
438 lpbTypes[i] & PT_BEZIERTO )
439 {
440 if ( cCount < i+3 ) _SEH_LEAVE;
441 else i += 2;
442 }
443 }
444
445 /* if no moveto occurs, we will close the figure here */
446 lastmove.x = Dc_Attr->ptlCurrent.x;
447 lastmove.y = Dc_Attr->ptlCurrent.y;
448
449 /* now let's draw */
450 for ( i = 0; i < cCount; i++ )
451 {
452 if ( lpbTypes[i] == PT_MOVETO )
453 {
454 IntGdiMoveToEx( dc, lppt[i].x, lppt[i].y, NULL );
455 lastmove.x = Dc_Attr->ptlCurrent.x;
456 lastmove.y = Dc_Attr->ptlCurrent.y;
457 }
458 else if ( lpbTypes[i] & PT_LINETO )
459 IntGdiLineTo( dc, lppt[i].x, lppt[i].y );
460 else if ( lpbTypes[i] & PT_BEZIERTO )
461 {
462 POINT pts[4];
463 pts[0].x = Dc_Attr->ptlCurrent.x;
464 pts[0].y = Dc_Attr->ptlCurrent.y;
465 RtlCopyMemory(pts + 1, &lppt[i], sizeof(POINT) * 3);
466 IntGdiPolyBezier(dc, pts, 4);
467 i += 2;
468 }
469 else _SEH_LEAVE;
470
471 if ( lpbTypes[i] & PT_CLOSEFIGURE )
472 {
473 if ( PATH_IsPathOpen(dc->DcLevel) )
474 {
475 pPath = PATH_LockPath( dc->DcLevel.hPath );
476 if (pPath)
477 {
478 IntGdiCloseFigure( pPath );
479 PATH_UnlockPath( pPath );
480 }
481 }
482 else IntGdiLineTo( dc, lastmove.x, lastmove.y );
483 }
484 }
485
486 result = TRUE;
487 }
488 _SEH_HANDLE
489 {
490 SetLastNtError(_SEH_GetExceptionCode());
491 }
492 _SEH_END;
493
494 DC_UnlockDc(dc);
495
496 return result;
497 }
498
499
500 /* EOF */