update dev300-m58
[ooovba.git] / drawinglayer / source / processor2d / vclmetafileprocessor2d.cxx
blob82db20f2b35b5c4fa0c6d258ce319cb9d58155af
1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile: vclmetafileprocessor2d.cxx,v $
7 * $Revision: 1.25 $
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/vclmetafileprocessor2d.hxx>
40 #include <tools/gen.hxx>
41 #include <vcl/virdev.hxx>
42 #include <vcl/gdimtf.hxx>
43 #include <vcl/gradient.hxx>
44 #include <drawinglayer/attribute/fillattribute.hxx>
45 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
46 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
47 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
48 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
49 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
50 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
51 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
52 #include <basegfx/polygon/b2dpolygonclipper.hxx>
53 #include <basegfx/polygon/b2dpolypolygontools.hxx>
54 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
55 #include <drawinglayer/primitive2d/unifiedalphaprimitive2d.hxx>
56 #include <drawinglayer/primitive2d/alphaprimitive2d.hxx>
57 #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
58 #include <drawinglayer/processor2d/vclpixelprocessor2d.hxx>
59 #include <tools/stream.hxx>
60 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
61 #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
62 #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
63 #include <vcl/graphictools.hxx>
64 #include <vcl/metaact.hxx>
65 #include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
66 #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
67 #include <comphelper/processfactory.hxx>
68 #include <rtl/ustring.hxx>
69 #include <com/sun/star/i18n/CharacterIteratorMode.hdl>
70 #include <com/sun/star/i18n/WordType.hpp>
71 #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
72 #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
73 #include <basegfx/polygon/b2dpolygontools.hxx>
74 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
75 #include <helperchartrenderer.hxx>
76 #include <drawinglayer/primitive2d/hittestprimitive2d.hxx>
78 //////////////////////////////////////////////////////////////////////////////
79 // for PDFExtOutDevData Graphic support
81 #include <vcl/graph.hxx>
82 #include <vcl/svapp.hxx>
83 #include <toolkit/helper/formpdfexport.hxx>
85 //////////////////////////////////////////////////////////////////////////////
86 // for Control printing
88 #include <com/sun/star/beans/XPropertySet.hpp>
90 //////////////////////////////////////////////////////////////////////////////
91 // for current chart PrettyPrinting support
93 #include <drawinglayer/primitive2d/chartprimitive2d.hxx>
95 //////////////////////////////////////////////////////////////////////////////
96 // for StructureTagPrimitive support in sd's unomodel.cxx
98 #include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
100 //////////////////////////////////////////////////////////////////////////////
102 using namespace com::sun::star;
104 //////////////////////////////////////////////////////////////////////////////
106 namespace drawinglayer
108 namespace processor2d
110 Rectangle VclMetafileProcessor2D::impDumpToMetaFile(
111 const primitive2d::Primitive2DSequence& rContent,
112 GDIMetaFile& o_rContentMetafile)
114 // Prepare VDev, MetaFile and connections
115 OutputDevice* pLastOutputDevice = mpOutputDevice;
116 basegfx::B2DRange aPrimitiveRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
118 // transform primitive range with current transformation (e.g shadow offset)
119 aPrimitiveRange.transform(maCurrentTransformation);
121 const Rectangle aPrimitiveRectangle(
122 basegfx::fround(aPrimitiveRange.getMinX()), basegfx::fround(aPrimitiveRange.getMinY()),
123 basegfx::fround(aPrimitiveRange.getMaxX()), basegfx::fround(aPrimitiveRange.getMaxY()));
124 VirtualDevice aContentVDev;
125 MapMode aNewMapMode(pLastOutputDevice->GetMapMode());
127 mpOutputDevice = &aContentVDev;
128 aContentVDev.EnableOutput(false);
129 aContentVDev.SetMapMode(pLastOutputDevice->GetMapMode());
130 o_rContentMetafile.Record(&aContentVDev);
131 aContentVDev.SetLineColor(pLastOutputDevice->GetLineColor());
132 aContentVDev.SetFillColor(pLastOutputDevice->GetFillColor());
133 aContentVDev.SetFont(pLastOutputDevice->GetFont());
134 aContentVDev.SetDrawMode(pLastOutputDevice->GetDrawMode());
135 aContentVDev.SetSettings(pLastOutputDevice->GetSettings());
136 aContentVDev.SetRefPoint(pLastOutputDevice->GetRefPoint());
138 // dump to MetaFile
139 process(rContent);
141 // cleanups
142 o_rContentMetafile.Stop();
143 o_rContentMetafile.WindStart();
144 aNewMapMode.SetOrigin(aPrimitiveRectangle.TopLeft());
145 o_rContentMetafile.SetPrefMapMode(aNewMapMode);
146 o_rContentMetafile.SetPrefSize(aPrimitiveRectangle.GetSize());
147 mpOutputDevice = pLastOutputDevice;
149 return aPrimitiveRectangle;
152 void VclMetafileProcessor2D::impConvertFillGradientAttributeToVCLGradient(
153 Gradient& o_rVCLGradient,
154 const attribute::FillGradientAttribute& rFiGrAtt,
155 bool bIsTransparenceGradient)
157 if(bIsTransparenceGradient)
159 // it's about alpha channel intensities (black/white), do not use color modifier
160 o_rVCLGradient.SetStartColor(Color(rFiGrAtt.getStartColor()));
161 o_rVCLGradient.SetEndColor(Color(rFiGrAtt.getEndColor()));
163 else
165 // use color modifier to influence start/end color of gradient
166 o_rVCLGradient.SetStartColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getStartColor())));
167 o_rVCLGradient.SetEndColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getEndColor())));
170 o_rVCLGradient.SetAngle(static_cast< sal_uInt16 >(rFiGrAtt.getAngle() * (1.0 / F_PI1800)));
171 o_rVCLGradient.SetBorder(static_cast< sal_uInt16 >(rFiGrAtt.getBorder() * 100.0));
172 o_rVCLGradient.SetOfsX(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetX() * 100.0));
173 o_rVCLGradient.SetOfsY(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetY() * 100.0));
174 o_rVCLGradient.SetSteps(rFiGrAtt.getSteps());
176 // defaults for intensity; those were computed into the start/end colors already
177 o_rVCLGradient.SetStartIntensity(100);
178 o_rVCLGradient.SetEndIntensity(100);
180 switch(rFiGrAtt.getStyle())
182 default : // attribute::GRADIENTSTYLE_LINEAR :
184 o_rVCLGradient.SetStyle(GRADIENT_LINEAR);
185 break;
187 case attribute::GRADIENTSTYLE_AXIAL :
189 o_rVCLGradient.SetStyle(GRADIENT_AXIAL);
190 break;
192 case attribute::GRADIENTSTYLE_RADIAL :
194 o_rVCLGradient.SetStyle(GRADIENT_RADIAL);
195 break;
197 case attribute::GRADIENTSTYLE_ELLIPTICAL :
199 o_rVCLGradient.SetStyle(GRADIENT_ELLIPTICAL);
200 break;
202 case attribute::GRADIENTSTYLE_SQUARE :
204 o_rVCLGradient.SetStyle(GRADIENT_SQUARE);
205 break;
207 case attribute::GRADIENTSTYLE_RECT :
209 o_rVCLGradient.SetStyle(GRADIENT_RECT);
210 break;
215 void VclMetafileProcessor2D::impStartSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill)
217 if(pSvtGraphicFill && !mnSvtGraphicFillCount)
219 SvMemoryStream aMemStm;
221 aMemStm << *pSvtGraphicFill;
222 mrMetaFile.AddAction(new MetaCommentAction("XPATHFILL_SEQ_BEGIN", 0, static_cast< const BYTE* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END)));
223 mnSvtGraphicFillCount++;
227 void VclMetafileProcessor2D::impEndSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill)
229 if(pSvtGraphicFill && mnSvtGraphicFillCount)
231 mnSvtGraphicFillCount--;
232 mrMetaFile.AddAction(new MetaCommentAction("XPATHFILL_SEQ_END"));
233 delete pSvtGraphicFill;
237 SvtGraphicStroke* VclMetafileProcessor2D::impTryToCreateSvtGraphicStroke(
238 const basegfx::B2DPolygon& rB2DPolygon,
239 const basegfx::BColor* pColor,
240 const attribute::LineAttribute* pLineAttribute,
241 const attribute::StrokeAttribute* pStrokeAttribute,
242 const attribute::LineStartEndAttribute* pStart,
243 const attribute::LineStartEndAttribute* pEnd)
245 SvtGraphicStroke* pRetval = 0;
247 if(rB2DPolygon.count() && !mnSvtGraphicStrokeCount)
249 basegfx::BColor aStrokeColor;
250 basegfx::B2DPolyPolygon aStartArrow;
251 basegfx::B2DPolyPolygon aEndArrow;
253 if(pColor)
255 aStrokeColor = *pColor;
257 else if(pLineAttribute)
259 aStrokeColor = maBColorModifierStack.getModifiedColor(pLineAttribute->getColor());
262 // It IS needed to record the stroke color at all in the metafile,
263 // SvtGraphicStroke has NO entry for stroke color(!)
264 mpOutputDevice->SetLineColor(Color(aStrokeColor));
266 if(!rB2DPolygon.isClosed())
268 double fPolyLength(0.0);
270 if(pStart && pStart->isActive())
272 fPolyLength = basegfx::tools::getLength(rB2DPolygon);
274 aStartArrow = basegfx::tools::createAreaGeometryForLineStartEnd(
275 rB2DPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(),
276 fPolyLength, pStart->isCentered() ? 0.5 : 0.0, 0);
279 if(pEnd && pEnd->isActive())
281 if(basegfx::fTools::equalZero(fPolyLength))
283 fPolyLength = basegfx::tools::getLength(rB2DPolygon);
286 aEndArrow = basegfx::tools::createAreaGeometryForLineStartEnd(
287 rB2DPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(),
288 fPolyLength, pEnd->isCentered() ? 0.5 : 0.0, 0);
292 SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone);
293 double fLineWidth(0.0);
294 double fMiterLength(0.0);
295 SvtGraphicStroke::DashArray aDashArray;
297 if(pLineAttribute)
299 // pre-fill fLineWidth
300 fLineWidth = pLineAttribute->getWidth();
302 // pre-fill fMiterLength
303 fMiterLength = fLineWidth;
305 // get Join
306 switch(pLineAttribute->getLineJoin())
308 default : // basegfx::B2DLINEJOIN_NONE :
310 eJoin = SvtGraphicStroke::joinNone;
311 break;
313 case basegfx::B2DLINEJOIN_BEVEL :
315 eJoin = SvtGraphicStroke::joinBevel;
316 break;
318 case basegfx::B2DLINEJOIN_MIDDLE :
319 case basegfx::B2DLINEJOIN_MITER :
321 eJoin = SvtGraphicStroke::joinMiter;
322 // ATM 15 degrees is assumed
323 fMiterLength /= rtl::math::sin(M_PI * (15.0 / 360.0));
324 break;
326 case basegfx::B2DLINEJOIN_ROUND :
328 eJoin = SvtGraphicStroke::joinRound;
329 break;
334 if(pStrokeAttribute)
336 // copy dash array
337 aDashArray = pStrokeAttribute->getDotDashArray();
340 // #i101734# apply current object transformation to created geometry.
341 // This is a partial fix. When a object transformation is used which
342 // e.g. contains a scaleX != scaleY, an unproportional scaling would
343 // have to be applied to the evtl. existing fat line. The current
344 // concept of PDF export and SvtGraphicStroke usage does simply not
345 // allow handling such definitions. The only clean way would be to
346 // add the transformation to SvtGraphicStroke and to handle it there
347 basegfx::B2DPolygon aB2DPolygon(rB2DPolygon);
349 aB2DPolygon.transform(maCurrentTransformation);
350 aStartArrow.transform(maCurrentTransformation);
351 aEndArrow.transform(maCurrentTransformation);
353 pRetval = new SvtGraphicStroke(
354 Polygon(aB2DPolygon),
355 PolyPolygon(aStartArrow),
356 PolyPolygon(aEndArrow),
357 mfCurrentUnifiedTransparence,
358 fLineWidth,
359 SvtGraphicStroke::capButt,
360 eJoin,
361 fMiterLength,
362 aDashArray);
365 return pRetval;
368 void VclMetafileProcessor2D::impStartSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke)
370 if(pSvtGraphicStroke && !mnSvtGraphicStrokeCount)
372 SvMemoryStream aMemStm;
374 aMemStm << *pSvtGraphicStroke;
375 mrMetaFile.AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_BEGIN", 0, static_cast< const BYTE* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END)));
376 mnSvtGraphicStrokeCount++;
380 void VclMetafileProcessor2D::impEndSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke)
382 if(pSvtGraphicStroke && mnSvtGraphicStrokeCount)
384 mnSvtGraphicStrokeCount--;
385 mrMetaFile.AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_END"));
386 delete pSvtGraphicStroke;
390 // init static break iterator
391 uno::Reference< ::com::sun::star::i18n::XBreakIterator > VclMetafileProcessor2D::mxBreakIterator;
393 VclMetafileProcessor2D::VclMetafileProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev)
394 : VclProcessor2D(rViewInformation, rOutDev),
395 mrMetaFile(*rOutDev.GetConnectMetaFile()),
396 mnSvtGraphicFillCount(0),
397 mnSvtGraphicStrokeCount(0),
398 mfCurrentUnifiedTransparence(0.0),
399 mpPDFExtOutDevData(dynamic_cast< vcl::PDFExtOutDevData* >(rOutDev.GetExtOutDevData()))
401 OSL_ENSURE(rOutDev.GetConnectMetaFile(), "VclMetafileProcessor2D: Used on OutDev which has no MetaFile Target (!)");
402 // draw to logic coordinates, do not initialize maCurrentTransformation to viewTransformation
403 // but only to ObjectTransformation. Do not change MapMode of destination.
404 maCurrentTransformation = rViewInformation.getObjectTransformation();
407 VclMetafileProcessor2D::~VclMetafileProcessor2D()
409 // MapMode was not changed, no restore necessary
412 /***********************************************************************************************
414 Support of MetaCommentActions in the VclMetafileProcessor2D
415 Found MetaCommentActions and how they are supported:
417 XGRAD_SEQ_BEGIN, XGRAD_SEQ_END:
419 Used inside OutputDevice::DrawGradient to mark the start and end of a MetaGradientEx action.
420 It is used in various exporters/importers to have direct access to the gradient before it
421 is rendered by VCL (and thus fragmented to polygon color actions and others). On that base, e.g.
422 the Metafile to SdrObject import creates it's gradient objects.
423 Best (and safest) way to support it here is to use PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
424 map it back to the corresponding tools PolyPolygon and the Gradient and just call
425 OutputDevice::DrawGradient which creates the necessary compatible actions.
427 XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END:
429 Two producers, one is vcl/source/gdi/gdimtf.cxx, line 1273. There, it is transformed
430 inside GDIMetaFile::Rotate, nothing to take care of here.
431 The second producer is in graphics/svx/source/svdraw/impgrfll.cxx, line 374. This is used
432 with each incarnation of Imp_GraphicFill when a metafile is recorded, fillstyle is not
433 XFILL_NONE and not completely transparent. It creates a SvtGraphicFill and streams it
434 to the comment action. A closing end token is created in the destructor.
435 Usages of Imp_GraphicFill are in Do_Paint_Object-methods of SdrCircObj, SdrPathObj and
436 SdrRectObj.
437 The token users pick various actions from SvtGraphicFill, so it may need to be added for all kind
438 of filled objects, even simple colored polygons. It is added as extra information; the
439 Metafile actions between the two tokens are interpreted as output generated from those
440 fills. Thus, users have the choice to use the SvtGraphicFill info or the created output
441 actions.
442 Even for XFillTransparenceItem it is used, thus it may need to be supported in
443 UnifiedAlphaPrimitive2D, too, when interpreted as normally filled PolyPolygon.
444 Implemented for:
445 PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D,
446 PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D,
447 PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
448 PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D,
449 and for PRIMITIVE2D_ID_UNIFIEDALPHAPRIMITIVE2D when detected unified alpha
451 XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END:
453 Similar to pathfill, but using SvtGraphicStroke instead. It also has two producers where one
454 is also the GDIMetaFile::Rotate. Another user is MetaCommentAction::Move which modifies the
455 contained path accordingly.
456 The other one is SdrObject::Imp_DrawLineGeometry. It's done when MetaFile is set at OutDev and
457 only when geometry is a single polygon (!). I see no reason for that; in the PS exporter this
458 would hinder to make use of PolyPolygon strokes. I will need to add support at:
459 PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D
460 PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D
461 PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D
462 This can be done hierarchical, too.
463 Okay, base implementation done based on those three primitives.
465 FIELD_SEQ_BEGIN, FIELD_SEQ_END
467 Used from slideshow for URLs, created from diverse SvxField implementations inside
468 createBeginComment()/createEndComment(). createBeginComment() is used from editeng\impedit3.cxx
469 inside ImpEditEngine::Paint.
470 Created TextHierarchyFieldPrimitive2D and added needed infos there; it is an group primitive and wraps
471 text primitives (but is not limited to that). It contains the field type if special actions for the
472 support of FIELD_SEQ_BEGIN/END are needed; this is the case for Page and URL fields. If more is
473 needed, it may be supported there.
474 FIELD_SEQ_BEGIN;PageField
475 FIELD_SEQ_END
476 Okay, these are now completely supported by TextHierarchyFieldPrimitive2D. URL works, too.
478 XTEXT
480 XTEXT_EOC(i) end of character
481 XTEXT_EOW(i) end of word
482 XTEXT_EOS(i) end of sentence
484 this three are with index and are created with the help of a i18n::XBreakIterator in
485 ImplDrawWithComments. Simplifying, moving out text painting, reworking to create some
486 data structure for holding those TEXT infos.
487 Supported directly by TextSimplePortionPrimitive2D with adding a Locale to the basic text
488 primitive. In the MetaFileRenderer, the creation is now done (see below). This has the advantage
489 that this creations do not need to be done for all paints all the time. This would be
490 expensive since the BreakIterator and it's usage is expensive and for each paint also the
491 whole character stops would need to be created.
492 Created only for TextDecoratedPortionPrimitive2D due to XTEXT_EOL and XTEXT_EOP (see below)
494 XTEXT_EOL() end of line
495 XTEXT_EOP() end of paragraph
497 First try with boolean marks at TextDecoratedPortionPrimitive2D did not work too well,
498 i decided to solve it with structure. I added the TextHierarchyPrimitives for this,
499 namely:
500 - TextHierarchyLinePrimitive2D: Encapsulates single line
501 - TextHierarchyParagraphPrimitive2D: Encapsulates single paragraph
502 - TextHierarchyBlockPrimitive2D: encapsulates object texts (only one ATM)
503 Those are now supported in hierarchy. This means the MetaFile renderer will support them
504 by using them, reculrively using their content and adding MetaFile comments as needed.
505 This also means that when another text layouter will be used it will be necessary to
506 create/support the same HierarchyPrimitives to support users.
507 To transport the information using this hierarchy is best suited to all future needs;
508 the slideshow will be able to profit from it directly when using primitives; all other
509 renderers not interested in the text structure will just ignore the encapsulations.
511 XTEXT_PAINTSHAPE_BEGIN, XTEXT_PAINTSHAPE_END
512 Supported now by the TextHierarchyBlockPrimitive2D.
514 EPSReplacementGraphic:
515 Only used in goodies\source\filter.vcl\ieps\ieps.cxx and svx\source\xml\xmlgrhlp.cxx to
516 hold the original EPS which was imported in the same MetaFile as first 2 entries. Only
517 used to export the original again (if exists).
518 Not necessary to support with MetaFuleRenderer.
520 XTEXT_SCROLLRECT, XTEXT_PAINTRECT
521 Currently used to get extra MetaFile infos using GraphicExporter which again uses
522 SdrTextObj::GetTextScrollMetaFileAndRectangle(). ATM works with primitives since
523 the rectangle data is added directly by the GraphicsExporter as comment. Does not need
524 to be adapted at once.
525 When adapting later, the only user - the diashow - should directly use the provided
526 Anination infos in the appropriate primitives (e.g. AnimatedSwitchPrimitive2D)
528 PRNSPOOL_TRANSPARENTBITMAP_BEGIN, PRNSPOOL_TRANSPARENTBITMAP_END
529 VCL usage when printing PL -> THB. Okay, THB confirms that it is only used as
530 a fix (hack) while VCL printing. It is needed to not downscale a bitmap which
531 was explicitely created for the printer already again to some default maximum
532 bitmap sizes.
533 Nothing to do here for the primitive renderer.
535 Support for vcl::PDFExtOutDevData:
536 PL knows that SJ did that stuff, it's used to hold a pointer to PDFExtOutDevData at
537 the OutDev. When set, some extra data is written there. Trying simple PDF export and
538 watching if i get those infos.
539 Well, a PDF export does not use e.g. ImpEditEngine::Paint since the PdfFilter uses
540 the SdXImpressDocument::render and thus uses the VclMetafileProcessor2D. I will check
541 if i get a PDFExtOutDevData at the target output device.
542 Indeed, i get one. Checking what all may be done when that extra-device-info is there.
544 All in all i have to talk to SJ. I will need to emulate some of those actions, but
545 i need to discuss which ones.
546 In the future, all those infos would be taken from the primitive sequence anyways,
547 thus these extensions would potentially be temporary, too.
548 Discussed with SJ, added the necessary support and tested it. Details follow.
550 - In ImpEditEngine::Paint, paragraph infos and URL stuff is added.
551 Added in primitive MetaFile renderer.
552 Checking URL: Indeed, current version exports it, but it is missing in primitive
553 CWS version. Adding support.
554 Okay, URLs work. Checked, Done.
556 - UnoControlPDFExportContact is only created when PDFExtOutDevData is used at the
557 target and uno control data is created in UnoControlPDFExportContact::do_PaintObject.
558 This may be added in primitive MetaFile renderer.
559 Adding support...
560 OOps, the necessary helper stuff is in svx/source/form/formpdxexport.cxx in namespace
561 svxform. Have to talk to FS if this has to be like that. Especially since
562 ::vcl::PDFWriter::AnyWidget is filled out, which is already part of vcl.
563 Wrote an eMail to FS, he is on vacation currently. I see no reason why not to move
564 that stuff to somewhere else, maybe tools or svtools ?!? We will see...
565 Moved to toolkit, so i have to link against it. I tried VCL first, but it did
566 not work since VCLUnoHelper::CreateFont is unresolved in VCL (!). Other then the name
567 may imply, it is defined in toolkit (!). Since toolkit is linked against VCL itself,
568 the lowest move,ment plave is toolkit.
569 Checked form control export, it works well. Done.
571 - In goodies, in GraphicObject::Draw, when the used Graphic is linked, infos are
572 generated. I will need to check what happens here with primitives.
573 To support, use of GraphicPrimitive2D (PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D) may be needed.
574 Added support, but feature is broken in main version, so i cannot test at all.
575 Writing a bug to CL (or SJ) and seeing what happens (#i80380#).
576 SJ took a look and we got it working. Tested VCL MetaFile Renderer based export,
577 as intended, the original file is exported. Works, Done.
582 To be done:
584 - Maybe there are more places to take care of for vcl::PDFExtOutDevData!
588 ****************************************************************************************************/
590 void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
592 switch(rCandidate.getPrimitiveID())
594 case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
596 // directdraw of wrong spell primitive
597 // Ignore for VclMetafileProcessor2D, this is for printing and MetaFile recording only
598 break;
600 case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D :
602 const primitive2d::GraphicPrimitive2D& rGraphicPrimitive = static_cast< const primitive2d::GraphicPrimitive2D& >(rCandidate);
603 bool bUsingPDFExtOutDevData(false);
604 basegfx::B2DVector aTranslate, aScale;
605 static bool bSuppressPDFExtOutDevDataSupport(false);
607 if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport)
609 // emulate data handling from UnoControlPDFExportContact, original see
610 // goodies/source/graphic/grfmgr.cxx
611 const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic();
613 if(rGraphic.IsLink())
615 const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
617 if(!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted())
619 const basegfx::B2DHomMatrix& rTransform = rGraphicPrimitive.getTransform();
620 double fRotate, fShearX;
621 rTransform.decompose(aScale, aTranslate, fRotate, fShearX);
623 if( basegfx::fTools::equalZero( fRotate ) && ( aScale.getX() > 0.0 ) && ( aScale.getY() > 0.0 ) )
625 bUsingPDFExtOutDevData = true;
626 mpPDFExtOutDevData->BeginGroup();
632 // process recursively and add MetaFile comment
633 process(rGraphicPrimitive.get2DDecomposition(getViewInformation2D()));
635 if(bUsingPDFExtOutDevData)
637 // emulate data handling from UnoControlPDFExportContact, original see
638 // goodies/source/graphic/grfmgr.cxx
639 const basegfx::B2DRange aCurrentRange(
640 aTranslate.getX(), aTranslate.getY(),
641 aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
642 const Rectangle aCurrentRect(
643 sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())),
644 sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY())));
645 const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
646 Rectangle aCropRect;
648 if(rAttr.IsCropped())
650 // calculate scalings between real image size and logic object size. This
651 // is necessary since the crop values are relative to original bitmap size
652 double fFactorX(1.0);
653 double fFactorY(1.0);
656 const MapMode aMapMode100thmm(MAP_100TH_MM);
657 const Size aBitmapSize(Application::GetDefaultDevice()->LogicToLogic(
658 rGraphicPrimitive.getGraphicObject().GetPrefSize(),
659 rGraphicPrimitive.getGraphicObject().GetPrefMapMode(), aMapMode100thmm));
660 const double fDivX(aBitmapSize.Width() - rAttr.GetLeftCrop() - rAttr.GetRightCrop());
661 const double fDivY(aBitmapSize.Height() - rAttr.GetTopCrop() - rAttr.GetBottomCrop());
663 if(!basegfx::fTools::equalZero(fDivX))
665 fFactorX = aScale.getX() / fDivX;
668 if(!basegfx::fTools::equalZero(fDivY))
670 fFactorY = aScale.getY() / fDivY;
674 // calculate crop range and rect
675 basegfx::B2DRange aCropRange;
676 aCropRange.expand(aCurrentRange.getMinimum() - basegfx::B2DPoint(rAttr.GetLeftCrop() * fFactorX, rAttr.GetTopCrop() * fFactorY));
677 aCropRange.expand(aCurrentRange.getMaximum() + basegfx::B2DPoint(rAttr.GetRightCrop() * fFactorX, rAttr.GetBottomCrop() * fFactorY));
679 aCropRect = Rectangle(
680 sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())),
681 sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY())));
684 mpPDFExtOutDevData->EndGroup(rGraphicPrimitive.getGraphicObject().GetGraphic(),
685 rAttr.GetTransparency(),
686 aCurrentRect,
687 aCropRect);
690 break;
692 case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
694 const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate);
695 const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl());
696 bool bIsPrintableControl(false);
698 // find out if control is printable
699 if(rXControl.is())
703 uno::Reference< beans::XPropertySet > xModelProperties(rXControl->getModel(), uno::UNO_QUERY);
704 uno::Reference< beans::XPropertySetInfo > xPropertyInfo(xModelProperties.is()
705 ? xModelProperties->getPropertySetInfo()
706 : uno::Reference< beans::XPropertySetInfo >());
707 const ::rtl::OUString sPrintablePropertyName(RTL_CONSTASCII_USTRINGPARAM("Printable"));
709 if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName))
711 OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl);
714 catch(const uno::Exception&)
716 OSL_ENSURE(false, "VclMetafileProcessor2D: No access to printable flag of Control, caught an exception!");
720 // PDF export and printing only for printable controls
721 if(bIsPrintableControl)
723 const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields());
724 bool bDoProcessRecursively(true);
726 if(bPDFExport)
728 // PDF export. Emulate data handling from UnoControlPDFExportContact
729 // I have now moved describePDFControl to toolkit, thus i can implement the PDF
730 // form control support now as follows
731 ::std::auto_ptr< ::vcl::PDFWriter::AnyWidget > pPDFControl;
732 ::toolkitform::describePDFControl(rXControl, pPDFControl);
734 if(pPDFControl.get())
736 // still need to fill in the location (is a class Rectangle)
737 const basegfx::B2DRange aRangeLogic(rControlPrimitive.getB2DRange(getViewInformation2D()));
738 const Rectangle aRectLogic(
739 (sal_Int32)floor(aRangeLogic.getMinX()), (sal_Int32)floor(aRangeLogic.getMinY()),
740 (sal_Int32)ceil(aRangeLogic.getMaxX()), (sal_Int32)ceil(aRangeLogic.getMaxY()));
741 pPDFControl->Location = aRectLogic;
743 Size aFontSize(pPDFControl->TextFont.GetSize());
744 aFontSize = mpOutputDevice->LogicToLogic(aFontSize, MapMode(MAP_POINT), mpOutputDevice->GetMapMode());
745 pPDFControl->TextFont.SetSize(aFontSize);
747 mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form);
748 mpPDFExtOutDevData->CreateControl(*pPDFControl.get());
749 mpPDFExtOutDevData->EndStructureElement();
751 // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject);
752 // do not process recursively
753 bDoProcessRecursively = false;
755 else
757 // PDF export did not work, try simple output.
758 // Fallback to printer output by not setting bDoProcessRecursively
759 // to false.
763 // #i93169# used flag the wrong way; true means that nothing was done yet
764 if(bDoProcessRecursively)
766 // printer output
769 // remember old graphics and create new
770 uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW);
771 const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics());
772 const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics());
774 if(xNewGraphics.is())
776 // link graphics and view
777 xControlView->setGraphics(xNewGraphics);
779 // get position
780 const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform());
781 const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0));
783 // draw it
784 xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY()));
785 bDoProcessRecursively = false;
787 // restore original graphics
788 xControlView->setGraphics(xOriginalGraphics);
791 catch( const uno::Exception& )
793 OSL_ENSURE(false, "VclMetafileProcessor2D: Printing of Control failed, caught an exception!");
797 // process recursively if not done yet to export as decomposition (bitmap)
798 if(bDoProcessRecursively)
800 process(rControlPrimitive.get2DDecomposition(getViewInformation2D()));
804 break;
806 case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D :
808 // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to)
809 // thus do the MetafileAction embedding stuff but just handle recursively.
810 const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive = static_cast< const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate);
811 static const ByteString aCommentStringCommon("FIELD_SEQ_BEGIN");
812 static const ByteString aCommentStringPage("FIELD_SEQ_BEGIN;PageField");
813 static const ByteString aCommentStringEnd("FIELD_SEQ_END");
815 switch(rFieldPrimitive.getType())
817 default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON :
819 mrMetaFile.AddAction(new MetaCommentAction(aCommentStringCommon));
820 break;
822 case drawinglayer::primitive2d::FIELD_TYPE_PAGE :
824 mrMetaFile.AddAction(new MetaCommentAction(aCommentStringPage));
825 break;
827 case drawinglayer::primitive2d::FIELD_TYPE_URL :
829 const rtl::OUString& rURL = rFieldPrimitive.getString();
830 const String aOldString(rURL);
831 mrMetaFile.AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast< const BYTE* >(aOldString.GetBuffer()), 2 * aOldString.Len()));
832 break;
836 // process recursively
837 const primitive2d::Primitive2DSequence rContent = rFieldPrimitive.get2DDecomposition(getViewInformation2D());
838 process(rContent);
840 // for the end comment the type is not relevant yet, they are all the same. Just add.
841 mrMetaFile.AddAction(new MetaCommentAction(aCommentStringEnd));
843 if(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType())
845 // emulate data handling from ImpEditEngine::Paint
846 const basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
847 const Rectangle aRectLogic(
848 (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()),
849 (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY()));
850 vcl::PDFExtOutDevBookmarkEntry aBookmark;
851 aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic);
852 aBookmark.aBookmark = rFieldPrimitive.getString();
853 std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks();
854 rBookmarks.push_back( aBookmark );
857 break;
859 case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D :
861 const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive = static_cast< const primitive2d::TextHierarchyLinePrimitive2D& >(rCandidate);
862 static const ByteString aCommentString("XTEXT_EOL");
864 // process recursively and add MetaFile comment
865 process(rLinePrimitive.get2DDecomposition(getViewInformation2D()));
866 mrMetaFile.AddAction(new MetaCommentAction(aCommentString));
868 break;
870 case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D :
872 // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The
873 // "XTEXT_EOC" is used, use here, too.
874 const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive = static_cast< const primitive2d::TextHierarchyBulletPrimitive2D& >(rCandidate);
875 static const ByteString aCommentString("XTEXT_EOC");
877 // process recursively and add MetaFile comment
878 process(rBulletPrimitive.get2DDecomposition(getViewInformation2D()));
879 mrMetaFile.AddAction(new MetaCommentAction(aCommentString));
881 break;
883 case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D :
885 const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive = static_cast< const primitive2d::TextHierarchyParagraphPrimitive2D& >(rCandidate);
886 static const ByteString aCommentString("XTEXT_EOP");
888 if(mpPDFExtOutDevData)
890 // emulate data handling from ImpEditEngine::Paint
891 mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );
894 // process recursively and add MetaFile comment
895 process(rParagraphPrimitive.get2DDecomposition(getViewInformation2D()));
896 mrMetaFile.AddAction(new MetaCommentAction(aCommentString));
898 if(mpPDFExtOutDevData)
900 // emulate data handling from ImpEditEngine::Paint
901 mpPDFExtOutDevData->EndStructureElement();
904 break;
906 case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D :
908 const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive = static_cast< const primitive2d::TextHierarchyBlockPrimitive2D& >(rCandidate);
909 static const ByteString aCommentStringA("XTEXT_PAINTSHAPE_BEGIN");
910 static const ByteString aCommentStringB("XTEXT_PAINTSHAPE_END");
912 // add MetaFile comment, process recursively and add MetaFile comment
913 mrMetaFile.AddAction(new MetaCommentAction(aCommentStringA));
914 process(rBlockPrimitive.get2DDecomposition(getViewInformation2D()));
915 mrMetaFile.AddAction(new MetaCommentAction(aCommentStringB));
917 break;
919 case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
920 case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
922 // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate
923 const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate = static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate);
924 // const primitive2d::TextDecoratedPortionPrimitive2D* pTextDecoratedCandidate = dynamic_cast< const primitive2d::TextDecoratedPortionPrimitive2D* >(&rCandidate);
926 // Adapt evtl. used special DrawMode
927 const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
928 adaptTextToFillDrawMode();
930 // directdraw of text simple portion; use default processing
931 RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate);
933 // restore DrawMode
934 mpOutputDevice->SetDrawMode(nOriginalDrawMode);
936 // #i101169# if(pTextDecoratedCandidate)
938 // support for TEXT_ MetaFile actions only for decorated texts
939 if(!mxBreakIterator.is())
941 uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory());
942 mxBreakIterator.set(xMSF->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), uno::UNO_QUERY);
945 if(mxBreakIterator.is())
947 const rtl::OUString& rTxt = rTextCandidate.getText();
948 const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength());
950 if(nTextLength)
952 const ::com::sun::star::lang::Locale& rLocale = rTextCandidate.getLocale();
953 const sal_Int32 nTextPosition(rTextCandidate.getTextPosition());
955 sal_Int32 nDone;
956 sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
957 ::com::sun::star::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True));
958 sal_Int32 nNextSentenceBreak(mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale));
959 static const ByteString aCommentStringA("XTEXT_EOC");
960 static const ByteString aCommentStringB("XTEXT_EOW");
961 static const ByteString aCommentStringC("XTEXT_EOS");
963 for(sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++)
965 // create the entries for the respective break positions
966 if(i == nNextCellBreak)
968 mrMetaFile.AddAction(new MetaCommentAction(aCommentStringA, i - nTextPosition));
969 nNextCellBreak = mxBreakIterator->nextCharacters(rTxt, i, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
971 if(i == nNextWordBoundary.endPos)
973 mrMetaFile.AddAction(new MetaCommentAction(aCommentStringB, i - nTextPosition));
974 nNextWordBoundary = mxBreakIterator->getWordBoundary(rTxt, i + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True);
976 if(i == nNextSentenceBreak)
978 mrMetaFile.AddAction(new MetaCommentAction(aCommentStringC, i - nTextPosition));
979 nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale);
986 break;
988 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
990 // direct draw of hairline; use default processing
991 // also support SvtGraphicStroke MetaCommentAction
992 const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate);
993 const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor()));
994 SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(rHairlinePrimitive.getB2DPolygon(), &aLineColor, 0, 0, 0, 0);
996 impStartSvtGraphicStroke(pSvtGraphicStroke);
997 RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), false);
998 impEndSvtGraphicStroke(pSvtGraphicStroke);
999 break;
1001 case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D :
1003 // support SvtGraphicStroke MetaCommentAction
1004 const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate);
1005 SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(rStrokePrimitive.getB2DPolygon(), 0, &rStrokePrimitive.getLineAttribute(),
1006 &rStrokePrimitive.getStrokeAttribute(), 0, 0);
1008 // Adapt OutDev's DrawMode if special ones were used
1009 const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
1010 adaptLineToFillDrawMode();
1012 impStartSvtGraphicStroke(pSvtGraphicStroke);
1014 // #i101491#
1015 // Change default of fat line generation for MetaFiles: Create MetaPolyLineAction
1016 // instead of decomposing all geometries when the polygon has more than given amount of
1017 // points; else the decomposition will get too expensive quiclky. OTOH
1018 // the decomposition provides the better quality e.g. taking edge roundings
1019 // into account which will NOT be taken into account with LineInfo-based actions
1020 const sal_uInt32 nSubPolygonCount(rStrokePrimitive.getB2DPolygon().count());
1021 bool bDone(0 == nSubPolygonCount);
1023 if(!bDone && nSubPolygonCount > 1000)
1025 // create MetaPolyLineActions, but without LINE_DASH
1026 const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute();
1028 if(basegfx::fTools::more(rLine.getWidth(), 0.0))
1030 const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute();
1031 basegfx::B2DPolyPolygon aHairLinePolyPolygon;
1033 if(0.0 == rStroke.getFullDotDashLen())
1035 aHairLinePolyPolygon.append(rStrokePrimitive.getB2DPolygon());
1037 else
1039 basegfx::tools::applyLineDashing(
1040 rStrokePrimitive.getB2DPolygon(), rStroke.getDotDashArray(),
1041 &aHairLinePolyPolygon, 0, rStroke.getFullDotDashLen());
1044 const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLine.getColor()));
1045 mpOutputDevice->SetLineColor(Color(aHairlineColor));
1046 mpOutputDevice->SetFillColor();
1048 aHairLinePolyPolygon.transform(maCurrentTransformation);
1050 const LineInfo aLineInfo(LINE_SOLID, basegfx::fround(rLine.getWidth()));
1052 for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++)
1054 const basegfx::B2DPolygon aCandidate(aHairLinePolyPolygon.getB2DPolygon(a));
1056 if(aCandidate.count() > 1)
1058 const Polygon aToolsPolygon(aCandidate);
1060 mrMetaFile.AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo));
1064 bDone = true;
1068 if(!bDone)
1070 // use decomposition (creates line geometry as filled polygon
1071 // geometry)
1072 process(rCandidate.get2DDecomposition(getViewInformation2D()));
1075 impEndSvtGraphicStroke(pSvtGraphicStroke);
1077 // restore DrawMode
1078 mpOutputDevice->SetDrawMode(nOriginalDrawMode);
1080 break;
1082 case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D :
1084 // support SvtGraphicStroke MetaCommentAction
1085 const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive = static_cast< const primitive2d::PolygonStrokeArrowPrimitive2D& >(rCandidate);
1086 SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(rStrokeArrowPrimitive.getB2DPolygon(), 0, &rStrokeArrowPrimitive.getLineAttribute(),
1087 &rStrokeArrowPrimitive.getStrokeAttribute(), &rStrokeArrowPrimitive.getStart(), &rStrokeArrowPrimitive.getEnd());
1089 impStartSvtGraphicStroke(pSvtGraphicStroke);
1090 process(rCandidate.get2DDecomposition(getViewInformation2D()));
1091 impEndSvtGraphicStroke(pSvtGraphicStroke);
1092 break;
1094 case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
1096 // direct draw of transformed BitmapEx primitive; use default processing
1097 RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
1098 break;
1100 case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D :
1102 // need to handle PolyPolygonBitmapPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
1103 SvtGraphicFill* pSvtGraphicFill = 0;
1105 if(!mnSvtGraphicFillCount)
1107 const primitive2d::PolyPolygonBitmapPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate);
1108 basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon());
1109 aLocalPolyPolygon.transform(maCurrentTransformation);
1111 if(aLocalPolyPolygon.count())
1113 // calculate transformation. Get real object size, all values in FillBitmapAttribute
1114 // are relative to the unified object
1115 const attribute::FillBitmapAttribute& rFillBitmapAttribute = rBitmapCandidate .getFillBitmap();
1116 const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(aLocalPolyPolygon));
1117 const basegfx::B2DVector aOutlineSize(aOutlineRange.getRange());
1119 // get absolute values
1120 const basegfx::B2DVector aFillBitmapSize(rFillBitmapAttribute.getSize() * aOutlineSize);
1121 const basegfx::B2DPoint aFillBitmapTopLeft(rFillBitmapAttribute.getTopLeft() * aOutlineSize);
1123 // the scaling needs scale from pixel to logic coordinate system
1124 const Bitmap& rBitmap = rFillBitmapAttribute.getBitmap();
1125 Size aBmpSizePixel(rBitmap.GetSizePixel());
1127 if(!aBmpSizePixel.Width())
1129 aBmpSizePixel.Width() = 1;
1132 if(!aBmpSizePixel.Height())
1134 aBmpSizePixel.Height() = 1;
1137 // setup transformation like in impgrfll
1138 SvtGraphicFill::Transform aTransform;
1140 // scale values are divided by bitmap pixel sizes
1141 aTransform.matrix[0] = aFillBitmapSize.getX() / aBmpSizePixel.Width();
1142 aTransform.matrix[4] = aFillBitmapSize.getY() / aBmpSizePixel.Height();
1144 // translates are absolute
1145 aTransform.matrix[2] = aFillBitmapTopLeft.getX();
1146 aTransform.matrix[5] = aFillBitmapTopLeft.getY();
1148 // setup fill graphic like in impgrfll
1149 Graphic aFillGraphic = Graphic(rBitmap);
1150 aFillGraphic.SetPrefMapMode(MapMode(MAP_PIXEL));
1151 aFillGraphic.SetPrefSize(aBmpSizePixel);
1153 pSvtGraphicFill = new SvtGraphicFill(
1154 PolyPolygon(aLocalPolyPolygon),
1155 Color(),
1156 0.0,
1157 SvtGraphicFill::fillEvenOdd,
1158 SvtGraphicFill::fillTexture,
1159 aTransform,
1160 rFillBitmapAttribute.getTiling(),
1161 SvtGraphicFill::hatchSingle,
1162 Color(),
1163 SvtGraphicFill::gradientLinear,
1164 Color(),
1165 Color(),
1167 aFillGraphic);
1171 // Do use decomposition; encapsulate with SvtGraphicFill
1172 impStartSvtGraphicFill(pSvtGraphicFill);
1173 process(rCandidate.get2DDecomposition(getViewInformation2D()));
1174 impEndSvtGraphicFill(pSvtGraphicFill);
1176 break;
1178 case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D :
1180 // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
1181 SvtGraphicFill* pSvtGraphicFill = 0;
1183 if(!mnSvtGraphicFillCount)
1185 const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate = static_cast< const primitive2d::PolyPolygonHatchPrimitive2D& >(rCandidate);
1186 basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon());
1187 aLocalPolyPolygon.transform(maCurrentTransformation);
1189 if(aLocalPolyPolygon.count())
1191 // re-create a VCL hatch as base data
1192 const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch();
1193 SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle);
1195 switch(rFillHatchAttribute.getStyle())
1197 default: // attribute::HATCHSTYLE_SINGLE :
1199 eHatch = SvtGraphicFill::hatchSingle;
1200 break;
1202 case attribute::HATCHSTYLE_DOUBLE :
1204 eHatch = SvtGraphicFill::hatchDouble;
1205 break;
1207 case attribute::HATCHSTYLE_TRIPLE :
1209 eHatch = SvtGraphicFill::hatchTriple;
1210 break;
1214 SvtGraphicFill::Transform aTransform;
1216 // scale
1217 aTransform.matrix[0] *= rFillHatchAttribute.getDistance();
1218 aTransform.matrix[4] *= rFillHatchAttribute.getDistance();
1220 // rotate (was never correct in impgrfll anyways, use correct angle now)
1221 aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle());
1222 aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle());
1223 aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle());
1224 aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle());
1226 pSvtGraphicFill = new SvtGraphicFill(
1227 PolyPolygon(aLocalPolyPolygon),
1228 Color(),
1229 0.0,
1230 SvtGraphicFill::fillEvenOdd,
1231 SvtGraphicFill::fillHatch,
1232 aTransform,
1233 false,
1234 eHatch,
1235 Color(rFillHatchAttribute.getColor()),
1236 SvtGraphicFill::gradientLinear,
1237 Color(),
1238 Color(),
1240 Graphic());
1244 // Do use decomposition; encapsulate with SvtGraphicFill
1245 impStartSvtGraphicFill(pSvtGraphicFill);
1246 process(rCandidate.get2DDecomposition(getViewInformation2D()));
1247 impEndSvtGraphicFill(pSvtGraphicFill);
1249 break;
1251 case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D :
1253 const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate);
1255 // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END
1256 // it is safest to use the VCL OutputDevice::DrawGradient method which creates those.
1257 // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon
1258 Gradient aVCLGradient;
1259 impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false);
1260 basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon());
1261 aLocalPolyPolygon.transform(maCurrentTransformation);
1263 // #i82145# ATM VCL printing of gradients using curved shapes does not work,
1264 // i submitted the bug with the given ID to THB. When that task is fixed it is
1265 // necessary to again remove this subdivision since it decreases possible
1266 // printing quality (not even resolution-dependent for now). THB will tell
1267 // me when that task is fixed in the master
1268 const PolyPolygon aToolsPolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(aLocalPolyPolygon));
1270 // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
1271 SvtGraphicFill* pSvtGraphicFill = 0;
1273 if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1275 // setup gradient stuff like in like in impgrfll
1276 SvtGraphicFill::GradientType eGrad(SvtGraphicFill::gradientLinear);
1278 switch(aVCLGradient.GetStyle())
1280 default : // GRADIENT_LINEAR:
1281 case GRADIENT_AXIAL:
1282 eGrad = SvtGraphicFill::gradientLinear;
1283 break;
1284 case GRADIENT_RADIAL:
1285 case GRADIENT_ELLIPTICAL:
1286 eGrad = SvtGraphicFill::gradientRadial;
1287 break;
1288 case GRADIENT_SQUARE:
1289 case GRADIENT_RECT:
1290 eGrad = SvtGraphicFill::gradientRectangular;
1291 break;
1294 pSvtGraphicFill = new SvtGraphicFill(
1295 aToolsPolyPolygon,
1296 Color(),
1297 0.0,
1298 SvtGraphicFill::fillEvenOdd,
1299 SvtGraphicFill::fillGradient,
1300 SvtGraphicFill::Transform(),
1301 false,
1302 SvtGraphicFill::hatchSingle,
1303 Color(),
1304 eGrad,
1305 aVCLGradient.GetStartColor(),
1306 aVCLGradient.GetEndColor(),
1307 aVCLGradient.GetSteps(),
1308 Graphic());
1311 // call VCL directly; encapsulate with SvtGraphicFill
1312 impStartSvtGraphicFill(pSvtGraphicFill);
1313 mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient);
1314 impEndSvtGraphicFill(pSvtGraphicFill);
1316 // NO usage of common own gradient randerer, not used ATM for VCL MetaFile, see text above
1317 // RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate));
1318 break;
1320 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
1322 const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate));
1323 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
1324 basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
1325 aLocalPolyPolygon.transform(maCurrentTransformation);
1327 // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
1328 SvtGraphicFill* pSvtGraphicFill = 0;
1330 if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1332 // setup simple color fill stuff like in impgrfll
1333 pSvtGraphicFill = new SvtGraphicFill(
1334 PolyPolygon(aLocalPolyPolygon),
1335 Color(aPolygonColor),
1336 0.0,
1337 SvtGraphicFill::fillEvenOdd,
1338 SvtGraphicFill::fillSolid,
1339 SvtGraphicFill::Transform(),
1340 false,
1341 SvtGraphicFill::hatchSingle,
1342 Color(),
1343 SvtGraphicFill::gradientLinear,
1344 Color(),
1345 Color(),
1347 Graphic());
1350 // set line and fill color
1351 mpOutputDevice->SetFillColor(Color(aPolygonColor));
1352 mpOutputDevice->SetLineColor();
1354 // call VCL directly; encapsulate with SvtGraphicFill
1355 impStartSvtGraphicFill(pSvtGraphicFill);
1356 mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
1357 impEndSvtGraphicFill(pSvtGraphicFill);
1359 break;
1361 case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
1363 // direct draw of MetaFile, use default pocessing
1364 RenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate));
1365 break;
1367 case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
1369 // mask group. Special handling for MetaFiles.
1370 const primitive2d::MaskPrimitive2D& rMaskCandidate = static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate);
1372 if(rMaskCandidate.getChildren().hasElements())
1374 basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
1376 if(aMask.count())
1378 // prepare new mask polygon and rescue current one
1379 aMask.transform(maCurrentTransformation);
1380 const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon);
1382 if(maClipPolyPolygon.count())
1384 // there is already a clip polygon set; build clipped union of
1385 // current mask polygon and new one
1386 maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(aMask, maClipPolyPolygon, false, false);
1388 else
1390 // use mask directly
1391 maClipPolyPolygon = aMask;
1394 if(maClipPolyPolygon.count())
1396 // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!)
1397 // Removed subdivision and fixed in Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where
1398 // the ClipRegion is built from the Polygon. A AdaptiveSubdivide on the source polygon was missing there
1399 mpOutputDevice->Push(PUSH_CLIPREGION);
1400 //mpOutputDevice->SetClipRegion(Region(PolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(maClipPolyPolygon))));
1401 mpOutputDevice->SetClipRegion(Region(PolyPolygon(maClipPolyPolygon)));
1404 // recursively paint content
1405 process(rMaskCandidate.getChildren());
1407 if(maClipPolyPolygon.count())
1409 // restore VCL clip region
1410 mpOutputDevice->Pop();
1413 // restore to rescued clip polygon
1414 maClipPolyPolygon = aLastClipPolyPolygon;
1416 else
1418 // no mask, no clipping. recursively paint content
1419 process(rMaskCandidate.getChildren());
1423 break;
1425 case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
1427 // modified color group. Force output to unified color. Use default pocessing.
1428 RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate));
1429 break;
1431 case PRIMITIVE2D_ID_UNIFIEDALPHAPRIMITIVE2D :
1433 // for metafile: Need to examine what the pure vcl version is doing here actually
1434 // - uses DrawTransparent with metafile for content and a gradient
1435 // - uses DrawTransparent for single PolyPoylgons directly. Can be detected by
1436 // checking the content for single PolyPolygonColorPrimitive2D
1437 const primitive2d::UnifiedAlphaPrimitive2D& rUniAlphaCandidate = static_cast< const primitive2d::UnifiedAlphaPrimitive2D& >(rCandidate);
1438 const primitive2d::Primitive2DSequence rContent = rUniAlphaCandidate.getChildren();
1440 if(rContent.hasElements())
1442 // try to identify a single PolyPolygonColorPrimitive2D in the
1443 // content part of the alpha primitive
1444 const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = 0;
1445 static bool bForceToMetafile(false);
1447 if(!bForceToMetafile && 1 == rContent.getLength())
1449 const primitive2d::Primitive2DReference xReference(rContent[0]);
1450 pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get());
1453 // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and
1454 // PolyPolygonBitmapPrimitive2D are derived from PolyPolygonColorPrimitive2D.
1455 // Check also for correct ID to exclude derived implementations
1456 if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitiveID())
1458 // single transparent PolyPolygon identified, use directly
1459 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor()));
1460 basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon());
1461 aLocalPolyPolygon.transform(maCurrentTransformation);
1463 // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
1464 SvtGraphicFill* pSvtGraphicFill = 0;
1466 if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1468 // setup simple color with transparence fill stuff like in impgrfll
1469 pSvtGraphicFill = new SvtGraphicFill(
1470 PolyPolygon(aLocalPolyPolygon),
1471 Color(aPolygonColor),
1472 rUniAlphaCandidate.getAlpha(),
1473 SvtGraphicFill::fillEvenOdd,
1474 SvtGraphicFill::fillSolid,
1475 SvtGraphicFill::Transform(),
1476 false,
1477 SvtGraphicFill::hatchSingle,
1478 Color(),
1479 SvtGraphicFill::gradientLinear,
1480 Color(),
1481 Color(),
1483 Graphic());
1486 // set line and fill color
1487 const sal_uInt16 nTransPercentVcl((sal_uInt16)basegfx::fround(rUniAlphaCandidate.getAlpha() * 100.0));
1488 mpOutputDevice->SetFillColor(Color(aPolygonColor));
1489 mpOutputDevice->SetLineColor();
1491 // call VCL directly; encapsulate with SvtGraphicFill
1492 impStartSvtGraphicFill(pSvtGraphicFill);
1493 mpOutputDevice->DrawTransparent(
1494 PolyPolygon(aLocalPolyPolygon),
1495 nTransPercentVcl);
1496 impEndSvtGraphicFill(pSvtGraphicFill);
1498 else
1500 // svae old mfCurrentUnifiedTransparence and set new one
1501 // so that contained SvtGraphicStroke may use the current one
1502 const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence);
1503 mfCurrentUnifiedTransparence = rUniAlphaCandidate.getAlpha();
1505 // various content, create content-metafile
1506 GDIMetaFile aContentMetafile;
1507 const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
1509 // restore mfCurrentUnifiedTransparence; it may have been used
1510 // while processing the sub-content in impDumpToMetaFile
1511 mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence;
1513 // create uniform VCL gradient for uniform transparency
1514 Gradient aVCLGradient;
1515 const sal_uInt8 nTransPercentVcl((sal_uInt8)basegfx::fround(rUniAlphaCandidate.getAlpha() * 255.0));
1516 const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl);
1518 aVCLGradient.SetStyle(GRADIENT_LINEAR);
1519 aVCLGradient.SetStartColor(aTransColor);
1520 aVCLGradient.SetEndColor(aTransColor);
1521 aVCLGradient.SetAngle(0);
1522 aVCLGradient.SetBorder(0);
1523 aVCLGradient.SetOfsX(0);
1524 aVCLGradient.SetOfsY(0);
1525 aVCLGradient.SetStartIntensity(100);
1526 aVCLGradient.SetEndIntensity(100);
1527 aVCLGradient.SetSteps(2);
1529 // render it to VCL
1530 mpOutputDevice->DrawTransparent(
1531 aContentMetafile, aPrimitiveRectangle.TopLeft(),
1532 aPrimitiveRectangle.GetSize(), aVCLGradient);
1536 break;
1538 case PRIMITIVE2D_ID_ALPHAPRIMITIVE2D :
1540 // for metafile: Need to examine what the pure vcl version is doing here actually
1541 // - uses DrawTransparent with metafile for content and a gradient
1542 // i can detect this here with checking the gradient part for a single
1543 // FillGradientPrimitive2D and reconstruct the gradient.
1544 // If that detection goes wrong, i have to create an alpha-blended bitmap. Eventually
1545 // do that in stripes, else RenderAlphaPrimitive2D may just be used
1546 const primitive2d::AlphaPrimitive2D& rAlphaCandidate = static_cast< const primitive2d::AlphaPrimitive2D& >(rCandidate);
1547 const primitive2d::Primitive2DSequence rContent = rAlphaCandidate.getChildren();
1548 const primitive2d::Primitive2DSequence rAlpha = rAlphaCandidate.getAlpha();
1550 if(rContent.hasElements() && rAlpha.hasElements())
1552 // try to identify a single FillGradientPrimitive2D in the
1553 // alpha part of the primitive
1554 const primitive2d::FillGradientPrimitive2D* pFiGradient = 0;
1555 static bool bForceToBigTransparentVDev(false);
1557 if(!bForceToBigTransparentVDev && 1 == rAlpha.getLength())
1559 const primitive2d::Primitive2DReference xReference(rAlpha[0]);
1560 pFiGradient = dynamic_cast< const primitive2d::FillGradientPrimitive2D* >(xReference.get());
1563 // Check also for correct ID to exclude derived implementations
1564 if(pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitiveID())
1566 // various content, create content-metafile
1567 GDIMetaFile aContentMetafile;
1568 const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
1570 // re-create a VCL-gradient from FillGradientPrimitive2D
1571 Gradient aVCLGradient;
1572 impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(), true);
1574 // render it to VCL
1575 mpOutputDevice->DrawTransparent(
1576 aContentMetafile, aPrimitiveRectangle.TopLeft(),
1577 aPrimitiveRectangle.GetSize(), aVCLGradient);
1579 else
1581 // sub-transparence group. Draw to VDev first.
1582 // this may get refined to tiling when resolution is too big here
1584 // need to avoid switching off MapMode stuff here; maybe need another
1585 // tooling class, cannot just do the same as with the pixel renderer.
1586 // Need to experiment...
1588 // Okay, basic implementation finished and tested. The DPI stuff was hard
1589 // and not easy to find out that it's needed.
1590 // Since this will not yet happen normally (as long as noone constructs
1591 // alpha primitives with non-trivial alpha content) i will for now not
1592 // refine to tiling here.
1594 basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
1595 aViewRange.transform(maCurrentTransformation);
1596 const Rectangle aRectLogic(
1597 (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()),
1598 (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY()));
1599 const Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic));
1600 const Size aSizePixel(aRectPixel.GetSize());
1601 const Point aEmptyPoint;
1602 VirtualDevice aBufferDevice;
1604 if(aBufferDevice.SetOutputSizePixel(aSizePixel))
1606 // create and set MapModes for target devices
1607 MapMode aNewMapMode(mpOutputDevice->GetMapMode());
1608 aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top()));
1609 aBufferDevice.SetMapMode(aNewMapMode);
1611 // prepare view transformation for target renderers
1612 // ATTENTION! Need to apply another scaling because of the potential DPI differences
1613 // between Printer and VDev (mpOutputDevice and aBufferDevice here).
1614 // To get the DPI, LogicToPixel from (1,1) from MAP_INCH needs to be used.
1615 basegfx::B2DHomMatrix aViewTransform(aBufferDevice.GetViewTransformation());
1616 const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MAP_INCH));
1617 const Size aDPINew(aBufferDevice.LogicToPixel(Size(1, 1), MAP_INCH));
1618 const double fDPIXChange((double)aDPIOld.getWidth() / (double)aDPINew.getWidth());
1619 const double fDPIYChange((double)aDPIOld.getHeight() / (double)aDPINew.getHeight());
1621 if(!basegfx::fTools::equal(fDPIXChange, 1.0) || !basegfx::fTools::equal(fDPIYChange, 1.0))
1623 aViewTransform.scale(fDPIXChange, fDPIYChange);
1626 // create view information and pixel renderer. Reuse known ViewInformation
1627 // except new transformation and range
1628 const geometry::ViewInformation2D aViewInfo(
1629 getViewInformation2D().getObjectTransformation(),
1630 aViewTransform,
1631 aViewRange,
1632 getViewInformation2D().getVisualizedPage(),
1633 getViewInformation2D().getViewTime(),
1634 getViewInformation2D().getExtendedInformationSequence());
1636 VclPixelProcessor2D aBufferProcessor(aViewInfo, aBufferDevice);
1638 // draw content using pixel renderer
1639 aBufferProcessor.process(rContent);
1640 const Bitmap aBmContent(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel));
1642 // draw alpha using pixel renderer
1643 aBufferDevice.Erase();
1644 aBufferProcessor.process(rAlpha);
1645 const AlphaMask aBmAlpha(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel));
1647 #ifdef DBG_UTIL
1648 static bool bDoSaveForVisualControl(false);
1649 if(bDoSaveForVisualControl)
1651 SvFileStream aNew(String(ByteString( "c:\\test.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC);
1652 aNew << aBmContent;
1654 #endif
1656 // paint
1657 mpOutputDevice->DrawBitmapEx(
1658 aRectLogic.TopLeft(),
1659 aRectLogic.GetSize(),
1660 BitmapEx(aBmContent, aBmAlpha));
1665 break;
1667 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
1669 // use default transform group pocessing
1670 RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
1671 break;
1673 case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
1675 // new XDrawPage for ViewInformation2D
1676 RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate));
1677 break;
1679 case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
1681 // use default marker array pocessing
1682 RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate));
1683 break;
1685 case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
1687 // use default point array pocessing
1688 RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate));
1689 break;
1691 case PRIMITIVE2D_ID_CHARTPRIMITIVE2D :
1693 // ChartPrimitive2D
1694 const primitive2d::ChartPrimitive2D& rChartPrimitive = static_cast< const primitive2d::ChartPrimitive2D& >(rCandidate);
1696 if(!renderChartPrimitive2D(
1697 rChartPrimitive,
1698 *mpOutputDevice,
1699 getViewInformation2D()))
1701 // fallback to decomposition (MetaFile)
1702 process(rChartPrimitive.get2DDecomposition(getViewInformation2D()));
1704 break;
1706 case PRIMITIVE2D_ID_STRUCTURETAGRIMITIVE2D :
1708 // structured tag primitive
1709 const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate = static_cast< const primitive2d::StructureTagPrimitive2D& >(rCandidate);
1710 const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement());
1711 const bool bTagUsed(vcl::PDFWriter::NonStructElement != rTagElement);
1713 if(mpPDFExtOutDevData && bTagUsed)
1715 // write start tag
1716 mpPDFExtOutDevData->BeginStructureElement(rTagElement);
1719 // proccess childs normally
1720 process(rStructureTagCandidate.getChildren());
1722 if(mpPDFExtOutDevData && bTagUsed)
1724 // write end tag
1725 mpPDFExtOutDevData->EndStructureElement();
1728 break;
1730 case PRIMITIVE2D_ID_HITTESTPRIMITIVE2D :
1732 // #i99123#
1733 // invisible primitive; to rebuilt the old MetaFile creation, it is necessary to
1734 // not ignore them (as it was thought), but to add a MetaFile entry for them.
1735 basegfx::B2DRange aInvisibleRange(rCandidate.getB2DRange(getViewInformation2D()));
1737 if(!aInvisibleRange.isEmpty())
1739 aInvisibleRange.transform(maCurrentTransformation);
1740 const Rectangle aRectLogic(
1741 (sal_Int32)floor(aInvisibleRange.getMinX()), (sal_Int32)floor(aInvisibleRange.getMinY()),
1742 (sal_Int32)ceil(aInvisibleRange.getMaxX()), (sal_Int32)ceil(aInvisibleRange.getMaxY()));
1744 mpOutputDevice->SetFillColor();
1745 mpOutputDevice->SetLineColor();
1746 mpOutputDevice->DrawRect(aRectLogic);
1749 break;
1751 default :
1753 // process recursively
1754 process(rCandidate.get2DDecomposition(getViewInformation2D()));
1755 break;
1759 } // end of namespace processor2d
1760 } // end of namespace drawinglayer
1762 //////////////////////////////////////////////////////////////////////////////
1763 // eof