/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <memory>
#include "text.hxx"
#include <com/sun/star/awt/CharSet.hpp>
#include <com/sun/star/awt/FontWeight.hpp>
#include <com/sun/star/awt/FontUnderline.hpp>
#include <com/sun/star/awt/XBitmap.hpp>
#include <com/sun/star/beans/XPropertyState.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/container/XEnumerationAccess.hpp>
#include <com/sun/star/container/XIndexReplace.hpp>
#include <com/sun/star/i18n/BreakIterator.hpp>
#include <com/sun/star/i18n/ScriptDirection.hpp>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <com/sun/star/text/FontRelief.hpp>
#include <com/sun/star/text/XTextField.hpp>
#include <com/sun/star/text/XTextRange.hpp>
#include <com/sun/star/style/LineSpacing.hpp>
#include <com/sun/star/style/LineSpacingMode.hpp>
#include <com/sun/star/style/ParagraphAdjust.hpp>
#include <com/sun/star/style/TabStop.hpp>
#include <com/sun/star/graphic/XGraphic.hpp>
#include <comphelper/processfactory.hxx>
#include <editeng/svxenum.hxx>
#include <editeng/frmdir.hxx>
#include <filter/msfilter/util.hxx>
#include <i18nutil/scripttypedetector.hxx>
#include <o3tl/any.hxx>
#include <svl/languageoptions.hxx>
#include <osl/diagnose.h>
#include <i18nlangtag/languagetag.hxx>
#include <tools/UnitConversion.hxx>
#include <vcl/settings.hxx>
#include <vcl/metric.hxx>
#include <vcl/virdev.hxx>
#include <vcl/svapp.hxx>
using namespace css;
static css::uno::Reference< css::i18n::XBreakIterator > xPPTBreakIter;
PortionObj::PortionObj(const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
FontCollection& rFontCollection)
: meCharColor(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meCharHeight(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meFontName(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meAsianOrComplexFont(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meCharEscapement(css::beans::PropertyState_AMBIGUOUS_VALUE)
, mnCharAttrHard(0)
, mnCharColor(0)
, mnCharAttr(0)
, mnFont(0)
, mnAsianOrComplexFont(0xffff)
, mnTextSize(0)
, mbLastPortion(true)
{
mXPropSet = rXPropSet;
ImplGetPortionValues( rFontCollection, false );
}
PortionObj::PortionObj(css::uno::Reference< css::text::XTextRange > & rXTextRange,
bool bLast, FontCollection& rFontCollection)
: meCharColor(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meCharHeight(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meFontName(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meAsianOrComplexFont(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meCharEscapement(css::beans::PropertyState_AMBIGUOUS_VALUE)
, mnCharAttrHard(0)
, mnCharColor(0)
, mnCharAttr(0)
, mnCharHeight(0)
, mnFont(0)
, mnAsianOrComplexFont(0xffff)
, mnCharEscapement(0)
, mbLastPortion(bLast)
{
OUString aString( rXTextRange->getString() );
OUString aURL;
mnTextSize = aString.getLength();
if ( bLast )
mnTextSize++;
if ( !mnTextSize )
return;
bool bRTL_endingParen = false;
mpFieldEntry = nullptr;
sal_uInt32 nFieldType = 0;
mXPropSet.set( rXTextRange, css::uno::UNO_QUERY );
mXPropState.set( rXTextRange, css::uno::UNO_QUERY );
bool bPropSetsValid = ( mXPropSet.is() && mXPropState.is() );
if ( bPropSetsValid )
nFieldType = ImplGetTextField( rXTextRange, mXPropSet, aURL );
if ( nFieldType )
{
mpFieldEntry.reset( new FieldEntry( nFieldType, 0, mnTextSize ) );
if ( nFieldType >> 28 == 4 )
{
mpFieldEntry->aRepresentation = aString;
mpFieldEntry->aFieldUrl = aURL;
}
}
bool bSymbol = false;
if ( bPropSetsValid && ImplGetPropertyValue( u"CharFontCharSet"_ustr, false ) )
{
sal_Int16 nCharset = 0;
mAny >>= nCharset;
if ( nCharset == css::awt::CharSet::SYMBOL )
bSymbol = true;
}
if ( mpFieldEntry && ( nFieldType & 0x800000 ) ) // placeholder ?
{
mnTextSize = 1;
if ( bLast )
mnTextSize++;
mpText.reset( new sal_uInt16[ mnTextSize ] );
mpText[ 0 ] = 0x2a;
}
else
{
// For i39516 - a closing parenthesis that ends an RTL string is displayed backwards by PPT
// Solution: add a Unicode Right-to-Left Mark, following the method described in i18024
if (bLast && !aString.isEmpty()
&& aString[aString.getLength() - 1] == ')'
&& FontCollection::GetScriptDirection(aString) == css::i18n::ScriptDirection::RIGHT_TO_LEFT)
{
mnTextSize++;
bRTL_endingParen = true;
}
mpText.reset( new sal_uInt16[ mnTextSize ] );
sal_uInt16 nChar;
for ( sal_Int32 i = 0; i < aString.getLength(); i++ )
{
nChar = static_cast<sal_uInt16>(aString[ i ]);
if ( nChar == 0xa )
nChar++;
else if ( !bSymbol )
{
switch ( nChar )
{
// Currency
case 128: nChar = 0x20AC; break;
// Punctuation and other
case 130: nChar = 0x201A; break;// SINGLE LOW-9 QUOTATION MARK
case 131: nChar = 0x0192; break;// LATIN SMALL LETTER F WITH HOOK
case 132: nChar = 0x201E; break;// DOUBLE LOW-9 QUOTATION MARK
// LOW DOUBLE PRIME QUOTATION MARK
case 133: nChar = 0x2026; break;// HORIZONTAL ELLIPSES
case 134: nChar = 0x2020; break;// DAGGER
case 135: nChar = 0x2021; break;// DOUBLE DAGGER
case 136: nChar = 0x02C6; break;// MODIFIER LETTER CIRCUMFLEX ACCENT
case 137: nChar = 0x2030; break;// PER MILLE SIGN
case 138: nChar = 0x0160; break;// LATIN CAPITAL LETTER S WITH CARON
case 139: nChar = 0x2039; break;// SINGLE LEFT-POINTING ANGLE QUOTATION MARK
case 140: nChar = 0x0152; break;// LATIN CAPITAL LIGATURE OE
case 142: nChar = 0x017D; break;// LATIN CAPITAL LETTER Z WITH CARON
case 145: nChar = 0x2018; break;// LEFT SINGLE QUOTATION MARK
// MODIFIER LETTER TURNED COMMA
case 146: nChar = 0x2019; break;// RIGHT SINGLE QUOTATION MARK
// MODIFIER LETTER APOSTROPHE
case 147: nChar = 0x201C; break;// LEFT DOUBLE QUOTATION MARK
// REVERSED DOUBLE PRIME QUOTATION MARK
case 148: nChar = 0x201D; break;// RIGHT DOUBLE QUOTATION MARK
// REVERSED DOUBLE PRIME QUOTATION MARK
case 149: nChar = 0x2022; break;// BULLET
case 150: nChar = 0x2013; break;// EN DASH
case 151: nChar = 0x2014; break;// EM DASH
case 152: nChar = 0x02DC; break;// SMALL TILDE
case 153: nChar = 0x2122; break;// TRADE MARK SIGN
case 154: nChar = 0x0161; break;// LATIN SMALL LETTER S WITH CARON
case 155: nChar = 0x203A; break;// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
case 156: nChar = 0x0153; break;// LATIN SMALL LIGATURE OE
case 158: nChar = 0x017E; break;// LATIN SMALL LETTER Z WITH CARON
case 159: nChar = 0x0178; break;// LATIN CAPITAL LETTER Y WITH DIAERESIS
}
}
mpText[ i ] = nChar;
}
}
if ( bRTL_endingParen )
mpText[ mnTextSize - 2 ] = 0x200F; // Unicode Right-to-Left mark
if ( bLast )
mpText[ mnTextSize - 1 ] = 0xd;
if ( bPropSetsValid )
ImplGetPortionValues( rFontCollection, true );
}
PortionObj::PortionObj( const PortionObj& rPortionObj )
: PropStateValue( rPortionObj )
{
ImplConstruct( rPortionObj );
}
PortionObj::~PortionObj()
{
ImplClear();
}
void PortionObj::Write( SvStream* pStrm, bool bLast )
{
sal_uInt32 nCount = mnTextSize;
if ( bLast && mbLastPortion )
nCount--;
for ( sal_uInt32 i = 0; i < nCount; i++ )
pStrm->WriteUInt16( mpText[ i ] );
}
void PortionObj::ImplGetPortionValues( FontCollection& rFontCollection, bool bGetPropStateValue )
{
bool bOk = ImplGetPropertyValue( u"CharFontName"_ustr, bGetPropStateValue );
meFontName = ePropState;
if ( bOk )
{
FontCollectionEntry aFontDesc( *o3tl::doAccess<OUString>(mAny) );
sal_uInt32 nCount = rFontCollection.GetCount();
mnFont = static_cast<sal_uInt16>(rFontCollection.GetId( aFontDesc ));
if ( mnFont == nCount )
{
FontCollectionEntry& rFontDesc = rFontCollection.GetLast();
if ( ImplGetPropertyValue( u"CharFontCharSet"_ustr, false ) )
mAny >>= rFontDesc.CharSet;
if ( ImplGetPropertyValue( u"CharFontFamily"_ustr, false ) )
mAny >>= rFontDesc.Family;
if ( ImplGetPropertyValue( u"CharFontPitch"_ustr, false ) )
mAny >>= rFontDesc.Pitch;
}
}
sal_Int16 nScriptType = SvtLanguageOptions::FromSvtScriptTypeToI18N( SvtLanguageOptions::GetScriptTypeOfLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ) );
if ( mpText && mnTextSize && xPPTBreakIter.is() )
{
OUString sT( reinterpret_cast<sal_Unicode *>(mpText.get()), mnTextSize );
nScriptType = xPPTBreakIter->getScriptType( sT, 0 );
}
if ( nScriptType != css::i18n::ScriptType::COMPLEX )
{
bOk = ImplGetPropertyValue( u"CharFontNameAsian"_ustr, bGetPropStateValue );
meAsianOrComplexFont = ePropState;
if ( bOk )
{
FontCollectionEntry aFontDesc( *o3tl::doAccess<OUString>(mAny) );
sal_uInt32 nCount = rFontCollection.GetCount();
mnAsianOrComplexFont = static_cast<sal_uInt16>(rFontCollection.GetId( aFontDesc ));
if ( mnAsianOrComplexFont == nCount )
{
FontCollectionEntry& rFontDesc = rFontCollection.GetLast();
if ( ImplGetPropertyValue( u"CharFontCharSetAsian"_ustr, false ) )
mAny >>= rFontDesc.CharSet;
if ( ImplGetPropertyValue( u"CharFontFamilyAsian"_ustr, false ) )
mAny >>= rFontDesc.Family;
if ( ImplGetPropertyValue( u"CharFontPitchAsian"_ustr, false ) )
mAny >>= rFontDesc.Pitch;
}
}
}
else
{
bOk = ImplGetPropertyValue( u"CharFontNameComplex"_ustr, bGetPropStateValue );
meAsianOrComplexFont = ePropState;
if ( bOk )
{
FontCollectionEntry aFontDesc( *o3tl::doAccess<OUString>(mAny) );
sal_uInt32 nCount = rFontCollection.GetCount();
mnAsianOrComplexFont = static_cast<sal_uInt16>(rFontCollection.GetId( aFontDesc ));
if ( mnAsianOrComplexFont == nCount )
{
FontCollectionEntry& rFontDesc = rFontCollection.GetLast();
if ( ImplGetPropertyValue( u"CharFontCharSetComplex"_ustr, false ) )
mAny >>= rFontDesc.CharSet;
if ( ImplGetPropertyValue( u"CharFontFamilyComplex"_ustr, false ) )
mAny >>= rFontDesc.Family;
if ( ImplGetPropertyValue( u"CharFontPitchComplex"_ustr, false ) )
mAny >>= rFontDesc.Pitch;
}
}
}
OUString aCharHeightName, aCharWeightName, aCharLocaleName, aCharPostureName;
switch( nScriptType )
{
case css::i18n::ScriptType::ASIAN :
{
aCharHeightName = "CharHeightAsian";
aCharWeightName = "CharWeightAsian";
aCharLocaleName = "CharLocaleAsian";
aCharPostureName = "CharPostureAsian";
break;
}
case css::i18n::ScriptType::COMPLEX :
{
aCharHeightName = "CharHeightComplex";
aCharWeightName = "CharWeightComplex";
aCharLocaleName = "CharLocaleComplex";
aCharPostureName = "CharPostureComplex";
break;
}
default:
{
aCharHeightName = "CharHeight";
aCharWeightName = "CharWeight";
aCharLocaleName = "CharLocale";
aCharPostureName = "CharPosture";
break;
}
}
mnCharHeight = 24;
if ( GetPropertyValue( mAny, mXPropSet, aCharHeightName ) )
{
float fVal(0.0);
if ( mAny >>= fVal )
{
mnCharHeight = static_cast<sal_uInt16>( fVal + 0.5 );
meCharHeight = GetPropertyState( mXPropSet, aCharHeightName );
}
}
if ( GetPropertyValue( mAny, mXPropSet, aCharWeightName ) )
{
float fFloat(0.0);
if ( mAny >>= fFloat )
{
if ( fFloat >= css::awt::FontWeight::SEMIBOLD )
mnCharAttr |= 1;
if ( GetPropertyState( mXPropSet, aCharWeightName ) == css::beans::PropertyState_DIRECT_VALUE )
mnCharAttrHard |= 1;
}
}
if ( GetPropertyValue( mAny, mXPropSet, aCharLocaleName ) )
{
css::lang::Locale aLocale;
if ( mAny >>= aLocale )
meCharLocale = std::move(aLocale);
}
if ( GetPropertyValue( mAny, mXPropSet, aCharPostureName ) )
{
css::awt::FontSlant aFS;
if ( mAny >>= aFS )
{
switch( aFS )
{
case css::awt::FontSlant_OBLIQUE :
case css::awt::FontSlant_ITALIC :
mnCharAttr |= 2;
break;
default:
break;
}
if ( GetPropertyState( mXPropSet, aCharPostureName ) == css::beans::PropertyState_DIRECT_VALUE )
mnCharAttrHard |= 2;
}
}
if ( ImplGetPropertyValue( u"CharUnderline"_ustr, bGetPropStateValue ) )
{
sal_Int16 nVal(0);
mAny >>= nVal;
switch ( nVal )
{
case css::awt::FontUnderline::SINGLE :
case css::awt::FontUnderline::DOUBLE :
case css::awt::FontUnderline::DOTTED :
mnCharAttr |= 4;
}
}
if ( ePropState == css::beans::PropertyState_DIRECT_VALUE )
mnCharAttrHard |= 4;
if ( ImplGetPropertyValue( u"CharShadowed"_ustr, bGetPropStateValue ) )
{
bool bBool(false);
mAny >>= bBool;
if ( bBool )
mnCharAttr |= 0x10;
}
if ( ePropState == css::beans::PropertyState_DIRECT_VALUE )
mnCharAttrHard |= 16;
if ( ImplGetPropertyValue( u"CharRelief"_ustr, bGetPropStateValue ) )
{
sal_Int16 nVal(0);
mAny >>= nVal;
if ( nVal != css::text::FontRelief::NONE )
mnCharAttr |= 512;
}
if ( ePropState == css::beans::PropertyState_DIRECT_VALUE )
mnCharAttrHard |= 512;
if ( ImplGetPropertyValue( u"CharColor"_ustr, bGetPropStateValue ) )
{
sal_uInt32 nSOColor = *( o3tl::doAccess<sal_uInt32>(mAny) );
mnCharColor = nSOColor & 0xff00ff00; // green and hibyte
mnCharColor |= static_cast<sal_uInt8>(nSOColor) << 16; // red and blue is switched
mnCharColor |= static_cast<sal_uInt8>( nSOColor >> 16 );
}
meCharColor = ePropState;
mnCharEscapement = 0;
if ( ImplGetPropertyValue( u"CharEscapement"_ustr, bGetPropStateValue ) )
{
mAny >>= mnCharEscapement;
if ( mnCharEscapement > 100 )
mnCharEscapement = 33;
else if ( mnCharEscapement < -100 )
mnCharEscapement = -33;
}
meCharEscapement = ePropState;
}
void PortionObj::ImplClear()
{
mpFieldEntry.reset();
mpText.reset();
}
void PortionObj::ImplConstruct( const PortionObj& rPortionObj )
{
meCharColor = rPortionObj.meCharColor;
meCharHeight = rPortionObj.meCharHeight;
meFontName = rPortionObj.meFontName;
meAsianOrComplexFont = rPortionObj.meAsianOrComplexFont;
meCharEscapement = rPortionObj.meCharEscapement;
meCharLocale = rPortionObj.meCharLocale;
mnCharAttrHard = rPortionObj.mnCharAttrHard;
mbLastPortion = rPortionObj.mbLastPortion;
mnTextSize = rPortionObj.mnTextSize;
mnCharColor = rPortionObj.mnCharColor;
mnCharEscapement = rPortionObj.mnCharEscapement;
mnCharAttr = rPortionObj.mnCharAttr;
mnCharHeight = rPortionObj.mnCharHeight;
mnFont = rPortionObj.mnFont;
mnAsianOrComplexFont = rPortionObj.mnAsianOrComplexFont;
if ( rPortionObj.mpText )
{
mpText.reset( new sal_uInt16[ mnTextSize ] );
memcpy( mpText.get(), rPortionObj.mpText.get(), mnTextSize << 1 );
}
if ( rPortionObj.mpFieldEntry )
mpFieldEntry.reset( new FieldEntry( *( rPortionObj.mpFieldEntry ) ) );
}
sal_uInt32 PortionObj::ImplCalculateTextPositions( sal_uInt32 nCurrentTextPosition )
{
if ( mpFieldEntry && ( !mpFieldEntry->nFieldStartPos ) )
{
mpFieldEntry->nFieldStartPos += nCurrentTextPosition;
mpFieldEntry->nFieldEndPos += nCurrentTextPosition;
}
return mnTextSize;
}
// Return: 0 = no TextField
// bit28->31 text field type :
// 1 = Date
// 2 = Time
// 3 = SlideNumber
// 4 = Url
// 5 = DateTime
// 6 = header
// 7 = footer
// bit24->27 text field sub type (optional)
// 23-> PPT Textfield needs a placeholder
sal_uInt32 PortionObj::ImplGetTextField( css::uno::Reference< css::text::XTextRange > & ,
const css::uno::Reference< css::beans::XPropertySet > & rXPropSet, OUString& rURL )
{
sal_uInt32 nRetValue = 0;
sal_Int32 nFormat;
css::uno::Any aAny;
if ( GetPropertyValue( aAny, rXPropSet, u"TextPortionType"_ustr, true ) )
{
auto aTextFieldType = o3tl::doAccess<OUString>(aAny);
if ( *aTextFieldType == "TextField" )
{
if ( GetPropertyValue( aAny, rXPropSet, *aTextFieldType, true ) )
{
css::uno::Reference< css::text::XTextField > aXTextField;
if ( aAny >>= aXTextField )
{
if ( aXTextField.is() )
{
css::uno::Reference< css::beans::XPropertySet > xFieldPropSet( aXTextField, css::uno::UNO_QUERY );
if ( xFieldPropSet.is() )
{
OUString aFieldKind( aXTextField->getPresentation( true ) );
if ( aFieldKind == "Date" )
{
if ( GetPropertyValue( aAny, xFieldPropSet, u"IsFix"_ustr, true ) )
{
bool bBool = false;
aAny >>= bBool;
if ( !bBool ) // Fixed DateFields does not exist in PPT
{
if ( GetPropertyValue( aAny, xFieldPropSet, u"Format"_ustr, true ) )
{
nFormat = *o3tl::doAccess<sal_Int32>(aAny);
switch ( nFormat )
{
default:
case 5 :
case 4 :
case 2 : nFormat = 0; break;
case 8 :
case 9 :
case 3 : nFormat = 1; break;
case 7 :
case 6 : nFormat = 2; break;
}
nRetValue |= ( ( ( 1 << 4 ) | nFormat ) << 24 ) | 0x800000;
}
}
}
}
else if ( aFieldKind == "URL" )
{
if ( GetPropertyValue( aAny, xFieldPropSet, u"URL"_ustr, true ) )
rURL = *o3tl::doAccess<OUString>(aAny);
nRetValue = 4 << 28;
}
else if ( aFieldKind == "Page" )
{
nRetValue = 3 << 28 | 0x800000;
}
else if ( aFieldKind == "Pages" )
{
}
else if ( aFieldKind == "Time" )
{
if ( GetPropertyValue( aAny, xFieldPropSet, u"IsFix"_ustr, true ) )
{
bool bBool = false;
aAny >>= bBool;
if ( !bBool )
{
if ( GetPropertyValue( aAny, xFieldPropSet, u"IsFix"_ustr, true ) )
{
nFormat = *o3tl::doAccess<sal_Int32>(aAny);
nRetValue |= ( ( ( 2 << 4 ) | nFormat ) << 24 ) | 0x800000;
}
}
}
}
else if ( aFieldKind == "File" )
{
}
else if ( aFieldKind == "Table" )
{
}
else if ( aFieldKind == "ExtTime" )
{
if ( GetPropertyValue( aAny, xFieldPropSet, u"IsFix"_ustr, true ) )
{
bool bBool = false;
aAny >>= bBool;
if ( !bBool )
{
if ( GetPropertyValue( aAny, xFieldPropSet, u"Format"_ustr, true ) )
{
nFormat = *o3tl::doAccess<sal_Int32>(aAny);
switch ( nFormat )
{
default:
case 6 :
case 7 :
case 8 :
case 2 : nFormat = 12; break;
case 3 : nFormat = 9; break;
case 5 :
case 4 : nFormat = 10; break;
}
nRetValue |= ( ( ( 2 << 4 ) | nFormat ) << 24 ) | 0x800000;
}
}
}
}
else if ( aFieldKind == "ExtFile" )
{
}
else if ( aFieldKind == "Author" )
{
}
else if ( aFieldKind == "DateTime" )
{
nRetValue = 5 << 28 | 0x800000;
}
else if ( aFieldKind == "Header" )
{
nRetValue = 6 << 28 | 0x800000;
}
else if ( aFieldKind == "Footer" )
{
nRetValue = 7 << 28 | 0x800000;
}
}
}
}
}
}
}
return nRetValue;
}
PortionObj& PortionObj::operator=( const PortionObj& rPortionObj )
{
if ( this != &rPortionObj )
{
ImplClear();
ImplConstruct( rPortionObj );
}
return *this;
}
ParagraphObj::ParagraphObj(const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
PPTExBulletProvider* pProv)
: mnTextSize(0)
, mbFirstParagraph(false)
, mbLastParagraph(false)
, meBullet(css::beans::PropertyState_AMBIGUOUS_VALUE)
, mnTextAdjust(0)
, mnLineSpacing(0)
, mbFixedLineSpacing(false)
, mnLineSpacingTop(0)
, mnLineSpacingBottom(0)
, mbForbiddenRules(false)
, mbParagraphPunctation(false)
, mnBiDi(0)
{
mXPropSet = rXPropSet;
bExtendedParameters = false;
nDepth = 0;
nBulletFlags = 0;
nParaFlags = 0;
ImplGetParagraphValues( pProv, false );
}
ParagraphObj::ParagraphObj(css::uno::Reference< css::text::XTextContent > const & rXTextContent,
ParaFlags aParaFlags, FontCollection& rFontCollection, PPTExBulletProvider& rProv )
: mnTextSize(0)
, mbIsBullet(false)
, mbFirstParagraph( aParaFlags.bFirstParagraph )
, mbLastParagraph( aParaFlags.bLastParagraph )
, meBullet(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meTextAdjust(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meLineSpacing(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meLineSpacingTop(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meLineSpacingBottom(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meForbiddenRules(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meParagraphPunctation(css::beans::PropertyState_AMBIGUOUS_VALUE)
, meBiDi(css::beans::PropertyState_AMBIGUOUS_VALUE)
, mnTextAdjust(0)
, mnLineSpacing(0)
, mbFixedLineSpacing(false)
, mnLineSpacingTop(0)
, mnLineSpacingBottom(0)
, mbForbiddenRules(false)
, mbParagraphPunctation(false)
, mnBiDi(0)
{
bExtendedParameters = false;
nDepth = 0;
nBulletFlags = 0;
nParaFlags = 0;
mXPropSet.set( rXTextContent, css::uno::UNO_QUERY );
mXPropState.set( rXTextContent, css::uno::UNO_QUERY );
if ( !(mXPropSet.is() && mXPropState.is()) )
return;
css::uno::Reference< css::container::XEnumerationAccess > aXTextPortionEA( rXTextContent, css::uno::UNO_QUERY );
if ( aXTextPortionEA.is() )
{
css::uno::Reference< css::container::XEnumeration > aXTextPortionE( aXTextPortionEA->createEnumeration() );
if ( aXTextPortionE.is() )
{
while ( aXTextPortionE->hasMoreElements() )
{
css::uno::Reference< css::text::XTextRange > aXCursorText;
css::uno::Any aAny( aXTextPortionE->nextElement() );
if ( aAny >>= aXCursorText )
{
std::unique_ptr<PortionObj> pPortionObj(new PortionObj( aXCursorText, !aXTextPortionE->hasMoreElements(), rFontCollection ));
if ( pPortionObj->Count() )
mvPortions.push_back( std::move(pPortionObj) );
}
}
}
}
ImplGetParagraphValues( &rProv, true );
}
ParagraphObj::~ParagraphObj()
{
ImplClear();
}
void ParagraphObj::Write( SvStream* pStrm )
{
for ( std::vector<std::unique_ptr<PortionObj> >::iterator it = mvPortions.begin(); it != mvPortions.end(); ++it )
(*it)->Write( pStrm, mbLastParagraph );
}
void ParagraphObj::ImplClear()
{
mvPortions.clear();
}
void ParagraphObj::CalculateGraphicBulletSize( sal_uInt16 nFontHeight )
{
if ( ( nNumberingType != SVX_NUM_BITMAP ) || ( nBulletId == 0xffff ) )
return;
// calculate the bullet real size for this graphic
if ( aBuGraSize.Width() && aBuGraSize.Height() )
{
double fCharHeight = nFontHeight;
double fLen = aBuGraSize.Height();
fCharHeight = fCharHeight * 0.2540;
double fQuo = fLen / fCharHeight;
nBulletRealSize = static_cast<sal_Int16>( fQuo + 0.5 );
if ( static_cast<sal_uInt16>(nBulletRealSize) > 400 )
nBulletRealSize = 400;
}
}
void ParagraphObj::ImplGetNumberingLevel( PPTExBulletProvider* pBuProv, sal_Int16 nNumberingDepth, bool bIsBullet, bool bGetPropStateValue )
{
css::uno::Any aAny;
if ( GetPropertyValue( aAny, mXPropSet, u"ParaLeftMargin"_ustr ) )
{
sal_Int32 nVal(0);
if ( aAny >>= nVal )
nTextOfs = convertMm100ToMasterUnit(nVal);
}
if ( GetPropertyValue( aAny, mXPropSet, u"ParaFirstLineIndent"_ustr ) )
{
if ( aAny >>= nBulletOfs )
nBulletOfs = convertMm100ToMasterUnit(nBulletOfs);
}
if ( GetPropertyValue( aAny, mXPropSet, u"NumberingIsNumber"_ustr ) )
aAny >>= bNumberingIsNumber;
css::uno::Reference< css::container::XIndexReplace > aXIndexReplace;
if ( bIsBullet && ImplGetPropertyValue( u"NumberingRules"_ustr, bGetPropStateValue ) )
{
if ( ( mAny >>= aXIndexReplace ) && nNumberingDepth < aXIndexReplace->getCount() )
{
mAny = aXIndexReplace->getByIndex( nNumberingDepth );
auto aPropertySequence = o3tl::doAccess<css::uno::Sequence<css::beans::PropertyValue>>(mAny);
if ( aPropertySequence->hasElements() )
{
bExtendedParameters = true;
nBulletRealSize = 100;
nMappedNumType = 0;
uno::Reference<graphic::XGraphic> xGraphic;
for ( const css::beans::PropertyValue& rPropValue : *aPropertySequence )
{
OUString aPropName( rPropValue.Name );
if ( aPropName == "NumberingType" )
nNumberingType = static_cast<SvxNumType>(*o3tl::doAccess<sal_Int16>(rPropValue.Value));
else if ( aPropName == "Adjust" )
nHorzAdjust = *o3tl::doAccess<sal_Int16>(rPropValue.Value);
else if ( aPropName == "BulletChar" )
{
OUString aString( *o3tl::doAccess<OUString>(rPropValue.Value) );
if ( !aString.isEmpty() )
cBulletId = aString[ 0 ];
}
else if ( aPropName == "BulletFont" )
{
aFontDesc = *o3tl::doAccess<css::awt::FontDescriptor>(rPropValue.Value);
// Our numbullet dialog has set the wrong textencoding for our "StarSymbol" font,
// instead of a Unicode encoding the encoding RTL_TEXTENCODING_SYMBOL was used.
// Because there might exist a lot of damaged documents I added this two lines
// which fixes the bullet problem for the export.
if ( aFontDesc.Name.equalsIgnoreAsciiCase("StarSymbol") )
aFontDesc.CharSet = RTL_TEXTENCODING_MS_1252;
}
else if ( aPropName == "GraphicBitmap" )
{
auto xBitmap = rPropValue.Value.get<uno::Reference<awt::XBitmap>>();
xGraphic.set(xBitmap, uno::UNO_QUERY);
}
else if ( aPropName == "GraphicSize" )
{
if (auto aSize = o3tl::tryAccess<css::awt::Size>(rPropValue.Value))
{
// don't cast awt::Size to Size as on 64-bits they are not the same.
aBuGraSize.setWidth( aSize->Width );
aBuGraSize.setHeight( aSize->Height );
}
}
else if ( aPropName == "StartWith" )
nStartWith = *o3tl::doAccess<sal_Int16>(rPropValue.Value);
else if ( aPropName == "LeftMargin" )
nTextOfs += convertMm100ToMasterUnit(*o3tl::doAccess<sal_Int32>(rPropValue.Value));
else if ( aPropName == "FirstLineOffset" )
nBulletOfs += convertMm100ToMasterUnit(*o3tl::doAccess<sal_Int32>(rPropValue.Value));
else if ( aPropName == "BulletColor" )
{
sal_uInt32 nSOColor = *o3tl::doAccess<sal_uInt32>(rPropValue.Value);
nBulletColor = nSOColor & 0xff00ff00; // green and hibyte
nBulletColor |= static_cast<sal_uInt8>(nSOColor) << 16; // red
nBulletColor |= static_cast<sal_uInt8>( nSOColor >> 16 ) | 0xfe000000; // blue
}
else if ( aPropName == "BulletRelSize" )
{
nBulletRealSize = *o3tl::doAccess<sal_Int16>(rPropValue.Value);
nParaFlags |= 0x40;
nBulletFlags |= 8;
}
else if ( aPropName == "Prefix" )
sPrefix = *o3tl::doAccess<OUString>(rPropValue.Value);
else if ( aPropName == "Suffix" )
sSuffix = *o3tl::doAccess<OUString>(rPropValue.Value);
#ifdef DBG_UTIL
else if ( aPropName != "SymbolTextDistance" && aPropName != "GraphicBitmap" )
{
OSL_FAIL( "Unknown Property" );
}
#endif
}
if (xGraphic.is())
{
if ( aBuGraSize.Width() && aBuGraSize.Height() )
{
nBulletId = pBuProv->GetId(xGraphic, aBuGraSize );
if ( nBulletId != 0xffff )
bExtendedBulletsUsed = true;
}
else
{
nNumberingType = SVX_NUM_NUMBER_NONE;
}
}
CalculateGraphicBulletSize( ( mvPortions.empty() ) ? 24 : mvPortions.front()->mnCharHeight );
switch( nNumberingType )
{
case SVX_NUM_NUMBER_NONE : nParaFlags |= 0xf; break;
case SVX_NUM_CHAR_SPECIAL : // Bullet
{
if ( IsOpenSymbol(aFontDesc.Name) )
{
rtl_TextEncoding eChrSet = aFontDesc.CharSet;
cBulletId = msfilter::util::bestFitOpenSymbolToMSFont(cBulletId, eChrSet, aFontDesc.Name);
aFontDesc.CharSet = eChrSet;
}
if ( !aFontDesc.Name.isEmpty() )
{
nParaFlags |= 0x90; // we define the font and charset
}
[[fallthrough]];
}
case SVX_NUM_CHARS_UPPER_LETTER : // count from a-z, aa - az, ba - bz, ...
case SVX_NUM_CHARS_LOWER_LETTER :
case SVX_NUM_ROMAN_UPPER :
case SVX_NUM_ROMAN_LOWER :
case SVX_NUM_ARABIC :
case SVX_NUM_PAGEDESC : // numbering from the page template
case SVX_NUM_BITMAP :
case SVX_NUM_CHARS_UPPER_LETTER_N : // count from a-z, aa-zz, aaa-zzz
case SVX_NUM_CHARS_LOWER_LETTER_N :
case SVX_NUM_NUMBER_UPPER_ZH:
case SVX_NUM_CIRCLE_NUMBER:
case SVX_NUM_NUMBER_UPPER_ZH_TW:
case SVX_NUM_NUMBER_LOWER_ZH:
case SVX_NUM_FULL_WIDTH_ARABIC:
{
if ( nNumberingType != SVX_NUM_CHAR_SPECIAL )
{
bExtendedBulletsUsed = true;
if ( nNumberingDepth & 1 )
cBulletId = 0x2013; // defaulting bullet characters for ppt97
else if ( nNumberingDepth == 4 )
cBulletId = 0xbb;
else
cBulletId = 0x2022;
switch( nNumberingType )
{
case SVX_NUM_CHARS_UPPER_LETTER :
case SVX_NUM_CHARS_UPPER_LETTER_N :
{
if ( sSuffix == ")" )
{
if ( sPrefix == "(" )
nMappedNumType = 0xa0001; // (A)
else
nMappedNumType = 0xb0001; // A)
}
else
nMappedNumType = 0x10001; // A.
}
break;
case SVX_NUM_CHARS_LOWER_LETTER :
case SVX_NUM_CHARS_LOWER_LETTER_N :
{
if ( sSuffix == ")" )
{
if ( sPrefix == "(" )
nMappedNumType = 0x80001; // (a)
else
nMappedNumType = 0x90001; // a)
}
else
nMappedNumType = 0x00001; // a.
}
break;
case SVX_NUM_ROMAN_UPPER :
{
if ( sSuffix == ")" )
{
if ( sPrefix == "(" )
nMappedNumType = 0xe0001; // (I)
else
nMappedNumType = 0xf0001; // I)
}
else
nMappedNumType = 0x70001; // I.
}
break;
case SVX_NUM_ROMAN_LOWER :
{
if ( sSuffix == ")" )
{
if ( sPrefix == "(" )
nMappedNumType = 0x40001; // (i)
else
nMappedNumType = 0x50001; // i)
}
else
nMappedNumType = 0x60001; // i.
}
break;
case SVX_NUM_ARABIC :
{
if ( sSuffix == ")" )
{
if ( sPrefix == "(" )
nMappedNumType = 0xc0001; // (1)
else
nMappedNumType = 0x20001; // 1)
}
else
{
if ( sSuffix.isEmpty() && sPrefix.isEmpty() )
nMappedNumType = 0xd0001; // 1
else
nMappedNumType = 0x30001; // 1.
}
}
break;
case SVX_NUM_NUMBER_UPPER_ZH :
{
if ( !sSuffix.isEmpty() )
nMappedNumType = 0x110001; // Simplified Chinese with single-byte period.
else
nMappedNumType = 0x100001; // Simplified Chinese.
}
break;
case SVX_NUM_CIRCLE_NUMBER :
{
nMappedNumType = 0x120001; // Double byte circle numbers.
}
break;
case SVX_NUM_NUMBER_UPPER_ZH_TW :
{
if ( !sSuffix.isEmpty() )
nMappedNumType = 0x160001; // Traditional Chinese with single-byte period.
else
nMappedNumType = 0x150001; // Traditional Chinese.
}
break;
case SVX_NUM_NUMBER_LOWER_ZH :
{
if ( sSuffix == u"\uff0e" )
nMappedNumType = 0x260001; // Japanese with double-byte period.
else if ( !sSuffix.isEmpty() )
nMappedNumType = 0x1B0001; // Japanese/Korean with single-byte period.
else
nMappedNumType = 0x1A0001; // Japanese/Korean.
}
break;
case SVX_NUM_FULL_WIDTH_ARABIC :
{
if ( !sSuffix.isEmpty() )
nMappedNumType = 0x1D0001; // Double-byte Arabic numbers with double-byte period.
else
nMappedNumType = 0x1C0001; // Double-byte Arabic numbers.
}
break;
default:
break;
}
}
nParaFlags |= 0x2f;
nBulletFlags |= 6;
if ( mbIsBullet && bNumberingIsNumber )
nBulletFlags |= 1;
break;
}
default:
break;
}
}
}
}
nBulletOfs = nTextOfs + nBulletOfs;
if ( nBulletOfs < 0 )
nBulletOfs = 0;
}
void ParagraphObj::ImplGetParagraphValues( PPTExBulletProvider* pBuProv, bool bGetPropStateValue )
{
css::uno::Any aAny;
if ( GetPropertyValue( aAny, mXPropSet, u"NumberingLevel"_ustr, true ) )
{
if ( bGetPropStateValue )
meBullet = GetPropertyState( mXPropSet, u"NumberingLevel"_ustr );
nDepth = *o3tl::doAccess<sal_Int16>(aAny);
if ( nDepth < 0 )
{
mbIsBullet = false;
nDepth = 0;
}
else
{
if ( nDepth > 4 )
nDepth = 4;
mbIsBullet = true;
}
}
else
{
nDepth = 0;
mbIsBullet = false;
}
ImplGetNumberingLevel( pBuProv, nDepth, mbIsBullet, bGetPropStateValue );
if ( ImplGetPropertyValue( u"ParaTabStops"_ustr, bGetPropStateValue ) )
maTabStop = *o3tl::doAccess<css::uno::Sequence<css::style::TabStop>>(mAny);
sal_Int16 eTextAdjust = sal_Int16(css::style::ParagraphAdjust_LEFT);
if ( GetPropertyValue( aAny, mXPropSet, u"ParaAdjust"_ustr, bGetPropStateValue ) )
aAny >>= eTextAdjust;
switch ( static_cast<css::style::ParagraphAdjust>(eTextAdjust) )
{
case css::style::ParagraphAdjust_CENTER :
mnTextAdjust = 1;
break;
case css::style::ParagraphAdjust_RIGHT :
mnTextAdjust = 2;
break;
case css::style::ParagraphAdjust_BLOCK :
mnTextAdjust = 3;
break;
default :
case css::style::ParagraphAdjust_LEFT :
mnTextAdjust = 0;
break;
}
meTextAdjust = ePropState;
if ( ImplGetPropertyValue( u"ParaLineSpacing"_ustr, bGetPropStateValue ) )
{
css::style::LineSpacing aLineSpacing
= *o3tl::doAccess<css::style::LineSpacing>(mAny);
switch ( aLineSpacing.Mode )
{
case css::style::LineSpacingMode::FIX :
mnLineSpacing = static_cast<sal_Int16>(-( aLineSpacing.Height ) );
mbFixedLineSpacing = true;
break;
case css::style::LineSpacingMode::MINIMUM :
case css::style::LineSpacingMode::LEADING :
mnLineSpacing = static_cast<sal_Int16>(-( aLineSpacing.Height ) );
mbFixedLineSpacing = false;
break;
case css::style::LineSpacingMode::PROP :
default:
mnLineSpacing = aLineSpacing.Height;
break;
}
}
meLineSpacing = ePropState;
if ( ImplGetPropertyValue( u"ParaBottomMargin"_ustr, bGetPropStateValue ) )
{
double fSpacing = *o3tl::doAccess<sal_uInt32>(mAny) + convertMasterUnitToMm100(1.0) - 1;
mnLineSpacingBottom = std::round(-convertMm100ToMasterUnit(fSpacing));
}
meLineSpacingBottom = ePropState;
if ( ImplGetPropertyValue( u"ParaTopMargin"_ustr, bGetPropStateValue ) )
{
double fSpacing = *o3tl::doAccess<sal_uInt32>(mAny) + convertMasterUnitToMm100(1.0) - 1;
mnLineSpacingTop = std::round(-convertMm100ToMasterUnit(fSpacing));
}
meLineSpacingTop = ePropState;
if ( ImplGetPropertyValue( u"ParaIsForbiddenRules"_ustr, bGetPropStateValue ) )
mAny >>= mbForbiddenRules;
meForbiddenRules = ePropState;
if ( ImplGetPropertyValue( u"ParaIsHangingPunctuation"_ustr, bGetPropStateValue ) )
mAny >>= mbParagraphPunctation;
meParagraphPunctation = ePropState;
mnBiDi = 0;
if ( ImplGetPropertyValue( u"WritingMode"_ustr, bGetPropStateValue ) )
{
sal_Int16 nWritingMode = 0;
mAny >>= nWritingMode;
SvxFrameDirection eWritingMode = static_cast<SvxFrameDirection>(nWritingMode);
if ( ( eWritingMode == SvxFrameDirection::Horizontal_RL_TB )
|| ( eWritingMode == SvxFrameDirection::Vertical_RL_TB ) )
{
mnBiDi = 1;
}
}
meBiDi = ePropState;
}
void ParagraphObj::ImplConstruct( const ParagraphObj& rParagraphObj )
{
mbIsBullet = rParagraphObj.mbIsBullet;
meBullet = rParagraphObj.meBullet;
meTextAdjust = rParagraphObj.meTextAdjust;
meLineSpacing = rParagraphObj.meLineSpacing;
meLineSpacingTop = rParagraphObj.meLineSpacingTop;
meLineSpacingBottom = rParagraphObj.meLineSpacingBottom;
meForbiddenRules = rParagraphObj.meForbiddenRules;
meParagraphPunctation = rParagraphObj.meParagraphPunctation;
meBiDi =rParagraphObj.meBiDi;
mbFixedLineSpacing = rParagraphObj.mbFixedLineSpacing;
mnTextSize = rParagraphObj.mnTextSize;
mnTextAdjust = rParagraphObj.mnTextAdjust;
mnLineSpacing = rParagraphObj.mnLineSpacing;
mnLineSpacingTop = rParagraphObj.mnLineSpacingTop;
mnLineSpacingBottom = rParagraphObj.mnLineSpacingBottom;
mbFirstParagraph = rParagraphObj.mbFirstParagraph;
mbLastParagraph = rParagraphObj.mbLastParagraph;
mbParagraphPunctation = rParagraphObj.mbParagraphPunctation;
mbForbiddenRules = rParagraphObj.mbForbiddenRules;
mnBiDi = rParagraphObj.mnBiDi;
for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = rParagraphObj.begin(); it != rParagraphObj.end(); ++it )
mvPortions.push_back( std::make_unique<PortionObj>( **it ) );
maTabStop = rParagraphObj.maTabStop;
bExtendedParameters = rParagraphObj.bExtendedParameters;
nParaFlags = rParagraphObj.nParaFlags;
nBulletFlags = rParagraphObj.nBulletFlags;
sPrefix = rParagraphObj.sPrefix;
sSuffix = rParagraphObj.sSuffix;
sGraphicUrl = rParagraphObj.sGraphicUrl; // String to a graphic
aBuGraSize = rParagraphObj.aBuGraSize;
nNumberingType = rParagraphObj.nNumberingType; // this is actually a SvxEnum
nHorzAdjust = rParagraphObj.nHorzAdjust;
nBulletColor = rParagraphObj.nBulletColor;
nBulletOfs = rParagraphObj.nBulletOfs;
nStartWith = rParagraphObj.nStartWith; // start of numbering
nTextOfs = rParagraphObj.nTextOfs;
nBulletRealSize = rParagraphObj.nBulletRealSize; // scale in percent
nDepth = rParagraphObj.nDepth; // actual depth
cBulletId = rParagraphObj.cBulletId; // if Numbering Type == CharSpecial
aFontDesc = rParagraphObj.aFontDesc;
bExtendedBulletsUsed = rParagraphObj.bExtendedBulletsUsed;
nBulletId = rParagraphObj.nBulletId;
}
sal_uInt32 ParagraphObj::ImplCalculateTextPositions( sal_uInt32 nCurrentTextPosition )
{
mnTextSize = 0;
for ( std::vector<std::unique_ptr<PortionObj> >::iterator it = mvPortions.begin(); it != mvPortions.end(); ++it )
mnTextSize += (*it)->ImplCalculateTextPositions( nCurrentTextPosition + mnTextSize );
return mnTextSize;
}
ParagraphObj& ParagraphObj::operator=( const ParagraphObj& rParagraphObj )
{
if ( this != &rParagraphObj )
{
ImplClear();
ImplConstruct( rParagraphObj );
}
return *this;
}
struct ImplTextObj
{
sal_uInt32 mnTextSize;
int mnInstance;
std::vector<std::unique_ptr<ParagraphObj>> maList;
bool mbHasExtendedBullets;
explicit ImplTextObj( int nInstance );
};
ImplTextObj::ImplTextObj( int nInstance )
: mnTextSize(0),
mnInstance(nInstance),
mbHasExtendedBullets(false)
{
}
TextObj::TextObj( css::uno::Reference< css::text::XSimpleText > const & rXTextRef,
int nInstance, FontCollection& rFontCollection, PPTExBulletProvider& rProv ):
mpImplTextObj(std::make_shared<ImplTextObj>(nInstance))
{
css::uno::Reference< css::container::XEnumerationAccess > aXTextParagraphEA( rXTextRef, css::uno::UNO_QUERY );
if ( aXTextParagraphEA.is() )
{
css::uno::Reference< css::container::XEnumeration > aXTextParagraphE( aXTextParagraphEA->createEnumeration() );
if ( aXTextParagraphE.is() )
{
ParaFlags aParaFlags;
while ( aXTextParagraphE->hasMoreElements() )
{
css::uno::Reference< css::text::XTextContent > aXParagraph;
css::uno::Any aAny( aXTextParagraphE->nextElement() );
if ( aAny >>= aXParagraph )
{
if ( !aXTextParagraphE->hasMoreElements() )
aParaFlags.bLastParagraph = true;
std::unique_ptr<ParagraphObj> pPara(new ParagraphObj( aXParagraph, aParaFlags, rFontCollection, rProv ));
mpImplTextObj->mbHasExtendedBullets |= pPara->bExtendedBulletsUsed;
mpImplTextObj->maList.push_back( std::move(pPara) );
aParaFlags.bFirstParagraph = false;
}
}
}
}
ImplCalculateTextPositions();
}
void TextObj::ImplCalculateTextPositions()
{
mpImplTextObj->mnTextSize = 0;
for ( sal_uInt32 i = 0; i < ParagraphCount(); ++i )
mpImplTextObj->mnTextSize += GetParagraph(i)->ImplCalculateTextPositions( mpImplTextObj->mnTextSize );
}
ParagraphObj* TextObj::GetParagraph(int idx)
{
return mpImplTextObj->maList[idx].get();
}
sal_uInt32 TextObj::ParagraphCount() const
{
return mpImplTextObj->maList.size();
}
sal_uInt32 TextObj::Count() const
{
return mpImplTextObj->mnTextSize;
}
int TextObj::GetInstance() const
{
return mpImplTextObj->mnInstance;
}
bool TextObj::HasExtendedBullets() const
{
return mpImplTextObj->mbHasExtendedBullets;
}
void FontCollectionEntry::ImplInit( const OUString& rName )
{
OUString aSubstName( GetSubsFontName( rName, SubsFontFlags::ONLYONE | SubsFontFlags::MS ) );
if ( !aSubstName.isEmpty() )
{
Name = aSubstName;
}
else
{
Name = rName;
}
}
FontCollection::~FontCollection()
{
pVDev.disposeAndClear();
xPPTBreakIter = nullptr;
}
FontCollection::FontCollection() :
pVDev ( nullptr )
{
xPPTBreakIter = css::i18n::BreakIterator::create( ::comphelper::getProcessComponentContext() );
}
short FontCollection::GetScriptDirection( std::u16string_view rString )
{
short nRet = ScriptTypeDetector::getScriptDirection( rString, 0, css::i18n::ScriptDirection::NEUTRAL );
return nRet;
}
sal_uInt32 FontCollection::GetId( FontCollectionEntry& rEntry )
{
if( !rEntry.Name.isEmpty() )
{
const sal_uInt32 nFonts = maFonts.size();
for( sal_uInt32 i = 0; i < nFonts; i++ )
{
const FontCollectionEntry* pEntry = GetById( i );
if( pEntry->Name == rEntry.Name )
return i;
}
vcl::Font aFont;
aFont.SetCharSet( rEntry.CharSet );
aFont.SetFamilyName( rEntry.Original );
aFont.SetFontHeight( 100 );
if ( !pVDev )
pVDev = VclPtr<VirtualDevice>::Create();
pVDev->SetFont( aFont );
FontMetric aMetric( pVDev->GetFontMetric() );
sal_uInt16 nTxtHeight = static_cast<sal_uInt16>(aMetric.GetAscent()) + static_cast<sal_uInt16>(aMetric.GetDescent());
if ( nTxtHeight )
{
double fScaling = static_cast<double>(nTxtHeight) / 120.0;
if ( ( fScaling > 0.50 ) && ( fScaling < 1.5 ) )
rEntry.Scaling = fScaling;
}
maFonts.push_back(rEntry);
return nFonts;
}
return 0;
}
const FontCollectionEntry* FontCollection::GetById( sal_uInt32 nId )
{
return nId < maFonts.size() ? &maFonts[nId] : nullptr;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V547 Expression 'bBool' is always false.
↑ V547 Expression '!bBool' is always true.
↑ V547 Expression '!bBool' is always true.
↑ V547 Expression '!bBool' is always true.
↑ V785 Constant expression in switch statement.