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/canvasprocessor.hxx>
21 : #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
22 : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
23 : #include <com/sun/star/rendering/XCanvas.hpp>
24 : #include <vcl/canvastools.hxx>
25 : #include <basegfx/tools/canvastools.hxx>
26 : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
27 : #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
28 : #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
29 : #include <canvas/canvastools.hxx>
30 : #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
31 : #include <basegfx/polygon/b2dpolygonclipper.hxx>
32 : #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
33 : #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
34 : #include <cppcanvas/basegfxfactory.hxx>
35 : #include <com/sun/star/rendering/XBitmapCanvas.hpp>
36 : #include <cppcanvas/vclfactory.hxx>
37 : #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
38 : #include <drawinglayer/primitive2d/textprimitive2d.hxx>
39 : #include <com/sun/star/rendering/TextDirection.hpp>
40 : #include <vclhelperbitmaptransform.hxx>
41 : #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
42 : #include <basegfx/polygon/b2dpolygontools.hxx>
43 : #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
44 : #include <basegfx/tuple/b2i64tuple.hxx>
45 : #include <basegfx/range/b2irange.hxx>
46 : #include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp>
47 : #include <com/sun/star/rendering/PanoseProportion.hpp>
48 : #include <com/sun/star/rendering/CompositeOperation.hpp>
49 : #include <com/sun/star/rendering/StrokeAttributes.hpp>
50 : #include <com/sun/star/rendering/PathJoinType.hpp>
51 : #include <com/sun/star/rendering/PathCapType.hpp>
52 : #include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
53 : #include <com/sun/star/rendering/TexturingMode.hpp>
54 : #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
55 : #include <vclhelperbufferdevice.hxx>
56 : #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
57 : #include <helperwrongspellrenderer.hxx>
58 : #include <basegfx/matrix/b2dhommatrixtools.hxx>
59 :
60 : #include "getdigitlanguage.hxx"
61 :
62 : //////////////////////////////////////////////////////////////////////////////
63 :
64 : using namespace com::sun::star;
65 :
66 : //////////////////////////////////////////////////////////////////////////////
67 :
68 : namespace drawinglayer
69 : {
70 : namespace processor2d
71 : {
72 : //////////////////////////////////////////////////////////////////////////////
73 : // single primitive renderers
74 :
75 0 : void canvasProcessor2D::impRenderMaskPrimitive2D(const primitive2d::MaskPrimitive2D& rMaskCandidate)
76 : {
77 0 : const primitive2d::Primitive2DSequence& rChildren = rMaskCandidate.getChildren();
78 : static bool bUseMaskBitmapMethod(true);
79 :
80 0 : if(rChildren.hasElements())
81 : {
82 0 : basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
83 :
84 0 : if(!aMask.count())
85 : {
86 : // no mask, no clipping. recursively paint content
87 0 : process(rChildren);
88 : }
89 : else
90 : {
91 : // there are principally two methods for implementing the mask primitive. One
92 : // is to set a clip polygon at the canvas, the other is to create and use a
93 : // transparence-using XBitmap for content and draw the mask as transparence. Both have their
94 : // advantages and disadvantages, so here are both with a bool allowing simple
95 : // change
96 0 : if(bUseMaskBitmapMethod)
97 : {
98 : // get logic range of transparent part, clip with ViewRange
99 0 : basegfx::B2DRange aLogicRange(aMask.getB2DRange());
100 :
101 0 : if(!getViewInformation2D().getViewport().isEmpty())
102 : {
103 0 : aLogicRange.intersect(getViewInformation2D().getViewport());
104 : }
105 :
106 0 : if(!aLogicRange.isEmpty())
107 : {
108 : // get discrete range of transparent part
109 0 : basegfx::B2DRange aDiscreteRange(aLogicRange);
110 0 : aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
111 :
112 : // expand to next covering discrete values (pixel bounds)
113 0 : aDiscreteRange.expand(basegfx::B2DTuple(floor(aDiscreteRange.getMinX()), floor(aDiscreteRange.getMinY())));
114 0 : aDiscreteRange.expand(basegfx::B2DTuple(ceil(aDiscreteRange.getMaxX()), ceil(aDiscreteRange.getMaxY())));
115 :
116 : // use VCL-based buffer device
117 0 : impBufferDevice aBufferDevice(*mpOutputDevice, aDiscreteRange, false);
118 :
119 0 : if(aBufferDevice.isVisible())
120 : {
121 : // remember current OutDev, Canvas and ViewInformation
122 0 : OutputDevice* pLastOutputDevice = mpOutputDevice;
123 0 : uno::Reference< rendering::XCanvas > xLastCanvas(mxCanvas);
124 0 : const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
125 :
126 : // prepare discrete offset for XBitmap, do not forget that the buffer bitmap
127 : // may be truncated to discrete visible pixels
128 : const basegfx::B2DHomMatrix aDiscreteOffset(basegfx::tools::createTranslateB2DHomMatrix(
129 0 : aDiscreteRange.getMinX() > 0.0 ? -aDiscreteRange.getMinX() : 0.0,
130 0 : aDiscreteRange.getMinY() > 0.0 ? -aDiscreteRange.getMinY() : 0.0));
131 :
132 : // create new local ViewInformation2D with new transformation
133 : const geometry::ViewInformation2D aViewInformation2D(
134 0 : getViewInformation2D().getObjectTransformation(),
135 0 : aDiscreteOffset * getViewInformation2D().getViewTransformation(),
136 0 : getViewInformation2D().getViewport(),
137 0 : getViewInformation2D().getVisualizedPage(),
138 0 : getViewInformation2D().getViewTime(),
139 0 : getViewInformation2D().getExtendedInformationSequence());
140 0 : updateViewInformation(aViewInformation2D);
141 :
142 : // set OutDev and Canvas to content target
143 0 : mpOutputDevice = &aBufferDevice.getContent();
144 0 : mxCanvas = mpOutputDevice->GetCanvas();
145 0 : canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
146 :
147 : // if ViewState transform is changed, the clipping polygon needs to be adapted, too
148 0 : const basegfx::B2DPolyPolygon aOldClipPolyPolygon(maClipPolyPolygon);
149 :
150 0 : if(maClipPolyPolygon.count())
151 : {
152 0 : maClipPolyPolygon.transform(aDiscreteOffset);
153 0 : maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
154 : }
155 :
156 : // paint content
157 0 : process(rChildren);
158 :
159 : // draw mask
160 0 : const basegfx::BColor aBlack(0.0, 0.0, 0.0);
161 0 : maRenderState.DeviceColor = aBlack.colorToDoubleSequence(mxCanvas->getDevice());
162 :
163 0 : if(getOptionsDrawinglayer().IsAntiAliasing())
164 : {
165 : // with AA, use 8bit AlphaMask to get nice borders
166 0 : VirtualDevice& rTransparence = aBufferDevice.getTransparence();
167 0 : rTransparence.GetCanvas()->fillPolyPolygon(
168 0 : basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), aMask),
169 0 : maViewState, maRenderState);
170 : }
171 : else
172 : {
173 : // No AA, use 1bit mask
174 0 : VirtualDevice& rMask = aBufferDevice.getMask();
175 0 : rMask.GetCanvas()->fillPolyPolygon(
176 0 : basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), aMask),
177 0 : maViewState, maRenderState);
178 : }
179 :
180 : // back to old color stack, OutDev, Canvas and ViewTransform
181 0 : mpOutputDevice = pLastOutputDevice;
182 0 : mxCanvas = xLastCanvas;
183 0 : updateViewInformation(aLastViewInformation2D);
184 0 : canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
185 :
186 : // restore clipping polygon
187 0 : maClipPolyPolygon = aOldClipPolyPolygon;
188 :
189 0 : if(maClipPolyPolygon.count())
190 : {
191 0 : maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
192 : }
193 :
194 : // dump buffer to outdev
195 0 : aBufferDevice.paint();
196 0 : }
197 : }
198 : }
199 : else
200 : {
201 : // transform new mask polygon to view coordinates for processing. All masks
202 : // are processed in view coordinates and clipped against each other evtl. to
203 : // create multi-clips
204 0 : aMask.transform(getViewInformation2D().getObjectTransformation());
205 :
206 : // remember last current clip polygon
207 0 : const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon);
208 :
209 0 : if(maClipPolyPolygon.count())
210 : {
211 : // there is already a clip polygon set; build clipped union of
212 : // current mask polygon and new one
213 0 : maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(aMask, maClipPolyPolygon, false, false);
214 : }
215 : else
216 : {
217 : // use mask directly
218 0 : maClipPolyPolygon = aMask;
219 : }
220 :
221 : // set at ViewState
222 0 : if(maClipPolyPolygon.count())
223 : {
224 : // set new as clip polygon
225 0 : maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
226 : }
227 : else
228 : {
229 : // empty, reset
230 0 : maViewState.Clip.clear();
231 : }
232 :
233 : // paint content
234 0 : process(rChildren);
235 :
236 : // restore local current to rescued clip polygon
237 0 : maClipPolyPolygon = aLastClipPolyPolygon;
238 :
239 : // set at ViewState
240 0 : if(maClipPolyPolygon.count())
241 : {
242 : // set new as clip polygon
243 0 : maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
244 : }
245 : else
246 : {
247 : // empty, reset
248 0 : maViewState.Clip.clear();
249 0 : }
250 : }
251 0 : }
252 : }
253 0 : }
254 :
255 0 : void canvasProcessor2D::impRenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D& rMetaCandidate)
256 : {
257 0 : GDIMetaFile aMetaFile;
258 :
259 0 : if(maBColorModifierStack.count())
260 : {
261 0 : const basegfx::BColor aRGBBaseColor(0, 0, 0);
262 0 : const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor));
263 0 : aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor));
264 : }
265 : else
266 : {
267 0 : aMetaFile = rMetaCandidate.getMetaFile();
268 : }
269 :
270 0 : cppcanvas::BitmapCanvasSharedPtr pCanvas(cppcanvas::VCLFactory::getInstance().createCanvas(
271 0 : uno::Reference<rendering::XBitmapCanvas>(mxCanvas, uno::UNO_QUERY_THROW)));
272 0 : cppcanvas::RendererSharedPtr pMtfRenderer(cppcanvas::VCLFactory::getInstance().createRenderer(
273 0 : pCanvas, aMetaFile, cppcanvas::Renderer::Parameters()));
274 :
275 0 : if(pMtfRenderer)
276 : {
277 0 : pCanvas->setTransformation(getViewInformation2D().getObjectToViewTransformation());
278 0 : pMtfRenderer->setTransformation(rMetaCandidate.getTransform());
279 0 : pMtfRenderer->draw();
280 0 : }
281 0 : }
282 :
283 0 : void canvasProcessor2D::impRenderTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate)
284 : {
285 0 : if(rTextCandidate.getTextLength())
286 : {
287 0 : double fShearX(0.0);
288 : {
289 0 : const basegfx::B2DHomMatrix aLocalTransform(getViewInformation2D().getObjectToViewTransformation() * rTextCandidate.getTextTransform());
290 0 : basegfx::B2DVector aScale, aTranslate;
291 : double fRotate;
292 0 : aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
293 : }
294 :
295 0 : if(!basegfx::fTools::equalZero(fShearX))
296 : {
297 : // text is sheared. As long as the canvas renderers do not support this,
298 : // use the decomposed primitive
299 0 : process(rTextCandidate.get2DDecomposition(getViewInformation2D()));
300 : }
301 : else
302 : {
303 0 : const attribute::FontAttribute& rFontAttr(rTextCandidate.getFontAttribute());
304 0 : rendering::FontRequest aFontRequest;
305 :
306 0 : aFontRequest.FontDescription.FamilyName = rFontAttr.getFamilyName();
307 0 : aFontRequest.FontDescription.StyleName = rFontAttr.getStyleName();
308 0 : aFontRequest.FontDescription.IsSymbolFont = rFontAttr.getSymbol() ? util::TriState_YES : util::TriState_NO;
309 0 : aFontRequest.FontDescription.IsVertical = rFontAttr.getVertical() ? util::TriState_YES : util::TriState_NO;
310 : // TODO(F2): improve vclenum->panose conversion
311 0 : aFontRequest.FontDescription.FontDescription.Weight = static_cast< sal_uInt8 >(rFontAttr.getWeight());
312 : aFontRequest.FontDescription.FontDescription.Proportion =
313 0 : rFontAttr.getMonospaced()
314 : ? rendering::PanoseProportion::MONO_SPACED
315 0 : : rendering::PanoseProportion::ANYTHING;
316 0 : aFontRequest.FontDescription.FontDescription.Letterform = rFontAttr.getItalic() ? 9 : 0;
317 :
318 : // init CellSize to 1.0, else a default font height will be used
319 0 : aFontRequest.CellSize = 1.0;
320 0 : aFontRequest.Locale = rTextCandidate.getLocale();
321 :
322 : // font matrix should only be used for glyph rotations etc.
323 0 : com::sun::star::geometry::Matrix2D aFontMatrix;
324 0 : canvas::tools::setIdentityMatrix2D(aFontMatrix);
325 :
326 0 : uno::Reference<rendering::XCanvasFont> xFont(mxCanvas->createFont(
327 0 : aFontRequest, uno::Sequence< beans::PropertyValue >(), aFontMatrix));
328 :
329 0 : if(xFont.is())
330 : {
331 : // got a font, now try to get a TextLayout
332 : const rendering::StringContext aStringContext(
333 0 : rTextCandidate.getText(), rTextCandidate.getTextPosition(), rTextCandidate.getTextLength());
334 0 : uno::Reference<rendering::XTextLayout> xLayout(xFont->createTextLayout(
335 0 : aStringContext, com::sun::star::rendering::TextDirection::WEAK_LEFT_TO_RIGHT, 0));
336 :
337 0 : if(xLayout.is())
338 : {
339 : // got a text layout, apply DXArray if given
340 0 : const ::std::vector< double >& rDXArray = rTextCandidate.getDXArray();
341 0 : const sal_uInt32 nDXCount(rDXArray.size());
342 :
343 0 : if(nDXCount)
344 : {
345 : // DXArray does not need to be adapted to getTextPosition/getTextLength,
346 : // it is already provided correctly
347 0 : const uno::Sequence< double > aDXSequence(&rDXArray[0], nDXCount);
348 0 : xLayout->applyLogicalAdvancements(aDXSequence);
349 : }
350 :
351 : // set text color
352 0 : const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rTextCandidate.getFontColor()));
353 0 : maRenderState.DeviceColor = aRGBColor.colorToDoubleSequence(mxCanvas->getDevice());
354 :
355 : // set text transformation
356 : canvas::tools::setRenderStateTransform(maRenderState,
357 0 : getViewInformation2D().getObjectTransformation() * rTextCandidate.getTextTransform());
358 :
359 : // paint
360 0 : mxCanvas->drawTextLayout(xLayout, maViewState, maRenderState);
361 0 : }
362 0 : }
363 : }
364 : }
365 0 : }
366 :
367 0 : void canvasProcessor2D::impRenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate)
368 : {
369 : // apply possible color modification to BitmapEx
370 0 : BitmapEx aModifiedBitmapEx(impModifyBitmapEx(maBColorModifierStack, rBitmapCandidate.getBitmapEx()));
371 :
372 0 : if(aModifiedBitmapEx.IsEmpty())
373 : {
374 : // replace with color filled polygon
375 0 : const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor()));
376 0 : const basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon());
377 :
378 0 : maRenderState.DeviceColor = aModifiedColor.colorToDoubleSequence(mxCanvas->getDevice());
379 : canvas::tools::setRenderStateTransform(maRenderState,
380 0 : getViewInformation2D().getObjectTransformation() * rBitmapCandidate.getTransform());
381 :
382 0 : mxCanvas->fillPolyPolygon(basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
383 0 : mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aPolygon)), maViewState, maRenderState);
384 : }
385 : else
386 : {
387 : // adapt object's transformation to the correct scale
388 0 : basegfx::B2DVector aScale, aTranslate;
389 0 : const Size aSizePixel(aModifiedBitmapEx.GetSizePixel());
390 :
391 0 : if(0 != aSizePixel.Width() && 0 != aSizePixel.Height())
392 : {
393 : double fRotate, fShearX;
394 0 : rBitmapCandidate.getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
395 : const basegfx::B2DHomMatrix aNewMatrix(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
396 0 : aScale.getX() / aSizePixel.Width(), aScale.getY() / aSizePixel.Height(),
397 0 : fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
398 :
399 : canvas::tools::setRenderStateTransform(maRenderState,
400 0 : getViewInformation2D().getObjectTransformation() * aNewMatrix);
401 :
402 0 : mxCanvas->drawBitmap(
403 0 : vcl::unotools::xBitmapFromBitmapEx(mxCanvas->getDevice(), aModifiedBitmapEx),
404 0 : maViewState, maRenderState);
405 0 : }
406 0 : }
407 0 : }
408 :
409 0 : void canvasProcessor2D::impRenderTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransparenceCandidate)
410 : {
411 0 : const primitive2d::Primitive2DSequence& rChildren = rTransparenceCandidate.getChildren();
412 0 : const primitive2d::Primitive2DSequence& rTransparence = rTransparenceCandidate.getTransparence();
413 :
414 0 : if(rChildren.hasElements() && rTransparence.hasElements())
415 : {
416 : // get logic range of transparent part and clip with ViewRange
417 0 : basegfx::B2DRange aLogicRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rChildren, getViewInformation2D()));
418 :
419 0 : if(!getViewInformation2D().getViewport().isEmpty())
420 : {
421 0 : aLogicRange.intersect(getViewInformation2D().getViewport());
422 : }
423 :
424 0 : if(!aLogicRange.isEmpty())
425 : {
426 : // get discrete range of transparent part
427 0 : basegfx::B2DRange aDiscreteRange(aLogicRange);
428 0 : aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
429 :
430 : // expand to next covering discrete values (pixel bounds)
431 0 : aDiscreteRange.expand(basegfx::B2DTuple(floor(aDiscreteRange.getMinX()), floor(aDiscreteRange.getMinY())));
432 0 : aDiscreteRange.expand(basegfx::B2DTuple(ceil(aDiscreteRange.getMaxX()), ceil(aDiscreteRange.getMaxY())));
433 :
434 : // use VCL-based buffer device
435 0 : impBufferDevice aBufferDevice(*mpOutputDevice, aDiscreteRange, false);
436 :
437 0 : if(aBufferDevice.isVisible())
438 : {
439 : // remember current OutDev, Canvas and ViewInformation
440 0 : OutputDevice* pLastOutputDevice = mpOutputDevice;
441 0 : uno::Reference< rendering::XCanvas > xLastCanvas(mxCanvas);
442 0 : const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
443 :
444 : // prepare discrete offset for XBitmap, do not forget that the buffer bitmap
445 : // may be truncated to discrete visible pixels
446 : const basegfx::B2DHomMatrix aDiscreteOffset(basegfx::tools::createTranslateB2DHomMatrix(
447 0 : aDiscreteRange.getMinX() > 0.0 ? -aDiscreteRange.getMinX() : 0.0,
448 0 : aDiscreteRange.getMinY() > 0.0 ? -aDiscreteRange.getMinY() : 0.0));
449 :
450 : // create new local ViewInformation2D with new transformation
451 : const geometry::ViewInformation2D aViewInformation2D(
452 0 : getViewInformation2D().getObjectTransformation(),
453 0 : aDiscreteOffset * getViewInformation2D().getViewTransformation(),
454 0 : getViewInformation2D().getViewport(),
455 0 : getViewInformation2D().getVisualizedPage(),
456 0 : getViewInformation2D().getViewTime(),
457 0 : getViewInformation2D().getExtendedInformationSequence());
458 0 : updateViewInformation(aViewInformation2D);
459 :
460 : // set OutDev and Canvas to content target
461 0 : mpOutputDevice = &aBufferDevice.getContent();
462 0 : mxCanvas = mpOutputDevice->GetCanvas();
463 0 : canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
464 :
465 : // if ViewState transform is changed, the clipping polygon needs to be adapted, too
466 0 : const basegfx::B2DPolyPolygon aOldClipPolyPolygon(maClipPolyPolygon);
467 :
468 0 : if(maClipPolyPolygon.count())
469 : {
470 0 : maClipPolyPolygon.transform(aDiscreteOffset);
471 0 : maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
472 : }
473 :
474 : // paint content
475 0 : process(rChildren);
476 :
477 : // set to mask
478 0 : mpOutputDevice = &aBufferDevice.getTransparence();
479 0 : mxCanvas = mpOutputDevice->GetCanvas();
480 0 : canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
481 :
482 : // when painting transparence masks, reset the color stack
483 0 : basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack);
484 0 : maBColorModifierStack = basegfx::BColorModifierStack();
485 :
486 : // paint mask to it (always with transparence intensities, evtl. with AA)
487 0 : process(rTransparence);
488 :
489 : // back to old color stack, OutDev, Canvas and ViewTransform
490 0 : maBColorModifierStack = aLastBColorModifierStack;
491 0 : mpOutputDevice = pLastOutputDevice;
492 0 : mxCanvas = xLastCanvas;
493 0 : updateViewInformation(aLastViewInformation2D);
494 0 : canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
495 :
496 : // restore clipping polygon
497 0 : maClipPolyPolygon = aOldClipPolyPolygon;
498 :
499 0 : if(maClipPolyPolygon.count())
500 : {
501 0 : maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
502 : }
503 :
504 : // dump buffer to outdev
505 0 : aBufferDevice.paint();
506 0 : }
507 : }
508 : }
509 0 : }
510 :
511 0 : void canvasProcessor2D::impRenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive)
512 : {
513 : // support direct fat line geometry. This moves the decomposition to the canvas.
514 : // As long as our canvases are used (which also use basegfx tooling) this makes
515 : // no difference, but potentially canvases may better support this
516 : static bool bSupportFatLineDirectly(true);
517 0 : bool bOutputDone(false);
518 :
519 0 : if(bSupportFatLineDirectly)
520 : {
521 0 : const attribute::LineAttribute& rLineAttribute = rPolygonStrokePrimitive.getLineAttribute();
522 0 : const attribute::StrokeAttribute& rStrokeAttribute = rPolygonStrokePrimitive.getStrokeAttribute();
523 :
524 0 : if(0.0 < rLineAttribute.getWidth() || 0 != rStrokeAttribute.getDotDashArray().size())
525 : {
526 0 : rendering::StrokeAttributes aStrokeAttribute;
527 :
528 0 : aStrokeAttribute.StrokeWidth = rLineAttribute.getWidth();
529 0 : aStrokeAttribute.MiterLimit = 15.0; // degrees; maybe here (15.0 * F_PI180) is needed, not clear in the documentation
530 0 : const ::std::vector< double >& rDotDashArray = rStrokeAttribute.getDotDashArray();
531 :
532 0 : if(!rDotDashArray.empty())
533 : {
534 0 : aStrokeAttribute.DashArray = uno::Sequence< double >(&rDotDashArray[0], rDotDashArray.size());
535 : }
536 :
537 0 : switch(rLineAttribute.getLineJoin())
538 : {
539 : default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE
540 0 : aStrokeAttribute.JoinType = rendering::PathJoinType::NONE;
541 0 : break;
542 : case basegfx::B2DLINEJOIN_BEVEL:
543 0 : aStrokeAttribute.JoinType = rendering::PathJoinType::BEVEL;
544 0 : break;
545 : case basegfx::B2DLINEJOIN_MITER:
546 0 : aStrokeAttribute.JoinType = rendering::PathJoinType::MITER;
547 0 : break;
548 : case basegfx::B2DLINEJOIN_ROUND:
549 0 : aStrokeAttribute.JoinType = rendering::PathJoinType::ROUND;
550 0 : break;
551 : }
552 :
553 0 : switch(rLineAttribute.getLineCap())
554 : {
555 : case com::sun::star::drawing::LineCap_ROUND:
556 0 : aStrokeAttribute.StartCapType = rendering::PathCapType::ROUND;
557 0 : aStrokeAttribute.EndCapType = rendering::PathCapType::ROUND;
558 0 : break;
559 : case com::sun::star::drawing::LineCap_SQUARE:
560 0 : aStrokeAttribute.StartCapType = rendering::PathCapType::SQUARE;
561 0 : aStrokeAttribute.EndCapType = rendering::PathCapType::SQUARE;
562 0 : break;
563 : default: // com::sun::star::drawing::LineCap_BUTT
564 0 : aStrokeAttribute.StartCapType = rendering::PathCapType::BUTT;
565 0 : aStrokeAttribute.EndCapType = rendering::PathCapType::BUTT;
566 0 : break;
567 : }
568 :
569 0 : const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor()));
570 0 : maRenderState.DeviceColor = aHairlineColor.colorToDoubleSequence(mxCanvas->getDevice());
571 0 : canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
572 :
573 0 : mxCanvas->strokePolyPolygon(
574 0 : basegfx::unotools::xPolyPolygonFromB2DPolygon(mxCanvas->getDevice(), rPolygonStrokePrimitive.getB2DPolygon()),
575 0 : maViewState, maRenderState, aStrokeAttribute);
576 :
577 0 : bOutputDone = true;
578 : }
579 : }
580 :
581 0 : if(!bOutputDone)
582 : {
583 : // process decomposition
584 0 : process(rPolygonStrokePrimitive.get2DDecomposition(getViewInformation2D()));
585 : }
586 0 : }
587 :
588 0 : void canvasProcessor2D::impRenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapPrimitive2D)
589 : {
590 : // support tiled fills directly when tiling is on
591 : static bool bSupportFillBitmapDirectly(true);
592 0 : bool bOutputDone(false);
593 :
594 0 : if(bSupportFillBitmapDirectly)
595 : {
596 0 : const attribute::FillBitmapAttribute& rFillBitmapAttribute = rFillBitmapPrimitive2D.getFillBitmap();
597 :
598 0 : if(rFillBitmapAttribute.getTiling())
599 : {
600 : // apply possible color modification to Bitmap
601 0 : const BitmapEx aChangedBitmapEx(impModifyBitmapEx(maBColorModifierStack, rFillBitmapAttribute.getBitmapEx()));
602 :
603 0 : if(aChangedBitmapEx.IsEmpty())
604 : {
605 : // replace with color filled polygon
606 0 : const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor()));
607 0 : const basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon());
608 :
609 0 : maRenderState.DeviceColor = aModifiedColor.colorToDoubleSequence(mxCanvas->getDevice());
610 : canvas::tools::setRenderStateTransform(maRenderState,
611 0 : getViewInformation2D().getObjectTransformation() * rFillBitmapPrimitive2D.getTransformation());
612 :
613 0 : mxCanvas->fillPolyPolygon(basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
614 0 : mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aPolygon)), maViewState, maRenderState);
615 : }
616 : else
617 : {
618 0 : const Size aSizePixel(aChangedBitmapEx.GetSizePixel());
619 :
620 0 : if(0 != aSizePixel.Width() && 0 != aSizePixel.Height())
621 : {
622 : // create texture matrix from texture to object (where object is unit square here),
623 : // so use values directly
624 : const basegfx::B2DHomMatrix aTextureMatrix(basegfx::tools::createScaleTranslateB2DHomMatrix(
625 0 : rFillBitmapAttribute.getSize().getX(), rFillBitmapAttribute.getSize().getY(),
626 0 : rFillBitmapAttribute.getTopLeft().getX(), rFillBitmapAttribute.getTopLeft().getY()));
627 :
628 : // create and fill texture
629 0 : rendering::Texture aTexture;
630 :
631 0 : basegfx::unotools::affineMatrixFromHomMatrix(aTexture.AffineTransform, aTextureMatrix);
632 0 : aTexture.Alpha = 1.0;
633 0 : aTexture.Bitmap = vcl::unotools::xBitmapFromBitmapEx(mxCanvas->getDevice(), aChangedBitmapEx);
634 0 : aTexture.RepeatModeX = rendering::TexturingMode::REPEAT;
635 0 : aTexture.RepeatModeY = rendering::TexturingMode::REPEAT;
636 :
637 : // canvas needs a polygon to fill, create unit rectangle polygon
638 0 : const basegfx::B2DPolygon aOutlineRectangle(basegfx::tools::createUnitPolygon());
639 :
640 : // set primitive's transformation as render state transform
641 : canvas::tools::setRenderStateTransform(maRenderState,
642 0 : getViewInformation2D().getObjectTransformation() * rFillBitmapPrimitive2D.getTransformation());
643 :
644 : // put texture into a uno sequence for handover
645 0 : uno::Sequence< rendering::Texture > aSeq(1);
646 0 : aSeq[0] = aTexture;
647 :
648 : // draw textured rectangle
649 0 : mxCanvas->fillTexturedPolyPolygon(
650 0 : basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aOutlineRectangle)),
651 0 : maViewState, maRenderState, aSeq);
652 : }
653 : }
654 :
655 0 : bOutputDone = true;
656 : }
657 : }
658 :
659 0 : if(!bOutputDone)
660 : {
661 : // process decomposition
662 0 : process(rFillBitmapPrimitive2D.get2DDecomposition(getViewInformation2D()));
663 : }
664 0 : }
665 :
666 0 : void canvasProcessor2D::impRenderUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate)
667 : {
668 0 : if(0.0 == rUniTransparenceCandidate.getTransparence())
669 : {
670 : // not transparent at all, directly use content
671 0 : process(rUniTransparenceCandidate.getChildren());
672 : }
673 0 : else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0)
674 : {
675 0 : const primitive2d::Primitive2DSequence rChildren = rUniTransparenceCandidate.getChildren();
676 :
677 0 : if(rChildren.hasElements())
678 : {
679 0 : bool bOutputDone(false);
680 :
681 : // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case,
682 : // use the fillPolyPolygon method with correctly set transparence. This is a often used
683 : // case, so detectiong it is valuable
684 0 : if(1 == rChildren.getLength())
685 : {
686 0 : const primitive2d::Primitive2DReference xReference(rChildren[0]);
687 0 : const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get());
688 :
689 0 : if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID())
690 : {
691 : // direct draw of PolyPolygon with color and transparence
692 0 : const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor()));
693 :
694 : // add transparence modulation value to DeviceColor
695 0 : uno::Sequence< double > aColor(4);
696 :
697 0 : aColor[0] = aPolygonColor.getRed();
698 0 : aColor[1] = aPolygonColor.getGreen();
699 0 : aColor[2] = aPolygonColor.getBlue();
700 0 : aColor[3] = 1.0 - rUniTransparenceCandidate.getTransparence();
701 0 : maRenderState.DeviceColor = aColor;
702 :
703 0 : canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
704 0 : mxCanvas->fillPolyPolygon(
705 0 : basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), pPoPoColor->getB2DPolyPolygon()),
706 0 : maViewState, maRenderState);
707 0 : bOutputDone = true;
708 0 : }
709 : }
710 :
711 0 : if(!bOutputDone)
712 : {
713 : // process decomposition. This will be decomposed to an TransparencePrimitive2D
714 : // with the same child context and a single polygon for transparent context. This could be
715 : // directly handled here with known VCL-buffer technology, but would only
716 : // make a small difference compared to directly rendering the TransparencePrimitive2D
717 : // using impRenderTransparencePrimitive2D above.
718 0 : process(rUniTransparenceCandidate.get2DDecomposition(getViewInformation2D()));
719 : }
720 0 : }
721 : }
722 0 : }
723 :
724 : //////////////////////////////////////////////////////////////////////////////
725 : // internal processing support
726 :
727 0 : void canvasProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
728 : {
729 0 : switch(rCandidate.getPrimitive2DID())
730 : {
731 : case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
732 : {
733 : // direct draw of hairline
734 0 : const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate);
735 0 : const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
736 :
737 0 : maRenderState.DeviceColor = aHairlineColor.colorToDoubleSequence(mxCanvas->getDevice());
738 0 : canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
739 0 : mxCanvas->drawPolyPolygon(
740 0 : basegfx::unotools::xPolyPolygonFromB2DPolygon(mxCanvas->getDevice(), rPolygonCandidate.getB2DPolygon()),
741 0 : maViewState, maRenderState);
742 :
743 0 : break;
744 : }
745 : case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
746 : {
747 : // direct draw of PolyPolygon with color
748 0 : const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate = static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate);
749 0 : const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
750 :
751 0 : maRenderState.DeviceColor = aPolygonColor.colorToDoubleSequence(mxCanvas->getDevice());
752 0 : canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
753 0 : mxCanvas->fillPolyPolygon(
754 0 : basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), rPolygonCandidate.getB2DPolyPolygon()),
755 0 : maViewState, maRenderState);
756 :
757 0 : break;
758 : }
759 : case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
760 : {
761 : // modified color group. Force output to unified color.
762 0 : const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate = static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate);
763 :
764 0 : if(rModifiedCandidate.getChildren().hasElements())
765 : {
766 0 : maBColorModifierStack.push(rModifiedCandidate.getColorModifier());
767 0 : process(rModifiedCandidate.getChildren());
768 0 : maBColorModifierStack.pop();
769 : }
770 :
771 0 : break;
772 : }
773 : case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
774 : {
775 : // mask group
776 0 : impRenderMaskPrimitive2D(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate));
777 :
778 0 : break;
779 : }
780 : case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
781 : {
782 : // transform group. Remember current ViewInformation2D
783 0 : const primitive2d::TransformPrimitive2D& rTransformCandidate = static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate);
784 0 : const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
785 :
786 : // create new local ViewInformation2D with new transformation
787 : const geometry::ViewInformation2D aViewInformation2D(
788 0 : getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(),
789 0 : getViewInformation2D().getViewTransformation(),
790 0 : getViewInformation2D().getViewport(),
791 0 : getViewInformation2D().getVisualizedPage(),
792 0 : getViewInformation2D().getViewTime(),
793 0 : getViewInformation2D().getExtendedInformationSequence());
794 0 : updateViewInformation(aViewInformation2D);
795 :
796 : // set at canvas
797 0 : canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
798 :
799 : // proccess content
800 0 : process(rTransformCandidate.getChildren());
801 :
802 : // restore transformations
803 0 : updateViewInformation(aLastViewInformation2D);
804 :
805 : // restore at canvas
806 0 : canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
807 :
808 0 : break;
809 : }
810 : case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
811 : {
812 : // new XDrawPage for ViewInformation2D
813 0 : const primitive2d::PagePreviewPrimitive2D& rPagePreviewCandidate = static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate);
814 :
815 : // remember current transformation and ViewInformation
816 0 : const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
817 :
818 : // create new local ViewInformation2D
819 : const geometry::ViewInformation2D aViewInformation2D(
820 0 : getViewInformation2D().getObjectTransformation(),
821 0 : getViewInformation2D().getViewTransformation(),
822 0 : getViewInformation2D().getViewport(),
823 0 : rPagePreviewCandidate.getXDrawPage(),
824 0 : getViewInformation2D().getViewTime(),
825 0 : getViewInformation2D().getExtendedInformationSequence());
826 0 : updateViewInformation(aViewInformation2D);
827 :
828 : // proccess decomposed content
829 0 : process(rPagePreviewCandidate.get2DDecomposition(getViewInformation2D()));
830 :
831 : // restore transformations
832 0 : updateViewInformation(aLastViewInformation2D);
833 0 : break;
834 : }
835 : case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
836 : {
837 : // MetaFile primitive
838 0 : impRenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate));
839 :
840 0 : break;
841 : }
842 : case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
843 : {
844 : // PointArray primitive
845 0 : const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate = static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate);
846 :
847 : // set point color
848 0 : const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor()));
849 0 : maRenderState.DeviceColor = aRGBColor.colorToDoubleSequence(mxCanvas->getDevice());
850 0 : canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
851 :
852 0 : const std::vector< basegfx::B2DPoint >& rPointVector = rPointArrayCandidate.getPositions();
853 0 : const sal_uInt32 nPointCount(rPointVector.size());
854 :
855 0 : for(sal_uInt32 a(0); a < nPointCount; a++)
856 : {
857 0 : const basegfx::B2DPoint& rPoint = rPointVector[a];
858 0 : mxCanvas->drawPoint(basegfx::unotools::point2DFromB2DPoint(rPoint), maViewState, maRenderState);
859 : }
860 :
861 0 : break;
862 : }
863 : case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
864 : {
865 : // TextSimplePortion primitive
866 0 : impRenderTextSimplePortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate));
867 :
868 0 : break;
869 : }
870 : case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
871 : {
872 : // Bitmap primitive
873 0 : impRenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
874 :
875 0 : break;
876 : }
877 : case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
878 : {
879 : // Transparence primitive
880 0 : impRenderTransparencePrimitive2D(static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate));
881 :
882 0 : break;
883 : }
884 : case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
885 : {
886 : // PolygonStrokePrimitive
887 0 : impRenderPolygonStrokePrimitive2D(static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate));
888 :
889 0 : break;
890 : }
891 : case PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D :
892 : {
893 : // FillBitmapPrimitive2D
894 0 : impRenderFillBitmapPrimitive2D(static_cast< const primitive2d::FillBitmapPrimitive2D& >(rCandidate));
895 :
896 0 : break;
897 : }
898 : case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D :
899 : {
900 : // UnifiedTransparencePrimitive2D
901 0 : impRenderUnifiedTransparencePrimitive2D(static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate));
902 :
903 0 : break;
904 : }
905 : case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
906 : {
907 : // wrong spell primitive. Handled directly here using VCL since VCL has a nice and
908 : // very direct waveline painting which is needed for this. If VCL is to be avoided,
909 : // this can be removed anytime and the decomposition may be used
910 0 : const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive = static_cast< const primitive2d::WrongSpellPrimitive2D& >(rCandidate);
911 :
912 0 : if(!renderWrongSpellPrimitive2D(
913 : rWrongSpellPrimitive,
914 : *mpOutputDevice,
915 0 : getViewInformation2D().getObjectToViewTransformation(),
916 0 : maBColorModifierStack))
917 : {
918 : // fallback to decomposition (MetaFile)
919 0 : process(rWrongSpellPrimitive.get2DDecomposition(getViewInformation2D()));
920 : }
921 :
922 0 : break;
923 : }
924 :
925 : // nice to have:
926 : //
927 : // case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
928 : // - support FormControls more direct eventually, not sure if this is needed
929 : // with the canvas renderer. The decomposition provides a bitmap representation
930 : // of the control which will work
931 : //
932 :
933 : default :
934 : {
935 : // process recursively
936 0 : process(rCandidate.get2DDecomposition(getViewInformation2D()));
937 :
938 0 : break;
939 : }
940 : }
941 0 : }
942 :
943 : //////////////////////////////////////////////////////////////////////////////
944 : // process support
945 :
946 0 : canvasProcessor2D::canvasProcessor2D(
947 : const geometry::ViewInformation2D& rViewInformation,
948 : OutputDevice& rOutDev)
949 : : BaseProcessor2D(rViewInformation),
950 : mpOutputDevice(&rOutDev),
951 : mxCanvas(rOutDev.GetCanvas()),
952 : maViewState(),
953 : maRenderState(),
954 : maBColorModifierStack(),
955 : maDrawinglayerOpt(),
956 : maClipPolyPolygon(),
957 0 : meLang(drawinglayer::detail::getDigitLanguage())
958 : {
959 0 : canvas::tools::initViewState(maViewState);
960 0 : canvas::tools::initRenderState(maRenderState);
961 0 : canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
962 :
963 : // set digit language, derived from SvtCTLOptions to have the correct
964 : // number display for arabic/hindi numerals
965 0 : rOutDev.SetDigitLanguage(meLang);
966 :
967 : // prepare output directly to pixels
968 0 : mpOutputDevice->Push(PUSH_MAPMODE);
969 0 : mpOutputDevice->SetMapMode();
970 :
971 : // react on AntiAliasing settings
972 0 : if(getOptionsDrawinglayer().IsAntiAliasing())
973 : {
974 0 : mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() | ANTIALIASING_ENABLE_B2DDRAW);
975 : }
976 : else
977 : {
978 0 : mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW);
979 : }
980 0 : }
981 :
982 0 : canvasProcessor2D::~canvasProcessor2D()
983 : {
984 : // restore MapMode
985 0 : mpOutputDevice->Pop();
986 :
987 : // restore AntiAliasing
988 0 : mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW);
989 0 : }
990 : } // end of namespace processor2d
991 : } // end of namespace drawinglayer
992 :
993 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|