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 #include "oox/xls/richstring.hxx"
23
24 #include <com/sun/star/text/XText.hpp>
25 #include <rtl/ustrbuf.hxx>
26 #include "oox/helper/attributelist.hxx"
27 #include "oox/helper/propertyset.hxx"
28 #include "oox/xls/biffinputstream.hxx"
29
30 namespace oox {
31 namespace xls {
32
33 // ============================================================================
34
35 using namespace ::com::sun::star::text;
36 using namespace ::com::sun::star::uno;
37
38 using ::rtl::OString;
39 using ::rtl::OUString;
40 using ::rtl::OUStringBuffer;
41
42 // ============================================================================
43
44 namespace {
45
46 const sal_uInt8 BIFF12_STRINGFLAG_FONTS = 0x01;
47 const sal_uInt8 BIFF12_STRINGFLAG_PHONETICS = 0x02;
48
lclNeedsRichTextFormat(const Font * pFont)49 inline bool lclNeedsRichTextFormat( const Font* pFont )
50 {
51 return pFont && pFont->needsRichTextFormat();
52 }
53
54 } // namespace
55
56 // ============================================================================
57
RichStringPortion(const WorkbookHelper & rHelper)58 RichStringPortion::RichStringPortion( const WorkbookHelper& rHelper ) :
59 WorkbookHelper( rHelper ),
60 mnFontId( -1 ),
61 mbConverted( false )
62 {
63 }
64
setText(const OUString & rText)65 void RichStringPortion::setText( const OUString& rText )
66 {
67 maText = rText;
68 }
69
createFont()70 FontRef RichStringPortion::createFont()
71 {
72 mxFont.reset( new Font( *this, false ) );
73 return mxFont;
74 }
75
setFontId(sal_Int32 nFontId)76 void RichStringPortion::setFontId( sal_Int32 nFontId )
77 {
78 mnFontId = nFontId;
79 }
80
finalizeImport()81 void RichStringPortion::finalizeImport()
82 {
83 if( mxFont.get() )
84 mxFont->finalizeImport();
85 else if( mnFontId >= 0 )
86 mxFont = getStyles().getFont( mnFontId );
87 }
88
convert(const Reference<XText> & rxText,const Font * pFont,bool bReplace)89 void RichStringPortion::convert( const Reference< XText >& rxText, const Font* pFont, bool bReplace )
90 {
91 if ( mbConverted )
92 return;
93
94 Reference< XTextRange > xRange;
95 if( bReplace )
96 xRange.set( rxText, UNO_QUERY );
97 else
98 xRange = rxText->getEnd();
99 OSL_ENSURE( xRange.is(), "RichStringPortion::convert - cannot get text range interface" );
100
101 if( xRange.is() )
102 {
103 xRange->setString( maText );
104 if( mxFont.get() )
105 {
106 PropertySet aPropSet( xRange );
107 mxFont->writeToPropertySet( aPropSet, FONT_PROPTYPE_TEXT );
108 }
109 /* Some font attributes cannot be set to cell formatting in Calc but
110 require to use rich formatting, e.g. font escapement. But do not
111 use the passed font if this portion has its own font. */
112 else if( lclNeedsRichTextFormat( pFont ) )
113 {
114 PropertySet aPropSet( xRange );
115 pFont->writeToPropertySet( aPropSet, FONT_PROPTYPE_TEXT );
116 }
117 }
118
119 mbConverted = true;
120 }
121
122 // ----------------------------------------------------------------------------
123
read(SequenceInputStream & rStrm)124 void FontPortionModel::read( SequenceInputStream& rStrm )
125 {
126 mnPos = rStrm.readuInt16();
127 mnFontId = rStrm.readuInt16();
128 }
129
read(BiffInputStream & rStrm,BiffFontPortionMode eMode)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
appendPortion(const FontPortionModel & rPortion)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
importPortions(SequenceInputStream & rStrm)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
importPortions(BiffInputStream & rStrm,sal_uInt16 nCount,BiffFontPortionMode eMode)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
importPortions(BiffInputStream & rStrm,bool b16Bit)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
PhoneticDataModel()202 PhoneticDataModel::PhoneticDataModel() :
203 mnFontId( -1 ),
204 mnType( XML_fullwidthKatakana ),
205 mnAlignment( XML_left )
206 {
207 }
208
setBiffData(sal_Int32 nType,sal_Int32 nAlignment)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
PhoneticSettings(const WorkbookHelper & rHelper)220 PhoneticSettings::PhoneticSettings( const WorkbookHelper& rHelper ) :
221 WorkbookHelper( rHelper )
222 {
223 }
224
importPhoneticPr(const AttributeList & rAttribs)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
importPhoneticPr(SequenceInputStream & rStrm)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
importPhoneticPr(BiffInputStream & rStrm)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
importStringData(SequenceInputStream & rStrm)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
importStringData(BiffInputStream & rStrm)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
RichStringPhonetic(const WorkbookHelper & rHelper)268 RichStringPhonetic::RichStringPhonetic( const WorkbookHelper& rHelper ) :
269 WorkbookHelper( rHelper ),
270 mnBasePos( -1 ),
271 mnBaseEnd( -1 )
272 {
273 }
274
setText(const OUString & rText)275 void RichStringPhonetic::setText( const OUString& rText )
276 {
277 maText = rText;
278 }
279
importPhoneticRun(const AttributeList & rAttribs)280 void RichStringPhonetic::importPhoneticRun( const AttributeList& rAttribs )
281 {
282 mnBasePos = rAttribs.getInteger( XML_sb, -1 );
283 mnBaseEnd = rAttribs.getInteger( XML_eb, -1 );
284 }
285
setBaseRange(sal_Int32 nBasePos,sal_Int32 nBaseEnd)286 void RichStringPhonetic::setBaseRange( sal_Int32 nBasePos, sal_Int32 nBaseEnd )
287 {
288 mnBasePos = nBasePos;
289 mnBaseEnd = nBaseEnd;
290 }
291
292 // ----------------------------------------------------------------------------
293
read(SequenceInputStream & rStrm)294 void PhoneticPortionModel::read( SequenceInputStream& rStrm )
295 {
296 mnPos = rStrm.readuInt16();
297 mnBasePos = rStrm.readuInt16();
298 mnBaseLen = rStrm.readuInt16();
299 }
300
read(BiffInputStream & rStrm)301 void PhoneticPortionModel::read( BiffInputStream& rStrm )
302 {
303 mnPos = rStrm.readuInt16();
304 mnBasePos = rStrm.readuInt16();
305 mnBaseLen = rStrm.readuInt16();
306 }
307
308 // ----------------------------------------------------------------------------
309
appendPortion(const PhoneticPortionModel & rPortion)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
importPortions(SequenceInputStream & rStrm)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
importPortions(BiffInputStream & rStrm,sal_Int32 nPhoneticSize)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
RichString(const WorkbookHelper & rHelper)371 RichString::RichString( const WorkbookHelper& rHelper ) :
372 WorkbookHelper( rHelper ),
373 maPhonSettings( rHelper )
374 {
375 }
376
importText(const AttributeList &)377 RichStringPortionRef RichString::importText( const AttributeList& )
378 {
379 return createPortion();
380 }
381
importRun(const AttributeList &)382 RichStringPortionRef RichString::importRun( const AttributeList& )
383 {
384 return createPortion();
385 }
386
importPhoneticRun(const AttributeList & rAttribs)387 RichStringPhoneticRef RichString::importPhoneticRun( const AttributeList& rAttribs )
388 {
389 RichStringPhoneticRef xPhonetic = createPhonetic();
390 xPhonetic->importPhoneticRun( rAttribs );
391 return xPhonetic;
392 }
393
importPhoneticPr(const AttributeList & rAttribs)394 void RichString::importPhoneticPr( const AttributeList& rAttribs )
395 {
396 maPhonSettings.importPhoneticPr( rAttribs );
397 }
398
importString(SequenceInputStream & rStrm,bool bRich)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
importCharArray(BiffInputStream & rStrm,sal_uInt16 nChars,rtl_TextEncoding eTextEnc)425 void RichString::importCharArray( BiffInputStream& rStrm, sal_uInt16 nChars, rtl_TextEncoding eTextEnc )
426 {
427 createPortion()->setText( rStrm.readCharArrayUC( nChars, eTextEnc ) );
428 }
429
importByteString(BiffInputStream & rStrm,rtl_TextEncoding eTextEnc,BiffStringFlags nFlags)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
importUniString(BiffInputStream & rStrm,BiffStringFlags nFlags)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
finalizeImport()508 void RichString::finalizeImport()
509 {
510 maTextPortions.forEachMem( &RichStringPortion::finalizeImport );
511 }
512
extractPlainString(OUString & orString,const Font * pFirstPortionFont) const513 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
convert(const Reference<XText> & rxText,bool bReplaceOld,const Font * pFirstPortionFont) const530 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
createPortion()542 RichStringPortionRef RichString::createPortion()
543 {
544 RichStringPortionRef xPortion( new RichStringPortion( *this ) );
545 maTextPortions.push_back( xPortion );
546 return xPortion;
547 }
548
createPhonetic()549 RichStringPhoneticRef RichString::createPhonetic()
550 {
551 RichStringPhoneticRef xPhonetic( new RichStringPhonetic( *this ) );
552 maPhonPortions.push_back( xPhonetic );
553 return xPhonetic;
554 }
555
createTextPortions(const OString & rText,rtl_TextEncoding eTextEnc,FontPortionModelList & rPortions)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
createTextPortions(const OUString & rText,FontPortionModelList & rPortions)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
createPhoneticPortions(const::rtl::OUString & rText,PhoneticPortionModelList & rPortions,sal_Int32 nBaseLen)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