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( sal_False
);
160 void CanvasHelper::clear()
165 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
166 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
168 rOutDev
.EnableMapMode( sal_False
);
169 rOutDev
.SetLineColor( COL_WHITE
);
170 rOutDev
.SetFillColor( COL_WHITE
);
171 rOutDev
.SetClipRegion();
172 rOutDev
.DrawRect( Rectangle( Point(),
173 rOutDev
.GetOutputSizePixel()) );
177 OutputDevice
& rOutDev2( mp2ndOutDev
->getOutDev() );
179 rOutDev2
.SetDrawMode( DRAWMODE_DEFAULT
);
180 rOutDev2
.EnableMapMode( sal_False
);
181 rOutDev2
.SetLineColor( COL_WHITE
);
182 rOutDev2
.SetFillColor( COL_WHITE
);
183 rOutDev2
.SetClipRegion();
184 rOutDev2
.DrawRect( Rectangle( Point(),
185 rOutDev2
.GetOutputSizePixel()) );
186 rOutDev2
.SetDrawMode( DRAWMODE_BLACKLINE
| DRAWMODE_BLACKFILL
| DRAWMODE_BLACKTEXT
|
187 DRAWMODE_BLACKGRADIENT
| DRAWMODE_BLACKBITMAP
);
192 void CanvasHelper::drawPoint( const rendering::XCanvas
* ,
193 const geometry::RealPoint2D
& aPoint
,
194 const rendering::ViewState
& viewState
,
195 const rendering::RenderState
& renderState
)
201 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
202 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
204 const Point
aOutPoint( tools::mapRealPoint2D( aPoint
,
205 viewState
, renderState
) );
207 mpOutDev
->getOutDev().DrawPixel( aOutPoint
);
210 mp2ndOutDev
->getOutDev().DrawPixel( aOutPoint
);
214 void CanvasHelper::drawLine( const rendering::XCanvas
* ,
215 const geometry::RealPoint2D
& aStartRealPoint2D
,
216 const geometry::RealPoint2D
& aEndRealPoint2D
,
217 const rendering::ViewState
& viewState
,
218 const rendering::RenderState
& renderState
)
224 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
225 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
227 const Point
aStartPoint( tools::mapRealPoint2D( aStartRealPoint2D
,
228 viewState
, renderState
) );
229 const Point
aEndPoint( tools::mapRealPoint2D( aEndRealPoint2D
,
230 viewState
, renderState
) );
232 mpOutDev
->getOutDev().DrawLine( aStartPoint
, aEndPoint
);
235 mp2ndOutDev
->getOutDev().DrawLine( aStartPoint
, aEndPoint
);
239 void CanvasHelper::drawBezier( const rendering::XCanvas
* ,
240 const geometry::RealBezierSegment2D
& aBezierSegment
,
241 const geometry::RealPoint2D
& _aEndPoint
,
242 const rendering::ViewState
& viewState
,
243 const rendering::RenderState
& renderState
)
247 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
248 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
250 const Point
& rStartPoint( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment
.Px
,
252 viewState
, renderState
) );
253 const Point
& rCtrlPoint1( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment
.C1x
,
255 viewState
, renderState
) );
256 const Point
& rCtrlPoint2( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment
.C2x
,
258 viewState
, renderState
) );
259 const Point
& rEndPoint( tools::mapRealPoint2D( _aEndPoint
,
260 viewState
, renderState
) );
263 aPoly
.SetPoint( rStartPoint
, 0 );
264 aPoly
.SetFlags( 0, POLY_NORMAL
);
265 aPoly
.SetPoint( rCtrlPoint1
, 1 );
266 aPoly
.SetFlags( 1, POLY_CONTROL
);
267 aPoly
.SetPoint( rCtrlPoint2
, 2 );
268 aPoly
.SetFlags( 2, POLY_CONTROL
);
269 aPoly
.SetPoint( rEndPoint
, 3 );
270 aPoly
.SetFlags( 3, POLY_NORMAL
);
273 mpOutDev
->getOutDev().DrawPolygon( aPoly
);
275 mp2ndOutDev
->getOutDev().DrawPolygon( aPoly
);
279 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawPolyPolygon( const rendering::XCanvas
* ,
280 const uno::Reference
< rendering::XPolyPolygon2D
>& xPolyPolygon
,
281 const rendering::ViewState
& viewState
,
282 const rendering::RenderState
& renderState
)
284 ENSURE_ARG_OR_THROW( xPolyPolygon
.is(),
289 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
290 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
292 const ::basegfx::B2DPolyPolygon
& rPolyPoly(
293 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon
) );
294 const PolyPolygon
aPolyPoly( tools::mapPolyPolygon( rPolyPoly
, viewState
, renderState
) );
296 if( rPolyPoly
.isClosed() )
298 mpOutDev
->getOutDev().DrawPolyPolygon( aPolyPoly
);
301 mp2ndOutDev
->getOutDev().DrawPolyPolygon( aPolyPoly
);
305 // mixed open/closed state. Cannot render open polygon
306 // via DrawPolyPolygon(), since that implicitley
307 // closed every polygon. OTOH, no need to distinguish
308 // further and render closed polygons via
309 // DrawPolygon(), and open ones via DrawPolyLine():
310 // closed polygons will simply already contain the
312 sal_uInt16
nSize( aPolyPoly
.Count() );
314 for( sal_uInt16 i
=0; i
<nSize
; ++i
)
316 mpOutDev
->getOutDev().DrawPolyLine( aPolyPoly
[i
] );
319 mp2ndOutDev
->getOutDev().DrawPolyLine( aPolyPoly
[i
] );
324 // TODO(P1): Provide caching here.
325 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
328 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::strokePolyPolygon( const rendering::XCanvas
* ,
329 const uno::Reference
< rendering::XPolyPolygon2D
>& xPolyPolygon
,
330 const rendering::ViewState
& viewState
,
331 const rendering::RenderState
& renderState
,
332 const rendering::StrokeAttributes
& strokeAttributes
)
334 ENSURE_ARG_OR_THROW( xPolyPolygon
.is(),
339 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
341 ::basegfx::B2DHomMatrix aMatrix
;
342 ::canvas::tools::mergeViewAndRenderTransform(aMatrix
, viewState
, renderState
);
344 ::basegfx::B2DSize
aLinePixelSize(strokeAttributes
.StrokeWidth
,
345 strokeAttributes
.StrokeWidth
);
346 aLinePixelSize
*= aMatrix
;
348 ::basegfx::B2DPolyPolygon
aPolyPoly(
349 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon
) );
351 if( aPolyPoly
.areControlPointsUsed() )
353 // AW: Not needed for ApplyLineDashing anymore; should be removed
354 aPolyPoly
= ::basegfx::tools::adaptiveSubdivideByAngle(aPolyPoly
);
357 // apply dashing, if any
358 if( strokeAttributes
.DashArray
.getLength() )
360 const ::std::vector
<double>& aDashArray(
361 ::comphelper::sequenceToContainer
< ::std::vector
<double> >(strokeAttributes
.DashArray
) );
363 ::basegfx::B2DPolyPolygon aDashedPolyPoly
;
365 for( sal_uInt32 i
=0; i
<aPolyPoly
.count(); ++i
)
367 // AW: new interface; You may also get gaps in the same run now
368 basegfx::tools::applyLineDashing(aPolyPoly
.getB2DPolygon(i
), aDashArray
, &aDashedPolyPoly
);
369 //aDashedPolyPoly.append(
370 // ::basegfx::tools::applyLineDashing( aPolyPoly.getB2DPolygon(i),
374 aPolyPoly
= aDashedPolyPoly
;
377 ::basegfx::B2DPolyPolygon aStrokedPolyPoly
;
378 if( aLinePixelSize
.getLength() < 1.42 )
380 // line width < 1.0 in device pixel, thus, output as a
381 // simple hairline poly-polygon
382 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
384 aStrokedPolyPoly
= aPolyPoly
;
388 // render as a 'thick' line
389 setupOutDevState( viewState
, renderState
, FILL_COLOR
);
391 for( sal_uInt32 i
=0; i
<aPolyPoly
.count(); ++i
)
393 // TODO(F2): Use MiterLimit from StrokeAttributes,
394 // need to convert it here to angle.
396 // TODO(F2): Also use Cap settings from
397 // StrokeAttributes, the
398 // createAreaGeometryForLineStartEnd() method does not
399 // seem to fit very well here
401 // AW: New interface, will create bezier polygons now
402 aStrokedPolyPoly
.append(basegfx::tools::createAreaGeometry(
403 aPolyPoly
.getB2DPolygon(i
),
404 strokeAttributes
.StrokeWidth
*0.5,
405 b2DJoineFromJoin(strokeAttributes
.JoinType
),
406 unoCapeFromCap(strokeAttributes
.StartCapType
)
408 //aStrokedPolyPoly.append(
409 // ::basegfx::tools::createAreaGeometryForPolygon( aPolyPoly.getB2DPolygon(i),
410 // strokeAttributes.StrokeWidth*0.5,
411 // b2DJoineFromJoin(strokeAttributes.JoinType) ) );
415 // transform only _now_, all the StrokeAttributes are in
417 aStrokedPolyPoly
.transform( aMatrix
);
419 const PolyPolygon
aVCLPolyPoly( aStrokedPolyPoly
);
421 // TODO(F2): When using alpha here, must handle that via
422 // temporary surface or somesuch.
424 // Note: the generated stroke poly-polygon is NOT free of
425 // self-intersections. Therefore, if we would render it
426 // via OutDev::DrawPolyPolygon(), on/off fill would
427 // generate off areas on those self-intersections.
428 sal_uInt16
nSize( aVCLPolyPoly
.Count() );
430 for( sal_uInt16 i
=0; i
<nSize
; ++i
)
432 if( aStrokedPolyPoly
.getB2DPolygon( i
).isClosed() ) {
433 mpOutDev
->getOutDev().DrawPolygon( aVCLPolyPoly
[i
] );
435 mp2ndOutDev
->getOutDev().DrawPolygon( aVCLPolyPoly
[i
] );
437 const sal_uInt16 nPolySize
= aVCLPolyPoly
[i
].GetSize();
439 Point rPrevPoint
= aVCLPolyPoly
[i
].GetPoint( 0 );
442 for( sal_uInt16 j
=1; j
<nPolySize
; j
++ ) {
443 rPoint
= aVCLPolyPoly
[i
].GetPoint( j
);
444 mpOutDev
->getOutDev().DrawLine( rPrevPoint
, rPoint
);
446 mp2ndOutDev
->getOutDev().DrawLine( rPrevPoint
, rPoint
);
454 // TODO(P1): Provide caching here.
455 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
458 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas
* ,
459 const uno::Reference
< rendering::XPolyPolygon2D
>& ,
460 const rendering::ViewState
& ,
461 const rendering::RenderState
& ,
462 const uno::Sequence
< rendering::Texture
>& ,
463 const rendering::StrokeAttributes
& )
465 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
468 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::strokeTextureMappedPolyPolygon( const rendering::XCanvas
* ,
469 const uno::Reference
< rendering::XPolyPolygon2D
>& ,
470 const rendering::ViewState
& ,
471 const rendering::RenderState
& ,
472 const uno::Sequence
< rendering::Texture
>& ,
473 const uno::Reference
< geometry::XMapping2D
>& ,
474 const rendering::StrokeAttributes
& )
476 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
479 uno::Reference
< rendering::XPolyPolygon2D
> CanvasHelper::queryStrokeShapes( const rendering::XCanvas
* ,
480 const uno::Reference
< rendering::XPolyPolygon2D
>& ,
481 const rendering::ViewState
& ,
482 const rendering::RenderState
& ,
483 const rendering::StrokeAttributes
& )
485 return uno::Reference
< rendering::XPolyPolygon2D
>(NULL
);
488 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::fillPolyPolygon( const rendering::XCanvas
* ,
489 const uno::Reference
< rendering::XPolyPolygon2D
>& xPolyPolygon
,
490 const rendering::ViewState
& viewState
,
491 const rendering::RenderState
& renderState
)
493 ENSURE_ARG_OR_THROW( xPolyPolygon
.is(),
498 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
500 const int nTransparency( setupOutDevState( viewState
, renderState
, FILL_COLOR
) );
501 ::basegfx::B2DPolyPolygon
aB2DPolyPoly(
502 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon
));
503 aB2DPolyPoly
.setClosed(true); // ensure closed poly, otherwise VCL does not fill
504 const PolyPolygon
aPolyPoly( tools::mapPolyPolygon(
506 viewState
, renderState
) );
507 const bool bSourceAlpha( renderState
.CompositeOperation
== rendering::CompositeOperation::SOURCE
);
508 if( !nTransparency
|| bSourceAlpha
)
510 mpOutDev
->getOutDev().DrawPolyPolygon( aPolyPoly
);
514 const int nTransPercent( (nTransparency
* 100 + 128) / 255 ); // normal rounding, no truncation here
515 mpOutDev
->getOutDev().DrawTransparent( aPolyPoly
, (sal_uInt16
)nTransPercent
);
520 // HACK. Normally, CanvasHelper does not care about
521 // actually what mp2ndOutDev is... well, here we do &
522 // assume a 1bpp target - everything beyond 97%
523 // transparency is fully transparent
524 if( nTransparency
< 253 )
526 mp2ndOutDev
->getOutDev().SetFillColor( COL_BLACK
);
527 mp2ndOutDev
->getOutDev().DrawPolyPolygon( aPolyPoly
);
532 // TODO(P1): Provide caching here.
533 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
536 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas
* ,
537 const uno::Reference
< rendering::XPolyPolygon2D
>& ,
538 const rendering::ViewState
& ,
539 const rendering::RenderState
& ,
540 const uno::Sequence
< rendering::Texture
>& ,
541 const uno::Reference
< geometry::XMapping2D
>& )
543 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
546 uno::Reference
< rendering::XCanvasFont
> CanvasHelper::createFont( const rendering::XCanvas
* ,
547 const rendering::FontRequest
& fontRequest
,
548 const uno::Sequence
< beans::PropertyValue
>& extraFontProperties
,
549 const geometry::Matrix2D
& fontMatrix
)
551 if( mpOutDev
&& mpDevice
)
553 // TODO(F2): font properties and font matrix
554 return uno::Reference
< rendering::XCanvasFont
>(
555 new CanvasFont(fontRequest
, extraFontProperties
, fontMatrix
,
556 *mpDevice
, mpOutDev
) );
559 return uno::Reference
< rendering::XCanvasFont
>();
562 uno::Sequence
< rendering::FontInfo
> CanvasHelper::queryAvailableFonts( const rendering::XCanvas
* ,
563 const rendering::FontInfo
& ,
564 const uno::Sequence
< beans::PropertyValue
>& )
567 return uno::Sequence
< rendering::FontInfo
>();
570 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawText( const rendering::XCanvas
* ,
571 const rendering::StringContext
& text
,
572 const uno::Reference
< rendering::XCanvasFont
>& xFont
,
573 const rendering::ViewState
& viewState
,
574 const rendering::RenderState
& renderState
,
575 sal_Int8 textDirection
)
577 ENSURE_ARG_OR_THROW( xFont
.is(),
582 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
585 if( !setupTextOutput( aOutpos
, viewState
, renderState
, xFont
) )
586 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
); // no output necessary
588 // change text direction and layout mode
589 sal_uIntPtr
nLayoutMode(0);
590 switch( textDirection
)
592 case rendering::TextDirection::WEAK_LEFT_TO_RIGHT
:
593 nLayoutMode
|= TEXT_LAYOUT_BIDI_LTR
;
594 // FALLTHROUGH intended
595 case rendering::TextDirection::STRONG_LEFT_TO_RIGHT
:
596 nLayoutMode
|= TEXT_LAYOUT_BIDI_LTR
| TEXT_LAYOUT_BIDI_STRONG
;
597 nLayoutMode
|= TEXT_LAYOUT_TEXTORIGIN_LEFT
;
600 case rendering::TextDirection::WEAK_RIGHT_TO_LEFT
:
601 nLayoutMode
|= TEXT_LAYOUT_BIDI_RTL
;
602 // FALLTHROUGH intended
603 case rendering::TextDirection::STRONG_RIGHT_TO_LEFT
:
604 nLayoutMode
|= TEXT_LAYOUT_BIDI_RTL
| TEXT_LAYOUT_BIDI_STRONG
;
605 nLayoutMode
|= TEXT_LAYOUT_TEXTORIGIN_RIGHT
;
610 mpOutDev
->getOutDev().SetLayoutMode( nLayoutMode
);
611 mpOutDev
->getOutDev().DrawText( aOutpos
,
613 ::canvas::tools::numeric_cast
<sal_uInt16
>(text
.StartPosition
),
614 ::canvas::tools::numeric_cast
<sal_uInt16
>(text
.Length
) );
618 mp2ndOutDev
->getOutDev().SetLayoutMode( nLayoutMode
);
619 mp2ndOutDev
->getOutDev().DrawText( aOutpos
,
621 ::canvas::tools::numeric_cast
<sal_uInt16
>(text
.StartPosition
),
622 ::canvas::tools::numeric_cast
<sal_uInt16
>(text
.Length
) );
626 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
629 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawTextLayout( const rendering::XCanvas
* ,
630 const uno::Reference
< rendering::XTextLayout
>& xLayoutedText
,
631 const rendering::ViewState
& viewState
,
632 const rendering::RenderState
& renderState
)
634 ENSURE_ARG_OR_THROW( xLayoutedText
.is(),
637 TextLayout
* pTextLayout
= dynamic_cast< TextLayout
* >( xLayoutedText
.get() );
643 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
645 // TODO(T3): Race condition. We're taking the font
646 // from xLayoutedText, and then calling draw() at it,
647 // without exclusive access. Move setupTextOutput(),
648 // e.g. to impltools?
651 if( !setupTextOutput( aOutpos
, viewState
, renderState
, xLayoutedText
->getFont() ) )
652 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
); // no output necessary
654 // TODO(F2): What about the offset scalings?
656 pTextLayout
->draw( mpOutDev
->getOutDev(), aOutpos
, viewState
, renderState
);
659 pTextLayout
->draw( mp2ndOutDev
->getOutDev(), aOutpos
, viewState
, renderState
);
664 ENSURE_ARG_OR_THROW( false,
665 "TextLayout not compatible with this canvas" );
668 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
671 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::implDrawBitmap( const rendering::XCanvas
* pCanvas
,
672 const uno::Reference
< rendering::XBitmap
>& xBitmap
,
673 const rendering::ViewState
& viewState
,
674 const rendering::RenderState
& renderState
,
675 bool bModulateColors
)
677 ENSURE_ARG_OR_THROW( xBitmap
.is(),
680 ::canvas::tools::verifyInput( renderState
,
681 BOOST_CURRENT_FUNCTION
,
684 bModulateColors
? 3 : 0 );
688 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
689 setupOutDevState( viewState
, renderState
, IGNORE_COLOR
);
691 ::basegfx::B2DHomMatrix aMatrix
;
692 ::canvas::tools::mergeViewAndRenderTransform(aMatrix
, viewState
, renderState
);
694 ::basegfx::B2DPoint
aOutputPos( 0.0, 0.0 );
695 aOutputPos
*= aMatrix
;
697 BitmapEx
aBmpEx( tools::bitmapExFromXBitmap(xBitmap
) );
699 // TODO(F2): Implement modulation again for other color
700 // channels (currently, works only for alpha). Note: this
701 // is already implemented in transformBitmap()
702 if( bModulateColors
&&
703 renderState
.DeviceColor
.getLength() > 3 )
705 // optimize away the case where alpha modulation value
706 // is 1.0 - we then simply switch off modulation at all
707 bModulateColors
= !::rtl::math::approxEqual(
708 renderState
.DeviceColor
[3], 1.0);
711 // check whether we can render bitmap as-is: must not
712 // modulate colors, matrix must either be the identity
713 // transform (that's clear), _or_ contain only
714 // translational components.
715 if( !bModulateColors
&&
716 (aMatrix
.isIdentity() ||
717 (::basegfx::fTools::equalZero( aMatrix
.get(0,1) ) &&
718 ::basegfx::fTools::equalZero( aMatrix
.get(1,0) ) &&
719 ::rtl::math::approxEqual(aMatrix
.get(0,0), 1.0) &&
720 ::rtl::math::approxEqual(aMatrix
.get(1,1), 1.0)) ) )
722 // optimized case: identity matrix, or only
723 // translational components.
724 mpOutDev
->getOutDev().DrawBitmapEx( ::vcl::unotools::pointFromB2DPoint( aOutputPos
),
729 // HACK. Normally, CanvasHelper does not care about
730 // actually what mp2ndOutDev is... well, here we do &
731 // assume a 1bpp target - everything beyond 97%
732 // transparency is fully transparent
733 if( aBmpEx
.IsAlpha() )
735 Bitmap
aMask( aBmpEx
.GetAlpha().GetBitmap() );
736 aMask
.MakeMono( 253 );
737 aBmpEx
= BitmapEx( aBmpEx
.GetBitmap(), aMask
);
739 else if( aBmpEx
.IsTransparent() )
741 aBmpEx
= BitmapEx( aBmpEx
.GetBitmap(), aBmpEx
.GetMask() );
744 mp2ndOutDev
->getOutDev().DrawBitmapEx( ::vcl::unotools::pointFromB2DPoint( aOutputPos
),
748 // Returning a cache object is not useful, the XBitmap
749 // itself serves this purpose
750 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
754 // Matrix contains non-trivial transformation (or
755 // color modulation is requested), decompose to check
756 // whether GraphicObject suffices
757 ::basegfx::B2DVector aScale
;
760 aMatrix
.decompose( aScale
, aOutputPos
, nRotate
, nShearX
);
762 GraphicAttr aGrfAttr
;
763 GraphicObjectSharedPtr pGrfObj
;
765 ::Size
aBmpSize( aBmpEx
.GetSizePixel() );
767 // setup alpha modulation
768 if( bModulateColors
)
770 const double nAlphaModulation( renderState
.DeviceColor
[3] );
772 // TODO(F1): Note that the GraphicManager has a
773 // subtle difference in how it calculates the
774 // resulting alpha value: it's using the inverse
775 // alpha values (i.e. 'transparency'), and
776 // calculates transOrig + transModulate, instead
777 // of transOrig + transModulate -
778 // transOrig*transModulate (which would be
779 // equivalent to the origAlpha*modulateAlpha the
780 // DX canvas performs)
781 aGrfAttr
.SetTransparency(
782 static_cast< sal_uInt8
>(
783 ::basegfx::fround( 255.0*( 1.0 - nAlphaModulation
) ) ) );
786 if( ::basegfx::fTools::equalZero( nShearX
) )
788 // no shear, GraphicObject is enough (the
789 // GraphicObject only supports scaling, rotation
792 // #i75339# don't apply mirror flags, having
793 // negative size values is enough to make
794 // GraphicObject flip the bitmap
796 // The angle has to be mapped from radian to tenths of
797 // degress with the orientation reversed: [0,2Pi) ->
798 // (3600,0]. Note that the original angle may have
799 // values outside the [0,2Pi) interval.
800 const double nAngleInTenthOfDegrees (3600.0 - nRotate
* 3600.0 / (2*M_PI
));
801 aGrfAttr
.SetRotation( static_cast< sal_uInt16
>(::basegfx::fround(nAngleInTenthOfDegrees
)) );
803 pGrfObj
.reset( new GraphicObject( aBmpEx
) );
807 // modify output position, to account for the fact
808 // that transformBitmap() always normalizes its output
809 // bitmap into the smallest enclosing box.
810 ::basegfx::B2DRectangle aDestRect
;
811 ::canvas::tools::calcTransformedRectBounds( aDestRect
,
812 ::basegfx::B2DRectangle(0,
818 aOutputPos
.setX( aDestRect
.getMinX() );
819 aOutputPos
.setY( aDestRect
.getMinY() );
821 // complex transformation, use generic affine bitmap
823 aBmpEx
= tools::transformBitmap( aBmpEx
,
825 renderState
.DeviceColor
,
826 tools::MODULATE_NONE
);
828 pGrfObj
.reset( new GraphicObject( aBmpEx
) );
830 // clear scale values, generated bitmap already
832 aScale
.setX( 1.0 ); aScale
.setY( 1.0 );
834 // update bitmap size, bitmap has changed above.
835 aBmpSize
= aBmpEx
.GetSizePixel();
838 // output GraphicObject
839 const ::Point
aPt( ::vcl::unotools::pointFromB2DPoint( aOutputPos
) );
840 const ::Size
aSz( ::basegfx::fround( aScale
.getX() * aBmpSize
.Width() ),
841 ::basegfx::fround( aScale
.getY() * aBmpSize
.Height() ) );
843 pGrfObj
->Draw( &mpOutDev
->getOutDev(),
849 pGrfObj
->Draw( &mp2ndOutDev
->getOutDev(),
854 // created GraphicObject, which possibly cached
855 // display bitmap - return cache object, to retain
857 return uno::Reference
< rendering::XCachedPrimitive
>(
858 new CachedBitmap( pGrfObj
,
864 // cast away const, need to
865 // change refcount (as this is
866 // ~invisible to client code,
867 // still logically const)
868 const_cast< rendering::XCanvas
* >(pCanvas
)) );
873 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
876 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawBitmap( const rendering::XCanvas
* pCanvas
,
877 const uno::Reference
< rendering::XBitmap
>& xBitmap
,
878 const rendering::ViewState
& viewState
,
879 const rendering::RenderState
& renderState
)
881 return implDrawBitmap( pCanvas
,
888 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawBitmapModulated( const rendering::XCanvas
* pCanvas
,
889 const uno::Reference
< rendering::XBitmap
>& xBitmap
,
890 const rendering::ViewState
& viewState
,
891 const rendering::RenderState
& renderState
)
893 return implDrawBitmap( pCanvas
,
900 uno::Reference
< rendering::XGraphicDevice
> CanvasHelper::getDevice()
902 // cast away const, need to change refcount (as this is
903 // ~invisible to client code, still logically const)
904 return uno::Reference
< rendering::XGraphicDevice
>(mpDevice
);
907 void CanvasHelper::copyRect( const rendering::XCanvas
* ,
908 const uno::Reference
< rendering::XBitmapCanvas
>& ,
909 const geometry::RealRectangle2D
& ,
910 const rendering::ViewState
& ,
911 const rendering::RenderState
& ,
912 const geometry::RealRectangle2D
& ,
913 const rendering::ViewState
& ,
914 const rendering::RenderState
& )
919 geometry::IntegerSize2D
CanvasHelper::getSize()
921 if( !mpOutDev
.get() )
922 return geometry::IntegerSize2D(); // we're disposed
924 return ::vcl::unotools::integerSize2DFromSize( mpOutDev
->getOutDev().GetOutputSizePixel() );
927 uno::Reference
< rendering::XBitmap
> CanvasHelper::getScaledBitmap( const geometry::RealSize2D
& newSize
,
930 if( !mpOutDev
.get() || !mpDevice
)
931 return uno::Reference
< rendering::XBitmap
>(); // we're disposed
933 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
935 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
936 rOutDev
.EnableMapMode( sal_False
);
938 // TODO(F2): Support alpha vdev canvas here
939 const Point
aEmptyPoint(0,0);
940 const Size
aBmpSize( rOutDev
.GetOutputSizePixel() );
942 Bitmap
aBitmap( rOutDev
.GetBitmap(aEmptyPoint
, aBmpSize
) );
944 aBitmap
.Scale( ::vcl::unotools::sizeFromRealSize2D(newSize
),
945 beFast
? BMP_SCALE_DEFAULT
: BMP_SCALE_BESTQUALITY
);
947 return uno::Reference
< rendering::XBitmap
>(
948 new CanvasBitmap( aBitmap
, *mpDevice
, mpOutDev
) );
951 uno::Sequence
< sal_Int8
> CanvasHelper::getData( rendering::IntegerBitmapLayout
& rLayout
,
952 const geometry::IntegerRectangle2D
& rect
)
954 if( !mpOutDev
.get() )
955 return uno::Sequence
< sal_Int8
>(); // we're disposed
957 rLayout
= getMemoryLayout();
959 // TODO(F2): Support alpha canvas here
960 const Rectangle
aRect( ::vcl::unotools::rectangleFromIntegerRectangle2D(rect
) );
962 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
964 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
965 rOutDev
.EnableMapMode( sal_False
);
967 Bitmap
aBitmap( rOutDev
.GetBitmap(aRect
.TopLeft(),
970 Bitmap::ScopedReadAccess
pReadAccess( aBitmap
);
972 ENSURE_OR_THROW( pReadAccess
.get() != NULL
,
973 "Could not acquire read access to OutDev bitmap" );
975 const sal_Int32
nWidth( rect
.X2
- rect
.X1
);
976 const sal_Int32
nHeight( rect
.Y2
- rect
.Y1
);
978 rLayout
.ScanLines
= nHeight
;
979 rLayout
.ScanLineBytes
= nWidth
*4;
980 rLayout
.ScanLineStride
= rLayout
.ScanLineBytes
;
982 uno::Sequence
< sal_Int8
> aRes( 4*nWidth
*nHeight
);
983 sal_Int8
* pRes
= aRes
.getArray();
986 for( int y
=0; y
<nHeight
; ++y
)
988 for( int x
=0; x
<nWidth
; ++x
)
990 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetRed();
991 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetGreen();
992 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetBlue();
993 pRes
[ nCurrPos
++ ] = -1;
1000 void CanvasHelper::setData( const uno::Sequence
< sal_Int8
>& data
,
1001 const rendering::IntegerBitmapLayout
& aLayout
,
1002 const geometry::IntegerRectangle2D
& rect
)
1004 if( !mpOutDev
.get() )
1005 return; // we're disposed
1007 const rendering::IntegerBitmapLayout
aRefLayout( getMemoryLayout() );
1008 ENSURE_ARG_OR_THROW( aRefLayout
.PlaneStride
!= aLayout
.PlaneStride
||
1009 aRefLayout
.ColorSpace
!= aLayout
.ColorSpace
||
1010 aRefLayout
.Palette
!= aLayout
.Palette
||
1011 aRefLayout
.IsMsbFirst
!= aLayout
.IsMsbFirst
,
1012 "Mismatching memory layout" );
1014 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
1016 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
1017 rOutDev
.EnableMapMode( sal_False
);
1019 const Rectangle
aRect( ::vcl::unotools::rectangleFromIntegerRectangle2D(rect
) );
1020 const sal_uInt16
nBitCount( ::std::min( (sal_uInt16
)24U,
1021 (sal_uInt16
)rOutDev
.GetBitCount() ) );
1022 const BitmapPalette
* pPalette
= NULL
;
1024 if( nBitCount
<= 8 )
1026 // TODO(Q1): Extract this to a common place, e.g. GraphicDevice
1028 // try to determine palette from output device (by
1029 // extracting a 1,1 bitmap, and querying it)
1030 const Point aEmptyPoint
;
1031 const Size
aSize(1,1);
1032 Bitmap
aTmpBitmap( rOutDev
.GetBitmap( aEmptyPoint
,
1035 Bitmap::ScopedReadAccess
pReadAccess( aTmpBitmap
);
1037 pPalette
= &pReadAccess
->GetPalette();
1040 // TODO(F2): Support alpha canvas here
1041 Bitmap
aBitmap( aRect
.GetSize(), nBitCount
, pPalette
);
1043 bool bCopyBack( false ); // only copy something back, if we
1044 // actually changed some pixel
1046 Bitmap::ScopedWriteAccess
pWriteAccess( aBitmap
);
1048 ENSURE_OR_THROW( pWriteAccess
.get() != NULL
,
1049 "Could not acquire write access to OutDev bitmap" );
1051 // for the time being, always read as RGB
1052 const sal_Int32
nWidth( rect
.X2
- rect
.X1
);
1053 const sal_Int32
nHeight( rect
.Y2
- rect
.Y1
);
1054 int x
, y
, nCurrPos(0);
1055 for( y
=0; y
<nHeight
; ++y
)
1057 switch( pWriteAccess
->GetScanlineFormat() )
1059 case BMP_FORMAT_8BIT_PAL
:
1061 Scanline pScan
= pWriteAccess
->GetScanline( y
);
1063 for( x
=0; x
<nWidth
; ++x
)
1065 *pScan
++ = (sal_uInt8
)pWriteAccess
->GetBestPaletteIndex(
1066 BitmapColor( data
[ nCurrPos
],
1068 data
[ nCurrPos
+2 ] ) );
1075 case BMP_FORMAT_24BIT_TC_BGR
:
1077 Scanline pScan
= pWriteAccess
->GetScanline( y
);
1079 for( x
=0; x
<nWidth
; ++x
)
1081 *pScan
++ = data
[ nCurrPos
+2 ];
1082 *pScan
++ = data
[ nCurrPos
+1 ];
1083 *pScan
++ = data
[ nCurrPos
];
1090 case BMP_FORMAT_24BIT_TC_RGB
:
1092 Scanline pScan
= pWriteAccess
->GetScanline( y
);
1094 for( x
=0; x
<nWidth
; ++x
)
1096 *pScan
++ = data
[ nCurrPos
];
1097 *pScan
++ = data
[ nCurrPos
+1 ];
1098 *pScan
++ = data
[ nCurrPos
+2 ];
1107 for( x
=0; x
<nWidth
; ++x
)
1109 pWriteAccess
->SetPixel( y
, x
, BitmapColor( data
[ nCurrPos
],
1111 data
[ nCurrPos
+2 ] ) );
1122 // copy back only here, since the BitmapAccessors must be
1123 // destroyed beforehand
1126 // TODO(F2): Support alpha canvas here
1127 rOutDev
.DrawBitmap(aRect
.TopLeft(), aBitmap
);
1131 void CanvasHelper::setPixel( const uno::Sequence
< sal_Int8
>& color
,
1132 const rendering::IntegerBitmapLayout
& rLayout
,
1133 const geometry::IntegerPoint2D
& pos
)
1135 if( !mpOutDev
.get() )
1136 return; // we're disposed
1138 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
1140 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
1141 rOutDev
.EnableMapMode( sal_False
);
1143 const Size
aBmpSize( rOutDev
.GetOutputSizePixel() );
1145 ENSURE_ARG_OR_THROW( pos
.X
>= 0 && pos
.X
< aBmpSize
.Width(),
1146 "X coordinate out of bounds" );
1147 ENSURE_ARG_OR_THROW( pos
.Y
>= 0 && pos
.Y
< aBmpSize
.Height(),
1148 "Y coordinate out of bounds" );
1149 ENSURE_ARG_OR_THROW( color
.getLength() > 3,
1150 "not enough color components" );
1152 const rendering::IntegerBitmapLayout
aRefLayout( getMemoryLayout() );
1153 ENSURE_ARG_OR_THROW( aRefLayout
.PlaneStride
!= rLayout
.PlaneStride
||
1154 aRefLayout
.ColorSpace
!= rLayout
.ColorSpace
||
1155 aRefLayout
.Palette
!= rLayout
.Palette
||
1156 aRefLayout
.IsMsbFirst
!= rLayout
.IsMsbFirst
,
1157 "Mismatching memory layout" );
1159 // TODO(F2): Support alpha canvas here
1160 rOutDev
.DrawPixel( ::vcl::unotools::pointFromIntegerPoint2D( pos
),
1161 ::canvas::tools::stdIntSequenceToColor( color
));
1164 uno::Sequence
< sal_Int8
> CanvasHelper::getPixel( rendering::IntegerBitmapLayout
& rLayout
,
1165 const geometry::IntegerPoint2D
& pos
)
1167 if( !mpOutDev
.get() )
1168 return uno::Sequence
< sal_Int8
>(); // we're disposed
1170 rLayout
= getMemoryLayout();
1171 rLayout
.ScanLines
= 1;
1172 rLayout
.ScanLineBytes
= 4;
1173 rLayout
.ScanLineStride
= rLayout
.ScanLineBytes
;
1175 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
1177 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
1178 rOutDev
.EnableMapMode( sal_False
);
1180 const Size
aBmpSize( rOutDev
.GetOutputSizePixel() );
1182 ENSURE_ARG_OR_THROW( pos
.X
>= 0 && pos
.X
< aBmpSize
.Width(),
1183 "X coordinate out of bounds" );
1184 ENSURE_ARG_OR_THROW( pos
.Y
>= 0 && pos
.Y
< aBmpSize
.Height(),
1185 "Y coordinate out of bounds" );
1187 // TODO(F2): Support alpha canvas here
1188 return ::canvas::tools::colorToStdIntSequence(
1190 ::vcl::unotools::pointFromIntegerPoint2D( pos
)));
1193 rendering::IntegerBitmapLayout
CanvasHelper::getMemoryLayout()
1195 if( !mpOutDev
.get() )
1196 return rendering::IntegerBitmapLayout(); // we're disposed
1198 rendering::IntegerBitmapLayout
xBitmapLayout( ::canvas::tools::getStdMemoryLayout(getSize()) );
1200 xBitmapLayout
.ColorSpace
= canvas::tools::getStdColorSpaceWithoutAlpha();
1202 return xBitmapLayout
;
1205 int CanvasHelper::setupOutDevState( const rendering::ViewState
& viewState
,
1206 const rendering::RenderState
& renderState
,
1207 ColorType eColorType
) const
1209 ENSURE_OR_THROW( mpOutDev
.get(),
1210 "outdev null. Are we disposed?" );
1212 ::canvas::tools::verifyInput( renderState
,
1213 BOOST_CURRENT_FUNCTION
,
1216 eColorType
== IGNORE_COLOR
? 0 : 3 );
1218 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
1219 OutputDevice
* p2ndOutDev
= NULL
;
1221 rOutDev
.EnableMapMode( sal_False
);
1224 p2ndOutDev
= &mp2ndOutDev
->getOutDev();
1226 int nTransparency(0);
1228 // TODO(P2): Don't change clipping all the time, maintain current clip
1229 // state and change only when update is necessary
1231 // accumulate non-empty clips into one region
1232 // ==========================================
1234 Region
aClipRegion( REGION_NULL
);
1236 if( viewState
.Clip
.is() )
1238 ::basegfx::B2DPolyPolygon
aClipPoly(
1239 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(viewState
.Clip
) );
1241 if( aClipPoly
.count() )
1243 // setup non-empty clipping
1244 ::basegfx::B2DHomMatrix aMatrix
;
1245 aClipPoly
.transform(
1246 ::basegfx::unotools::homMatrixFromAffineMatrix( aMatrix
,
1247 viewState
.AffineTransform
) );
1249 aClipRegion
= Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly
) );
1253 // clip polygon is empty
1254 aClipRegion
.SetEmpty();
1258 if( renderState
.Clip
.is() )
1260 ::basegfx::B2DPolyPolygon
aClipPoly(
1261 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(renderState
.Clip
) );
1263 ::basegfx::B2DHomMatrix aMatrix
;
1264 aClipPoly
.transform(
1265 ::canvas::tools::mergeViewAndRenderTransform( aMatrix
,
1269 if( aClipPoly
.count() )
1271 // setup non-empty clipping
1272 Region aRegion
= Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly
) );
1273 aClipRegion
.Intersect( aRegion
);
1277 // clip polygon is empty
1278 aClipRegion
.SetEmpty();
1282 // setup accumulated clip region. Note that setting an
1283 // empty clip region denotes "clip everything" on the
1284 // OutputDevice (which is why we translate that into
1285 // SetClipRegion() here). When both view and render clip
1286 // are empty, aClipRegion remains default-constructed,
1288 if( aClipRegion
.IsNull() )
1290 rOutDev
.SetClipRegion();
1293 p2ndOutDev
->SetClipRegion();
1297 rOutDev
.SetClipRegion( aClipRegion
);
1300 p2ndOutDev
->SetClipRegion( aClipRegion
);
1303 Color
aColor( COL_WHITE
);
1305 if( renderState
.DeviceColor
.getLength() > 2 )
1307 aColor
= ::vcl::unotools::stdColorSpaceSequenceToColor(
1308 renderState
.DeviceColor
);
1311 // extract alpha, and make color opaque
1312 // afterwards. Otherwise, OutputDevice won't draw anything
1313 nTransparency
= aColor
.GetTransparency();
1314 aColor
.SetTransparency(0);
1316 if( eColorType
!= IGNORE_COLOR
)
1318 switch( eColorType
)
1321 rOutDev
.SetLineColor( aColor
);
1322 rOutDev
.SetFillColor();
1326 p2ndOutDev
->SetLineColor( aColor
);
1327 p2ndOutDev
->SetFillColor();
1332 rOutDev
.SetFillColor( aColor
);
1333 rOutDev
.SetLineColor();
1337 p2ndOutDev
->SetFillColor( aColor
);
1338 p2ndOutDev
->SetLineColor();
1343 rOutDev
.SetTextColor( aColor
);
1346 p2ndOutDev
->SetTextColor( aColor
);
1350 ENSURE_OR_THROW( false,
1351 "Unexpected color type");
1356 return nTransparency
;
1359 bool CanvasHelper::setupTextOutput( ::Point
& o_rOutPos
,
1360 const rendering::ViewState
& viewState
,
1361 const rendering::RenderState
& renderState
,
1362 const uno::Reference
< rendering::XCanvasFont
>& xFont
) const
1364 ENSURE_OR_THROW( mpOutDev
.get(),
1365 "outdev null. Are we disposed?" );
1367 setupOutDevState( viewState
, renderState
, TEXT_COLOR
);
1369 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
1373 CanvasFont
* pFont
= dynamic_cast< CanvasFont
* >( xFont
.get() );
1375 ENSURE_ARG_OR_THROW( pFont
,
1376 "Font not compatible with this canvas" );
1378 aVCLFont
= pFont
->getVCLFont();
1380 Color
aColor( COL_BLACK
);
1382 if( renderState
.DeviceColor
.getLength() > 2 )
1384 aColor
= ::vcl::unotools::stdColorSpaceSequenceToColor(
1385 renderState
.DeviceColor
);
1389 aVCLFont
.SetColor( aColor
);
1390 aVCLFont
.SetFillColor( aColor
);
1392 // no need to replicate this for mp2ndOutDev, we're modifying only aVCLFont here.
1393 if( !tools::setupFontTransform( o_rOutPos
, aVCLFont
, viewState
, renderState
, rOutDev
) )
1396 rOutDev
.SetFont( aVCLFont
);
1399 mp2ndOutDev
->getOutDev().SetFont( aVCLFont
);
1404 bool CanvasHelper::repaint( const GraphicObjectSharedPtr
& rGrf
,
1405 const rendering::ViewState
& viewState
,
1406 const rendering::RenderState
& renderState
,
1409 const GraphicAttr
& rAttr
) const
1411 ENSURE_OR_RETURN_FALSE( rGrf
,
1412 "Invalid Graphic" );
1415 return false; // disposed
1418 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
1419 setupOutDevState( viewState
, renderState
, IGNORE_COLOR
);
1421 if( !rGrf
->Draw( &mpOutDev
->getOutDev(), rPt
, rSz
, &rAttr
) )
1424 // #i80779# Redraw also into mask outdev
1426 return rGrf
->Draw( &mp2ndOutDev
->getOutDev(), rPt
, rSz
, &rAttr
);
1432 void CanvasHelper::flush() const
1434 if( mpOutDev
&& mpOutDev
->getOutDev().GetOutDevType() == OUTDEV_WINDOW
)
1436 // TODO(Q3): Evil downcast. And what's more, Window::Flush is
1437 // not even const. Wah.
1438 static_cast<Window
&>(mpOutDev
->getOutDev()).Flush();
1441 if( mp2ndOutDev
&& mp2ndOutDev
->getOutDev().GetOutDevType() == OUTDEV_WINDOW
)
1443 // TODO(Q3): Evil downcast. And what's more, Window::Flush is
1444 // not even const. Wah.
1445 static_cast<Window
&>(mp2ndOutDev
->getOutDev()).Flush();
1451 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */