Update ooo320-m1
[ooovba.git] / drawinglayer / source / processor2d / canvasprocessor.cxx
blob77cb2b33502e65a9310b3504f15c0723a2fb3691
1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile: canvasprocessor.cxx,v $
7 * $Revision: 1.8 $
9 * last change: $Author: aw $ $Date: 2008-07-21 17:41:18 $
11 * The Contents of this file are made available subject to
12 * the terms of GNU Lesser General Public License Version 2.1.
15 * GNU Lesser General Public License Version 2.1
16 * =============================================
17 * Copyright 2005 by Sun Microsystems, Inc.
18 * 901 San Antonio Road, Palo Alto, CA 94303, USA
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License version 2.1, as published by the Free Software Foundation.
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
32 * MA 02111-1307 USA
34 ************************************************************************/
36 // MARKER(update_precomp.py): autogen include statement, do not remove
37 #include "precompiled_drawinglayer.hxx"
39 #include <drawinglayer/processor2d/canvasprocessor.hxx>
40 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
41 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
42 #include <com/sun/star/rendering/XCanvas.hpp>
43 #include <vcl/canvastools.hxx>
44 #include <basegfx/tools/canvastools.hxx>
45 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
46 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
47 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
48 #include <canvas/canvastools.hxx>
49 #include <svtools/ctloptions.hxx>
50 #include <vcl/svapp.hxx>
51 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
52 #include <basegfx/polygon/b2dpolygonclipper.hxx>
53 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
54 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
55 #include <cppcanvas/basegfxfactory.hxx>
56 #include <com/sun/star/rendering/XBitmapCanvas.hpp>
57 #include <cppcanvas/vclfactory.hxx>
58 #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
59 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
60 #include <com/sun/star/rendering/TextDirection.hpp>
61 #include <vclhelperbitmaptransform.hxx>
62 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
63 #include <basegfx/polygon/b2dpolygontools.hxx>
64 #include <drawinglayer/primitive2d/alphaprimitive2d.hxx>
65 #include <basegfx/tuple/b2i64tuple.hxx>
66 #include <basegfx/range/b2irange.hxx>
67 #include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp>
68 #include <com/sun/star/rendering/CompositeOperation.hpp>
69 #include <com/sun/star/rendering/StrokeAttributes.hpp>
70 #include <com/sun/star/rendering/PathJoinType.hpp>
71 #include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
72 #include <com/sun/star/rendering/TexturingMode.hpp>
73 #include <drawinglayer/primitive2d/unifiedalphaprimitive2d.hxx>
74 #include <vclhelperbufferdevice.hxx>
75 #include <drawinglayer/primitive2d/chartprimitive2d.hxx>
76 #include <helperchartrenderer.hxx>
77 #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
78 #include <helperwrongspellrenderer.hxx>
80 //////////////////////////////////////////////////////////////////////////////
82 using namespace com::sun::star;
84 //////////////////////////////////////////////////////////////////////////////
85 // AW: Adding the canvas example from THB here to extract stuff later
87 // TODO(Q3): share impCreateEmptyBitmapWithPattern() and other
88 // helper methods with vclprocessor.cxx
89 Bitmap impCreateEmptyBitmapWithPattern(Bitmap aSource, const Size& aTargetSizePixel)
91 Bitmap aRetval;
92 BitmapReadAccess* pReadAccess = aSource.AcquireReadAccess();
94 if(pReadAccess)
96 if(aSource.GetBitCount() <= 8)
98 BitmapPalette aPalette(pReadAccess->GetPalette());
99 aRetval = Bitmap(aTargetSizePixel, aSource.GetBitCount(), &aPalette);
101 else
103 aRetval = Bitmap(aTargetSizePixel, aSource.GetBitCount());
106 delete pReadAccess;
109 return aRetval;
112 Bitmap impModifyBitmap(const basegfx::BColorModifier& rModifier, const Bitmap& rSource)
114 Bitmap aRetval(rSource);
116 switch(rModifier.getMode())
118 case basegfx::BCOLORMODIFYMODE_REPLACE :
120 aRetval = impCreateEmptyBitmapWithPattern(aRetval, Size(1L, 1L));
121 aRetval.Erase(Color(rModifier.getBColor()));
122 break;
125 default : // BCOLORMODIFYMODE_INTERPOLATE, BCOLORMODIFYMODE_GRAY, BCOLORMODIFYMODE_BLACKANDWHITE
127 BitmapWriteAccess* pContent = aRetval.AcquireWriteAccess();
129 if(pContent)
131 for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
133 for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
135 const Color aColor = pContent->GetPixel(y, x);
136 const basegfx::BColor aBColor(rModifier.getModifiedColor(aColor.getBColor()));
137 pContent->SetPixel(y, x, BitmapColor(Color(aBColor)));
141 delete pContent;
144 break;
148 return aRetval;
151 Bitmap impModifyBitmap(const basegfx::BColorModifierStack& rBColorModifierStack, const Bitmap& rSource)
153 Bitmap aRetval(rSource);
155 for(sal_uInt32 a(rBColorModifierStack.count()); a; )
157 const basegfx::BColorModifier& rModifier = rBColorModifierStack.getBColorModifier(--a);
158 aRetval = impModifyBitmap(rModifier, aRetval);
161 return aRetval;
164 sal_uInt32 impCalcGradientSteps(sal_uInt32 nSteps, const basegfx::B2DRange& rRange, sal_uInt32 nMaxDist)
166 if(nSteps == 0L)
167 nSteps = (sal_uInt32)(rRange.getWidth() + rRange.getHeight()) / 8;
169 if(nSteps < 2L)
171 nSteps = 2L;
174 if(nSteps > nMaxDist)
176 nSteps = nMaxDist;
179 return nSteps;
182 void canvasProcessor::impDrawGradientSimple(
183 const basegfx::B2DPolyPolygon& rTargetForm,
184 const ::std::vector< basegfx::B2DHomMatrix >& rMatrices,
185 const ::std::vector< basegfx::BColor >& rColors,
186 const basegfx::B2DPolygon& rUnitPolygon)
188 uno::Reference< rendering::XPolyPolygon2D > xPoly(
189 basegfx::unotools::xPolyPolygonFromB2DPolygon(
190 mxCanvas->getDevice(),
191 rUnitPolygon));
192 uno::Reference< rendering::XPolyPolygon2D > xTargetPoly(
193 basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
194 mxCanvas->getDevice(),
195 rTargetForm));
197 for(sal_uInt32 a(0L); a < rColors.size(); a++)
199 // set correct color
200 const basegfx::BColor aFillColor(rColors[a]);
202 maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
203 mxCanvas->getDevice(),
204 aFillColor);
206 if(a)
208 if(a - 1L < rMatrices.size())
210 canvas::tools::setRenderStateTransform( maRenderState,
211 rMatrices[a - 1L] );
212 mxCanvas->fillPolyPolygon(xPoly,maViewState,maRenderState);
215 else
217 canvas::tools::setRenderStateTransform( maRenderState,
218 basegfx::B2DHomMatrix() );
219 mxCanvas->fillPolyPolygon(xTargetPoly,maViewState,maRenderState);
224 void canvasProcessor::impDrawGradientComplex(
225 const basegfx::B2DPolyPolygon& rTargetForm,
226 const ::std::vector< basegfx::B2DHomMatrix >& rMatrices,
227 const ::std::vector< basegfx::BColor >& rColors,
228 const basegfx::B2DPolygon& rUnitPolygon)
230 uno::Reference< rendering::XPolyPolygon2D > xPoly(
231 basegfx::unotools::xPolyPolygonFromB2DPolygon(
232 mxCanvas->getDevice(),
233 rUnitPolygon));
234 uno::Reference< rendering::XPolyPolygon2D > xTargetPoly(
235 basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
236 mxCanvas->getDevice(),
237 rTargetForm));
239 maRenderState.Clip = xTargetPoly;
241 // draw gradient PolyPolygons
242 for(std::size_t a = 0L; a < rMatrices.size(); a++)
244 // set correct color
245 if(rColors.size() > a)
247 const basegfx::BColor aFillColor(rColors[a]);
249 maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
250 mxCanvas->getDevice(),
251 aFillColor);
254 canvas::tools::setRenderStateTransform( maRenderState,
255 rMatrices[a] );
257 if(a)
258 mxCanvas->fillPolyPolygon(xPoly,maViewState,maRenderState);
259 else
260 mxCanvas->fillPolyPolygon(xTargetPoly,maViewState,maRenderState);
263 maRenderState.Clip.clear();
266 void canvasProcessor::impDrawGradient(
267 const basegfx::B2DPolyPolygon& rTargetForm,
268 ::drawinglayer::primitive::GradientStyle eGradientStyle,
269 sal_uInt32 nSteps,
270 const basegfx::BColor& rStart,
271 const basegfx::BColor& rEnd,
272 double fBorder, double fAngle, double fOffsetX, double fOffsetY, bool bSimple)
274 fprintf(stderr,"impDrawGradient\n");
276 basegfx::B2DPolyPolygon aTmp(rTargetForm);
277 aTmp.transform( maWorldToView );
278 const basegfx::B2DRange aOutlineRangePixel(basegfx::tools::getRange(aTmp));
279 const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(rTargetForm));
281 fprintf(stderr,"impDrawGradient: #%d\n",nSteps);
283 if( // step count is infinite, can use native canvas
284 // gradients here
285 nSteps == 0 ||
286 // step count is sufficiently high, such that no
287 // discernible difference should be visible.
288 nSteps > 64 )
290 uno::Reference< rendering::XParametricPolyPolygon2DFactory > xFactory(
291 mxCanvas->getDevice()->getParametricPolyPolygonFactory() );
293 if( xFactory.is() )
295 fprintf(stderr,"native gradient #1\n");
297 basegfx::B2DHomMatrix aTextureTransformation;
298 rendering::Texture aTexture;
300 aTexture.RepeatModeX = rendering::TexturingMode::CLAMP;
301 aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
302 aTexture.Alpha = 1.0;
305 // setup start/end color values
306 // ----------------------------
308 const uno::Sequence< double > aStartColor(
309 basegfx::unotools::colorToDoubleSequence( mxCanvas->getDevice(),
310 rStart ));
311 const uno::Sequence< double > aEndColor(
312 basegfx::unotools::colorToDoubleSequence( mxCanvas->getDevice(),
313 rEnd ));
315 // Setup texture transformation
316 // ----------------------------
318 const basegfx::B2DRange& rBounds(
319 basegfx::tools::getRange( rTargetForm ));
321 // setup rotation angle. VCL rotates
322 // counter-clockwise, while canvas transformation
323 // rotates clockwise
324 //fAngle = -fAngle;
326 switch(eGradientStyle)
328 case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR:
329 // FALLTHROUGH intended
330 case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL:
332 // standard orientation for VCL linear
333 // gradient is vertical, thus, rotate 90
334 // degrees
335 fAngle += M_PI/2.0;
337 // shrink texture, to account for border
338 // (only in x direction, linear gradient
339 // is constant in y direction, anyway)
340 aTextureTransformation.scale(
341 basegfx::pruneScaleValue(1.0 - fBorder),
342 1.0 );
344 double fBorderX(0.0);
346 // determine type of gradient (and necessary
347 // transformation matrix, should it be emulated by a
348 // generic gradient)
349 switch(eGradientStyle)
351 case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR:
352 // linear gradients don't respect
353 // offsets (they are implicitely
354 // assumed to be 50%). linear
355 // gradients don't have border on
356 // both sides, only on the
357 // startColor side. Gradient is
358 // invariant in y direction: leave
359 // y offset alone.
360 fBorderX = fBorder;
361 aTexture.Gradient = xFactory->createLinearHorizontalGradient( aStartColor,
362 aEndColor );
363 break;
365 case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL:
366 // axial gradients have border on
367 // both sides. Gradient is
368 // invariant in y direction: leave
369 // y offset alone.
370 fBorderX = fBorder * .5;
371 aTexture.Gradient = xFactory->createAxialHorizontalGradient( aStartColor,
372 aEndColor );
373 break;
376 // apply border offset values
377 aTextureTransformation.translate( fBorderX,
378 0.0 );
380 // rotate texture according to gradient rotation
381 aTextureTransformation.translate( -0.5, -0.5 );
382 aTextureTransformation.rotate( fAngle );
384 // to let the first strip of a rotated
385 // gradient start at the _edge_ of the
386 // bound rect (and not, due to rotation,
387 // slightly inside), slightly enlarge the
388 // gradient:
390 // y/2 sin(alpha) + x/2 cos(alpha)
392 // (values to change are not actual
393 // gradient scales, but original bound
394 // rect dimensions. Since we still want
395 // the border setting to apply after that,
396 // we multiply with that as above for
397 // nScaleX)
398 const double nScale(
399 basegfx::pruneScaleValue(
400 fabs( rBounds.getHeight()*sin(fAngle) ) +
401 fabs( rBounds.getWidth()*cos(fAngle) )));
403 aTextureTransformation.scale( nScale, nScale );
405 // translate back origin to center of
406 // primitive
407 aTextureTransformation.translate( 0.5*rBounds.getWidth(),
408 0.5*rBounds.getHeight() );
409 break;
412 case ::drawinglayer::primitive::GRADIENTSTYLE_RADIAL:
413 // FALLTHROUGH intended
414 case ::drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL:
415 // FALLTHROUGH intended
416 case ::drawinglayer::primitive::GRADIENTSTYLE_SQUARE:
417 // FALLTHROUGH intended
418 case ::drawinglayer::primitive::GRADIENTSTYLE_RECT:
420 fprintf(stderr,"native gradient #2\n");
422 // determine scale factors for the gradient (must
423 // be scaled up from [0,1]x[0,1] rect to object
424 // bounds). Will potentially changed in switch
425 // statement below.
426 // Respect border value, while doing so, the VCL
427 // gradient's border will effectively shrink the
428 // resulting gradient.
429 double nScaleX( rBounds.getWidth() * (1.0 - fBorder) );
430 double nScaleY( rBounds.getHeight()* (1.0 - fBorder) );
432 // determine offset values. Since the
433 // border is divided half-by-half to both
434 // sides of the gradient, divide
435 // translation offset by an additional
436 // factor of 2. Also respect offset here,
437 // but since VCL gradients have their
438 // center at [0,0] for zero offset, but
439 // canvas gradients have their top, left
440 // edge aligned with the primitive, and
441 // offset of 50% effectively must yield
442 // zero shift. Both values will
443 // potentially be adapted in switch
444 // statement below.
445 double nOffsetX( rBounds.getWidth() *
446 (2.0 * fOffsetX - 1.0 + fBorder)*.5 );
447 double nOffsetY( rBounds.getHeight() *
448 (2.0 * fOffsetY - 1.0 + fBorder)*.5 );
450 // determine type of gradient (and necessary
451 // transformation matrix, should it be emulated by a
452 // generic gradient)
453 switch(eGradientStyle)
455 case ::drawinglayer::primitive::GRADIENTSTYLE_RADIAL:
457 // create isotrophic scaling
458 if( nScaleX > nScaleY )
460 nOffsetY -= (nScaleX - nScaleY) * 0.5;
461 nScaleY = nScaleX;
463 else
465 nOffsetX -= (nScaleY - nScaleX) * 0.5;
466 nScaleX = nScaleY;
469 // enlarge gradient to match bound rect diagonal
470 aTextureTransformation.translate( -0.5, -0.5 );
471 const double nScale( hypot(rBounds.getWidth(),
472 rBounds.getHeight()) / nScaleX );
473 aTextureTransformation.scale( nScale, nScale );
474 aTextureTransformation.translate( 0.5, 0.5 );
476 aTexture.Gradient = xFactory->createEllipticalGradient(
477 aEndColor,
478 aStartColor,
479 cssgeom::RealRectangle2D(0.0,0.0,
480 1.0,1.0) );
482 break;
484 case ::drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL:
486 // enlarge gradient slightly
487 aTextureTransformation.translate( -0.5, -0.5 );
488 const double nSqrt2( sqrt(2.0) );
489 aTextureTransformation.scale( nSqrt2,nSqrt2 );
490 aTextureTransformation.translate( 0.5, 0.5 );
492 aTexture.Gradient = xFactory->createEllipticalGradient(
493 aEndColor,
494 aStartColor,
495 cssgeom::RealRectangle2D( rBounds.getMinX(),
496 rBounds.getMinY(),
497 rBounds.getMaxX(),
498 rBounds.getMaxY() ));
500 break;
502 case ::drawinglayer::primitive::GRADIENTSTYLE_SQUARE:
504 // create isotrophic scaling
505 if( nScaleX > nScaleY )
507 nOffsetY -= (nScaleX - nScaleY) * 0.5;
508 nScaleY = nScaleX;
510 else
512 nOffsetX -= (nScaleY - nScaleX) * 0.5;
513 nScaleX = nScaleY;
516 aTexture.Gradient = xFactory->createRectangularGradient(
517 aEndColor,
518 aStartColor,
519 cssgeom::RealRectangle2D(0.0,0.0,
520 1.0,1.0));
522 break;
524 case ::drawinglayer::primitive::GRADIENTSTYLE_RECT:
526 aTexture.Gradient = xFactory->createRectangularGradient(
527 aEndColor,
528 aStartColor,
529 cssgeom::RealRectangle2D( rBounds.getMinX(),
530 rBounds.getMinY(),
531 rBounds.getMaxX(),
532 rBounds.getMaxY() ));
534 break;
537 nScaleX = basegfx::pruneScaleValue( nScaleX );
538 nScaleY = basegfx::pruneScaleValue( nScaleY );
540 aTextureTransformation.scale( nScaleX, nScaleY );
542 // rotate texture according to gradient rotation
543 aTextureTransformation.translate( -0.5*nScaleX, -0.5*nScaleY );
544 aTextureTransformation.rotate( fAngle );
545 aTextureTransformation.translate( 0.5*nScaleX, 0.5*nScaleY );
547 aTextureTransformation.translate( nOffsetX, nOffsetY );
549 break;
551 default:
552 OSL_ENSURE( false,
553 "canvasProcessor::impDrawGradient(): Unexpected gradient type" );
554 break;
557 // As the texture coordinate space is relative to
558 // the polygon coordinate space (NOT to the
559 // polygon itself), move gradient to the start of
560 // the actual polygon. If we skip this, the
561 // gradient will always display at the origin, and
562 // not within the polygon bound (which might be
563 // miles away from the origin).
564 aTextureTransformation.translate( rBounds.getMinX(),
565 rBounds.getMinY() );
567 basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform,
568 aTextureTransformation );
569 uno::Sequence< rendering::Texture > aSeq(1);
570 aSeq[0] = aTexture;
572 mxCanvas->fillTexturedPolyPolygon(
573 basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
574 mxCanvas->getDevice(),
575 rTargetForm),
576 maViewState,
577 maRenderState,
578 aSeq );
580 // done, using native gradients
581 return;
584 else
586 // make sure steps is not too high/low
587 nSteps = impCalcGradientSteps(nSteps,
588 aOutlineRangePixel,
589 sal_uInt32((rStart.getMaximumDistance(rEnd) * 127.5) + 0.5));
592 ::std::vector< basegfx::B2DHomMatrix > aMatrices;
593 ::std::vector< basegfx::BColor > aColors;
594 basegfx::B2DPolygon aUnitPolygon;
596 if( drawinglayer::primitive::GRADIENTSTYLE_RADIAL == eGradientStyle ||
597 drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL == eGradientStyle)
599 const basegfx::B2DPoint aCircleCenter(0.5, 0.5);
600 aUnitPolygon = basegfx::tools::createPolygonFromEllipse(aCircleCenter, 0.5, 0.5);
601 aUnitPolygon = basegfx::tools::adaptiveSubdivideByAngle(aUnitPolygon);
603 else
605 aUnitPolygon = basegfx::tools::createPolygonFromRect(
606 basegfx::B2DRange(0.0, 0.0, 1.0, 1.0));
609 // create geometries
610 switch(eGradientStyle)
612 case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR:
614 ::drawinglayer::primitive::geoTexSvxGradientLinear aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle);
615 aGradient.appendTransformations(aMatrices);
616 aGradient.appendColors(aColors);
617 break;
619 case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL:
621 ::drawinglayer::primitive::geoTexSvxGradientAxial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle);
622 aGradient.appendTransformations(aMatrices);
623 aGradient.appendColors(aColors);
624 break;
626 case ::drawinglayer::primitive::GRADIENTSTYLE_RADIAL:
628 ::drawinglayer::primitive::geoTexSvxGradientRadial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetY);
629 aGradient.appendTransformations(aMatrices);
630 aGradient.appendColors(aColors);
631 break;
633 case ::drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL:
635 ::drawinglayer::primitive::geoTexSvxGradientElliptical aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle);
636 aGradient.appendTransformations(aMatrices);
637 aGradient.appendColors(aColors);
638 break;
640 case ::drawinglayer::primitive::GRADIENTSTYLE_SQUARE:
642 ::drawinglayer::primitive::geoTexSvxGradientSquare aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle);
643 aGradient.appendTransformations(aMatrices);
644 aGradient.appendColors(aColors);
645 break;
647 case ::drawinglayer::primitive::GRADIENTSTYLE_RECT:
649 ::drawinglayer::primitive::geoTexSvxGradientRect aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle);
650 aGradient.appendTransformations(aMatrices);
651 aGradient.appendColors(aColors);
652 break;
656 // paint them with mask using the XOR method
657 if(aMatrices.size())
659 if(bSimple)
661 impDrawGradientSimple(rTargetForm, aMatrices, aColors, aUnitPolygon);
663 else
665 impDrawGradientComplex(rTargetForm, aMatrices, aColors, aUnitPolygon);
672 //////////////////////////////////////////////////////////////////////////////
673 // rendering support
675 // directdraw of text simple portion
676 void canvasProcessor::impRender_STXP(const textSimplePortionPrimitive& rTextCandidate)
678 const fontAttributes& rFontAttrs( rTextCandidate.getFontAttributes() );
679 rendering::FontRequest aFontRequest;
681 aFontRequest.FontDescription.FamilyName = rFontAttrs.maFamilyName;
682 aFontRequest.FontDescription.StyleName = rFontAttrs.maStyleName;
683 aFontRequest.FontDescription.IsSymbolFont = rFontAttrs.mbSymbol ? util::TriState_YES : util::TriState_NO;
684 aFontRequest.FontDescription.IsVertical = rFontAttrs.mbVertical ? util::TriState_YES : util::TriState_NO;
686 // TODO(F2): improve vclenum->panose conversion
687 aFontRequest.FontDescription.FontDescription.Weight =
688 rFontAttrs.mnWeight;
689 aFontRequest.FontDescription.FontDescription.Letterform =
690 rFontAttrs.mbItalic ? 9 : 0;
692 // font matrix should only be used for glyph rotations etc.
693 css::geometry::Matrix2D aFontMatrix;
694 canvas::tools::setIdentityMatrix2D( aFontMatrix );
696 uno::Reference<rendering::XCanvasFont> xFont(
697 mxCanvas->createFont( aFontRequest,
698 uno::Sequence< beans::PropertyValue >(),
699 aFontMatrix ));
701 if( !xFont.is() )
702 return;
704 uno::Reference<rendering::XTextLayout> xLayout(
705 xFont->createTextLayout(
706 rendering::StringContext( rTextCandidate.getText(),
708 rTextCandidate.getText().Len() ),
709 // TODO(F3): Is this sufficient?
710 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
711 0 ));
712 if( !xLayout.is() )
713 return;
715 xLayout->applyLogicalAdvancements(
716 uno::Sequence<double>(&rTextCandidate.getDXArray()[0],
717 rTextCandidate.getDXArray().size() ));
719 const basegfx::BColor aRGBColor(
720 maBColorModifierStack.getModifiedColor(
721 rTextCandidate.getFontColor()));
723 maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
724 mxCanvas->getDevice(),
725 aRGBColor);
727 // get render parameters and paint
728 mxCanvas->drawTextLayout( xLayout,
729 maViewState,
730 maRenderState );
733 // direct draw of hairline
734 void canvasProcessor::impRender_POHL(const polygonHairlinePrimitive& rPolygonCandidate)
736 const basegfx::BColor aRGBColor(
737 maBColorModifierStack.getModifiedColor(
738 rPolygonCandidate.getBColor()));
740 maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
741 mxCanvas->getDevice(),
742 aRGBColor);
744 mxCanvas->drawPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolygon(
745 mxCanvas->getDevice(),
746 rPolygonCandidate.getB2DPolygon()),
747 maViewState,
748 maRenderState );
751 // direct draw of transformed BitmapEx primitive
752 void canvasProcessor::impRender_BMPR(const bitmapPrimitive& rBitmapCandidate)
754 BitmapEx aBitmapEx(rBitmapCandidate.getBitmapEx());
756 if(maBColorModifierStack.count())
758 // TODO(Q3): Share common bmp modification code with
759 // vclprocessor.cxx
760 Bitmap aChangedBitmap(impModifyBitmap(maBColorModifierStack, aBitmapEx.GetBitmap()));
762 if(aBitmapEx.IsTransparent())
764 if(aBitmapEx.IsAlpha())
765 aBitmapEx = BitmapEx(aChangedBitmap, aBitmapEx.GetAlpha());
766 else
767 aBitmapEx = BitmapEx(aChangedBitmap, aBitmapEx.GetMask());
769 else
770 aBitmapEx = BitmapEx(aChangedBitmap);
773 mxCanvas->drawBitmap(
774 vcl::unotools::xBitmapFromBitmapEx( mxCanvas->getDevice(),
775 aBitmapEx ),
776 maViewState,
777 maRenderState);
780 void canvasProcessor::impRender_PPLB(const polyPolygonBitmapPrimitive& rPolyBitmapCandidate )
782 const fillBitmapAttribute& rFillBmpAttr( rPolyBitmapCandidate.getFillBitmap() );
783 const basegfx::B2DPolyPolygon& rPoly( rPolyBitmapCandidate.getB2DPolyPolygon() );
785 // TODO(Q3): Share common bmp modification code with
786 // vclprocessor.cxx
787 Bitmap aChangedBitmap(
788 impModifyBitmap(maBColorModifierStack,
789 rFillBmpAttr.getBitmap()));
791 rendering::Texture aTexture;
792 const basegfx::B2DVector aBmpSize( rFillBmpAttr.getSize() );
794 const basegfx::B2DRange& rBounds(
795 basegfx::tools::getRange( rPoly ));
797 basegfx::B2DHomMatrix aScale;
798 aScale.scale( aBmpSize.getX() * rBounds.getWidth(),
799 aBmpSize.getY() * rBounds.getHeight() );
801 basegfx::unotools::affineMatrixFromHomMatrix(
802 aTexture.AffineTransform,
803 aScale );
805 aTexture.Alpha = 1.0;
806 aTexture.Bitmap =
807 ::vcl::unotools::xBitmapFromBitmapEx(
808 mxCanvas->getDevice(),
809 aChangedBitmap );
810 aTexture.RepeatModeX = rendering::TexturingMode::REPEAT;
811 aTexture.RepeatModeY = rendering::TexturingMode::REPEAT;
813 uno::Sequence< rendering::Texture > aSeq(1);
814 aSeq[0] = aTexture;
816 mxCanvas->fillTexturedPolyPolygon(
817 basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
818 mxCanvas->getDevice(),
819 rPoly),
820 maViewState,
821 maRenderState,
822 aSeq );
825 // direct draw of gradient
826 void canvasProcessor::impRender_PPLG(const polyPolygonGradientPrimitive& rPolygonCandidate)
828 const fillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient());
829 basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor()));
830 basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor()));
831 basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
833 if(aStartColor == aEndColor)
835 // no gradient at all, draw as polygon
837 maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
838 mxCanvas->getDevice(),
839 aStartColor);
841 mxCanvas->drawPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
842 mxCanvas->getDevice(),
843 aLocalPolyPolygon),
844 maViewState,
845 maRenderState );
847 else
849 // TODO(F3): if rGradient.getSteps() > 0, render
850 // gradient manually!
851 impDrawGradient(
852 aLocalPolyPolygon, rGradient.getStyle(), rGradient.getSteps(),
853 aStartColor, aEndColor, rGradient.getBorder(),
854 -rGradient.getAngle(), rGradient.getOffsetX(), rGradient.getOffsetY(), false);
858 // direct draw of PolyPolygon with color
859 void canvasProcessor::impRender_PPLC(const polyPolygonColorPrimitive& rPolygonCandidate)
861 const basegfx::BColor aRGBColor(
862 maBColorModifierStack.getModifiedColor(
863 rPolygonCandidate.getBColor()));
865 maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
866 mxCanvas->getDevice(),
867 aRGBColor);
869 mxCanvas->fillPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
870 mxCanvas->getDevice(),
871 rPolygonCandidate.getB2DPolyPolygon()),
872 maViewState,
873 maRenderState );
876 // direct draw of MetaFile
877 void canvasProcessor::impRender_META(const metafilePrimitive& rMetaCandidate)
879 // get metafile (copy it)
880 GDIMetaFile aMetaFile;
882 // TODO(Q3): Share common metafile modification code with
883 // vclprocessor.cxx
884 if(maBColorModifierStack.count())
886 const basegfx::BColor aRGBBaseColor(0, 0, 0);
887 const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor));
888 aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor));
890 else
892 aMetaFile = rMetaCandidate.getMetaFile();
895 cppcanvas::BitmapCanvasSharedPtr pCanvas(
896 cppcanvas::VCLFactory::getInstance().createCanvas(
897 uno::Reference<rendering::XBitmapCanvas>(
898 mxCanvas,
899 uno::UNO_QUERY_THROW) ));
900 cppcanvas::RendererSharedPtr pMtfRenderer(
901 cppcanvas::VCLFactory::getInstance().createRenderer(
902 pCanvas,
903 aMetaFile,
904 cppcanvas::Renderer::Parameters() ));
905 if( pMtfRenderer )
907 pCanvas->setTransformation(maWorldToView);
908 pMtfRenderer->setTransformation(rMetaCandidate.getTransform());
909 pMtfRenderer->draw();
913 // mask group. Set mask polygon as clip
914 void canvasProcessor::impRender_MASK(const maskPrimitive& rMaskCandidate)
916 const primitiveVector& rSubList = rMaskCandidate.getPrimitiveVector();
918 if(!rSubList.empty())
920 // TODO(F3): cannot use state-global renderstate, when recursing!
921 maRenderState.Clip =
922 basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
923 mxCanvas->getDevice(),
924 rMaskCandidate.getMask());
926 // paint to it
927 process(rSubList);
929 maRenderState.Clip.clear();
933 // modified color group. Force output to unified color.
934 void canvasProcessor::impRender_MCOL(const modifiedColorPrimitive& rModifiedCandidate)
936 const primitiveVector& rSubList = rModifiedCandidate.getPrimitiveVector();
938 if(!rSubList.empty())
940 maBColorModifierStack.push(rModifiedCandidate.getColorModifier());
941 process(rModifiedCandidate.getPrimitiveVector());
942 maBColorModifierStack.pop();
946 // sub-transparence group. Draw to bitmap device first.
947 void canvasProcessor::impRender_TRPR(const transparencePrimitive& rTransCandidate)
949 const primitiveVector& rSubList = rTransCandidate.getPrimitiveVector();
951 if(!rSubList.empty())
953 basegfx::B2DRange aRange(
954 get2DRangeFromVector(rSubList,
955 getViewInformation()));
956 aRange.transform(maWorldToView);
957 const basegfx::B2I64Tuple& rSize(
958 canvas::tools::spritePixelAreaFromB2DRange(aRange).getRange());
959 uno::Reference< rendering::XCanvas > xBitmap(
960 mxCanvas->getDevice()->createCompatibleAlphaBitmap(
961 css::geometry::IntegerSize2D(rSize.getX(),
962 rSize.getY())),
963 uno::UNO_QUERY_THROW);
965 // remember last worldToView and add pixel offset
966 basegfx::B2DHomMatrix aLastWorldToView(maWorldToView);
967 basegfx::B2DHomMatrix aPixelOffset;
968 aPixelOffset.translate(aRange.getMinX(),
969 aRange.getMinY());
970 setWorldToView(aPixelOffset * maWorldToView);
972 // remember last canvas, set bitmap as target
973 uno::Reference< rendering::XCanvas > xLastCanvas( mxCanvas );
974 mxCanvas = xBitmap;
976 // paint content to it
977 process(rSubList);
979 // TODO(F3): render transparent list to alpha
980 // channel. Note that the OutDev implementation has a
981 // shortcoming, in that nested transparency groups
982 // don't work - alpha is not combined properly.
984 // process(rTransCandidate.getTransparenceList());
986 // back to old OutDev and worldToView
987 mxCanvas = xLastCanvas;
988 setWorldToView(aLastWorldToView);
990 // DUMMY: add alpha modulation value to DeviceColor
991 // TODO(F3): color management
992 canvas::tools::setDeviceColor( maRenderState,
993 1.0, 1.0, 1.0, 0.5 );
994 // finally, draw bitmap
995 mxCanvas->drawBitmapModulated(
996 uno::Reference< rendering::XBitmap >(
997 xBitmap,
998 uno::UNO_QUERY_THROW),
999 maViewState,
1000 maRenderState );
1004 // transform group.
1005 void canvasProcessor::impRender_TRN2(const transformPrimitive& rTransformCandidate)
1007 // remember current transformation
1008 basegfx::B2DHomMatrix aLastWorldToView(maWorldToView);
1010 // create new transformations
1011 setWorldToView(maWorldToView * rTransformCandidate.getTransformation());
1013 // let break down
1014 process(rTransformCandidate.getPrimitiveVector());
1016 // restore transformations
1017 setWorldToView(aLastWorldToView);
1020 // marker
1021 void canvasProcessor::impRender_MARK(const markerPrimitive& rMarkCandidate)
1023 const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rMarkCandidate.getRGBColor()));
1025 canvas::tools::initRenderState(maMarkerRenderState);
1026 maMarkerRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
1027 mxCanvas->getDevice(),
1028 aRGBColor);
1030 // Markers are special objects - their position is
1031 // determined by the view transformation, but their size
1032 // is always the same
1033 const basegfx::B2DPoint aViewPos(maWorldToView * rMarkCandidate.getPosition());
1035 uno::Reference< rendering::XPolyPolygon2D > xMarkerPoly;
1036 uno::Reference< rendering::XPolyPolygon2D > xHighlightMarkerPoly;
1037 switch(rMarkCandidate.getStyle())
1039 default:
1040 case MARKERSTYLE_POINT:
1041 mxCanvas->drawPoint( basegfx::unotools::point2DFromB2DPoint(aViewPos),
1042 maMarkerViewState,
1043 maMarkerRenderState );
1044 return;
1046 case MARKERSTYLE_CROSS:
1047 if( !mxCrossMarkerPoly.is() )
1049 basegfx::B2DPolyPolygon aPoly;
1050 basegfx::tools::importFromSvgD(
1051 aPoly,
1052 rtl::OUString::createFromAscii(
1053 "m-1 0 h2 m0 -1 v2" ));
1054 mxCrossMarkerPoly =
1055 basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1056 mxCanvas->getDevice(),
1057 aPoly );
1059 xMarkerPoly = mxCrossMarkerPoly;
1060 break;
1062 case MARKERSTYLE_GLUEPOINT :
1063 if( !mxGluePointPoly.is() )
1065 basegfx::B2DPolyPolygon aPoly;
1066 basegfx::tools::importFromSvgD(
1067 aPoly,
1068 rtl::OUString::createFromAscii(
1069 "m-2 -3 l5 5 m-3 -2 l5 5 m-3 2 l5 -5 m-2 3 l5 -5" ));
1070 mxGluePointPoly =
1071 basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1072 mxCanvas->getDevice(),
1073 aPoly );
1075 if( !mxGluePointHighlightPoly.is() )
1077 basegfx::B2DPolyPolygon aPoly;
1078 basegfx::tools::importFromSvgD(
1079 aPoly,
1080 rtl::OUString::createFromAscii(
1081 "m-2 -2 l4 4 m-2 2 l4 -4" ));
1082 mxGluePointHighlightPoly =
1083 basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1084 mxCanvas->getDevice(),
1085 aPoly );
1087 xMarkerPoly = mxGluePointPoly;
1088 xHighlightMarkerPoly = mxGluePointHighlightPoly;
1089 break;
1092 basegfx::B2DRange aRange;
1093 rMarkCandidate.getRealtiveViewRange(aRange);
1094 const basegfx::B2DPoint aCenter(aRange.getCenter());
1096 basegfx::B2DHomMatrix aTranslate;
1097 aTranslate.translate(aViewPos.getX()+aCenter.getX(),
1098 aViewPos.getY()+aCenter.getY());
1100 canvas::tools::setRenderStateTransform( maMarkerRenderState,
1101 aTranslate );
1104 mxCanvas->drawPolyPolygon( xMarkerPoly,
1105 maMarkerViewState,
1106 maMarkerRenderState );
1107 if( xHighlightMarkerPoly.is() )
1109 // TODO(F3): color management
1110 canvas::tools::setDeviceColor(maMarkerRenderState,
1111 0.0, 0.0, 1.0, 1.0);
1112 mxCanvas->drawPolyPolygon( xMarkerPoly,
1113 maMarkerViewState,
1114 maMarkerRenderState );
1118 void canvasProcessor::setWorldToView(const basegfx::B2DHomMatrix& rMat)
1120 maWorldToView = rMat;
1121 canvas::tools::setViewStateTransform(maViewState,
1122 maWorldToView);
1125 //////////////////////////////////////////////////////////////////////////////
1126 // internal processing support
1128 void canvasProcessor::process(const primitiveVector& rSource)
1130 primitiveVector::const_iterator aCurr = rSource.begin();
1131 const primitiveVector::const_iterator aEnd = rSource.end();
1132 while( aCurr != aEnd )
1134 const referencedPrimitive& rCandidate = *aCurr;
1136 switch(rCandidate.getID())
1138 case CreatePrimitiveID('S', 'T', 'X', 'P'):
1140 // directdraw of text simple portion
1141 impRender_STXP(static_cast< const textSimplePortionPrimitive& >(rCandidate.getBasePrimitive()));
1142 break;
1145 case CreatePrimitiveID('P', 'O', 'H', 'L'):
1147 // direct draw of hairline
1148 impRender_POHL(static_cast< const polygonHairlinePrimitive& >(rCandidate.getBasePrimitive()));
1149 break;
1152 case CreatePrimitiveID('B', 'M', 'P', 'R'):
1154 // direct draw of transformed BitmapEx primitive
1155 impRender_BMPR(static_cast< const bitmapPrimitive& >(rCandidate.getBasePrimitive()));
1156 break;
1159 case CreatePrimitiveID('F', 'B', 'M', 'P'):
1161 OSL_ENSURE(false,"fillBitmapPrimitive not yet implemented");
1162 break;
1165 case CreatePrimitiveID('P', 'P', 'L', 'B'):
1167 // direct draw of polygon with bitmap fill
1168 impRender_PPLB(static_cast< const polyPolygonBitmapPrimitive& >(rCandidate.getBasePrimitive()));
1169 break;
1172 case CreatePrimitiveID('P', 'P', 'L', 'G'):
1174 // direct draw of gradient
1175 impRender_PPLG(static_cast< const polyPolygonGradientPrimitive& >(rCandidate.getBasePrimitive()));
1176 break;
1179 case CreatePrimitiveID('P', 'P', 'L', 'C'):
1181 // direct draw of PolyPolygon with color
1182 impRender_PPLC(static_cast< const polyPolygonColorPrimitive& >(rCandidate.getBasePrimitive()));
1183 break;
1186 case CreatePrimitiveID('M', 'E', 'T', 'A'):
1188 // direct draw of MetaFile
1189 impRender_META(static_cast< const metafilePrimitive& >(rCandidate.getBasePrimitive()));
1190 break;
1193 case CreatePrimitiveID('M', 'A', 'S', 'K'):
1195 // mask group. Force output to VDev and create mask from given mask
1196 impRender_MASK(static_cast< const maskPrimitive& >(rCandidate.getBasePrimitive()));
1197 break;
1200 case CreatePrimitiveID('M', 'C', 'O', 'L'):
1202 // modified color group. Force output to unified color.
1203 impRender_MCOL(static_cast< const modifiedColorPrimitive& >(rCandidate.getBasePrimitive()));
1204 break;
1207 case CreatePrimitiveID('T', 'R', 'P', 'R'):
1209 // sub-transparence group. Draw to VDev first.
1210 impRender_TRPR(static_cast< const transparencePrimitive& >(rCandidate.getBasePrimitive()));
1211 break;
1214 case CreatePrimitiveID('T', 'R', 'N', '2'):
1216 // transform group.
1217 impRender_TRN2(static_cast< const transformPrimitive& >(rCandidate.getBasePrimitive()));
1218 break;
1221 case CreatePrimitiveID('M', 'A', 'R', 'K'):
1223 // marker
1224 impRender_MARK(static_cast< const markerPrimitive& >(rCandidate.getBasePrimitive()));
1225 break;
1228 case CreatePrimitiveID('A', 'N', 'S', 'W'):
1229 case CreatePrimitiveID('A', 'N', 'B', 'L'):
1230 case CreatePrimitiveID('A', 'N', 'I', 'N'):
1232 // check timing, but do not accept
1233 const animatedSwitchPrimitive& rAnimatedCandidate(static_cast< const animatedSwitchPrimitive& >(rCandidate.getBasePrimitive()));
1234 const ::drawinglayer::animation::animationEntryList& rAnimationList = rAnimatedCandidate.getAnimationList();
1235 const double fNewTime(rAnimationList.getNextEventTime(getViewInformation().getViewTime()));
1237 // let break down
1238 process(rAnimatedCandidate.getDecomposition(getViewInformation()));
1240 break;
1243 default:
1245 // let break down
1246 process(rCandidate.getBasePrimitive().getDecomposition(getViewInformation()));
1250 ++aCurr;
1254 canvasProcessor::canvasProcessor( const ::drawinglayer::geometry::viewInformation& rViewInformation,
1255 const uno::Reference<rendering::XCanvas>& rCanvas ) :
1256 processor(rViewInformation),
1257 mxCanvas( rCanvas ),
1258 mxCrossMarkerPoly(),
1259 mxGluePointPoly(),
1260 mxGluePointHighlightPoly(),
1261 maBColorModifierStack(),
1262 maWorldToView(),
1263 maViewState(),
1264 maRenderState(),
1265 maMarkerViewState(),
1266 maMarkerRenderState()
1268 canvas::tools::initViewState(maViewState);
1269 canvas::tools::initRenderState(maRenderState);
1270 canvas::tools::initViewState(maMarkerViewState);
1271 canvas::tools::initRenderState(maMarkerRenderState);
1273 maWorldToView = maViewInformation.getViewTransformation();
1275 canvas::tools::setViewStateTransform(maViewState,
1276 maWorldToView);
1279 canvasProcessor::~canvasProcessor()
1282 //////////////////////////////////////////////////////////////////////////////
1284 namespace drawinglayer
1286 namespace processor2d
1288 //////////////////////////////////////////////////////////////////////////////
1289 // single primitive renderers
1291 void canvasProcessor2D::impRenderMaskPrimitive2D(const primitive2d::MaskPrimitive2D& rMaskCandidate)
1293 const primitive2d::Primitive2DSequence& rChildren = rMaskCandidate.getChildren();
1294 static bool bUseMaskBitmapMethod(true);
1296 if(rChildren.hasElements())
1298 basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
1300 if(!aMask.count())
1302 // no mask, no clipping. recursively paint content
1303 process(rChildren);
1305 else
1307 // there are principally two methods for implementing the mask primitive. One
1308 // is to set a clip polygon at the canvas, the other is to create and use a
1309 // alpha-using XBitmap for content and draw the mask as alpha. Both have their
1310 // advantages and disadvantages, so here are both with a bool allowing simple
1311 // change
1312 if(bUseMaskBitmapMethod)
1314 // get logic range of transparent part, clip with ViewRange
1315 basegfx::B2DRange aLogicRange(aMask.getB2DRange());
1317 if(!getViewInformation2D().getViewport().isEmpty())
1319 aLogicRange.intersect(getViewInformation2D().getViewport());
1322 if(!aLogicRange.isEmpty())
1324 // get discrete range of transparent part
1325 basegfx::B2DRange aDiscreteRange(aLogicRange);
1326 aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
1328 // expand to next covering discrete values (pixel bounds)
1329 aDiscreteRange.expand(basegfx::B2DTuple(floor(aDiscreteRange.getMinX()), floor(aDiscreteRange.getMinY())));
1330 aDiscreteRange.expand(basegfx::B2DTuple(ceil(aDiscreteRange.getMaxX()), ceil(aDiscreteRange.getMaxY())));
1332 // use VCL-based buffer device
1333 impBufferDevice aBufferDevice(*mpOutputDevice, aDiscreteRange, false);
1335 if(aBufferDevice.isVisible())
1337 // remember current OutDev, Canvas and ViewInformation
1338 OutputDevice* pLastOutputDevice = mpOutputDevice;
1339 uno::Reference< rendering::XCanvas > xLastCanvas(mxCanvas);
1340 const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
1342 // prepare discrete offset for XBitmap, do not forget that the buffer bitmap
1343 // may be truncated to discrete visible pixels
1344 basegfx::B2DHomMatrix aDiscreteOffset;
1345 aDiscreteOffset.translate(
1346 aDiscreteRange.getMinX() > 0.0 ? -aDiscreteRange.getMinX() : 0.0,
1347 aDiscreteRange.getMinY() > 0.0 ? -aDiscreteRange.getMinY() : 0.0);
1349 // create new local ViewInformation2D with new transformation
1350 const geometry::ViewInformation2D aViewInformation2D(
1351 getViewInformation2D().getObjectTransformation(),
1352 aDiscreteOffset * getViewInformation2D().getViewTransformation(),
1353 getViewInformation2D().getViewport(),
1354 getViewInformation2D().getVisualizedPage(),
1355 getViewInformation2D().getViewTime(),
1356 getViewInformation2D().getExtendedInformationSequence());
1357 updateViewInformation(aViewInformation2D);
1359 // set OutDev and Canvas to content target
1360 mpOutputDevice = &aBufferDevice.getContent();
1361 mxCanvas = mpOutputDevice->GetCanvas();
1362 canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
1364 // if ViewState transform is changed, the clipping polygon needs to be adapted, too
1365 const basegfx::B2DPolyPolygon aOldClipPolyPolygon(maClipPolyPolygon);
1367 if(maClipPolyPolygon.count())
1369 maClipPolyPolygon.transform(aDiscreteOffset);
1370 maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
1373 // paint content
1374 process(rChildren);
1376 // draw mask
1377 const basegfx::BColor aBlack(0.0, 0.0, 0.0);
1378 maRenderState.DeviceColor = aBlack.colorToDoubleSequence(mxCanvas->getDevice());
1380 if(getOptionsDrawinglayer().IsAntiAliasing())
1382 // with AA, use 8bit AlphaMask to get nice borders
1383 VirtualDevice& rAlpha = aBufferDevice.getAlpha();
1384 rAlpha.GetCanvas()->fillPolyPolygon(
1385 basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), aMask),
1386 maViewState, maRenderState);
1388 else
1390 // No AA, use 1bit mask
1391 VirtualDevice& rMask = aBufferDevice.getMask();
1392 rMask.GetCanvas()->fillPolyPolygon(
1393 basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), aMask),
1394 maViewState, maRenderState);
1397 // back to old color stack, OutDev, Canvas and ViewTransform
1398 mpOutputDevice = pLastOutputDevice;
1399 mxCanvas = xLastCanvas;
1400 updateViewInformation(aLastViewInformation2D);
1401 canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
1403 // restore clipping polygon
1404 maClipPolyPolygon = aOldClipPolyPolygon;
1406 if(maClipPolyPolygon.count())
1408 maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
1411 // dump buffer to outdev
1412 aBufferDevice.paint();
1416 else
1418 // transform new mask polygon to view coordinates for processing. All masks
1419 // are processed in view coordinates and clipped against each other evtl. to
1420 // create multi-clips
1421 aMask.transform(getViewInformation2D().getObjectTransformation());
1423 // remember last current clip polygon
1424 const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon);
1426 if(maClipPolyPolygon.count())
1428 // there is already a clip polygon set; build clipped union of
1429 // current mask polygon and new one
1430 maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(aMask, maClipPolyPolygon, false, false);
1432 else
1434 // use mask directly
1435 maClipPolyPolygon = aMask;
1438 // set at ViewState
1439 if(maClipPolyPolygon.count())
1441 // set new as clip polygon
1442 maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
1444 else
1446 // empty, reset
1447 maViewState.Clip.clear();
1450 // paint content
1451 process(rChildren);
1453 // restore local current to rescued clip polygon
1454 maClipPolyPolygon = aLastClipPolyPolygon;
1456 // set at ViewState
1457 if(maClipPolyPolygon.count())
1459 // set new as clip polygon
1460 maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
1462 else
1464 // empty, reset
1465 maViewState.Clip.clear();
1472 void canvasProcessor2D::impRenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D& rMetaCandidate)
1474 GDIMetaFile aMetaFile;
1476 if(maBColorModifierStack.count())
1478 const basegfx::BColor aRGBBaseColor(0, 0, 0);
1479 const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor));
1480 aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor));
1482 else
1484 aMetaFile = rMetaCandidate.getMetaFile();
1487 cppcanvas::BitmapCanvasSharedPtr pCanvas(cppcanvas::VCLFactory::getInstance().createCanvas(
1488 uno::Reference<rendering::XBitmapCanvas>(mxCanvas, uno::UNO_QUERY_THROW)));
1489 cppcanvas::RendererSharedPtr pMtfRenderer(cppcanvas::VCLFactory::getInstance().createRenderer(
1490 pCanvas, aMetaFile, cppcanvas::Renderer::Parameters()));
1492 if(pMtfRenderer)
1494 pCanvas->setTransformation(getViewInformation2D().getObjectToViewTransformation());
1495 pMtfRenderer->setTransformation(rMetaCandidate.getTransform());
1496 pMtfRenderer->draw();
1500 void canvasProcessor2D::impRenderTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate)
1502 if(rTextCandidate.getTextLength())
1504 double fShearX(0.0);
1506 const basegfx::B2DHomMatrix aLocalTransform(getViewInformation2D().getObjectToViewTransformation() * rTextCandidate.getTextTransform());
1507 basegfx::B2DVector aScale, aTranslate;
1508 double fRotate;
1509 aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
1512 if(!basegfx::fTools::equalZero(fShearX))
1514 // text is sheared. As long as the canvas renderers do not support this,
1515 // use the decomposed primitive
1516 process(rTextCandidate.get2DDecomposition(getViewInformation2D()));
1518 else
1520 const primitive2d::FontAttributes& rFontAttrs(rTextCandidate.getFontAttributes());
1521 rendering::FontRequest aFontRequest;
1523 aFontRequest.FontDescription.FamilyName = rFontAttrs.getFamilyName();
1524 aFontRequest.FontDescription.StyleName = rFontAttrs.getStyleName();
1525 aFontRequest.FontDescription.IsSymbolFont = rFontAttrs.getSymbol() ? util::TriState_YES : util::TriState_NO;
1526 aFontRequest.FontDescription.IsVertical = rFontAttrs.getVertical() ? util::TriState_YES : util::TriState_NO;
1527 // TODO(F2): improve vclenum->panose conversion
1528 aFontRequest.FontDescription.FontDescription.Weight = static_cast< sal_uInt8 >(rFontAttrs.getWeight());
1529 aFontRequest.FontDescription.FontDescription.Letterform = rFontAttrs.getItalic() ? 9 : 0;
1531 // init CellSize to 1.0, else a default font height will be used
1532 aFontRequest.CellSize = 1.0;
1533 aFontRequest.Locale = rTextCandidate.getLocale();
1535 // font matrix should only be used for glyph rotations etc.
1536 com::sun::star::geometry::Matrix2D aFontMatrix;
1537 canvas::tools::setIdentityMatrix2D(aFontMatrix);
1539 uno::Reference<rendering::XCanvasFont> xFont(mxCanvas->createFont(
1540 aFontRequest, uno::Sequence< beans::PropertyValue >(), aFontMatrix));
1542 if(xFont.is())
1544 // got a font, now try to get a TextLayout
1545 const rendering::StringContext aStringContext(
1546 rTextCandidate.getText(), rTextCandidate.getTextPosition(), rTextCandidate.getTextLength());
1547 uno::Reference<rendering::XTextLayout> xLayout(xFont->createTextLayout(
1548 aStringContext, com::sun::star::rendering::TextDirection::WEAK_LEFT_TO_RIGHT, 0));
1550 if(xLayout.is())
1552 // got a text layout, apply DXArray if given
1553 const ::std::vector< double >& rDXArray = rTextCandidate.getDXArray();
1554 const sal_uInt32 nDXCount(rDXArray.size());
1556 if(nDXCount)
1558 // DXArray does not need to be adapted to getTextPosition/getTextLength,
1559 // it is already provided correctly
1560 const uno::Sequence< double > aDXSequence(&rDXArray[0], nDXCount);
1561 xLayout->applyLogicalAdvancements(aDXSequence);
1564 // set text color
1565 const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rTextCandidate.getFontColor()));
1566 maRenderState.DeviceColor = aRGBColor.colorToDoubleSequence(mxCanvas->getDevice());
1568 // set text transformation
1569 canvas::tools::setRenderStateTransform(maRenderState,
1570 getViewInformation2D().getObjectTransformation() * rTextCandidate.getTextTransform());
1572 // paint
1573 mxCanvas->drawTextLayout(xLayout, maViewState, maRenderState);
1580 void canvasProcessor2D::impRenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate)
1582 // apply possible color modification to BitmapEx
1583 BitmapEx aModifiedBitmapEx(impModifyBitmapEx(maBColorModifierStack, rBitmapCandidate.getBitmapEx()));
1585 if(aModifiedBitmapEx.IsEmpty())
1587 // replace with color filled polygon
1588 const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor()));
1589 const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0)));
1591 maRenderState.DeviceColor = aModifiedColor.colorToDoubleSequence(mxCanvas->getDevice());
1592 canvas::tools::setRenderStateTransform(maRenderState,
1593 getViewInformation2D().getObjectTransformation() * rBitmapCandidate.getTransform());
1595 mxCanvas->fillPolyPolygon(basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1596 mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aPolygon)), maViewState, maRenderState);
1598 else
1600 // adapt object's transformation to the correct scale
1601 basegfx::B2DVector aScale, aTranslate;
1602 double fRotate, fShearX;
1603 basegfx::B2DHomMatrix aNewMatrix;
1604 const Size aSizePixel(aModifiedBitmapEx.GetSizePixel());
1606 if(0 != aSizePixel.Width() && 0 != aSizePixel.Height())
1608 rBitmapCandidate.getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
1609 aNewMatrix.scale(aScale.getX() / aSizePixel.Width(), aScale.getY() / aSizePixel.Height());
1610 aNewMatrix.shearX(fShearX);
1611 aNewMatrix.rotate(fRotate);
1612 aNewMatrix.translate(aTranslate.getX(), aTranslate.getY());
1614 canvas::tools::setRenderStateTransform(maRenderState,
1615 getViewInformation2D().getObjectTransformation() * aNewMatrix);
1617 mxCanvas->drawBitmap(
1618 vcl::unotools::xBitmapFromBitmapEx(mxCanvas->getDevice(), aModifiedBitmapEx),
1619 maViewState, maRenderState);
1624 void canvasProcessor2D::impRenderAlphaPrimitive2D(const primitive2d::AlphaPrimitive2D& rAlphaCandidate)
1626 const primitive2d::Primitive2DSequence& rChildren = rAlphaCandidate.getChildren();
1627 const primitive2d::Primitive2DSequence& rAlpha = rAlphaCandidate.getAlpha();
1629 if(rChildren.hasElements() && rAlpha.hasElements())
1631 // get logic range of transparent part and clip with ViewRange
1632 basegfx::B2DRange aLogicRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rChildren, getViewInformation2D()));
1634 if(!getViewInformation2D().getViewport().isEmpty())
1636 aLogicRange.intersect(getViewInformation2D().getViewport());
1639 if(!aLogicRange.isEmpty())
1641 // get discrete range of transparent part
1642 basegfx::B2DRange aDiscreteRange(aLogicRange);
1643 aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
1645 // expand to next covering discrete values (pixel bounds)
1646 aDiscreteRange.expand(basegfx::B2DTuple(floor(aDiscreteRange.getMinX()), floor(aDiscreteRange.getMinY())));
1647 aDiscreteRange.expand(basegfx::B2DTuple(ceil(aDiscreteRange.getMaxX()), ceil(aDiscreteRange.getMaxY())));
1649 // use VCL-based buffer device
1650 impBufferDevice aBufferDevice(*mpOutputDevice, aDiscreteRange, false);
1652 if(aBufferDevice.isVisible())
1654 // remember current OutDev, Canvas and ViewInformation
1655 OutputDevice* pLastOutputDevice = mpOutputDevice;
1656 uno::Reference< rendering::XCanvas > xLastCanvas(mxCanvas);
1657 const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
1659 // prepare discrete offset for XBitmap, do not forget that the buffer bitmap
1660 // may be truncated to discrete visible pixels
1661 basegfx::B2DHomMatrix aDiscreteOffset;
1662 aDiscreteOffset.translate(
1663 aDiscreteRange.getMinX() > 0.0 ? -aDiscreteRange.getMinX() : 0.0,
1664 aDiscreteRange.getMinY() > 0.0 ? -aDiscreteRange.getMinY() : 0.0);
1666 // create new local ViewInformation2D with new transformation
1667 const geometry::ViewInformation2D aViewInformation2D(
1668 getViewInformation2D().getObjectTransformation(),
1669 aDiscreteOffset * getViewInformation2D().getViewTransformation(),
1670 getViewInformation2D().getViewport(),
1671 getViewInformation2D().getVisualizedPage(),
1672 getViewInformation2D().getViewTime(),
1673 getViewInformation2D().getExtendedInformationSequence());
1674 updateViewInformation(aViewInformation2D);
1676 // set OutDev and Canvas to content target
1677 mpOutputDevice = &aBufferDevice.getContent();
1678 mxCanvas = mpOutputDevice->GetCanvas();
1679 canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
1681 // if ViewState transform is changed, the clipping polygon needs to be adapted, too
1682 const basegfx::B2DPolyPolygon aOldClipPolyPolygon(maClipPolyPolygon);
1684 if(maClipPolyPolygon.count())
1686 maClipPolyPolygon.transform(aDiscreteOffset);
1687 maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
1690 // paint content
1691 process(rChildren);
1693 // set to mask
1694 mpOutputDevice = &aBufferDevice.getAlpha();
1695 mxCanvas = mpOutputDevice->GetCanvas();
1696 canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
1698 // when painting alpha masks, reset the color stack
1699 basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack);
1700 maBColorModifierStack = basegfx::BColorModifierStack();
1702 // paint mask to it (always with alpha intensities, evtl. with AA)
1703 process(rAlpha);
1705 // back to old color stack, OutDev, Canvas and ViewTransform
1706 maBColorModifierStack = aLastBColorModifierStack;
1707 mpOutputDevice = pLastOutputDevice;
1708 mxCanvas = xLastCanvas;
1709 updateViewInformation(aLastViewInformation2D);
1710 canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
1712 // restore clipping polygon
1713 maClipPolyPolygon = aOldClipPolyPolygon;
1715 if(maClipPolyPolygon.count())
1717 maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
1720 // dump buffer to outdev
1721 aBufferDevice.paint();
1727 void canvasProcessor2D::impRenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive)
1729 // support direct fat line geometry. This moves the decomposition to the canvas.
1730 // As long as our canvases are used (which also use basegfx tooling) this makes
1731 // no difference, but potentially canvases may better support this
1732 static bool bSupportFatLineDirectly(true);
1733 bool bOutputDone(false);
1735 if(bSupportFatLineDirectly)
1737 const attribute::LineAttribute& rLineAttribute = rPolygonStrokePrimitive.getLineAttribute();
1738 const attribute::StrokeAttribute& rStrokeAttribute = rPolygonStrokePrimitive.getStrokeAttribute();
1740 if(0.0 < rLineAttribute.getWidth() || 0 != rStrokeAttribute.getDotDashArray().size())
1742 rendering::StrokeAttributes aStrokeAttribute;
1744 aStrokeAttribute.StrokeWidth = rLineAttribute.getWidth();
1745 aStrokeAttribute.MiterLimit = 15.0; // degrees; maybe here (15.0 * F_PI180) is needed, not clear in the documentation
1746 const ::std::vector< double >& rDotDashArray = rStrokeAttribute.getDotDashArray();
1748 if(rDotDashArray.size())
1750 aStrokeAttribute.DashArray = uno::Sequence< double >(&rDotDashArray[0], rDotDashArray.size());
1753 switch(rLineAttribute.getLineJoin())
1755 default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE
1756 aStrokeAttribute.JoinType = rendering::PathJoinType::NONE;
1757 break;
1758 case basegfx::B2DLINEJOIN_BEVEL:
1759 aStrokeAttribute.JoinType = rendering::PathJoinType::BEVEL;
1760 break;
1761 case basegfx::B2DLINEJOIN_MITER:
1762 aStrokeAttribute.JoinType = rendering::PathJoinType::MITER;
1763 break;
1764 case basegfx::B2DLINEJOIN_ROUND:
1765 aStrokeAttribute.JoinType = rendering::PathJoinType::ROUND;
1766 break;
1769 const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor()));
1770 maRenderState.DeviceColor = aHairlineColor.colorToDoubleSequence(mxCanvas->getDevice());
1771 canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
1773 mxCanvas->strokePolyPolygon(
1774 basegfx::unotools::xPolyPolygonFromB2DPolygon(mxCanvas->getDevice(), rPolygonStrokePrimitive.getB2DPolygon()),
1775 maViewState, maRenderState, aStrokeAttribute);
1777 bOutputDone = true;
1781 if(!bOutputDone)
1783 // process decomposition
1784 process(rPolygonStrokePrimitive.get2DDecomposition(getViewInformation2D()));
1788 void canvasProcessor2D::impRenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapPrimitive2D)
1790 // support tiled fills directly when tiling is on
1791 static bool bSupportFillBitmapDirectly(true);
1792 bool bOutputDone(false);
1794 if(bSupportFillBitmapDirectly)
1796 const attribute::FillBitmapAttribute& rFillBitmapAttribute = rFillBitmapPrimitive2D.getFillBitmap();
1798 if(rFillBitmapAttribute.getTiling())
1800 // apply possible color modification to Bitmap
1801 const BitmapEx aChangedBitmapEx(impModifyBitmapEx(maBColorModifierStack, BitmapEx(rFillBitmapAttribute.getBitmap())));
1803 if(aChangedBitmapEx.IsEmpty())
1805 // replace with color filled polygon
1806 const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor()));
1807 const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0)));
1809 maRenderState.DeviceColor = aModifiedColor.colorToDoubleSequence(mxCanvas->getDevice());
1810 canvas::tools::setRenderStateTransform(maRenderState,
1811 getViewInformation2D().getObjectTransformation() * rFillBitmapPrimitive2D.getTransformation());
1813 mxCanvas->fillPolyPolygon(basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1814 mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aPolygon)), maViewState, maRenderState);
1816 else
1818 const Size aSizePixel(aChangedBitmapEx.GetSizePixel());
1820 if(0 != aSizePixel.Width() && 0 != aSizePixel.Height())
1822 // create texture matrix from texture to object (where object is unit square here),
1823 // so use values directly
1824 basegfx::B2DHomMatrix aTextureMatrix;
1825 aTextureMatrix.scale(
1826 rFillBitmapAttribute.getSize().getX(),
1827 rFillBitmapAttribute.getSize().getY());
1828 aTextureMatrix.translate(
1829 rFillBitmapAttribute.getTopLeft().getX(),
1830 rFillBitmapAttribute.getTopLeft().getY());
1832 // create and fill texture
1833 rendering::Texture aTexture;
1835 basegfx::unotools::affineMatrixFromHomMatrix(aTexture.AffineTransform, aTextureMatrix);
1836 aTexture.Alpha = 1.0;
1837 aTexture.Bitmap = vcl::unotools::xBitmapFromBitmapEx(mxCanvas->getDevice(), aChangedBitmapEx);
1838 aTexture.RepeatModeX = rendering::TexturingMode::REPEAT;
1839 aTexture.RepeatModeY = rendering::TexturingMode::REPEAT;
1841 // canvas needs a polygon to fill, create unit rectangle polygon
1842 const basegfx::B2DPolygon aOutlineRectangle(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0)));
1844 // set primitive's transformation as render state transform
1845 canvas::tools::setRenderStateTransform(maRenderState,
1846 getViewInformation2D().getObjectTransformation() * rFillBitmapPrimitive2D.getTransformation());
1848 // put texture into a uno sequence for handover
1849 uno::Sequence< rendering::Texture > aSeq(1);
1850 aSeq[0] = aTexture;
1852 // draw textured rectangle
1853 mxCanvas->fillTexturedPolyPolygon(
1854 basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aOutlineRectangle)),
1855 maViewState, maRenderState, aSeq);
1859 bOutputDone = true;
1863 if(!bOutputDone)
1865 // process decomposition
1866 process(rFillBitmapPrimitive2D.get2DDecomposition(getViewInformation2D()));
1870 void canvasProcessor2D::impRenderUnifiedAlphaPrimitive2D(const primitive2d::UnifiedAlphaPrimitive2D& rUniAlphaCandidate)
1872 const primitive2d::Primitive2DSequence rChildren = rUniAlphaCandidate.getChildren();
1874 if(rChildren.hasElements())
1876 bool bOutputDone(false);
1878 // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case,
1879 // use the fillPolyPolygon method with correctly set alpha. This is a often used
1880 // case, so detectiong it is valuable
1881 if(1 == rChildren.getLength())
1883 const primitive2d::Primitive2DReference xReference(rChildren[0]);
1884 const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get());
1886 if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitiveID())
1888 // direct draw of PolyPolygon with color and transparence
1889 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor()));
1891 // add alpha modulation value to DeviceColor
1892 uno::Sequence< double > aColor(4);
1894 aColor[0] = aPolygonColor.getRed();
1895 aColor[1] = aPolygonColor.getGreen();
1896 aColor[2] = aPolygonColor.getBlue();
1897 aColor[3] = 1.0 - rUniAlphaCandidate.getAlpha();
1898 maRenderState.DeviceColor = aColor;
1900 canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
1901 mxCanvas->fillPolyPolygon(
1902 basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), pPoPoColor->getB2DPolyPolygon()),
1903 maViewState, maRenderState);
1904 bOutputDone = true;
1908 if(!bOutputDone)
1910 // process decomposition. This will be decomposed to an AlphaPrimitive2D
1911 // with the same child context and a single polygon for alpha context. This could be
1912 // directly handled here with known VCL-buffer technology, but would only
1913 // make a small difference compared to directly rendering the AlphaPrimitive2D
1914 // using impRenderAlphaPrimitive2D above.
1915 process(rUniAlphaCandidate.get2DDecomposition(getViewInformation2D()));
1920 //////////////////////////////////////////////////////////////////////////////
1921 // internal processing support
1923 void canvasProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
1925 switch(rCandidate.getPrimitiveID())
1927 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
1929 // direct draw of hairline
1930 const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate);
1931 const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
1933 maRenderState.DeviceColor = aHairlineColor.colorToDoubleSequence(mxCanvas->getDevice());
1934 canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
1935 mxCanvas->drawPolyPolygon(
1936 basegfx::unotools::xPolyPolygonFromB2DPolygon(mxCanvas->getDevice(), rPolygonCandidate.getB2DPolygon()),
1937 maViewState, maRenderState);
1939 break;
1941 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
1943 // direct draw of PolyPolygon with color
1944 const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate = static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate);
1945 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
1947 maRenderState.DeviceColor = aPolygonColor.colorToDoubleSequence(mxCanvas->getDevice());
1948 canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
1949 mxCanvas->fillPolyPolygon(
1950 basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), rPolygonCandidate.getB2DPolyPolygon()),
1951 maViewState, maRenderState);
1953 break;
1955 case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
1957 // modified color group. Force output to unified color.
1958 const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate = static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate);
1960 if(rModifiedCandidate.getChildren().hasElements())
1962 maBColorModifierStack.push(rModifiedCandidate.getColorModifier());
1963 process(rModifiedCandidate.getChildren());
1964 maBColorModifierStack.pop();
1967 break;
1969 case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
1971 // mask group
1972 impRenderMaskPrimitive2D(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate));
1974 break;
1976 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
1978 // transform group. Remember current ViewInformation2D
1979 const primitive2d::TransformPrimitive2D& rTransformCandidate = static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate);
1980 const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
1982 // create new local ViewInformation2D with new transformation
1983 const geometry::ViewInformation2D aViewInformation2D(
1984 getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(),
1985 getViewInformation2D().getViewTransformation(),
1986 getViewInformation2D().getViewport(),
1987 getViewInformation2D().getVisualizedPage(),
1988 getViewInformation2D().getViewTime(),
1989 getViewInformation2D().getExtendedInformationSequence());
1990 updateViewInformation(aViewInformation2D);
1992 // set at canvas
1993 canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
1995 // proccess content
1996 process(rTransformCandidate.getChildren());
1998 // restore transformations
1999 updateViewInformation(aLastViewInformation2D);
2001 // restore at canvas
2002 canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
2004 break;
2006 case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
2008 // new XDrawPage for ViewInformation2D
2009 const primitive2d::PagePreviewPrimitive2D& rPagePreviewCandidate = static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate);
2011 // remember current transformation and ViewInformation
2012 const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
2014 // create new local ViewInformation2D
2015 const geometry::ViewInformation2D aViewInformation2D(
2016 getViewInformation2D().getObjectTransformation(),
2017 getViewInformation2D().getViewTransformation(),
2018 getViewInformation2D().getViewport(),
2019 rPagePreviewCandidate.getXDrawPage(),
2020 getViewInformation2D().getViewTime(),
2021 getViewInformation2D().getExtendedInformationSequence());
2022 updateViewInformation(aViewInformation2D);
2024 // proccess decomposed content
2025 process(rPagePreviewCandidate.get2DDecomposition(getViewInformation2D()));
2027 // restore transformations
2028 updateViewInformation(aLastViewInformation2D);
2029 break;
2031 case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
2033 // MetaFile primitive
2034 impRenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate));
2036 break;
2038 case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
2040 // PointArray primitive
2041 const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate = static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate);
2043 // set point color
2044 const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor()));
2045 maRenderState.DeviceColor = aRGBColor.colorToDoubleSequence(mxCanvas->getDevice());
2046 canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
2048 const std::vector< basegfx::B2DPoint >& rPointVector = rPointArrayCandidate.getPositions();
2049 const sal_uInt32 nPointCount(rPointVector.size());
2051 for(sal_uInt32 a(0); a < nPointCount; a++)
2053 const basegfx::B2DPoint& rPoint = rPointVector[a];
2054 mxCanvas->drawPoint(basegfx::unotools::point2DFromB2DPoint(rPoint), maViewState, maRenderState);
2057 break;
2059 case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
2061 // TextSimplePortion primitive
2062 impRenderTextSimplePortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate));
2064 break;
2066 case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
2068 // Bitmap primitive
2069 impRenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
2071 break;
2073 case PRIMITIVE2D_ID_ALPHAPRIMITIVE2D :
2075 // Alpha primitive
2076 impRenderAlphaPrimitive2D(static_cast< const primitive2d::AlphaPrimitive2D& >(rCandidate));
2078 break;
2080 case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
2082 // PolygonStrokePrimitive
2083 impRenderPolygonStrokePrimitive2D(static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate));
2085 break;
2087 case PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D :
2089 // FillBitmapPrimitive2D
2090 impRenderFillBitmapPrimitive2D(static_cast< const primitive2d::FillBitmapPrimitive2D& >(rCandidate));
2092 break;
2094 case PRIMITIVE2D_ID_UNIFIEDALPHAPRIMITIVE2D :
2096 // UnifiedAlphaPrimitive2D
2097 impRenderUnifiedAlphaPrimitive2D(static_cast< const primitive2d::UnifiedAlphaPrimitive2D& >(rCandidate));
2099 break;
2101 case PRIMITIVE2D_ID_CHARTPRIMITIVE2D :
2103 // chart primitive in canvas renderer; restore original DrawMode during call
2104 // since the evtl. used ChartPrettyPainter will use the MapMode
2105 const primitive2d::ChartPrimitive2D& rChartPrimitive = static_cast< const primitive2d::ChartPrimitive2D& >(rCandidate);
2106 mpOutputDevice->Push(PUSH_MAPMODE);
2107 mpOutputDevice->SetMapMode(maOriginalMapMode);
2109 if(!renderChartPrimitive2D(
2110 rChartPrimitive,
2111 *mpOutputDevice,
2112 getViewInformation2D()))
2114 // fallback to decomposition (MetaFile)
2115 process(rChartPrimitive.get2DDecomposition(getViewInformation2D()));
2118 mpOutputDevice->Pop();
2119 break;
2121 case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
2123 // wrong spell primitive. Handled directly here using VCL since VCL has a nice and
2124 // very direct waveline painting which is needed for this. If VCL is to be avoided,
2125 // this can be removed anytime and the decomposition may be used
2126 const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive = static_cast< const primitive2d::WrongSpellPrimitive2D& >(rCandidate);
2128 if(!renderWrongSpellPrimitive2D(
2129 rWrongSpellPrimitive,
2130 *mpOutputDevice,
2131 getViewInformation2D().getObjectToViewTransformation(),
2132 maBColorModifierStack))
2134 // fallback to decomposition (MetaFile)
2135 process(rWrongSpellPrimitive.get2DDecomposition(getViewInformation2D()));
2138 break;
2141 // nice to have:
2143 // case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
2144 // - support FormControls more direct eventually, not sure if this is needed
2145 // with the canvas renderer. The decomposition provides a bitmap representation
2146 // of the control which will work
2149 default :
2151 // process recursively
2152 process(rCandidate.get2DDecomposition(getViewInformation2D()));
2154 break;
2159 //////////////////////////////////////////////////////////////////////////////
2160 // process support
2162 canvasProcessor2D::canvasProcessor2D(
2163 const geometry::ViewInformation2D& rViewInformation,
2164 OutputDevice& rOutDev)
2165 : BaseProcessor2D(rViewInformation),
2166 maOriginalMapMode(rOutDev.GetMapMode()),
2167 mpOutputDevice(&rOutDev),
2168 mxCanvas(rOutDev.GetCanvas()),
2169 maViewState(),
2170 maRenderState(),
2171 maBColorModifierStack(),
2172 maDrawinglayerOpt(),
2173 maClipPolyPolygon(),
2174 meLang(LANGUAGE_SYSTEM)
2176 const SvtCTLOptions aSvtCTLOptions;
2178 canvas::tools::initViewState(maViewState);
2179 canvas::tools::initRenderState(maRenderState);
2180 canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
2182 // set digit language, derived from SvtCTLOptions to have the correct
2183 // number display for arabic/hindi numerals
2184 if(SvtCTLOptions::NUMERALS_HINDI == aSvtCTLOptions.GetCTLTextNumerals())
2186 meLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
2188 else if(SvtCTLOptions::NUMERALS_ARABIC == aSvtCTLOptions.GetCTLTextNumerals())
2190 meLang = LANGUAGE_ENGLISH;
2192 else
2194 meLang = (LanguageType)Application::GetSettings().GetLanguage();
2197 rOutDev.SetDigitLanguage(meLang);
2199 // prepare output directly to pixels
2200 mpOutputDevice->Push(PUSH_MAPMODE);
2201 mpOutputDevice->SetMapMode();
2203 // react on AntiAliasing settings
2204 if(getOptionsDrawinglayer().IsAntiAliasing())
2206 mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() | ANTIALIASING_ENABLE_B2DDRAW);
2208 else
2210 mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW);
2214 canvasProcessor2D::~canvasProcessor2D()
2216 // restore MapMode
2217 mpOutputDevice->Pop();
2219 // restore AntiAliasing
2220 mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW);
2222 } // end of namespace processor2d
2223 } // end of namespace drawinglayer
2225 //////////////////////////////////////////////////////////////////////////////
2226 // eof