fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / canvas / source / vcl / canvashelper.cxx
blob0f3718feed64b6429a1b5a454caa1ecbb6d9d7eb
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( sal_False );
160 void CanvasHelper::clear()
162 // are we disposed?
163 if( mpOutDev )
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()) );
175 if( mp2ndOutDev )
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 )
197 // are we disposed?
198 if( mpOutDev )
200 // nope, render
201 tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev );
202 setupOutDevState( viewState, renderState, LINE_COLOR );
204 const Point aOutPoint( tools::mapRealPoint2D( aPoint,
205 viewState, renderState ) );
206 // TODO(F1): alpha
207 mpOutDev->getOutDev().DrawPixel( aOutPoint );
209 if( mp2ndOutDev )
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 )
220 // are we disposed?
221 if( mpOutDev )
223 // nope, render
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 ) );
231 // TODO(F2): alpha
232 mpOutDev->getOutDev().DrawLine( aStartPoint, aEndPoint );
234 if( mp2ndOutDev )
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 )
245 if( mpOutDev )
247 tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev );
248 setupOutDevState( viewState, renderState, LINE_COLOR );
250 const Point& rStartPoint( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.Px,
251 aBezierSegment.Py),
252 viewState, renderState ) );
253 const Point& rCtrlPoint1( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.C1x,
254 aBezierSegment.C1y),
255 viewState, renderState ) );
256 const Point& rCtrlPoint2( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.C2x,
257 aBezierSegment.C2y),
258 viewState, renderState ) );
259 const Point& rEndPoint( tools::mapRealPoint2D( _aEndPoint,
260 viewState, renderState ) );
262 ::Polygon aPoly(4);
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 );
272 // TODO(F2): alpha
273 mpOutDev->getOutDev().DrawPolygon( aPoly );
274 if( mp2ndOutDev )
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(),
285 "polygon is NULL");
287 if( mpOutDev )
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 );
300 if( mp2ndOutDev )
301 mp2ndOutDev->getOutDev().DrawPolyPolygon( aPolyPoly );
303 else
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
311 // closing segment.
312 sal_uInt16 nSize( aPolyPoly.Count() );
314 for( sal_uInt16 i=0; i<nSize; ++i )
316 mpOutDev->getOutDev().DrawPolyLine( aPolyPoly[i] );
318 if( mp2ndOutDev )
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(),
335 "polygon is NULL");
337 if( mpOutDev )
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),
371 // aDashArray ) );
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;
386 else
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
416 // user coordinates.
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] );
434 if( mp2ndOutDev )
435 mp2ndOutDev->getOutDev().DrawPolygon( aVCLPolyPoly[i] );
436 } else {
437 const sal_uInt16 nPolySize = aVCLPolyPoly[i].GetSize();
438 if( nPolySize ) {
439 Point rPrevPoint = aVCLPolyPoly[i].GetPoint( 0 );
440 Point rPoint;
442 for( sal_uInt16 j=1; j<nPolySize; j++ ) {
443 rPoint = aVCLPolyPoly[i].GetPoint( j );
444 mpOutDev->getOutDev().DrawLine( rPrevPoint, rPoint );
445 if( mp2ndOutDev )
446 mp2ndOutDev->getOutDev().DrawLine( rPrevPoint, rPoint );
447 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(),
494 "polygon is NULL");
496 if( mpOutDev )
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(
505 aB2DPolyPoly,
506 viewState, renderState ) );
507 const bool bSourceAlpha( renderState.CompositeOperation == rendering::CompositeOperation::SOURCE );
508 if( !nTransparency || bSourceAlpha )
510 mpOutDev->getOutDev().DrawPolyPolygon( aPolyPoly );
512 else
514 const int nTransPercent( (nTransparency * 100 + 128) / 255 ); // normal rounding, no truncation here
515 mpOutDev->getOutDev().DrawTransparent( aPolyPoly, (sal_uInt16)nTransPercent );
518 if( mp2ndOutDev )
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 >& )
566 // TODO(F2)
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(),
578 "font is NULL");
580 if( mpOutDev )
582 tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev );
584 ::Point aOutpos;
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;
598 break;
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;
606 break;
609 // TODO(F2): alpha
610 mpOutDev->getOutDev().SetLayoutMode( nLayoutMode );
611 mpOutDev->getOutDev().DrawText( aOutpos,
612 text.Text,
613 ::canvas::tools::numeric_cast<sal_uInt16>(text.StartPosition),
614 ::canvas::tools::numeric_cast<sal_uInt16>(text.Length) );
616 if( mp2ndOutDev )
618 mp2ndOutDev->getOutDev().SetLayoutMode( nLayoutMode );
619 mp2ndOutDev->getOutDev().DrawText( aOutpos,
620 text.Text,
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(),
635 "layout is NULL");
637 TextLayout* pTextLayout = dynamic_cast< TextLayout* >( xLayoutedText.get() );
639 if( pTextLayout )
641 if( mpOutDev )
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?
650 ::Point aOutpos;
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?
655 // TODO(F2): alpha
656 pTextLayout->draw( mpOutDev->getOutDev(), aOutpos, viewState, renderState );
658 if( mp2ndOutDev )
659 pTextLayout->draw( mp2ndOutDev->getOutDev(), aOutpos, viewState, renderState );
662 else
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(),
678 "bitmap is NULL");
680 ::canvas::tools::verifyInput( renderState,
681 BOOST_CURRENT_FUNCTION,
682 mpDevice,
684 bModulateColors ? 3 : 0 );
686 if( mpOutDev )
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 ),
725 aBmpEx );
727 if( mp2ndOutDev )
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 ),
745 aBmpEx );
748 // Returning a cache object is not useful, the XBitmap
749 // itself serves this purpose
750 return uno::Reference< rendering::XCachedPrimitive >(NULL);
752 else
754 // Matrix contains non-trivial transformation (or
755 // color modulation is requested), decompose to check
756 // whether GraphicObject suffices
757 ::basegfx::B2DVector aScale;
758 double nRotate;
759 double nShearX;
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
790 // and translation)
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 ) );
805 else
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,
814 aBmpSize.Width(),
815 aBmpSize.Height()),
816 aMatrix );
818 aOutputPos.setX( aDestRect.getMinX() );
819 aOutputPos.setY( aDestRect.getMinY() );
821 // complex transformation, use generic affine bitmap
822 // transformation
823 aBmpEx = tools::transformBitmap( aBmpEx,
824 aMatrix,
825 renderState.DeviceColor,
826 tools::MODULATE_NONE );
828 pGrfObj.reset( new GraphicObject( aBmpEx ) );
830 // clear scale values, generated bitmap already
831 // contains scaling
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(),
844 aPt,
845 aSz,
846 &aGrfAttr );
848 if( mp2ndOutDev )
849 pGrfObj->Draw( &mp2ndOutDev->getOutDev(),
850 aPt,
851 aSz,
852 &aGrfAttr );
854 // created GraphicObject, which possibly cached
855 // display bitmap - return cache object, to retain
856 // that information.
857 return uno::Reference< rendering::XCachedPrimitive >(
858 new CachedBitmap( pGrfObj,
859 aPt,
860 aSz,
861 aGrfAttr,
862 viewState,
863 renderState,
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)) );
872 // Nothing rendered
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,
882 xBitmap,
883 viewState,
884 renderState,
885 false );
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,
894 xBitmap,
895 viewState,
896 renderState,
897 true );
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& )
916 // TODO(F1)
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,
928 sal_Bool beFast )
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(),
968 aRect.GetSize()) );
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();
985 int nCurrPos(0);
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;
997 return aRes;
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,
1033 aSize ) );
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 ],
1067 data[ nCurrPos+1 ],
1068 data[ nCurrPos+2 ] ) );
1070 nCurrPos += 4;
1073 break;
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 ];
1085 nCurrPos += 4;
1088 break;
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 ];
1100 nCurrPos += 4;
1103 break;
1105 default:
1107 for( x=0; x<nWidth; ++x )
1109 pWriteAccess->SetPixel( y, x, BitmapColor( data[ nCurrPos ],
1110 data[ nCurrPos+1 ],
1111 data[ nCurrPos+2 ] ) );
1112 nCurrPos += 4;
1115 break;
1119 bCopyBack = true;
1122 // copy back only here, since the BitmapAccessors must be
1123 // destroyed beforehand
1124 if( bCopyBack )
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(
1189 rOutDev.GetPixel(
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()) );
1199 if ( !mbHaveAlpha )
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,
1214 mpDevice,
1216 eColorType == IGNORE_COLOR ? 0 : 3 );
1218 OutputDevice& rOutDev( mpOutDev->getOutDev() );
1219 OutputDevice* p2ndOutDev = NULL;
1221 rOutDev.EnableMapMode( sal_False );
1223 if( mp2ndOutDev )
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 ) );
1251 else
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,
1266 viewState,
1267 renderState ) );
1269 if( aClipPoly.count() )
1271 // setup non-empty clipping
1272 Region aRegion = Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly ) );
1273 aClipRegion.Intersect( aRegion );
1275 else
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,
1287 // i.e. empty, too.
1288 if( aClipRegion.IsNull() )
1290 rOutDev.SetClipRegion();
1292 if( p2ndOutDev )
1293 p2ndOutDev->SetClipRegion();
1295 else
1297 rOutDev.SetClipRegion( aClipRegion );
1299 if( p2ndOutDev )
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 )
1320 case LINE_COLOR:
1321 rOutDev.SetLineColor( aColor );
1322 rOutDev.SetFillColor();
1324 if( p2ndOutDev )
1326 p2ndOutDev->SetLineColor( aColor );
1327 p2ndOutDev->SetFillColor();
1329 break;
1331 case FILL_COLOR:
1332 rOutDev.SetFillColor( aColor );
1333 rOutDev.SetLineColor();
1335 if( p2ndOutDev )
1337 p2ndOutDev->SetFillColor( aColor );
1338 p2ndOutDev->SetLineColor();
1340 break;
1342 case TEXT_COLOR:
1343 rOutDev.SetTextColor( aColor );
1345 if( p2ndOutDev )
1346 p2ndOutDev->SetTextColor( aColor );
1347 break;
1349 default:
1350 ENSURE_OR_THROW( false,
1351 "Unexpected color type");
1352 break;
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() );
1371 ::Font aVCLFont;
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 );
1388 // setup font color
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 ) )
1394 return false;
1396 rOutDev.SetFont( aVCLFont );
1398 if( mp2ndOutDev )
1399 mp2ndOutDev->getOutDev().SetFont( aVCLFont );
1401 return true;
1404 bool CanvasHelper::repaint( const GraphicObjectSharedPtr& rGrf,
1405 const rendering::ViewState& viewState,
1406 const rendering::RenderState& renderState,
1407 const ::Point& rPt,
1408 const ::Size& rSz,
1409 const GraphicAttr& rAttr ) const
1411 ENSURE_OR_RETURN_FALSE( rGrf,
1412 "Invalid Graphic" );
1414 if( !mpOutDev )
1415 return false; // disposed
1416 else
1418 tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev );
1419 setupOutDevState( viewState, renderState, IGNORE_COLOR );
1421 if( !rGrf->Draw( &mpOutDev->getOutDev(), rPt, rSz, &rAttr ) )
1422 return false;
1424 // #i80779# Redraw also into mask outdev
1425 if( mp2ndOutDev )
1426 return rGrf->Draw( &mp2ndOutDev->getOutDev(), rPt, rSz, &rAttr );
1428 return true;
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: */