fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / drawinglayer / source / primitive2d / textdecoratedprimitive2d.cxx
blob258ccecdb5301b8d524aa07b94aadef5ff354fdf
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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
36 namespace primitive2d
38 void TextDecoratedPortionPrimitive2D::impCreateGeometryContent(
39 std::vector< Primitive2DReference >& rTarget,
40 basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose& rDecTrans,
41 const String& rText,
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(),
51 rText,
52 aTextPosition,
53 aTextLength,
54 rDXArray,
55 rFontAttribute,
56 getLocale(),
57 getFontColor())));
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(
72 getFontAttribute(),
73 rDecTrans.getScale().getX(),
74 rDecTrans.getScale().getY(),
75 getLocale());
77 // get text width
78 double fTextWidth(0.0);
80 if(rDXArray.empty())
82 fTextWidth = aTextLayouter.getTextWidth(rText, aTextPosition, aTextLength);
84 else
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;
97 if(bOverlineUsed)
99 // create primitive geometry for overline
100 rTarget.push_back(Primitive2DReference(
101 new TextLinePrimitive2D(
102 rDecTrans.getB2DHomMatrix(),
103 fTextWidth,
104 aTextLayouter.getOverlineOffset(),
105 aTextLayouter.getOverlineHeight(),
106 getFontOverline(),
107 getOverlineColor())));
110 if(bUnderlineUsed)
112 // create primitive geometry for underline
113 rTarget.push_back(Primitive2DReference(
114 new TextLinePrimitive2D(
115 rDecTrans.getB2DHomMatrix(),
116 fTextWidth,
117 aTextLayouter.getUnderlineOffset(),
118 aTextLayouter.getUnderlineHeight(),
119 getFontUnderline(),
120 getTextlineColor())));
123 if(bStrikeoutUsed)
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(),
134 fTextWidth,
135 getFontColor(),
136 aStrikeoutChar,
137 getFontAttribute(),
138 getLocale())));
140 else
142 // strikeout with geometry
143 rTarget.push_back(Primitive2DReference(
144 new TextGeometryStrikeoutPrimitive2D(
145 rDecTrans.getB2DHomMatrix(),
146 fTextWidth,
147 getFontColor(),
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
170 return aBroken;
172 else
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,
183 // Strikeout, etc...
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());
203 if(nMemberCount)
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;
225 if(bHasShadow)
227 // create shadow with current content (in aRetval). Text shadow
228 // is constant, relative to font size, rotated with the text and has a
229 // constant color.
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(
241 aShadowTransform,
242 aShadowColor,
243 aRetval));
246 if(bHasTextRelief)
248 // create emboss using an own helper primitive since this will
249 // be view-dependent
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;
260 else
262 aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT;
265 else
267 if(TEXT_RELIEF_ENGRAVED == getTextRelief())
269 aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED;
271 else
273 aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED;
277 Primitive2DReference aNewTextEffect(new TextEffectPrimitive2D(
278 aRetval,
279 aDecTrans.getTranslate(),
280 aDecTrans.getRotate(),
281 aTextEffectStyle2D));
282 aRetval = Primitive2DSequence(&aNewTextEffect, 1);
284 else if(bHasOutline)
286 // create outline using an own helper primitive since this will
287 // be view-dependent
288 Primitive2DReference aNewTextEffect(new TextEffectPrimitive2D(
289 aRetval,
290 aDecTrans.getTranslate(),
291 aDecTrans.getRotate(),
292 TEXTEFFECTSTYLE2D_OUTLINE));
293 aRetval = Primitive2DSequence(&aNewTextEffect, 1);
296 if(aShadow.is())
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);
307 return aRetval;
310 TextDecoratedPortionPrimitive2D::TextDecoratedPortionPrimitive2D(
312 // TextSimplePortionPrimitive2D parameters
313 const basegfx::B2DHomMatrix& rNewTransform,
314 const String& rText,
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,
322 // local parameters
323 const basegfx::BColor& rOverlineColor,
324 const basegfx::BColor& rTextlineColor,
325 TextLine eFontOverline,
326 TextLine eFontUnderline,
327 bool bUnderlineAbove,
328 TextStrikeout eTextStrikeout,
329 bool bWordLineMode,
330 TextEmphasisMark eTextEmphasisMark,
331 bool bEmphasisMarkAbove,
332 bool bEmphasisMarkBelow,
333 TextRelief eTextRelief,
334 bool bShadow)
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),
347 mbShadow(bShadow)
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()
358 || getShadow());
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());
381 return false;
384 // #i96475#
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
393 // geometric objects
394 return BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
396 else
398 // no relevant decoration used, fallback to TextSimplePortionPrimitive2D::getB2DRange
399 return TextSimplePortionPrimitive2D::getB2DRange(rViewInformation);
403 // provide unique ID
404 ImplPrimitive2DIDBlock(TextDecoratedPortionPrimitive2D, PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D)
406 } // end of namespace primitive2d
407 } // end of namespace drawinglayer
409 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */