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