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/textlayoutdevice.hxx>
30 : : #include <comphelper/processfactory.hxx>
31 : : #include <comphelper/scoped_disposing_ptr.hxx>
32 : : #include <vcl/timer.hxx>
33 : : #include <vcl/virdev.hxx>
34 : : #include <vcl/font.hxx>
35 : : #include <vcl/metric.hxx>
36 : : #include <i18npool/mslangid.hxx>
37 : : #include <drawinglayer/primitive2d/textprimitive2d.hxx>
38 : : #include <vcl/svapp.hxx>
39 : :
40 : : //////////////////////////////////////////////////////////////////////////////
41 : : // VDev RevDevice provider
42 : :
43 : : namespace
44 : : {
45 : : class ImpTimedRefDev;
46 : :
47 : : //the scoped_timed_RefDev owns a ImpTimeRefDev and releases it on dtor
48 : : //or disposing of the default XComponentContext which causes the underlying
49 : : //OutputDevice to get released
50 : : //
51 : : //The ImpTimerRefDev itself, if the timeout ever gets hit, will call
52 : : //reset on the scoped_timed_RefDev to release the ImpTimerRefDev early
53 : : //if its unused for a few minutes
54 [ - + ]: 30 : class scoped_timed_RefDev : public comphelper::scoped_disposing_ptr<ImpTimedRefDev>
55 : : {
56 : : public:
57 [ + - ][ + - ]: 30 : scoped_timed_RefDev() : comphelper::scoped_disposing_ptr<ImpTimedRefDev>((::com::sun::star::uno::Reference<com::sun::star::lang::XComponent>(::comphelper::getProcessComponentContext(), ::com::sun::star::uno::UNO_QUERY_THROW)))
58 : : {
59 : 30 : }
60 : : };
61 : :
62 : : class the_scoped_timed_RefDev : public rtl::Static<scoped_timed_RefDev, the_scoped_timed_RefDev> {};
63 : :
64 : : class ImpTimedRefDev : public Timer
65 : : {
66 : : scoped_timed_RefDev& mrOwnerOfMe;
67 : : VirtualDevice* mpVirDev;
68 : : sal_uInt32 mnUseCount;
69 : :
70 : : public:
71 : : explicit ImpTimedRefDev(scoped_timed_RefDev& rOwnerofMe);
72 : : ~ImpTimedRefDev();
73 : : virtual void Timeout();
74 : :
75 : : VirtualDevice& acquireVirtualDevice();
76 : : void releaseVirtualDevice();
77 : : };
78 : :
79 : 32 : ImpTimedRefDev::ImpTimedRefDev(scoped_timed_RefDev& rOwnerOfMe)
80 : : : mrOwnerOfMe(rOwnerOfMe),
81 : : mpVirDev(0L),
82 : 32 : mnUseCount(0L)
83 : : {
84 [ + - ]: 32 : SetTimeout(3L * 60L * 1000L); // three minutes
85 [ + - ]: 32 : Start();
86 : 32 : }
87 : :
88 : 32 : ImpTimedRefDev::~ImpTimedRefDev()
89 : : {
90 : : OSL_ENSURE(0L == mnUseCount, "destruction of a still used ImpTimedRefDev (!)");
91 [ + - ][ + - ]: 32 : delete mpVirDev;
92 [ - + ]: 64 : }
93 : :
94 : 8 : void ImpTimedRefDev::Timeout()
95 : : {
96 : : // for obvious reasons, do not call anything after this
97 : 8 : mrOwnerOfMe.reset();
98 : 8 : }
99 : :
100 : 24013 : VirtualDevice& ImpTimedRefDev::acquireVirtualDevice()
101 : : {
102 [ + + ]: 24013 : if(!mpVirDev)
103 : : {
104 [ + - ]: 32 : mpVirDev = new VirtualDevice();
105 : 32 : mpVirDev->SetReferenceDevice( VirtualDevice::REFDEV_MODE_MSO1 );
106 : : }
107 : :
108 [ + + ]: 24013 : if(!mnUseCount)
109 : : {
110 : 22791 : Stop();
111 : : }
112 : :
113 : 24013 : mnUseCount++;
114 : :
115 : 24013 : return *mpVirDev;
116 : : }
117 : :
118 : 24013 : void ImpTimedRefDev::releaseVirtualDevice()
119 : : {
120 : : OSL_ENSURE(mnUseCount, "mismatch call number to releaseVirtualDevice() (!)");
121 : 24013 : mnUseCount--;
122 : :
123 [ + + ]: 24013 : if(!mnUseCount)
124 : : {
125 : 22791 : Start();
126 : : }
127 : 24013 : }
128 : : } // end of anonymous namespace
129 : :
130 : : //////////////////////////////////////////////////////////////////////////////
131 : : // access to one global ImpTimedRefDev incarnation in namespace drawinglayer::primitive
132 : :
133 : : namespace drawinglayer
134 : : {
135 : : namespace primitive2d
136 : : {
137 : : // static methods here
138 : 24013 : VirtualDevice& acquireGlobalVirtualDevice()
139 : : {
140 : 24013 : scoped_timed_RefDev& rStdRefDevice = the_scoped_timed_RefDev::get();
141 : :
142 [ + + ]: 24013 : if(!rStdRefDevice)
143 [ + - ]: 32 : rStdRefDevice.reset(new ImpTimedRefDev(rStdRefDevice));
144 : :
145 : 24013 : return rStdRefDevice->acquireVirtualDevice();
146 : : }
147 : :
148 : 24013 : void releaseGlobalVirtualDevice()
149 : : {
150 : 24013 : scoped_timed_RefDev& rStdRefDevice = the_scoped_timed_RefDev::get();
151 : :
152 : : OSL_ENSURE(rStdRefDevice, "releaseGlobalVirtualDevice() without prior acquireGlobalVirtualDevice() call(!)");
153 : 24013 : rStdRefDevice->releaseVirtualDevice();
154 : 24013 : }
155 : :
156 : 24013 : TextLayouterDevice::TextLayouterDevice()
157 : 24013 : : mrDevice(acquireGlobalVirtualDevice())
158 : : {
159 : 24013 : }
160 : :
161 : 24013 : TextLayouterDevice::~TextLayouterDevice()
162 : : {
163 : 24013 : releaseGlobalVirtualDevice();
164 : 24013 : }
165 : :
166 : 23427 : void TextLayouterDevice::setFont(const Font& rFont)
167 : : {
168 : 23427 : mrDevice.SetFont( rFont );
169 : 23427 : }
170 : :
171 : 23427 : void TextLayouterDevice::setFontAttribute(
172 : : const attribute::FontAttribute& rFontAttribute,
173 : : double fFontScaleX,
174 : : double fFontScaleY,
175 : : const ::com::sun::star::lang::Locale& rLocale)
176 : : {
177 : : setFont(getVclFontFromFontAttribute(
178 : : rFontAttribute,
179 : : fFontScaleX,
180 : : fFontScaleY,
181 : : 0.0,
182 [ + - ]: 23427 : rLocale));
183 : 23427 : }
184 : :
185 : 1790 : double TextLayouterDevice::getOverlineOffset() const
186 : : {
187 : 1790 : const ::FontMetric& rMetric = mrDevice.GetFontMetric();
188 [ + - ][ + - ]: 1790 : double fRet = (rMetric.GetIntLeading() / 2.0) - rMetric.GetAscent();
189 : 1790 : return fRet;
190 : : }
191 : :
192 : 2428 : double TextLayouterDevice::getUnderlineOffset() const
193 : : {
194 : 2428 : const ::FontMetric& rMetric = mrDevice.GetFontMetric();
195 [ + - ]: 2428 : double fRet = rMetric.GetDescent() / 2.0;
196 : 2428 : return fRet;
197 : : }
198 : :
199 : 1175 : double TextLayouterDevice::getStrikeoutOffset() const
200 : : {
201 : 1175 : const ::FontMetric& rMetric = mrDevice.GetFontMetric();
202 [ + - ][ + - ]: 1175 : double fRet = (rMetric.GetAscent() - rMetric.GetIntLeading()) / 3.0;
203 : 1175 : return fRet;
204 : : }
205 : :
206 : 1790 : double TextLayouterDevice::getOverlineHeight() const
207 : : {
208 : 1790 : const ::FontMetric& rMetric = mrDevice.GetFontMetric();
209 [ + - ]: 1790 : double fRet = rMetric.GetIntLeading() / 2.5;
210 : 1790 : return fRet;
211 : : }
212 : :
213 : 3603 : double TextLayouterDevice::getUnderlineHeight() const
214 : : {
215 : 3603 : const ::FontMetric& rMetric = mrDevice.GetFontMetric();
216 [ + - ]: 3603 : double fRet = rMetric.GetDescent() / 4.0;
217 : 3603 : return fRet;
218 : : }
219 : :
220 : 0 : double TextLayouterDevice::getTextHeight() const
221 : : {
222 : 0 : return mrDevice.GetTextHeight();
223 : : }
224 : :
225 : 72 : double TextLayouterDevice::getTextWidth(
226 : : const String& rText,
227 : : sal_uInt32 nIndex,
228 : : sal_uInt32 nLength) const
229 : : {
230 : 72 : return mrDevice.GetTextWidth(rText, nIndex, nLength);
231 : : }
232 : :
233 : 843 : bool TextLayouterDevice::getTextOutlines(
234 : : basegfx::B2DPolyPolygonVector& rB2DPolyPolyVector,
235 : : const String& rText,
236 : : sal_uInt32 nIndex,
237 : : sal_uInt32 nLength,
238 : : const ::std::vector< double >& rDXArray) const
239 : : {
240 : 843 : const sal_uInt32 nDXArrayCount(rDXArray.size());
241 : 843 : sal_uInt32 nTextLength(nLength);
242 : 843 : const sal_uInt32 nStringLength(rText.Len());
243 : :
244 [ - + ]: 843 : if(nTextLength + nIndex > nStringLength)
245 : : {
246 : 0 : nTextLength = nStringLength - nIndex;
247 : : }
248 : :
249 [ + - ]: 843 : if(nDXArrayCount)
250 : : {
251 : : OSL_ENSURE(nDXArrayCount == nTextLength, "DXArray size does not correspond to text portion size (!)");
252 [ + - ]: 843 : std::vector< sal_Int32 > aIntegerDXArray(nDXArrayCount);
253 : :
254 [ + + ]: 2887 : for(sal_uInt32 a(0); a < nDXArrayCount; a++)
255 : : {
256 [ + - ][ + - ]: 2044 : aIntegerDXArray[a] = basegfx::fround(rDXArray[a]);
257 : : }
258 : :
259 : : return mrDevice.GetTextOutlines(
260 : : rB2DPolyPolyVector,
261 : : rText,
262 : : nIndex,
263 : : nIndex,
264 : : nLength,
265 : : true,
266 : : 0,
267 [ + - ][ + - ]: 843 : &(aIntegerDXArray[0]));
268 : : }
269 : : else
270 : : {
271 : : return mrDevice.GetTextOutlines(
272 : : rB2DPolyPolyVector,
273 : : rText,
274 : : nIndex,
275 : : nIndex,
276 : : nLength,
277 : : true,
278 : : 0,
279 : 843 : 0);
280 : : }
281 : : }
282 : :
283 : 19868 : basegfx::B2DRange TextLayouterDevice::getTextBoundRect(
284 : : const String& rText,
285 : : sal_uInt32 nIndex,
286 : : sal_uInt32 nLength) const
287 : : {
288 : 19868 : sal_uInt32 nTextLength(nLength);
289 : 19868 : const sal_uInt32 nStringLength(rText.Len());
290 : :
291 [ - + ]: 19868 : if(nTextLength + nIndex > nStringLength)
292 : : {
293 : 0 : nTextLength = nStringLength - nIndex;
294 : : }
295 : :
296 [ + - ]: 19868 : if(nTextLength)
297 : : {
298 [ + - ]: 19868 : Rectangle aRect;
299 : :
300 : : mrDevice.GetTextBoundRect(
301 : : aRect,
302 : : rText,
303 : : nIndex,
304 : : nIndex,
305 [ + - ]: 19868 : nLength);
306 : :
307 : : // #i104432#, #i102556# take empty results into account
308 [ + - ][ + + ]: 19868 : if(!aRect.IsEmpty())
309 : : {
310 : : return basegfx::B2DRange(
311 : 18330 : aRect.Left(), aRect.Top(),
312 [ + - ]: 38198 : aRect.Right(), aRect.Bottom());
313 : : }
314 : : }
315 : :
316 : 19868 : return basegfx::B2DRange();
317 : : }
318 : :
319 : 0 : double TextLayouterDevice::getFontAscent() const
320 : : {
321 : 0 : const ::FontMetric& rMetric = mrDevice.GetFontMetric();
322 [ # # ]: 0 : return rMetric.GetAscent();
323 : : }
324 : :
325 : 0 : double TextLayouterDevice::getFontDescent() const
326 : : {
327 : 0 : const ::FontMetric& rMetric = mrDevice.GetFontMetric();
328 [ # # ]: 0 : return rMetric.GetDescent();
329 : : }
330 : :
331 : 0 : void TextLayouterDevice::addTextRectActions(
332 : : const Rectangle& rRectangle,
333 : : const String& rText,
334 : : sal_uInt16 nStyle,
335 : : GDIMetaFile& rGDIMetaFile) const
336 : : {
337 : : mrDevice.AddTextRectActions(
338 : 0 : rRectangle, rText, nStyle, rGDIMetaFile);
339 : 0 : }
340 : :
341 : 0 : ::std::vector< double > TextLayouterDevice::getTextArray(
342 : : const String& rText,
343 : : sal_uInt32 nIndex,
344 : : sal_uInt32 nLength) const
345 : : {
346 : 0 : ::std::vector< double > aRetval;
347 : 0 : sal_uInt32 nTextLength(nLength);
348 : 0 : const sal_uInt32 nStringLength(rText.Len());
349 : :
350 [ # # ]: 0 : if(nTextLength + nIndex > nStringLength)
351 : : {
352 : 0 : nTextLength = nStringLength - nIndex;
353 : : }
354 : :
355 [ # # ]: 0 : if(nTextLength)
356 : : {
357 [ # # ]: 0 : aRetval.reserve(nTextLength);
358 [ # # ]: 0 : ::std::vector<sal_Int32> aArray(nTextLength);
359 [ # # ][ # # ]: 0 : mrDevice.GetTextArray(rText, &aArray[0], nIndex, nLength);
360 [ # # ]: 0 : aRetval.assign(aArray.begin(), aArray.end());
361 : : }
362 : :
363 : 0 : return aRetval;
364 : : }
365 : :
366 : : } // end of namespace primitive2d
367 : : } // end of namespace drawinglayer
368 : :
369 : : //////////////////////////////////////////////////////////////////////////////
370 : : // helper methods for vcl font handling
371 : :
372 : : namespace drawinglayer
373 : : {
374 : : namespace primitive2d
375 : : {
376 : 40986 : Font getVclFontFromFontAttribute(
377 : : const attribute::FontAttribute& rFontAttribute,
378 : : double fFontScaleX,
379 : : double fFontScaleY,
380 : : double fFontRotation,
381 : : const ::com::sun::star::lang::Locale& rLocale)
382 : : {
383 : : // detect FontScaling
384 : 40986 : const sal_uInt32 nHeight(basegfx::fround(fabs(fFontScaleY)));
385 : 40986 : const sal_uInt32 nWidth(basegfx::fround(fabs(fFontScaleX)));
386 : 40986 : const bool bFontIsScaled(nHeight != nWidth);
387 : :
388 : : #ifdef WIN32
389 : : // for WIN32 systems, start with creating an unscaled font. If FontScaling
390 : : // is wanted, that width needs to be adapted using FontMetric again to get a
391 : : // width of the unscaled font
392 : : Font aRetval(
393 : : rFontAttribute.getFamilyName(),
394 : : rFontAttribute.getStyleName(),
395 : : Size(0, nHeight));
396 : : #else
397 : : // for non-WIN32 systems things are easier since these accept a Font creation
398 : : // with initially nWidth != nHeight for FontScaling. Despite that, use zero for
399 : : // FontWidth when no scaling is used to explicitly have that zero when e.g. the
400 : : // Font would be recorded in a MetaFile (The MetaFile FontAction WILL record a
401 : : // set FontWidth; import that in a WIN32 system, and trouble is there)
402 : : Font aRetval(
403 [ + - ]: 40986 : rFontAttribute.getFamilyName(),
404 [ + - ]: 40986 : rFontAttribute.getStyleName(),
405 [ + - ][ + + ]: 81972 : Size(bFontIsScaled ? nWidth : 0, nHeight));
406 : : #endif
407 : : // define various other FontAttribute
408 [ + - ]: 40986 : aRetval.SetAlign(ALIGN_BASELINE);
409 [ + - ][ - + ]: 40986 : aRetval.SetCharSet(rFontAttribute.getSymbol() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE);
[ + - ]
410 [ + - ][ - + ]: 40986 : aRetval.SetVertical(rFontAttribute.getVertical() ? sal_True : sal_False);
[ + - ]
411 [ + - ][ + - ]: 40986 : aRetval.SetWeight(static_cast<FontWeight>(rFontAttribute.getWeight()));
412 [ + - ][ + + ]: 40986 : aRetval.SetItalic(rFontAttribute.getItalic() ? ITALIC_NORMAL : ITALIC_NONE);
[ + - ]
413 [ + - ][ + - ]: 40986 : aRetval.SetOutline(rFontAttribute.getOutline());
414 [ + - ][ - + ]: 40986 : aRetval.SetPitch(rFontAttribute.getMonospaced() ? PITCH_FIXED : PITCH_VARIABLE);
[ + - ]
415 [ + - ][ + - ]: 40986 : aRetval.SetLanguage(MsLangId::convertLocaleToLanguage(rLocale));
416 : :
417 : : #ifdef WIN32
418 : : // for WIN32 systems, correct the FontWidth if FontScaling is used
419 : : if(bFontIsScaled && nHeight > 0)
420 : : {
421 : : const FontMetric aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aRetval));
422 : :
423 : : if(aUnscaledFontMetric.GetWidth() > 0)
424 : : {
425 : : const double fScaleFactor((double)nWidth / (double)nHeight);
426 : : const sal_uInt32 nScaledWidth(basegfx::fround((double)aUnscaledFontMetric.GetWidth() * fScaleFactor));
427 : : aRetval.SetWidth(nScaledWidth);
428 : : }
429 : : }
430 : : #endif
431 : : // handle FontRotation (if defined)
432 [ - + ]: 40986 : if(!basegfx::fTools::equalZero(fFontRotation))
433 : : {
434 : 0 : sal_Int16 aRotate10th((sal_Int16)(fFontRotation * (-1800.0/F_PI)));
435 [ # # ]: 0 : aRetval.SetOrientation(aRotate10th % 3600);
436 : : }
437 : :
438 : 40986 : return aRetval;
439 : : }
440 : :
441 : 20919 : attribute::FontAttribute getFontAttributeFromVclFont(
442 : : basegfx::B2DVector& o_rSize,
443 : : const Font& rFont,
444 : : bool bRTL,
445 : : bool bBiDiStrong)
446 : : {
447 : : const attribute::FontAttribute aRetval(
448 : 20919 : rFont.GetName(),
449 : 20919 : rFont.GetStyleName(),
450 : 20919 : static_cast<sal_uInt16>(rFont.GetWeight()),
451 : 20919 : RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet(),
452 : 20919 : rFont.IsVertical(),
453 : 20919 : ITALIC_NONE != rFont.GetItalic(),
454 : 20919 : PITCH_FIXED == rFont.GetPitch(),
455 : 20919 : rFont.IsOutline(),
456 : : bRTL,
457 : 20919 : bBiDiStrong);
458 : : // TODO: eKerning
459 : :
460 : : // set FontHeight and init to no FontScaling
461 [ + - ][ + - ]: 20919 : o_rSize.setY(rFont.GetSize().getHeight() > 0 ? rFont.GetSize().getHeight() : 0);
[ + - ]
462 : 20919 : o_rSize.setX(o_rSize.getY());
463 : :
464 : : #ifdef WIN32
465 : : // for WIN32 systems, the FontScaling at the Font is detected by
466 : : // checking that FontWidth != 0. When FontScaling is used, WIN32
467 : : // needs to do extra stuff to detect the correct width (since it's
468 : : // zero and not equal the font height) and it's relationship to
469 : : // the height
470 : : if(rFont.GetSize().getWidth() > 0)
471 : : {
472 : : Font aUnscaledFont(rFont);
473 : : aUnscaledFont.SetWidth(0);
474 : : const FontMetric aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aUnscaledFont));
475 : :
476 : : if(aUnscaledFontMetric.GetWidth() > 0)
477 : : {
478 : : const double fScaleFactor((double)rFont.GetSize().getWidth() / (double)aUnscaledFontMetric.GetWidth());
479 : : o_rSize.setX(fScaleFactor * o_rSize.getY());
480 : : }
481 : : }
482 : : #else
483 : : // For non-WIN32 systems the detection is the same, but the value
484 : : // is easier achieved since width == height is interpreted as no
485 : : // scaling. Ergo, Width == 0 means width == height, and width != 0
486 : : // means the scaling is in the direct relation of width to height
487 [ + + ][ + - ]: 20919 : if(rFont.GetSize().getWidth() > 0)
488 : : {
489 [ + - ]: 1461 : o_rSize.setX((double)rFont.GetSize().getWidth());
490 : : }
491 : : #endif
492 : 20919 : return aRetval;
493 : : }
494 : : } // end of namespace primitive2d
495 : : } // end of namespace drawinglayer
496 : :
497 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|