/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_drawinglayer.hxx" #include #include #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////// // 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() ? sal_True : sal_False); aRetval.SetWeight(static_cast(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(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