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 <tools/poly.hxx>
21
22#include <vcl/gradient.hxx>
23#include <vcl/metaact.hxx>
24#include <vcl/settings.hxx>
25#include <vcl/virdev.hxx>
26#include <vcl/window.hxx>
27
28#include <salgdi.hxx>
29
30#include <cassert>
31#include <memory>
32
33#define GRADIENT_DEFAULT_STEPCOUNT 0
34
36 const Gradient& rGradient )
37{
39
40 // Convert rectangle to a tools::PolyPolygon by first converting to a Polygon
41 tools::Polygon aPolygon ( rRect );
42 tools::PolyPolygon aPolyPoly ( aPolygon );
43
44 DrawGradient ( aPolyPoly, rGradient );
45}
46
48 const Gradient& rGradient )
49{
51
54 // don't return on mbOutputClipped here, as we may need to draw the clipped metafile, even if the output is clipped
55
56 if ( rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize() )
57 {
59 {
61
63 SetLineColor( aColor );
64 SetFillColor( aColor );
65 DrawPolyPolygon( rPolyPoly );
66 Pop();
67 return;
68 }
69
70 Gradient aGradient( rGradient );
71
73 aGradient.MakeGrayscale();
74
75 DrawGradientToMetafile( rPolyPoly, rGradient );
76
78 return;
79
80 // Clip and then draw the gradient
81 if( !tools::Rectangle( PixelToLogic( Point() ), GetOutputSize() ).IsEmpty() )
82 {
83 const tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
84
85 // convert rectangle to pixels
86 tools::Rectangle aRect( ImplLogicToDevicePixel( aBoundRect ) );
87 aRect.Normalize();
88
89 // do nothing if the rectangle is empty
90 if ( !aRect.IsEmpty() )
91 {
92 tools::PolyPolygon aClixPolyPoly( ImplLogicToDevicePixel( rPolyPoly ) );
93 bool bDrawn = false;
94
95 if( !mpGraphics && !AcquireGraphics() )
96 return;
97
98 // secure clip region
100 IntersectClipRegion( aBoundRect );
101
104
105 // try to draw gradient natively
106 if (!mbOutputClipped)
107 bDrawn = mpGraphics->DrawGradient( aClixPolyPoly, aGradient, *this );
108
109 if (!bDrawn && !mbOutputClipped)
110 {
111 // draw gradients without border
113 {
115 mbInitLineColor = true;
116 }
117
118 mbInitFillColor = true;
119
120 // calculate step count if necessary
121 if ( !aGradient.GetSteps() )
123
124 if ( rPolyPoly.IsRect() )
125 {
126 // because we draw with no border line, we have to expand gradient
127 // rect to avoid missing lines on the right and bottom edge
128 aRect.AdjustLeft( -1 );
129 aRect.AdjustTop( -1 );
130 aRect.AdjustRight( 1 );
131 aRect.AdjustBottom( 1 );
132 }
133
134 // if the clipping polypolygon is a rectangle, then it's the same size as the bounding of the
135 // polypolygon, so pass in a NULL for the clipping parameter
136 if( aGradient.GetStyle() == GradientStyle::Linear || rGradient.GetStyle() == GradientStyle::Axial )
137 DrawLinearGradient( aRect, aGradient, aClixPolyPoly.IsRect() ? nullptr : &aClixPolyPoly );
138 else
139 DrawComplexGradient( aRect, aGradient, aClixPolyPoly.IsRect() ? nullptr : &aClixPolyPoly );
140 }
141
142 Pop();
143 }
144 }
145 }
146
147 if( mpAlphaVDev )
148 {
149 const Color aFillCol( mpAlphaVDev->GetFillColor() );
151 mpAlphaVDev->DrawPolyPolygon( rPolyPoly );
152 mpAlphaVDev->SetFillColor( aFillCol );
153 }
154}
155
157{
158 const tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
159 const bool bOldOutput = IsOutputEnabled();
160
161 EnableOutput( false );
164 DrawGradient( aBoundRect, rGradient );
167 DrawPolyPolygon( rPolyPoly );
169 DrawGradient( aBoundRect, rGradient );
170 Pop();
171 EnableOutput( bOldOutput );
172}
173
175 const Gradient& rGradient )
176{
177 assert(!is_double_buffered_window());
178
179 if ( !mpMetaFile )
180 return;
181
182 if ( !(rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize()) )
183 return;
184
185 const tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
186
187 if (aBoundRect.IsEmpty())
188 return;
189
190 Gradient aGradient( rGradient );
191
193 aGradient.MakeGrayscale();
194
195 if ( rPolyPoly.IsRect() )
196 {
197 mpMetaFile->AddAction( new MetaGradientAction( aBoundRect, std::move(aGradient) ) );
198 }
199 else
200 {
201 mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_BEGIN" ) );
202 mpMetaFile->AddAction( new MetaGradientExAction( rPolyPoly, rGradient ) );
203
204 ClipAndDrawGradientMetafile ( rGradient, rPolyPoly );
205
206 mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_END" ) );
207 }
208}
209
210namespace
211{
213 {
214 if ( nValue < 0 )
215 return 0;
216 else if ( nValue > 0xFF )
217 return 0xFF;
218 else
219 return static_cast<sal_uInt8>(nValue);
220 }
221}
222
224 const Gradient& rGradient,
225 const tools::PolyPolygon* pClixPolyPoly )
226{
227 assert(!is_double_buffered_window());
228
229 // get BoundRect of rotated rectangle
230 tools::Rectangle aRect;
231 Point aCenter;
232 Degree10 nAngle = rGradient.GetAngle() % 3600_deg10;
233
234 rGradient.GetBoundRect( rRect, aRect, aCenter );
235
236 bool bLinear = (rGradient.GetStyle() == GradientStyle::Linear);
237 double fBorder = rGradient.GetBorder() * aRect.GetHeight() / 100.0;
238 if ( !bLinear )
239 {
240 fBorder /= 2.0;
241 }
242 tools::Rectangle aMirrorRect = aRect; // used in style axial
243 aMirrorRect.SetTop( ( aRect.Top() + aRect.Bottom() ) / 2 );
244 if ( !bLinear )
245 {
246 aRect.SetBottom( aMirrorRect.Top() );
247 }
248
249 // colour-intensities of start- and finish; change if needed
250 tools::Long nFactor;
251 Color aStartCol = rGradient.GetStartColor();
252 Color aEndCol = rGradient.GetEndColor();
253 tools::Long nStartRed = aStartCol.GetRed();
254 tools::Long nStartGreen = aStartCol.GetGreen();
255 tools::Long nStartBlue = aStartCol.GetBlue();
256 tools::Long nEndRed = aEndCol.GetRed();
257 tools::Long nEndGreen = aEndCol.GetGreen();
258 tools::Long nEndBlue = aEndCol.GetBlue();
259 nFactor = rGradient.GetStartIntensity();
260 nStartRed = (nStartRed * nFactor) / 100;
261 nStartGreen = (nStartGreen * nFactor) / 100;
262 nStartBlue = (nStartBlue * nFactor) / 100;
263 nFactor = rGradient.GetEndIntensity();
264 nEndRed = (nEndRed * nFactor) / 100;
265 nEndGreen = (nEndGreen * nFactor) / 100;
266 nEndBlue = (nEndBlue * nFactor) / 100;
267
268 // gradient style axial has exchanged start and end colors
269 if ( !bLinear)
270 {
271 std::swap( nStartRed, nEndRed );
272 std::swap( nStartGreen, nEndGreen );
273 std::swap( nStartBlue, nEndBlue );
274 }
275
276 sal_uInt8 nRed;
277 sal_uInt8 nGreen;
278 sal_uInt8 nBlue;
279
280 // Create border
281 tools::Rectangle aBorderRect = aRect;
282 tools::Polygon aPoly( 4 );
283 if (fBorder > 0.0)
284 {
285 nRed = static_cast<sal_uInt8>(nStartRed);
286 nGreen = static_cast<sal_uInt8>(nStartGreen);
287 nBlue = static_cast<sal_uInt8>(nStartBlue);
288
289 mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
290
291 aBorderRect.SetBottom( static_cast<tools::Long>( aBorderRect.Top() + fBorder ) );
292 aRect.SetTop( aBorderRect.Bottom() );
293 aPoly[0] = aBorderRect.TopLeft();
294 aPoly[1] = aBorderRect.TopRight();
295 aPoly[2] = aBorderRect.BottomRight();
296 aPoly[3] = aBorderRect.BottomLeft();
297 aPoly.Rotate( aCenter, nAngle );
298
299 ImplDrawPolygon( aPoly, pClixPolyPoly );
300
301 if ( !bLinear)
302 {
303 aBorderRect = aMirrorRect;
304 aBorderRect.SetTop( static_cast<tools::Long>( aBorderRect.Bottom() - fBorder ) );
305 aMirrorRect.SetBottom( aBorderRect.Top() );
306 aPoly[0] = aBorderRect.TopLeft();
307 aPoly[1] = aBorderRect.TopRight();
308 aPoly[2] = aBorderRect.BottomRight();
309 aPoly[3] = aBorderRect.BottomLeft();
310 aPoly.Rotate( aCenter, nAngle );
311
312 ImplDrawPolygon( aPoly, pClixPolyPoly );
313 }
314 }
315
316 // calculate step count
317 tools::Long nStepCount = GetGradientSteps(rGradient, aRect);
318
319 // minimal three steps and maximal as max color steps
320 tools::Long nAbsRedSteps = std::abs( nEndRed - nStartRed );
321 tools::Long nAbsGreenSteps = std::abs( nEndGreen - nStartGreen );
322 tools::Long nAbsBlueSteps = std::abs( nEndBlue - nStartBlue );
323 tools::Long nMaxColorSteps = std::max( nAbsRedSteps , nAbsGreenSteps );
324 nMaxColorSteps = std::max( nMaxColorSteps, nAbsBlueSteps );
325 tools::Long nSteps = std::min( nStepCount, nMaxColorSteps );
326 if ( nSteps < 3)
327 {
328 nSteps = 3;
329 }
330
331 double fScanInc = static_cast<double>(aRect.GetHeight()) / static_cast<double>(nSteps);
332 double fGradientLine = static_cast<double>(aRect.Top());
333 double fMirrorGradientLine = static_cast<double>(aMirrorRect.Bottom());
334
335 const double fStepsMinus1 = static_cast<double>(nSteps) - 1.0;
336 if ( !bLinear)
337 {
338 nSteps -= 1; // draw middle polygons as one polygon after loop to avoid gap
339 }
340
341 for ( tools::Long i = 0; i < nSteps; i++ )
342 {
343 // linear interpolation of color
344 const double fAlpha = static_cast<double>(i) / fStepsMinus1;
345 double fTempColor = static_cast<double>(nStartRed) * (1.0-fAlpha) + static_cast<double>(nEndRed) * fAlpha;
346 nRed = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
347 fTempColor = static_cast<double>(nStartGreen) * (1.0-fAlpha) + static_cast<double>(nEndGreen) * fAlpha;
348 nGreen = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
349 fTempColor = static_cast<double>(nStartBlue) * (1.0-fAlpha) + static_cast<double>(nEndBlue) * fAlpha;
350 nBlue = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
351
352 mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
353
354 // Polygon for this color step
355 aRect.SetTop( static_cast<tools::Long>( fGradientLine + static_cast<double>(i) * fScanInc ) );
356 aRect.SetBottom( static_cast<tools::Long>( fGradientLine + ( static_cast<double>(i) + 1.0 ) * fScanInc ) );
357 aPoly[0] = aRect.TopLeft();
358 aPoly[1] = aRect.TopRight();
359 aPoly[2] = aRect.BottomRight();
360 aPoly[3] = aRect.BottomLeft();
361 aPoly.Rotate( aCenter, nAngle );
362
363 ImplDrawPolygon( aPoly, pClixPolyPoly );
364
365 if ( !bLinear )
366 {
367 aMirrorRect.SetBottom( static_cast<tools::Long>( fMirrorGradientLine - static_cast<double>(i) * fScanInc ) );
368 aMirrorRect.SetTop( static_cast<tools::Long>( fMirrorGradientLine - (static_cast<double>(i) + 1.0)* fScanInc ) );
369 aPoly[0] = aMirrorRect.TopLeft();
370 aPoly[1] = aMirrorRect.TopRight();
371 aPoly[2] = aMirrorRect.BottomRight();
372 aPoly[3] = aMirrorRect.BottomLeft();
373 aPoly.Rotate( aCenter, nAngle );
374
375 ImplDrawPolygon( aPoly, pClixPolyPoly );
376 }
377 }
378 if ( bLinear)
379 return;
380
381 // draw middle polygon with end color
382 nRed = GetGradientColorValue(nEndRed);
383 nGreen = GetGradientColorValue(nEndGreen);
384 nBlue = GetGradientColorValue(nEndBlue);
385
386 mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
387
388 aRect.SetTop( static_cast<tools::Long>( fGradientLine + static_cast<double>(nSteps) * fScanInc ) );
389 aRect.SetBottom( static_cast<tools::Long>( fMirrorGradientLine - static_cast<double>(nSteps) * fScanInc ) );
390 aPoly[0] = aRect.TopLeft();
391 aPoly[1] = aRect.TopRight();
392 aPoly[2] = aRect.BottomRight();
393 aPoly[3] = aRect.BottomLeft();
394 aPoly.Rotate( aCenter, nAngle );
395
396 ImplDrawPolygon( aPoly, pClixPolyPoly );
397
398}
399
401{
402 auto pOwnerWindow = GetOwnerWindow();
403 return pOwnerWindow && pOwnerWindow->SupportsDoubleBuffering();
404}
405
407 const Gradient& rGradient,
408 const tools::PolyPolygon* pClixPolyPoly )
409{
410 assert(!is_double_buffered_window());
411
412 // Determine if we output via Polygon or PolyPolygon
413 // For all rasteroperations other than Overpaint always use PolyPolygon,
414 // as we will get wrong results if we output multiple times on top of each other.
415 // Also for printers always use PolyPolygon, as not all printers
416 // can print polygons on top of each other.
417
418 std::optional<tools::PolyPolygon> xPolyPoly;
419 tools::Rectangle aRect;
420 Point aCenter;
421 Color aStartCol( rGradient.GetStartColor() );
422 Color aEndCol( rGradient.GetEndColor() );
423 tools::Long nStartRed = ( static_cast<tools::Long>(aStartCol.GetRed()) * rGradient.GetStartIntensity() ) / 100;
424 tools::Long nStartGreen = ( static_cast<tools::Long>(aStartCol.GetGreen()) * rGradient.GetStartIntensity() ) / 100;
425 tools::Long nStartBlue = ( static_cast<tools::Long>(aStartCol.GetBlue()) * rGradient.GetStartIntensity() ) / 100;
426 tools::Long nEndRed = ( static_cast<tools::Long>(aEndCol.GetRed()) * rGradient.GetEndIntensity() ) / 100;
427 tools::Long nEndGreen = ( static_cast<tools::Long>(aEndCol.GetGreen()) * rGradient.GetEndIntensity() ) / 100;
428 tools::Long nEndBlue = ( static_cast<tools::Long>(aEndCol.GetBlue()) * rGradient.GetEndIntensity() ) / 100;
429 tools::Long nRedSteps = nEndRed - nStartRed;
430 tools::Long nGreenSteps = nEndGreen - nStartGreen;
431 tools::Long nBlueSteps = nEndBlue - nStartBlue;
432 Degree10 nAngle = rGradient.GetAngle() % 3600_deg10;
433
434 rGradient.GetBoundRect( rRect, aRect, aCenter );
435
437 xPolyPoly = tools::PolyPolygon( 2 );
438
439 tools::Long nStepCount = GetGradientSteps(rGradient, rRect);
440
441 // at least three steps and at most the number of colour differences
442 tools::Long nSteps = std::max( nStepCount, tools::Long(2) );
443 tools::Long nCalcSteps = std::abs( nRedSteps );
444 tools::Long nTempSteps = std::abs( nGreenSteps );
445 if ( nTempSteps > nCalcSteps )
446 nCalcSteps = nTempSteps;
447 nTempSteps = std::abs( nBlueSteps );
448 if ( nTempSteps > nCalcSteps )
449 nCalcSteps = nTempSteps;
450 if ( nCalcSteps < nSteps )
451 nSteps = nCalcSteps;
452 if ( !nSteps )
453 nSteps = 1;
454
455 // determine output limits and stepsizes for all directions
456 tools::Polygon aPoly;
457 double fScanLeft = aRect.Left();
458 double fScanTop = aRect.Top();
459 double fScanRight = aRect.Right();
460 double fScanBottom = aRect.Bottom();
461 double fScanIncX = static_cast<double>(aRect.GetWidth()) / static_cast<double>(nSteps) * 0.5;
462 double fScanIncY = static_cast<double>(aRect.GetHeight()) / static_cast<double>(nSteps) * 0.5;
463
464 // all gradients are rendered as nested rectangles which shrink
465 // equally in each dimension - except for 'square' gradients
466 // which shrink to a central vertex but are not per-se square.
467 if( rGradient.GetStyle() != GradientStyle::Square )
468 {
469 fScanIncY = std::min( fScanIncY, fScanIncX );
470 fScanIncX = fScanIncY;
471 }
472 sal_uInt8 nRed = static_cast<sal_uInt8>(nStartRed), nGreen = static_cast<sal_uInt8>(nStartGreen), nBlue = static_cast<sal_uInt8>(nStartBlue);
473 bool bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
474
475 mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
476
477 if( xPolyPoly )
478 {
479 aPoly = rRect;
480 xPolyPoly->Insert( aPoly );
481 xPolyPoly->Insert( aPoly );
482 }
483 else
484 {
485 // extend rect, to avoid missing bounding line
486 tools::Rectangle aExtRect( rRect );
487
488 aExtRect.AdjustLeft( -1 );
489 aExtRect.AdjustTop( -1 );
490 aExtRect.AdjustRight(1 );
491 aExtRect.AdjustBottom(1 );
492
493 aPoly = aExtRect;
494 ImplDrawPolygon( aPoly, pClixPolyPoly );
495 }
496
497 // loop to output Polygon/PolyPolygon sequentially
498 for( tools::Long i = 1; i < nSteps; i++ )
499 {
500 // calculate new Polygon
501 fScanLeft += fScanIncX;
502 aRect.SetLeft( static_cast<tools::Long>( fScanLeft ) );
503 fScanTop += fScanIncY;
504 aRect.SetTop( static_cast<tools::Long>( fScanTop ) );
505 fScanRight -= fScanIncX;
506 aRect.SetRight( static_cast<tools::Long>( fScanRight ) );
507 fScanBottom -= fScanIncY;
508 aRect.SetBottom( static_cast<tools::Long>( fScanBottom ) );
509
510 if( ( aRect.GetWidth() < 2 ) || ( aRect.GetHeight() < 2 ) )
511 break;
512
513 if( rGradient.GetStyle() == GradientStyle::Radial || rGradient.GetStyle() == GradientStyle::Elliptical )
514 aPoly = tools::Polygon( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
515 else
516 aPoly = tools::Polygon( aRect );
517
518 aPoly.Rotate( aCenter, nAngle );
519
520 // adapt colour accordingly
521 const tools::Long nStepIndex = ( xPolyPoly ? i : ( i + 1 ) );
522 nRed = GetGradientColorValue( nStartRed + ( ( nRedSteps * nStepIndex ) / nSteps ) );
523 nGreen = GetGradientColorValue( nStartGreen + ( ( nGreenSteps * nStepIndex ) / nSteps ) );
524 nBlue = GetGradientColorValue( nStartBlue + ( ( nBlueSteps * nStepIndex ) / nSteps ) );
525
526 // either slow tools::PolyPolygon output or fast Polygon-Painting
527 if( xPolyPoly )
528 {
529 bPaintLastPolygon = true; // #107349# Paint last polygon only if loop has generated any output
530
531 xPolyPoly->Replace( xPolyPoly->GetObject( 1 ), 0 );
532 xPolyPoly->Replace( aPoly, 1 );
533
534 ImplDrawPolyPolygon( *xPolyPoly, pClixPolyPoly );
535
536 // #107349# Set fill color _after_ geometry painting:
537 // xPolyPoly's geometry is the band from last iteration's
538 // aPoly to current iteration's aPoly. The window outdev
539 // path (see else below), on the other hand, paints the
540 // full aPoly. Thus, here, we're painting the band before
541 // the one painted in the window outdev path below. To get
542 // matching colors, have to delay color setting here.
543 mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
544 }
545 else
546 {
547 // #107349# Set fill color _before_ geometry painting
548 mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
549
550 ImplDrawPolygon( aPoly, pClixPolyPoly );
551 }
552 }
553
554 // we should draw last inner Polygon if we output PolyPolygon
555 if( !xPolyPoly )
556 return;
557
558 const tools::Polygon& rPoly = xPolyPoly->GetObject( 1 );
559
560 if( rPoly.GetBoundRect().IsEmpty() )
561 return;
562
563 // #107349# Paint last polygon with end color only if loop
564 // has generated output. Otherwise, the current
565 // (i.e. start) color is taken, to generate _any_ output.
566 if( bPaintLastPolygon )
567 {
568 nRed = GetGradientColorValue( nEndRed );
569 nGreen = GetGradientColorValue( nEndGreen );
570 nBlue = GetGradientColorValue( nEndBlue );
571 }
572
573 mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
574 ImplDrawPolygon( rPoly, pClixPolyPoly );
575}
576
578{
579 tools::Long nInc = (nMinRect < 50) ? 2 : 4;
580
581 return nInc;
582}
583
585{
586 // calculate step count
587 tools::Long nStepCount = rGradient.GetSteps();
588
589 if (nStepCount)
590 return nStepCount;
591
592 tools::Long nMinRect = 0;
593
594 if (rGradient.GetStyle() == GradientStyle::Linear || rGradient.GetStyle() == GradientStyle::Axial)
595 nMinRect = rRect.GetHeight();
596 else
597 nMinRect = std::min(rRect.GetWidth(), rRect.GetHeight());
598
599 tools::Long nInc = GetGradientStepCount(nMinRect);
600
601 if (!nInc)
602 nInc = 1;
603
604 return nMinRect / nInc;
605}
606
608{
609 Color aColor;
610
611 // we should never call on this function if any of these aren't set!
613
615 aColor = COL_BLACK;
617 aColor = COL_WHITE;
619 {
622 else
624 }
625
626 return aColor;
627}
628
629/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const StyleSettings & GetStyleSettings() const
sal_uInt8 GetBlue() const
sal_uInt8 GetRed() const
sal_uInt8 GetGreen() const
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:581
sal_uInt16 GetStartIntensity() const
GradientStyle GetStyle() const
Degree10 GetAngle() const
sal_uInt16 GetEndIntensity() const
sal_uInt16 GetBorder() const
const Color & GetEndColor() const
void MakeGrayscale()
const Color & GetStartColor() const
void SetSteps(sal_uInt16 nSteps)
sal_uInt16 GetSteps() const
void GetBoundRect(const tools::Rectangle &rRect, tools::Rectangle &rBoundRect, Point &rCenter) const
Size GetOutputSize() const
Definition: outdev.hxx:327
virtual void InitClipRegion()
SAL_DLLPRIVATE bool is_double_buffered_window() const
void EnableOutput(bool bEnable=true)
Definition: outdev.cxx:341
DrawModeFlags mnDrawMode
Definition: outdev.hxx:220
bool mbOutputClipped
Definition: outdev.hxx:245
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:347
SAL_DLLPRIVATE void DrawGradientToMetafile(const tools::PolyPolygon &rPolyPoly, const Gradient &rGradient)
SAL_DLLPRIVATE void DrawComplexGradient(const tools::Rectangle &rRect, const Gradient &rGradient, const tools::PolyPolygon *pClipPolyPoly)
SAL_DLLPRIVATE void ImplDrawPolygon(const tools::Polygon &rPoly, const tools::PolyPolygon *pClipPolyPoly=nullptr)
Definition: polygon.cxx:443
virtual bool AcquireGraphics() const =0
Acquire a graphics device that the output device uses to draw on.
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1123
SAL_DLLPRIVATE bool ImplIsRecordLayout() const
Definition: outdev.cxx:708
GDIMetaFile * mpMetaFile
Definition: outdev.hxx:185
void SetLineColor()
Definition: line.cxx:37
bool mbInitLineColor
Definition: outdev.hxx:248
SalGraphics * mpGraphics
Graphics context to draw on.
Definition: outdev.hxx:182
SAL_DLLPRIVATE void ImplDrawPolyPolygon(const tools::PolyPolygon &rPolyPoly, const tools::PolyPolygon *pClipPolyPoly)
Definition: polygon.cxx:461
SAL_DLLPRIVATE tools::Long GetGradientSteps(Gradient const &rGradient, tools::Rectangle const &rRect)
virtual bool UsePolyPolygonForComplexGradient()=0
bool mbInitClipRegion
Definition: outdev.hxx:252
void SetFillColor()
Definition: fill.cxx:29
virtual void ClipAndDrawGradientMetafile(const Gradient &rGradient, const tools::PolyPolygon &rPolyPoly)
void SetRasterOp(RasterOp eRasterOp)
Definition: outdev.cxx:320
bool IsDeviceOutputNecessary() const
Definition: outdev.hxx:481
VclPtr< VirtualDevice > mpAlphaVDev
Definition: outdev.hxx:196
virtual tools::Long GetGradientStepCount(tools::Long nMinRect)
void Push(vcl::PushFlags nFlags=vcl::PushFlags::ALL)
Definition: stack.cxx:32
void DrawGradient(const tools::Rectangle &rRect, const Gradient &rGradient)
void DrawPolyPolygon(const tools::PolyPolygon &rPolyPoly)
Render the given poly-polygon.
Definition: polygon.cxx:34
void Pop()
Definition: stack.cxx:91
bool IsOutputEnabled() const
Definition: outdev.hxx:480
const AllSettings & GetSettings() const
Definition: outdev.hxx:288
bool mbLineColor
Definition: outdev.hxx:246
void IntersectClipRegion(const tools::Rectangle &rRect)
SAL_DLLPRIVATE Color GetSingleColorGradientFill()
virtual vcl::Window * GetOwnerWindow() const
Get the vcl::Window that this OutputDevice belongs to, if any.
Definition: outdev.hxx:1899
SAL_DLLPRIVATE void DrawLinearGradient(const tools::Rectangle &rRect, const Gradient &rGradient, const tools::PolyPolygon *pClipPolyPoly)
bool mbInitFillColor
Definition: outdev.hxx:249
const Color & GetFillColor() const
Definition: outdev.hxx:515
virtual void SetLineColor()=0
virtual void SetFillColor()=0
bool DrawGradient(const tools::PolyPolygon &rPolyPoly, const Gradient &rGradient, const OutputDevice &rOutDev)
const Color & GetWindowColor() const
const Color & GetHighlightColor() const
sal_uInt16 Count() const
bool IsRect() const
tools::Rectangle GetBoundRect() const
tools::Rectangle GetBoundRect() const
void Rotate(const Point &rCenter, double fSin, double fCos)
constexpr Point Center() const
constexpr tools::Long GetWidth() const
constexpr void SetLeft(tools::Long v)
constexpr void SetTop(tools::Long v)
constexpr tools::Long Top() const
constexpr Point TopLeft() const
constexpr void SetRight(tools::Long v)
constexpr tools::Long Right() const
tools::Long AdjustTop(tools::Long nVertMoveDelta)
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
constexpr void SetBottom(tools::Long v)
constexpr Point BottomRight() const
constexpr Point TopRight() const
constexpr tools::Long GetHeight() const
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
constexpr bool IsEmpty() const
constexpr Point BottomLeft() const
constexpr ::Color COL_WHITE(0xFF, 0xFF, 0xFF)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
sal_Int16 nValue
static sal_uInt8 GetGradientColorValue(tools::Long nValue)
int i
long Long
#define GRADIENT_DEFAULT_STEPCOUNT
unsigned char sal_uInt8