Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include <canvas/debug.hxx>
31 : : #include <tools/diagnose_ex.h>
32 : : #include <canvas/verbosetrace.hxx>
33 : : #include <osl/mutex.hxx>
34 : : #include <vcl/svapp.hxx>
35 : : #include <rtl/logfile.hxx>
36 : : #include <comphelper/sequence.hxx>
37 : : #include <comphelper/anytostring.hxx>
38 : : #include <cppuhelper/exc_hlp.hxx>
39 : : #include <cppcanvas/canvas.hxx>
40 : : #include <com/sun/star/rendering/XGraphicDevice.hpp>
41 : : #include <com/sun/star/rendering/TexturingMode.hpp>
42 : : #include <com/sun/star/uno/Sequence.hxx>
43 : : #include <com/sun/star/geometry/RealPoint2D.hpp>
44 : : #include <com/sun/star/rendering/PanoseProportion.hpp>
45 : : #include <com/sun/star/rendering/ViewState.hpp>
46 : : #include <com/sun/star/rendering/RenderState.hpp>
47 : : #include <com/sun/star/rendering/XCanvasFont.hpp>
48 : : #include <com/sun/star/rendering/XPolyPolygon2D.hpp>
49 : : #include <com/sun/star/rendering/XCanvas.hpp>
50 : : #include <com/sun/star/rendering/PathCapType.hpp>
51 : : #include <com/sun/star/rendering/PathJoinType.hpp>
52 : : #include <basegfx/tools/canvastools.hxx>
53 : : #include <basegfx/tools/gradienttools.hxx>
54 : : #include <basegfx/numeric/ftools.hxx>
55 : : #include <basegfx/polygon/b2dpolypolygontools.hxx>
56 : : #include <basegfx/polygon/b2dpolygontools.hxx>
57 : : #include <basegfx/polygon/b2dpolygon.hxx>
58 : : #include <basegfx/polygon/b2dpolypolygon.hxx>
59 : : #include <basegfx/matrix/b2dhommatrix.hxx>
60 : : #include <basegfx/vector/b2dsize.hxx>
61 : : #include <basegfx/range/b2drectangle.hxx>
62 : : #include <basegfx/point/b2dpoint.hxx>
63 : : #include <basegfx/tuple/b2dtuple.hxx>
64 : : #include <basegfx/polygon/b2dpolygonclipper.hxx>
65 : : #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
66 : : #include <canvas/canvastools.hxx>
67 : : #include <vcl/canvastools.hxx>
68 : : #include <vcl/salbtype.hxx>
69 : : #include <vcl/gdimtf.hxx>
70 : : #include <vcl/metaact.hxx>
71 : : #include <vcl/virdev.hxx>
72 : : #include <vcl/metric.hxx>
73 : : #include <vcl/graphictools.hxx>
74 : : #include <tools/poly.hxx>
75 : : #include <i18npool/mslangid.hxx>
76 : : #include <implrenderer.hxx>
77 : : #include <tools.hxx>
78 : : #include <outdevstate.hxx>
79 : : #include <action.hxx>
80 : : #include <bitmapaction.hxx>
81 : : #include <lineaction.hxx>
82 : : #include <pointaction.hxx>
83 : : #include <polypolyaction.hxx>
84 : : #include <rendergraphicaction.hxx>
85 : : #include <textaction.hxx>
86 : : #include <transparencygroupaction.hxx>
87 : : #include <vector>
88 : : #include <algorithm>
89 : : #include <iterator>
90 : : #include <boost/scoped_array.hpp>
91 : : #include "mtftools.hxx"
92 : : #include "outdevstate.hxx"
93 : : #include <basegfx/matrix/b2dhommatrixtools.hxx>
94 : :
95 : : #if OSL_DEBUG_LEVEL > 1
96 : : #define EMFP_DEBUG(x) x
97 : : #else
98 : : #define EMFP_DEBUG(x)
99 : : #endif
100 : :
101 : : using namespace ::com::sun::star;
102 : :
103 : :
104 : : // free support functions
105 : : // ======================
106 : : namespace
107 : : {
108 : 0 : template < class MetaActionType > void setStateColor( MetaActionType* pAct,
109 : : bool& rIsColorSet,
110 : : uno::Sequence< double >& rColorSequence,
111 : : const cppcanvas::CanvasSharedPtr& rCanvas )
112 : : {
113 : : // set rIsColorSet and check for true at the same time
114 [ # # ][ # # ]: 0 : if( (rIsColorSet=pAct->IsSetting()) != false )
[ # # ][ # # ]
115 : : {
116 : 0 : ::Color aColor( pAct->GetColor() );
117 : :
118 : : // force alpha part of color to
119 : : // opaque. transparent painting is done
120 : : // explicitly via META_TRANSPARENT_ACTION
121 [ # # # # : 0 : aColor.SetTransparency(0);
# # # # ]
122 : : //aColor.SetTransparency(128);
123 : :
124 [ # # ][ # # ]: 0 : rColorSequence = ::vcl::unotools::colorToDoubleSequence(
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
125 : : aColor,
126 : : rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
127 : : }
128 : 0 : }
129 : :
130 : 0 : void setupStrokeAttributes( rendering::StrokeAttributes& o_rStrokeAttributes,
131 : : const ::cppcanvas::internal::ActionFactoryParameters& rParms,
132 : : const LineInfo& rLineInfo )
133 : : {
134 : 0 : const ::basegfx::B2DSize aWidth( rLineInfo.GetWidth(), 0 );
135 : : o_rStrokeAttributes.StrokeWidth =
136 [ # # ][ # # ]: 0 : (rParms.mrStates.getState().mapModeTransform * aWidth).getX();
137 : :
138 : : // setup reasonable defaults
139 : 0 : o_rStrokeAttributes.MiterLimit = 15.0; // 1.0 was no good default; GDI+'s limit is 10.0, our's is 15.0
140 : 0 : o_rStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
141 : 0 : o_rStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
142 : :
143 [ # # # # ]: 0 : switch(rLineInfo.GetLineJoin())
144 : : {
145 : : default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE
146 : 0 : o_rStrokeAttributes.JoinType = rendering::PathJoinType::NONE;
147 : 0 : break;
148 : : case basegfx::B2DLINEJOIN_BEVEL:
149 : 0 : o_rStrokeAttributes.JoinType = rendering::PathJoinType::BEVEL;
150 : 0 : break;
151 : : case basegfx::B2DLINEJOIN_MITER:
152 : 0 : o_rStrokeAttributes.JoinType = rendering::PathJoinType::MITER;
153 : 0 : break;
154 : : case basegfx::B2DLINEJOIN_ROUND:
155 : 0 : o_rStrokeAttributes.JoinType = rendering::PathJoinType::ROUND;
156 : 0 : break;
157 : : }
158 : :
159 [ # # ]: 0 : if( LINE_DASH == rLineInfo.GetStyle() )
160 : : {
161 [ # # ]: 0 : const ::cppcanvas::internal::OutDevState& rState( rParms.mrStates.getState() );
162 : :
163 : : // TODO(F1): Interpret OutDev::GetRefPoint() for the start of the dashing.
164 : :
165 : : // interpret dash info only if explicitly enabled as
166 : : // style
167 : 0 : const ::basegfx::B2DSize aDistance( rLineInfo.GetDistance(), 0 );
168 [ # # ]: 0 : const double nDistance( (rState.mapModeTransform * aDistance).getX() );
169 : :
170 : 0 : const ::basegfx::B2DSize aDashLen( rLineInfo.GetDashLen(), 0 );
171 [ # # ]: 0 : const double nDashLen( (rState.mapModeTransform * aDashLen).getX() );
172 : :
173 : 0 : const ::basegfx::B2DSize aDotLen( rLineInfo.GetDotLen(), 0 );
174 [ # # ]: 0 : const double nDotLen( (rState.mapModeTransform * aDotLen).getX() );
175 : :
176 : 0 : const sal_Int32 nNumArryEntries( 2*rLineInfo.GetDashCount() +
177 : 0 : 2*rLineInfo.GetDotCount() );
178 : :
179 [ # # ]: 0 : o_rStrokeAttributes.DashArray.realloc( nNumArryEntries );
180 [ # # ]: 0 : double* pDashArray = o_rStrokeAttributes.DashArray.getArray();
181 : :
182 : :
183 : : // iteratively fill dash array, first with dashs, then
184 : : // with dots.
185 : : // ===================================================
186 : :
187 : 0 : sal_Int32 nCurrEntry=0;
188 : :
189 [ # # ]: 0 : for( sal_Int32 i=0; i<rLineInfo.GetDashCount(); ++i )
190 : : {
191 : 0 : pDashArray[nCurrEntry++] = nDashLen;
192 : 0 : pDashArray[nCurrEntry++] = nDistance;
193 : : }
194 [ # # ]: 0 : for( sal_Int32 i=0; i<rLineInfo.GetDotCount(); ++i )
195 : : {
196 : 0 : pDashArray[nCurrEntry++] = nDotLen;
197 : 0 : pDashArray[nCurrEntry++] = nDistance;
198 : 0 : }
199 : 0 : }
200 : 0 : }
201 : :
202 : :
203 : : /** Create masked BitmapEx, where the white areas of rBitmap are
204 : : transparent, and the other appear in rMaskColor.
205 : : */
206 : 0 : BitmapEx createMaskBmpEx( const Bitmap& rBitmap,
207 : : const ::Color& rMaskColor )
208 : : {
209 : 0 : const ::Color aWhite( COL_WHITE );
210 [ # # ]: 0 : BitmapPalette aBiLevelPalette(2);
211 : 0 : aBiLevelPalette[0] = aWhite;
212 : 0 : aBiLevelPalette[1] = rMaskColor;
213 : :
214 [ # # ]: 0 : Bitmap aMask( rBitmap.CreateMask( aWhite ));
215 : : Bitmap aSolid( rBitmap.GetSizePixel(),
216 : : 1,
217 [ # # ][ # # ]: 0 : &aBiLevelPalette );
218 [ # # ]: 0 : aSolid.Erase( rMaskColor );
219 : :
220 [ # # ][ # # ]: 0 : return BitmapEx( aSolid, aMask );
[ # # ]
221 : : }
222 : :
223 : : /** Shameless rip from vcl/source/gdi/outdev3.cxx
224 : :
225 : : Should consolidate, into something like basetxt...
226 : : */
227 : 0 : sal_Unicode getLocalizedChar( sal_Unicode nChar, LanguageType eLang )
228 : : {
229 : : // currently only conversion from ASCII digits is interesting
230 [ # # ][ # # ]: 0 : if( (nChar < '0') || ('9' < nChar) )
231 : 0 : return nChar;
232 : :
233 : 0 : sal_Unicode nOffset(0);
234 : : // eLang & LANGUAGE_MASK_PRIMARY catches language independent of region.
235 : : // CAVEAT! To some like Mongolian MS assigned the same primary language
236 : : // although the script type is different!
237 [ # # # # : 0 : switch( eLang & LANGUAGE_MASK_PRIMARY )
# # # # #
# # # # #
# # ]
238 : : {
239 : : default:
240 : 0 : break;
241 : :
242 : : case LANGUAGE_ARABIC_SAUDI_ARABIA & LANGUAGE_MASK_PRIMARY:
243 : : case LANGUAGE_URDU & LANGUAGE_MASK_PRIMARY:
244 : : case LANGUAGE_PUNJABI & LANGUAGE_MASK_PRIMARY: //???
245 : 0 : nOffset = 0x0660 - '0'; // arabic/persian/urdu
246 : 0 : break;
247 : : case LANGUAGE_BENGALI & LANGUAGE_MASK_PRIMARY:
248 : 0 : nOffset = 0x09E6 - '0'; // bengali
249 : 0 : break;
250 : : case LANGUAGE_BURMESE & LANGUAGE_MASK_PRIMARY:
251 : 0 : nOffset = 0x1040 - '0'; // burmese
252 : 0 : break;
253 : : case LANGUAGE_HINDI & LANGUAGE_MASK_PRIMARY:
254 : 0 : nOffset = 0x0966 - '0'; // devanagari
255 : 0 : break;
256 : : case LANGUAGE_GUJARATI & LANGUAGE_MASK_PRIMARY:
257 : 0 : nOffset = 0x0AE6 - '0'; // gujarati
258 : 0 : break;
259 : : case LANGUAGE_KANNADA & LANGUAGE_MASK_PRIMARY:
260 : 0 : nOffset = 0x0CE6 - '0'; // kannada
261 : 0 : break;
262 : : case LANGUAGE_KHMER & LANGUAGE_MASK_PRIMARY:
263 : 0 : nOffset = 0x17E0 - '0'; // khmer
264 : 0 : break;
265 : : case LANGUAGE_LAO & LANGUAGE_MASK_PRIMARY:
266 : 0 : nOffset = 0x0ED0 - '0'; // lao
267 : 0 : break;
268 : : case LANGUAGE_MALAYALAM & LANGUAGE_MASK_PRIMARY:
269 : 0 : nOffset = 0x0D66 - '0'; // malayalam
270 : 0 : break;
271 : : case LANGUAGE_MONGOLIAN & LANGUAGE_MASK_PRIMARY:
272 [ # # ]: 0 : if (eLang == LANGUAGE_MONGOLIAN_MONGOLIAN)
273 : 0 : nOffset = 0x1810 - '0'; // mongolian
274 : : else
275 : 0 : nOffset = 0; // mongolian cyrillic
276 : 0 : break;
277 : : case LANGUAGE_ORIYA & LANGUAGE_MASK_PRIMARY:
278 : 0 : nOffset = 0x0B66 - '0'; // oriya
279 : 0 : break;
280 : : case LANGUAGE_TAMIL & LANGUAGE_MASK_PRIMARY:
281 : 0 : nOffset = 0x0BE7 - '0'; // tamil
282 : 0 : break;
283 : : case LANGUAGE_TELUGU & LANGUAGE_MASK_PRIMARY:
284 : 0 : nOffset = 0x0C66 - '0'; // telugu
285 : 0 : break;
286 : : case LANGUAGE_THAI & LANGUAGE_MASK_PRIMARY:
287 : 0 : nOffset = 0x0E50 - '0'; // thai
288 : 0 : break;
289 : : case LANGUAGE_TIBETAN & LANGUAGE_MASK_PRIMARY:
290 : 0 : nOffset = 0x0F20 - '0'; // tibetan
291 : 0 : break;
292 : : }
293 : :
294 : 0 : nChar = sal::static_int_cast<sal_Unicode>(nChar + nOffset);
295 : 0 : return nChar;
296 : : }
297 : :
298 : 0 : void convertToLocalizedNumerals( XubString& rStr,
299 : : LanguageType eTextLanguage )
300 : : {
301 : 0 : const sal_Unicode* pBase = rStr.GetBuffer();
302 : 0 : const sal_Unicode* pBegin = pBase + 0;
303 : 0 : const xub_StrLen nEndIndex = rStr.Len();
304 : 0 : const sal_Unicode* pEnd = pBase + nEndIndex;
305 : :
306 [ # # ]: 0 : for( ; pBegin < pEnd; ++pBegin )
307 : : {
308 : : // TODO: are there non-digit localizations?
309 [ # # ][ # # ]: 0 : if( (*pBegin >= '0') && (*pBegin <= '9') )
310 : : {
311 : : // translate characters to local preference
312 : 0 : sal_Unicode cChar = getLocalizedChar( *pBegin, eTextLanguage );
313 [ # # ]: 0 : if( cChar != *pBegin )
314 : 0 : rStr.SetChar( sal::static_int_cast<sal_uInt16>(pBegin - pBase), cChar );
315 : : }
316 : : }
317 : 0 : }
318 : : }
319 : :
320 : :
321 : : namespace cppcanvas
322 : : {
323 : : namespace internal
324 : : {
325 : : // state stack manipulators
326 : : // ------------------------
327 : 0 : void VectorOfOutDevStates::clearStateStack()
328 : : {
329 : 0 : m_aStates.clear();
330 [ # # ]: 0 : const OutDevState aDefaultState;
331 [ # # ][ # # ]: 0 : m_aStates.push_back(aDefaultState);
332 : 0 : }
333 : :
334 : 0 : OutDevState& VectorOfOutDevStates::getState()
335 : : {
336 : 0 : return m_aStates.back();
337 : : }
338 : :
339 : 0 : const OutDevState& VectorOfOutDevStates::getState() const
340 : : {
341 : 0 : return m_aStates.back();
342 : : }
343 : :
344 : 0 : void VectorOfOutDevStates::pushState(sal_uInt16 nFlags)
345 : : {
346 : 0 : m_aStates.push_back( getState() );
347 : 0 : getState().pushFlags = nFlags;
348 : 0 : }
349 : :
350 : 0 : void VectorOfOutDevStates::popState()
351 : : {
352 [ # # ]: 0 : if( getState().pushFlags != PUSH_ALL )
353 : : {
354 : : // a state is pushed which is incomplete, i.e. does not
355 : : // restore everything to the previous stack level when
356 : : // popped.
357 : : // That means, we take the old state, and restore every
358 : : // OutDevState member whose flag is set, from the new to the
359 : : // old state. Then the new state gets overwritten by the
360 : : // calculated state
361 : :
362 : : // preset to-be-calculated new state with old state
363 [ # # ][ # # ]: 0 : OutDevState aCalculatedNewState( getState() );
364 : :
365 : : // selectively copy to-be-restored content over saved old
366 : : // state
367 [ # # ]: 0 : m_aStates.pop_back();
368 : :
369 [ # # ]: 0 : const OutDevState& rNewState( getState() );
370 : :
371 [ # # ]: 0 : if( (aCalculatedNewState.pushFlags & PUSH_LINECOLOR) )
372 : : {
373 [ # # ]: 0 : aCalculatedNewState.lineColor = rNewState.lineColor;
374 : 0 : aCalculatedNewState.isLineColorSet = rNewState.isLineColorSet;
375 : : }
376 : :
377 [ # # ]: 0 : if( (aCalculatedNewState.pushFlags & PUSH_FILLCOLOR) )
378 : : {
379 [ # # ]: 0 : aCalculatedNewState.fillColor = rNewState.fillColor;
380 : 0 : aCalculatedNewState.isFillColorSet = rNewState.isFillColorSet;
381 : : }
382 : :
383 [ # # ]: 0 : if( (aCalculatedNewState.pushFlags & PUSH_FONT) )
384 : : {
385 [ # # ]: 0 : aCalculatedNewState.xFont = rNewState.xFont;
386 : 0 : aCalculatedNewState.fontRotation = rNewState.fontRotation;
387 : 0 : aCalculatedNewState.textReliefStyle = rNewState.textReliefStyle;
388 : 0 : aCalculatedNewState.textOverlineStyle = rNewState.textOverlineStyle;
389 : 0 : aCalculatedNewState.textUnderlineStyle = rNewState.textUnderlineStyle;
390 : 0 : aCalculatedNewState.textStrikeoutStyle = rNewState.textStrikeoutStyle;
391 : 0 : aCalculatedNewState.textEmphasisMarkStyle = rNewState.textEmphasisMarkStyle;
392 : 0 : aCalculatedNewState.isTextEffectShadowSet = rNewState.isTextEffectShadowSet;
393 : 0 : aCalculatedNewState.isTextWordUnderlineSet = rNewState.isTextWordUnderlineSet;
394 : 0 : aCalculatedNewState.isTextOutlineModeSet = rNewState.isTextOutlineModeSet;
395 : : }
396 : :
397 [ # # ]: 0 : if( (aCalculatedNewState.pushFlags & PUSH_TEXTCOLOR) )
398 : : {
399 [ # # ]: 0 : aCalculatedNewState.textColor = rNewState.textColor;
400 : : }
401 : :
402 [ # # ]: 0 : if( (aCalculatedNewState.pushFlags & PUSH_MAPMODE) )
403 : : {
404 [ # # ]: 0 : aCalculatedNewState.mapModeTransform = rNewState.mapModeTransform;
405 : : }
406 : :
407 [ # # ]: 0 : if( (aCalculatedNewState.pushFlags & PUSH_CLIPREGION) )
408 : : {
409 [ # # ]: 0 : aCalculatedNewState.clip = rNewState.clip;
410 : 0 : aCalculatedNewState.clipRect = rNewState.clipRect;
411 [ # # ]: 0 : aCalculatedNewState.xClipPoly = rNewState.xClipPoly;
412 : : }
413 : :
414 : : // TODO(F2): Raster ops NYI
415 : : // if( (aCalculatedNewState.pushFlags & PUSH_RASTEROP) )
416 : : // {
417 : : // }
418 : :
419 [ # # ]: 0 : if( (aCalculatedNewState.pushFlags & PUSH_TEXTFILLCOLOR) )
420 : : {
421 [ # # ]: 0 : aCalculatedNewState.textFillColor = rNewState.textFillColor;
422 : 0 : aCalculatedNewState.isTextFillColorSet = rNewState.isTextFillColorSet;
423 : : }
424 : :
425 [ # # ]: 0 : if( (aCalculatedNewState.pushFlags & PUSH_TEXTALIGN) )
426 : : {
427 : 0 : aCalculatedNewState.textReferencePoint = rNewState.textReferencePoint;
428 : : }
429 : :
430 : : // TODO(F1): Refpoint handling NYI
431 : : // if( (aCalculatedNewState.pushFlags & PUSH_REFPOINT) )
432 : : // {
433 : : // }
434 : :
435 [ # # ]: 0 : if( (aCalculatedNewState.pushFlags & PUSH_TEXTLINECOLOR) )
436 : : {
437 [ # # ]: 0 : aCalculatedNewState.textLineColor = rNewState.textLineColor;
438 : 0 : aCalculatedNewState.isTextLineColorSet = rNewState.isTextLineColorSet;
439 : : }
440 : :
441 [ # # ]: 0 : if( (aCalculatedNewState.pushFlags & PUSH_TEXTLAYOUTMODE) )
442 : : {
443 : 0 : aCalculatedNewState.textAlignment = rNewState.textAlignment;
444 : 0 : aCalculatedNewState.textDirection = rNewState.textDirection;
445 : : }
446 : :
447 : : // TODO(F2): Text language handling NYI
448 : : // if( (aCalculatedNewState.pushFlags & PUSH_TEXTLANGUAGE) )
449 : : // {
450 : : // }
451 : :
452 : : // always copy push mode
453 : 0 : aCalculatedNewState.pushFlags = rNewState.pushFlags;
454 : :
455 : : // flush to stack
456 [ # # ][ # # ]: 0 : getState() = aCalculatedNewState;
[ # # ]
457 : : }
458 : : else
459 : : {
460 : 0 : m_aStates.pop_back();
461 : : }
462 : 0 : }
463 : :
464 : 0 : bool ImplRenderer::createFillAndStroke( const ::basegfx::B2DPolyPolygon& rPolyPoly,
465 : : const ActionFactoryParameters& rParms )
466 : : {
467 [ # # ]: 0 : const OutDevState& rState( rParms.mrStates.getState() );
468 [ # # ][ # # : 0 : if( (!rState.isLineColorSet &&
# # # # ]
[ # # ]
469 : 0 : !rState.isFillColorSet) ||
470 : 0 : (rState.lineColor.getLength() == 0 &&
471 : 0 : rState.fillColor.getLength() == 0) )
472 : : {
473 : 0 : return false;
474 : : }
475 : :
476 : : ActionSharedPtr pPolyAction(
477 : : internal::PolyPolyActionFactory::createPolyPolyAction(
478 [ # # ]: 0 : rPolyPoly, rParms.mrCanvas, rState ) );
479 : :
480 [ # # ]: 0 : if( pPolyAction )
481 : : {
482 : : maActions.push_back(
483 : : MtfAction(
484 : : pPolyAction,
485 [ # # ][ # # ]: 0 : rParms.mrCurrActionIndex ) );
[ # # ]
486 : :
487 [ # # ]: 0 : rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
488 : : }
489 : :
490 [ # # ]: 0 : return true;
491 : : }
492 : :
493 : 0 : bool ImplRenderer::createFillAndStroke( const ::basegfx::B2DPolygon& rPoly,
494 : : const ActionFactoryParameters& rParms )
495 : : {
496 : : return createFillAndStroke( ::basegfx::B2DPolyPolygon( rPoly ),
497 [ # # ]: 0 : rParms );
498 : : }
499 : :
500 : 0 : void ImplRenderer::skipContent( GDIMetaFile& rMtf,
501 : : const char* pCommentString,
502 : : sal_Int32& io_rCurrActionIndex ) const
503 : : {
504 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( pCommentString,
[ # # ][ # # ]
505 : : "ImplRenderer::skipContent(): NULL string given" );
506 : :
507 : : MetaAction* pCurrAct;
508 [ # # ]: 0 : while( (pCurrAct=rMtf.NextAction()) != NULL )
509 : : {
510 : : // increment action index, we've skipped an action.
511 : 0 : ++io_rCurrActionIndex;
512 : :
513 [ # # # # ]: 0 : if( pCurrAct->GetType() == META_COMMENT_ACTION &&
[ # # ]
514 : 0 : static_cast<MetaCommentAction*>(pCurrAct)->GetComment().equalsIgnoreAsciiCase(
515 : 0 : pCommentString) )
516 : : {
517 : : // requested comment found, done
518 : 0 : return;
519 : : }
520 : : }
521 : :
522 : : // EOF
523 : 0 : return;
524 : : }
525 : :
526 : 0 : bool ImplRenderer::isActionContained( GDIMetaFile& rMtf,
527 : : const char* pCommentString,
528 : : sal_uInt16 nType ) const
529 : : {
530 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( pCommentString,
[ # # ][ # # ]
531 : : "ImplRenderer::isActionContained(): NULL string given" );
532 : :
533 : 0 : bool bRet( false );
534 : :
535 : : // at least _one_ call to GDIMetaFile::NextAction() is
536 : : // executed
537 : 0 : sal_uIntPtr nPos( 1 );
538 : :
539 : : MetaAction* pCurrAct;
540 [ # # ]: 0 : while( (pCurrAct=rMtf.NextAction()) != NULL )
541 : : {
542 [ # # ]: 0 : if( pCurrAct->GetType() == nType )
543 : : {
544 : 0 : bRet = true; // action type found
545 : 0 : break;
546 : : }
547 : :
548 [ # # # # ]: 0 : if( pCurrAct->GetType() == META_COMMENT_ACTION &&
[ # # ]
549 : 0 : static_cast<MetaCommentAction*>(pCurrAct)->GetComment().equalsIgnoreAsciiCase(
550 : 0 : pCommentString) )
551 : : {
552 : : // delimiting end comment found, done
553 : 0 : bRet = false; // not yet found
554 : 0 : break;
555 : : }
556 : :
557 : 0 : ++nPos;
558 : : }
559 : :
560 : : // rewind metafile to previous position (this method must
561 : : // not change the current metaaction)
562 [ # # ]: 0 : while( nPos-- )
563 : 0 : rMtf.WindPrev();
564 : :
565 [ # # ]: 0 : if( !pCurrAct )
566 : : {
567 : : // EOF, and not yet found
568 : 0 : bRet = false;
569 : : }
570 : :
571 : 0 : return bRet;
572 : : }
573 : :
574 : 0 : void ImplRenderer::createGradientAction( const ::PolyPolygon& rPoly,
575 : : const ::Gradient& rGradient,
576 : : const ActionFactoryParameters& rParms,
577 : : bool bIsPolygonRectangle,
578 : : bool bSubsettableActions )
579 : : {
580 : : DBG_TESTSOLARMUTEX();
581 : :
582 [ # # ]: 0 : ::basegfx::B2DPolyPolygon aDevicePoly( rPoly.getB2DPolyPolygon() );
583 [ # # ][ # # ]: 0 : aDevicePoly.transform( rParms.mrStates.getState().mapModeTransform );
584 : :
585 : : // decide, whether this gradient can be rendered natively
586 : : // by the canvas, or must be emulated via VCL gradient
587 : : // action extraction.
588 : 0 : const sal_uInt16 nSteps( rGradient.GetSteps() );
589 : :
590 [ # # ][ # # ]: 0 : if( // step count is infinite, can use native canvas
591 : : // gradients here
592 : : nSteps == 0 ||
593 : : // step count is sufficiently high, such that no
594 : : // discernible difference should be visible.
595 : : nSteps > 64 )
596 : : {
597 : : uno::Reference< lang::XMultiServiceFactory> xFactory(
598 [ # # ][ # # ]: 0 : rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() );
[ # # ][ # # ]
[ # # ]
599 : :
600 [ # # ]: 0 : if( xFactory.is() )
601 : : {
602 [ # # ]: 0 : rendering::Texture aTexture;
603 : :
604 : 0 : aTexture.RepeatModeX = rendering::TexturingMode::CLAMP;
605 : 0 : aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
606 : 0 : aTexture.Alpha = 1.0;
607 : :
608 : :
609 : : // setup start/end color values
610 : : // ----------------------------
611 : :
612 : : // scale color coefficients with gradient intensities
613 : 0 : const sal_uInt16 nStartIntensity( rGradient.GetStartIntensity() );
614 : 0 : ::Color aVCLStartColor( rGradient.GetStartColor() );
615 [ # # ]: 0 : aVCLStartColor.SetRed( (sal_uInt8)(aVCLStartColor.GetRed() * nStartIntensity / 100) );
616 [ # # ]: 0 : aVCLStartColor.SetGreen( (sal_uInt8)(aVCLStartColor.GetGreen() * nStartIntensity / 100) );
617 [ # # ]: 0 : aVCLStartColor.SetBlue( (sal_uInt8)(aVCLStartColor.GetBlue() * nStartIntensity / 100) );
618 : :
619 : 0 : const sal_uInt16 nEndIntensity( rGradient.GetEndIntensity() );
620 : 0 : ::Color aVCLEndColor( rGradient.GetEndColor() );
621 [ # # ]: 0 : aVCLEndColor.SetRed( (sal_uInt8)(aVCLEndColor.GetRed() * nEndIntensity / 100) );
622 [ # # ]: 0 : aVCLEndColor.SetGreen( (sal_uInt8)(aVCLEndColor.GetGreen() * nEndIntensity / 100) );
623 [ # # ]: 0 : aVCLEndColor.SetBlue( (sal_uInt8)(aVCLEndColor.GetBlue() * nEndIntensity / 100) );
624 : :
625 : : uno::Reference<rendering::XColorSpace> xColorSpace(
626 [ # # ][ # # ]: 0 : rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace());
[ # # ][ # # ]
[ # # ]
627 : : const uno::Sequence< double > aStartColor(
628 : : ::vcl::unotools::colorToDoubleSequence( aVCLStartColor,
629 [ # # ]: 0 : xColorSpace ));
630 : : const uno::Sequence< double > aEndColor(
631 : : ::vcl::unotools::colorToDoubleSequence( aVCLEndColor,
632 [ # # ]: 0 : xColorSpace ));
633 : :
634 [ # # ]: 0 : uno::Sequence< uno::Sequence < double > > aColors(2);
635 [ # # ]: 0 : uno::Sequence< double > aStops(2);
636 : :
637 [ # # ]: 0 : if( rGradient.GetStyle() == GradientStyle_AXIAL )
638 : : {
639 [ # # ]: 0 : aStops.realloc(3);
640 [ # # ]: 0 : aColors.realloc(3);
641 : :
642 [ # # ]: 0 : aStops[0] = 0.0;
643 [ # # ]: 0 : aStops[1] = 0.5;
644 [ # # ]: 0 : aStops[2] = 1.0;
645 : :
646 [ # # ][ # # ]: 0 : aColors[0] = aEndColor;
647 [ # # ][ # # ]: 0 : aColors[1] = aStartColor;
648 [ # # ][ # # ]: 0 : aColors[2] = aEndColor;
649 : : }
650 : : else
651 : : {
652 [ # # ]: 0 : aStops[0] = 0.0;
653 [ # # ]: 0 : aStops[1] = 1.0;
654 : :
655 [ # # ][ # # ]: 0 : aColors[0] = aStartColor;
656 [ # # ][ # # ]: 0 : aColors[1] = aEndColor;
657 : : }
658 : :
659 : : const ::basegfx::B2DRectangle aBounds(
660 [ # # ]: 0 : ::basegfx::tools::getRange(aDevicePoly) );
661 : : const ::basegfx::B2DVector aOffset(
662 : 0 : rGradient.GetOfsX() / 100.0,
663 : 0 : rGradient.GetOfsY() / 100.0);
664 : 0 : double fRotation( rGradient.GetAngle() * M_PI / 1800.0 );
665 : 0 : const double fBorder( rGradient.GetBorder() / 100.0 );
666 : :
667 [ # # ]: 0 : basegfx::B2DHomMatrix aRot90;
668 [ # # ]: 0 : aRot90.rotate(M_PI_2);
669 : :
670 [ # # ]: 0 : basegfx::ODFGradientInfo aGradInfo;
671 : 0 : rtl::OUString aGradientService;
672 [ # # # # : 0 : switch( rGradient.GetStyle() )
# # # ]
673 : : {
674 : : case GradientStyle_LINEAR:
675 : : basegfx::tools::createLinearODFGradientInfo(aGradInfo,
676 : : aBounds,
677 : : nSteps,
678 : : fBorder,
679 [ # # ]: 0 : fRotation);
680 : : // map odf to svg gradient orientation - x
681 : : // instead of y direction
682 [ # # ][ # # ]: 0 : aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aRot90;
[ # # ]
683 : 0 : aGradientService = "LinearGradient";
684 : 0 : break;
685 : :
686 : : case GradientStyle_AXIAL:
687 : : {
688 : : // Adapt the border so that it is suitable
689 : : // for the axial gradient. An axial
690 : : // gradient consists of two linear
691 : : // gradients. Each of those covers half
692 : : // of the total size. In order to
693 : : // compensate for the condensed display of
694 : : // the linear gradients, we have to
695 : : // enlarge the area taken up by the actual
696 : : // gradient (1-fBorder). After that we
697 : : // have to turn the result back into a
698 : : // border value, hence the second (left
699 : : // most 1-...
700 : 0 : const double fAxialBorder (1-2*(1-fBorder));
701 : : basegfx::tools::createAxialODFGradientInfo(aGradInfo,
702 : : aBounds,
703 : : nSteps,
704 : : fAxialBorder,
705 [ # # ]: 0 : fRotation);
706 : : // map odf to svg gradient orientation - x
707 : : // instead of y direction
708 [ # # ][ # # ]: 0 : aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aRot90;
[ # # ]
709 : :
710 : : // map odf axial gradient to 3-stop linear
711 : : // gradient - shift left by 0.5
712 [ # # ]: 0 : basegfx::B2DHomMatrix aShift;
713 [ # # ]: 0 : aShift.translate(-0.5,0);
714 [ # # ][ # # ]: 0 : aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aShift;
[ # # ]
715 : :
716 : 0 : aGradientService = "LinearGradient";
717 [ # # ]: 0 : break;
718 : : }
719 : :
720 : : case GradientStyle_RADIAL:
721 : : basegfx::tools::createRadialODFGradientInfo(aGradInfo,
722 : : aBounds,
723 : : aOffset,
724 : : nSteps,
725 [ # # ]: 0 : fBorder);
726 : 0 : aGradientService = "EllipticalGradient";
727 : 0 : break;
728 : :
729 : : case GradientStyle_ELLIPTICAL:
730 : : basegfx::tools::createEllipticalODFGradientInfo(aGradInfo,
731 : : aBounds,
732 : : aOffset,
733 : : nSteps,
734 : : fBorder,
735 [ # # ]: 0 : fRotation);
736 : 0 : aGradientService = "EllipticalGradient";
737 : 0 : break;
738 : :
739 : : case GradientStyle_SQUARE:
740 : : basegfx::tools::createSquareODFGradientInfo(aGradInfo,
741 : : aBounds,
742 : : aOffset,
743 : : nSteps,
744 : : fBorder,
745 [ # # ]: 0 : fRotation);
746 : 0 : aGradientService = "RectangularGradient";
747 : 0 : break;
748 : :
749 : : case GradientStyle_RECT:
750 : : basegfx::tools::createRectangularODFGradientInfo(aGradInfo,
751 : : aBounds,
752 : : aOffset,
753 : : nSteps,
754 : : fBorder,
755 [ # # ]: 0 : fRotation);
756 : 0 : aGradientService = "RectangularGradient";
757 : 0 : break;
758 : :
759 : : default:
760 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( false,
[ # # ]
761 : : "ImplRenderer::createGradientAction(): Unexpected gradient type" );
762 : : break;
763 : : }
764 : :
765 : : // As the texture coordinate space is relative to
766 : : // the polygon coordinate space (NOT to the
767 : : // polygon itself), move gradient to the start of
768 : : // the actual polygon. If we skip this, the
769 : : // gradient will always display at the origin, and
770 : : // not within the polygon bound (which might be
771 : : // miles away from the origin).
772 : : aGradInfo.maTextureTransform.translate( aBounds.getMinX(),
773 [ # # ][ # # ]: 0 : aBounds.getMinY() );
[ # # ]
774 : : ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform,
775 [ # # ]: 0 : aGradInfo.maTextureTransform );
776 : :
777 [ # # ]: 0 : uno::Sequence<uno::Any> args(3);
778 : 0 : beans::PropertyValue aProp;
779 : 0 : aProp.Name = "Colors";
780 [ # # ]: 0 : aProp.Value <<= aColors;
781 [ # # ][ # # ]: 0 : args[0] <<= aProp;
782 : 0 : aProp.Name = "Stops";
783 [ # # ]: 0 : aProp.Value <<= aStops;
784 [ # # ][ # # ]: 0 : args[1] <<= aProp;
785 : 0 : aProp.Name = "AspectRatio";
786 [ # # ]: 0 : aProp.Value <<= aGradInfo.mfAspectRatio;
787 [ # # ][ # # ]: 0 : args[2] <<= aProp;
788 : :
789 : : aTexture.Gradient.set(
790 [ # # ]: 0 : xFactory->createInstanceWithArguments(aGradientService,
791 : 0 : args),
792 [ # # ][ # # ]: 0 : uno::UNO_QUERY);
793 [ # # ]: 0 : if( aTexture.Gradient.is() )
794 : : {
795 : : ActionSharedPtr pPolyAction(
796 : : internal::PolyPolyActionFactory::createPolyPolyAction(
797 : : aDevicePoly,
798 : : rParms.mrCanvas,
799 [ # # ]: 0 : rParms.mrStates.getState(),
800 [ # # ]: 0 : aTexture ) );
801 : :
802 [ # # ]: 0 : if( pPolyAction )
803 : : {
804 : : maActions.push_back(
805 : : MtfAction(
806 : : pPolyAction,
807 [ # # ][ # # ]: 0 : rParms.mrCurrActionIndex ) );
[ # # ]
808 : :
809 [ # # ]: 0 : rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
810 : : }
811 : :
812 : : // done, using native gradients
813 [ # # ]: 0 : return;
814 [ # # ][ # # ]: 0 : }
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
815 [ # # ]: 0 : }
816 : : }
817 : :
818 : : // cannot currently use native canvas gradients, as a
819 : : // finite step size is given (this funny feature is not
820 : : // supported by the XCanvas API)
821 [ # # ]: 0 : rParms.mrStates.pushState(PUSH_ALL);
822 : :
823 [ # # ]: 0 : if( !bIsPolygonRectangle )
824 : : {
825 : : // only clip, if given polygon is not a rectangle in
826 : : // the first place (the gradient is always limited to
827 : : // the given bound rect)
828 : : updateClipping(
829 : : aDevicePoly,
830 : : rParms,
831 [ # # ]: 0 : true );
832 : : }
833 : :
834 [ # # ]: 0 : GDIMetaFile aTmpMtf;
835 : : rParms.mrVDev.AddGradientActions( rPoly.GetBoundRect(),
836 : : rGradient,
837 [ # # ][ # # ]: 0 : aTmpMtf );
838 : :
839 [ # # ]: 0 : createActions( aTmpMtf, rParms, bSubsettableActions );
840 : :
841 [ # # ][ # # ]: 0 : rParms.mrStates.popState();
[ # # ][ # # ]
842 : : }
843 : :
844 : 0 : uno::Reference< rendering::XCanvasFont > ImplRenderer::createFont( double& o_rFontRotation,
845 : : const ::Font& rFont,
846 : : const ActionFactoryParameters& rParms ) const
847 : : {
848 : 0 : rendering::FontRequest aFontRequest;
849 : :
850 [ # # ]: 0 : if( rParms.mrParms.maFontName.is_initialized() )
851 [ # # ]: 0 : aFontRequest.FontDescription.FamilyName = *rParms.mrParms.maFontName;
852 : : else
853 [ # # ][ # # ]: 0 : aFontRequest.FontDescription.FamilyName = rFont.GetName();
854 : :
855 [ # # ][ # # ]: 0 : aFontRequest.FontDescription.StyleName = rFont.GetStyleName();
856 : :
857 [ # # ][ # # ]: 0 : aFontRequest.FontDescription.IsSymbolFont = (rFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL) ? util::TriState_YES : util::TriState_NO;
858 [ # # ][ # # ]: 0 : aFontRequest.FontDescription.IsVertical = rFont.IsVertical() ? util::TriState_YES : util::TriState_NO;
859 : :
860 : : // TODO(F2): improve vclenum->panose conversion
861 : : aFontRequest.FontDescription.FontDescription.Weight =
862 : 0 : rParms.mrParms.maFontWeight.is_initialized() ?
863 [ # # ]: 0 : *rParms.mrParms.maFontWeight :
864 [ # # ][ # # ]: 0 : ::canvas::tools::numeric_cast<sal_Int8>( ::basegfx::fround( rFont.GetWeight() ) );
[ # # ]
865 : : aFontRequest.FontDescription.FontDescription.Letterform =
866 : 0 : rParms.mrParms.maFontLetterForm.is_initialized() ?
867 [ # # ]: 0 : *rParms.mrParms.maFontLetterForm :
868 [ # # ][ # # ]: 0 : (rFont.GetItalic() == ITALIC_NONE) ? 0 : 9;
[ # # ]
869 : : aFontRequest.FontDescription.FontDescription.Proportion =
870 : 0 : rParms.mrParms.maFontProportion.is_initialized() ?
871 [ # # ]: 0 : *rParms.mrParms.maFontProportion :
872 [ # # ]: 0 : (rFont.GetPitch() == PITCH_FIXED)
873 : : ? rendering::PanoseProportion::MONO_SPACED
874 [ # # ][ # # ]: 0 : : rendering::PanoseProportion::ANYTHING;
875 : :
876 [ # # ]: 0 : LanguageType aLang = rFont.GetLanguage();
877 [ # # ]: 0 : aFontRequest.Locale = MsLangId::convertLanguageToLocale(aLang, false);
878 : :
879 : : // setup state-local text transformation,
880 : : // if the font be rotated
881 [ # # ]: 0 : const short nFontAngle( rFont.GetOrientation() );
882 [ # # ]: 0 : if( nFontAngle != 0 )
883 : : {
884 : : // set to unity transform rotated by font angle
885 : 0 : const double nAngle( nFontAngle * (F_PI / 1800.0) );
886 : 0 : o_rFontRotation = -nAngle;
887 : : }
888 : : else
889 : : {
890 : 0 : o_rFontRotation = 0.0;
891 : : }
892 : :
893 : 0 : geometry::Matrix2D aFontMatrix;
894 [ # # ]: 0 : ::canvas::tools::setIdentityMatrix2D( aFontMatrix );
895 : :
896 : : // TODO(F2): use correct scale direction, font
897 : : // height might be width or anything else
898 : :
899 : : // TODO(Q3): This code smells of programming by
900 : : // coincidence (the next two if statements)
901 [ # # ]: 0 : const ::Size rFontSizeLog( rFont.GetSize() );
902 : 0 : const sal_Int32 nFontWidthLog = rFontSizeLog.Width();
903 [ # # ]: 0 : if( nFontWidthLog != 0 )
904 : : {
905 [ # # ]: 0 : ::Font aTestFont = rFont;
906 [ # # ]: 0 : aTestFont.SetWidth( 0 );
907 [ # # ][ # # ]: 0 : sal_Int32 nNormalWidth = rParms.mrVDev.GetFontMetric( aTestFont ).GetWidth();
[ # # ]
908 [ # # ]: 0 : if( nNormalWidth != nFontWidthLog )
909 [ # # ]: 0 : if( nNormalWidth )
910 [ # # ]: 0 : aFontMatrix.m00 = (double)nFontWidthLog / nNormalWidth;
911 : : }
912 : :
913 : : // #i52608# apply map mode scale also to font matrix - an
914 : : // anisotrophic mapmode must be reflected in an
915 : : // anisotrophic font matrix scale.
916 [ # # ]: 0 : const OutDevState& rState( rParms.mrStates.getState() );
917 [ # # ]: 0 : if( !::basegfx::fTools::equal(
918 [ # # ]: 0 : rState.mapModeTransform.get(0,0),
919 [ # # ]: 0 : rState.mapModeTransform.get(1,1)) )
920 : : {
921 [ # # ]: 0 : const double nScaleX( rState.mapModeTransform.get(0,0) );
922 [ # # ]: 0 : const double nScaleY( rState.mapModeTransform.get(1,1) );
923 : :
924 : : // note: no reason to check for division by zero, we
925 : : // always have the value closer (or equal) to zero as
926 : : // the nominator.
927 [ # # ]: 0 : if( fabs(nScaleX) < fabs(nScaleY) )
928 : 0 : aFontMatrix.m00 *= nScaleX / nScaleY;
929 : : else
930 : 0 : aFontMatrix.m11 *= nScaleY / nScaleX;
931 : : }
932 [ # # ][ # # ]: 0 : aFontRequest.CellSize = (rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize(rFontSizeLog)).getY();
933 : :
934 [ # # ][ # # ]: 0 : return rParms.mrCanvas->getUNOCanvas()->createFont( aFontRequest,
935 : : uno::Sequence< beans::PropertyValue >(),
936 [ # # ][ # # ]: 0 : aFontMatrix );
[ # # ]
937 : : }
938 : :
939 : : // create text effects such as shadow/relief/embossed
940 : 0 : void ImplRenderer::createTextAction( const ::Point& rStartPoint,
941 : : const String rString,
942 : : int nIndex,
943 : : int nLength,
944 : : const sal_Int32* pCharWidths,
945 : : const ActionFactoryParameters& rParms,
946 : : bool bSubsettableActions )
947 : : {
948 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( nIndex >= 0 && nLength <= rString.Len() + nIndex,
[ # # ][ # # ]
[ # # ][ # # ]
949 : : "ImplRenderer::createTextWithEffectsAction(): Invalid text index" );
950 : :
951 [ # # ]: 0 : if( !nLength )
952 : 0 : return; // zero-length text, no visible output
953 : :
954 [ # # ]: 0 : const OutDevState& rState( rParms.mrStates.getState() );
955 : :
956 : : // TODO(F2): implement all text effects
957 : : // if( rState.textAlignment ); // TODO(F2): NYI
958 : :
959 : 0 : ::Color aShadowColor( COL_AUTO );
960 : 0 : ::Color aReliefColor( COL_AUTO );
961 : 0 : ::Size aShadowOffset;
962 : 0 : ::Size aReliefOffset;
963 : :
964 : : uno::Reference<rendering::XColorSpace> xColorSpace(
965 [ # # ][ # # ]: 0 : rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
[ # # ][ # # ]
[ # # ]
966 : :
967 [ # # ]: 0 : if( rState.isTextEffectShadowSet )
968 : : {
969 : : // calculate shadow offset (similar to outdev3.cxx)
970 : : // TODO(F3): better match with outdev3.cxx
971 [ # # ]: 0 : sal_Int32 nShadowOffset = static_cast<sal_Int32>(1.5 + ((rParms.mrVDev.GetFont().GetHeight()-24.0)/24.0));
972 [ # # ]: 0 : if( nShadowOffset < 1 )
973 : 0 : nShadowOffset = 1;
974 : :
975 : 0 : aShadowOffset.setWidth( nShadowOffset );
976 : 0 : aShadowOffset.setHeight( nShadowOffset );
977 : :
978 : : // determine shadow color (from outdev3.cxx)
979 : : ::Color aTextColor = ::vcl::unotools::doubleSequenceToColor(
980 [ # # ][ # # ]: 0 : rState.textColor, xColorSpace );
[ # # ]
981 : 0 : bool bIsDark = (aTextColor.GetColor() == COL_BLACK)
982 [ # # ][ # # ]: 0 : || (aTextColor.GetLuminance() < 8);
[ # # ]
983 : :
984 [ # # ]: 0 : aShadowColor = bIsDark ? COL_LIGHTGRAY : COL_BLACK;
985 [ # # ]: 0 : aShadowColor.SetTransparency( aTextColor.GetTransparency() );
986 : : }
987 : :
988 [ # # ]: 0 : if( rState.textReliefStyle )
989 : : {
990 : : // calculate relief offset (similar to outdev3.cxx)
991 [ # # ]: 0 : sal_Int32 nReliefOffset = rParms.mrVDev.PixelToLogic( Size( 1, 1 ) ).Height();
992 : 0 : nReliefOffset += nReliefOffset/2;
993 [ # # ]: 0 : if( nReliefOffset < 1 )
994 : 0 : nReliefOffset = 1;
995 : :
996 [ # # ]: 0 : if( rState.textReliefStyle == RELIEF_ENGRAVED )
997 : 0 : nReliefOffset = -nReliefOffset;
998 : :
999 : 0 : aReliefOffset.setWidth( nReliefOffset );
1000 : 0 : aReliefOffset.setHeight( nReliefOffset );
1001 : :
1002 : : // determine relief color (from outdev3.cxx)
1003 : : ::Color aTextColor = ::vcl::unotools::doubleSequenceToColor(
1004 [ # # ][ # # ]: 0 : rState.textColor, xColorSpace );
[ # # ]
1005 : :
1006 : 0 : aReliefColor = ::Color( COL_LIGHTGRAY );
1007 : :
1008 : : // we don't have a automatic color, so black is always
1009 : : // drawn on white (literally copied from
1010 : : // vcl/source/gdi/outdev3.cxx)
1011 [ # # ]: 0 : if( aTextColor.GetColor() == COL_BLACK )
1012 : : {
1013 : 0 : aTextColor = ::Color( COL_WHITE );
1014 [ # # ]: 0 : rParms.mrStates.getState().textColor =
1015 : : ::vcl::unotools::colorToDoubleSequence(
1016 [ # # ][ # # ]: 0 : aTextColor, xColorSpace );
[ # # ]
1017 : : }
1018 : :
1019 [ # # ]: 0 : if( aTextColor.GetColor() == COL_WHITE )
1020 : 0 : aReliefColor = ::Color( COL_BLACK );
1021 [ # # ]: 0 : aReliefColor.SetTransparency( aTextColor.GetTransparency() );
1022 : : }
1023 : :
1024 : : // create the actual text action
1025 : : ActionSharedPtr pTextAction(
1026 : : TextActionFactory::createTextAction(
1027 : : rStartPoint,
1028 : : aReliefOffset,
1029 : : aReliefColor,
1030 : : aShadowOffset,
1031 : : aShadowColor,
1032 : : rString,
1033 : : nIndex,
1034 : : nLength,
1035 : : pCharWidths,
1036 : : rParms.mrVDev,
1037 : : rParms.mrCanvas,
1038 : : rState,
1039 : : rParms.mrParms,
1040 [ # # ]: 0 : bSubsettableActions ) );
1041 : :
1042 [ # # ]: 0 : ActionSharedPtr pStrikeoutTextAction;
1043 : :
1044 [ # # ][ # # ]: 0 : if ( rState.textStrikeoutStyle == STRIKEOUT_X || rState.textStrikeoutStyle == STRIKEOUT_SLASH )
1045 : : {
1046 [ # # ]: 0 : long nWidth = rParms.mrVDev.GetTextWidth( rString,nIndex,nLength );
1047 : :
1048 : : xub_Unicode pChars[4];
1049 [ # # ]: 0 : if ( rState.textStrikeoutStyle == STRIKEOUT_X )
1050 : 0 : pChars[0] = 'X';
1051 : : else
1052 : 0 : pChars[0] = '/';
1053 : 0 : pChars[3]=pChars[2]=pChars[1]=pChars[0];
1054 : :
1055 : : long nStrikeoutWidth = (rParms.mrVDev.GetTextWidth(
1056 [ # # ][ # # ]: 0 : rtl::OUString(pChars, SAL_N_ELEMENTS(pChars))) + 2) / 4;
[ # # ]
1057 : :
1058 [ # # ]: 0 : if( nStrikeoutWidth <= 0 )
1059 : 0 : nStrikeoutWidth = 1;
1060 : :
1061 : 0 : long nMaxWidth = nStrikeoutWidth/2;
1062 [ # # ]: 0 : if ( nMaxWidth < 2 )
1063 : 0 : nMaxWidth = 2;
1064 : 0 : nMaxWidth += nWidth + 1;
1065 : :
1066 : 0 : long nFullStrikeoutWidth = 0;
1067 [ # # ]: 0 : String aStrikeoutText;
1068 [ # # ]: 0 : while( (nFullStrikeoutWidth+=nStrikeoutWidth ) < nMaxWidth+1 )
1069 [ # # ]: 0 : aStrikeoutText += pChars[0];
1070 : :
1071 : 0 : xub_StrLen nLen = aStrikeoutText.Len();
1072 : :
1073 [ # # ]: 0 : if( nLen )
1074 : : {
1075 : 0 : long nInterval = ( nWidth - nStrikeoutWidth * nLen ) / nLen;
1076 : 0 : nStrikeoutWidth += nInterval;
1077 [ # # ]: 0 : sal_Int32* pStrikeoutCharWidths = new sal_Int32[nLen];
1078 : :
1079 [ # # ]: 0 : for ( int i = 0;i<nLen; i++)
1080 : : {
1081 : 0 : pStrikeoutCharWidths[i] = nStrikeoutWidth;
1082 : : }
1083 : :
1084 [ # # ]: 0 : for ( int i = 1;i< nLen; i++ )
1085 : : {
1086 : 0 : pStrikeoutCharWidths[ i ] += pStrikeoutCharWidths[ i-1 ];
1087 : : }
1088 : :
1089 : 0 : sal_Int32 nStartPos = 0;
1090 : :
1091 : : pStrikeoutTextAction =
1092 : : TextActionFactory::createTextAction(
1093 : : rStartPoint,
1094 : : aReliefOffset,
1095 : : aReliefColor,
1096 : : aShadowOffset,
1097 : : aShadowColor,
1098 : : aStrikeoutText,
1099 : : nStartPos,
1100 : 0 : aStrikeoutText.Len(),
1101 : : pStrikeoutCharWidths,
1102 : : rParms.mrVDev,
1103 : : rParms.mrCanvas,
1104 : : rState,
1105 : : rParms.mrParms,
1106 [ # # ][ # # ]: 0 : bSubsettableActions ) ;
[ # # ]
1107 [ # # ]: 0 : }
1108 : : }
1109 : :
1110 [ # # ]: 0 : if( pTextAction )
1111 : : {
1112 : : maActions.push_back(
1113 : : MtfAction(
1114 : : pTextAction,
1115 [ # # ][ # # ]: 0 : rParms.mrCurrActionIndex ) );
[ # # ]
1116 : :
1117 [ # # ]: 0 : if ( pStrikeoutTextAction )
1118 : : {
1119 : : maActions.push_back(
1120 : : MtfAction(
1121 : : pStrikeoutTextAction,
1122 [ # # ][ # # ]: 0 : rParms.mrCurrActionIndex ) );
[ # # ]
1123 : : }
1124 : :
1125 [ # # ]: 0 : rParms.mrCurrActionIndex += pTextAction->getActionCount()-1;
1126 [ # # ][ # # ]: 0 : }
1127 : : }
1128 : :
1129 : 0 : void ImplRenderer::updateClipping( const ::basegfx::B2DPolyPolygon& rClipPoly,
1130 : : const ActionFactoryParameters& rParms,
1131 : : bool bIntersect )
1132 : : {
1133 [ # # ]: 0 : ::cppcanvas::internal::OutDevState& rState( rParms.mrStates.getState() );
1134 [ # # ]: 0 : ::basegfx::B2DPolyPolygon aClipPoly( rClipPoly );
1135 : :
1136 [ # # ]: 0 : const bool bEmptyClipRect( rState.clipRect.IsEmpty() );
1137 [ # # ]: 0 : const bool bEmptyClipPoly( rState.clip.count() == 0 );
1138 : :
1139 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( bEmptyClipPoly || bEmptyClipRect,
[ # # ][ # # ]
[ # # ]
1140 : : "ImplRenderer::updateClipping(): Clip rect and polygon are both set!" );
1141 : :
1142 [ # # ][ # # ]: 0 : if( !bIntersect ||
[ # # ]
1143 : : (bEmptyClipRect && bEmptyClipPoly) )
1144 : : {
1145 [ # # ]: 0 : rState.clip = rClipPoly;
1146 : : }
1147 : : else
1148 : : {
1149 [ # # ]: 0 : if( !bEmptyClipRect )
1150 : : {
1151 : : // TODO(P3): Use Liang-Barsky polygon clip here,
1152 : : // after all, one object is just a rectangle!
1153 : :
1154 : : // convert rect to polygon beforehand, must revert
1155 : : // to general polygon clipping here.
1156 : : rState.clip = ::basegfx::B2DPolyPolygon(
1157 : : ::basegfx::tools::createPolygonFromRect(
1158 : : // #121100# VCL rectangular clips always
1159 : : // include one more pixel to the right
1160 : : // and the bottom
1161 : 0 : ::basegfx::B2DRectangle( rState.clipRect.Left(),
1162 : 0 : rState.clipRect.Top(),
1163 : 0 : rState.clipRect.Right()+1,
1164 [ # # ][ # # ]: 0 : rState.clipRect.Bottom()+1 ) ) );
[ # # ][ # # ]
[ # # ][ # # ]
1165 : : }
1166 : :
1167 : : // AW: Simplified
1168 : : rState.clip = basegfx::tools::clipPolyPolygonOnPolyPolygon(
1169 [ # # ][ # # ]: 0 : aClipPoly, rState.clip, true, false);
[ # # ]
1170 : : }
1171 : :
1172 : : // by now, our clip resides in the OutDevState::clip
1173 : : // poly-polygon.
1174 : 0 : rState.clipRect.SetEmpty();
1175 : :
1176 [ # # ][ # # ]: 0 : if( rState.clip.count() == 0 )
1177 : : {
1178 [ # # ][ # # ]: 0 : if( rState.clipRect.IsEmpty() )
1179 : : {
1180 : 0 : rState.xClipPoly.clear();
1181 : : }
1182 : : else
1183 : : {
1184 : : rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1185 [ # # ][ # # ]: 0 : rParms.mrCanvas->getUNOCanvas()->getDevice(),
1186 : : ::basegfx::B2DPolyPolygon(
1187 : : ::basegfx::tools::createPolygonFromRect(
1188 : : // #121100# VCL rectangular clips
1189 : : // always include one more pixel to
1190 : : // the right and the bottom
1191 : 0 : ::basegfx::B2DRectangle( rState.clipRect.Left(),
1192 : 0 : rState.clipRect.Top(),
1193 : 0 : rState.clipRect.Right()+1,
1194 [ # # ][ # # ]: 0 : rState.clipRect.Bottom()+1 ) ) ) );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1195 : : }
1196 : : }
1197 : : else
1198 : : {
1199 : : rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1200 [ # # ][ # # ]: 0 : rParms.mrCanvas->getUNOCanvas()->getDevice(),
1201 [ # # ][ # # ]: 0 : rState.clip );
[ # # ]
1202 [ # # ]: 0 : }
1203 : 0 : }
1204 : :
1205 : 0 : void ImplRenderer::updateClipping( const ::Rectangle& rClipRect,
1206 : : const ActionFactoryParameters& rParms,
1207 : : bool bIntersect )
1208 : : {
1209 : 0 : ::cppcanvas::internal::OutDevState& rState( rParms.mrStates.getState() );
1210 : :
1211 : 0 : const bool bEmptyClipRect( rState.clipRect.IsEmpty() );
1212 : 0 : const bool bEmptyClipPoly( rState.clip.count() == 0 );
1213 : :
1214 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( bEmptyClipPoly || bEmptyClipRect,
[ # # ][ # # ]
[ # # ]
1215 : : "ImplRenderer::updateClipping(): Clip rect and polygon are both set!" );
1216 : :
1217 [ # # ][ # # ]: 0 : if( !bIntersect ||
[ # # ]
1218 : : (bEmptyClipRect && bEmptyClipPoly) )
1219 : : {
1220 : 0 : rState.clipRect = rClipRect;
1221 : 0 : rState.clip.clear();
1222 : : }
1223 [ # # ]: 0 : else if( bEmptyClipPoly )
1224 : : {
1225 : 0 : rState.clipRect.Intersection( rClipRect );
1226 : 0 : rState.clip.clear();
1227 : : }
1228 : : else
1229 : : {
1230 : : // TODO(P3): Handle a fourth case here, when all clip
1231 : : // polygons are rectangular, once B2DMultiRange's
1232 : : // sweep line implementation is done.
1233 : :
1234 : : // general case: convert to polygon and clip
1235 : : // -----------------------------------------
1236 : :
1237 : : // convert rect to polygon beforehand, must revert
1238 : : // to general polygon clipping here.
1239 : : ::basegfx::B2DPolyPolygon aClipPoly(
1240 : : ::basegfx::tools::createPolygonFromRect(
1241 : 0 : ::basegfx::B2DRectangle( rClipRect.Left(),
1242 : 0 : rClipRect.Top(),
1243 : 0 : rClipRect.Right(),
1244 [ # # ][ # # ]: 0 : rClipRect.Bottom() ) ) );
[ # # ][ # # ]
1245 : :
1246 : 0 : rState.clipRect.SetEmpty();
1247 : :
1248 : : // AW: Simplified
1249 : : rState.clip = basegfx::tools::clipPolyPolygonOnPolyPolygon(
1250 [ # # ][ # # ]: 0 : aClipPoly, rState.clip, true, false);
[ # # ][ # # ]
1251 : : }
1252 : :
1253 [ # # ]: 0 : if( rState.clip.count() == 0 )
1254 : : {
1255 [ # # ]: 0 : if( rState.clipRect.IsEmpty() )
1256 : : {
1257 : 0 : rState.xClipPoly.clear();
1258 : : }
1259 : : else
1260 : : {
1261 : : rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1262 [ # # ][ # # ]: 0 : rParms.mrCanvas->getUNOCanvas()->getDevice(),
1263 : : ::basegfx::B2DPolyPolygon(
1264 : : ::basegfx::tools::createPolygonFromRect(
1265 : : // #121100# VCL rectangular clips
1266 : : // always include one more pixel to
1267 : : // the right and the bottom
1268 : 0 : ::basegfx::B2DRectangle( rState.clipRect.Left(),
1269 : 0 : rState.clipRect.Top(),
1270 : 0 : rState.clipRect.Right()+1,
1271 [ # # ][ # # ]: 0 : rState.clipRect.Bottom()+1 ) ) ) );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1272 : : }
1273 : : }
1274 : : else
1275 : : {
1276 : : rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1277 [ # # ]: 0 : rParms.mrCanvas->getUNOCanvas()->getDevice(),
1278 [ # # ][ # # ]: 0 : rState.clip );
[ # # ]
1279 : : }
1280 : 0 : }
1281 : :
1282 : 0 : bool ImplRenderer::createActions( GDIMetaFile& rMtf,
1283 : : const ActionFactoryParameters& rFactoryParms,
1284 : : bool bSubsettableActions )
1285 : : {
1286 : : /* TODO(P2): interpret mtf-comments
1287 : : ================================
1288 : :
1289 : : - gradient fillings (do that via comments)
1290 : :
1291 : : - think about mapping. _If_ we do everything in logical
1292 : : coordinates (which would solve the probs for stroke
1293 : : widths and text offsets), then we would have to
1294 : : recalc scaling for every drawing operation. This is
1295 : : because the outdev map mode might change at any time.
1296 : : Also keep in mind, that, although we've double precision
1297 : : float arithmetic now, different offsets might still
1298 : : generate different roundings (aka
1299 : : 'OutputDevice::SetPixelOffset())
1300 : :
1301 : : */
1302 : :
1303 : : // alias common parameters
1304 : 0 : VectorOfOutDevStates& rStates(rFactoryParms.mrStates);
1305 : 0 : const CanvasSharedPtr& rCanvas(rFactoryParms.mrCanvas);
1306 : 0 : ::VirtualDevice& rVDev(rFactoryParms.mrVDev);
1307 : 0 : const Parameters& rParms(rFactoryParms.mrParms);
1308 : 0 : sal_Int32& io_rCurrActionIndex(rFactoryParms.mrCurrActionIndex);
1309 : :
1310 : :
1311 : : // Loop over every metaaction
1312 : : // ==========================
1313 : : MetaAction* pCurrAct;
1314 : :
1315 : : // TODO(P1): think about caching
1316 [ # # ]: 0 : for( pCurrAct=rMtf.FirstAction();
1317 : : pCurrAct;
1318 : : pCurrAct = rMtf.NextAction() )
1319 : : {
1320 : : // execute every action, to keep VDev state up-to-date
1321 : : // currently used only for
1322 : : // - the map mode
1323 : : // - the line/fill color when processing a META_TRANSPARENT_ACTION
1324 : : // - SetFont to process font metric specific actions
1325 : 0 : pCurrAct->Execute( &rVDev );
1326 : :
1327 : : EMFP_DEBUG(printf("MTF\trecord type: 0x%x (%d)\n", pCurrAct->GetType(), pCurrAct->GetType()));
1328 : :
1329 [ # # # # : 0 : switch( pCurrAct->GetType() )
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
1330 : : {
1331 : : // ------------------------------------------------------------
1332 : :
1333 : : // In the first part of this monster-switch, we
1334 : : // handle all state-changing meta actions. These
1335 : : // are all handled locally.
1336 : :
1337 : : // ------------------------------------------------------------
1338 : :
1339 : : case META_PUSH_ACTION:
1340 : : {
1341 : 0 : MetaPushAction* pPushAction = static_cast<MetaPushAction*>(pCurrAct);
1342 : 0 : rStates.pushState(pPushAction->GetFlags());
1343 : : }
1344 : 0 : break;
1345 : :
1346 : : case META_POP_ACTION:
1347 : 0 : rStates.popState();
1348 : 0 : break;
1349 : :
1350 : : case META_TEXTLANGUAGE_ACTION:
1351 : : // FALLTHROUGH intended
1352 : : case META_REFPOINT_ACTION:
1353 : : // handled via pCurrAct->Execute( &rVDev )
1354 : 0 : break;
1355 : :
1356 : : case META_MAPMODE_ACTION:
1357 : : // modify current mapModeTransformation
1358 : : // transformation, such that subsequent
1359 : : // coordinates map correctly
1360 : 0 : tools::calcLogic2PixelAffineTransform( rStates.getState().mapModeTransform,
1361 : 0 : rVDev );
1362 : 0 : break;
1363 : :
1364 : : // monitor clip regions, to assemble clip polygon on our own
1365 : : case META_CLIPREGION_ACTION:
1366 : : {
1367 : 0 : MetaClipRegionAction* pClipAction = static_cast<MetaClipRegionAction*>(pCurrAct);
1368 : :
1369 [ # # ]: 0 : if( !pClipAction->IsClipping() )
1370 : : {
1371 : : // clear clipping
1372 : 0 : rStates.getState().clip.clear();
1373 : : }
1374 : : else
1375 : : {
1376 [ # # ]: 0 : if( !pClipAction->GetRegion().HasPolyPolygon() )
1377 : : {
1378 : : VERBOSE_TRACE( "ImplRenderer::createActions(): non-polygonal clip "
1379 : : "region encountered, falling back to bounding box!" );
1380 : :
1381 : : // #121806# explicitly kept integer
1382 : : Rectangle aClipRect(
1383 : : rVDev.LogicToPixel(
1384 [ # # ][ # # ]: 0 : pClipAction->GetRegion().GetBoundRect() ) );
1385 : :
1386 : : // intersect current clip with given rect
1387 : : updateClipping(
1388 : : aClipRect,
1389 : : rFactoryParms,
1390 [ # # ]: 0 : false );
1391 : : }
1392 : : else
1393 : : {
1394 : : // set new clip polygon (don't intersect
1395 : : // with old one, just set it)
1396 : :
1397 : : // #121806# explicitly kept integer
1398 : : updateClipping(
1399 : : rVDev.LogicToPixel(
1400 : 0 : pClipAction->GetRegion().GetPolyPolygon() ).getB2DPolyPolygon(),
1401 : : rFactoryParms,
1402 [ # # ][ # # ]: 0 : false );
[ # # ][ # # ]
[ # # ]
1403 : : }
1404 : : }
1405 : :
1406 : 0 : break;
1407 : : }
1408 : :
1409 : : case META_ISECTRECTCLIPREGION_ACTION:
1410 : : {
1411 : 0 : MetaISectRectClipRegionAction* pClipAction = static_cast<MetaISectRectClipRegionAction*>(pCurrAct);
1412 : :
1413 : : // #121806# explicitly kept integer
1414 : : Rectangle aClipRect(
1415 [ # # ]: 0 : rVDev.LogicToPixel( pClipAction->GetRect() ) );
1416 : :
1417 : : // intersect current clip with given rect
1418 : : updateClipping(
1419 : : aClipRect,
1420 : : rFactoryParms,
1421 [ # # ]: 0 : true );
1422 : :
1423 : : break;
1424 : : }
1425 : :
1426 : : case META_ISECTREGIONCLIPREGION_ACTION:
1427 : : {
1428 : 0 : MetaISectRegionClipRegionAction* pClipAction = static_cast<MetaISectRegionClipRegionAction*>(pCurrAct);
1429 : :
1430 [ # # ]: 0 : if( !pClipAction->GetRegion().HasPolyPolygon() )
1431 : : {
1432 : : VERBOSE_TRACE( "ImplRenderer::createActions(): non-polygonal clip "
1433 : : "region encountered, falling back to bounding box!" );
1434 : :
1435 : : // #121806# explicitly kept integer
1436 : : Rectangle aClipRect(
1437 [ # # ][ # # ]: 0 : rVDev.LogicToPixel( pClipAction->GetRegion().GetBoundRect() ) );
1438 : :
1439 : : // intersect current clip with given rect
1440 : : updateClipping(
1441 : : aClipRect,
1442 : : rFactoryParms,
1443 [ # # ]: 0 : true );
1444 : : }
1445 : : else
1446 : : {
1447 : : // intersect current clip with given clip polygon
1448 : :
1449 : : // #121806# explicitly kept integer
1450 : : updateClipping(
1451 : : rVDev.LogicToPixel(
1452 : 0 : pClipAction->GetRegion().GetPolyPolygon() ).getB2DPolyPolygon(),
1453 : : rFactoryParms,
1454 [ # # ][ # # ]: 0 : true );
[ # # ][ # # ]
[ # # ]
1455 : : }
1456 : :
1457 : 0 : break;
1458 : : }
1459 : :
1460 : : case META_MOVECLIPREGION_ACTION:
1461 : : // TODO(F2): NYI
1462 : 0 : break;
1463 : :
1464 : : case META_LINECOLOR_ACTION:
1465 [ # # ]: 0 : if( !rParms.maLineColor.is_initialized() )
1466 : : {
1467 : : setStateColor( static_cast<MetaLineColorAction*>(pCurrAct),
1468 : 0 : rStates.getState().isLineColorSet,
1469 : 0 : rStates.getState().lineColor,
1470 : 0 : rCanvas );
1471 : : }
1472 : 0 : break;
1473 : :
1474 : : case META_FILLCOLOR_ACTION:
1475 [ # # ]: 0 : if( !rParms.maFillColor.is_initialized() )
1476 : : {
1477 : : setStateColor( static_cast<MetaFillColorAction*>(pCurrAct),
1478 : 0 : rStates.getState().isFillColorSet,
1479 : 0 : rStates.getState().fillColor,
1480 : 0 : rCanvas );
1481 : : }
1482 : 0 : break;
1483 : :
1484 : : case META_TEXTCOLOR_ACTION:
1485 : : {
1486 [ # # ]: 0 : if( !rParms.maTextColor.is_initialized() )
1487 : : {
1488 : : // Text color is set unconditionally, thus, no
1489 : : // use of setStateColor here
1490 : 0 : ::Color aColor( static_cast<MetaTextColorAction*>(pCurrAct)->GetColor() );
1491 : :
1492 : : // force alpha part of color to
1493 : : // opaque. transparent painting is done
1494 : : // explicitly via META_TRANSPARENT_ACTION
1495 [ # # ]: 0 : aColor.SetTransparency(0);
1496 : :
1497 [ # # ]: 0 : rStates.getState().textColor =
1498 : : ::vcl::unotools::colorToDoubleSequence(
1499 : : aColor,
1500 [ # # ][ # # ]: 0 : rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1501 : : }
1502 : : }
1503 : 0 : break;
1504 : :
1505 : : case META_TEXTFILLCOLOR_ACTION:
1506 [ # # ]: 0 : if( !rParms.maTextColor.is_initialized() )
1507 : : {
1508 : : setStateColor( static_cast<MetaTextFillColorAction*>(pCurrAct),
1509 : 0 : rStates.getState().isTextFillColorSet,
1510 : 0 : rStates.getState().textFillColor,
1511 : 0 : rCanvas );
1512 : : }
1513 : 0 : break;
1514 : :
1515 : : case META_TEXTLINECOLOR_ACTION:
1516 [ # # ]: 0 : if( !rParms.maTextColor.is_initialized() )
1517 : : {
1518 : : setStateColor( static_cast<MetaTextLineColorAction*>(pCurrAct),
1519 : 0 : rStates.getState().isTextLineColorSet,
1520 : 0 : rStates.getState().textLineColor,
1521 : 0 : rCanvas );
1522 : : }
1523 : 0 : break;
1524 : :
1525 : : case META_TEXTALIGN_ACTION:
1526 : : {
1527 : 0 : ::cppcanvas::internal::OutDevState& rState = rStates.getState();
1528 : 0 : const TextAlign eTextAlign( static_cast<MetaTextAlignAction*>(pCurrAct)->GetTextAlign() );
1529 : :
1530 : 0 : rState.textReferencePoint = eTextAlign;
1531 : : }
1532 : 0 : break;
1533 : :
1534 : : case META_FONT_ACTION:
1535 : : {
1536 : 0 : ::cppcanvas::internal::OutDevState& rState = rStates.getState();
1537 : 0 : const ::Font& rFont( static_cast<MetaFontAction*>(pCurrAct)->GetFont() );
1538 : :
1539 : : rState.xFont = createFont( rState.fontRotation,
1540 : : rFont,
1541 [ # # ]: 0 : rFactoryParms );
1542 : :
1543 : : // TODO(Q2): define and use appropriate enumeration types
1544 : 0 : rState.textReliefStyle = (sal_Int8)rFont.GetRelief();
1545 : 0 : rState.textOverlineStyle = (sal_Int8)rFont.GetOverline();
1546 : 0 : rState.textUnderlineStyle = rParms.maFontUnderline.is_initialized() ?
1547 : 0 : (*rParms.maFontUnderline ? (sal_Int8)UNDERLINE_SINGLE : (sal_Int8)UNDERLINE_NONE) :
1548 [ # # # # ]: 0 : (sal_Int8)rFont.GetUnderline();
1549 : 0 : rState.textStrikeoutStyle = (sal_Int8)rFont.GetStrikeout();
1550 : 0 : rState.textEmphasisMarkStyle = (sal_Int8)rFont.GetEmphasisMark();
1551 : 0 : rState.isTextEffectShadowSet = (rFont.IsShadow() != sal_False);
1552 : 0 : rState.isTextWordUnderlineSet = (rFont.IsWordLineMode() != sal_False);
1553 : 0 : rState.isTextOutlineModeSet = (rFont.IsOutline() != sal_False);
1554 : : }
1555 : 0 : break;
1556 : :
1557 : : case META_RASTEROP_ACTION:
1558 : : // TODO(F2): NYI
1559 : 0 : break;
1560 : :
1561 : : case META_LAYOUTMODE_ACTION:
1562 : : {
1563 : : // TODO(F2): A lot is missing here
1564 : 0 : int nLayoutMode = static_cast<MetaLayoutModeAction*>(pCurrAct)->GetLayoutMode();
1565 : 0 : ::cppcanvas::internal::OutDevState& rState = rStates.getState();
1566 [ # # # # : 0 : switch( nLayoutMode & (TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_BIDI_STRONG) )
# ]
1567 : : {
1568 : : case TEXT_LAYOUT_BIDI_LTR:
1569 : 0 : rState.textDirection = rendering::TextDirection::WEAK_LEFT_TO_RIGHT;
1570 : 0 : break;
1571 : :
1572 : : case (TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG):
1573 : 0 : rState.textDirection = rendering::TextDirection::STRONG_LEFT_TO_RIGHT;
1574 : 0 : break;
1575 : :
1576 : : case TEXT_LAYOUT_BIDI_RTL:
1577 : 0 : rState.textDirection = rendering::TextDirection::WEAK_RIGHT_TO_LEFT;
1578 : 0 : break;
1579 : :
1580 : : case (TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG):
1581 : 0 : rState.textDirection = rendering::TextDirection::STRONG_RIGHT_TO_LEFT;
1582 : 0 : break;
1583 : : }
1584 : :
1585 : 0 : rState.textAlignment = 0; // TODO(F2): rendering::TextAlignment::LEFT_ALIGNED;
1586 [ # # ][ # # ]: 0 : if( (nLayoutMode & (TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_RIGHT) )
1587 : 0 : && !(nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT ) )
1588 : : {
1589 : 0 : rState.textAlignment = 1; // TODO(F2): rendering::TextAlignment::RIGHT_ALIGNED;
1590 : : }
1591 : : }
1592 : 0 : break;
1593 : :
1594 : : // ------------------------------------------------------------
1595 : :
1596 : : // In the second part of this monster-switch, we
1597 : : // handle all recursing meta actions. These are the
1598 : : // ones generating a metafile by themselves, which is
1599 : : // then processed by recursively calling this method.
1600 : :
1601 : : // ------------------------------------------------------------
1602 : :
1603 : : case META_GRADIENT_ACTION:
1604 : : {
1605 : 0 : MetaGradientAction* pGradAct = static_cast<MetaGradientAction*>(pCurrAct);
1606 : 0 : createGradientAction( ::Polygon( pGradAct->GetRect() ),
1607 : 0 : pGradAct->GetGradient(),
1608 : : rFactoryParms,
1609 : : true,
1610 [ # # ][ # # ]: 0 : bSubsettableActions );
[ # # ]
1611 : : }
1612 : 0 : break;
1613 : :
1614 : : case META_HATCH_ACTION:
1615 : : {
1616 : : // TODO(F2): use native Canvas hatches here
1617 [ # # ]: 0 : GDIMetaFile aTmpMtf;
1618 : :
1619 : 0 : rVDev.AddHatchActions( static_cast<MetaHatchAction*>(pCurrAct)->GetPolyPolygon(),
1620 : 0 : static_cast<MetaHatchAction*>(pCurrAct)->GetHatch(),
1621 [ # # ]: 0 : aTmpMtf );
1622 : : createActions( aTmpMtf, rFactoryParms,
1623 [ # # ][ # # ]: 0 : bSubsettableActions );
1624 : : }
1625 : 0 : break;
1626 : :
1627 : : case META_EPS_ACTION:
1628 : : {
1629 : 0 : MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pCurrAct);
1630 : 0 : const GDIMetaFile& rSubstitute = pAct->GetSubstitute();
1631 : :
1632 : : // #121806# explicitly kept integer
1633 : 0 : const Size aMtfSize( rSubstitute.GetPrefSize() );
1634 : : const Size aMtfSizePixPre( rVDev.LogicToPixel( aMtfSize,
1635 [ # # ]: 0 : rSubstitute.GetPrefMapMode() ) );
1636 : :
1637 : : // #i44110# correct null-sized output - there
1638 : : // are metafiles which have zero size in at
1639 : : // least one dimension
1640 [ # # ]: 0 : const Size aMtfSizePix( ::std::max( aMtfSizePixPre.Width(), 1L ),
1641 [ # # ]: 0 : ::std::max( aMtfSizePixPre.Height(), 1L ) );
1642 : :
1643 : : // Setup local transform, such that the
1644 : : // metafile renders itself into the given
1645 : : // output rectangle
1646 [ # # ]: 0 : rStates.pushState(PUSH_ALL);
1647 : :
1648 [ # # ]: 0 : rVDev.Push();
1649 [ # # ]: 0 : rVDev.SetMapMode( rSubstitute.GetPrefMapMode() );
1650 : :
1651 [ # # ]: 0 : const ::Point& rPos( rVDev.LogicToPixel( pAct->GetPoint() ) );
1652 [ # # ]: 0 : const ::Size& rSize( rVDev.LogicToPixel( pAct->GetSize() ) );
1653 : :
1654 [ # # ]: 0 : rStates.getState().transform.translate( rPos.X(),
1655 [ # # ]: 0 : rPos.Y() );
1656 [ # # ]: 0 : rStates.getState().transform.scale( (double)rSize.Width() / aMtfSizePix.Width(),
1657 [ # # ]: 0 : (double)rSize.Height() / aMtfSizePix.Height() );
1658 : :
1659 : 0 : createActions( const_cast<GDIMetaFile&>(pAct->GetSubstitute()),
1660 : : rFactoryParms,
1661 [ # # ]: 0 : bSubsettableActions );
1662 : :
1663 [ # # ]: 0 : rVDev.Pop();
1664 [ # # ]: 0 : rStates.popState();
1665 : : }
1666 : 0 : break;
1667 : :
1668 : : // handle metafile comments, to retrieve
1669 : : // meta-information for gradients, fills and
1670 : : // strokes. May skip actions, and may recurse.
1671 : : case META_COMMENT_ACTION:
1672 : : {
1673 : 0 : MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pCurrAct);
1674 : :
1675 : : // Handle gradients
1676 [ # # ]: 0 : if (pAct->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XGRAD_SEQ_BEGIN")))
1677 : : {
1678 : 0 : MetaGradientExAction* pGradAction = NULL;
1679 : 0 : bool bDone( false );
1680 [ # # ][ # # ]: 0 : while( !bDone &&
[ # # ]
1681 : : (pCurrAct=rMtf.NextAction()) != NULL )
1682 : : {
1683 [ # # # ]: 0 : switch( pCurrAct->GetType() )
1684 : : {
1685 : : // extract gradient info
1686 : : case META_GRADIENTEX_ACTION:
1687 : 0 : pGradAction = static_cast<MetaGradientExAction*>(pCurrAct);
1688 : 0 : break;
1689 : :
1690 : : // skip broken-down rendering, output gradient when sequence is ended
1691 : : case META_COMMENT_ACTION:
1692 [ # # ]: 0 : if( static_cast<MetaCommentAction*>(pCurrAct)->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XGRAD_SEQ_END")) )
1693 : : {
1694 : 0 : bDone = true;
1695 : :
1696 [ # # ]: 0 : if( pGradAction )
1697 : : {
1698 : 0 : createGradientAction( pGradAction->GetPolyPolygon(),
1699 : 0 : pGradAction->GetGradient(),
1700 : : rFactoryParms,
1701 : : false,
1702 : 0 : bSubsettableActions );
1703 : : }
1704 : : }
1705 : 0 : break;
1706 : : }
1707 : : }
1708 : : }
1709 : : // TODO(P2): Handle drawing layer strokes, via
1710 : : // XPATHSTROKE_SEQ_BEGIN comment
1711 : :
1712 : : // Handle drawing layer fills
1713 [ # # ]: 0 : else if( pAct->GetComment().equalsL(RTL_CONSTASCII_STRINGPARAM("XPATHFILL_SEQ_BEGIN")) )
1714 : : {
1715 : 0 : const sal_uInt8* pData = pAct->GetData();
1716 [ # # ]: 0 : if ( pData )
1717 : : {
1718 [ # # ]: 0 : SvMemoryStream aMemStm( (void*)pData, pAct->GetDataSize(), STREAM_READ );
1719 : :
1720 [ # # ]: 0 : SvtGraphicFill aFill;
1721 [ # # ]: 0 : aMemStm >> aFill;
1722 : :
1723 : : // TODO(P2): Also handle gradients and
1724 : : // hatches like this
1725 : :
1726 : : // only evaluate comment for pure
1727 : : // bitmap fills. If a transparency
1728 : : // gradient is involved (denoted by
1729 : : // the FloatTransparent action), take
1730 : : // the normal meta actions.
1731 [ # # ][ # # ]: 0 : if( aFill.getFillType() == SvtGraphicFill::fillTexture &&
[ # # ][ # # ]
1732 : : !isActionContained( rMtf,
1733 : : "XPATHFILL_SEQ_END",
1734 [ # # ]: 0 : META_FLOATTRANSPARENT_ACTION ) )
1735 : : {
1736 [ # # ]: 0 : rendering::Texture aTexture;
1737 : :
1738 : : // TODO(F1): the SvtGraphicFill
1739 : : // can also transport metafiles
1740 : : // here, handle that case, too
1741 [ # # ]: 0 : Graphic aGraphic;
1742 [ # # ]: 0 : aFill.getGraphic( aGraphic );
1743 : :
1744 [ # # ]: 0 : BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
1745 : 0 : const ::Size aBmpSize( aBmpEx.GetSizePixel() );
1746 : :
1747 [ # # ]: 0 : ::SvtGraphicFill::Transform aTransform;
1748 [ # # ]: 0 : aFill.getTransform( aTransform );
1749 : :
1750 [ # # ]: 0 : ::basegfx::B2DHomMatrix aMatrix;
1751 : :
1752 : : // convert to basegfx matrix
1753 [ # # ]: 0 : aMatrix.set(0,0, aTransform.matrix[ 0 ] );
1754 [ # # ]: 0 : aMatrix.set(0,1, aTransform.matrix[ 1 ] );
1755 [ # # ]: 0 : aMatrix.set(0,2, aTransform.matrix[ 2 ] );
1756 [ # # ]: 0 : aMatrix.set(1,0, aTransform.matrix[ 3 ] );
1757 [ # # ]: 0 : aMatrix.set(1,1, aTransform.matrix[ 4 ] );
1758 [ # # ]: 0 : aMatrix.set(1,2, aTransform.matrix[ 5 ] );
1759 : :
1760 [ # # ]: 0 : ::basegfx::B2DHomMatrix aScale;
1761 : 0 : aScale.scale( aBmpSize.Width(),
1762 [ # # ]: 0 : aBmpSize.Height() );
1763 : :
1764 : : // post-multiply with the bitmap
1765 : : // size (XCanvas' texture assumes
1766 : : // the given bitmap to be
1767 : : // normalized to [0,1]x[0,1]
1768 : : // rectangle)
1769 [ # # ][ # # ]: 0 : aMatrix = aMatrix * aScale;
[ # # ]
1770 : :
1771 : : // pre-multiply with the
1772 : : // logic-to-pixel scale factor
1773 : : // (the metafile comment works in
1774 : : // logical coordinates).
1775 [ # # ]: 0 : ::basegfx::B2DHomMatrix aLogic2PixelTransform;
1776 : : aMatrix *= tools::calcLogic2PixelLinearTransform( aLogic2PixelTransform,
1777 [ # # ][ # # ]: 0 : rVDev );
1778 : :
1779 : : ::basegfx::unotools::affineMatrixFromHomMatrix(
1780 : : aTexture.AffineTransform,
1781 [ # # ]: 0 : aMatrix );
1782 : :
1783 [ # # ]: 0 : aTexture.Alpha = 1.0 - aFill.getTransparency();
1784 : : aTexture.Bitmap =
1785 : : ::vcl::unotools::xBitmapFromBitmapEx(
1786 [ # # ][ # # ]: 0 : rCanvas->getUNOCanvas()->getDevice(),
1787 [ # # ][ # # ]: 0 : aBmpEx );
[ # # ]
1788 [ # # ][ # # ]: 0 : if( aFill.isTiling() )
1789 : : {
1790 : 0 : aTexture.RepeatModeX = rendering::TexturingMode::REPEAT;
1791 : 0 : aTexture.RepeatModeY = rendering::TexturingMode::REPEAT;
1792 : : }
1793 : : else
1794 : : {
1795 : 0 : aTexture.RepeatModeX = rendering::TexturingMode::NONE;
1796 : 0 : aTexture.RepeatModeY = rendering::TexturingMode::NONE;
1797 : : }
1798 : :
1799 [ # # ]: 0 : ::PolyPolygon aPath;
1800 [ # # ]: 0 : aFill.getPath( aPath );
1801 : :
1802 [ # # ]: 0 : ::basegfx::B2DPolyPolygon aPoly( aPath.getB2DPolyPolygon() );
1803 [ # # ][ # # ]: 0 : aPoly.transform( rStates.getState().mapModeTransform );
1804 : : ActionSharedPtr pPolyAction(
1805 : : internal::PolyPolyActionFactory::createPolyPolyAction(
1806 : : aPoly,
1807 : : rCanvas,
1808 [ # # ]: 0 : rStates.getState(),
1809 [ # # ]: 0 : aTexture ) );
1810 : :
1811 [ # # ]: 0 : if( pPolyAction )
1812 : : {
1813 : : maActions.push_back(
1814 : : MtfAction(
1815 : : pPolyAction,
1816 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
1817 : :
1818 [ # # ]: 0 : io_rCurrActionIndex += pPolyAction->getActionCount()-1;
1819 : : }
1820 : :
1821 : : // skip broken-down render output
1822 : : skipContent( rMtf,
1823 : : "XPATHFILL_SEQ_END",
1824 [ # # ][ # # ]: 0 : io_rCurrActionIndex );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1825 [ # # ][ # # ]: 0 : }
1826 : : }
1827 : : }
1828 : : // Handle drawing layer fills
1829 [ # # ]: 0 : else if( pAct->GetComment().equalsL(RTL_CONSTASCII_STRINGPARAM("EMF_PLUS")) ) {
1830 : : static int count = -1, limit = 0x7fffffff;
1831 [ # # ]: 0 : if (count == -1) {
1832 : 0 : count = 0;
1833 [ # # ]: 0 : if (char *env = getenv ("EMF_PLUS_LIMIT")) {
1834 : 0 : limit = atoi (env);
1835 : : EMFP_DEBUG (printf ("EMF+ records limit: %d\n", limit));
1836 : : }
1837 : : }
1838 : : EMFP_DEBUG (printf ("EMF+ passed to canvas mtf renderer, size: %u\n", (unsigned int)pAct->GetDataSize ()));
1839 [ # # ]: 0 : if (count < limit)
1840 : 0 : processEMFPlus( pAct, rFactoryParms, rStates.getState(), rCanvas );
1841 : 0 : count ++;
1842 [ # # ]: 0 : } else if( pAct->GetComment().equalsL(RTL_CONSTASCII_STRINGPARAM("EMF_PLUS_HEADER_INFO")) ) {
1843 : : EMFP_DEBUG (printf ("EMF+ passed to canvas mtf renderer - header info, size: %u\n", (unsigned int)pAct->GetDataSize ()));
1844 : :
1845 [ # # ]: 0 : SvMemoryStream rMF ((void*) pAct->GetData (), pAct->GetDataSize (), STREAM_READ);
1846 : :
1847 [ # # ][ # # ]: 0 : rMF >> nFrameLeft >> nFrameTop >> nFrameRight >> nFrameBottom;
[ # # ][ # # ]
1848 : : EMFP_DEBUG (printf ("EMF+ picture frame: %d,%d - %d,%d\n", (int)nFrameLeft, (int)nFrameTop, (int)nFrameRight, (int)nFrameBottom));
1849 [ # # ][ # # ]: 0 : rMF >> nPixX >> nPixY >> nMmX >> nMmY;
[ # # ][ # # ]
1850 : : EMFP_DEBUG (printf ("EMF+ ref device pixel size: %dx%d mm size: %dx%d\n", (int)nPixX, (int)nPixY, (int)nMmX, (int)nMmY));
1851 : :
1852 [ # # ][ # # ]: 0 : rMF >> aBaseTransform;
1853 : : //aWorldTransform.Set (aBaseTransform);
1854 : : }
1855 : : }
1856 : 0 : break;
1857 : :
1858 : : // ------------------------------------------------------------
1859 : :
1860 : : // In the third part of this monster-switch, we
1861 : : // handle all 'acting' meta actions. These are all
1862 : : // processed by constructing function objects for
1863 : : // them, which will later ease caching.
1864 : :
1865 : : // ------------------------------------------------------------
1866 : :
1867 : : case META_POINT_ACTION:
1868 : : {
1869 : 0 : const OutDevState& rState( rStates.getState() );
1870 [ # # ]: 0 : if( rState.lineColor.getLength() )
1871 : : {
1872 : : ActionSharedPtr pPointAction(
1873 : : internal::PointActionFactory::createPointAction(
1874 : : rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint(
1875 : 0 : static_cast<MetaPointAction*>(pCurrAct)->GetPoint() ),
1876 : : rCanvas,
1877 [ # # ][ # # ]: 0 : rState ) );
[ # # ]
1878 : :
1879 [ # # ]: 0 : if( pPointAction )
1880 : : {
1881 : : maActions.push_back(
1882 : : MtfAction(
1883 : : pPointAction,
1884 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
1885 : :
1886 [ # # ]: 0 : io_rCurrActionIndex += pPointAction->getActionCount()-1;
1887 [ # # ]: 0 : }
1888 : : }
1889 : : }
1890 : 0 : break;
1891 : :
1892 : : case META_PIXEL_ACTION:
1893 : : {
1894 : 0 : const OutDevState& rState( rStates.getState() );
1895 [ # # ]: 0 : if( rState.lineColor.getLength() )
1896 : : {
1897 : : ActionSharedPtr pPointAction(
1898 : : internal::PointActionFactory::createPointAction(
1899 : : rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint(
1900 : 0 : static_cast<MetaPixelAction*>(pCurrAct)->GetPoint() ),
1901 : : rCanvas,
1902 : : rState,
1903 [ # # ][ # # ]: 0 : static_cast<MetaPixelAction*>(pCurrAct)->GetColor() ) );
[ # # ]
1904 : :
1905 [ # # ]: 0 : if( pPointAction )
1906 : : {
1907 : : maActions.push_back(
1908 : : MtfAction(
1909 : : pPointAction,
1910 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
1911 : :
1912 [ # # ]: 0 : io_rCurrActionIndex += pPointAction->getActionCount()-1;
1913 [ # # ]: 0 : }
1914 : : }
1915 : : }
1916 : 0 : break;
1917 : :
1918 : : case META_LINE_ACTION:
1919 : : {
1920 : 0 : const OutDevState& rState( rStates.getState() );
1921 [ # # ]: 0 : if( rState.lineColor.getLength() )
1922 : : {
1923 : 0 : MetaLineAction* pLineAct = static_cast<MetaLineAction*>(pCurrAct);
1924 : :
1925 : 0 : const LineInfo& rLineInfo( pLineAct->GetLineInfo() );
1926 : :
1927 : : const ::basegfx::B2DPoint aStartPoint(
1928 [ # # ][ # # ]: 0 : rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( pLineAct->GetStartPoint() ));
1929 : : const ::basegfx::B2DPoint aEndPoint(
1930 [ # # ][ # # ]: 0 : rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( pLineAct->GetEndPoint() ));
1931 : :
1932 [ # # ]: 0 : ActionSharedPtr pLineAction;
1933 : :
1934 [ # # ]: 0 : if( rLineInfo.IsDefault() )
1935 : : {
1936 : : // plain hair line
1937 : : pLineAction =
1938 : : internal::LineActionFactory::createLineAction(
1939 : : aStartPoint,
1940 : : aEndPoint,
1941 : : rCanvas,
1942 [ # # ][ # # ]: 0 : rState );
[ # # ]
1943 : :
1944 [ # # ]: 0 : if( pLineAction )
1945 : : {
1946 : : maActions.push_back(
1947 : : MtfAction(
1948 : : pLineAction,
1949 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
1950 : :
1951 [ # # ]: 0 : io_rCurrActionIndex += pLineAction->getActionCount()-1;
1952 : : }
1953 : : }
1954 [ # # ]: 0 : else if( LINE_NONE != rLineInfo.GetStyle() )
1955 : : {
1956 : : // 'thick' line
1957 [ # # ]: 0 : rendering::StrokeAttributes aStrokeAttributes;
1958 : :
1959 : : setupStrokeAttributes( aStrokeAttributes,
1960 : : rFactoryParms,
1961 [ # # ]: 0 : rLineInfo );
1962 : :
1963 : : // XCanvas can only stroke polygons,
1964 : : // not simple lines - thus, handle
1965 : : // this case via the polypolygon
1966 : : // action
1967 [ # # ]: 0 : ::basegfx::B2DPolygon aPoly;
1968 [ # # ]: 0 : aPoly.append( aStartPoint );
1969 [ # # ]: 0 : aPoly.append( aEndPoint );
1970 : : pLineAction =
1971 : : internal::PolyPolyActionFactory::createPolyPolyAction(
1972 : : ::basegfx::B2DPolyPolygon( aPoly ),
1973 [ # # ][ # # ]: 0 : rCanvas, rState, aStrokeAttributes );
[ # # ][ # # ]
[ # # ]
1974 : :
1975 [ # # ]: 0 : if( pLineAction )
1976 : : {
1977 : : maActions.push_back(
1978 : : MtfAction(
1979 : : pLineAction,
1980 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
1981 : :
1982 [ # # ]: 0 : io_rCurrActionIndex += pLineAction->getActionCount()-1;
1983 [ # # ][ # # ]: 0 : }
1984 [ # # ]: 0 : }
1985 : : // else: line style is default
1986 : : // (i.e. invisible), don't generate action
1987 : : }
1988 : : }
1989 : 0 : break;
1990 : :
1991 : : case META_RECT_ACTION:
1992 : : {
1993 : : const Rectangle& rRect(
1994 : 0 : static_cast<MetaRectAction*>(pCurrAct)->GetRect() );
1995 : :
1996 [ # # ][ # # ]: 0 : if( rRect.IsEmpty() )
1997 : : break;
1998 : :
1999 [ # # ]: 0 : const OutDevState& rState( rStates.getState() );
2000 : : const ::basegfx::B2DPoint aTopLeftPixel(
2001 [ # # ][ # # ]: 0 : rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ) );
2002 : : const ::basegfx::B2DPoint aBottomRightPixel(
2003 : : rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) +
2004 : : // #121100# OutputDevice::DrawRect() fills
2005 : : // rectangles Apple-like, i.e. with one
2006 : : // additional pixel to the right and bottom.
2007 [ # # ][ # # ]: 0 : ::basegfx::B2DPoint(1,1) );
[ # # ]
2008 : :
2009 : : createFillAndStroke( ::basegfx::tools::createPolygonFromRect(
2010 : : ::basegfx::B2DRange( aTopLeftPixel,
2011 : : aBottomRightPixel )),
2012 [ # # ][ # # ]: 0 : rFactoryParms );
[ # # ][ # # ]
2013 : 0 : break;
2014 : : }
2015 : :
2016 : : case META_ROUNDRECT_ACTION:
2017 : : {
2018 : : const Rectangle& rRect(
2019 : 0 : static_cast<MetaRoundRectAction*>(pCurrAct)->GetRect());
2020 : :
2021 [ # # ][ # # ]: 0 : if( rRect.IsEmpty() )
2022 : : break;
2023 : :
2024 : : ::basegfx::B2DPolygon aPoly(
2025 : : ::basegfx::tools::createPolygonFromRect(
2026 : : ::basegfx::B2DRange(
2027 : : ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ),
2028 : : ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) +
2029 : : ::basegfx::B2DPoint(1,1) ),
2030 [ # # ]: 0 : ( (double) static_cast<MetaRoundRectAction*>(pCurrAct)->GetHorzRound() ) / rRect.GetWidth(),
2031 [ # # ][ # # ]: 0 : ( (double) static_cast<MetaRoundRectAction*>(pCurrAct)->GetVertRound() ) / rRect.GetHeight() ) );
[ # # ][ # # ]
[ # # ][ # # ]
2032 [ # # ][ # # ]: 0 : aPoly.transform( rStates.getState().mapModeTransform );
2033 : :
2034 : : createFillAndStroke( aPoly,
2035 [ # # ][ # # ]: 0 : rFactoryParms );
2036 : : }
2037 : 0 : break;
2038 : :
2039 : : case META_ELLIPSE_ACTION:
2040 : : {
2041 : : const Rectangle& rRect(
2042 : 0 : static_cast<MetaEllipseAction*>(pCurrAct)->GetRect() );
2043 : :
2044 [ # # ][ # # ]: 0 : if( rRect.IsEmpty() )
2045 : : break;
2046 : :
2047 : : const ::basegfx::B2DRange aRange(
2048 : : ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ),
2049 : : ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) +
2050 [ # # ][ # # ]: 0 : ::basegfx::B2DPoint(1,1) );
[ # # ][ # # ]
2051 : :
2052 : : ::basegfx::B2DPolygon aPoly(
2053 : : ::basegfx::tools::createPolygonFromEllipse(
2054 : : aRange.getCenter(),
2055 : : aRange.getWidth(),
2056 [ # # ][ # # ]: 0 : aRange.getHeight() ));
[ # # ][ # # ]
2057 [ # # ][ # # ]: 0 : aPoly.transform( rStates.getState().mapModeTransform );
2058 : :
2059 : : createFillAndStroke( aPoly,
2060 [ # # ][ # # ]: 0 : rFactoryParms );
2061 : : }
2062 : 0 : break;
2063 : :
2064 : : case META_ARC_ACTION:
2065 : : {
2066 : : // TODO(F1): Missing basegfx functionality. Mind empty rects!
2067 : 0 : const Polygon aToolsPoly( static_cast<MetaArcAction*>(pCurrAct)->GetRect(),
2068 : 0 : static_cast<MetaArcAction*>(pCurrAct)->GetStartPoint(),
2069 [ # # ]: 0 : static_cast<MetaArcAction*>(pCurrAct)->GetEndPoint(), POLY_ARC );
2070 [ # # ]: 0 : ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() );
2071 [ # # ][ # # ]: 0 : aPoly.transform( rStates.getState().mapModeTransform );
2072 : :
2073 : : createFillAndStroke( aPoly,
2074 [ # # ][ # # ]: 0 : rFactoryParms );
[ # # ]
2075 : : }
2076 : 0 : break;
2077 : :
2078 : : case META_PIE_ACTION:
2079 : : {
2080 : : // TODO(F1): Missing basegfx functionality. Mind empty rects!
2081 : 0 : const Polygon aToolsPoly( static_cast<MetaPieAction*>(pCurrAct)->GetRect(),
2082 : 0 : static_cast<MetaPieAction*>(pCurrAct)->GetStartPoint(),
2083 [ # # ]: 0 : static_cast<MetaPieAction*>(pCurrAct)->GetEndPoint(), POLY_PIE );
2084 [ # # ]: 0 : ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() );
2085 [ # # ][ # # ]: 0 : aPoly.transform( rStates.getState().mapModeTransform );
2086 : :
2087 : : createFillAndStroke( aPoly,
2088 [ # # ][ # # ]: 0 : rFactoryParms );
[ # # ]
2089 : : }
2090 : 0 : break;
2091 : :
2092 : : case META_CHORD_ACTION:
2093 : : {
2094 : : // TODO(F1): Missing basegfx functionality. Mind empty rects!
2095 : 0 : const Polygon aToolsPoly( static_cast<MetaChordAction*>(pCurrAct)->GetRect(),
2096 : 0 : static_cast<MetaChordAction*>(pCurrAct)->GetStartPoint(),
2097 [ # # ]: 0 : static_cast<MetaChordAction*>(pCurrAct)->GetEndPoint(), POLY_CHORD );
2098 [ # # ]: 0 : ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() );
2099 [ # # ][ # # ]: 0 : aPoly.transform( rStates.getState().mapModeTransform );
2100 : :
2101 : : createFillAndStroke( aPoly,
2102 [ # # ][ # # ]: 0 : rFactoryParms );
[ # # ]
2103 : : }
2104 : 0 : break;
2105 : :
2106 : : case META_POLYLINE_ACTION:
2107 : : {
2108 : 0 : const OutDevState& rState( rStates.getState() );
2109 [ # # ]: 0 : if( rState.lineColor.getLength() ||
[ # # # # ]
2110 : 0 : rState.fillColor.getLength() )
2111 : : {
2112 : 0 : MetaPolyLineAction* pPolyLineAct = static_cast<MetaPolyLineAction*>(pCurrAct);
2113 : :
2114 : 0 : const LineInfo& rLineInfo( pPolyLineAct->GetLineInfo() );
2115 [ # # ]: 0 : ::basegfx::B2DPolygon aPoly( pPolyLineAct->GetPolygon().getB2DPolygon() );
2116 [ # # ]: 0 : aPoly.transform( rState.mapModeTransform );
2117 : :
2118 [ # # ]: 0 : ActionSharedPtr pLineAction;
2119 : :
2120 [ # # ]: 0 : if( rLineInfo.IsDefault() )
2121 : : {
2122 : : // plain hair line polygon
2123 : : pLineAction =
2124 : : internal::PolyPolyActionFactory::createLinePolyPolyAction(
2125 : : ::basegfx::B2DPolyPolygon(aPoly),
2126 : : rCanvas,
2127 [ # # ][ # # ]: 0 : rState );
[ # # ][ # # ]
[ # # ]
2128 : :
2129 [ # # ]: 0 : if( pLineAction )
2130 : : {
2131 : : maActions.push_back(
2132 : : MtfAction(
2133 : : pLineAction,
2134 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2135 : :
2136 [ # # ]: 0 : io_rCurrActionIndex += pLineAction->getActionCount()-1;
2137 : : }
2138 : : }
2139 [ # # ]: 0 : else if( LINE_NONE != rLineInfo.GetStyle() )
2140 : : {
2141 : : // 'thick' line polygon
2142 [ # # ]: 0 : rendering::StrokeAttributes aStrokeAttributes;
2143 : :
2144 : : setupStrokeAttributes( aStrokeAttributes,
2145 : : rFactoryParms,
2146 [ # # ]: 0 : rLineInfo );
2147 : :
2148 : : pLineAction =
2149 : : internal::PolyPolyActionFactory::createPolyPolyAction(
2150 : : ::basegfx::B2DPolyPolygon(aPoly),
2151 : : rCanvas,
2152 : : rState,
2153 [ # # ][ # # ]: 0 : aStrokeAttributes ) ;
[ # # ][ # # ]
[ # # ]
2154 : :
2155 [ # # ]: 0 : if( pLineAction )
2156 : : {
2157 : : maActions.push_back(
2158 : : MtfAction(
2159 : : pLineAction,
2160 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2161 : :
2162 [ # # ]: 0 : io_rCurrActionIndex += pLineAction->getActionCount()-1;
2163 [ # # ]: 0 : }
2164 [ # # ][ # # ]: 0 : }
2165 : : // else: line style is default
2166 : : // (i.e. invisible), don't generate action
2167 : : }
2168 : : }
2169 : 0 : break;
2170 : :
2171 : : case META_POLYGON_ACTION:
2172 : : {
2173 [ # # ]: 0 : ::basegfx::B2DPolygon aPoly( static_cast<MetaPolygonAction*>(pCurrAct)->GetPolygon().getB2DPolygon() );
2174 [ # # ][ # # ]: 0 : aPoly.transform( rStates.getState().mapModeTransform );
2175 : : createFillAndStroke( aPoly,
2176 [ # # ][ # # ]: 0 : rFactoryParms );
2177 : : }
2178 : 0 : break;
2179 : :
2180 : : case META_POLYPOLYGON_ACTION:
2181 : : {
2182 [ # # ]: 0 : ::basegfx::B2DPolyPolygon aPoly( static_cast<MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon().getB2DPolyPolygon() );
2183 [ # # ][ # # ]: 0 : aPoly.transform( rStates.getState().mapModeTransform );
2184 : : createFillAndStroke( aPoly,
2185 [ # # ][ # # ]: 0 : rFactoryParms );
2186 : : }
2187 : 0 : break;
2188 : :
2189 : : case META_BMP_ACTION:
2190 : : {
2191 : 0 : MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pCurrAct);
2192 : :
2193 : : ActionSharedPtr pBmpAction(
2194 : : internal::BitmapActionFactory::createBitmapAction(
2195 : 0 : pAct->GetBitmap(),
2196 [ # # ]: 0 : rStates.getState().mapModeTransform *
2197 : 0 : ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2198 : : rCanvas,
2199 [ # # # # ]: 0 : rStates.getState() ) );
[ # # # # ]
[ # # ][ # # ]
2200 : :
2201 [ # # ]: 0 : if( pBmpAction )
2202 : : {
2203 : : maActions.push_back(
2204 : : MtfAction(
2205 : : pBmpAction,
2206 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2207 : :
2208 [ # # ]: 0 : io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2209 [ # # ]: 0 : }
2210 : : }
2211 : 0 : break;
2212 : :
2213 : : case META_BMPSCALE_ACTION:
2214 : : {
2215 : 0 : MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pCurrAct);
2216 : :
2217 : : ActionSharedPtr pBmpAction(
2218 : : internal::BitmapActionFactory::createBitmapAction(
2219 : 0 : pAct->GetBitmap(),
2220 [ # # ]: 0 : rStates.getState().mapModeTransform *
2221 : 0 : ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2222 [ # # ]: 0 : rStates.getState().mapModeTransform *
2223 : 0 : ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ),
2224 : : rCanvas,
2225 [ # # # # ]: 0 : rStates.getState() ) );
[ # # # # ]
[ # # # # ]
[ # # ][ # # ]
2226 : :
2227 [ # # ]: 0 : if( pBmpAction )
2228 : : {
2229 : : maActions.push_back(
2230 : : MtfAction(
2231 : : pBmpAction,
2232 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2233 : :
2234 [ # # ]: 0 : io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2235 [ # # ]: 0 : }
2236 : : }
2237 : 0 : break;
2238 : :
2239 : : case META_BMPSCALEPART_ACTION:
2240 : : {
2241 : 0 : MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pCurrAct);
2242 : :
2243 : : // crop bitmap to given source rectangle (no
2244 : : // need to copy and convert the whole bitmap)
2245 [ # # ]: 0 : Bitmap aBmp( pAct->GetBitmap() );
2246 : 0 : const Rectangle aCropRect( pAct->GetSrcPoint(),
2247 [ # # ]: 0 : pAct->GetSrcSize() );
2248 [ # # ]: 0 : aBmp.Crop( aCropRect );
2249 : :
2250 : : ActionSharedPtr pBmpAction(
2251 : : internal::BitmapActionFactory::createBitmapAction(
2252 : : aBmp,
2253 [ # # ]: 0 : rStates.getState().mapModeTransform *
2254 : 0 : ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ),
2255 [ # # ]: 0 : rStates.getState().mapModeTransform *
2256 : 0 : ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ),
2257 : : rCanvas,
2258 [ # # # # ]: 0 : rStates.getState() ) );
[ # # # # ]
[ # # ][ # # ]
[ # # ][ # # ]
2259 : :
2260 [ # # ]: 0 : if( pBmpAction )
2261 : : {
2262 : : maActions.push_back(
2263 : : MtfAction(
2264 : : pBmpAction,
2265 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2266 : :
2267 [ # # ]: 0 : io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2268 [ # # ][ # # ]: 0 : }
2269 : : }
2270 : 0 : break;
2271 : :
2272 : : case META_BMPEX_ACTION:
2273 : : {
2274 : 0 : MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pCurrAct);
2275 : :
2276 : : ActionSharedPtr pBmpAction(
2277 : : internal::BitmapActionFactory::createBitmapAction(
2278 : 0 : pAct->GetBitmapEx(),
2279 [ # # ]: 0 : rStates.getState().mapModeTransform *
2280 : 0 : ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2281 : : rCanvas,
2282 [ # # # # ]: 0 : rStates.getState() ) );
[ # # # # ]
2283 : :
2284 [ # # ]: 0 : if( pBmpAction )
2285 : : {
2286 : : maActions.push_back(
2287 : : MtfAction(
2288 : : pBmpAction,
2289 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2290 : :
2291 [ # # ]: 0 : io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2292 [ # # ]: 0 : }
2293 : : }
2294 : 0 : break;
2295 : :
2296 : : case META_BMPEXSCALE_ACTION:
2297 : : {
2298 : 0 : MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pCurrAct);
2299 : :
2300 : : ActionSharedPtr pBmpAction(
2301 : : internal::BitmapActionFactory::createBitmapAction(
2302 : 0 : pAct->GetBitmapEx(),
2303 [ # # ]: 0 : rStates.getState().mapModeTransform *
2304 : 0 : ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2305 [ # # ]: 0 : rStates.getState().mapModeTransform *
2306 : 0 : ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ),
2307 : : rCanvas,
2308 [ # # # # ]: 0 : rStates.getState() ) );
[ # # # # ]
[ # # # # ]
2309 : :
2310 [ # # ]: 0 : if( pBmpAction )
2311 : : {
2312 : : maActions.push_back(
2313 : : MtfAction(
2314 : : pBmpAction,
2315 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2316 : :
2317 [ # # ]: 0 : io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2318 [ # # ]: 0 : }
2319 : : }
2320 : 0 : break;
2321 : :
2322 : : case META_BMPEXSCALEPART_ACTION:
2323 : : {
2324 : 0 : MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pCurrAct);
2325 : :
2326 : : // crop bitmap to given source rectangle (no
2327 : : // need to copy and convert the whole bitmap)
2328 [ # # ]: 0 : BitmapEx aBmp( pAct->GetBitmapEx() );
2329 : 0 : const Rectangle aCropRect( pAct->GetSrcPoint(),
2330 [ # # ]: 0 : pAct->GetSrcSize() );
2331 [ # # ]: 0 : aBmp.Crop( aCropRect );
2332 : :
2333 : : ActionSharedPtr pBmpAction(
2334 : : internal::BitmapActionFactory::createBitmapAction(
2335 : : aBmp,
2336 [ # # ]: 0 : rStates.getState().mapModeTransform *
2337 : 0 : ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ),
2338 [ # # ]: 0 : rStates.getState().mapModeTransform *
2339 : 0 : ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ),
2340 : : rCanvas,
2341 [ # # # # ]: 0 : rStates.getState() ) );
[ # # # # ]
[ # # ][ # # ]
2342 : :
2343 [ # # ]: 0 : if( pBmpAction )
2344 : : {
2345 : : maActions.push_back(
2346 : : MtfAction(
2347 : : pBmpAction,
2348 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2349 : :
2350 [ # # ]: 0 : io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2351 [ # # ][ # # ]: 0 : }
2352 : : }
2353 : 0 : break;
2354 : :
2355 : : case META_MASK_ACTION:
2356 : : {
2357 : 0 : MetaMaskAction* pAct = static_cast<MetaMaskAction*>(pCurrAct);
2358 : :
2359 : : // create masked BitmapEx right here, as the
2360 : : // canvas does not provide equivalent
2361 : : // functionality
2362 : 0 : BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(),
2363 [ # # ]: 0 : pAct->GetColor() ));
2364 : :
2365 : : ActionSharedPtr pBmpAction(
2366 : : internal::BitmapActionFactory::createBitmapAction(
2367 : : aBmp,
2368 [ # # ]: 0 : rStates.getState().mapModeTransform *
2369 : 0 : ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2370 : : rCanvas,
2371 [ # # # # ]: 0 : rStates.getState() ) );
[ # # ][ # # ]
2372 : :
2373 [ # # ]: 0 : if( pBmpAction )
2374 : : {
2375 : : maActions.push_back(
2376 : : MtfAction(
2377 : : pBmpAction,
2378 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2379 : :
2380 [ # # ]: 0 : io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2381 [ # # ][ # # ]: 0 : }
2382 : : }
2383 : 0 : break;
2384 : :
2385 : : case META_MASKSCALE_ACTION:
2386 : : {
2387 : 0 : MetaMaskScaleAction* pAct = static_cast<MetaMaskScaleAction*>(pCurrAct);
2388 : :
2389 : : // create masked BitmapEx right here, as the
2390 : : // canvas does not provide equivalent
2391 : : // functionality
2392 : 0 : BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(),
2393 [ # # ]: 0 : pAct->GetColor() ));
2394 : :
2395 : : ActionSharedPtr pBmpAction(
2396 : : internal::BitmapActionFactory::createBitmapAction(
2397 : : aBmp,
2398 [ # # ]: 0 : rStates.getState().mapModeTransform *
2399 : 0 : ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2400 [ # # ]: 0 : rStates.getState().mapModeTransform *
2401 : 0 : ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ),
2402 : : rCanvas,
2403 [ # # # # ]: 0 : rStates.getState() ) );
[ # # # # ]
[ # # ][ # # ]
2404 : :
2405 [ # # ]: 0 : if( pBmpAction )
2406 : : {
2407 : : maActions.push_back(
2408 : : MtfAction(
2409 : : pBmpAction,
2410 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2411 : :
2412 [ # # ]: 0 : io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2413 [ # # ][ # # ]: 0 : }
2414 : : }
2415 : 0 : break;
2416 : :
2417 : : case META_MASKSCALEPART_ACTION:
2418 : : {
2419 : 0 : MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pCurrAct);
2420 : :
2421 : : // create masked BitmapEx right here, as the
2422 : : // canvas does not provide equivalent
2423 : : // functionality
2424 : 0 : BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(),
2425 [ # # ]: 0 : pAct->GetColor() ));
2426 : :
2427 : : // crop bitmap to given source rectangle (no
2428 : : // need to copy and convert the whole bitmap)
2429 : 0 : const Rectangle aCropRect( pAct->GetSrcPoint(),
2430 [ # # ]: 0 : pAct->GetSrcSize() );
2431 [ # # ]: 0 : aBmp.Crop( aCropRect );
2432 : :
2433 : : ActionSharedPtr pBmpAction(
2434 : : internal::BitmapActionFactory::createBitmapAction(
2435 : : aBmp,
2436 [ # # ]: 0 : rStates.getState().mapModeTransform *
2437 : 0 : ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ),
2438 [ # # ]: 0 : rStates.getState().mapModeTransform *
2439 : 0 : ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ),
2440 : : rCanvas,
2441 [ # # # # ]: 0 : rStates.getState() ) );
[ # # # # ]
[ # # ][ # # ]
2442 : :
2443 [ # # ]: 0 : if( pBmpAction )
2444 : : {
2445 : : maActions.push_back(
2446 : : MtfAction(
2447 : : pBmpAction,
2448 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2449 : :
2450 [ # # ]: 0 : io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2451 [ # # ][ # # ]: 0 : }
2452 : : }
2453 : 0 : break;
2454 : :
2455 : : case META_GRADIENTEX_ACTION:
2456 : : // TODO(F1): use native Canvas gradients here
2457 : : // action is ignored here, because redundant to META_GRADIENT_ACTION
2458 : 0 : break;
2459 : :
2460 : : case META_WALLPAPER_ACTION:
2461 : : // TODO(F2): NYI
2462 : 0 : break;
2463 : :
2464 : : case META_TRANSPARENT_ACTION:
2465 : : {
2466 : 0 : const OutDevState& rState( rStates.getState() );
2467 [ # # ]: 0 : if( rState.lineColor.getLength() ||
[ # # # # ]
2468 : 0 : rState.fillColor.getLength() )
2469 : : {
2470 : 0 : MetaTransparentAction* pAct = static_cast<MetaTransparentAction*>(pCurrAct);
2471 [ # # ]: 0 : ::basegfx::B2DPolyPolygon aPoly( pAct->GetPolyPolygon().getB2DPolyPolygon() );
2472 [ # # ]: 0 : aPoly.transform( rState.mapModeTransform );
2473 : :
2474 : : ActionSharedPtr pPolyAction(
2475 : : internal::PolyPolyActionFactory::createPolyPolyAction(
2476 : : aPoly,
2477 : : rCanvas,
2478 : : rState,
2479 [ # # ]: 0 : pAct->GetTransparence() ) );
2480 : :
2481 [ # # ]: 0 : if( pPolyAction )
2482 : : {
2483 : : maActions.push_back(
2484 : : MtfAction(
2485 : : pPolyAction,
2486 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2487 : :
2488 [ # # ]: 0 : io_rCurrActionIndex += pPolyAction->getActionCount()-1;
2489 [ # # ][ # # ]: 0 : }
2490 : : }
2491 : : }
2492 : 0 : break;
2493 : :
2494 : : case META_FLOATTRANSPARENT_ACTION:
2495 : : {
2496 : 0 : MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pCurrAct);
2497 : :
2498 : : internal::MtfAutoPtr pMtf(
2499 [ # # ][ # # ]: 0 : new ::GDIMetaFile( pAct->GetGDIMetaFile() ) );
2500 : :
2501 : : // TODO(P2): Use native canvas gradients here (saves a lot of UNO calls)
2502 : : internal::GradientAutoPtr pGradient(
2503 [ # # ][ # # ]: 0 : new Gradient( pAct->GetGradient() ) );
2504 : :
2505 : : DBG_TESTSOLARMUTEX();
2506 : :
2507 : : ActionSharedPtr pFloatTransAction(
2508 : : internal::TransparencyGroupActionFactory::createTransparencyGroupAction(
2509 : : pMtf,
2510 : : pGradient,
2511 : : rParms,
2512 [ # # ]: 0 : rStates.getState().mapModeTransform *
2513 : 0 : ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2514 [ # # ]: 0 : rStates.getState().mapModeTransform *
2515 : 0 : ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ),
2516 : : rCanvas,
2517 [ # # # # ]: 0 : rStates.getState() ) );
[ # # ][ # # ]
[ # # # # ]
2518 : :
2519 [ # # ]: 0 : if( pFloatTransAction )
2520 : : {
2521 : : maActions.push_back(
2522 : : MtfAction(
2523 : : pFloatTransAction,
2524 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2525 : :
2526 [ # # ]: 0 : io_rCurrActionIndex += pFloatTransAction->getActionCount()-1;
2527 [ # # ][ # # ]: 0 : }
[ # # ]
2528 : : }
2529 : 0 : break;
2530 : :
2531 : : case META_TEXT_ACTION:
2532 : : {
2533 : 0 : MetaTextAction* pAct = static_cast<MetaTextAction*>(pCurrAct);
2534 [ # # ]: 0 : XubString sText = XubString( pAct->GetText() );
2535 : :
2536 [ # # ]: 0 : if( rVDev.GetDigitLanguage())
2537 [ # # ]: 0 : convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() );
2538 : :
2539 : : createTextAction(
2540 : 0 : pAct->GetPoint(),
2541 : : sText,
2542 : 0 : pAct->GetIndex(),
2543 : 0 : pAct->GetLen() == (sal_uInt16)STRING_LEN ? pAct->GetText().getLength() - pAct->GetIndex() : pAct->GetLen(),
2544 : : NULL,
2545 : : rFactoryParms,
2546 [ # # ][ # # ]: 0 : bSubsettableActions );
[ # # # #
# # ]
2547 : : }
2548 : 0 : break;
2549 : :
2550 : : case META_TEXTARRAY_ACTION:
2551 : : {
2552 : 0 : MetaTextArrayAction* pAct = static_cast<MetaTextArrayAction*>(pCurrAct);
2553 [ # # ]: 0 : XubString sText = XubString( pAct->GetText() );
2554 : :
2555 [ # # ]: 0 : if( rVDev.GetDigitLanguage())
2556 [ # # ]: 0 : convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() );
2557 : :
2558 : : createTextAction(
2559 : 0 : pAct->GetPoint(),
2560 : : sText,
2561 : 0 : pAct->GetIndex(),
2562 : 0 : pAct->GetLen() == (sal_uInt16)STRING_LEN ? pAct->GetText().getLength() - pAct->GetIndex() : pAct->GetLen(),
2563 : 0 : pAct->GetDXArray(),
2564 : : rFactoryParms,
2565 [ # # ][ # # ]: 0 : bSubsettableActions );
[ # # # #
# # ]
2566 : : }
2567 : 0 : break;
2568 : :
2569 : : case META_TEXTLINE_ACTION:
2570 : : {
2571 : 0 : MetaTextLineAction* pAct = static_cast<MetaTextLineAction*>(pCurrAct);
2572 : :
2573 [ # # ]: 0 : const OutDevState& rState( rStates.getState() );
2574 : : const ::Size aBaselineOffset( tools::getBaselineOffset( rState,
2575 [ # # ]: 0 : rVDev ) );
2576 : : const ::basegfx::B2DSize aSize( rState.mapModeTransform *
2577 : 0 : ::basegfx::B2DSize(pAct->GetWidth(),
2578 [ # # ]: 0 : 0 ));
2579 : :
2580 : : ActionSharedPtr pPolyAction(
2581 : : PolyPolyActionFactory::createPolyPolyAction(
2582 : : tools::createTextLinesPolyPolygon(
2583 : : rState.mapModeTransform *
2584 : : ::basegfx::B2DPoint(
2585 : 0 : ::vcl::unotools::b2DPointFromPoint(pAct->GetStartPoint()) +
2586 : : ::vcl::unotools::b2DSizeFromSize(aBaselineOffset)),
2587 : 0 : aSize.getX(),
2588 : : tools::createTextLineInfo( rVDev,
2589 : : rState )),
2590 : : rCanvas,
2591 [ # # ][ # # ]: 0 : rState ) );
[ # # ][ # # ]
[ # # # #
# # ]
2592 : :
2593 [ # # ]: 0 : if( pPolyAction.get() )
2594 : : {
2595 : : maActions.push_back(
2596 : : MtfAction(
2597 : : pPolyAction,
2598 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2599 : :
2600 [ # # ]: 0 : io_rCurrActionIndex += pPolyAction->getActionCount()-1;
2601 [ # # ]: 0 : }
2602 : : }
2603 : 0 : break;
2604 : :
2605 : : case META_TEXTRECT_ACTION:
2606 : : {
2607 : 0 : MetaTextRectAction* pAct = static_cast<MetaTextRectAction*>(pCurrAct);
2608 : :
2609 [ # # ]: 0 : rStates.pushState(PUSH_ALL);
2610 : :
2611 : : // use the VDev to break up the text rect
2612 : : // action into readily formatted lines
2613 [ # # ]: 0 : GDIMetaFile aTmpMtf;
2614 : 0 : rVDev.AddTextRectActions( pAct->GetRect(),
2615 : 0 : pAct->GetText(),
2616 : 0 : pAct->GetStyle(),
2617 [ # # ]: 0 : aTmpMtf );
[ # # # # ]
2618 : :
2619 : : createActions( aTmpMtf,
2620 : : rFactoryParms,
2621 [ # # ]: 0 : bSubsettableActions );
2622 : :
2623 [ # # ]: 0 : rStates.popState();
2624 : :
2625 [ # # ]: 0 : break;
2626 : : }
2627 : :
2628 : : case META_STRETCHTEXT_ACTION:
2629 : : {
2630 : 0 : MetaStretchTextAction* pAct = static_cast<MetaStretchTextAction*>(pCurrAct);
2631 [ # # ]: 0 : XubString sText = XubString( pAct->GetText() );
2632 : :
2633 [ # # ]: 0 : if( rVDev.GetDigitLanguage())
2634 [ # # ]: 0 : convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() );
2635 : :
2636 : 0 : const sal_uInt16 nLen( pAct->GetLen() == (sal_uInt16)STRING_LEN ?
2637 [ # # ]: 0 : pAct->GetText().getLength() - pAct->GetIndex() : pAct->GetLen() );
2638 : :
2639 : : // #i70897# Nothing to do, actually...
2640 [ # # ]: 0 : if( nLen == 0 )
2641 : : break;
2642 : :
2643 : : // have to fit the text into the given
2644 : : // width. This is achieved by internally
2645 : : // generating a DX array, and uniformly
2646 : : // distributing the excess/insufficient width
2647 : : // to every logical character.
2648 [ # # ]: 0 : ::boost::scoped_array< sal_Int32 > pDXArray( new sal_Int32[nLen] );
2649 : :
2650 : 0 : rVDev.GetTextArray( pAct->GetText(), pDXArray.get(),
2651 [ # # ][ # # ]: 0 : pAct->GetIndex(), pAct->GetLen() );
[ # # ]
2652 : :
2653 : 0 : const sal_Int32 nWidthDifference( pAct->GetWidth() - pDXArray[ nLen-1 ] );
2654 : :
2655 : : // Last entry of pDXArray contains total width of the text
2656 : 0 : sal_Int32* p=pDXArray.get();
2657 [ # # ]: 0 : for( sal_uInt16 i=1; i<=nLen; ++i )
2658 : : {
2659 : : // calc ratio for every array entry, to
2660 : : // distribute rounding errors 'evenly'
2661 : : // across the characters. Note that each
2662 : : // entry represents the 'end' position of
2663 : : // the corresponding character, thus, we
2664 : : // let i run from 1 to nLen.
2665 : 0 : *p++ += (sal_Int32)i*nWidthDifference/nLen;
2666 : : }
2667 : :
2668 : : createTextAction(
2669 : 0 : pAct->GetPoint(),
2670 : : sText,
2671 : 0 : pAct->GetIndex(),
2672 : 0 : pAct->GetLen() == (sal_uInt16)STRING_LEN ? pAct->GetText().getLength() - pAct->GetIndex() : pAct->GetLen(),
2673 : 0 : pDXArray.get(),
2674 : : rFactoryParms,
2675 [ # # ][ # # ]: 0 : bSubsettableActions );
[ # # ][ # # ]
[ # # # #
# # ]
2676 : : }
2677 : 0 : break;
2678 : :
2679 : : case META_RENDERGRAPHIC_ACTION:
2680 : : {
2681 : 0 : MetaRenderGraphicAction* pAct = static_cast<MetaRenderGraphicAction*>(pCurrAct);
2682 : :
2683 : : ActionSharedPtr pRenderGraphicAction(
2684 : : internal::RenderGraphicActionFactory::createRenderGraphicAction(
2685 : 0 : pAct->GetRenderGraphic(),
2686 [ # # ]: 0 : rStates.getState().mapModeTransform *
2687 : 0 : ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2688 [ # # ]: 0 : rStates.getState().mapModeTransform *
2689 : 0 : ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ),
2690 : : rCanvas,
2691 [ # # # # ]: 0 : rStates.getState() ) );
[ # # # # ]
[ # # # # ]
2692 : :
2693 [ # # ]: 0 : if( pRenderGraphicAction )
2694 : : {
2695 : : maActions.push_back(
2696 : : MtfAction(
2697 : : pRenderGraphicAction,
2698 [ # # ][ # # ]: 0 : io_rCurrActionIndex ) );
[ # # ]
2699 : :
2700 [ # # ]: 0 : io_rCurrActionIndex += pRenderGraphicAction->getActionCount()-1;
2701 [ # # ]: 0 : }
2702 : : }
2703 : 0 : break;
2704 : :
2705 : : default:
2706 : : OSL_FAIL( "Unknown meta action type encountered" );
2707 : 0 : break;
2708 : : }
2709 : :
2710 : : // increment action index (each mtf action counts _at
2711 : : // least_ one. Some count for more, therefore,
2712 : : // io_rCurrActionIndex is sometimes incremented by
2713 : : // pAct->getActionCount()-1 above, the -1 being the
2714 : : // correction for the unconditional increment here).
2715 : 0 : ++io_rCurrActionIndex;
2716 : : }
2717 : :
2718 : 0 : return true;
2719 : : }
2720 : :
2721 : :
2722 : : namespace
2723 : : {
2724 : 0 : class ActionRenderer
2725 : : {
2726 : : public:
2727 : 0 : ActionRenderer( const ::basegfx::B2DHomMatrix& rTransformation ) :
2728 : : maTransformation( rTransformation ),
2729 : 0 : mbRet( true )
2730 : : {
2731 : 0 : }
2732 : :
2733 : 0 : bool result() const
2734 : : {
2735 : 0 : return mbRet;
2736 : : }
2737 : :
2738 : 0 : void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction )
2739 : : {
2740 : : // ANDing the result. We want to fail if at least
2741 : : // one action failed.
2742 : 0 : mbRet &= rAction.mpAction->render( maTransformation );
2743 : 0 : }
2744 : :
2745 : 0 : void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction,
2746 : : const Action::Subset& rSubset )
2747 : : {
2748 : : // ANDing the result. We want to fail if at least
2749 : : // one action failed.
2750 : 0 : mbRet &= rAction.mpAction->renderSubset( maTransformation,
2751 : 0 : rSubset );
2752 : 0 : }
2753 : :
2754 : : private:
2755 : : ::basegfx::B2DHomMatrix maTransformation;
2756 : : bool mbRet;
2757 : : };
2758 : :
2759 : 0 : class AreaQuery
2760 : : {
2761 : : public:
2762 : 0 : AreaQuery( const ::basegfx::B2DHomMatrix& rTransformation ) :
2763 : : maTransformation( rTransformation ),
2764 [ # # ]: 0 : maBounds()
2765 : : {
2766 : 0 : }
2767 : :
2768 : 0 : bool result() const
2769 : : {
2770 : 0 : return true; // nothing can fail here
2771 : : }
2772 : :
2773 : 0 : void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction )
2774 : : {
2775 [ # # ]: 0 : maBounds.expand( rAction.mpAction->getBounds( maTransformation ) );
2776 : 0 : }
2777 : :
2778 : 0 : void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction,
2779 : : const Action::Subset& rSubset )
2780 : : {
2781 : 0 : maBounds.expand( rAction.mpAction->getBounds( maTransformation,
2782 [ # # ]: 0 : rSubset ) );
2783 : 0 : }
2784 : :
2785 : 0 : ::basegfx::B2DRange getBounds() const
2786 : : {
2787 : 0 : return maBounds;
2788 : : }
2789 : :
2790 : : private:
2791 : : ::basegfx::B2DHomMatrix maTransformation;
2792 : : ::basegfx::B2DRange maBounds;
2793 : : };
2794 : :
2795 : : // Doing that via inline class. Compilers tend to not inline free
2796 : : // functions.
2797 : : struct UpperBoundActionIndexComparator
2798 : : {
2799 : 0 : bool operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rLHS,
2800 : : const ::cppcanvas::internal::ImplRenderer::MtfAction& rRHS )
2801 : : {
2802 : : const sal_Int32 nLHSCount( rLHS.mpAction ?
2803 [ # # ]: 0 : rLHS.mpAction->getActionCount() : 0 );
2804 : : const sal_Int32 nRHSCount( rRHS.mpAction ?
2805 [ # # ]: 0 : rRHS.mpAction->getActionCount() : 0 );
2806 : :
2807 : : // compare end of action range, to have an action selected
2808 : : // by lower_bound even if the requested index points in
2809 : : // the middle of the action's range
2810 : 0 : return rLHS.mnOrigIndex + nLHSCount < rRHS.mnOrigIndex + nRHSCount;
2811 : : }
2812 : : };
2813 : :
2814 : : /** Algorithm to apply given functor to a subset range
2815 : :
2816 : : @tpl Functor
2817 : :
2818 : : Functor to call for each element of the subset
2819 : : range. Must provide the following method signatures:
2820 : : bool result() (returning false if operation failed)
2821 : :
2822 : : */
2823 : : template< typename Functor > bool
2824 : 0 : forSubsetRange( Functor& rFunctor,
2825 : : ImplRenderer::ActionVector::const_iterator aRangeBegin,
2826 : : ImplRenderer::ActionVector::const_iterator aRangeEnd,
2827 : : sal_Int32 nStartIndex,
2828 : : sal_Int32 nEndIndex,
2829 : : const ImplRenderer::ActionVector::const_iterator& rEnd )
2830 : : {
2831 [ # # ][ # # ]: 0 : if( aRangeBegin == aRangeEnd )
2832 : : {
2833 : : // only a single action. Setup subset, and call functor
2834 : : Action::Subset aSubset;
2835 [ # # ][ # # ]: 0 : aSubset.mnSubsetBegin = ::std::max( sal_Int32( 0 ),
2836 : : nStartIndex - aRangeBegin->mnOrigIndex );
2837 [ # # ][ # # ]: 0 : aSubset.mnSubsetEnd = ::std::min( aRangeBegin->mpAction->getActionCount(),
[ # # ][ # # ]
2838 : : nEndIndex - aRangeBegin->mnOrigIndex );
2839 : :
2840 [ # # ][ # # ]: 0 : ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0,
[ # # ][ # # ]
2841 : : "ImplRenderer::forSubsetRange(): Invalid indices" );
2842 : :
2843 [ # # ][ # # ]: 0 : rFunctor( *aRangeBegin, aSubset );
2844 : : }
2845 : : else
2846 : : {
2847 : : // more than one action.
2848 : :
2849 : : // render partial first, full intermediate, and
2850 : : // partial last action
2851 : : Action::Subset aSubset;
2852 [ # # ][ # # ]: 0 : aSubset.mnSubsetBegin = ::std::max( sal_Int32( 0 ),
2853 : : nStartIndex - aRangeBegin->mnOrigIndex );
2854 [ # # ][ # # ]: 0 : aSubset.mnSubsetEnd = aRangeBegin->mpAction->getActionCount();
2855 : :
2856 [ # # ][ # # ]: 0 : ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0,
[ # # ][ # # ]
2857 : : "ImplRenderer::forSubsetRange(): Invalid indices" );
2858 : :
2859 [ # # ][ # # ]: 0 : rFunctor( *aRangeBegin, aSubset );
2860 : :
2861 : : // first action rendered, skip to next
2862 : 0 : ++aRangeBegin;
2863 : :
2864 : : // render full middle actions
2865 [ # # ][ # # ]: 0 : while( aRangeBegin != aRangeEnd )
[ # # ][ # # ]
2866 [ # # ][ # # ]: 0 : rFunctor( *aRangeBegin++ );
2867 : :
2868 [ # # ][ # # ]: 0 : if( aRangeEnd == rEnd ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
2869 : : aRangeEnd->mnOrigIndex > nEndIndex )
2870 : : {
2871 : : // aRangeEnd denotes end of action vector,
2872 : : //
2873 : : // or
2874 : : //
2875 : : // nEndIndex references something _after_
2876 : : // aRangeBegin, but _before_ aRangeEnd
2877 : : //
2878 : : // either way: no partial action left
2879 : 0 : return rFunctor.result();
2880 : : }
2881 : :
2882 : 0 : aSubset.mnSubsetBegin = 0;
2883 : 0 : aSubset.mnSubsetEnd = nEndIndex - aRangeEnd->mnOrigIndex;
2884 : :
2885 [ # # ][ # # ]: 0 : ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0,
[ # # ][ # # ]
2886 : : "ImplRenderer::forSubsetRange(): Invalid indices" );
2887 : :
2888 [ # # ][ # # ]: 0 : rFunctor( *aRangeEnd, aSubset );
2889 : : }
2890 : :
2891 : 0 : return rFunctor.result();
2892 : : }
2893 : : }
2894 : :
2895 : 0 : bool ImplRenderer::getSubsetIndices( sal_Int32& io_rStartIndex,
2896 : : sal_Int32& io_rEndIndex,
2897 : : ActionVector::const_iterator& o_rRangeBegin,
2898 : : ActionVector::const_iterator& o_rRangeEnd ) const
2899 : : {
2900 [ # # ]: 0 : ENSURE_OR_RETURN_FALSE( io_rStartIndex<=io_rEndIndex,
2901 : : "ImplRenderer::getSubsetIndices(): invalid action range" );
2902 : :
2903 [ # # ]: 0 : ENSURE_OR_RETURN_FALSE( !maActions.empty(),
2904 : : "ImplRenderer::getSubsetIndices(): no actions to render" );
2905 : :
2906 [ # # ]: 0 : const sal_Int32 nMinActionIndex( maActions.front().mnOrigIndex );
2907 [ # # ]: 0 : const sal_Int32 nMaxActionIndex( maActions.back().mnOrigIndex +
2908 [ # # ][ # # ]: 0 : maActions.back().mpAction->getActionCount() );
2909 : :
2910 : : // clip given range to permissible values (there might be
2911 : : // ranges before and behind the valid indices)
2912 : : io_rStartIndex = ::std::max( nMinActionIndex,
2913 [ # # ]: 0 : io_rStartIndex );
2914 : : io_rEndIndex = ::std::min( nMaxActionIndex,
2915 [ # # ]: 0 : io_rEndIndex );
2916 : :
2917 [ # # ][ # # ]: 0 : if( io_rStartIndex == io_rEndIndex ||
2918 : : io_rStartIndex > io_rEndIndex )
2919 : : {
2920 : : // empty range, don't render anything. The second
2921 : : // condition e.g. happens if the requested range lies
2922 : : // fully before or behind the valid action indices.
2923 : 0 : return false;
2924 : : }
2925 : :
2926 : :
2927 : 0 : const ActionVector::const_iterator aBegin( maActions.begin() );
2928 : 0 : const ActionVector::const_iterator aEnd( maActions.end() );
2929 : :
2930 : :
2931 : : // find start and end action
2932 : : // =========================
2933 : : o_rRangeBegin = ::std::lower_bound( aBegin, aEnd,
2934 : : MtfAction( ActionSharedPtr(), io_rStartIndex ),
2935 [ # # ][ # # ]: 0 : UpperBoundActionIndexComparator() );
[ # # ][ # # ]
[ # # ]
2936 : : o_rRangeEnd = ::std::lower_bound( aBegin, aEnd,
2937 : : MtfAction( ActionSharedPtr(), io_rEndIndex ),
2938 [ # # ][ # # ]: 0 : UpperBoundActionIndexComparator() );
[ # # ][ # # ]
[ # # ]
2939 : 0 : return true;
2940 : : }
2941 : :
2942 : :
2943 : : // Public methods
2944 : : // ====================================================================
2945 : :
2946 : 0 : ImplRenderer::ImplRenderer( const CanvasSharedPtr& rCanvas,
2947 : : const GDIMetaFile& rMtf,
2948 : : const Parameters& rParams ) :
2949 : : CanvasGraphicHelper( rCanvas ),
2950 [ # # ][ # # ]: 0 : maActions()
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
2951 : : {
2952 : : RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::ImplRenderer(mtf)" );
2953 : :
2954 : : OSL_ENSURE( rCanvas.get() != NULL && rCanvas->getUNOCanvas().is(),
2955 : : "ImplRenderer::ImplRenderer(): Invalid canvas" );
2956 : : OSL_ENSURE( rCanvas->getUNOCanvas()->getDevice().is(),
2957 : : "ImplRenderer::ImplRenderer(): Invalid graphic device" );
2958 : :
2959 : : // make sure canvas and graphic device are valid; action
2960 : : // creation don't check that every time
2961 [ # # # # : 0 : if( rCanvas.get() == NULL ||
# # ][ # # ]
[ # # # #
# # ][ # # ]
2962 [ # # ][ # # ]: 0 : !rCanvas->getUNOCanvas().is() ||
[ # # ][ # # ]
[ # # ][ # # ]
2963 [ # # ][ # # ]: 0 : !rCanvas->getUNOCanvas()->getDevice().is() )
[ # # ][ # # ]
[ # # ]
[ # # # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
[ # # # # ]
2964 : : {
2965 : : // leave actions empty
2966 : 0 : return;
2967 : : }
2968 : :
2969 [ # # ][ # # ]: 0 : VectorOfOutDevStates aStateStack;
2970 : :
2971 [ # # ][ # # ]: 0 : VirtualDevice aVDev;
2972 [ # # ][ # # ]: 0 : aVDev.EnableOutput( sal_False );
2973 : :
2974 : : // Setup VDev for state tracking and mapping
2975 : : // =========================================
2976 : :
2977 [ # # ][ # # ]: 0 : aVDev.SetMapMode( rMtf.GetPrefMapMode() );
2978 : :
2979 : 0 : const Size aMtfSize( rMtf.GetPrefSize() );
2980 : : const Size aMtfSizePixPre( aVDev.LogicToPixel( aMtfSize,
2981 [ # # # # ]: 0 : rMtf.GetPrefMapMode() ) );
2982 : :
2983 : : // #i44110# correct null-sized output - there are shapes
2984 : : // which have zero size in at least one dimension
2985 [ # # ][ # # ]: 0 : const Size aMtfSizePix( ::std::max( aMtfSizePixPre.Width(), 1L ),
2986 [ # # ][ # # ]: 0 : ::std::max( aMtfSizePixPre.Height(), 1L ) );
2987 : :
2988 : 0 : sal_Int32 nCurrActions(0);
2989 : : ActionFactoryParameters aParms(aStateStack,
2990 : : rCanvas,
2991 : : aVDev,
2992 : : rParams,
2993 : 0 : nCurrActions );
2994 : :
2995 : : // init state stack
2996 [ # # # # ]: 0 : aStateStack.clearStateStack();
2997 : :
2998 : : // Setup local state, such that the metafile renders
2999 : : // itself into a one-by-one square at the origin for
3000 : : // identity view and render transformations
3001 [ # # # # ]: 0 : aStateStack.getState().transform.scale( 1.0 / aMtfSizePix.Width(),
3002 [ # # ][ # # ]: 0 : 1.0 / aMtfSizePix.Height() );
3003 : :
3004 [ # # ][ # # ]: 0 : tools::calcLogic2PixelAffineTransform( aStateStack.getState().mapModeTransform,
3005 [ # # ][ # # ]: 0 : aVDev );
3006 : :
3007 [ # # ][ # # ]: 0 : ColorSharedPtr pColor( getCanvas()->createColor() );
[ # # ][ # # ]
[ # # ][ # # ]
3008 : :
3009 : : {
3010 [ # # ][ # # ]: 0 : ::cppcanvas::internal::OutDevState& rState = aStateStack.getState();
3011 : : // setup default text color to black
3012 : : rState.textColor =
3013 : : rState.textFillColor =
3014 [ # # ][ # # ]: 0 : rState.textLineColor = pColor->getDeviceColor( 0x000000FF );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
3015 : : }
3016 : :
3017 : : // apply overrides from the Parameters struct
3018 [ # # ][ # # ]: 0 : if( rParams.maFillColor.is_initialized() )
3019 : : {
3020 [ # # ][ # # ]: 0 : ::cppcanvas::internal::OutDevState& rState = aStateStack.getState();
3021 : 0 : rState.isFillColorSet = true;
3022 [ # # ][ # # ]: 0 : rState.fillColor = pColor->getDeviceColor( *rParams.maFillColor );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
3023 : : }
3024 [ # # ][ # # ]: 0 : if( rParams.maLineColor.is_initialized() )
3025 : : {
3026 [ # # ][ # # ]: 0 : ::cppcanvas::internal::OutDevState& rState = aStateStack.getState();
3027 : 0 : rState.isLineColorSet = true;
3028 [ # # ][ # # ]: 0 : rState.lineColor = pColor->getDeviceColor( *rParams.maLineColor );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
3029 : : }
3030 [ # # ][ # # ]: 0 : if( rParams.maTextColor.is_initialized() )
3031 : : {
3032 [ # # ][ # # ]: 0 : ::cppcanvas::internal::OutDevState& rState = aStateStack.getState();
3033 : 0 : rState.isTextFillColorSet = true;
3034 : 0 : rState.isTextLineColorSet = true;
3035 : : rState.textColor =
3036 : : rState.textFillColor =
3037 [ # # ][ # # ]: 0 : rState.textLineColor = pColor->getDeviceColor( *rParams.maTextColor );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
3038 : : }
3039 [ # # # # : 0 : if( rParams.maFontName.is_initialized() ||
# # # # #
# ][ # # ]
[ # # # #
# # # # #
# ][ # # ]
3040 : 0 : rParams.maFontWeight.is_initialized() ||
3041 : 0 : rParams.maFontLetterForm.is_initialized() ||
3042 : 0 : rParams.maFontUnderline.is_initialized() ||
3043 : 0 : rParams.maFontProportion.is_initialized() )
3044 : : {
3045 [ # # ][ # # ]: 0 : ::cppcanvas::internal::OutDevState& rState = aStateStack.getState();
3046 : :
3047 : : rState.xFont = createFont( rState.fontRotation,
3048 : : ::Font(), // default font
3049 [ # # ][ # # ]: 0 : aParms );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
3050 : : }
3051 : :
3052 : : /* EMF+ */
3053 : 0 : memset (aObjects, 0, sizeof (aObjects));
3054 : 0 : mbMultipart = false;
3055 : :
3056 : : createActions( const_cast<GDIMetaFile&>(rMtf), // HACK(Q2):
3057 : : // we're
3058 : : // changing
3059 : : // the
3060 : : // current
3061 : : // action
3062 : : // in
3063 : : // createActions!
3064 : : aParms,
3065 : : true // TODO(P1): make subsettability configurable
3066 [ # # ][ # # ]: 0 : );
[ # # ][ # # ]
[ # # ][ # # ]
3067 : : }
3068 : :
3069 [ # # ][ # # ]: 0 : ImplRenderer::~ImplRenderer()
[ # # ][ # # ]
[ # # ][ # # ]
3070 : : {
3071 [ # # ][ # # ]: 0 : }
[ # # ]
[ # # # # ]
[ # # ][ # # ]
[ # # ]
[ # # # # ]
3072 : :
3073 : 0 : bool ImplRenderer::drawSubset( sal_Int32 nStartIndex,
3074 : : sal_Int32 nEndIndex ) const
3075 : : {
3076 : : RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::drawSubset()" );
3077 : :
3078 : 0 : ActionVector::const_iterator aRangeBegin;
3079 : 0 : ActionVector::const_iterator aRangeEnd;
3080 : :
3081 : : try
3082 : : {
3083 [ # # ]: 0 : if( !getSubsetIndices( nStartIndex, nEndIndex,
3084 [ # # ]: 0 : aRangeBegin, aRangeEnd ) )
3085 : 0 : return true; // nothing to render (but _that_ was successful)
3086 : :
3087 : : // now, aRangeBegin references the action in which the
3088 : : // subset rendering must start, and aRangeEnd references
3089 : : // the action in which the subset rendering must end (it
3090 : : // might also end right at the start of the referenced
3091 : : // action, such that zero of that action needs to be
3092 : : // rendered).
3093 : :
3094 : :
3095 : : // render subset of actions
3096 : : // ========================
3097 : :
3098 [ # # ]: 0 : ::basegfx::B2DHomMatrix aMatrix;
3099 : : ::canvas::tools::getRenderStateTransform( aMatrix,
3100 [ # # ][ # # ]: 0 : getRenderState() );
3101 : :
3102 [ # # ]: 0 : ActionRenderer aRenderer( aMatrix );
3103 : :
3104 : : return forSubsetRange( aRenderer,
3105 : : aRangeBegin,
3106 : : aRangeEnd,
3107 : : nStartIndex,
3108 : : nEndIndex,
3109 [ # # ][ # # ]: 0 : maActions.end() );
[ # # ][ # # ]
3110 : : }
3111 [ # # ]: 0 : catch( uno::Exception& )
3112 : : {
3113 : : OSL_FAIL( rtl::OUStringToOString(
3114 : : comphelper::anyToString( cppu::getCaughtException() ),
3115 : : RTL_TEXTENCODING_UTF8 ).getStr() );
3116 : :
3117 : : // convert error to return value
3118 : 0 : return false;
3119 : : }
3120 : : }
3121 : :
3122 : 0 : ::basegfx::B2DRange ImplRenderer::getSubsetArea( sal_Int32 nStartIndex,
3123 : : sal_Int32 nEndIndex ) const
3124 : : {
3125 : : RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::getSubsetArea()" );
3126 : :
3127 : 0 : ActionVector::const_iterator aRangeBegin;
3128 : 0 : ActionVector::const_iterator aRangeEnd;
3129 : :
3130 [ # # ]: 0 : if( !getSubsetIndices( nStartIndex, nEndIndex,
3131 [ # # ]: 0 : aRangeBegin, aRangeEnd ) )
3132 [ # # ]: 0 : return ::basegfx::B2DRange(); // nothing to render -> empty range
3133 : :
3134 : : // now, aRangeBegin references the action in which the
3135 : : // subset querying must start, and aRangeEnd references
3136 : : // the action in which the subset querying must end (it
3137 : : // might also end right at the start of the referenced
3138 : : // action, such that zero of that action needs to be
3139 : : // queried).
3140 : :
3141 : :
3142 : : // query bounds for subset of actions
3143 : : // ==================================
3144 : :
3145 [ # # ]: 0 : ::basegfx::B2DHomMatrix aMatrix;
3146 : : ::canvas::tools::getRenderStateTransform( aMatrix,
3147 [ # # ][ # # ]: 0 : getRenderState() );
3148 : :
3149 [ # # ]: 0 : AreaQuery aQuery( aMatrix );
3150 : : forSubsetRange( aQuery,
3151 : : aRangeBegin,
3152 : : aRangeEnd,
3153 : : nStartIndex,
3154 : : nEndIndex,
3155 [ # # ]: 0 : maActions.end() );
3156 : :
3157 [ # # ][ # # ]: 0 : return aQuery.getBounds();
3158 : : }
3159 : :
3160 : 0 : bool ImplRenderer::draw() const
3161 : : {
3162 : : RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::draw()" );
3163 : :
3164 [ # # ]: 0 : ::basegfx::B2DHomMatrix aMatrix;
3165 : : ::canvas::tools::getRenderStateTransform( aMatrix,
3166 [ # # ][ # # ]: 0 : getRenderState() );
3167 : :
3168 : : try
3169 : : {
3170 [ # # ][ # # ]: 0 : return ::std::for_each( maActions.begin(), maActions.end(), ActionRenderer( aMatrix ) ).result();
[ # # ][ # # ]
[ # # ]
3171 : : }
3172 [ # # ]: 0 : catch( uno::Exception& )
3173 : : {
3174 : : OSL_FAIL( rtl::OUStringToOString(
3175 : : comphelper::anyToString( cppu::getCaughtException() ),
3176 : : RTL_TEXTENCODING_UTF8 ).getStr() );
3177 : :
3178 : 0 : return false;
3179 [ # # ]: 0 : }
3180 : : }
3181 : : }
3182 : : }
3183 : :
3184 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|