[WIN32K]
[reactos.git] / reactos / win32ss / gdi / 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(
320 _Inout_ SURFOBJ *DestObj,
321 _In_ CLIPOBJ *Clip,
322 _In_ BRUSHOBJ *pbo,
323 _In_ LONG x1,
324 _In_ LONG y1,
325 _In_ LONG x2,
326 _In_ LONG y2,
327 _In_opt_ RECTL *RectBounds,
328 _In_ MIX mix)
329 {
330 LONG x, y, deltax, deltay, xchange, ychange, hx, vy;
331 ULONG i;
332 ULONG Pixel = pbo->iSolidColor;
333 SURFOBJ *OutputObj;
334 RECTL DestRect;
335 POINTL Translate;
336 INTENG_ENTER_LEAVE EnterLeave;
337 RECT_ENUM RectEnum;
338 BOOL EnumMore;
339 CLIPOBJ *pcoPriv = NULL;
340
341 if (x1 < x2)
342 {
343 DestRect.left = x1;
344 DestRect.right = x2;
345 }
346 else
347 {
348 DestRect.left = x2;
349 DestRect.right = x1 + 1;
350 }
351 if (y1 < y2)
352 {
353 DestRect.top = y1;
354 DestRect.bottom = y2;
355 }
356 else
357 {
358 DestRect.top = y2;
359 DestRect.bottom = y1 + 1;
360 }
361
362 if (! IntEngEnter(&EnterLeave, DestObj, &DestRect, FALSE, &Translate, &OutputObj))
363 {
364 return FALSE;
365 }
366
367 if (!Clip)
368 {
369 Clip = pcoPriv = IntEngCreateClipRegion(0, 0, RectBounds);
370 if (!Clip)
371 {
372 return FALSE;
373 }
374 }
375
376 x1 += Translate.x;
377 x2 += Translate.x;
378 y1 += Translate.y;
379 y2 += Translate.y;
380
381 x = x1;
382 y = y1;
383 deltax = x2 - x1;
384 deltay = y2 - y1;
385
386 if (0 == deltax && 0 == deltay)
387 {
388 return TRUE;
389 }
390
391 if (deltax < 0)
392 {
393 xchange = -1;
394 deltax = - deltax;
395 hx = x2 + 1;
396 }
397 else
398 {
399 xchange = 1;
400 hx = x1;
401 }
402
403 if (deltay < 0)
404 {
405 ychange = -1;
406 deltay = - deltay;
407 vy = y2 + 1;
408 }
409 else
410 {
411 ychange = 1;
412 vy = y1;
413 }
414
415 if (y1 == y2)
416 {
417 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
418 do
419 {
420 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
421 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top + Translate.y <= y1; i++)
422 {
423 if (y1 < RectEnum.arcl[i].bottom + Translate.y &&
424 RectEnum.arcl[i].left + Translate.x <= hx + deltax &&
425 hx < RectEnum.arcl[i].right + Translate.x &&
426 max(hx, RectEnum.arcl[i].left + Translate.x) <
427 min(hx + deltax, RectEnum.arcl[i].right + Translate.x))
428 {
429 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_HLine(
430 OutputObj,
431 max(hx, RectEnum.arcl[i].left + Translate.x),
432 min(hx + deltax, RectEnum.arcl[i].right + Translate.x),
433 y1, Pixel);
434 }
435 }
436 }
437 while (EnumMore);
438 }
439 else if (x1 == x2)
440 {
441 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
442 do
443 {
444 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
445 for (i = 0; i < RectEnum.c; i++)
446 {
447 if (RectEnum.arcl[i].left + Translate.x <= x1 &&
448 x1 < RectEnum.arcl[i].right + Translate.x &&
449 RectEnum.arcl[i].top + Translate.y <= vy + deltay &&
450 vy < RectEnum.arcl[i].bottom + Translate.y)
451 {
452 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_VLine(
453 OutputObj, x1,
454 max(vy, RectEnum.arcl[i].top + Translate.y),
455 min(vy + deltay, RectEnum.arcl[i].bottom + Translate.y),
456 Pixel);
457 }
458 }
459 }
460 while (EnumMore);
461 }
462 else
463 {
464 if (0 < xchange)
465 {
466 if (0 < ychange)
467 {
468 NWtoSE(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate);
469 }
470 else
471 {
472 SWtoNE(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate);
473 }
474 }
475 else
476 {
477 if (0 < ychange)
478 {
479 NEtoSW(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate);
480 }
481 else
482 {
483 SEtoNW(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate);
484 }
485 }
486 }
487
488 if (pcoPriv)
489 {
490 IntEngDeleteClipRegion(pcoPriv);
491 }
492
493 return IntEngLeave(&EnterLeave);
494 }
495
496 BOOL APIENTRY
497 IntEngLineTo(SURFOBJ *psoDest,
498 CLIPOBJ *ClipObj,
499 BRUSHOBJ *pbo,
500 LONG x1,
501 LONG y1,
502 LONG x2,
503 LONG y2,
504 RECTL *RectBounds,
505 MIX Mix)
506 {
507 BOOLEAN ret;
508 SURFACE *psurfDest;
509 PEBRUSHOBJ GdiBrush;
510 RECTL b;
511
512 ASSERT(psoDest);
513 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
514 ASSERT(psurfDest);
515
516 GdiBrush = CONTAINING_RECORD(
517 pbo,
518 EBRUSHOBJ,
519 BrushObject);
520 ASSERT(GdiBrush);
521 ASSERT(GdiBrush->pbrush);
522
523 if (GdiBrush->pbrush->flAttrs & BR_IS_NULL)
524 return TRUE;
525
526 /* No success yet */
527 ret = FALSE;
528
529 /* Clip lines totally outside the clip region. This is not done as an
530 * optimization (there are very few lines drawn outside the region) but
531 * as a workaround for what seems to be a problem in the CL54XX driver */
532 if (NULL == ClipObj || DC_TRIVIAL == ClipObj->iDComplexity)
533 {
534 b.left = 0;
535 b.right = psoDest->sizlBitmap.cx;
536 b.top = 0;
537 b.bottom = psoDest->sizlBitmap.cy;
538 }
539 else
540 {
541 b = ClipObj->rclBounds;
542 }
543 if ((x1 < b.left && x2 < b.left) || (b.right <= x1 && b.right <= x2) ||
544 (y1 < b.top && y2 < b.top) || (b.bottom <= y1 && b.bottom <= y2))
545 {
546 return TRUE;
547 }
548
549 b.left = min(x1, x2);
550 b.right = max(x1, x2);
551 b.top = min(y1, y2);
552 b.bottom = max(y1, y2);
553 if (b.left == b.right) b.right++;
554 if (b.top == b.bottom) b.bottom++;
555
556 if (psurfDest->flags & HOOK_LINETO)
557 {
558 /* Call the driver's DrvLineTo */
559 ret = GDIDEVFUNCS(psoDest).LineTo(
560 psoDest, ClipObj, pbo, x1, y1, x2, y2, &b, Mix);
561 }
562
563 #if 0
564 if (! ret && (psurfDest->flags & HOOK_STROKEPATH))
565 {
566 /* FIXME: Emulate LineTo using drivers DrvStrokePath and set ret on success */
567 }
568 #endif
569
570 if (! ret)
571 {
572 ret = EngLineTo(psoDest, ClipObj, pbo, x1, y1, x2, y2, RectBounds, Mix);
573 }
574
575 return ret;
576 }
577
578 BOOL APIENTRY
579 IntEngPolyline(SURFOBJ *psoDest,
580 CLIPOBJ *Clip,
581 BRUSHOBJ *pbo,
582 CONST LPPOINT pt,
583 LONG dCount,
584 MIX Mix)
585 {
586 LONG i;
587 RECTL rect;
588 BOOL ret = FALSE;
589
590 // Draw the Polyline with a call to IntEngLineTo for each segment.
591 for (i = 1; i < dCount; i++)
592 {
593 rect.left = min(pt[i-1].x, pt[i].x);
594 rect.top = min(pt[i-1].y, pt[i].y);
595 rect.right = max(pt[i-1].x, pt[i].x);
596 rect.bottom = max(pt[i-1].y, pt[i].y);
597 ret = IntEngLineTo(psoDest,
598 Clip,
599 pbo,
600 pt[i-1].x,
601 pt[i-1].y,
602 pt[i].x,
603 pt[i].y,
604 &rect,
605 Mix);
606 if (!ret)
607 {
608 break;
609 }
610 }
611
612 return ret;
613 }
614
615 /* EOF */