bump product version to 6.4.0.3
[LibreOffice.git] / sd / source / filter / eppt / pptx-text.cxx
blobf3b3393c32d87cbb0c9983db43ec2c82917e4d43
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include "text.hxx"
23 #include <com/sun/star/awt/CharSet.hpp>
24 #include <com/sun/star/awt/FontWeight.hpp>
25 #include <com/sun/star/awt/FontUnderline.hpp>
26 #include <com/sun/star/awt/XBitmap.hpp>
27 #include <com/sun/star/beans/XPropertyState.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/container/XEnumerationAccess.hpp>
30 #include <com/sun/star/container/XIndexReplace.hpp>
31 #include <com/sun/star/i18n/BreakIterator.hpp>
32 #include <com/sun/star/i18n/ScriptDirection.hpp>
33 #include <com/sun/star/i18n/ScriptType.hpp>
34 #include <com/sun/star/text/FontRelief.hpp>
35 #include <com/sun/star/text/XTextField.hpp>
36 #include <com/sun/star/text/XTextRange.hpp>
37 #include <com/sun/star/style/LineSpacing.hpp>
38 #include <com/sun/star/style/LineSpacingMode.hpp>
39 #include <com/sun/star/style/ParagraphAdjust.hpp>
40 #include <com/sun/star/style/TabStop.hpp>
41 #include <com/sun/star/graphic/XGraphic.hpp>
43 #include <comphelper/processfactory.hxx>
44 #include <editeng/svxenum.hxx>
45 #include <editeng/frmdir.hxx>
46 #include <filter/msfilter/util.hxx>
47 #include <i18nutil/scripttypedetector.hxx>
48 #include <o3tl/any.hxx>
49 #include <svl/languageoptions.hxx>
50 #include <osl/diagnose.h>
51 #include <i18nlangtag/languagetag.hxx>
53 #include <vcl/settings.hxx>
54 #include <vcl/metric.hxx>
55 #include <vcl/virdev.hxx>
56 #include <vcl/svapp.hxx>
58 using namespace css;
60 static css::uno::Reference< css::i18n::XBreakIterator > xPPTBreakIter;
62 PortionObj::PortionObj(const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
63 FontCollection& rFontCollection)
64 : meCharColor(css::beans::PropertyState_AMBIGUOUS_VALUE)
65 , meCharHeight(css::beans::PropertyState_AMBIGUOUS_VALUE)
66 , meFontName(css::beans::PropertyState_AMBIGUOUS_VALUE)
67 , meAsianOrComplexFont(css::beans::PropertyState_AMBIGUOUS_VALUE)
68 , meCharEscapement(css::beans::PropertyState_AMBIGUOUS_VALUE)
69 , mnCharAttrHard(0)
70 , mnCharAttr(0)
71 , mnFont(0)
72 , mnAsianOrComplexFont(0xffff)
73 , mnTextSize(0)
74 , mbLastPortion(true)
76 mXPropSet = rXPropSet;
78 ImplGetPortionValues( rFontCollection, false );
81 PortionObj::PortionObj(css::uno::Reference< css::text::XTextRange > & rXTextRange,
82 bool bLast, FontCollection& rFontCollection)
83 : meCharColor(css::beans::PropertyState_AMBIGUOUS_VALUE)
84 , meCharHeight(css::beans::PropertyState_AMBIGUOUS_VALUE)
85 , meFontName(css::beans::PropertyState_AMBIGUOUS_VALUE)
86 , meAsianOrComplexFont(css::beans::PropertyState_AMBIGUOUS_VALUE)
87 , meCharEscapement(css::beans::PropertyState_AMBIGUOUS_VALUE)
88 , mnCharAttrHard(0)
89 , mnCharColor(0)
90 , mnCharAttr(0)
91 , mnCharHeight(0)
92 , mnFont(0)
93 , mnAsianOrComplexFont(0xffff)
94 , mnCharEscapement(0)
95 , mbLastPortion(bLast)
97 OUString aString( rXTextRange->getString() );
98 OUString aURL;
100 mnTextSize = aString.getLength();
101 if ( bLast )
102 mnTextSize++;
104 if ( !mnTextSize )
105 return;
107 bool bRTL_endingParen = false;
108 mpFieldEntry = nullptr;
109 sal_uInt32 nFieldType = 0;
111 mXPropSet.set( rXTextRange, css::uno::UNO_QUERY );
112 mXPropState.set( rXTextRange, css::uno::UNO_QUERY );
114 bool bPropSetsValid = ( mXPropSet.is() && mXPropState.is() );
115 if ( bPropSetsValid )
116 nFieldType = ImplGetTextField( rXTextRange, mXPropSet, aURL );
117 if ( nFieldType )
119 mpFieldEntry.reset( new FieldEntry( nFieldType, 0, mnTextSize ) );
120 if ( nFieldType >> 28 == 4 )
122 mpFieldEntry->aRepresentation = aString;
123 mpFieldEntry->aFieldUrl = aURL;
126 bool bSymbol = false;
128 if ( bPropSetsValid && ImplGetPropertyValue( "CharFontCharSet", false ) )
130 sal_Int16 nCharset = 0;
131 mAny >>= nCharset;
132 if ( nCharset == css::awt::CharSet::SYMBOL )
133 bSymbol = true;
135 if ( mpFieldEntry && ( nFieldType & 0x800000 ) ) // placeholder ?
137 mnTextSize = 1;
138 if ( bLast )
139 mnTextSize++;
140 mpText.reset( new sal_uInt16[ mnTextSize ] );
141 mpText[ 0 ] = 0x2a;
143 else
145 // For i39516 - a closing parenthesis that ends an RTL string is displayed backwards by PPT
146 // Solution: add a Unicode Right-to-Left Mark, following the method described in i18024
147 if (bLast && !aString.isEmpty()
148 && aString[aString.getLength() - 1] == ')'
149 && FontCollection::GetScriptDirection(aString) == css::i18n::ScriptDirection::RIGHT_TO_LEFT)
151 mnTextSize++;
152 bRTL_endingParen = true;
154 mpText.reset( new sal_uInt16[ mnTextSize ] );
155 sal_uInt16 nChar;
156 for ( sal_Int32 i = 0; i < aString.getLength(); i++ )
158 nChar = static_cast<sal_uInt16>(aString[ i ]);
159 if ( nChar == 0xa )
160 nChar++;
161 else if ( !bSymbol )
163 switch ( nChar )
165 // Currency
166 case 128: nChar = 0x20AC; break;
167 // Punctuation and other
168 case 130: nChar = 0x201A; break;// SINGLE LOW-9 QUOTATION MARK
169 case 131: nChar = 0x0192; break;// LATIN SMALL LETTER F WITH HOOK
170 case 132: nChar = 0x201E; break;// DOUBLE LOW-9 QUOTATION MARK
171 // LOW DOUBLE PRIME QUOTATION MARK
172 case 133: nChar = 0x2026; break;// HORIZONTAL ELLIPSES
173 case 134: nChar = 0x2020; break;// DAGGER
174 case 135: nChar = 0x2021; break;// DOUBLE DAGGER
175 case 136: nChar = 0x02C6; break;// MODIFIER LETTER CIRCUMFLEX ACCENT
176 case 137: nChar = 0x2030; break;// PER MILLE SIGN
177 case 138: nChar = 0x0160; break;// LATIN CAPITAL LETTER S WITH CARON
178 case 139: nChar = 0x2039; break;// SINGLE LEFT-POINTING ANGLE QUOTATION MARK
179 case 140: nChar = 0x0152; break;// LATIN CAPITAL LIGATURE OE
180 case 142: nChar = 0x017D; break;// LATIN CAPITAL LETTER Z WITH CARON
181 case 145: nChar = 0x2018; break;// LEFT SINGLE QUOTATION MARK
182 // MODIFIER LETTER TURNED COMMA
183 case 146: nChar = 0x2019; break;// RIGHT SINGLE QUOTATION MARK
184 // MODIFIER LETTER APOSTROPHE
185 case 147: nChar = 0x201C; break;// LEFT DOUBLE QUOTATION MARK
186 // REVERSED DOUBLE PRIME QUOTATION MARK
187 case 148: nChar = 0x201D; break;// RIGHT DOUBLE QUOTATION MARK
188 // REVERSED DOUBLE PRIME QUOTATION MARK
189 case 149: nChar = 0x2022; break;// BULLET
190 case 150: nChar = 0x2013; break;// EN DASH
191 case 151: nChar = 0x2014; break;// EM DASH
192 case 152: nChar = 0x02DC; break;// SMALL TILDE
193 case 153: nChar = 0x2122; break;// TRADE MARK SIGN
194 case 154: nChar = 0x0161; break;// LATIN SMALL LETTER S WITH CARON
195 case 155: nChar = 0x203A; break;// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
196 case 156: nChar = 0x0153; break;// LATIN SMALL LIGATURE OE
197 case 158: nChar = 0x017E; break;// LATIN SMALL LETTER Z WITH CARON
198 case 159: nChar = 0x0178; break;// LATIN CAPITAL LETTER Y WITH DIAERESIS
201 mpText[ i ] = nChar;
204 if ( bRTL_endingParen )
205 mpText[ mnTextSize - 2 ] = 0x200F; // Unicode Right-to-Left mark
207 if ( bLast )
208 mpText[ mnTextSize - 1 ] = 0xd;
210 if ( bPropSetsValid )
211 ImplGetPortionValues( rFontCollection, true );
214 PortionObj::PortionObj( const PortionObj& rPortionObj )
215 : PropStateValue( rPortionObj )
217 ImplConstruct( rPortionObj );
220 PortionObj::~PortionObj()
222 ImplClear();
225 void PortionObj::Write( SvStream* pStrm, bool bLast )
227 sal_uInt32 nCount = mnTextSize;
228 if ( bLast && mbLastPortion )
229 nCount--;
230 for ( sal_uInt32 i = 0; i < nCount; i++ )
231 pStrm->WriteUInt16( mpText[ i ] );
234 void PortionObj::ImplGetPortionValues( FontCollection& rFontCollection, bool bGetPropStateValue )
237 bool bOk = ImplGetPropertyValue( "CharFontName", bGetPropStateValue );
238 meFontName = ePropState;
239 if ( bOk )
241 FontCollectionEntry aFontDesc( *o3tl::doAccess<OUString>(mAny) );
242 sal_uInt32 nCount = rFontCollection.GetCount();
243 mnFont = static_cast<sal_uInt16>(rFontCollection.GetId( aFontDesc ));
244 if ( mnFont == nCount )
246 FontCollectionEntry& rFontDesc = rFontCollection.GetLast();
247 if ( ImplGetPropertyValue( "CharFontCharSet", false ) )
248 mAny >>= rFontDesc.CharSet;
249 if ( ImplGetPropertyValue( "CharFontFamily", false ) )
250 mAny >>= rFontDesc.Family;
251 if ( ImplGetPropertyValue( "CharFontPitch", false ) )
252 mAny >>= rFontDesc.Pitch;
256 sal_Int16 nScriptType = SvtLanguageOptions::FromSvtScriptTypeToI18N( SvtLanguageOptions::GetScriptTypeOfLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ) );
257 if ( mpText && mnTextSize && xPPTBreakIter.is() )
259 OUString sT( reinterpret_cast<sal_Unicode *>(mpText.get()), mnTextSize );
260 nScriptType = xPPTBreakIter->getScriptType( sT, 0 );
262 if ( nScriptType != css::i18n::ScriptType::COMPLEX )
264 bOk = ImplGetPropertyValue( "CharFontNameAsian", bGetPropStateValue );
265 meAsianOrComplexFont = ePropState;
266 if ( bOk )
268 FontCollectionEntry aFontDesc( *o3tl::doAccess<OUString>(mAny) );
269 sal_uInt32 nCount = rFontCollection.GetCount();
270 mnAsianOrComplexFont = static_cast<sal_uInt16>(rFontCollection.GetId( aFontDesc ));
271 if ( mnAsianOrComplexFont == nCount )
273 FontCollectionEntry& rFontDesc = rFontCollection.GetLast();
274 if ( ImplGetPropertyValue( "CharFontCharSetAsian", false ) )
275 mAny >>= rFontDesc.CharSet;
276 if ( ImplGetPropertyValue( "CharFontFamilyAsian", false ) )
277 mAny >>= rFontDesc.Family;
278 if ( ImplGetPropertyValue( "CharFontPitchAsian", false ) )
279 mAny >>= rFontDesc.Pitch;
283 else
285 bOk = ImplGetPropertyValue( "CharFontNameComplex", bGetPropStateValue );
286 meAsianOrComplexFont = ePropState;
287 if ( bOk )
289 FontCollectionEntry aFontDesc( *o3tl::doAccess<OUString>(mAny) );
290 sal_uInt32 nCount = rFontCollection.GetCount();
291 mnAsianOrComplexFont = static_cast<sal_uInt16>(rFontCollection.GetId( aFontDesc ));
292 if ( mnAsianOrComplexFont == nCount )
294 FontCollectionEntry& rFontDesc = rFontCollection.GetLast();
295 if ( ImplGetPropertyValue( "CharFontCharSetComplex", false ) )
296 mAny >>= rFontDesc.CharSet;
297 if ( ImplGetPropertyValue( "CharFontFamilyComplex", false ) )
298 mAny >>= rFontDesc.Family;
299 if ( ImplGetPropertyValue( "CharFontPitchComplex", false ) )
300 mAny >>= rFontDesc.Pitch;
305 OUString aCharHeightName, aCharWeightName, aCharLocaleName, aCharPostureName;
306 switch( nScriptType )
308 case css::i18n::ScriptType::ASIAN :
310 aCharHeightName = "CharHeightAsian";
311 aCharWeightName = "CharWeightAsian";
312 aCharLocaleName = "CharLocaleAsian";
313 aCharPostureName = "CharPostureAsian";
314 break;
316 case css::i18n::ScriptType::COMPLEX :
318 aCharHeightName = "CharHeightComplex";
319 aCharWeightName = "CharWeightComplex";
320 aCharLocaleName = "CharLocaleComplex";
321 aCharPostureName = "CharPostureComplex";
322 break;
324 default:
326 aCharHeightName = "CharHeight";
327 aCharWeightName = "CharWeight";
328 aCharLocaleName = "CharLocale";
329 aCharPostureName = "CharPosture";
330 break;
334 mnCharHeight = 24;
335 if ( GetPropertyValue( mAny, mXPropSet, aCharHeightName ) )
337 float fVal(0.0);
338 if ( mAny >>= fVal )
340 mnCharHeight = static_cast<sal_uInt16>( fVal + 0.5 );
341 meCharHeight = GetPropertyState( mXPropSet, aCharHeightName );
344 if ( GetPropertyValue( mAny, mXPropSet, aCharWeightName ) )
346 float fFloat(0.0);
347 if ( mAny >>= fFloat )
349 if ( fFloat >= css::awt::FontWeight::SEMIBOLD )
350 mnCharAttr |= 1;
351 if ( GetPropertyState( mXPropSet, aCharWeightName ) == css::beans::PropertyState_DIRECT_VALUE )
352 mnCharAttrHard |= 1;
355 if ( GetPropertyValue( mAny, mXPropSet, aCharLocaleName ) )
357 css::lang::Locale eLocale;
358 if ( mAny >>= eLocale )
359 meCharLocale = eLocale;
361 if ( GetPropertyValue( mAny, mXPropSet, aCharPostureName ) )
363 css::awt::FontSlant aFS;
364 if ( mAny >>= aFS )
366 switch( aFS )
368 case css::awt::FontSlant_OBLIQUE :
369 case css::awt::FontSlant_ITALIC :
370 mnCharAttr |= 2;
371 break;
372 default:
373 break;
375 if ( GetPropertyState( mXPropSet, aCharPostureName ) == css::beans::PropertyState_DIRECT_VALUE )
376 mnCharAttrHard |= 2;
380 if ( ImplGetPropertyValue( "CharUnderline", bGetPropStateValue ) )
382 sal_Int16 nVal(0);
383 mAny >>= nVal;
384 switch ( nVal )
386 case css::awt::FontUnderline::SINGLE :
387 case css::awt::FontUnderline::DOUBLE :
388 case css::awt::FontUnderline::DOTTED :
389 mnCharAttr |= 4;
392 if ( ePropState == css::beans::PropertyState_DIRECT_VALUE )
393 mnCharAttrHard |= 4;
395 if ( ImplGetPropertyValue( "CharShadowed", bGetPropStateValue ) )
397 bool bBool(false);
398 mAny >>= bBool;
399 if ( bBool )
400 mnCharAttr |= 0x10;
402 if ( ePropState == css::beans::PropertyState_DIRECT_VALUE )
403 mnCharAttrHard |= 16;
405 if ( ImplGetPropertyValue( "CharRelief", bGetPropStateValue ) )
407 sal_Int16 nVal(0);
408 mAny >>= nVal;
409 if ( nVal != css::text::FontRelief::NONE )
410 mnCharAttr |= 512;
412 if ( ePropState == css::beans::PropertyState_DIRECT_VALUE )
413 mnCharAttrHard |= 512;
415 if ( ImplGetPropertyValue( "CharColor", bGetPropStateValue ) )
417 sal_uInt32 nSOColor = *( o3tl::doAccess<sal_uInt32>(mAny) );
418 mnCharColor = nSOColor & 0xff00ff00; // green and hibyte
419 mnCharColor |= static_cast<sal_uInt8>(nSOColor) << 16; // red and blue is switched
420 mnCharColor |= static_cast<sal_uInt8>( nSOColor >> 16 );
422 meCharColor = ePropState;
424 mnCharEscapement = 0;
425 if ( ImplGetPropertyValue( "CharEscapement", bGetPropStateValue ) )
427 mAny >>= mnCharEscapement;
428 if ( mnCharEscapement > 100 )
429 mnCharEscapement = 33;
430 else if ( mnCharEscapement < -100 )
431 mnCharEscapement = -33;
433 meCharEscapement = ePropState;
436 void PortionObj::ImplClear()
438 mpFieldEntry.reset();
439 mpText.reset();
442 void PortionObj::ImplConstruct( const PortionObj& rPortionObj )
444 meCharColor = rPortionObj.meCharColor;
445 meCharHeight = rPortionObj.meCharHeight;
446 meFontName = rPortionObj.meFontName;
447 meAsianOrComplexFont = rPortionObj.meAsianOrComplexFont;
448 meCharEscapement = rPortionObj.meCharEscapement;
449 meCharLocale = rPortionObj.meCharLocale;
450 mnCharAttrHard = rPortionObj.mnCharAttrHard;
452 mbLastPortion = rPortionObj.mbLastPortion;
453 mnTextSize = rPortionObj.mnTextSize;
454 mnCharColor = rPortionObj.mnCharColor;
455 mnCharEscapement = rPortionObj.mnCharEscapement;
456 mnCharAttr = rPortionObj.mnCharAttr;
457 mnCharHeight = rPortionObj.mnCharHeight;
458 mnFont = rPortionObj.mnFont;
459 mnAsianOrComplexFont = rPortionObj.mnAsianOrComplexFont;
461 if ( rPortionObj.mpText )
463 mpText.reset( new sal_uInt16[ mnTextSize ] );
464 memcpy( mpText.get(), rPortionObj.mpText.get(), mnTextSize << 1 );
467 if ( rPortionObj.mpFieldEntry )
468 mpFieldEntry.reset( new FieldEntry( *( rPortionObj.mpFieldEntry ) ) );
471 sal_uInt32 PortionObj::ImplCalculateTextPositions( sal_uInt32 nCurrentTextPosition )
473 if ( mpFieldEntry && ( !mpFieldEntry->nFieldStartPos ) )
475 mpFieldEntry->nFieldStartPos += nCurrentTextPosition;
476 mpFieldEntry->nFieldEndPos += nCurrentTextPosition;
478 return mnTextSize;
481 // Return: 0 = no TextField
482 // bit28->31 text field type :
483 // 1 = Date
484 // 2 = Time
485 // 3 = SlideNumber
486 // 4 = Url
487 // 5 = DateTime
488 // 6 = header
489 // 7 = footer
490 // bit24->27 text field sub type (optional)
491 // 23-> PPT Textfield needs a placeholder
493 sal_uInt32 PortionObj::ImplGetTextField( css::uno::Reference< css::text::XTextRange > & ,
494 const css::uno::Reference< css::beans::XPropertySet > & rXPropSet, OUString& rURL )
496 sal_uInt32 nRetValue = 0;
497 sal_Int32 nFormat;
498 css::uno::Any aAny;
499 if ( GetPropertyValue( aAny, rXPropSet, "TextPortionType", true ) )
501 auto aTextFieldType = o3tl::doAccess<OUString>(aAny);
502 if ( *aTextFieldType == "TextField" )
504 if ( GetPropertyValue( aAny, rXPropSet, *aTextFieldType, true ) )
506 css::uno::Reference< css::text::XTextField > aXTextField;
507 if ( aAny >>= aXTextField )
509 if ( aXTextField.is() )
511 css::uno::Reference< css::beans::XPropertySet > xFieldPropSet( aXTextField, css::uno::UNO_QUERY );
512 if ( xFieldPropSet.is() )
514 OUString aFieldKind( aXTextField->getPresentation( true ) );
515 if ( aFieldKind == "Date" )
517 if ( GetPropertyValue( aAny, xFieldPropSet, "IsFix", true ) )
519 bool bBool = false;
520 aAny >>= bBool;
521 if ( !bBool ) // Fixed DateFields does not exist in PPT
523 if ( GetPropertyValue( aAny, xFieldPropSet, "Format", true ) )
525 nFormat = *o3tl::doAccess<sal_Int32>(aAny);
526 switch ( nFormat )
528 default:
529 case 5 :
530 case 4 :
531 case 2 : nFormat = 0; break;
532 case 8 :
533 case 9 :
534 case 3 : nFormat = 1; break;
535 case 7 :
536 case 6 : nFormat = 2; break;
538 nRetValue |= ( ( ( 1 << 4 ) | nFormat ) << 24 ) | 0x800000;
543 else if ( aFieldKind == "URL" )
545 if ( GetPropertyValue( aAny, xFieldPropSet, "URL", true ) )
546 rURL = *o3tl::doAccess<OUString>(aAny);
547 nRetValue = 4 << 28;
549 else if ( aFieldKind == "Page" )
551 nRetValue = 3 << 28 | 0x800000;
553 else if ( aFieldKind == "Pages" )
557 else if ( aFieldKind == "Time" )
559 if ( GetPropertyValue( aAny, xFieldPropSet, "IsFix", true ) )
561 bool bBool = false;
562 aAny >>= bBool;
563 if ( !bBool )
565 if ( GetPropertyValue( aAny, xFieldPropSet, "IsFix", true ) )
567 nFormat = *o3tl::doAccess<sal_Int32>(aAny);
568 nRetValue |= ( ( ( 2 << 4 ) | nFormat ) << 24 ) | 0x800000;
573 else if ( aFieldKind == "File" )
577 else if ( aFieldKind == "Table" )
581 else if ( aFieldKind == "ExtTime" )
583 if ( GetPropertyValue( aAny, xFieldPropSet, "IsFix", true ) )
585 bool bBool = false;
586 aAny >>= bBool;
587 if ( !bBool )
589 if ( GetPropertyValue( aAny, xFieldPropSet, "Format", true ) )
591 nFormat = *o3tl::doAccess<sal_Int32>(aAny);
592 switch ( nFormat )
594 default:
595 case 6 :
596 case 7 :
597 case 8 :
598 case 2 : nFormat = 12; break;
599 case 3 : nFormat = 9; break;
600 case 5 :
601 case 4 : nFormat = 10; break;
604 nRetValue |= ( ( ( 2 << 4 ) | nFormat ) << 24 ) | 0x800000;
609 else if ( aFieldKind == "ExtFile" )
613 else if ( aFieldKind == "Author" )
617 else if ( aFieldKind == "DateTime" )
619 nRetValue = 5 << 28 | 0x800000;
621 else if ( aFieldKind == "Header" )
623 nRetValue = 6 << 28 | 0x800000;
625 else if ( aFieldKind == "Footer" )
627 nRetValue = 7 << 28 | 0x800000;
635 return nRetValue;
638 PortionObj& PortionObj::operator=( const PortionObj& rPortionObj )
640 if ( this != &rPortionObj )
642 ImplClear();
643 ImplConstruct( rPortionObj );
645 return *this;
648 ParagraphObj::ParagraphObj(const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
649 PPTExBulletProvider* pProv)
650 : PropStateValue()
651 , SOParagraph()
652 , mvPortions()
653 , mnTextSize(0)
654 , mbFirstParagraph(false)
655 , mbLastParagraph(false)
656 , mnTextAdjust(0)
657 , mnLineSpacing(0)
658 , mbFixedLineSpacing(false)
659 , mnLineSpacingTop(0)
660 , mnLineSpacingBottom(0)
661 , mbForbiddenRules(false)
662 , mbParagraphPunctation(false)
663 , mnBiDi(0)
665 mXPropSet = rXPropSet;
667 bExtendedParameters = false;
669 nDepth = 0;
670 nBulletFlags = 0;
671 nParaFlags = 0;
673 ImplGetParagraphValues( pProv, false );
676 ParagraphObj::ParagraphObj(css::uno::Reference< css::text::XTextContent > const & rXTextContent,
677 ParaFlags aParaFlags, FontCollection& rFontCollection, PPTExBulletProvider& rProv )
678 : PropStateValue()
679 , SOParagraph()
680 , mvPortions()
681 , mnTextSize(0)
682 , mbIsBullet(false)
683 , mbFirstParagraph( aParaFlags.bFirstParagraph )
684 , mbLastParagraph( aParaFlags.bLastParagraph )
685 , meBullet(css::beans::PropertyState_AMBIGUOUS_VALUE)
686 , meTextAdjust(css::beans::PropertyState_AMBIGUOUS_VALUE)
687 , meLineSpacing(css::beans::PropertyState_AMBIGUOUS_VALUE)
688 , meLineSpacingTop(css::beans::PropertyState_AMBIGUOUS_VALUE)
689 , meLineSpacingBottom(css::beans::PropertyState_AMBIGUOUS_VALUE)
690 , meForbiddenRules(css::beans::PropertyState_AMBIGUOUS_VALUE)
691 , meParagraphPunctation(css::beans::PropertyState_AMBIGUOUS_VALUE)
692 , meBiDi(css::beans::PropertyState_AMBIGUOUS_VALUE)
693 , mnTextAdjust(0)
694 , mnLineSpacing(0)
695 , mbFixedLineSpacing(false)
696 , mnLineSpacingTop(0)
697 , mnLineSpacingBottom(0)
698 , mbForbiddenRules(false)
699 , mbParagraphPunctation(false)
700 , mnBiDi(0)
702 bExtendedParameters = false;
704 nDepth = 0;
705 nBulletFlags = 0;
706 nParaFlags = 0;
708 mXPropSet.set( rXTextContent, css::uno::UNO_QUERY );
710 mXPropState.set( rXTextContent, css::uno::UNO_QUERY );
712 if ( !(mXPropSet.is() && mXPropState.is()) )
713 return;
715 css::uno::Reference< css::container::XEnumerationAccess > aXTextPortionEA( rXTextContent, css::uno::UNO_QUERY );
716 if ( aXTextPortionEA.is() )
718 css::uno::Reference< css::container::XEnumeration > aXTextPortionE( aXTextPortionEA->createEnumeration() );
719 if ( aXTextPortionE.is() )
721 while ( aXTextPortionE->hasMoreElements() )
723 css::uno::Reference< css::text::XTextRange > aXCursorText;
724 css::uno::Any aAny( aXTextPortionE->nextElement() );
725 if ( aAny >>= aXCursorText )
727 std::unique_ptr<PortionObj> pPortionObj(new PortionObj( aXCursorText, !aXTextPortionE->hasMoreElements(), rFontCollection ));
728 if ( pPortionObj->Count() )
729 mvPortions.push_back( std::move(pPortionObj) );
734 ImplGetParagraphValues( &rProv, true );
737 ParagraphObj::~ParagraphObj()
739 ImplClear();
742 void ParagraphObj::Write( SvStream* pStrm )
744 for ( std::vector<std::unique_ptr<PortionObj> >::iterator it = mvPortions.begin(); it != mvPortions.end(); ++it )
745 (*it)->Write( pStrm, mbLastParagraph );
748 void ParagraphObj::ImplClear()
750 mvPortions.clear();
753 void ParagraphObj::CalculateGraphicBulletSize( sal_uInt16 nFontHeight )
755 if ( !(( nNumberingType == SVX_NUM_BITMAP ) && ( nBulletId != 0xffff )) )
756 return;
758 // calculate the bullet real size for this graphic
759 if ( aBuGraSize.Width() && aBuGraSize.Height() )
761 double fCharHeight = nFontHeight;
762 double fLen = aBuGraSize.Height();
763 fCharHeight = fCharHeight * 0.2540;
764 double fQuo = fLen / fCharHeight;
765 nBulletRealSize = static_cast<sal_Int16>( fQuo + 0.5 );
766 if ( static_cast<sal_uInt16>(nBulletRealSize) > 400 )
767 nBulletRealSize = 400;
771 void ParagraphObj::ImplGetNumberingLevel( PPTExBulletProvider* pBuProv, sal_Int16 nNumberingDepth, bool bIsBullet, bool bGetPropStateValue )
773 css::uno::Any aAny;
774 if ( GetPropertyValue( aAny, mXPropSet, "ParaLeftMargin" ) )
776 sal_Int32 nVal(0);
777 if ( aAny >>= nVal )
778 nTextOfs = static_cast< sal_Int16 >( nVal / ( 2540.0 / 576 ) + 0.5 ) ;
780 if ( GetPropertyValue( aAny, mXPropSet, "ParaFirstLineIndent" ) )
782 if ( aAny >>= nBulletOfs )
783 nBulletOfs = static_cast< sal_Int32 >( nBulletOfs / ( 2540.0 / 576 ) + 0.5 );
785 if ( GetPropertyValue( aAny, mXPropSet, "NumberingIsNumber" ) )
786 aAny >>= bNumberingIsNumber;
788 css::uno::Reference< css::container::XIndexReplace > aXIndexReplace;
790 if ( bIsBullet && ImplGetPropertyValue( "NumberingRules", bGetPropStateValue ) )
792 if ( ( mAny >>= aXIndexReplace ) && nNumberingDepth < aXIndexReplace->getCount() )
794 mAny = aXIndexReplace->getByIndex( nNumberingDepth );
795 auto aPropertySequence = o3tl::doAccess<css::uno::Sequence<css::beans::PropertyValue>>(mAny);
797 if ( aPropertySequence->hasElements() )
799 bExtendedParameters = true;
800 nBulletRealSize = 100;
801 nMappedNumType = 0;
803 uno::Reference<graphic::XGraphic> xGraphic;
804 for ( const css::beans::PropertyValue& rPropValue : *aPropertySequence )
806 OUString aPropName( rPropValue.Name );
807 if ( aPropName == "NumberingType" )
808 nNumberingType = static_cast<SvxNumType>(*o3tl::doAccess<sal_Int16>(rPropValue.Value));
809 else if ( aPropName == "Adjust" )
810 nHorzAdjust = *o3tl::doAccess<sal_Int16>(rPropValue.Value);
811 else if ( aPropName == "BulletChar" )
813 OUString aString( *o3tl::doAccess<OUString>(rPropValue.Value) );
814 if ( !aString.isEmpty() )
815 cBulletId = aString[ 0 ];
817 else if ( aPropName == "BulletFont" )
819 aFontDesc = *o3tl::doAccess<css::awt::FontDescriptor>(rPropValue.Value);
821 // Our numbullet dialog has set the wrong textencoding for our "StarSymbol" font,
822 // instead of a Unicode encoding the encoding RTL_TEXTENCODING_SYMBOL was used.
823 // Because there might exist a lot of damaged documemts I added this two lines
824 // which fixes the bullet problem for the export.
825 if ( aFontDesc.Name.equalsIgnoreAsciiCase("StarSymbol") )
826 aFontDesc.CharSet = RTL_TEXTENCODING_MS_1252;
829 else if ( aPropName == "GraphicBitmap" )
831 auto xBitmap = rPropValue.Value.get<uno::Reference<awt::XBitmap>>();
832 xGraphic.set(xBitmap, uno::UNO_QUERY);
834 else if ( aPropName == "GraphicSize" )
836 if (auto aSize = o3tl::tryAccess<css::awt::Size>(rPropValue.Value))
838 // don't cast awt::Size to Size as on 64-bits they are not the same.
839 aBuGraSize.setWidth( aSize->Width );
840 aBuGraSize.setHeight( aSize->Height );
843 else if ( aPropName == "StartWith" )
844 nStartWith = *o3tl::doAccess<sal_Int16>(rPropValue.Value);
845 else if ( aPropName == "LeftMargin" )
846 nTextOfs = nTextOfs + static_cast< sal_Int16 >( *o3tl::doAccess<sal_Int32>(rPropValue.Value) / ( 2540.0 / 576 ) );
847 else if ( aPropName == "FirstLineOffset" )
848 nBulletOfs += static_cast<sal_Int16>( *o3tl::doAccess<sal_Int32>(rPropValue.Value) / ( 2540.0 / 576 ) );
849 else if ( aPropName == "BulletColor" )
851 sal_uInt32 nSOColor = *o3tl::doAccess<sal_uInt32>(rPropValue.Value);
852 nBulletColor = nSOColor & 0xff00ff00; // green and hibyte
853 nBulletColor |= static_cast<sal_uInt8>(nSOColor) << 16; // red
854 nBulletColor |= static_cast<sal_uInt8>( nSOColor >> 16 ) | 0xfe000000; // blue
856 else if ( aPropName == "BulletRelSize" )
858 nBulletRealSize = *o3tl::doAccess<sal_Int16>(rPropValue.Value);
859 nParaFlags |= 0x40;
860 nBulletFlags |= 8;
862 else if ( aPropName == "Prefix" )
863 sPrefix = *o3tl::doAccess<OUString>(rPropValue.Value);
864 else if ( aPropName == "Suffix" )
865 sSuffix = *o3tl::doAccess<OUString>(rPropValue.Value);
866 #ifdef DBG_UTIL
867 else if ( ! (
868 ( aPropName == "SymbolTextDistance" )
869 || ( aPropName == "GraphicBitmap" ) ) )
871 OSL_FAIL( "Unknown Property" );
873 #endif
876 if (xGraphic.is())
878 if ( aBuGraSize.Width() && aBuGraSize.Height() )
880 Graphic aGraphic(xGraphic);
881 nBulletId = pBuProv->GetId(xGraphic, aBuGraSize );
882 if ( nBulletId != 0xffff )
883 bExtendedBulletsUsed = true;
885 else
887 nNumberingType = SVX_NUM_NUMBER_NONE;
891 CalculateGraphicBulletSize( ( mvPortions.empty() ) ? 24 : mvPortions.front()->mnCharHeight );
893 switch( nNumberingType )
895 case SVX_NUM_NUMBER_NONE : nParaFlags |= 0xf; break;
897 case SVX_NUM_CHAR_SPECIAL : // Bullet
899 if ( IsStarSymbol(aFontDesc.Name) )
901 rtl_TextEncoding eChrSet = aFontDesc.CharSet;
902 cBulletId = msfilter::util::bestFitOpenSymbolToMSFont(cBulletId, eChrSet, aFontDesc.Name);
903 aFontDesc.CharSet = eChrSet;
906 if ( !aFontDesc.Name.isEmpty() )
908 nParaFlags |= 0x90; // we define the font and charset
911 [[fallthrough]];
913 case SVX_NUM_CHARS_UPPER_LETTER : // count from a-z, aa - az, ba - bz, ...
914 case SVX_NUM_CHARS_LOWER_LETTER :
915 case SVX_NUM_ROMAN_UPPER :
916 case SVX_NUM_ROMAN_LOWER :
917 case SVX_NUM_ARABIC :
918 case SVX_NUM_PAGEDESC : // numbering from the page template
919 case SVX_NUM_BITMAP :
920 case SVX_NUM_CHARS_UPPER_LETTER_N : // count from a-z, aa-zz, aaa-zzz
921 case SVX_NUM_CHARS_LOWER_LETTER_N :
922 case SVX_NUM_NUMBER_UPPER_ZH:
923 case SVX_NUM_CIRCLE_NUMBER:
924 case SVX_NUM_NUMBER_UPPER_ZH_TW:
925 case SVX_NUM_NUMBER_LOWER_ZH:
926 case SVX_NUM_FULL_WIDTH_ARABIC:
928 if ( nNumberingType != SVX_NUM_CHAR_SPECIAL )
930 bExtendedBulletsUsed = true;
931 if ( nNumberingDepth & 1 )
932 cBulletId = 0x2013; // defaulting bullet characters for ppt97
933 else if ( nNumberingDepth == 4 )
934 cBulletId = 0xbb;
935 else
936 cBulletId = 0x2022;
938 switch( nNumberingType )
940 case SVX_NUM_CHARS_UPPER_LETTER :
941 case SVX_NUM_CHARS_UPPER_LETTER_N :
943 if ( sSuffix == ")" )
945 if ( sPrefix == "(" )
946 nMappedNumType = 0xa0001; // (A)
947 else
948 nMappedNumType = 0xb0001; // A)
950 else
951 nMappedNumType = 0x10001; // A.
953 break;
954 case SVX_NUM_CHARS_LOWER_LETTER :
955 case SVX_NUM_CHARS_LOWER_LETTER_N :
957 if ( sSuffix == ")" )
959 if ( sPrefix == "(" )
960 nMappedNumType = 0x80001; // (a)
961 else
962 nMappedNumType = 0x90001; // a)
964 else
965 nMappedNumType = 0x00001; // a.
967 break;
968 case SVX_NUM_ROMAN_UPPER :
970 if ( sSuffix == ")" )
972 if ( sPrefix == "(" )
973 nMappedNumType = 0xe0001; // (I)
974 else
975 nMappedNumType = 0xf0001; // I)
977 else
978 nMappedNumType = 0x70001; // I.
980 break;
981 case SVX_NUM_ROMAN_LOWER :
983 if ( sSuffix == ")" )
985 if ( sPrefix == "(" )
986 nMappedNumType = 0x40001; // (i)
987 else
988 nMappedNumType = 0x50001; // i)
990 else
991 nMappedNumType = 0x60001; // i.
993 break;
994 case SVX_NUM_ARABIC :
996 if ( sSuffix == ")" )
998 if ( sPrefix == "(" )
999 nMappedNumType = 0xc0001; // (1)
1000 else
1001 nMappedNumType = 0x20001; // 1)
1003 else
1005 if ( sSuffix.isEmpty() && sPrefix.isEmpty() )
1006 nMappedNumType = 0xd0001; // 1
1007 else
1008 nMappedNumType = 0x30001; // 1.
1011 break;
1012 case SVX_NUM_NUMBER_UPPER_ZH :
1014 if ( !sSuffix.isEmpty() )
1015 nMappedNumType = 0x110001; // Simplified Chinese with single-byte period.
1016 else
1017 nMappedNumType = 0x100001; // Simplified Chinese.
1019 break;
1020 case SVX_NUM_CIRCLE_NUMBER :
1022 nMappedNumType = 0x120001; // Double byte circle numbers.
1024 break;
1025 case SVX_NUM_NUMBER_UPPER_ZH_TW :
1027 if ( !sSuffix.isEmpty() )
1028 nMappedNumType = 0x160001; // Traditional Chinese with single-byte period.
1029 else
1030 nMappedNumType = 0x150001; // Traditional Chinese.
1032 break;
1033 case SVX_NUM_NUMBER_LOWER_ZH :
1035 if ( sSuffix == u"\uff0e" )
1036 nMappedNumType = 0x260001; // Japanese with double-byte period.
1037 else if ( !sSuffix.isEmpty() )
1038 nMappedNumType = 0x1B0001; // Japanese/Korean with single-byte period.
1039 else
1040 nMappedNumType = 0x1A0001; // Japanese/Korean.
1042 break;
1043 case SVX_NUM_FULL_WIDTH_ARABIC :
1045 if ( !sSuffix.isEmpty() )
1046 nMappedNumType = 0x1D0001; // Double-byte Arabic numbers with double-byte period.
1047 else
1048 nMappedNumType = 0x1C0001; // Double-byte Arabic numbers.
1050 break;
1051 default:
1052 break;
1055 nParaFlags |= 0x2f;
1056 nBulletFlags |= 6;
1057 if ( mbIsBullet && bNumberingIsNumber )
1058 nBulletFlags |= 1;
1059 break;
1061 default:
1062 break;
1067 nBulletOfs = nTextOfs + nBulletOfs;
1068 if ( nBulletOfs < 0 )
1069 nBulletOfs = 0;
1072 void ParagraphObj::ImplGetParagraphValues( PPTExBulletProvider* pBuProv, bool bGetPropStateValue )
1074 css::uno::Any aAny;
1075 if ( GetPropertyValue( aAny, mXPropSet, "NumberingLevel", true ) )
1077 if ( bGetPropStateValue )
1078 meBullet = GetPropertyState( mXPropSet, "NumberingLevel" );
1079 nDepth = *o3tl::doAccess<sal_Int16>(aAny);
1081 if ( nDepth < 0 )
1083 mbIsBullet = false;
1084 nDepth = 0;
1086 else
1088 if ( nDepth > 4 )
1089 nDepth = 4;
1090 mbIsBullet = true;
1093 else
1095 nDepth = 0;
1096 mbIsBullet = false;
1098 ImplGetNumberingLevel( pBuProv, nDepth, mbIsBullet, bGetPropStateValue );
1100 if ( ImplGetPropertyValue( "ParaTabStops", bGetPropStateValue ) )
1101 maTabStop = *o3tl::doAccess<css::uno::Sequence<css::style::TabStop>>(mAny);
1102 sal_Int16 eTextAdjust = sal_Int16(css::style::ParagraphAdjust_LEFT);
1103 if ( GetPropertyValue( aAny, mXPropSet, "ParaAdjust", bGetPropStateValue ) )
1104 aAny >>= eTextAdjust;
1105 switch ( static_cast<css::style::ParagraphAdjust>(eTextAdjust) )
1107 case css::style::ParagraphAdjust_CENTER :
1108 mnTextAdjust = 1;
1109 break;
1110 case css::style::ParagraphAdjust_RIGHT :
1111 mnTextAdjust = 2;
1112 break;
1113 case css::style::ParagraphAdjust_BLOCK :
1114 mnTextAdjust = 3;
1115 break;
1116 default :
1117 case css::style::ParagraphAdjust_LEFT :
1118 mnTextAdjust = 0;
1119 break;
1121 meTextAdjust = ePropState;
1123 if ( ImplGetPropertyValue( "ParaLineSpacing", bGetPropStateValue ) )
1125 css::style::LineSpacing aLineSpacing
1126 = *o3tl::doAccess<css::style::LineSpacing>(mAny);
1127 switch ( aLineSpacing.Mode )
1129 case css::style::LineSpacingMode::FIX :
1130 mnLineSpacing = static_cast<sal_Int16>(-( aLineSpacing.Height ) );
1131 mbFixedLineSpacing = true;
1132 break;
1133 case css::style::LineSpacingMode::MINIMUM :
1134 case css::style::LineSpacingMode::LEADING :
1135 mnLineSpacing = static_cast<sal_Int16>(-( aLineSpacing.Height ) );
1136 mbFixedLineSpacing = false;
1137 break;
1139 case css::style::LineSpacingMode::PROP :
1140 default:
1141 mnLineSpacing = static_cast<sal_Int16>( aLineSpacing.Height );
1142 break;
1145 meLineSpacing = ePropState;
1147 if ( ImplGetPropertyValue( "ParaBottomMargin", bGetPropStateValue ) )
1149 double fSpacing = *o3tl::doAccess<sal_uInt32>(mAny) + ( 2540.0 / 576.0 ) - 1;
1150 mnLineSpacingBottom = static_cast<sal_Int16>(-( fSpacing * 576.0 / 2540.0 ) );
1152 meLineSpacingBottom = ePropState;
1154 if ( ImplGetPropertyValue( "ParaTopMargin", bGetPropStateValue ) )
1156 double fSpacing = *o3tl::doAccess<sal_uInt32>(mAny) + ( 2540.0 / 576.0 ) - 1;
1157 mnLineSpacingTop = static_cast<sal_Int16>(-( fSpacing * 576.0 / 2540.0 ) );
1159 meLineSpacingTop = ePropState;
1161 if ( ImplGetPropertyValue( "ParaIsForbiddenRules", bGetPropStateValue ) )
1162 mAny >>= mbForbiddenRules;
1163 meForbiddenRules = ePropState;
1165 if ( ImplGetPropertyValue( "ParaIsHangingPunctuation", bGetPropStateValue ) )
1166 mAny >>= mbParagraphPunctation;
1167 meParagraphPunctation = ePropState;
1169 mnBiDi = 0;
1170 if ( ImplGetPropertyValue( "WritingMode", bGetPropStateValue ) )
1172 sal_Int16 nWritingMode = 0;
1173 mAny >>= nWritingMode;
1175 SvxFrameDirection eWritingMode = static_cast<SvxFrameDirection>(nWritingMode);
1176 if ( ( eWritingMode == SvxFrameDirection::Horizontal_RL_TB )
1177 || ( eWritingMode == SvxFrameDirection::Vertical_RL_TB ) )
1179 mnBiDi = 1;
1182 meBiDi = ePropState;
1185 void ParagraphObj::ImplConstruct( const ParagraphObj& rParagraphObj )
1187 mbIsBullet = rParagraphObj.mbIsBullet;
1188 meBullet = rParagraphObj.meBullet;
1189 meTextAdjust = rParagraphObj.meTextAdjust;
1190 meLineSpacing = rParagraphObj.meLineSpacing;
1191 meLineSpacingTop = rParagraphObj.meLineSpacingTop;
1192 meLineSpacingBottom = rParagraphObj.meLineSpacingBottom;
1193 meForbiddenRules = rParagraphObj.meForbiddenRules;
1194 meParagraphPunctation = rParagraphObj.meParagraphPunctation;
1195 meBiDi =rParagraphObj.meBiDi;
1196 mbFixedLineSpacing = rParagraphObj.mbFixedLineSpacing;
1197 mnTextSize = rParagraphObj.mnTextSize;
1198 mnTextAdjust = rParagraphObj.mnTextAdjust;
1199 mnLineSpacing = rParagraphObj.mnLineSpacing;
1200 mnLineSpacingTop = rParagraphObj.mnLineSpacingTop;
1201 mnLineSpacingBottom = rParagraphObj.mnLineSpacingBottom;
1202 mbFirstParagraph = rParagraphObj.mbFirstParagraph;
1203 mbLastParagraph = rParagraphObj.mbLastParagraph;
1204 mbParagraphPunctation = rParagraphObj.mbParagraphPunctation;
1205 mbForbiddenRules = rParagraphObj.mbForbiddenRules;
1206 mnBiDi = rParagraphObj.mnBiDi;
1208 for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = rParagraphObj.begin(); it != rParagraphObj.end(); ++it )
1209 mvPortions.push_back( std::make_unique<PortionObj>( **it ) );
1211 maTabStop = rParagraphObj.maTabStop;
1212 bExtendedParameters = rParagraphObj.bExtendedParameters;
1213 nParaFlags = rParagraphObj.nParaFlags;
1214 nBulletFlags = rParagraphObj.nBulletFlags;
1215 sPrefix = rParagraphObj.sPrefix;
1216 sSuffix = rParagraphObj.sSuffix;
1217 sGraphicUrl = rParagraphObj.sGraphicUrl; // String to a graphic
1218 aBuGraSize = rParagraphObj.aBuGraSize;
1219 nNumberingType = rParagraphObj.nNumberingType; // this is actually a SvxEnum
1220 nHorzAdjust = rParagraphObj.nHorzAdjust;
1221 nBulletColor = rParagraphObj.nBulletColor;
1222 nBulletOfs = rParagraphObj.nBulletOfs;
1223 nStartWith = rParagraphObj.nStartWith; // start of numbering
1224 nTextOfs = rParagraphObj.nTextOfs;
1225 nBulletRealSize = rParagraphObj.nBulletRealSize; // scale in percent
1226 nDepth = rParagraphObj.nDepth; // actual depth
1227 cBulletId = rParagraphObj.cBulletId; // if Numbering Type == CharSpecial
1228 aFontDesc = rParagraphObj.aFontDesc;
1230 bExtendedBulletsUsed = rParagraphObj.bExtendedBulletsUsed;
1231 nBulletId = rParagraphObj.nBulletId;
1234 sal_uInt32 ParagraphObj::ImplCalculateTextPositions( sal_uInt32 nCurrentTextPosition )
1236 mnTextSize = 0;
1237 for ( std::vector<std::unique_ptr<PortionObj> >::iterator it = mvPortions.begin(); it != mvPortions.end(); ++it )
1238 mnTextSize += (*it)->ImplCalculateTextPositions( nCurrentTextPosition + mnTextSize );
1239 return mnTextSize;
1242 ParagraphObj& ParagraphObj::operator=( const ParagraphObj& rParagraphObj )
1244 if ( this != &rParagraphObj )
1246 ImplClear();
1247 ImplConstruct( rParagraphObj );
1249 return *this;
1252 struct ImplTextObj
1254 sal_uInt32 mnTextSize;
1255 int mnInstance;
1256 std::vector<std::unique_ptr<ParagraphObj>> maList;
1257 bool mbHasExtendedBullets;
1259 explicit ImplTextObj( int nInstance );
1262 ImplTextObj::ImplTextObj( int nInstance )
1263 : maList()
1265 mnTextSize = 0;
1266 mnInstance = nInstance;
1267 mbHasExtendedBullets = false;
1270 TextObj::TextObj( css::uno::Reference< css::text::XSimpleText > const & rXTextRef,
1271 int nInstance, FontCollection& rFontCollection, PPTExBulletProvider& rProv ):
1272 mpImplTextObj(new ImplTextObj(nInstance))
1274 css::uno::Reference< css::container::XEnumerationAccess > aXTextParagraphEA( rXTextRef, css::uno::UNO_QUERY );
1276 if ( aXTextParagraphEA.is() )
1278 css::uno::Reference< css::container::XEnumeration > aXTextParagraphE( aXTextParagraphEA->createEnumeration() );
1279 if ( aXTextParagraphE.is() )
1281 ParaFlags aParaFlags;
1282 while ( aXTextParagraphE->hasMoreElements() )
1284 css::uno::Reference< css::text::XTextContent > aXParagraph;
1285 css::uno::Any aAny( aXTextParagraphE->nextElement() );
1286 if ( aAny >>= aXParagraph )
1288 if ( !aXTextParagraphE->hasMoreElements() )
1289 aParaFlags.bLastParagraph = true;
1290 std::unique_ptr<ParagraphObj> pPara(new ParagraphObj( aXParagraph, aParaFlags, rFontCollection, rProv ));
1291 mpImplTextObj->mbHasExtendedBullets |= pPara->bExtendedBulletsUsed;
1292 mpImplTextObj->maList.push_back( std::move(pPara) );
1293 aParaFlags.bFirstParagraph = false;
1298 ImplCalculateTextPositions();
1301 void TextObj::ImplCalculateTextPositions()
1303 mpImplTextObj->mnTextSize = 0;
1304 for ( sal_uInt32 i = 0; i < ParagraphCount(); ++i )
1305 mpImplTextObj->mnTextSize += GetParagraph(i)->ImplCalculateTextPositions( mpImplTextObj->mnTextSize );
1308 ParagraphObj* TextObj::GetParagraph(int idx)
1310 return mpImplTextObj->maList[idx].get();
1313 sal_uInt32 TextObj::ParagraphCount() const
1315 return mpImplTextObj->maList.size();
1318 sal_uInt32 TextObj::Count() const
1320 return mpImplTextObj->mnTextSize;
1323 int TextObj::GetInstance() const
1325 return mpImplTextObj->mnInstance;
1328 bool TextObj::HasExtendedBullets() const
1330 return mpImplTextObj->mbHasExtendedBullets;
1333 FontCollectionEntry::~FontCollectionEntry()
1337 void FontCollectionEntry::ImplInit( const OUString& rName )
1339 OUString aSubstName( GetSubsFontName( rName, SubsFontFlags::ONLYONE | SubsFontFlags::MS ) );
1340 if ( !aSubstName.isEmpty() )
1342 Name = aSubstName;
1344 else
1346 Name = rName;
1350 FontCollection::~FontCollection()
1352 pVDev.disposeAndClear();
1353 xPPTBreakIter = nullptr;
1356 FontCollection::FontCollection() :
1357 pVDev ( nullptr )
1359 xPPTBreakIter = css::i18n::BreakIterator::create( ::comphelper::getProcessComponentContext() );
1362 short FontCollection::GetScriptDirection( const OUString& rString )
1364 short nRet = ScriptTypeDetector::getScriptDirection( rString, 0, css::i18n::ScriptDirection::NEUTRAL );
1365 return nRet;
1368 sal_uInt32 FontCollection::GetId( FontCollectionEntry& rEntry )
1370 if( !rEntry.Name.isEmpty() )
1372 const sal_uInt32 nFonts = maFonts.size();
1374 for( sal_uInt32 i = 0; i < nFonts; i++ )
1376 const FontCollectionEntry* pEntry = GetById( i );
1377 if( pEntry->Name == rEntry.Name )
1378 return i;
1380 vcl::Font aFont;
1381 aFont.SetCharSet( rEntry.CharSet );
1382 aFont.SetFamilyName( rEntry.Original );
1383 aFont.SetFontHeight( 100 );
1385 if ( !pVDev )
1386 pVDev = VclPtr<VirtualDevice>::Create();
1388 pVDev->SetFont( aFont );
1389 FontMetric aMetric( pVDev->GetFontMetric() );
1391 sal_uInt16 nTxtHeight = static_cast<sal_uInt16>(aMetric.GetAscent()) + static_cast<sal_uInt16>(aMetric.GetDescent());
1393 if ( nTxtHeight )
1395 double fScaling = static_cast<double>(nTxtHeight) / 120.0;
1396 if ( ( fScaling > 0.50 ) && ( fScaling < 1.5 ) )
1397 rEntry.Scaling = fScaling;
1400 maFonts.push_back(rEntry);
1401 return nFonts;
1403 return 0;
1406 const FontCollectionEntry* FontCollection::GetById( sal_uInt32 nId )
1408 return nId < maFonts.size() ? &maFonts[nId] : nullptr;
1411 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */