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