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