1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <drawingml/textparagraphpropertiescontext.hxx>
22 #include <com/sun/star/text/WritingMode2.hpp>
23 #include <com/sun/star/style/ParagraphAdjust.hpp>
24 #include <com/sun/star/xml/sax/SAXException.hpp>
25 #include <com/sun/star/graphic/XGraphic.hpp>
26 #include <com/sun/star/awt/Size.hpp>
27 #include <com/sun/star/uno/Reference.hxx>
29 #include <sal/log.hxx>
30 #include <comphelper/diagnose_ex.hxx>
31 #include <tools/UnitConversion.hxx>
33 #include <drawingml/colorchoicecontext.hxx>
34 #include <drawingml/misccontexts.hxx>
35 #include <drawingml/textcharacterpropertiescontext.hxx>
36 #include <drawingml/fillproperties.hxx>
37 #include <oox/helper/attributelist.hxx>
38 #include "textspacingcontext.hxx"
39 #include "texttabstoplistcontext.hxx"
40 #include <oox/token/namespaces.hxx>
41 #include <oox/token/properties.hxx>
42 #include <oox/token/tokens.hxx>
44 using namespace ::oox::core
;
45 using namespace ::com::sun::star::uno
;
46 using namespace ::com::sun::star::xml::sax
;
47 using namespace ::com::sun::star::style
;
48 using namespace ::com::sun::star::text
;
49 using namespace ::com::sun::star::graphic
;
51 namespace oox::drawingml
{
54 double lclGetGraphicAspectRatio( const Reference
< XGraphic
>& rxGraphic
)
57 Reference
< com::sun::star::beans::XPropertySet
> xGraphicPropertySet( rxGraphic
, UNO_QUERY_THROW
);
58 css::awt::Size
aSizeHmm( 0, 0 );
59 xGraphicPropertySet
->getPropertyValue( "Size100thMM" ) >>= aSizeHmm
;
61 if( aSizeHmm
.Width
> 0 && aSizeHmm
.Height
> 0)
62 return double(aSizeHmm
.Width
)/double(aSizeHmm
.Height
);
65 css::awt::Size
aSourceSizePixel( 0, 0 );
66 xGraphicPropertySet
->getPropertyValue( "SizePixel" ) >>= aSourceSizePixel
;
68 if( aSourceSizePixel
.Width
> 0 && aSourceSizePixel
.Height
> 0 )
69 return double(aSourceSizePixel
.Width
)/double(aSourceSizePixel
.Height
);
76 // CT_TextParagraphProperties
77 TextParagraphPropertiesContext::TextParagraphPropertiesContext( ContextHandler2Helper
const & rParent
,
78 const AttributeList
& rAttribs
,
79 TextParagraphProperties
& rTextParagraphProperties
)
80 : ContextHandler2( rParent
)
81 , mrTextParagraphProperties( rTextParagraphProperties
)
82 , mrBulletList( rTextParagraphProperties
.getBulletList() )
86 PropertyMap
& rPropertyMap( mrTextParagraphProperties
.getTextParagraphPropertyMap() );
89 if ( rAttribs
.hasAttribute( XML_algn
) )
91 mrTextParagraphProperties
.getParaAdjust() = GetParaAdjust( rAttribs
.getToken( XML_algn
, XML_l
) );
93 // TODO see to do the same with RubyAdjust
96 if ( rAttribs
.hasAttribute(XML_defTabSz
))
98 sValue
= rAttribs
.getStringDefaulted(XML_defTabSz
);
101 mrTextParagraphProperties
.getDefaultTabSize() = GetCoordinate(sValue
);
105 // bool bEaLineBrk = rAttribs.getBool( XML_eaLnBrk, true );
106 if ( rAttribs
.hasAttribute( XML_latinLnBrk
) )
108 bool bLatinLineBrk
= rAttribs
.getBool( XML_latinLnBrk
, true );
109 rPropertyMap
.setProperty( PROP_ParaIsHyphenation
, bLatinLineBrk
);
111 // TODO see what to do with Asian hyphenation
113 // ST_TextFontAlignType
115 // sal_Int32 nFontAlign = rAttribs.getToken( XML_fontAlgn, XML_base );
117 if ( rAttribs
.hasAttribute( XML_hangingPunct
) )
119 bool bHangingPunct
= rAttribs
.getBool( XML_hangingPunct
, false );
120 rPropertyMap
.setProperty( PROP_ParaIsHangingPunctuation
, bHangingPunct
);
124 if ( rAttribs
.hasAttribute( XML_indent
) )
126 sValue
= rAttribs
.getStringDefaulted( XML_indent
);
127 mrTextParagraphProperties
.getFirstLineIndentation() = std::optional
< sal_Int32
>( sValue
.isEmpty() ? 0 : GetCoordinate( sValue
) );
130 // ST_TextIndentLevelType
131 // -1 is an invalid value and denote the lack of level
132 sal_Int32 nLevel
= rAttribs
.getInteger( XML_lvl
, 0 );
133 if( nLevel
> 8 || nLevel
< 0 )
138 mrTextParagraphProperties
.setLevel( static_cast< sal_Int16
>( nLevel
) );
140 char name
[] = "Outline X";
141 name
[8] = static_cast<char>( '1' + nLevel
);
142 const OUString
sStyleNameValue( OUString::createFromAscii( name
) );
143 mrBulletList
.setStyleName( sStyleNameValue
);
147 if ( rAttribs
.hasAttribute( XML_marL
) )
149 sValue
= rAttribs
.getStringDefaulted( XML_marL
);
150 mrTextParagraphProperties
.getParaLeftMargin() = std::optional
< sal_Int32
>( sValue
.isEmpty() ? 0 : GetCoordinate( sValue
) );
154 if ( rAttribs
.hasAttribute( XML_marR
) )
156 sValue
= rAttribs
.getStringDefaulted( XML_marR
);
157 sal_Int32 nMarR
= sValue
.isEmpty() ? 0 : GetCoordinate( sValue
) ;
158 rPropertyMap
.setProperty( PROP_ParaRightMargin
, nMarR
);
161 if ( rAttribs
.hasAttribute( XML_rtl
) )
163 bool bRtl
= rAttribs
.getBool( XML_rtl
, false );
164 rPropertyMap
.setProperty( PROP_WritingMode
, ( bRtl
? WritingMode2::RL_TB
: WritingMode2::LR_TB
));
168 TextParagraphPropertiesContext::~TextParagraphPropertiesContext()
170 PropertyMap
& rPropertyMap( mrTextParagraphProperties
.getTextParagraphPropertyMap() );
171 if ( mrTextParagraphProperties
.getLineSpacing().bHasValue
)
172 rPropertyMap
.setProperty( PROP_ParaLineSpacing
, mrTextParagraphProperties
.getLineSpacing().toLineSpacing());
174 rPropertyMap
.setProperty( PROP_ParaLineSpacing
, css::style::LineSpacing( css::style::LineSpacingMode::PROP
, 100 ));
176 ::std::vector
< TabStop
>::size_type nTabCount
= maTabList
.size();
179 Sequence
< TabStop
> aSeq( nTabCount
);
180 TabStop
* aArray
= aSeq
.getArray();
181 OSL_ENSURE( aArray
!= nullptr, "sequence array is NULL" );
182 ::std::copy( maTabList
.begin(), maTabList
.end(), aArray
);
183 rPropertyMap
.setProperty( PROP_ParaTabStops
, aSeq
);
186 if (mxBlipProps
&& mxBlipProps
->mxFillGraphic
.is())
188 mrBulletList
.setGraphic( mxBlipProps
->mxFillGraphic
);
189 mrBulletList
.setBulletAspectRatio( lclGetGraphicAspectRatio(mxBlipProps
->mxFillGraphic
) );
192 if( mrBulletList
.is() )
193 rPropertyMap
.setProperty( PROP_IsNumbering
, true);
194 sal_Int16 nLevel
= mrTextParagraphProperties
.getLevel();
195 rPropertyMap
.setProperty( PROP_NumberingLevel
, nLevel
);
196 rPropertyMap
.setProperty( PROP_NumberingIsNumber
, true);
198 if( mrTextParagraphProperties
.getParaAdjust() )
199 rPropertyMap
.setProperty( PROP_ParaAdjust
, *mrTextParagraphProperties
.getParaAdjust());
202 ContextHandlerRef
TextParagraphPropertiesContext::onCreateContext( sal_Int32 aElementToken
, const AttributeList
& rAttribs
)
204 switch( aElementToken
)
206 case A_TOKEN( lnSpc
): // CT_TextSpacing
207 return new TextSpacingContext( *this, mrTextParagraphProperties
.getLineSpacing() );
208 case A_TOKEN( spcBef
): // CT_TextSpacing
209 return new TextSpacingContext( *this, mrTextParagraphProperties
.getParaTopMargin() );
210 case A_TOKEN( spcAft
): // CT_TextSpacing
211 return new TextSpacingContext( *this, mrTextParagraphProperties
.getParaBottomMargin() );
212 // EG_TextBulletColor
213 case A_TOKEN( buClrTx
): // CT_TextBulletColorFollowText ???
214 mrBulletList
.mbBulletColorFollowText
<<= true;
216 case A_TOKEN( buClr
): // CT_Color
217 return new ColorContext( *this, *mrBulletList
.maBulletColorPtr
);
219 case A_TOKEN( buSzTx
): // CT_TextBulletSizeFollowText
220 mrBulletList
.mbBulletSizeFollowText
<<= true;
222 case A_TOKEN( buSzPct
): // CT_TextBulletSizePercent
223 mrBulletList
.setBulletSize( std::lround( GetPercent( rAttribs
.getStringDefaulted( XML_val
) ) / 1000.f
) );
225 case A_TOKEN( buSzPts
): // CT_TextBulletSizePoint
226 mrBulletList
.setBulletSize(0);
227 mrBulletList
.setFontSize( static_cast<sal_Int16
>(GetTextSize( rAttribs
.getStringDefaulted( XML_val
) ) ) );
230 // EG_TextBulletTypeface
231 case A_TOKEN( buFontTx
): // CT_TextBulletTypefaceFollowText
232 mrBulletList
.mbBulletFontFollowText
<<= true;
234 case A_TOKEN( buFont
): // CT_TextFont
235 mrBulletList
.maBulletFont
.setAttributes( rAttribs
);
239 case A_TOKEN( buNone
): // CT_TextNoBullet
240 mrBulletList
.setNone();
242 case A_TOKEN( buAutoNum
): // CT_TextAutonumberBullet
245 sal_Int32 nType
= rAttribs
.getToken( XML_type
, 0 );
246 sal_Int32 nStartAt
= rAttribs
.getInteger( XML_startAt
, 1 );
247 if( nStartAt
> 32767 )
251 else if( nStartAt
< 1 )
255 mrBulletList
.setStartAt( nStartAt
);
256 mrBulletList
.setType( nType
);
258 catch(SAXException
& /* e */ )
260 TOOLS_WARN_EXCEPTION("oox", "OOX: SAXException in XML_buAutoNum");
264 case A_TOKEN( buChar
): // CT_TextCharBullet
267 mrBulletList
.setBulletChar( rAttribs
.getStringDefaulted( XML_char
) );
268 mrBulletList
.setSuffixNone();
270 catch(SAXException
& /* e */)
272 TOOLS_WARN_EXCEPTION("oox", "OOX: SAXException in XML_buChar");
275 case A_TOKEN( buBlip
): // CT_TextBlipBullet
277 mxBlipProps
= std::make_shared
<BlipFillProperties
>();
278 return new BlipFillContext(*this, rAttribs
, *mxBlipProps
, nullptr);
280 case A_TOKEN( tabLst
): // CT_TextTabStopList
281 return new TextTabStopListContext( *this, maTabList
);
282 case A_TOKEN( defRPr
): // CT_TextCharacterProperties
283 return new TextCharacterPropertiesContext( *this, rAttribs
, mrTextParagraphProperties
.getTextCharacterProperties() );
286 std::optional
< OUString
> oParaAdjust
= rAttribs
.getString( W_TOKEN(val
) );
287 if( oParaAdjust
.has_value() && !oParaAdjust
.value().isEmpty() )
289 const OUString
& sParaAdjust
= oParaAdjust
.value();
290 if( sParaAdjust
== "left" )
291 mrTextParagraphProperties
.setParaAdjust(ParagraphAdjust_LEFT
);
292 else if ( sParaAdjust
== "right" )
293 mrTextParagraphProperties
.setParaAdjust(ParagraphAdjust_RIGHT
);
294 else if ( sParaAdjust
== "center" )
295 mrTextParagraphProperties
.setParaAdjust(ParagraphAdjust_CENTER
);
296 else if ( sParaAdjust
== "both" )
297 mrTextParagraphProperties
.setParaAdjust(ParagraphAdjust_BLOCK
);
301 case W_TOKEN( spacing
):
304 if( !rAttribs
.getBool(W_TOKEN(beforeAutospacing
), false) )
306 std::optional
<sal_Int32
> oBefore
= rAttribs
.getInteger(W_TOKEN(before
));
307 if (oBefore
.has_value())
309 TextSpacing
& rSpacing
= mrTextParagraphProperties
.getParaTopMargin();
310 rSpacing
.nUnit
= TextSpacing::Unit::Points
;
311 rSpacing
.nValue
= convertTwipToMm100(oBefore
.value());
312 rSpacing
.bHasValue
= true;
316 std::optional
<sal_Int32
> oBeforeLines
= rAttribs
.getInteger(W_TOKEN(beforeLines
));
317 if (oBeforeLines
.has_value())
319 TextSpacing
& rSpacing
= mrTextParagraphProperties
.getParaTopMargin();
320 rSpacing
.nUnit
= TextSpacing::Unit::Percent
;
321 rSpacing
.nValue
= oBeforeLines
.value() * MAX_PERCENT
/ 100;
322 rSpacing
.bHasValue
= true;
328 if( !rAttribs
.getBool(W_TOKEN(afterAutospacing
), false) )
330 std::optional
<sal_Int32
> oAfter
= rAttribs
.getInteger(W_TOKEN(after
));
331 if (oAfter
.has_value())
333 TextSpacing
& rSpacing
= mrTextParagraphProperties
.getParaBottomMargin();
334 rSpacing
.nUnit
= TextSpacing::Unit::Points
;
335 rSpacing
.nValue
= convertTwipToMm100(oAfter
.value());
336 rSpacing
.bHasValue
= true;
340 std::optional
<sal_Int32
> oAfterLines
= rAttribs
.getInteger(W_TOKEN(afterLines
));
341 if (oAfterLines
.has_value())
343 TextSpacing
& rSpacing
= mrTextParagraphProperties
.getParaBottomMargin();
344 rSpacing
.nUnit
= TextSpacing::Unit::Percent
;
345 rSpacing
.nValue
= oAfterLines
.value() * MAX_PERCENT
/ 100;
346 rSpacing
.bHasValue
= true;
352 std::optional
<OUString
> oLineRule
= rAttribs
.getString(W_TOKEN(lineRule
));
353 std::optional
<sal_Int32
> oLineSpacing
= rAttribs
.getInteger(W_TOKEN(line
));
354 if (oLineSpacing
.has_value())
356 TextSpacing
& rLineSpacing
= mrTextParagraphProperties
.getLineSpacing();
357 if( !oLineRule
.has_value() || oLineRule
.value() == "auto" )
359 rLineSpacing
.nUnit
= TextSpacing::Unit::Percent
;
360 rLineSpacing
.nValue
= oLineSpacing
.value() * MAX_PERCENT
/ 240;
364 rLineSpacing
.nUnit
= TextSpacing::Unit::Points
;
365 rLineSpacing
.nValue
= convertTwipToMm100(oLineSpacing
.value());
367 rLineSpacing
.bHasValue
= true;
372 SAL_WARN("oox", "TextParagraphPropertiesContext::onCreateContext: unhandled element: " << getBaseToken(aElementToken
));
379 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */