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 : :
34 : : #include <rtl/logfile.hxx>
35 : :
36 : : #include <com/sun/star/rendering/PathCapType.hpp>
37 : : #include <com/sun/star/rendering/PathJoinType.hpp>
38 : : #include <com/sun/star/rendering/XCanvas.hpp>
39 : : #include <com/sun/star/rendering/XCanvasFont.hpp>
40 : :
41 : : #include <basegfx/numeric/ftools.hxx>
42 : : #include <basegfx/matrix/b2dhommatrix.hxx>
43 : : #include <basegfx/range/b2drectangle.hxx>
44 : : #include <basegfx/vector/b2dsize.hxx>
45 : : #include <basegfx/polygon/b2dpolypolygontools.hxx>
46 : : #include <basegfx/polygon/b2dpolygontools.hxx>
47 : : #include <basegfx/matrix/b2dhommatrixtools.hxx>
48 : :
49 : : #include <tools/gen.hxx>
50 : : #include <vcl/canvastools.hxx>
51 : : #include <vcl/virdev.hxx>
52 : :
53 : : #include <basegfx/tools/canvastools.hxx>
54 : : #include <canvas/canvastools.hxx>
55 : :
56 : : #include <boost/scoped_array.hpp>
57 : : #include <boost/bind.hpp>
58 : : #include <boost/utility.hpp>
59 : :
60 : : #include "textaction.hxx"
61 : : #include "outdevstate.hxx"
62 : : #include "mtftools.hxx"
63 : :
64 : :
65 : : using namespace ::com::sun::star;
66 : :
67 : : namespace cppcanvas
68 : : {
69 : : namespace internal
70 : : {
71 : : namespace
72 : : {
73 : 0 : void init( rendering::RenderState& o_rRenderState,
74 : : const ::basegfx::B2DPoint& rStartPoint,
75 : : const OutDevState& rState,
76 : : const CanvasSharedPtr& rCanvas )
77 : : {
78 [ # # ]: 0 : tools::initRenderState(o_rRenderState,rState);
79 : :
80 : : // #i36950# Offset clip back to origin (as it's also moved
81 : : // by rStartPoint)
82 : : // #i53964# Also take VCL font rotation into account,
83 : : // since this, opposed to the FontMatrix rotation
84 : : // elsewhere, _does_ get incorporated into the render
85 : : // state transform.
86 : : tools::modifyClip( o_rRenderState,
87 : : rState,
88 : : rCanvas,
89 : : rStartPoint,
90 : : NULL,
91 [ # # ]: 0 : &rState.fontRotation );
92 : :
93 [ # # ]: 0 : basegfx::B2DHomMatrix aLocalTransformation(basegfx::tools::createRotateB2DHomMatrix(rState.fontRotation));
94 : : aLocalTransformation.translate( rStartPoint.getX(),
95 [ # # ]: 0 : rStartPoint.getY() );
96 : : ::canvas::tools::appendToRenderState( o_rRenderState,
97 [ # # ]: 0 : aLocalTransformation );
98 : :
99 [ # # ][ # # ]: 0 : o_rRenderState.DeviceColor = rState.textColor;
100 : 0 : }
101 : :
102 : 0 : void init( rendering::RenderState& o_rRenderState,
103 : : const ::basegfx::B2DPoint& rStartPoint,
104 : : const OutDevState& rState,
105 : : const CanvasSharedPtr& rCanvas,
106 : : const ::basegfx::B2DHomMatrix& rTextTransform )
107 : : {
108 : 0 : init( o_rRenderState, rStartPoint, rState, rCanvas );
109 : :
110 : : // TODO(F2): Also inversely-transform clip with
111 : : // rTextTransform (which is actually rather hard, as the
112 : : // text transform is _prepended_ to the render state)!
113 : :
114 : : // prepend extra font transform to render state
115 : : // (prepend it, because it's interpreted in the unit
116 : : // rect coordinate space)
117 : : ::canvas::tools::prependToRenderState( o_rRenderState,
118 : 0 : rTextTransform );
119 : 0 : }
120 : :
121 : 0 : void init( rendering::RenderState& o_rRenderState,
122 : : uno::Reference< rendering::XCanvasFont >& o_rFont,
123 : : const ::basegfx::B2DPoint& rStartPoint,
124 : : const OutDevState& rState,
125 : : const CanvasSharedPtr& rCanvas )
126 : : {
127 : : // ensure that o_rFont is valid. It is possible that
128 : : // text actions are generated without previously
129 : : // setting a font. Then, just take a default font
130 [ # # ]: 0 : if( !o_rFont.is() )
131 : : {
132 : : // Use completely default FontRequest
133 : 0 : const rendering::FontRequest aFontRequest;
134 : :
135 : 0 : geometry::Matrix2D aFontMatrix;
136 [ # # ]: 0 : ::canvas::tools::setIdentityMatrix2D( aFontMatrix );
137 : :
138 [ # # ][ # # ]: 0 : o_rFont = rCanvas->getUNOCanvas()->createFont(
139 : : aFontRequest,
140 : : uno::Sequence< beans::PropertyValue >(),
141 [ # # ][ # # ]: 0 : aFontMatrix );
[ # # ][ # # ]
142 : : }
143 : :
144 : : init( o_rRenderState,
145 : : rStartPoint,
146 : : rState,
147 : 0 : rCanvas );
148 : 0 : }
149 : :
150 : 0 : void init( rendering::RenderState& o_rRenderState,
151 : : uno::Reference< rendering::XCanvasFont >& o_rFont,
152 : : const ::basegfx::B2DPoint& rStartPoint,
153 : : const OutDevState& rState,
154 : : const CanvasSharedPtr& rCanvas,
155 : : const ::basegfx::B2DHomMatrix& rTextTransform )
156 : : {
157 : 0 : init( o_rRenderState, o_rFont, rStartPoint, rState, rCanvas );
158 : :
159 : : // TODO(F2): Also inversely-transform clip with
160 : : // rTextTransform (which is actually rather hard, as the
161 : : // text transform is _prepended_ to the render state)!
162 : :
163 : : // prepend extra font transform to render state
164 : : // (prepend it, because it's interpreted in the unit
165 : : // rect coordinate space)
166 : : ::canvas::tools::prependToRenderState( o_rRenderState,
167 : 0 : rTextTransform );
168 : 0 : }
169 : :
170 : 0 : ::basegfx::B2DPolyPolygon textLinesFromLogicalOffsets( const uno::Sequence< double >& rOffsets,
171 : : const tools::TextLineInfo& rTextLineInfo )
172 : : {
173 : : return tools::createTextLinesPolyPolygon(
174 : : 0.0,
175 : : // extract character cell furthest to the right
176 : : *(::std::max_element(
177 : : rOffsets.getConstArray(),
178 : 0 : rOffsets.getConstArray() + rOffsets.getLength() )),
179 [ # # ]: 0 : rTextLineInfo );
180 : : }
181 : :
182 : 0 : uno::Sequence< double > setupDXArray( const sal_Int32* pCharWidths,
183 : : sal_Int32 nLen,
184 : : const OutDevState& rState )
185 : : {
186 : : // convert character widths from logical units
187 : 0 : uno::Sequence< double > aCharWidthSeq( nLen );
188 [ # # ]: 0 : double* pOutputWidths( aCharWidthSeq.getArray() );
189 : :
190 : : // #143885# maintain (nearly) full precision of DX
191 : : // array, by circumventing integer-based
192 : : // OutDev-mapping
193 [ # # ]: 0 : const double nScale( rState.mapModeTransform.get(0,0) );
194 [ # # ]: 0 : for( int i = 0; i < nLen; ++i )
195 : : {
196 : : // TODO(F2): use correct scale direction
197 : 0 : *pOutputWidths++ = *pCharWidths++ * nScale;
198 : : }
199 : :
200 : 0 : return aCharWidthSeq;
201 : : }
202 : :
203 : 0 : uno::Sequence< double > setupDXArray( const ::String& rText,
204 : : sal_Int32 nStartPos,
205 : : sal_Int32 nLen,
206 : : VirtualDevice& rVDev,
207 : : const OutDevState& rState )
208 : : {
209 : : // no external DX array given, create one from given
210 : : // string
211 [ # # ]: 0 : ::boost::scoped_array< sal_Int32 > pCharWidths( new sal_Int32[nLen] );
212 : :
213 : : rVDev.GetTextArray( rText, pCharWidths.get(),
214 : : static_cast<sal_uInt16>(nStartPos),
215 [ # # ]: 0 : static_cast<sal_uInt16>(nLen) );
216 : :
217 [ # # ][ # # ]: 0 : return setupDXArray( pCharWidths.get(), nLen, rState );
218 : : }
219 : :
220 : 0 : ::basegfx::B2DPoint adaptStartPoint( const ::basegfx::B2DPoint& rStartPoint,
221 : : const OutDevState& rState,
222 : : const uno::Sequence< double >& rOffsets )
223 : : {
224 : 0 : ::basegfx::B2DPoint aLocalPoint( rStartPoint );
225 : :
226 [ # # ]: 0 : if( rState.textAlignment )
227 : : {
228 : : // text origin is right, not left. Modify start point
229 : : // accordingly, because XCanvas::drawTextLayout()
230 : : // always aligns left!
231 : :
232 : 0 : const double nOffset( rOffsets[ rOffsets.getLength()-1 ] );
233 : :
234 : : // correct start point for rotated text: rotate around
235 : : // former start point
236 : 0 : aLocalPoint.setX( aLocalPoint.getX() + cos( rState.fontRotation )*nOffset );
237 : 0 : aLocalPoint.setY( aLocalPoint.getY() + sin( rState.fontRotation )*nOffset );
238 : : }
239 : :
240 : 0 : return aLocalPoint;
241 : : }
242 : :
243 : : /** Perform common setup for array text actions
244 : :
245 : : This method creates the XTextLayout object and
246 : : initializes it, e.g. with the logical advancements.
247 : : */
248 : 0 : void initArrayAction( rendering::RenderState& o_rRenderState,
249 : : uno::Reference< rendering::XTextLayout >& o_rTextLayout,
250 : : const ::basegfx::B2DPoint& rStartPoint,
251 : : const ::rtl::OUString& rText,
252 : : sal_Int32 nStartPos,
253 : : sal_Int32 nLen,
254 : : const uno::Sequence< double >& rOffsets,
255 : : const CanvasSharedPtr& rCanvas,
256 : : const OutDevState& rState,
257 : : const ::basegfx::B2DHomMatrix* pTextTransform )
258 : : {
259 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( rOffsets.getLength(),
[ # # ][ # # ]
260 : : "::cppcanvas::internal::initArrayAction(): zero-length DX array" );
261 : :
262 : : const ::basegfx::B2DPoint aLocalStartPoint(
263 [ # # ]: 0 : adaptStartPoint( rStartPoint, rState, rOffsets ) );
264 : :
265 : 0 : uno::Reference< rendering::XCanvasFont > xFont( rState.xFont );
266 : :
267 [ # # ]: 0 : if( pTextTransform )
268 [ # # ]: 0 : init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas, *pTextTransform );
269 : : else
270 [ # # ]: 0 : init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas );
271 : :
272 [ # # ]: 0 : o_rTextLayout = xFont->createTextLayout(
273 : : rendering::StringContext( rText, nStartPos, nLen ),
274 : : rState.textDirection,
275 [ # # ][ # # ]: 0 : 0 );
276 : :
277 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( o_rTextLayout.is(),
[ # # ][ # # ]
278 : : "::cppcanvas::internal::initArrayAction(): Invalid font" );
279 : :
280 [ # # ][ # # ]: 0 : o_rTextLayout->applyLogicalAdvancements( rOffsets );
281 : 0 : }
282 : :
283 : 0 : double getLineWidth( ::VirtualDevice& rVDev,
284 : : const OutDevState& rState,
285 : : const rendering::StringContext& rStringContext )
286 : : {
287 : : // TODO(F2): use correct scale direction
288 : : const ::basegfx::B2DSize aSize( rVDev.GetTextWidth( rStringContext.Text,
289 : : static_cast<sal_uInt16>(rStringContext.StartPosition),
290 [ # # ]: 0 : static_cast<sal_uInt16>(rStringContext.Length) ),
[ # # # # ]
291 : 0 : 0 );
292 : :
293 [ # # ]: 0 : return (rState.mapModeTransform * aSize).getX();
294 : : }
295 : :
296 : : uno::Sequence< double >
297 : 0 : calcSubsetOffsets( rendering::RenderState& io_rRenderState,
298 : : double& o_rMinPos,
299 : : double& o_rMaxPos,
300 : : const uno::Reference< rendering::XTextLayout >& rOrigTextLayout,
301 : : const ::cppcanvas::internal::Action::Subset& rSubset )
302 : : {
303 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( rSubset.mnSubsetEnd > rSubset.mnSubsetBegin,
[ # # ][ # # ]
304 : : "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
305 : :
306 [ # # ][ # # ]: 0 : uno::Sequence< double > aOrigOffsets( rOrigTextLayout->queryLogicalAdvancements() );
307 : 0 : const double* pOffsets( aOrigOffsets.getConstArray() );
308 : :
309 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( aOrigOffsets.getLength() >= rSubset.mnSubsetEnd,
[ # # ][ # # ]
310 : : "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
311 : :
312 : : // TODO(F3): It currently seems that for RTL text, the
313 : : // DX offsets are nevertheless increasing in logical
314 : : // text order (I'd expect they are decreasing,
315 : : // mimicking the fact that the text is output
316 : : // right-to-left). This breaks text effects for ALL
317 : : // RTL languages.
318 : :
319 : : // determine leftmost position in given subset range -
320 : : // as the DX array contains the output positions
321 : : // starting with the second character (the first is
322 : : // assumed to have output position 0), correct begin
323 : : // iterator.
324 : : const double nMinPos( rSubset.mnSubsetBegin <= 0 ? 0 :
325 : : *(::std::min_element( pOffsets+rSubset.mnSubsetBegin-1,
326 [ # # ][ # # ]: 0 : pOffsets+rSubset.mnSubsetEnd )) );
327 : :
328 : : // determine rightmost position in given subset range
329 : : // - as the DX array contains the output positions
330 : : // starting with the second character (the first is
331 : : // assumed to have output position 0), correct begin
332 : : // iterator.
333 : : const double nMaxPos(
334 : : *(::std::max_element( pOffsets + (rSubset.mnSubsetBegin <= 0 ?
335 : : 0 : rSubset.mnSubsetBegin-1),
336 [ # # ][ # # ]: 0 : pOffsets + rSubset.mnSubsetEnd )) );
337 : :
338 : :
339 : : // adapt render state, to move text output to given offset
340 : : // -------------------------------------------------------
341 : :
342 : : // TODO(F1): Strictly speaking, we also have to adapt
343 : : // the clip here, which normally should _not_ move
344 : : // with the output offset. Neglected for now, as it
345 : : // does not matter for drawing layer output
346 : :
347 [ # # ]: 0 : if( rSubset.mnSubsetBegin > 0 )
348 : : {
349 [ # # ]: 0 : ::basegfx::B2DHomMatrix aTranslation;
350 [ # # ][ # # ]: 0 : if( rOrigTextLayout->getFont()->getFontRequest().FontDescription.IsVertical )
[ # # ][ # # ]
[ # # ]
351 : : {
352 : : // vertical text -> offset in y direction
353 [ # # ]: 0 : aTranslation.translate( 0.0, nMinPos );
354 : : }
355 : : else
356 : : {
357 : : // horizontal text -> offset in x direction
358 [ # # ]: 0 : aTranslation.translate( nMinPos, 0.0 );
359 : : }
360 : :
361 : : ::canvas::tools::appendToRenderState( io_rRenderState,
362 [ # # ][ # # ]: 0 : aTranslation );
363 : : }
364 : :
365 : :
366 : : // reduce DX array to given substring
367 : : // ----------------------------------
368 : :
369 : 0 : const sal_Int32 nNewElements( rSubset.mnSubsetEnd - rSubset.mnSubsetBegin );
370 [ # # ]: 0 : uno::Sequence< double > aAdaptedOffsets( nNewElements );
371 [ # # ]: 0 : double* pAdaptedOffsets( aAdaptedOffsets.getArray() );
372 : :
373 : : // move to new output position (subtract nMinPos,
374 : : // which is the new '0' position), copy only the range
375 : : // as given by rSubset.
376 : : ::std::transform( pOffsets + rSubset.mnSubsetBegin,
377 : : pOffsets + rSubset.mnSubsetEnd,
378 : : pAdaptedOffsets,
379 : : ::boost::bind( ::std::minus<double>(),
380 : : _1,
381 [ # # ][ # # ]: 0 : nMinPos ) );
382 : :
383 : 0 : o_rMinPos = nMinPos;
384 : 0 : o_rMaxPos = nMaxPos;
385 : :
386 [ # # ]: 0 : return aAdaptedOffsets;
387 : : }
388 : :
389 : : uno::Reference< rendering::XTextLayout >
390 : 0 : createSubsetLayout( const rendering::StringContext& rOrigContext,
391 : : const ::cppcanvas::internal::Action::Subset& rSubset,
392 : : const uno::Reference< rendering::XTextLayout >& rOrigTextLayout )
393 : : {
394 : : // create temporary new text layout with subset string
395 : : // ---------------------------------------------------
396 : :
397 : : const sal_Int32 nNewStartPos( rOrigContext.StartPosition + ::std::min(
398 [ # # ]: 0 : rSubset.mnSubsetBegin, rOrigContext.Length-1 ) );
399 : : const sal_Int32 nNewLength( ::std::max(
400 : : ::std::min(
401 : : rSubset.mnSubsetEnd - rSubset.mnSubsetBegin,
402 [ # # ]: 0 : rOrigContext.Length ),
403 [ # # ]: 0 : sal_Int32( 0 ) ) );
404 : :
405 : : const rendering::StringContext aContext( rOrigContext.Text,
406 : : nNewStartPos,
407 : 0 : nNewLength );
408 : :
409 : : uno::Reference< rendering::XTextLayout > xTextLayout(
410 [ # # ][ # # ]: 0 : rOrigTextLayout->getFont()->createTextLayout( aContext,
[ # # ]
411 [ # # ][ # # ]: 0 : rOrigTextLayout->getMainTextDirection(),
412 : 0 : 0 ),
413 [ # # ][ # # ]: 0 : uno::UNO_QUERY_THROW );
414 : :
415 : 0 : return xTextLayout;
416 : : }
417 : :
418 : : /** Setup subset text layout
419 : :
420 : : @param io_rTextLayout
421 : : Must contain original (full set) text layout on input,
422 : : will contain subsetted text layout (or empty
423 : : reference, for empty subsets) on output.
424 : :
425 : : @param io_rRenderState
426 : : Must contain original render state on input, will
427 : : contain shifted render state concatenated with
428 : : rTransformation on output.
429 : :
430 : : @param rTransformation
431 : : Additional transformation, to be prepended to render
432 : : state
433 : :
434 : : @param rSubset
435 : : Subset to prepare
436 : : */
437 : 0 : void createSubsetLayout( uno::Reference< rendering::XTextLayout >& io_rTextLayout,
438 : : rendering::RenderState& io_rRenderState,
439 : : double& o_rMinPos,
440 : : double& o_rMaxPos,
441 : : const ::basegfx::B2DHomMatrix& rTransformation,
442 : : const Action::Subset& rSubset )
443 : : {
444 [ # # ]: 0 : ::canvas::tools::prependToRenderState(io_rRenderState, rTransformation);
445 : :
446 [ # # ]: 0 : if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd )
447 : : {
448 : : // empty range, empty layout
449 : 0 : io_rTextLayout.clear();
450 : :
451 : : return;
452 : : }
453 : :
454 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( io_rTextLayout.is(),
[ # # ][ # # ]
455 : : "createSubsetLayout(): Invalid input layout" );
456 : :
457 [ # # ][ # # ]: 0 : const rendering::StringContext& rOrigContext( io_rTextLayout->getText() );
458 : :
459 [ # # ][ # # ]: 0 : if( rSubset.mnSubsetBegin == 0 &&
460 : : rSubset.mnSubsetEnd == rOrigContext.Length )
461 : : {
462 : : // full range, no need for subsetting
463 : : return;
464 : : }
465 : :
466 : : uno::Reference< rendering::XTextLayout > xTextLayout(
467 [ # # ]: 0 : createSubsetLayout( rOrigContext, rSubset, io_rTextLayout ) );
468 : :
469 [ # # ]: 0 : if( xTextLayout.is() )
470 : : {
471 [ # # ]: 0 : xTextLayout->applyLogicalAdvancements(
472 : : calcSubsetOffsets( io_rRenderState,
473 : : o_rMinPos,
474 : : o_rMaxPos,
475 : : io_rTextLayout,
476 [ # # ][ # # ]: 0 : rSubset ) );
[ # # ]
477 : : }
478 : :
479 [ # # ][ # # ]: 0 : io_rTextLayout = xTextLayout;
480 : : }
481 : :
482 : :
483 : : /** Interface for renderEffectText functor below.
484 : :
485 : : This is interface is used from the renderEffectText()
486 : : method below, to call the client implementation.
487 : : */
488 : 0 : class TextRenderer
489 : : {
490 : : public:
491 [ # # ]: 0 : virtual ~TextRenderer() {}
492 : :
493 : : /// Render text with given RenderState
494 : : virtual bool operator()( const rendering::RenderState& rRenderState ) const = 0;
495 : : };
496 : :
497 : : /** Render effect text.
498 : :
499 : : @param rRenderer
500 : : Functor object, will be called to render the actual
501 : : part of the text effect (the text itself and the means
502 : : to render it are unknown to this method)
503 : : */
504 : 0 : bool renderEffectText( const TextRenderer& rRenderer,
505 : : const rendering::RenderState& rRenderState,
506 : : const rendering::ViewState& /*rViewState*/,
507 : : const uno::Reference< rendering::XCanvas >& xCanvas,
508 : : const ::Color& rShadowColor,
509 : : const ::basegfx::B2DSize& rShadowOffset,
510 : : const ::Color& rReliefColor,
511 : : const ::basegfx::B2DSize& rReliefOffset )
512 : : {
513 : 0 : ::Color aEmptyColor( COL_AUTO );
514 : : uno::Reference<rendering::XColorSpace> xColorSpace(
515 [ # # ][ # # ]: 0 : xCanvas->getDevice()->getDeviceColorSpace() );
[ # # ][ # # ]
516 : :
517 : : // draw shadow text, if enabled
518 [ # # ]: 0 : if( rShadowColor != aEmptyColor )
519 : : {
520 [ # # ]: 0 : rendering::RenderState aShadowState( rRenderState );
521 [ # # ]: 0 : ::basegfx::B2DHomMatrix aTranslate;
522 : :
523 : : aTranslate.translate( rShadowOffset.getX(),
524 [ # # ]: 0 : rShadowOffset.getY() );
525 : :
526 [ # # ]: 0 : ::canvas::tools::appendToRenderState(aShadowState, aTranslate);
527 : :
528 : : aShadowState.DeviceColor =
529 : : ::vcl::unotools::colorToDoubleSequence( rShadowColor,
530 [ # # ][ # # ]: 0 : xColorSpace );
[ # # ]
531 : :
532 [ # # ][ # # ]: 0 : rRenderer( aShadowState );
[ # # ]
533 : : }
534 : :
535 : : // draw relief text, if enabled
536 [ # # ]: 0 : if( rReliefColor != aEmptyColor )
537 : : {
538 [ # # ]: 0 : rendering::RenderState aReliefState( rRenderState );
539 [ # # ]: 0 : ::basegfx::B2DHomMatrix aTranslate;
540 : :
541 : : aTranslate.translate( rReliefOffset.getX(),
542 [ # # ]: 0 : rReliefOffset.getY() );
543 : :
544 [ # # ]: 0 : ::canvas::tools::appendToRenderState(aReliefState, aTranslate);
545 : :
546 : : aReliefState.DeviceColor =
547 : : ::vcl::unotools::colorToDoubleSequence( rReliefColor,
548 [ # # ][ # # ]: 0 : xColorSpace );
[ # # ]
549 : :
550 [ # # ][ # # ]: 0 : rRenderer( aReliefState );
[ # # ]
551 : : }
552 : :
553 : : // draw normal text
554 [ # # ]: 0 : rRenderer( rRenderState );
555 : :
556 : 0 : return true;
557 : : }
558 : :
559 : :
560 : 0 : ::basegfx::B2DRange calcEffectTextBounds( const ::basegfx::B2DRange& rTextBounds,
561 : : const ::basegfx::B2DRange& rLineBounds,
562 : : const ::basegfx::B2DSize& rReliefOffset,
563 : : const ::basegfx::B2DSize& rShadowOffset,
564 : : const rendering::RenderState& rRenderState,
565 : : const rendering::ViewState& rViewState )
566 : : {
567 : 0 : ::basegfx::B2DRange aBounds( rTextBounds );
568 : :
569 : : // add extends of text lines
570 [ # # ]: 0 : aBounds.expand( rLineBounds );
571 : :
572 : : // TODO(Q3): Provide this functionality at the B2DRange
573 : 0 : ::basegfx::B2DRange aTotalBounds( aBounds );
574 : : aTotalBounds.expand(
575 [ # # ]: 0 : ::basegfx::B2DRange( aBounds.getMinX() + rReliefOffset.getX(),
576 [ # # ]: 0 : aBounds.getMinY() + rReliefOffset.getY(),
577 [ # # ]: 0 : aBounds.getMaxX() + rReliefOffset.getX(),
578 [ # # ][ # # ]: 0 : aBounds.getMaxY() + rReliefOffset.getY() ) );
[ # # ]
579 : : aTotalBounds.expand(
580 [ # # ]: 0 : ::basegfx::B2DRange( aBounds.getMinX() + rShadowOffset.getX(),
581 [ # # ]: 0 : aBounds.getMinY() + rShadowOffset.getY(),
582 [ # # ]: 0 : aBounds.getMaxX() + rShadowOffset.getX(),
583 [ # # ][ # # ]: 0 : aBounds.getMaxY() + rShadowOffset.getY() ) );
[ # # ]
584 : :
585 : : return tools::calcDevicePixelBounds( aTotalBounds,
586 : : rViewState,
587 [ # # ]: 0 : rRenderState );
588 : : }
589 : :
590 : 0 : void initEffectLinePolyPolygon( ::basegfx::B2DSize& o_rOverallSize,
591 : : uno::Reference< rendering::XPolyPolygon2D >& o_rTextLines,
592 : : const CanvasSharedPtr& rCanvas,
593 : : const uno::Sequence< double >& rOffsets,
594 : : const tools::TextLineInfo rLineInfo )
595 : : {
596 : : const ::basegfx::B2DPolyPolygon aPoly(
597 : : textLinesFromLogicalOffsets(
598 : : rOffsets,
599 [ # # ]: 0 : rLineInfo ) );
600 : :
601 [ # # ][ # # ]: 0 : o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange();
[ # # ]
602 : :
603 : : o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
604 [ # # ][ # # ]: 0 : rCanvas->getUNOCanvas()->getDevice(),
605 [ # # ][ # # ]: 0 : aPoly );
[ # # ][ # # ]
606 : 0 : }
607 : :
608 : 0 : void initEffectLinePolyPolygon( ::basegfx::B2DSize& o_rOverallSize,
609 : : uno::Reference< rendering::XPolyPolygon2D >& o_rTextLines,
610 : : const CanvasSharedPtr& rCanvas,
611 : : double nLineWidth,
612 : : const tools::TextLineInfo rLineInfo )
613 : : {
614 : : const ::basegfx::B2DPolyPolygon aPoly(
615 : : tools::createTextLinesPolyPolygon( 0.0, nLineWidth,
616 [ # # ]: 0 : rLineInfo ) );
617 : :
618 [ # # ][ # # ]: 0 : o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange();
[ # # ]
619 : :
620 : : o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
621 [ # # ][ # # ]: 0 : rCanvas->getUNOCanvas()->getDevice(),
622 [ # # ][ # # ]: 0 : aPoly );
[ # # ][ # # ]
623 : 0 : }
624 : :
625 : :
626 : : // -------------------------------------------------------------------------
627 : :
628 [ # # ][ # # ]: 0 : class TextAction : public Action, private ::boost::noncopyable
[ # # ]
629 : : {
630 : : public:
631 : : TextAction( const ::basegfx::B2DPoint& rStartPoint,
632 : : const ::rtl::OUString& rString,
633 : : sal_Int32 nStartPos,
634 : : sal_Int32 nLen,
635 : : const CanvasSharedPtr& rCanvas,
636 : : const OutDevState& rState );
637 : :
638 : : TextAction( const ::basegfx::B2DPoint& rStartPoint,
639 : : const ::rtl::OUString& rString,
640 : : sal_Int32 nStartPos,
641 : : sal_Int32 nLen,
642 : : const CanvasSharedPtr& rCanvas,
643 : : const OutDevState& rState,
644 : : const ::basegfx::B2DHomMatrix& rTextTransform );
645 : :
646 : : virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
647 : : virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
648 : : const Subset& rSubset ) const;
649 : :
650 : : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
651 : : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
652 : : const Subset& rSubset ) const;
653 : :
654 : : virtual sal_Int32 getActionCount() const;
655 : :
656 : : private:
657 : : // TODO(P2): This is potentially a real mass object
658 : : // (every character might be a separate TextAction),
659 : : // thus, make it as lightweight as possible. For
660 : : // example, share common RenderState among several
661 : : // TextActions, maybe using maOffsets for the
662 : : // translation.
663 : :
664 : : uno::Reference< rendering::XCanvasFont > mxFont;
665 : : const rendering::StringContext maStringContext;
666 : : const CanvasSharedPtr mpCanvas;
667 : : rendering::RenderState maState;
668 : : const sal_Int8 maTextDirection;
669 : : };
670 : :
671 : 0 : TextAction::TextAction( const ::basegfx::B2DPoint& rStartPoint,
672 : : const ::rtl::OUString& rString,
673 : : sal_Int32 nStartPos,
674 : : sal_Int32 nLen,
675 : : const CanvasSharedPtr& rCanvas,
676 : : const OutDevState& rState ) :
677 : : mxFont( rState.xFont ),
678 : : maStringContext( rString, nStartPos, nLen ),
679 : : mpCanvas( rCanvas ),
680 : : maState(),
681 [ # # ][ # # ]: 0 : maTextDirection( rState.textDirection )
682 : : {
683 : : init( maState, mxFont,
684 : : rStartPoint,
685 [ # # ]: 0 : rState, rCanvas );
686 : :
687 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( mxFont.is(),
[ # # ][ # # ]
688 : : "::cppcanvas::internal::TextAction(): Invalid font" );
689 : 0 : }
690 : :
691 : 0 : TextAction::TextAction( const ::basegfx::B2DPoint& rStartPoint,
692 : : const ::rtl::OUString& rString,
693 : : sal_Int32 nStartPos,
694 : : sal_Int32 nLen,
695 : : const CanvasSharedPtr& rCanvas,
696 : : const OutDevState& rState,
697 : : const ::basegfx::B2DHomMatrix& rTextTransform ) :
698 : : mxFont( rState.xFont ),
699 : : maStringContext( rString, nStartPos, nLen ),
700 : : mpCanvas( rCanvas ),
701 : : maState(),
702 [ # # ][ # # ]: 0 : maTextDirection( rState.textDirection )
703 : : {
704 : : init( maState, mxFont,
705 : : rStartPoint,
706 [ # # ]: 0 : rState, rCanvas, rTextTransform );
707 : :
708 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( mxFont.is(),
[ # # ][ # # ]
709 : : "::cppcanvas::internal::TextAction(): Invalid font" );
710 : 0 : }
711 : :
712 : 0 : bool TextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
713 : : {
714 : : RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextAction::render()" );
715 : : RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextAction: 0x%X", this );
716 : :
717 [ # # ]: 0 : rendering::RenderState aLocalState( maState );
718 [ # # ]: 0 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
719 : :
720 [ # # ][ # # ]: 0 : mpCanvas->getUNOCanvas()->drawText( maStringContext, mxFont,
721 [ # # ][ # # ]: 0 : mpCanvas->getViewState(), aLocalState, maTextDirection );
[ # # ]
722 : :
723 [ # # ]: 0 : return true;
724 : : }
725 : :
726 : 0 : bool TextAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
727 : : const Subset& /*rSubset*/ ) const
728 : : {
729 : : OSL_FAIL( "TextAction::renderSubset(): Subset not supported by this object" );
730 : :
731 : : // TODO(P1): Retrieve necessary font metric info for
732 : : // TextAction from XCanvas. Currently, the
733 : : // TextActionFactory does not generate this object for
734 : : // _subsettable_ text
735 : 0 : return render( rTransformation );
736 : : }
737 : :
738 : 0 : ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
739 : : {
740 : : // create XTextLayout, to have the
741 : : // XTextLayout::queryTextBounds() method available
742 : : uno::Reference< rendering::XTextLayout > xTextLayout(
743 [ # # ]: 0 : mxFont->createTextLayout(
744 : : maStringContext,
745 : : maTextDirection,
746 [ # # ]: 0 : 0 ) );
747 : :
748 [ # # ]: 0 : rendering::RenderState aLocalState( maState );
749 [ # # ]: 0 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
750 : :
751 : : return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
752 [ # # ][ # # ]: 0 : xTextLayout->queryTextBounds() ),
753 : 0 : mpCanvas->getViewState(),
754 [ # # ][ # # ]: 0 : aLocalState );
[ # # ][ # # ]
[ # # ]
755 : : }
756 : :
757 : 0 : ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
758 : : const Subset& /*rSubset*/ ) const
759 : : {
760 : : OSL_FAIL( "TextAction::getBounds(): Subset not supported by this object" );
761 : :
762 : : // TODO(P1): Retrieve necessary font metric info for
763 : : // TextAction from XCanvas. Currently, the
764 : : // TextActionFactory does not generate this object for
765 : : // _subsettable_ text
766 : 0 : return getBounds( rTransformation );
767 : : }
768 : :
769 : 0 : sal_Int32 TextAction::getActionCount() const
770 : : {
771 : : // TODO(P1): Retrieve necessary font metric info for
772 : : // TextAction from XCanvas. Currently, the
773 : : // TextActionFactory does not generate this object for
774 : : // _subsettable_ text
775 : 0 : return 1;
776 : : }
777 : :
778 : :
779 : : // -------------------------------------------------------------------------
780 : :
781 [ # # ][ # # ]: 0 : class EffectTextAction :
[ # # ]
782 : : public Action,
783 : : public TextRenderer,
784 : : private ::boost::noncopyable
785 : : {
786 : : public:
787 : : EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
788 : : const ::basegfx::B2DSize& rReliefOffset,
789 : : const ::Color& rReliefColor,
790 : : const ::basegfx::B2DSize& rShadowOffset,
791 : : const ::Color& rShadowColor,
792 : : const ::rtl::OUString& rText,
793 : : sal_Int32 nStartPos,
794 : : sal_Int32 nLen,
795 : : VirtualDevice& rVDev,
796 : : const CanvasSharedPtr& rCanvas,
797 : : const OutDevState& rState );
798 : :
799 : : EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
800 : : const ::basegfx::B2DSize& rReliefOffset,
801 : : const ::Color& rReliefColor,
802 : : const ::basegfx::B2DSize& rShadowOffset,
803 : : const ::Color& rShadowColor,
804 : : const ::rtl::OUString& rText,
805 : : sal_Int32 nStartPos,
806 : : sal_Int32 nLen,
807 : : VirtualDevice& rVDev,
808 : : const CanvasSharedPtr& rCanvas,
809 : : const OutDevState& rState,
810 : : const ::basegfx::B2DHomMatrix& rTextTransform );
811 : :
812 : : virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
813 : : virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
814 : : const Subset& rSubset ) const;
815 : :
816 : : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
817 : : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
818 : : const Subset& rSubset ) const;
819 : :
820 : : virtual sal_Int32 getActionCount() const;
821 : :
822 : : private:
823 : : /// Interface TextRenderer
824 : : virtual bool operator()( const rendering::RenderState& rRenderState ) const;
825 : :
826 : : // TODO(P2): This is potentially a real mass object
827 : : // (every character might be a separate TextAction),
828 : : // thus, make it as lightweight as possible. For
829 : : // example, share common RenderState among several
830 : : // TextActions, maybe using maOffsets for the
831 : : // translation.
832 : :
833 : : uno::Reference< rendering::XCanvasFont > mxFont;
834 : : const rendering::StringContext maStringContext;
835 : : const CanvasSharedPtr mpCanvas;
836 : : rendering::RenderState maState;
837 : : const tools::TextLineInfo maTextLineInfo;
838 : : ::basegfx::B2DSize maLinesOverallSize;
839 : : const double mnLineWidth;
840 : : uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
841 : : const ::basegfx::B2DSize maReliefOffset;
842 : : const ::Color maReliefColor;
843 : : const ::basegfx::B2DSize maShadowOffset;
844 : : const ::Color maShadowColor;
845 : : const sal_Int8 maTextDirection;
846 : : };
847 : :
848 : 0 : EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
849 : : const ::basegfx::B2DSize& rReliefOffset,
850 : : const ::Color& rReliefColor,
851 : : const ::basegfx::B2DSize& rShadowOffset,
852 : : const ::Color& rShadowColor,
853 : : const ::rtl::OUString& rText,
854 : : sal_Int32 nStartPos,
855 : : sal_Int32 nLen,
856 : : VirtualDevice& rVDev,
857 : : const CanvasSharedPtr& rCanvas,
858 : : const OutDevState& rState ) :
859 : : mxFont( rState.xFont ),
860 : : maStringContext( rText, nStartPos, nLen ),
861 : : mpCanvas( rCanvas ),
862 : : maState(),
863 : : maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
864 : : maLinesOverallSize(),
865 [ # # ]: 0 : mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ),
866 : : mxTextLines(),
867 : : maReliefOffset( rReliefOffset ),
868 : : maReliefColor( rReliefColor ),
869 : : maShadowOffset( rShadowOffset ),
870 : : maShadowColor( rShadowColor ),
871 [ # # ][ # # ]: 0 : maTextDirection( rState.textDirection )
[ # # ]
872 : : {
873 : : initEffectLinePolyPolygon( maLinesOverallSize,
874 : : mxTextLines,
875 : : rCanvas,
876 : : mnLineWidth,
877 [ # # ]: 0 : maTextLineInfo );
878 : :
879 : : init( maState, mxFont,
880 : : rStartPoint,
881 [ # # ]: 0 : rState, rCanvas );
882 : :
883 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(),
[ # # ][ # # ]
[ # # ][ # # ]
884 : : "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
885 : 0 : }
886 : :
887 : 0 : EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
888 : : const ::basegfx::B2DSize& rReliefOffset,
889 : : const ::Color& rReliefColor,
890 : : const ::basegfx::B2DSize& rShadowOffset,
891 : : const ::Color& rShadowColor,
892 : : const ::rtl::OUString& rText,
893 : : sal_Int32 nStartPos,
894 : : sal_Int32 nLen,
895 : : VirtualDevice& rVDev,
896 : : const CanvasSharedPtr& rCanvas,
897 : : const OutDevState& rState,
898 : : const ::basegfx::B2DHomMatrix& rTextTransform ) :
899 : : mxFont( rState.xFont ),
900 : : maStringContext( rText, nStartPos, nLen ),
901 : : mpCanvas( rCanvas ),
902 : : maState(),
903 : : maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
904 : : maLinesOverallSize(),
905 [ # # ]: 0 : mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ),
906 : : mxTextLines(),
907 : : maReliefOffset( rReliefOffset ),
908 : : maReliefColor( rReliefColor ),
909 : : maShadowOffset( rShadowOffset ),
910 : : maShadowColor( rShadowColor ),
911 [ # # ][ # # ]: 0 : maTextDirection( rState.textDirection )
[ # # ]
912 : : {
913 : : initEffectLinePolyPolygon( maLinesOverallSize,
914 : : mxTextLines,
915 : : rCanvas,
916 : : mnLineWidth,
917 [ # # ]: 0 : maTextLineInfo );
918 : :
919 : : init( maState, mxFont,
920 : : rStartPoint,
921 [ # # ]: 0 : rState, rCanvas, rTextTransform );
922 : :
923 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(),
[ # # ][ # # ]
[ # # ][ # # ]
924 : : "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
925 : 0 : }
926 : :
927 : 0 : bool EffectTextAction::operator()( const rendering::RenderState& rRenderState ) const
928 : : {
929 : 0 : const rendering::ViewState& rViewState( mpCanvas->getViewState() );
930 [ # # ]: 0 : const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
931 : :
932 [ # # ]: 0 : rCanvas->fillPolyPolygon( mxTextLines,
933 : : rViewState,
934 [ # # ]: 0 : rRenderState );
935 : :
936 [ # # ]: 0 : rCanvas->drawText( maStringContext, mxFont,
937 : : rViewState,
938 : : rRenderState,
939 [ # # ]: 0 : maTextDirection );
940 : :
941 : 0 : return true;
942 : : }
943 : :
944 : 0 : bool EffectTextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
945 : : {
946 : : RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextAction::render()" );
947 : : RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextAction: 0x%X", this );
948 : :
949 [ # # ]: 0 : rendering::RenderState aLocalState( maState );
950 [ # # ]: 0 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
951 : :
952 : : return renderEffectText( *this,
953 : : aLocalState,
954 : 0 : mpCanvas->getViewState(),
955 : 0 : mpCanvas->getUNOCanvas(),
956 : : maShadowColor,
957 : : maShadowOffset,
958 : : maReliefColor,
959 [ # # ][ # # ]: 0 : maReliefOffset );
[ # # ]
[ # # # # ]
960 : : }
961 : :
962 : 0 : bool EffectTextAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
963 : : const Subset& /*rSubset*/ ) const
964 : : {
965 : : OSL_FAIL( "EffectTextAction::renderSubset(): Subset not supported by this object" );
966 : :
967 : : // TODO(P1): Retrieve necessary font metric info for
968 : : // TextAction from XCanvas. Currently, the
969 : : // TextActionFactory does not generate this object for
970 : : // subsettable text
971 : 0 : return render( rTransformation );
972 : : }
973 : :
974 : 0 : ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
975 : : {
976 : : // create XTextLayout, to have the
977 : : // XTextLayout::queryTextBounds() method available
978 : : uno::Reference< rendering::XTextLayout > xTextLayout(
979 [ # # ]: 0 : mxFont->createTextLayout(
980 : : maStringContext,
981 : : maTextDirection,
982 [ # # ]: 0 : 0 ) );
983 : :
984 [ # # ]: 0 : rendering::RenderState aLocalState( maState );
985 [ # # ]: 0 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
986 : :
987 : : return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
988 [ # # ][ # # ]: 0 : xTextLayout->queryTextBounds() ),
989 : : ::basegfx::B2DRange( 0,0,
990 : : maLinesOverallSize.getX(),
991 : : maLinesOverallSize.getY() ),
992 : : maReliefOffset,
993 : : maShadowOffset,
994 : : aLocalState,
995 [ # # ][ # # ]: 0 : mpCanvas->getViewState() );
[ # # ][ # # ]
[ # # ][ # # ]
996 : : }
997 : :
998 : 0 : ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
999 : : const Subset& /*rSubset*/ ) const
1000 : : {
1001 : : OSL_FAIL( "EffectTextAction::getBounds(): Subset not supported by this object" );
1002 : :
1003 : : // TODO(P1): Retrieve necessary font metric info for
1004 : : // TextAction from XCanvas. Currently, the
1005 : : // TextActionFactory does not generate this object for
1006 : : // _subsettable_ text
1007 : 0 : return getBounds( rTransformation );
1008 : : }
1009 : :
1010 : 0 : sal_Int32 EffectTextAction::getActionCount() const
1011 : : {
1012 : : // TODO(P1): Retrieve necessary font metric info for
1013 : : // TextAction from XCanvas. Currently, the
1014 : : // TextActionFactory does not generate this object for
1015 : : // subsettable text
1016 : 0 : return 1;
1017 : : }
1018 : :
1019 : :
1020 : : // -------------------------------------------------------------------------
1021 : :
1022 [ # # ][ # # ]: 0 : class TextArrayAction : public Action, private ::boost::noncopyable
[ # # ]
1023 : : {
1024 : : public:
1025 : : TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1026 : : const ::rtl::OUString& rString,
1027 : : sal_Int32 nStartPos,
1028 : : sal_Int32 nLen,
1029 : : const uno::Sequence< double >& rOffsets,
1030 : : const CanvasSharedPtr& rCanvas,
1031 : : const OutDevState& rState );
1032 : :
1033 : : TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1034 : : const ::rtl::OUString& rString,
1035 : : sal_Int32 nStartPos,
1036 : : sal_Int32 nLen,
1037 : : const uno::Sequence< double >& rOffsets,
1038 : : const CanvasSharedPtr& rCanvas,
1039 : : const OutDevState& rState,
1040 : : const ::basegfx::B2DHomMatrix& rTextTransform );
1041 : :
1042 : : virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1043 : : virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1044 : : const Subset& rSubset ) const;
1045 : :
1046 : : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1047 : : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1048 : : const Subset& rSubset ) const;
1049 : :
1050 : : virtual sal_Int32 getActionCount() const;
1051 : :
1052 : : private:
1053 : : // TODO(P2): This is potentially a real mass object
1054 : : // (every character might be a separate TextAction),
1055 : : // thus, make it as lightweight as possible. For
1056 : : // example, share common RenderState among several
1057 : : // TextActions, maybe using maOffsets for the
1058 : : // translation.
1059 : :
1060 : : uno::Reference< rendering::XTextLayout > mxTextLayout;
1061 : : const CanvasSharedPtr mpCanvas;
1062 : : rendering::RenderState maState;
1063 : : };
1064 : :
1065 : 0 : TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1066 : : const ::rtl::OUString& rString,
1067 : : sal_Int32 nStartPos,
1068 : : sal_Int32 nLen,
1069 : : const uno::Sequence< double >& rOffsets,
1070 : : const CanvasSharedPtr& rCanvas,
1071 : : const OutDevState& rState ) :
1072 : : mxTextLayout(),
1073 : : mpCanvas( rCanvas ),
1074 [ # # ][ # # ]: 0 : maState()
1075 : : {
1076 : : initArrayAction( maState,
1077 : : mxTextLayout,
1078 : : rStartPoint,
1079 : : rString,
1080 : : nStartPos,
1081 : : nLen,
1082 : : rOffsets,
1083 : : rCanvas,
1084 [ # # ]: 0 : rState, NULL );
1085 : 0 : }
1086 : :
1087 : 0 : TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1088 : : const ::rtl::OUString& rString,
1089 : : sal_Int32 nStartPos,
1090 : : sal_Int32 nLen,
1091 : : const uno::Sequence< double >& rOffsets,
1092 : : const CanvasSharedPtr& rCanvas,
1093 : : const OutDevState& rState,
1094 : : const ::basegfx::B2DHomMatrix& rTextTransform ) :
1095 : : mxTextLayout(),
1096 : : mpCanvas( rCanvas ),
1097 [ # # ][ # # ]: 0 : maState()
1098 : : {
1099 : : initArrayAction( maState,
1100 : : mxTextLayout,
1101 : : rStartPoint,
1102 : : rString,
1103 : : nStartPos,
1104 : : nLen,
1105 : : rOffsets,
1106 : : rCanvas,
1107 : : rState,
1108 [ # # ]: 0 : &rTextTransform );
1109 : 0 : }
1110 : :
1111 : 0 : bool TextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1112 : : {
1113 : : RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::render()" );
1114 : : RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this );
1115 : :
1116 [ # # ]: 0 : rendering::RenderState aLocalState( maState );
1117 [ # # ]: 0 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1118 : :
1119 [ # # ][ # # ]: 0 : mpCanvas->getUNOCanvas()->drawTextLayout( mxTextLayout,
1120 : 0 : mpCanvas->getViewState(),
1121 [ # # ][ # # ]: 0 : aLocalState );
[ # # ]
1122 : :
1123 [ # # ]: 0 : return true;
1124 : : }
1125 : :
1126 : 0 : bool TextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1127 : : const Subset& rSubset ) const
1128 : : {
1129 : : RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::renderSubset()" );
1130 : : RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this );
1131 : :
1132 [ # # ]: 0 : rendering::RenderState aLocalState( maState );
1133 : 0 : uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1134 : :
1135 : : double nDummy0, nDummy1;
1136 : : createSubsetLayout( xTextLayout,
1137 : : aLocalState,
1138 : : nDummy0,
1139 : : nDummy1,
1140 : : rTransformation,
1141 [ # # ]: 0 : rSubset );
1142 : :
1143 [ # # ]: 0 : if( !xTextLayout.is() )
1144 : 0 : return true; // empty layout, render nothing
1145 : :
1146 [ # # ][ # # ]: 0 : mpCanvas->getUNOCanvas()->drawTextLayout( xTextLayout,
1147 : 0 : mpCanvas->getViewState(),
1148 [ # # ][ # # ]: 0 : aLocalState );
[ # # ]
1149 : :
1150 [ # # ]: 0 : return true;
1151 : : }
1152 : :
1153 : 0 : ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1154 : : {
1155 [ # # ]: 0 : rendering::RenderState aLocalState( maState );
1156 [ # # ]: 0 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1157 : :
1158 : : return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1159 [ # # ][ # # ]: 0 : mxTextLayout->queryTextBounds() ),
1160 : 0 : mpCanvas->getViewState(),
1161 [ # # ][ # # ]: 0 : aLocalState );
[ # # ][ # # ]
[ # # ]
1162 : : }
1163 : :
1164 : 0 : ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1165 : : const Subset& rSubset ) const
1166 : : {
1167 : : RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::getBounds( subset )" );
1168 : : RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this );
1169 : :
1170 [ # # ]: 0 : rendering::RenderState aLocalState( maState );
1171 : 0 : uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1172 : :
1173 : : double nDummy0, nDummy1;
1174 : : createSubsetLayout( xTextLayout,
1175 : : aLocalState,
1176 : : nDummy0,
1177 : : nDummy1,
1178 : : rTransformation,
1179 [ # # ]: 0 : rSubset );
1180 : :
1181 [ # # ]: 0 : if( !xTextLayout.is() )
1182 [ # # ]: 0 : return ::basegfx::B2DRange(); // empty layout, empty bounds
1183 : :
1184 : : return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1185 [ # # ][ # # ]: 0 : xTextLayout->queryTextBounds() ),
1186 : 0 : mpCanvas->getViewState(),
1187 [ # # ][ # # ]: 0 : aLocalState );
[ # # ][ # # ]
[ # # ]
1188 : : }
1189 : :
1190 : 0 : sal_Int32 TextArrayAction::getActionCount() const
1191 : : {
1192 : 0 : const rendering::StringContext& rOrigContext( mxTextLayout->getText() );
1193 : :
1194 : 0 : return rOrigContext.Length;
1195 : : }
1196 : :
1197 : :
1198 : : // -------------------------------------------------------------------------
1199 : :
1200 [ # # ][ # # ]: 0 : class EffectTextArrayAction :
[ # # ]
1201 : : public Action,
1202 : : public TextRenderer,
1203 : : private ::boost::noncopyable
1204 : : {
1205 : : public:
1206 : : EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1207 : : const ::basegfx::B2DSize& rReliefOffset,
1208 : : const ::Color& rReliefColor,
1209 : : const ::basegfx::B2DSize& rShadowOffset,
1210 : : const ::Color& rShadowColor,
1211 : : const ::rtl::OUString& rText,
1212 : : sal_Int32 nStartPos,
1213 : : sal_Int32 nLen,
1214 : : const uno::Sequence< double >& rOffsets,
1215 : : VirtualDevice& rVDev,
1216 : : const CanvasSharedPtr& rCanvas,
1217 : : const OutDevState& rState );
1218 : : EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1219 : : const ::basegfx::B2DSize& rReliefOffset,
1220 : : const ::Color& rReliefColor,
1221 : : const ::basegfx::B2DSize& rShadowOffset,
1222 : : const ::Color& rShadowColor,
1223 : : const ::rtl::OUString& rText,
1224 : : sal_Int32 nStartPos,
1225 : : sal_Int32 nLen,
1226 : : const uno::Sequence< double >& rOffsets,
1227 : : VirtualDevice& rVDev,
1228 : : const CanvasSharedPtr& rCanvas,
1229 : : const OutDevState& rState,
1230 : : const ::basegfx::B2DHomMatrix& rTextTransform );
1231 : :
1232 : : virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1233 : : virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1234 : : const Subset& rSubset ) const;
1235 : :
1236 : : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1237 : : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1238 : : const Subset& rSubset ) const;
1239 : :
1240 : : virtual sal_Int32 getActionCount() const;
1241 : :
1242 : : private:
1243 : : // TextRenderer interface
1244 : : virtual bool operator()( const rendering::RenderState& rRenderState ) const;
1245 : :
1246 : : // TODO(P2): This is potentially a real mass object
1247 : : // (every character might be a separate TextAction),
1248 : : // thus, make it as lightweight as possible. For
1249 : : // example, share common RenderState among several
1250 : : // TextActions, maybe using maOffsets for the
1251 : : // translation.
1252 : :
1253 : : uno::Reference< rendering::XTextLayout > mxTextLayout;
1254 : : const CanvasSharedPtr mpCanvas;
1255 : : rendering::RenderState maState;
1256 : : const tools::TextLineInfo maTextLineInfo;
1257 : : ::basegfx::B2DSize maLinesOverallSize;
1258 : : uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
1259 : : const ::basegfx::B2DSize maReliefOffset;
1260 : : const ::Color maReliefColor;
1261 : : const ::basegfx::B2DSize maShadowOffset;
1262 : : const ::Color maShadowColor;
1263 : : };
1264 : :
1265 : 0 : EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1266 : : const ::basegfx::B2DSize& rReliefOffset,
1267 : : const ::Color& rReliefColor,
1268 : : const ::basegfx::B2DSize& rShadowOffset,
1269 : : const ::Color& rShadowColor,
1270 : : const ::rtl::OUString& rText,
1271 : : sal_Int32 nStartPos,
1272 : : sal_Int32 nLen,
1273 : : const uno::Sequence< double >& rOffsets,
1274 : : VirtualDevice& rVDev,
1275 : : const CanvasSharedPtr& rCanvas,
1276 : : const OutDevState& rState ) :
1277 : : mxTextLayout(),
1278 : : mpCanvas( rCanvas ),
1279 : : maState(),
1280 : : maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1281 : : maLinesOverallSize(),
1282 : : mxTextLines(),
1283 : : maReliefOffset( rReliefOffset ),
1284 : : maReliefColor( rReliefColor ),
1285 : : maShadowOffset( rShadowOffset ),
1286 [ # # ][ # # ]: 0 : maShadowColor( rShadowColor )
[ # # ]
1287 : : {
1288 : : initEffectLinePolyPolygon( maLinesOverallSize,
1289 : : mxTextLines,
1290 : : rCanvas,
1291 : : rOffsets,
1292 [ # # ]: 0 : maTextLineInfo );
1293 : :
1294 : : initArrayAction( maState,
1295 : : mxTextLayout,
1296 : : rStartPoint,
1297 : : rText,
1298 : : nStartPos,
1299 : : nLen,
1300 : : rOffsets,
1301 : : rCanvas,
1302 [ # # ]: 0 : rState, NULL );
1303 : 0 : }
1304 : :
1305 : 0 : EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1306 : : const ::basegfx::B2DSize& rReliefOffset,
1307 : : const ::Color& rReliefColor,
1308 : : const ::basegfx::B2DSize& rShadowOffset,
1309 : : const ::Color& rShadowColor,
1310 : : const ::rtl::OUString& rText,
1311 : : sal_Int32 nStartPos,
1312 : : sal_Int32 nLen,
1313 : : const uno::Sequence< double >& rOffsets,
1314 : : VirtualDevice& rVDev,
1315 : : const CanvasSharedPtr& rCanvas,
1316 : : const OutDevState& rState,
1317 : : const ::basegfx::B2DHomMatrix& rTextTransform ) :
1318 : : mxTextLayout(),
1319 : : mpCanvas( rCanvas ),
1320 : : maState(),
1321 : : maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1322 : : maLinesOverallSize(),
1323 : : mxTextLines(),
1324 : : maReliefOffset( rReliefOffset ),
1325 : : maReliefColor( rReliefColor ),
1326 : : maShadowOffset( rShadowOffset ),
1327 [ # # ][ # # ]: 0 : maShadowColor( rShadowColor )
[ # # ]
1328 : : {
1329 : : initEffectLinePolyPolygon( maLinesOverallSize,
1330 : : mxTextLines,
1331 : : rCanvas,
1332 : : rOffsets,
1333 [ # # ]: 0 : maTextLineInfo );
1334 : :
1335 : : initArrayAction( maState,
1336 : : mxTextLayout,
1337 : : rStartPoint,
1338 : : rText,
1339 : : nStartPos,
1340 : : nLen,
1341 : : rOffsets,
1342 : : rCanvas,
1343 : : rState,
1344 [ # # ]: 0 : &rTextTransform );
1345 : 0 : }
1346 : :
1347 : 0 : bool EffectTextArrayAction::operator()( const rendering::RenderState& rRenderState ) const
1348 : : {
1349 : 0 : const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1350 [ # # ]: 0 : const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
1351 : :
1352 [ # # ]: 0 : rCanvas->fillPolyPolygon( mxTextLines,
1353 : : rViewState,
1354 [ # # ]: 0 : rRenderState );
1355 : :
1356 [ # # ]: 0 : rCanvas->drawTextLayout( mxTextLayout,
1357 : : rViewState,
1358 [ # # ]: 0 : rRenderState );
1359 : :
1360 : 0 : return true;
1361 : : }
1362 : :
1363 : 0 : bool EffectTextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1364 : : {
1365 : : RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::render()" );
1366 : : RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this );
1367 : :
1368 [ # # ]: 0 : rendering::RenderState aLocalState( maState );
1369 [ # # ]: 0 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1370 : :
1371 : : return renderEffectText( *this,
1372 : : aLocalState,
1373 : 0 : mpCanvas->getViewState(),
1374 : 0 : mpCanvas->getUNOCanvas(),
1375 : : maShadowColor,
1376 : : maShadowOffset,
1377 : : maReliefColor,
1378 [ # # ][ # # ]: 0 : maReliefOffset );
[ # # ]
[ # # # # ]
1379 : : }
1380 : :
1381 [ # # ]: 0 : class EffectTextArrayRenderHelper : public TextRenderer
1382 : : {
1383 : : public:
1384 : 0 : EffectTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas,
1385 : : const uno::Reference< rendering::XTextLayout >& rTextLayout,
1386 : : const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon,
1387 : : const rendering::ViewState& rViewState ) :
1388 : : mrCanvas( rCanvas ),
1389 : : mrTextLayout( rTextLayout ),
1390 : : mrLinePolygon( rLinePolygon ),
1391 : 0 : mrViewState( rViewState )
1392 : : {
1393 : 0 : }
1394 : :
1395 : : // TextRenderer interface
1396 : 0 : virtual bool operator()( const rendering::RenderState& rRenderState ) const
1397 : : {
1398 : 0 : mrCanvas->fillPolyPolygon( mrLinePolygon,
1399 : : mrViewState,
1400 : 0 : rRenderState );
1401 : :
1402 : 0 : mrCanvas->drawTextLayout( mrTextLayout,
1403 : : mrViewState,
1404 : 0 : rRenderState );
1405 : :
1406 : 0 : return true;
1407 : : }
1408 : :
1409 : : private:
1410 : : const uno::Reference< rendering::XCanvas >& mrCanvas;
1411 : : const uno::Reference< rendering::XTextLayout >& mrTextLayout;
1412 : : const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon;
1413 : : const rendering::ViewState& mrViewState;
1414 : : };
1415 : :
1416 : 0 : bool EffectTextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1417 : : const Subset& rSubset ) const
1418 : : {
1419 : : RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::renderSubset()" );
1420 : : RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this );
1421 : :
1422 [ # # ]: 0 : rendering::RenderState aLocalState( maState );
1423 : 0 : uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1424 [ # # ][ # # ]: 0 : const geometry::RealRectangle2D aTextBounds( mxTextLayout->queryTextBounds() );
1425 : :
1426 : 0 : double nMinPos(0.0);
1427 : 0 : double nMaxPos(aTextBounds.X2 - aTextBounds.X1);
1428 : :
1429 : : createSubsetLayout( xTextLayout,
1430 : : aLocalState,
1431 : : nMinPos,
1432 : : nMaxPos,
1433 : : rTransformation,
1434 [ # # ]: 0 : rSubset );
1435 : :
1436 [ # # ]: 0 : if( !xTextLayout.is() )
1437 : 0 : return true; // empty layout, render nothing
1438 : :
1439 : :
1440 : : // create and setup local line polygon
1441 : : // ===================================
1442 : :
1443 [ # # ]: 0 : uno::Reference< rendering::XCanvas > xCanvas( mpCanvas->getUNOCanvas() );
1444 [ # # ]: 0 : const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1445 : :
1446 : : uno::Reference< rendering::XPolyPolygon2D > xTextLines(
1447 : : ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1448 [ # # ]: 0 : xCanvas->getDevice(),
1449 : : tools::createTextLinesPolyPolygon(
1450 : : 0.0, nMaxPos - nMinPos,
1451 [ # # ][ # # ]: 0 : maTextLineInfo ) ) );
[ # # ][ # # ]
1452 : :
1453 : :
1454 : : // render everything
1455 : : // =================
1456 : :
1457 : : return renderEffectText(
1458 : : EffectTextArrayRenderHelper( xCanvas,
1459 : : xTextLayout,
1460 : : xTextLines,
1461 : : rViewState ),
1462 : : aLocalState,
1463 : : rViewState,
1464 : : xCanvas,
1465 : : maShadowColor,
1466 : : maShadowOffset,
1467 : : maReliefColor,
1468 [ # # ][ # # ]: 0 : maReliefOffset );
[ # # ]
1469 : : }
1470 : :
1471 : 0 : ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1472 : : {
1473 [ # # ]: 0 : rendering::RenderState aLocalState( maState );
1474 [ # # ]: 0 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1475 : :
1476 : : return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1477 [ # # ][ # # ]: 0 : mxTextLayout->queryTextBounds() ),
1478 : : ::basegfx::B2DRange( 0,0,
1479 : : maLinesOverallSize.getX(),
1480 : : maLinesOverallSize.getY() ),
1481 : : maReliefOffset,
1482 : : maShadowOffset,
1483 : : aLocalState,
1484 [ # # ][ # # ]: 0 : mpCanvas->getViewState() );
[ # # ][ # # ]
[ # # ][ # # ]
1485 : : }
1486 : :
1487 : 0 : ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1488 : : const Subset& rSubset ) const
1489 : : {
1490 : : RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::getBounds( subset )" );
1491 : : RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this );
1492 : :
1493 [ # # ]: 0 : rendering::RenderState aLocalState( maState );
1494 : 0 : uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1495 [ # # ][ # # ]: 0 : const geometry::RealRectangle2D aTextBounds( mxTextLayout->queryTextBounds() );
1496 : :
1497 : 0 : double nMinPos(0.0);
1498 : 0 : double nMaxPos(aTextBounds.X2 - aTextBounds.X1);
1499 : :
1500 : : createSubsetLayout( xTextLayout,
1501 : : aLocalState,
1502 : : nMinPos,
1503 : : nMaxPos,
1504 : : rTransformation,
1505 [ # # ]: 0 : rSubset );
1506 : :
1507 [ # # ]: 0 : if( !xTextLayout.is() )
1508 [ # # ]: 0 : return ::basegfx::B2DRange(); // empty layout, empty bounds
1509 : :
1510 : :
1511 : : // create and setup local line polygon
1512 : : // ===================================
1513 : :
1514 : : const ::basegfx::B2DPolyPolygon aPoly(
1515 : : tools::createTextLinesPolyPolygon(
1516 : : 0.0, nMaxPos - nMinPos,
1517 [ # # ]: 0 : maTextLineInfo ) );
1518 : :
1519 : : return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1520 [ # # ][ # # ]: 0 : xTextLayout->queryTextBounds() ),
1521 : : ::basegfx::tools::getRange( aPoly ),
1522 : : maReliefOffset,
1523 : : maShadowOffset,
1524 : : aLocalState,
1525 [ # # ][ # # ]: 0 : mpCanvas->getViewState() );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1526 : : }
1527 : :
1528 : 0 : sal_Int32 EffectTextArrayAction::getActionCount() const
1529 : : {
1530 : 0 : const rendering::StringContext& rOrigContext( mxTextLayout->getText() );
1531 : :
1532 : 0 : return rOrigContext.Length;
1533 : : }
1534 : :
1535 : :
1536 : : // -------------------------------------------------------------------------
1537 : :
1538 [ # # ][ # # ]: 0 : class OutlineAction :
[ # # ][ # # ]
[ # # ]
1539 : : public Action,
1540 : : public TextRenderer,
1541 : : private ::boost::noncopyable
1542 : : {
1543 : : public:
1544 : : OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1545 : : const ::basegfx::B2DSize& rReliefOffset,
1546 : : const ::Color& rReliefColor,
1547 : : const ::basegfx::B2DSize& rShadowOffset,
1548 : : const ::Color& rShadowColor,
1549 : : const ::basegfx::B2DRectangle& rOutlineBounds,
1550 : : const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1551 : : const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1552 : : const uno::Sequence< double >& rOffsets,
1553 : : VirtualDevice& rVDev,
1554 : : const CanvasSharedPtr& rCanvas,
1555 : : const OutDevState& rState );
1556 : : OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1557 : : const ::basegfx::B2DSize& rReliefOffset,
1558 : : const ::Color& rReliefColor,
1559 : : const ::basegfx::B2DSize& rShadowOffset,
1560 : : const ::Color& rShadowColor,
1561 : : const ::basegfx::B2DRectangle& rOutlineBounds,
1562 : : const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1563 : : const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1564 : : const uno::Sequence< double >& rOffsets,
1565 : : VirtualDevice& rVDev,
1566 : : const CanvasSharedPtr& rCanvas,
1567 : : const OutDevState& rState,
1568 : : const ::basegfx::B2DHomMatrix& rTextTransform );
1569 : :
1570 : : virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1571 : : virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1572 : : const Subset& rSubset ) const;
1573 : :
1574 : : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1575 : : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1576 : : const Subset& rSubset ) const;
1577 : :
1578 : : virtual sal_Int32 getActionCount() const;
1579 : :
1580 : : private:
1581 : : // TextRenderer interface
1582 : : virtual bool operator()( const rendering::RenderState& rRenderState ) const;
1583 : :
1584 : : // TODO(P2): This is potentially a real mass object
1585 : : // (every character might be a separate TextAction),
1586 : : // thus, make it as lightweight as possible. For
1587 : : // example, share common RenderState among several
1588 : : // TextActions, maybe using maOffsets for the
1589 : : // translation.
1590 : :
1591 : : uno::Reference< rendering::XPolyPolygon2D > mxTextPoly;
1592 : :
1593 : : /** This vector denotes the index of the start polygon
1594 : : for the respective glyph sequence.
1595 : :
1596 : : To get a polygon index range for a given character
1597 : : index i, take [ maPolygonGlyphMap[i],
1598 : : maPolygonGlyphMap[i+1] ). Note that this is wrong
1599 : : for BiDi
1600 : : */
1601 : : const ::std::vector< sal_Int32 > maPolygonGlyphMap;
1602 : : const uno::Sequence< double > maOffsets;
1603 : : const CanvasSharedPtr mpCanvas;
1604 : : rendering::RenderState maState;
1605 : : double mnOutlineWidth;
1606 : : const uno::Sequence< double > maFillColor;
1607 : : const tools::TextLineInfo maTextLineInfo;
1608 : : ::basegfx::B2DSize maLinesOverallSize;
1609 : : const ::basegfx::B2DRectangle maOutlineBounds;
1610 : : uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
1611 : : const ::basegfx::B2DSize maReliefOffset;
1612 : : const ::Color maReliefColor;
1613 : : const ::basegfx::B2DSize maShadowOffset;
1614 : : const ::Color maShadowColor;
1615 : : };
1616 : :
1617 : 0 : double calcOutlineWidth( const OutDevState& rState,
1618 : : VirtualDevice& rVDev )
1619 : : {
1620 : : const ::basegfx::B2DSize aFontSize( 0,
1621 [ # # ]: 0 : rVDev.GetFont().GetHeight() / 64.0 );
1622 : :
1623 : : const double nOutlineWidth(
1624 [ # # ]: 0 : (rState.mapModeTransform * aFontSize).getY() );
1625 : :
1626 [ # # ]: 0 : return nOutlineWidth < 1.0 ? 1.0 : nOutlineWidth;
1627 : : }
1628 : :
1629 : 0 : OutlineAction::OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1630 : : const ::basegfx::B2DSize& rReliefOffset,
1631 : : const ::Color& rReliefColor,
1632 : : const ::basegfx::B2DSize& rShadowOffset,
1633 : : const ::Color& rShadowColor,
1634 : : const ::basegfx::B2DRectangle& rOutlineBounds,
1635 : : const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1636 : : const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1637 : : const uno::Sequence< double >& rOffsets,
1638 : : VirtualDevice& rVDev,
1639 : : const CanvasSharedPtr& rCanvas,
1640 : : const OutDevState& rState ) :
1641 : : mxTextPoly( rTextPoly ),
1642 : : maPolygonGlyphMap( rPolygonGlyphMap ),
1643 : : maOffsets( rOffsets ),
1644 : : mpCanvas( rCanvas ),
1645 : : maState(),
1646 [ # # ]: 0 : mnOutlineWidth( calcOutlineWidth(rState,rVDev) ),
1647 : : maFillColor(
1648 : : ::vcl::unotools::colorToDoubleSequence(
1649 : : ::Color( COL_WHITE ),
1650 [ # # ][ # # ]: 0 : rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
[ # # ][ # # ]
1651 : : maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1652 : : maLinesOverallSize(),
1653 : : maOutlineBounds( rOutlineBounds ),
1654 : : mxTextLines(),
1655 : : maReliefOffset( rReliefOffset ),
1656 : : maReliefColor( rReliefColor ),
1657 : : maShadowOffset( rShadowOffset ),
1658 [ # # ][ # # ]: 0 : maShadowColor( rShadowColor )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1659 : : {
1660 : : initEffectLinePolyPolygon( maLinesOverallSize,
1661 : : mxTextLines,
1662 : : rCanvas,
1663 : : rOffsets,
1664 [ # # ]: 0 : maTextLineInfo );
1665 : :
1666 : : init( maState,
1667 : : rStartPoint,
1668 : : rState,
1669 [ # # ]: 0 : rCanvas );
1670 : 0 : }
1671 : :
1672 : 0 : OutlineAction::OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1673 : : const ::basegfx::B2DSize& rReliefOffset,
1674 : : const ::Color& rReliefColor,
1675 : : const ::basegfx::B2DSize& rShadowOffset,
1676 : : const ::Color& rShadowColor,
1677 : : const ::basegfx::B2DRectangle& rOutlineBounds,
1678 : : const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1679 : : const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1680 : : const uno::Sequence< double >& rOffsets,
1681 : : VirtualDevice& rVDev,
1682 : : const CanvasSharedPtr& rCanvas,
1683 : : const OutDevState& rState,
1684 : : const ::basegfx::B2DHomMatrix& rTextTransform ) :
1685 : : mxTextPoly( rTextPoly ),
1686 : : maPolygonGlyphMap( rPolygonGlyphMap ),
1687 : : maOffsets( rOffsets ),
1688 : : mpCanvas( rCanvas ),
1689 : : maState(),
1690 [ # # ]: 0 : mnOutlineWidth( calcOutlineWidth(rState,rVDev) ),
1691 : : maFillColor(
1692 : : ::vcl::unotools::colorToDoubleSequence(
1693 : : ::Color( COL_WHITE ),
1694 [ # # ][ # # ]: 0 : rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
[ # # ][ # # ]
1695 : : maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1696 : : maLinesOverallSize(),
1697 : : maOutlineBounds( rOutlineBounds ),
1698 : : mxTextLines(),
1699 : : maReliefOffset( rReliefOffset ),
1700 : : maReliefColor( rReliefColor ),
1701 : : maShadowOffset( rShadowOffset ),
1702 [ # # ][ # # ]: 0 : maShadowColor( rShadowColor )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1703 : : {
1704 : : initEffectLinePolyPolygon( maLinesOverallSize,
1705 : : mxTextLines,
1706 : : rCanvas,
1707 : : rOffsets,
1708 [ # # ]: 0 : maTextLineInfo );
1709 : :
1710 : : init( maState,
1711 : : rStartPoint,
1712 : : rState,
1713 : : rCanvas,
1714 [ # # ]: 0 : rTextTransform );
1715 : 0 : }
1716 : :
1717 : 0 : bool OutlineAction::operator()( const rendering::RenderState& rRenderState ) const
1718 : : {
1719 [ # # ]: 0 : const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1720 [ # # ]: 0 : const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
1721 : :
1722 [ # # ]: 0 : rendering::StrokeAttributes aStrokeAttributes;
1723 : :
1724 : 0 : aStrokeAttributes.StrokeWidth = mnOutlineWidth;
1725 : 0 : aStrokeAttributes.MiterLimit = 1.0;
1726 : 0 : aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
1727 : 0 : aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
1728 : 0 : aStrokeAttributes.JoinType = rendering::PathJoinType::MITER;
1729 : :
1730 [ # # ]: 0 : rendering::RenderState aLocalState( rRenderState );
1731 [ # # ]: 0 : aLocalState.DeviceColor = maFillColor;
1732 : :
1733 : : // TODO(P1): implement caching
1734 : :
1735 : : // background of text
1736 [ # # ]: 0 : rCanvas->fillPolyPolygon( mxTextPoly,
1737 : : rViewState,
1738 [ # # ]: 0 : aLocalState );
1739 : :
1740 : : // border line of text
1741 [ # # ]: 0 : rCanvas->strokePolyPolygon( mxTextPoly,
1742 : : rViewState,
1743 : : rRenderState,
1744 [ # # ]: 0 : aStrokeAttributes );
1745 : :
1746 : : // underlines/strikethrough - background
1747 [ # # ]: 0 : rCanvas->fillPolyPolygon( mxTextLines,
1748 : : rViewState,
1749 [ # # ]: 0 : aLocalState );
1750 : : // underlines/strikethrough - border
1751 [ # # ]: 0 : rCanvas->strokePolyPolygon( mxTextLines,
1752 : : rViewState,
1753 : : rRenderState,
1754 [ # # ]: 0 : aStrokeAttributes );
1755 : :
1756 [ # # ][ # # ]: 0 : return true;
[ # # ]
1757 : : }
1758 : :
1759 : 0 : bool OutlineAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1760 : : {
1761 : : RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::render()" );
1762 : : RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this );
1763 : :
1764 [ # # ]: 0 : rendering::RenderState aLocalState( maState );
1765 [ # # ]: 0 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1766 : :
1767 : : return renderEffectText( *this,
1768 : : aLocalState,
1769 : 0 : mpCanvas->getViewState(),
1770 : 0 : mpCanvas->getUNOCanvas(),
1771 : : maShadowColor,
1772 : : maShadowOffset,
1773 : : maReliefColor,
1774 [ # # ][ # # ]: 0 : maReliefOffset );
[ # # ]
[ # # # # ]
1775 : : }
1776 : :
1777 : : class OutlineTextArrayRenderHelper : public TextRenderer
1778 : : {
1779 : : public:
1780 : : OutlineTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas,
1781 : : const uno::Reference< rendering::XPolyPolygon2D >& rTextPolygon,
1782 : : const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon,
1783 : : const rendering::ViewState& rViewState,
1784 : : double nOutlineWidth ) :
1785 : : maFillColor(
1786 : : ::vcl::unotools::colorToDoubleSequence(
1787 : : ::Color( COL_WHITE ),
1788 : : rCanvas->getDevice()->getDeviceColorSpace() )),
1789 : : mnOutlineWidth( nOutlineWidth ),
1790 : : mrCanvas( rCanvas ),
1791 : : mrTextPolygon( rTextPolygon ),
1792 : : mrLinePolygon( rLinePolygon ),
1793 : : mrViewState( rViewState )
1794 : : {
1795 : : }
1796 : :
1797 : : // TextRenderer interface
1798 : : virtual bool operator()( const rendering::RenderState& rRenderState ) const
1799 : : {
1800 : : rendering::StrokeAttributes aStrokeAttributes;
1801 : :
1802 : : aStrokeAttributes.StrokeWidth = mnOutlineWidth;
1803 : : aStrokeAttributes.MiterLimit = 1.0;
1804 : : aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
1805 : : aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
1806 : : aStrokeAttributes.JoinType = rendering::PathJoinType::MITER;
1807 : :
1808 : : rendering::RenderState aLocalState( rRenderState );
1809 : : aLocalState.DeviceColor = maFillColor;
1810 : :
1811 : : // TODO(P1): implement caching
1812 : :
1813 : : // background of text
1814 : : mrCanvas->fillPolyPolygon( mrTextPolygon,
1815 : : mrViewState,
1816 : : aLocalState );
1817 : :
1818 : : // border line of text
1819 : : mrCanvas->strokePolyPolygon( mrTextPolygon,
1820 : : mrViewState,
1821 : : rRenderState,
1822 : : aStrokeAttributes );
1823 : :
1824 : : // underlines/strikethrough - background
1825 : : mrCanvas->fillPolyPolygon( mrLinePolygon,
1826 : : mrViewState,
1827 : : aLocalState );
1828 : : // underlines/strikethrough - border
1829 : : mrCanvas->strokePolyPolygon( mrLinePolygon,
1830 : : mrViewState,
1831 : : rRenderState,
1832 : : aStrokeAttributes );
1833 : :
1834 : : return true;
1835 : : }
1836 : :
1837 : : private:
1838 : : const uno::Sequence< double > maFillColor;
1839 : : double mnOutlineWidth;
1840 : : const uno::Reference< rendering::XCanvas >& mrCanvas;
1841 : : const uno::Reference< rendering::XPolyPolygon2D >& mrTextPolygon;
1842 : : const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon;
1843 : : const rendering::ViewState& mrViewState;
1844 : : };
1845 : :
1846 : 0 : bool OutlineAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1847 : : const Subset& rSubset ) const
1848 : : {
1849 : : RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::OutlineAction::renderSubset()" );
1850 : : RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::OutlineAction: 0x%X", this );
1851 : :
1852 [ # # ]: 0 : if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd )
1853 : 0 : return true; // empty range, render nothing
1854 : :
1855 : : #if 1
1856 : : // TODO(F3): Subsetting NYI for outline text!
1857 : 0 : return render( rTransformation );
1858 : : #else
1859 : : const rendering::StringContext rOrigContext( mxTextLayout->getText() );
1860 : :
1861 : : if( rSubset.mnSubsetBegin == 0 &&
1862 : : rSubset.mnSubsetEnd == rOrigContext.Length )
1863 : : {
1864 : : // full range, no need for subsetting
1865 : : return render( rTransformation );
1866 : : }
1867 : :
1868 : : rendering::RenderState aLocalState( maState );
1869 : : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1870 : :
1871 : :
1872 : : // create and setup local Text polygon
1873 : : // ===================================
1874 : :
1875 : : uno::Reference< rendering::XPolyPolygon2D > xTextPolygon();
1876 : :
1877 : : // TODO(P3): Provide an API method for that!
1878 : :
1879 : : if( !xTextLayout.is() )
1880 : : return false;
1881 : :
1882 : : // render everything
1883 : : // =================
1884 : :
1885 : : return renderEffectText(
1886 : : OutlineTextArrayRenderHelper(
1887 : : xCanvas,
1888 : : mnOutlineWidth,
1889 : : xTextLayout,
1890 : : xTextLines,
1891 : : rViewState ),
1892 : : aLocalState,
1893 : : rViewState,
1894 : : xCanvas,
1895 : : maShadowColor,
1896 : : maShadowOffset,
1897 : : maReliefColor,
1898 : : maReliefOffset );
1899 : : #endif
1900 : : }
1901 : :
1902 : 0 : ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1903 : : {
1904 [ # # ]: 0 : rendering::RenderState aLocalState( maState );
1905 [ # # ]: 0 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1906 : :
1907 : : return calcEffectTextBounds( maOutlineBounds,
1908 : : ::basegfx::B2DRange( 0,0,
1909 : : maLinesOverallSize.getX(),
1910 : : maLinesOverallSize.getY() ),
1911 : : maReliefOffset,
1912 : : maShadowOffset,
1913 : : aLocalState,
1914 [ # # ][ # # ]: 0 : mpCanvas->getViewState() );
[ # # ][ # # ]
[ # # ]
1915 : : }
1916 : :
1917 : 0 : ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1918 : : const Subset& /*rSubset*/ ) const
1919 : : {
1920 : : OSL_FAIL( "OutlineAction::getBounds(): Subset not yet supported by this object" );
1921 : :
1922 : 0 : return getBounds( rTransformation );
1923 : : }
1924 : :
1925 : 0 : sal_Int32 OutlineAction::getActionCount() const
1926 : : {
1927 : : // TODO(F3): Subsetting NYI for outline text!
1928 : 0 : return maOffsets.getLength();
1929 : : }
1930 : :
1931 : :
1932 : : // ======================================================================
1933 : : //
1934 : : // Action factory methods
1935 : : //
1936 : : // ======================================================================
1937 : :
1938 : : /** Create an outline action
1939 : :
1940 : : This method extracts the polygonal outline from the
1941 : : text, and creates a properly setup OutlineAction from
1942 : : it.
1943 : : */
1944 : 0 : ActionSharedPtr createOutline( const ::basegfx::B2DPoint& rStartPoint,
1945 : : const ::basegfx::B2DSize& rReliefOffset,
1946 : : const ::Color& rReliefColor,
1947 : : const ::basegfx::B2DSize& rShadowOffset,
1948 : : const ::Color& rShadowColor,
1949 : : const String& rText,
1950 : : sal_Int32 nStartPos,
1951 : : sal_Int32 nLen,
1952 : : const sal_Int32* pDXArray,
1953 : : VirtualDevice& rVDev,
1954 : : const CanvasSharedPtr& rCanvas,
1955 : : const OutDevState& rState,
1956 : : const Renderer::Parameters& rParms )
1957 : : {
1958 : : // operate on raw DX array here (in logical coordinate
1959 : : // system), to have a higher resolution
1960 : : // PolyPolygon. That polygon is then converted to
1961 : : // device coordinate system.
1962 : :
1963 : : // #i68512# Temporarily switch off font rotation
1964 : : // (which is already contained in the render state
1965 : : // transformation matrix - otherwise, glyph polygons
1966 : : // will be rotated twice)
1967 [ # # ]: 0 : const ::Font aOrigFont( rVDev.GetFont() );
1968 [ # # ]: 0 : ::Font aUnrotatedFont( aOrigFont );
1969 [ # # ]: 0 : aUnrotatedFont.SetOrientation(0);
1970 [ # # ]: 0 : rVDev.SetFont( aUnrotatedFont );
1971 : :
1972 : : // TODO(F3): Don't understand parameter semantics of
1973 : : // GetTextOutlines()
1974 [ # # ]: 0 : ::basegfx::B2DPolyPolygon aResultingPolyPolygon;
1975 [ # # ]: 0 : PolyPolyVector aVCLPolyPolyVector;
1976 : : const bool bHaveOutlines( rVDev.GetTextOutlines( aVCLPolyPolyVector, rText,
1977 : : static_cast<sal_uInt16>(nStartPos),
1978 : : static_cast<sal_uInt16>(nStartPos),
1979 : : static_cast<sal_uInt16>(nLen),
1980 [ # # ]: 0 : sal_True, 0, pDXArray ) );
1981 [ # # ]: 0 : rVDev.SetFont(aOrigFont);
1982 : :
1983 [ # # ]: 0 : if( !bHaveOutlines )
1984 [ # # ]: 0 : return ActionSharedPtr();
1985 : :
1986 [ # # ]: 0 : ::std::vector< sal_Int32 > aPolygonGlyphMap;
1987 : :
1988 : : // first glyph starts at polygon index 0
1989 [ # # ]: 0 : aPolygonGlyphMap.push_back( 0 );
1990 : :
1991 : : // remove offsetting from mapmode transformation
1992 : : // (outline polygons must stay at origin, only need to
1993 : : // be scaled)
1994 : : ::basegfx::B2DHomMatrix aMapModeTransform(
1995 [ # # ]: 0 : rState.mapModeTransform );
1996 [ # # ]: 0 : aMapModeTransform.set(0,2, 0.0);
1997 [ # # ]: 0 : aMapModeTransform.set(1,2, 0.0);
1998 : :
1999 [ # # ]: 0 : PolyPolyVector::const_iterator aIter( aVCLPolyPolyVector.begin() );
2000 [ # # ]: 0 : const PolyPolyVector::const_iterator aEnd( aVCLPolyPolyVector.end() );
2001 [ # # ][ # # ]: 0 : for( ; aIter!= aEnd; ++aIter )
[ # # ]
2002 : : {
2003 [ # # ]: 0 : ::basegfx::B2DPolyPolygon aPolyPolygon;
2004 : :
2005 [ # # ][ # # ]: 0 : aPolyPolygon = aIter->getB2DPolyPolygon();
[ # # ][ # # ]
2006 [ # # ]: 0 : aPolyPolygon.transform( aMapModeTransform );
2007 : :
2008 : : // append result to collecting polypoly
2009 [ # # ][ # # ]: 0 : for( sal_uInt32 i=0; i<aPolyPolygon.count(); ++i )
2010 : : {
2011 : : // #i47795# Ensure closed polygons (since
2012 : : // FreeType returns the glyph outlines
2013 : : // open)
2014 [ # # ]: 0 : const ::basegfx::B2DPolygon& rPoly( aPolyPolygon.getB2DPolygon( i ) );
2015 [ # # ]: 0 : const sal_uInt32 nCount( rPoly.count() );
2016 [ # # ][ # # ]: 0 : if( nCount<3 ||
[ # # ]
2017 [ # # ]: 0 : rPoly.isClosed() )
2018 : : {
2019 : : // polygon either degenerate, or
2020 : : // already closed.
2021 [ # # ]: 0 : aResultingPolyPolygon.append( rPoly );
2022 : : }
2023 : : else
2024 : : {
2025 [ # # ]: 0 : ::basegfx::B2DPolygon aPoly(rPoly);
2026 [ # # ]: 0 : aPoly.setClosed(true);
2027 : :
2028 [ # # ][ # # ]: 0 : aResultingPolyPolygon.append( aPoly );
2029 : : }
2030 [ # # ]: 0 : }
2031 : :
2032 : : // TODO(F3): Depending on the semantics of
2033 : : // GetTextOutlines(), this here is wrong!
2034 : :
2035 : : // calc next glyph index
2036 [ # # ][ # # ]: 0 : aPolygonGlyphMap.push_back( aResultingPolyPolygon.count() );
2037 [ # # ]: 0 : }
2038 : :
2039 : : const uno::Sequence< double > aCharWidthSeq(
2040 : : pDXArray ?
2041 : : setupDXArray( pDXArray, nLen, rState ) :
2042 : : setupDXArray( rText,
2043 : : nStartPos,
2044 : : nLen,
2045 : : rVDev,
2046 [ # # ][ # # ]: 0 : rState ));
[ # # ]
2047 : : const uno::Reference< rendering::XPolyPolygon2D > xTextPoly(
2048 : : ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
2049 [ # # ][ # # ]: 0 : rCanvas->getUNOCanvas()->getDevice(),
2050 [ # # ][ # # ]: 0 : aResultingPolyPolygon ) );
2051 : :
2052 [ # # ]: 0 : if( rParms.maTextTransformation.is_initialized() )
2053 : : {
2054 : : return ActionSharedPtr(
2055 : : new OutlineAction(
2056 : : rStartPoint,
2057 : : rReliefOffset,
2058 : : rReliefColor,
2059 : : rShadowOffset,
2060 : : rShadowColor,
2061 : : ::basegfx::tools::getRange(aResultingPolyPolygon),
2062 : : xTextPoly,
2063 : : aPolygonGlyphMap,
2064 : : aCharWidthSeq,
2065 : : rVDev,
2066 : : rCanvas,
2067 : : rState,
2068 [ # # ][ # # ]: 0 : *rParms.maTextTransformation ) );
[ # # ][ # # ]
[ # # ]
2069 : : }
2070 : : else
2071 : : {
2072 : : return ActionSharedPtr(
2073 : : new OutlineAction(
2074 : : rStartPoint,
2075 : : rReliefOffset,
2076 : : rReliefColor,
2077 : : rShadowOffset,
2078 : : rShadowColor,
2079 : : ::basegfx::tools::getRange(aResultingPolyPolygon),
2080 : : xTextPoly,
2081 : : aPolygonGlyphMap,
2082 : : aCharWidthSeq,
2083 : : rVDev,
2084 : : rCanvas,
2085 [ # # ][ # # ]: 0 : rState ) );
[ # # ][ # # ]
2086 [ # # ][ # # ]: 0 : }
[ # # ][ # # ]
[ # # ]
2087 : : }
2088 : :
2089 : : } // namespace
2090 : :
2091 : :
2092 : : // ---------------------------------------------------------------------------------
2093 : :
2094 : 0 : ActionSharedPtr TextActionFactory::createTextAction( const ::Point& rStartPoint,
2095 : : const ::Size& rReliefOffset,
2096 : : const ::Color& rReliefColor,
2097 : : const ::Size& rShadowOffset,
2098 : : const ::Color& rShadowColor,
2099 : : const String& rText,
2100 : : sal_Int32 nStartPos,
2101 : : sal_Int32 nLen,
2102 : : const sal_Int32* pDXArray,
2103 : : VirtualDevice& rVDev,
2104 : : const CanvasSharedPtr& rCanvas,
2105 : : const OutDevState& rState,
2106 : : const Renderer::Parameters& rParms,
2107 : : bool bSubsettable )
2108 : : {
2109 : : const ::Size aBaselineOffset( tools::getBaselineOffset( rState,
2110 [ # # ]: 0 : rVDev ) );
2111 : : // #143885# maintain (nearly) full precision positioning,
2112 : : // by circumventing integer-based OutDev-mapping
2113 : : const ::basegfx::B2DPoint aStartPoint(
2114 : : rState.mapModeTransform *
2115 : 0 : ::basegfx::B2DPoint(rStartPoint.X() + aBaselineOffset.Width(),
2116 [ # # ]: 0 : rStartPoint.Y() + aBaselineOffset.Height()) );
2117 : :
2118 : : const ::basegfx::B2DSize aReliefOffset(
2119 [ # # ][ # # ]: 0 : rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rReliefOffset ) );
2120 : : const ::basegfx::B2DSize aShadowOffset(
2121 [ # # ][ # # ]: 0 : rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rShadowOffset ) );
2122 : :
2123 [ # # ]: 0 : if( rState.isTextOutlineModeSet )
2124 : : {
2125 : : return createOutline(
2126 : : aStartPoint,
2127 : : aReliefOffset,
2128 : : rReliefColor,
2129 : : aShadowOffset,
2130 : : rShadowColor,
2131 : : rText,
2132 : : nStartPos,
2133 : : nLen,
2134 : : pDXArray,
2135 : : rVDev,
2136 : : rCanvas,
2137 : : rState,
2138 [ # # ]: 0 : rParms );
2139 : : }
2140 : :
2141 : : // convert DX array to device coordinate system (and
2142 : : // create it in the first place, if pDXArray is NULL)
2143 : : const uno::Sequence< double > aCharWidths(
2144 : : pDXArray ?
2145 : : setupDXArray( pDXArray, nLen, rState ) :
2146 : : setupDXArray( rText,
2147 : : nStartPos,
2148 : : nLen,
2149 : : rVDev,
2150 [ # # ][ # # ]: 0 : rState ));
[ # # ]
2151 : :
2152 : : // determine type of text action to create
2153 : : // =======================================
2154 : :
2155 : 0 : const ::Color aEmptyColor( COL_AUTO );
2156 : :
2157 : : // no DX array, and no need to subset - no need to store
2158 : : // DX array, then.
2159 [ # # ][ # # ]: 0 : if( !pDXArray && !bSubsettable )
2160 : : {
2161 : : // effects, or not?
2162 [ # # ][ # # ]: 0 : if( !rState.textOverlineStyle &&
[ # # # #
# # ][ # # ]
2163 : 0 : !rState.textUnderlineStyle &&
2164 : 0 : !rState.textStrikeoutStyle &&
2165 : 0 : rReliefColor == aEmptyColor &&
2166 : 0 : rShadowColor == aEmptyColor )
2167 : : {
2168 : : // nope
2169 [ # # ]: 0 : if( rParms.maTextTransformation.is_initialized() )
2170 : : {
2171 : : return ActionSharedPtr( new TextAction(
2172 : : aStartPoint,
2173 : : rText,
2174 : : nStartPos,
2175 : : nLen,
2176 : : rCanvas,
2177 : : rState,
2178 [ # # ][ # # ]: 0 : *rParms.maTextTransformation ) );
[ # # ][ # # ]
[ # # ]
2179 : : }
2180 : : else
2181 : : {
2182 : : return ActionSharedPtr( new TextAction(
2183 : : aStartPoint,
2184 : : rText,
2185 : : nStartPos,
2186 : : nLen,
2187 : : rCanvas,
2188 [ # # ][ # # ]: 0 : rState ) );
[ # # ][ # # ]
2189 : : }
2190 : : }
2191 : : else
2192 : : {
2193 : : // at least one of the effects requested
2194 [ # # ]: 0 : if( rParms.maTextTransformation.is_initialized() )
2195 : : return ActionSharedPtr( new EffectTextAction(
2196 : : aStartPoint,
2197 : : aReliefOffset,
2198 : : rReliefColor,
2199 : : aShadowOffset,
2200 : : rShadowColor,
2201 : : rText,
2202 : : nStartPos,
2203 : : nLen,
2204 : : rVDev,
2205 : : rCanvas,
2206 : : rState,
2207 [ # # ][ # # ]: 0 : *rParms.maTextTransformation ) );
[ # # ][ # # ]
[ # # ]
2208 : : else
2209 : : return ActionSharedPtr( new EffectTextAction(
2210 : : aStartPoint,
2211 : : aReliefOffset,
2212 : : rReliefColor,
2213 : : aShadowOffset,
2214 : : rShadowColor,
2215 : : rText,
2216 : : nStartPos,
2217 : : nLen,
2218 : : rVDev,
2219 : : rCanvas,
2220 [ # # ][ # # ]: 0 : rState ) );
[ # # ][ # # ]
2221 : : }
2222 : : }
2223 : : else
2224 : : {
2225 : : // DX array necessary - any effects?
2226 [ # # ][ # # ]: 0 : if( !rState.textOverlineStyle &&
[ # # # #
# # ][ # # ]
2227 : 0 : !rState.textUnderlineStyle &&
2228 : 0 : !rState.textStrikeoutStyle &&
2229 : 0 : rReliefColor == aEmptyColor &&
2230 : 0 : rShadowColor == aEmptyColor )
2231 : : {
2232 : : // nope
2233 [ # # ]: 0 : if( rParms.maTextTransformation.is_initialized() )
2234 : : return ActionSharedPtr( new TextArrayAction(
2235 : : aStartPoint,
2236 : : rText,
2237 : : nStartPos,
2238 : : nLen,
2239 : : aCharWidths,
2240 : : rCanvas,
2241 : : rState,
2242 [ # # ][ # # ]: 0 : *rParms.maTextTransformation ) );
[ # # ][ # # ]
[ # # ]
2243 : : else
2244 : : return ActionSharedPtr( new TextArrayAction(
2245 : : aStartPoint,
2246 : : rText,
2247 : : nStartPos,
2248 : : nLen,
2249 : : aCharWidths,
2250 : : rCanvas,
2251 [ # # ][ # # ]: 0 : rState ) );
[ # # ][ # # ]
2252 : : }
2253 : : else
2254 : : {
2255 : : // at least one of the effects requested
2256 [ # # ]: 0 : if( rParms.maTextTransformation.is_initialized() )
2257 : : return ActionSharedPtr( new EffectTextArrayAction(
2258 : : aStartPoint,
2259 : : aReliefOffset,
2260 : : rReliefColor,
2261 : : aShadowOffset,
2262 : : rShadowColor,
2263 : : rText,
2264 : : nStartPos,
2265 : : nLen,
2266 : : aCharWidths,
2267 : : rVDev,
2268 : : rCanvas,
2269 : : rState,
2270 [ # # ][ # # ]: 0 : *rParms.maTextTransformation ) );
[ # # ][ # # ]
[ # # ]
2271 : : else
2272 : : return ActionSharedPtr( new EffectTextArrayAction(
2273 : : aStartPoint,
2274 : : aReliefOffset,
2275 : : rReliefColor,
2276 : : aShadowOffset,
2277 : : rShadowColor,
2278 : : rText,
2279 : : nStartPos,
2280 : : nLen,
2281 : : aCharWidths,
2282 : : rVDev,
2283 : : rCanvas,
2284 [ # # ][ # # ]: 0 : rState ) );
[ # # ][ # # ]
2285 : : }
2286 : : }
2287 : : #if defined(__GNUC__)
2288 [ # # ]: 0 : return ActionSharedPtr();
2289 : : #endif
2290 : : }
2291 : : }
2292 [ + - ][ + - ]: 735 : }
2293 : :
2294 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|