/************************************************************** * * 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_svtools.hxx" #include #include #include #include #include #include #include using namespace ::std; using namespace ::rtl; using namespace ::com::sun::star; //_____________________________________________________________________________ class SvtScriptedTextHelper_Impl { private: OutputDevice& mrOutDevice; /// The output device for drawing the text. Font maLatinFont; /// The font for latin text portions. Font maAsianFont; /// The font for asian text portions. Font maCmplxFont; /// The font for complex text portions. Font maDefltFont; /// The default font of the output device. OUString maText; /// The text. vector< sal_Int32 > maPosVec; /// The start position of each text portion. vector< sal_Int16 > maScriptVec; /// The script type of each text portion. vector< sal_Int32 > maWidthVec; /// The output width of each text portion. Size maTextSize; /// The size the text will take in the current output device. /** Assignment operator not implemented to prevent usage. */ SvtScriptedTextHelper_Impl& operator=( const SvtScriptedTextHelper_Impl& ); /** Gets the font of the given script type. */ const Font& GetFont( sal_uInt16 _nScript ) const; /** Sets a font on the output device depending on the script type. */ inline void SetOutDevFont( sal_uInt16 _nScript ) { mrOutDevice.SetFont( GetFont( _nScript ) ); } /** Fills maPosVec with positions of all changes of script type. This method expects correctly initialized maPosVec and maScriptVec. */ void CalculateSizes(); /** Fills maPosVec with positions of all changes of script type and maScriptVec with the script type of each portion. */ void CalculateBreaks( const uno::Reference< i18n::XBreakIterator >& _xBreakIter ); public: /** This constructor sets an output device and fonts for all script types. */ SvtScriptedTextHelper_Impl( OutputDevice& _rOutDevice, Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ); /** Copy constructor. */ SvtScriptedTextHelper_Impl( const SvtScriptedTextHelper_Impl& _rCopy ); /** Destructor. */ ~SvtScriptedTextHelper_Impl(); /** Sets new fonts and recalculates the text width. */ void SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ); /** Sets a new text and calculates all script breaks and the text width. */ void SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter ); /** Returns the previously set text. */ const OUString& GetText() const; /** Returns a size struct containing the width and height of the text in the current output device. */ const Size& GetTextSize() const; /** Draws the text in the current output device. */ void DrawText( const Point& _rPos ); }; SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl( OutputDevice& _rOutDevice, Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) : mrOutDevice( _rOutDevice ), maLatinFont( _pLatinFont ? *_pLatinFont : _rOutDevice.GetFont() ), maAsianFont( _pAsianFont ? *_pAsianFont : _rOutDevice.GetFont() ), maCmplxFont( _pCmplxFont ? *_pCmplxFont : _rOutDevice.GetFont() ), maDefltFont( _rOutDevice.GetFont() ) { } SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl( const SvtScriptedTextHelper_Impl& _rCopy ) : mrOutDevice( _rCopy.mrOutDevice ), maLatinFont( _rCopy.maLatinFont ), maAsianFont( _rCopy.maAsianFont ), maCmplxFont( _rCopy.maCmplxFont ), maDefltFont( _rCopy.maDefltFont ), maText( _rCopy.maText ), maPosVec( _rCopy.maPosVec ), maScriptVec( _rCopy.maScriptVec ), maWidthVec( _rCopy.maWidthVec ), maTextSize( _rCopy.maTextSize ) { } SvtScriptedTextHelper_Impl::~SvtScriptedTextHelper_Impl() { } const Font& SvtScriptedTextHelper_Impl::GetFont( sal_uInt16 _nScript ) const { switch( _nScript ) { case i18n::ScriptType::LATIN: return maLatinFont; case i18n::ScriptType::ASIAN: return maAsianFont; case i18n::ScriptType::COMPLEX: return maCmplxFont; } return maDefltFont; } void SvtScriptedTextHelper_Impl::CalculateSizes() { maTextSize.Width() = maTextSize.Height() = 0; maDefltFont = mrOutDevice.GetFont(); // calculate text portion widths and total width maWidthVec.clear(); if( !maPosVec.empty() ) { DBG_ASSERT( maPosVec.size() - 1 == maScriptVec.size(), "SvtScriptedTextHelper_Impl::CalculateWidth - invalid vectors" ); xub_StrLen nThisPos = static_cast< xub_StrLen >( maPosVec[ 0 ] ); xub_StrLen nNextPos; sal_Int32 nPosVecSize = maPosVec.size(); sal_Int32 nPosVecIndex = 1; sal_Int16 nScript; sal_Int32 nScriptVecIndex = 0; sal_Int32 nCurrWidth; while( nPosVecIndex < nPosVecSize ) { nNextPos = static_cast< xub_StrLen >( maPosVec[ nPosVecIndex++ ] ); nScript = maScriptVec[ nScriptVecIndex++ ]; SetOutDevFont( nScript ); nCurrWidth = mrOutDevice.GetTextWidth( maText, nThisPos, nNextPos - nThisPos ); maWidthVec.push_back( nCurrWidth ); maTextSize.Width() += nCurrWidth; nThisPos = nNextPos; } } // calculate maximum font height SetOutDevFont( i18n::ScriptType::LATIN ); maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() ); SetOutDevFont( i18n::ScriptType::ASIAN ); maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() ); SetOutDevFont( i18n::ScriptType::COMPLEX ); maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() ); mrOutDevice.SetFont( maDefltFont ); } void SvtScriptedTextHelper_Impl::CalculateBreaks( const uno::Reference< i18n::XBreakIterator >& _xBreakIter ) { maPosVec.clear(); maScriptVec.clear(); DBG_ASSERT( _xBreakIter.is(), "SvtScriptedTextHelper_Impl::CalculateBreaks - no break iterator" ); sal_Int32 nLen = maText.getLength(); if( nLen ) { if( _xBreakIter.is() ) { sal_Int32 nThisPos = 0; // first position of this portion sal_Int32 nNextPos = 0; // first position of next portion sal_Int16 nPortScript; // script type of this portion do { nPortScript = _xBreakIter->getScriptType( maText, nThisPos ); nNextPos = _xBreakIter->endOfScript( maText, nThisPos, nPortScript ); switch( nPortScript ) { case i18n::ScriptType::LATIN: case i18n::ScriptType::ASIAN: case i18n::ScriptType::COMPLEX: maPosVec.push_back( nThisPos ); maScriptVec.push_back( nPortScript ); break; default: { /* *** handling of weak characters *** - first portion is weak: Use OutputDevice::HasGlyphs() to find the correct font - weak portion follows another portion: Script type of preceding portion is used */ if( maPosVec.empty() ) { sal_Int32 nCharIx = 0; sal_Int32 nNextCharIx = 0; sal_Int16 nScript; do { nScript = i18n::ScriptType::LATIN; while( (nScript != i18n::ScriptType::WEAK) && (nCharIx == nNextCharIx) ) { nNextCharIx = mrOutDevice.HasGlyphs( GetFont( nScript ), maText, sal::static_int_cast< sal_uInt16 >(nCharIx), sal::static_int_cast< sal_uInt16 >(nNextPos - nCharIx) ); if( nCharIx == nNextCharIx ) ++nScript; } if( nNextCharIx == nCharIx ) ++nNextCharIx; maPosVec.push_back( nCharIx ); maScriptVec.push_back( nScript ); nCharIx = nNextCharIx; } while( nCharIx < nNextPos ); } // nothing to do for following portions } } nThisPos = nNextPos; } while( (0 <= nThisPos) && (nThisPos < nLen) ); } else // no break iterator: whole text LATIN { maPosVec.push_back( 0 ); maScriptVec.push_back( i18n::ScriptType::LATIN ); } // push end position of last portion if( !maPosVec.empty() ) maPosVec.push_back( nLen ); } CalculateSizes(); } void SvtScriptedTextHelper_Impl::SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) { maLatinFont = _pLatinFont ? *_pLatinFont : maDefltFont; maAsianFont = _pAsianFont ? *_pAsianFont : maDefltFont; maCmplxFont = _pCmplxFont ? *_pCmplxFont : maDefltFont; CalculateSizes(); } void SvtScriptedTextHelper_Impl::SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter ) { maText = _rText; CalculateBreaks( _xBreakIter ); } const OUString& SvtScriptedTextHelper_Impl::GetText() const { return maText; } const Size& SvtScriptedTextHelper_Impl::GetTextSize() const { return maTextSize; } void SvtScriptedTextHelper_Impl::DrawText( const Point& _rPos ) { if( !maText.getLength() || maPosVec.empty() ) return; DBG_ASSERT( maPosVec.size() - 1 == maScriptVec.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" ); DBG_ASSERT( maScriptVec.size() == maWidthVec.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" ); maDefltFont = mrOutDevice.GetFont(); Point aCurrPos( _rPos ); xub_StrLen nThisPos = static_cast< xub_StrLen >( maPosVec[ 0 ] ); xub_StrLen nNextPos; sal_Int32 nPosVecSize = maPosVec.size(); sal_Int32 nPosVecIndex = 1; sal_Int16 nScript; sal_Int32 nVecIndex = 0; while( nPosVecIndex < nPosVecSize ) { nNextPos = static_cast< xub_StrLen >( maPosVec[ nPosVecIndex++ ] ); nScript = maScriptVec[ nVecIndex ]; SetOutDevFont( nScript ); mrOutDevice.DrawText( aCurrPos, maText, nThisPos, nNextPos - nThisPos ); aCurrPos.X() += maWidthVec[ nVecIndex++ ]; aCurrPos.X() += mrOutDevice.GetTextHeight() / 5; // add 20% of font height as portion spacing nThisPos = nNextPos; } mrOutDevice.SetFont( maDefltFont ); } //_____________________________________________________________________________ SvtScriptedTextHelper::SvtScriptedTextHelper( OutputDevice& _rOutDevice ) : mpImpl( new SvtScriptedTextHelper_Impl( _rOutDevice, NULL, NULL, NULL ) ) { } SvtScriptedTextHelper::SvtScriptedTextHelper( OutputDevice& _rOutDevice, Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) : mpImpl( new SvtScriptedTextHelper_Impl( _rOutDevice, _pLatinFont, _pAsianFont, _pCmplxFont ) ) { } SvtScriptedTextHelper::SvtScriptedTextHelper( const SvtScriptedTextHelper& _rCopy ) : mpImpl( new SvtScriptedTextHelper_Impl( *_rCopy.mpImpl ) ) { } SvtScriptedTextHelper::~SvtScriptedTextHelper() { delete mpImpl; } void SvtScriptedTextHelper::SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) { mpImpl->SetFonts( _pLatinFont, _pAsianFont, _pCmplxFont ); } void SvtScriptedTextHelper::SetDefaultFont() { mpImpl->SetFonts( NULL, NULL, NULL ); } void SvtScriptedTextHelper::SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter ) { mpImpl->SetText( _rText, _xBreakIter ); } const OUString& SvtScriptedTextHelper::GetText() const { return mpImpl->GetText(); } sal_Int32 SvtScriptedTextHelper::GetTextWidth() const { return mpImpl->GetTextSize().Width(); } sal_Int32 SvtScriptedTextHelper::GetTextHeight() const { return mpImpl->GetTextSize().Height(); } const Size& SvtScriptedTextHelper::GetTextSize() const { return mpImpl->GetTextSize(); } void SvtScriptedTextHelper::DrawText( const Point& _rPos ) { mpImpl->DrawText( _rPos ); } //_____________________________________________________________________________