Sync trunk r40500
[reactos.git] / reactos / subsystems / win32 / win32k / eng / lineto.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 * $Id$
20 */
21
22 #include <w32k.h>
23
24 #define NDEBUG
25 #include <debug.h>
26
27 static void FASTCALL
28 TranslateRects(RECT_ENUM *RectEnum, POINTL* Translate)
29 {
30 RECTL* CurrentRect;
31
32 if (0 != Translate->x || 0 != Translate->y)
33 {
34 for (CurrentRect = RectEnum->arcl; CurrentRect < RectEnum->arcl + RectEnum->c; CurrentRect++)
35 {
36 CurrentRect->left += Translate->x;
37 CurrentRect->right += Translate->x;
38 CurrentRect->top += Translate->y;
39 CurrentRect->bottom += Translate->y;
40 }
41 }
42 }
43
44 /*
45 * Draw a line from top-left to bottom-right
46 */
47 void FASTCALL
48 NWtoSE(SURFOBJ* OutputObj, CLIPOBJ* Clip,
49 BRUSHOBJ* pbo, LONG x, LONG y, LONG deltax, LONG deltay,
50 POINTL* Translate)
51 {
52 int i;
53 int error;
54 BOOLEAN EnumMore;
55 RECTL* ClipRect;
56 RECT_ENUM RectEnum;
57 ULONG Pixel = pbo->iSolidColor;
58 LONG delta;
59
60 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
61 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
62 TranslateRects(&RectEnum, Translate);
63 ClipRect = RectEnum.arcl;
64 delta = max(deltax, deltay);
65 i = 0;
66 error = delta >> 1;
67 while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
68 {
69 while ((ClipRect < RectEnum.arcl + RectEnum.c /* there's still a current clip rect */
70 && (ClipRect->bottom <= y /* but it's above us */
71 || (ClipRect->top <= y && ClipRect->right <= x))) /* or to the left of us */
72 || EnumMore) /* no current clip rect, but rects left */
73 {
74 /* Skip to the next clip rect */
75 if (RectEnum.arcl + RectEnum.c <= ClipRect)
76 {
77 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
78 TranslateRects(&RectEnum, Translate);
79 ClipRect = RectEnum.arcl;
80 }
81 else
82 {
83 ClipRect++;
84 }
85 }
86 if (ClipRect < RectEnum.arcl + RectEnum.c) /* If there's no current clip rect we're done */
87 {
88 if (ClipRect->left <= x && ClipRect->top <= y)
89 {
90 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_PutPixel(
91 OutputObj, x, y, Pixel);
92 }
93 if (deltax < deltay)
94 {
95 y++;
96 error = error + deltax;
97 if (deltay <= error)
98 {
99 x++;
100 error = error - deltay;
101 }
102 }
103 else
104 {
105 x++;
106 error = error + deltay;
107 if (deltax <= error)
108 {
109 y++;
110 error = error - deltax;
111 }
112 }
113 i++;
114 }
115 }
116 }
117
118 void FASTCALL
119 SWtoNE(SURFOBJ* OutputObj, CLIPOBJ* Clip,
120 BRUSHOBJ* pbo, LONG x, LONG y, LONG deltax, LONG deltay,
121 POINTL* Translate)
122 {
123 int i;
124 int error;
125 BOOLEAN EnumMore;
126 RECTL* ClipRect;
127 RECT_ENUM RectEnum;
128 ULONG Pixel = pbo->iSolidColor;
129 LONG delta;
130
131 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTUP, 0);
132 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
133 TranslateRects(&RectEnum, Translate);
134 ClipRect = RectEnum.arcl;
135 delta = max(deltax, deltay);
136 i = 0;
137 error = delta >> 1;
138 while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
139 {
140 while ((ClipRect < RectEnum.arcl + RectEnum.c
141 && (y < ClipRect->top
142 || (y < ClipRect->bottom && ClipRect->right <= x)))
143 || EnumMore)
144 {
145 if (RectEnum.arcl + RectEnum.c <= ClipRect)
146 {
147 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
148 TranslateRects(&RectEnum, Translate);
149 ClipRect = RectEnum.arcl;
150 }
151 else
152 {
153 ClipRect++;
154 }
155 }
156 if (ClipRect < RectEnum.arcl + RectEnum.c)
157 {
158 if (ClipRect->left <= x && y < ClipRect->bottom)
159 {
160 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_PutPixel(
161 OutputObj, x, y, Pixel);
162 }
163 if (deltax < deltay)
164 {
165 y--;
166 error = error + deltax;
167 if (deltay <= error)
168 {
169 x++;
170 error = error - deltay;
171 }
172 }
173 else
174 {
175 x++;
176 error = error + deltay;
177 if (deltax <= error)
178 {
179 y--;
180 error = error - deltax;
181 }
182 }
183 i++;
184 }
185 }
186 }
187
188 void FASTCALL
189 NEtoSW(SURFOBJ* OutputObj, CLIPOBJ* Clip,
190 BRUSHOBJ* pbo, LONG x, LONG y, LONG deltax, LONG deltay,
191 POINTL* Translate)
192 {
193 int i;
194 int error;
195 BOOLEAN EnumMore;
196 RECTL* ClipRect;
197 RECT_ENUM RectEnum;
198 ULONG Pixel = pbo->iSolidColor;
199 LONG delta;
200
201 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_LEFTDOWN, 0);
202 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
203 TranslateRects(&RectEnum, Translate);
204 ClipRect = RectEnum.arcl;
205 delta = max(deltax, deltay);
206 i = 0;
207 error = delta >> 1;
208 while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
209 {
210 while ((ClipRect < RectEnum.arcl + RectEnum.c
211 && (ClipRect->bottom <= y
212 || (ClipRect->top <= y && x < ClipRect->left)))
213 || EnumMore)
214 {
215 if (RectEnum.arcl + RectEnum.c <= ClipRect)
216 {
217 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
218 TranslateRects(&RectEnum, Translate);
219 ClipRect = RectEnum.arcl;
220 }
221 else
222 {
223 ClipRect++;
224 }
225 }
226 if (ClipRect < RectEnum.arcl + RectEnum.c)
227 {
228 if (x < ClipRect->right && ClipRect->top <= y)
229 {
230 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_PutPixel(
231 OutputObj, x, y, Pixel);
232 }
233 if (deltax < deltay)
234 {
235 y++;
236 error = error + deltax;
237 if (deltay <= error)
238 {
239 x--;
240 error = error - deltay;
241 }
242 }
243 else
244 {
245 x--;
246 error = error + deltay;
247 if (deltax <= error)
248 {
249 y++;
250 error = error - deltax;
251 }
252 }
253 i++;
254 }
255 }
256 }
257
258 void FASTCALL
259 SEtoNW(SURFOBJ* OutputObj, CLIPOBJ* Clip,
260 BRUSHOBJ* pbo, LONG x, LONG y, LONG deltax, LONG deltay,
261 POINTL* Translate)
262 {
263 int i;
264 int error;
265 BOOLEAN EnumMore;
266 RECTL* ClipRect;
267 RECT_ENUM RectEnum;
268 ULONG Pixel = pbo->iSolidColor;
269 LONG delta;
270
271 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_LEFTUP, 0);
272 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
273 TranslateRects(&RectEnum, Translate);
274 ClipRect = RectEnum.arcl;
275 delta = max(deltax, deltay);
276 i = 0;
277 error = delta >> 1;
278 while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
279 {
280 while ((ClipRect < RectEnum.arcl + RectEnum.c
281 && (y < ClipRect->top
282 || (y < ClipRect->bottom && x < ClipRect->left)))
283 || EnumMore)
284 {
285 if (RectEnum.arcl + RectEnum.c <= ClipRect)
286 {
287 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
288 TranslateRects(&RectEnum, Translate);
289 ClipRect = RectEnum.arcl;
290 }
291 else
292 {
293 ClipRect++;
294 }
295 }
296 if (ClipRect < RectEnum.arcl + RectEnum.c)
297 {
298 if (x < ClipRect->right && y < ClipRect->bottom)
299 {
300 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_PutPixel(
301 OutputObj, x, y, Pixel);
302 }
303 if (deltax < deltay)
304 {
305 y--;
306 error = error + deltax;
307 if (deltay <= error)
308 {
309 x--;
310 error = error - deltay;
311 }
312 }
313 else
314 {
315 x--;
316 error = error + deltay;
317 if (deltax <= error)
318 {
319 y--;
320 error = error - deltax;
321 }
322 }
323 i++;
324 }
325 }
326 }
327
328 /*
329 * @implemented
330 */
331 BOOL APIENTRY
332 EngLineTo(SURFOBJ *DestObj,
333 CLIPOBJ *Clip,
334 BRUSHOBJ *pbo,
335 LONG x1,
336 LONG y1,
337 LONG x2,
338 LONG y2,
339 RECTL *RectBounds,
340 MIX mix)
341 {
342 LONG x, y, deltax, deltay, xchange, ychange, hx, vy;
343 ULONG i;
344 ULONG Pixel = pbo->iSolidColor;
345 SURFOBJ *OutputObj;
346 RECTL DestRect;
347 POINTL Translate;
348 INTENG_ENTER_LEAVE EnterLeave;
349 RECT_ENUM RectEnum;
350 BOOL EnumMore;
351 CLIPOBJ *pcoPriv = NULL;
352
353 if (x1 < x2)
354 {
355 DestRect.left = x1;
356 DestRect.right = x2;
357 }
358 else
359 {
360 DestRect.left = x2;
361 DestRect.right = x1 + 1;
362 }
363 if (y1 < y2)
364 {
365 DestRect.top = y1;
366 DestRect.bottom = y2;
367 }
368 else
369 {
370 DestRect.top = y2;
371 DestRect.bottom = y1 + 1;
372 }
373
374 if (! IntEngEnter(&EnterLeave, DestObj, &DestRect, FALSE, &Translate, &OutputObj))
375 {
376 return FALSE;
377 }
378
379 if (!Clip)
380 {
381 Clip = pcoPriv = IntEngCreateClipRegion(0, 0, RectBounds);
382 if (!Clip)
383 {
384 return FALSE;
385 }
386 }
387
388 x1 += Translate.x;
389 x2 += Translate.x;
390 y1 += Translate.y;
391 y2 += Translate.y;
392
393 x = x1;
394 y = y1;
395 deltax = x2 - x1;
396 deltay = y2 - y1;
397
398 if (0 == deltax && 0 == deltay)
399 {
400 return TRUE;
401 }
402
403 if (deltax < 0)
404 {
405 xchange = -1;
406 deltax = - deltax;
407 hx = x2 + 1;
408 }
409 else
410 {
411 xchange = 1;
412 hx = x1;
413 }
414
415 if (deltay < 0)
416 {
417 ychange = -1;
418 deltay = - deltay;
419 vy = y2 + 1;
420 }
421 else
422 {
423 ychange = 1;
424 vy = y1;
425 }
426
427 if (y1 == y2)
428 {
429 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
430 do
431 {
432 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
433 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top + Translate.y <= y1; i++)
434 {
435 if (y1 < RectEnum.arcl[i].bottom + Translate.y &&
436 RectEnum.arcl[i].left + Translate.x <= hx + deltax &&
437 hx < RectEnum.arcl[i].right + Translate.x &&
438 max(hx, RectEnum.arcl[i].left + Translate.x) <
439 min(hx + deltax, RectEnum.arcl[i].right + Translate.x))
440 {
441 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_HLine(
442 OutputObj,
443 max(hx, RectEnum.arcl[i].left + Translate.x),
444 min(hx + deltax, RectEnum.arcl[i].right + Translate.x),
445 y1, Pixel);
446 }
447 }
448 }
449 while (EnumMore);
450 }
451 else if (x1 == x2)
452 {
453 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
454 do
455 {
456 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
457 for (i = 0; i < RectEnum.c; i++)
458 {
459 if (RectEnum.arcl[i].left + Translate.x <= x1 &&
460 x1 < RectEnum.arcl[i].right + Translate.x &&
461 RectEnum.arcl[i].top + Translate.y <= vy + deltay &&
462 vy < RectEnum.arcl[i].bottom + Translate.y)
463 {
464 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_VLine(
465 OutputObj, x1,
466 max(vy, RectEnum.arcl[i].top + Translate.y),
467 min(vy + deltay, RectEnum.arcl[i].bottom + Translate.y),
468 Pixel);
469 }
470 }
471 }
472 while (EnumMore);
473 }
474 else
475 {
476 if (0 < xchange)
477 {
478 if (0 < ychange)
479 {
480 NWtoSE(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate);
481 }
482 else
483 {
484 SWtoNE(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate);
485 }
486 }
487 else
488 {
489 if (0 < ychange)
490 {
491 NEtoSW(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate);
492 }
493 else
494 {
495 SEtoNW(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate);
496 }
497 }
498 }
499
500 if (pcoPriv)
501 {
502 IntEngDeleteClipRegion(pcoPriv);
503 }
504
505 return IntEngLeave(&EnterLeave);
506 }
507
508 BOOL APIENTRY
509 IntEngLineTo(SURFOBJ *psoDest,
510 CLIPOBJ *ClipObj,
511 BRUSHOBJ *pbo,
512 LONG x1,
513 LONG y1,
514 LONG x2,
515 LONG y2,
516 RECTL *RectBounds,
517 MIX Mix)
518 {
519 BOOLEAN ret;
520 SURFACE *psurfDest;
521 PEBRUSHOBJ GdiBrush;
522 RECTL b;
523
524 ASSERT(psoDest);
525 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
526 ASSERT(psurfDest);
527
528 GdiBrush = CONTAINING_RECORD(
529 pbo,
530 EBRUSHOBJ,
531 BrushObject);
532 ASSERT(GdiBrush);
533 ASSERT(GdiBrush->pbrush);
534
535 if (GdiBrush->pbrush->flAttrs & GDIBRUSH_IS_NULL)
536 return TRUE;
537
538 /* No success yet */
539 ret = FALSE;
540
541 /* Clip lines totally outside the clip region. This is not done as an
542 * optimization (there are very few lines drawn outside the region) but
543 * as a workaround for what seems to be a problem in the CL54XX driver */
544 if (NULL == ClipObj || DC_TRIVIAL == ClipObj->iDComplexity)
545 {
546 b.left = 0;
547 b.right = psoDest->sizlBitmap.cx;
548 b.top = 0;
549 b.bottom = psoDest->sizlBitmap.cy;
550 }
551 else
552 {
553 b = ClipObj->rclBounds;
554 }
555 if ((x1 < b.left && x2 < b.left) || (b.right <= x1 && b.right <= x2) ||
556 (y1 < b.top && y2 < b.top) || (b.bottom <= y1 && b.bottom <= y2))
557 {
558 return TRUE;
559 }
560
561 b.left = min(x1, x2);
562 b.right = max(x1, x2);
563 b.top = min(y1, y2);
564 b.bottom = max(y1, y2);
565 if (b.left == b.right) b.right++;
566 if (b.top == b.bottom) b.bottom++;
567
568 SURFACE_LockBitmapBits(psurfDest);
569 MouseSafetyOnDrawStart(psoDest, x1, y1, x2, y2);
570
571 if (psurfDest->flHooks & HOOK_LINETO)
572 {
573 /* Call the driver's DrvLineTo */
574 ret = GDIDEVFUNCS(psoDest).LineTo(
575 psoDest, ClipObj, pbo, x1, y1, x2, y2, &b, Mix);
576 }
577
578 #if 0
579 if (! ret && (psurfDest->flHooks & HOOK_STROKEPATH))
580 {
581 /* FIXME: Emulate LineTo using drivers DrvStrokePath and set ret on success */
582 }
583 #endif
584
585 if (! ret)
586 {
587 ret = EngLineTo(psoDest, ClipObj, pbo, x1, y1, x2, y2, RectBounds, Mix);
588 }
589
590 MouseSafetyOnDrawEnd(psoDest);
591 SURFACE_UnlockBitmapBits(psurfDest);
592
593 return ret;
594 }
595
596 BOOL APIENTRY
597 IntEngPolyline(SURFOBJ *psoDest,
598 CLIPOBJ *Clip,
599 BRUSHOBJ *pbo,
600 CONST LPPOINT pt,
601 LONG dCount,
602 MIX Mix)
603 {
604 LONG i;
605 RECTL rect;
606 BOOL ret = FALSE;
607
608 //Draw the Polyline with a call to IntEngLineTo for each segment.
609 for (i = 1; i < dCount; i++)
610 {
611 rect.left = min(pt[i-1].x, pt[i].x);
612 rect.top = min(pt[i-1].y, pt[i].y);
613 rect.right = max(pt[i-1].x, pt[i].x);
614 rect.bottom = max(pt[i-1].y, pt[i].y);
615 ret = IntEngLineTo(psoDest,
616 Clip,
617 pbo,
618 pt[i-1].x,
619 pt[i-1].y,
620 pt[i].x,
621 pt[i].y,
622 &rect,
623 Mix);
624 if (!ret)
625 {
626 break;
627 }
628 }
629
630 return ret;
631 }
632
633 /* EOF */