summaryrefslogtreecommitdiff
path: root/drawinglayer/source/primitive2d/textlayoutdevice.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'drawinglayer/source/primitive2d/textlayoutdevice.cxx')
-rw-r--r--drawinglayer/source/primitive2d/textlayoutdevice.cxx496
1 files changed, 496 insertions, 0 deletions
diff --git a/drawinglayer/source/primitive2d/textlayoutdevice.cxx b/drawinglayer/source/primitive2d/textlayoutdevice.cxx
new file mode 100644
index 000000000000..c3435333a3d3
--- /dev/null
+++ b/drawinglayer/source/primitive2d/textlayoutdevice.cxx
@@ -0,0 +1,496 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/font.hxx>
+#include <vcl/metric.hxx>
+#include <i18npool/mslangid.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <vcl/svapp.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// VDev RevDevice provider
+
+namespace
+{
+ class ImpTimedRefDev : public Timer
+ {
+ ImpTimedRefDev** mppStaticPointerOnMe;
+ VirtualDevice* mpVirDev;
+ sal_uInt32 mnUseCount;
+
+ public:
+ ImpTimedRefDev(ImpTimedRefDev** ppStaticPointerOnMe);
+ ~ImpTimedRefDev();
+ virtual void Timeout();
+
+ VirtualDevice& acquireVirtualDevice();
+ void releaseVirtualDevice();
+ };
+
+ ImpTimedRefDev::ImpTimedRefDev(ImpTimedRefDev** ppStaticPointerOnMe)
+ : mppStaticPointerOnMe(ppStaticPointerOnMe),
+ mpVirDev(0L),
+ mnUseCount(0L)
+ {
+ SetTimeout(3L * 60L * 1000L); // three minutes
+ Start();
+ }
+
+ ImpTimedRefDev::~ImpTimedRefDev()
+ {
+ OSL_ENSURE(0L == mnUseCount, "destruction of a still used ImpTimedRefDev (!)");
+
+ if(mppStaticPointerOnMe && *mppStaticPointerOnMe)
+ {
+ *mppStaticPointerOnMe = 0L;
+ }
+
+ if(mpVirDev)
+ {
+ delete mpVirDev;
+ }
+ }
+
+ void ImpTimedRefDev::Timeout()
+ {
+ // for obvious reasons, do not call anything after this
+ delete (this);
+ }
+
+ VirtualDevice& ImpTimedRefDev::acquireVirtualDevice()
+ {
+ if(!mpVirDev)
+ {
+ mpVirDev = new VirtualDevice();
+ mpVirDev->SetReferenceDevice( VirtualDevice::REFDEV_MODE_MSO1 );
+ }
+
+ if(!mnUseCount)
+ {
+ Stop();
+ }
+
+ mnUseCount++;
+
+ return *mpVirDev;
+ }
+
+ void ImpTimedRefDev::releaseVirtualDevice()
+ {
+ OSL_ENSURE(mnUseCount, "mismatch call number to releaseVirtualDevice() (!)");
+ mnUseCount--;
+
+ if(!mnUseCount)
+ {
+ Start();
+ }
+ }
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////////////
+// access to one global ImpTimedRefDev incarnation in namespace drawinglayer::primitive
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ // static pointer here
+ static ImpTimedRefDev* pImpGlobalRefDev = 0L;
+
+ // static methods here
+ VirtualDevice& acquireGlobalVirtualDevice()
+ {
+ if(!pImpGlobalRefDev)
+ {
+ pImpGlobalRefDev = new ImpTimedRefDev(&pImpGlobalRefDev);
+ }
+
+ return pImpGlobalRefDev->acquireVirtualDevice();
+ }
+
+ void releaseGlobalVirtualDevice()
+ {
+ OSL_ENSURE(pImpGlobalRefDev, "releaseGlobalVirtualDevice() without prior acquireGlobalVirtualDevice() call(!)");
+ pImpGlobalRefDev->releaseVirtualDevice();
+ }
+
+ TextLayouterDevice::TextLayouterDevice()
+ : mrDevice(acquireGlobalVirtualDevice())
+ {
+ }
+
+ TextLayouterDevice::~TextLayouterDevice()
+ {
+ releaseGlobalVirtualDevice();
+ }
+
+ void TextLayouterDevice::setFont(const Font& rFont)
+ {
+ mrDevice.SetFont( rFont );
+ }
+
+ void TextLayouterDevice::setFontAttribute(
+ const attribute::FontAttribute& rFontAttribute,
+ double fFontScaleX,
+ double fFontScaleY,
+ const ::com::sun::star::lang::Locale& rLocale)
+ {
+ setFont(getVclFontFromFontAttribute(
+ rFontAttribute,
+ fFontScaleX,
+ fFontScaleY,
+ 0.0,
+ rLocale));
+ }
+
+ double TextLayouterDevice::getOverlineOffset() const
+ {
+ const ::FontMetric& rMetric = mrDevice.GetFontMetric();
+ double fRet = (rMetric.GetIntLeading() / 2.0) - rMetric.GetAscent();
+ return fRet;
+ }
+
+ double TextLayouterDevice::getUnderlineOffset() const
+ {
+ const ::FontMetric& rMetric = mrDevice.GetFontMetric();
+ double fRet = rMetric.GetDescent() / 2.0;
+ return fRet;
+ }
+
+ double TextLayouterDevice::getStrikeoutOffset() const
+ {
+ const ::FontMetric& rMetric = mrDevice.GetFontMetric();
+ double fRet = (rMetric.GetAscent() - rMetric.GetIntLeading()) / 3.0;
+ return fRet;
+ }
+
+ double TextLayouterDevice::getOverlineHeight() const
+ {
+ const ::FontMetric& rMetric = mrDevice.GetFontMetric();
+ double fRet = rMetric.GetIntLeading() / 2.5;
+ return fRet;
+ }
+
+ double TextLayouterDevice::getUnderlineHeight() const
+ {
+ const ::FontMetric& rMetric = mrDevice.GetFontMetric();
+ double fRet = rMetric.GetDescent() / 4.0;
+ return fRet;
+ }
+
+ double TextLayouterDevice::getTextHeight() const
+ {
+ return mrDevice.GetTextHeight();
+ }
+
+ double TextLayouterDevice::getTextWidth(
+ const String& rText,
+ sal_uInt32 nIndex,
+ sal_uInt32 nLength) const
+ {
+ return mrDevice.GetTextWidth(rText, nIndex, nLength);
+ }
+
+ bool TextLayouterDevice::getTextOutlines(
+ basegfx::B2DPolyPolygonVector& rB2DPolyPolyVector,
+ const String& rText,
+ sal_uInt32 nIndex,
+ sal_uInt32 nLength,
+ const ::std::vector< double >& rDXArray) const
+ {
+ const sal_uInt32 nDXArrayCount(rDXArray.size());
+ sal_uInt32 nTextLength(nLength);
+ const sal_uInt32 nStringLength(rText.Len());
+
+ if(nTextLength + nIndex > nStringLength)
+ {
+ nTextLength = nStringLength - nIndex;
+ }
+
+ if(nDXArrayCount)
+ {
+ OSL_ENSURE(nDXArrayCount == nTextLength, "DXArray size does not correspond to text portion size (!)");
+ std::vector< sal_Int32 > aIntegerDXArray(nDXArrayCount);
+
+ for(sal_uInt32 a(0); a < nDXArrayCount; a++)
+ {
+ aIntegerDXArray[a] = basegfx::fround(rDXArray[a]);
+ }
+
+ return mrDevice.GetTextOutlines(
+ rB2DPolyPolyVector,
+ rText,
+ nIndex,
+ nIndex,
+ nLength,
+ true,
+ 0,
+ &(aIntegerDXArray[0]));
+ }
+ else
+ {
+ return mrDevice.GetTextOutlines(
+ rB2DPolyPolyVector,
+ rText,
+ nIndex,
+ nIndex,
+ nLength,
+ true,
+ 0,
+ 0);
+ }
+ }
+
+ basegfx::B2DRange TextLayouterDevice::getTextBoundRect(
+ const String& rText,
+ sal_uInt32 nIndex,
+ sal_uInt32 nLength) const
+ {
+ sal_uInt32 nTextLength(nLength);
+ const sal_uInt32 nStringLength(rText.Len());
+
+ if(nTextLength + nIndex > nStringLength)
+ {
+ nTextLength = nStringLength - nIndex;
+ }
+
+ if(nTextLength)
+ {
+ Rectangle aRect;
+
+ mrDevice.GetTextBoundRect(
+ aRect,
+ rText,
+ nIndex,
+ nIndex,
+ nLength);
+
+ // #i104432#, #i102556# take empty results into account
+ if(!aRect.IsEmpty())
+ {
+ return basegfx::B2DRange(
+ aRect.Left(), aRect.Top(),
+ aRect.Right(), aRect.Bottom());
+ }
+ }
+
+ return basegfx::B2DRange();
+ }
+
+ double TextLayouterDevice::getFontAscent() const
+ {
+ const ::FontMetric& rMetric = mrDevice.GetFontMetric();
+ return rMetric.GetAscent();
+ }
+
+ double TextLayouterDevice::getFontDescent() const
+ {
+ const ::FontMetric& rMetric = mrDevice.GetFontMetric();
+ return rMetric.GetDescent();
+ }
+
+ void TextLayouterDevice::addTextRectActions(
+ const Rectangle& rRectangle,
+ const String& rText,
+ sal_uInt16 nStyle,
+ GDIMetaFile& rGDIMetaFile) const
+ {
+ mrDevice.AddTextRectActions(
+ rRectangle, rText, nStyle, rGDIMetaFile);
+ }
+
+ ::std::vector< double > TextLayouterDevice::getTextArray(
+ const String& rText,
+ sal_uInt32 nIndex,
+ sal_uInt32 nLength) const
+ {
+ ::std::vector< double > aRetval;
+ sal_uInt32 nTextLength(nLength);
+ const sal_uInt32 nStringLength(rText.Len());
+
+ if(nTextLength + nIndex > nStringLength)
+ {
+ nTextLength = nStringLength - nIndex;
+ }
+
+ if(nTextLength)
+ {
+ aRetval.reserve(nTextLength);
+ sal_Int32* pArray = new sal_Int32[nTextLength];
+ mrDevice.GetTextArray(rText, pArray, nIndex, nLength);
+
+ for(sal_uInt32 a(0); a < nTextLength; a++)
+ {
+ aRetval.push_back(pArray[a]);
+ }
+ }
+
+ return aRetval;
+ }
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// helper methods for vcl font handling
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Font getVclFontFromFontAttribute(
+ const attribute::FontAttribute& rFontAttribute,
+ double fFontScaleX,
+ double fFontScaleY,
+ double fFontRotation,
+ const ::com::sun::star::lang::Locale& rLocale)
+ {
+ // detect FontScaling
+ const sal_uInt32 nHeight(basegfx::fround(fabs(fFontScaleY)));
+ const sal_uInt32 nWidth(basegfx::fround(fabs(fFontScaleX)));
+ const bool bFontIsScaled(nHeight != nWidth);
+
+#ifdef WIN32
+ // for WIN32 systems, start with creating an unscaled font. If FontScaling
+ // is wanted, that width needs to be adapted using FontMetric again to get a
+ // width of the unscaled font
+ Font aRetval(
+ rFontAttribute.getFamilyName(),
+ rFontAttribute.getStyleName(),
+ Size(0, nHeight));
+#else
+ // for non-WIN32 systems things are easier since these accept a Font creation
+ // with initially nWidth != nHeight for FontScaling. Despite that, use zero for
+ // FontWidth when no scaling is used to explicitely have that zero when e.g. the
+ // Font would be recorded in a MetaFile (The MetaFile FontAction WILL record a
+ // set FontWidth; import that in a WIN32 system, and trouble is there)
+ Font aRetval(
+ rFontAttribute.getFamilyName(),
+ rFontAttribute.getStyleName(),
+ Size(bFontIsScaled ? nWidth : 0, nHeight));
+#endif
+ // define various other FontAttribute
+ aRetval.SetAlign(ALIGN_BASELINE);
+ aRetval.SetCharSet(rFontAttribute.getSymbol() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE);
+ aRetval.SetVertical(rFontAttribute.getVertical() ? TRUE : FALSE);
+ aRetval.SetWeight(static_cast<FontWeight>(rFontAttribute.getWeight()));
+ aRetval.SetItalic(rFontAttribute.getItalic() ? ITALIC_NORMAL : ITALIC_NONE);
+ aRetval.SetOutline(rFontAttribute.getOutline());
+ aRetval.SetPitch(rFontAttribute.getMonospaced() ? PITCH_FIXED : PITCH_VARIABLE);
+ aRetval.SetLanguage(MsLangId::convertLocaleToLanguage(rLocale));
+
+#ifdef WIN32
+ // for WIN32 systems, correct the FontWidth if FontScaling is used
+ if(bFontIsScaled && nHeight > 0)
+ {
+ const FontMetric aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aRetval));
+
+ if(aUnscaledFontMetric.GetWidth() > 0)
+ {
+ const double fScaleFactor((double)nWidth / (double)nHeight);
+ const sal_uInt32 nScaledWidth(basegfx::fround((double)aUnscaledFontMetric.GetWidth() * fScaleFactor));
+ aRetval.SetWidth(nScaledWidth);
+ }
+ }
+#endif
+ // handle FontRotation (if defined)
+ if(!basegfx::fTools::equalZero(fFontRotation))
+ {
+ sal_Int16 aRotate10th((sal_Int16)(fFontRotation * (-1800.0/F_PI)));
+ aRetval.SetOrientation(aRotate10th % 3600);
+ }
+
+ return aRetval;
+ }
+
+ attribute::FontAttribute getFontAttributeFromVclFont(
+ basegfx::B2DVector& o_rSize,
+ const Font& rFont,
+ bool bRTL,
+ bool bBiDiStrong)
+ {
+ const attribute::FontAttribute aRetval(
+ rFont.GetName(),
+ rFont.GetStyleName(),
+ static_cast<sal_uInt16>(rFont.GetWeight()),
+ RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet(),
+ rFont.IsVertical(),
+ ITALIC_NONE != rFont.GetItalic(),
+ PITCH_FIXED == rFont.GetPitch(),
+ rFont.IsOutline(),
+ bRTL,
+ bBiDiStrong);
+ // TODO: eKerning
+
+ // set FontHeight and init to no FontScaling
+ o_rSize.setY(rFont.GetSize().getHeight() > 0 ? rFont.GetSize().getHeight() : 0);
+ o_rSize.setX(o_rSize.getY());
+
+#ifdef WIN32
+ // for WIN32 systems, the FontScaling at the Font is detected by
+ // checking that FontWidth != 0. When FontScaling is used, WIN32
+ // needs to do extra stuff to detect the correct width (since it's
+ // zero and not equal the font height) and it's relationship to
+ // the height
+ if(rFont.GetSize().getWidth() > 0)
+ {
+ Font aUnscaledFont(rFont);
+ aUnscaledFont.SetWidth(0);
+ const FontMetric aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aUnscaledFont));
+
+ if(aUnscaledFontMetric.GetWidth() > 0)
+ {
+ const double fScaleFactor((double)rFont.GetSize().getWidth() / (double)aUnscaledFontMetric.GetWidth());
+ o_rSize.setX(fScaleFactor * o_rSize.getY());
+ }
+ }
+#else
+ // For non-WIN32 systems the detection is the same, but the value
+ // is easier achieved since width == height is interpreted as no
+ // scaling. Ergo, Width == 0 means width == height, and width != 0
+ // means the scaling is in the direct relation of width to height
+ if(rFont.GetSize().getWidth() > 0)
+ {
+ o_rSize.setX((double)rFont.GetSize().getWidth());
+ }
+#endif
+ return aRetval;
+ }
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */