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