1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <stdio.h>
32 #include <string.h>
33 
34 #include <tools/svwin.h>
35 #include <tools/debug.hxx>
36 
37 #include <win/wincomp.hxx>
38 #include <win/saldata.hxx>
39 #include <win/salgdi.h>
40 
41 #ifndef min
42 #define min(a,b)	(((a) < (b)) ? (a) : (b))
43 #endif
44 #ifndef max
45 #define max(a,b)	(((a) > (b)) ? (a) : (b))
46 #endif
47 
48 #if defined _MSC_VER
49 #pragma warning(push, 1)
50 #endif
51 
52 #include <GdiPlus.h>
53 #include <GdiPlusEnums.h>
54 #include <GdiPlusColor.h>
55 
56 #if defined _MSC_VER
57 #pragma warning(pop)
58 #endif
59 
60 #include <basegfx/polygon/b2dpolygon.hxx>
61 
62 // -----------------------------------------------------------------------
63 
64 void impAddB2DPolygonToGDIPlusGraphicsPathReal(Gdiplus::GraphicsPath& rPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin)
65 {
66     sal_uInt32 nCount(rPolygon.count());
67 
68     if(nCount)
69     {
70         const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1);
71         const bool bControls(rPolygon.areControlPointsUsed());
72         basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0));
73         Gdiplus::PointF aFCurr(Gdiplus::REAL(aCurr.getX()), Gdiplus::REAL(aCurr.getY()));
74 
75         for(sal_uInt32 a(0); a < nEdgeCount; a++)
76         {
77 	        const sal_uInt32 nNextIndex((a + 1) % nCount);
78 	        const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex));
79 	        const Gdiplus::PointF aFNext(Gdiplus::REAL(aNext.getX()), Gdiplus::REAL(aNext.getY()));
80 
81 	        if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex)))
82 	        {
83 		        const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a));
84 		        const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex));
85 
86 		        rPath.AddBezier(
87 			        aFCurr,
88 			        Gdiplus::PointF(Gdiplus::REAL(aCa.getX()), Gdiplus::REAL(aCa.getY())),
89 			        Gdiplus::PointF(Gdiplus::REAL(aCb.getX()), Gdiplus::REAL(aCb.getY())),
90 			        aFNext);
91 	        }
92 	        else
93 	        {
94 		        rPath.AddLine(aFCurr, aFNext);
95 	        }
96 
97 	        if(a + 1 < nEdgeCount)
98 	        {
99 		        aFCurr = aFNext;
100 
101 			    if(bNoLineJoin)
102 			    {
103 				    rPath.StartFigure();
104 			    }
105 	        }
106         }
107     }
108 }
109 
110 void impAddB2DPolygonToGDIPlusGraphicsPathInteger(Gdiplus::GraphicsPath& rPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin)
111 {
112     sal_uInt32 nCount(rPolygon.count());
113 
114     if(nCount)
115     {
116         const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1);
117         const bool bControls(rPolygon.areControlPointsUsed());
118         basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0));
119         Gdiplus::Point aICurr(INT(aCurr.getX()), INT(aCurr.getY()));
120 
121         for(sal_uInt32 a(0); a < nEdgeCount; a++)
122         {
123 	        const sal_uInt32 nNextIndex((a + 1) % nCount);
124 	        const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex));
125 	        const Gdiplus::Point aINext(INT(aNext.getX()), INT(aNext.getY()));
126 
127 	        if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex)))
128 	        {
129 		        const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a));
130 		        const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex));
131 
132 		        rPath.AddBezier(
133 			        aICurr,
134 			        Gdiplus::Point(INT(aCa.getX()), INT(aCa.getY())),
135 			        Gdiplus::Point(INT(aCb.getX()), INT(aCb.getY())),
136 			        aINext);
137 	        }
138 	        else
139 	        {
140 		        rPath.AddLine(aICurr, aINext);
141 	        }
142 
143 	        if(a + 1 < nEdgeCount)
144 	        {
145 		        aICurr = aINext;
146 
147 			    if(bNoLineJoin)
148 			    {
149 				    rPath.StartFigure();
150 			    }
151 	        }
152         }
153     }
154 }
155 
156 bool WinSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency)
157 {
158 	const sal_uInt32 nCount(rPolyPolygon.count());
159 
160 	if(mbBrush && nCount && (fTransparency >= 0.0 && fTransparency < 1.0))
161 	{
162 		Gdiplus::Graphics aGraphics(mhDC);
163 		const sal_uInt8 aTrans((sal_uInt8)255 - (sal_uInt8)basegfx::fround(fTransparency * 255.0));
164 		Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maFillColor), SALCOLOR_GREEN(maFillColor), SALCOLOR_BLUE(maFillColor));
165 		Gdiplus::SolidBrush aTestBrush(aTestColor);
166 		Gdiplus::GraphicsPath aPath;
167 
168 		for(sal_uInt32 a(0); a < nCount; a++)
169 		{
170             if(0 != a)
171             {
172                 aPath.StartFigure(); // #i101491# not needed for first run
173             }
174 
175 			impAddB2DPolygonToGDIPlusGraphicsPathReal(aPath, rPolyPolygon.getB2DPolygon(a), false);
176             aPath.CloseFigure();
177 		}
178 
179         if(getAntiAliasB2DDraw())
180         {
181             aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
182         }
183         else
184         {
185     		aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone);
186         }
187 
188 		aGraphics.FillPath(&aTestBrush, &aPath);
189 	}
190 
191  	return true;
192 }
193 
194 bool WinSalGraphics::drawPolyLine( const basegfx::B2DPolygon& rPolygon, double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin eLineJoin )
195 {
196     const sal_uInt32 nCount(rPolygon.count());
197 
198 	if(mbPen && nCount)
199 	{
200 		Gdiplus::Graphics aGraphics(mhDC);
201 		const sal_uInt8 aTrans = (sal_uInt8)basegfx::fround( 255 * (1.0 - fTransparency) );
202 		Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maLineColor), SALCOLOR_GREEN(maLineColor), SALCOLOR_BLUE(maLineColor));
203 		Gdiplus::Pen aTestPen(aTestColor, Gdiplus::REAL(rLineWidths.getX()));
204 		Gdiplus::GraphicsPath aPath;
205 		bool bNoLineJoin(false);
206 
207 		switch(eLineJoin)
208 		{
209 			default : // basegfx::B2DLINEJOIN_NONE :
210 			{
211 				if(basegfx::fTools::more(rLineWidths.getX(), 0.0))
212 				{
213 					bNoLineJoin = true;
214 				}
215 				break;
216 			}
217 			case basegfx::B2DLINEJOIN_BEVEL :
218 			{
219 				aTestPen.SetLineJoin(Gdiplus::LineJoinBevel);
220 				break;
221 			}
222 			case basegfx::B2DLINEJOIN_MIDDLE :
223 			case basegfx::B2DLINEJOIN_MITER :
224 			{
225 				const Gdiplus::REAL aMiterLimit(15.0);
226 				aTestPen.SetMiterLimit(aMiterLimit);
227 				aTestPen.SetLineJoin(Gdiplus::LineJoinMiter);
228 				break;
229 			}
230 			case basegfx::B2DLINEJOIN_ROUND :
231 			{
232 				aTestPen.SetLineJoin(Gdiplus::LineJoinRound);
233 				break;
234 			}
235 		}
236 
237 		if(nCount > 250 && basegfx::fTools::more(rLineWidths.getX(), 1.5))
238         {
239     		impAddB2DPolygonToGDIPlusGraphicsPathInteger(aPath, rPolygon, bNoLineJoin);
240         }
241         else
242         {
243     		impAddB2DPolygonToGDIPlusGraphicsPathReal(aPath, rPolygon, bNoLineJoin);
244         }
245 
246         if(rPolygon.isClosed() && !bNoLineJoin)
247         {
248             // #i101491# needed to create the correct line joins
249             aPath.CloseFigure();
250         }
251 
252         if(getAntiAliasB2DDraw())
253         {
254     		aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
255         }
256         else
257         {
258     		aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone);
259         }
260 
261 		aGraphics.DrawPath(&aTestPen, &aPath);
262 	}
263 
264 	return true;
265 }
266 
267 // -----------------------------------------------------------------------
268