xref: /AOO41X/main/vcl/win/source/gdi/salgdi_gdiplus.cxx (revision 54628ca40d27d15cc98fe861da7fff7e60c2f7d6)
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(
191     const basegfx::B2DPolygon& rPolygon,
192     double fTransparency,
193     const basegfx::B2DVector& rLineWidths,
194     basegfx::B2DLineJoin eLineJoin,
195     com::sun::star::drawing::LineCap eLineCap)
196 {
197     const sal_uInt32 nCount(rPolygon.count());
198 
199     if(mbPen && nCount)
200     {
201         Gdiplus::Graphics aGraphics(mhDC);
202         const sal_uInt8 aTrans = (sal_uInt8)basegfx::fround( 255 * (1.0 - fTransparency) );
203         Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maLineColor), SALCOLOR_GREEN(maLineColor), SALCOLOR_BLUE(maLineColor));
204         Gdiplus::Pen aTestPen(aTestColor, Gdiplus::REAL(rLineWidths.getX()));
205         Gdiplus::GraphicsPath aPath;
206         bool bNoLineJoin(false);
207 
208         switch(eLineJoin)
209         {
210             default : // basegfx::B2DLINEJOIN_NONE :
211             {
212                 if(basegfx::fTools::more(rLineWidths.getX(), 0.0))
213                 {
214                     bNoLineJoin = true;
215                 }
216                 break;
217             }
218             case basegfx::B2DLINEJOIN_BEVEL :
219             {
220                 aTestPen.SetLineJoin(Gdiplus::LineJoinBevel);
221                 break;
222             }
223             case basegfx::B2DLINEJOIN_MIDDLE :
224             case basegfx::B2DLINEJOIN_MITER :
225             {
226                 const Gdiplus::REAL aMiterLimit(15.0);
227                 aTestPen.SetMiterLimit(aMiterLimit);
228                 aTestPen.SetLineJoin(Gdiplus::LineJoinMiter);
229                 break;
230             }
231             case basegfx::B2DLINEJOIN_ROUND :
232             {
233                 aTestPen.SetLineJoin(Gdiplus::LineJoinRound);
234                 break;
235             }
236         }
237 
238         switch(eLineCap)
239         {
240             default: /*com::sun::star::drawing::LineCap_BUTT*/
241             {
242                 // nothing to do
243                 break;
244             }
245             case com::sun::star::drawing::LineCap_ROUND:
246             {
247                 aTestPen.SetStartCap(Gdiplus::LineCapRound);
248                 aTestPen.SetEndCap(Gdiplus::LineCapRound);
249                 break;
250             }
251             case com::sun::star::drawing::LineCap_SQUARE:
252             {
253                 aTestPen.SetStartCap(Gdiplus::LineCapSquare);
254                 aTestPen.SetEndCap(Gdiplus::LineCapSquare);
255                 break;
256             }
257         }
258 
259         if(nCount > 250 && basegfx::fTools::more(rLineWidths.getX(), 1.5))
260         {
261             impAddB2DPolygonToGDIPlusGraphicsPathInteger(aPath, rPolygon, bNoLineJoin);
262         }
263         else
264         {
265             impAddB2DPolygonToGDIPlusGraphicsPathReal(aPath, rPolygon, bNoLineJoin);
266         }
267 
268         if(rPolygon.isClosed() && !bNoLineJoin)
269         {
270             // #i101491# needed to create the correct line joins
271             aPath.CloseFigure();
272         }
273 
274         if(getAntiAliasB2DDraw())
275         {
276             aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
277         }
278         else
279         {
280             aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone);
281         }
282 
283         aGraphics.DrawPath(&aTestPen, &aPath);
284     }
285 
286     return true;
287 }
288 
289 // -----------------------------------------------------------------------
290