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