1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
21 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
22 #include <drawinglayer/attribute/strokeattribute.hxx>
23 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
24 #include <basegfx/matrix/b2dhommatrixtools.hxx>
25 #include <drawinglayer/primitive2d/texteffectprimitive2d.hxx>
26 #include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
27 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
28 #include <drawinglayer/primitive2d/textlineprimitive2d.hxx>
29 #include <drawinglayer/primitive2d/textstrikeoutprimitive2d.hxx>
30 #include <drawinglayer/primitive2d/textbreakuphelper.hxx>
32 //////////////////////////////////////////////////////////////////////////////
34 namespace drawinglayer
38 void TextDecoratedPortionPrimitive2D::impCreateGeometryContent(
39 std::vector
< Primitive2DReference
>& rTarget
,
40 basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose
& rDecTrans
,
42 xub_StrLen aTextPosition
,
43 xub_StrLen aTextLength
,
44 const ::std::vector
< double >& rDXArray
,
45 const attribute::FontAttribute
& rFontAttribute
) const
47 // create the SimpleTextPrimitive needed in any case
48 rTarget
.push_back(Primitive2DReference(
49 new TextSimplePortionPrimitive2D(
50 rDecTrans
.getB2DHomMatrix(),
59 // see if something else needs to be done
60 const bool bOverlineUsed(TEXT_LINE_NONE
!= getFontOverline());
61 const bool bUnderlineUsed(TEXT_LINE_NONE
!= getFontUnderline());
62 const bool bStrikeoutUsed(TEXT_STRIKEOUT_NONE
!= getTextStrikeout());
64 if(bUnderlineUsed
|| bStrikeoutUsed
|| bOverlineUsed
)
66 // common preparations
67 TextLayouterDevice aTextLayouter
;
69 // TextLayouterDevice is needed to get metrics for text decorations like
70 // underline/strikeout/emphasis marks from it. For setup, the font size is needed
71 aTextLayouter
.setFontAttribute(
73 rDecTrans
.getScale().getX(),
74 rDecTrans
.getScale().getY(),
78 double fTextWidth(0.0);
82 fTextWidth
= aTextLayouter
.getTextWidth(rText
, aTextPosition
, aTextLength
);
86 fTextWidth
= rDXArray
.back() * rDecTrans
.getScale().getX();
87 const double fFontScaleX(rDecTrans
.getScale().getX());
89 if(!basegfx::fTools::equal(fFontScaleX
, 1.0)
90 && !basegfx::fTools::equalZero(fFontScaleX
))
92 // need to take FontScaling out of the DXArray
93 fTextWidth
/= fFontScaleX
;
99 // create primitive geometry for overline
100 rTarget
.push_back(Primitive2DReference(
101 new TextLinePrimitive2D(
102 rDecTrans
.getB2DHomMatrix(),
104 aTextLayouter
.getOverlineOffset(),
105 aTextLayouter
.getOverlineHeight(),
107 getOverlineColor())));
112 // create primitive geometry for underline
113 rTarget
.push_back(Primitive2DReference(
114 new TextLinePrimitive2D(
115 rDecTrans
.getB2DHomMatrix(),
117 aTextLayouter
.getUnderlineOffset(),
118 aTextLayouter
.getUnderlineHeight(),
120 getTextlineColor())));
125 // create primitive geometry for strikeout
126 if(TEXT_STRIKEOUT_SLASH
== getTextStrikeout() || TEXT_STRIKEOUT_X
== getTextStrikeout())
128 // strikeout with character
129 const sal_Unicode
aStrikeoutChar(TEXT_STRIKEOUT_SLASH
== getTextStrikeout() ? '/' : 'X');
131 rTarget
.push_back(Primitive2DReference(
132 new TextCharacterStrikeoutPrimitive2D(
133 rDecTrans
.getB2DHomMatrix(),
142 // strikeout with geometry
143 rTarget
.push_back(Primitive2DReference(
144 new TextGeometryStrikeoutPrimitive2D(
145 rDecTrans
.getB2DHomMatrix(),
148 aTextLayouter
.getUnderlineHeight(),
149 aTextLayouter
.getStrikeoutOffset(),
150 getTextStrikeout())));
155 // TODO: Handle Font Emphasis Above/Below
158 Primitive2DSequence
TextDecoratedPortionPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D
& /*rViewInformation*/) const
160 if(getWordLineMode())
162 // support for single word mode; split to single word primitives
163 // using TextBreakupHelper
164 const TextBreakupHelper
aTextBreakupHelper(*this);
165 const Primitive2DSequence
aBroken(aTextBreakupHelper
.getResult(BreakupUnit_word
));
167 if(aBroken
.hasElements())
169 // was indeed split to several words, use as result
174 // no split, was already a single word. Continue to
175 // decompse local entity
178 std::vector
< Primitive2DReference
> aNewPrimitives
;
179 basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose
aDecTrans(getTextTransform());
180 Primitive2DSequence aRetval
;
182 // create basic geometry such as SimpleTextPrimitive, Overline, Underline,
184 // prepare new font attributes WITHOUT outline
185 const attribute::FontAttribute
aNewFontAttribute(
186 getFontAttribute().getFamilyName(),
187 getFontAttribute().getStyleName(),
188 getFontAttribute().getWeight(),
189 getFontAttribute().getSymbol(),
190 getFontAttribute().getVertical(),
191 getFontAttribute().getItalic(),
192 getFontAttribute().getMonospaced(),
193 false, // no outline anymore, handled locally
194 getFontAttribute().getRTL(),
195 getFontAttribute().getBiDiStrong());
197 // handle as one word
198 impCreateGeometryContent(aNewPrimitives
, aDecTrans
, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttribute
);
200 // convert to Primitive2DSequence
201 const sal_uInt32
nMemberCount(aNewPrimitives
.size());
205 aRetval
.realloc(nMemberCount
);
207 for(sal_uInt32
a(0); a
< nMemberCount
; a
++)
209 aRetval
[a
] = aNewPrimitives
[a
];
213 // Handle Shadow, Outline and TextRelief
214 if(aRetval
.hasElements())
216 // outline AND shadow depend on NO TextRelief (see dialog)
217 const bool bHasTextRelief(TEXT_RELIEF_NONE
!= getTextRelief());
218 const bool bHasShadow(!bHasTextRelief
&& getShadow());
219 const bool bHasOutline(!bHasTextRelief
&& getFontAttribute().getOutline());
221 if(bHasShadow
|| bHasTextRelief
|| bHasOutline
)
223 Primitive2DReference aShadow
;
227 // create shadow with current content (in aRetval). Text shadow
228 // is constant, relative to font size, rotated with the text and has a
230 // shadow parameter values
231 static double fFactor(1.0 / 24.0);
232 const double fTextShadowOffset(aDecTrans
.getScale().getY() * fFactor
);
233 static basegfx::BColor
aShadowColor(0.3, 0.3, 0.3);
235 // preapare shadow transform matrix
236 const basegfx::B2DHomMatrix
aShadowTransform(basegfx::tools::createTranslateB2DHomMatrix(
237 fTextShadowOffset
, fTextShadowOffset
));
239 // create shadow primitive
240 aShadow
= Primitive2DReference(new ShadowPrimitive2D(
248 // create emboss using an own helper primitive since this will
250 const basegfx::BColor
aBBlack(0.0, 0.0, 0.0);
251 const bool bDefaultTextColor(aBBlack
== getFontColor());
252 TextEffectStyle2D
aTextEffectStyle2D(TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED
);
254 if(bDefaultTextColor
)
256 if(TEXT_RELIEF_ENGRAVED
== getTextRelief())
258 aTextEffectStyle2D
= TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED_DEFAULT
;
262 aTextEffectStyle2D
= TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT
;
267 if(TEXT_RELIEF_ENGRAVED
== getTextRelief())
269 aTextEffectStyle2D
= TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED
;
273 aTextEffectStyle2D
= TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED
;
277 Primitive2DReference
aNewTextEffect(new TextEffectPrimitive2D(
279 aDecTrans
.getTranslate(),
280 aDecTrans
.getRotate(),
281 aTextEffectStyle2D
));
282 aRetval
= Primitive2DSequence(&aNewTextEffect
, 1);
286 // create outline using an own helper primitive since this will
288 Primitive2DReference
aNewTextEffect(new TextEffectPrimitive2D(
290 aDecTrans
.getTranslate(),
291 aDecTrans
.getRotate(),
292 TEXTEFFECTSTYLE2D_OUTLINE
));
293 aRetval
= Primitive2DSequence(&aNewTextEffect
, 1);
298 // put shadow in front if there is one to paint timely before
299 // but placed behind content
300 const Primitive2DSequence
aContent(aRetval
);
301 aRetval
= Primitive2DSequence(&aShadow
, 1);
302 appendPrimitive2DSequenceToPrimitive2DSequence(aRetval
, aContent
);
310 TextDecoratedPortionPrimitive2D::TextDecoratedPortionPrimitive2D(
312 // TextSimplePortionPrimitive2D parameters
313 const basegfx::B2DHomMatrix
& rNewTransform
,
315 xub_StrLen aTextPosition
,
316 xub_StrLen aTextLength
,
317 const ::std::vector
< double >& rDXArray
,
318 const attribute::FontAttribute
& rFontAttribute
,
319 const ::com::sun::star::lang::Locale
& rLocale
,
320 const basegfx::BColor
& rFontColor
,
323 const basegfx::BColor
& rOverlineColor
,
324 const basegfx::BColor
& rTextlineColor
,
325 TextLine eFontOverline
,
326 TextLine eFontUnderline
,
327 bool bUnderlineAbove
,
328 TextStrikeout eTextStrikeout
,
330 TextEmphasisMark eTextEmphasisMark
,
331 bool bEmphasisMarkAbove
,
332 bool bEmphasisMarkBelow
,
333 TextRelief eTextRelief
,
335 : TextSimplePortionPrimitive2D(rNewTransform
, rText
, aTextPosition
, aTextLength
, rDXArray
, rFontAttribute
, rLocale
, rFontColor
),
336 maOverlineColor(rOverlineColor
),
337 maTextlineColor(rTextlineColor
),
338 meFontOverline(eFontOverline
),
339 meFontUnderline(eFontUnderline
),
340 meTextStrikeout(eTextStrikeout
),
341 meTextEmphasisMark(eTextEmphasisMark
),
342 meTextRelief(eTextRelief
),
343 mbUnderlineAbove(bUnderlineAbove
),
344 mbWordLineMode(bWordLineMode
),
345 mbEmphasisMarkAbove(bEmphasisMarkAbove
),
346 mbEmphasisMarkBelow(bEmphasisMarkBelow
),
351 bool TextDecoratedPortionPrimitive2D::decoratedIsNeeded() const
353 return (TEXT_LINE_NONE
!= getFontOverline()
354 || TEXT_LINE_NONE
!= getFontUnderline()
355 || TEXT_STRIKEOUT_NONE
!= getTextStrikeout()
356 || TEXT_EMPHASISMARK_NONE
!= getTextEmphasisMark()
357 || TEXT_RELIEF_NONE
!= getTextRelief()
361 bool TextDecoratedPortionPrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
363 if(TextSimplePortionPrimitive2D::operator==(rPrimitive
))
365 const TextDecoratedPortionPrimitive2D
& rCompare
= (TextDecoratedPortionPrimitive2D
&)rPrimitive
;
367 return (getOverlineColor() == rCompare
.getOverlineColor()
368 && getTextlineColor() == rCompare
.getTextlineColor()
369 && getFontOverline() == rCompare
.getFontOverline()
370 && getFontUnderline() == rCompare
.getFontUnderline()
371 && getTextStrikeout() == rCompare
.getTextStrikeout()
372 && getTextEmphasisMark() == rCompare
.getTextEmphasisMark()
373 && getTextRelief() == rCompare
.getTextRelief()
374 && getUnderlineAbove() == rCompare
.getUnderlineAbove()
375 && getWordLineMode() == rCompare
.getWordLineMode()
376 && getEmphasisMarkAbove() == rCompare
.getEmphasisMarkAbove()
377 && getEmphasisMarkBelow() == rCompare
.getEmphasisMarkBelow()
378 && getShadow() == rCompare
.getShadow());
385 // Added missing implementation. Decorations may (will) stick out of the text's
386 // inking area, so add them if needed
387 basegfx::B2DRange
TextDecoratedPortionPrimitive2D::getB2DRange(const geometry::ViewInformation2D
& rViewInformation
) const
389 if(decoratedIsNeeded())
391 // decoration is used, fallback to BufferedDecompositionPrimitive2D::getB2DRange which uses
392 // the own local decomposition for computation and thus creates all necessary
394 return BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation
);
398 // no relevant decoration used, fallback to TextSimplePortionPrimitive2D::getB2DRange
399 return TextSimplePortionPrimitive2D::getB2DRange(rViewInformation
);
404 ImplPrimitive2DIDBlock(TextDecoratedPortionPrimitive2D
, PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D
)
406 } // end of namespace primitive2d
407 } // end of namespace drawinglayer
409 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */