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