LCOV - code coverage report
Current view: top level - drawinglayer/source/primitive2d - textlayoutdevice.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 130 153 85.0 %
Date: 2014-11-03 Functions: 27 32 84.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10