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