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 112 /* Some font attributes cannot be set to cell formattiing in Calc but 113 require to use rich formatting, e.g. font escapement. */ 114 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 true; 526 } 527 return false; 528 } 529 530 void RichString::convert( const Reference< XText >& rxText, const Font* pFirstPortionFont ) const 531 { 532 bool bReplace = true; 533 for( PortionVector::const_iterator aIt = maTextPortions.begin(), aEnd = maTextPortions.end(); aIt != aEnd; ++aIt ) 534 { 535 (*aIt)->convert( rxText, pFirstPortionFont, bReplace ); 536 pFirstPortionFont = 0; // use passed font for first portion only 537 bReplace = false; // do not replace first portion text with following portions 538 } 539 } 540 541 // private -------------------------------------------------------------------- 542 543 RichStringPortionRef RichString::createPortion() 544 { 545 RichStringPortionRef xPortion( new RichStringPortion( *this ) ); 546 maTextPortions.push_back( xPortion ); 547 return xPortion; 548 } 549 550 RichStringPhoneticRef RichString::createPhonetic() 551 { 552 RichStringPhoneticRef xPhonetic( new RichStringPhonetic( *this ) ); 553 maPhonPortions.push_back( xPhonetic ); 554 return xPhonetic; 555 } 556 557 void RichString::createTextPortions( const OString& rText, rtl_TextEncoding eTextEnc, FontPortionModelList& rPortions ) 558 { 559 maTextPortions.clear(); 560 sal_Int32 nStrLen = rText.getLength(); 561 if( nStrLen > 0 ) 562 { 563 // add leading and trailing string position to ease the following loop 564 if( rPortions.empty() || (rPortions.front().mnPos > 0) ) 565 rPortions.insert( rPortions.begin(), FontPortionModel( 0, -1 ) ); 566 if( rPortions.back().mnPos < nStrLen ) 567 rPortions.push_back( FontPortionModel( nStrLen, -1 ) ); 568 569 // create all string portions according to the font id vector 570 for( FontPortionModelList::const_iterator aIt = rPortions.begin(); aIt->mnPos < nStrLen; ++aIt ) 571 { 572 sal_Int32 nPortionLen = (aIt + 1)->mnPos - aIt->mnPos; 573 if( (0 < nPortionLen) && (aIt->mnPos + nPortionLen <= nStrLen) ) 574 { 575 // convert byte string to unicode string, using current font encoding 576 FontRef xFont = getStyles().getFont( aIt->mnFontId ); 577 rtl_TextEncoding eFontEnc = xFont.get() ? xFont->getFontEncoding() : eTextEnc; 578 OUString aUniStr = OStringToOUString( rText.copy( aIt->mnPos, nPortionLen ), eFontEnc ); 579 // create string portion 580 RichStringPortionRef xPortion = createPortion(); 581 xPortion->setText( aUniStr ); 582 xPortion->setFontId( aIt->mnFontId ); 583 } 584 } 585 } 586 } 587 588 void RichString::createTextPortions( const OUString& rText, FontPortionModelList& rPortions ) 589 { 590 maTextPortions.clear(); 591 sal_Int32 nStrLen = rText.getLength(); 592 if( nStrLen > 0 ) 593 { 594 // add leading and trailing string position to ease the following loop 595 if( rPortions.empty() || (rPortions.front().mnPos > 0) ) 596 rPortions.insert( rPortions.begin(), FontPortionModel( 0, -1 ) ); 597 if( rPortions.back().mnPos < nStrLen ) 598 rPortions.push_back( FontPortionModel( nStrLen, -1 ) ); 599 600 // create all string portions according to the font id vector 601 for( FontPortionModelList::const_iterator aIt = rPortions.begin(); aIt->mnPos < nStrLen; ++aIt ) 602 { 603 sal_Int32 nPortionLen = (aIt + 1)->mnPos - aIt->mnPos; 604 if( (0 < nPortionLen) && (aIt->mnPos + nPortionLen <= nStrLen) ) 605 { 606 RichStringPortionRef xPortion = createPortion(); 607 xPortion->setText( rText.copy( aIt->mnPos, nPortionLen ) ); 608 xPortion->setFontId( aIt->mnFontId ); 609 } 610 } 611 } 612 } 613 614 void RichString::createPhoneticPortions( const ::rtl::OUString& rText, PhoneticPortionModelList& rPortions, sal_Int32 nBaseLen ) 615 { 616 maPhonPortions.clear(); 617 sal_Int32 nStrLen = rText.getLength(); 618 if( nStrLen > 0 ) 619 { 620 // no portions - assign phonetic text to entire base text 621 if( rPortions.empty() ) 622 rPortions.push_back( PhoneticPortionModel( 0, 0, nBaseLen ) ); 623 // add trailing string position to ease the following loop 624 if( rPortions.back().mnPos < nStrLen ) 625 rPortions.push_back( PhoneticPortionModel( nStrLen, nBaseLen, 0 ) ); 626 627 // create all phonetic portions according to the portions vector 628 for( PhoneticPortionModelList::const_iterator aIt = rPortions.begin(); aIt->mnPos < nStrLen; ++aIt ) 629 { 630 sal_Int32 nPortionLen = (aIt + 1)->mnPos - aIt->mnPos; 631 if( (0 < nPortionLen) && (aIt->mnPos + nPortionLen <= nStrLen) ) 632 { 633 RichStringPhoneticRef xPhonetic = createPhonetic(); 634 xPhonetic->setText( rText.copy( aIt->mnPos, nPortionLen ) ); 635 xPhonetic->setBaseRange( aIt->mnBasePos, aIt->mnBasePos + aIt->mnBaseLen ); 636 } 637 } 638 } 639 } 640 641 // ============================================================================ 642 643 } // namespace xls 644 } // namespace oox 645