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