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