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 : : #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
30 : : #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
31 : : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
32 : : #include <drawinglayer/attribute/strokeattribute.hxx>
33 : : #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
34 : : #include <basegfx/matrix/b2dhommatrixtools.hxx>
35 : : #include <comphelper/processfactory.hxx>
36 : : #include <com/sun/star/i18n/WordType.hpp>
37 : : #include <drawinglayer/primitive2d/texteffectprimitive2d.hxx>
38 : : #include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
39 : : #include <com/sun/star/i18n/XBreakIterator.hpp>
40 : : #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
41 : : #include <drawinglayer/primitive2d/textlineprimitive2d.hxx>
42 : : #include <drawinglayer/primitive2d/textstrikeoutprimitive2d.hxx>
43 : :
44 : : //////////////////////////////////////////////////////////////////////////////
45 : :
46 : : namespace drawinglayer
47 : : {
48 : : namespace primitive2d
49 : : {
50 : 2662 : void TextDecoratedPortionPrimitive2D::impCreateGeometryContent(
51 : : std::vector< Primitive2DReference >& rTarget,
52 : : basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose& rDecTrans,
53 : : const String& rText,
54 : : xub_StrLen aTextPosition,
55 : : xub_StrLen aTextLength,
56 : : const ::std::vector< double >& rDXArray,
57 : : const attribute::FontAttribute& rFontAttribute) const
58 : : {
59 : : // create the SimpleTextPrimitive needed in any case
60 : : rTarget.push_back(Primitive2DReference(
61 : : new TextSimplePortionPrimitive2D(
62 : : rDecTrans.getB2DHomMatrix(),
63 : : rText,
64 : : aTextPosition,
65 : : aTextLength,
66 : : rDXArray,
67 : : rFontAttribute,
68 : 2662 : getLocale(),
69 [ + - ][ + - ]: 2662 : getFontColor())));
[ + - ]
70 : :
71 : : // see if something else needs to be done
72 : 2662 : const bool bOverlineUsed(TEXT_LINE_NONE != getFontOverline());
73 : 2662 : const bool bUnderlineUsed(TEXT_LINE_NONE != getFontUnderline());
74 : 2662 : const bool bStrikeoutUsed(TEXT_STRIKEOUT_NONE != getTextStrikeout());
75 : :
76 [ + + ][ + + ]: 2662 : if(bUnderlineUsed || bStrikeoutUsed || bOverlineUsed)
[ + + ]
77 : : {
78 : : // common preparations
79 [ + - ]: 2644 : TextLayouterDevice aTextLayouter;
80 : :
81 : : // TextLayouterDevice is needed to get metrics for text decorations like
82 : : // underline/strikeout/emphasis marks from it. For setup, the font size is needed
83 : : aTextLayouter.setFontAttribute(
84 : 2644 : getFontAttribute(),
85 [ + - ]: 2644 : rDecTrans.getScale().getX(),
86 [ + - ]: 2644 : rDecTrans.getScale().getY(),
87 [ + - ]: 10576 : getLocale());
88 : :
89 : : // get text width
90 : 2644 : double fTextWidth(0.0);
91 : :
92 [ - + ]: 2644 : if(rDXArray.empty())
93 : : {
94 [ # # ]: 0 : fTextWidth = aTextLayouter.getTextWidth(rText, aTextPosition, aTextLength);
95 : : }
96 : : else
97 : : {
98 [ + - ][ + - ]: 2644 : fTextWidth = rDXArray.back() * rDecTrans.getScale().getX();
99 [ + - ]: 2644 : const double fFontScaleX(rDecTrans.getScale().getX());
100 : :
101 [ + - ][ + - ]: 5288 : if(!basegfx::fTools::equal(fFontScaleX, 1.0)
[ + - + - ]
102 : 2644 : && !basegfx::fTools::equalZero(fFontScaleX))
103 : : {
104 : : // need to take FontScaling out of the DXArray
105 : 2644 : fTextWidth /= fFontScaleX;
106 : : }
107 : : }
108 : :
109 [ + + ]: 2644 : if(bOverlineUsed)
110 : : {
111 : : // create primitive geometry for overline
112 : : rTarget.push_back(Primitive2DReference(
113 : : new TextLinePrimitive2D(
114 : : rDecTrans.getB2DHomMatrix(),
115 : : fTextWidth,
116 : : aTextLayouter.getOverlineOffset(),
117 : : aTextLayouter.getOverlineHeight(),
118 : : getFontOverline(),
119 [ + - ][ + - ]: 1790 : getOverlineColor())));
[ + - ][ + - ]
[ + - ][ + - ]
120 : : }
121 : :
122 [ + + ]: 2644 : if(bUnderlineUsed)
123 : : {
124 : : // create primitive geometry for underline
125 : : rTarget.push_back(Primitive2DReference(
126 : : new TextLinePrimitive2D(
127 : : rDecTrans.getB2DHomMatrix(),
128 : : fTextWidth,
129 : : aTextLayouter.getUnderlineOffset(),
130 : : aTextLayouter.getUnderlineHeight(),
131 : : getFontUnderline(),
132 [ + - ][ + - ]: 2428 : getTextlineColor())));
[ + - ][ + - ]
[ + - ][ + - ]
133 : : }
134 : :
135 [ + + ]: 2644 : if(bStrikeoutUsed)
136 : : {
137 : : // create primitive geometry for strikeout
138 [ + + ][ - + ]: 1247 : if(TEXT_STRIKEOUT_SLASH == getTextStrikeout() || TEXT_STRIKEOUT_X == getTextStrikeout())
[ + + ]
139 : : {
140 : : // strikeout with character
141 [ + - ]: 72 : const sal_Unicode aStrikeoutChar(TEXT_STRIKEOUT_SLASH == getTextStrikeout() ? '/' : 'X');
142 : :
143 : : rTarget.push_back(Primitive2DReference(
144 : : new TextCharacterStrikeoutPrimitive2D(
145 : : rDecTrans.getB2DHomMatrix(),
146 : : fTextWidth,
147 : 72 : getFontColor(),
148 : : aStrikeoutChar,
149 : 72 : getFontAttribute(),
150 [ + - ][ + - ]: 72 : getLocale())));
[ + - ][ + - ]
151 : : }
152 : : else
153 : : {
154 : : // strikeout with geometry
155 : : rTarget.push_back(Primitive2DReference(
156 : : new TextGeometryStrikeoutPrimitive2D(
157 : : rDecTrans.getB2DHomMatrix(),
158 : : fTextWidth,
159 : 1175 : getFontColor(),
160 : : aTextLayouter.getUnderlineHeight(),
161 : : aTextLayouter.getStrikeoutOffset(),
162 [ + - ][ + - ]: 1175 : getTextStrikeout())));
[ + - ][ + - ]
[ + - ][ + - ]
163 : : }
164 [ + - ]: 2644 : }
165 : : }
166 : :
167 : : // TODO: Handle Font Emphasis Above/Below
168 : 2662 : }
169 : :
170 : 1619 : void TextDecoratedPortionPrimitive2D::impCorrectTextBoundary(::com::sun::star::i18n::Boundary& rNextWordBoundary) const
171 : : {
172 : : // truncate aNextWordBoundary to min/max possible values. This is necessary since the word start may be
173 : : // before/after getTextPosition() when a long string is the content and getTextPosition()
174 : : // is right inside a word. Same for end.
175 : 1619 : const sal_Int32 aMinPos(static_cast< sal_Int32 >(getTextPosition()));
176 : 1619 : const sal_Int32 aMaxPos(aMinPos + static_cast< sal_Int32 >(getTextLength()));
177 : :
178 [ + + ]: 1619 : if(rNextWordBoundary.startPos < aMinPos)
179 : : {
180 : 316 : rNextWordBoundary.startPos = aMinPos;
181 : : }
182 [ - + ]: 1303 : else if(rNextWordBoundary.startPos > aMaxPos)
183 : : {
184 : 0 : rNextWordBoundary.startPos = aMaxPos;
185 : : }
186 : :
187 [ - + ]: 1619 : if(rNextWordBoundary.endPos < aMinPos)
188 : : {
189 : 0 : rNextWordBoundary.endPos = aMinPos;
190 : : }
191 [ + + ]: 1619 : else if(rNextWordBoundary.endPos > aMaxPos)
192 : : {
193 : 384 : rNextWordBoundary.endPos = aMaxPos;
194 : : }
195 : 1619 : }
196 : :
197 : 907 : void TextDecoratedPortionPrimitive2D::impSplitSingleWords(
198 : : std::vector< Primitive2DReference >& rTarget,
199 : : basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose& rDecTrans) const
200 : : {
201 : : // break iterator support
202 : : // made static so it only needs to be fetched once, even with many single
203 : : // constructed VclMetafileProcessor2D. It's still incarnated on demand,
204 : : // but exists for OOo runtime now by purpose.
205 [ + + ][ + - ]: 907 : static ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xLocalBreakIterator;
206 : :
207 [ + + ]: 907 : if(!xLocalBreakIterator.is())
208 : : {
209 [ + - ]: 4 : ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory());
210 [ + - ][ + - ]: 4 : xLocalBreakIterator.set(xMSF->createInstance("com.sun.star.i18n.BreakIterator"), ::com::sun::star::uno::UNO_QUERY);
[ + - ]
211 : : }
212 : :
213 [ + - ][ + - ]: 907 : if(xLocalBreakIterator.is() && getTextLength())
[ + - ]
214 : : {
215 : : // init word iterator, get first word and truncate to possibilities
216 [ + - ]: 907 : ::com::sun::star::i18n::Boundary aNextWordBoundary(xLocalBreakIterator->getWordBoundary(
217 [ + - ][ + - ]: 907 : getText(), getTextPosition(), getLocale(), ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True));
218 : :
219 [ - + ]: 907 : if(aNextWordBoundary.endPos == getTextPosition())
220 : : {
221 : : // backward hit, force next word
222 [ # # ]: 0 : aNextWordBoundary = xLocalBreakIterator->getWordBoundary(
223 [ # # ][ # # ]: 0 : getText(), getTextPosition() + 1, getLocale(), ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True);
224 : : }
225 : :
226 [ + - ]: 907 : impCorrectTextBoundary(aNextWordBoundary);
227 : :
228 : : // prepare new font attributes WITHOUT outline
229 : : const attribute::FontAttribute aNewFontAttribute(
230 [ + - ]: 907 : getFontAttribute().getFamilyName(),
231 [ + - ]: 907 : getFontAttribute().getStyleName(),
232 [ + - ]: 907 : getFontAttribute().getWeight(),
233 [ + - ]: 907 : getFontAttribute().getSymbol(),
234 [ + - ]: 907 : getFontAttribute().getVertical(),
235 [ + - ]: 907 : getFontAttribute().getItalic(),
236 [ + - ]: 907 : getFontAttribute().getMonospaced(),
237 : : false, // no outline anymore, handled locally
238 [ + - ]: 907 : getFontAttribute().getRTL(),
239 [ + - ][ + - ]: 1814 : getFontAttribute().getBiDiStrong());
240 : :
241 [ + - ][ + + ]: 907 : if(aNextWordBoundary.startPos == getTextPosition() && aNextWordBoundary.endPos == getTextLength())
[ + + ]
242 : : {
243 : : // it IS only a single word, handle as one word
244 [ + - ]: 321 : impCreateGeometryContent(rTarget, rDecTrans, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttribute);
245 : : }
246 : : else
247 : : {
248 : : // prepare TextLayouter
249 : 586 : const bool bNoDXArray(getDXArray().empty());
250 [ + - ]: 586 : TextLayouterDevice aTextLayouter;
251 : :
252 [ - + ]: 586 : if(bNoDXArray)
253 : : {
254 : : // ..but only completely when no DXArray
255 : : aTextLayouter.setFontAttribute(
256 : 0 : getFontAttribute(),
257 [ # # ]: 0 : rDecTrans.getScale().getX(),
258 [ # # ]: 0 : rDecTrans.getScale().getY(),
259 [ # # ]: 0 : getLocale());
260 : : }
261 : :
262 : : // do iterate over single words
263 [ + + ]: 1816 : while(aNextWordBoundary.startPos != aNextWordBoundary.endPos)
264 : : {
265 : : // prepare values for new portion
266 : 1230 : const xub_StrLen nNewTextStart(static_cast< xub_StrLen >(aNextWordBoundary.startPos));
267 : 1230 : const xub_StrLen nNewTextEnd(static_cast< xub_StrLen >(aNextWordBoundary.endPos));
268 : :
269 : : // prepare transform for the single word
270 [ + - ]: 1230 : basegfx::B2DHomMatrix aNewTransform;
271 [ + - ]: 1230 : ::std::vector< double > aNewDXArray;
272 : 1230 : const bool bNewStartIsNotOldStart(nNewTextStart > getTextPosition());
273 : :
274 [ + - ]: 1230 : if(!bNoDXArray)
275 : : {
276 : : // prepare new DXArray for the single word
277 : : aNewDXArray = ::std::vector< double >(
278 : 1230 : getDXArray().begin() + static_cast< sal_uInt32 >(nNewTextStart - getTextPosition()),
279 [ + - + - ]: 2460 : getDXArray().begin() + static_cast< sal_uInt32 >(nNewTextEnd - getTextPosition()));
[ + - ]
280 : : }
281 : :
282 [ + + ]: 1230 : if(bNewStartIsNotOldStart)
283 : : {
284 : : // needs to be moved to a new start position
285 : 644 : double fOffset(0.0);
286 : :
287 [ - + ]: 644 : if(bNoDXArray)
288 : : {
289 : : // evaluate using TextLayouter
290 [ # # ]: 0 : fOffset = aTextLayouter.getTextWidth(getText(), getTextPosition(), nNewTextStart);
291 : : }
292 : : else
293 : : {
294 : : // get from DXArray
295 : 644 : const sal_uInt32 nIndex(static_cast< sal_uInt32 >(nNewTextStart - getTextPosition()));
296 [ + - ]: 644 : fOffset = getDXArray()[nIndex - 1];
297 : : }
298 : :
299 : : // need offset without FontScale for building the new transformation. The
300 : : // new transformation will be multiplied with the current text transformation
301 : : // so FontScale would be double
302 : 644 : double fOffsetNoScale(fOffset);
303 [ + - ]: 644 : const double fFontScaleX(rDecTrans.getScale().getX());
304 : :
305 [ + - ][ + - ]: 1288 : if(!basegfx::fTools::equal(fFontScaleX, 1.0)
[ + - + - ]
306 : 644 : && !basegfx::fTools::equalZero(fFontScaleX))
307 : : {
308 : 644 : fOffsetNoScale /= fFontScaleX;
309 : : }
310 : :
311 : : // apply needed offset to transformation
312 [ + - ]: 644 : aNewTransform.translate(fOffsetNoScale, 0.0);
313 : :
314 [ + - ]: 644 : if(!bNoDXArray)
315 : : {
316 : : // DXArray values need to be corrected with the offset, too. Here,
317 : : // take the scaled offset since the DXArray is scaled
318 : 644 : const sal_uInt32 nArraySize(aNewDXArray.size());
319 : :
320 [ + + ]: 1737 : for(sal_uInt32 a(0); a < nArraySize; a++)
321 : : {
322 [ + - ]: 1093 : aNewDXArray[a] -= fOffset;
323 : : }
324 : : }
325 : : }
326 : :
327 : : // add text transformation to new transformation
328 [ + - ]: 1230 : aNewTransform *= rDecTrans.getB2DHomMatrix();
329 : :
330 : : // create geometry content for the single word. Do not forget
331 : : // to use the new transformation
332 [ + - ]: 1230 : basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose aDecTrans(aNewTransform);
333 : :
334 : 1230 : impCreateGeometryContent(rTarget, aDecTrans, getText(), nNewTextStart,
335 [ + - ]: 1230 : nNewTextEnd - nNewTextStart, aNewDXArray, aNewFontAttribute);
336 : :
337 [ + + ]: 1230 : if(aNextWordBoundary.endPos >= getTextPosition() + getTextLength())
338 : : {
339 : : // end reached
340 : 518 : aNextWordBoundary.startPos = aNextWordBoundary.endPos;
341 : : }
342 : : else
343 : : {
344 : : // get new word portion
345 : 712 : const sal_Int32 nLastEndPos(aNextWordBoundary.endPos);
346 : :
347 [ + - ]: 712 : aNextWordBoundary = xLocalBreakIterator->getWordBoundary(
348 : 712 : getText(), aNextWordBoundary.endPos, getLocale(),
349 [ + - ][ + - ]: 712 : ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True);
350 : :
351 [ + + ]: 712 : if(nLastEndPos == aNextWordBoundary.endPos)
352 : : {
353 : : // backward hit, force next word
354 [ + - ]: 506 : aNextWordBoundary = xLocalBreakIterator->getWordBoundary(
355 : 506 : getText(), nLastEndPos + 1, getLocale(),
356 [ + - ][ + - ]: 506 : ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True);
357 : : }
358 : :
359 [ + - ]: 712 : impCorrectTextBoundary(aNextWordBoundary);
360 : : }
361 [ + - ][ + - ]: 1816 : }
[ + - ]
362 [ + - ]: 907 : }
363 : : }
364 : 907 : }
365 : :
366 : 2018 : Primitive2DSequence TextDecoratedPortionPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
367 : : {
368 [ + - ]: 2018 : std::vector< Primitive2DReference > aNewPrimitives;
369 [ + - ]: 2018 : basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose aDecTrans(getTextTransform());
370 [ + - ]: 2018 : Primitive2DSequence aRetval;
371 : :
372 : : // create basic geometry such as SimpleTextPrimitive, Overline, Underline,
373 : : // Strikeout, etc...
374 [ + + ]: 2018 : if(getWordLineMode())
375 : : {
376 : : // support for single word mode
377 [ + - ]: 907 : impSplitSingleWords(aNewPrimitives, aDecTrans);
378 : : }
379 : : else
380 : : {
381 : : // prepare new font attributes WITHOUT outline
382 : : const attribute::FontAttribute aNewFontAttribute(
383 [ + - ]: 1111 : getFontAttribute().getFamilyName(),
384 [ + - ]: 1111 : getFontAttribute().getStyleName(),
385 [ + - ]: 1111 : getFontAttribute().getWeight(),
386 [ + - ]: 1111 : getFontAttribute().getSymbol(),
387 [ + - ]: 1111 : getFontAttribute().getVertical(),
388 [ + - ]: 1111 : getFontAttribute().getItalic(),
389 : : false, // no outline anymore, handled locally
390 [ + - ]: 1111 : getFontAttribute().getRTL(),
391 [ + - ][ + - ]: 2222 : getFontAttribute().getBiDiStrong());
392 : :
393 : : // handle as one word
394 [ + - ][ + - ]: 1111 : impCreateGeometryContent(aNewPrimitives, aDecTrans, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttribute);
395 : : }
396 : :
397 : : // convert to Primitive2DSequence
398 : 2018 : const sal_uInt32 nMemberCount(aNewPrimitives.size());
399 : :
400 [ + - ]: 2018 : if(nMemberCount)
401 : : {
402 [ + - ]: 2018 : aRetval.realloc(nMemberCount);
403 : :
404 [ + + ]: 10145 : for(sal_uInt32 a(0); a < nMemberCount; a++)
405 : : {
406 [ + - ][ + - ]: 8127 : aRetval[a] = aNewPrimitives[a];
407 : : }
408 : : }
409 : :
410 : : // Handle Shadow, Outline and TextRelief
411 [ + - ]: 2018 : if(aRetval.hasElements())
412 : : {
413 : : // outline AND shadow depend on NO TextRelief (see dialog)
414 : 2018 : const bool bHasTextRelief(TEXT_RELIEF_NONE != getTextRelief());
415 [ + + ][ + + ]: 2018 : const bool bHasShadow(!bHasTextRelief && getShadow());
416 [ + + ][ + - ]: 2018 : const bool bHasOutline(!bHasTextRelief && getFontAttribute().getOutline());
[ + + ]
417 : :
418 [ + + ][ + + ]: 2018 : if(bHasShadow || bHasTextRelief || bHasOutline)
[ + + ]
419 : : {
420 : 1798 : Primitive2DReference aShadow;
421 : :
422 [ + + ]: 1798 : if(bHasShadow)
423 : : {
424 : : // create shadow with current content (in aRetval). Text shadow
425 : : // is constant, relative to font size, rotated with the text and has a
426 : : // constant color.
427 : : // shadow parameter values
428 : : static double fFactor(1.0 / 24.0);
429 [ + - ]: 338 : const double fTextShadowOffset(aDecTrans.getScale().getY() * fFactor);
430 [ + - ][ + + ]: 338 : static basegfx::BColor aShadowColor(0.3, 0.3, 0.3);
431 : :
432 : : // preapare shadow transform matrix
433 : : const basegfx::B2DHomMatrix aShadowTransform(basegfx::tools::createTranslateB2DHomMatrix(
434 [ + - ]: 338 : fTextShadowOffset, fTextShadowOffset));
435 : :
436 : : // create shadow primitive
437 : : aShadow = Primitive2DReference(new ShadowPrimitive2D(
438 : : aShadowTransform,
439 : : aShadowColor,
440 [ + - ][ + - ]: 338 : aRetval));
[ + - ][ + - ]
[ + - ]
441 : : }
442 : :
443 [ + + ]: 1798 : if(bHasTextRelief)
444 : : {
445 : : // create emboss using an own helper primitive since this will
446 : : // be view-dependent
447 : 1372 : const basegfx::BColor aBBlack(0.0, 0.0, 0.0);
448 : 1372 : const bool bDefaultTextColor(aBBlack == getFontColor());
449 : 1372 : TextEffectStyle2D aTextEffectStyle2D(TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED);
450 : :
451 [ - + ]: 1372 : if(bDefaultTextColor)
452 : : {
453 [ # # ]: 0 : if(TEXT_RELIEF_ENGRAVED == getTextRelief())
454 : : {
455 : 0 : aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED_DEFAULT;
456 : : }
457 : : else
458 : : {
459 : 0 : aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT;
460 : : }
461 : : }
462 : : else
463 : : {
464 [ - + ]: 1372 : if(TEXT_RELIEF_ENGRAVED == getTextRelief())
465 : : {
466 : 0 : aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED;
467 : : }
468 : : else
469 : : {
470 : 1372 : aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED;
471 : : }
472 : : }
473 : :
474 : : Primitive2DReference aNewTextEffect(new TextEffectPrimitive2D(
475 : : aRetval,
476 [ + - ]: 1372 : aDecTrans.getTranslate(),
477 : : aDecTrans.getRotate(),
478 [ + - ][ + - ]: 1372 : aTextEffectStyle2D));
[ + - ][ + - ]
479 [ + - ][ + - ]: 1372 : aRetval = Primitive2DSequence(&aNewTextEffect, 1);
[ + - ]
480 : : }
481 [ + + ]: 426 : else if(bHasOutline)
482 : : {
483 : : // create outline using an own helper primitive since this will
484 : : // be view-dependent
485 : : Primitive2DReference aNewTextEffect(new TextEffectPrimitive2D(
486 : : aRetval,
487 [ + - ]: 355 : aDecTrans.getTranslate(),
488 : : aDecTrans.getRotate(),
489 [ + - ][ + - ]: 355 : TEXTEFFECTSTYLE2D_OUTLINE));
[ + - ][ + - ]
490 [ + - ][ + - ]: 355 : aRetval = Primitive2DSequence(&aNewTextEffect, 1);
[ + - ]
491 : : }
492 : :
493 [ + + ]: 1798 : if(aShadow.is())
494 : : {
495 : : // put shadow in front if there is one to paint timely before
496 : : // but placed behind content
497 [ + - ]: 338 : const Primitive2DSequence aContent(aRetval);
498 [ + - ][ + - ]: 338 : aRetval = Primitive2DSequence(&aShadow, 1);
[ + - ]
499 [ + - ][ + - ]: 338 : appendPrimitive2DSequenceToPrimitive2DSequence(aRetval, aContent);
500 : 1798 : }
501 : : }
502 : : }
503 : :
504 [ + - ]: 2018 : return aRetval;
505 : : }
506 : :
507 : 2018 : TextDecoratedPortionPrimitive2D::TextDecoratedPortionPrimitive2D(
508 : :
509 : : // TextSimplePortionPrimitive2D parameters
510 : : const basegfx::B2DHomMatrix& rNewTransform,
511 : : const String& rText,
512 : : xub_StrLen aTextPosition,
513 : : xub_StrLen aTextLength,
514 : : const ::std::vector< double >& rDXArray,
515 : : const attribute::FontAttribute& rFontAttribute,
516 : : const ::com::sun::star::lang::Locale& rLocale,
517 : : const basegfx::BColor& rFontColor,
518 : :
519 : : // local parameters
520 : : const basegfx::BColor& rOverlineColor,
521 : : const basegfx::BColor& rTextlineColor,
522 : : TextLine eFontOverline,
523 : : TextLine eFontUnderline,
524 : : bool bUnderlineAbove,
525 : : TextStrikeout eTextStrikeout,
526 : : bool bWordLineMode,
527 : : TextEmphasisMark eTextEmphasisMark,
528 : : bool bEmphasisMarkAbove,
529 : : bool bEmphasisMarkBelow,
530 : : TextRelief eTextRelief,
531 : : bool bShadow)
532 : : : TextSimplePortionPrimitive2D(rNewTransform, rText, aTextPosition, aTextLength, rDXArray, rFontAttribute, rLocale, rFontColor),
533 : : maOverlineColor(rOverlineColor),
534 : : maTextlineColor(rTextlineColor),
535 : : meFontOverline(eFontOverline),
536 : : meFontUnderline(eFontUnderline),
537 : : meTextStrikeout(eTextStrikeout),
538 : : meTextEmphasisMark(eTextEmphasisMark),
539 : : meTextRelief(eTextRelief),
540 : : mbUnderlineAbove(bUnderlineAbove),
541 : : mbWordLineMode(bWordLineMode),
542 : : mbEmphasisMarkAbove(bEmphasisMarkAbove),
543 : : mbEmphasisMarkBelow(bEmphasisMarkBelow),
544 : 2018 : mbShadow(bShadow)
545 : : {
546 : 2018 : }
547 : :
548 : 0 : bool TextDecoratedPortionPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
549 : : {
550 [ # # ]: 0 : if(TextSimplePortionPrimitive2D::operator==(rPrimitive))
551 : : {
552 : 0 : const TextDecoratedPortionPrimitive2D& rCompare = (TextDecoratedPortionPrimitive2D&)rPrimitive;
553 : :
554 : 0 : return (getOverlineColor() == rCompare.getOverlineColor()
555 : 0 : && getTextlineColor() == rCompare.getTextlineColor()
556 : 0 : && getFontOverline() == rCompare.getFontOverline()
557 : 0 : && getFontUnderline() == rCompare.getFontUnderline()
558 : 0 : && getTextStrikeout() == rCompare.getTextStrikeout()
559 : 0 : && getTextEmphasisMark() == rCompare.getTextEmphasisMark()
560 : 0 : && getTextRelief() == rCompare.getTextRelief()
561 : 0 : && getUnderlineAbove() == rCompare.getUnderlineAbove()
562 : 0 : && getWordLineMode() == rCompare.getWordLineMode()
563 : 0 : && getEmphasisMarkAbove() == rCompare.getEmphasisMarkAbove()
564 : 0 : && getEmphasisMarkBelow() == rCompare.getEmphasisMarkBelow()
565 [ # # ][ # # : 0 : && getShadow() == rCompare.getShadow());
# # # # #
# # # # #
# # # # #
# # # #
# ]
566 : : }
567 : :
568 : 0 : return false;
569 : : }
570 : :
571 : : // #i96475#
572 : : // Added missing implementation. Decorations may (will) stick out of the text's
573 : : // inking area, so add them if needed
574 : 14348 : basegfx::B2DRange TextDecoratedPortionPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
575 : : {
576 : : const bool bDecoratedIsNeeded(
577 : 14348 : TEXT_LINE_NONE != getFontOverline()
578 : 3659 : || TEXT_LINE_NONE != getFontUnderline()
579 : 465 : || TEXT_STRIKEOUT_NONE != getTextStrikeout()
580 : 62 : || TEXT_EMPHASISMARK_NONE != getTextEmphasisMark()
581 : 0 : || TEXT_RELIEF_NONE != getTextRelief()
582 [ # # ][ + + : 18534 : || getShadow());
+ + + + -
+ # # ]
583 : :
584 [ + - ]: 14348 : if(bDecoratedIsNeeded)
585 : : {
586 : : // decoration is used, fallback to BufferedDecompositionPrimitive2D::getB2DRange which uses
587 : : // the own local decomposition for computation and thus creates all necessary
588 : : // geometric objects
589 : 14348 : return BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
590 : : }
591 : : else
592 : : {
593 : : // no relevant decoration used, fallback to TextSimplePortionPrimitive2D::getB2DRange
594 : 14348 : return TextSimplePortionPrimitive2D::getB2DRange(rViewInformation);
595 : : }
596 : : }
597 : :
598 : : // provide unique ID
599 : 2357 : ImplPrimitrive2DIDBlock(TextDecoratedPortionPrimitive2D, PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D)
600 : :
601 : : } // end of namespace primitive2d
602 : : } // end of namespace drawinglayer
603 : :
604 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|