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 #include "oox/xls/richstring.hxx" 29 30 #include <com/sun/star/text/XText.hpp> 31 #include <rtl/ustrbuf.hxx> 32 #include "oox/helper/attributelist.hxx" 33 #include "oox/helper/propertyset.hxx" 34 #include "oox/xls/biffinputstream.hxx" 35 36 namespace oox { 37 namespace xls { 38 39 // ============================================================================ 40 41 using namespace ::com::sun::star::text; 42 using namespace ::com::sun::star::uno; 43 44 using ::rtl::OString; 45 using ::rtl::OUString; 46 using ::rtl::OUStringBuffer; 47 48 // ============================================================================ 49 50 namespace { 51 52 const sal_uInt8 BIFF12_STRINGFLAG_FONTS = 0x01; 53 const sal_uInt8 BIFF12_STRINGFLAG_PHONETICS = 0x02; 54 55 inline bool lclNeedsRichTextFormat( const Font* pFont ) 56 { 57 return pFont && pFont->needsRichTextFormat(); 58 } 59 60 } // namespace 61 62 // ============================================================================ 63 64 RichStringPortion::RichStringPortion( const WorkbookHelper& rHelper ) : 65 WorkbookHelper( rHelper ), 66 mnFontId( -1 ) 67 { 68 } 69 70 void RichStringPortion::setText( const OUString& rText ) 71 { 72 maText = rText; 73 } 74 75 FontRef RichStringPortion::createFont() 76 { 77 mxFont.reset( new Font( *this, false ) ); 78 return mxFont; 79 } 80 81 void RichStringPortion::setFontId( sal_Int32 nFontId ) 82 { 83 mnFontId = nFontId; 84 } 85 86 void RichStringPortion::finalizeImport() 87 { 88 if( mxFont.get() ) 89 mxFont->finalizeImport(); 90 else if( mnFontId >= 0 ) 91 mxFont = getStyles().getFont( mnFontId ); 92 } 93 94 void RichStringPortion::convert( const Reference< XText >& rxText, const Font* pFont, bool bReplace ) 95 { 96 Reference< XTextRange > xRange; 97 if( bReplace ) 98 xRange.set( rxText, UNO_QUERY ); 99 else 100 xRange = rxText->getEnd(); 101 OSL_ENSURE( xRange.is(), "RichStringPortion::convert - cannot get text range interface" ); 102 103 if( xRange.is() ) 104 { 105 xRange->setString( maText ); 106 if( mxFont.get() ) 107 { 108 PropertySet aPropSet( xRange ); 109 mxFont->writeToPropertySet( aPropSet, FONT_PROPTYPE_TEXT ); 110 } 111 /* Some font attributes cannot be set to cell formatting in Calc but 112 require to use rich formatting, e.g. font escapement. But do not 113 use the passed font if this portion has its own font. */ 114 else if( lclNeedsRichTextFormat( pFont ) ) 115 { 116 PropertySet aPropSet( xRange ); 117 pFont->writeToPropertySet( aPropSet, FONT_PROPTYPE_TEXT ); 118 } 119 } 120 } 121 122 // ---------------------------------------------------------------------------- 123 124 void FontPortionModel::read( SequenceInputStream& rStrm ) 125 { 126 mnPos = rStrm.readuInt16(); 127 mnFontId = rStrm.readuInt16(); 128 } 129 130 void FontPortionModel::read( BiffInputStream& rStrm, BiffFontPortionMode eMode ) 131 { 132 switch( eMode ) 133 { 134 case BIFF_FONTPORTION_8BIT: 135 mnPos = rStrm.readuInt8(); 136 mnFontId = rStrm.readuInt8(); 137 break; 138 case BIFF_FONTPORTION_16BIT: 139 mnPos = rStrm.readuInt16(); 140 mnFontId = rStrm.readuInt16(); 141 break; 142 case BIFF_FONTPORTION_OBJ: 143 mnPos = rStrm.readuInt16(); 144 mnFontId = rStrm.readuInt16(); 145 rStrm.skip( 4 ); 146 break; 147 } 148 } 149 150 // ---------------------------------------------------------------------------- 151 152 void FontPortionModelList::appendPortion( const FontPortionModel& rPortion ) 153 { 154 // #i33341# real life -- same character index may occur several times 155 OSL_ENSURE( empty() || (back().mnPos <= rPortion.mnPos), "FontPortionModelList::appendPortion - wrong char order" ); 156 if( empty() || (back().mnPos < rPortion.mnPos) ) 157 push_back( rPortion ); 158 else 159 back().mnFontId = rPortion.mnFontId; 160 } 161 162 void FontPortionModelList::importPortions( SequenceInputStream& rStrm ) 163 { 164 sal_Int32 nCount = rStrm.readInt32(); 165 clear(); 166 if( nCount > 0 ) 167 { 168 reserve( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / 4 ) ); 169 /* #i33341# real life -- same character index may occur several times 170 -> use appendPortion() to validate string position. */ 171 FontPortionModel aPortion; 172 for( sal_Int32 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex ) 173 { 174 aPortion.read( rStrm ); 175 appendPortion( aPortion ); 176 } 177 } 178 } 179 180 void FontPortionModelList::importPortions( BiffInputStream& rStrm, sal_uInt16 nCount, BiffFontPortionMode eMode ) 181 { 182 clear(); 183 reserve( nCount ); 184 /* #i33341# real life -- same character index may occur several times 185 -> use appendPortion() to validate string position. */ 186 FontPortionModel aPortion; 187 for( sal_uInt16 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex ) 188 { 189 aPortion.read( rStrm, eMode ); 190 appendPortion( aPortion ); 191 } 192 } 193 194 void FontPortionModelList::importPortions( BiffInputStream& rStrm, bool b16Bit ) 195 { 196 sal_uInt16 nCount = b16Bit ? rStrm.readuInt16() : rStrm.readuInt8(); 197 importPortions( rStrm, nCount, b16Bit ? BIFF_FONTPORTION_16BIT : BIFF_FONTPORTION_8BIT ); 198 } 199 200 // ============================================================================ 201 202 PhoneticDataModel::PhoneticDataModel() : 203 mnFontId( -1 ), 204 mnType( XML_fullwidthKatakana ), 205 mnAlignment( XML_left ) 206 { 207 } 208 209 void PhoneticDataModel::setBiffData( sal_Int32 nType, sal_Int32 nAlignment ) 210 { 211 static const sal_Int32 spnTypeIds[] = { XML_halfwidthKatakana, XML_fullwidthKatakana, XML_hiragana, XML_noConversion }; 212 mnType = STATIC_ARRAY_SELECT( spnTypeIds, nType, XML_fullwidthKatakana ); 213 214 static const sal_Int32 spnAlignments[] = { XML_noControl, XML_left, XML_center, XML_distributed }; 215 mnAlignment = STATIC_ARRAY_SELECT( spnAlignments, nAlignment, XML_left ); 216 } 217 218 // ---------------------------------------------------------------------------- 219 220 PhoneticSettings::PhoneticSettings( const WorkbookHelper& rHelper ) : 221 WorkbookHelper( rHelper ) 222 { 223 } 224 225 void PhoneticSettings::importPhoneticPr( const AttributeList& rAttribs ) 226 { 227 maModel.mnFontId = rAttribs.getInteger( XML_fontId, -1 ); 228 maModel.mnType = rAttribs.getToken( XML_type, XML_fullwidthKatakana ); 229 maModel.mnAlignment = rAttribs.getToken( XML_alignment, XML_left ); 230 } 231 232 void PhoneticSettings::importPhoneticPr( SequenceInputStream& rStrm ) 233 { 234 sal_uInt16 nFontId; 235 sal_Int32 nType, nAlignment; 236 rStrm >> nFontId >> nType >> nAlignment; 237 maModel.mnFontId = nFontId; 238 maModel.setBiffData( nType, nAlignment ); 239 } 240 241 void PhoneticSettings::importPhoneticPr( BiffInputStream& rStrm ) 242 { 243 sal_uInt16 nFontId, nFlags; 244 rStrm >> nFontId >> nFlags; 245 maModel.mnFontId = nFontId; 246 maModel.setBiffData( extractValue< sal_Int32 >( nFlags, 0, 2 ), extractValue< sal_Int32 >( nFlags, 2, 2 ) ); 247 // following: range list with cells showing phonetic text 248 } 249 250 void PhoneticSettings::importStringData( SequenceInputStream& rStrm ) 251 { 252 sal_uInt16 nFontId, nFlags; 253 rStrm >> nFontId >> nFlags; 254 maModel.mnFontId = nFontId; 255 maModel.setBiffData( extractValue< sal_Int32 >( nFlags, 0, 2 ), extractValue< sal_Int32 >( nFlags, 2, 2 ) ); 256 } 257 258 void PhoneticSettings::importStringData( BiffInputStream& rStrm ) 259 { 260 sal_uInt16 nFontId, nFlags; 261 rStrm >> nFontId >> nFlags; 262 maModel.mnFontId = nFontId; 263 maModel.setBiffData( extractValue< sal_Int32 >( nFlags, 0, 2 ), extractValue< sal_Int32 >( nFlags, 2, 2 ) ); 264 } 265 266 // ============================================================================ 267 268 RichStringPhonetic::RichStringPhonetic( const WorkbookHelper& rHelper ) : 269 WorkbookHelper( rHelper ), 270 mnBasePos( -1 ), 271 mnBaseEnd( -1 ) 272 { 273 } 274 275 void RichStringPhonetic::setText( const OUString& rText ) 276 { 277 maText = rText; 278 } 279 280 void RichStringPhonetic::importPhoneticRun( const AttributeList& rAttribs ) 281 { 282 mnBasePos = rAttribs.getInteger( XML_sb, -1 ); 283 mnBaseEnd = rAttribs.getInteger( XML_eb, -1 ); 284 } 285 286 void RichStringPhonetic::setBaseRange( sal_Int32 nBasePos, sal_Int32 nBaseEnd ) 287 { 288 mnBasePos = nBasePos; 289 mnBaseEnd = nBaseEnd; 290 } 291 292 // ---------------------------------------------------------------------------- 293 294 void PhoneticPortionModel::read( SequenceInputStream& rStrm ) 295 { 296 mnPos = rStrm.readuInt16(); 297 mnBasePos = rStrm.readuInt16(); 298 mnBaseLen = rStrm.readuInt16(); 299 } 300 301 void PhoneticPortionModel::read( BiffInputStream& rStrm ) 302 { 303 mnPos = rStrm.readuInt16(); 304 mnBasePos = rStrm.readuInt16(); 305 mnBaseLen = rStrm.readuInt16(); 306 } 307 308 // ---------------------------------------------------------------------------- 309 310 void PhoneticPortionModelList::appendPortion( const PhoneticPortionModel& rPortion ) 311 { 312 // same character index may occur several times 313 OSL_ENSURE( empty() || ((back().mnPos <= rPortion.mnPos) && 314 (back().mnBasePos + back().mnBaseLen <= rPortion.mnBasePos)), 315 "PhoneticPortionModelList::appendPortion - wrong char order" ); 316 if( empty() || (back().mnPos < rPortion.mnPos) ) 317 { 318 push_back( rPortion ); 319 } 320 else if( back().mnPos == rPortion.mnPos ) 321 { 322 back().mnBasePos = rPortion.mnBasePos; 323 back().mnBaseLen = rPortion.mnBaseLen; 324 } 325 } 326 327 void PhoneticPortionModelList::importPortions( SequenceInputStream& rStrm ) 328 { 329 sal_Int32 nCount = rStrm.readInt32(); 330 clear(); 331 if( nCount > 0 ) 332 { 333 reserve( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / 6 ) ); 334 PhoneticPortionModel aPortion; 335 for( sal_Int32 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex ) 336 { 337 aPortion.read( rStrm ); 338 appendPortion( aPortion ); 339 } 340 } 341 } 342 343 OUString PhoneticPortionModelList::importPortions( BiffInputStream& rStrm, sal_Int32 nPhoneticSize ) 344 { 345 OUString aPhoneticText; 346 sal_uInt16 nPortionCount, nTextLen1, nTextLen2; 347 rStrm >> nPortionCount >> nTextLen1 >> nTextLen2; 348 OSL_ENSURE( nTextLen1 == nTextLen2, "PhoneticPortionModelList::importPortions - wrong phonetic text length" ); 349 if( (nTextLen1 == nTextLen2) && (nTextLen1 > 0) ) 350 { 351 sal_Int32 nMinSize = 2 * nTextLen1 + 6 * nPortionCount + 14; 352 OSL_ENSURE( nMinSize <= nPhoneticSize, "PhoneticPortionModelList::importPortions - wrong size of phonetic data" ); 353 if( nMinSize <= nPhoneticSize ) 354 { 355 aPhoneticText = rStrm.readUnicodeArray( nTextLen1 ); 356 clear(); 357 reserve( nPortionCount ); 358 PhoneticPortionModel aPortion; 359 for( sal_uInt16 nPortion = 0; nPortion < nPortionCount; ++nPortion ) 360 { 361 aPortion.read( rStrm ); 362 appendPortion( aPortion ); 363 } 364 } 365 } 366 return aPhoneticText; 367 } 368 369 // ============================================================================ 370 371 RichString::RichString( const WorkbookHelper& rHelper ) : 372 WorkbookHelper( rHelper ), 373 maPhonSettings( rHelper ) 374 { 375 } 376 377 RichStringPortionRef RichString::importText( const AttributeList& ) 378 { 379 return createPortion(); 380 } 381 382 RichStringPortionRef RichString::importRun( const AttributeList& ) 383 { 384 return createPortion(); 385 } 386 387 RichStringPhoneticRef RichString::importPhoneticRun( const AttributeList& rAttribs ) 388 { 389 RichStringPhoneticRef xPhonetic = createPhonetic(); 390 xPhonetic->importPhoneticRun( rAttribs ); 391 return xPhonetic; 392 } 393 394 void RichString::importPhoneticPr( const AttributeList& rAttribs ) 395 { 396 maPhonSettings.importPhoneticPr( rAttribs ); 397 } 398 399 void RichString::importString( SequenceInputStream& rStrm, bool bRich ) 400 { 401 sal_uInt8 nFlags = bRich ? rStrm.readuInt8() : 0; 402 OUString aBaseText = BiffHelper::readString( rStrm ); 403 404 if( !rStrm.isEof() && getFlag( nFlags, BIFF12_STRINGFLAG_FONTS ) ) 405 { 406 FontPortionModelList aPortions; 407 aPortions.importPortions( rStrm ); 408 createTextPortions( aBaseText, aPortions ); 409 } 410 else 411 { 412 createPortion()->setText( aBaseText ); 413 } 414 415 if( !rStrm.isEof() && getFlag( nFlags, BIFF12_STRINGFLAG_PHONETICS ) ) 416 { 417 OUString aPhoneticText = BiffHelper::readString( rStrm ); 418 PhoneticPortionModelList aPortions; 419 aPortions.importPortions( rStrm ); 420 maPhonSettings.importStringData( rStrm ); 421 createPhoneticPortions( aPhoneticText, aPortions, aBaseText.getLength() ); 422 } 423 } 424 425 void RichString::importCharArray( BiffInputStream& rStrm, sal_uInt16 nChars, rtl_TextEncoding eTextEnc ) 426 { 427 createPortion()->setText( rStrm.readCharArrayUC( nChars, eTextEnc ) ); 428 } 429 430 void RichString::importByteString( BiffInputStream& rStrm, rtl_TextEncoding eTextEnc, BiffStringFlags nFlags ) 431 { 432 OSL_ENSURE( !getFlag( nFlags, BIFF_STR_KEEPFONTS ), "RichString::importString - keep fonts not implemented" ); 433 OSL_ENSURE( !getFlag( nFlags, static_cast< BiffStringFlags >( ~(BIFF_STR_8BITLENGTH | BIFF_STR_EXTRAFONTS) ) ), "RichString::importByteString - unknown flag" ); 434 bool b8BitLength = getFlag( nFlags, BIFF_STR_8BITLENGTH ); 435 436 OString aBaseText = rStrm.readByteString( !b8BitLength ); 437 438 if( !rStrm.isEof() && getFlag( nFlags, BIFF_STR_EXTRAFONTS ) ) 439 { 440 FontPortionModelList aPortions; 441 aPortions.importPortions( rStrm, false ); 442 createTextPortions( aBaseText, eTextEnc, aPortions ); 443 } 444 else 445 { 446 createPortion()->setText( OStringToOUString( aBaseText, eTextEnc ) ); 447 } 448 } 449 450 void RichString::importUniString( BiffInputStream& rStrm, BiffStringFlags nFlags ) 451 { 452 OSL_ENSURE( !getFlag( nFlags, BIFF_STR_KEEPFONTS ), "RichString::importUniString - keep fonts not implemented" ); 453 OSL_ENSURE( !getFlag( nFlags, static_cast< BiffStringFlags >( ~(BIFF_STR_8BITLENGTH | BIFF_STR_SMARTFLAGS) ) ), "RichString::importUniString - unknown flag" ); 454 bool b8BitLength = getFlag( nFlags, BIFF_STR_8BITLENGTH ); 455 456 // --- string header --- 457 sal_uInt16 nChars = b8BitLength ? rStrm.readuInt8() : rStrm.readuInt16(); 458 sal_uInt8 nFlagField = 0; 459 if( (nChars > 0) || !getFlag( nFlags, BIFF_STR_SMARTFLAGS ) ) 460 rStrm >> nFlagField; 461 bool b16Bit = getFlag( nFlagField, BIFF_STRF_16BIT ); 462 bool bFonts = getFlag( nFlagField, BIFF_STRF_RICH ); 463 bool bPhonetic = getFlag( nFlagField, BIFF_STRF_PHONETIC ); 464 sal_uInt16 nFontCount = bFonts ? rStrm.readuInt16() : 0; 465 sal_Int32 nPhoneticSize = bPhonetic ? rStrm.readInt32() : 0; 466 467 // --- character array --- 468 OUString aBaseText = rStrm.readUniStringChars( nChars, b16Bit ); 469 470 // --- formatting --- 471 // #122185# bRich flag may be set, but format runs may be missing 472 if( !rStrm.isEof() && (nFontCount > 0) ) 473 { 474 FontPortionModelList aPortions; 475 aPortions.importPortions( rStrm, nFontCount, BIFF_FONTPORTION_16BIT ); 476 createTextPortions( aBaseText, aPortions ); 477 } 478 else 479 { 480 createPortion()->setText( aBaseText ); 481 } 482 483 // --- Asian phonetic information --- 484 // #122185# bPhonetic flag may be set, but phonetic info may be missing 485 if( !rStrm.isEof() && (nPhoneticSize > 0) ) 486 { 487 sal_Int64 nPhoneticEnd = rStrm.tell() + nPhoneticSize; 488 OSL_ENSURE( nPhoneticSize > 14, "RichString::importUniString - wrong size of phonetic data" ); 489 if( nPhoneticSize > 14 ) 490 { 491 sal_uInt16 nId, nSize; 492 rStrm >> nId >> nSize; 493 OSL_ENSURE( nId == 1, "RichString::importUniString - unknown phonetic data identifier" ); 494 sal_Int32 nMinSize = nSize + 4; 495 OSL_ENSURE( nMinSize <= nPhoneticSize, "RichString::importUniString - wrong size of phonetic data" ); 496 if( (nId == 1) && (nMinSize <= nPhoneticSize) ) 497 { 498 maPhonSettings.importStringData( rStrm ); 499 PhoneticPortionModelList aPortions; 500 OUString aPhoneticText = aPortions.importPortions( rStrm, nPhoneticSize ); 501 createPhoneticPortions( aPhoneticText, aPortions, aBaseText.getLength() ); 502 } 503 } 504 rStrm.seek( nPhoneticEnd ); 505 } 506 } 507 508 void RichString::finalizeImport() 509 { 510 maTextPortions.forEachMem( &RichStringPortion::finalizeImport ); 511 } 512 513 bool RichString::extractPlainString( OUString& orString, const Font* pFirstPortionFont ) const 514 { 515 if( !maPhonPortions.empty() ) 516 return false; 517 if( maTextPortions.empty() ) 518 { 519 orString = OUString(); 520 return true; 521 } 522 if( (maTextPortions.size() == 1) && !maTextPortions.front()->hasFont() && !lclNeedsRichTextFormat( pFirstPortionFont ) ) 523 { 524 orString = maTextPortions.front()->getText(); 525 return orString.indexOf( '\x0A' ) < 0; 526 } 527 return false; 528 } 529 530 void RichString::convert( const Reference< XText >& rxText, bool bReplaceOld, const Font* pFirstPortionFont ) const 531 { 532 for( PortionVector::const_iterator aIt = maTextPortions.begin(), aEnd = maTextPortions.end(); aIt != aEnd; ++aIt ) 533 { 534 (*aIt)->convert( rxText, pFirstPortionFont, bReplaceOld ); 535 pFirstPortionFont = 0; // use passed font for first portion only 536 bReplaceOld = false; // do not replace first portion text with following portions 537 } 538 } 539 540 // private -------------------------------------------------------------------- 541 542 RichStringPortionRef RichString::createPortion() 543 { 544 RichStringPortionRef xPortion( new RichStringPortion( *this ) ); 545 maTextPortions.push_back( xPortion ); 546 return xPortion; 547 } 548 549 RichStringPhoneticRef RichString::createPhonetic() 550 { 551 RichStringPhoneticRef xPhonetic( new RichStringPhonetic( *this ) ); 552 maPhonPortions.push_back( xPhonetic ); 553 return xPhonetic; 554 } 555 556 void RichString::createTextPortions( const OString& rText, rtl_TextEncoding eTextEnc, FontPortionModelList& rPortions ) 557 { 558 maTextPortions.clear(); 559 sal_Int32 nStrLen = rText.getLength(); 560 if( nStrLen > 0 ) 561 { 562 // add leading and trailing string position to ease the following loop 563 if( rPortions.empty() || (rPortions.front().mnPos > 0) ) 564 rPortions.insert( rPortions.begin(), FontPortionModel( 0, -1 ) ); 565 if( rPortions.back().mnPos < nStrLen ) 566 rPortions.push_back( FontPortionModel( nStrLen, -1 ) ); 567 568 // create all string portions according to the font id vector 569 for( FontPortionModelList::const_iterator aIt = rPortions.begin(); aIt->mnPos < nStrLen; ++aIt ) 570 { 571 sal_Int32 nPortionLen = (aIt + 1)->mnPos - aIt->mnPos; 572 if( (0 < nPortionLen) && (aIt->mnPos + nPortionLen <= nStrLen) ) 573 { 574 // convert byte string to unicode string, using current font encoding 575 FontRef xFont = getStyles().getFont( aIt->mnFontId ); 576 rtl_TextEncoding eFontEnc = xFont.get() ? xFont->getFontEncoding() : eTextEnc; 577 OUString aUniStr = OStringToOUString( rText.copy( aIt->mnPos, nPortionLen ), eFontEnc ); 578 // create string portion 579 RichStringPortionRef xPortion = createPortion(); 580 xPortion->setText( aUniStr ); 581 xPortion->setFontId( aIt->mnFontId ); 582 } 583 } 584 } 585 } 586 587 void RichString::createTextPortions( const OUString& rText, FontPortionModelList& rPortions ) 588 { 589 maTextPortions.clear(); 590 sal_Int32 nStrLen = rText.getLength(); 591 if( nStrLen > 0 ) 592 { 593 // add leading and trailing string position to ease the following loop 594 if( rPortions.empty() || (rPortions.front().mnPos > 0) ) 595 rPortions.insert( rPortions.begin(), FontPortionModel( 0, -1 ) ); 596 if( rPortions.back().mnPos < nStrLen ) 597 rPortions.push_back( FontPortionModel( nStrLen, -1 ) ); 598 599 // create all string portions according to the font id vector 600 for( FontPortionModelList::const_iterator aIt = rPortions.begin(); aIt->mnPos < nStrLen; ++aIt ) 601 { 602 sal_Int32 nPortionLen = (aIt + 1)->mnPos - aIt->mnPos; 603 if( (0 < nPortionLen) && (aIt->mnPos + nPortionLen <= nStrLen) ) 604 { 605 RichStringPortionRef xPortion = createPortion(); 606 xPortion->setText( rText.copy( aIt->mnPos, nPortionLen ) ); 607 xPortion->setFontId( aIt->mnFontId ); 608 } 609 } 610 } 611 } 612 613 void RichString::createPhoneticPortions( const ::rtl::OUString& rText, PhoneticPortionModelList& rPortions, sal_Int32 nBaseLen ) 614 { 615 maPhonPortions.clear(); 616 sal_Int32 nStrLen = rText.getLength(); 617 if( nStrLen > 0 ) 618 { 619 // no portions - assign phonetic text to entire base text 620 if( rPortions.empty() ) 621 rPortions.push_back( PhoneticPortionModel( 0, 0, nBaseLen ) ); 622 // add trailing string position to ease the following loop 623 if( rPortions.back().mnPos < nStrLen ) 624 rPortions.push_back( PhoneticPortionModel( nStrLen, nBaseLen, 0 ) ); 625 626 // create all phonetic portions according to the portions vector 627 for( PhoneticPortionModelList::const_iterator aIt = rPortions.begin(); aIt->mnPos < nStrLen; ++aIt ) 628 { 629 sal_Int32 nPortionLen = (aIt + 1)->mnPos - aIt->mnPos; 630 if( (0 < nPortionLen) && (aIt->mnPos + nPortionLen <= nStrLen) ) 631 { 632 RichStringPhoneticRef xPhonetic = createPhonetic(); 633 xPhonetic->setText( rText.copy( aIt->mnPos, nPortionLen ) ); 634 xPhonetic->setBaseRange( aIt->mnBasePos, aIt->mnBasePos + aIt->mnBaseLen ); 635 } 636 } 637 } 638 } 639 640 // ============================================================================ 641 642 } // namespace xls 643 } // namespace oox 644