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

Generated by: LCOV version 1.11