fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / drawinglayer / source / processor2d / vclmetafileprocessor2d.cxx
blobec5ad2d48d7157bd0c3107f8944efba2b8fd38df
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <drawinglayer/processor2d/vclmetafileprocessor2d.hxx>
21 #include <tools/gen.hxx>
22 #include <vcl/virdev.hxx>
23 #include <vcl/gdimtf.hxx>
24 #include <vcl/gradient.hxx>
25 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
26 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
27 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
28 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
29 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
30 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
31 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
32 #include <basegfx/polygon/b2dpolygonclipper.hxx>
33 #include <basegfx/polygon/b2dpolypolygontools.hxx>
34 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
35 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
36 #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
37 #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
38 #include <drawinglayer/processor2d/vclpixelprocessor2d.hxx>
39 #include <tools/stream.hxx>
40 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
41 #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
42 #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
43 #include <vcl/graphictools.hxx>
44 #include <vcl/metaact.hxx>
45 #include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
46 #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
47 #include <comphelper/processfactory.hxx>
48 #include <rtl/ustring.hxx>
49 #include <com/sun/star/i18n/BreakIterator.hpp>
50 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
51 #include <com/sun/star/i18n/WordType.hpp>
52 #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
53 #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
54 #include <basegfx/polygon/b2dpolygontools.hxx>
55 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
56 #include <drawinglayer/primitive2d/epsprimitive2d.hxx>
57 #include <basegfx/polygon/b2dlinegeometry.hxx>
59 //////////////////////////////////////////////////////////////////////////////
60 // for PDFExtOutDevData Graphic support
62 #include <vcl/graph.hxx>
63 #include <vcl/svapp.hxx>
64 #include <toolkit/helper/formpdfexport.hxx>
66 //////////////////////////////////////////////////////////////////////////////
67 // for Control printing
69 #include <com/sun/star/beans/XPropertySet.hpp>
71 //////////////////////////////////////////////////////////////////////////////
72 // for StructureTagPrimitive support in sd's unomodel.cxx
74 #include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
76 //////////////////////////////////////////////////////////////////////////////
78 using namespace com::sun::star;
80 //////////////////////////////////////////////////////////////////////////////
81 // #112245# definition for maximum allowed point count due to Metafile target.
82 // To be on the safe side with the old tools polygon, use slightly less then
83 // the theoretical maximum (bad experiences with tools polygon)
85 #define MAX_POLYGON_POINT_COUNT_METAFILE (0x0000fff0)
87 //////////////////////////////////////////////////////////////////////////////
89 namespace
91 // #112245# helper to split line polygon in half
92 void splitLinePolygon(
93 const basegfx::B2DPolygon& rBasePolygon,
94 basegfx::B2DPolygon& o_aLeft,
95 basegfx::B2DPolygon& o_aRight)
97 const sal_uInt32 nCount(rBasePolygon.count());
99 if(nCount)
101 const sal_uInt32 nHalfCount((nCount - 1) >> 1);
103 o_aLeft = basegfx::B2DPolygon(rBasePolygon, 0, nHalfCount + 1);
104 o_aLeft.setClosed(false);
106 o_aRight = basegfx::B2DPolygon(rBasePolygon, nHalfCount, nCount - nHalfCount);
107 o_aRight.setClosed(false);
109 if(rBasePolygon.isClosed())
111 o_aRight.append(rBasePolygon.getB2DPoint(0));
113 if(rBasePolygon.areControlPointsUsed())
115 o_aRight.setControlPoints(
116 o_aRight.count() - 1,
117 rBasePolygon.getPrevControlPoint(0),
118 rBasePolygon.getNextControlPoint(0));
122 else
124 o_aLeft.clear();
125 o_aRight.clear();
129 // #112245# helper to evtl. split filled polygons to maximum metafile point count
130 bool fillPolyPolygonNeededToBeSplit(basegfx::B2DPolyPolygon& rPolyPolygon)
132 bool bRetval(false);
133 const sal_uInt32 nPolyCount(rPolyPolygon.count());
135 if(nPolyCount)
137 basegfx::B2DPolyPolygon aSplitted;
139 for(sal_uInt32 a(0); a < nPolyCount; a++)
141 const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(a));
142 const sal_uInt32 nPointCount(aCandidate.count());
143 bool bNeedToSplit(false);
145 if(aCandidate.areControlPointsUsed())
147 // compare with the maximum for bezier curved polygons
148 bNeedToSplit = nPointCount > ((MAX_POLYGON_POINT_COUNT_METAFILE / 3L) - 1L);
150 else
152 // compare with the maximum for simple point polygons
153 bNeedToSplit = nPointCount > (MAX_POLYGON_POINT_COUNT_METAFILE - 1);
156 if(bNeedToSplit)
158 // need to split the partial polygon
159 const basegfx::B2DRange aRange(aCandidate.getB2DRange());
160 const basegfx::B2DPoint aCenter(aRange.getCenter());
162 if(aRange.getWidth() > aRange.getHeight())
164 // clip in left and right
165 const basegfx::B2DPolyPolygon aLeft(
166 basegfx::tools::clipPolygonOnParallelAxis(
167 aCandidate,
168 false,
169 true,
170 aCenter.getX(),
171 false));
172 const basegfx::B2DPolyPolygon aRight(
173 basegfx::tools::clipPolygonOnParallelAxis(
174 aCandidate,
175 false,
176 false,
177 aCenter.getX(),
178 false));
180 aSplitted.append(aLeft);
181 aSplitted.append(aRight);
183 else
185 // clip in top and bottom
186 const basegfx::B2DPolyPolygon aTop(
187 basegfx::tools::clipPolygonOnParallelAxis(
188 aCandidate,
189 true,
190 true,
191 aCenter.getY(),
192 false));
193 const basegfx::B2DPolyPolygon aBottom(
194 basegfx::tools::clipPolygonOnParallelAxis(
195 aCandidate,
196 true,
197 false,
198 aCenter.getY(),
199 false));
201 aSplitted.append(aTop);
202 aSplitted.append(aBottom);
205 else
207 aSplitted.append(aCandidate);
211 if(aSplitted.count() != nPolyCount)
213 rPolyPolygon = aSplitted;
217 return bRetval;
220 /** Filter input polypolygon for effectively empty sub-fills
222 Needed to fix fdo#37559
224 @param rPoly
225 PolyPolygon to filter
227 @return converted tools PolyPolygon, w/o one-point fills
229 PolyPolygon getFillPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly )
231 // filter input rPoly
232 basegfx::B2DPolyPolygon aPoly;
233 sal_uInt32 nCount(rPoly.count());
234 for( sal_uInt32 i=0; i<nCount; ++i )
236 basegfx::B2DPolygon aCandidate(rPoly.getB2DPolygon(i));
237 if( !aCandidate.isClosed() || aCandidate.count() > 1 )
238 aPoly.append(aCandidate);
240 return PolyPolygon(aPoly);
243 } // end of anonymous namespace
245 //////////////////////////////////////////////////////////////////////////////
247 namespace drawinglayer
249 namespace processor2d
251 Rectangle VclMetafileProcessor2D::impDumpToMetaFile(
252 const primitive2d::Primitive2DSequence& rContent,
253 GDIMetaFile& o_rContentMetafile)
255 // Prepare VDev, MetaFile and connections
256 OutputDevice* pLastOutputDevice = mpOutputDevice;
257 GDIMetaFile* pLastMetafile = mpMetaFile;
258 basegfx::B2DRange aPrimitiveRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
260 // transform primitive range with current transformation (e.g shadow offset)
261 aPrimitiveRange.transform(maCurrentTransformation);
263 const Rectangle aPrimitiveRectangle(
264 basegfx::fround(aPrimitiveRange.getMinX()), basegfx::fround(aPrimitiveRange.getMinY()),
265 basegfx::fround(aPrimitiveRange.getMaxX()), basegfx::fround(aPrimitiveRange.getMaxY()));
266 VirtualDevice aContentVDev;
267 MapMode aNewMapMode(pLastOutputDevice->GetMapMode());
269 mpOutputDevice = &aContentVDev;
270 mpMetaFile = &o_rContentMetafile;
271 aContentVDev.EnableOutput(false);
272 aContentVDev.SetMapMode(pLastOutputDevice->GetMapMode());
273 o_rContentMetafile.Record(&aContentVDev);
274 aContentVDev.SetLineColor(pLastOutputDevice->GetLineColor());
275 aContentVDev.SetFillColor(pLastOutputDevice->GetFillColor());
276 aContentVDev.SetFont(pLastOutputDevice->GetFont());
277 aContentVDev.SetDrawMode(pLastOutputDevice->GetDrawMode());
278 aContentVDev.SetSettings(pLastOutputDevice->GetSettings());
279 aContentVDev.SetRefPoint(pLastOutputDevice->GetRefPoint());
281 // dump to MetaFile
282 process(rContent);
284 // cleanups
285 o_rContentMetafile.Stop();
286 o_rContentMetafile.WindStart();
287 aNewMapMode.SetOrigin(aPrimitiveRectangle.TopLeft());
288 o_rContentMetafile.SetPrefMapMode(aNewMapMode);
289 o_rContentMetafile.SetPrefSize(aPrimitiveRectangle.GetSize());
290 mpOutputDevice = pLastOutputDevice;
291 mpMetaFile = pLastMetafile;
293 return aPrimitiveRectangle;
296 void VclMetafileProcessor2D::impConvertFillGradientAttributeToVCLGradient(
297 Gradient& o_rVCLGradient,
298 const attribute::FillGradientAttribute& rFiGrAtt,
299 bool bIsTransparenceGradient)
301 if(bIsTransparenceGradient)
303 // it's about transparence channel intensities (black/white), do not use color modifier
304 o_rVCLGradient.SetStartColor(Color(rFiGrAtt.getStartColor()));
305 o_rVCLGradient.SetEndColor(Color(rFiGrAtt.getEndColor()));
307 else
309 // use color modifier to influence start/end color of gradient
310 o_rVCLGradient.SetStartColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getStartColor())));
311 o_rVCLGradient.SetEndColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getEndColor())));
314 o_rVCLGradient.SetAngle(static_cast< sal_uInt16 >(rFiGrAtt.getAngle() * (1.0 / F_PI1800)));
315 o_rVCLGradient.SetBorder(static_cast< sal_uInt16 >(rFiGrAtt.getBorder() * 100.0));
316 o_rVCLGradient.SetOfsX(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetX() * 100.0));
317 o_rVCLGradient.SetOfsY(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetY() * 100.0));
318 o_rVCLGradient.SetSteps(rFiGrAtt.getSteps());
320 // defaults for intensity; those were computed into the start/end colors already
321 o_rVCLGradient.SetStartIntensity(100);
322 o_rVCLGradient.SetEndIntensity(100);
324 switch(rFiGrAtt.getStyle())
326 default : // attribute::GRADIENTSTYLE_LINEAR :
328 o_rVCLGradient.SetStyle(GradientStyle_LINEAR);
329 break;
331 case attribute::GRADIENTSTYLE_AXIAL :
333 o_rVCLGradient.SetStyle(GradientStyle_AXIAL);
334 break;
336 case attribute::GRADIENTSTYLE_RADIAL :
338 o_rVCLGradient.SetStyle(GradientStyle_RADIAL);
339 break;
341 case attribute::GRADIENTSTYLE_ELLIPTICAL :
343 o_rVCLGradient.SetStyle(GradientStyle_ELLIPTICAL);
344 break;
346 case attribute::GRADIENTSTYLE_SQUARE :
348 o_rVCLGradient.SetStyle(GradientStyle_SQUARE);
349 break;
351 case attribute::GRADIENTSTYLE_RECT :
353 o_rVCLGradient.SetStyle(GradientStyle_RECT);
354 break;
359 void VclMetafileProcessor2D::impStartSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill)
361 if(pSvtGraphicFill && !mnSvtGraphicFillCount)
363 SvMemoryStream aMemStm;
365 aMemStm << *pSvtGraphicFill;
366 mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END)));
367 mnSvtGraphicFillCount++;
371 void VclMetafileProcessor2D::impEndSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill)
373 if(pSvtGraphicFill && mnSvtGraphicFillCount)
375 mnSvtGraphicFillCount--;
376 mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_END"));
377 delete pSvtGraphicFill;
381 double VclMetafileProcessor2D::getTransformedLineWidth( double fWidth ) const
383 // #i113922# the LineWidth is duplicated in the MetaPolylineAction,
384 // and also inside the SvtGraphicStroke and needs transforming into
385 // the same space as its co-ordinates here cf. fdo#61789
386 // This is a partial fix. When a object transformation is used which
387 // e.g. contains a scaleX != scaleY, an unproportional scaling will happen.
388 const basegfx::B2DVector aDiscreteUnit( maCurrentTransformation * basegfx::B2DVector( fWidth, 0.0 ) );
390 return aDiscreteUnit.getLength();
393 SvtGraphicStroke* VclMetafileProcessor2D::impTryToCreateSvtGraphicStroke(
394 const basegfx::B2DPolygon& rB2DPolygon,
395 const basegfx::BColor* pColor,
396 const attribute::LineAttribute* pLineAttribute,
397 const attribute::StrokeAttribute* pStrokeAttribute,
398 const attribute::LineStartEndAttribute* pStart,
399 const attribute::LineStartEndAttribute* pEnd)
401 SvtGraphicStroke* pRetval = 0;
403 if(rB2DPolygon.count() && !mnSvtGraphicStrokeCount)
405 basegfx::BColor aStrokeColor;
406 basegfx::B2DPolyPolygon aStartArrow;
407 basegfx::B2DPolyPolygon aEndArrow;
409 if(pColor)
411 aStrokeColor = *pColor;
413 else if(pLineAttribute)
415 aStrokeColor = maBColorModifierStack.getModifiedColor(pLineAttribute->getColor());
418 // It IS needed to record the stroke color at all in the metafile,
419 // SvtGraphicStroke has NO entry for stroke color(!)
420 mpOutputDevice->SetLineColor(Color(aStrokeColor));
422 if(!rB2DPolygon.isClosed())
424 double fPolyLength(0.0);
426 if(pStart && pStart->isActive())
428 fPolyLength = basegfx::tools::getLength(rB2DPolygon);
430 aStartArrow = basegfx::tools::createAreaGeometryForLineStartEnd(
431 rB2DPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(),
432 fPolyLength, pStart->isCentered() ? 0.5 : 0.0, 0);
435 if(pEnd && pEnd->isActive())
437 if(basegfx::fTools::equalZero(fPolyLength))
439 fPolyLength = basegfx::tools::getLength(rB2DPolygon);
442 aEndArrow = basegfx::tools::createAreaGeometryForLineStartEnd(
443 rB2DPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(),
444 fPolyLength, pEnd->isCentered() ? 0.5 : 0.0, 0);
448 SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone);
449 SvtGraphicStroke::CapType eCap(SvtGraphicStroke::capButt);
450 double fLineWidth(0.0);
451 double fMiterLength(0.0);
452 SvtGraphicStroke::DashArray aDashArray;
454 if(pLineAttribute)
456 fLineWidth = fMiterLength = getTransformedLineWidth( pLineAttribute->getWidth() );
458 // get Join
459 switch(pLineAttribute->getLineJoin())
461 default : // basegfx::B2DLINEJOIN_NONE :
463 eJoin = SvtGraphicStroke::joinNone;
464 break;
466 case basegfx::B2DLINEJOIN_BEVEL :
468 eJoin = SvtGraphicStroke::joinBevel;
469 break;
471 case basegfx::B2DLINEJOIN_MIDDLE :
472 case basegfx::B2DLINEJOIN_MITER :
474 eJoin = SvtGraphicStroke::joinMiter;
475 // ATM 15 degrees is assumed
476 fMiterLength /= rtl::math::sin(M_PI * (15.0 / 360.0));
477 break;
479 case basegfx::B2DLINEJOIN_ROUND :
481 eJoin = SvtGraphicStroke::joinRound;
482 break;
486 // get stroke
487 switch(pLineAttribute->getLineCap())
489 default: /* com::sun::star::drawing::LineCap_BUTT */
491 eCap = SvtGraphicStroke::capButt;
492 break;
494 case com::sun::star::drawing::LineCap_ROUND:
496 eCap = SvtGraphicStroke::capRound;
497 break;
499 case com::sun::star::drawing::LineCap_SQUARE:
501 eCap = SvtGraphicStroke::capSquare;
502 break;
507 if(pStrokeAttribute)
509 // copy dash array
510 aDashArray = pStrokeAttribute->getDotDashArray();
513 // #i101734# apply current object transformation to created geometry.
514 // This is a partial fix. When a object transformation is used which
515 // e.g. contains a scaleX != scaleY, an unproportional scaling would
516 // have to be applied to the evtl. existing fat line. The current
517 // concept of PDF export and SvtGraphicStroke usage does simply not
518 // allow handling such definitions. The only clean way would be to
519 // add the transformation to SvtGraphicStroke and to handle it there
520 basegfx::B2DPolygon aB2DPolygon(rB2DPolygon);
522 aB2DPolygon.transform(maCurrentTransformation);
523 aStartArrow.transform(maCurrentTransformation);
524 aEndArrow.transform(maCurrentTransformation);
526 pRetval = new SvtGraphicStroke(
527 Polygon(aB2DPolygon),
528 PolyPolygon(aStartArrow),
529 PolyPolygon(aEndArrow),
530 mfCurrentUnifiedTransparence,
531 fLineWidth,
532 eCap,
533 eJoin,
534 fMiterLength,
535 aDashArray);
538 return pRetval;
541 void VclMetafileProcessor2D::impStartSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke)
543 if(pSvtGraphicStroke && !mnSvtGraphicStrokeCount)
545 SvMemoryStream aMemStm;
547 aMemStm << *pSvtGraphicStroke;
548 mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END)));
549 mnSvtGraphicStrokeCount++;
553 void VclMetafileProcessor2D::impEndSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke)
555 if(pSvtGraphicStroke && mnSvtGraphicStrokeCount)
557 mnSvtGraphicStrokeCount--;
558 mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_END"));
559 delete pSvtGraphicStroke;
563 // init static break iterator
564 uno::Reference< ::com::sun::star::i18n::XBreakIterator > VclMetafileProcessor2D::mxBreakIterator;
566 VclMetafileProcessor2D::VclMetafileProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev)
567 : VclProcessor2D(rViewInformation, rOutDev),
568 mpMetaFile(rOutDev.GetConnectMetaFile()),
569 mnSvtGraphicFillCount(0),
570 mnSvtGraphicStrokeCount(0),
571 mfCurrentUnifiedTransparence(0.0),
572 mpPDFExtOutDevData(dynamic_cast< vcl::PDFExtOutDevData* >(rOutDev.GetExtOutDevData()))
574 OSL_ENSURE(rOutDev.GetConnectMetaFile(), "VclMetafileProcessor2D: Used on OutDev which has no MetaFile Target (!)");
575 // draw to logic coordinates, do not initialize maCurrentTransformation to viewTransformation
576 // but only to ObjectTransformation. Do not change MapMode of destination.
577 maCurrentTransformation = rViewInformation.getObjectTransformation();
580 VclMetafileProcessor2D::~VclMetafileProcessor2D()
582 // MapMode was not changed, no restore necessary
585 /***********************************************************************************************
587 Support of MetaCommentActions in the VclMetafileProcessor2D
588 Found MetaCommentActions and how they are supported:
590 XGRAD_SEQ_BEGIN, XGRAD_SEQ_END:
592 Used inside OutputDevice::DrawGradient to mark the start and end of a MetaGradientEx action.
593 It is used in various exporters/importers to have direct access to the gradient before it
594 is rendered by VCL (and thus fragmented to polygon color actions and others). On that base, e.g.
595 the Metafile to SdrObject import creates it's gradient objects.
596 Best (and safest) way to support it here is to use PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
597 map it back to the corresponding tools PolyPolygon and the Gradient and just call
598 OutputDevice::DrawGradient which creates the necessary compatible actions.
600 XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END:
602 Two producers, one is vcl/source/gdi/gdimtf.cxx, line 1273. There, it is transformed
603 inside GDIMetaFile::Rotate, nothing to take care of here.
604 The second producer is in graphics/svx/source/svdraw/impgrfll.cxx, line 374. This is used
605 with each incarnation of Imp_GraphicFill when a metafile is recorded, fillstyle is not
606 XFILL_NONE and not completely transparent. It creates a SvtGraphicFill and streams it
607 to the comment action. A closing end token is created in the destructor.
608 Usages of Imp_GraphicFill are in Do_Paint_Object-methods of SdrCircObj, SdrPathObj and
609 SdrRectObj.
610 The token users pick various actions from SvtGraphicFill, so it may need to be added for all kind
611 of filled objects, even simple colored polygons. It is added as extra information; the
612 Metafile actions between the two tokens are interpreted as output generated from those
613 fills. Thus, users have the choice to use the SvtGraphicFill info or the created output
614 actions.
615 Even for XFillTransparenceItem it is used, thus it may need to be supported in
616 UnifiedTransparencePrimitive2D, too, when interpreted as normally filled PolyPolygon.
617 Implemented for:
618 PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D,
619 PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D,
620 PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
621 PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D,
622 and for PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D when detected unified transparence
624 XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END:
626 Similar to pathfill, but using SvtGraphicStroke instead. It also has two producers where one
627 is also the GDIMetaFile::Rotate. Another user is MetaCommentAction::Move which modifies the
628 contained path accordingly.
629 The other one is SdrObject::Imp_DrawLineGeometry. It's done when MetaFile is set at OutDev and
630 only when geometry is a single polygon (!). I see no reason for that; in the PS exporter this
631 would hinder to make use of PolyPolygon strokes. I will need to add support at:
632 PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D
633 PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D
634 PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D
635 This can be done hierarchical, too.
636 Okay, base implementation done based on those three primitives.
638 FIELD_SEQ_BEGIN, FIELD_SEQ_END
640 Used from slideshow for URLs, created from diverse SvxField implementations inside
641 createBeginComment()/createEndComment(). createBeginComment() is used from editeng\impedit3.cxx
642 inside ImpEditEngine::Paint.
643 Created TextHierarchyFieldPrimitive2D and added needed infos there; it is an group primitive and wraps
644 text primitives (but is not limited to that). It contains the field type if special actions for the
645 support of FIELD_SEQ_BEGIN/END are needed; this is the case for Page and URL fields. If more is
646 needed, it may be supported there.
647 FIELD_SEQ_BEGIN;PageField
648 FIELD_SEQ_END
649 Okay, these are now completely supported by TextHierarchyFieldPrimitive2D. URL works, too.
651 XTEXT
653 XTEXT_EOC(i) end of character
654 XTEXT_EOW(i) end of word
655 XTEXT_EOS(i) end of sentence
657 this three are with index and are created with the help of a i18n::XBreakIterator in
658 ImplDrawWithComments. Simplifying, moving out text painting, reworking to create some
659 data structure for holding those TEXT infos.
660 Supported directly by TextSimplePortionPrimitive2D with adding a Locale to the basic text
661 primitive. In the MetaFileRenderer, the creation is now done (see below). This has the advantage
662 that this creations do not need to be done for all paints all the time. This would be
663 expensive since the BreakIterator and it's usage is expensive and for each paint also the
664 whole character stops would need to be created.
665 Created only for TextDecoratedPortionPrimitive2D due to XTEXT_EOL and XTEXT_EOP (see below)
667 XTEXT_EOL() end of line
668 XTEXT_EOP() end of paragraph
670 First try with boolean marks at TextDecoratedPortionPrimitive2D did not work too well,
671 i decided to solve it with structure. I added the TextHierarchyPrimitives for this,
672 namely:
673 - TextHierarchyLinePrimitive2D: Encapsulates single line
674 - TextHierarchyParagraphPrimitive2D: Encapsulates single paragraph
675 - TextHierarchyBlockPrimitive2D: encapsulates object texts (only one ATM)
676 Those are now supported in hierarchy. This means the MetaFile renderer will support them
677 by using them, reculrively using their content and adding MetaFile comments as needed.
678 This also means that when another text layouter will be used it will be necessary to
679 create/support the same HierarchyPrimitives to support users.
680 To transport the information using this hierarchy is best suited to all future needs;
681 the slideshow will be able to profit from it directly when using primitives; all other
682 renderers not interested in the text structure will just ignore the encapsulations.
684 XTEXT_PAINTSHAPE_BEGIN, XTEXT_PAINTSHAPE_END
685 Supported now by the TextHierarchyBlockPrimitive2D.
687 EPSReplacementGraphic:
688 Only used in goodies\source\filter.vcl\ieps\ieps.cxx and svx\source\xml\xmlgrhlp.cxx to
689 hold the original EPS which was imported in the same MetaFile as first 2 entries. Only
690 used to export the original again (if exists).
691 Not necessary to support with MetaFuleRenderer.
693 XTEXT_SCROLLRECT, XTEXT_PAINTRECT
694 Currently used to get extra MetaFile infos using GraphicExporter which again uses
695 SdrTextObj::GetTextScrollMetaFileAndRectangle(). ATM works with primitives since
696 the rectangle data is added directly by the GraphicsExporter as comment. Does not need
697 to be adapted at once.
698 When adapting later, the only user - the diashow - should directly use the provided
699 Anination infos in the appropriate primitives (e.g. AnimatedSwitchPrimitive2D)
701 PRNSPOOL_TRANSPARENTBITMAP_BEGIN, PRNSPOOL_TRANSPARENTBITMAP_END
702 VCL usage when printing PL -> THB. Okay, THB confirms that it is only used as
703 a fix (hack) while VCL printing. It is needed to not downscale a bitmap which
704 was explicitly created for the printer already again to some default maximum
705 bitmap sizes.
706 Nothing to do here for the primitive renderer.
708 Support for vcl::PDFExtOutDevData:
709 PL knows that SJ did that stuff, it's used to hold a pointer to PDFExtOutDevData at
710 the OutDev. When set, some extra data is written there. Trying simple PDF export and
711 watching if i get those infos.
712 Well, a PDF export does not use e.g. ImpEditEngine::Paint since the PdfFilter uses
713 the SdXImpressDocument::render and thus uses the VclMetafileProcessor2D. I will check
714 if i get a PDFExtOutDevData at the target output device.
715 Indeed, i get one. Checking what all may be done when that extra-device-info is there.
717 All in all i have to talk to SJ. I will need to emulate some of those actions, but
718 i need to discuss which ones.
719 In the future, all those infos would be taken from the primitive sequence anyways,
720 thus these extensions would potentially be temporary, too.
721 Discussed with SJ, added the necessary support and tested it. Details follow.
723 - In ImpEditEngine::Paint, paragraph infos and URL stuff is added.
724 Added in primitive MetaFile renderer.
725 Checking URL: Indeed, current version exports it, but it is missing in primitive
726 CWS version. Adding support.
727 Okay, URLs work. Checked, Done.
729 - UnoControlPDFExportContact is only created when PDFExtOutDevData is used at the
730 target and uno control data is created in UnoControlPDFExportContact::do_PaintObject.
731 This may be added in primitive MetaFile renderer.
732 Adding support...
733 OOps, the necessary helper stuff is in svx/source/form/formpdxexport.cxx in namespace
734 svxform. Have to talk to FS if this has to be like that. Especially since
735 ::vcl::PDFWriter::AnyWidget is filled out, which is already part of vcl.
736 Wrote an eMail to FS, he is on vacation currently. I see no reason why not to move
737 that stuff to somewhere else, maybe tools or svtools ?!? We will see...
738 Moved to toolkit, so i have to link against it. I tried VCL first, but it did
739 not work since VCLUnoHelper::CreateFont is unresolved in VCL (!). Other then the name
740 may imply, it is defined in toolkit (!). Since toolkit is linked against VCL itself,
741 the lowest move,ment plave is toolkit.
742 Checked form control export, it works well. Done.
744 - In goodies, in GraphicObject::Draw, when the used Graphic is linked, infos are
745 generated. I will need to check what happens here with primitives.
746 To support, use of GraphicPrimitive2D (PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D) may be needed.
747 Added support, but feature is broken in main version, so i cannot test at all.
748 Writing a bug to CL (or SJ) and seeing what happens (#i80380#).
749 SJ took a look and we got it working. Tested VCL MetaFile Renderer based export,
750 as intended, the original file is exported. Works, Done.
755 To be done:
757 - Maybe there are more places to take care of for vcl::PDFExtOutDevData!
761 ****************************************************************************************************/
763 void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
765 switch(rCandidate.getPrimitive2DID())
767 case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
769 // directdraw of wrong spell primitive
770 // Ignore for VclMetafileProcessor2D, this is for printing and MetaFile recording only
771 break;
773 case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D :
775 const primitive2d::GraphicPrimitive2D& rGraphicPrimitive = static_cast< const primitive2d::GraphicPrimitive2D& >(rCandidate);
776 bool bUsingPDFExtOutDevData(false);
777 basegfx::B2DVector aTranslate, aScale;
778 static bool bSuppressPDFExtOutDevDataSupport(false);
780 if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport)
782 // emulate data handling from UnoControlPDFExportContact, original see
783 // svtools/source/graphic/grfmgr.cxx
784 const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic();
786 if(rGraphic.IsLink())
788 const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
790 if(!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted())
792 const basegfx::B2DHomMatrix& rTransform = rGraphicPrimitive.getTransform();
793 double fRotate, fShearX;
794 rTransform.decompose(aScale, aTranslate, fRotate, fShearX);
796 if( basegfx::fTools::equalZero( fRotate ) && ( aScale.getX() > 0.0 ) && ( aScale.getY() > 0.0 ) )
798 bUsingPDFExtOutDevData = true;
799 mpPDFExtOutDevData->BeginGroup();
805 // process recursively and add MetaFile comment
806 process(rGraphicPrimitive.get2DDecomposition(getViewInformation2D()));
808 if(bUsingPDFExtOutDevData)
810 // emulate data handling from UnoControlPDFExportContact, original see
811 // svtools/source/graphic/grfmgr.cxx
812 const basegfx::B2DRange aCurrentRange(
813 aTranslate.getX(), aTranslate.getY(),
814 aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
815 const Rectangle aCurrentRect(
816 sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())),
817 sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY())));
818 const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
819 Rectangle aCropRect;
821 if(rAttr.IsCropped())
823 // calculate scalings between real image size and logic object size. This
824 // is necessary since the crop values are relative to original bitmap size
825 double fFactorX(1.0);
826 double fFactorY(1.0);
829 const MapMode aMapMode100thmm(MAP_100TH_MM);
830 const Size aBitmapSize(Application::GetDefaultDevice()->LogicToLogic(
831 rGraphicPrimitive.getGraphicObject().GetPrefSize(),
832 rGraphicPrimitive.getGraphicObject().GetPrefMapMode(), aMapMode100thmm));
833 const double fDivX(aBitmapSize.Width() - rAttr.GetLeftCrop() - rAttr.GetRightCrop());
834 const double fDivY(aBitmapSize.Height() - rAttr.GetTopCrop() - rAttr.GetBottomCrop());
836 if(!basegfx::fTools::equalZero(fDivX))
838 fFactorX = aScale.getX() / fDivX;
841 if(!basegfx::fTools::equalZero(fDivY))
843 fFactorY = aScale.getY() / fDivY;
847 // calculate crop range and rect
848 basegfx::B2DRange aCropRange;
849 aCropRange.expand(aCurrentRange.getMinimum() - basegfx::B2DPoint(rAttr.GetLeftCrop() * fFactorX, rAttr.GetTopCrop() * fFactorY));
850 aCropRange.expand(aCurrentRange.getMaximum() + basegfx::B2DPoint(rAttr.GetRightCrop() * fFactorX, rAttr.GetBottomCrop() * fFactorY));
852 aCropRect = Rectangle(
853 sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())),
854 sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY())));
857 mpPDFExtOutDevData->EndGroup(rGraphicPrimitive.getGraphicObject().GetGraphic(),
858 rAttr.GetTransparency(),
859 aCurrentRect,
860 aCropRect);
863 break;
865 case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
867 const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate);
868 const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl());
869 bool bIsPrintableControl(false);
871 // find out if control is printable
872 if(rXControl.is())
876 uno::Reference< beans::XPropertySet > xModelProperties(rXControl->getModel(), uno::UNO_QUERY);
877 uno::Reference< beans::XPropertySetInfo > xPropertyInfo(xModelProperties.is()
878 ? xModelProperties->getPropertySetInfo()
879 : uno::Reference< beans::XPropertySetInfo >());
880 const OUString sPrintablePropertyName("Printable");
882 if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName))
884 OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl);
887 catch(const uno::Exception&)
889 OSL_FAIL("VclMetafileProcessor2D: No access to printable flag of Control, caught an exception!");
893 // PDF export and printing only for printable controls
894 if(bIsPrintableControl)
896 const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields());
897 bool bDoProcessRecursively(true);
899 if(bPDFExport)
901 // PDF export. Emulate data handling from UnoControlPDFExportContact
902 // I have now moved describePDFControl to toolkit, thus i can implement the PDF
903 // form control support now as follows
904 ::std::auto_ptr< ::vcl::PDFWriter::AnyWidget > pPDFControl;
905 ::toolkitform::describePDFControl( rXControl, pPDFControl, *mpPDFExtOutDevData );
907 if(pPDFControl.get())
909 // still need to fill in the location (is a class Rectangle)
910 const basegfx::B2DRange aRangeLogic(rControlPrimitive.getB2DRange(getViewInformation2D()));
911 const Rectangle aRectLogic(
912 (sal_Int32)floor(aRangeLogic.getMinX()), (sal_Int32)floor(aRangeLogic.getMinY()),
913 (sal_Int32)ceil(aRangeLogic.getMaxX()), (sal_Int32)ceil(aRangeLogic.getMaxY()));
914 pPDFControl->Location = aRectLogic;
916 Size aFontSize(pPDFControl->TextFont.GetSize());
917 aFontSize = mpOutputDevice->LogicToLogic(aFontSize, MapMode(MAP_POINT), mpOutputDevice->GetMapMode());
918 pPDFControl->TextFont.SetSize(aFontSize);
920 mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form);
921 mpPDFExtOutDevData->CreateControl(*pPDFControl.get());
922 mpPDFExtOutDevData->EndStructureElement();
924 // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject);
925 // do not process recursively
926 bDoProcessRecursively = false;
928 else
930 // PDF export did not work, try simple output.
931 // Fallback to printer output by not setting bDoProcessRecursively
932 // to false.
936 // #i93169# used flag the wrong way; true means that nothing was done yet
937 if(bDoProcessRecursively)
939 // printer output
942 // remember old graphics and create new
943 uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW);
944 const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics());
945 const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics());
947 if(xNewGraphics.is())
949 // link graphics and view
950 xControlView->setGraphics(xNewGraphics);
952 // get position
953 const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform());
954 const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0));
956 // draw it
957 xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY()));
958 bDoProcessRecursively = false;
960 // restore original graphics
961 xControlView->setGraphics(xOriginalGraphics);
964 catch( const uno::Exception& )
966 OSL_FAIL("VclMetafileProcessor2D: Printing of Control failed, caught an exception!");
970 // process recursively if not done yet to export as decomposition (bitmap)
971 if(bDoProcessRecursively)
973 process(rControlPrimitive.get2DDecomposition(getViewInformation2D()));
977 break;
979 case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D :
981 // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to)
982 // thus do the MetafileAction embedding stuff but just handle recursively.
983 const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive = static_cast< const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate);
984 const OString aCommentStringCommon(RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_BEGIN"));
985 const OString aCommentStringPage(RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_BEGIN;PageField"));
986 const OString aCommentStringEnd(RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_END"));
988 switch(rFieldPrimitive.getType())
990 default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON :
992 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon));
993 break;
995 case drawinglayer::primitive2d::FIELD_TYPE_PAGE :
997 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage));
998 break;
1000 case drawinglayer::primitive2d::FIELD_TYPE_URL :
1002 const OUString& rURL = rFieldPrimitive.getString();
1003 const String aOldString(rURL);
1004 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast< const sal_uInt8* >(aOldString.GetBuffer()), 2 * aOldString.Len()));
1005 break;
1009 // process recursively
1010 const primitive2d::Primitive2DSequence rContent = rFieldPrimitive.get2DDecomposition(getViewInformation2D());
1011 process(rContent);
1013 // for the end comment the type is not relevant yet, they are all the same. Just add.
1014 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd));
1016 if(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType())
1018 // emulate data handling from ImpEditEngine::Paint
1019 const basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
1020 const Rectangle aRectLogic(
1021 (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()),
1022 (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY()));
1023 vcl::PDFExtOutDevBookmarkEntry aBookmark;
1024 aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic);
1025 aBookmark.aBookmark = rFieldPrimitive.getString();
1026 std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks();
1027 rBookmarks.push_back( aBookmark );
1030 break;
1032 case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D :
1034 const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive = static_cast< const primitive2d::TextHierarchyLinePrimitive2D& >(rCandidate);
1035 const OString aCommentString(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOL"));
1037 // process recursively and add MetaFile comment
1038 process(rLinePrimitive.get2DDecomposition(getViewInformation2D()));
1039 mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
1041 break;
1043 case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D :
1045 // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The
1046 // "XTEXT_EOC" is used, use here, too.
1047 const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive = static_cast< const primitive2d::TextHierarchyBulletPrimitive2D& >(rCandidate);
1048 const OString aCommentString(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOC"));
1050 // process recursively and add MetaFile comment
1051 process(rBulletPrimitive.get2DDecomposition(getViewInformation2D()));
1052 mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
1054 break;
1056 case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D :
1058 const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive = static_cast< const primitive2d::TextHierarchyParagraphPrimitive2D& >(rCandidate);
1059 const OString aCommentString(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOP"));
1061 if(mpPDFExtOutDevData)
1063 // emulate data handling from ImpEditEngine::Paint
1064 mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );
1067 // process recursively and add MetaFile comment
1068 process(rParagraphPrimitive.get2DDecomposition(getViewInformation2D()));
1069 mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
1071 if(mpPDFExtOutDevData)
1073 // emulate data handling from ImpEditEngine::Paint
1074 mpPDFExtOutDevData->EndStructureElement();
1077 break;
1079 case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D :
1081 const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive = static_cast< const primitive2d::TextHierarchyBlockPrimitive2D& >(rCandidate);
1082 const OString aCommentStringA(RTL_CONSTASCII_STRINGPARAM("XTEXT_PAINTSHAPE_BEGIN"));
1083 const OString aCommentStringB(RTL_CONSTASCII_STRINGPARAM("XTEXT_PAINTSHAPE_END"));
1085 // add MetaFile comment, process recursively and add MetaFile comment
1086 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA));
1087 process(rBlockPrimitive.get2DDecomposition(getViewInformation2D()));
1088 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB));
1090 break;
1092 case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
1093 case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
1095 // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate
1096 const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate = static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate);
1097 // const primitive2d::TextDecoratedPortionPrimitive2D* pTextDecoratedCandidate = dynamic_cast< const primitive2d::TextDecoratedPortionPrimitive2D* >(&rCandidate);
1099 // Adapt evtl. used special DrawMode
1100 const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
1101 adaptTextToFillDrawMode();
1103 // directdraw of text simple portion; use default processing
1104 RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate);
1106 // restore DrawMode
1107 mpOutputDevice->SetDrawMode(nOriginalDrawMode);
1109 // #i101169# if(pTextDecoratedCandidate)
1111 // support for TEXT_ MetaFile actions only for decorated texts
1112 if(!mxBreakIterator.is())
1114 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1115 mxBreakIterator = i18n::BreakIterator::create(xContext);
1118 const OUString& rTxt = rTextCandidate.getText();
1119 const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength());
1121 if(nTextLength)
1123 const ::com::sun::star::lang::Locale& rLocale = rTextCandidate.getLocale();
1124 const sal_Int32 nTextPosition(rTextCandidate.getTextPosition());
1126 sal_Int32 nDone;
1127 sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
1128 ::com::sun::star::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True));
1129 sal_Int32 nNextSentenceBreak(mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale));
1130 const OString aCommentStringA(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOC"));
1131 const OString aCommentStringB(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOW"));
1132 const OString aCommentStringC(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOS"));
1134 for(sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++)
1136 // create the entries for the respective break positions
1137 if(i == nNextCellBreak)
1139 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA, i - nTextPosition));
1140 nNextCellBreak = mxBreakIterator->nextCharacters(rTxt, i, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
1142 if(i == nNextWordBoundary.endPos)
1144 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB, i - nTextPosition));
1145 nNextWordBoundary = mxBreakIterator->getWordBoundary(rTxt, i + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True);
1147 if(i == nNextSentenceBreak)
1149 mpMetaFile->AddAction(new MetaCommentAction(aCommentStringC, i - nTextPosition));
1150 nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale);
1156 break;
1158 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
1160 const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate);
1161 const basegfx::B2DPolygon& rBasePolygon = rHairlinePrimitive.getB2DPolygon();
1163 if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
1165 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1166 // per polygon. If there are more, split the polygon in half and call recursively
1167 basegfx::B2DPolygon aLeft, aRight;
1168 splitLinePolygon(rBasePolygon, aLeft, aRight);
1169 const primitive2d::PolygonHairlinePrimitive2D aPLeft(aLeft, rHairlinePrimitive.getBColor());
1170 const primitive2d::PolygonHairlinePrimitive2D aPRight(aRight, rHairlinePrimitive.getBColor());
1172 processBasePrimitive2D(aPLeft);
1173 processBasePrimitive2D(aPRight);
1175 else
1177 // direct draw of hairline; use default processing
1178 // support SvtGraphicStroke MetaCommentAction
1179 const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor()));
1180 SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
1181 rHairlinePrimitive.getB2DPolygon(),
1182 &aLineColor,
1183 0, 0, 0, 0);
1185 impStartSvtGraphicStroke(pSvtGraphicStroke);
1186 RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), false);
1187 impEndSvtGraphicStroke(pSvtGraphicStroke);
1189 break;
1191 case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D :
1193 const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate);
1194 const basegfx::B2DPolygon& rBasePolygon = rStrokePrimitive.getB2DPolygon();
1196 if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
1198 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1199 // per polygon. If there are more, split the polygon in half and call recursively
1200 basegfx::B2DPolygon aLeft, aRight;
1201 splitLinePolygon(rBasePolygon, aLeft, aRight);
1202 const primitive2d::PolygonStrokePrimitive2D aPLeft(
1203 aLeft, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute());
1204 const primitive2d::PolygonStrokePrimitive2D aPRight(
1205 aRight, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute());
1207 processBasePrimitive2D(aPLeft);
1208 processBasePrimitive2D(aPRight);
1210 else
1212 // support SvtGraphicStroke MetaCommentAction
1213 SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
1214 rBasePolygon, 0,
1215 &rStrokePrimitive.getLineAttribute(),
1216 &rStrokePrimitive.getStrokeAttribute(),
1217 0, 0);
1219 impStartSvtGraphicStroke(pSvtGraphicStroke);
1220 const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute();
1222 // create MetaPolyLineActions, but without LINE_DASH
1223 if(basegfx::fTools::more(rLine.getWidth(), 0.0))
1225 const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute();
1226 basegfx::B2DPolyPolygon aHairLinePolyPolygon;
1228 if(0.0 == rStroke.getFullDotDashLen())
1230 aHairLinePolyPolygon.append(rBasePolygon);
1232 else
1234 basegfx::tools::applyLineDashing(
1235 rBasePolygon, rStroke.getDotDashArray(),
1236 &aHairLinePolyPolygon, 0, rStroke.getFullDotDashLen());
1239 const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLine.getColor()));
1240 mpOutputDevice->SetLineColor(Color(aHairlineColor));
1241 mpOutputDevice->SetFillColor();
1242 aHairLinePolyPolygon.transform(maCurrentTransformation);
1244 // use the transformed line width
1245 LineInfo aLineInfo(LINE_SOLID, basegfx::fround(getTransformedLineWidth(rLine.getWidth())));
1246 aLineInfo.SetLineJoin(rLine.getLineJoin());
1247 aLineInfo.SetLineCap(rLine.getLineCap());
1249 for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++)
1251 const basegfx::B2DPolygon aCandidate(aHairLinePolyPolygon.getB2DPolygon(a));
1253 if(aCandidate.count() > 1)
1255 const Polygon aToolsPolygon(aCandidate);
1257 mpMetaFile->AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo));
1261 else
1263 process(rCandidate.get2DDecomposition(getViewInformation2D()));
1266 impEndSvtGraphicStroke(pSvtGraphicStroke);
1269 break;
1271 case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D :
1273 const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive = static_cast< const primitive2d::PolygonStrokeArrowPrimitive2D& >(rCandidate);
1274 const basegfx::B2DPolygon& rBasePolygon = rStrokeArrowPrimitive.getB2DPolygon();
1276 if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
1278 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1279 // per polygon. If there are more, split the polygon in half and call recursively
1280 basegfx::B2DPolygon aLeft, aRight;
1281 splitLinePolygon(rBasePolygon, aLeft, aRight);
1282 const attribute::LineStartEndAttribute aEmpty;
1283 const primitive2d::PolygonStrokeArrowPrimitive2D aPLeft(
1284 aLeft,
1285 rStrokeArrowPrimitive.getLineAttribute(),
1286 rStrokeArrowPrimitive.getStrokeAttribute(),
1287 rStrokeArrowPrimitive.getStart(),
1288 aEmpty);
1289 const primitive2d::PolygonStrokeArrowPrimitive2D aPRight(
1290 aRight,
1291 rStrokeArrowPrimitive.getLineAttribute(),
1292 rStrokeArrowPrimitive.getStrokeAttribute(),
1293 aEmpty,
1294 rStrokeArrowPrimitive.getEnd());
1296 processBasePrimitive2D(aPLeft);
1297 processBasePrimitive2D(aPRight);
1299 else
1301 // support SvtGraphicStroke MetaCommentAction
1302 SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
1303 rBasePolygon, 0,
1304 &rStrokeArrowPrimitive.getLineAttribute(),
1305 &rStrokeArrowPrimitive.getStrokeAttribute(),
1306 &rStrokeArrowPrimitive.getStart(),
1307 &rStrokeArrowPrimitive.getEnd());
1309 // write LineGeometry start marker
1310 impStartSvtGraphicStroke(pSvtGraphicStroke);
1312 // #i116162# When B&W is set as DrawMode, DRAWMODE_WHITEFILL is used
1313 // to let all fills be just white; for lines DRAWMODE_BLACKLINE is used
1314 // so all line geometry is supposed to get black. Since in the in-between
1315 // stages of line geometry drawing filled polygons are used (e.g. line
1316 // start/ends) it is necessary to change these drawmodes to preserve
1317 // that lines shall be black; thus change DRAWMODE_WHITEFILL to
1318 // DRAWMODE_BLACKFILL during line geometry processing to have line geometry
1319 // parts filled black.
1320 const sal_uLong nOldDrawMode(mpOutputDevice->GetDrawMode());
1321 const bool bDrawmodeChange(nOldDrawMode & DRAWMODE_WHITEFILL && mnSvtGraphicStrokeCount);
1323 if(bDrawmodeChange)
1325 mpOutputDevice->SetDrawMode((nOldDrawMode & ~DRAWMODE_WHITEFILL) | DRAWMODE_BLACKFILL);
1328 // process sub-line geometry (evtl. filled PolyPolygons)
1329 process(rCandidate.get2DDecomposition(getViewInformation2D()));
1331 if(bDrawmodeChange)
1333 mpOutputDevice->SetDrawMode(nOldDrawMode);
1336 // write LineGeometry end marker
1337 impEndSvtGraphicStroke(pSvtGraphicStroke);
1340 break;
1342 case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
1344 // direct draw of transformed BitmapEx primitive; use default processing
1345 RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
1346 break;
1348 case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D :
1350 // need to handle PolyPolygonBitmapPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
1351 const primitive2d::PolyPolygonBitmapPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate);
1352 basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon());
1354 if(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1356 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1357 // per polygon. If there are more use the splitted polygon and call recursively
1358 const primitive2d::PolyPolygonBitmapPrimitive2D aSplitted(
1359 aLocalPolyPolygon,
1360 rBitmapCandidate.getFillBitmap());
1362 processBasePrimitive2D(aSplitted);
1364 else
1366 SvtGraphicFill* pSvtGraphicFill = 0;
1368 if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1370 aLocalPolyPolygon.transform(maCurrentTransformation);
1371 // calculate transformation. Get real object size, all values in FillBitmapAttribute
1372 // are relative to the unified object
1373 const attribute::FillBitmapAttribute& rFillBitmapAttribute = rBitmapCandidate .getFillBitmap();
1374 const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(aLocalPolyPolygon));
1375 const basegfx::B2DVector aOutlineSize(aOutlineRange.getRange());
1377 // get absolute values
1378 const basegfx::B2DVector aFillBitmapSize(rFillBitmapAttribute.getSize() * aOutlineSize);
1379 const basegfx::B2DPoint aFillBitmapTopLeft(rFillBitmapAttribute.getTopLeft() * aOutlineSize);
1381 // the scaling needs scale from pixel to logic coordinate system
1382 const BitmapEx& rBitmapEx = rFillBitmapAttribute.getBitmapEx();
1383 Size aBmpSizePixel(rBitmapEx.GetSizePixel());
1385 if(!aBmpSizePixel.Width())
1387 aBmpSizePixel.Width() = 1;
1390 if(!aBmpSizePixel.Height())
1392 aBmpSizePixel.Height() = 1;
1395 // setup transformation like in impgrfll
1396 SvtGraphicFill::Transform aTransform;
1398 // scale values are divided by bitmap pixel sizes
1399 aTransform.matrix[0] = aFillBitmapSize.getX() / aBmpSizePixel.Width();
1400 aTransform.matrix[4] = aFillBitmapSize.getY() / aBmpSizePixel.Height();
1402 // translates are absolute
1403 aTransform.matrix[2] = aFillBitmapTopLeft.getX();
1404 aTransform.matrix[5] = aFillBitmapTopLeft.getY();
1406 // setup fill graphic like in impgrfll
1407 Graphic aFillGraphic = Graphic(rBitmapEx);
1408 aFillGraphic.SetPrefMapMode(MapMode(MAP_PIXEL));
1409 aFillGraphic.SetPrefSize(aBmpSizePixel);
1411 pSvtGraphicFill = new SvtGraphicFill(
1412 getFillPolyPolygon(aLocalPolyPolygon),
1413 Color(),
1414 0.0,
1415 SvtGraphicFill::fillEvenOdd,
1416 SvtGraphicFill::fillTexture,
1417 aTransform,
1418 rFillBitmapAttribute.getTiling(),
1419 SvtGraphicFill::hatchSingle,
1420 Color(),
1421 SvtGraphicFill::gradientLinear,
1422 Color(),
1423 Color(),
1425 aFillGraphic);
1428 // Do use decomposition; encapsulate with SvtGraphicFill
1429 impStartSvtGraphicFill(pSvtGraphicFill);
1430 process(rCandidate.get2DDecomposition(getViewInformation2D()));
1431 impEndSvtGraphicFill(pSvtGraphicFill);
1434 break;
1436 case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D :
1438 // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
1439 const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate = static_cast< const primitive2d::PolyPolygonHatchPrimitive2D& >(rCandidate);
1440 const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch();
1441 basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon());
1443 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1444 // per polygon. Split polygon until there are less than that
1445 while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1448 if(rFillHatchAttribute.isFillBackground())
1450 // with fixing #i111954# (see below) the possible background
1451 // fill of a hatched object was lost.Generate a background fill
1452 // primitive and render it
1453 const primitive2d::Primitive2DReference xBackground(
1454 new primitive2d::PolyPolygonColorPrimitive2D(
1455 aLocalPolyPolygon,
1456 rHatchCandidate.getBackgroundColor()));
1458 process(primitive2d::Primitive2DSequence(&xBackground, 1));
1461 SvtGraphicFill* pSvtGraphicFill = 0;
1462 aLocalPolyPolygon.transform(maCurrentTransformation);
1464 if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1466 // re-create a VCL hatch as base data
1467 SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle);
1469 switch(rFillHatchAttribute.getStyle())
1471 default: // attribute::HATCHSTYLE_SINGLE :
1473 eHatch = SvtGraphicFill::hatchSingle;
1474 break;
1476 case attribute::HATCHSTYLE_DOUBLE :
1478 eHatch = SvtGraphicFill::hatchDouble;
1479 break;
1481 case attribute::HATCHSTYLE_TRIPLE :
1483 eHatch = SvtGraphicFill::hatchTriple;
1484 break;
1488 SvtGraphicFill::Transform aTransform;
1490 // scale
1491 aTransform.matrix[0] *= rFillHatchAttribute.getDistance();
1492 aTransform.matrix[4] *= rFillHatchAttribute.getDistance();
1494 // rotate (was never correct in impgrfll anyways, use correct angle now)
1495 aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle());
1496 aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle());
1497 aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle());
1498 aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle());
1500 pSvtGraphicFill = new SvtGraphicFill(
1501 getFillPolyPolygon(aLocalPolyPolygon),
1502 Color(),
1503 0.0,
1504 SvtGraphicFill::fillEvenOdd,
1505 SvtGraphicFill::fillHatch,
1506 aTransform,
1507 false,
1508 eHatch,
1509 Color(rFillHatchAttribute.getColor()),
1510 SvtGraphicFill::gradientLinear,
1511 Color(),
1512 Color(),
1514 Graphic());
1517 // Do use decomposition; encapsulate with SvtGraphicFill
1518 impStartSvtGraphicFill(pSvtGraphicFill);
1520 // #i111954# do NOT use decomposition, but use direct VCL-command
1521 // process(rCandidate.get2DDecomposition(getViewInformation2D()));
1522 const PolyPolygon aToolsPolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(aLocalPolyPolygon));
1523 const HatchStyle aHatchStyle(
1524 attribute::HATCHSTYLE_SINGLE == rFillHatchAttribute.getStyle() ? HATCH_SINGLE :
1525 attribute::HATCHSTYLE_DOUBLE == rFillHatchAttribute.getStyle() ? HATCH_DOUBLE :
1526 HATCH_TRIPLE);
1528 mpOutputDevice->DrawHatch(aToolsPolyPolygon,
1529 Hatch(aHatchStyle,
1530 Color(rFillHatchAttribute.getColor()),
1531 basegfx::fround(rFillHatchAttribute.getDistance()),
1532 basegfx::fround(rFillHatchAttribute.getAngle() / F_PI1800)));
1534 impEndSvtGraphicFill(pSvtGraphicFill);
1536 break;
1538 case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D :
1540 basegfx::B2DVector aScale, aTranslate;
1541 double fRotate, fShearX;
1543 maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
1545 if(!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX))
1547 // #i121185# When rotation or shear is used, a VCL Gradient cannot be used directly.
1548 // This is because VCL Gradient mechanism does *not* support to rotate the gradient
1549 // with objects and this case is not expressable in a Metafile (and cannot be added
1550 // since the FileFormats used, e.g. *.wmf, do not support it either).
1551 // Such cases happen when a graphic object uses a Metafile as graphic information or
1552 // a fill style definition uses a Metafile. In this cases the graphic content is
1553 // rotated with the graphic or filled object; this is not supported by the target
1554 // format of this conversion renderer - Metafiles.
1555 // To solve this, not a Gradient is written, but the decomposition of this object
1556 // is written to the Metafile. This is the PolyPolygons building the gradient fill.
1557 // These will need more space and time, but the result will be as if the Gradient
1558 // was rotated with the object.
1559 // This mechanism is used by all exporters still not using Primtives (e.g. Print,
1560 // Slideshow, Export rto PDF, export to Picture, ...) but relying on Metafile
1561 // transfers. One more reason to *change* these to primitives.
1562 // BTW: One more example how useful the principles of primitives are; the decomposition
1563 // is by definition a simpler, maybe more expensive representation of the same content.
1564 process(rCandidate.get2DDecomposition(getViewInformation2D()));
1566 else
1568 const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate);
1569 basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon());
1571 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1572 // per polygon. Split polygon until there are less than that
1573 while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1576 // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END
1577 // it is safest to use the VCL OutputDevice::DrawGradient method which creates those.
1578 // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon
1579 Gradient aVCLGradient;
1580 impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false);
1581 aLocalPolyPolygon.transform(maCurrentTransformation);
1583 // #i82145# ATM VCL printing of gradients using curved shapes does not work,
1584 // i submitted the bug with the given ID to THB. When that task is fixed it is
1585 // necessary to again remove this subdivision since it decreases possible
1586 // printing quality (not even resolution-dependent for now). THB will tell
1587 // me when that task is fixed in the master
1588 const PolyPolygon aToolsPolyPolygon(
1589 getFillPolyPolygon(
1590 basegfx::tools::adaptiveSubdivideByAngle(aLocalPolyPolygon)));
1593 // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
1594 SvtGraphicFill* pSvtGraphicFill = 0;
1596 if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1598 // setup gradient stuff like in like in impgrfll
1599 SvtGraphicFill::GradientType eGrad(SvtGraphicFill::gradientLinear);
1601 switch(aVCLGradient.GetStyle())
1603 default : // GradientStyle_LINEAR:
1604 case GradientStyle_AXIAL:
1605 eGrad = SvtGraphicFill::gradientLinear;
1606 break;
1607 case GradientStyle_RADIAL:
1608 case GradientStyle_ELLIPTICAL:
1609 eGrad = SvtGraphicFill::gradientRadial;
1610 break;
1611 case GradientStyle_SQUARE:
1612 case GradientStyle_RECT:
1613 eGrad = SvtGraphicFill::gradientRectangular;
1614 break;
1617 pSvtGraphicFill = new SvtGraphicFill(
1618 aToolsPolyPolygon,
1619 Color(),
1620 0.0,
1621 SvtGraphicFill::fillEvenOdd,
1622 SvtGraphicFill::fillGradient,
1623 SvtGraphicFill::Transform(),
1624 false,
1625 SvtGraphicFill::hatchSingle,
1626 Color(),
1627 eGrad,
1628 aVCLGradient.GetStartColor(),
1629 aVCLGradient.GetEndColor(),
1630 aVCLGradient.GetSteps(),
1631 Graphic());
1634 // call VCL directly; encapsulate with SvtGraphicFill
1635 impStartSvtGraphicFill(pSvtGraphicFill);
1636 mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient);
1637 impEndSvtGraphicFill(pSvtGraphicFill);
1639 // NO usage of common own gradient randerer, not used ATM for VCL MetaFile, see text above
1640 // RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate));
1643 break;
1645 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
1647 const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate));
1648 basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
1650 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1651 // per polygon. Split polygon until there are less than that
1652 while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1655 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
1656 aLocalPolyPolygon.transform(maCurrentTransformation);
1658 // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
1659 SvtGraphicFill* pSvtGraphicFill = 0;
1661 if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1663 // setup simple color fill stuff like in impgrfll
1664 pSvtGraphicFill = new SvtGraphicFill(
1665 getFillPolyPolygon(aLocalPolyPolygon),
1666 Color(aPolygonColor),
1667 0.0,
1668 SvtGraphicFill::fillEvenOdd,
1669 SvtGraphicFill::fillSolid,
1670 SvtGraphicFill::Transform(),
1671 false,
1672 SvtGraphicFill::hatchSingle,
1673 Color(),
1674 SvtGraphicFill::gradientLinear,
1675 Color(),
1676 Color(),
1678 Graphic());
1681 // set line and fill color
1682 mpOutputDevice->SetFillColor(Color(aPolygonColor));
1683 mpOutputDevice->SetLineColor();
1685 // call VCL directly; encapsulate with SvtGraphicFill
1686 impStartSvtGraphicFill(pSvtGraphicFill);
1687 mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
1688 impEndSvtGraphicFill(pSvtGraphicFill);
1690 break;
1692 case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
1694 static bool bUseMetaFilePrimitiveDecomposition(true);
1695 const primitive2d::MetafilePrimitive2D& aMetafile = static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate);
1697 if(bUseMetaFilePrimitiveDecomposition && !aMetafile.getMetaFile().GetUseCanvas())
1699 // use new Metafile decomposition
1700 process(rCandidate.get2DDecomposition(getViewInformation2D()));
1702 else
1704 // direct draw of MetaFile, use default pocessing
1705 RenderMetafilePrimitive2D(aMetafile);
1708 break;
1710 case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
1712 // mask group. Special handling for MetaFiles.
1713 const primitive2d::MaskPrimitive2D& rMaskCandidate = static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate);
1715 if(rMaskCandidate.getChildren().hasElements())
1717 basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
1719 if(aMask.count())
1721 // prepare new mask polygon and rescue current one
1722 aMask.transform(maCurrentTransformation);
1723 const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon);
1725 if(maClipPolyPolygon.count())
1727 // there is already a clip polygon set; build clipped union of
1728 // current mask polygon and new one
1729 maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
1730 aMask,
1731 maClipPolyPolygon,
1732 true, // #i106516# we want the inside of aMask, not the outside
1733 false);
1735 else
1737 // use mask directly
1738 maClipPolyPolygon = aMask;
1741 if(maClipPolyPolygon.count())
1743 // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!)
1744 // Removed subdivision and fixed in Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where
1745 // the ClipRegion is built from the Polygon. A AdaptiveSubdivide on the source polygon was missing there
1746 mpOutputDevice->Push(PUSH_CLIPREGION);
1747 //mpOutputDevice->SetClipRegion(Region(PolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(maClipPolyPolygon))));
1748 //mpOutputDevice->SetClipRegion(Region(PolyPolygon(maClipPolyPolygon)));
1749 mpOutputDevice->SetClipRegion(Region(maClipPolyPolygon));
1752 // recursively paint content
1753 process(rMaskCandidate.getChildren());
1755 if(maClipPolyPolygon.count())
1757 // restore VCL clip region
1758 mpOutputDevice->Pop();
1761 // restore to rescued clip polygon
1762 maClipPolyPolygon = aLastClipPolyPolygon;
1764 else
1766 // no mask, no clipping. recursively paint content
1767 process(rMaskCandidate.getChildren());
1771 break;
1773 case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
1775 // modified color group. Force output to unified color. Use default pocessing.
1776 RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate));
1777 break;
1779 case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D :
1781 // for metafile: Need to examine what the pure vcl version is doing here actually
1782 // - uses DrawTransparent with metafile for content and a gradient
1783 // - uses DrawTransparent for single PolyPoylgons directly. Can be detected by
1784 // checking the content for single PolyPolygonColorPrimitive2D
1785 const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate = static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate);
1786 const primitive2d::Primitive2DSequence rContent = rUniTransparenceCandidate.getChildren();
1788 if(rContent.hasElements())
1790 if(0.0 == rUniTransparenceCandidate.getTransparence())
1792 // not transparent at all, use content
1793 process(rUniTransparenceCandidate.getChildren());
1795 else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0)
1797 // try to identify a single PolyPolygonColorPrimitive2D in the
1798 // content part of the transparence primitive
1799 const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = 0;
1800 static bool bForceToMetafile(false);
1802 if(!bForceToMetafile && 1 == rContent.getLength())
1804 const primitive2d::Primitive2DReference xReference(rContent[0]);
1805 pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get());
1808 // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and
1809 // PolyPolygonBitmapPrimitive2D are derived from PolyPolygonColorPrimitive2D.
1810 // Check also for correct ID to exclude derived implementations
1811 if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID())
1813 // single transparent PolyPolygon identified, use directly
1814 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor()));
1815 basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon());
1817 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1818 // per polygon. Split polygon until there are less than that
1819 while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1822 // now transform
1823 aLocalPolyPolygon.transform(maCurrentTransformation);
1825 // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
1826 SvtGraphicFill* pSvtGraphicFill = 0;
1828 if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1830 // setup simple color with transparence fill stuff like in impgrfll
1831 pSvtGraphicFill = new SvtGraphicFill(
1832 getFillPolyPolygon(aLocalPolyPolygon),
1833 Color(aPolygonColor),
1834 rUniTransparenceCandidate.getTransparence(),
1835 SvtGraphicFill::fillEvenOdd,
1836 SvtGraphicFill::fillSolid,
1837 SvtGraphicFill::Transform(),
1838 false,
1839 SvtGraphicFill::hatchSingle,
1840 Color(),
1841 SvtGraphicFill::gradientLinear,
1842 Color(),
1843 Color(),
1845 Graphic());
1848 // set line and fill color
1849 const sal_uInt16 nTransPercentVcl((sal_uInt16)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 100.0));
1850 mpOutputDevice->SetFillColor(Color(aPolygonColor));
1851 mpOutputDevice->SetLineColor();
1853 // call VCL directly; encapsulate with SvtGraphicFill
1854 impStartSvtGraphicFill(pSvtGraphicFill);
1855 mpOutputDevice->DrawTransparent(
1856 PolyPolygon(aLocalPolyPolygon),
1857 nTransPercentVcl);
1858 impEndSvtGraphicFill(pSvtGraphicFill);
1860 else
1862 // svae old mfCurrentUnifiedTransparence and set new one
1863 // so that contained SvtGraphicStroke may use the current one
1864 const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence);
1865 // #i105377# paint the content metafile opaque as the transparency gets
1866 // split of into the gradient below
1867 // mfCurrentUnifiedTransparence = rUniTransparenceCandidate.getTransparence();
1868 mfCurrentUnifiedTransparence = 0;
1870 // various content, create content-metafile
1871 GDIMetaFile aContentMetafile;
1872 const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
1874 // restore mfCurrentUnifiedTransparence; it may have been used
1875 // while processing the sub-content in impDumpToMetaFile
1876 mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence;
1878 // create uniform VCL gradient for uniform transparency
1879 Gradient aVCLGradient;
1880 const sal_uInt8 nTransPercentVcl((sal_uInt8)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 255.0));
1881 const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl);
1883 aVCLGradient.SetStyle(GradientStyle_LINEAR);
1884 aVCLGradient.SetStartColor(aTransColor);
1885 aVCLGradient.SetEndColor(aTransColor);
1886 aVCLGradient.SetAngle(0);
1887 aVCLGradient.SetBorder(0);
1888 aVCLGradient.SetOfsX(0);
1889 aVCLGradient.SetOfsY(0);
1890 aVCLGradient.SetStartIntensity(100);
1891 aVCLGradient.SetEndIntensity(100);
1892 aVCLGradient.SetSteps(2);
1894 // render it to VCL
1895 mpOutputDevice->DrawTransparent(
1896 aContentMetafile, aPrimitiveRectangle.TopLeft(),
1897 aPrimitiveRectangle.GetSize(), aVCLGradient);
1902 break;
1904 case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
1906 // for metafile: Need to examine what the pure vcl version is doing here actually
1907 // - uses DrawTransparent with metafile for content and a gradient
1908 // i can detect this here with checking the gradient part for a single
1909 // FillGradientPrimitive2D and reconstruct the gradient.
1910 // If that detection goes wrong, i have to create an transparence-blended bitmap. Eventually
1911 // do that in stripes, else RenderTransparencePrimitive2D may just be used
1912 const primitive2d::TransparencePrimitive2D& rTransparenceCandidate = static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate);
1913 const primitive2d::Primitive2DSequence rContent = rTransparenceCandidate.getChildren();
1914 const primitive2d::Primitive2DSequence rTransparence = rTransparenceCandidate.getTransparence();
1916 if(rContent.hasElements() && rTransparence.hasElements())
1918 // try to identify a single FillGradientPrimitive2D in the
1919 // transparence part of the primitive
1920 const primitive2d::FillGradientPrimitive2D* pFiGradient = 0;
1921 static bool bForceToBigTransparentVDev(false);
1923 if(!bForceToBigTransparentVDev && 1 == rTransparence.getLength())
1925 const primitive2d::Primitive2DReference xReference(rTransparence[0]);
1926 pFiGradient = dynamic_cast< const primitive2d::FillGradientPrimitive2D* >(xReference.get());
1929 // Check also for correct ID to exclude derived implementations
1930 if(pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitive2DID())
1932 // various content, create content-metafile
1933 GDIMetaFile aContentMetafile;
1934 const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
1936 // re-create a VCL-gradient from FillGradientPrimitive2D
1937 Gradient aVCLGradient;
1938 impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(), true);
1940 // render it to VCL
1941 mpOutputDevice->DrawTransparent(
1942 aContentMetafile, aPrimitiveRectangle.TopLeft(),
1943 aPrimitiveRectangle.GetSize(), aVCLGradient);
1945 else
1947 // sub-transparence group. Draw to VDev first.
1948 // this may get refined to tiling when resolution is too big here
1950 // need to avoid switching off MapMode stuff here; maybe need another
1951 // tooling class, cannot just do the same as with the pixel renderer.
1952 // Need to experiment...
1954 // Okay, basic implementation finished and tested. The DPI stuff was hard
1955 // and not easy to find out that it's needed.
1956 // Since this will not yet happen normally (as long as noone constructs
1957 // transparence primitives with non-trivial transparence content) i will for now not
1958 // refine to tiling here.
1960 basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
1961 aViewRange.transform(maCurrentTransformation);
1962 const Rectangle aRectLogic(
1963 (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()),
1964 (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY()));
1965 const Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic));
1966 Size aSizePixel(aRectPixel.GetSize());
1967 const Point aEmptyPoint;
1968 VirtualDevice aBufferDevice;
1969 const sal_uInt32 nMaxQuadratPixels(500000);
1970 const sal_uInt32 nViewVisibleArea(aSizePixel.getWidth() * aSizePixel.getHeight());
1971 double fReduceFactor(1.0);
1973 if(nViewVisibleArea > nMaxQuadratPixels)
1975 // reduce render size
1976 fReduceFactor = sqrt((double)nMaxQuadratPixels / (double)nViewVisibleArea);
1977 aSizePixel = Size(basegfx::fround((double)aSizePixel.getWidth() * fReduceFactor),
1978 basegfx::fround((double)aSizePixel.getHeight() * fReduceFactor));
1981 if(aBufferDevice.SetOutputSizePixel(aSizePixel))
1983 // create and set MapModes for target devices
1984 MapMode aNewMapMode(mpOutputDevice->GetMapMode());
1985 aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top()));
1986 aBufferDevice.SetMapMode(aNewMapMode);
1988 // prepare view transformation for target renderers
1989 // ATTENTION! Need to apply another scaling because of the potential DPI differences
1990 // between Printer and VDev (mpOutputDevice and aBufferDevice here).
1991 // To get the DPI, LogicToPixel from (1,1) from MAP_INCH needs to be used.
1992 basegfx::B2DHomMatrix aViewTransform(aBufferDevice.GetViewTransformation());
1993 const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MAP_INCH));
1994 const Size aDPINew(aBufferDevice.LogicToPixel(Size(1, 1), MAP_INCH));
1995 const double fDPIXChange((double)aDPIOld.getWidth() / (double)aDPINew.getWidth());
1996 const double fDPIYChange((double)aDPIOld.getHeight() / (double)aDPINew.getHeight());
1998 if(!basegfx::fTools::equal(fDPIXChange, 1.0) || !basegfx::fTools::equal(fDPIYChange, 1.0))
2000 aViewTransform.scale(fDPIXChange, fDPIYChange);
2003 // also take scaling from Size reduction into acount
2004 if(!basegfx::fTools::equal(fReduceFactor, 1.0))
2006 aViewTransform.scale(fReduceFactor, fReduceFactor);
2009 // create view information and pixel renderer. Reuse known ViewInformation
2010 // except new transformation and range
2011 const geometry::ViewInformation2D aViewInfo(
2012 getViewInformation2D().getObjectTransformation(),
2013 aViewTransform,
2014 aViewRange,
2015 getViewInformation2D().getVisualizedPage(),
2016 getViewInformation2D().getViewTime(),
2017 getViewInformation2D().getExtendedInformationSequence());
2019 VclPixelProcessor2D aBufferProcessor(aViewInfo, aBufferDevice);
2021 // draw content using pixel renderer
2022 aBufferProcessor.process(rContent);
2023 const Bitmap aBmContent(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel));
2025 // draw transparence using pixel renderer
2026 aBufferDevice.Erase();
2027 aBufferProcessor.process(rTransparence);
2028 const AlphaMask aBmAlpha(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel));
2030 // paint
2031 mpOutputDevice->DrawBitmapEx(
2032 aRectLogic.TopLeft(),
2033 aRectLogic.GetSize(),
2034 BitmapEx(aBmContent, aBmAlpha));
2039 break;
2041 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
2043 // use default transform group pocessing
2044 RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
2045 break;
2047 case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
2049 // new XDrawPage for ViewInformation2D
2050 RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate));
2051 break;
2053 case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
2055 // use default marker array pocessing
2056 RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate));
2057 break;
2059 case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
2061 // use default point array pocessing
2062 RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate));
2063 break;
2065 case PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D :
2067 // structured tag primitive
2068 const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate = static_cast< const primitive2d::StructureTagPrimitive2D& >(rCandidate);
2069 const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement());
2070 const bool bTagUsed(vcl::PDFWriter::NonStructElement != rTagElement);
2072 if(mpPDFExtOutDevData && bTagUsed)
2074 // write start tag
2075 mpPDFExtOutDevData->BeginStructureElement(rTagElement);
2078 // proccess children normally
2079 process(rStructureTagCandidate.getChildren());
2081 if(mpPDFExtOutDevData && bTagUsed)
2083 // write end tag
2084 mpPDFExtOutDevData->EndStructureElement();
2087 break;
2089 case PRIMITIVE2D_ID_EPSPRIMITIVE2D :
2091 RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate));
2092 break;
2094 default :
2096 // process recursively
2097 process(rCandidate.get2DDecomposition(getViewInformation2D()));
2098 break;
2102 } // end of namespace processor2d
2103 } // end of namespace drawinglayer
2105 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */