1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <canvas/debug.hxx>
21 #include <tools/diagnose_ex.h>
23 #include <rtl/math.hxx>
25 #include <com/sun/star/rendering/CompositeOperation.hpp>
26 #include <com/sun/star/util/Endianness.hpp>
27 #include <com/sun/star/rendering/TextDirection.hpp>
28 #include <com/sun/star/rendering/TexturingMode.hpp>
29 #include <com/sun/star/rendering/PathCapType.hpp>
30 #include <com/sun/star/rendering/PathJoinType.hpp>
31 #include <com/sun/star/drawing/LineCap.hpp>
33 #include <tools/poly.hxx>
34 #include <vcl/window.hxx>
35 #include <vcl/bitmapex.hxx>
36 #include <vcl/bmpacc.hxx>
37 #include <vcl/canvastools.hxx>
39 #include <basegfx/matrix/b2dhommatrix.hxx>
40 #include <basegfx/range/b2drectangle.hxx>
41 #include <basegfx/point/b2dpoint.hxx>
42 #include <basegfx/vector/b2dsize.hxx>
43 #include <basegfx/polygon/b2dpolygon.hxx>
44 #include <basegfx/polygon/b2dpolygontools.hxx>
45 #include <basegfx/polygon/b2dpolypolygontools.hxx>
46 #include <basegfx/polygon/b2dlinegeometry.hxx>
47 #include <basegfx/tools/canvastools.hxx>
48 #include <basegfx/numeric/ftools.hxx>
52 #include <comphelper/sequence.hxx>
53 #include <canvas/canvastools.hxx>
55 #include "textlayout.hxx"
56 #include "canvashelper.hxx"
57 #include "canvasbitmap.hxx"
58 #include "impltools.hxx"
59 #include "canvasfont.hxx"
62 using namespace ::com::sun::star
;
68 basegfx::B2DLineJoin
b2DJoineFromJoin( sal_Int8 nJoinType
)
72 case rendering::PathJoinType::NONE
:
73 return basegfx::B2DLINEJOIN_NONE
;
75 case rendering::PathJoinType::MITER
:
76 return basegfx::B2DLINEJOIN_MITER
;
78 case rendering::PathJoinType::ROUND
:
79 return basegfx::B2DLINEJOIN_ROUND
;
81 case rendering::PathJoinType::BEVEL
:
82 return basegfx::B2DLINEJOIN_BEVEL
;
85 ENSURE_OR_THROW( false,
86 "b2DJoineFromJoin(): Unexpected join type" );
89 return basegfx::B2DLINEJOIN_NONE
;
92 drawing::LineCap
unoCapeFromCap( sal_Int8 nCapType
)
96 case rendering::PathCapType::BUTT
:
97 return drawing::LineCap_BUTT
;
99 case rendering::PathCapType::ROUND
:
100 return drawing::LineCap_ROUND
;
102 case rendering::PathCapType::SQUARE
:
103 return drawing::LineCap_SQUARE
;
106 ENSURE_OR_THROW( false,
107 "unoCapeFromCap(): Unexpected cap type" );
109 return drawing::LineCap_BUTT
;
113 CanvasHelper::CanvasHelper() :
122 void CanvasHelper::disposing()
125 mpProtectedOutDev
.reset();
130 void CanvasHelper::init( rendering::XGraphicDevice
& rDevice
,
131 const OutDevProviderSharedPtr
& rOutDev
,
135 // cast away const, need to change refcount (as this is
136 // ~invisible to client code, still logically const)
138 mbHaveAlpha
= bHaveAlpha
;
140 setOutDev( rOutDev
, bProtect
);
143 void CanvasHelper::setOutDev( const OutDevProviderSharedPtr
& rOutDev
,
147 mpProtectedOutDev
= rOutDev
;
149 mpProtectedOutDev
.reset();
154 void CanvasHelper::setBackgroundOutDev( const OutDevProviderSharedPtr
& rOutDev
)
156 mp2ndOutDev
= rOutDev
;
157 mp2ndOutDev
->getOutDev().EnableMapMode( false );
158 mp2ndOutDev
->getOutDev().SetAntialiasing( AntialiasingFlags::EnableB2dDraw
);
161 void CanvasHelper::clear()
166 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
167 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
169 rOutDev
.EnableMapMode( false );
170 rOutDev
.SetAntialiasing( AntialiasingFlags::EnableB2dDraw
);
171 rOutDev
.SetLineColor( COL_WHITE
);
172 rOutDev
.SetFillColor( COL_WHITE
);
173 rOutDev
.SetClipRegion();
174 rOutDev
.DrawRect( Rectangle( Point(),
175 rOutDev
.GetOutputSizePixel()) );
179 OutputDevice
& rOutDev2( mp2ndOutDev
->getOutDev() );
181 rOutDev2
.SetDrawMode( DrawModeFlags::Default
);
182 rOutDev2
.EnableMapMode( false );
183 rOutDev2
.SetAntialiasing( AntialiasingFlags::EnableB2dDraw
);
184 rOutDev2
.SetLineColor( COL_WHITE
);
185 rOutDev2
.SetFillColor( COL_WHITE
);
186 rOutDev2
.SetClipRegion();
187 rOutDev2
.DrawRect( Rectangle( Point(),
188 rOutDev2
.GetOutputSizePixel()) );
189 rOutDev2
.SetDrawMode( DrawModeFlags::BlackLine
| DrawModeFlags::BlackFill
| DrawModeFlags::BlackText
|
190 DrawModeFlags::BlackGradient
| DrawModeFlags::BlackBitmap
);
195 void CanvasHelper::drawPoint( const rendering::XCanvas
* ,
196 const geometry::RealPoint2D
& aPoint
,
197 const rendering::ViewState
& viewState
,
198 const rendering::RenderState
& renderState
)
204 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
205 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
207 const Point
aOutPoint( tools::mapRealPoint2D( aPoint
,
208 viewState
, renderState
) );
210 mpOutDev
->getOutDev().DrawPixel( aOutPoint
);
213 mp2ndOutDev
->getOutDev().DrawPixel( aOutPoint
);
217 void CanvasHelper::drawLine( const rendering::XCanvas
* ,
218 const geometry::RealPoint2D
& aStartRealPoint2D
,
219 const geometry::RealPoint2D
& aEndRealPoint2D
,
220 const rendering::ViewState
& viewState
,
221 const rendering::RenderState
& renderState
)
227 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
228 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
230 const Point
aStartPoint( tools::mapRealPoint2D( aStartRealPoint2D
,
231 viewState
, renderState
) );
232 const Point
aEndPoint( tools::mapRealPoint2D( aEndRealPoint2D
,
233 viewState
, renderState
) );
235 mpOutDev
->getOutDev().DrawLine( aStartPoint
, aEndPoint
);
238 mp2ndOutDev
->getOutDev().DrawLine( aStartPoint
, aEndPoint
);
242 void CanvasHelper::drawBezier( const rendering::XCanvas
* ,
243 const geometry::RealBezierSegment2D
& aBezierSegment
,
244 const geometry::RealPoint2D
& _aEndPoint
,
245 const rendering::ViewState
& viewState
,
246 const rendering::RenderState
& renderState
)
250 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
251 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
253 const Point
& rStartPoint( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment
.Px
,
255 viewState
, renderState
) );
256 const Point
& rCtrlPoint1( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment
.C1x
,
258 viewState
, renderState
) );
259 const Point
& rCtrlPoint2( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment
.C2x
,
261 viewState
, renderState
) );
262 const Point
& rEndPoint( tools::mapRealPoint2D( _aEndPoint
,
263 viewState
, renderState
) );
266 aPoly
.SetPoint( rStartPoint
, 0 );
267 aPoly
.SetFlags( 0, POLY_NORMAL
);
268 aPoly
.SetPoint( rCtrlPoint1
, 1 );
269 aPoly
.SetFlags( 1, POLY_CONTROL
);
270 aPoly
.SetPoint( rCtrlPoint2
, 2 );
271 aPoly
.SetFlags( 2, POLY_CONTROL
);
272 aPoly
.SetPoint( rEndPoint
, 3 );
273 aPoly
.SetFlags( 3, POLY_NORMAL
);
276 mpOutDev
->getOutDev().DrawPolygon( aPoly
);
278 mp2ndOutDev
->getOutDev().DrawPolygon( aPoly
);
282 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawPolyPolygon( const rendering::XCanvas
* ,
283 const uno::Reference
< rendering::XPolyPolygon2D
>& xPolyPolygon
,
284 const rendering::ViewState
& viewState
,
285 const rendering::RenderState
& renderState
)
287 ENSURE_ARG_OR_THROW( xPolyPolygon
.is(),
292 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
293 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
295 const ::basegfx::B2DPolyPolygon
& rPolyPoly(
296 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon
) );
297 const ::tools::PolyPolygon
aPolyPoly( tools::mapPolyPolygon( rPolyPoly
, viewState
, renderState
) );
299 if( rPolyPoly
.isClosed() )
301 mpOutDev
->getOutDev().DrawPolyPolygon( aPolyPoly
);
304 mp2ndOutDev
->getOutDev().DrawPolyPolygon( aPolyPoly
);
308 // mixed open/closed state. Cannot render open polygon
309 // via DrawPolyPolygon(), since that implicitley
310 // closed every polygon. OTOH, no need to distinguish
311 // further and render closed polygons via
312 // DrawPolygon(), and open ones via DrawPolyLine():
313 // closed polygons will simply already contain the
315 sal_uInt16
nSize( aPolyPoly
.Count() );
317 for( sal_uInt16 i
=0; i
<nSize
; ++i
)
319 mpOutDev
->getOutDev().DrawPolyLine( aPolyPoly
[i
] );
322 mp2ndOutDev
->getOutDev().DrawPolyLine( aPolyPoly
[i
] );
327 // TODO(P1): Provide caching here.
328 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
331 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::strokePolyPolygon( const rendering::XCanvas
* ,
332 const uno::Reference
< rendering::XPolyPolygon2D
>& xPolyPolygon
,
333 const rendering::ViewState
& viewState
,
334 const rendering::RenderState
& renderState
,
335 const rendering::StrokeAttributes
& strokeAttributes
)
337 ENSURE_ARG_OR_THROW( xPolyPolygon
.is(),
342 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
344 ::basegfx::B2DHomMatrix aMatrix
;
345 ::canvas::tools::mergeViewAndRenderTransform(aMatrix
, viewState
, renderState
);
347 ::basegfx::B2DSize
aLinePixelSize(strokeAttributes
.StrokeWidth
,
348 strokeAttributes
.StrokeWidth
);
349 aLinePixelSize
*= aMatrix
;
351 ::basegfx::B2DPolyPolygon
aPolyPoly(
352 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon
) );
354 if( aPolyPoly
.areControlPointsUsed() )
356 // AW: Not needed for ApplyLineDashing anymore; should be removed
357 aPolyPoly
= ::basegfx::tools::adaptiveSubdivideByAngle(aPolyPoly
);
360 // apply dashing, if any
361 if( strokeAttributes
.DashArray
.getLength() )
363 const ::std::vector
<double>& aDashArray(
364 ::comphelper::sequenceToContainer
< ::std::vector
<double> >(strokeAttributes
.DashArray
) );
366 ::basegfx::B2DPolyPolygon aDashedPolyPoly
;
368 for( sal_uInt32 i
=0; i
<aPolyPoly
.count(); ++i
)
370 // AW: new interface; You may also get gaps in the same run now
371 basegfx::tools::applyLineDashing(aPolyPoly
.getB2DPolygon(i
), aDashArray
, &aDashedPolyPoly
);
372 //aDashedPolyPoly.append(
373 // ::basegfx::tools::applyLineDashing( aPolyPoly.getB2DPolygon(i),
377 aPolyPoly
= aDashedPolyPoly
;
380 ::basegfx::B2DPolyPolygon aStrokedPolyPoly
;
381 if( aLinePixelSize
.getLength() < 1.42 )
383 // line width < 1.0 in device pixel, thus, output as a
384 // simple hairline poly-polygon
385 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
387 aStrokedPolyPoly
= aPolyPoly
;
391 // render as a 'thick' line
392 setupOutDevState( viewState
, renderState
, FILL_COLOR
);
394 for( sal_uInt32 i
=0; i
<aPolyPoly
.count(); ++i
)
396 // TODO(F2): Use MiterLimit from StrokeAttributes,
397 // need to convert it here to angle.
399 // TODO(F2): Also use Cap settings from
400 // StrokeAttributes, the
401 // createAreaGeometryForLineStartEnd() method does not
402 // seem to fit very well here
404 // AW: New interface, will create bezier polygons now
405 aStrokedPolyPoly
.append(basegfx::tools::createAreaGeometry(
406 aPolyPoly
.getB2DPolygon(i
),
407 strokeAttributes
.StrokeWidth
*0.5,
408 b2DJoineFromJoin(strokeAttributes
.JoinType
),
409 unoCapeFromCap(strokeAttributes
.StartCapType
)
411 //aStrokedPolyPoly.append(
412 // ::basegfx::tools::createAreaGeometryForPolygon( aPolyPoly.getB2DPolygon(i),
413 // strokeAttributes.StrokeWidth*0.5,
414 // b2DJoineFromJoin(strokeAttributes.JoinType) ) );
418 // transform only _now_, all the StrokeAttributes are in
420 aStrokedPolyPoly
.transform( aMatrix
);
422 const ::tools::PolyPolygon
aVCLPolyPoly( aStrokedPolyPoly
);
424 // TODO(F2): When using alpha here, must handle that via
425 // temporary surface or somesuch.
427 // Note: the generated stroke poly-polygon is NOT free of
428 // self-intersections. Therefore, if we would render it
429 // via OutDev::DrawPolyPolygon(), on/off fill would
430 // generate off areas on those self-intersections.
431 sal_uInt16
nSize( aVCLPolyPoly
.Count() );
433 for( sal_uInt16 i
=0; i
<nSize
; ++i
)
435 if( aStrokedPolyPoly
.getB2DPolygon( i
).isClosed() ) {
436 mpOutDev
->getOutDev().DrawPolygon( aVCLPolyPoly
[i
] );
438 mp2ndOutDev
->getOutDev().DrawPolygon( aVCLPolyPoly
[i
] );
440 const sal_uInt16 nPolySize
= aVCLPolyPoly
[i
].GetSize();
442 Point rPrevPoint
= aVCLPolyPoly
[i
].GetPoint( 0 );
445 for( sal_uInt16 j
=1; j
<nPolySize
; j
++ ) {
446 rPoint
= aVCLPolyPoly
[i
].GetPoint( j
);
447 mpOutDev
->getOutDev().DrawLine( rPrevPoint
, rPoint
);
449 mp2ndOutDev
->getOutDev().DrawLine( rPrevPoint
, rPoint
);
457 // TODO(P1): Provide caching here.
458 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
461 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas
* ,
462 const uno::Reference
< rendering::XPolyPolygon2D
>& ,
463 const rendering::ViewState
& ,
464 const rendering::RenderState
& ,
465 const uno::Sequence
< rendering::Texture
>& ,
466 const rendering::StrokeAttributes
& )
468 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
471 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::strokeTextureMappedPolyPolygon( const rendering::XCanvas
* ,
472 const uno::Reference
< rendering::XPolyPolygon2D
>& ,
473 const rendering::ViewState
& ,
474 const rendering::RenderState
& ,
475 const uno::Sequence
< rendering::Texture
>& ,
476 const uno::Reference
< geometry::XMapping2D
>& ,
477 const rendering::StrokeAttributes
& )
479 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
482 uno::Reference
< rendering::XPolyPolygon2D
> CanvasHelper::queryStrokeShapes( const rendering::XCanvas
* ,
483 const uno::Reference
< rendering::XPolyPolygon2D
>& ,
484 const rendering::ViewState
& ,
485 const rendering::RenderState
& ,
486 const rendering::StrokeAttributes
& )
488 return uno::Reference
< rendering::XPolyPolygon2D
>(NULL
);
491 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::fillPolyPolygon( const rendering::XCanvas
* ,
492 const uno::Reference
< rendering::XPolyPolygon2D
>& xPolyPolygon
,
493 const rendering::ViewState
& viewState
,
494 const rendering::RenderState
& renderState
)
496 ENSURE_ARG_OR_THROW( xPolyPolygon
.is(),
501 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
503 const int nTransparency( setupOutDevState( viewState
, renderState
, FILL_COLOR
) );
504 ::basegfx::B2DPolyPolygon
aB2DPolyPoly(
505 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon
));
506 aB2DPolyPoly
.setClosed(true); // ensure closed poly, otherwise VCL does not fill
507 const ::tools::PolyPolygon
aPolyPoly( tools::mapPolyPolygon(
509 viewState
, renderState
) );
510 const bool bSourceAlpha( renderState
.CompositeOperation
== rendering::CompositeOperation::SOURCE
);
511 if( !nTransparency
|| bSourceAlpha
)
513 mpOutDev
->getOutDev().DrawPolyPolygon( aPolyPoly
);
517 const int nTransPercent( (nTransparency
* 100 + 128) / 255 ); // normal rounding, no truncation here
518 mpOutDev
->getOutDev().DrawTransparent( aPolyPoly
, (sal_uInt16
)nTransPercent
);
523 // HACK. Normally, CanvasHelper does not care about
524 // actually what mp2ndOutDev is... well, here we do &
525 // assume a 1bpp target - everything beyond 97%
526 // transparency is fully transparent
527 if( nTransparency
< 253 )
529 mp2ndOutDev
->getOutDev().SetFillColor( COL_BLACK
);
530 mp2ndOutDev
->getOutDev().DrawPolyPolygon( aPolyPoly
);
535 // TODO(P1): Provide caching here.
536 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
539 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas
* ,
540 const uno::Reference
< rendering::XPolyPolygon2D
>& ,
541 const rendering::ViewState
& ,
542 const rendering::RenderState
& ,
543 const uno::Sequence
< rendering::Texture
>& ,
544 const uno::Reference
< geometry::XMapping2D
>& )
546 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
549 uno::Reference
< rendering::XCanvasFont
> CanvasHelper::createFont( const rendering::XCanvas
* ,
550 const rendering::FontRequest
& fontRequest
,
551 const uno::Sequence
< beans::PropertyValue
>& extraFontProperties
,
552 const geometry::Matrix2D
& fontMatrix
)
554 if( mpOutDev
&& mpDevice
)
556 // TODO(F2): font properties and font matrix
557 return uno::Reference
< rendering::XCanvasFont
>(
558 new CanvasFont(fontRequest
, extraFontProperties
, fontMatrix
,
559 *mpDevice
, mpOutDev
) );
562 return uno::Reference
< rendering::XCanvasFont
>();
565 uno::Sequence
< rendering::FontInfo
> CanvasHelper::queryAvailableFonts( const rendering::XCanvas
* ,
566 const rendering::FontInfo
& ,
567 const uno::Sequence
< beans::PropertyValue
>& )
570 return uno::Sequence
< rendering::FontInfo
>();
573 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawText( const rendering::XCanvas
* ,
574 const rendering::StringContext
& text
,
575 const uno::Reference
< rendering::XCanvasFont
>& xFont
,
576 const rendering::ViewState
& viewState
,
577 const rendering::RenderState
& renderState
,
578 sal_Int8 textDirection
)
580 ENSURE_ARG_OR_THROW( xFont
.is(),
585 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
588 if( !setupTextOutput( aOutpos
, viewState
, renderState
, xFont
) )
589 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
); // no output necessary
591 // change text direction and layout mode
592 ComplexTextLayoutMode
nLayoutMode(TEXT_LAYOUT_DEFAULT
);
593 switch( textDirection
)
595 case rendering::TextDirection::WEAK_LEFT_TO_RIGHT
:
596 // FALLTHROUGH intended
597 case rendering::TextDirection::STRONG_LEFT_TO_RIGHT
:
598 nLayoutMode
|= TEXT_LAYOUT_BIDI_STRONG
;
599 nLayoutMode
|= TEXT_LAYOUT_TEXTORIGIN_LEFT
;
602 case rendering::TextDirection::WEAK_RIGHT_TO_LEFT
:
603 nLayoutMode
|= TEXT_LAYOUT_BIDI_RTL
;
604 // FALLTHROUGH intended
605 case rendering::TextDirection::STRONG_RIGHT_TO_LEFT
:
606 nLayoutMode
|= TEXT_LAYOUT_BIDI_RTL
| TEXT_LAYOUT_BIDI_STRONG
;
607 nLayoutMode
|= TEXT_LAYOUT_TEXTORIGIN_RIGHT
;
612 mpOutDev
->getOutDev().SetLayoutMode( nLayoutMode
);
613 mpOutDev
->getOutDev().DrawText( aOutpos
,
615 ::canvas::tools::numeric_cast
<sal_uInt16
>(text
.StartPosition
),
616 ::canvas::tools::numeric_cast
<sal_uInt16
>(text
.Length
) );
620 mp2ndOutDev
->getOutDev().SetLayoutMode( nLayoutMode
);
621 mp2ndOutDev
->getOutDev().DrawText( aOutpos
,
623 ::canvas::tools::numeric_cast
<sal_uInt16
>(text
.StartPosition
),
624 ::canvas::tools::numeric_cast
<sal_uInt16
>(text
.Length
) );
628 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
631 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawTextLayout( const rendering::XCanvas
* ,
632 const uno::Reference
< rendering::XTextLayout
>& xLayoutedText
,
633 const rendering::ViewState
& viewState
,
634 const rendering::RenderState
& renderState
)
636 ENSURE_ARG_OR_THROW( xLayoutedText
.is(),
639 TextLayout
* pTextLayout
= dynamic_cast< TextLayout
* >( xLayoutedText
.get() );
645 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
647 // TODO(T3): Race condition. We're taking the font
648 // from xLayoutedText, and then calling draw() at it,
649 // without exclusive access. Move setupTextOutput(),
650 // e.g. to impltools?
653 if( !setupTextOutput( aOutpos
, viewState
, renderState
, xLayoutedText
->getFont() ) )
654 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
); // no output necessary
656 // TODO(F2): What about the offset scalings?
658 pTextLayout
->draw( mpOutDev
->getOutDev(), aOutpos
, viewState
, renderState
);
661 pTextLayout
->draw( mp2ndOutDev
->getOutDev(), aOutpos
, viewState
, renderState
);
666 ENSURE_ARG_OR_THROW( false,
667 "TextLayout not compatible with this canvas" );
670 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
673 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::implDrawBitmap( const rendering::XCanvas
* pCanvas
,
674 const uno::Reference
< rendering::XBitmap
>& xBitmap
,
675 const rendering::ViewState
& viewState
,
676 const rendering::RenderState
& renderState
,
677 bool bModulateColors
)
679 ENSURE_ARG_OR_THROW( xBitmap
.is(),
682 ::canvas::tools::verifyInput( renderState
,
683 BOOST_CURRENT_FUNCTION
,
686 bModulateColors
? 3 : 0 );
690 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
691 setupOutDevState( viewState
, renderState
, IGNORE_COLOR
);
693 ::basegfx::B2DHomMatrix aMatrix
;
694 ::canvas::tools::mergeViewAndRenderTransform(aMatrix
, viewState
, renderState
);
696 ::basegfx::B2DPoint
aOutputPos( 0.0, 0.0 );
697 aOutputPos
*= aMatrix
;
699 BitmapEx
aBmpEx( tools::bitmapExFromXBitmap(xBitmap
) );
701 // TODO(F2): Implement modulation again for other color
702 // channels (currently, works only for alpha). Note: this
703 // is already implemented in transformBitmap()
704 if( bModulateColors
&&
705 renderState
.DeviceColor
.getLength() > 3 )
707 // optimize away the case where alpha modulation value
708 // is 1.0 - we then simply switch off modulation at all
709 bModulateColors
= !::rtl::math::approxEqual(
710 renderState
.DeviceColor
[3], 1.0);
713 // check whether we can render bitmap as-is: must not
714 // modulate colors, matrix must either be the identity
715 // transform (that's clear), _or_ contain only
716 // translational components.
717 if( !bModulateColors
&&
718 (aMatrix
.isIdentity() ||
719 (::basegfx::fTools::equalZero( aMatrix
.get(0,1) ) &&
720 ::basegfx::fTools::equalZero( aMatrix
.get(1,0) ) &&
721 ::rtl::math::approxEqual(aMatrix
.get(0,0), 1.0) &&
722 ::rtl::math::approxEqual(aMatrix
.get(1,1), 1.0)) ) )
724 // optimized case: identity matrix, or only
725 // translational components.
726 mpOutDev
->getOutDev().DrawBitmapEx( vcl::unotools::pointFromB2DPoint( aOutputPos
),
731 // HACK. Normally, CanvasHelper does not care about
732 // actually what mp2ndOutDev is... well, here we do &
733 // assume a 1bpp target - everything beyond 97%
734 // transparency is fully transparent
735 if( aBmpEx
.IsAlpha() )
737 Bitmap
aMask( aBmpEx
.GetAlpha().GetBitmap() );
738 aMask
.MakeMono( 253 );
739 aBmpEx
= BitmapEx( aBmpEx
.GetBitmap(), aMask
);
741 else if( aBmpEx
.IsTransparent() )
743 aBmpEx
= BitmapEx( aBmpEx
.GetBitmap(), aBmpEx
.GetMask() );
746 mp2ndOutDev
->getOutDev().DrawBitmapEx( vcl::unotools::pointFromB2DPoint( aOutputPos
),
750 // Returning a cache object is not useful, the XBitmap
751 // itself serves this purpose
752 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
756 // Matrix contains non-trivial transformation (or
757 // color modulation is requested), decompose to check
758 // whether GraphicObject suffices
759 ::basegfx::B2DVector aScale
;
762 aMatrix
.decompose( aScale
, aOutputPos
, nRotate
, nShearX
);
764 GraphicAttr aGrfAttr
;
765 GraphicObjectSharedPtr pGrfObj
;
767 ::Size
aBmpSize( aBmpEx
.GetSizePixel() );
769 // setup alpha modulation
770 if( bModulateColors
)
772 const double nAlphaModulation( renderState
.DeviceColor
[3] );
774 // TODO(F1): Note that the GraphicManager has a
775 // subtle difference in how it calculates the
776 // resulting alpha value: it's using the inverse
777 // alpha values (i.e. 'transparency'), and
778 // calculates transOrig + transModulate, instead
779 // of transOrig + transModulate -
780 // transOrig*transModulate (which would be
781 // equivalent to the origAlpha*modulateAlpha the
782 // DX canvas performs)
783 aGrfAttr
.SetTransparency(
784 static_cast< sal_uInt8
>(
785 ::basegfx::fround( 255.0*( 1.0 - nAlphaModulation
) ) ) );
788 if( ::basegfx::fTools::equalZero( nShearX
) )
790 // no shear, GraphicObject is enough (the
791 // GraphicObject only supports scaling, rotation
794 // #i75339# don't apply mirror flags, having
795 // negative size values is enough to make
796 // GraphicObject flip the bitmap
798 // The angle has to be mapped from radian to tenths of
799 // degress with the orientation reversed: [0,2Pi) ->
800 // (3600,0]. Note that the original angle may have
801 // values outside the [0,2Pi) interval.
802 const double nAngleInTenthOfDegrees (3600.0 - nRotate
* 3600.0 / (2*M_PI
));
803 aGrfAttr
.SetRotation( static_cast< sal_uInt16
>(::basegfx::fround(nAngleInTenthOfDegrees
)) );
805 pGrfObj
.reset( new GraphicObject( aBmpEx
) );
809 // modify output position, to account for the fact
810 // that transformBitmap() always normalizes its output
811 // bitmap into the smallest enclosing box.
812 ::basegfx::B2DRectangle aDestRect
;
813 ::canvas::tools::calcTransformedRectBounds( aDestRect
,
814 ::basegfx::B2DRectangle(0,
820 aOutputPos
.setX( aDestRect
.getMinX() );
821 aOutputPos
.setY( aDestRect
.getMinY() );
823 // complex transformation, use generic affine bitmap
825 aBmpEx
= tools::transformBitmap( aBmpEx
,
827 renderState
.DeviceColor
,
828 tools::MODULATE_NONE
);
830 pGrfObj
.reset( new GraphicObject( aBmpEx
) );
832 // clear scale values, generated bitmap already
834 aScale
.setX( 1.0 ); aScale
.setY( 1.0 );
836 // update bitmap size, bitmap has changed above.
837 aBmpSize
= aBmpEx
.GetSizePixel();
840 // output GraphicObject
841 const ::Point
aPt( vcl::unotools::pointFromB2DPoint( aOutputPos
) );
842 const ::Size
aSz( ::basegfx::fround( aScale
.getX() * aBmpSize
.Width() ),
843 ::basegfx::fround( aScale
.getY() * aBmpSize
.Height() ) );
845 pGrfObj
->Draw( &mpOutDev
->getOutDev(),
851 pGrfObj
->Draw( &mp2ndOutDev
->getOutDev(),
856 // created GraphicObject, which possibly cached
857 // display bitmap - return cache object, to retain
859 return uno::Reference
< rendering::XCachedPrimitive
>(
860 new CachedBitmap( pGrfObj
,
866 // cast away const, need to
867 // change refcount (as this is
868 // ~invisible to client code,
869 // still logically const)
870 const_cast< rendering::XCanvas
* >(pCanvas
)) );
875 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
878 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawBitmap( const rendering::XCanvas
* pCanvas
,
879 const uno::Reference
< rendering::XBitmap
>& xBitmap
,
880 const rendering::ViewState
& viewState
,
881 const rendering::RenderState
& renderState
)
883 return implDrawBitmap( pCanvas
,
890 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawBitmapModulated( const rendering::XCanvas
* pCanvas
,
891 const uno::Reference
< rendering::XBitmap
>& xBitmap
,
892 const rendering::ViewState
& viewState
,
893 const rendering::RenderState
& renderState
)
895 return implDrawBitmap( pCanvas
,
902 geometry::IntegerSize2D
CanvasHelper::getSize()
904 if( !mpOutDev
.get() )
905 return geometry::IntegerSize2D(); // we're disposed
907 return vcl::unotools::integerSize2DFromSize( mpOutDev
->getOutDev().GetOutputSizePixel() );
910 uno::Reference
< rendering::XBitmap
> CanvasHelper::getScaledBitmap( const geometry::RealSize2D
& newSize
,
913 if( !mpOutDev
.get() || !mpDevice
)
914 return uno::Reference
< rendering::XBitmap
>(); // we're disposed
916 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
918 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
919 rOutDev
.EnableMapMode( false );
920 rOutDev
.SetAntialiasing( AntialiasingFlags::EnableB2dDraw
);
922 // TODO(F2): Support alpha vdev canvas here
923 const Point
aEmptyPoint(0,0);
924 const Size
aBmpSize( rOutDev
.GetOutputSizePixel() );
926 Bitmap
aBitmap( rOutDev
.GetBitmap(aEmptyPoint
, aBmpSize
) );
928 aBitmap
.Scale( vcl::unotools::sizeFromRealSize2D(newSize
),
929 beFast
? BmpScaleFlag::Default
: BmpScaleFlag::BestQuality
);
931 return uno::Reference
< rendering::XBitmap
>(
932 new CanvasBitmap( aBitmap
, *mpDevice
, mpOutDev
) );
935 uno::Sequence
< sal_Int8
> CanvasHelper::getData( rendering::IntegerBitmapLayout
& rLayout
,
936 const geometry::IntegerRectangle2D
& rect
)
938 if( !mpOutDev
.get() )
939 return uno::Sequence
< sal_Int8
>(); // we're disposed
941 rLayout
= getMemoryLayout();
943 // TODO(F2): Support alpha canvas here
944 const Rectangle
aRect( vcl::unotools::rectangleFromIntegerRectangle2D(rect
) );
946 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
948 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
949 rOutDev
.EnableMapMode( false );
950 rOutDev
.SetAntialiasing( AntialiasingFlags::EnableB2dDraw
);
952 Bitmap
aBitmap( rOutDev
.GetBitmap(aRect
.TopLeft(),
955 Bitmap::ScopedReadAccess
pReadAccess( aBitmap
);
957 ENSURE_OR_THROW( pReadAccess
.get() != NULL
,
958 "Could not acquire read access to OutDev bitmap" );
960 const sal_Int32
nWidth( rect
.X2
- rect
.X1
);
961 const sal_Int32
nHeight( rect
.Y2
- rect
.Y1
);
963 rLayout
.ScanLines
= nHeight
;
964 rLayout
.ScanLineBytes
= nWidth
*4;
965 rLayout
.ScanLineStride
= rLayout
.ScanLineBytes
;
967 uno::Sequence
< sal_Int8
> aRes( 4*nWidth
*nHeight
);
968 sal_Int8
* pRes
= aRes
.getArray();
971 for( int y
=0; y
<nHeight
; ++y
)
973 for( int x
=0; x
<nWidth
; ++x
)
975 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetRed();
976 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetGreen();
977 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetBlue();
978 pRes
[ nCurrPos
++ ] = -1;
985 void CanvasHelper::setData( const uno::Sequence
< sal_Int8
>& data
,
986 const rendering::IntegerBitmapLayout
& aLayout
,
987 const geometry::IntegerRectangle2D
& rect
)
989 if( !mpOutDev
.get() )
990 return; // we're disposed
992 const rendering::IntegerBitmapLayout
aRefLayout( getMemoryLayout() );
993 ENSURE_ARG_OR_THROW( aRefLayout
.PlaneStride
!= aLayout
.PlaneStride
||
994 aRefLayout
.ColorSpace
!= aLayout
.ColorSpace
||
995 aRefLayout
.Palette
!= aLayout
.Palette
||
996 aRefLayout
.IsMsbFirst
!= aLayout
.IsMsbFirst
,
997 "Mismatching memory layout" );
999 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
1001 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
1002 rOutDev
.EnableMapMode( false );
1003 rOutDev
.SetAntialiasing( AntialiasingFlags::EnableB2dDraw
);
1005 const Rectangle
aRect( vcl::unotools::rectangleFromIntegerRectangle2D(rect
) );
1006 const sal_uInt16
nBitCount( ::std::min( (sal_uInt16
)24U,
1007 (sal_uInt16
)rOutDev
.GetBitCount() ) );
1008 const BitmapPalette
* pPalette
= NULL
;
1010 if( nBitCount
<= 8 )
1012 // TODO(Q1): Extract this to a common place, e.g. GraphicDevice
1014 // try to determine palette from output device (by
1015 // extracting a 1,1 bitmap, and querying it)
1016 const Point aEmptyPoint
;
1017 const Size
aSize(1,1);
1018 Bitmap
aTmpBitmap( rOutDev
.GetBitmap( aEmptyPoint
,
1021 Bitmap::ScopedReadAccess
pReadAccess( aTmpBitmap
);
1023 pPalette
= &pReadAccess
->GetPalette();
1026 // TODO(F2): Support alpha canvas here
1027 Bitmap
aBitmap( aRect
.GetSize(), nBitCount
, pPalette
);
1029 bool bCopyBack( false ); // only copy something back, if we
1030 // actually changed some pixel
1032 Bitmap::ScopedWriteAccess
pWriteAccess( aBitmap
);
1034 ENSURE_OR_THROW( pWriteAccess
.get() != NULL
,
1035 "Could not acquire write access to OutDev bitmap" );
1037 // for the time being, always read as RGB
1038 const sal_Int32
nWidth( rect
.X2
- rect
.X1
);
1039 const sal_Int32
nHeight( rect
.Y2
- rect
.Y1
);
1040 int x
, y
, nCurrPos(0);
1041 for( y
=0; y
<nHeight
; ++y
)
1043 switch( pWriteAccess
->GetScanlineFormat() )
1045 case BMP_FORMAT_8BIT_PAL
:
1047 Scanline pScan
= pWriteAccess
->GetScanline( y
);
1049 for( x
=0; x
<nWidth
; ++x
)
1051 *pScan
++ = (sal_uInt8
)pWriteAccess
->GetBestPaletteIndex(
1052 BitmapColor( data
[ nCurrPos
],
1054 data
[ nCurrPos
+2 ] ) );
1061 case BMP_FORMAT_24BIT_TC_BGR
:
1063 Scanline pScan
= pWriteAccess
->GetScanline( y
);
1065 for( x
=0; x
<nWidth
; ++x
)
1067 *pScan
++ = data
[ nCurrPos
+2 ];
1068 *pScan
++ = data
[ nCurrPos
+1 ];
1069 *pScan
++ = data
[ nCurrPos
];
1076 case BMP_FORMAT_24BIT_TC_RGB
:
1078 Scanline pScan
= pWriteAccess
->GetScanline( y
);
1080 for( x
=0; x
<nWidth
; ++x
)
1082 *pScan
++ = data
[ nCurrPos
];
1083 *pScan
++ = data
[ nCurrPos
+1 ];
1084 *pScan
++ = data
[ nCurrPos
+2 ];
1093 for( x
=0; x
<nWidth
; ++x
)
1095 pWriteAccess
->SetPixel( y
, x
, BitmapColor( data
[ nCurrPos
],
1097 data
[ nCurrPos
+2 ] ) );
1108 // copy back only here, since the BitmapAccessors must be
1109 // destroyed beforehand
1112 // TODO(F2): Support alpha canvas here
1113 rOutDev
.DrawBitmap(aRect
.TopLeft(), aBitmap
);
1117 void CanvasHelper::setPixel( const uno::Sequence
< sal_Int8
>& color
,
1118 const rendering::IntegerBitmapLayout
& rLayout
,
1119 const geometry::IntegerPoint2D
& pos
)
1121 if( !mpOutDev
.get() )
1122 return; // we're disposed
1124 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
1126 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
1127 rOutDev
.EnableMapMode( false );
1128 rOutDev
.SetAntialiasing( AntialiasingFlags::EnableB2dDraw
);
1130 const Size
aBmpSize( rOutDev
.GetOutputSizePixel() );
1132 ENSURE_ARG_OR_THROW( pos
.X
>= 0 && pos
.X
< aBmpSize
.Width(),
1133 "X coordinate out of bounds" );
1134 ENSURE_ARG_OR_THROW( pos
.Y
>= 0 && pos
.Y
< aBmpSize
.Height(),
1135 "Y coordinate out of bounds" );
1136 ENSURE_ARG_OR_THROW( color
.getLength() > 3,
1137 "not enough color components" );
1139 const rendering::IntegerBitmapLayout
aRefLayout( getMemoryLayout() );
1140 ENSURE_ARG_OR_THROW( aRefLayout
.PlaneStride
!= rLayout
.PlaneStride
||
1141 aRefLayout
.ColorSpace
!= rLayout
.ColorSpace
||
1142 aRefLayout
.Palette
!= rLayout
.Palette
||
1143 aRefLayout
.IsMsbFirst
!= rLayout
.IsMsbFirst
,
1144 "Mismatching memory layout" );
1146 // TODO(F2): Support alpha canvas here
1147 rOutDev
.DrawPixel( vcl::unotools::pointFromIntegerPoint2D( pos
),
1148 ::canvas::tools::stdIntSequenceToColor( color
));
1151 uno::Sequence
< sal_Int8
> CanvasHelper::getPixel( rendering::IntegerBitmapLayout
& rLayout
,
1152 const geometry::IntegerPoint2D
& pos
)
1154 if( !mpOutDev
.get() )
1155 return uno::Sequence
< sal_Int8
>(); // we're disposed
1157 rLayout
= getMemoryLayout();
1158 rLayout
.ScanLines
= 1;
1159 rLayout
.ScanLineBytes
= 4;
1160 rLayout
.ScanLineStride
= rLayout
.ScanLineBytes
;
1162 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
1164 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
1165 rOutDev
.EnableMapMode( false );
1166 rOutDev
.SetAntialiasing( AntialiasingFlags::EnableB2dDraw
);
1168 const Size
aBmpSize( rOutDev
.GetOutputSizePixel() );
1170 ENSURE_ARG_OR_THROW( pos
.X
>= 0 && pos
.X
< aBmpSize
.Width(),
1171 "X coordinate out of bounds" );
1172 ENSURE_ARG_OR_THROW( pos
.Y
>= 0 && pos
.Y
< aBmpSize
.Height(),
1173 "Y coordinate out of bounds" );
1175 // TODO(F2): Support alpha canvas here
1176 return ::canvas::tools::colorToStdIntSequence(
1178 vcl::unotools::pointFromIntegerPoint2D( pos
)));
1181 rendering::IntegerBitmapLayout
CanvasHelper::getMemoryLayout()
1183 if( !mpOutDev
.get() )
1184 return rendering::IntegerBitmapLayout(); // we're disposed
1186 rendering::IntegerBitmapLayout
xBitmapLayout( ::canvas::tools::getStdMemoryLayout(getSize()) );
1188 xBitmapLayout
.ColorSpace
= canvas::tools::getStdColorSpaceWithoutAlpha();
1190 return xBitmapLayout
;
1193 int CanvasHelper::setupOutDevState( const rendering::ViewState
& viewState
,
1194 const rendering::RenderState
& renderState
,
1195 ColorType eColorType
) const
1197 ENSURE_OR_THROW( mpOutDev
.get(),
1198 "outdev null. Are we disposed?" );
1200 ::canvas::tools::verifyInput( renderState
,
1201 BOOST_CURRENT_FUNCTION
,
1204 eColorType
== IGNORE_COLOR
? 0 : 3 );
1206 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
1207 OutputDevice
* p2ndOutDev
= NULL
;
1209 rOutDev
.EnableMapMode( false );
1210 rOutDev
.SetAntialiasing( AntialiasingFlags::EnableB2dDraw
);
1213 p2ndOutDev
= &mp2ndOutDev
->getOutDev();
1215 int nTransparency(0);
1217 // TODO(P2): Don't change clipping all the time, maintain current clip
1218 // state and change only when update is necessary
1219 ::canvas::tools::clipOutDev(viewState
, renderState
, rOutDev
, p2ndOutDev
);
1221 Color
aColor( COL_WHITE
);
1223 if( renderState
.DeviceColor
.getLength() > 2 )
1225 aColor
= vcl::unotools::stdColorSpaceSequenceToColor(
1226 renderState
.DeviceColor
);
1229 // extract alpha, and make color opaque
1230 // afterwards. Otherwise, OutputDevice won't draw anything
1231 nTransparency
= aColor
.GetTransparency();
1232 aColor
.SetTransparency(0);
1234 if( eColorType
!= IGNORE_COLOR
)
1236 switch( eColorType
)
1239 rOutDev
.SetLineColor( aColor
);
1240 rOutDev
.SetFillColor();
1244 p2ndOutDev
->SetLineColor( aColor
);
1245 p2ndOutDev
->SetFillColor();
1250 rOutDev
.SetFillColor( aColor
);
1251 rOutDev
.SetLineColor();
1255 p2ndOutDev
->SetFillColor( aColor
);
1256 p2ndOutDev
->SetLineColor();
1261 rOutDev
.SetTextColor( aColor
);
1264 p2ndOutDev
->SetTextColor( aColor
);
1268 ENSURE_OR_THROW( false,
1269 "Unexpected color type");
1274 return nTransparency
;
1277 bool CanvasHelper::setupTextOutput( ::Point
& o_rOutPos
,
1278 const rendering::ViewState
& viewState
,
1279 const rendering::RenderState
& renderState
,
1280 const uno::Reference
< rendering::XCanvasFont
>& xFont
) const
1282 ENSURE_OR_THROW( mpOutDev
.get(),
1283 "outdev null. Are we disposed?" );
1285 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
1287 setupOutDevState( viewState
, renderState
, TEXT_COLOR
);
1289 CanvasFont
* pFont
= dynamic_cast< CanvasFont
* >( xFont
.get() );
1291 ENSURE_ARG_OR_THROW( pFont
,
1292 "Font not compatible with this canvas" );
1294 vcl::Font aVCLFont
= pFont
->getVCLFont();
1296 Color
aColor( COL_BLACK
);
1298 if( renderState
.DeviceColor
.getLength() > 2 )
1300 aColor
= vcl::unotools::stdColorSpaceSequenceToColor(
1301 renderState
.DeviceColor
);
1305 aVCLFont
.SetColor( aColor
);
1306 aVCLFont
.SetFillColor( aColor
);
1308 // no need to replicate this for mp2ndOutDev, we're modifying only aVCLFont here.
1309 if( !tools::setupFontTransform( o_rOutPos
, aVCLFont
, viewState
, renderState
, rOutDev
) )
1312 rOutDev
.SetFont( aVCLFont
);
1315 mp2ndOutDev
->getOutDev().SetFont( aVCLFont
);
1320 bool CanvasHelper::repaint( const GraphicObjectSharedPtr
& rGrf
,
1321 const rendering::ViewState
& viewState
,
1322 const rendering::RenderState
& renderState
,
1325 const GraphicAttr
& rAttr
) const
1327 ENSURE_OR_RETURN_FALSE( rGrf
,
1328 "Invalid Graphic" );
1331 return false; // disposed
1334 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
1335 setupOutDevState( viewState
, renderState
, IGNORE_COLOR
);
1337 if( !rGrf
->Draw( &mpOutDev
->getOutDev(), rPt
, rSz
, &rAttr
) )
1340 // #i80779# Redraw also into mask outdev
1342 return rGrf
->Draw( &mp2ndOutDev
->getOutDev(), rPt
, rSz
, &rAttr
);
1348 void CanvasHelper::flush() const
1350 if( mpOutDev
&& mpOutDev
->getOutDev().GetOutDevType() == OUTDEV_WINDOW
)
1352 // TODO(Q3): Evil downcast. And what's more, Window::Flush is
1353 // not even const. Wah.
1354 static_cast<vcl::Window
&>(mpOutDev
->getOutDev()).Flush();
1357 if( mp2ndOutDev
&& mp2ndOutDev
->getOutDev().GetOutDevType() == OUTDEV_WINDOW
)
1359 // TODO(Q3): Evil downcast. And what's more, Window::Flush is
1360 // not even const. Wah.
1361 static_cast<vcl::Window
&>(mp2ndOutDev
->getOutDev()).Flush();
1367 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */