xref: /trunk/main/vcl/win/source/gdi/salgdi_gdiplus.cxx (revision 74f1be36d980b87a5a095b012e7b3e9b4a8605eb)
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