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 <primitive2d/texteffectprimitive2d.hxx>
21 #include <drawinglayer/geometry/viewinformation2d.hxx>
22 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
23 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
24 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
25 #include <basegfx/matrix/b2dhommatrixtools.hxx>
27 namespace drawinglayer::primitive2d
29 const double fDiscreteSize(1.1);
31 void TextEffectPrimitive2D::create2DDecomposition(
32 Primitive2DContainer
& rContainer
, const geometry::ViewInformation2D
& rViewInformation
) const
34 // get the distance of one discrete units from target display. Use between 1.0 and sqrt(2) to
35 // have good results on rotated objects, too
36 const basegfx::B2DVector
aDistance(rViewInformation
.getInverseObjectToViewTransformation()
37 * basegfx::B2DVector(fDiscreteSize
, fDiscreteSize
));
38 const basegfx::B2DVector
aDiagonalDistance(aDistance
* (1.0 / 1.44));
40 switch (getTextEffectStyle2D())
42 case TextEffectStyle2D::ReliefEmbossed
:
43 case TextEffectStyle2D::ReliefEngraved
:
44 case TextEffectStyle2D::ReliefEmbossedDefault
:
45 case TextEffectStyle2D::ReliefEngravedDefault
:
47 // prepare transform of sub-group back to (0,0) and align to X-Axis
48 basegfx::B2DHomMatrix
aBackTransform(basegfx::utils::createTranslateB2DHomMatrix(
49 -getRotationCenter().getX(), -getRotationCenter().getY()));
50 aBackTransform
.rotate(-getDirection());
52 // prepare transform of sub-group back to its position and rotation
53 basegfx::B2DHomMatrix
aForwardTransform(
54 basegfx::utils::createRotateB2DHomMatrix(getDirection()));
55 aForwardTransform
.translate(getRotationCenter().getX(), getRotationCenter().getY());
57 // create transformation for one discrete unit
58 const bool bEmbossed(TextEffectStyle2D::ReliefEmbossed
== getTextEffectStyle2D()
59 || TextEffectStyle2D::ReliefEmbossedDefault
60 == getTextEffectStyle2D());
61 const bool bDefaultTextColor(
62 TextEffectStyle2D::ReliefEmbossedDefault
== getTextEffectStyle2D()
63 || TextEffectStyle2D::ReliefEngravedDefault
== getTextEffectStyle2D());
64 basegfx::B2DHomMatrix
aTransform(aBackTransform
);
69 aTransform
.translate(aDiagonalDistance
.getX(), aDiagonalDistance
.getY());
74 aTransform
.translate(-aDiagonalDistance
.getX(), -aDiagonalDistance
.getY());
77 aTransform
*= aForwardTransform
;
79 if (bDefaultTextColor
)
81 // emboss/engrave in black, original forced to white
82 const basegfx::BColorModifierSharedPtr aBColorModifierToGray
83 = std::make_shared
<basegfx::BColorModifier_replace
>(basegfx::BColor(0.0));
84 const Primitive2DReference
xModifiedColor(new ModifiedColorPrimitive2D(
85 Primitive2DContainer(getTextContent()), aBColorModifierToGray
));
88 new TransformPrimitive2D(aTransform
, Primitive2DContainer
{ xModifiedColor
}));
91 const basegfx::BColorModifierSharedPtr aBColorModifierToWhite
92 = std::make_shared
<basegfx::BColorModifier_replace
>(basegfx::BColor(1.0));
94 rContainer
.push_back(new ModifiedColorPrimitive2D(
95 Primitive2DContainer(getTextContent()), aBColorModifierToWhite
));
99 // emboss/engrave in gray, keep original's color
100 const basegfx::BColorModifierSharedPtr aBColorModifierToGray
101 = std::make_shared
<basegfx::BColorModifier_replace
>(
102 basegfx::BColor(0.75)); // 192
103 const Primitive2DReference
xModifiedColor(new ModifiedColorPrimitive2D(
104 Primitive2DContainer(getTextContent()), aBColorModifierToGray
));
106 rContainer
.push_back(
107 new TransformPrimitive2D(aTransform
, Primitive2DContainer
{ xModifiedColor
}));
110 rContainer
.push_back(new GroupPrimitive2D(Primitive2DContainer(getTextContent())));
115 case TextEffectStyle2D::Outline
:
117 // create transform primitives in all directions
118 basegfx::B2DHomMatrix aTransform
;
120 aTransform
.set(0, 2, aDistance
.getX());
121 aTransform
.set(1, 2, 0.0);
122 rContainer
.push_back(
123 new TransformPrimitive2D(aTransform
, Primitive2DContainer(getTextContent())));
125 aTransform
.set(0, 2, aDiagonalDistance
.getX());
126 aTransform
.set(1, 2, aDiagonalDistance
.getY());
127 rContainer
.push_back(
128 new TransformPrimitive2D(aTransform
, Primitive2DContainer(getTextContent())));
130 aTransform
.set(0, 2, 0.0);
131 aTransform
.set(1, 2, aDistance
.getY());
132 rContainer
.push_back(
133 new TransformPrimitive2D(aTransform
, Primitive2DContainer(getTextContent())));
135 aTransform
.set(0, 2, -aDiagonalDistance
.getX());
136 aTransform
.set(1, 2, aDiagonalDistance
.getY());
137 rContainer
.push_back(
138 new TransformPrimitive2D(aTransform
, Primitive2DContainer(getTextContent())));
140 aTransform
.set(0, 2, -aDistance
.getX());
141 aTransform
.set(1, 2, 0.0);
142 rContainer
.push_back(
143 new TransformPrimitive2D(aTransform
, Primitive2DContainer(getTextContent())));
145 aTransform
.set(0, 2, -aDiagonalDistance
.getX());
146 aTransform
.set(1, 2, -aDiagonalDistance
.getY());
147 rContainer
.push_back(
148 new TransformPrimitive2D(aTransform
, Primitive2DContainer(getTextContent())));
150 aTransform
.set(0, 2, 0.0);
151 aTransform
.set(1, 2, -aDistance
.getY());
152 rContainer
.push_back(
153 new TransformPrimitive2D(aTransform
, Primitive2DContainer(getTextContent())));
155 aTransform
.set(0, 2, aDiagonalDistance
.getX());
156 aTransform
.set(1, 2, -aDiagonalDistance
.getY());
157 rContainer
.push_back(
158 new TransformPrimitive2D(aTransform
, Primitive2DContainer(getTextContent())));
160 // at last, place original over it, but force to white
161 const basegfx::BColorModifierSharedPtr aBColorModifierToWhite
162 = std::make_shared
<basegfx::BColorModifier_replace
>(basegfx::BColor(1.0, 1.0, 1.0));
163 rContainer
.push_back(new ModifiedColorPrimitive2D(
164 Primitive2DContainer(getTextContent()), aBColorModifierToWhite
));
171 TextEffectPrimitive2D::TextEffectPrimitive2D(Primitive2DContainer
&& rTextContent
,
172 const basegfx::B2DPoint
& rRotationCenter
,
174 TextEffectStyle2D eTextEffectStyle2D
)
175 : maTextContent(std::move(rTextContent
))
176 , maRotationCenter(rRotationCenter
)
177 , mfDirection(fDirection
)
178 , meTextEffectStyle2D(eTextEffectStyle2D
)
182 bool TextEffectPrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
184 if (BasePrimitive2D::operator==(rPrimitive
))
186 const TextEffectPrimitive2D
& rCompare
187 = static_cast<const TextEffectPrimitive2D
&>(rPrimitive
);
189 return (getTextContent() == rCompare
.getTextContent()
190 && getRotationCenter() == rCompare
.getRotationCenter()
191 && getDirection() == rCompare
.getDirection()
192 && getTextEffectStyle2D() == rCompare
.getTextEffectStyle2D());
199 TextEffectPrimitive2D::getB2DRange(const geometry::ViewInformation2D
& rViewInformation
) const
201 // get range of content and grow by used fDiscreteSize. That way it is not necessary to ask
202 // the whole decomposition for its ranges (which may be expensive with outline mode which
203 // then will ask 9 times at nearly the same content. This may even be refined here using the
204 // TextEffectStyle information, e.g. for TEXTEFFECTSTYLE2D_RELIEF the grow needs only to
205 // be in two directions
206 basegfx::B2DRange
aRetval(getTextContent().getB2DRange(rViewInformation
));
207 aRetval
.grow(fDiscreteSize
);
212 void TextEffectPrimitive2D::get2DDecomposition(
213 Primitive2DDecompositionVisitor
& rVisitor
,
214 const geometry::ViewInformation2D
& rViewInformation
) const
216 if (!getBuffered2DDecomposition().empty())
218 if (maLastObjectToViewTransformation
!= rViewInformation
.getObjectToViewTransformation())
220 // conditions of last local decomposition have changed, delete
221 const_cast<TextEffectPrimitive2D
*>(this)->setBuffered2DDecomposition(
222 Primitive2DContainer());
226 if (getBuffered2DDecomposition().empty())
228 // remember ViewRange and ViewTransformation
229 const_cast<TextEffectPrimitive2D
*>(this)->maLastObjectToViewTransformation
230 = rViewInformation
.getObjectToViewTransformation();
233 // use parent implementation
234 BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor
, rViewInformation
);
238 sal_uInt32
TextEffectPrimitive2D::getPrimitive2DID() const
240 return PRIMITIVE2D_ID_TEXTEFFECTPRIMITIVE2D
;
243 } // end of namespace
245 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */