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