bump product version to 6.3.0.0.beta1
[LibreOffice.git] / oox / source / vml / vmltextboxcontext.cxx
blob7f5072536983ec15a4f2af12e3a7c2d04ff5bdf0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
30 namespace oox {
31 namespace vml {
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() )
46 switch( nElement )
48 case XML_font:
49 maFont.moName = rAttribs.getXString( XML_face );
50 maFont.moColor = rAttribs.getXString( XML_color );
51 maFont.monSize = rAttribs.getInteger( XML_size );
52 break;
53 case XML_u:
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;
56 break;
57 case XML_sub:
58 case XML_sup:
59 OSL_ENSURE( !maFont.monEscapement, "TextPortionContext::TextPortionContext - nested <sub> or <sup> elements" );
60 maFont.monEscapement = nElement;
61 break;
62 case XML_b:
63 OSL_ENSURE( !maFont.mobBold, "TextPortionContext::TextPortionContext - nested <b> elements" );
64 maFont.mobBold = true;
65 break;
66 case XML_i:
67 OSL_ENSURE( !maFont.mobItalic, "TextPortionContext::TextPortionContext - nested <i> elements" );
68 maFont.mobItalic = true;
69 break;
70 case XML_s:
71 OSL_ENSURE( !maFont.mobStrikeout, "TextPortionContext::TextPortionContext - nested <s> elements" );
72 maFont.mobStrikeout = true;
73 break;
74 case OOX_TOKEN(dml, blip):
76 OptValue<OUString> oRelId = rAttribs.getString(R_TOKEN(embed));
77 if (oRelId.has())
78 mrTextBox.mrTypeModel.moGraphicPath = getFragmentPathFromRelId(oRelId.get());
80 break;
81 case VML_TOKEN(imagedata):
83 OptValue<OUString> oRelId = rAttribs.getString(R_TOKEN(id));
84 if (oRelId.has())
85 mrTextBox.mrTypeModel.moGraphicPath = getFragmentPathFromRelId(oRelId.get());
87 break;
88 case XML_span:
89 case W_TOKEN(r):
90 break;
91 default:
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)
100 return this;
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))
107 return;
109 switch( getCurrentElement() )
111 case XML_span:
112 // replace all NBSP characters with SP
113 mrTextBox.appendPortion( maParagraph, maFont, rChars.replace( 0xA0, ' ' ) );
114 break;
115 default:
116 mrTextBox.appendPortion( maParagraph, maFont, rChars );
120 void TextPortionContext::onStartElement(const AttributeList& rAttribs)
122 switch (getCurrentElement())
124 case W_TOKEN(b):
125 maFont.mobBold = true;
126 break;
127 case W_TOKEN(sz):
128 maFont.monSize = rAttribs.getInteger( W_TOKEN(val) );
129 break;
130 case W_TOKEN(br):
131 mrTextBox.appendPortion( maParagraph, maFont, "\n" );
132 break;
133 case W_TOKEN(color):
134 maFont.moColor = rAttribs.getString( W_TOKEN(val) );
135 break;
136 case W_TOKEN(spacing):
137 maFont.monSpacing = rAttribs.getInteger(W_TOKEN(val));
138 break;
139 case W_TOKEN(r):
140 case W_TOKEN(rPr):
141 case W_TOKEN(t):
142 break;
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));
148 break;
149 default:
150 SAL_INFO("oox", "unhandled: 0x" << std::hex<< getCurrentElement());
151 break;
155 void TextPortionContext::onEndElement()
157 if (getNamespace(getCurrentElement()) == NMSP_doc && getCurrentElement() != W_TOKEN(t))
158 return;
160 /* A child element without own child elements may contain a single space
161 character, for example:
163 <div>
164 <font><i>abc</i></font>
165 <font> </font>
166 <font><b>def</b></font>
167 </div>
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();
188 OUString value;
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;
215 while( 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;
227 else
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;
240 break;
241 case XML_div:
242 if( nElement == XML_font ) return new TextPortionContext( *this, mrTextBox, maParagraph, TextFontModel(), nElement, rAttribs );
243 break;
244 case W_TOKEN(txbxContent):
245 if (nElement == W_TOKEN(p)) return this;
246 break;
247 case W_TOKEN(p):
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 );
252 else
253 return this;
254 break;
255 case W_TOKEN(pPr):
256 case W_TOKEN(sdt):
257 return this;
258 break;
259 default:
260 SAL_INFO("oox", "unhandled 0x" << std::hex << getCurrentElement());
261 break;
263 return nullptr;
266 void TextBoxContext::onStartElement(const AttributeList& rAttribs)
268 switch (getCurrentElement())
270 case W_TOKEN(jc):
271 maParagraph.moParaAdjust = rAttribs.getString( W_TOKEN(val) );
272 break;
276 void TextBoxContext::onEndElement()
278 if (getCurrentElement() == W_TOKEN(p))
280 mrTextBox.appendPortion( maParagraph, TextFontModel(), "\n" );
281 maParagraph = TextParagraphModel();
285 } // namespace vml
286 } // namespace oox
288 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */