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