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 {
39  assert(!is_double_buffered_window());
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 {
51  assert(!is_double_buffered_window());
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 {
178  assert(!is_double_buffered_window());
179 
180  if ( !mpMetaFile )
181  return;
182 
183  if ( !(rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize()) )
184  return;
185 
186  const tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
187 
188  if (aBoundRect.IsEmpty())
189  return;
190 
191  Gradient aGradient( rGradient );
192 
194  aGradient.MakeGrayscale();
195 
196  if ( rPolyPoly.IsRect() )
197  {
198  mpMetaFile->AddAction( new MetaGradientAction( aBoundRect, aGradient ) );
199  }
200  else
201  {
202  mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_BEGIN" ) );
203  mpMetaFile->AddAction( new MetaGradientExAction( rPolyPoly, rGradient ) );
204 
205  ClipAndDrawGradientMetafile ( rGradient, rPolyPoly );
206 
207  mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_END" ) );
208  }
209 }
210 
211 namespace
212 {
214  {
215  if ( nValue < 0 )
216  return 0;
217  else if ( nValue > 0xFF )
218  return 0xFF;
219  else
220  return static_cast<sal_uInt8>(nValue);
221  }
222 }
223 
225  const Gradient& rGradient,
226  const tools::PolyPolygon* pClixPolyPoly )
227 {
228  assert(!is_double_buffered_window());
229 
230  // get BoundRect of rotated rectangle
231  tools::Rectangle aRect;
232  Point aCenter;
233  Degree10 nAngle = rGradient.GetAngle() % 3600_deg10;
234 
235  rGradient.GetBoundRect( rRect, aRect, aCenter );
236 
237  bool bLinear = (rGradient.GetStyle() == GradientStyle::Linear);
238  double fBorder = rGradient.GetBorder() * aRect.GetHeight() / 100.0;
239  if ( !bLinear )
240  {
241  fBorder /= 2.0;
242  }
243  tools::Rectangle aMirrorRect = aRect; // used in style axial
244  aMirrorRect.SetTop( ( aRect.Top() + aRect.Bottom() ) / 2 );
245  if ( !bLinear )
246  {
247  aRect.SetBottom( aMirrorRect.Top() );
248  }
249 
250  // colour-intensities of start- and finish; change if needed
251  tools::Long nFactor;
252  Color aStartCol = rGradient.GetStartColor();
253  Color aEndCol = rGradient.GetEndColor();
254  tools::Long nStartRed = aStartCol.GetRed();
255  tools::Long nStartGreen = aStartCol.GetGreen();
256  tools::Long nStartBlue = aStartCol.GetBlue();
257  tools::Long nEndRed = aEndCol.GetRed();
258  tools::Long nEndGreen = aEndCol.GetGreen();
259  tools::Long nEndBlue = aEndCol.GetBlue();
260  nFactor = rGradient.GetStartIntensity();
261  nStartRed = (nStartRed * nFactor) / 100;
262  nStartGreen = (nStartGreen * nFactor) / 100;
263  nStartBlue = (nStartBlue * nFactor) / 100;
264  nFactor = rGradient.GetEndIntensity();
265  nEndRed = (nEndRed * nFactor) / 100;
266  nEndGreen = (nEndGreen * nFactor) / 100;
267  nEndBlue = (nEndBlue * nFactor) / 100;
268 
269  // gradient style axial has exchanged start and end colors
270  if ( !bLinear)
271  {
272  tools::Long nTempColor = nStartRed;
273  nStartRed = nEndRed;
274  nEndRed = nTempColor;
275  nTempColor = nStartGreen;
276  nStartGreen = nEndGreen;
277  nEndGreen = nTempColor;
278  nTempColor = nStartBlue;
279  nStartBlue = nEndBlue;
280  nEndBlue = nTempColor;
281  }
282 
283  sal_uInt8 nRed;
284  sal_uInt8 nGreen;
285  sal_uInt8 nBlue;
286 
287  // Create border
288  tools::Rectangle aBorderRect = aRect;
289  tools::Polygon aPoly( 4 );
290  if (fBorder > 0.0)
291  {
292  nRed = static_cast<sal_uInt8>(nStartRed);
293  nGreen = static_cast<sal_uInt8>(nStartGreen);
294  nBlue = static_cast<sal_uInt8>(nStartBlue);
295 
296  mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
297 
298  aBorderRect.SetBottom( static_cast<tools::Long>( aBorderRect.Top() + fBorder ) );
299  aRect.SetTop( aBorderRect.Bottom() );
300  aPoly[0] = aBorderRect.TopLeft();
301  aPoly[1] = aBorderRect.TopRight();
302  aPoly[2] = aBorderRect.BottomRight();
303  aPoly[3] = aBorderRect.BottomLeft();
304  aPoly.Rotate( aCenter, nAngle );
305 
306  ImplDrawPolygon( aPoly, pClixPolyPoly );
307 
308  if ( !bLinear)
309  {
310  aBorderRect = aMirrorRect;
311  aBorderRect.SetTop( static_cast<tools::Long>( aBorderRect.Bottom() - fBorder ) );
312  aMirrorRect.SetBottom( aBorderRect.Top() );
313  aPoly[0] = aBorderRect.TopLeft();
314  aPoly[1] = aBorderRect.TopRight();
315  aPoly[2] = aBorderRect.BottomRight();
316  aPoly[3] = aBorderRect.BottomLeft();
317  aPoly.Rotate( aCenter, nAngle );
318 
319  ImplDrawPolygon( aPoly, pClixPolyPoly );
320  }
321  }
322 
323  // calculate step count
324  tools::Long nStepCount = GetGradientSteps(rGradient, aRect);
325 
326  // minimal three steps and maximal as max color steps
327  tools::Long nAbsRedSteps = std::abs( nEndRed - nStartRed );
328  tools::Long nAbsGreenSteps = std::abs( nEndGreen - nStartGreen );
329  tools::Long nAbsBlueSteps = std::abs( nEndBlue - nStartBlue );
330  tools::Long nMaxColorSteps = std::max( nAbsRedSteps , nAbsGreenSteps );
331  nMaxColorSteps = std::max( nMaxColorSteps, nAbsBlueSteps );
332  tools::Long nSteps = std::min( nStepCount, nMaxColorSteps );
333  if ( nSteps < 3)
334  {
335  nSteps = 3;
336  }
337 
338  double fScanInc = static_cast<double>(aRect.GetHeight()) / static_cast<double>(nSteps);
339  double fGradientLine = static_cast<double>(aRect.Top());
340  double fMirrorGradientLine = static_cast<double>(aMirrorRect.Bottom());
341 
342  const double fStepsMinus1 = static_cast<double>(nSteps) - 1.0;
343  if ( !bLinear)
344  {
345  nSteps -= 1; // draw middle polygons as one polygon after loop to avoid gap
346  }
347 
348  for ( tools::Long i = 0; i < nSteps; i++ )
349  {
350  // linear interpolation of color
351  const double fAlpha = static_cast<double>(i) / fStepsMinus1;
352  double fTempColor = static_cast<double>(nStartRed) * (1.0-fAlpha) + static_cast<double>(nEndRed) * fAlpha;
353  nRed = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
354  fTempColor = static_cast<double>(nStartGreen) * (1.0-fAlpha) + static_cast<double>(nEndGreen) * fAlpha;
355  nGreen = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
356  fTempColor = static_cast<double>(nStartBlue) * (1.0-fAlpha) + static_cast<double>(nEndBlue) * fAlpha;
357  nBlue = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
358 
359  mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
360 
361  // Polygon for this color step
362  aRect.SetTop( static_cast<tools::Long>( fGradientLine + static_cast<double>(i) * fScanInc ) );
363  aRect.SetBottom( static_cast<tools::Long>( fGradientLine + ( static_cast<double>(i) + 1.0 ) * fScanInc ) );
364  aPoly[0] = aRect.TopLeft();
365  aPoly[1] = aRect.TopRight();
366  aPoly[2] = aRect.BottomRight();
367  aPoly[3] = aRect.BottomLeft();
368  aPoly.Rotate( aCenter, nAngle );
369 
370  ImplDrawPolygon( aPoly, pClixPolyPoly );
371 
372  if ( !bLinear )
373  {
374  aMirrorRect.SetBottom( static_cast<tools::Long>( fMirrorGradientLine - static_cast<double>(i) * fScanInc ) );
375  aMirrorRect.SetTop( static_cast<tools::Long>( fMirrorGradientLine - (static_cast<double>(i) + 1.0)* fScanInc ) );
376  aPoly[0] = aMirrorRect.TopLeft();
377  aPoly[1] = aMirrorRect.TopRight();
378  aPoly[2] = aMirrorRect.BottomRight();
379  aPoly[3] = aMirrorRect.BottomLeft();
380  aPoly.Rotate( aCenter, nAngle );
381 
382  ImplDrawPolygon( aPoly, pClixPolyPoly );
383  }
384  }
385  if ( bLinear)
386  return;
387 
388  // draw middle polygon with end color
389  nRed = GetGradientColorValue(nEndRed);
390  nGreen = GetGradientColorValue(nEndGreen);
391  nBlue = GetGradientColorValue(nEndBlue);
392 
393  mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
394 
395  aRect.SetTop( static_cast<tools::Long>( fGradientLine + static_cast<double>(nSteps) * fScanInc ) );
396  aRect.SetBottom( static_cast<tools::Long>( fMirrorGradientLine - static_cast<double>(nSteps) * fScanInc ) );
397  aPoly[0] = aRect.TopLeft();
398  aPoly[1] = aRect.TopRight();
399  aPoly[2] = aRect.BottomRight();
400  aPoly[3] = aRect.BottomLeft();
401  aPoly.Rotate( aCenter, nAngle );
402 
403  ImplDrawPolygon( aPoly, pClixPolyPoly );
404 
405 }
406 
408 {
409  auto pOwnerWindow = GetOwnerWindow();
410  return pOwnerWindow && pOwnerWindow->SupportsDoubleBuffering();
411 }
412 
414  const Gradient& rGradient,
415  const tools::PolyPolygon* pClixPolyPoly )
416 {
417  assert(!is_double_buffered_window());
418 
419  // Determine if we output via Polygon or PolyPolygon
420  // For all rasteroperations other than Overpaint always use PolyPolygon,
421  // as we will get wrong results if we output multiple times on top of each other.
422  // Also for printers always use PolyPolygon, as not all printers
423  // can print polygons on top of each other.
424 
425  std::optional<tools::PolyPolygon> xPolyPoly;
426  tools::Rectangle aRect;
427  Point aCenter;
428  Color aStartCol( rGradient.GetStartColor() );
429  Color aEndCol( rGradient.GetEndColor() );
430  tools::Long nStartRed = ( static_cast<tools::Long>(aStartCol.GetRed()) * rGradient.GetStartIntensity() ) / 100;
431  tools::Long nStartGreen = ( static_cast<tools::Long>(aStartCol.GetGreen()) * rGradient.GetStartIntensity() ) / 100;
432  tools::Long nStartBlue = ( static_cast<tools::Long>(aStartCol.GetBlue()) * rGradient.GetStartIntensity() ) / 100;
433  tools::Long nEndRed = ( static_cast<tools::Long>(aEndCol.GetRed()) * rGradient.GetEndIntensity() ) / 100;
434  tools::Long nEndGreen = ( static_cast<tools::Long>(aEndCol.GetGreen()) * rGradient.GetEndIntensity() ) / 100;
435  tools::Long nEndBlue = ( static_cast<tools::Long>(aEndCol.GetBlue()) * rGradient.GetEndIntensity() ) / 100;
436  tools::Long nRedSteps = nEndRed - nStartRed;
437  tools::Long nGreenSteps = nEndGreen - nStartGreen;
438  tools::Long nBlueSteps = nEndBlue - nStartBlue;
439  Degree10 nAngle = rGradient.GetAngle() % 3600_deg10;
440 
441  rGradient.GetBoundRect( rRect, aRect, aCenter );
442 
444  xPolyPoly = tools::PolyPolygon( 2 );
445 
446  tools::Long nStepCount = GetGradientSteps(rGradient, rRect);
447 
448  // at least three steps and at most the number of colour differences
449  tools::Long nSteps = std::max( nStepCount, tools::Long(2) );
450  tools::Long nCalcSteps = std::abs( nRedSteps );
451  tools::Long nTempSteps = std::abs( nGreenSteps );
452  if ( nTempSteps > nCalcSteps )
453  nCalcSteps = nTempSteps;
454  nTempSteps = std::abs( nBlueSteps );
455  if ( nTempSteps > nCalcSteps )
456  nCalcSteps = nTempSteps;
457  if ( nCalcSteps < nSteps )
458  nSteps = nCalcSteps;
459  if ( !nSteps )
460  nSteps = 1;
461 
462  // determine output limits and stepsizes for all directions
463  tools::Polygon aPoly;
464  double fScanLeft = aRect.Left();
465  double fScanTop = aRect.Top();
466  double fScanRight = aRect.Right();
467  double fScanBottom = aRect.Bottom();
468  double fScanIncX = static_cast<double>(aRect.GetWidth()) / static_cast<double>(nSteps) * 0.5;
469  double fScanIncY = static_cast<double>(aRect.GetHeight()) / static_cast<double>(nSteps) * 0.5;
470 
471  // all gradients are rendered as nested rectangles which shrink
472  // equally in each dimension - except for 'square' gradients
473  // which shrink to a central vertex but are not per-se square.
474  if( rGradient.GetStyle() != GradientStyle::Square )
475  {
476  fScanIncY = std::min( fScanIncY, fScanIncX );
477  fScanIncX = fScanIncY;
478  }
479  sal_uInt8 nRed = static_cast<sal_uInt8>(nStartRed), nGreen = static_cast<sal_uInt8>(nStartGreen), nBlue = static_cast<sal_uInt8>(nStartBlue);
480  bool bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
481 
482  mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
483 
484  if( xPolyPoly )
485  {
486  aPoly = rRect;
487  xPolyPoly->Insert( aPoly );
488  xPolyPoly->Insert( aPoly );
489  }
490  else
491  {
492  // extend rect, to avoid missing bounding line
493  tools::Rectangle aExtRect( rRect );
494 
495  aExtRect.AdjustLeft( -1 );
496  aExtRect.AdjustTop( -1 );
497  aExtRect.AdjustRight(1 );
498  aExtRect.AdjustBottom(1 );
499 
500  aPoly = aExtRect;
501  ImplDrawPolygon( aPoly, pClixPolyPoly );
502  }
503 
504  // loop to output Polygon/PolyPolygon sequentially
505  for( tools::Long i = 1; i < nSteps; i++ )
506  {
507  // calculate new Polygon
508  fScanLeft += fScanIncX;
509  aRect.SetLeft( static_cast<tools::Long>( fScanLeft ) );
510  fScanTop += fScanIncY;
511  aRect.SetTop( static_cast<tools::Long>( fScanTop ) );
512  fScanRight -= fScanIncX;
513  aRect.SetRight( static_cast<tools::Long>( fScanRight ) );
514  fScanBottom -= fScanIncY;
515  aRect.SetBottom( static_cast<tools::Long>( fScanBottom ) );
516 
517  if( ( aRect.GetWidth() < 2 ) || ( aRect.GetHeight() < 2 ) )
518  break;
519 
520  if( rGradient.GetStyle() == GradientStyle::Radial || rGradient.GetStyle() == GradientStyle::Elliptical )
521  aPoly = tools::Polygon( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
522  else
523  aPoly = tools::Polygon( aRect );
524 
525  aPoly.Rotate( aCenter, nAngle );
526 
527  // adapt colour accordingly
528  const tools::Long nStepIndex = ( xPolyPoly ? i : ( i + 1 ) );
529  nRed = GetGradientColorValue( nStartRed + ( ( nRedSteps * nStepIndex ) / nSteps ) );
530  nGreen = GetGradientColorValue( nStartGreen + ( ( nGreenSteps * nStepIndex ) / nSteps ) );
531  nBlue = GetGradientColorValue( nStartBlue + ( ( nBlueSteps * nStepIndex ) / nSteps ) );
532 
533  // either slow tools::PolyPolygon output or fast Polygon-Painting
534  if( xPolyPoly )
535  {
536  bPaintLastPolygon = true; // #107349# Paint last polygon only if loop has generated any output
537 
538  xPolyPoly->Replace( xPolyPoly->GetObject( 1 ), 0 );
539  xPolyPoly->Replace( aPoly, 1 );
540 
541  ImplDrawPolyPolygon( *xPolyPoly, pClixPolyPoly );
542 
543  // #107349# Set fill color _after_ geometry painting:
544  // xPolyPoly's geometry is the band from last iteration's
545  // aPoly to current iteration's aPoly. The window outdev
546  // path (see else below), on the other hand, paints the
547  // full aPoly. Thus, here, we're painting the band before
548  // the one painted in the window outdev path below. To get
549  // matching colors, have to delay color setting here.
550  mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
551  }
552  else
553  {
554  // #107349# Set fill color _before_ geometry painting
555  mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
556 
557  ImplDrawPolygon( aPoly, pClixPolyPoly );
558  }
559  }
560 
561  // we should draw last inner Polygon if we output PolyPolygon
562  if( !xPolyPoly )
563  return;
564 
565  const tools::Polygon& rPoly = xPolyPoly->GetObject( 1 );
566 
567  if( rPoly.GetBoundRect().IsEmpty() )
568  return;
569 
570  // #107349# Paint last polygon with end color only if loop
571  // has generated output. Otherwise, the current
572  // (i.e. start) color is taken, to generate _any_ output.
573  if( bPaintLastPolygon )
574  {
575  nRed = GetGradientColorValue( nEndRed );
576  nGreen = GetGradientColorValue( nEndGreen );
577  nBlue = GetGradientColorValue( nEndBlue );
578  }
579 
580  mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
581  ImplDrawPolygon( rPoly, pClixPolyPoly );
582 }
583 
585 {
586  tools::Long nInc = (nMinRect < 50) ? 2 : 4;
587 
588  return nInc;
589 }
590 
592 {
593  // calculate step count
594  tools::Long nStepCount = rGradient.GetSteps();
595 
596  if (nStepCount)
597  return nStepCount;
598 
599  tools::Long nMinRect = 0;
600 
601  if (rGradient.GetStyle() == GradientStyle::Linear || rGradient.GetStyle() == GradientStyle::Axial)
602  nMinRect = rRect.GetHeight();
603  else
604  nMinRect = std::min(rRect.GetWidth(), rRect.GetHeight());
605 
606  tools::Long nInc = GetGradientStepCount(nMinRect);
607 
608  if (!nInc)
609  nInc = 1;
610 
611  return nMinRect / nInc;
612 }
613 
615 {
616  Color aColor;
617 
618  // we should never call on this function if any of these aren't set!
620 
622  aColor = COL_BLACK;
624  aColor = COL_WHITE;
627 
628  return aColor;
629 }
630 
631 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 Count() const
void EnableOutput(bool bEnable=true)
Definition: outdev.cxx:343
virtual tools::Long GetGradientStepCount(tools::Long nMinRect)
GradientStyle GetStyle() const
sal_uInt8 GetRed() const
SAL_DLLPRIVATE bool ImplIsRecordLayout() const
Definition: outdev.cxx:724
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)
constexpr tools::Long Left() const
DrawModeFlags mnDrawMode
Definition: outdev.hxx:226
long Long
const StyleSettings & GetStyleSettings() const
void Push(vcl::PushFlags nFlags=vcl::PushFlags::ALL)
Definition: stack.cxx:33
bool IsOutputEnabled() const
Definition: outdev.hxx:487
bool mbOutputClipped
Definition: outdev.hxx:252
sal_uInt16 GetBorder() const
SAL_DLLPRIVATE bool is_double_buffered_window() const
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)
bool DrawGradient(const tools::PolyPolygon &rPolyPoly, const Gradient &rGradient, const OutputDevice &rOutDev)
void SetSteps(sal_uInt16 nSteps)
SAL_DLLPRIVATE void DrawLinearGradient(const tools::Rectangle &rRect, const Gradient &rGradient, const tools::PolyPolygon *pClipPolyPoly)
constexpr Point BottomLeft() const
constexpr tools::Long GetWidth() const
void Pop()
Definition: stack.cxx:92
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
sal_uInt8 GetBlue() const
constexpr bool IsEmpty() const
void Rotate(const Point &rCenter, double fSin, double fCos)
constexpr void SetLeft(tools::Long v)
static sal_uInt8 GetGradientColorValue(tools::Long nValue)
SalGraphics * mpGraphics
Graphics context to draw on.
Definition: outdev.hxx:188
virtual void SetFillColor()=0
void SetLineColor()
Definition: line.cxx:36
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:334
bool mbInitLineColor
Definition: outdev.hxx:255
constexpr tools::Long Right() const
void SetFillColor()
Definition: fill.cxx:29
constexpr tools::Long Top() const
sal_uInt16 GetEndIntensity() const
bool mbLineColor
Definition: outdev.hxx:253
constexpr void SetRight(tools::Long v)
const AllSettings & GetSettings() const
Definition: outdev.hxx:295
constexpr void SetBottom(tools::Long v)
constexpr void SetTop(tools::Long v)
constexpr Point Center() const
sal_uInt16 GetSteps() const
constexpr Point TopLeft() const
tools::Long AdjustTop(tools::Long nVertMoveDelta)
const Color & GetStartColor() const
constexpr tools::Long Bottom() const
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1164
sal_uInt8 GetGreen() const
VclPtr< VirtualDevice > mpAlphaVDev
Definition: outdev.hxx:202
Degree10 GetAngle() const
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:581
bool mbInitClipRegion
Definition: outdev.hxx:259
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_WHITE
constexpr Point TopRight() const
const Color & GetEndColor() const
void SetRasterOp(RasterOp eRasterOp)
Definition: outdev.cxx:322
SAL_DLLPRIVATE tools::Long GetGradientSteps(Gradient const &rGradient, tools::Rectangle const &rRect)
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:256
constexpr Point BottomRight() const
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:386
tools::Rectangle GetBoundRect() const
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
tools::Rectangle GetBoundRect() const
bool IsDeviceOutputNecessary() const
Definition: outdev.hxx:488
void DrawGradient(const tools::Rectangle &rRect, const Gradient &rGradient)
virtual vcl::Window * GetOwnerWindow() const
Get the vcl::Window that this OutputDevice belongs to, if any.
Definition: outdev.hxx:1923
sal_uInt16 GetStartIntensity() const
virtual void ClipAndDrawGradientMetafile(const Gradient &rGradient, const tools::PolyPolygon &rPolyPoly)
const Color & GetFillColor() const
Definition: outdev.hxx:526
GDIMetaFile * mpMetaFile
Definition: outdev.hxx:191
SAL_DLLPRIVATE void ImplDrawPolygon(const tools::Polygon &rPoly, const tools::PolyPolygon *pClipPolyPoly=nullptr)
Definition: polygon.cxx:445
constexpr tools::Long GetHeight() const