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/textprimitive2d.hxx>
30 : : #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
31 : : #include <basegfx/polygon/b2dpolypolygon.hxx>
32 : : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
33 : : #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
34 : : #include <drawinglayer/primitive2d/texteffectprimitive2d.hxx>
35 : : #include <basegfx/matrix/b2dhommatrixtools.hxx>
36 : :
37 : : //////////////////////////////////////////////////////////////////////////////
38 : :
39 : : using namespace com::sun::star;
40 : :
41 : : //////////////////////////////////////////////////////////////////////////////
42 : :
43 : : namespace
44 : : {
45 : : // adapts fontScale for usage with TextLayouter. Input is rScale which is the extracted
46 : : // scale from a text transformation. A copy is modified so that it contains only positive
47 : : // scalings and XY-equal scalings to allow to get a non-X-scaled Vcl-Font for TextLayouter.
48 : : // rScale is adapted accordingly to contain the corrected scale which would need to be
49 : : // applied to e.g. outlines received from TextLayouter under usage of fontScale. This
50 : : // includes Y-Scale, X-Scale-correction and mirrorings.
51 : 20711 : basegfx::B2DVector getCorrectedScaleAndFontScale(basegfx::B2DVector& rScale)
52 : : {
53 : : // copy input value
54 : 20711 : basegfx::B2DVector aFontScale(rScale);
55 : :
56 : : // correct FontHeight settings
57 [ - + ]: 20711 : if(basegfx::fTools::equalZero(aFontScale.getY()))
58 : : {
59 : : // no font height; choose one and adapt scale to get back to original scaling
60 : : static double fDefaultFontScale(100.0);
61 : 0 : rScale.setY(1.0 / fDefaultFontScale);
62 : 0 : aFontScale.setY(fDefaultFontScale);
63 : : }
64 [ - + ]: 20711 : else if(basegfx::fTools::less(aFontScale.getY(), 0.0))
65 : : {
66 : : // negative font height; invert and adapt scale to get back to original scaling
67 : 0 : aFontScale.setY(-aFontScale.getY());
68 : 0 : rScale.setY(-1.0);
69 : : }
70 : : else
71 : : {
72 : : // positive font height; adapt scale; scaling will be part of the polygons
73 : 20711 : rScale.setY(1.0);
74 : : }
75 : :
76 : : // correct FontWidth settings
77 [ + + ]: 20711 : if(basegfx::fTools::equal(aFontScale.getX(), aFontScale.getY()))
78 : : {
79 : : // no FontScale, adapt scale
80 : 19266 : rScale.setX(1.0);
81 : : }
82 : : else
83 : : {
84 : : // If FontScale is used, force to no FontScale to get a non-scaled VCL font.
85 : : // Adapt scaling in X accordingly.
86 : 1445 : rScale.setX(aFontScale.getX() / aFontScale.getY());
87 : 1445 : aFontScale.setX(aFontScale.getY());
88 : : }
89 : :
90 : 20711 : return aFontScale;
91 : : }
92 : : } // end of anonymous namespace
93 : :
94 : : //////////////////////////////////////////////////////////////////////////////
95 : :
96 : : namespace drawinglayer
97 : : {
98 : : namespace primitive2d
99 : : {
100 : 843 : void TextSimplePortionPrimitive2D::getTextOutlinesAndTransformation(basegfx::B2DPolyPolygonVector& rTarget, basegfx::B2DHomMatrix& rTransformation) const
101 : : {
102 [ + - ]: 843 : if(getTextLength())
103 : : {
104 : : // decompose object transformation to single values
105 : 843 : basegfx::B2DVector aScale, aTranslate;
106 : : double fRotate, fShearX;
107 : :
108 : : // if decomposition returns false, create no geometry since e.g. scaling may
109 : : // be zero
110 [ + - ][ + - ]: 843 : if(getTextTransform().decompose(aScale, aTranslate, fRotate, fShearX))
111 : : {
112 : : // handle special case: If scale is negative in (x,y) (3rd quadrant), it can
113 : : // be expressed as rotation by PI
114 [ - + ][ # # ]: 843 : if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
[ - + ][ - + ]
[ + - ][ + - ]
[ - + ]
115 : : {
116 [ # # ]: 0 : aScale = basegfx::absolute(aScale);
117 : 0 : fRotate += F_PI;
118 : : }
119 : :
120 : : // for the TextLayouterDevice, it is necessary to have a scaling representing
121 : : // the font size. Since we want to extract polygons here, it is okay to
122 : : // work just with scaling and to ignore shear, rotation and translation,
123 : : // all that can be applied to the polygons later
124 : 843 : const basegfx::B2DVector aFontScale(getCorrectedScaleAndFontScale(aScale));
125 : :
126 : : // prepare textlayoutdevice
127 [ + - ]: 843 : TextLayouterDevice aTextLayouter;
128 : : aTextLayouter.setFontAttribute(
129 : 843 : getFontAttribute(),
130 : : aFontScale.getX(),
131 : : aFontScale.getY(),
132 [ + - ]: 1686 : getLocale());
133 : :
134 : : // When getting outlines from stretched text (aScale.getX() != 1.0) it
135 : : // is necessary to inverse-scale the DXArray (if used) to not get the
136 : : // outlines already aligned to given, but wrong DXArray
137 [ + - ][ - + ]: 843 : if(getDXArray().size() && !basegfx::fTools::equal(aScale.getX(), 1.0))
[ + - ][ + - ]
[ - + ]
138 : : {
139 [ # # ]: 0 : ::std::vector< double > aScaledDXArray = getDXArray();
140 : 0 : const double fDXArrayScale(1.0 / aScale.getX());
141 : :
142 [ # # ]: 0 : for(sal_uInt32 a(0); a < aScaledDXArray.size(); a++)
143 : : {
144 [ # # ]: 0 : aScaledDXArray[a] *= fDXArrayScale;
145 : : }
146 : :
147 : : // get the text outlines
148 : : aTextLayouter.getTextOutlines(
149 : : rTarget,
150 : 0 : getText(),
151 : 0 : getTextPosition(),
152 : 0 : getTextLength(),
153 [ # # ]: 0 : aScaledDXArray);
154 : : }
155 : : else
156 : : {
157 : : // get the text outlines
158 : : aTextLayouter.getTextOutlines(
159 : : rTarget,
160 : 843 : getText(),
161 : 843 : getTextPosition(),
162 : 843 : getTextLength(),
163 [ + - ]: 1686 : getDXArray());
164 : : }
165 : :
166 : : // create primitives for the outlines
167 : 843 : const sal_uInt32 nCount(rTarget.size());
168 : :
169 [ + - ]: 843 : if(nCount)
170 : : {
171 : : // prepare object transformation for polygons
172 : : rTransformation = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
173 [ + - ][ + - ]: 843 : aScale, fShearX, fRotate, aTranslate);
[ + - ]
174 [ + - ]: 843 : }
175 : 843 : }
176 : : }
177 : 843 : }
178 : :
179 : 843 : Primitive2DSequence TextSimplePortionPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
180 : : {
181 : 843 : Primitive2DSequence aRetval;
182 : :
183 [ + - ]: 843 : if(getTextLength())
184 : : {
185 [ + - ]: 843 : basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
186 [ + - ]: 843 : basegfx::B2DHomMatrix aPolygonTransform;
187 : :
188 : : // get text outlines and their object transformation
189 [ + - ]: 843 : getTextOutlinesAndTransformation(aB2DPolyPolyVector, aPolygonTransform);
190 : :
191 : : // create primitives for the outlines
192 : 843 : const sal_uInt32 nCount(aB2DPolyPolyVector.size());
193 : :
194 [ + - ]: 843 : if(nCount)
195 : : {
196 : : // alloc space for the primitives
197 [ + - ]: 843 : aRetval.realloc(nCount);
198 : :
199 : : // color-filled polypolygons
200 [ + + ]: 2849 : for(sal_uInt32 a(0L); a < nCount; a++)
201 : : {
202 : : // prepare polypolygon
203 [ + - ]: 2006 : basegfx::B2DPolyPolygon& rPolyPolygon = aB2DPolyPolyVector[a];
204 [ + - ]: 2006 : rPolyPolygon.transform(aPolygonTransform);
205 [ + - ][ + - ]: 2006 : aRetval[a] = new PolyPolygonColorPrimitive2D(rPolyPolygon, getFontColor());
[ + - ][ + - ]
206 : : }
207 : :
208 [ + - ][ + + ]: 843 : if(getFontAttribute().getOutline())
209 : : {
210 : : // decompose polygon transformation to single values
211 : 72 : basegfx::B2DVector aScale, aTranslate;
212 : : double fRotate, fShearX;
213 [ + - ]: 72 : aPolygonTransform.decompose(aScale, aTranslate, fRotate, fShearX);
214 : :
215 : : // create outline text effect with current content and replace
216 : : Primitive2DReference aNewTextEffect(new TextEffectPrimitive2D(
217 : : aRetval,
218 : : aTranslate,
219 : : fRotate,
220 [ + - ][ + - ]: 72 : TEXTEFFECTSTYLE2D_OUTLINE));
[ + - ]
221 : :
222 [ + - ][ + - ]: 72 : aRetval = Primitive2DSequence(&aNewTextEffect, 1);
[ + - ]
223 : : }
224 [ + - ]: 843 : }
225 : : }
226 : :
227 : 843 : return aRetval;
228 : : }
229 : :
230 : 23653 : TextSimplePortionPrimitive2D::TextSimplePortionPrimitive2D(
231 : : const basegfx::B2DHomMatrix& rNewTransform,
232 : : const String& rText,
233 : : xub_StrLen aTextPosition,
234 : : xub_StrLen aTextLength,
235 : : const ::std::vector< double >& rDXArray,
236 : : const attribute::FontAttribute& rFontAttribute,
237 : : const ::com::sun::star::lang::Locale& rLocale,
238 : : const basegfx::BColor& rFontColor,
239 : : bool bFilled,
240 : : long nWidthToFill)
241 : : : BufferedDecompositionPrimitive2D(),
242 : : maTextTransform(rNewTransform),
243 : : maText(rText),
244 : : maTextPosition(aTextPosition),
245 : : maTextLength(aTextLength),
246 : : maDXArray(rDXArray),
247 : : maFontAttribute(rFontAttribute),
248 : : maLocale(rLocale),
249 : : maFontColor(rFontColor),
250 : : maB2DRange(),
251 : : mbFilled(bFilled),
252 [ + - ][ + - ]: 23653 : mnWidthToFill(nWidthToFill)
[ + - ][ + - ]
[ + - ]
253 : : {
254 : : #if OSL_DEBUG_LEVEL > 0
255 : : const xub_StrLen aStringLength(getText().Len());
256 : : OSL_ENSURE(aStringLength >= getTextPosition() && aStringLength >= getTextPosition() + getTextLength(),
257 : : "TextSimplePortionPrimitive2D with text out of range (!)");
258 : : #endif
259 : 23653 : }
260 : :
261 : 0 : bool LocalesAreEqual(const ::com::sun::star::lang::Locale& rA, const ::com::sun::star::lang::Locale& rB)
262 : : {
263 : 0 : return (rA.Language == rB.Language
264 : 0 : && rA.Country == rB.Country
265 [ # # ]: 0 : && rA.Variant == rB.Variant);
[ # # # # ]
266 : : }
267 : :
268 : 0 : bool TextSimplePortionPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
269 : : {
270 [ # # ]: 0 : if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
271 : : {
272 : 0 : const TextSimplePortionPrimitive2D& rCompare = (TextSimplePortionPrimitive2D&)rPrimitive;
273 : :
274 : 0 : return (getTextTransform() == rCompare.getTextTransform()
275 : 0 : && getText() == rCompare.getText()
276 : 0 : && getTextPosition() == rCompare.getTextPosition()
277 : 0 : && getTextLength() == rCompare.getTextLength()
278 : 0 : && getDXArray() == rCompare.getDXArray()
279 : 0 : && getFontAttribute() == rCompare.getFontAttribute()
280 : 0 : && LocalesAreEqual(getLocale(), rCompare.getLocale())
281 : 0 : && getFontColor() == rCompare.getFontColor()
282 : : && mbFilled == rCompare.mbFilled
283 [ # # ][ # # ]: 0 : && mnWidthToFill == rCompare.mnWidthToFill);
[ # # # #
# # # # #
# # # # #
# # ]
284 : : }
285 : :
286 : 0 : return false;
287 : : }
288 : :
289 : 143685 : basegfx::B2DRange TextSimplePortionPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
290 : : {
291 [ + + ][ + - ]: 143685 : if(maB2DRange.isEmpty() && getTextLength())
[ + + ]
292 : : {
293 : : // get TextBoundRect as base size
294 : : // decompose object transformation to single values
295 : 19868 : basegfx::B2DVector aScale, aTranslate;
296 : : double fRotate, fShearX;
297 : :
298 [ + - ][ + - ]: 19868 : if(getTextTransform().decompose(aScale, aTranslate, fRotate, fShearX))
299 : : {
300 : : // for the TextLayouterDevice, it is necessary to have a scaling representing
301 : : // the font size. Since we want to extract polygons here, it is okay to
302 : : // work just with scaling and to ignore shear, rotation and translation,
303 : : // all that can be applied to the polygons later
304 : 19868 : const basegfx::B2DVector aFontScale(getCorrectedScaleAndFontScale(aScale));
305 : :
306 : : // prepare textlayoutdevice
307 [ + - ]: 19868 : TextLayouterDevice aTextLayouter;
308 : : aTextLayouter.setFontAttribute(
309 : 19868 : getFontAttribute(),
310 : : aFontScale.getX(),
311 : : aFontScale.getY(),
312 [ + - ]: 39736 : getLocale());
313 : :
314 : : // get basic text range
315 [ + - ]: 19868 : basegfx::B2DRange aNewRange(aTextLayouter.getTextBoundRect(getText(), getTextPosition(), getTextLength()));
316 : :
317 : : // #i104432#, #i102556# take empty results into account
318 [ + - ][ + + ]: 19868 : if(!aNewRange.isEmpty())
319 : : {
320 : : // prepare object transformation for range
321 : : const basegfx::B2DHomMatrix aRangeTransformation(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
322 [ + - ]: 18330 : aScale, fShearX, fRotate, aTranslate));
323 : :
324 : : // apply range transformation to it
325 [ + - ]: 18330 : aNewRange.transform(aRangeTransformation);
326 : :
327 : : // assign to buffered value
328 [ + - ]: 18330 : const_cast< TextSimplePortionPrimitive2D* >(this)->maB2DRange = aNewRange;
329 [ + - ]: 19868 : }
330 : 19868 : }
331 : : }
332 : :
333 : 143685 : return maB2DRange;
334 : : }
335 : :
336 : : // provide unique ID
337 : 17661 : ImplPrimitrive2DIDBlock(TextSimplePortionPrimitive2D, PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D)
338 : :
339 : : } // end of namespace primitive2d
340 : : } // end of namespace drawinglayer
341 : :
342 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|