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/vml/vmlformatting.hxx"
21 #include "oox/vml/vmltextboxcontext.hxx"
22 #include "oox/vml/vmlshape.hxx"
23 #include <com/sun/star/drawing/XShape.hpp>
28 // ============================================================================
30 using ::oox::core::ContextHandler2
;
31 using ::oox::core::ContextHandler2Helper
;
32 using ::oox::core::ContextHandlerRef
;
34 // ============================================================================
36 TextPortionContext::TextPortionContext( ContextHandler2Helper
& rParent
,
37 TextBox
& rTextBox
, TextParagraphModel
& rParagraph
, const TextFontModel
& rParentFont
,
38 sal_Int32 nElement
, const AttributeList
& rAttribs
) :
39 ContextHandler2( rParent
),
40 mrTextBox( rTextBox
),
41 maParagraph( rParagraph
),
42 maFont( rParentFont
),
43 mnInitialPortions( rTextBox
.getPortionCount() )
48 maFont
.moName
= rAttribs
.getXString( XML_face
);
49 maFont
.moColor
= rAttribs
.getXString( XML_color
);
50 maFont
.monSize
= rAttribs
.getInteger( XML_size
);
53 OSL_ENSURE( !maFont
.monUnderline
, "TextPortionContext::TextPortionContext - nested <u> elements" );
54 maFont
.monUnderline
= (rAttribs
.getToken( XML_class
, XML_TOKEN_INVALID
) == XML_font4
) ? XML_double
: XML_single
;
58 OSL_ENSURE( !maFont
.monEscapement
, "TextPortionContext::TextPortionContext - nested <sub> or <sup> elements" );
59 maFont
.monEscapement
= nElement
;
62 OSL_ENSURE( !maFont
.mobBold
, "TextPortionContext::TextPortionContext - nested <b> elements" );
63 maFont
.mobBold
= true;
66 OSL_ENSURE( !maFont
.mobItalic
, "TextPortionContext::TextPortionContext - nested <i> elements" );
67 maFont
.mobItalic
= true;
70 OSL_ENSURE( !maFont
.mobStrikeout
, "TextPortionContext::TextPortionContext - nested <s> elements" );
71 maFont
.mobStrikeout
= true;
73 case OOX_TOKEN(dml
, blip
):
75 OptValue
<OUString
> oRelId
= rAttribs
.getString(R_TOKEN(embed
));
77 mrTextBox
.mrTypeModel
.moGraphicPath
= getFragmentPathFromRelId(oRelId
.get());
80 case VML_TOKEN(imagedata
):
82 OptValue
<OUString
> oRelId
= rAttribs
.getString(R_TOKEN(id
));
84 mrTextBox
.mrTypeModel
.moGraphicPath
= getFragmentPathFromRelId(oRelId
.get());
88 case OOX_TOKEN(doc
, r
):
91 OSL_ENSURE( false, "TextPortionContext::TextPortionContext - unknown element" );
95 ContextHandlerRef
TextPortionContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
97 OSL_ENSURE( nElement
!= XML_font
, "TextPortionContext::onCreateContext - nested <font> elements" );
98 if (getNamespace(getCurrentElement()) == NMSP_doc
)
100 return new TextPortionContext( *this, mrTextBox
, maParagraph
, maFont
, nElement
, rAttribs
);
103 void TextPortionContext::onCharacters( const OUString
& rChars
)
105 if (getNamespace(getCurrentElement()) == NMSP_doc
&& getCurrentElement() != OOX_TOKEN(doc
, t
))
108 switch( getCurrentElement() )
111 // replace all NBSP characters with SP
112 mrTextBox
.appendPortion( maParagraph
, maFont
, rChars
.replace( 0xA0, ' ' ) );
115 mrTextBox
.appendPortion( maParagraph
, maFont
, rChars
);
119 void TextPortionContext::onStartElement(const AttributeList
& rAttribs
)
121 switch (getCurrentElement())
123 case OOX_TOKEN(doc
, b
):
124 maFont
.mobBold
= true;
126 case OOX_TOKEN(doc
, sz
):
127 maFont
.monSize
= rAttribs
.getInteger( OOX_TOKEN(doc
, val
) );
129 case OOX_TOKEN(doc
, br
):
130 mrTextBox
.appendPortion( maParagraph
, maFont
, "\n" );
132 case OOX_TOKEN(doc
, color
):
133 maFont
.moColor
= rAttribs
.getString( OOX_TOKEN(doc
, val
) );
135 case OOX_TOKEN(doc
, spacing
):
136 maFont
.monSpacing
= rAttribs
.getInteger(OOX_TOKEN(doc
, val
));
138 case OOX_TOKEN(doc
, r
):
139 case OOX_TOKEN(doc
, rPr
):
140 case OOX_TOKEN(doc
, t
):
143 SAL_INFO("oox", "unhandled: 0x" << std::hex
<< getCurrentElement());
148 void TextPortionContext::onEndElement()
150 if (getNamespace(getCurrentElement()) == NMSP_doc
&& getCurrentElement() != OOX_TOKEN(doc
, t
))
153 /* A child element without own child elements may contain a single space
154 character, for example:
157 <font><i>abc</i></font>
159 <font><b>def</b></font>
162 represents the italic text 'abc', an unformatted space character, and
163 the bold text 'def'. Unfortunately, the XML parser skips the space
164 character without issuing a 'characters' event. The class member
165 'mnInitialPortions' contains the number of text portions existing when
166 this context has been constructed. If no text has been added in the
167 meantime, the space character has to be added manually.
169 if( mrTextBox
.getPortionCount() == mnInitialPortions
)
170 mrTextBox
.appendPortion( maParagraph
, maFont
, OUString( sal_Unicode( ' ' ) ) );
173 // ============================================================================
175 TextBoxContext::TextBoxContext( ContextHandler2Helper
& rParent
, TextBox
& rTextBox
, const AttributeList
& rAttribs
,
176 const GraphicHelper
& graphicHelper
) :
177 ContextHandler2( rParent
),
178 mrTextBox( rTextBox
)
180 if( rAttribs
.getString( XML_insetmode
).get() != "auto" )
182 OUString inset
= rAttribs
.getString( XML_inset
).get();
184 ConversionHelper::separatePair( value
, inset
, inset
, ',' );
185 rTextBox
.borderDistanceLeft
= ConversionHelper::decodeMeasureToHmm( graphicHelper
,
186 value
.isEmpty() ? "0.1in" : value
, 0, false, false );
187 ConversionHelper::separatePair( value
, inset
, inset
, ',' );
188 rTextBox
.borderDistanceTop
= ConversionHelper::decodeMeasureToHmm( graphicHelper
,
189 value
.isEmpty() ? "0.05in" : value
, 0, false, false );
190 ConversionHelper::separatePair( value
, inset
, inset
, ',' );
191 rTextBox
.borderDistanceRight
= ConversionHelper::decodeMeasureToHmm( graphicHelper
,
192 value
.isEmpty() ? "0.1in" : value
, 0, false, false );
193 ConversionHelper::separatePair( value
, inset
, inset
, ',' );
194 rTextBox
.borderDistanceBottom
= ConversionHelper::decodeMeasureToHmm( graphicHelper
,
195 value
.isEmpty() ? "0.05in" : value
, 0, false, false );
196 rTextBox
.borderDistanceSet
= true;
199 OUString sStyle
= rAttribs
.getString( XML_style
, OUString() );
200 sal_Int32 nIndex
= 0;
203 OUString aName
, aValue
;
204 if( ConversionHelper::separatePair( aName
, aValue
, sStyle
.getToken( 0, ';', nIndex
), ':' ) )
206 if( aName
== "layout-flow" ) rTextBox
.maLayoutFlow
= aValue
;
207 else if (aName
== "mso-fit-shape-to-text")
208 rTextBox
.mrTypeModel
.mbAutoHeight
= true;
210 SAL_WARN("oox", "unhandled style property: " << aName
);
215 ContextHandlerRef
TextBoxContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
217 switch( getCurrentElement() )
219 case VML_TOKEN( textbox
):
220 if( nElement
== XML_div
) return this;
221 else if (nElement
== OOX_TOKEN(doc
, txbxContent
)) return this;
224 if( nElement
== XML_font
) return new TextPortionContext( *this, mrTextBox
, maParagraph
, TextFontModel(), nElement
, rAttribs
);
226 case OOX_TOKEN(doc
, txbxContent
):
227 if (nElement
== OOX_TOKEN(doc
, p
)) return this;
229 case OOX_TOKEN(doc
, p
):
230 case OOX_TOKEN(doc
, sdtContent
):
231 if (nElement
== OOX_TOKEN(doc
, r
))
232 return new TextPortionContext( *this, mrTextBox
, maParagraph
, TextFontModel(), nElement
, rAttribs
);
236 case OOX_TOKEN(doc
, pPr
):
237 case OOX_TOKEN(doc
, sdt
):
241 SAL_INFO("oox", "unhandled 0x" << std::hex
<< getCurrentElement());
247 void TextBoxContext::onStartElement(const AttributeList
& rAttribs
)
249 switch (getCurrentElement())
251 case OOX_TOKEN(doc
, jc
):
252 maParagraph
.moParaAdjust
= rAttribs
.getString( OOX_TOKEN(doc
, val
) );
257 void TextBoxContext::onEndElement()
259 if (getCurrentElement() == OOX_TOKEN(doc
, p
))
261 mrTextBox
.appendPortion( maParagraph
, TextFontModel(), "\n" );
262 maParagraph
= TextParagraphModel();
266 // ============================================================================
271 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */