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