0f6f39dad9b7aa86169ff3f697f89c33b486a492
[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: lineto.c,v 1.35 2004/07/14 20:48:57 navaraf Exp $
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 (deltax < 0)
385 {
386 xchange = -1;
387 deltax = - deltax;
388 hx = x2 + 1;
389 }
390 else
391 {
392 xchange = 1;
393 hx = x1;
394 }
395
396 if (deltay < 0)
397 {
398 ychange = -1;
399 deltay = - deltay;
400 vy = y2 + 1;
401 }
402 else
403 {
404 ychange = 1;
405 vy = y1;
406 }
407
408 if (y1 == y2)
409 {
410 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
411 do
412 {
413 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
414 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top + Translate.y <= y1; i++)
415 {
416 if (y1 < RectEnum.arcl[i].bottom + Translate.y &&
417 RectEnum.arcl[i].left + Translate.x <= hx + deltax &&
418 hx < RectEnum.arcl[i].right + Translate.x)
419 {
420 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_HLine(
421 OutputObj,
422 max(hx, RectEnum.arcl[i].left + Translate.x),
423 min(hx + deltax, RectEnum.arcl[i].right + Translate.x),
424 y1, Pixel);
425 }
426 }
427 }
428 while (EnumMore);
429 }
430 else if (x1 == x2)
431 {
432 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
433 do
434 {
435 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
436 for (i = 0; i < RectEnum.c; i++)
437 {
438 if (RectEnum.arcl[i].left + Translate.x <= x1 &&
439 x1 < RectEnum.arcl[i].right + Translate.x &&
440 RectEnum.arcl[i].top + Translate.y <= vy + deltay &&
441 vy < RectEnum.arcl[i].bottom + Translate.y)
442 {
443 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_VLine(
444 OutputObj, x1,
445 max(vy, RectEnum.arcl[i].top + Translate.y),
446 min(vy + deltay, RectEnum.arcl[i].bottom + Translate.y),
447 Pixel);
448 }
449 }
450 }
451 while (EnumMore);
452 }
453 else
454 {
455 if (0 < xchange)
456 {
457 if (0 < ychange)
458 {
459 NWtoSE(OutputObj, Clip, Brush, x, y, deltax, deltay, &Translate);
460 }
461 else
462 {
463 SWtoNE(OutputObj, Clip, Brush, x, y, deltax, deltay, &Translate);
464 }
465 }
466 else
467 {
468 if (0 < ychange)
469 {
470 NEtoSW(OutputObj, Clip, Brush, x, y, deltax, deltay, &Translate);
471 }
472 else
473 {
474 SEtoNW(OutputObj, Clip, Brush, x, y, deltax, deltay, &Translate);
475 }
476 }
477 }
478
479 return IntEngLeave(&EnterLeave);
480 }
481
482 BOOL STDCALL
483 IntEngLineTo(BITMAPOBJ *DestObj,
484 CLIPOBJ *Clip,
485 BRUSHOBJ *Brush,
486 LONG x1,
487 LONG y1,
488 LONG x2,
489 LONG y2,
490 RECTL *RectBounds,
491 MIX mix)
492 {
493 BOOLEAN ret;
494 SURFOBJ *DestSurf = &DestObj->SurfObj;
495 PGDIBRUSHINST GdiBrush;
496 RECTL b;
497
498 GdiBrush = CONTAINING_RECORD(
499 Brush,
500 GDIBRUSHINST,
501 BrushObject);
502
503 if (GdiBrush->GdiBrushObject->flAttrs & GDIBRUSH_IS_NULL)
504 return TRUE;
505
506 /* No success yet */
507 ret = FALSE;
508
509 b.left = min(x1, x2);
510 b.right = max(x1, x2);
511 b.top = min(y1, y2);
512 b.bottom = max(y1, y2);
513 if (b.left == b.right) b.right++;
514 if (b.top == b.bottom) b.bottom++;
515 MouseSafetyOnDrawStart(DestSurf, x1, y1, x2, y2);
516
517 if (DestObj->flHooks & HOOK_LINETO)
518 {
519 /* Call the driver's DrvLineTo */
520 ret = GDIDEVFUNCS(DestSurf).LineTo(
521 DestSurf, Clip, Brush, x1, y1, x2, y2, /*RectBounds*/&b, mix);
522 }
523
524 #if 0
525 if (! ret && (DestObj->flHooks & HOOK_STROKEPATH))
526 {
527 /* FIXME: Emulate LineTo using drivers DrvStrokePath and set ret on success */
528 }
529 #endif
530
531 if (! ret)
532 {
533 ret = EngLineTo(DestSurf, Clip, Brush, x1, y1, x2, y2, RectBounds, mix);
534 }
535
536 MouseSafetyOnDrawEnd(DestSurf);
537
538 return ret;
539 }
540
541 BOOL STDCALL
542 IntEngPolyline(BITMAPOBJ *DestObj,
543 CLIPOBJ *Clip,
544 BRUSHOBJ *Brush,
545 CONST LPPOINT pt,
546 LONG dCount,
547 MIX mix)
548 {
549 LONG i;
550 RECTL rect;
551 BOOL ret = FALSE;
552
553 //Draw the Polyline with a call to IntEngLineTo for each segment.
554 for (i = 1; i < dCount; i++)
555 {
556 rect.left = min(pt[i-1].x, pt[i].x);
557 rect.top = min(pt[i-1].y, pt[i].y);
558 rect.right = max(pt[i-1].x, pt[i].x);
559 rect.bottom = max(pt[i-1].y, pt[i].y);
560 ret = IntEngLineTo(DestObj,
561 Clip,
562 Brush,
563 pt[i-1].x,
564 pt[i-1].y,
565 pt[i].x,
566 pt[i].y,
567 &rect,
568 mix);
569 if (!ret)
570 {
571 break;
572 }
573 }
574
575 return ret;
576 }
577
578 /* EOF */