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 <tools/debug.hxx> 28 #include <tools/line.hxx> 29 #include <tools/poly.hxx> 30 31 #include <vcl/gradient.hxx> 32 #include <vcl/metaact.hxx> 33 #include <vcl/gdimtf.hxx> 34 #include <vcl/salbtype.hxx> 35 #include <vcl/hatch.hxx> 36 #include <vcl/window.hxx> 37 #include <vcl/virdev.hxx> 38 #include <vcl/outdev.hxx> 39 40 #include "pdfwriter_impl.hxx" 41 42 #include "window.h" 43 #include "salframe.hxx" 44 #include "salgdi.hxx" 45 #include "svdata.hxx" 46 #include "outdata.hxx" 47 48 #include <basegfx/polygon/b2dpolygon.hxx> 49 #include <basegfx/polygon/b2dpolypolygon.hxx> 50 #include <basegfx/matrix/b2dhommatrix.hxx> 51 52 // ----------- 53 // - Defines - 54 // ----------- 55 56 #define HATCH_MAXPOINTS 1024 57 #define GRADIENT_DEFAULT_STEPCOUNT 0 58 59 // ---------------- 60 // - Cmp-Function - 61 // ---------------- 62 63 extern "C" int __LOADONCALLAPI ImplHatchCmpFnc( const void* p1, const void* p2 ) 64 { 65 const long nX1 = ( (Point*) p1 )->X(); 66 const long nX2 = ( (Point*) p2 )->X(); 67 const long nY1 = ( (Point*) p1 )->Y(); 68 const long nY2 = ( (Point*) p2 )->Y(); 69 70 return ( nX1 > nX2 ? 1 : nX1 == nX2 ? nY1 > nY2 ? 1: nY1 == nY2 ? 0 : -1 : -1 ); 71 } 72 73 // ======================================================================= 74 75 DBG_NAMEEX( OutputDevice ) 76 DBG_NAMEEX( Gradient ) 77 78 // ======================================================================= 79 80 void OutputDevice::ImplDrawPolygon( const Polygon& rPoly, const PolyPolygon* pClipPolyPoly ) 81 { 82 if( pClipPolyPoly ) 83 ImplDrawPolyPolygon( rPoly, pClipPolyPoly ); 84 else 85 { 86 sal_uInt16 nPoints = rPoly.GetSize(); 87 88 if ( nPoints < 2 ) 89 return; 90 91 const SalPoint* pPtAry = (const SalPoint*)rPoly.GetConstPointAry(); 92 mpGraphics->DrawPolygon( nPoints, pPtAry, this ); 93 } 94 } 95 96 // ----------------------------------------------------------------------- 97 98 void OutputDevice::ImplDrawPolyPolygon( const PolyPolygon& rPolyPoly, const PolyPolygon* pClipPolyPoly ) 99 { 100 PolyPolygon* pPolyPoly; 101 102 if( pClipPolyPoly ) 103 { 104 pPolyPoly = new PolyPolygon; 105 rPolyPoly.GetIntersection( *pClipPolyPoly, *pPolyPoly ); 106 } 107 else 108 pPolyPoly = (PolyPolygon*) &rPolyPoly; 109 110 if( pPolyPoly->Count() == 1 ) 111 { 112 const Polygon rPoly = pPolyPoly->GetObject( 0 ); 113 sal_uInt16 nSize = rPoly.GetSize(); 114 115 if( nSize >= 2 ) 116 { 117 const SalPoint* pPtAry = (const SalPoint*)rPoly.GetConstPointAry(); 118 mpGraphics->DrawPolygon( nSize, pPtAry, this ); 119 } 120 } 121 else if( pPolyPoly->Count() ) 122 { 123 sal_uInt16 nCount = pPolyPoly->Count(); 124 sal_uInt32* pPointAry = new sal_uInt32[nCount]; 125 PCONSTSALPOINT* pPointAryAry = new PCONSTSALPOINT[nCount]; 126 sal_uInt16 i = 0; 127 do 128 { 129 const Polygon& rPoly = pPolyPoly->GetObject( i ); 130 sal_uInt16 nSize = rPoly.GetSize(); 131 if ( nSize ) 132 { 133 pPointAry[i] = nSize; 134 pPointAryAry[i] = (PCONSTSALPOINT)rPoly.GetConstPointAry(); 135 i++; 136 } 137 else 138 nCount--; 139 } 140 while( i < nCount ); 141 142 if( nCount == 1 ) 143 mpGraphics->DrawPolygon( *pPointAry, *pPointAryAry, this ); 144 else 145 mpGraphics->DrawPolyPolygon( nCount, pPointAry, pPointAryAry, this ); 146 147 delete[] pPointAry; 148 delete[] pPointAryAry; 149 } 150 151 if( pClipPolyPoly ) 152 delete pPolyPoly; 153 } 154 155 // ----------------------------------------------------------------------- 156 157 inline sal_uInt8 ImplGetGradientColorValue( long nValue ) 158 { 159 if ( nValue < 0 ) 160 return 0; 161 else if ( nValue > 0xFF ) 162 return 0xFF; 163 else 164 return (sal_uInt8)nValue; 165 } 166 167 // ----------------------------------------------------------------------- 168 169 void OutputDevice::ImplDrawLinearGradient( const Rectangle& rRect, 170 const Gradient& rGradient, 171 sal_Bool bMtf, const PolyPolygon* pClipPolyPoly ) 172 { 173 // get BoundRect of rotated rectangle 174 Rectangle aRect = rRect; 175 sal_uInt16 nAngle = rGradient.GetAngle() % 3600; 176 double fAngle = nAngle * F_PI1800; 177 double fWidth = aRect.GetWidth(); 178 double fHeight = aRect.GetHeight(); 179 double fDX = fWidth * fabs( cos( fAngle ) ) + 180 fHeight * fabs( sin( fAngle ) ); 181 double fDY = fHeight * fabs( cos( fAngle ) ) + 182 fWidth * fabs( sin( fAngle ) ); 183 fDX = (fDX - fWidth) * 0.5 + 0.5; 184 fDY = (fDY - fHeight) * 0.5 + 0.5; 185 aRect.Left() -= (long)fDX; 186 aRect.Right() += (long)fDX; 187 aRect.Top() -= (long)fDY; 188 aRect.Bottom() += (long)fDY; 189 190 sal_Bool bLinear = ( rGradient.GetStyle() == GRADIENT_LINEAR ); 191 double fBorder = rGradient.GetBorder() * aRect.GetHeight() / 100.0; 192 Point aCenter = rRect.Center(); 193 if ( !bLinear ) 194 { 195 fBorder /= 2.0; 196 } 197 Rectangle aMirrorRect = aRect; // used in style axial 198 aMirrorRect.Top() = ( aRect.Top() + aRect.Bottom() ) / 2; 199 if ( !bLinear ) 200 { 201 aRect.Bottom() = aMirrorRect.Top(); 202 } 203 204 // Intensitaeten von Start- und Endfarbe ggf. aendern 205 long nFactor; 206 Color aStartCol = rGradient.GetStartColor(); 207 Color aEndCol = rGradient.GetEndColor(); 208 long nStartRed = aStartCol.GetRed(); 209 long nStartGreen = aStartCol.GetGreen(); 210 long nStartBlue = aStartCol.GetBlue(); 211 long nEndRed = aEndCol.GetRed(); 212 long nEndGreen = aEndCol.GetGreen(); 213 long nEndBlue = aEndCol.GetBlue(); 214 nFactor = rGradient.GetStartIntensity(); 215 nStartRed = (nStartRed * nFactor) / 100; 216 nStartGreen = (nStartGreen * nFactor) / 100; 217 nStartBlue = (nStartBlue * nFactor) / 100; 218 nFactor = rGradient.GetEndIntensity(); 219 nEndRed = (nEndRed * nFactor) / 100; 220 nEndGreen = (nEndGreen * nFactor) / 100; 221 nEndBlue = (nEndBlue * nFactor) / 100; 222 223 // gradient style axial has exchanged start and end colors 224 if ( !bLinear) 225 { 226 long nTempColor = nStartRed; 227 nStartRed = nEndRed; 228 nEndRed = nTempColor; 229 nTempColor = nStartGreen; 230 nStartGreen = nEndGreen; 231 nEndGreen = nTempColor; 232 nTempColor = nStartBlue; 233 nStartBlue = nEndBlue; 234 nEndBlue = nTempColor; 235 } 236 237 sal_uInt8 nRed; 238 sal_uInt8 nGreen; 239 sal_uInt8 nBlue; 240 241 // Create border 242 Rectangle aBorderRect = aRect; 243 Polygon aPoly( 4 ); 244 if (fBorder > 0.0) 245 { 246 nRed = (sal_uInt8)nStartRed; 247 nGreen = (sal_uInt8)nStartGreen; 248 nBlue = (sal_uInt8)nStartBlue; 249 if ( bMtf ) 250 mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) ); 251 else 252 mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); 253 254 aBorderRect.Bottom() = (long)( aBorderRect.Top() + fBorder ); 255 aRect.Top() = aBorderRect.Bottom(); 256 aPoly[0] = aBorderRect.TopLeft(); 257 aPoly[1] = aBorderRect.TopRight(); 258 aPoly[2] = aBorderRect.BottomRight(); 259 aPoly[3] = aBorderRect.BottomLeft(); 260 aPoly.Rotate( aCenter, nAngle ); 261 if ( bMtf ) 262 mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) ); 263 else 264 ImplDrawPolygon( aPoly, pClipPolyPoly ); 265 if ( !bLinear) 266 { 267 aBorderRect = aMirrorRect; 268 aBorderRect.Top() = (long) ( aBorderRect.Bottom() - fBorder ); 269 aMirrorRect.Bottom() = aBorderRect.Top(); 270 aPoly[0] = aBorderRect.TopLeft(); 271 aPoly[1] = aBorderRect.TopRight(); 272 aPoly[2] = aBorderRect.BottomRight(); 273 aPoly[3] = aBorderRect.BottomLeft(); 274 aPoly.Rotate( aCenter, nAngle ); 275 if ( bMtf ) 276 mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) ); 277 else 278 ImplDrawPolygon( aPoly, pClipPolyPoly ); 279 } 280 } 281 282 // calculate step count 283 long nStepCount = rGradient.GetSteps(); 284 // generate nStepCount, if not passed 285 long nMinRect = aRect.GetHeight(); 286 if ( !nStepCount ) 287 { 288 long nInc = 1; 289 if ( meOutDevType != OUTDEV_PRINTER && !bMtf ) 290 { 291 nInc = (nMinRect < 50) ? 2 : 4; 292 } 293 else 294 { 295 // Use display-equivalent step size calculation 296 nInc = (nMinRect < 800) ? 10 : 20; 297 } 298 nStepCount = nMinRect / nInc; 299 } 300 301 // minimal three steps and maximal as max color steps 302 long nAbsRedSteps = Abs( nEndRed - nStartRed ); 303 long nAbsGreenSteps = Abs( nEndGreen - nStartGreen ); 304 long nAbsBlueSteps = Abs( nEndBlue - nStartBlue ); 305 long nMaxColorSteps = Max( nAbsRedSteps , nAbsGreenSteps ); 306 nMaxColorSteps = Max( nMaxColorSteps, nAbsBlueSteps ); 307 long nSteps = Min( nStepCount, nMaxColorSteps ); 308 if ( nSteps < 3) 309 { 310 nSteps = 3; 311 } 312 313 double fScanInc = ((double)aRect.GetHeight()) / (double) nSteps; 314 double fGradientLine = (double)aRect.Top(); 315 double fMirrorGradientLine = (double) aMirrorRect.Bottom(); 316 317 double fAlpha = 0.0; 318 const double fStepsMinus1 = ((double)nSteps) - 1.0; 319 double fTempColor; 320 if ( !bLinear) 321 { 322 nSteps -= 1; // draw middle polygons as one polygon after loop to avoid gap 323 } 324 for ( long i = 0; i < nSteps; i++ ) 325 { 326 // linear interpolation of color 327 fAlpha = ((double)i) / fStepsMinus1; 328 fTempColor = ((double)nStartRed) * (1.0-fAlpha) + ((double)nEndRed) * fAlpha; 329 nRed = ImplGetGradientColorValue((long)fTempColor); 330 fTempColor = ((double)nStartGreen) * (1.0-fAlpha) + ((double)nEndGreen) * fAlpha; 331 nGreen = ImplGetGradientColorValue((long)fTempColor); 332 fTempColor = ((double)nStartBlue) * (1.0-fAlpha) + ((double)nEndBlue) * fAlpha; 333 nBlue = ImplGetGradientColorValue((long)fTempColor); 334 if ( bMtf ) 335 mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) ); 336 else 337 mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); 338 339 // Polygon for this color step 340 aRect.Top() = (long)( fGradientLine + ((double) i) * fScanInc ); 341 aRect.Bottom() = (long)( fGradientLine + ( ((double) i) + 1.0 ) * fScanInc ); 342 aPoly[0] = aRect.TopLeft(); 343 aPoly[1] = aRect.TopRight(); 344 aPoly[2] = aRect.BottomRight(); 345 aPoly[3] = aRect.BottomLeft(); 346 aPoly.Rotate( aCenter, nAngle ); 347 if ( bMtf ) 348 mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) ); 349 else 350 ImplDrawPolygon( aPoly, pClipPolyPoly ); 351 if ( !bLinear ) 352 { 353 aMirrorRect.Bottom() = (long)( fMirrorGradientLine - ((double) i) * fScanInc ); 354 aMirrorRect.Top() = (long)( fMirrorGradientLine - (((double) i) + 1.0)* fScanInc ); 355 aPoly[0] = aMirrorRect.TopLeft(); 356 aPoly[1] = aMirrorRect.TopRight(); 357 aPoly[2] = aMirrorRect.BottomRight(); 358 aPoly[3] = aMirrorRect.BottomLeft(); 359 aPoly.Rotate( aCenter, nAngle ); 360 if ( bMtf ) 361 mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) ); 362 else 363 ImplDrawPolygon( aPoly, pClipPolyPoly ); 364 } 365 } 366 if ( !bLinear) 367 { 368 // draw middle polygon with end color 369 nRed = ImplGetGradientColorValue(nEndRed); 370 nGreen = ImplGetGradientColorValue(nEndGreen); 371 nBlue = ImplGetGradientColorValue(nEndBlue); 372 if ( bMtf ) 373 mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) ); 374 else 375 mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); 376 377 aRect.Top() = (long)( fGradientLine + ((double)nSteps) * fScanInc ); 378 aRect.Bottom() = (long)( fMirrorGradientLine - ((double) nSteps) * fScanInc ); 379 aPoly[0] = aRect.TopLeft(); 380 aPoly[1] = aRect.TopRight(); 381 aPoly[2] = aRect.BottomRight(); 382 aPoly[3] = aRect.BottomLeft(); 383 aPoly.Rotate( aCenter, nAngle ); 384 if ( bMtf ) 385 mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) ); 386 else 387 ImplDrawPolygon( aPoly, pClipPolyPoly ); 388 } 389 } 390 391 // ----------------------------------------------------------------------- 392 393 void OutputDevice::ImplDrawComplexGradient( const Rectangle& rRect, 394 const Gradient& rGradient, 395 sal_Bool bMtf, const PolyPolygon* pClipPolyPoly ) 396 { 397 // Feststellen ob Ausgabe ueber Polygon oder PolyPolygon 398 // Bei Rasteroperationen ungleich Overpaint immer PolyPolygone, 399 // da es zu falschen Ergebnissen kommt, wenn man mehrfach uebereinander 400 // ausgibt 401 // Bei Druckern auch immer PolyPolygone, da nicht alle Drucker 402 // das Uebereinanderdrucken von Polygonen koennen 403 // Virtuelle Device werden auch ausgeklammert, da einige Treiber 404 // ansonsten zu langsam sind 405 PolyPolygon* pPolyPoly; 406 Rectangle aRect( rRect ); 407 Color aStartCol( rGradient.GetStartColor() ); 408 Color aEndCol( rGradient.GetEndColor() ); 409 long nStartRed = ( (long) aStartCol.GetRed() * rGradient.GetStartIntensity() ) / 100; 410 long nStartGreen = ( (long) aStartCol.GetGreen() * rGradient.GetStartIntensity() ) / 100; 411 long nStartBlue = ( (long) aStartCol.GetBlue() * rGradient.GetStartIntensity() ) / 100; 412 long nEndRed = ( (long) aEndCol.GetRed() * rGradient.GetEndIntensity() ) / 100; 413 long nEndGreen = ( (long) aEndCol.GetGreen() * rGradient.GetEndIntensity() ) / 100; 414 long nEndBlue = ( (long) aEndCol.GetBlue() * rGradient.GetEndIntensity() ) / 100; 415 long nRedSteps = nEndRed - nStartRed; 416 long nGreenSteps = nEndGreen - nStartGreen; 417 long nBlueSteps = nEndBlue - nStartBlue; 418 long nStepCount = rGradient.GetSteps(); 419 sal_uInt16 nAngle = rGradient.GetAngle() % 3600; 420 421 if( (meRasterOp != ROP_OVERPAINT) || (meOutDevType != OUTDEV_WINDOW) || bMtf ) 422 pPolyPoly = new PolyPolygon( 2 ); 423 else 424 pPolyPoly = NULL; 425 426 if( rGradient.GetStyle() == GRADIENT_SQUARE || rGradient.GetStyle() == GRADIENT_RECT ) 427 { 428 const double fAngle = nAngle * F_PI1800; 429 const double fWidth = aRect.GetWidth(); 430 const double fHeight = aRect.GetHeight(); 431 double fDX = fWidth * fabs( cos( fAngle ) ) + fHeight * fabs( sin( fAngle ) ); 432 double fDY = fHeight * fabs( cos( fAngle ) ) + fWidth * fabs( sin( fAngle ) ); 433 434 fDX = ( fDX - fWidth ) * 0.5 + 0.5; 435 fDY = ( fDY - fHeight ) * 0.5 + 0.5; 436 437 aRect.Left() -= (long) fDX; 438 aRect.Right() += (long) fDX; 439 aRect.Top() -= (long) fDY; 440 aRect.Bottom() += (long) fDY; 441 } 442 443 Size aSize( aRect.GetSize() ); 444 445 if( rGradient.GetStyle() == GRADIENT_RADIAL ) 446 { 447 // Radien-Berechnung fuer Kreis 448 aSize.Width() = (long)(0.5 + sqrt((double)aSize.Width()*(double)aSize.Width() + (double)aSize.Height()*(double)aSize.Height())); 449 aSize.Height() = aSize.Width(); 450 } 451 else if( rGradient.GetStyle() == GRADIENT_ELLIPTICAL ) 452 { 453 // Radien-Berechnung fuer Ellipse 454 aSize.Width() = (long)( 0.5 + (double) aSize.Width() * 1.4142 ); 455 aSize.Height() = (long)( 0.5 + (double) aSize.Height() * 1.4142 ); 456 } 457 else if( rGradient.GetStyle() == GRADIENT_SQUARE ) 458 { 459 if ( aSize.Width() > aSize.Height() ) 460 aSize.Height() = aSize.Width(); 461 else 462 aSize.Width() = aSize.Height(); 463 } 464 465 // neue Mittelpunkte berechnen 466 long nZWidth = aRect.GetWidth() * (long) rGradient.GetOfsX() / 100; 467 long nZHeight = aRect.GetHeight() * (long) rGradient.GetOfsY() / 100; 468 long nBorderX = (long) rGradient.GetBorder() * aSize.Width() / 100; 469 long nBorderY = (long) rGradient.GetBorder() * aSize.Height() / 100; 470 Point aCenter( aRect.Left() + nZWidth, aRect.Top() + nZHeight ); 471 472 // Rand beruecksichtigen 473 aSize.Width() -= nBorderX; 474 aSize.Height() -= nBorderY; 475 476 // Ausgaberechteck neu setzen 477 aRect.Left() = aCenter.X() - ( aSize.Width() >> 1 ); 478 aRect.Top() = aCenter.Y() - ( aSize.Height() >> 1 ); 479 480 aRect.SetSize( aSize ); 481 long nMinRect = Min( aRect.GetWidth(), aRect.GetHeight() ); 482 483 // Anzahl der Schritte berechnen, falls nichts uebergeben wurde 484 if( !nStepCount ) 485 { 486 long nInc; 487 488 if ( meOutDevType != OUTDEV_PRINTER && !bMtf ) 489 { 490 nInc = ( nMinRect < 50 ) ? 2 : 4; 491 } 492 else 493 { 494 // #105998# Use display-equivalent step size calculation 495 nInc = (nMinRect < 800) ? 10 : 20; 496 } 497 498 if( !nInc ) 499 nInc = 1; 500 501 nStepCount = nMinRect / nInc; 502 } 503 504 // minimal drei Schritte und maximal die Anzahl der Farbunterschiede 505 long nSteps = Max( nStepCount, 2L ); 506 long nCalcSteps = Abs( nRedSteps ); 507 long nTempSteps = Abs( nGreenSteps ); 508 if ( nTempSteps > nCalcSteps ) 509 nCalcSteps = nTempSteps; 510 nTempSteps = Abs( nBlueSteps ); 511 if ( nTempSteps > nCalcSteps ) 512 nCalcSteps = nTempSteps; 513 if ( nCalcSteps < nSteps ) 514 nSteps = nCalcSteps; 515 if ( !nSteps ) 516 nSteps = 1; 517 518 // Ausgabebegrenzungen und Schrittweite fuer jede Richtung festlegen 519 Polygon aPoly; 520 double fScanLeft = aRect.Left(); 521 double fScanTop = aRect.Top(); 522 double fScanRight = aRect.Right(); 523 double fScanBottom = aRect.Bottom(); 524 double fScanInc = (double) nMinRect / (double) nSteps * 0.5; 525 sal_uInt8 nRed = (sal_uInt8) nStartRed, nGreen = (sal_uInt8) nStartGreen, nBlue = (sal_uInt8) nStartBlue; 526 bool bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output 527 528 if( bMtf ) 529 mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) ); 530 else 531 mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); 532 533 if( pPolyPoly ) 534 { 535 pPolyPoly->Insert( aPoly = rRect ); 536 pPolyPoly->Insert( aPoly ); 537 } 538 else 539 { 540 // extend rect, to avoid missing bounding line 541 Rectangle aExtRect( rRect ); 542 543 aExtRect.Left() -= 1; 544 aExtRect.Top() -= 1; 545 aExtRect.Right() += 1; 546 aExtRect.Bottom() += 1; 547 548 ImplDrawPolygon( aPoly = aExtRect, pClipPolyPoly ); 549 } 550 551 // Schleife, um nacheinander die Polygone/PolyPolygone auszugeben 552 for( long i = 1; i < nSteps; i++ ) 553 { 554 // neues Polygon berechnen 555 aRect.Left() = (long)( fScanLeft += fScanInc ); 556 aRect.Top() = (long)( fScanTop += fScanInc ); 557 aRect.Right() = (long)( fScanRight -= fScanInc ); 558 aRect.Bottom() = (long)( fScanBottom -= fScanInc ); 559 560 if( ( aRect.GetWidth() < 2 ) || ( aRect.GetHeight() < 2 ) ) 561 break; 562 563 if( rGradient.GetStyle() == GRADIENT_RADIAL || rGradient.GetStyle() == GRADIENT_ELLIPTICAL ) 564 aPoly = Polygon( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 ); 565 else 566 aPoly = Polygon( aRect ); 567 568 aPoly.Rotate( aCenter, nAngle ); 569 570 // Farbe entsprechend anpassen 571 const long nStepIndex = ( ( pPolyPoly != NULL ) ? i : ( i + 1 ) ); 572 nRed = ImplGetGradientColorValue( nStartRed + ( ( nRedSteps * nStepIndex ) / nSteps ) ); 573 nGreen = ImplGetGradientColorValue( nStartGreen + ( ( nGreenSteps * nStepIndex ) / nSteps ) ); 574 nBlue = ImplGetGradientColorValue( nStartBlue + ( ( nBlueSteps * nStepIndex ) / nSteps ) ); 575 576 // entweder langsame PolyPolygon-Ausgaben oder schnelles Polygon-Painting 577 if( pPolyPoly ) 578 { 579 bPaintLastPolygon = true; // #107349# Paint last polygon only if loop has generated any output 580 581 pPolyPoly->Replace( pPolyPoly->GetObject( 1 ), 0 ); 582 pPolyPoly->Replace( aPoly, 1 ); 583 584 if( bMtf ) 585 mpMetaFile->AddAction( new MetaPolyPolygonAction( *pPolyPoly ) ); 586 else 587 ImplDrawPolyPolygon( *pPolyPoly, pClipPolyPoly ); 588 589 // #107349# Set fill color _after_ geometry painting: 590 // pPolyPoly's geometry is the band from last iteration's 591 // aPoly to current iteration's aPoly. The window outdev 592 // path (see else below), on the other hand, paints the 593 // full aPoly. Thus, here, we're painting the band before 594 // the one painted in the window outdev path below. To get 595 // matching colors, have to delay color setting here. 596 if( bMtf ) 597 mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) ); 598 else 599 mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); 600 } 601 else 602 { 603 // #107349# Set fill color _before_ geometry painting 604 if( bMtf ) 605 mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) ); 606 else 607 mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); 608 609 ImplDrawPolygon( aPoly, pClipPolyPoly ); 610 } 611 } 612 613 // Falls PolyPolygon-Ausgabe, muessen wir noch ein letztes inneres Polygon zeichnen 614 if( pPolyPoly ) 615 { 616 const Polygon& rPoly = pPolyPoly->GetObject( 1 ); 617 618 if( !rPoly.GetBoundRect().IsEmpty() ) 619 { 620 // #107349# Paint last polygon with end color only if loop 621 // has generated output. Otherwise, the current 622 // (i.e. start) color is taken, to generate _any_ output. 623 if( bPaintLastPolygon ) 624 { 625 nRed = ImplGetGradientColorValue( nEndRed ); 626 nGreen = ImplGetGradientColorValue( nEndGreen ); 627 nBlue = ImplGetGradientColorValue( nEndBlue ); 628 } 629 630 if( bMtf ) 631 { 632 mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) ); 633 mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) ); 634 } 635 else 636 { 637 mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); 638 ImplDrawPolygon( rPoly, pClipPolyPoly ); 639 } 640 } 641 642 delete pPolyPoly; 643 } 644 } 645 646 // ----------------------------------------------------------------------- 647 648 void OutputDevice::DrawGradient( const Rectangle& rRect, 649 const Gradient& rGradient ) 650 { 651 DBG_TRACE( "OutputDevice::DrawGradient()" ); 652 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 653 DBG_CHKOBJ( &rGradient, Gradient, NULL ); 654 655 if ( mnDrawMode & DRAWMODE_NOGRADIENT ) 656 return; 657 else if ( mnDrawMode & ( DRAWMODE_BLACKGRADIENT | DRAWMODE_WHITEGRADIENT | DRAWMODE_SETTINGSGRADIENT) ) 658 { 659 Color aColor; 660 661 if ( mnDrawMode & DRAWMODE_BLACKGRADIENT ) 662 aColor = Color( COL_BLACK ); 663 else if ( mnDrawMode & DRAWMODE_WHITEGRADIENT ) 664 aColor = Color( COL_WHITE ); 665 else if ( mnDrawMode & DRAWMODE_SETTINGSGRADIENT ) 666 aColor = GetSettings().GetStyleSettings().GetWindowColor(); 667 668 if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT ) 669 { 670 aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80, 671 ( aColor.GetGreen() >> 1 ) | 0x80, 672 ( aColor.GetBlue() >> 1 ) | 0x80 ); 673 } 674 675 Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); 676 SetLineColor( aColor ); 677 SetFillColor( aColor ); 678 DrawRect( rRect ); 679 Pop(); 680 return; 681 } 682 683 Gradient aGradient( rGradient ); 684 685 if ( mnDrawMode & ( DRAWMODE_GRAYGRADIENT | DRAWMODE_GHOSTEDGRADIENT ) ) 686 { 687 Color aStartCol( aGradient.GetStartColor() ); 688 Color aEndCol( aGradient.GetEndColor() ); 689 690 if ( mnDrawMode & DRAWMODE_GRAYGRADIENT ) 691 { 692 sal_uInt8 cStartLum = aStartCol.GetLuminance(), cEndLum = aEndCol.GetLuminance(); 693 aStartCol = Color( cStartLum, cStartLum, cStartLum ); 694 aEndCol = Color( cEndLum, cEndLum, cEndLum ); 695 } 696 697 if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT ) 698 { 699 aStartCol = Color( ( aStartCol.GetRed() >> 1 ) | 0x80, 700 ( aStartCol.GetGreen() >> 1 ) | 0x80, 701 ( aStartCol.GetBlue() >> 1 ) | 0x80 ); 702 703 aEndCol = Color( ( aEndCol.GetRed() >> 1 ) | 0x80, 704 ( aEndCol.GetGreen() >> 1 ) | 0x80, 705 ( aEndCol.GetBlue() >> 1 ) | 0x80 ); 706 } 707 708 aGradient.SetStartColor( aStartCol ); 709 aGradient.SetEndColor( aEndCol ); 710 } 711 712 if( mpMetaFile ) 713 mpMetaFile->AddAction( new MetaGradientAction( rRect, aGradient ) ); 714 715 if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() ) 716 return; 717 718 // Rechteck in Pixel umrechnen 719 Rectangle aRect( ImplLogicToDevicePixel( rRect ) ); 720 aRect.Justify(); 721 722 // Wenn Rechteck leer ist, brauchen wir nichts machen 723 if ( !aRect.IsEmpty() ) 724 { 725 // Clip Region sichern 726 Push( PUSH_CLIPREGION ); 727 IntersectClipRegion( rRect ); 728 729 // because we draw with no border line, we have to expand gradient 730 // rect to avoid missing lines on the right and bottom edge 731 aRect.Left()--; 732 aRect.Top()--; 733 aRect.Right()++; 734 aRect.Bottom()++; 735 736 // we need a graphics 737 if ( !mpGraphics ) 738 { 739 if ( !ImplGetGraphics() ) 740 return; 741 } 742 743 if ( mbInitClipRegion ) 744 ImplInitClipRegion(); 745 746 if ( !mbOutputClipped ) 747 { 748 // Gradienten werden ohne Umrandung gezeichnet 749 if ( mbLineColor || mbInitLineColor ) 750 { 751 mpGraphics->SetLineColor(); 752 mbInitLineColor = sal_True; 753 } 754 755 mbInitFillColor = sal_True; 756 757 // calculate step count if neccessary 758 if ( !aGradient.GetSteps() ) 759 aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT ); 760 761 if( aGradient.GetStyle() == GRADIENT_LINEAR || aGradient.GetStyle() == GRADIENT_AXIAL ) 762 ImplDrawLinearGradient( aRect, aGradient, sal_False, NULL ); 763 else 764 ImplDrawComplexGradient( aRect, aGradient, sal_False, NULL ); 765 } 766 767 Pop(); 768 } 769 770 if( mpAlphaVDev ) 771 { 772 // #i32109#: Make gradient area opaque 773 mpAlphaVDev->ImplFillOpaqueRectangle( rRect ); 774 } 775 } 776 777 // ----------------------------------------------------------------------- 778 779 void OutputDevice::DrawGradient( const PolyPolygon& rPolyPoly, 780 const Gradient& rGradient ) 781 { 782 DBG_TRACE( "OutputDevice::DrawGradient()" ); 783 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 784 DBG_CHKOBJ( &rGradient, Gradient, NULL ); 785 786 if( mbInitClipRegion ) 787 ImplInitClipRegion(); 788 789 if( mbOutputClipped ) 790 return; 791 792 if( !mpGraphics ) 793 if( !ImplGetGraphics() ) 794 return; 795 796 if( rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize() && !( mnDrawMode & DRAWMODE_NOGRADIENT ) ) 797 { 798 if ( mnDrawMode & ( DRAWMODE_BLACKGRADIENT | DRAWMODE_WHITEGRADIENT | DRAWMODE_SETTINGSGRADIENT) ) 799 { 800 Color aColor; 801 802 if ( mnDrawMode & DRAWMODE_BLACKGRADIENT ) 803 aColor = Color( COL_BLACK ); 804 else if ( mnDrawMode & DRAWMODE_WHITEGRADIENT ) 805 aColor = Color( COL_WHITE ); 806 else if ( mnDrawMode & DRAWMODE_SETTINGSGRADIENT ) 807 aColor = GetSettings().GetStyleSettings().GetWindowColor(); 808 809 if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT ) 810 { 811 aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80, 812 ( aColor.GetGreen() >> 1 ) | 0x80, 813 ( aColor.GetBlue() >> 1 ) | 0x80 ); 814 } 815 816 Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); 817 SetLineColor( aColor ); 818 SetFillColor( aColor ); 819 DrawPolyPolygon( rPolyPoly ); 820 Pop(); 821 return; 822 } 823 824 if( mpMetaFile ) 825 { 826 const Rectangle aRect( rPolyPoly.GetBoundRect() ); 827 828 mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_BEGIN" ) ); 829 mpMetaFile->AddAction( new MetaGradientExAction( rPolyPoly, rGradient ) ); 830 831 if( OUTDEV_PRINTER == meOutDevType ) 832 { 833 Push( PUSH_CLIPREGION ); 834 IntersectClipRegion( rPolyPoly ); 835 DrawGradient( aRect, rGradient ); 836 Pop(); 837 } 838 else 839 { 840 const sal_Bool bOldOutput = IsOutputEnabled(); 841 842 EnableOutput( sal_False ); 843 Push( PUSH_RASTEROP ); 844 SetRasterOp( ROP_XOR ); 845 DrawGradient( aRect, rGradient ); 846 SetFillColor( COL_BLACK ); 847 SetRasterOp( ROP_0 ); 848 DrawPolyPolygon( rPolyPoly ); 849 SetRasterOp( ROP_XOR ); 850 DrawGradient( aRect, rGradient ); 851 Pop(); 852 EnableOutput( bOldOutput ); 853 } 854 855 mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_END" ) ); 856 } 857 858 if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() ) 859 return; 860 861 Gradient aGradient( rGradient ); 862 863 if ( mnDrawMode & ( DRAWMODE_GRAYGRADIENT | DRAWMODE_GHOSTEDGRADIENT ) ) 864 { 865 Color aStartCol( aGradient.GetStartColor() ); 866 Color aEndCol( aGradient.GetEndColor() ); 867 868 if ( mnDrawMode & DRAWMODE_GRAYGRADIENT ) 869 { 870 sal_uInt8 cStartLum = aStartCol.GetLuminance(), cEndLum = aEndCol.GetLuminance(); 871 aStartCol = Color( cStartLum, cStartLum, cStartLum ); 872 aEndCol = Color( cEndLum, cEndLum, cEndLum ); 873 } 874 875 if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT ) 876 { 877 aStartCol = Color( ( aStartCol.GetRed() >> 1 ) | 0x80, 878 ( aStartCol.GetGreen() >> 1 ) | 0x80, 879 ( aStartCol.GetBlue() >> 1 ) | 0x80 ); 880 881 aEndCol = Color( ( aEndCol.GetRed() >> 1 ) | 0x80, 882 ( aEndCol.GetGreen() >> 1 ) | 0x80, 883 ( aEndCol.GetBlue() >> 1 ) | 0x80 ); 884 } 885 886 aGradient.SetStartColor( aStartCol ); 887 aGradient.SetEndColor( aEndCol ); 888 } 889 890 if( OUTDEV_PRINTER == meOutDevType || ImplGetSVData()->maGDIData.mbNoXORClipping ) 891 { 892 const Rectangle aBoundRect( rPolyPoly.GetBoundRect() ); 893 894 if( !Rectangle( PixelToLogic( Point() ), GetOutputSize() ).IsEmpty() ) 895 { 896 // Rechteck in Pixel umrechnen 897 Rectangle aRect( ImplLogicToDevicePixel( aBoundRect ) ); 898 aRect.Justify(); 899 900 // Wenn Rechteck leer ist, brauchen wir nichts machen 901 if ( !aRect.IsEmpty() ) 902 { 903 if( !mpGraphics && !ImplGetGraphics() ) 904 return; 905 906 if( mbInitClipRegion ) 907 ImplInitClipRegion(); 908 909 if( !mbOutputClipped ) 910 { 911 PolyPolygon aClipPolyPoly( ImplLogicToDevicePixel( rPolyPoly ) ); 912 913 // Gradienten werden ohne Umrandung gezeichnet 914 if( mbLineColor || mbInitLineColor ) 915 { 916 mpGraphics->SetLineColor(); 917 mbInitLineColor = sal_True; 918 } 919 920 mbInitFillColor = sal_True; 921 922 // calculate step count if neccessary 923 if ( !aGradient.GetSteps() ) 924 aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT ); 925 926 if( aGradient.GetStyle() == GRADIENT_LINEAR || aGradient.GetStyle() == GRADIENT_AXIAL ) 927 ImplDrawLinearGradient( aRect, aGradient, sal_False, &aClipPolyPoly ); 928 else 929 ImplDrawComplexGradient( aRect, aGradient, sal_False, &aClipPolyPoly ); 930 } 931 } 932 } 933 } 934 else 935 { 936 const PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) ); 937 const Rectangle aBoundRect( aPolyPoly.GetBoundRect() ); 938 Point aPoint; 939 Rectangle aDstRect( aPoint, GetOutputSizePixel() ); 940 941 aDstRect.Intersection( aBoundRect ); 942 943 if( OUTDEV_WINDOW == meOutDevType ) 944 { 945 const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() ); 946 947 if( !aPaintRgn.IsNull() ) 948 aDstRect.Intersection( LogicToPixel( aPaintRgn ).GetBoundRect() ); 949 } 950 951 if( !aDstRect.IsEmpty() ) 952 { 953 VirtualDevice* pVDev; 954 const Size aDstSize( aDstRect.GetSize() ); 955 956 if( HasAlpha() ) 957 { 958 // #110958# Pay attention to alpha VDevs here, otherwise, 959 // background will be wrong: Temp VDev has to have alpha, too. 960 pVDev = new VirtualDevice( *this, 0, GetAlphaBitCount() > 1 ? 0 : 1 ); 961 } 962 else 963 { 964 // nothing special here. Plain VDev 965 pVDev = new VirtualDevice(); 966 } 967 968 if( pVDev->SetOutputSizePixel( aDstSize) ) 969 { 970 MapMode aVDevMap; 971 const sal_Bool bOldMap = mbMap; 972 973 EnableMapMode( sal_False ); 974 975 pVDev->DrawOutDev( Point(), aDstSize, aDstRect.TopLeft(), aDstSize, *this ); 976 pVDev->SetRasterOp( ROP_XOR ); 977 aVDevMap.SetOrigin( Point( -aDstRect.Left(), -aDstRect.Top() ) ); 978 pVDev->SetMapMode( aVDevMap ); 979 pVDev->DrawGradient( aBoundRect, aGradient ); 980 pVDev->SetFillColor( COL_BLACK ); 981 pVDev->SetRasterOp( ROP_0 ); 982 pVDev->DrawPolyPolygon( aPolyPoly ); 983 pVDev->SetRasterOp( ROP_XOR ); 984 pVDev->DrawGradient( aBoundRect, aGradient ); 985 aVDevMap.SetOrigin( Point() ); 986 pVDev->SetMapMode( aVDevMap ); 987 DrawOutDev( aDstRect.TopLeft(), aDstSize, Point(), aDstSize, *pVDev ); 988 989 EnableMapMode( bOldMap ); 990 } 991 992 delete pVDev; 993 } 994 } 995 } 996 997 if( mpAlphaVDev ) 998 mpAlphaVDev->DrawPolyPolygon( rPolyPoly ); 999 } 1000 1001 // ----------------------------------------------------------------------- 1002 1003 void OutputDevice::AddGradientActions( const Rectangle& rRect, const Gradient& rGradient, 1004 GDIMetaFile& rMtf ) 1005 { 1006 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1007 DBG_CHKOBJ( &rGradient, Gradient, NULL ); 1008 1009 Rectangle aRect( rRect ); 1010 1011 aRect.Justify(); 1012 1013 // Wenn Rechteck leer ist, brauchen wir nichts machen 1014 if ( !aRect.IsEmpty() ) 1015 { 1016 Gradient aGradient( rGradient ); 1017 GDIMetaFile* pOldMtf = mpMetaFile; 1018 1019 mpMetaFile = &rMtf; 1020 mpMetaFile->AddAction( new MetaPushAction( PUSH_ALL ) ); 1021 mpMetaFile->AddAction( new MetaISectRectClipRegionAction( aRect ) ); 1022 mpMetaFile->AddAction( new MetaLineColorAction( Color(), sal_False ) ); 1023 1024 // because we draw with no border line, we have to expand gradient 1025 // rect to avoid missing lines on the right and bottom edge 1026 aRect.Left()--; 1027 aRect.Top()--; 1028 aRect.Right()++; 1029 aRect.Bottom()++; 1030 1031 // calculate step count if neccessary 1032 if ( !aGradient.GetSteps() ) 1033 aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT ); 1034 1035 if( aGradient.GetStyle() == GRADIENT_LINEAR || aGradient.GetStyle() == GRADIENT_AXIAL ) 1036 ImplDrawLinearGradient( aRect, aGradient, sal_True, NULL ); 1037 else 1038 ImplDrawComplexGradient( aRect, aGradient, sal_True, NULL ); 1039 1040 mpMetaFile->AddAction( new MetaPopAction() ); 1041 mpMetaFile = pOldMtf; 1042 } 1043 } 1044 1045 // ----------------------------------------------------------------------- 1046 1047 void OutputDevice::DrawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch ) 1048 { 1049 DBG_TRACE( "OutputDevice::DrawHatch()" ); 1050 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1051 1052 Hatch aHatch( rHatch ); 1053 1054 if ( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE | 1055 DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE | 1056 DRAWMODE_SETTINGSLINE ) ) 1057 { 1058 Color aColor( rHatch.GetColor() ); 1059 1060 if ( mnDrawMode & DRAWMODE_BLACKLINE ) 1061 aColor = Color( COL_BLACK ); 1062 else if ( mnDrawMode & DRAWMODE_WHITELINE ) 1063 aColor = Color( COL_WHITE ); 1064 else if ( mnDrawMode & DRAWMODE_GRAYLINE ) 1065 { 1066 const sal_uInt8 cLum = aColor.GetLuminance(); 1067 aColor = Color( cLum, cLum, cLum ); 1068 } 1069 else if( mnDrawMode & DRAWMODE_SETTINGSLINE ) 1070 { 1071 aColor = GetSettings().GetStyleSettings().GetFontColor(); 1072 } 1073 1074 if ( mnDrawMode & DRAWMODE_GHOSTEDLINE ) 1075 { 1076 aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80, 1077 ( aColor.GetGreen() >> 1 ) | 0x80, 1078 ( aColor.GetBlue() >> 1 ) | 0x80); 1079 } 1080 1081 aHatch.SetColor( aColor ); 1082 } 1083 1084 if( mpMetaFile ) 1085 mpMetaFile->AddAction( new MetaHatchAction( rPolyPoly, aHatch ) ); 1086 1087 if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() ) 1088 return; 1089 1090 if( !mpGraphics && !ImplGetGraphics() ) 1091 return; 1092 1093 if( mbInitClipRegion ) 1094 ImplInitClipRegion(); 1095 1096 if( mbOutputClipped ) 1097 return; 1098 1099 if( rPolyPoly.Count() ) 1100 { 1101 PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) ); 1102 GDIMetaFile* pOldMetaFile = mpMetaFile; 1103 sal_Bool bOldMap = mbMap; 1104 1105 aPolyPoly.Optimize( POLY_OPTIMIZE_NO_SAME ); 1106 aHatch.SetDistance( ImplLogicWidthToDevicePixel( aHatch.GetDistance() ) ); 1107 1108 mpMetaFile = NULL; 1109 EnableMapMode( sal_False ); 1110 Push( PUSH_LINECOLOR ); 1111 SetLineColor( aHatch.GetColor() ); 1112 ImplInitLineColor(); 1113 ImplDrawHatch( aPolyPoly, aHatch, sal_False ); 1114 Pop(); 1115 EnableMapMode( bOldMap ); 1116 mpMetaFile = pOldMetaFile; 1117 } 1118 1119 if( mpAlphaVDev ) 1120 mpAlphaVDev->DrawHatch( rPolyPoly, rHatch ); 1121 } 1122 1123 // ----------------------------------------------------------------------- 1124 1125 void OutputDevice::AddHatchActions( const PolyPolygon& rPolyPoly, const Hatch& rHatch, 1126 GDIMetaFile& rMtf ) 1127 { 1128 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); 1129 1130 PolyPolygon aPolyPoly( rPolyPoly ); 1131 aPolyPoly.Optimize( POLY_OPTIMIZE_NO_SAME | POLY_OPTIMIZE_CLOSE ); 1132 1133 if( aPolyPoly.Count() ) 1134 { 1135 GDIMetaFile* pOldMtf = mpMetaFile; 1136 1137 mpMetaFile = &rMtf; 1138 mpMetaFile->AddAction( new MetaPushAction( PUSH_ALL ) ); 1139 mpMetaFile->AddAction( new MetaLineColorAction( rHatch.GetColor(), sal_True ) ); 1140 ImplDrawHatch( aPolyPoly, rHatch, sal_True ); 1141 mpMetaFile->AddAction( new MetaPopAction() ); 1142 mpMetaFile = pOldMtf; 1143 } 1144 } 1145 1146 // ----------------------------------------------------------------------- 1147 1148 void OutputDevice::ImplDrawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch, sal_Bool bMtf ) 1149 { 1150 if(rPolyPoly.Count()) 1151 { 1152 // #115630# ImplDrawHatch does not work with beziers included in the polypolygon, take care of that 1153 bool bIsCurve(false); 1154 1155 for(sal_uInt16 a(0); !bIsCurve && a < rPolyPoly.Count(); a++) 1156 { 1157 if(rPolyPoly[a].HasFlags()) 1158 { 1159 bIsCurve = true; 1160 } 1161 } 1162 1163 if(bIsCurve) 1164 { 1165 OSL_ENSURE(false, "ImplDrawHatch does *not* support curves, falling back to AdaptiveSubdivide()..."); 1166 PolyPolygon aPolyPoly; 1167 1168 rPolyPoly.AdaptiveSubdivide(aPolyPoly); 1169 ImplDrawHatch(aPolyPoly, rHatch, bMtf); 1170 } 1171 else 1172 { 1173 Rectangle aRect( rPolyPoly.GetBoundRect() ); 1174 const long nLogPixelWidth = ImplDevicePixelToLogicWidth( 1 ); 1175 const long nWidth = ImplDevicePixelToLogicWidth( Max( ImplLogicWidthToDevicePixel( rHatch.GetDistance() ), 3L ) ); 1176 Point* pPtBuffer = new Point[ HATCH_MAXPOINTS ]; 1177 Point aPt1, aPt2, aEndPt1; 1178 Size aInc; 1179 1180 // Single hatch 1181 aRect.Left() -= nLogPixelWidth; aRect.Top() -= nLogPixelWidth; aRect.Right() += nLogPixelWidth; aRect.Bottom() += nLogPixelWidth; 1182 ImplCalcHatchValues( aRect, nWidth, rHatch.GetAngle(), aPt1, aPt2, aInc, aEndPt1 ); 1183 do 1184 { 1185 ImplDrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer, bMtf ); 1186 aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height(); 1187 aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height(); 1188 } 1189 while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) ); 1190 1191 if( ( rHatch.GetStyle() == HATCH_DOUBLE ) || ( rHatch.GetStyle() == HATCH_TRIPLE ) ) 1192 { 1193 // Double hatch 1194 ImplCalcHatchValues( aRect, nWidth, rHatch.GetAngle() + 900, aPt1, aPt2, aInc, aEndPt1 ); 1195 do 1196 { 1197 ImplDrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer, bMtf ); 1198 aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height(); 1199 aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height(); 1200 } 1201 while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) ); 1202 1203 if( rHatch.GetStyle() == HATCH_TRIPLE ) 1204 { 1205 // Triple hatch 1206 ImplCalcHatchValues( aRect, nWidth, rHatch.GetAngle() + 450, aPt1, aPt2, aInc, aEndPt1 ); 1207 do 1208 { 1209 ImplDrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer, bMtf ); 1210 aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height(); 1211 aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height(); 1212 } 1213 while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) ); 1214 } 1215 } 1216 1217 delete[] pPtBuffer; 1218 } 1219 } 1220 } 1221 1222 // ----------------------------------------------------------------------- 1223 1224 void OutputDevice::ImplCalcHatchValues( const Rectangle& rRect, long nDist, sal_uInt16 nAngle10, 1225 Point& rPt1, Point& rPt2, Size& rInc, Point& rEndPt1 ) 1226 { 1227 Point aRef; 1228 long nAngle = nAngle10 % 1800; 1229 long nOffset = 0; 1230 1231 if( nAngle > 900 ) 1232 nAngle -= 1800; 1233 1234 aRef = ( !IsRefPoint() ? rRect.TopLeft() : GetRefPoint() ); 1235 1236 if( 0 == nAngle ) 1237 { 1238 rInc = Size( 0, nDist ); 1239 rPt1 = rRect.TopLeft(); 1240 rPt2 = rRect.TopRight(); 1241 rEndPt1 = rRect.BottomLeft(); 1242 1243 if( aRef.Y() <= rRect.Top() ) 1244 nOffset = ( ( rRect.Top() - aRef.Y() ) % nDist ); 1245 else 1246 nOffset = ( nDist - ( ( aRef.Y() - rRect.Top() ) % nDist ) ); 1247 1248 rPt1.Y() -= nOffset; 1249 rPt2.Y() -= nOffset; 1250 } 1251 else if( 900 == nAngle ) 1252 { 1253 rInc = Size( nDist, 0 ); 1254 rPt1 = rRect.TopLeft(); 1255 rPt2 = rRect.BottomLeft(); 1256 rEndPt1 = rRect.TopRight(); 1257 1258 if( aRef.X() <= rRect.Left() ) 1259 nOffset = ( rRect.Left() - aRef.X() ) % nDist; 1260 else 1261 nOffset = nDist - ( ( aRef.X() - rRect.Left() ) % nDist ); 1262 1263 rPt1.X() -= nOffset; 1264 rPt2.X() -= nOffset; 1265 } 1266 else if( nAngle >= -450 && nAngle <= 450 ) 1267 { 1268 const double fAngle = F_PI1800 * labs( nAngle ); 1269 const double fTan = tan( fAngle ); 1270 const long nYOff = FRound( ( rRect.Right() - rRect.Left() ) * fTan ); 1271 long nPY; 1272 1273 rInc = Size( 0, nDist = FRound( nDist / cos( fAngle ) ) ); 1274 1275 if( nAngle > 0 ) 1276 { 1277 rPt1 = rRect.TopLeft(); 1278 rPt2 = Point( rRect.Right(), rRect.Top() - nYOff ); 1279 rEndPt1 = Point( rRect.Left(), rRect.Bottom() + nYOff ); 1280 nPY = FRound( aRef.Y() - ( ( rPt1.X() - aRef.X() ) * fTan ) ); 1281 } 1282 else 1283 { 1284 rPt1 = rRect.TopRight(); 1285 rPt2 = Point( rRect.Left(), rRect.Top() - nYOff ); 1286 rEndPt1 = Point( rRect.Right(), rRect.Bottom() + nYOff ); 1287 nPY = FRound( aRef.Y() + ( ( rPt1.X() - aRef.X() ) * fTan ) ); 1288 } 1289 1290 if( nPY <= rPt1.Y() ) 1291 nOffset = ( rPt1.Y() - nPY ) % nDist; 1292 else 1293 nOffset = nDist - ( ( nPY - rPt1.Y() ) % nDist ); 1294 1295 rPt1.Y() -= nOffset; 1296 rPt2.Y() -= nOffset; 1297 } 1298 else 1299 { 1300 const double fAngle = F_PI1800 * labs( nAngle ); 1301 const double fTan = tan( fAngle ); 1302 const long nXOff = FRound( ( rRect.Bottom() - rRect.Top() ) / fTan ); 1303 long nPX; 1304 1305 rInc = Size( nDist = FRound( nDist / sin( fAngle ) ), 0 ); 1306 1307 if( nAngle > 0 ) 1308 { 1309 rPt1 = rRect.TopLeft(); 1310 rPt2 = Point( rRect.Left() - nXOff, rRect.Bottom() ); 1311 rEndPt1 = Point( rRect.Right() + nXOff, rRect.Top() ); 1312 nPX = FRound( aRef.X() - ( ( rPt1.Y() - aRef.Y() ) / fTan ) ); 1313 } 1314 else 1315 { 1316 rPt1 = rRect.BottomLeft(); 1317 rPt2 = Point( rRect.Left() - nXOff, rRect.Top() ); 1318 rEndPt1 = Point( rRect.Right() + nXOff, rRect.Bottom() ); 1319 nPX = FRound( aRef.X() + ( ( rPt1.Y() - aRef.Y() ) / fTan ) ); 1320 } 1321 1322 if( nPX <= rPt1.X() ) 1323 nOffset = ( rPt1.X() - nPX ) % nDist; 1324 else 1325 nOffset = nDist - ( ( nPX - rPt1.X() ) % nDist ); 1326 1327 rPt1.X() -= nOffset; 1328 rPt2.X() -= nOffset; 1329 } 1330 } 1331 1332 // ------------------------------------------------------------------------ 1333 1334 void OutputDevice::ImplDrawHatchLine( const Line& rLine, const PolyPolygon& rPolyPoly, 1335 Point* pPtBuffer, sal_Bool bMtf ) 1336 { 1337 double fX, fY; 1338 long nAdd, nPCounter = 0; 1339 1340 for( long nPoly = 0, nPolyCount = rPolyPoly.Count(); nPoly < nPolyCount; nPoly++ ) 1341 { 1342 const Polygon& rPoly = rPolyPoly[ (sal_uInt16) nPoly ]; 1343 1344 if( rPoly.GetSize() > 1 ) 1345 { 1346 Line aCurSegment( rPoly[ 0 ], Point() ); 1347 1348 for( long i = 1, nCount = rPoly.GetSize(); i <= nCount; i++ ) 1349 { 1350 aCurSegment.SetEnd( rPoly[ (sal_uInt16)( i % nCount ) ] ); 1351 nAdd = 0; 1352 1353 if( rLine.Intersection( aCurSegment, fX, fY ) ) 1354 { 1355 if( ( fabs( fX - aCurSegment.GetStart().X() ) <= 0.0000001 ) && 1356 ( fabs( fY - aCurSegment.GetStart().Y() ) <= 0.0000001 ) ) 1357 { 1358 const Line aPrevSegment( rPoly[ (sal_uInt16)( ( i > 1 ) ? ( i - 2 ) : ( nCount - 1 ) ) ], aCurSegment.GetStart() ); 1359 const double fPrevDistance = rLine.GetDistance( aPrevSegment.GetStart() ); 1360 const double fCurDistance = rLine.GetDistance( aCurSegment.GetEnd() ); 1361 1362 if( ( fPrevDistance <= 0.0 && fCurDistance > 0.0 ) || 1363 ( fPrevDistance > 0.0 && fCurDistance < 0.0 ) ) 1364 { 1365 nAdd = 1; 1366 } 1367 } 1368 else if( ( fabs( fX - aCurSegment.GetEnd().X() ) <= 0.0000001 ) && 1369 ( fabs( fY - aCurSegment.GetEnd().Y() ) <= 0.0000001 ) ) 1370 { 1371 const Line aNextSegment( aCurSegment.GetEnd(), rPoly[ (sal_uInt16)( ( i + 1 ) % nCount ) ] ); 1372 1373 if( ( fabs( rLine.GetDistance( aNextSegment.GetEnd() ) ) <= 0.0000001 ) && 1374 ( rLine.GetDistance( aCurSegment.GetStart() ) > 0.0 ) ) 1375 { 1376 nAdd = 1; 1377 } 1378 } 1379 else 1380 nAdd = 1; 1381 1382 if( nAdd ) 1383 pPtBuffer[ nPCounter++ ] = Point( FRound( fX ), FRound( fY ) ); 1384 } 1385 1386 aCurSegment.SetStart( aCurSegment.GetEnd() ); 1387 } 1388 } 1389 } 1390 1391 if( nPCounter > 1 ) 1392 { 1393 qsort( pPtBuffer, nPCounter, sizeof( Point ), ImplHatchCmpFnc ); 1394 1395 if( nPCounter & 1 ) 1396 nPCounter--; 1397 1398 if( bMtf ) 1399 { 1400 for( long i = 0; i < nPCounter; i += 2 ) 1401 mpMetaFile->AddAction( new MetaLineAction( pPtBuffer[ i ], pPtBuffer[ i + 1 ] ) ); 1402 } 1403 else 1404 { 1405 for( long i = 0; i < nPCounter; i += 2 ) 1406 { 1407 if( mpPDFWriter ) 1408 { 1409 mpPDFWriter->drawLine( pPtBuffer[ i ], pPtBuffer[ i+1 ] ); 1410 } 1411 else 1412 { 1413 const Point aPt1( ImplLogicToDevicePixel( pPtBuffer[ i ] ) ); 1414 const Point aPt2( ImplLogicToDevicePixel( pPtBuffer[ i + 1 ] ) ); 1415 mpGraphics->DrawLine( aPt1.X(), aPt1.Y(), aPt2.X(), aPt2.Y(), this ); 1416 } 1417 } 1418 } 1419 } 1420 } 1421