xref: /AOO41X/main/drawinglayer/source/primitive2d/textlayoutdevice.cxx (revision cc213d65944007657c386b79f0ff74c182b75087)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_drawinglayer.hxx"
26 
27 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
28 #include <vcl/timer.hxx>
29 #include <vcl/virdev.hxx>
30 #include <vcl/font.hxx>
31 #include <vcl/metric.hxx>
32 #include <i18npool/mslangid.hxx>
33 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
34 #include <vcl/svapp.hxx>
35 
36 //////////////////////////////////////////////////////////////////////////////
37 // VDev RevDevice provider
38 
39 namespace
40 {
41     class ImpTimedRefDev : public Timer
42     {
43         ImpTimedRefDev**                    mppStaticPointerOnMe;
44         VirtualDevice*                      mpVirDev;
45         sal_uInt32                          mnUseCount;
46 
47     public:
48         ImpTimedRefDev(ImpTimedRefDev** ppStaticPointerOnMe);
49         ~ImpTimedRefDev();
50         virtual void Timeout();
51 
52         VirtualDevice& acquireVirtualDevice();
53         void releaseVirtualDevice();
54     };
55 
ImpTimedRefDev(ImpTimedRefDev ** ppStaticPointerOnMe)56     ImpTimedRefDev::ImpTimedRefDev(ImpTimedRefDev** ppStaticPointerOnMe)
57     :   mppStaticPointerOnMe(ppStaticPointerOnMe),
58         mpVirDev(0L),
59         mnUseCount(0L)
60     {
61         SetTimeout(3L * 60L * 1000L); // three minutes
62         Start();
63     }
64 
~ImpTimedRefDev()65     ImpTimedRefDev::~ImpTimedRefDev()
66     {
67         OSL_ENSURE(0L == mnUseCount, "destruction of a still used ImpTimedRefDev (!)");
68 
69         if(mppStaticPointerOnMe && *mppStaticPointerOnMe)
70         {
71             *mppStaticPointerOnMe = 0L;
72         }
73 
74         if(mpVirDev)
75         {
76             delete mpVirDev;
77         }
78     }
79 
Timeout()80     void ImpTimedRefDev::Timeout()
81     {
82         // for obvious reasons, do not call anything after this
83         delete (this);
84     }
85 
acquireVirtualDevice()86     VirtualDevice& ImpTimedRefDev::acquireVirtualDevice()
87     {
88         if(!mpVirDev)
89         {
90             mpVirDev = new VirtualDevice();
91             mpVirDev->SetReferenceDevice( VirtualDevice::REFDEV_MODE_MSO1 );
92         }
93 
94         if(!mnUseCount)
95         {
96             Stop();
97         }
98 
99         mnUseCount++;
100 
101         return *mpVirDev;
102     }
103 
releaseVirtualDevice()104     void ImpTimedRefDev::releaseVirtualDevice()
105     {
106         OSL_ENSURE(mnUseCount, "mismatch call number to releaseVirtualDevice() (!)");
107         mnUseCount--;
108 
109         if(!mnUseCount)
110         {
111             Start();
112         }
113     }
114 } // end of anonymous namespace
115 
116 //////////////////////////////////////////////////////////////////////////////
117 // access to one global ImpTimedRefDev incarnation in namespace drawinglayer::primitive
118 
119 namespace drawinglayer
120 {
121     namespace primitive2d
122     {
123         // static pointer here
124         static ImpTimedRefDev* pImpGlobalRefDev = 0L;
125 
126         // static methods here
acquireGlobalVirtualDevice()127         VirtualDevice& acquireGlobalVirtualDevice()
128         {
129             if(!pImpGlobalRefDev)
130             {
131                 pImpGlobalRefDev = new ImpTimedRefDev(&pImpGlobalRefDev);
132             }
133 
134             return pImpGlobalRefDev->acquireVirtualDevice();
135         }
136 
releaseGlobalVirtualDevice()137         void releaseGlobalVirtualDevice()
138         {
139             OSL_ENSURE(pImpGlobalRefDev, "releaseGlobalVirtualDevice() without prior acquireGlobalVirtualDevice() call(!)");
140             pImpGlobalRefDev->releaseVirtualDevice();
141         }
142 
TextLayouterDevice()143         TextLayouterDevice::TextLayouterDevice()
144         :   mrDevice(acquireGlobalVirtualDevice())
145         {
146         }
147 
~TextLayouterDevice()148         TextLayouterDevice::~TextLayouterDevice()
149         {
150             releaseGlobalVirtualDevice();
151         }
152 
setFont(const Font & rFont)153         void TextLayouterDevice::setFont(const Font& rFont)
154         {
155             mrDevice.SetFont( rFont );
156         }
157 
setFontAttribute(const attribute::FontAttribute & rFontAttribute,double fFontScaleX,double fFontScaleY,const::com::sun::star::lang::Locale & rLocale)158         void TextLayouterDevice::setFontAttribute(
159             const attribute::FontAttribute& rFontAttribute,
160             double fFontScaleX,
161             double fFontScaleY,
162             const ::com::sun::star::lang::Locale& rLocale)
163         {
164             setFont(getVclFontFromFontAttribute(
165                 rFontAttribute,
166                 fFontScaleX,
167                 fFontScaleY,
168                 0.0,
169                 rLocale));
170         }
171 
getOverlineOffset() const172         double TextLayouterDevice::getOverlineOffset() const
173         {
174             const ::FontMetric& rMetric = mrDevice.GetFontMetric();
175             double fRet = (rMetric.GetIntLeading() / 2.0) - rMetric.GetAscent();
176             return fRet;
177         }
178 
getUnderlineOffset() const179         double TextLayouterDevice::getUnderlineOffset() const
180         {
181             const ::FontMetric& rMetric = mrDevice.GetFontMetric();
182             double fRet = rMetric.GetDescent() / 2.0;
183             return fRet;
184         }
185 
getStrikeoutOffset() const186         double TextLayouterDevice::getStrikeoutOffset() const
187         {
188             const ::FontMetric& rMetric = mrDevice.GetFontMetric();
189             double fRet = (rMetric.GetAscent() - rMetric.GetIntLeading()) / 3.0;
190             return fRet;
191         }
192 
getOverlineHeight() const193         double TextLayouterDevice::getOverlineHeight() const
194         {
195             const ::FontMetric& rMetric = mrDevice.GetFontMetric();
196             double fRet = rMetric.GetIntLeading() / 2.5;
197             return fRet;
198         }
199 
getUnderlineHeight() const200         double TextLayouterDevice::getUnderlineHeight() const
201         {
202             const ::FontMetric& rMetric = mrDevice.GetFontMetric();
203             double fRet = rMetric.GetDescent() / 4.0;
204             return fRet;
205         }
206 
getTextHeight() const207         double TextLayouterDevice::getTextHeight() const
208         {
209             return mrDevice.GetTextHeight();
210         }
211 
getTextWidth(const String & rText,sal_uInt32 nIndex,sal_uInt32 nLength) const212         double TextLayouterDevice::getTextWidth(
213             const String& rText,
214             sal_uInt32 nIndex,
215             sal_uInt32 nLength) const
216         {
217             return mrDevice.GetTextWidth(rText, nIndex, nLength);
218         }
219 
getTextOutlines(basegfx::B2DPolyPolygonVector & rB2DPolyPolyVector,const String & rText,sal_uInt32 nIndex,sal_uInt32 nLength,const::std::vector<double> & rDXArray) const220         bool TextLayouterDevice::getTextOutlines(
221             basegfx::B2DPolyPolygonVector& rB2DPolyPolyVector,
222             const String& rText,
223             sal_uInt32 nIndex,
224             sal_uInt32 nLength,
225             const ::std::vector< double >& rDXArray) const
226         {
227             const sal_uInt32 nDXArrayCount(rDXArray.size());
228             sal_uInt32 nTextLength(nLength);
229             const sal_uInt32 nStringLength(rText.Len());
230 
231             if(nTextLength + nIndex > nStringLength)
232             {
233                 nTextLength = nStringLength - nIndex;
234             }
235 
236             if(nDXArrayCount)
237             {
238                 OSL_ENSURE(nDXArrayCount == nTextLength, "DXArray size does not correspond to text portion size (!)");
239                 std::vector< sal_Int32 > aIntegerDXArray(nDXArrayCount);
240 
241                 for(sal_uInt32 a(0); a < nDXArrayCount; a++)
242                 {
243                     aIntegerDXArray[a] = basegfx::fround(rDXArray[a]);
244                 }
245 
246                 return mrDevice.GetTextOutlines(
247                     rB2DPolyPolyVector,
248                     rText,
249                     nIndex,
250                     nIndex,
251                     nLength,
252                     true,
253                     0,
254                     &(aIntegerDXArray[0]));
255             }
256             else
257             {
258                 return mrDevice.GetTextOutlines(
259                     rB2DPolyPolyVector,
260                     rText,
261                     nIndex,
262                     nIndex,
263                     nLength,
264                     true,
265                     0,
266                     0);
267             }
268         }
269 
getTextBoundRect(const String & rText,sal_uInt32 nIndex,sal_uInt32 nLength) const270         basegfx::B2DRange TextLayouterDevice::getTextBoundRect(
271             const String& rText,
272             sal_uInt32 nIndex,
273             sal_uInt32 nLength) const
274         {
275             sal_uInt32 nTextLength(nLength);
276             const sal_uInt32 nStringLength(rText.Len());
277 
278             if(nTextLength + nIndex > nStringLength)
279             {
280                 nTextLength = nStringLength - nIndex;
281             }
282 
283             if(nTextLength)
284             {
285                 Rectangle aRect;
286 
287                 mrDevice.GetTextBoundRect(
288                     aRect,
289                     rText,
290                     nIndex,
291                     nIndex,
292                     nLength);
293 
294                 // #i104432#, #i102556# take empty results into account
295                 if(!aRect.IsEmpty())
296                 {
297                     return basegfx::B2DRange(
298                         aRect.Left(), aRect.Top(),
299                         aRect.Right(), aRect.Bottom());
300                 }
301             }
302 
303             return basegfx::B2DRange();
304         }
305 
getFontAscent() const306         double TextLayouterDevice::getFontAscent() const
307         {
308             const ::FontMetric& rMetric = mrDevice.GetFontMetric();
309             return rMetric.GetAscent();
310         }
311 
getFontDescent() const312         double TextLayouterDevice::getFontDescent() const
313         {
314             const ::FontMetric& rMetric = mrDevice.GetFontMetric();
315             return rMetric.GetDescent();
316         }
317 
addTextRectActions(const Rectangle & rRectangle,const String & rText,sal_uInt16 nStyle,GDIMetaFile & rGDIMetaFile) const318         void TextLayouterDevice::addTextRectActions(
319             const Rectangle& rRectangle,
320             const String& rText,
321             sal_uInt16 nStyle,
322             GDIMetaFile& rGDIMetaFile) const
323         {
324             mrDevice.AddTextRectActions(
325                 rRectangle, rText, nStyle, rGDIMetaFile);
326         }
327 
getTextArray(const String & rText,sal_uInt32 nIndex,sal_uInt32 nLength) const328         ::std::vector< double > TextLayouterDevice::getTextArray(
329             const String& rText,
330             sal_uInt32 nIndex,
331             sal_uInt32 nLength) const
332         {
333             ::std::vector< double > aRetval;
334             sal_uInt32 nTextLength(nLength);
335             const sal_uInt32 nStringLength(rText.Len());
336 
337             if(nTextLength + nIndex > nStringLength)
338             {
339                 nTextLength = nStringLength - nIndex;
340             }
341 
342             if(nTextLength)
343             {
344                 aRetval.reserve(nTextLength);
345                 ::std::vector<sal_Int32> aDXArray( nTextLength);
346                 mrDevice.GetTextArray(rText, &aDXArray[0], nIndex, nLength);
347 
348                 for(sal_uInt32 a(0); a < nTextLength; a++)
349                 {
350                     aRetval.push_back(aDXArray[a]);
351                 }
352             }
353 
354             return aRetval;
355         }
356 
357     } // end of namespace primitive2d
358 } // end of namespace drawinglayer
359 
360 //////////////////////////////////////////////////////////////////////////////
361 // helper methods for vcl font handling
362 
363 namespace drawinglayer
364 {
365     namespace primitive2d
366     {
getVclFontFromFontAttribute(const attribute::FontAttribute & rFontAttribute,double fFontScaleX,double fFontScaleY,double fFontRotation,const::com::sun::star::lang::Locale & rLocale)367         Font getVclFontFromFontAttribute(
368             const attribute::FontAttribute& rFontAttribute,
369             double fFontScaleX,
370             double fFontScaleY,
371             double fFontRotation,
372             const ::com::sun::star::lang::Locale& rLocale)
373         {
374             // detect FontScaling
375             const sal_uInt32 nHeight(basegfx::fround(fabs(fFontScaleY)));
376             const sal_uInt32 nWidth(basegfx::fround(fabs(fFontScaleX)));
377             const bool bFontIsScaled(nHeight != nWidth);
378 
379 #ifdef WIN32
380             // for WIN32 systems, start with creating an unscaled font. If FontScaling
381             // is wanted, that width needs to be adapted using FontMetric again to get a
382             // width of the unscaled font
383             Font aRetval(
384                 rFontAttribute.getFamilyName(),
385                 rFontAttribute.getStyleName(),
386                 Size(0, nHeight));
387 #else
388             // for non-WIN32 systems things are easier since these accept a Font creation
389             // with initially nWidth != nHeight for FontScaling. Despite that, use zero for
390             // FontWidth when no scaling is used to explicitely have that zero when e.g. the
391             // Font would be recorded in a MetaFile (The MetaFile FontAction WILL record a
392             // set FontWidth; import that in a WIN32 system, and trouble is there)
393             Font aRetval(
394                 rFontAttribute.getFamilyName(),
395                 rFontAttribute.getStyleName(),
396                 Size(bFontIsScaled ? nWidth : 0, nHeight));
397 #endif
398             // define various other FontAttribute
399             aRetval.SetAlign(ALIGN_BASELINE);
400             aRetval.SetCharSet(rFontAttribute.getSymbol() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE);
401             aRetval.SetVertical(rFontAttribute.getVertical() ? sal_True : sal_False);
402             aRetval.SetWeight(static_cast<FontWeight>(rFontAttribute.getWeight()));
403             aRetval.SetItalic(rFontAttribute.getItalic() ? ITALIC_NORMAL : ITALIC_NONE);
404             aRetval.SetOutline(rFontAttribute.getOutline());
405             aRetval.SetPitch(rFontAttribute.getMonospaced() ? PITCH_FIXED : PITCH_VARIABLE);
406             aRetval.SetLanguage(MsLangId::convertLocaleToLanguage(rLocale));
407 
408 #ifdef WIN32
409             // for WIN32 systems, correct the FontWidth if FontScaling is used
410             if(bFontIsScaled && nHeight > 0)
411             {
412                 const FontMetric aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aRetval));
413 
414                 if(aUnscaledFontMetric.GetWidth() > 0)
415                 {
416                     const double fScaleFactor((double)nWidth / (double)nHeight);
417                     const sal_uInt32 nScaledWidth(basegfx::fround((double)aUnscaledFontMetric.GetWidth() * fScaleFactor));
418                     aRetval.SetWidth(nScaledWidth);
419                 }
420             }
421 #endif
422             // handle FontRotation (if defined)
423             if(!basegfx::fTools::equalZero(fFontRotation))
424             {
425                 sal_Int16 aRotate10th((sal_Int16)(fFontRotation * (-1800.0/F_PI)));
426                 aRetval.SetOrientation(aRotate10th % 3600);
427             }
428 
429             return aRetval;
430         }
431 
getFontAttributeFromVclFont(basegfx::B2DVector & o_rSize,const Font & rFont,bool bRTL,bool bBiDiStrong)432         attribute::FontAttribute getFontAttributeFromVclFont(
433             basegfx::B2DVector& o_rSize,
434             const Font& rFont,
435             bool bRTL,
436             bool bBiDiStrong)
437         {
438             const attribute::FontAttribute aRetval(
439                 rFont.GetName(),
440                 rFont.GetStyleName(),
441                 static_cast<sal_uInt16>(rFont.GetWeight()),
442                 RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet(),
443                 rFont.IsVertical(),
444                 ITALIC_NONE != rFont.GetItalic(),
445                 PITCH_FIXED == rFont.GetPitch(),
446                 rFont.IsOutline(),
447                 bRTL,
448                 bBiDiStrong);
449             // TODO: eKerning
450 
451             // set FontHeight and init to no FontScaling
452             o_rSize.setY(rFont.GetSize().getHeight() > 0 ? rFont.GetSize().getHeight() : 0);
453             o_rSize.setX(o_rSize.getY());
454 
455 #ifdef WIN32
456             // for WIN32 systems, the FontScaling at the Font is detected by
457             // checking that FontWidth != 0. When FontScaling is used, WIN32
458             // needs to do extra stuff to detect the correct width (since it's
459             // zero and not equal the font height) and it's relationship to
460             // the height
461             if(rFont.GetSize().getWidth() > 0)
462             {
463                 Font aUnscaledFont(rFont);
464                 aUnscaledFont.SetWidth(0);
465                 const FontMetric aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aUnscaledFont));
466 
467                 if(aUnscaledFontMetric.GetWidth() > 0)
468                 {
469                     const double fScaleFactor((double)rFont.GetSize().getWidth() / (double)aUnscaledFontMetric.GetWidth());
470                     o_rSize.setX(fScaleFactor * o_rSize.getY());
471                 }
472             }
473 #else
474             // For non-WIN32 systems the detection is the same, but the value
475             // is easier achieved since width == height is interpreted as no
476             // scaling. Ergo, Width == 0 means width == height, and width != 0
477             // means the scaling is in the direct relation of width to height
478             if(rFont.GetSize().getWidth() > 0)
479             {
480                 o_rSize.setX((double)rFont.GetSize().getWidth());
481             }
482 #endif
483             return aRetval;
484         }
485     } // end of namespace primitive2d
486 } // end of namespace drawinglayer
487 
488 //////////////////////////////////////////////////////////////////////////////
489 // eof
490