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
lclNeedsRichTextFormat(const Font * pFont)51 inline bool lclNeedsRichTextFormat( const Font* pFont )
52 {
53 return pFont && pFont->needsRichTextFormat();
54 }
55
56 } // namespace
57
58 // ============================================================================
59
RichStringPortion(const WorkbookHelper & rHelper)60 RichStringPortion::RichStringPortion( const WorkbookHelper& rHelper ) :
61 WorkbookHelper( rHelper ),
62 mnFontId( -1 )
63 {
64 }
65
setText(const OUString & rText)66 void RichStringPortion::setText( const OUString& rText )
67 {
68 maText = rText;
69 }
70
createFont()71 FontRef RichStringPortion::createFont()
72 {
73 mxFont.reset( new Font( *this, false ) );
74 return mxFont;
75 }
76
setFontId(sal_Int32 nFontId)77 void RichStringPortion::setFontId( sal_Int32 nFontId )
78 {
79 mnFontId = nFontId;
80 }
81
finalizeImport()82 void RichStringPortion::finalizeImport()
83 {
84 if( mxFont.get() )
85 mxFont->finalizeImport();
86 else if( mnFontId >= 0 )
87 mxFont = getStyles().getFont( mnFontId );
88 }
89
convert(const Reference<XText> & rxText,const Font * pFont,bool bReplace)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
read(SequenceInputStream & rStrm)120 void FontPortionModel::read( SequenceInputStream& rStrm )
121 {
122 mnPos = rStrm.readuInt16();
123 mnFontId = rStrm.readuInt16();
124 }
125
read(BiffInputStream & rStrm,BiffFontPortionMode eMode)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
appendPortion(const FontPortionModel & rPortion)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
importPortions(SequenceInputStream & rStrm)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
importPortions(BiffInputStream & rStrm,sal_uInt16 nCount,BiffFontPortionMode eMode)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
importPortions(BiffInputStream & rStrm,bool b16Bit)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
PhoneticDataModel()198 PhoneticDataModel::PhoneticDataModel() :
199 mnFontId( -1 ),
200 mnType( XML_fullwidthKatakana ),
201 mnAlignment( XML_left )
202 {
203 }
204
setBiffData(sal_Int32 nType,sal_Int32 nAlignment)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
PhoneticSettings(const WorkbookHelper & rHelper)216 PhoneticSettings::PhoneticSettings( const WorkbookHelper& rHelper ) :
217 WorkbookHelper( rHelper )
218 {
219 }
220
importPhoneticPr(const AttributeList & rAttribs)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
importPhoneticPr(SequenceInputStream & rStrm)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
importPhoneticPr(BiffInputStream & rStrm)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
importStringData(SequenceInputStream & rStrm)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
importStringData(BiffInputStream & rStrm)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
RichStringPhonetic(const WorkbookHelper & rHelper)264 RichStringPhonetic::RichStringPhonetic( const WorkbookHelper& rHelper ) :
265 WorkbookHelper( rHelper ),
266 mnBasePos( -1 ),
267 mnBaseEnd( -1 )
268 {
269 }
270
setText(const OUString & rText)271 void RichStringPhonetic::setText( const OUString& rText )
272 {
273 maText = rText;
274 }
275
importPhoneticRun(const AttributeList & rAttribs)276 void RichStringPhonetic::importPhoneticRun( const AttributeList& rAttribs )
277 {
278 mnBasePos = rAttribs.getInteger( XML_sb, -1 );
279 mnBaseEnd = rAttribs.getInteger( XML_eb, -1 );
280 }
281
setBaseRange(sal_Int32 nBasePos,sal_Int32 nBaseEnd)282 void RichStringPhonetic::setBaseRange( sal_Int32 nBasePos, sal_Int32 nBaseEnd )
283 {
284 mnBasePos = nBasePos;
285 mnBaseEnd = nBaseEnd;
286 }
287
288 // ----------------------------------------------------------------------------
289
read(SequenceInputStream & rStrm)290 void PhoneticPortionModel::read( SequenceInputStream& rStrm )
291 {
292 mnPos = rStrm.readuInt16();
293 mnBasePos = rStrm.readuInt16();
294 mnBaseLen = rStrm.readuInt16();
295 }
296
read(BiffInputStream & rStrm)297 void PhoneticPortionModel::read( BiffInputStream& rStrm )
298 {
299 mnPos = rStrm.readuInt16();
300 mnBasePos = rStrm.readuInt16();
301 mnBaseLen = rStrm.readuInt16();
302 }
303
304 // ----------------------------------------------------------------------------
305
appendPortion(const PhoneticPortionModel & rPortion)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
importPortions(SequenceInputStream & rStrm)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
importPortions(BiffInputStream & rStrm,sal_Int32 nPhoneticSize)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
RichString(const WorkbookHelper & rHelper)367 RichString::RichString( const WorkbookHelper& rHelper ) :
368 WorkbookHelper( rHelper ),
369 maPhonSettings( rHelper )
370 {
371 }
372
importText(const AttributeList &)373 RichStringPortionRef RichString::importText( const AttributeList& )
374 {
375 return createPortion();
376 }
377
importRun(const AttributeList &)378 RichStringPortionRef RichString::importRun( const AttributeList& )
379 {
380 return createPortion();
381 }
382
importPhoneticRun(const AttributeList & rAttribs)383 RichStringPhoneticRef RichString::importPhoneticRun( const AttributeList& rAttribs )
384 {
385 RichStringPhoneticRef xPhonetic = createPhonetic();
386 xPhonetic->importPhoneticRun( rAttribs );
387 return xPhonetic;
388 }
389
importPhoneticPr(const AttributeList & rAttribs)390 void RichString::importPhoneticPr( const AttributeList& rAttribs )
391 {
392 maPhonSettings.importPhoneticPr( rAttribs );
393 }
394
importString(SequenceInputStream & rStrm,bool bRich)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
importCharArray(BiffInputStream & rStrm,sal_uInt16 nChars,rtl_TextEncoding eTextEnc)421 void RichString::importCharArray( BiffInputStream& rStrm, sal_uInt16 nChars, rtl_TextEncoding eTextEnc )
422 {
423 createPortion()->setText( rStrm.readCharArrayUC( nChars, eTextEnc ) );
424 }
425
importByteString(BiffInputStream & rStrm,rtl_TextEncoding eTextEnc,BiffStringFlags nFlags)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
importUniString(BiffInputStream & rStrm,BiffStringFlags nFlags)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
finalizeImport()504 void RichString::finalizeImport()
505 {
506 maTextPortions.forEachMem( &RichStringPortion::finalizeImport );
507 }
508
extractPlainString(OUString & orString,const Font * pFirstPortionFont) const509 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
convert(const Reference<XText> & rxText,bool bReplaceOld,const Font * pFirstPortionFont) const526 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
createPortion()538 RichStringPortionRef RichString::createPortion()
539 {
540 RichStringPortionRef xPortion( new RichStringPortion( *this ) );
541 maTextPortions.push_back( xPortion );
542 return xPortion;
543 }
544
createPhonetic()545 RichStringPhoneticRef RichString::createPhonetic()
546 {
547 RichStringPhoneticRef xPhonetic( new RichStringPhonetic( *this ) );
548 maPhonPortions.push_back( xPhonetic );
549 return xPhonetic;
550 }
551
createTextPortions(const OString & rText,rtl_TextEncoding eTextEnc,FontPortionModelList & rPortions)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
createTextPortions(const OUString & rText,FontPortionModelList & rPortions)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
createPhoneticPortions(const::rtl::OUString & rText,PhoneticPortionModelList & rPortions,sal_Int32 nBaseLen)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