1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: canvashelper.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_canvas.hxx"
34 #include <canvas/debug.hxx>
35 #include <tools/diagnose_ex.h>
37 #include <rtl/math.hxx>
39 #include <com/sun/star/rendering/CompositeOperation.hpp>
40 #include <com/sun/star/util/Endianness.hpp>
41 #include <com/sun/star/rendering/TextDirection.hpp>
42 #include <com/sun/star/rendering/TexturingMode.hpp>
43 #include <com/sun/star/rendering/PathCapType.hpp>
44 #include <com/sun/star/rendering/PathJoinType.hpp>
46 #include <tools/poly.hxx>
47 #include <vcl/window.hxx>
48 #include <vcl/bitmapex.hxx>
49 #include <vcl/bmpacc.hxx>
50 #include <vcl/canvastools.hxx>
52 #include <basegfx/matrix/b2dhommatrix.hxx>
53 #include <basegfx/range/b2drectangle.hxx>
54 #include <basegfx/point/b2dpoint.hxx>
55 #include <basegfx/vector/b2dsize.hxx>
56 #include <basegfx/polygon/b2dpolygon.hxx>
57 #include <basegfx/polygon/b2dpolygontools.hxx>
58 #include <basegfx/polygon/b2dpolypolygontools.hxx>
59 #include <basegfx/polygon/b2dlinegeometry.hxx>
60 #include <basegfx/tools/canvastools.hxx>
61 #include <basegfx/numeric/ftools.hxx>
65 #include <comphelper/sequence.hxx>
66 #include <canvas/canvastools.hxx>
68 #include "textlayout.hxx"
69 #include "canvashelper.hxx"
70 #include "canvasbitmap.hxx"
71 #include "impltools.hxx"
72 #include "canvasfont.hxx"
75 using namespace ::com::sun::star
;
81 basegfx::B2DLineJoin
b2DJoineFromJoin( sal_Int8 nJoinType
)
85 case rendering::PathJoinType::NONE
:
86 return basegfx::B2DLINEJOIN_NONE
;
88 case rendering::PathJoinType::MITER
:
89 return basegfx::B2DLINEJOIN_MITER
;
91 case rendering::PathJoinType::ROUND
:
92 return basegfx::B2DLINEJOIN_ROUND
;
94 case rendering::PathJoinType::BEVEL
:
95 return basegfx::B2DLINEJOIN_BEVEL
;
98 ENSURE_OR_THROW( false,
99 "b2DJoineFromJoin(): Unexpected join type" );
102 return basegfx::B2DLINEJOIN_NONE
;
106 CanvasHelper::CanvasHelper() :
115 void CanvasHelper::disposing()
118 mpProtectedOutDev
.reset();
123 void CanvasHelper::init( rendering::XGraphicDevice
& rDevice
,
124 const OutDevProviderSharedPtr
& rOutDev
,
128 // cast away const, need to change refcount (as this is
129 // ~invisible to client code, still logically const)
131 mbHaveAlpha
= bHaveAlpha
;
133 setOutDev( rOutDev
, bProtect
);
136 void CanvasHelper::setOutDev( const OutDevProviderSharedPtr
& rOutDev
,
140 mpProtectedOutDev
= rOutDev
;
142 mpProtectedOutDev
.reset();
147 void CanvasHelper::setBackgroundOutDev( const OutDevProviderSharedPtr
& rOutDev
)
149 mp2ndOutDev
= rOutDev
;
150 mp2ndOutDev
->getOutDev().EnableMapMode( FALSE
);
153 void CanvasHelper::clear()
158 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
159 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
161 rOutDev
.EnableMapMode( FALSE
);
162 rOutDev
.SetLineColor( COL_WHITE
);
163 rOutDev
.SetFillColor( COL_WHITE
);
164 rOutDev
.DrawRect( Rectangle( Point(),
165 rOutDev
.GetOutputSizePixel()) );
169 OutputDevice
& rOutDev2( mp2ndOutDev
->getOutDev() );
171 rOutDev2
.SetDrawMode( DRAWMODE_DEFAULT
);
172 rOutDev2
.EnableMapMode( FALSE
);
173 rOutDev2
.SetLineColor( COL_WHITE
);
174 rOutDev2
.SetFillColor( COL_WHITE
);
175 rOutDev2
.DrawRect( Rectangle( Point(),
176 rOutDev2
.GetOutputSizePixel()) );
177 rOutDev2
.SetDrawMode( DRAWMODE_BLACKLINE
| DRAWMODE_BLACKFILL
| DRAWMODE_BLACKTEXT
|
178 DRAWMODE_BLACKGRADIENT
| DRAWMODE_BLACKBITMAP
);
183 void CanvasHelper::drawPoint( const rendering::XCanvas
* ,
184 const geometry::RealPoint2D
& aPoint
,
185 const rendering::ViewState
& viewState
,
186 const rendering::RenderState
& renderState
)
192 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
193 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
195 const Point
aOutPoint( tools::mapRealPoint2D( aPoint
,
196 viewState
, renderState
) );
198 mpOutDev
->getOutDev().DrawPixel( aOutPoint
);
201 mp2ndOutDev
->getOutDev().DrawPixel( aOutPoint
);
205 void CanvasHelper::drawLine( const rendering::XCanvas
* ,
206 const geometry::RealPoint2D
& aStartRealPoint2D
,
207 const geometry::RealPoint2D
& aEndRealPoint2D
,
208 const rendering::ViewState
& viewState
,
209 const rendering::RenderState
& renderState
)
215 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
216 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
218 const Point
aStartPoint( tools::mapRealPoint2D( aStartRealPoint2D
,
219 viewState
, renderState
) );
220 const Point
aEndPoint( tools::mapRealPoint2D( aEndRealPoint2D
,
221 viewState
, renderState
) );
223 mpOutDev
->getOutDev().DrawLine( aStartPoint
, aEndPoint
);
226 mp2ndOutDev
->getOutDev().DrawLine( aStartPoint
, aEndPoint
);
230 void CanvasHelper::drawBezier( const rendering::XCanvas
* ,
231 const geometry::RealBezierSegment2D
& aBezierSegment
,
232 const geometry::RealPoint2D
& _aEndPoint
,
233 const rendering::ViewState
& viewState
,
234 const rendering::RenderState
& renderState
)
238 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
239 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
241 const Point
& rStartPoint( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment
.Px
,
243 viewState
, renderState
) );
244 const Point
& rCtrlPoint1( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment
.C1x
,
246 viewState
, renderState
) );
247 const Point
& rCtrlPoint2( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment
.C2x
,
249 viewState
, renderState
) );
250 const Point
& rEndPoint( tools::mapRealPoint2D( _aEndPoint
,
251 viewState
, renderState
) );
254 aPoly
.SetPoint( rStartPoint
, 0 );
255 aPoly
.SetFlags( 0, POLY_NORMAL
);
256 aPoly
.SetPoint( rCtrlPoint1
, 1 );
257 aPoly
.SetFlags( 1, POLY_CONTROL
);
258 aPoly
.SetPoint( rCtrlPoint2
, 2 );
259 aPoly
.SetFlags( 2, POLY_CONTROL
);
260 aPoly
.SetPoint( rEndPoint
, 3 );
261 aPoly
.SetFlags( 3, POLY_NORMAL
);
264 mpOutDev
->getOutDev().DrawPolygon( aPoly
);
266 mp2ndOutDev
->getOutDev().DrawPolygon( aPoly
);
270 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawPolyPolygon( const rendering::XCanvas
* ,
271 const uno::Reference
< rendering::XPolyPolygon2D
>& xPolyPolygon
,
272 const rendering::ViewState
& viewState
,
273 const rendering::RenderState
& renderState
)
275 ENSURE_ARG_OR_THROW( xPolyPolygon
.is(),
280 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
281 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
283 const ::basegfx::B2DPolyPolygon
& rPolyPoly(
284 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon
) );
285 const PolyPolygon
aPolyPoly( tools::mapPolyPolygon( rPolyPoly
, viewState
, renderState
) );
287 if( rPolyPoly
.isClosed() )
289 mpOutDev
->getOutDev().DrawPolyPolygon( aPolyPoly
);
292 mp2ndOutDev
->getOutDev().DrawPolyPolygon( aPolyPoly
);
296 // mixed open/closed state. Cannot render open polygon
297 // via DrawPolyPolygon(), since that implicitley
298 // closed every polygon. OTOH, no need to distinguish
299 // further and render closed polygons via
300 // DrawPolygon(), and open ones via DrawPolyLine():
301 // closed polygons will simply already contain the
303 USHORT
nSize( aPolyPoly
.Count() );
305 for( USHORT i
=0; i
<nSize
; ++i
)
307 mpOutDev
->getOutDev().DrawPolyLine( aPolyPoly
[i
] );
310 mp2ndOutDev
->getOutDev().DrawPolyLine( aPolyPoly
[i
] );
315 // TODO(P1): Provide caching here.
316 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
319 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::strokePolyPolygon( const rendering::XCanvas
* ,
320 const uno::Reference
< rendering::XPolyPolygon2D
>& xPolyPolygon
,
321 const rendering::ViewState
& viewState
,
322 const rendering::RenderState
& renderState
,
323 const rendering::StrokeAttributes
& strokeAttributes
)
325 ENSURE_ARG_OR_THROW( xPolyPolygon
.is(),
330 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
332 ::basegfx::B2DHomMatrix aMatrix
;
333 ::canvas::tools::mergeViewAndRenderTransform(aMatrix
, viewState
, renderState
);
335 ::basegfx::B2DSize
aLinePixelSize(strokeAttributes
.StrokeWidth
,
336 strokeAttributes
.StrokeWidth
);
337 aLinePixelSize
*= aMatrix
;
339 ::basegfx::B2DPolyPolygon
aPolyPoly(
340 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon
) );
342 if( aPolyPoly
.areControlPointsUsed() )
344 // AW: Not needed for ApplyLineDashing anymore; should be removed
345 aPolyPoly
= ::basegfx::tools::adaptiveSubdivideByAngle(aPolyPoly
);
348 // apply dashing, if any
349 if( strokeAttributes
.DashArray
.getLength() )
351 const ::std::vector
<double>& aDashArray(
352 ::comphelper::sequenceToContainer
< ::std::vector
<double> >(strokeAttributes
.DashArray
) );
354 ::basegfx::B2DPolyPolygon aDashedPolyPoly
;
356 for( sal_uInt32 i
=0; i
<aPolyPoly
.count(); ++i
)
358 // AW: new interface; You may also get gaps in the same run now
359 basegfx::tools::applyLineDashing(aPolyPoly
.getB2DPolygon(i
), aDashArray
, &aDashedPolyPoly
);
360 //aDashedPolyPoly.append(
361 // ::basegfx::tools::applyLineDashing( aPolyPoly.getB2DPolygon(i),
365 aPolyPoly
= aDashedPolyPoly
;
368 ::basegfx::B2DPolyPolygon aStrokedPolyPoly
;
369 if( aLinePixelSize
.getLength() < 1.42 )
371 // line width < 1.0 in device pixel, thus, output as a
372 // simple hairline poly-polygon
373 setupOutDevState( viewState
, renderState
, LINE_COLOR
);
375 aStrokedPolyPoly
= aPolyPoly
;
379 // render as a 'thick' line
380 setupOutDevState( viewState
, renderState
, FILL_COLOR
);
382 for( sal_uInt32 i
=0; i
<aPolyPoly
.count(); ++i
)
384 // TODO(F2): Use MiterLimit from StrokeAttributes,
385 // need to convert it here to angle.
387 // TODO(F2): Also use Cap settings from
388 // StrokeAttributes, the
389 // createAreaGeometryForLineStartEnd() method does not
390 // seem to fit very well here
392 // AW: New interface, will create bezier polygons now
393 aStrokedPolyPoly
.append(basegfx::tools::createAreaGeometry(
394 aPolyPoly
.getB2DPolygon(i
), strokeAttributes
.StrokeWidth
*0.5, b2DJoineFromJoin(strokeAttributes
.JoinType
)));
395 //aStrokedPolyPoly.append(
396 // ::basegfx::tools::createAreaGeometryForPolygon( aPolyPoly.getB2DPolygon(i),
397 // strokeAttributes.StrokeWidth*0.5,
398 // b2DJoineFromJoin(strokeAttributes.JoinType) ) );
402 // transform only _now_, all the StrokeAttributes are in
404 aStrokedPolyPoly
.transform( aMatrix
);
406 const PolyPolygon
aVCLPolyPoly( aStrokedPolyPoly
);
408 // TODO(F2): When using alpha here, must handle that via
409 // temporary surface or somesuch.
411 // Note: the generated stroke poly-polygon is NOT free of
412 // self-intersections. Therefore, if we would render it
413 // via OutDev::DrawPolyPolygon(), on/off fill would
414 // generate off areas on those self-intersections.
415 USHORT
nSize( aVCLPolyPoly
.Count() );
417 for( USHORT i
=0; i
<nSize
; ++i
)
419 if( aStrokedPolyPoly
.getB2DPolygon( i
).isClosed() ) {
420 mpOutDev
->getOutDev().DrawPolygon( aVCLPolyPoly
[i
] );
422 mp2ndOutDev
->getOutDev().DrawPolygon( aVCLPolyPoly
[i
] );
424 const USHORT nPolySize
= aVCLPolyPoly
[i
].GetSize();
426 Point rPrevPoint
= aVCLPolyPoly
[i
].GetPoint( 0 );
429 for( USHORT j
=1; j
<nPolySize
; j
++ ) {
430 rPoint
= aVCLPolyPoly
[i
].GetPoint( j
);
431 mpOutDev
->getOutDev().DrawLine( rPrevPoint
, rPoint
);
433 mp2ndOutDev
->getOutDev().DrawLine( rPrevPoint
, rPoint
);
441 // TODO(P1): Provide caching here.
442 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
445 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas
* ,
446 const uno::Reference
< rendering::XPolyPolygon2D
>& ,
447 const rendering::ViewState
& ,
448 const rendering::RenderState
& ,
449 const uno::Sequence
< rendering::Texture
>& ,
450 const rendering::StrokeAttributes
& )
452 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
455 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::strokeTextureMappedPolyPolygon( const rendering::XCanvas
* ,
456 const uno::Reference
< rendering::XPolyPolygon2D
>& ,
457 const rendering::ViewState
& ,
458 const rendering::RenderState
& ,
459 const uno::Sequence
< rendering::Texture
>& ,
460 const uno::Reference
< geometry::XMapping2D
>& ,
461 const rendering::StrokeAttributes
& )
463 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
466 uno::Reference
< rendering::XPolyPolygon2D
> CanvasHelper::queryStrokeShapes( const rendering::XCanvas
* ,
467 const uno::Reference
< rendering::XPolyPolygon2D
>& ,
468 const rendering::ViewState
& ,
469 const rendering::RenderState
& ,
470 const rendering::StrokeAttributes
& )
472 return uno::Reference
< rendering::XPolyPolygon2D
>(NULL
);
475 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::fillPolyPolygon( const rendering::XCanvas
* ,
476 const uno::Reference
< rendering::XPolyPolygon2D
>& xPolyPolygon
,
477 const rendering::ViewState
& viewState
,
478 const rendering::RenderState
& renderState
)
480 ENSURE_ARG_OR_THROW( xPolyPolygon
.is(),
485 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
487 const int nTransparency( setupOutDevState( viewState
, renderState
, FILL_COLOR
) );
488 const int nTransPercent( (nTransparency
* 100 + 128) / 255 ); // normal rounding, no truncation here
489 ::basegfx::B2DPolyPolygon
aB2DPolyPoly(
490 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon
));
491 aB2DPolyPoly
.setClosed(true); // ensure closed poly, otherwise VCL does not fill
492 const PolyPolygon
aPolyPoly( tools::mapPolyPolygon(
494 viewState
, renderState
) );
495 const bool bSourceAlpha( renderState
.CompositeOperation
== rendering::CompositeOperation::SOURCE
);
496 if( !nTransparency
|| bSourceAlpha
)
498 mpOutDev
->getOutDev().DrawPolyPolygon( aPolyPoly
);
502 mpOutDev
->getOutDev().DrawTransparent( aPolyPoly
, (USHORT
)nTransPercent
);
507 if( !nTransparency
|| bSourceAlpha
)
509 // HACK. Normally, CanvasHelper does not care
510 // about actually what mp2ndOutDev is...
511 if( bSourceAlpha
&& nTransparency
== 255 )
513 mp2ndOutDev
->getOutDev().SetDrawMode( DRAWMODE_WHITELINE
| DRAWMODE_WHITEFILL
| DRAWMODE_WHITETEXT
|
514 DRAWMODE_WHITEGRADIENT
| DRAWMODE_WHITEBITMAP
);
515 mp2ndOutDev
->getOutDev().SetFillColor( COL_WHITE
);
516 mp2ndOutDev
->getOutDev().DrawPolyPolygon( aPolyPoly
);
517 mp2ndOutDev
->getOutDev().SetDrawMode( DRAWMODE_BLACKLINE
| DRAWMODE_BLACKFILL
| DRAWMODE_BLACKTEXT
|
518 DRAWMODE_BLACKGRADIENT
| DRAWMODE_BLACKBITMAP
);
522 mp2ndOutDev
->getOutDev().DrawPolyPolygon( aPolyPoly
);
527 mp2ndOutDev
->getOutDev().DrawTransparent( aPolyPoly
, (USHORT
)nTransPercent
);
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 ULONG
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
<USHORT
>(text
.StartPosition
),
614 ::canvas::tools::numeric_cast
<USHORT
>(text
.Length
) );
618 mp2ndOutDev
->getOutDev().SetLayoutMode( nLayoutMode
);
619 mp2ndOutDev
->getOutDev().DrawText( aOutpos
,
621 ::canvas::tools::numeric_cast
<USHORT
>(text
.StartPosition
),
622 ::canvas::tools::numeric_cast
<USHORT
>(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
),
728 mp2ndOutDev
->getOutDev().DrawBitmapEx( ::vcl::unotools::pointFromB2DPoint( aOutputPos
),
731 // Returning a cache object is not useful, the XBitmap
732 // itself serves this purpose
733 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
737 // Matrix contains non-trivial transformation (or
738 // color modulation is requested), decompose to check
739 // whether GraphicObject suffices
740 ::basegfx::B2DVector aScale
;
743 aMatrix
.decompose( aScale
, aOutputPos
, nRotate
, nShearX
);
745 GraphicAttr aGrfAttr
;
746 GraphicObjectSharedPtr pGrfObj
;
748 ::Size
aBmpSize( aBmpEx
.GetSizePixel() );
750 // setup alpha modulation
751 if( bModulateColors
)
753 const double nAlphaModulation( renderState
.DeviceColor
[3] );
755 // TODO(F1): Note that the GraphicManager has a
756 // subtle difference in how it calculates the
757 // resulting alpha value: it's using the inverse
758 // alpha values (i.e. 'transparency'), and
759 // calculates transOrig + transModulate, instead
760 // of transOrig + transModulate -
761 // transOrig*transModulate (which would be
762 // equivalent to the origAlpha*modulateAlpha the
763 // DX canvas performs)
764 aGrfAttr
.SetTransparency(
766 ::basegfx::fround( 255.0*( 1.0 - nAlphaModulation
) ) ) );
769 if( ::basegfx::fTools::equalZero( nShearX
) )
771 // no shear, GraphicObject is enough (the
772 // GraphicObject only supports scaling, rotation
775 // #i75339# don't apply mirror flags, having
776 // negative size values is enough to make
777 // GraphicObject flip the bitmap
779 // The angle has to be mapped from radian to tenths of
780 // degress with the orientation reversed: [0,2Pi) ->
781 // (3600,0]. Note that the original angle may have
782 // values outside the [0,2Pi) interval.
783 const double nAngleInTenthOfDegrees (3600.0 - nRotate
* 3600.0 / (2*M_PI
));
784 aGrfAttr
.SetRotation( static_cast< USHORT
>(::basegfx::fround(nAngleInTenthOfDegrees
)) );
786 pGrfObj
.reset( new GraphicObject( aBmpEx
) );
790 // modify output position, to account for the fact
791 // that transformBitmap() always normalizes its output
792 // bitmap into the smallest enclosing box.
793 ::basegfx::B2DRectangle aDestRect
;
794 ::canvas::tools::calcTransformedRectBounds( aDestRect
,
795 ::basegfx::B2DRectangle(0,
801 aOutputPos
.setX( aDestRect
.getMinX() );
802 aOutputPos
.setY( aDestRect
.getMinY() );
804 // complex transformation, use generic affine bitmap
806 aBmpEx
= tools::transformBitmap( aBmpEx
,
808 renderState
.DeviceColor
,
809 tools::MODULATE_NONE
);
811 pGrfObj
.reset( new GraphicObject( aBmpEx
) );
813 // clear scale values, generated bitmap already
815 aScale
.setX( 1.0 ); aScale
.setY( 1.0 );
817 // update bitmap size, bitmap has changed above.
818 aBmpSize
= aBmpEx
.GetSizePixel();
821 // output GraphicObject
822 const ::Point
aPt( ::vcl::unotools::pointFromB2DPoint( aOutputPos
) );
823 const ::Size
aSz( ::basegfx::fround( aScale
.getX() * aBmpSize
.Width() ),
824 ::basegfx::fround( aScale
.getY() * aBmpSize
.Height() ) );
826 pGrfObj
->Draw( &mpOutDev
->getOutDev(),
832 pGrfObj
->Draw( &mp2ndOutDev
->getOutDev(),
837 // created GraphicObject, which possibly cached
838 // display bitmap - return cache object, to retain
840 return uno::Reference
< rendering::XCachedPrimitive
>(
841 new CachedBitmap( pGrfObj
,
847 // cast away const, need to
848 // change refcount (as this is
849 // ~invisible to client code,
850 // still logically const)
851 const_cast< rendering::XCanvas
* >(pCanvas
)) );
856 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
859 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawBitmap( const rendering::XCanvas
* pCanvas
,
860 const uno::Reference
< rendering::XBitmap
>& xBitmap
,
861 const rendering::ViewState
& viewState
,
862 const rendering::RenderState
& renderState
)
864 return implDrawBitmap( pCanvas
,
871 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawBitmapModulated( const rendering::XCanvas
* pCanvas
,
872 const uno::Reference
< rendering::XBitmap
>& xBitmap
,
873 const rendering::ViewState
& viewState
,
874 const rendering::RenderState
& renderState
)
876 return implDrawBitmap( pCanvas
,
883 uno::Reference
< rendering::XGraphicDevice
> CanvasHelper::getDevice()
885 // cast away const, need to change refcount (as this is
886 // ~invisible to client code, still logically const)
887 return uno::Reference
< rendering::XGraphicDevice
>(mpDevice
);
890 void CanvasHelper::copyRect( const rendering::XCanvas
* ,
891 const uno::Reference
< rendering::XBitmapCanvas
>& ,
892 const geometry::RealRectangle2D
& ,
893 const rendering::ViewState
& ,
894 const rendering::RenderState
& ,
895 const geometry::RealRectangle2D
& ,
896 const rendering::ViewState
& ,
897 const rendering::RenderState
& )
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
);
921 // TODO(F2): Support alpha vdev canvas here
922 const Point
aEmptyPoint(0,0);
923 const Size
aBmpSize( rOutDev
.GetOutputSizePixel() );
925 Bitmap
aBitmap( rOutDev
.GetBitmap(aEmptyPoint
, aBmpSize
) );
927 aBitmap
.Scale( ::vcl::unotools::sizeFromRealSize2D(newSize
),
928 beFast
? BMP_SCALE_FAST
: BMP_SCALE_INTERPOLATE
);
930 return uno::Reference
< rendering::XBitmap
>(
931 new CanvasBitmap( aBitmap
, *mpDevice
, mpOutDev
) );
934 uno::Sequence
< sal_Int8
> CanvasHelper::getData( rendering::IntegerBitmapLayout
& rLayout
,
935 const geometry::IntegerRectangle2D
& rect
)
937 if( !mpOutDev
.get() )
938 return uno::Sequence
< sal_Int8
>(); // we're disposed
940 rLayout
= getMemoryLayout();
942 // TODO(F2): Support alpha canvas here
943 const Rectangle
aRect( ::vcl::unotools::rectangleFromIntegerRectangle2D(rect
) );
945 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
947 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
948 rOutDev
.EnableMapMode( FALSE
);
950 Bitmap
aBitmap( rOutDev
.GetBitmap(aRect
.TopLeft(),
953 ScopedBitmapReadAccess
pReadAccess( aBitmap
.AcquireReadAccess(),
956 ENSURE_OR_THROW( pReadAccess
.get() != NULL
,
957 "Could not acquire read access to OutDev bitmap" );
959 const sal_Int32
nWidth( rect
.X2
- rect
.X1
);
960 const sal_Int32
nHeight( rect
.Y2
- rect
.Y1
);
962 rLayout
.ScanLines
= nHeight
;
963 rLayout
.ScanLineBytes
= nWidth
*4;
964 rLayout
.ScanLineStride
= rLayout
.ScanLineBytes
;
966 uno::Sequence
< sal_Int8
> aRes( 4*nWidth
*nHeight
);
967 sal_Int8
* pRes
= aRes
.getArray();
970 for( int y
=0; y
<nHeight
; ++y
)
972 for( int x
=0; x
<nWidth
; ++x
)
974 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetRed();
975 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetGreen();
976 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetBlue();
977 pRes
[ nCurrPos
++ ] = -1;
984 void CanvasHelper::setData( const uno::Sequence
< sal_Int8
>& data
,
985 const rendering::IntegerBitmapLayout
& aLayout
,
986 const geometry::IntegerRectangle2D
& rect
)
988 if( !mpOutDev
.get() )
989 return; // we're disposed
991 const rendering::IntegerBitmapLayout
aRefLayout( getMemoryLayout() );
992 ENSURE_ARG_OR_THROW( aRefLayout
.PlaneStride
!= aLayout
.PlaneStride
||
993 aRefLayout
.ColorSpace
!= aLayout
.ColorSpace
||
994 aRefLayout
.Palette
!= aLayout
.Palette
||
995 aRefLayout
.IsMsbFirst
!= aLayout
.IsMsbFirst
,
996 "Mismatching memory layout" );
998 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
1000 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
1001 rOutDev
.EnableMapMode( FALSE
);
1003 const Rectangle
aRect( ::vcl::unotools::rectangleFromIntegerRectangle2D(rect
) );
1004 const USHORT
nBitCount( ::std::min( (USHORT
)24U,
1005 (USHORT
)rOutDev
.GetBitCount() ) );
1006 const BitmapPalette
* pPalette
= NULL
;
1008 if( nBitCount
<= 8 )
1010 // TODO(Q1): Extract this to a common place, e.g. GraphicDevice
1012 // try to determine palette from output device (by
1013 // extracting a 1,1 bitmap, and querying it)
1014 const Point aEmptyPoint
;
1015 const Size
aSize(1,1);
1016 Bitmap
aTmpBitmap( rOutDev
.GetBitmap( aEmptyPoint
,
1019 ScopedBitmapReadAccess
pReadAccess( aTmpBitmap
.AcquireReadAccess(),
1022 pPalette
= &pReadAccess
->GetPalette();
1025 // TODO(F2): Support alpha canvas here
1026 Bitmap
aBitmap( aRect
.GetSize(), nBitCount
, pPalette
);
1028 bool bCopyBack( false ); // only copy something back, if we
1029 // actually changed some pixel
1031 ScopedBitmapWriteAccess
pWriteAccess( aBitmap
.AcquireWriteAccess(),
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
++ = (BYTE
)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
);
1129 const Size
aBmpSize( rOutDev
.GetOutputSizePixel() );
1131 ENSURE_ARG_OR_THROW( pos
.X
>= 0 && pos
.X
< aBmpSize
.Width(),
1132 "X coordinate out of bounds" );
1133 ENSURE_ARG_OR_THROW( pos
.Y
>= 0 && pos
.Y
< aBmpSize
.Height(),
1134 "Y coordinate out of bounds" );
1135 ENSURE_ARG_OR_THROW( color
.getLength() > 3,
1136 "not enough color components" );
1138 const rendering::IntegerBitmapLayout
aRefLayout( getMemoryLayout() );
1139 ENSURE_ARG_OR_THROW( aRefLayout
.PlaneStride
!= rLayout
.PlaneStride
||
1140 aRefLayout
.ColorSpace
!= rLayout
.ColorSpace
||
1141 aRefLayout
.Palette
!= rLayout
.Palette
||
1142 aRefLayout
.IsMsbFirst
!= rLayout
.IsMsbFirst
,
1143 "Mismatching memory layout" );
1145 // TODO(F2): Support alpha canvas here
1146 rOutDev
.DrawPixel( ::vcl::unotools::pointFromIntegerPoint2D( pos
),
1147 ::canvas::tools::stdIntSequenceToColor( color
));
1150 uno::Sequence
< sal_Int8
> CanvasHelper::getPixel( rendering::IntegerBitmapLayout
& rLayout
,
1151 const geometry::IntegerPoint2D
& pos
)
1153 if( !mpOutDev
.get() )
1154 return uno::Sequence
< sal_Int8
>(); // we're disposed
1156 rLayout
= getMemoryLayout();
1157 rLayout
.ScanLines
= 1;
1158 rLayout
.ScanLineBytes
= 4;
1159 rLayout
.ScanLineStride
= rLayout
.ScanLineBytes
;
1161 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
1163 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
1164 rOutDev
.EnableMapMode( FALSE
);
1166 const Size
aBmpSize( rOutDev
.GetOutputSizePixel() );
1168 ENSURE_ARG_OR_THROW( pos
.X
>= 0 && pos
.X
< aBmpSize
.Width(),
1169 "X coordinate out of bounds" );
1170 ENSURE_ARG_OR_THROW( pos
.Y
>= 0 && pos
.Y
< aBmpSize
.Height(),
1171 "Y coordinate out of bounds" );
1173 // TODO(F2): Support alpha canvas here
1174 return ::canvas::tools::colorToStdIntSequence(
1176 ::vcl::unotools::pointFromIntegerPoint2D( pos
)));
1179 rendering::IntegerBitmapLayout
CanvasHelper::getMemoryLayout()
1181 if( !mpOutDev
.get() )
1182 return rendering::IntegerBitmapLayout(); // we're disposed
1184 return ::canvas::tools::getStdMemoryLayout(getSize());
1187 int CanvasHelper::setupOutDevState( const rendering::ViewState
& viewState
,
1188 const rendering::RenderState
& renderState
,
1189 ColorType eColorType
) const
1191 ENSURE_OR_THROW( mpOutDev
.get(),
1192 "outdev null. Are we disposed?" );
1194 ::canvas::tools::verifyInput( renderState
,
1195 BOOST_CURRENT_FUNCTION
,
1198 eColorType
== IGNORE_COLOR
? 0 : 3 );
1200 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
1201 OutputDevice
* p2ndOutDev
= NULL
;
1203 rOutDev
.EnableMapMode( FALSE
);
1206 p2ndOutDev
= &mp2ndOutDev
->getOutDev();
1208 int nTransparency(0);
1210 // TODO(P2): Don't change clipping all the time, maintain current clip
1211 // state and change only when update is necessary
1213 // accumulate non-empty clips into one region
1214 // ==========================================
1216 Region
aClipRegion( REGION_NULL
);
1218 if( viewState
.Clip
.is() )
1220 ::basegfx::B2DPolyPolygon
aClipPoly(
1221 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(viewState
.Clip
) );
1223 if( aClipPoly
.count() )
1225 // setup non-empty clipping
1226 ::basegfx::B2DHomMatrix aMatrix
;
1227 aClipPoly
.transform(
1228 ::basegfx::unotools::homMatrixFromAffineMatrix( aMatrix
,
1229 viewState
.AffineTransform
) );
1231 aClipRegion
= Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly
) );
1235 // clip polygon is empty
1236 aClipRegion
.SetEmpty();
1240 if( renderState
.Clip
.is() )
1242 ::basegfx::B2DPolyPolygon
aClipPoly(
1243 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(renderState
.Clip
) );
1245 ::basegfx::B2DHomMatrix aMatrix
;
1246 aClipPoly
.transform(
1247 ::canvas::tools::mergeViewAndRenderTransform( aMatrix
,
1251 if( aClipPoly
.count() )
1253 // setup non-empty clipping
1254 Region aRegion
= Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly
) );
1255 aClipRegion
.Intersect( aRegion
);
1259 // clip polygon is empty
1260 aClipRegion
.SetEmpty();
1264 // setup accumulated clip region. Note that setting an
1265 // empty clip region denotes "clip everything" on the
1266 // OutputDevice (which is why we translate that into
1267 // SetClipRegion() here). When both view and render clip
1268 // are empty, aClipRegion remains default-constructed,
1270 if( aClipRegion
.IsNull() )
1272 rOutDev
.SetClipRegion();
1275 p2ndOutDev
->SetClipRegion();
1279 rOutDev
.SetClipRegion( aClipRegion
);
1282 p2ndOutDev
->SetClipRegion( aClipRegion
);
1285 if( eColorType
!= IGNORE_COLOR
)
1287 Color
aColor( COL_WHITE
);
1289 if( renderState
.DeviceColor
.getLength() > 2 )
1291 aColor
= ::vcl::unotools::stdColorSpaceSequenceToColor(
1292 renderState
.DeviceColor
);
1295 // extract alpha, and make color opaque
1296 // afterwards. Otherwise, OutputDevice won't draw anything
1297 nTransparency
= aColor
.GetTransparency();
1298 aColor
.SetTransparency(0);
1300 switch( eColorType
)
1303 rOutDev
.SetLineColor( aColor
);
1304 rOutDev
.SetFillColor();
1308 p2ndOutDev
->SetLineColor( aColor
);
1309 p2ndOutDev
->SetFillColor();
1314 rOutDev
.SetFillColor( aColor
);
1315 rOutDev
.SetLineColor();
1319 p2ndOutDev
->SetFillColor( aColor
);
1320 p2ndOutDev
->SetLineColor();
1325 rOutDev
.SetTextColor( aColor
);
1328 p2ndOutDev
->SetTextColor( aColor
);
1332 ENSURE_OR_THROW( false,
1333 "Unexpected color type");
1338 return nTransparency
;
1341 bool CanvasHelper::setupTextOutput( ::Point
& o_rOutPos
,
1342 const rendering::ViewState
& viewState
,
1343 const rendering::RenderState
& renderState
,
1344 const uno::Reference
< rendering::XCanvasFont
>& xFont
) const
1346 ENSURE_OR_THROW( mpOutDev
.get(),
1347 "outdev null. Are we disposed?" );
1349 setupOutDevState( viewState
, renderState
, TEXT_COLOR
);
1351 OutputDevice
& rOutDev( mpOutDev
->getOutDev() );
1355 CanvasFont
* pFont
= dynamic_cast< CanvasFont
* >( xFont
.get() );
1357 ENSURE_ARG_OR_THROW( pFont
,
1358 "Font not compatible with this canvas" );
1360 aVCLFont
= pFont
->getVCLFont();
1362 Color
aColor( COL_BLACK
);
1364 if( renderState
.DeviceColor
.getLength() > 2 )
1366 aColor
= ::vcl::unotools::stdColorSpaceSequenceToColor(
1367 renderState
.DeviceColor
);
1371 aVCLFont
.SetColor( aColor
);
1372 aVCLFont
.SetFillColor( aColor
);
1374 // no need to replicate this for mp2ndOutDev, we're modifying only aVCLFont here.
1375 if( !tools::setupFontTransform( o_rOutPos
, aVCLFont
, viewState
, renderState
, rOutDev
) )
1378 rOutDev
.SetFont( aVCLFont
);
1381 mp2ndOutDev
->getOutDev().SetFont( aVCLFont
);
1386 bool CanvasHelper::repaint( const GraphicObjectSharedPtr
& rGrf
,
1387 const rendering::ViewState
& viewState
,
1388 const rendering::RenderState
& renderState
,
1391 const GraphicAttr
& rAttr
) const
1393 ENSURE_OR_RETURN( rGrf
,
1394 "Invalid Graphic" );
1397 return false; // disposed
1400 tools::OutDevStateKeeper
aStateKeeper( mpProtectedOutDev
);
1401 setupOutDevState( viewState
, renderState
, IGNORE_COLOR
);
1403 if( !rGrf
->Draw( &mpOutDev
->getOutDev(), rPt
, rSz
, &rAttr
) )
1406 // #i80779# Redraw also into mask outdev
1408 return rGrf
->Draw( &mp2ndOutDev
->getOutDev(), rPt
, rSz
, &rAttr
);
1414 void CanvasHelper::flush() const
1416 if( mpOutDev
&& mpOutDev
->getOutDev().GetOutDevType() == OUTDEV_WINDOW
)
1418 // TODO(Q3): Evil downcast. And what's more, Window::Flush is
1419 // not even const. Wah.
1420 static_cast<Window
&>(mpOutDev
->getOutDev()).Flush();
1423 if( mp2ndOutDev
&& mp2ndOutDev
->getOutDev().GetOutDevType() == OUTDEV_WINDOW
)
1425 // TODO(Q3): Evil downcast. And what's more, Window::Flush is
1426 // not even const. Wah.
1427 static_cast<Window
&>(mp2ndOutDev
->getOutDev()).Flush();