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 <osl/diagnose.h>
27 #include <sal/log.hxx>
31 using ::oox::core::ContextHandler2
;
32 using ::oox::core::ContextHandler2Helper
;
33 using ::oox::core::ContextHandlerRef
;
35 TextPortionContext::TextPortionContext( ContextHandler2Helper
const & rParent
,
36 TextBox
& rTextBox
, TextParagraphModel
const & rParagraph
, const TextFontModel
& rParentFont
,
37 sal_Int32 nElement
, const AttributeList
& rAttribs
) :
38 ContextHandler2( rParent
),
39 mrTextBox( rTextBox
),
40 maParagraph( rParagraph
),
41 maFont( rParentFont
),
42 mnInitialPortions( rTextBox
.getPortionCount() )
47 maFont
.moName
= rAttribs
.getXString( XML_face
);
48 maFont
.moColor
= rAttribs
.getXString( XML_color
);
49 maFont
.monSize
= rAttribs
.getInteger( XML_size
);
52 OSL_ENSURE( !maFont
.monUnderline
, "TextPortionContext::TextPortionContext - nested <u> elements" );
53 maFont
.monUnderline
= (rAttribs
.getToken( XML_class
, XML_TOKEN_INVALID
) == XML_font4
) ? XML_double
: XML_single
;
57 OSL_ENSURE( !maFont
.monEscapement
, "TextPortionContext::TextPortionContext - nested <sub> or <sup> elements" );
58 maFont
.monEscapement
= nElement
;
61 OSL_ENSURE( !maFont
.mobBold
, "TextPortionContext::TextPortionContext - nested <b> elements" );
62 maFont
.mobBold
= true;
65 OSL_ENSURE( !maFont
.mobItalic
, "TextPortionContext::TextPortionContext - nested <i> elements" );
66 maFont
.mobItalic
= true;
69 OSL_ENSURE( !maFont
.mobStrikeout
, "TextPortionContext::TextPortionContext - nested <s> elements" );
70 maFont
.mobStrikeout
= true;
72 case OOX_TOKEN(dml
, blip
):
74 OptValue
<OUString
> oRelId
= rAttribs
.getString(R_TOKEN(embed
));
76 mrTextBox
.mrTypeModel
.moGraphicPath
= getFragmentPathFromRelId(oRelId
.get());
79 case VML_TOKEN(imagedata
):
81 OptValue
<OUString
> oRelId
= rAttribs
.getString(R_TOKEN(id
));
83 mrTextBox
.mrTypeModel
.moGraphicPath
= getFragmentPathFromRelId(oRelId
.get());
90 OSL_ENSURE( false, "TextPortionContext::TextPortionContext - unknown element" );
94 ContextHandlerRef
TextPortionContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
96 OSL_ENSURE( nElement
!= XML_font
, "TextPortionContext::onCreateContext - nested <font> elements" );
97 if (getNamespace(getCurrentElement()) == NMSP_doc
)
99 return new TextPortionContext( *this, mrTextBox
, maParagraph
, maFont
, nElement
, rAttribs
);
102 void TextPortionContext::onCharacters( const OUString
& rChars
)
104 if (getNamespace(getCurrentElement()) == NMSP_doc
&& getCurrentElement() != W_TOKEN(t
))
107 switch( getCurrentElement() )
110 // replace all NBSP characters with SP
111 mrTextBox
.appendPortion( maParagraph
, maFont
, rChars
.replace( 0xA0, ' ' ) );
114 mrTextBox
.appendPortion( maParagraph
, maFont
, rChars
);
118 void TextPortionContext::onStartElement(const AttributeList
& rAttribs
)
120 switch (getCurrentElement())
123 maFont
.mobBold
= true;
126 maFont
.monSize
= rAttribs
.getInteger( W_TOKEN(val
) );
129 mrTextBox
.appendPortion( maParagraph
, maFont
, "\n" );
132 maFont
.moColor
= rAttribs
.getString( W_TOKEN(val
) );
134 case W_TOKEN(spacing
):
135 maFont
.monSpacing
= rAttribs
.getInteger(W_TOKEN(val
));
141 case W_TOKEN(rFonts
):
142 // See https://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.runfonts(v=office.14).aspx
143 maFont
.moName
= rAttribs
.getString(W_TOKEN(ascii
));
144 maFont
.moNameAsian
= rAttribs
.getString(W_TOKEN(eastAsia
));
145 maFont
.moNameComplex
= rAttribs
.getString(W_TOKEN(cs
));
148 SAL_INFO("oox", "unhandled: 0x" << std::hex
<< getCurrentElement());
153 void TextPortionContext::onEndElement()
155 if (getNamespace(getCurrentElement()) == NMSP_doc
&& getCurrentElement() != W_TOKEN(t
))
158 /* A child element without own child elements may contain a single space
159 character, for example:
162 <font><i>abc</i></font>
164 <font><b>def</b></font>
167 represents the italic text 'abc', an unformatted space character, and
168 the bold text 'def'. Unfortunately, the XML parser skips the space
169 character without issuing a 'characters' event. The class member
170 'mnInitialPortions' contains the number of text portions existing when
171 this context has been constructed. If no text has been added in the
172 meantime, the space character has to be added manually.
174 if( mrTextBox
.getPortionCount() == mnInitialPortions
)
175 mrTextBox
.appendPortion( maParagraph
, maFont
, OUString( ' ' ) );
178 TextBoxContext::TextBoxContext( ContextHandler2Helper
const & rParent
, TextBox
& rTextBox
, const AttributeList
& rAttribs
,
179 const GraphicHelper
& graphicHelper
) :
180 ContextHandler2( rParent
),
181 mrTextBox( rTextBox
)
183 if( rAttribs
.getString( XML_insetmode
).get() != "auto" )
185 OUString inset
= rAttribs
.getString( XML_inset
).get();
187 OUString remainingStr
;
189 ConversionHelper::separatePair( value
, remainingStr
, inset
, ',' );
190 rTextBox
.borderDistanceLeft
= ConversionHelper::decodeMeasureToHmm( graphicHelper
,
191 value
.isEmpty() ? "0.1in" : value
, 0, false, false );
193 inset
= remainingStr
;
194 ConversionHelper::separatePair( value
, remainingStr
, inset
, ',' );
195 rTextBox
.borderDistanceTop
= ConversionHelper::decodeMeasureToHmm( graphicHelper
,
196 value
.isEmpty() ? "0.05in" : value
, 0, false, false );
198 inset
= remainingStr
;
199 ConversionHelper::separatePair( value
, remainingStr
, inset
, ',' );
200 rTextBox
.borderDistanceRight
= ConversionHelper::decodeMeasureToHmm( graphicHelper
,
201 value
.isEmpty() ? "0.1in" : value
, 0, false, false );
203 inset
= remainingStr
;
204 ConversionHelper::separatePair( value
, remainingStr
, inset
, ',' );
205 rTextBox
.borderDistanceBottom
= ConversionHelper::decodeMeasureToHmm( graphicHelper
,
206 value
.isEmpty() ? "0.05in" : value
, 0, false, false );
208 rTextBox
.borderDistanceSet
= true;
211 OUString sStyle
= rAttribs
.getString( XML_style
, OUString() );
212 sal_Int32 nIndex
= 0;
215 OUString aName
, aValue
;
216 if( ConversionHelper::separatePair( aName
, aValue
, sStyle
.getToken( 0, ';', nIndex
), ':' ) )
218 if( aName
== "layout-flow" ) rTextBox
.maLayoutFlow
= aValue
;
219 else if (aName
== "mso-fit-shape-to-text")
220 rTextBox
.mrTypeModel
.mbAutoHeight
= true;
221 else if (aName
== "mso-layout-flow-alt")
222 rTextBox
.mrTypeModel
.maLayoutFlowAlt
= aValue
;
223 else if (aName
== "mso-next-textbox")
224 rTextBox
.msNextTextbox
= aValue
;
226 SAL_WARN("oox", "unhandled style property: " << aName
);
231 ContextHandlerRef
TextBoxContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
233 switch( getCurrentElement() )
235 case VML_TOKEN( textbox
):
236 if( nElement
== XML_div
) return this;
237 else if (nElement
== W_TOKEN(txbxContent
)) return this;
240 if( nElement
== XML_font
) return new TextPortionContext( *this, mrTextBox
, maParagraph
, TextFontModel(), nElement
, rAttribs
);
242 case W_TOKEN(txbxContent
):
243 if (nElement
== W_TOKEN(p
)) return this;
246 case W_TOKEN(sdtContent
):
247 case W_TOKEN(smartTag
):
248 if (nElement
== W_TOKEN(r
))
249 return new TextPortionContext( *this, mrTextBox
, maParagraph
, TextFontModel(), nElement
, rAttribs
);
258 SAL_INFO("oox", "unhandled 0x" << std::hex
<< getCurrentElement());
264 void TextBoxContext::onStartElement(const AttributeList
& rAttribs
)
266 switch (getCurrentElement())
269 maParagraph
.moParaAdjust
= rAttribs
.getString( W_TOKEN(val
) );
271 case W_TOKEN(pStyle
):
272 maParagraph
.moParaStyleName
= rAttribs
.getString( W_TOKEN(val
) );
277 void TextBoxContext::onEndElement()
279 if (getCurrentElement() == W_TOKEN(p
))
281 mrTextBox
.appendPortion( maParagraph
, TextFontModel(), "\n" );
282 maParagraph
= TextParagraphModel();
286 } // namespace oox::vml
288 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */