Branch libreoffice-5-0-4
[LibreOffice.git] / canvas / source / vcl / canvashelper.cxx
blob5f3ee58f21a3457b27803100608d3e84a9d19c26
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
50 #include <utility>
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;
64 namespace vclcanvas
66 namespace
68 basegfx::B2DLineJoin b2DJoineFromJoin( sal_Int8 nJoinType )
70 switch( 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;
84 default:
85 ENSURE_OR_THROW( false,
86 "b2DJoineFromJoin(): Unexpected join type" );
89 return basegfx::B2DLINEJOIN_NONE;
92 drawing::LineCap unoCapeFromCap( sal_Int8 nCapType)
94 switch ( 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;
105 default:
106 ENSURE_OR_THROW( false,
107 "unoCapeFromCap(): Unexpected cap type" );
109 return drawing::LineCap_BUTT;
113 CanvasHelper::CanvasHelper() :
114 mpDevice(),
115 mpProtectedOutDev(),
116 mpOutDev(),
117 mp2ndOutDev(),
118 mbHaveAlpha( false )
122 void CanvasHelper::disposing()
124 mpDevice = NULL;
125 mpProtectedOutDev.reset();
126 mpOutDev.reset();
127 mp2ndOutDev.reset();
130 void CanvasHelper::init( rendering::XGraphicDevice& rDevice,
131 const OutDevProviderSharedPtr& rOutDev,
132 bool bProtect,
133 bool bHaveAlpha )
135 // cast away const, need to change refcount (as this is
136 // ~invisible to client code, still logically const)
137 mpDevice = &rDevice;
138 mbHaveAlpha = bHaveAlpha;
140 setOutDev( rOutDev, bProtect );
143 void CanvasHelper::setOutDev( const OutDevProviderSharedPtr& rOutDev,
144 bool bProtect )
146 if( bProtect )
147 mpProtectedOutDev = rOutDev;
148 else
149 mpProtectedOutDev.reset();
151 mpOutDev = rOutDev;
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()
163 // are we disposed?
164 if( mpOutDev )
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()) );
177 if( mp2ndOutDev )
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 )
200 // are we disposed?
201 if( mpOutDev )
203 // nope, render
204 tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev );
205 setupOutDevState( viewState, renderState, LINE_COLOR );
207 const Point aOutPoint( tools::mapRealPoint2D( aPoint,
208 viewState, renderState ) );
209 // TODO(F1): alpha
210 mpOutDev->getOutDev().DrawPixel( aOutPoint );
212 if( mp2ndOutDev )
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 )
223 // are we disposed?
224 if( mpOutDev )
226 // nope, render
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 ) );
234 // TODO(F2): alpha
235 mpOutDev->getOutDev().DrawLine( aStartPoint, aEndPoint );
237 if( mp2ndOutDev )
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 )
248 if( mpOutDev )
250 tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev );
251 setupOutDevState( viewState, renderState, LINE_COLOR );
253 const Point& rStartPoint( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.Px,
254 aBezierSegment.Py),
255 viewState, renderState ) );
256 const Point& rCtrlPoint1( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.C1x,
257 aBezierSegment.C1y),
258 viewState, renderState ) );
259 const Point& rCtrlPoint2( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.C2x,
260 aBezierSegment.C2y),
261 viewState, renderState ) );
262 const Point& rEndPoint( tools::mapRealPoint2D( _aEndPoint,
263 viewState, renderState ) );
265 ::Polygon aPoly(4);
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 );
275 // TODO(F2): alpha
276 mpOutDev->getOutDev().DrawPolygon( aPoly );
277 if( mp2ndOutDev )
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(),
288 "polygon is NULL");
290 if( mpOutDev )
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 );
303 if( mp2ndOutDev )
304 mp2ndOutDev->getOutDev().DrawPolyPolygon( aPolyPoly );
306 else
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
314 // closing segment.
315 sal_uInt16 nSize( aPolyPoly.Count() );
317 for( sal_uInt16 i=0; i<nSize; ++i )
319 mpOutDev->getOutDev().DrawPolyLine( aPolyPoly[i] );
321 if( mp2ndOutDev )
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(),
338 "polygon is NULL");
340 if( mpOutDev )
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),
374 // aDashArray ) );
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;
389 else
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
419 // user coordinates.
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] );
437 if( mp2ndOutDev )
438 mp2ndOutDev->getOutDev().DrawPolygon( aVCLPolyPoly[i] );
439 } else {
440 const sal_uInt16 nPolySize = aVCLPolyPoly[i].GetSize();
441 if( nPolySize ) {
442 Point rPrevPoint = aVCLPolyPoly[i].GetPoint( 0 );
443 Point rPoint;
445 for( sal_uInt16 j=1; j<nPolySize; j++ ) {
446 rPoint = aVCLPolyPoly[i].GetPoint( j );
447 mpOutDev->getOutDev().DrawLine( rPrevPoint, rPoint );
448 if( mp2ndOutDev )
449 mp2ndOutDev->getOutDev().DrawLine( rPrevPoint, rPoint );
450 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(),
497 "polygon is NULL");
499 if( mpOutDev )
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(
508 aB2DPolyPoly,
509 viewState, renderState ) );
510 const bool bSourceAlpha( renderState.CompositeOperation == rendering::CompositeOperation::SOURCE );
511 if( !nTransparency || bSourceAlpha )
513 mpOutDev->getOutDev().DrawPolyPolygon( aPolyPoly );
515 else
517 const int nTransPercent( (nTransparency * 100 + 128) / 255 ); // normal rounding, no truncation here
518 mpOutDev->getOutDev().DrawTransparent( aPolyPoly, (sal_uInt16)nTransPercent );
521 if( mp2ndOutDev )
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 >& )
569 // TODO(F2)
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(),
581 "font is NULL");
583 if( mpOutDev )
585 tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev );
587 ::Point aOutpos;
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;
600 break;
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;
608 break;
611 // TODO(F2): alpha
612 mpOutDev->getOutDev().SetLayoutMode( nLayoutMode );
613 mpOutDev->getOutDev().DrawText( aOutpos,
614 text.Text,
615 ::canvas::tools::numeric_cast<sal_uInt16>(text.StartPosition),
616 ::canvas::tools::numeric_cast<sal_uInt16>(text.Length) );
618 if( mp2ndOutDev )
620 mp2ndOutDev->getOutDev().SetLayoutMode( nLayoutMode );
621 mp2ndOutDev->getOutDev().DrawText( aOutpos,
622 text.Text,
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(),
637 "layout is NULL");
639 TextLayout* pTextLayout = dynamic_cast< TextLayout* >( xLayoutedText.get() );
641 if( pTextLayout )
643 if( mpOutDev )
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?
652 ::Point aOutpos;
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?
657 // TODO(F2): alpha
658 pTextLayout->draw( mpOutDev->getOutDev(), aOutpos, viewState, renderState );
660 if( mp2ndOutDev )
661 pTextLayout->draw( mp2ndOutDev->getOutDev(), aOutpos, viewState, renderState );
664 else
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(),
680 "bitmap is NULL");
682 ::canvas::tools::verifyInput( renderState,
683 BOOST_CURRENT_FUNCTION,
684 mpDevice,
686 bModulateColors ? 3 : 0 );
688 if( mpOutDev )
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 ),
727 aBmpEx );
729 if( mp2ndOutDev )
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 ),
747 aBmpEx );
750 // Returning a cache object is not useful, the XBitmap
751 // itself serves this purpose
752 return uno::Reference< rendering::XCachedPrimitive >(NULL);
754 else
756 // Matrix contains non-trivial transformation (or
757 // color modulation is requested), decompose to check
758 // whether GraphicObject suffices
759 ::basegfx::B2DVector aScale;
760 double nRotate;
761 double nShearX;
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
792 // and translation)
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 ) );
807 else
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,
816 aBmpSize.Width(),
817 aBmpSize.Height()),
818 aMatrix );
820 aOutputPos.setX( aDestRect.getMinX() );
821 aOutputPos.setY( aDestRect.getMinY() );
823 // complex transformation, use generic affine bitmap
824 // transformation
825 aBmpEx = tools::transformBitmap( aBmpEx,
826 aMatrix,
827 renderState.DeviceColor,
828 tools::MODULATE_NONE );
830 pGrfObj.reset( new GraphicObject( aBmpEx ) );
832 // clear scale values, generated bitmap already
833 // contains scaling
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(),
846 aPt,
847 aSz,
848 &aGrfAttr );
850 if( mp2ndOutDev )
851 pGrfObj->Draw( &mp2ndOutDev->getOutDev(),
852 aPt,
853 aSz,
854 &aGrfAttr );
856 // created GraphicObject, which possibly cached
857 // display bitmap - return cache object, to retain
858 // that information.
859 return uno::Reference< rendering::XCachedPrimitive >(
860 new CachedBitmap( pGrfObj,
861 aPt,
862 aSz,
863 aGrfAttr,
864 viewState,
865 renderState,
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)) );
874 // Nothing rendered
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,
884 xBitmap,
885 viewState,
886 renderState,
887 false );
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,
896 xBitmap,
897 viewState,
898 renderState,
899 true );
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,
911 bool beFast )
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(),
953 aRect.GetSize()) );
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();
970 int nCurrPos(0);
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;
982 return aRes;
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,
1019 aSize ) );
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 ],
1053 data[ nCurrPos+1 ],
1054 data[ nCurrPos+2 ] ) );
1056 nCurrPos += 4;
1059 break;
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 ];
1071 nCurrPos += 4;
1074 break;
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 ];
1086 nCurrPos += 4;
1089 break;
1091 default:
1093 for( x=0; x<nWidth; ++x )
1095 pWriteAccess->SetPixel( y, x, BitmapColor( data[ nCurrPos ],
1096 data[ nCurrPos+1 ],
1097 data[ nCurrPos+2 ] ) );
1098 nCurrPos += 4;
1101 break;
1105 bCopyBack = true;
1108 // copy back only here, since the BitmapAccessors must be
1109 // destroyed beforehand
1110 if( bCopyBack )
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(
1177 rOutDev.GetPixel(
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()) );
1187 if ( !mbHaveAlpha )
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,
1202 mpDevice,
1204 eColorType == IGNORE_COLOR ? 0 : 3 );
1206 OutputDevice& rOutDev( mpOutDev->getOutDev() );
1207 OutputDevice* p2ndOutDev = NULL;
1209 rOutDev.EnableMapMode( false );
1210 rOutDev.SetAntialiasing( AntialiasingFlags::EnableB2dDraw );
1212 if( mp2ndOutDev )
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 )
1238 case LINE_COLOR:
1239 rOutDev.SetLineColor( aColor );
1240 rOutDev.SetFillColor();
1242 if( p2ndOutDev )
1244 p2ndOutDev->SetLineColor( aColor );
1245 p2ndOutDev->SetFillColor();
1247 break;
1249 case FILL_COLOR:
1250 rOutDev.SetFillColor( aColor );
1251 rOutDev.SetLineColor();
1253 if( p2ndOutDev )
1255 p2ndOutDev->SetFillColor( aColor );
1256 p2ndOutDev->SetLineColor();
1258 break;
1260 case TEXT_COLOR:
1261 rOutDev.SetTextColor( aColor );
1263 if( p2ndOutDev )
1264 p2ndOutDev->SetTextColor( aColor );
1265 break;
1267 default:
1268 ENSURE_OR_THROW( false,
1269 "Unexpected color type");
1270 break;
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 );
1304 // setup font color
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 ) )
1310 return false;
1312 rOutDev.SetFont( aVCLFont );
1314 if( mp2ndOutDev )
1315 mp2ndOutDev->getOutDev().SetFont( aVCLFont );
1317 return true;
1320 bool CanvasHelper::repaint( const GraphicObjectSharedPtr& rGrf,
1321 const rendering::ViewState& viewState,
1322 const rendering::RenderState& renderState,
1323 const ::Point& rPt,
1324 const ::Size& rSz,
1325 const GraphicAttr& rAttr ) const
1327 ENSURE_OR_RETURN_FALSE( rGrf,
1328 "Invalid Graphic" );
1330 if( !mpOutDev )
1331 return false; // disposed
1332 else
1334 tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev );
1335 setupOutDevState( viewState, renderState, IGNORE_COLOR );
1337 if( !rGrf->Draw( &mpOutDev->getOutDev(), rPt, rSz, &rAttr ) )
1338 return false;
1340 // #i80779# Redraw also into mask outdev
1341 if( mp2ndOutDev )
1342 return rGrf->Draw( &mp2ndOutDev->getOutDev(), rPt, rSz, &rAttr );
1344 return true;
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: */