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 <svx/unopage.hxx>
30 #include <sal/log.hxx>
31 #include <tools/diagnose_ex.h>
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 // sValue = rAttribs.getString( XML_defTabSz ).get(); SJ: we need to be able to set the default tab size for each text object,
97 // this is possible at the moment only for the whole document.
98 // sal_Int32 nDefTabSize = ( sValue.getLength() == 0 ? 0 : GetCoordinate( sValue ) );
101 // bool bEaLineBrk = rAttribs.getBool( XML_eaLnBrk, true );
102 if ( rAttribs
.hasAttribute( XML_latinLnBrk
) )
104 bool bLatinLineBrk
= rAttribs
.getBool( XML_latinLnBrk
, true );
105 rPropertyMap
.setProperty( PROP_ParaIsHyphenation
, bLatinLineBrk
);
107 // TODO see what to do with Asian hyphenation
109 // ST_TextFontAlignType
111 // sal_Int32 nFontAlign = rAttribs.getToken( XML_fontAlgn, XML_base );
113 if ( rAttribs
.hasAttribute( XML_hangingPunct
) )
115 bool bHangingPunct
= rAttribs
.getBool( XML_hangingPunct
, false );
116 rPropertyMap
.setProperty( PROP_ParaIsHangingPunctuation
, bHangingPunct
);
120 if ( rAttribs
.hasAttribute( XML_indent
) )
122 sValue
= rAttribs
.getString( XML_indent
).get();
123 mrTextParagraphProperties
.getFirstLineIndentation() = std::optional
< sal_Int32
>( sValue
.isEmpty() ? 0 : GetCoordinate( sValue
) );
126 // ST_TextIndentLevelType
127 // -1 is an invalid value and denote the lack of level
128 sal_Int32 nLevel
= rAttribs
.getInteger( XML_lvl
, 0 );
129 if( nLevel
> 8 || nLevel
< 0 )
134 mrTextParagraphProperties
.setLevel( static_cast< sal_Int16
>( nLevel
) );
136 char name
[] = "Outline X";
137 name
[8] = static_cast<char>( '1' + nLevel
);
138 const OUString
sStyleNameValue( OUString::createFromAscii( name
) );
139 mrBulletList
.setStyleName( sStyleNameValue
);
143 if ( rAttribs
.hasAttribute( XML_marL
) )
145 sValue
= rAttribs
.getString( XML_marL
).get();
146 mrTextParagraphProperties
.getParaLeftMargin() = std::optional
< sal_Int32
>( sValue
.isEmpty() ? 0 : GetCoordinate( sValue
) );
150 if ( rAttribs
.hasAttribute( XML_marR
) )
152 sValue
= rAttribs
.getString( XML_marR
).get();
153 sal_Int32 nMarR
= sValue
.isEmpty() ? 0 : GetCoordinate( sValue
) ;
154 rPropertyMap
.setProperty( PROP_ParaRightMargin
, nMarR
);
157 if ( rAttribs
.hasAttribute( XML_rtl
) )
159 bool bRtl
= rAttribs
.getBool( XML_rtl
, false );
160 rPropertyMap
.setProperty( PROP_WritingMode
, ( bRtl
? WritingMode2::RL_TB
: WritingMode2::LR_TB
));
164 TextParagraphPropertiesContext::~TextParagraphPropertiesContext()
166 PropertyMap
& rPropertyMap( mrTextParagraphProperties
.getTextParagraphPropertyMap() );
167 if ( mrTextParagraphProperties
.getLineSpacing().bHasValue
)
168 rPropertyMap
.setProperty( PROP_ParaLineSpacing
, mrTextParagraphProperties
.getLineSpacing().toLineSpacing());
170 rPropertyMap
.setProperty( PROP_ParaLineSpacing
, css::style::LineSpacing( css::style::LineSpacingMode::PROP
, 100 ));
172 ::std::vector
< TabStop
>::size_type nTabCount
= maTabList
.size();
175 Sequence
< TabStop
> aSeq( nTabCount
);
176 TabStop
* aArray
= aSeq
.getArray();
177 OSL_ENSURE( aArray
!= nullptr, "sequence array is NULL" );
178 ::std::copy( maTabList
.begin(), maTabList
.end(), aArray
);
179 rPropertyMap
.setProperty( PROP_ParaTabStops
, aSeq
);
182 if (mxBlipProps
&& mxBlipProps
->mxFillGraphic
.is())
184 mrBulletList
.setGraphic( mxBlipProps
->mxFillGraphic
);
185 mrBulletList
.setBulletAspectRatio( lclGetGraphicAspectRatio(mxBlipProps
->mxFillGraphic
) );
188 if( mrBulletList
.is() )
189 rPropertyMap
.setProperty( PROP_IsNumbering
, true);
190 sal_Int16 nLevel
= mrTextParagraphProperties
.getLevel();
191 rPropertyMap
.setProperty( PROP_NumberingLevel
, nLevel
);
192 rPropertyMap
.setProperty( PROP_NumberingIsNumber
, true);
194 if( mrTextParagraphProperties
.getParaAdjust() )
195 rPropertyMap
.setProperty( PROP_ParaAdjust
, *mrTextParagraphProperties
.getParaAdjust());
198 ContextHandlerRef
TextParagraphPropertiesContext::onCreateContext( sal_Int32 aElementToken
, const AttributeList
& rAttribs
)
200 switch( aElementToken
)
202 case A_TOKEN( lnSpc
): // CT_TextSpacing
203 return new TextSpacingContext( *this, mrTextParagraphProperties
.getLineSpacing() );
204 case A_TOKEN( spcBef
): // CT_TextSpacing
205 return new TextSpacingContext( *this, mrTextParagraphProperties
.getParaTopMargin() );
206 case A_TOKEN( spcAft
): // CT_TextSpacing
207 return new TextSpacingContext( *this, mrTextParagraphProperties
.getParaBottomMargin() );
208 // EG_TextBulletColor
209 case A_TOKEN( buClrTx
): // CT_TextBulletColorFollowText ???
210 mrBulletList
.mbBulletColorFollowText
<<= true;
212 case A_TOKEN( buClr
): // CT_Color
213 return new ColorContext( *this, *mrBulletList
.maBulletColorPtr
);
215 case A_TOKEN( buSzTx
): // CT_TextBulletSizeFollowText
216 mrBulletList
.setBulletSize(100);
218 case A_TOKEN( buSzPct
): // CT_TextBulletSizePercent
219 mrBulletList
.setBulletSize( std::lround( GetPercent( rAttribs
.getString( XML_val
).get() ) / 1000.f
) );
221 case A_TOKEN( buSzPts
): // CT_TextBulletSizePoint
222 mrBulletList
.setBulletSize(0);
223 mrBulletList
.setFontSize( static_cast<sal_Int16
>(GetTextSize( rAttribs
.getString( XML_val
).get() ) ) );
226 // EG_TextBulletTypeface
227 case A_TOKEN( buFontTx
): // CT_TextBulletTypefaceFollowText
228 mrBulletList
.mbBulletFontFollowText
<<= true;
230 case A_TOKEN( buFont
): // CT_TextFont
231 mrBulletList
.maBulletFont
.setAttributes( rAttribs
);
235 case A_TOKEN( buNone
): // CT_TextNoBullet
236 mrBulletList
.setNone();
238 case A_TOKEN( buAutoNum
): // CT_TextAutonumberBullet
241 sal_Int32 nType
= rAttribs
.getToken( XML_type
, 0 );
242 sal_Int32 nStartAt
= rAttribs
.getInteger( XML_startAt
, 1 );
243 if( nStartAt
> 32767 )
247 else if( nStartAt
< 1 )
251 mrBulletList
.setStartAt( nStartAt
);
252 mrBulletList
.setType( nType
);
254 catch(SAXException
& /* e */ )
256 TOOLS_WARN_EXCEPTION("oox", "OOX: SAXException in XML_buAutoNum");
260 case A_TOKEN( buChar
): // CT_TextCharBullet
263 mrBulletList
.setBulletChar( rAttribs
.getString( XML_char
).get() );
264 mrBulletList
.setSuffixNone();
266 catch(SAXException
& /* e */)
268 TOOLS_WARN_EXCEPTION("oox", "OOX: SAXException in XML_buChar");
271 case A_TOKEN( buBlip
): // CT_TextBlipBullet
273 mxBlipProps
= std::make_shared
<BlipFillProperties
>();
274 return new BlipFillContext( *this, rAttribs
, *mxBlipProps
);
276 case A_TOKEN( tabLst
): // CT_TextTabStopList
277 return new TextTabStopListContext( *this, maTabList
);
278 case A_TOKEN( defRPr
): // CT_TextCharacterProperties
279 return new TextCharacterPropertiesContext( *this, rAttribs
, mrTextParagraphProperties
.getTextCharacterProperties() );
282 OptValue
< OUString
> oParaAdjust
= rAttribs
.getString( W_TOKEN(val
) );
283 if( oParaAdjust
.has() && !oParaAdjust
.get().isEmpty() )
285 const OUString
& sParaAdjust
= oParaAdjust
.get();
286 if( sParaAdjust
== "left" )
287 mrTextParagraphProperties
.setParaAdjust(ParagraphAdjust_LEFT
);
288 else if ( sParaAdjust
== "right" )
289 mrTextParagraphProperties
.setParaAdjust(ParagraphAdjust_RIGHT
);
290 else if ( sParaAdjust
== "center" )
291 mrTextParagraphProperties
.setParaAdjust(ParagraphAdjust_CENTER
);
292 else if ( sParaAdjust
== "both" )
293 mrTextParagraphProperties
.setParaAdjust(ParagraphAdjust_BLOCK
);
297 case W_TOKEN( spacing
):
300 if( !rAttribs
.getBool(W_TOKEN(beforeAutospacing
), false) )
302 OptValue
<sal_Int32
> oBefore
= rAttribs
.getInteger(W_TOKEN(before
));
305 TextSpacing
& rSpacing
= mrTextParagraphProperties
.getParaTopMargin();
306 rSpacing
.nUnit
= TextSpacing::Unit::Points
;
307 rSpacing
.nValue
= TWIPS_TO_MM(oBefore
.get());
308 rSpacing
.bHasValue
= true;
312 OptValue
<sal_Int32
> oBeforeLines
= rAttribs
.getInteger(W_TOKEN(beforeLines
));
313 if (oBeforeLines
.has())
315 TextSpacing
& rSpacing
= mrTextParagraphProperties
.getParaTopMargin();
316 rSpacing
.nUnit
= TextSpacing::Unit::Percent
;
317 rSpacing
.nValue
= oBeforeLines
.get() * MAX_PERCENT
/ 100;
318 rSpacing
.bHasValue
= true;
324 if( !rAttribs
.getBool(W_TOKEN(afterAutospacing
), false) )
326 OptValue
<sal_Int32
> oAfter
= rAttribs
.getInteger(W_TOKEN(after
));
329 TextSpacing
& rSpacing
= mrTextParagraphProperties
.getParaBottomMargin();
330 rSpacing
.nUnit
= TextSpacing::Unit::Points
;
331 rSpacing
.nValue
= TWIPS_TO_MM(oAfter
.get());
332 rSpacing
.bHasValue
= true;
336 OptValue
<sal_Int32
> oAfterLines
= rAttribs
.getInteger(W_TOKEN(afterLines
));
337 if (oAfterLines
.has())
339 TextSpacing
& rSpacing
= mrTextParagraphProperties
.getParaBottomMargin();
340 rSpacing
.nUnit
= TextSpacing::Unit::Percent
;
341 rSpacing
.nValue
= oAfterLines
.get() * MAX_PERCENT
/ 100;
342 rSpacing
.bHasValue
= true;
348 OptValue
<OUString
> oLineRule
= rAttribs
.getString(W_TOKEN(lineRule
));
349 OptValue
<sal_Int32
> oLineSpacing
= rAttribs
.getInteger(W_TOKEN(line
));
350 if (oLineSpacing
.has())
352 TextSpacing
& rLineSpacing
= mrTextParagraphProperties
.getLineSpacing();
353 if( !oLineRule
.has() || oLineRule
.get() == "auto" )
355 rLineSpacing
.nUnit
= TextSpacing::Unit::Percent
;
356 rLineSpacing
.nValue
= oLineSpacing
.get() * MAX_PERCENT
/ 240;
360 rLineSpacing
.nUnit
= TextSpacing::Unit::Points
;
361 rLineSpacing
.nValue
= TWIPS_TO_MM(oLineSpacing
.get());
363 rLineSpacing
.bHasValue
= true;
368 SAL_WARN("oox", "TextParagraphPropertiesContext::onCreateContext: unhandled element: " << getBaseToken(aElementToken
));
375 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */