update dev300-m58
[ooovba.git] / canvas / source / vcl / canvashelper.cxx
blob837519e841b2a3b9e0a63e5404930fbf72852b82
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: canvashelper.cxx,v $
10 * $Revision: 1.19 $
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>
63 #include <utility>
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;
77 namespace vclcanvas
79 namespace
81 basegfx::B2DLineJoin b2DJoineFromJoin( sal_Int8 nJoinType )
83 switch( 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;
97 default:
98 ENSURE_OR_THROW( false,
99 "b2DJoineFromJoin(): Unexpected join type" );
102 return basegfx::B2DLINEJOIN_NONE;
106 CanvasHelper::CanvasHelper() :
107 mpDevice(),
108 mpProtectedOutDev(),
109 mpOutDev(),
110 mp2ndOutDev(),
111 mbHaveAlpha( false )
115 void CanvasHelper::disposing()
117 mpDevice = NULL;
118 mpProtectedOutDev.reset();
119 mpOutDev.reset();
120 mp2ndOutDev.reset();
123 void CanvasHelper::init( rendering::XGraphicDevice& rDevice,
124 const OutDevProviderSharedPtr& rOutDev,
125 bool bProtect,
126 bool bHaveAlpha )
128 // cast away const, need to change refcount (as this is
129 // ~invisible to client code, still logically const)
130 mpDevice = &rDevice;
131 mbHaveAlpha = bHaveAlpha;
133 setOutDev( rOutDev, bProtect );
136 void CanvasHelper::setOutDev( const OutDevProviderSharedPtr& rOutDev,
137 bool bProtect )
139 if( bProtect )
140 mpProtectedOutDev = rOutDev;
141 else
142 mpProtectedOutDev.reset();
144 mpOutDev = rOutDev;
147 void CanvasHelper::setBackgroundOutDev( const OutDevProviderSharedPtr& rOutDev )
149 mp2ndOutDev = rOutDev;
150 mp2ndOutDev->getOutDev().EnableMapMode( FALSE );
153 void CanvasHelper::clear()
155 // are we disposed?
156 if( mpOutDev )
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()) );
167 if( mp2ndOutDev )
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 )
188 // are we disposed?
189 if( mpOutDev )
191 // nope, render
192 tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev );
193 setupOutDevState( viewState, renderState, LINE_COLOR );
195 const Point aOutPoint( tools::mapRealPoint2D( aPoint,
196 viewState, renderState ) );
197 // TODO(F1): alpha
198 mpOutDev->getOutDev().DrawPixel( aOutPoint );
200 if( mp2ndOutDev )
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 )
211 // are we disposed?
212 if( mpOutDev )
214 // nope, render
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 ) );
222 // TODO(F2): alpha
223 mpOutDev->getOutDev().DrawLine( aStartPoint, aEndPoint );
225 if( mp2ndOutDev )
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 )
236 if( mpOutDev )
238 tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev );
239 setupOutDevState( viewState, renderState, LINE_COLOR );
241 const Point& rStartPoint( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.Px,
242 aBezierSegment.Py),
243 viewState, renderState ) );
244 const Point& rCtrlPoint1( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.C1x,
245 aBezierSegment.C1y),
246 viewState, renderState ) );
247 const Point& rCtrlPoint2( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.C2x,
248 aBezierSegment.C2y),
249 viewState, renderState ) );
250 const Point& rEndPoint( tools::mapRealPoint2D( _aEndPoint,
251 viewState, renderState ) );
253 ::Polygon aPoly(4);
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 );
263 // TODO(F2): alpha
264 mpOutDev->getOutDev().DrawPolygon( aPoly );
265 if( mp2ndOutDev )
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(),
276 "polygon is NULL");
278 if( mpOutDev )
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 );
291 if( mp2ndOutDev )
292 mp2ndOutDev->getOutDev().DrawPolyPolygon( aPolyPoly );
294 else
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
302 // closing segment.
303 USHORT nSize( aPolyPoly.Count() );
305 for( USHORT i=0; i<nSize; ++i )
307 mpOutDev->getOutDev().DrawPolyLine( aPolyPoly[i] );
309 if( mp2ndOutDev )
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(),
326 "polygon is NULL");
328 if( mpOutDev )
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),
362 // aDashArray ) );
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;
377 else
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
403 // user coordinates.
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] );
421 if( mp2ndOutDev )
422 mp2ndOutDev->getOutDev().DrawPolygon( aVCLPolyPoly[i] );
423 } else {
424 const USHORT nPolySize = aVCLPolyPoly[i].GetSize();
425 if( nPolySize ) {
426 Point rPrevPoint = aVCLPolyPoly[i].GetPoint( 0 );
427 Point rPoint;
429 for( USHORT j=1; j<nPolySize; j++ ) {
430 rPoint = aVCLPolyPoly[i].GetPoint( j );
431 mpOutDev->getOutDev().DrawLine( rPrevPoint, rPoint );
432 if( mp2ndOutDev )
433 mp2ndOutDev->getOutDev().DrawLine( rPrevPoint, rPoint );
434 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(),
481 "polygon is NULL");
483 if( mpOutDev )
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(
493 aB2DPolyPoly,
494 viewState, renderState ) );
495 const bool bSourceAlpha( renderState.CompositeOperation == rendering::CompositeOperation::SOURCE );
496 if( !nTransparency || bSourceAlpha )
498 mpOutDev->getOutDev().DrawPolyPolygon( aPolyPoly );
500 else
502 mpOutDev->getOutDev().DrawTransparent( aPolyPoly, (USHORT)nTransPercent );
505 if( mp2ndOutDev )
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 );
520 else
522 mp2ndOutDev->getOutDev().DrawPolyPolygon( aPolyPoly );
525 else
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 >& )
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 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;
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<USHORT>(text.StartPosition),
614 ::canvas::tools::numeric_cast<USHORT>(text.Length) );
616 if( mp2ndOutDev )
618 mp2ndOutDev->getOutDev().SetLayoutMode( nLayoutMode );
619 mp2ndOutDev->getOutDev().DrawText( aOutpos,
620 text.Text,
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(),
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 )
728 mp2ndOutDev->getOutDev().DrawBitmapEx( ::vcl::unotools::pointFromB2DPoint( aOutputPos ),
729 aBmpEx );
731 // Returning a cache object is not useful, the XBitmap
732 // itself serves this purpose
733 return uno::Reference< rendering::XCachedPrimitive >(NULL);
735 else
737 // Matrix contains non-trivial transformation (or
738 // color modulation is requested), decompose to check
739 // whether GraphicObject suffices
740 ::basegfx::B2DVector aScale;
741 double nRotate;
742 double nShearX;
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(
765 static_cast< BYTE >(
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
773 // and translation)
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 ) );
788 else
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,
797 aBmpSize.Width(),
798 aBmpSize.Height()),
799 aMatrix );
801 aOutputPos.setX( aDestRect.getMinX() );
802 aOutputPos.setY( aDestRect.getMinY() );
804 // complex transformation, use generic affine bitmap
805 // transformation
806 aBmpEx = tools::transformBitmap( aBmpEx,
807 aMatrix,
808 renderState.DeviceColor,
809 tools::MODULATE_NONE );
811 pGrfObj.reset( new GraphicObject( aBmpEx ) );
813 // clear scale values, generated bitmap already
814 // contains scaling
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(),
827 aPt,
828 aSz,
829 &aGrfAttr );
831 if( mp2ndOutDev )
832 pGrfObj->Draw( &mp2ndOutDev->getOutDev(),
833 aPt,
834 aSz,
835 &aGrfAttr );
837 // created GraphicObject, which possibly cached
838 // display bitmap - return cache object, to retain
839 // that information.
840 return uno::Reference< rendering::XCachedPrimitive >(
841 new CachedBitmap( pGrfObj,
842 aPt,
843 aSz,
844 aGrfAttr,
845 viewState,
846 renderState,
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)) );
855 // Nothing rendered
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,
865 xBitmap,
866 viewState,
867 renderState,
868 false );
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,
877 xBitmap,
878 viewState,
879 renderState,
880 true );
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& )
899 // TODO(F1)
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 sal_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 );
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(),
951 aRect.GetSize()) );
953 ScopedBitmapReadAccess pReadAccess( aBitmap.AcquireReadAccess(),
954 aBitmap );
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();
969 int nCurrPos(0);
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;
981 return aRes;
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,
1017 aSize ) );
1019 ScopedBitmapReadAccess pReadAccess( aTmpBitmap.AcquireReadAccess(),
1020 aTmpBitmap );
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(),
1032 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++ = (BYTE)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 );
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(
1175 rOutDev.GetPixel(
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,
1196 mpDevice,
1198 eColorType == IGNORE_COLOR ? 0 : 3 );
1200 OutputDevice& rOutDev( mpOutDev->getOutDev() );
1201 OutputDevice* p2ndOutDev = NULL;
1203 rOutDev.EnableMapMode( FALSE );
1205 if( mp2ndOutDev )
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 ) );
1233 else
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,
1248 viewState,
1249 renderState ) );
1251 if( aClipPoly.count() )
1253 // setup non-empty clipping
1254 Region aRegion = Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly ) );
1255 aClipRegion.Intersect( aRegion );
1257 else
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,
1269 // i.e. empty, too.
1270 if( aClipRegion.IsNull() )
1272 rOutDev.SetClipRegion();
1274 if( p2ndOutDev )
1275 p2ndOutDev->SetClipRegion();
1277 else
1279 rOutDev.SetClipRegion( aClipRegion );
1281 if( p2ndOutDev )
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 )
1302 case LINE_COLOR:
1303 rOutDev.SetLineColor( aColor );
1304 rOutDev.SetFillColor();
1306 if( p2ndOutDev )
1308 p2ndOutDev->SetLineColor( aColor );
1309 p2ndOutDev->SetFillColor();
1311 break;
1313 case FILL_COLOR:
1314 rOutDev.SetFillColor( aColor );
1315 rOutDev.SetLineColor();
1317 if( p2ndOutDev )
1319 p2ndOutDev->SetFillColor( aColor );
1320 p2ndOutDev->SetLineColor();
1322 break;
1324 case TEXT_COLOR:
1325 rOutDev.SetTextColor( aColor );
1327 if( p2ndOutDev )
1328 p2ndOutDev->SetTextColor( aColor );
1329 break;
1331 default:
1332 ENSURE_OR_THROW( false,
1333 "Unexpected color type");
1334 break;
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() );
1353 ::Font aVCLFont;
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 );
1370 // setup font color
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 ) )
1376 return false;
1378 rOutDev.SetFont( aVCLFont );
1380 if( mp2ndOutDev )
1381 mp2ndOutDev->getOutDev().SetFont( aVCLFont );
1383 return true;
1386 bool CanvasHelper::repaint( const GraphicObjectSharedPtr& rGrf,
1387 const rendering::ViewState& viewState,
1388 const rendering::RenderState& renderState,
1389 const ::Point& rPt,
1390 const ::Size& rSz,
1391 const GraphicAttr& rAttr ) const
1393 ENSURE_OR_RETURN( rGrf,
1394 "Invalid Graphic" );
1396 if( !mpOutDev )
1397 return false; // disposed
1398 else
1400 tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev );
1401 setupOutDevState( viewState, renderState, IGNORE_COLOR );
1403 if( !rGrf->Draw( &mpOutDev->getOutDev(), rPt, rSz, &rAttr ) )
1404 return false;
1406 // #i80779# Redraw also into mask outdev
1407 if( mp2ndOutDev )
1408 return rGrf->Draw( &mp2ndOutDev->getOutDev(), rPt, rSz, &rAttr );
1410 return true;
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();