2 * DIBDRV implementation of GDI driver graphics functions
4 * Copyright 2009 Massimo Del Fedele
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dibdrv
);
28 static inline void OrderInt(int *i1
, int *i2
)
44 /* clips a line segment by a rectangular window */
45 static inline BYTE
outCodes(const POINT
*p
, const RECT
*r
)
51 else if(p
->y
>= r
->bottom
)
55 else if(p
->x
< r
->left
)
60 static BOOL
ClipLine(const POINT
*p1
, const POINT
*p2
, const RECT
*r
, POINT
*pc1
, POINT
*pc2
)
62 BYTE outCode1
,outCode2
;
66 pc1
->x
= p1
->x
; pc1
->y
= p1
->y
;
67 pc2
->x
= p2
->x
; pc2
->y
= p2
->y
;
70 outCode1
= outCodes(pc1
, r
);
71 outCode2
= outCodes(pc2
, r
);
72 if(outCode1
& outCode2
)
74 if(!outCode1
&& !outCode2
)
78 tmp
= pc1
->x
; pc1
->x
= pc2
->x
; pc2
->x
= tmp
;
79 tmp
= pc1
->y
; pc1
->y
= pc2
->y
; pc2
->y
= tmp
;
80 tmpCode
= outCode1
; outCode1
= outCode2
; outCode2
= tmpCode
;
82 if(outCode1
& TOP_SIDE
)
84 pc1
->x
+= MulDiv(pc2
->x
- pc1
->x
, r
->top
- pc1
->y
, pc2
->y
- pc1
->y
);
87 else if(outCode1
& BOTTOM_SIDE
)
89 pc1
->x
+= MulDiv(pc2
->x
- pc1
->x
, r
->bottom
- 1 - pc1
->y
, pc2
->y
- pc1
->y
);
90 pc1
->y
= r
->bottom
- 1;
92 else if(outCode1
& RIGHT_SIDE
)
94 pc1
->y
+= MulDiv(pc2
->y
- pc1
->y
, r
->right
- 1 - pc1
->x
, pc2
->x
- pc1
->x
);
95 pc1
->x
= r
->right
- 1;
97 else if(outCode1
& LEFT_SIDE
)
99 pc1
->y
+= MulDiv(pc2
->y
- pc1
->y
, r
->left
- pc1
->x
, pc2
->x
- pc1
->x
);
105 /* Clips a polygon by an horizontal/vertical line
106 which indicates the side :
108 static inline BOOL
PointInside(const POINT
*p
, const RECT
*r
, BYTE side
)
113 return p
->x
>= r
->left
;
115 return p
->y
>= r
->top
;
117 return p
->x
< r
->right
;
119 return p
->y
< r
->bottom
;
125 static inline void SideIntersect(const POINT
*p1
, const POINT
*p2
, const RECT
*r
, BYTE side
, POINT
*inters
)
129 case LEFT_SIDE
: /* left */
131 inters
->y
= MulDiv(p2
->y
- p1
->y
, r
->left
- p1
->x
, p2
->x
- p1
->x
) + p1
->y
;
133 case TOP_SIDE
: /* top */
134 inters
->x
= MulDiv(p2
->x
- p1
->x
, r
->top
- p1
->y
, p2
->y
- p1
->y
) + p1
->x
;
135 inters
->y
= r
->bottom
;
137 case RIGHT_SIDE
: /* right */
138 inters
->x
= r
->right
- 1;
139 inters
->y
= MulDiv(p2
->y
- p1
->y
, r
->right
- 1 - p1
->x
, p2
->x
- p1
->x
) + p1
->y
;
141 case BOTTOM_SIDE
: /* bottom */
142 inters
->x
= MulDiv(p2
->x
- p1
->x
, r
->bottom
- 1 - p1
->y
, p2
->y
- p1
->y
) + p1
->x
;
143 inters
->y
= r
->bottom
- 1;
151 static BOOL
ClipPolygonBySide(const POINT
*pt
, int count
, const RECT
*r
, BYTE side
, POINT
**clipped
, int *clippedCount
)
154 const POINT
*p1
, *p2
;
157 if(!(*clipped
= HeapAlloc(GetProcessHeap(), 0, sizeof(POINT
) * count
* 2)))
164 for(iPoint
= 0 ; iPoint
< count
; iPoint
++)
166 if(PointInside(p2
, r
, side
))
168 /* point p is "inside" */
169 if(!PointInside(p1
, r
, side
))
171 /* p is "inside" and s is "outside" */
172 SideIntersect(p2
, p1
, r
, side
, pOut
++);
180 else if(PointInside( p1
, r
, side
))
182 /* s is "inside" and p is "outside" */
183 SideIntersect(p1
, p2
, r
, side
, pOut
++);
188 return *clippedCount
;
192 /* Clips a polygon by a rectangular window - returns a new polygon */
193 static BOOL
ClipPolygon(const POINT
* pt
, int count
, const RECT
*r
, POINT
**newPt
, int *newCount
)
199 if(!ClipPolygonBySide(pt
, count
, r
, LEFT_SIDE
, &pc1
, &count1
))
201 res
= ClipPolygonBySide(pc1
, count1
, r
, TOP_SIDE
, &pc2
, &count2
);
202 HeapFree(GetProcessHeap(), 0, pc1
);
205 res
= ClipPolygonBySide(pc2
, count2
, r
, RIGHT_SIDE
, &pc1
, &count1
);
206 HeapFree(GetProcessHeap(), 0, pc2
);
209 res
= ClipPolygonBySide(pc1
, count1
, r
, BOTTOM_SIDE
, &pc2
, &count2
);
210 HeapFree(GetProcessHeap(), 0, pc1
);
219 /* Intersects a line given by 2 points with an horizontal scan line at height y */
220 static BOOL
ScanLine(const POINT
*p1
, const POINT
*p2
, int ys
, POINT
*pRes
)
225 /* if line lies completely over or under scan line, no intersection */
226 if((p1
->y
< ys
&& p2
->y
< ys
) || (p1
->y
>= ys
&& p2
->y
>= ys
))
229 /* if line is parallel to x axis, we consider it not intersecting */
233 pRes
->x
= MulDiv(p2
->x
- p1
->x
, ys
- p1
->y
, p2
->y
- p1
->y
) + p1
->x
;
238 /* Gets an x-ordered list of intersection points of a scanline at position y
239 with a polygon/polyline */
240 static BOOL
ScanPolygon(const POINT
*pt
, int count
, int ys
, POINT
**scans
, int *scanCount
)
242 const POINT
*p1
, *p2
;
248 /* if not at least 2 points, nothing to return */
252 /* intersections count is AT MOST 'count'; we don't care to
253 allocate exact memory needed */
254 *scans
= HeapAlloc(GetProcessHeap(), 0, sizeof(POINT
)*count
);
258 /* builds unordered intersections */
262 for(iPoint
= 0; iPoint
< count
-1; iPoint
++)
266 if(ScanLine(p1
, p2
, ys
, pDest
))
274 if(ScanLine(p1
, p2
, ys
, pDest
))
280 /* now we sort the list -- duped point are left into
281 as they're needed for the scanline fill algorithm */
282 for(i
= 0, ps1
= *scans
; i
< *scanCount
-1; i
++, ps1
++)
283 for(j
= i
+1, ps2
= ps1
+1; j
< *scanCount
; j
++, ps2
++)
297 /* gets bounding box of a polygon */
298 void PolygonBoundingBox(const POINT
*pt
, int count
, RECT
*bBox
)
303 bBox
->left
= MAXLONG
; bBox
->right
= -MAXLONG
;
304 bBox
->top
= MAXLONG
; bBox
->bottom
= -MAXLONG
;
305 for(p
= pt
, iPoint
= 0; iPoint
< count
; iPoint
++, p
++)
307 if(p
->x
< bBox
->left
) bBox
->left
= p
->x
;
308 if(p
->x
> bBox
->right
) bBox
->right
= p
->x
;
309 if(p
->y
< bBox
->top
) bBox
->top
= p
->y
;
310 if(p
->y
> bBox
->bottom
) bBox
->bottom
= p
->y
;
314 /***********************************************************************
317 BOOL
DIBDRV_Arc( DIBDRVPHYSDEV
*physDev
, int left
, int top
, int right
, int bottom
,
318 int xstart
, int ystart
, int xend
, int yend
)
322 MAYBE(TRACE("physDev:%p, left:%d, top:%d, right:%d, bottom:%d, xstart:%d, ystart:%d, xend:%d, yend:%d\n",
323 physDev
, left
, top
, right
, bottom
, xstart
, ystart
, xend
, yend
));
327 /* DIB section selected in, use DIB Engine */
328 ONCE(FIXME("STUB\n"));
333 /* DDB selected in, use X11 driver */
334 res
= _DIBDRV_GetDisplayDriver()->pArc(physDev
->X11PhysDev
, left
, top
, right
, bottom
,
335 xstart
, ystart
, xend
, yend
);
340 /***********************************************************************
343 BOOL
DIBDRV_Chord( DIBDRVPHYSDEV
*physDev
, int left
, int top
, int right
, int bottom
,
344 int xstart
, int ystart
, int xend
, int yend
)
348 MAYBE(TRACE("physDev:%p, left:%d, top:%d, right:%d, bottom:%d, xstart:%d, ystart:%d, xend:%d, yend:%d\n",
349 physDev
, left
, top
, right
, bottom
, xstart
, ystart
, xend
, yend
));
353 /* DIB section selected in, use DIB Engine */
354 ONCE(FIXME("STUB\n"));
359 /* DDB selected in, use X11 driver */
360 res
= _DIBDRV_GetDisplayDriver()->pChord(physDev
->X11PhysDev
, left
, top
, right
, bottom
,
361 xstart
, ystart
, xend
, yend
);
366 /***********************************************************************
369 BOOL
DIBDRV_Ellipse( DIBDRVPHYSDEV
*physDev
, int left
, int top
, int right
, int bottom
)
373 MAYBE(TRACE("physDev:%p, left:%d, top:%d, right:%d, bottom:%d\n",
374 physDev
, left
, top
, right
, bottom
));
378 /* DIB section selected in, use DIB Engine */
379 ONCE(FIXME("STUB\n"));
384 /* DDB selected in, use X11 driver */
385 res
= _DIBDRV_GetDisplayDriver()->pEllipse(physDev
->X11PhysDev
, left
, top
, right
, bottom
);
390 /**********************************************************************
391 * DIBDRV_ExtFloodFill
393 BOOL
DIBDRV_ExtFloodFill( DIBDRVPHYSDEV
*physDev
, int x
, int y
, COLORREF color
,
398 MAYBE(TRACE("physDev:%p, x:%d, y:%d, color:%x, fillType:%d\n",
399 physDev
, x
, y
, color
, fillType
));
403 /* DIB section selected in, use DIB Engine */
404 ONCE(FIXME("STUB\n"));
409 /* DDB selected in, use X11 driver */
410 res
= _DIBDRV_GetDisplayDriver()->pExtFloodFill(physDev
->X11PhysDev
, x
, y
, color
, fillType
);
415 /***********************************************************************
418 BOOL
DIBDRV_GetDCOrgEx( DIBDRVPHYSDEV
*physDev
, LPPOINT lpp
)
422 MAYBE(TRACE("physDev:%p, lpp:%p\n", physDev
, lpp
));
426 /* DIB section selected in, use DIB Engine */
427 ONCE(FIXME("STUB\n"));
432 /* DDB selected in, use X11 driver */
433 res
= _DIBDRV_GetDisplayDriver()->pGetDCOrgEx(physDev
->X11PhysDev
, lpp
);
438 /***********************************************************************
441 COLORREF
DIBDRV_GetPixel( DIBDRVPHYSDEV
*physDev
, int x
, int y
)
445 MAYBE(TRACE("physDev:%p, x:%d, y:%d\n", physDev
, x
, y
));
449 res
= physDev
->physBitmap
.funcs
->GetPixel(&physDev
->physBitmap
, x
, y
);
453 /* DDB selected in, use X11 driver */
454 res
= _DIBDRV_GetDisplayDriver()->pGetPixel(physDev
->X11PhysDev
, x
, y
);
459 /***********************************************************************
462 BOOL
DIBDRV_LineTo( DIBDRVPHYSDEV
*physDev
, int x
, int y
)
467 MAYBE(TRACE("physDev:%p, x:%d, y:%d\n", physDev
, x
, y
));
471 GetCurrentPositionEx(physDev
->hdc
, &curPos
);
473 _DIBDRV_ResetDashOrigin(physDev
);
476 physDev
->penHLine(physDev
, curPos
.x
, x
, y
);
477 else if(curPos
.x
== x
)
478 physDev
->penVLine(physDev
, x
, curPos
.y
, y
);
480 physDev
->penLine(physDev
, curPos
.x
, curPos
.y
, x
, y
);
485 /* DDB selected in, use X11 driver */
486 res
= _DIBDRV_GetDisplayDriver()->pLineTo(physDev
->X11PhysDev
, x
, y
);
491 /***********************************************************************
494 BOOL
DIBDRV_Rectangle( DIBDRVPHYSDEV
*physDev
, int left
, int top
, int right
, int bottom
);
495 BOOL
DIBDRV_PaintRgn( DIBDRVPHYSDEV
*physDev
, HRGN hrgn
)
503 MAYBE(TRACE("physDev:%p, hrgn:%p\n", physDev
, hrgn
));
507 /* gets needed region data size */
508 if(!(size
= GetRegionData(hrgn
, 0, NULL
)))
511 /* allocates buffer and gets actual region data */
512 if(!(data
= HeapAlloc(GetProcessHeap(), 0, size
)))
514 if(!GetRegionData(hrgn
, size
, data
))
516 HeapFree(GetProcessHeap(), 0, data
);
520 /* paints the filled rectangles */
521 rect
= (RECT
*)data
->Buffer
;
522 for(i
= 0; i
< data
->rdh
.nCount
; i
++)
524 DIBDRV_Rectangle( physDev
, rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
527 HeapFree( GetProcessHeap(), 0, data
);
534 /* DDB selected in, use X11 driver */
535 res
= _DIBDRV_GetDisplayDriver()->pPaintRgn(physDev
->X11PhysDev
, hrgn
);
540 /***********************************************************************
543 BOOL
DIBDRV_Pie( DIBDRVPHYSDEV
*physDev
, int left
, int top
, int right
, int bottom
,
544 int xstart
, int ystart
, int xend
, int yend
)
548 MAYBE(TRACE("physDev:%p, left:%d, top:%d, right:%d, bottom:%d, xstart:%d, ystart:%d, xend:%d, yend:%d\n",
549 physDev
, left
, top
, right
, bottom
, xstart
, ystart
, xend
, yend
));
553 /* DIB section selected in, use DIB Engine */
554 ONCE(FIXME("STUB\n"));
559 /* DDB selected in, use X11 driver */
560 res
= _DIBDRV_GetDisplayDriver()->pPie(physDev
->X11PhysDev
, left
, top
, right
, bottom
,
561 xstart
, ystart
, xend
, yend
);
566 /**********************************************************************
569 BOOL
DIBDRV_Polygon( DIBDRVPHYSDEV
*physDev
, const POINT
* ptw
, int count
)
580 int scanCount
, iScan
;
581 const POINT
*p1
, *p2
;
585 MAYBE(TRACE("physDev:%p, pt:%p, count:%d\n", physDev
, ptw
, count
));
589 /* DIB section selected in, use DIB Engine */
593 /* first converts all points to device coords */
594 if(!(pt
= HeapAlloc(GetProcessHeap(), 0, sizeof(POINT
) * count
)))
596 memcpy(pt
, ptw
, sizeof(POINT
) * count
);
597 LPtoDP(physDev
->hdc
, pt
, count
);
599 /* cycle on all current clipping rectangles */
600 r
= physDev
->regionRects
;
601 for(iRec
= 0; iRec
< physDev
->regionRectCount
; iRec
++, r
++)
604 if(ClipPolygon(pt
, count
, r
, &clipped
, &clippedCount
))
606 /* gets polygon bounding box -- for ytop and ybottom */
607 PolygonBoundingBox(clipped
, clippedCount
, &bBox
);
609 /* gets all ordered intersections of polygon with
611 for(ys
= bBox
.top
; ys
< bBox
.bottom
; ys
++)
613 if(ScanPolygon(clipped
, clippedCount
, ys
, &scans
, &scanCount
))
621 while(iScan
< scanCount
- 1)
623 physDev
->brushHLine(physDev
, p1
->x
, p2
->x
, ys
);
629 HeapFree(GetProcessHeap(), 0, scans
);
632 HeapFree(GetProcessHeap(), 0, clipped
);
635 /* perimeter -- don't use PolyLine for speed */
637 for(iPoint
= 0; iPoint
< count
-1; iPoint
++)
640 if(ClipLine(p1
, p2
, r
, &pc1
, &pc2
))
643 physDev
->penLine(physDev
, pc1
.x
, pc1
.y
, pc2
.x
, pc2
.y
);
648 if(ClipLine(p1
, p2
, r
, &pc1
, &pc2
))
651 physDev
->penLine(physDev
, pc1
.x
, pc1
.y
, pc2
.x
, pc2
.y
);
655 HeapFree(GetProcessHeap(), 0, pt
);
660 /* DDB selected in, use X11 driver */
661 res
= _DIBDRV_GetDisplayDriver()->pPolygon(physDev
->X11PhysDev
, ptw
, count
);
667 /**********************************************************************
670 BOOL
DIBDRV_Polyline( DIBDRVPHYSDEV
*physDev
, const POINT
* ptw
, int count
)
674 MAYBE(TRACE("physDev:%p, pt:%p, count:%d\n", physDev
, ptw
, count
));
678 /* DIB section selected in, use DIB Engine */
688 /* first converts all points to device coords */
689 if(!(pt
= HeapAlloc(GetProcessHeap(), 0, sizeof(POINT
) * count
)))
691 memcpy(pt
, ptw
, sizeof(POINT
) * count
);
692 LPtoDP(physDev
->hdc
, pt
, count
);
694 r
= physDev
->regionRects
;
695 for(iRec
= 0; iRec
< physDev
->regionRectCount
; iRec
++)
697 const POINT
*p2
= pt
, *p1
;
698 for(iPoint
= 0; iPoint
< count
-1; iPoint
++)
701 if(ClipLine(p1
, p2
, r
, &pc1
, &pc2
))
704 physDev
->penLine(physDev
, pc1
.x
, pc1
.y
, pc2
.x
, pc2
.y
);
710 HeapFree(GetProcessHeap(), 0, pt
);
716 /* DDB selected in, use X11 driver */
717 res
= _DIBDRV_GetDisplayDriver()->pPolyline(physDev
->X11PhysDev
, ptw
, count
);
722 /**********************************************************************
725 BOOL
DIBDRV_PolyPolygon( DIBDRVPHYSDEV
*physDev
, const POINT
* pt
, const int* counts
, UINT polygons
)
729 MAYBE(TRACE("physDev:%p, pt:%p, counts:%p, polygons:%d\n", physDev
, pt
, counts
, polygons
));
733 /* DIB section selected in, use DIB Engine */
734 ONCE(FIXME("STUB\n"));
739 /* DDB selected in, use X11 driver */
740 res
= _DIBDRV_GetDisplayDriver()->pPolyPolygon(physDev
->X11PhysDev
, pt
, counts
, polygons
);
745 /**********************************************************************
746 * DIBDRV_PolyPolyline
748 BOOL
DIBDRV_PolyPolyline( DIBDRVPHYSDEV
*physDev
, const POINT
* pt
, const DWORD
* counts
,
753 MAYBE(TRACE("physDev:%p, pt:%p, counts:%p, polylines:%d\n", physDev
, pt
, counts
, polylines
));
757 /* DIB section selected in, use DIB Engine */
758 ONCE(FIXME("STUB\n"));
763 /* DDB selected in, use X11 driver */
764 res
= _DIBDRV_GetDisplayDriver()->pPolyPolyline(physDev
->X11PhysDev
, pt
, counts
, polylines
);
769 /***********************************************************************
772 BOOL
DIBDRV_Rectangle( DIBDRVPHYSDEV
*physDev
, int x1
, int y1
, int x2
, int y2
)
776 DIBDRVBITMAP
*bmp
= &physDev
->physBitmap
;
778 MAYBE(TRACE("physDev:%p, left:%d, top:%d, right:%d, bottom:%d\n", physDev
, x1
, y1
, x2
, y2
));
785 /* temporary fix.... should be done by clipping */
790 if(x1
>= bmp
->width
) x1
= bmp
->width
- 1;
791 if(y1
>= bmp
->height
) y1
= bmp
->height
- 1;
792 if(x2
> bmp
->width
) x2
= bmp
->width
;
793 if(y2
> bmp
->height
) y2
= bmp
->height
;
794 if(x1
>= x2
|| y1
>= y2
)
797 _DIBDRV_ResetDashOrigin(physDev
);
799 /* particular case where the rectangle
800 degenerates to a line or a point */
803 physDev
->penVLine(physDev
, x1
, y1
, y2
);
806 else if (y1
>= y2
-1)
808 physDev
->penHLine(physDev
, x1
, x2
, y1
);
812 /* Draw the perimeter */
813 physDev
->penHLine(physDev
, x1
, x2
, y1
);
814 physDev
->penHLine(physDev
, x1
, x2
, y2
- 1);
815 physDev
->penVLine(physDev
, x1
, y1
+ 1, y2
- 1);
816 physDev
->penVLine(physDev
, x2
- 1, y1
+ 1, y2
- 1);
818 /* fill the inside */
820 for (i
= y1
+ 1; i
< y2
- 1; i
++)
821 physDev
->brushHLine(physDev
, x1
+ 1, x2
- 1, i
);
829 /* DDB selected in, use X11 driver */
830 res
= _DIBDRV_GetDisplayDriver()->pRectangle(physDev
->X11PhysDev
, x1
, y1
, x2
, y2
);
835 /***********************************************************************
838 BOOL
DIBDRV_RoundRect( DIBDRVPHYSDEV
*physDev
, int left
, int top
, int right
,
839 int bottom
, int ell_width
, int ell_height
)
843 MAYBE(TRACE("physDev:%p, left:%d, top:%d, right:%d, bottom:%d, ell_width:%d, ell_height:%d\n",
844 physDev
, left
, top
, right
, bottom
, ell_width
, ell_height
));
848 /* DIB section selected in, use DIB Engine */
849 ONCE(FIXME("STUB\n"));
854 /* DDB selected in, use X11 driver */
855 res
= _DIBDRV_GetDisplayDriver()->pRoundRect(physDev
->X11PhysDev
, left
, top
, right
, bottom
,
856 ell_width
, ell_height
);
861 /***********************************************************************
864 COLORREF
DIBDRV_SetPixel( DIBDRVPHYSDEV
*physDev
, int x
, int y
, COLORREF color
)
869 MAYBE(TRACE("physDev:%p, x:%d, y:%d, color:%x\n", physDev
, x
, y
, color
));
873 /* gets previous pixel */
874 res
= physDev
->physBitmap
.funcs
->GetPixel(&physDev
->physBitmap
, x
, y
);
876 /* calculates AND and XOR from color */
877 _DIBDRV_CalcAndXorMasks(GetROP2(physDev
->hdc
), color
, &and, &xor);
880 physDev
->physBitmap
.funcs
->SetPixel(&physDev
->physBitmap
, x
, y
, and, xor);
884 /* DDB selected in, use X11 driver */
885 res
= _DIBDRV_GetDisplayDriver()->pSetPixel(physDev
->X11PhysDev
, x
, y
, color
);
890 /***********************************************************************
893 DWORD
DIBDRV_SetDCOrg( DIBDRVPHYSDEV
*physDev
, int x
, int y
)
897 MAYBE(TRACE("physDev:%p, x:%d, y:%d\n", physDev
, x
, y
));
901 /* DIB section selected in, use DIB Engine */
902 ONCE(FIXME("STUB\n"));
907 /* DDB selected in, use X11 driver */
908 res
= _DIBDRV_GetDisplayDriver()->pSetDCOrg(physDev
->X11PhysDev
, x
, y
);