1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_svtools.hxx" 30 #include <svtools/scriptedtext.hxx> 31 #include <vector> 32 #include <rtl/ustring.hxx> 33 #include <vcl/outdev.hxx> 34 #include <vcl/font.hxx> 35 #include <tools/debug.hxx> 36 #include <com/sun/star/i18n/ScriptType.hpp> 37 38 39 using namespace ::std; 40 using namespace ::rtl; 41 using namespace ::com::sun::star; 42 43 44 //_____________________________________________________________________________ 45 46 class SvtScriptedTextHelper_Impl 47 { 48 private: 49 OutputDevice& mrOutDevice; /// The output device for drawing the text. 50 Font maLatinFont; /// The font for latin text portions. 51 Font maAsianFont; /// The font for asian text portions. 52 Font maCmplxFont; /// The font for complex text portions. 53 Font maDefltFont; /// The default font of the output device. 54 OUString maText; /// The text. 55 56 vector< sal_Int32 > maPosVec; /// The start position of each text portion. 57 vector< sal_Int16 > maScriptVec; /// The script type of each text portion. 58 vector< sal_Int32 > maWidthVec; /// The output width of each text portion. 59 Size maTextSize; /// The size the text will take in the current output device. 60 61 /** Assignment operator not implemented to prevent usage. */ 62 SvtScriptedTextHelper_Impl& operator=( const SvtScriptedTextHelper_Impl& ); 63 64 /** Gets the font of the given script type. */ 65 const Font& GetFont( sal_uInt16 _nScript ) const; 66 /** Sets a font on the output device depending on the script type. */ 67 inline void SetOutDevFont( sal_uInt16 _nScript ) 68 { mrOutDevice.SetFont( GetFont( _nScript ) ); } 69 /** Fills maPosVec with positions of all changes of script type. 70 This method expects correctly initialized maPosVec and maScriptVec. */ 71 void CalculateSizes(); 72 /** Fills maPosVec with positions of all changes of script type and 73 maScriptVec with the script type of each portion. */ 74 void CalculateBreaks( 75 const uno::Reference< i18n::XBreakIterator >& _xBreakIter ); 76 77 public: 78 /** This constructor sets an output device and fonts for all script types. */ 79 SvtScriptedTextHelper_Impl( 80 OutputDevice& _rOutDevice, 81 Font* _pLatinFont, 82 Font* _pAsianFont, 83 Font* _pCmplxFont ); 84 /** Copy constructor. */ 85 SvtScriptedTextHelper_Impl( 86 const SvtScriptedTextHelper_Impl& _rCopy ); 87 /** Destructor. */ 88 ~SvtScriptedTextHelper_Impl(); 89 90 /** Sets new fonts and recalculates the text width. */ 91 void SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ); 92 /** Sets a new text and calculates all script breaks and the text width. */ 93 void SetText( 94 const OUString& _rText, 95 const uno::Reference< i18n::XBreakIterator >& _xBreakIter ); 96 97 /** Returns the previously set text. */ 98 const OUString& GetText() const; 99 /** Returns a size struct containing the width and height of the text in the current output device. */ 100 const Size& GetTextSize() const; 101 102 /** Draws the text in the current output device. */ 103 void DrawText( const Point& _rPos ); 104 }; 105 106 107 SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl( 108 OutputDevice& _rOutDevice, 109 Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) : 110 mrOutDevice( _rOutDevice ), 111 maLatinFont( _pLatinFont ? *_pLatinFont : _rOutDevice.GetFont() ), 112 maAsianFont( _pAsianFont ? *_pAsianFont : _rOutDevice.GetFont() ), 113 maCmplxFont( _pCmplxFont ? *_pCmplxFont : _rOutDevice.GetFont() ), 114 maDefltFont( _rOutDevice.GetFont() ) 115 { 116 } 117 118 SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl( const SvtScriptedTextHelper_Impl& _rCopy ) : 119 mrOutDevice( _rCopy.mrOutDevice ), 120 maLatinFont( _rCopy.maLatinFont ), 121 maAsianFont( _rCopy.maAsianFont ), 122 maCmplxFont( _rCopy.maCmplxFont ), 123 maDefltFont( _rCopy.maDefltFont ), 124 maText( _rCopy.maText ), 125 maPosVec( _rCopy.maPosVec ), 126 maScriptVec( _rCopy.maScriptVec ), 127 maWidthVec( _rCopy.maWidthVec ), 128 maTextSize( _rCopy.maTextSize ) 129 { 130 } 131 132 SvtScriptedTextHelper_Impl::~SvtScriptedTextHelper_Impl() 133 { 134 } 135 136 const Font& SvtScriptedTextHelper_Impl::GetFont( sal_uInt16 _nScript ) const 137 { 138 switch( _nScript ) 139 { 140 case i18n::ScriptType::LATIN: return maLatinFont; 141 case i18n::ScriptType::ASIAN: return maAsianFont; 142 case i18n::ScriptType::COMPLEX: return maCmplxFont; 143 } 144 return maDefltFont; 145 } 146 147 void SvtScriptedTextHelper_Impl::CalculateSizes() 148 { 149 maTextSize.Width() = maTextSize.Height() = 0; 150 maDefltFont = mrOutDevice.GetFont(); 151 152 // calculate text portion widths and total width 153 maWidthVec.clear(); 154 if( !maPosVec.empty() ) 155 { 156 DBG_ASSERT( maPosVec.size() - 1 == maScriptVec.size(), 157 "SvtScriptedTextHelper_Impl::CalculateWidth - invalid vectors" ); 158 159 xub_StrLen nThisPos = static_cast< xub_StrLen >( maPosVec[ 0 ] ); 160 xub_StrLen nNextPos; 161 sal_Int32 nPosVecSize = maPosVec.size(); 162 sal_Int32 nPosVecIndex = 1; 163 164 sal_Int16 nScript; 165 sal_Int32 nScriptVecIndex = 0; 166 167 sal_Int32 nCurrWidth; 168 169 while( nPosVecIndex < nPosVecSize ) 170 { 171 nNextPos = static_cast< xub_StrLen >( maPosVec[ nPosVecIndex++ ] ); 172 nScript = maScriptVec[ nScriptVecIndex++ ]; 173 174 SetOutDevFont( nScript ); 175 nCurrWidth = mrOutDevice.GetTextWidth( maText, nThisPos, nNextPos - nThisPos ); 176 maWidthVec.push_back( nCurrWidth ); 177 maTextSize.Width() += nCurrWidth; 178 nThisPos = nNextPos; 179 } 180 } 181 182 // calculate maximum font height 183 SetOutDevFont( i18n::ScriptType::LATIN ); 184 maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() ); 185 SetOutDevFont( i18n::ScriptType::ASIAN ); 186 maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() ); 187 SetOutDevFont( i18n::ScriptType::COMPLEX ); 188 maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() ); 189 190 mrOutDevice.SetFont( maDefltFont ); 191 } 192 193 void SvtScriptedTextHelper_Impl::CalculateBreaks( const uno::Reference< i18n::XBreakIterator >& _xBreakIter ) 194 { 195 maPosVec.clear(); 196 maScriptVec.clear(); 197 198 DBG_ASSERT( _xBreakIter.is(), "SvtScriptedTextHelper_Impl::CalculateBreaks - no break iterator" ); 199 200 sal_Int32 nLen = maText.getLength(); 201 if( nLen ) 202 { 203 if( _xBreakIter.is() ) 204 { 205 sal_Int32 nThisPos = 0; // first position of this portion 206 sal_Int32 nNextPos = 0; // first position of next portion 207 sal_Int16 nPortScript; // script type of this portion 208 do 209 { 210 nPortScript = _xBreakIter->getScriptType( maText, nThisPos ); 211 nNextPos = _xBreakIter->endOfScript( maText, nThisPos, nPortScript ); 212 213 switch( nPortScript ) 214 { 215 case i18n::ScriptType::LATIN: 216 case i18n::ScriptType::ASIAN: 217 case i18n::ScriptType::COMPLEX: 218 maPosVec.push_back( nThisPos ); 219 maScriptVec.push_back( nPortScript ); 220 break; 221 default: 222 { 223 /* *** handling of weak characters *** 224 - first portion is weak: Use OutputDevice::HasGlyphs() to find the correct font 225 - weak portion follows another portion: Script type of preceding portion is used */ 226 if( maPosVec.empty() ) 227 { 228 sal_Int32 nCharIx = 0; 229 sal_Int32 nNextCharIx = 0; 230 sal_Int16 nScript; 231 do 232 { 233 nScript = i18n::ScriptType::LATIN; 234 while( (nScript != i18n::ScriptType::WEAK) && (nCharIx == nNextCharIx) ) 235 { 236 nNextCharIx = mrOutDevice.HasGlyphs( GetFont( nScript ), maText, sal::static_int_cast< sal_uInt16 >(nCharIx), sal::static_int_cast< sal_uInt16 >(nNextPos - nCharIx) ); 237 if( nCharIx == nNextCharIx ) 238 ++nScript; 239 } 240 if( nNextCharIx == nCharIx ) 241 ++nNextCharIx; 242 243 maPosVec.push_back( nCharIx ); 244 maScriptVec.push_back( nScript ); 245 nCharIx = nNextCharIx; 246 } 247 while( nCharIx < nNextPos ); 248 } 249 // nothing to do for following portions 250 } 251 } 252 nThisPos = nNextPos; 253 } 254 while( (0 <= nThisPos) && (nThisPos < nLen) ); 255 } 256 else // no break iterator: whole text LATIN 257 { 258 maPosVec.push_back( 0 ); 259 maScriptVec.push_back( i18n::ScriptType::LATIN ); 260 } 261 262 // push end position of last portion 263 if( !maPosVec.empty() ) 264 maPosVec.push_back( nLen ); 265 } 266 CalculateSizes(); 267 } 268 269 void SvtScriptedTextHelper_Impl::SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) 270 { 271 maLatinFont = _pLatinFont ? *_pLatinFont : maDefltFont; 272 maAsianFont = _pAsianFont ? *_pAsianFont : maDefltFont; 273 maCmplxFont = _pCmplxFont ? *_pCmplxFont : maDefltFont; 274 CalculateSizes(); 275 } 276 277 void SvtScriptedTextHelper_Impl::SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter ) 278 { 279 maText = _rText; 280 CalculateBreaks( _xBreakIter ); 281 } 282 283 const OUString& SvtScriptedTextHelper_Impl::GetText() const 284 { 285 return maText; 286 } 287 288 const Size& SvtScriptedTextHelper_Impl::GetTextSize() const 289 { 290 return maTextSize; 291 } 292 293 void SvtScriptedTextHelper_Impl::DrawText( const Point& _rPos ) 294 { 295 if( !maText.getLength() || maPosVec.empty() ) 296 return; 297 298 DBG_ASSERT( maPosVec.size() - 1 == maScriptVec.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" ); 299 DBG_ASSERT( maScriptVec.size() == maWidthVec.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" ); 300 301 maDefltFont = mrOutDevice.GetFont(); 302 Point aCurrPos( _rPos ); 303 xub_StrLen nThisPos = static_cast< xub_StrLen >( maPosVec[ 0 ] ); 304 xub_StrLen nNextPos; 305 sal_Int32 nPosVecSize = maPosVec.size(); 306 sal_Int32 nPosVecIndex = 1; 307 308 sal_Int16 nScript; 309 sal_Int32 nVecIndex = 0; 310 311 while( nPosVecIndex < nPosVecSize ) 312 { 313 nNextPos = static_cast< xub_StrLen >( maPosVec[ nPosVecIndex++ ] ); 314 nScript = maScriptVec[ nVecIndex ]; 315 316 SetOutDevFont( nScript ); 317 mrOutDevice.DrawText( aCurrPos, maText, nThisPos, nNextPos - nThisPos ); 318 aCurrPos.X() += maWidthVec[ nVecIndex++ ]; 319 aCurrPos.X() += mrOutDevice.GetTextHeight() / 5; // add 20% of font height as portion spacing 320 nThisPos = nNextPos; 321 } 322 mrOutDevice.SetFont( maDefltFont ); 323 } 324 325 326 //_____________________________________________________________________________ 327 328 SvtScriptedTextHelper::SvtScriptedTextHelper( OutputDevice& _rOutDevice ) : 329 mpImpl( new SvtScriptedTextHelper_Impl( _rOutDevice, NULL, NULL, NULL ) ) 330 { 331 } 332 333 SvtScriptedTextHelper::SvtScriptedTextHelper( 334 OutputDevice& _rOutDevice, 335 Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) : 336 mpImpl( new SvtScriptedTextHelper_Impl( _rOutDevice, _pLatinFont, _pAsianFont, _pCmplxFont ) ) 337 { 338 } 339 340 SvtScriptedTextHelper::SvtScriptedTextHelper( const SvtScriptedTextHelper& _rCopy ) : 341 mpImpl( new SvtScriptedTextHelper_Impl( *_rCopy.mpImpl ) ) 342 { 343 } 344 345 SvtScriptedTextHelper::~SvtScriptedTextHelper() 346 { 347 delete mpImpl; 348 } 349 350 void SvtScriptedTextHelper::SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) 351 { 352 mpImpl->SetFonts( _pLatinFont, _pAsianFont, _pCmplxFont ); 353 } 354 355 void SvtScriptedTextHelper::SetDefaultFont() 356 { 357 mpImpl->SetFonts( NULL, NULL, NULL ); 358 } 359 360 void SvtScriptedTextHelper::SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter ) 361 { 362 mpImpl->SetText( _rText, _xBreakIter ); 363 } 364 365 const OUString& SvtScriptedTextHelper::GetText() const 366 { 367 return mpImpl->GetText(); 368 } 369 370 sal_Int32 SvtScriptedTextHelper::GetTextWidth() const 371 { 372 return mpImpl->GetTextSize().Width(); 373 } 374 375 sal_Int32 SvtScriptedTextHelper::GetTextHeight() const 376 { 377 return mpImpl->GetTextSize().Height(); 378 } 379 380 const Size& SvtScriptedTextHelper::GetTextSize() const 381 { 382 return mpImpl->GetTextSize(); 383 } 384 385 void SvtScriptedTextHelper::DrawText( const Point& _rPos ) 386 { 387 mpImpl->DrawText( _rPos ); 388 } 389 390 391 //_____________________________________________________________________________ 392 393