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 <oox/helper/attributelist.hxx>
21 #include <oox/vml/vmlformatting.hxx>
22 #include <oox/vml/vmltextboxcontext.hxx>
23 #include <oox/vml/vmlshape.hxx>
24 #include <oox/token/namespaces.hxx>
25 #include <oox/token/tokens.hxx>
26 #include <com/sun/star/drawing/XShape.hpp>
27 #include <osl/diagnose.h>
28 #include <sal/log.hxx>
33 using ::oox::core::ContextHandler2
;
34 using ::oox::core::ContextHandler2Helper
;
35 using ::oox::core::ContextHandlerRef
;
37 TextPortionContext::TextPortionContext( ContextHandler2Helper
const & rParent
,
38 TextBox
& rTextBox
, TextParagraphModel
const & rParagraph
, const TextFontModel
& rParentFont
,
39 sal_Int32 nElement
, const AttributeList
& rAttribs
) :
40 ContextHandler2( rParent
),
41 mrTextBox( rTextBox
),
42 maParagraph( rParagraph
),
43 maFont( rParentFont
),
44 mnInitialPortions( rTextBox
.getPortionCount() )
49 maFont
.moName
= rAttribs
.getXString( XML_face
);
50 maFont
.moColor
= rAttribs
.getXString( XML_color
);
51 maFont
.monSize
= rAttribs
.getInteger( XML_size
);
54 OSL_ENSURE( !maFont
.monUnderline
, "TextPortionContext::TextPortionContext - nested <u> elements" );
55 maFont
.monUnderline
= (rAttribs
.getToken( XML_class
, XML_TOKEN_INVALID
) == XML_font4
) ? XML_double
: XML_single
;
59 OSL_ENSURE( !maFont
.monEscapement
, "TextPortionContext::TextPortionContext - nested <sub> or <sup> elements" );
60 maFont
.monEscapement
= nElement
;
63 OSL_ENSURE( !maFont
.mobBold
, "TextPortionContext::TextPortionContext - nested <b> elements" );
64 maFont
.mobBold
= true;
67 OSL_ENSURE( !maFont
.mobItalic
, "TextPortionContext::TextPortionContext - nested <i> elements" );
68 maFont
.mobItalic
= true;
71 OSL_ENSURE( !maFont
.mobStrikeout
, "TextPortionContext::TextPortionContext - nested <s> elements" );
72 maFont
.mobStrikeout
= true;
74 case OOX_TOKEN(dml
, blip
):
76 OptValue
<OUString
> oRelId
= rAttribs
.getString(R_TOKEN(embed
));
78 mrTextBox
.mrTypeModel
.moGraphicPath
= getFragmentPathFromRelId(oRelId
.get());
81 case VML_TOKEN(imagedata
):
83 OptValue
<OUString
> oRelId
= rAttribs
.getString(R_TOKEN(id
));
85 mrTextBox
.mrTypeModel
.moGraphicPath
= getFragmentPathFromRelId(oRelId
.get());
92 OSL_ENSURE( false, "TextPortionContext::TextPortionContext - unknown element" );
96 ContextHandlerRef
TextPortionContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
98 OSL_ENSURE( nElement
!= XML_font
, "TextPortionContext::onCreateContext - nested <font> elements" );
99 if (getNamespace(getCurrentElement()) == NMSP_doc
)
101 return new TextPortionContext( *this, mrTextBox
, maParagraph
, maFont
, nElement
, rAttribs
);
104 void TextPortionContext::onCharacters( const OUString
& rChars
)
106 if (getNamespace(getCurrentElement()) == NMSP_doc
&& getCurrentElement() != W_TOKEN(t
))
109 switch( getCurrentElement() )
112 // replace all NBSP characters with SP
113 mrTextBox
.appendPortion( maParagraph
, maFont
, rChars
.replace( 0xA0, ' ' ) );
116 mrTextBox
.appendPortion( maParagraph
, maFont
, rChars
);
120 void TextPortionContext::onStartElement(const AttributeList
& rAttribs
)
122 switch (getCurrentElement())
125 maFont
.mobBold
= true;
128 maFont
.monSize
= rAttribs
.getInteger( W_TOKEN(val
) );
131 mrTextBox
.appendPortion( maParagraph
, maFont
, "\n" );
134 maFont
.moColor
= rAttribs
.getString( W_TOKEN(val
) );
136 case W_TOKEN(spacing
):
137 maFont
.monSpacing
= rAttribs
.getInteger(W_TOKEN(val
));
143 case W_TOKEN(rFonts
):
144 // See https://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.runfonts(v=office.14).aspx
145 maFont
.moName
= rAttribs
.getString(W_TOKEN(ascii
));
146 maFont
.moNameAsian
= rAttribs
.getString(W_TOKEN(eastAsia
));
147 maFont
.moNameComplex
= rAttribs
.getString(W_TOKEN(cs
));
150 SAL_INFO("oox", "unhandled: 0x" << std::hex
<< getCurrentElement());
155 void TextPortionContext::onEndElement()
157 if (getNamespace(getCurrentElement()) == NMSP_doc
&& getCurrentElement() != W_TOKEN(t
))
160 /* A child element without own child elements may contain a single space
161 character, for example:
164 <font><i>abc</i></font>
166 <font><b>def</b></font>
169 represents the italic text 'abc', an unformatted space character, and
170 the bold text 'def'. Unfortunately, the XML parser skips the space
171 character without issuing a 'characters' event. The class member
172 'mnInitialPortions' contains the number of text portions existing when
173 this context has been constructed. If no text has been added in the
174 meantime, the space character has to be added manually.
176 if( mrTextBox
.getPortionCount() == mnInitialPortions
)
177 mrTextBox
.appendPortion( maParagraph
, maFont
, OUString( ' ' ) );
180 TextBoxContext::TextBoxContext( ContextHandler2Helper
const & rParent
, TextBox
& rTextBox
, const AttributeList
& rAttribs
,
181 const GraphicHelper
& graphicHelper
) :
182 ContextHandler2( rParent
),
183 mrTextBox( rTextBox
)
185 if( rAttribs
.getString( XML_insetmode
).get() != "auto" )
187 OUString inset
= rAttribs
.getString( XML_inset
).get();
189 OUString remainingStr
;
191 ConversionHelper::separatePair( value
, remainingStr
, inset
, ',' );
192 rTextBox
.borderDistanceLeft
= ConversionHelper::decodeMeasureToHmm( graphicHelper
,
193 value
.isEmpty() ? "0.1in" : value
, 0, false, false );
195 inset
= remainingStr
;
196 ConversionHelper::separatePair( value
, remainingStr
, inset
, ',' );
197 rTextBox
.borderDistanceTop
= ConversionHelper::decodeMeasureToHmm( graphicHelper
,
198 value
.isEmpty() ? "0.05in" : value
, 0, false, false );
200 inset
= remainingStr
;
201 ConversionHelper::separatePair( value
, remainingStr
, inset
, ',' );
202 rTextBox
.borderDistanceRight
= ConversionHelper::decodeMeasureToHmm( graphicHelper
,
203 value
.isEmpty() ? "0.1in" : value
, 0, false, false );
205 inset
= remainingStr
;
206 ConversionHelper::separatePair( value
, remainingStr
, inset
, ',' );
207 rTextBox
.borderDistanceBottom
= ConversionHelper::decodeMeasureToHmm( graphicHelper
,
208 value
.isEmpty() ? "0.05in" : value
, 0, false, false );
210 rTextBox
.borderDistanceSet
= true;
213 OUString sStyle
= rAttribs
.getString( XML_style
, OUString() );
214 sal_Int32 nIndex
= 0;
217 OUString aName
, aValue
;
218 if( ConversionHelper::separatePair( aName
, aValue
, sStyle
.getToken( 0, ';', nIndex
), ':' ) )
220 if( aName
== "layout-flow" ) rTextBox
.maLayoutFlow
= aValue
;
221 else if (aName
== "mso-fit-shape-to-text")
222 rTextBox
.mrTypeModel
.mbAutoHeight
= true;
223 else if (aName
== "mso-layout-flow-alt")
224 rTextBox
.mrTypeModel
.maLayoutFlowAlt
= aValue
;
225 else if (aName
== "mso-next-textbox")
226 rTextBox
.msNextTextbox
= aValue
;
228 SAL_WARN("oox", "unhandled style property: " << aName
);
233 ContextHandlerRef
TextBoxContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
235 switch( getCurrentElement() )
237 case VML_TOKEN( textbox
):
238 if( nElement
== XML_div
) return this;
239 else if (nElement
== W_TOKEN(txbxContent
)) return this;
242 if( nElement
== XML_font
) return new TextPortionContext( *this, mrTextBox
, maParagraph
, TextFontModel(), nElement
, rAttribs
);
244 case W_TOKEN(txbxContent
):
245 if (nElement
== W_TOKEN(p
)) return this;
248 case W_TOKEN(sdtContent
):
249 case W_TOKEN(smartTag
):
250 if (nElement
== W_TOKEN(r
))
251 return new TextPortionContext( *this, mrTextBox
, maParagraph
, TextFontModel(), nElement
, rAttribs
);
260 SAL_INFO("oox", "unhandled 0x" << std::hex
<< getCurrentElement());
266 void TextBoxContext::onStartElement(const AttributeList
& rAttribs
)
268 switch (getCurrentElement())
271 maParagraph
.moParaAdjust
= rAttribs
.getString( W_TOKEN(val
) );
276 void TextBoxContext::onEndElement()
278 if (getCurrentElement() == W_TOKEN(p
))
280 mrTextBox
.appendPortion( maParagraph
, TextFontModel(), "\n" );
281 maParagraph
= TextParagraphModel();
288 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */