| /************************************************************** |
| * |
| * 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 <svtools/scriptedtext.hxx> |
| #include <vector> |
| #include <rtl/ustring.hxx> |
| #include <vcl/outdev.hxx> |
| #include <vcl/font.hxx> |
| #include <tools/debug.hxx> |
| #include <com/sun/star/i18n/ScriptType.hpp> |
| |
| |
| 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 ); |
| } |
| |
| |
| //_____________________________________________________________________________ |
| |