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