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