Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "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/maskprimitive2d.hxx>
31 : #include <drawinglayer/primitive2d/metafileprimitive2d.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 "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 <drawinglayer/primitive2d/openglprimitive2d.hxx>
48 : #include <comphelper/processfactory.hxx>
49 : #include <rtl/ustring.hxx>
50 : #include <com/sun/star/i18n/BreakIterator.hpp>
51 : #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
52 : #include <com/sun/star/i18n/WordType.hpp>
53 : #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
54 : #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
55 : #include <basegfx/polygon/b2dpolygontools.hxx>
56 : #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
57 : #include <drawinglayer/primitive2d/epsprimitive2d.hxx>
58 : #include <basegfx/polygon/b2dlinegeometry.hxx>
59 : #include <vcl/dibtools.hxx>
60 :
61 : // for PDFExtOutDevData Graphic support
62 : #include <vcl/graph.hxx>
63 : #include <vcl/svapp.hxx>
64 : #include <toolkit/helper/formpdfexport.hxx>
65 :
66 : // for Control printing
67 : #include <com/sun/star/beans/XPropertySet.hpp>
68 :
69 : // for StructureTagPrimitive support in sd's unomodel.cxx
70 : #include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
71 :
72 : using namespace com::sun::star;
73 :
74 : // #112245# definition for maximum allowed point count due to Metafile target.
75 : // To be on the safe side with the old tools polygon, use slightly less then
76 : // the theoretical maximum (bad experiences with tools polygon)
77 :
78 : #define MAX_POLYGON_POINT_COUNT_METAFILE (0x0000fff0)
79 :
80 : namespace
81 : {
82 : // #112245# helper to split line polygon in half
83 0 : void splitLinePolygon(
84 : const basegfx::B2DPolygon& rBasePolygon,
85 : basegfx::B2DPolygon& o_aLeft,
86 : basegfx::B2DPolygon& o_aRight)
87 : {
88 0 : const sal_uInt32 nCount(rBasePolygon.count());
89 :
90 0 : if(nCount)
91 : {
92 0 : const sal_uInt32 nHalfCount((nCount - 1) >> 1);
93 :
94 0 : o_aLeft = basegfx::B2DPolygon(rBasePolygon, 0, nHalfCount + 1);
95 0 : o_aLeft.setClosed(false);
96 :
97 0 : o_aRight = basegfx::B2DPolygon(rBasePolygon, nHalfCount, nCount - nHalfCount);
98 0 : o_aRight.setClosed(false);
99 :
100 0 : if(rBasePolygon.isClosed())
101 : {
102 0 : o_aRight.append(rBasePolygon.getB2DPoint(0));
103 :
104 0 : if(rBasePolygon.areControlPointsUsed())
105 : {
106 : o_aRight.setControlPoints(
107 0 : o_aRight.count() - 1,
108 : rBasePolygon.getPrevControlPoint(0),
109 0 : rBasePolygon.getNextControlPoint(0));
110 : }
111 : }
112 : }
113 : else
114 : {
115 0 : o_aLeft.clear();
116 0 : o_aRight.clear();
117 : }
118 0 : }
119 :
120 : // #112245# helper to evtl. split filled polygons to maximum metafile point count
121 2614 : bool fillPolyPolygonNeededToBeSplit(basegfx::B2DPolyPolygon& rPolyPolygon)
122 : {
123 2614 : bool bRetval(false);
124 2614 : const sal_uInt32 nPolyCount(rPolyPolygon.count());
125 :
126 2614 : if(nPolyCount)
127 : {
128 2614 : basegfx::B2DPolyPolygon aSplitted;
129 :
130 8244 : for(sal_uInt32 a(0); a < nPolyCount; a++)
131 : {
132 5630 : const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(a));
133 5630 : const sal_uInt32 nPointCount(aCandidate.count());
134 5630 : bool bNeedToSplit(false);
135 :
136 5630 : if(aCandidate.areControlPointsUsed())
137 : {
138 : // compare with the maximum for bezier curved polygons
139 368 : bNeedToSplit = nPointCount > ((MAX_POLYGON_POINT_COUNT_METAFILE / 3L) - 1L);
140 : }
141 : else
142 : {
143 : // compare with the maximum for simple point polygons
144 5262 : bNeedToSplit = nPointCount > (MAX_POLYGON_POINT_COUNT_METAFILE - 1);
145 : }
146 :
147 5630 : if(bNeedToSplit)
148 : {
149 : // need to split the partial polygon
150 0 : const basegfx::B2DRange aRange(aCandidate.getB2DRange());
151 0 : const basegfx::B2DPoint aCenter(aRange.getCenter());
152 :
153 0 : if(aRange.getWidth() > aRange.getHeight())
154 : {
155 : // clip in left and right
156 : const basegfx::B2DPolyPolygon aLeft(
157 : basegfx::tools::clipPolygonOnParallelAxis(
158 : aCandidate,
159 : false,
160 : true,
161 : aCenter.getX(),
162 0 : false));
163 : const basegfx::B2DPolyPolygon aRight(
164 : basegfx::tools::clipPolygonOnParallelAxis(
165 : aCandidate,
166 : false,
167 : false,
168 : aCenter.getX(),
169 0 : false));
170 :
171 0 : aSplitted.append(aLeft);
172 0 : aSplitted.append(aRight);
173 : }
174 : else
175 : {
176 : // clip in top and bottom
177 : const basegfx::B2DPolyPolygon aTop(
178 : basegfx::tools::clipPolygonOnParallelAxis(
179 : aCandidate,
180 : true,
181 : true,
182 : aCenter.getY(),
183 0 : false));
184 : const basegfx::B2DPolyPolygon aBottom(
185 : basegfx::tools::clipPolygonOnParallelAxis(
186 : aCandidate,
187 : true,
188 : false,
189 : aCenter.getY(),
190 0 : false));
191 :
192 0 : aSplitted.append(aTop);
193 0 : aSplitted.append(aBottom);
194 0 : }
195 : }
196 : else
197 : {
198 5630 : aSplitted.append(aCandidate);
199 : }
200 5630 : }
201 :
202 2614 : if(aSplitted.count() != nPolyCount)
203 : {
204 0 : rPolyPolygon = aSplitted;
205 2614 : }
206 : }
207 :
208 2614 : return bRetval;
209 : }
210 :
211 : /** Filter input polypolygon for effectively empty sub-fills
212 :
213 : Needed to fix fdo#37559
214 :
215 : @param rPoly
216 : tools::PolyPolygon to filter
217 :
218 : @return converted tools PolyPolygon, w/o one-point fills
219 : */
220 94 : tools::PolyPolygon getFillPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly )
221 : {
222 : // filter input rPoly
223 94 : basegfx::B2DPolyPolygon aPoly;
224 94 : sal_uInt32 nCount(rPoly.count());
225 676 : for( sal_uInt32 i=0; i<nCount; ++i )
226 : {
227 582 : basegfx::B2DPolygon aCandidate(rPoly.getB2DPolygon(i));
228 582 : if( !aCandidate.isClosed() || aCandidate.count() > 1 )
229 410 : aPoly.append(aCandidate);
230 582 : }
231 94 : return tools::PolyPolygon(aPoly);
232 : }
233 :
234 : } // end of anonymous namespace
235 :
236 : namespace drawinglayer
237 : {
238 : namespace processor2d
239 : {
240 0 : Rectangle VclMetafileProcessor2D::impDumpToMetaFile(
241 : const primitive2d::Primitive2DSequence& rContent,
242 : GDIMetaFile& o_rContentMetafile)
243 : {
244 : // Prepare VDev, MetaFile and connections
245 0 : OutputDevice* pLastOutputDevice = mpOutputDevice;
246 0 : GDIMetaFile* pLastMetafile = mpMetaFile;
247 0 : basegfx::B2DRange aPrimitiveRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
248 :
249 : // transform primitive range with current transformation (e.g shadow offset)
250 0 : aPrimitiveRange.transform(maCurrentTransformation);
251 :
252 : const Rectangle aPrimitiveRectangle(
253 0 : basegfx::fround(aPrimitiveRange.getMinX()), basegfx::fround(aPrimitiveRange.getMinY()),
254 0 : basegfx::fround(aPrimitiveRange.getMaxX()), basegfx::fround(aPrimitiveRange.getMaxY()));
255 0 : VirtualDevice aContentVDev;
256 0 : MapMode aNewMapMode(pLastOutputDevice->GetMapMode());
257 :
258 0 : mpOutputDevice = &aContentVDev;
259 0 : mpMetaFile = &o_rContentMetafile;
260 0 : aContentVDev.EnableOutput(false);
261 0 : aContentVDev.SetMapMode(pLastOutputDevice->GetMapMode());
262 0 : o_rContentMetafile.Record(&aContentVDev);
263 0 : aContentVDev.SetLineColor(pLastOutputDevice->GetLineColor());
264 0 : aContentVDev.SetFillColor(pLastOutputDevice->GetFillColor());
265 0 : aContentVDev.SetFont(pLastOutputDevice->GetFont());
266 0 : aContentVDev.SetDrawMode(pLastOutputDevice->GetDrawMode());
267 0 : aContentVDev.SetSettings(pLastOutputDevice->GetSettings());
268 0 : aContentVDev.SetRefPoint(pLastOutputDevice->GetRefPoint());
269 :
270 : // dump to MetaFile
271 0 : process(rContent);
272 :
273 : // cleanups
274 0 : o_rContentMetafile.Stop();
275 0 : o_rContentMetafile.WindStart();
276 0 : aNewMapMode.SetOrigin(aPrimitiveRectangle.TopLeft());
277 0 : o_rContentMetafile.SetPrefMapMode(aNewMapMode);
278 0 : o_rContentMetafile.SetPrefSize(aPrimitiveRectangle.GetSize());
279 0 : mpOutputDevice = pLastOutputDevice;
280 0 : mpMetaFile = pLastMetafile;
281 :
282 0 : return aPrimitiveRectangle;
283 : }
284 :
285 12 : void VclMetafileProcessor2D::impConvertFillGradientAttributeToVCLGradient(
286 : Gradient& o_rVCLGradient,
287 : const attribute::FillGradientAttribute& rFiGrAtt,
288 : bool bIsTransparenceGradient)
289 : {
290 12 : if(bIsTransparenceGradient)
291 : {
292 : // it's about transparence channel intensities (black/white), do not use color modifier
293 0 : o_rVCLGradient.SetStartColor(Color(rFiGrAtt.getStartColor()));
294 0 : o_rVCLGradient.SetEndColor(Color(rFiGrAtt.getEndColor()));
295 : }
296 : else
297 : {
298 : // use color modifier to influence start/end color of gradient
299 12 : o_rVCLGradient.SetStartColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getStartColor())));
300 12 : o_rVCLGradient.SetEndColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getEndColor())));
301 : }
302 :
303 12 : o_rVCLGradient.SetAngle(static_cast< sal_uInt16 >(rFiGrAtt.getAngle() * (1.0 / F_PI1800)));
304 12 : o_rVCLGradient.SetBorder(static_cast< sal_uInt16 >(rFiGrAtt.getBorder() * 100.0));
305 12 : o_rVCLGradient.SetOfsX(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetX() * 100.0));
306 12 : o_rVCLGradient.SetOfsY(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetY() * 100.0));
307 12 : o_rVCLGradient.SetSteps(rFiGrAtt.getSteps());
308 :
309 : // defaults for intensity; those were computed into the start/end colors already
310 12 : o_rVCLGradient.SetStartIntensity(100);
311 12 : o_rVCLGradient.SetEndIntensity(100);
312 :
313 12 : switch(rFiGrAtt.getStyle())
314 : {
315 : default : // attribute::GRADIENTSTYLE_LINEAR :
316 : {
317 4 : o_rVCLGradient.SetStyle(GradientStyle_LINEAR);
318 4 : break;
319 : }
320 : case attribute::GRADIENTSTYLE_AXIAL :
321 : {
322 8 : o_rVCLGradient.SetStyle(GradientStyle_AXIAL);
323 8 : break;
324 : }
325 : case attribute::GRADIENTSTYLE_RADIAL :
326 : {
327 0 : o_rVCLGradient.SetStyle(GradientStyle_RADIAL);
328 0 : break;
329 : }
330 : case attribute::GRADIENTSTYLE_ELLIPTICAL :
331 : {
332 0 : o_rVCLGradient.SetStyle(GradientStyle_ELLIPTICAL);
333 0 : break;
334 : }
335 : case attribute::GRADIENTSTYLE_SQUARE :
336 : {
337 0 : o_rVCLGradient.SetStyle(GradientStyle_SQUARE);
338 0 : break;
339 : }
340 : case attribute::GRADIENTSTYLE_RECT :
341 : {
342 0 : o_rVCLGradient.SetStyle(GradientStyle_RECT);
343 0 : break;
344 : }
345 : }
346 12 : }
347 :
348 94 : void VclMetafileProcessor2D::impStartSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill)
349 : {
350 94 : if(pSvtGraphicFill && !mnSvtGraphicFillCount)
351 : {
352 94 : SvMemoryStream aMemStm;
353 :
354 94 : WriteSvtGraphicFill( aMemStm, *pSvtGraphicFill );
355 94 : mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END)));
356 94 : mnSvtGraphicFillCount++;
357 : }
358 94 : }
359 :
360 94 : void VclMetafileProcessor2D::impEndSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill)
361 : {
362 94 : if(pSvtGraphicFill && mnSvtGraphicFillCount)
363 : {
364 94 : mnSvtGraphicFillCount--;
365 94 : mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_END"));
366 94 : delete pSvtGraphicFill;
367 : }
368 94 : }
369 :
370 4466 : double VclMetafileProcessor2D::getTransformedLineWidth( double fWidth ) const
371 : {
372 : // #i113922# the LineWidth is duplicated in the MetaPolylineAction,
373 : // and also inside the SvtGraphicStroke and needs transforming into
374 : // the same space as its co-ordinates here cf. fdo#61789
375 : // This is a partial fix. When a object transformation is used which
376 : // e.g. contains a scaleX != scaleY, an unproportional scaling will happen.
377 4466 : const basegfx::B2DVector aDiscreteUnit( maCurrentTransformation * basegfx::B2DVector( fWidth, 0.0 ) );
378 :
379 4466 : return aDiscreteUnit.getLength();
380 : }
381 :
382 3484 : SvtGraphicStroke* VclMetafileProcessor2D::impTryToCreateSvtGraphicStroke(
383 : const basegfx::B2DPolygon& rB2DPolygon,
384 : const basegfx::BColor* pColor,
385 : const attribute::LineAttribute* pLineAttribute,
386 : const attribute::StrokeAttribute* pStrokeAttribute,
387 : const attribute::LineStartEndAttribute* pStart,
388 : const attribute::LineStartEndAttribute* pEnd)
389 : {
390 3484 : SvtGraphicStroke* pRetval = 0;
391 :
392 3484 : if(rB2DPolygon.count() && !mnSvtGraphicStrokeCount)
393 : {
394 3386 : basegfx::B2DPolygon aLocalPolygon(rB2DPolygon);
395 6772 : basegfx::BColor aStrokeColor;
396 6772 : basegfx::B2DPolyPolygon aStartArrow;
397 6772 : basegfx::B2DPolyPolygon aEndArrow;
398 :
399 3386 : if(pColor)
400 : {
401 0 : aStrokeColor = *pColor;
402 : }
403 3386 : else if(pLineAttribute)
404 : {
405 3386 : aStrokeColor = maBColorModifierStack.getModifiedColor(pLineAttribute->getColor());
406 : }
407 :
408 : // It IS needed to record the stroke color at all in the metafile,
409 : // SvtGraphicStroke has NO entry for stroke color(!)
410 3386 : mpOutputDevice->SetLineColor(Color(aStrokeColor));
411 :
412 3386 : if(!aLocalPolygon.isClosed())
413 : {
414 498 : double fPolyLength(0.0);
415 498 : double fStart(0.0);
416 498 : double fEnd(0.0);
417 :
418 498 : if(pStart && pStart->isActive())
419 : {
420 78 : fPolyLength = basegfx::tools::getLength(aLocalPolygon);
421 :
422 234 : aStartArrow = basegfx::tools::createAreaGeometryForLineStartEnd(
423 78 : aLocalPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(),
424 156 : fPolyLength, pStart->isCentered() ? 0.5 : 0.0, &fStart);
425 : }
426 :
427 498 : if(pEnd && pEnd->isActive())
428 : {
429 98 : if(basegfx::fTools::equalZero(fPolyLength))
430 : {
431 72 : fPolyLength = basegfx::tools::getLength(aLocalPolygon);
432 : }
433 :
434 294 : aEndArrow = basegfx::tools::createAreaGeometryForLineStartEnd(
435 98 : aLocalPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(),
436 196 : fPolyLength, pEnd->isCentered() ? 0.5 : 0.0, &fEnd);
437 : }
438 :
439 498 : if(0.0 != fStart || 0.0 != fEnd)
440 : {
441 : // build new poly, consume something from old poly
442 98 : aLocalPolygon = basegfx::tools::getSnippetAbsolute(aLocalPolygon, fStart, fPolyLength - fEnd, fPolyLength);
443 : }
444 : }
445 :
446 3386 : SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone);
447 3386 : SvtGraphicStroke::CapType eCap(SvtGraphicStroke::capButt);
448 3386 : double fLineWidth(0.0);
449 3386 : double fMiterLength(0.0);
450 6772 : SvtGraphicStroke::DashArray aDashArray;
451 :
452 3386 : if(pLineAttribute)
453 : {
454 3386 : fLineWidth = fMiterLength = getTransformedLineWidth( pLineAttribute->getWidth() );
455 :
456 : // get Join
457 3386 : switch(pLineAttribute->getLineJoin())
458 : {
459 : default : // basegfx::B2DLINEJOIN_NONE :
460 : {
461 6 : eJoin = SvtGraphicStroke::joinNone;
462 6 : break;
463 : }
464 : case basegfx::B2DLINEJOIN_BEVEL :
465 : {
466 312 : eJoin = SvtGraphicStroke::joinBevel;
467 312 : break;
468 : }
469 : case basegfx::B2DLINEJOIN_MIDDLE :
470 : case basegfx::B2DLINEJOIN_MITER :
471 : {
472 404 : eJoin = SvtGraphicStroke::joinMiter;
473 : // ATM 15 degrees is assumed
474 404 : fMiterLength /= rtl::math::sin(M_PI * (15.0 / 360.0));
475 404 : break;
476 : }
477 : case basegfx::B2DLINEJOIN_ROUND :
478 : {
479 2664 : eJoin = SvtGraphicStroke::joinRound;
480 2664 : break;
481 : }
482 : }
483 :
484 : // get stroke
485 3386 : switch(pLineAttribute->getLineCap())
486 : {
487 : default: /* com::sun::star::drawing::LineCap_BUTT */
488 : {
489 3380 : eCap = SvtGraphicStroke::capButt;
490 3380 : break;
491 : }
492 : case com::sun::star::drawing::LineCap_ROUND:
493 : {
494 6 : eCap = SvtGraphicStroke::capRound;
495 6 : break;
496 : }
497 : case com::sun::star::drawing::LineCap_SQUARE:
498 : {
499 0 : eCap = SvtGraphicStroke::capSquare;
500 0 : break;
501 : }
502 : }
503 : }
504 :
505 3386 : if(pStrokeAttribute)
506 : {
507 : // copy dash array
508 3386 : aDashArray = pStrokeAttribute->getDotDashArray();
509 : }
510 :
511 : // #i101734# apply current object transformation to created geometry.
512 : // This is a partial fix. When a object transformation is used which
513 : // e.g. contains a scaleX != scaleY, an unproportional scaling would
514 : // have to be applied to the evtl. existing fat line. The current
515 : // concept of PDF export and SvtGraphicStroke usage does simply not
516 : // allow handling such definitions. The only clean way would be to
517 : // add the transformation to SvtGraphicStroke and to handle it there
518 3386 : aLocalPolygon.transform(maCurrentTransformation);
519 3386 : aStartArrow.transform(maCurrentTransformation);
520 3386 : aEndArrow.transform(maCurrentTransformation);
521 :
522 : pRetval = new SvtGraphicStroke(
523 : Polygon(aLocalPolygon),
524 : tools::PolyPolygon(aStartArrow),
525 : tools::PolyPolygon(aEndArrow),
526 : mfCurrentUnifiedTransparence,
527 : fLineWidth,
528 : eCap,
529 : eJoin,
530 : fMiterLength,
531 6772 : aDashArray);
532 : }
533 :
534 3484 : return pRetval;
535 : }
536 :
537 3484 : void VclMetafileProcessor2D::impStartSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke)
538 : {
539 3484 : if(pSvtGraphicStroke && !mnSvtGraphicStrokeCount)
540 : {
541 3386 : SvMemoryStream aMemStm;
542 :
543 3386 : WriteSvtGraphicStroke( aMemStm, *pSvtGraphicStroke );
544 3386 : mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END)));
545 3386 : mnSvtGraphicStrokeCount++;
546 : }
547 3484 : }
548 :
549 3484 : void VclMetafileProcessor2D::impEndSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke)
550 : {
551 3484 : if(pSvtGraphicStroke && mnSvtGraphicStrokeCount)
552 : {
553 3386 : mnSvtGraphicStrokeCount--;
554 3386 : mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_END"));
555 3386 : delete pSvtGraphicStroke;
556 : }
557 3484 : }
558 :
559 : // init static break iterator
560 381 : uno::Reference< ::com::sun::star::i18n::XBreakIterator > VclMetafileProcessor2D::mxBreakIterator;
561 :
562 1410 : VclMetafileProcessor2D::VclMetafileProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev)
563 : : VclProcessor2D(rViewInformation, rOutDev),
564 1410 : mpMetaFile(rOutDev.GetConnectMetaFile()),
565 : mnSvtGraphicFillCount(0),
566 : mnSvtGraphicStrokeCount(0),
567 : mfCurrentUnifiedTransparence(0.0),
568 2820 : mpPDFExtOutDevData(dynamic_cast< vcl::PDFExtOutDevData* >(rOutDev.GetExtOutDevData()))
569 : {
570 : OSL_ENSURE(rOutDev.GetConnectMetaFile(), "VclMetafileProcessor2D: Used on OutDev which has no MetaFile Target (!)");
571 : // draw to logic coordinates, do not initialize maCurrentTransformation to viewTransformation
572 : // but only to ObjectTransformation. Do not change MapMode of destination.
573 1410 : maCurrentTransformation = rViewInformation.getObjectTransformation();
574 1410 : }
575 :
576 2820 : VclMetafileProcessor2D::~VclMetafileProcessor2D()
577 : {
578 : // MapMode was not changed, no restore necessary
579 2820 : }
580 :
581 : /***********************************************************************************************
582 :
583 : Support of MetaCommentActions in the VclMetafileProcessor2D
584 : Found MetaCommentActions and how they are supported:
585 :
586 : XGRAD_SEQ_BEGIN, XGRAD_SEQ_END:
587 :
588 : Used inside OutputDevice::DrawGradient to mark the start and end of a MetaGradientEx action.
589 : It is used in various exporters/importers to have direct access to the gradient before it
590 : is rendered by VCL (and thus fragmented to polygon color actions and others). On that base, e.g.
591 : the Metafile to SdrObject import creates it's gradient objects.
592 : Best (and safest) way to support it here is to use PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
593 : map it back to the corresponding tools tools::PolyPolygon and the Gradient and just call
594 : OutputDevice::DrawGradient which creates the necessary compatible actions.
595 :
596 : XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END:
597 :
598 : Two producers, one is vcl/source/gdi/gdimtf.cxx, line 1273. There, it is transformed
599 : inside GDIMetaFile::Rotate, nothing to take care of here.
600 : The second producer is in graphics/svx/source/svdraw/impgrfll.cxx, line 374. This is used
601 : with each incarnation of Imp_GraphicFill when a metafile is recorded, fillstyle is not
602 : XFILL_NONE and not completely transparent. It creates a SvtGraphicFill and streams it
603 : to the comment action. A closing end token is created in the destructor.
604 : Usages of Imp_GraphicFill are in Do_Paint_Object-methods of SdrCircObj, SdrPathObj and
605 : SdrRectObj.
606 : The token users pick various actions from SvtGraphicFill, so it may need to be added for all kind
607 : of filled objects, even simple colored polygons. It is added as extra information; the
608 : Metafile actions between the two tokens are interpreted as output generated from those
609 : fills. Thus, users have the choice to use the SvtGraphicFill info or the created output
610 : actions.
611 : Even for XFillTransparenceItem it is used, thus it may need to be supported in
612 : UnifiedTransparencePrimitive2D, too, when interpreted as normally filled PolyPolygon.
613 : Implemented for:
614 : PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D,
615 : PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D,
616 : PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
617 : PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D,
618 : and for PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D when detected unified transparence
619 :
620 : XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END:
621 :
622 : Similar to pathfill, but using SvtGraphicStroke instead. It also has two producers where one
623 : is also the GDIMetaFile::Rotate. Another user is MetaCommentAction::Move which modifies the
624 : contained path accordingly.
625 : The other one is SdrObject::Imp_DrawLineGeometry. It's done when MetaFile is set at OutDev and
626 : only when geometry is a single polygon (!). I see no reason for that; in the PS exporter this
627 : would hinder to make use of tools::PolyPolygon strokes. I will need to add support at:
628 : PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D
629 : PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D
630 : PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D
631 : This can be done hierarchical, too.
632 : Okay, base implementation done based on those three primitives.
633 :
634 : FIELD_SEQ_BEGIN, FIELD_SEQ_END
635 :
636 : Used from slideshow for URLs, created from diverse SvxField implementations inside
637 : createBeginComment()/createEndComment(). createBeginComment() is used from editeng\impedit3.cxx
638 : inside ImpEditEngine::Paint.
639 : Created TextHierarchyFieldPrimitive2D and added needed infos there; it is an group primitive and wraps
640 : text primitives (but is not limited to that). It contains the field type if special actions for the
641 : support of FIELD_SEQ_BEGIN/END are needed; this is the case for Page and URL fields. If more is
642 : needed, it may be supported there.
643 : FIELD_SEQ_BEGIN;PageField
644 : FIELD_SEQ_END
645 : Okay, these are now completely supported by TextHierarchyFieldPrimitive2D. URL works, too.
646 :
647 : XTEXT
648 :
649 : XTEXT_EOC(i) end of character
650 : XTEXT_EOW(i) end of word
651 : XTEXT_EOS(i) end of sentence
652 :
653 : this three are with index and are created with the help of a i18n::XBreakIterator in
654 : ImplDrawWithComments. Simplifying, moving out text painting, reworking to create some
655 : data structure for holding those TEXT infos.
656 : Supported directly by TextSimplePortionPrimitive2D with adding a Locale to the basic text
657 : primitive. In the MetaFileRenderer, the creation is now done (see below). This has the advantage
658 : that this creations do not need to be done for all paints all the time. This would be
659 : expensive since the BreakIterator and it's usage is expensive and for each paint also the
660 : whole character stops would need to be created.
661 : Created only for TextDecoratedPortionPrimitive2D due to XTEXT_EOL and XTEXT_EOP (see below)
662 :
663 : XTEXT_EOL() end of line
664 : XTEXT_EOP() end of paragraph
665 :
666 : First try with boolean marks at TextDecoratedPortionPrimitive2D did not work too well,
667 : i decided to solve it with structure. I added the TextHierarchyPrimitives for this,
668 : namely:
669 : - TextHierarchyLinePrimitive2D: Encapsulates single line
670 : - TextHierarchyParagraphPrimitive2D: Encapsulates single paragraph
671 : - TextHierarchyBlockPrimitive2D: encapsulates object texts (only one ATM)
672 : Those are now supported in hierarchy. This means the MetaFile renderer will support them
673 : by using them, reculrively using their content and adding MetaFile comments as needed.
674 : This also means that when another text layouter will be used it will be necessary to
675 : create/support the same HierarchyPrimitives to support users.
676 : To transport the information using this hierarchy is best suited to all future needs;
677 : the slideshow will be able to profit from it directly when using primitives; all other
678 : renderers not interested in the text structure will just ignore the encapsulations.
679 :
680 : XTEXT_PAINTSHAPE_BEGIN, XTEXT_PAINTSHAPE_END
681 : Supported now by the TextHierarchyBlockPrimitive2D.
682 :
683 : EPSReplacementGraphic:
684 : Only used in goodies\source\filter.vcl\ieps\ieps.cxx and svx\source\xml\xmlgrhlp.cxx to
685 : hold the original EPS which was imported in the same MetaFile as first 2 entries. Only
686 : used to export the original again (if exists).
687 : Not necessary to support with MetaFuleRenderer.
688 :
689 : XTEXT_SCROLLRECT, XTEXT_PAINTRECT
690 : Currently used to get extra MetaFile infos using GraphicExporter which again uses
691 : SdrTextObj::GetTextScrollMetaFileAndRectangle(). ATM works with primitives since
692 : the rectangle data is added directly by the GraphicsExporter as comment. Does not need
693 : to be adapted at once.
694 : When adapting later, the only user - the diashow - should directly use the provided
695 : Anination infos in the appropriate primitives (e.g. AnimatedSwitchPrimitive2D)
696 :
697 : PRNSPOOL_TRANSPARENTBITMAP_BEGIN, PRNSPOOL_TRANSPARENTBITMAP_END
698 : VCL usage when printing PL -> THB. Okay, THB confirms that it is only used as
699 : a fix (hack) while VCL printing. It is needed to not downscale a bitmap which
700 : was explicitly created for the printer already again to some default maximum
701 : bitmap sizes.
702 : Nothing to do here for the primitive renderer.
703 :
704 : Support for vcl::PDFExtOutDevData:
705 : PL knows that SJ did that stuff, it's used to hold a pointer to PDFExtOutDevData at
706 : the OutDev. When set, some extra data is written there. Trying simple PDF export and
707 : watching if i get those infos.
708 : Well, a PDF export does not use e.g. ImpEditEngine::Paint since the PdfFilter uses
709 : the SdXImpressDocument::render and thus uses the VclMetafileProcessor2D. I will check
710 : if i get a PDFExtOutDevData at the target output device.
711 : Indeed, i get one. Checking what all may be done when that extra-device-info is there.
712 :
713 : All in all i have to talk to SJ. I will need to emulate some of those actions, but
714 : i need to discuss which ones.
715 : In the future, all those infos would be taken from the primitive sequence anyways,
716 : thus these extensions would potentially be temporary, too.
717 : Discussed with SJ, added the necessary support and tested it. Details follow.
718 :
719 : - In ImpEditEngine::Paint, paragraph infos and URL stuff is added.
720 : Added in primitive MetaFile renderer.
721 : Checking URL: Indeed, current version exports it, but it is missing in primitive
722 : CWS version. Adding support.
723 : Okay, URLs work. Checked, Done.
724 :
725 : - UnoControlPDFExportContact is only created when PDFExtOutDevData is used at the
726 : target and uno control data is created in UnoControlPDFExportContact::do_PaintObject.
727 : This may be added in primitive MetaFile renderer.
728 : Adding support...
729 : OOps, the necessary helper stuff is in svx/source/form/formpdxexport.cxx in namespace
730 : svxform. Have to talk to FS if this has to be like that. Especially since
731 : ::vcl::PDFWriter::AnyWidget is filled out, which is already part of vcl.
732 : Wrote an eMail to FS, he is on vacation currently. I see no reason why not to move
733 : that stuff to somewhere else, maybe tools or svtools ?!? We will see...
734 : Moved to toolkit, so i have to link against it. I tried VCL first, but it did
735 : not work since VCLUnoHelper::CreateFont is unresolved in VCL (!). Other then the name
736 : may imply, it is defined in toolkit (!). Since toolkit is linked against VCL itself,
737 : the lowest move,ment plave is toolkit.
738 : Checked form control export, it works well. Done.
739 :
740 : - In goodies, in GraphicObject::Draw, when the used Graphic is linked, infos are
741 : generated. I will need to check what happens here with primitives.
742 : To support, use of GraphicPrimitive2D (PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D) may be needed.
743 : Added support, but feature is broken in main version, so i cannot test at all.
744 : Writing a bug to CL (or SJ) and seeing what happens (#i80380#).
745 : SJ took a look and we got it working. Tested VCL MetaFile Renderer based export,
746 : as intended, the original file is exported. Works, Done.
747 :
748 :
749 :
750 :
751 : To be done:
752 :
753 : - Maybe there are more places to take care of for vcl::PDFExtOutDevData!
754 :
755 :
756 :
757 : ****************************************************************************************************/
758 :
759 24084 : void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
760 : {
761 24084 : switch(rCandidate.getPrimitive2DID())
762 : {
763 : case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
764 : {
765 : // directdraw of wrong spell primitive
766 : // Ignore for VclMetafileProcessor2D, this is for printing and MetaFile recording only
767 0 : break;
768 : }
769 : case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D :
770 : {
771 268 : const primitive2d::GraphicPrimitive2D& rGraphicPrimitive = static_cast< const primitive2d::GraphicPrimitive2D& >(rCandidate);
772 268 : bool bUsingPDFExtOutDevData(false);
773 536 : basegfx::B2DVector aTranslate, aScale;
774 : static bool bSuppressPDFExtOutDevDataSupport(false);
775 :
776 268 : if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport)
777 : {
778 : // emulate data handling from UnoControlPDFExportContact, original see
779 : // svtools/source/graphic/grfmgr.cxx
780 0 : const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic();
781 :
782 0 : if(rGraphic.IsLink())
783 : {
784 0 : const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
785 :
786 0 : if(!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted())
787 : {
788 0 : const basegfx::B2DHomMatrix& rTransform = rGraphicPrimitive.getTransform();
789 : double fRotate, fShearX;
790 0 : rTransform.decompose(aScale, aTranslate, fRotate, fShearX);
791 :
792 0 : if( basegfx::fTools::equalZero( fRotate ) && ( aScale.getX() > 0.0 ) && ( aScale.getY() > 0.0 ) )
793 : {
794 0 : bUsingPDFExtOutDevData = true;
795 0 : mpPDFExtOutDevData->BeginGroup();
796 : }
797 : }
798 : }
799 : }
800 :
801 : // process recursively and add MetaFile comment
802 268 : process(rGraphicPrimitive.get2DDecomposition(getViewInformation2D()));
803 :
804 268 : if(bUsingPDFExtOutDevData)
805 : {
806 : // emulate data handling from UnoControlPDFExportContact, original see
807 : // svtools/source/graphic/grfmgr.cxx
808 : const basegfx::B2DRange aCurrentRange(
809 : aTranslate.getX(), aTranslate.getY(),
810 0 : aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
811 : const Rectangle aCurrentRect(
812 0 : sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())),
813 0 : sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY())));
814 0 : const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
815 : // fdo#72530 don't pass empty Rectangle to EndGroup
816 0 : Rectangle aCropRect(aCurrentRect);
817 :
818 0 : if(rAttr.IsCropped())
819 : {
820 : // calculate scalings between real image size and logic object size. This
821 : // is necessary since the crop values are relative to original bitmap size
822 0 : double fFactorX(1.0);
823 0 : double fFactorY(1.0);
824 :
825 : {
826 0 : const MapMode aMapMode100thmm(MAP_100TH_MM);
827 : const Size aBitmapSize(OutputDevice::LogicToLogic(
828 0 : rGraphicPrimitive.getGraphicObject().GetPrefSize(),
829 0 : rGraphicPrimitive.getGraphicObject().GetPrefMapMode(), aMapMode100thmm));
830 0 : const double fDivX(aBitmapSize.Width() - rAttr.GetLeftCrop() - rAttr.GetRightCrop());
831 0 : const double fDivY(aBitmapSize.Height() - rAttr.GetTopCrop() - rAttr.GetBottomCrop());
832 :
833 0 : if(!basegfx::fTools::equalZero(fDivX))
834 : {
835 0 : fFactorX = aScale.getX() / fDivX;
836 : }
837 :
838 0 : if(!basegfx::fTools::equalZero(fDivY))
839 : {
840 0 : fFactorY = aScale.getY() / fDivY;
841 0 : }
842 : }
843 :
844 : // calculate crop range and rect
845 0 : basegfx::B2DRange aCropRange;
846 0 : aCropRange.expand(aCurrentRange.getMinimum() - basegfx::B2DPoint(rAttr.GetLeftCrop() * fFactorX, rAttr.GetTopCrop() * fFactorY));
847 0 : aCropRange.expand(aCurrentRange.getMaximum() + basegfx::B2DPoint(rAttr.GetRightCrop() * fFactorX, rAttr.GetBottomCrop() * fFactorY));
848 :
849 : aCropRect = Rectangle(
850 0 : sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())),
851 0 : sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY())));
852 : }
853 :
854 : // #i123295# 3rd param is uncropped rect, 4th is cropped. The primitive has the cropped
855 : // object transformation, thus aCurrentRect *is* the clip region while aCropRect is the expanded,
856 : // uncropped region. Thus, correct order is aCropRect, aCurrentRect
857 0 : mpPDFExtOutDevData->EndGroup(rGraphicPrimitive.getGraphicObject().GetGraphic(),
858 0 : rAttr.GetTransparency(),
859 : aCropRect,
860 0 : aCurrentRect);
861 : }
862 :
863 536 : break;
864 : }
865 : case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
866 : {
867 2 : const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate);
868 2 : const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl());
869 2 : bool bIsPrintableControl(false);
870 :
871 : // find out if control is printable
872 2 : if(rXControl.is())
873 : {
874 : try
875 : {
876 2 : uno::Reference< beans::XPropertySet > xModelProperties(rXControl->getModel(), uno::UNO_QUERY);
877 2 : uno::Reference< beans::XPropertySetInfo > xPropertyInfo(xModelProperties.is()
878 2 : ? xModelProperties->getPropertySetInfo()
879 6 : : uno::Reference< beans::XPropertySetInfo >());
880 4 : const OUString sPrintablePropertyName("Printable");
881 :
882 2 : if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName))
883 : {
884 2 : OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl);
885 2 : }
886 : }
887 0 : catch(const uno::Exception&)
888 : {
889 : OSL_FAIL("VclMetafileProcessor2D: No access to printable flag of Control, caught an exception!");
890 : }
891 : }
892 :
893 : // PDF export and printing only for printable controls
894 2 : if(bIsPrintableControl)
895 : {
896 2 : const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields());
897 2 : bool bDoProcessRecursively(true);
898 :
899 2 : if(bPDFExport)
900 : {
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::unique_ptr< ::vcl::PDFWriter::AnyWidget > pPDFControl(
905 0 : ::toolkitform::describePDFControl( rXControl, *mpPDFExtOutDevData ) );
906 :
907 0 : if(pPDFControl.get())
908 : {
909 : // still need to fill in the location (is a class Rectangle)
910 0 : const basegfx::B2DRange aRangeLogic(rControlPrimitive.getB2DRange(getViewInformation2D()));
911 : const Rectangle aRectLogic(
912 0 : (sal_Int32)floor(aRangeLogic.getMinX()), (sal_Int32)floor(aRangeLogic.getMinY()),
913 0 : (sal_Int32)ceil(aRangeLogic.getMaxX()), (sal_Int32)ceil(aRangeLogic.getMaxY()));
914 0 : pPDFControl->Location = aRectLogic;
915 :
916 0 : Size aFontSize(pPDFControl->TextFont.GetSize());
917 0 : aFontSize = OutputDevice::LogicToLogic(aFontSize, MapMode(MAP_POINT), mpOutputDevice->GetMapMode());
918 0 : pPDFControl->TextFont.SetSize(aFontSize);
919 :
920 0 : mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form);
921 0 : mpPDFExtOutDevData->CreateControl(*pPDFControl.get());
922 0 : mpPDFExtOutDevData->EndStructureElement();
923 :
924 : // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject);
925 : // do not process recursively
926 0 : bDoProcessRecursively = false;
927 : }
928 : else
929 : {
930 : // PDF export did not work, try simple output.
931 : // Fallback to printer output by not setting bDoProcessRecursively
932 : // to false.
933 0 : }
934 : }
935 :
936 : // #i93169# used flag the wrong way; true means that nothing was done yet
937 2 : if(bDoProcessRecursively)
938 : {
939 : // printer output
940 : try
941 : {
942 : // remember old graphics and create new
943 2 : uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW);
944 4 : const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics());
945 4 : const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics());
946 :
947 2 : if(xNewGraphics.is())
948 : {
949 : // link graphics and view
950 2 : xControlView->setGraphics(xNewGraphics);
951 :
952 : // get position
953 2 : const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform());
954 4 : const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0));
955 :
956 : // draw it
957 2 : xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY()));
958 2 : bDoProcessRecursively = false;
959 :
960 : // restore original graphics
961 4 : xControlView->setGraphics(xOriginalGraphics);
962 2 : }
963 : }
964 0 : catch( const uno::Exception& )
965 : {
966 : OSL_FAIL("VclMetafileProcessor2D: Printing of Control failed, caught an exception!");
967 : }
968 : }
969 :
970 : // process recursively if not done yet to export as decomposition (bitmap)
971 2 : if(bDoProcessRecursively)
972 : {
973 0 : process(rControlPrimitive.get2DDecomposition(getViewInformation2D()));
974 : }
975 : }
976 :
977 2 : break;
978 : }
979 : case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D :
980 : {
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 4 : const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive = static_cast< const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate);
984 4 : const OString aCommentStringCommon("FIELD_SEQ_BEGIN");
985 8 : const OString aCommentStringPage("FIELD_SEQ_BEGIN;PageField");
986 8 : const OString aCommentStringEnd("FIELD_SEQ_END");
987 :
988 4 : switch(rFieldPrimitive.getType())
989 : {
990 : default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON :
991 : {
992 4 : mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon));
993 4 : break;
994 : }
995 : case drawinglayer::primitive2d::FIELD_TYPE_PAGE :
996 : {
997 0 : mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage));
998 0 : break;
999 : }
1000 : case drawinglayer::primitive2d::FIELD_TYPE_URL :
1001 : {
1002 0 : const OUString& rURL = rFieldPrimitive.getString();
1003 0 : const OUString aOldString(rURL);
1004 0 : mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast< const sal_uInt8* >(aOldString.getStr()), 2 * aOldString.getLength()));
1005 0 : break;
1006 : }
1007 : }
1008 :
1009 : // process recursively
1010 4 : const primitive2d::Primitive2DSequence rContent = rFieldPrimitive.get2DDecomposition(getViewInformation2D());
1011 4 : process(rContent);
1012 :
1013 : // for the end comment the type is not relevant yet, they are all the same. Just add.
1014 4 : mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd));
1015 :
1016 4 : if(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType())
1017 : {
1018 : // emulate data handling from ImpEditEngine::Paint
1019 0 : const basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
1020 : const Rectangle aRectLogic(
1021 0 : (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()),
1022 0 : (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY()));
1023 0 : vcl::PDFExtOutDevBookmarkEntry aBookmark;
1024 0 : aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic);
1025 0 : aBookmark.aBookmark = rFieldPrimitive.getString();
1026 0 : std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks();
1027 0 : rBookmarks.push_back( aBookmark );
1028 : }
1029 :
1030 8 : break;
1031 : }
1032 : case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D :
1033 : {
1034 774 : const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive = static_cast< const primitive2d::TextHierarchyLinePrimitive2D& >(rCandidate);
1035 774 : const OString aCommentString("XTEXT_EOL");
1036 :
1037 : // process recursively and add MetaFile comment
1038 774 : process(rLinePrimitive.get2DDecomposition(getViewInformation2D()));
1039 774 : mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
1040 :
1041 774 : break;
1042 : }
1043 : case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D :
1044 : {
1045 : // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The
1046 : // "XTEXT_EOC" is used, use here, too.
1047 36 : const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive = static_cast< const primitive2d::TextHierarchyBulletPrimitive2D& >(rCandidate);
1048 36 : const OString aCommentString("XTEXT_EOC");
1049 :
1050 : // process recursively and add MetaFile comment
1051 36 : process(rBulletPrimitive.get2DDecomposition(getViewInformation2D()));
1052 36 : mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
1053 :
1054 36 : break;
1055 : }
1056 : case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D :
1057 : {
1058 714 : const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive = static_cast< const primitive2d::TextHierarchyParagraphPrimitive2D& >(rCandidate);
1059 714 : const OString aCommentString("XTEXT_EOP");
1060 :
1061 714 : if(mpPDFExtOutDevData)
1062 : {
1063 : // emulate data handling from ImpEditEngine::Paint
1064 0 : mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );
1065 : }
1066 :
1067 : // process recursively and add MetaFile comment
1068 714 : process(rParagraphPrimitive.get2DDecomposition(getViewInformation2D()));
1069 714 : mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
1070 :
1071 714 : if(mpPDFExtOutDevData)
1072 : {
1073 : // emulate data handling from ImpEditEngine::Paint
1074 0 : mpPDFExtOutDevData->EndStructureElement();
1075 : }
1076 :
1077 714 : break;
1078 : }
1079 : case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D :
1080 : {
1081 662 : const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive = static_cast< const primitive2d::TextHierarchyBlockPrimitive2D& >(rCandidate);
1082 662 : const OString aCommentStringA("XTEXT_PAINTSHAPE_BEGIN");
1083 1324 : const OString aCommentStringB("XTEXT_PAINTSHAPE_END");
1084 :
1085 : // add MetaFile comment, process recursively and add MetaFile comment
1086 662 : mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA));
1087 662 : process(rBlockPrimitive.get2DDecomposition(getViewInformation2D()));
1088 662 : mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB));
1089 :
1090 1324 : break;
1091 : }
1092 : case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
1093 : case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
1094 : {
1095 : // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate
1096 1008 : const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate = static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate);
1097 : // const primitive2d::TextDecoratedPortionPrimitive2D* pTextDecoratedCandidate = dynamic_cast< const primitive2d::TextDecoratedPortionPrimitive2D* >(&rCandidate);
1098 :
1099 : // Adapt evtl. used special DrawMode
1100 1008 : const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
1101 1008 : adaptTextToFillDrawMode();
1102 :
1103 : // directdraw of text simple portion; use default processing
1104 1008 : RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate);
1105 :
1106 : // restore DrawMode
1107 1008 : mpOutputDevice->SetDrawMode(nOriginalDrawMode);
1108 :
1109 : // #i101169# if(pTextDecoratedCandidate)
1110 : {
1111 : // support for TEXT_ MetaFile actions only for decorated texts
1112 1008 : if(!mxBreakIterator.is())
1113 : {
1114 20 : uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1115 20 : mxBreakIterator = i18n::BreakIterator::create(xContext);
1116 : }
1117 :
1118 1008 : const OUString& rTxt = rTextCandidate.getText();
1119 1008 : const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength());
1120 :
1121 1008 : if(nTextLength)
1122 : {
1123 1008 : const ::com::sun::star::lang::Locale& rLocale = rTextCandidate.getLocale();
1124 1008 : const sal_Int32 nTextPosition(rTextCandidate.getTextPosition());
1125 :
1126 : sal_Int32 nDone;
1127 1008 : sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
1128 1008 : ::com::sun::star::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True));
1129 1008 : sal_Int32 nNextSentenceBreak(mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale));
1130 1008 : const OString aCommentStringA("XTEXT_EOC");
1131 2016 : const OString aCommentStringB("XTEXT_EOW");
1132 2016 : const OString aCommentStringC("XTEXT_EOS");
1133 :
1134 9848 : for(sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++)
1135 : {
1136 : // create the entries for the respective break positions
1137 8840 : if(i == nNextCellBreak)
1138 : {
1139 8840 : mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA, i - nTextPosition));
1140 8840 : nNextCellBreak = mxBreakIterator->nextCharacters(rTxt, i, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
1141 : }
1142 8840 : if(i == nNextWordBoundary.endPos)
1143 : {
1144 948 : mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB, i - nTextPosition));
1145 948 : nNextWordBoundary = mxBreakIterator->getWordBoundary(rTxt, i + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True);
1146 : }
1147 8840 : if(i == nNextSentenceBreak)
1148 : {
1149 48 : mpMetaFile->AddAction(new MetaCommentAction(aCommentStringC, i - nTextPosition));
1150 48 : nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale);
1151 : }
1152 1008 : }
1153 : }
1154 : }
1155 :
1156 1008 : break;
1157 : }
1158 : case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
1159 : {
1160 3414 : const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate);
1161 3414 : const basegfx::B2DPolygon& rBasePolygon = rHairlinePrimitive.getB2DPolygon();
1162 :
1163 3414 : if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
1164 : {
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 0 : basegfx::B2DPolygon aLeft, aRight;
1168 0 : splitLinePolygon(rBasePolygon, aLeft, aRight);
1169 0 : const primitive2d::PolygonHairlinePrimitive2D aPLeft(aLeft, rHairlinePrimitive.getBColor());
1170 0 : const primitive2d::PolygonHairlinePrimitive2D aPRight(aRight, rHairlinePrimitive.getBColor());
1171 :
1172 0 : processBasePrimitive2D(aPLeft);
1173 0 : processBasePrimitive2D(aPRight);
1174 : }
1175 : else
1176 : {
1177 : // direct draw of hairline; use default processing
1178 : // support SvtGraphicStroke MetaCommentAction
1179 3414 : const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor()));
1180 3414 : SvtGraphicStroke* pSvtGraphicStroke = 0;
1181 :
1182 : // #i121267# Not needed, does not give better quality compared with
1183 : // the META_POLYPOLYGON_ACTION written by RenderPolygonHairlinePrimitive2D
1184 : // below
1185 3414 : bool bSupportSvtGraphicStroke(false);
1186 :
1187 3414 : if(bSupportSvtGraphicStroke)
1188 : {
1189 : pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
1190 0 : rHairlinePrimitive.getB2DPolygon(),
1191 : &aLineColor,
1192 0 : 0, 0, 0, 0);
1193 :
1194 0 : impStartSvtGraphicStroke(pSvtGraphicStroke);
1195 : }
1196 :
1197 3414 : RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), false);
1198 :
1199 3414 : if(bSupportSvtGraphicStroke)
1200 : {
1201 0 : impEndSvtGraphicStroke(pSvtGraphicStroke);
1202 3414 : }
1203 : }
1204 3414 : break;
1205 : }
1206 : case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D :
1207 : {
1208 3386 : const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate);
1209 3386 : const basegfx::B2DPolygon& rBasePolygon = rStrokePrimitive.getB2DPolygon();
1210 :
1211 3386 : if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
1212 : {
1213 : // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1214 : // per polygon. If there are more, split the polygon in half and call recursively
1215 0 : basegfx::B2DPolygon aLeft, aRight;
1216 0 : splitLinePolygon(rBasePolygon, aLeft, aRight);
1217 : const primitive2d::PolygonStrokePrimitive2D aPLeft(
1218 0 : aLeft, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute());
1219 : const primitive2d::PolygonStrokePrimitive2D aPRight(
1220 0 : aRight, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute());
1221 :
1222 0 : processBasePrimitive2D(aPLeft);
1223 0 : processBasePrimitive2D(aPRight);
1224 : }
1225 : else
1226 : {
1227 : // support SvtGraphicStroke MetaCommentAction
1228 : SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
1229 : rBasePolygon, 0,
1230 3386 : &rStrokePrimitive.getLineAttribute(),
1231 3386 : &rStrokePrimitive.getStrokeAttribute(),
1232 3386 : 0, 0);
1233 :
1234 3386 : impStartSvtGraphicStroke(pSvtGraphicStroke);
1235 3386 : const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute();
1236 :
1237 : // create MetaPolyLineActions, but without LINE_DASH
1238 3386 : if(basegfx::fTools::more(rLine.getWidth(), 0.0))
1239 : {
1240 1080 : const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute();
1241 1080 : basegfx::B2DPolyPolygon aHairLinePolyPolygon;
1242 :
1243 1080 : if(0.0 == rStroke.getFullDotDashLen())
1244 : {
1245 1080 : aHairLinePolyPolygon.append(rBasePolygon);
1246 : }
1247 : else
1248 : {
1249 : basegfx::tools::applyLineDashing(
1250 0 : rBasePolygon, rStroke.getDotDashArray(),
1251 0 : &aHairLinePolyPolygon, 0, rStroke.getFullDotDashLen());
1252 : }
1253 :
1254 2160 : const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLine.getColor()));
1255 1080 : mpOutputDevice->SetLineColor(Color(aHairlineColor));
1256 1080 : mpOutputDevice->SetFillColor();
1257 1080 : aHairLinePolyPolygon.transform(maCurrentTransformation);
1258 :
1259 : // use the transformed line width
1260 2160 : LineInfo aLineInfo(LINE_SOLID, basegfx::fround(getTransformedLineWidth(rLine.getWidth())));
1261 1080 : aLineInfo.SetLineJoin(rLine.getLineJoin());
1262 1080 : aLineInfo.SetLineCap(rLine.getLineCap());
1263 :
1264 2160 : for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++)
1265 : {
1266 1080 : const basegfx::B2DPolygon aCandidate(aHairLinePolyPolygon.getB2DPolygon(a));
1267 :
1268 1080 : if(aCandidate.count() > 1)
1269 : {
1270 572 : const Polygon aToolsPolygon(aCandidate);
1271 :
1272 572 : mpMetaFile->AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo));
1273 : }
1274 2160 : }
1275 : }
1276 : else
1277 : {
1278 2306 : process(rCandidate.get2DDecomposition(getViewInformation2D()));
1279 : }
1280 :
1281 3386 : impEndSvtGraphicStroke(pSvtGraphicStroke);
1282 : }
1283 :
1284 3386 : break;
1285 : }
1286 : case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D :
1287 : {
1288 98 : const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive = static_cast< const primitive2d::PolygonStrokeArrowPrimitive2D& >(rCandidate);
1289 98 : const basegfx::B2DPolygon& rBasePolygon = rStrokeArrowPrimitive.getB2DPolygon();
1290 :
1291 98 : if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
1292 : {
1293 : // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1294 : // per polygon. If there are more, split the polygon in half and call recursively
1295 0 : basegfx::B2DPolygon aLeft, aRight;
1296 0 : splitLinePolygon(rBasePolygon, aLeft, aRight);
1297 0 : const attribute::LineStartEndAttribute aEmpty;
1298 : const primitive2d::PolygonStrokeArrowPrimitive2D aPLeft(
1299 : aLeft,
1300 0 : rStrokeArrowPrimitive.getLineAttribute(),
1301 0 : rStrokeArrowPrimitive.getStrokeAttribute(),
1302 0 : rStrokeArrowPrimitive.getStart(),
1303 0 : aEmpty);
1304 : const primitive2d::PolygonStrokeArrowPrimitive2D aPRight(
1305 : aRight,
1306 0 : rStrokeArrowPrimitive.getLineAttribute(),
1307 0 : rStrokeArrowPrimitive.getStrokeAttribute(),
1308 : aEmpty,
1309 0 : rStrokeArrowPrimitive.getEnd());
1310 :
1311 0 : processBasePrimitive2D(aPLeft);
1312 0 : processBasePrimitive2D(aPRight);
1313 : }
1314 : else
1315 : {
1316 : // support SvtGraphicStroke MetaCommentAction
1317 : SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
1318 : rBasePolygon, 0,
1319 98 : &rStrokeArrowPrimitive.getLineAttribute(),
1320 98 : &rStrokeArrowPrimitive.getStrokeAttribute(),
1321 98 : &rStrokeArrowPrimitive.getStart(),
1322 196 : &rStrokeArrowPrimitive.getEnd());
1323 :
1324 : // write LineGeometry start marker
1325 98 : impStartSvtGraphicStroke(pSvtGraphicStroke);
1326 :
1327 : // #i116162# When B&W is set as DrawMode, DRAWMODE_WHITEFILL is used
1328 : // to let all fills be just white; for lines DRAWMODE_BLACKLINE is used
1329 : // so all line geometry is supposed to get black. Since in the in-between
1330 : // stages of line geometry drawing filled polygons are used (e.g. line
1331 : // start/ends) it is necessary to change these drawmodes to preserve
1332 : // that lines shall be black; thus change DRAWMODE_WHITEFILL to
1333 : // DRAWMODE_BLACKFILL during line geometry processing to have line geometry
1334 : // parts filled black.
1335 98 : const sal_uLong nOldDrawMode(mpOutputDevice->GetDrawMode());
1336 98 : const bool bDrawmodeChange(nOldDrawMode & DRAWMODE_WHITEFILL && mnSvtGraphicStrokeCount);
1337 :
1338 98 : if(bDrawmodeChange)
1339 : {
1340 0 : mpOutputDevice->SetDrawMode((nOldDrawMode & ~DRAWMODE_WHITEFILL) | DRAWMODE_BLACKFILL);
1341 : }
1342 :
1343 : // process sub-line geometry (evtl. filled PolyPolygons)
1344 98 : process(rCandidate.get2DDecomposition(getViewInformation2D()));
1345 :
1346 98 : if(bDrawmodeChange)
1347 : {
1348 0 : mpOutputDevice->SetDrawMode(nOldDrawMode);
1349 : }
1350 :
1351 : // write LineGeometry end marker
1352 98 : impEndSvtGraphicStroke(pSvtGraphicStroke);
1353 : }
1354 :
1355 98 : break;
1356 : }
1357 : case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
1358 : {
1359 : // direct draw of transformed BitmapEx primitive; use default processing, but without
1360 : // former testing if graphic content is inside discrete local viewport; this is not
1361 : // setup for metafile targets (metafile renderer tries to render in logic coordinates,
1362 : // the mapping is kept to the OutputDevice for better Metafile recording)
1363 916 : RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
1364 916 : break;
1365 : }
1366 : case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D :
1367 : {
1368 : // need to handle PolyPolygonGraphicPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
1369 80 : const primitive2d::PolyPolygonGraphicPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate);
1370 80 : basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon());
1371 :
1372 80 : if(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1373 : {
1374 : // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1375 : // per polygon. If there are more use the splitted polygon and call recursively
1376 : const primitive2d::PolyPolygonGraphicPrimitive2D aSplitted(
1377 : aLocalPolyPolygon,
1378 0 : rBitmapCandidate.getFillGraphic());
1379 :
1380 0 : processBasePrimitive2D(aSplitted);
1381 : }
1382 : else
1383 : {
1384 80 : SvtGraphicFill* pSvtGraphicFill = 0;
1385 :
1386 80 : if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1387 : {
1388 : // #121194# Changed implementation and checked usages fo convert to metafile,
1389 : // presentation start (uses SvtGraphicFill) and printing.
1390 :
1391 : // calculate transformation. Get real object size, all values in FillGraphicAttribute
1392 : // are relative to the unified object
1393 80 : aLocalPolyPolygon.transform(maCurrentTransformation);
1394 80 : const basegfx::B2DVector aOutlineSize(aLocalPolyPolygon.getB2DRange().getRange());
1395 :
1396 : // the scaling needs scale from pixel to logic coordinate system
1397 80 : const attribute::FillGraphicAttribute& rFillGraphicAttribute = rBitmapCandidate.getFillGraphic();
1398 80 : const Size aBmpSizePixel(rFillGraphicAttribute.getGraphic().GetSizePixel());
1399 :
1400 : // setup transformation like in impgrfll. Multiply with aOutlineSize
1401 : // to get from unit coordinates in rFillGraphicAttribute.getGraphicRange()
1402 : // to object coordinates with object's top left being at (0,0). Divide
1403 : // by pixel size so that scale from pixel to logic will work in SvtGraphicFill.
1404 : const basegfx::B2DVector aTransformScale(
1405 240 : rFillGraphicAttribute.getGraphicRange().getRange() /
1406 : basegfx::B2DVector(
1407 160 : std::max(1.0, double(aBmpSizePixel.Width())),
1408 320 : std::max(1.0, double(aBmpSizePixel.Height()))) *
1409 160 : aOutlineSize);
1410 : const basegfx::B2DPoint aTransformPosition(
1411 160 : rFillGraphicAttribute.getGraphicRange().getMinimum() * aOutlineSize);
1412 :
1413 : // setup transformation like in impgrfll
1414 80 : SvtGraphicFill::Transform aTransform;
1415 :
1416 : // scale values are divided by bitmap pixel sizes
1417 80 : aTransform.matrix[0] = aTransformScale.getX();
1418 80 : aTransform.matrix[4] = aTransformScale.getY();
1419 :
1420 : // translates are absolute
1421 80 : aTransform.matrix[2] = aTransformPosition.getX();
1422 80 : aTransform.matrix[5] = aTransformPosition.getY();
1423 :
1424 : pSvtGraphicFill = new SvtGraphicFill(
1425 : getFillPolyPolygon(aLocalPolyPolygon),
1426 : Color(),
1427 : 0.0,
1428 : SvtGraphicFill::fillEvenOdd,
1429 : SvtGraphicFill::fillTexture,
1430 : aTransform,
1431 80 : rFillGraphicAttribute.getTiling(),
1432 : SvtGraphicFill::hatchSingle,
1433 : Color(),
1434 : SvtGraphicFill::gradientLinear,
1435 : Color(),
1436 : Color(),
1437 : 0,
1438 240 : rFillGraphicAttribute.getGraphic());
1439 : }
1440 :
1441 : // Do use decomposition; encapsulate with SvtGraphicFill
1442 80 : impStartSvtGraphicFill(pSvtGraphicFill);
1443 80 : process(rCandidate.get2DDecomposition(getViewInformation2D()));
1444 80 : impEndSvtGraphicFill(pSvtGraphicFill);
1445 : }
1446 :
1447 80 : break;
1448 : }
1449 : case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D :
1450 : {
1451 : // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
1452 2 : const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate = static_cast< const primitive2d::PolyPolygonHatchPrimitive2D& >(rCandidate);
1453 2 : const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch();
1454 2 : basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon());
1455 :
1456 2 : if(aLocalPolyPolygon.getB2DRange() != rHatchCandidate.getDefinitionRange())
1457 : {
1458 : // the range which defines the hatch is different from the range of the
1459 : // geometry (used for writer frames). This cannot be done calling vcl, thus use
1460 : // decomposition here
1461 0 : process(rCandidate.get2DDecomposition(getViewInformation2D()));
1462 0 : break;
1463 : }
1464 :
1465 : // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1466 : // per polygon. Split polygon until there are less than that
1467 2 : while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1468 : ;
1469 :
1470 2 : if(rFillHatchAttribute.isFillBackground())
1471 : {
1472 : // with fixing #i111954# (see below) the possible background
1473 : // fill of a hatched object was lost.Generate a background fill
1474 : // primitive and render it
1475 : const primitive2d::Primitive2DReference xBackground(
1476 : new primitive2d::PolyPolygonColorPrimitive2D(
1477 : aLocalPolyPolygon,
1478 0 : rHatchCandidate.getBackgroundColor()));
1479 :
1480 0 : process(primitive2d::Primitive2DSequence(&xBackground, 1));
1481 : }
1482 :
1483 2 : SvtGraphicFill* pSvtGraphicFill = 0;
1484 2 : aLocalPolyPolygon.transform(maCurrentTransformation);
1485 :
1486 2 : if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1487 : {
1488 : // re-create a VCL hatch as base data
1489 2 : SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle);
1490 :
1491 2 : switch(rFillHatchAttribute.getStyle())
1492 : {
1493 : default: // attribute::HATCHSTYLE_SINGLE :
1494 : {
1495 2 : eHatch = SvtGraphicFill::hatchSingle;
1496 2 : break;
1497 : }
1498 : case attribute::HATCHSTYLE_DOUBLE :
1499 : {
1500 0 : eHatch = SvtGraphicFill::hatchDouble;
1501 0 : break;
1502 : }
1503 : case attribute::HATCHSTYLE_TRIPLE :
1504 : {
1505 0 : eHatch = SvtGraphicFill::hatchTriple;
1506 0 : break;
1507 : }
1508 : }
1509 :
1510 2 : SvtGraphicFill::Transform aTransform;
1511 :
1512 : // scale
1513 2 : aTransform.matrix[0] *= rFillHatchAttribute.getDistance();
1514 2 : aTransform.matrix[4] *= rFillHatchAttribute.getDistance();
1515 :
1516 : // rotate (was never correct in impgrfll anyways, use correct angle now)
1517 2 : aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle());
1518 2 : aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle());
1519 2 : aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle());
1520 2 : aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle());
1521 :
1522 : pSvtGraphicFill = new SvtGraphicFill(
1523 : getFillPolyPolygon(aLocalPolyPolygon),
1524 : Color(),
1525 : 0.0,
1526 : SvtGraphicFill::fillEvenOdd,
1527 : SvtGraphicFill::fillHatch,
1528 : aTransform,
1529 : false,
1530 : eHatch,
1531 2 : Color(rFillHatchAttribute.getColor()),
1532 : SvtGraphicFill::gradientLinear,
1533 : Color(),
1534 : Color(),
1535 : 0,
1536 4 : Graphic());
1537 : }
1538 :
1539 : // Do use decomposition; encapsulate with SvtGraphicFill
1540 2 : impStartSvtGraphicFill(pSvtGraphicFill);
1541 :
1542 : // #i111954# do NOT use decomposition, but use direct VCL-command
1543 : // process(rCandidate.get2DDecomposition(getViewInformation2D()));
1544 2 : const tools::PolyPolygon aToolsPolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(aLocalPolyPolygon));
1545 : const HatchStyle aHatchStyle(
1546 2 : attribute::HATCHSTYLE_SINGLE == rFillHatchAttribute.getStyle() ? HATCH_SINGLE :
1547 0 : attribute::HATCHSTYLE_DOUBLE == rFillHatchAttribute.getStyle() ? HATCH_DOUBLE :
1548 2 : HATCH_TRIPLE);
1549 :
1550 : mpOutputDevice->DrawHatch(aToolsPolyPolygon,
1551 : Hatch(aHatchStyle,
1552 2 : Color(rFillHatchAttribute.getColor()),
1553 2 : basegfx::fround(rFillHatchAttribute.getDistance()),
1554 6 : basegfx::fround(rFillHatchAttribute.getAngle() / F_PI1800)));
1555 :
1556 2 : impEndSvtGraphicFill(pSvtGraphicFill);
1557 :
1558 2 : break;
1559 : }
1560 : case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D :
1561 : {
1562 32 : basegfx::B2DVector aScale, aTranslate;
1563 : double fRotate, fShearX;
1564 :
1565 16 : maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
1566 :
1567 16 : if(!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX))
1568 : {
1569 : // #i121185# When rotation or shear is used, a VCL Gradient cannot be used directly.
1570 : // This is because VCL Gradient mechanism does *not* support to rotate the gradient
1571 : // with objects and this case is not expressable in a Metafile (and cannot be added
1572 : // since the FileFormats used, e.g. *.wmf, do not support it either).
1573 : // Such cases happen when a graphic object uses a Metafile as graphic information or
1574 : // a fill style definition uses a Metafile. In this cases the graphic content is
1575 : // rotated with the graphic or filled object; this is not supported by the target
1576 : // format of this conversion renderer - Metafiles.
1577 : // To solve this, not a Gradient is written, but the decomposition of this object
1578 : // is written to the Metafile. This is the PolyPolygons building the gradient fill.
1579 : // These will need more space and time, but the result will be as if the Gradient
1580 : // was rotated with the object.
1581 : // This mechanism is used by all exporters still not using Primtives (e.g. Print,
1582 : // Slideshow, Export rto PDF, export to Picture, ...) but relying on Metafile
1583 : // transfers. One more reason to *change* these to primitives.
1584 : // BTW: One more example how useful the principles of primitives are; the decomposition
1585 : // is by definition a simpler, maybe more expensive representation of the same content.
1586 0 : process(rCandidate.get2DDecomposition(getViewInformation2D()));
1587 0 : break;
1588 : }
1589 :
1590 16 : const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate);
1591 32 : basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon());
1592 :
1593 16 : if(aLocalPolyPolygon.getB2DRange() != rGradientCandidate.getDefinitionRange())
1594 : {
1595 : // the range which defines the gradient is different from the range of the
1596 : // geometry (used for writer frames). This cannot be done calling vcl, thus use
1597 : // decomposition here
1598 4 : process(rCandidate.get2DDecomposition(getViewInformation2D()));
1599 4 : break;
1600 : }
1601 :
1602 : // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1603 : // per polygon. Split polygon until there are less than that
1604 12 : while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1605 : ;
1606 :
1607 : // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END
1608 : // it is safest to use the VCL OutputDevice::DrawGradient method which creates those.
1609 : // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon
1610 24 : Gradient aVCLGradient;
1611 12 : impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false);
1612 12 : aLocalPolyPolygon.transform(maCurrentTransformation);
1613 :
1614 : // #i82145# ATM VCL printing of gradients using curved shapes does not work,
1615 : // i submitted the bug with the given ID to THB. When that task is fixed it is
1616 : // necessary to again remove this subdivision since it decreases possible
1617 : // printing quality (not even resolution-dependent for now). THB will tell
1618 : // me when that task is fixed in the master
1619 : const tools::PolyPolygon aToolsPolyPolygon(
1620 : getFillPolyPolygon(
1621 24 : basegfx::tools::adaptiveSubdivideByAngle(aLocalPolyPolygon)));
1622 :
1623 :
1624 : // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
1625 12 : SvtGraphicFill* pSvtGraphicFill = 0;
1626 :
1627 12 : if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1628 : {
1629 : // setup gradient stuff like in like in impgrfll
1630 12 : SvtGraphicFill::GradientType eGrad(SvtGraphicFill::gradientLinear);
1631 :
1632 12 : switch(aVCLGradient.GetStyle())
1633 : {
1634 : default : // GradientStyle_LINEAR:
1635 : case GradientStyle_AXIAL:
1636 12 : eGrad = SvtGraphicFill::gradientLinear;
1637 12 : break;
1638 : case GradientStyle_RADIAL:
1639 : case GradientStyle_ELLIPTICAL:
1640 0 : eGrad = SvtGraphicFill::gradientRadial;
1641 0 : break;
1642 : case GradientStyle_SQUARE:
1643 : case GradientStyle_RECT:
1644 0 : eGrad = SvtGraphicFill::gradientRectangular;
1645 0 : break;
1646 : }
1647 :
1648 : pSvtGraphicFill = new SvtGraphicFill(
1649 : aToolsPolyPolygon,
1650 : Color(),
1651 : 0.0,
1652 : SvtGraphicFill::fillEvenOdd,
1653 : SvtGraphicFill::fillGradient,
1654 : SvtGraphicFill::Transform(),
1655 : false,
1656 : SvtGraphicFill::hatchSingle,
1657 : Color(),
1658 : eGrad,
1659 12 : aVCLGradient.GetStartColor(),
1660 12 : aVCLGradient.GetEndColor(),
1661 12 : aVCLGradient.GetSteps(),
1662 48 : Graphic());
1663 : }
1664 :
1665 : // call VCL directly; encapsulate with SvtGraphicFill
1666 12 : impStartSvtGraphicFill(pSvtGraphicFill);
1667 12 : mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient);
1668 12 : impEndSvtGraphicFill(pSvtGraphicFill);
1669 :
1670 28 : break;
1671 : }
1672 : case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
1673 : {
1674 2444 : const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate));
1675 2444 : basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
1676 :
1677 : // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1678 : // per polygon. Split polygon until there are less than that
1679 2444 : while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1680 : ;
1681 :
1682 4888 : const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
1683 2444 : aLocalPolyPolygon.transform(maCurrentTransformation);
1684 :
1685 : // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
1686 2444 : SvtGraphicFill* pSvtGraphicFill = 0;
1687 :
1688 : // #i121267# Not needed, does not give better quality compared with
1689 : // the META_POLYPOLYGON_ACTION written by the DrawPolyPolygon command
1690 : // below
1691 2444 : bool bSupportSvtGraphicFill(false);
1692 :
1693 2444 : if(bSupportSvtGraphicFill && !mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1694 : {
1695 : // setup simple color fill stuff like in impgrfll
1696 : pSvtGraphicFill = new SvtGraphicFill(
1697 : getFillPolyPolygon(aLocalPolyPolygon),
1698 : Color(aPolygonColor),
1699 : 0.0,
1700 : SvtGraphicFill::fillEvenOdd,
1701 : SvtGraphicFill::fillSolid,
1702 : SvtGraphicFill::Transform(),
1703 : false,
1704 : SvtGraphicFill::hatchSingle,
1705 : Color(),
1706 : SvtGraphicFill::gradientLinear,
1707 : Color(),
1708 : Color(),
1709 : 0,
1710 0 : Graphic());
1711 : }
1712 :
1713 : // set line and fill color
1714 2444 : mpOutputDevice->SetFillColor(Color(aPolygonColor));
1715 2444 : mpOutputDevice->SetLineColor();
1716 :
1717 : // call VCL directly; encapsulate with SvtGraphicFill
1718 2444 : if(bSupportSvtGraphicFill)
1719 : {
1720 0 : impStartSvtGraphicFill(pSvtGraphicFill);
1721 : }
1722 :
1723 2444 : mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
1724 :
1725 2444 : if(bSupportSvtGraphicFill)
1726 : {
1727 0 : impEndSvtGraphicFill(pSvtGraphicFill);
1728 : }
1729 :
1730 4888 : break;
1731 : }
1732 : case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
1733 : {
1734 : static bool bUseMetaFilePrimitiveDecomposition(true);
1735 158 : const primitive2d::MetafilePrimitive2D& aMetafile = static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate);
1736 :
1737 158 : if(bUseMetaFilePrimitiveDecomposition && !aMetafile.getMetaFile().GetUseCanvas())
1738 : {
1739 : // Use new Metafile decomposition.
1740 : // TODO EMF+ stuffed into METACOMMENT support required
1741 82 : process(rCandidate.get2DDecomposition(getViewInformation2D()));
1742 : }
1743 : else
1744 : {
1745 : // direct draw of MetaFile, use default processing
1746 76 : RenderMetafilePrimitive2D(aMetafile);
1747 : }
1748 :
1749 158 : break;
1750 : }
1751 : case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
1752 : {
1753 : // mask group. Special handling for MetaFiles.
1754 98 : const primitive2d::MaskPrimitive2D& rMaskCandidate = static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate);
1755 :
1756 98 : if(rMaskCandidate.getChildren().hasElements())
1757 : {
1758 98 : basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
1759 :
1760 98 : if(aMask.count())
1761 : {
1762 : // prepare new mask polygon and rescue current one
1763 98 : aMask.transform(maCurrentTransformation);
1764 98 : const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon);
1765 :
1766 98 : if(maClipPolyPolygon.count())
1767 : {
1768 : // there is already a clip polygon set; build clipped union of
1769 : // current mask polygon and new one
1770 12 : maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
1771 : aMask,
1772 : maClipPolyPolygon,
1773 : true, // #i106516# we want the inside of aMask, not the outside
1774 6 : false);
1775 : }
1776 : else
1777 : {
1778 : // use mask directly
1779 92 : maClipPolyPolygon = aMask;
1780 : }
1781 :
1782 98 : if(maClipPolyPolygon.count())
1783 : {
1784 : // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!)
1785 : // Removed subdivision and fixed in vcl::Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where
1786 : // the ClipRegion is built from the Polygon. A AdaptiveSubdivide on the source polygon was missing there
1787 98 : mpOutputDevice->Push(PushFlags::CLIPREGION);
1788 98 : mpOutputDevice->SetClipRegion(vcl::Region(maClipPolyPolygon));
1789 :
1790 : // recursively paint content
1791 : // #i121267# Only need to process sub-content when clip polygon is *not* empty.
1792 : // If it is empty, the clip is empty and there can be nothing inside.
1793 98 : process(rMaskCandidate.getChildren());
1794 :
1795 : // restore VCL clip region
1796 98 : mpOutputDevice->Pop();
1797 : }
1798 :
1799 : // restore to rescued clip polygon
1800 98 : maClipPolyPolygon = aLastClipPolyPolygon;
1801 : }
1802 : else
1803 : {
1804 : // no mask, no clipping. recursively paint content
1805 0 : process(rMaskCandidate.getChildren());
1806 98 : }
1807 : }
1808 :
1809 98 : break;
1810 : }
1811 : case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
1812 : {
1813 : // modified color group. Force output to unified color. Use default pocessing.
1814 0 : RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate));
1815 0 : break;
1816 : }
1817 : case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D :
1818 : {
1819 : // for metafile: Need to examine what the pure vcl version is doing here actually
1820 : // - uses DrawTransparent with metafile for content and a gradient
1821 : // - uses DrawTransparent for single PolyPoylgons directly. Can be detected by
1822 : // checking the content for single PolyPolygonColorPrimitive2D
1823 76 : const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate = static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate);
1824 76 : const primitive2d::Primitive2DSequence rContent = rUniTransparenceCandidate.getChildren();
1825 :
1826 76 : if(rContent.hasElements())
1827 : {
1828 76 : if(0.0 == rUniTransparenceCandidate.getTransparence())
1829 : {
1830 : // not transparent at all, use content
1831 0 : process(rUniTransparenceCandidate.getChildren());
1832 : }
1833 76 : else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0)
1834 : {
1835 : // try to identify a single PolyPolygonColorPrimitive2D in the
1836 : // content part of the transparence primitive
1837 76 : const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = 0;
1838 : static bool bForceToMetafile(false);
1839 :
1840 76 : if(!bForceToMetafile && 1 == rContent.getLength())
1841 : {
1842 76 : const primitive2d::Primitive2DReference xReference(rContent[0]);
1843 76 : pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get());
1844 : }
1845 :
1846 : // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and
1847 : // PolyPolygonGraphicPrimitive2D are derived from PolyPolygonColorPrimitive2D.
1848 : // Check also for correct ID to exclude derived implementations
1849 76 : if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID())
1850 : {
1851 : // single transparent tools::PolyPolygon identified, use directly
1852 76 : const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor()));
1853 152 : basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon());
1854 :
1855 : // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1856 : // per polygon. Split polygon until there are less than that
1857 76 : while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1858 : ;
1859 :
1860 : // now transform
1861 76 : aLocalPolyPolygon.transform(maCurrentTransformation);
1862 :
1863 : // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
1864 76 : SvtGraphicFill* pSvtGraphicFill = 0;
1865 :
1866 : // #i121267# Not needed, does not give better quality compared with
1867 : // the META_POLYPOLYGON_ACTION written by the DrawPolyPolygon command
1868 : // below
1869 76 : bool bSupportSvtGraphicFill(false);
1870 :
1871 76 : if(bSupportSvtGraphicFill && !mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1872 : {
1873 : // setup simple color with transparence fill stuff like in impgrfll
1874 : pSvtGraphicFill = new SvtGraphicFill(
1875 : getFillPolyPolygon(aLocalPolyPolygon),
1876 : Color(aPolygonColor),
1877 : rUniTransparenceCandidate.getTransparence(),
1878 : SvtGraphicFill::fillEvenOdd,
1879 : SvtGraphicFill::fillSolid,
1880 : SvtGraphicFill::Transform(),
1881 : false,
1882 : SvtGraphicFill::hatchSingle,
1883 : Color(),
1884 : SvtGraphicFill::gradientLinear,
1885 : Color(),
1886 : Color(),
1887 : 0,
1888 0 : Graphic());
1889 : }
1890 :
1891 : // set line and fill color
1892 76 : const sal_uInt16 nTransPercentVcl((sal_uInt16)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 100.0));
1893 76 : mpOutputDevice->SetFillColor(Color(aPolygonColor));
1894 76 : mpOutputDevice->SetLineColor();
1895 :
1896 : // call VCL directly; encapsulate with SvtGraphicFill
1897 76 : if(bSupportSvtGraphicFill)
1898 : {
1899 0 : impStartSvtGraphicFill(pSvtGraphicFill);
1900 : }
1901 :
1902 : mpOutputDevice->DrawTransparent(
1903 : tools::PolyPolygon(aLocalPolyPolygon),
1904 76 : nTransPercentVcl);
1905 :
1906 76 : if(bSupportSvtGraphicFill)
1907 : {
1908 0 : impEndSvtGraphicFill(pSvtGraphicFill);
1909 76 : }
1910 : }
1911 : else
1912 : {
1913 : // svae old mfCurrentUnifiedTransparence and set new one
1914 : // so that contained SvtGraphicStroke may use the current one
1915 0 : const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence);
1916 : // #i105377# paint the content metafile opaque as the transparency gets
1917 : // split of into the gradient below
1918 : // mfCurrentUnifiedTransparence = rUniTransparenceCandidate.getTransparence();
1919 0 : mfCurrentUnifiedTransparence = 0;
1920 :
1921 : // various content, create content-metafile
1922 0 : GDIMetaFile aContentMetafile;
1923 0 : const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
1924 :
1925 : // restore mfCurrentUnifiedTransparence; it may have been used
1926 : // while processing the sub-content in impDumpToMetaFile
1927 0 : mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence;
1928 :
1929 : // create uniform VCL gradient for uniform transparency
1930 0 : Gradient aVCLGradient;
1931 0 : const sal_uInt8 nTransPercentVcl((sal_uInt8)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 255.0));
1932 0 : const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl);
1933 :
1934 0 : aVCLGradient.SetStyle(GradientStyle_LINEAR);
1935 0 : aVCLGradient.SetStartColor(aTransColor);
1936 0 : aVCLGradient.SetEndColor(aTransColor);
1937 0 : aVCLGradient.SetAngle(0);
1938 0 : aVCLGradient.SetBorder(0);
1939 0 : aVCLGradient.SetOfsX(0);
1940 0 : aVCLGradient.SetOfsY(0);
1941 0 : aVCLGradient.SetStartIntensity(100);
1942 0 : aVCLGradient.SetEndIntensity(100);
1943 0 : aVCLGradient.SetSteps(2);
1944 :
1945 : // render it to VCL
1946 : mpOutputDevice->DrawTransparent(
1947 : aContentMetafile, aPrimitiveRectangle.TopLeft(),
1948 0 : aPrimitiveRectangle.GetSize(), aVCLGradient);
1949 : }
1950 : }
1951 : }
1952 :
1953 76 : break;
1954 : }
1955 : case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
1956 : {
1957 : // for metafile: Need to examine what the pure vcl version is doing here actually
1958 : // - uses DrawTransparent with metafile for content and a gradient
1959 : // i can detect this here with checking the gradient part for a single
1960 : // FillGradientPrimitive2D and reconstruct the gradient.
1961 : // If that detection goes wrong, i have to create an transparence-blended bitmap. Eventually
1962 : // do that in stripes, else RenderTransparencePrimitive2D may just be used
1963 0 : const primitive2d::TransparencePrimitive2D& rTransparenceCandidate = static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate);
1964 0 : const primitive2d::Primitive2DSequence rContent = rTransparenceCandidate.getChildren();
1965 0 : const primitive2d::Primitive2DSequence rTransparence = rTransparenceCandidate.getTransparence();
1966 :
1967 0 : if(rContent.hasElements() && rTransparence.hasElements())
1968 : {
1969 : // try to identify a single FillGradientPrimitive2D in the
1970 : // transparence part of the primitive
1971 0 : const primitive2d::FillGradientPrimitive2D* pFiGradient = 0;
1972 : static bool bForceToBigTransparentVDev(false);
1973 :
1974 0 : if(!bForceToBigTransparentVDev && 1 == rTransparence.getLength())
1975 : {
1976 0 : const primitive2d::Primitive2DReference xReference(rTransparence[0]);
1977 0 : pFiGradient = dynamic_cast< const primitive2d::FillGradientPrimitive2D* >(xReference.get());
1978 : }
1979 :
1980 : // Check also for correct ID to exclude derived implementations
1981 0 : if(pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitive2DID())
1982 : {
1983 : // various content, create content-metafile
1984 0 : GDIMetaFile aContentMetafile;
1985 0 : const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
1986 :
1987 : // re-create a VCL-gradient from FillGradientPrimitive2D
1988 0 : Gradient aVCLGradient;
1989 0 : impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(), true);
1990 :
1991 : // render it to VCL
1992 : mpOutputDevice->DrawTransparent(
1993 : aContentMetafile, aPrimitiveRectangle.TopLeft(),
1994 0 : aPrimitiveRectangle.GetSize(), aVCLGradient);
1995 : }
1996 : else
1997 : {
1998 : // sub-transparence group. Draw to VDev first.
1999 : // this may get refined to tiling when resolution is too big here
2000 :
2001 : // need to avoid switching off MapMode stuff here; maybe need another
2002 : // tooling class, cannot just do the same as with the pixel renderer.
2003 : // Need to experiment...
2004 :
2005 : // Okay, basic implementation finished and tested. The DPI stuff was hard
2006 : // and not easy to find out that it's needed.
2007 : // Since this will not yet happen normally (as long as no one constructs
2008 : // transparence primitives with non-trivial transparence content) i will for now not
2009 : // refine to tiling here.
2010 :
2011 0 : basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
2012 0 : aViewRange.transform(maCurrentTransformation);
2013 : const Rectangle aRectLogic(
2014 0 : (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()),
2015 0 : (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY()));
2016 0 : const Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic));
2017 0 : Size aSizePixel(aRectPixel.GetSize());
2018 0 : const Point aEmptyPoint;
2019 0 : VirtualDevice aBufferDevice;
2020 0 : const sal_uInt32 nMaxQuadratPixels(500000);
2021 0 : const sal_uInt32 nViewVisibleArea(aSizePixel.getWidth() * aSizePixel.getHeight());
2022 0 : double fReduceFactor(1.0);
2023 :
2024 0 : if(nViewVisibleArea > nMaxQuadratPixels)
2025 : {
2026 : // reduce render size
2027 0 : fReduceFactor = sqrt((double)nMaxQuadratPixels / (double)nViewVisibleArea);
2028 0 : aSizePixel = Size(basegfx::fround((double)aSizePixel.getWidth() * fReduceFactor),
2029 0 : basegfx::fround((double)aSizePixel.getHeight() * fReduceFactor));
2030 : }
2031 :
2032 0 : if(aBufferDevice.SetOutputSizePixel(aSizePixel))
2033 : {
2034 : // create and set MapModes for target devices
2035 0 : MapMode aNewMapMode(mpOutputDevice->GetMapMode());
2036 0 : aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top()));
2037 0 : aBufferDevice.SetMapMode(aNewMapMode);
2038 :
2039 : // prepare view transformation for target renderers
2040 : // ATTENTION! Need to apply another scaling because of the potential DPI differences
2041 : // between Printer and VDev (mpOutputDevice and aBufferDevice here).
2042 : // To get the DPI, LogicToPixel from (1,1) from MAP_INCH needs to be used.
2043 0 : basegfx::B2DHomMatrix aViewTransform(aBufferDevice.GetViewTransformation());
2044 0 : const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MAP_INCH));
2045 0 : const Size aDPINew(aBufferDevice.LogicToPixel(Size(1, 1), MAP_INCH));
2046 0 : const double fDPIXChange((double)aDPIOld.getWidth() / (double)aDPINew.getWidth());
2047 0 : const double fDPIYChange((double)aDPIOld.getHeight() / (double)aDPINew.getHeight());
2048 :
2049 0 : if(!basegfx::fTools::equal(fDPIXChange, 1.0) || !basegfx::fTools::equal(fDPIYChange, 1.0))
2050 : {
2051 0 : aViewTransform.scale(fDPIXChange, fDPIYChange);
2052 : }
2053 :
2054 : // also take scaling from Size reduction into acount
2055 0 : if(!basegfx::fTools::equal(fReduceFactor, 1.0))
2056 : {
2057 0 : aViewTransform.scale(fReduceFactor, fReduceFactor);
2058 : }
2059 :
2060 : // create view information and pixel renderer. Reuse known ViewInformation
2061 : // except new transformation and range
2062 : const geometry::ViewInformation2D aViewInfo(
2063 0 : getViewInformation2D().getObjectTransformation(),
2064 : aViewTransform,
2065 : aViewRange,
2066 0 : getViewInformation2D().getVisualizedPage(),
2067 0 : getViewInformation2D().getViewTime(),
2068 0 : getViewInformation2D().getExtendedInformationSequence());
2069 :
2070 0 : VclPixelProcessor2D aBufferProcessor(aViewInfo, aBufferDevice);
2071 :
2072 : // draw content using pixel renderer
2073 0 : aBufferProcessor.process(rContent);
2074 0 : const Bitmap aBmContent(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel));
2075 :
2076 : // draw transparence using pixel renderer
2077 0 : aBufferDevice.Erase();
2078 0 : aBufferProcessor.process(rTransparence);
2079 0 : const AlphaMask aBmAlpha(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel));
2080 :
2081 : // paint
2082 : mpOutputDevice->DrawBitmapEx(
2083 : aRectLogic.TopLeft(),
2084 : aRectLogic.GetSize(),
2085 0 : BitmapEx(aBmContent, aBmAlpha));
2086 0 : }
2087 : }
2088 : }
2089 :
2090 0 : break;
2091 : }
2092 : case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
2093 : {
2094 : // use default transform group pocessing
2095 748 : RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
2096 748 : break;
2097 : }
2098 : case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
2099 : {
2100 : // new XDrawPage for ViewInformation2D
2101 0 : RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate));
2102 0 : break;
2103 : }
2104 : case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
2105 : {
2106 : // use default marker array pocessing
2107 0 : RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate));
2108 0 : break;
2109 : }
2110 : case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
2111 : {
2112 : // use default point array pocessing
2113 0 : RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate));
2114 0 : break;
2115 : }
2116 : case PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D :
2117 : {
2118 : // structured tag primitive
2119 0 : const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate = static_cast< const primitive2d::StructureTagPrimitive2D& >(rCandidate);
2120 0 : const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement());
2121 0 : const bool bTagUsed(vcl::PDFWriter::NonStructElement != rTagElement);
2122 :
2123 0 : if(mpPDFExtOutDevData && bTagUsed)
2124 : {
2125 : // write start tag
2126 0 : mpPDFExtOutDevData->BeginStructureElement(rTagElement);
2127 : }
2128 :
2129 : // process children normally
2130 0 : process(rStructureTagCandidate.getChildren());
2131 :
2132 0 : if(mpPDFExtOutDevData && bTagUsed)
2133 : {
2134 : // write end tag
2135 0 : mpPDFExtOutDevData->EndStructureElement();
2136 : }
2137 :
2138 0 : break;
2139 : }
2140 : case PRIMITIVE2D_ID_EPSPRIMITIVE2D :
2141 : {
2142 0 : RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate));
2143 0 : break;
2144 : }
2145 : case PRIMITIVE2D_ID_OPENGLPRIMITIVE2D:
2146 : {
2147 0 : RenderOpenGLPrimitive2D(static_cast< const primitive2d::OpenGLPrimitive2D& >(rCandidate));
2148 0 : break;
2149 : }
2150 : default :
2151 : {
2152 : // process recursively
2153 9180 : process(rCandidate.get2DDecomposition(getViewInformation2D()));
2154 9180 : break;
2155 : }
2156 : }
2157 24084 : }
2158 : } // end of namespace processor2d
2159 1143 : } // end of namespace drawinglayer
2160 :
2161 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|