LibreOffice Module vcl (master)  1
outdev/gradient.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <memory>
21 #include <cassert>
22 
23 #include <tools/poly.hxx>
24 #include <vcl/gdimtf.hxx>
25 #include <vcl/gradient.hxx>
26 #include <vcl/metaact.hxx>
27 #include <vcl/settings.hxx>
28 #include <vcl/outdev.hxx>
29 #include <vcl/virdev.hxx>
30 #include <vcl/window.hxx>
31 
32 #include <salgdi.hxx>
33 
34 #define GRADIENT_DEFAULT_STEPCOUNT 0
35 
37  const Gradient& rGradient )
38 {
40 
41  // Convert rectangle to a tools::PolyPolygon by first converting to a Polygon
42  tools::Polygon aPolygon ( rRect );
43  tools::PolyPolygon aPolyPoly ( aPolygon );
44 
45  DrawGradient ( aPolyPoly, rGradient );
46 }
47 
49  const Gradient& rGradient )
50 {
52 
53  if (mbInitClipRegion)
55  // don't return on mbOutputClipped here, as we may need to draw the clipped metafile, even if the output is clipped
56 
57  if ( rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize() )
58  {
60  {
62 
64  SetLineColor( aColor );
65  SetFillColor( aColor );
66  DrawPolyPolygon( rPolyPoly );
67  Pop();
68  return;
69  }
70 
71  Gradient aGradient( rGradient );
72 
74  aGradient.MakeGrayscale();
75 
76  DrawGradientToMetafile( rPolyPoly, rGradient );
77 
79  return;
80 
81  // Clip and then draw the gradient
82  if( !tools::Rectangle( PixelToLogic( Point() ), GetOutputSize() ).IsEmpty() )
83  {
84  const tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
85 
86  // convert rectangle to pixels
87  tools::Rectangle aRect( ImplLogicToDevicePixel( aBoundRect ) );
88  aRect.Justify();
89 
90  // do nothing if the rectangle is empty
91  if ( !aRect.IsEmpty() )
92  {
93  tools::PolyPolygon aClixPolyPoly( ImplLogicToDevicePixel( rPolyPoly ) );
94  bool bDrawn = false;
95 
96  if( !mpGraphics && !AcquireGraphics() )
97  return;
98 
99  // secure clip region
101  IntersectClipRegion( aBoundRect );
102 
103  if (mbInitClipRegion)
104  InitClipRegion();
105 
106  // try to draw gradient natively
107  if (!mbOutputClipped)
108  bDrawn = mpGraphics->DrawGradient( aClixPolyPoly, aGradient, *this );
109 
110  if (!bDrawn && !mbOutputClipped)
111  {
112  // draw gradients without border
114  {
116  mbInitLineColor = true;
117  }
118 
119  mbInitFillColor = true;
120 
121  // calculate step count if necessary
122  if ( !aGradient.GetSteps() )
124 
125  if ( rPolyPoly.IsRect() )
126  {
127  // because we draw with no border line, we have to expand gradient
128  // rect to avoid missing lines on the right and bottom edge
129  aRect.AdjustLeft( -1 );
130  aRect.AdjustTop( -1 );
131  aRect.AdjustRight( 1 );
132  aRect.AdjustBottom( 1 );
133  }
134 
135  // if the clipping polypolygon is a rectangle, then it's the same size as the bounding of the
136  // polypolygon, so pass in a NULL for the clipping parameter
137  if( aGradient.GetStyle() == GradientStyle::Linear || rGradient.GetStyle() == GradientStyle::Axial )
138  DrawLinearGradient( aRect, aGradient, aClixPolyPoly.IsRect() ? nullptr : &aClixPolyPoly );
139  else
140  DrawComplexGradient( aRect, aGradient, aClixPolyPoly.IsRect() ? nullptr : &aClixPolyPoly );
141  }
142 
143  Pop();
144  }
145  }
146  }
147 
148  if( mpAlphaVDev )
149  {
150  const Color aFillCol( mpAlphaVDev->GetFillColor() );
152  mpAlphaVDev->DrawPolyPolygon( rPolyPoly );
153  mpAlphaVDev->SetFillColor( aFillCol );
154  }
155 }
156 
157 void OutputDevice::ClipAndDrawGradientMetafile ( const Gradient &rGradient, const tools::PolyPolygon &rPolyPoly )
158 {
159  const tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
160  const bool bOldOutput = IsOutputEnabled();
161 
162  EnableOutput( false );
165  DrawGradient( aBoundRect, rGradient );
168  DrawPolyPolygon( rPolyPoly );
170  DrawGradient( aBoundRect, rGradient );
171  Pop();
172  EnableOutput( bOldOutput );
173 }
174 
176  const Gradient& rGradient )
177 {
179 
180  if ( !mpMetaFile )
181  return;
182 
183  if ( !(rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize()) )
184  return;
185 
186  Gradient aGradient( rGradient );
187 
189  aGradient.MakeGrayscale();
190 
191  const tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
192 
193  if ( rPolyPoly.IsRect() )
194  {
195  mpMetaFile->AddAction( new MetaGradientAction( aBoundRect, aGradient ) );
196  }
197  else
198  {
199  mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_BEGIN" ) );
200  mpMetaFile->AddAction( new MetaGradientExAction( rPolyPoly, rGradient ) );
201 
202  ClipAndDrawGradientMetafile ( rGradient, rPolyPoly );
203 
204  mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_END" ) );
205  }
206 
208  return;
209 
210  // Clip and then draw the gradient
211  if( tools::Rectangle( PixelToLogic( Point() ), GetOutputSize() ).IsEmpty() )
212  return;
213 
214  // convert rectangle to pixels
215  tools::Rectangle aRect( ImplLogicToDevicePixel( aBoundRect ) );
216  aRect.Justify();
217 
218  // do nothing if the rectangle is empty
219  if ( aRect.IsEmpty() )
220  return;
221 
222  if( mbOutputClipped )
223  return;
224 
225  // calculate step count if necessary
226  if ( !aGradient.GetSteps() )
228 
229  if ( rPolyPoly.IsRect() )
230  {
231  // because we draw with no border line, we have to expand gradient
232  // rect to avoid missing lines on the right and bottom edge
233  aRect.AdjustLeft( -1 );
234  aRect.AdjustTop( -1 );
235  aRect.AdjustRight( 1 );
236  aRect.AdjustBottom( 1 );
237  }
238 
239  // if the clipping polypolygon is a rectangle, then it's the same size as the bounding of the
240  // polypolygon, so pass in a NULL for the clipping parameter
241  if( aGradient.GetStyle() == GradientStyle::Linear || rGradient.GetStyle() == GradientStyle::Axial )
242  DrawLinearGradientToMetafile( aRect, aGradient );
243  else
244  DrawComplexGradientToMetafile( aRect, aGradient );
245 }
246 
247 namespace
248 {
249  sal_uInt8 GetGradientColorValue( tools::Long nValue )
250  {
251  if ( nValue < 0 )
252  return 0;
253  else if ( nValue > 0xFF )
254  return 0xFF;
255  else
256  return static_cast<sal_uInt8>(nValue);
257  }
258 }
259 
261  const Gradient& rGradient,
262  const tools::PolyPolygon* pClixPolyPoly )
263 {
265 
266  // get BoundRect of rotated rectangle
267  tools::Rectangle aRect;
268  Point aCenter;
269  Degree10 nAngle = rGradient.GetAngle() % 3600_deg10;
270 
271  rGradient.GetBoundRect( rRect, aRect, aCenter );
272 
273  bool bLinear = (rGradient.GetStyle() == GradientStyle::Linear);
274  double fBorder = rGradient.GetBorder() * aRect.GetHeight() / 100.0;
275  if ( !bLinear )
276  {
277  fBorder /= 2.0;
278  }
279  tools::Rectangle aMirrorRect = aRect; // used in style axial
280  aMirrorRect.SetTop( ( aRect.Top() + aRect.Bottom() ) / 2 );
281  if ( !bLinear )
282  {
283  aRect.SetBottom( aMirrorRect.Top() );
284  }
285 
286  // colour-intensities of start- and finish; change if needed
287  tools::Long nFactor;
288  Color aStartCol = rGradient.GetStartColor();
289  Color aEndCol = rGradient.GetEndColor();
290  tools::Long nStartRed = aStartCol.GetRed();
291  tools::Long nStartGreen = aStartCol.GetGreen();
292  tools::Long nStartBlue = aStartCol.GetBlue();
293  tools::Long nEndRed = aEndCol.GetRed();
294  tools::Long nEndGreen = aEndCol.GetGreen();
295  tools::Long nEndBlue = aEndCol.GetBlue();
296  nFactor = rGradient.GetStartIntensity();
297  nStartRed = (nStartRed * nFactor) / 100;
298  nStartGreen = (nStartGreen * nFactor) / 100;
299  nStartBlue = (nStartBlue * nFactor) / 100;
300  nFactor = rGradient.GetEndIntensity();
301  nEndRed = (nEndRed * nFactor) / 100;
302  nEndGreen = (nEndGreen * nFactor) / 100;
303  nEndBlue = (nEndBlue * nFactor) / 100;
304 
305  // gradient style axial has exchanged start and end colors
306  if ( !bLinear)
307  {
308  tools::Long nTempColor = nStartRed;
309  nStartRed = nEndRed;
310  nEndRed = nTempColor;
311  nTempColor = nStartGreen;
312  nStartGreen = nEndGreen;
313  nEndGreen = nTempColor;
314  nTempColor = nStartBlue;
315  nStartBlue = nEndBlue;
316  nEndBlue = nTempColor;
317  }
318 
319  sal_uInt8 nRed;
320  sal_uInt8 nGreen;
321  sal_uInt8 nBlue;
322 
323  // Create border
324  tools::Rectangle aBorderRect = aRect;
325  tools::Polygon aPoly( 4 );
326  if (fBorder > 0.0)
327  {
328  nRed = static_cast<sal_uInt8>(nStartRed);
329  nGreen = static_cast<sal_uInt8>(nStartGreen);
330  nBlue = static_cast<sal_uInt8>(nStartBlue);
331 
332  mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
333 
334  aBorderRect.SetBottom( static_cast<tools::Long>( aBorderRect.Top() + fBorder ) );
335  aRect.SetTop( aBorderRect.Bottom() );
336  aPoly[0] = aBorderRect.TopLeft();
337  aPoly[1] = aBorderRect.TopRight();
338  aPoly[2] = aBorderRect.BottomRight();
339  aPoly[3] = aBorderRect.BottomLeft();
340  aPoly.Rotate( aCenter, nAngle );
341 
342  ImplDrawPolygon( aPoly, pClixPolyPoly );
343 
344  if ( !bLinear)
345  {
346  aBorderRect = aMirrorRect;
347  aBorderRect.SetTop( static_cast<tools::Long>( aBorderRect.Bottom() - fBorder ) );
348  aMirrorRect.SetBottom( aBorderRect.Top() );
349  aPoly[0] = aBorderRect.TopLeft();
350  aPoly[1] = aBorderRect.TopRight();
351  aPoly[2] = aBorderRect.BottomRight();
352  aPoly[3] = aBorderRect.BottomLeft();
353  aPoly.Rotate( aCenter, nAngle );
354 
355  ImplDrawPolygon( aPoly, pClixPolyPoly );
356  }
357  }
358 
359  // calculate step count
360  tools::Long nStepCount = GetGradientSteps( rGradient, aRect, false/*bMtf*/ );
361 
362  // minimal three steps and maximal as max color steps
363  tools::Long nAbsRedSteps = std::abs( nEndRed - nStartRed );
364  tools::Long nAbsGreenSteps = std::abs( nEndGreen - nStartGreen );
365  tools::Long nAbsBlueSteps = std::abs( nEndBlue - nStartBlue );
366  tools::Long nMaxColorSteps = std::max( nAbsRedSteps , nAbsGreenSteps );
367  nMaxColorSteps = std::max( nMaxColorSteps, nAbsBlueSteps );
368  tools::Long nSteps = std::min( nStepCount, nMaxColorSteps );
369  if ( nSteps < 3)
370  {
371  nSteps = 3;
372  }
373 
374  double fScanInc = static_cast<double>(aRect.GetHeight()) / static_cast<double>(nSteps);
375  double fGradientLine = static_cast<double>(aRect.Top());
376  double fMirrorGradientLine = static_cast<double>(aMirrorRect.Bottom());
377 
378  const double fStepsMinus1 = static_cast<double>(nSteps) - 1.0;
379  if ( !bLinear)
380  {
381  nSteps -= 1; // draw middle polygons as one polygon after loop to avoid gap
382  }
383  for ( tools::Long i = 0; i < nSteps; i++ )
384  {
385  // linear interpolation of color
386  const double fAlpha = static_cast<double>(i) / fStepsMinus1;
387  double fTempColor = static_cast<double>(nStartRed) * (1.0-fAlpha) + static_cast<double>(nEndRed) * fAlpha;
388  nRed = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
389  fTempColor = static_cast<double>(nStartGreen) * (1.0-fAlpha) + static_cast<double>(nEndGreen) * fAlpha;
390  nGreen = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
391  fTempColor = static_cast<double>(nStartBlue) * (1.0-fAlpha) + static_cast<double>(nEndBlue) * fAlpha;
392  nBlue = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
393 
394  mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
395 
396  // Polygon for this color step
397  aRect.SetTop( static_cast<tools::Long>( fGradientLine + static_cast<double>(i) * fScanInc ) );
398  aRect.SetBottom( static_cast<tools::Long>( fGradientLine + ( static_cast<double>(i) + 1.0 ) * fScanInc ) );
399  aPoly[0] = aRect.TopLeft();
400  aPoly[1] = aRect.TopRight();
401  aPoly[2] = aRect.BottomRight();
402  aPoly[3] = aRect.BottomLeft();
403  aPoly.Rotate( aCenter, nAngle );
404 
405  ImplDrawPolygon( aPoly, pClixPolyPoly );
406 
407  if ( !bLinear )
408  {
409  aMirrorRect.SetBottom( static_cast<tools::Long>( fMirrorGradientLine - static_cast<double>(i) * fScanInc ) );
410  aMirrorRect.SetTop( static_cast<tools::Long>( fMirrorGradientLine - (static_cast<double>(i) + 1.0)* fScanInc ) );
411  aPoly[0] = aMirrorRect.TopLeft();
412  aPoly[1] = aMirrorRect.TopRight();
413  aPoly[2] = aMirrorRect.BottomRight();
414  aPoly[3] = aMirrorRect.BottomLeft();
415  aPoly.Rotate( aCenter, nAngle );
416 
417  ImplDrawPolygon( aPoly, pClixPolyPoly );
418  }
419  }
420  if ( bLinear)
421  return;
422 
423  // draw middle polygon with end color
424  nRed = GetGradientColorValue(nEndRed);
425  nGreen = GetGradientColorValue(nEndGreen);
426  nBlue = GetGradientColorValue(nEndBlue);
427 
428  mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
429 
430  aRect.SetTop( static_cast<tools::Long>( fGradientLine + static_cast<double>(nSteps) * fScanInc ) );
431  aRect.SetBottom( static_cast<tools::Long>( fMirrorGradientLine - static_cast<double>(nSteps) * fScanInc ) );
432  aPoly[0] = aRect.TopLeft();
433  aPoly[1] = aRect.TopRight();
434  aPoly[2] = aRect.BottomRight();
435  aPoly[3] = aRect.BottomLeft();
436  aPoly.Rotate( aCenter, nAngle );
437 
438  ImplDrawPolygon( aPoly, pClixPolyPoly );
439 
440 }
441 
443 {
444  const vcl::Window *pWindow = dynamic_cast<const vcl::Window*>(this);
445  return pWindow && pWindow->SupportsDoubleBuffering();
446 }
447 
449  const Gradient& rGradient,
450  const tools::PolyPolygon* pClixPolyPoly )
451 {
453 
454  // Determine if we output via Polygon or PolyPolygon
455  // For all rasteroperations other than Overpaint always use PolyPolygon,
456  // as we will get wrong results if we output multiple times on top of each other.
457  // Also for printers always use PolyPolygon, as not all printers
458  // can print polygons on top of each other.
459 
460  std::unique_ptr<tools::PolyPolygon> xPolyPoly;
461  tools::Rectangle aRect;
462  Point aCenter;
463  Color aStartCol( rGradient.GetStartColor() );
464  Color aEndCol( rGradient.GetEndColor() );
465  tools::Long nStartRed = ( static_cast<tools::Long>(aStartCol.GetRed()) * rGradient.GetStartIntensity() ) / 100;
466  tools::Long nStartGreen = ( static_cast<tools::Long>(aStartCol.GetGreen()) * rGradient.GetStartIntensity() ) / 100;
467  tools::Long nStartBlue = ( static_cast<tools::Long>(aStartCol.GetBlue()) * rGradient.GetStartIntensity() ) / 100;
468  tools::Long nEndRed = ( static_cast<tools::Long>(aEndCol.GetRed()) * rGradient.GetEndIntensity() ) / 100;
469  tools::Long nEndGreen = ( static_cast<tools::Long>(aEndCol.GetGreen()) * rGradient.GetEndIntensity() ) / 100;
470  tools::Long nEndBlue = ( static_cast<tools::Long>(aEndCol.GetBlue()) * rGradient.GetEndIntensity() ) / 100;
471  tools::Long nRedSteps = nEndRed - nStartRed;
472  tools::Long nGreenSteps = nEndGreen - nStartGreen;
473  tools::Long nBlueSteps = nEndBlue - nStartBlue;
474  Degree10 nAngle = rGradient.GetAngle() % 3600_deg10;
475 
476  rGradient.GetBoundRect( rRect, aRect, aCenter );
477 
479  xPolyPoly.reset(new tools::PolyPolygon( 2 ));
480 
481  tools::Long nStepCount = GetGradientSteps( rGradient, rRect, false/*bMtf*/, true/*bComplex*/ );
482 
483  // at least three steps and at most the number of colour differences
484  tools::Long nSteps = std::max( nStepCount, tools::Long(2) );
485  tools::Long nCalcSteps = std::abs( nRedSteps );
486  tools::Long nTempSteps = std::abs( nGreenSteps );
487  if ( nTempSteps > nCalcSteps )
488  nCalcSteps = nTempSteps;
489  nTempSteps = std::abs( nBlueSteps );
490  if ( nTempSteps > nCalcSteps )
491  nCalcSteps = nTempSteps;
492  if ( nCalcSteps < nSteps )
493  nSteps = nCalcSteps;
494  if ( !nSteps )
495  nSteps = 1;
496 
497  // determine output limits and stepsizes for all directions
498  tools::Polygon aPoly;
499  double fScanLeft = aRect.Left();
500  double fScanTop = aRect.Top();
501  double fScanRight = aRect.Right();
502  double fScanBottom = aRect.Bottom();
503  double fScanIncX = static_cast<double>(aRect.GetWidth()) / static_cast<double>(nSteps) * 0.5;
504  double fScanIncY = static_cast<double>(aRect.GetHeight()) / static_cast<double>(nSteps) * 0.5;
505 
506  // all gradients are rendered as nested rectangles which shrink
507  // equally in each dimension - except for 'square' gradients
508  // which shrink to a central vertex but are not per-se square.
509  if( rGradient.GetStyle() != GradientStyle::Square )
510  {
511  fScanIncY = std::min( fScanIncY, fScanIncX );
512  fScanIncX = fScanIncY;
513  }
514  sal_uInt8 nRed = static_cast<sal_uInt8>(nStartRed), nGreen = static_cast<sal_uInt8>(nStartGreen), nBlue = static_cast<sal_uInt8>(nStartBlue);
515  bool bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
516 
517  mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
518 
519  if( xPolyPoly )
520  {
521  aPoly = rRect;
522  xPolyPoly->Insert( aPoly );
523  xPolyPoly->Insert( aPoly );
524  }
525  else
526  {
527  // extend rect, to avoid missing bounding line
528  tools::Rectangle aExtRect( rRect );
529 
530  aExtRect.AdjustLeft( -1 );
531  aExtRect.AdjustTop( -1 );
532  aExtRect.AdjustRight(1 );
533  aExtRect.AdjustBottom(1 );
534 
535  aPoly = aExtRect;
536  ImplDrawPolygon( aPoly, pClixPolyPoly );
537  }
538 
539  // loop to output Polygon/PolyPolygon sequentially
540  for( tools::Long i = 1; i < nSteps; i++ )
541  {
542  // calculate new Polygon
543  fScanLeft += fScanIncX;
544  aRect.SetLeft( static_cast<tools::Long>( fScanLeft ) );
545  fScanTop += fScanIncY;
546  aRect.SetTop( static_cast<tools::Long>( fScanTop ) );
547  fScanRight -= fScanIncX;
548  aRect.SetRight( static_cast<tools::Long>( fScanRight ) );
549  fScanBottom -= fScanIncY;
550  aRect.SetBottom( static_cast<tools::Long>( fScanBottom ) );
551 
552  if( ( aRect.GetWidth() < 2 ) || ( aRect.GetHeight() < 2 ) )
553  break;
554 
555  if( rGradient.GetStyle() == GradientStyle::Radial || rGradient.GetStyle() == GradientStyle::Elliptical )
556  aPoly = tools::Polygon( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
557  else
558  aPoly = tools::Polygon( aRect );
559 
560  aPoly.Rotate( aCenter, nAngle );
561 
562  // adapt colour accordingly
563  const tools::Long nStepIndex = ( xPolyPoly ? i : ( i + 1 ) );
564  nRed = GetGradientColorValue( nStartRed + ( ( nRedSteps * nStepIndex ) / nSteps ) );
565  nGreen = GetGradientColorValue( nStartGreen + ( ( nGreenSteps * nStepIndex ) / nSteps ) );
566  nBlue = GetGradientColorValue( nStartBlue + ( ( nBlueSteps * nStepIndex ) / nSteps ) );
567 
568  // either slow tools::PolyPolygon output or fast Polygon-Painting
569  if( xPolyPoly )
570  {
571  bPaintLastPolygon = true; // #107349# Paint last polygon only if loop has generated any output
572 
573  xPolyPoly->Replace( xPolyPoly->GetObject( 1 ), 0 );
574  xPolyPoly->Replace( aPoly, 1 );
575 
576  ImplDrawPolyPolygon( *xPolyPoly, pClixPolyPoly );
577 
578  // #107349# Set fill color _after_ geometry painting:
579  // xPolyPoly's geometry is the band from last iteration's
580  // aPoly to current iteration's aPoly. The window outdev
581  // path (see else below), on the other hand, paints the
582  // full aPoly. Thus, here, we're painting the band before
583  // the one painted in the window outdev path below. To get
584  // matching colors, have to delay color setting here.
585  mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
586  }
587  else
588  {
589  // #107349# Set fill color _before_ geometry painting
590  mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
591 
592  ImplDrawPolygon( aPoly, pClixPolyPoly );
593  }
594  }
595 
596  // we should draw last inner Polygon if we output PolyPolygon
597  if( !xPolyPoly )
598  return;
599 
600  const tools::Polygon& rPoly = xPolyPoly->GetObject( 1 );
601 
602  if( rPoly.GetBoundRect().IsEmpty() )
603  return;
604 
605  // #107349# Paint last polygon with end color only if loop
606  // has generated output. Otherwise, the current
607  // (i.e. start) color is taken, to generate _any_ output.
608  if( bPaintLastPolygon )
609  {
610  nRed = GetGradientColorValue( nEndRed );
611  nGreen = GetGradientColorValue( nEndGreen );
612  nBlue = GetGradientColorValue( nEndBlue );
613  }
614 
615  mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
616  ImplDrawPolygon( rPoly, pClixPolyPoly );
617 }
618 
620  const Gradient& rGradient )
621 {
623 
624  // get BoundRect of rotated rectangle
625  tools::Rectangle aRect;
626  Point aCenter;
627  Degree10 nAngle = rGradient.GetAngle() % 3600_deg10;
628 
629  rGradient.GetBoundRect( rRect, aRect, aCenter );
630 
631  bool bLinear = (rGradient.GetStyle() == GradientStyle::Linear);
632  double fBorder = rGradient.GetBorder() * aRect.GetHeight() / 100.0;
633  if ( !bLinear )
634  {
635  fBorder /= 2.0;
636  }
637  tools::Rectangle aMirrorRect = aRect; // used in style axial
638  aMirrorRect.SetTop( ( aRect.Top() + aRect.Bottom() ) / 2 );
639  if ( !bLinear )
640  {
641  aRect.SetBottom( aMirrorRect.Top() );
642  }
643 
644  // colour-intensities of start- and finish; change if needed
645  tools::Long nFactor;
646  Color aStartCol = rGradient.GetStartColor();
647  Color aEndCol = rGradient.GetEndColor();
648  tools::Long nStartRed = aStartCol.GetRed();
649  tools::Long nStartGreen = aStartCol.GetGreen();
650  tools::Long nStartBlue = aStartCol.GetBlue();
651  tools::Long nEndRed = aEndCol.GetRed();
652  tools::Long nEndGreen = aEndCol.GetGreen();
653  tools::Long nEndBlue = aEndCol.GetBlue();
654  nFactor = rGradient.GetStartIntensity();
655  nStartRed = (nStartRed * nFactor) / 100;
656  nStartGreen = (nStartGreen * nFactor) / 100;
657  nStartBlue = (nStartBlue * nFactor) / 100;
658  nFactor = rGradient.GetEndIntensity();
659  nEndRed = (nEndRed * nFactor) / 100;
660  nEndGreen = (nEndGreen * nFactor) / 100;
661  nEndBlue = (nEndBlue * nFactor) / 100;
662 
663  // gradient style axial has exchanged start and end colors
664  if ( !bLinear)
665  {
666  tools::Long nTempColor = nStartRed;
667  nStartRed = nEndRed;
668  nEndRed = nTempColor;
669  nTempColor = nStartGreen;
670  nStartGreen = nEndGreen;
671  nEndGreen = nTempColor;
672  nTempColor = nStartBlue;
673  nStartBlue = nEndBlue;
674  nEndBlue = nTempColor;
675  }
676 
677  sal_uInt8 nRed;
678  sal_uInt8 nGreen;
679  sal_uInt8 nBlue;
680 
681  // Create border
682  tools::Rectangle aBorderRect = aRect;
683  tools::Polygon aPoly( 4 );
684  if (fBorder > 0.0)
685  {
686  nRed = static_cast<sal_uInt8>(nStartRed);
687  nGreen = static_cast<sal_uInt8>(nStartGreen);
688  nBlue = static_cast<sal_uInt8>(nStartBlue);
689 
690  mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
691 
692  aBorderRect.SetBottom( static_cast<tools::Long>( aBorderRect.Top() + fBorder ) );
693  aRect.SetTop( aBorderRect.Bottom() );
694  aPoly[0] = aBorderRect.TopLeft();
695  aPoly[1] = aBorderRect.TopRight();
696  aPoly[2] = aBorderRect.BottomRight();
697  aPoly[3] = aBorderRect.BottomLeft();
698  aPoly.Rotate( aCenter, nAngle );
699 
700  mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
701 
702  if ( !bLinear)
703  {
704  aBorderRect = aMirrorRect;
705  aBorderRect.SetTop( static_cast<tools::Long>( aBorderRect.Bottom() - fBorder ) );
706  aMirrorRect.SetBottom( aBorderRect.Top() );
707  aPoly[0] = aBorderRect.TopLeft();
708  aPoly[1] = aBorderRect.TopRight();
709  aPoly[2] = aBorderRect.BottomRight();
710  aPoly[3] = aBorderRect.BottomLeft();
711  aPoly.Rotate( aCenter, nAngle );
712 
713  mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
714  }
715  }
716 
717  tools::Long nStepCount = GetGradientSteps( rGradient, aRect, true/*bMtf*/ );
718 
719  // minimal three steps and maximal as max color steps
720  tools::Long nAbsRedSteps = std::abs( nEndRed - nStartRed );
721  tools::Long nAbsGreenSteps = std::abs( nEndGreen - nStartGreen );
722  tools::Long nAbsBlueSteps = std::abs( nEndBlue - nStartBlue );
723  tools::Long nMaxColorSteps = std::max( nAbsRedSteps , nAbsGreenSteps );
724  nMaxColorSteps = std::max( nMaxColorSteps, nAbsBlueSteps );
725  tools::Long nSteps = std::min( nStepCount, nMaxColorSteps );
726  if ( nSteps < 3)
727  {
728  nSteps = 3;
729  }
730 
731  double fScanInc = static_cast<double>(aRect.GetHeight()) / static_cast<double>(nSteps);
732  double fGradientLine = static_cast<double>(aRect.Top());
733  double fMirrorGradientLine = static_cast<double>(aMirrorRect.Bottom());
734 
735  const double fStepsMinus1 = static_cast<double>(nSteps) - 1.0;
736  if ( !bLinear)
737  {
738  nSteps -= 1; // draw middle polygons as one polygon after loop to avoid gap
739  }
740  for ( tools::Long i = 0; i < nSteps; i++ )
741  {
742  // linear interpolation of color
743  double fAlpha = static_cast<double>(i) / fStepsMinus1;
744  double fTempColor = static_cast<double>(nStartRed) * (1.0-fAlpha) + static_cast<double>(nEndRed) * fAlpha;
745  nRed = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
746  fTempColor = static_cast<double>(nStartGreen) * (1.0-fAlpha) + static_cast<double>(nEndGreen) * fAlpha;
747  nGreen = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
748  fTempColor = static_cast<double>(nStartBlue) * (1.0-fAlpha) + static_cast<double>(nEndBlue) * fAlpha;
749  nBlue = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
750 
751  mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
752 
753  // Polygon for this color step
754  aRect.SetTop( static_cast<tools::Long>( fGradientLine + static_cast<double>(i) * fScanInc ) );
755  aRect.SetBottom( static_cast<tools::Long>( fGradientLine + ( static_cast<double>(i) + 1.0 ) * fScanInc ) );
756  aPoly[0] = aRect.TopLeft();
757  aPoly[1] = aRect.TopRight();
758  aPoly[2] = aRect.BottomRight();
759  aPoly[3] = aRect.BottomLeft();
760  aPoly.Rotate( aCenter, nAngle );
761 
762  mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
763 
764  if ( !bLinear )
765  {
766  aMirrorRect.SetBottom( static_cast<tools::Long>( fMirrorGradientLine - static_cast<double>(i) * fScanInc ) );
767  aMirrorRect.SetTop( static_cast<tools::Long>( fMirrorGradientLine - (static_cast<double>(i) + 1.0)* fScanInc ) );
768  aPoly[0] = aMirrorRect.TopLeft();
769  aPoly[1] = aMirrorRect.TopRight();
770  aPoly[2] = aMirrorRect.BottomRight();
771  aPoly[3] = aMirrorRect.BottomLeft();
772  aPoly.Rotate( aCenter, nAngle );
773 
774  mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
775  }
776  }
777  if ( bLinear)
778  return;
779 
780  // draw middle polygon with end color
781  nRed = GetGradientColorValue(nEndRed);
782  nGreen = GetGradientColorValue(nEndGreen);
783  nBlue = GetGradientColorValue(nEndBlue);
784 
785  mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
786 
787  aRect.SetTop( static_cast<tools::Long>( fGradientLine + static_cast<double>(nSteps) * fScanInc ) );
788  aRect.SetBottom( static_cast<tools::Long>( fMirrorGradientLine - static_cast<double>(nSteps) * fScanInc ) );
789  aPoly[0] = aRect.TopLeft();
790  aPoly[1] = aRect.TopRight();
791  aPoly[2] = aRect.BottomRight();
792  aPoly[3] = aRect.BottomLeft();
793  aPoly.Rotate( aCenter, nAngle );
794 
795  mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
796 
797 }
798 
800  const Gradient& rGradient )
801 {
803 
804  // Determine if we output via Polygon or PolyPolygon
805  // For all rasteroperations other than Overpaint always use PolyPolygon,
806  // as we will get wrong results if we output multiple times on top of each other.
807  // Also for printers always use PolyPolygon, as not all printers
808  // can print polygons on top of each other.
809 
810  std::unique_ptr<tools::PolyPolygon> xPolyPoly;
811  tools::Rectangle aRect;
812  Point aCenter;
813  Color aStartCol( rGradient.GetStartColor() );
814  Color aEndCol( rGradient.GetEndColor() );
815  tools::Long nStartRed = ( static_cast<tools::Long>(aStartCol.GetRed()) * rGradient.GetStartIntensity() ) / 100;
816  tools::Long nStartGreen = ( static_cast<tools::Long>(aStartCol.GetGreen()) * rGradient.GetStartIntensity() ) / 100;
817  tools::Long nStartBlue = ( static_cast<tools::Long>(aStartCol.GetBlue()) * rGradient.GetStartIntensity() ) / 100;
818  tools::Long nEndRed = ( static_cast<tools::Long>(aEndCol.GetRed()) * rGradient.GetEndIntensity() ) / 100;
819  tools::Long nEndGreen = ( static_cast<tools::Long>(aEndCol.GetGreen()) * rGradient.GetEndIntensity() ) / 100;
820  tools::Long nEndBlue = ( static_cast<tools::Long>(aEndCol.GetBlue()) * rGradient.GetEndIntensity() ) / 100;
821  tools::Long nRedSteps = nEndRed - nStartRed;
822  tools::Long nGreenSteps = nEndGreen - nStartGreen;
823  tools::Long nBlueSteps = nEndBlue - nStartBlue;
824  Degree10 nAngle = rGradient.GetAngle() % 3600_deg10;
825 
826  rGradient.GetBoundRect( rRect, aRect, aCenter );
827 
828  xPolyPoly.reset(new tools::PolyPolygon( 2 ));
829 
830  // last parameter - true if complex gradient, false if linear
831  tools::Long nStepCount = GetGradientSteps( rGradient, rRect, true, true );
832 
833  // at least three steps and at most the number of colour differences
834  tools::Long nSteps = std::max( nStepCount, tools::Long(2) );
835  tools::Long nCalcSteps = std::abs( nRedSteps );
836  tools::Long nTempSteps = std::abs( nGreenSteps );
837  if ( nTempSteps > nCalcSteps )
838  nCalcSteps = nTempSteps;
839  nTempSteps = std::abs( nBlueSteps );
840  if ( nTempSteps > nCalcSteps )
841  nCalcSteps = nTempSteps;
842  if ( nCalcSteps < nSteps )
843  nSteps = nCalcSteps;
844  if ( !nSteps )
845  nSteps = 1;
846 
847  // determine output limits and stepsizes for all directions
848  tools::Polygon aPoly;
849  double fScanLeft = aRect.Left();
850  double fScanTop = aRect.Top();
851  double fScanRight = aRect.Right();
852  double fScanBottom = aRect.Bottom();
853  double fScanIncX = static_cast<double>(aRect.GetWidth()) / static_cast<double>(nSteps) * 0.5;
854  double fScanIncY = static_cast<double>(aRect.GetHeight()) / static_cast<double>(nSteps) * 0.5;
855 
856  // all gradients are rendered as nested rectangles which shrink
857  // equally in each dimension - except for 'square' gradients
858  // which shrink to a central vertex but are not per-se square.
859  if( rGradient.GetStyle() != GradientStyle::Square )
860  {
861  fScanIncY = std::min( fScanIncY, fScanIncX );
862  fScanIncX = fScanIncY;
863  }
864  sal_uInt8 nRed = static_cast<sal_uInt8>(nStartRed), nGreen = static_cast<sal_uInt8>(nStartGreen), nBlue = static_cast<sal_uInt8>(nStartBlue);
865  bool bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
866 
867  mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
868 
869  aPoly = rRect;
870  xPolyPoly->Insert( aPoly );
871  xPolyPoly->Insert( aPoly );
872 
873  // loop to output Polygon/PolyPolygon sequentially
874  for( tools::Long i = 1; i < nSteps; i++ )
875  {
876  // calculate new Polygon
877  fScanLeft += fScanIncX;
878  aRect.SetLeft( static_cast<tools::Long>( fScanLeft ) );
879  fScanTop += fScanIncY;
880  aRect.SetTop( static_cast<tools::Long>( fScanTop ) );
881  fScanRight -= fScanIncX;
882  aRect.SetRight( static_cast<tools::Long>( fScanRight ) );
883  fScanBottom -= fScanIncY;
884  aRect.SetBottom( static_cast<tools::Long>( fScanBottom ) );
885 
886  if( ( aRect.GetWidth() < 2 ) || ( aRect.GetHeight() < 2 ) )
887  break;
888 
889  if( rGradient.GetStyle() == GradientStyle::Radial || rGradient.GetStyle() == GradientStyle::Elliptical )
890  aPoly = tools::Polygon( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
891  else
892  aPoly = tools::Polygon( aRect );
893 
894  aPoly.Rotate( aCenter, nAngle );
895 
896  // adapt colour accordingly
897  const tools::Long nStepIndex = ( xPolyPoly ? i : ( i + 1 ) );
898  nRed = GetGradientColorValue( nStartRed + ( ( nRedSteps * nStepIndex ) / nSteps ) );
899  nGreen = GetGradientColorValue( nStartGreen + ( ( nGreenSteps * nStepIndex ) / nSteps ) );
900  nBlue = GetGradientColorValue( nStartBlue + ( ( nBlueSteps * nStepIndex ) / nSteps ) );
901 
902  bPaintLastPolygon = true; // #107349# Paint last polygon only if loop has generated any output
903 
904  xPolyPoly->Replace( xPolyPoly->GetObject( 1 ), 0 );
905  xPolyPoly->Replace( aPoly, 1 );
906 
907  mpMetaFile->AddAction( new MetaPolyPolygonAction( *xPolyPoly ) );
908 
909  // #107349# Set fill color _after_ geometry painting:
910  // xPolyPoly's geometry is the band from last iteration's
911  // aPoly to current iteration's aPoly. The window outdev
912  // path (see else below), on the other hand, paints the
913  // full aPoly. Thus, here, we're painting the band before
914  // the one painted in the window outdev path below. To get
915  // matching colors, have to delay color setting here.
916  mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
917  }
918 
919  const tools::Polygon& rPoly = xPolyPoly->GetObject( 1 );
920 
921  if( rPoly.GetBoundRect().IsEmpty() )
922  return;
923 
924  // #107349# Paint last polygon with end color only if loop
925  // has generated output. Otherwise, the current
926  // (i.e. start) color is taken, to generate _any_ output.
927  if( bPaintLastPolygon )
928  {
929  nRed = GetGradientColorValue( nEndRed );
930  nGreen = GetGradientColorValue( nEndGreen );
931  nBlue = GetGradientColorValue( nEndBlue );
932  }
933 
934  mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
935  mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) );
936 }
937 
939 {
940  tools::Long nInc = (nMinRect < 50) ? 2 : 4;
941 
942  return nInc;
943 }
944 
945 tools::Long OutputDevice::GetGradientSteps( const Gradient& rGradient, const tools::Rectangle& rRect, bool bMtf, bool bComplex )
946 {
947  // calculate step count
948  tools::Long nStepCount = rGradient.GetSteps();
949  tools::Long nMinRect;
950 
951  // generate nStepCount, if not passed
952  if (bComplex)
953  nMinRect = std::min( rRect.GetWidth(), rRect.GetHeight() );
954  else
955  nMinRect = rRect.GetHeight();
956 
957  if ( !nStepCount )
958  {
959  tools::Long nInc;
960 
961  nInc = GetGradientStepCount (nMinRect);
962  if ( !nInc || bMtf )
963  nInc = 1;
964  nStepCount = nMinRect / nInc;
965  }
966 
967  return nStepCount;
968 }
969 
971 {
972  Color aColor;
973 
974  // we should never call on this function if any of these aren't set!
976 
978  aColor = COL_BLACK;
980  aColor = COL_WHITE;
983 
984  return aColor;
985 }
986 
987 void OutputDevice::AddGradientActions( const tools::Rectangle& rRect, const Gradient& rGradient,
988  GDIMetaFile& rMtf )
989 {
990 
991  tools::Rectangle aRect( rRect );
992 
993  aRect.Justify();
994 
995  // do nothing if the rectangle is empty
996  if ( aRect.IsEmpty() )
997  return;
998 
999  Gradient aGradient( rGradient );
1000  GDIMetaFile* pOldMtf = mpMetaFile;
1001 
1002  mpMetaFile = &rMtf;
1003  mpMetaFile->AddAction( new MetaPushAction( PushFlags::ALL ) );
1004  mpMetaFile->AddAction( new MetaISectRectClipRegionAction( aRect ) );
1005  mpMetaFile->AddAction( new MetaLineColorAction( Color(), false ) );
1006 
1007  // because we draw with no border line, we have to expand gradient
1008  // rect to avoid missing lines on the right and bottom edge
1009  aRect.AdjustLeft( -1 );
1010  aRect.AdjustTop( -1 );
1011  aRect.AdjustRight( 1 );
1012  aRect.AdjustBottom( 1 );
1013 
1014  // calculate step count if necessary
1015  if ( !aGradient.GetSteps() )
1016  aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
1017 
1018  if( aGradient.GetStyle() == GradientStyle::Linear || aGradient.GetStyle() == GradientStyle::Axial )
1019  DrawLinearGradientToMetafile( aRect, aGradient );
1020  else
1021  DrawComplexGradientToMetafile( aRect, aGradient );
1022 
1023  mpMetaFile->AddAction( new MetaPopAction() );
1024  mpMetaFile = pOldMtf;
1025 
1026 }
1027 
1028 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 Count() const
void EnableOutput(bool bEnable=true)
Point TopLeft() const
virtual tools::Long GetGradientStepCount(tools::Long nMinRect)
GradientStyle GetStyle() const
sal_uInt8 GetRed() const
SAL_DLLPRIVATE bool ImplIsRecordLayout() const
Definition: outdev.cxx:644
virtual bool UsePolyPolygonForComplexGradient()=0
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
SAL_DLLPRIVATE void DrawComplexGradient(const tools::Rectangle &rRect, const Gradient &rGradient, const tools::PolyPolygon *pClipPolyPoly)
SAL_DLLPRIVATE tools::Long GetGradientSteps(const Gradient &rGradient, const tools::Rectangle &rRect, bool bMtf, bool bComplex=false)
Point BottomLeft() const
DrawModeFlags mnDrawMode
Definition: outdev.hxx:354
long Long
const StyleSettings & GetStyleSettings() const
bool IsOutputEnabled() const
Definition: outdev.hxx:604
bool mbOutputClipped
Definition: outdev.hxx:379
sal_uInt16 GetBorder() const
SAL_DLLPRIVATE bool is_double_buffered_window() const
tools::Long GetWidth() const
SAL_DLLPRIVATE void DrawLinearGradientToMetafile(const tools::Rectangle &rRect, const Gradient &rGradient)
void IntersectClipRegion(const tools::Rectangle &rRect)
SAL_DLLPRIVATE Color GetSingleColorGradientFill()
#define GRADIENT_DEFAULT_STEPCOUNT
SAL_DLLPRIVATE void DrawGradientToMetafile(const tools::PolyPolygon &rPolyPoly, const Gradient &rGradient)
void SetRight(tools::Long v)
bool DrawGradient(const tools::PolyPolygon &rPolyPoly, const Gradient &rGradient, const OutputDevice &rOutDev)
bool IsEmpty() const
void SetSteps(sal_uInt16 nSteps)
tools::Long Left() const
SAL_DLLPRIVATE void DrawLinearGradient(const tools::Rectangle &rRect, const Gradient &rGradient, const tools::PolyPolygon *pClipPolyPoly)
void SetLeft(tools::Long v)
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
tools::Long Bottom() const
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
sal_uInt8 GetBlue() const
void Rotate(const Point &rCenter, double fSin, double fCos)
SalGraphics * mpGraphics
Graphics context to draw on.
Definition: outdev.hxx:315
Point BottomRight() const
virtual void SetFillColor()=0
void SetLineColor()
void GetBoundRect(const tools::Rectangle &rRect, tools::Rectangle &rBoundRect, Point &rCenter) const
int i
virtual void SetLineColor()=0
virtual bool AcquireGraphics() const =0
Acquire a graphics device that the output device uses to draw on.
bool IsRect() const
Size GetOutputSize() const
Definition: outdev.hxx:454
bool mbInitLineColor
Definition: outdev.hxx:382
void SetFillColor()
sal_uInt16 GetEndIntensity() const
void AddGradientActions(const tools::Rectangle &rRect, const Gradient &rGradient, GDIMetaFile &rMtf)
bool mbLineColor
Definition: outdev.hxx:380
void SetTop(tools::Long v)
void SetBottom(tools::Long v)
const AllSettings & GetSettings() const
Definition: outdev.hxx:418
tools::Long Top() const
sal_uInt16 GetSteps() const
tools::Long AdjustTop(tools::Long nVertMoveDelta)
const Color & GetStartColor() const
Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1021
sal_uInt8 GetGreen() const
VclPtr< VirtualDevice > mpAlphaVDev
Definition: outdev.hxx:330
Degree10 GetAngle() const
SAL_DLLPRIVATE void DrawComplexGradientToMetafile(const tools::Rectangle &rRect, const Gradient &rGradient)
SAL_DLLPRIVATE void ImplDrawPolyPolygon(const tools::PolyPolygon &rPolyPoly, const tools::PolyPolygon *pClipPolyPoly)
Definition: polygon.cxx:463
void MakeGrayscale()
unsigned char sal_uInt8
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:564
bool mbInitClipRegion
Definition: outdev.hxx:386
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_WHITE
const Color & GetEndColor() const
void SetRasterOp(RasterOp eRasterOp)
void DrawPolyPolygon(const tools::PolyPolygon &rPolyPoly)
Render the given poly-polygon.
Definition: polygon.cxx:36
virtual void InitClipRegion()
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BLACK
const Color & GetWindowColor() const
bool mbInitFillColor
Definition: outdev.hxx:383
SAL_DLLPRIVATE tools::Rectangle ImplLogicToDevicePixel(const tools::Rectangle &rLogicRect) const
Convert a logical rectangle to a rectangle in physical device pixel units.
Definition: map.cxx:376
tools::Long GetHeight() const
tools::Rectangle GetBoundRect() const
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
tools::Rectangle GetBoundRect() const
bool IsDeviceOutputNecessary() const
Definition: outdev.hxx:605
void Push(PushFlags nFlags=PushFlags::ALL)
Definition: outdevstate.cxx:59
void DrawGradient(const tools::Rectangle &rRect, const Gradient &rGradient)
bool SupportsDoubleBuffering() const
Can the widget derived from this Window do the double-buffering via RenderContext properly...
Definition: window.cxx:3850
sal_uInt16 GetStartIntensity() const
virtual void ClipAndDrawGradientMetafile(const Gradient &rGradient, const tools::PolyPolygon &rPolyPoly)
Point TopRight() const
tools::Long Right() const
Point Center() const
const Color & GetFillColor() const
Definition: outdev.hxx:639
GDIMetaFile * mpMetaFile
Definition: outdev.hxx:318
SAL_DLLPRIVATE void ImplDrawPolygon(const tools::Polygon &rPoly, const tools::PolyPolygon *pClipPolyPoly=nullptr)
Definition: polygon.cxx:445