Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
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>
24 :
25 : namespace oox {
26 : namespace vml {
27 :
28 : using ::oox::core::ContextHandler2;
29 : using ::oox::core::ContextHandler2Helper;
30 : using ::oox::core::ContextHandlerRef;
31 :
32 536 : TextPortionContext::TextPortionContext( ContextHandler2Helper& rParent,
33 : TextBox& rTextBox, TextParagraphModel& rParagraph, const TextFontModel& rParentFont,
34 : sal_Int32 nElement, const AttributeList& rAttribs ) :
35 : ContextHandler2( rParent ),
36 : mrTextBox( rTextBox ),
37 : maParagraph( rParagraph ),
38 : maFont( rParentFont ),
39 536 : mnInitialPortions( rTextBox.getPortionCount() )
40 : {
41 536 : switch( nElement )
42 : {
43 : case XML_font:
44 2 : maFont.moName = rAttribs.getXString( XML_face );
45 2 : maFont.moColor = rAttribs.getXString( XML_color );
46 2 : maFont.monSize = rAttribs.getInteger( XML_size );
47 2 : break;
48 : case XML_u:
49 : OSL_ENSURE( !maFont.monUnderline, "TextPortionContext::TextPortionContext - nested <u> elements" );
50 0 : maFont.monUnderline = (rAttribs.getToken( XML_class, XML_TOKEN_INVALID ) == XML_font4) ? XML_double : XML_single;
51 0 : break;
52 : case XML_sub:
53 : case XML_sup:
54 : OSL_ENSURE( !maFont.monEscapement, "TextPortionContext::TextPortionContext - nested <sub> or <sup> elements" );
55 0 : maFont.monEscapement = nElement;
56 0 : break;
57 : case XML_b:
58 : OSL_ENSURE( !maFont.mobBold, "TextPortionContext::TextPortionContext - nested <b> elements" );
59 0 : maFont.mobBold = true;
60 0 : break;
61 : case XML_i:
62 : OSL_ENSURE( !maFont.mobItalic, "TextPortionContext::TextPortionContext - nested <i> elements" );
63 0 : maFont.mobItalic = true;
64 0 : break;
65 : case XML_s:
66 : OSL_ENSURE( !maFont.mobStrikeout, "TextPortionContext::TextPortionContext - nested <s> elements" );
67 0 : maFont.mobStrikeout = true;
68 0 : break;
69 : case OOX_TOKEN(dml, blip):
70 : {
71 4 : OptValue<OUString> oRelId = rAttribs.getString(R_TOKEN(embed));
72 4 : if (oRelId.has())
73 4 : mrTextBox.mrTypeModel.moGraphicPath = getFragmentPathFromRelId(oRelId.get());
74 : }
75 4 : break;
76 : case VML_TOKEN(imagedata):
77 : {
78 2 : OptValue<OUString> oRelId = rAttribs.getString(R_TOKEN(id));
79 2 : if (oRelId.has())
80 2 : mrTextBox.mrTypeModel.moGraphicPath = getFragmentPathFromRelId(oRelId.get());
81 : }
82 2 : break;
83 : case XML_span:
84 : case W_TOKEN(r):
85 416 : break;
86 : default:
87 : OSL_ENSURE( false, "TextPortionContext::TextPortionContext - unknown element" );
88 : }
89 536 : }
90 :
91 2486 : ContextHandlerRef TextPortionContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
92 : {
93 : OSL_ENSURE( nElement != XML_font, "TextPortionContext::onCreateContext - nested <font> elements" );
94 2486 : if (getNamespace(getCurrentElement()) == NMSP_doc)
95 2368 : return this;
96 118 : return new TextPortionContext( *this, mrTextBox, maParagraph, maFont, nElement, rAttribs );
97 : }
98 :
99 912 : void TextPortionContext::onCharacters( const OUString& rChars )
100 : {
101 912 : if (getNamespace(getCurrentElement()) == NMSP_doc && getCurrentElement() != W_TOKEN(t))
102 1242 : return;
103 :
104 582 : switch( getCurrentElement() )
105 : {
106 : case XML_span:
107 : // replace all NBSP characters with SP
108 0 : mrTextBox.appendPortion( maParagraph, maFont, rChars.replace( 0xA0, ' ' ) );
109 0 : break;
110 : default:
111 582 : mrTextBox.appendPortion( maParagraph, maFont, rChars );
112 : }
113 : }
114 :
115 2904 : void TextPortionContext::onStartElement(const AttributeList& rAttribs)
116 : {
117 2904 : switch (getCurrentElement())
118 : {
119 : case W_TOKEN(b):
120 46 : maFont.mobBold = true;
121 46 : break;
122 : case W_TOKEN(sz):
123 394 : maFont.monSize = rAttribs.getInteger( W_TOKEN(val) );
124 394 : break;
125 : case W_TOKEN(br):
126 2 : mrTextBox.appendPortion( maParagraph, maFont, "\n" );
127 2 : break;
128 : case W_TOKEN(color):
129 262 : maFont.moColor = rAttribs.getString( W_TOKEN(val) );
130 262 : break;
131 : case W_TOKEN(spacing):
132 4 : maFont.monSpacing = rAttribs.getInteger(W_TOKEN(val));
133 4 : break;
134 : case W_TOKEN(r):
135 : case W_TOKEN(rPr):
136 : case W_TOKEN(t):
137 1236 : break;
138 : default:
139 : SAL_INFO("oox", "unhandled: 0x" << std::hex<< getCurrentElement());
140 960 : break;
141 : }
142 2904 : }
143 :
144 2904 : void TextPortionContext::onEndElement()
145 : {
146 2904 : if (getNamespace(getCurrentElement()) == NMSP_doc && getCurrentElement() != W_TOKEN(t))
147 5274 : return;
148 :
149 : /* A child element without own child elements may contain a single space
150 : character, for example:
151 :
152 : <div>
153 : <font><i>abc</i></font>
154 : <font> </font>
155 : <font><b>def</b></font>
156 : </div>
157 :
158 : represents the italic text 'abc', an unformatted space character, and
159 : the bold text 'def'. Unfortunately, the XML parser skips the space
160 : character without issuing a 'characters' event. The class member
161 : 'mnInitialPortions' contains the number of text portions existing when
162 : this context has been constructed. If no text has been added in the
163 : meantime, the space character has to be added manually.
164 : */
165 534 : if( mrTextBox.getPortionCount() == mnInitialPortions )
166 70 : mrTextBox.appendPortion( maParagraph, maFont, OUString( ' ' ) );
167 : }
168 :
169 518 : TextBoxContext::TextBoxContext( ContextHandler2Helper& rParent, TextBox& rTextBox, const AttributeList& rAttribs,
170 : const GraphicHelper& graphicHelper ) :
171 : ContextHandler2( rParent ),
172 518 : mrTextBox( rTextBox )
173 : {
174 518 : if( rAttribs.getString( XML_insetmode ).get() != "auto" )
175 : {
176 518 : OUString inset = rAttribs.getString( XML_inset ).get();
177 1036 : OUString value;
178 1036 : OUString remainingStr;
179 :
180 518 : ConversionHelper::separatePair( value, remainingStr, inset, ',' );
181 : rTextBox.borderDistanceLeft = ConversionHelper::decodeMeasureToHmm( graphicHelper,
182 518 : value.isEmpty() ? "0.1in" : value, 0, false, false );
183 :
184 518 : inset = remainingStr;
185 518 : ConversionHelper::separatePair( value, remainingStr, inset, ',' );
186 : rTextBox.borderDistanceTop = ConversionHelper::decodeMeasureToHmm( graphicHelper,
187 518 : value.isEmpty() ? "0.05in" : value, 0, false, false );
188 :
189 518 : inset = remainingStr;
190 518 : ConversionHelper::separatePair( value, remainingStr, inset, ',' );
191 : rTextBox.borderDistanceRight = ConversionHelper::decodeMeasureToHmm( graphicHelper,
192 518 : value.isEmpty() ? "0.1in" : value, 0, false, false );
193 :
194 518 : inset = remainingStr;
195 518 : ConversionHelper::separatePair( value, remainingStr, inset, ',' );
196 : rTextBox.borderDistanceBottom = ConversionHelper::decodeMeasureToHmm( graphicHelper,
197 518 : value.isEmpty() ? "0.05in" : value, 0, false, false );
198 :
199 1036 : rTextBox.borderDistanceSet = true;
200 : }
201 :
202 518 : OUString sStyle = rAttribs.getString( XML_style, OUString() );
203 518 : sal_Int32 nIndex = 0;
204 1596 : while( nIndex >= 0 )
205 : {
206 1120 : OUString aName, aValue;
207 560 : if( ConversionHelper::separatePair( aName, aValue, sStyle.getToken( 0, ';', nIndex ), ':' ) )
208 : {
209 418 : if( aName == "layout-flow" ) rTextBox.maLayoutFlow = aValue;
210 408 : else if (aName == "mso-fit-shape-to-text")
211 296 : rTextBox.mrTypeModel.mbAutoHeight = true;
212 112 : else if (aName == "mso-layout-flow-alt")
213 6 : rTextBox.mrTypeModel.maLayoutFlowAlt = aValue;
214 : else
215 : SAL_WARN("oox", "unhandled style property: " << aName);
216 : }
217 1078 : }
218 518 : }
219 :
220 2110 : ContextHandlerRef TextBoxContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
221 : {
222 2110 : switch( getCurrentElement() )
223 : {
224 : case VML_TOKEN( textbox ):
225 372 : if( nElement == XML_div ) return this;
226 370 : else if (nElement == W_TOKEN(txbxContent)) return this;
227 0 : break;
228 : case XML_div:
229 2 : if( nElement == XML_font ) return new TextPortionContext( *this, mrTextBox, maParagraph, TextFontModel(), nElement, rAttribs );
230 0 : break;
231 : case W_TOKEN(txbxContent):
232 396 : if (nElement == W_TOKEN(p)) return this;
233 0 : break;
234 : case W_TOKEN(p):
235 : case W_TOKEN(sdtContent):
236 : case W_TOKEN(smartTag):
237 610 : if (nElement == W_TOKEN(r))
238 416 : return new TextPortionContext( *this, mrTextBox, maParagraph, TextFontModel(), nElement, rAttribs );
239 : else
240 194 : return this;
241 : break;
242 : case W_TOKEN(pPr):
243 : case W_TOKEN(sdt):
244 280 : return this;
245 : break;
246 : default:
247 : SAL_INFO("oox", "unhandled 0x" << std::hex << getCurrentElement());
248 450 : break;
249 : }
250 450 : return 0;
251 : }
252 :
253 1760 : void TextBoxContext::onStartElement(const AttributeList& rAttribs)
254 : {
255 1760 : switch (getCurrentElement())
256 : {
257 : case W_TOKEN(jc):
258 104 : maParagraph.moParaAdjust = rAttribs.getString( W_TOKEN(val) );
259 104 : break;
260 : }
261 1760 : }
262 :
263 1760 : void TextBoxContext::onEndElement()
264 : {
265 1760 : if (getCurrentElement() == W_TOKEN(p))
266 : {
267 396 : mrTextBox.appendPortion( maParagraph, TextFontModel(), "\n" );
268 396 : maParagraph = TextParagraphModel();
269 : }
270 1760 : }
271 :
272 : } // namespace vml
273 : } // namespace oox
274 :
275 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|