LibreOffice Module oox (master) 1
vmltextboxcontext.cxx
Go to the documentation of this file.
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
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>
28#include <o3tl/string_view.hxx>
29
30namespace oox::vml {
31
32using ::oox::core::ContextHandler2;
33using ::oox::core::ContextHandler2Helper;
35
36TextPortionContext::TextPortionContext( ContextHandler2Helper const & rParent,
37 TextBox& rTextBox, TextParagraphModel const & 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() )
44{
45 switch( nElement )
46 {
47 case XML_font:
48 maFont.moName = rAttribs.getXString( XML_face );
49 maFont.moColor = rAttribs.getXString( XML_color );
50 maFont.monSize = rAttribs.getInteger( XML_size );
51 break;
52 case XML_u:
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;
55 break;
56 case XML_sub:
57 case XML_sup:
58 OSL_ENSURE( !maFont.monEscapement, "TextPortionContext::TextPortionContext - nested <sub> or <sup> elements" );
59 maFont.monEscapement = nElement;
60 break;
61 case XML_b:
62 OSL_ENSURE( !maFont.mobBold, "TextPortionContext::TextPortionContext - nested <b> elements" );
63 maFont.mobBold = true;
64 break;
65 case XML_i:
66 OSL_ENSURE( !maFont.mobItalic, "TextPortionContext::TextPortionContext - nested <i> elements" );
67 maFont.mobItalic = true;
68 break;
69 case XML_s:
70 OSL_ENSURE( !maFont.mobStrikeout, "TextPortionContext::TextPortionContext - nested <s> elements" );
71 maFont.mobStrikeout = true;
72 break;
73 case OOX_TOKEN(dml, blip):
74 {
75 std::optional<OUString> oRelId = rAttribs.getString(R_TOKEN(embed));
76 if (oRelId.has_value())
78 }
79 break;
80 case VML_TOKEN(imagedata):
81 {
82 std::optional<OUString> oRelId = rAttribs.getString(R_TOKEN(id));
83 if (oRelId.has_value())
85 }
86 break;
87 case XML_span:
88 case W_TOKEN(r):
89 break;
90 default:
91 OSL_ENSURE( false, "TextPortionContext::TextPortionContext - unknown element" );
92 }
93}
94
96{
97 OSL_ENSURE( nElement != XML_font, "TextPortionContext::onCreateContext - nested <font> elements" );
98 if (getNamespace(getCurrentElement()) == NMSP_doc)
99 return this;
100 return new TextPortionContext( *this, mrTextBox, maParagraph, maFont, nElement, rAttribs );
101}
102
103void TextPortionContext::onCharacters( const OUString& rChars )
104{
105 if (getNamespace(getCurrentElement()) == NMSP_doc && getCurrentElement() != W_TOKEN(t))
106 return;
107
108 switch( getCurrentElement() )
109 {
110 case XML_span:
111 // replace all NBSP characters with SP
112 mrTextBox.appendPortion( maParagraph, maFont, rChars.replace( 0xA0, ' ' ) );
113 break;
114 default:
116 }
117}
118
120{
121 switch (getCurrentElement())
122 {
123 case W_TOKEN(b):
124 maFont.mobBold = true;
125 break;
126 case W_TOKEN(sz):
127 maFont.monSize = rAttribs.getInteger( W_TOKEN(val) );
128 break;
129 case W_TOKEN(br):
131 break;
132 case W_TOKEN(color):
133 maFont.moColor = rAttribs.getString( W_TOKEN(val) );
134 break;
135 case W_TOKEN(spacing):
136 maFont.monSpacing = rAttribs.getInteger(W_TOKEN(val));
137 break;
138 case W_TOKEN(r):
139 case W_TOKEN(rPr):
140 case W_TOKEN(t):
141 break;
142 case W_TOKEN(rFonts):
143 // See https://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.runfonts(v=office.14).aspx
144 maFont.moName = rAttribs.getString(W_TOKEN(ascii));
145 maFont.moNameAsian = rAttribs.getString(W_TOKEN(eastAsia));
146 maFont.moNameComplex = rAttribs.getString(W_TOKEN(cs));
147 break;
148 default:
149 SAL_INFO("oox", "unhandled: 0x" << std::hex<< getCurrentElement());
150 break;
151 }
152}
153
155{
156 if (getNamespace(getCurrentElement()) == NMSP_doc && getCurrentElement() != W_TOKEN(t))
157 return;
158
159 /* A child element without own child elements may contain a single space
160 character, for example:
161
162 <div>
163 <font><i>abc</i></font>
164 <font> </font>
165 <font><b>def</b></font>
166 </div>
167
168 represents the italic text 'abc', an unformatted space character, and
169 the bold text 'def'. Unfortunately, the XML parser skips the space
170 character without issuing a 'characters' event. The class member
171 'mnInitialPortions' contains the number of text portions existing when
172 this context has been constructed. If no text has been added in the
173 meantime, the space character has to be added manually.
174 */
176 mrTextBox.appendPortion( maParagraph, maFont, OUString( ' ' ) );
177}
178
179TextBoxContext::TextBoxContext( ContextHandler2Helper const & rParent, TextBox& rTextBox, const AttributeList& rAttribs,
180 const GraphicHelper& graphicHelper ) :
181 ContextHandler2( rParent ),
182 mrTextBox( rTextBox )
183{
184 if( rAttribs.getStringDefaulted( XML_insetmode ) != "auto" )
185 {
186 OUString inset = rAttribs.getStringDefaulted( XML_inset );
187 std::u16string_view value;
188 std::u16string_view remainingStr;
189
190 ConversionHelper::separatePair( value, remainingStr, inset, ',' );
192 value.empty() ? u"0.1in" : value, 0, false, false );
193
194 inset = remainingStr;
195 ConversionHelper::separatePair( value, remainingStr, inset, ',' );
197 value.empty() ? u"0.05in" : value, 0, false, false );
198
199 inset = remainingStr;
200 ConversionHelper::separatePair( value, remainingStr, inset, ',' );
202 value.empty() ? u"0.1in" : value, 0, false, false );
203
204 inset = remainingStr;
205 ConversionHelper::separatePair( value, remainingStr, inset, ',' );
207 value.empty() ? u"0.05in" : value, 0, false, false );
208
209 rTextBox.borderDistanceSet = true;
210 }
211
212 OUString sStyle = rAttribs.getString( XML_style, OUString() );
213 sal_Int32 nIndex = 0;
214 while( nIndex >= 0 )
215 {
216 std::u16string_view aName, aValue;
217 if( ConversionHelper::separatePair( aName, aValue, o3tl::getToken(sStyle, 0, ';', nIndex ), ':' ) )
218 {
219 if( aName == u"layout-flow" ) rTextBox.maLayoutFlow = aValue;
220 else if (aName == u"mso-fit-shape-to-text")
221 rTextBox.mrTypeModel.mbAutoHeight = true;
222 else if (aName == u"mso-layout-flow-alt")
223 rTextBox.mrTypeModel.maLayoutFlowAlt = aValue;
224 else if (aName == u"mso-next-textbox")
225 rTextBox.msNextTextbox = aValue;
226 else
227 SAL_WARN("oox", "unhandled style property: " << OUString(aName));
228 }
229 }
230}
231
233{
234 switch( getCurrentElement() )
235 {
236 case VML_TOKEN( textbox ):
237 if( nElement == XML_div ) return this;
238 else if (nElement == W_TOKEN(txbxContent)) return this;
239 break;
240 case XML_div:
241 if( nElement == XML_font ) return new TextPortionContext( *this, mrTextBox, maParagraph, TextFontModel(), nElement, rAttribs );
242 break;
243 case W_TOKEN(txbxContent):
244 if (nElement == W_TOKEN(p)) return this;
245 break;
246 case W_TOKEN(p):
247 case W_TOKEN(sdtContent):
248 case W_TOKEN(smartTag):
249 if (nElement == W_TOKEN(r))
250 return new TextPortionContext( *this, mrTextBox, maParagraph, TextFontModel(), nElement, rAttribs );
251 else
252 return this;
253 case W_TOKEN(pPr):
254 case W_TOKEN(sdt):
255 return this;
256 default:
257 SAL_INFO("oox", "unhandled 0x" << std::hex << getCurrentElement());
258 break;
259 }
260 return nullptr;
261}
262
264{
265 switch (getCurrentElement())
266 {
267 case W_TOKEN(jc):
268 maParagraph.moParaAdjust = rAttribs.getString( W_TOKEN(val) );
269 break;
270 case W_TOKEN(pStyle):
271 maParagraph.moParaStyleName = rAttribs.getString( W_TOKEN(val) );
272 break;
273 }
274}
275
277{
278 if (getCurrentElement() == W_TOKEN(p))
279 {
282 }
283}
284
285} // namespace oox::vml
286
287/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
Provides access to attribute values of an element.
OUString getStringDefaulted(sal_Int32 nAttrToken) const
Returns the string value of the specified attribute, returns an empty string if attribute not present...
std::optional< OUString > getXString(sal_Int32 nAttrToken) const
Returns the string value of the specified attribute.
std::optional< sal_Int32 > getInteger(sal_Int32 nAttrToken) const
Returns the 32-bit signed integer value of the specified attribute (decimal).
std::optional< OUString > getString(sal_Int32 nAttrToken) const
Returns the string value of the specified attribute.
std::optional< sal_Int32 > getToken(sal_Int32 nAttrToken) const
Returns the token identifier of the value of the specified attribute.
Provides helper functions for colors, device measurement conversion, graphics, and graphic objects ha...
sal_Int32 getCurrentElement() const
Returns the identifier of the currently processed element.
OUString getFragmentPathFromRelId(const OUString &rRelId) const
Returns the full fragment path for the passed relation identifier.
virtual ::oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElement, const AttributeList &rAttribs) override
Will be called to create a context handler for the passed element.
TextBoxContext(::oox::core::ContextHandler2Helper const &rParent, TextBox &rTextBox, const AttributeList &rAttribs, const GraphicHelper &graphicHelper)
TextParagraphModel maParagraph
virtual void onStartElement(const AttributeList &rAttribs) override
Will be called when a new element has been started.
virtual void onEndElement() override
Will be called when the current element is about to be left.
The textbox contains all text contents and properties.
Definition: vmltextbox.hxx:80
OUString maLayoutFlow
Definition: vmltextbox.hxx:99
void appendPortion(const TextParagraphModel &rParagraph, const TextFontModel &rFont, const OUString &rText)
Appends a new text portion to the textbox.
Definition: vmltextbox.cxx:59
OUString msNextTextbox
Definition: vmltextbox.hxx:100
bool borderDistanceSet
Text distance from the border (inset attribute of v:textbox), valid only if set.
Definition: vmltextbox.hxx:97
size_t getPortionCount() const
Returns the current number of text portions.
Definition: vmltextbox.hxx:88
ShapeTypeModel & mrTypeModel
Definition: vmltextbox.hxx:95
virtual void onStartElement(const AttributeList &rAttribs) override
Will be called when a new element has been started.
virtual void onEndElement() override
Will be called when the current element is about to be left.
TextPortionContext(::oox::core::ContextHandler2Helper const &rParent, TextBox &rTextBox, TextParagraphModel const &rParagraph, const TextFontModel &rParentFont, sal_Int32 nElement, const AttributeList &rAttribs)
virtual ::oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElement, const AttributeList &rAttribs) override
Will be called to create a context handler for the passed element.
virtual void onCharacters(const OUString &rChars) override
Will be called before a new child element starts, or if the current element is about to be left.
Any value
float u
sal_Int32 nIndex
OUString aName
void * p
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
::rtl::Reference< ContextHandler > ContextHandlerRef
OOX_DLLPUBLIC bool separatePair(std::u16string_view &orValue1, std::u16string_view &orValue2, std::u16string_view rValue, sal_Unicode cSep)
Returns two values contained in rValue separated by cSep.
OOX_DLLPUBLIC sal_Int32 decodeMeasureToHmm(const GraphicHelper &rGraphicHelper, std::u16string_view rValue, sal_Int32 nRefValue, bool bPixelX, bool bDefaultAsPixel)
Converts the passed VML measure string to 1/100 mm.
XML_TOKEN_INVALID
std::optional< OUString > moGraphicPath
Path to a graphic for this shape.
Definition: vmlshape.hxx:99
bool mbAutoHeight
If true, the height value is a minimum value (mostly used for textboxes)
Definition: vmlshape.hxx:87
OUString maLayoutFlowAlt
Specifies the alternate layout flow for text in textboxes.
Definition: vmlshape.hxx:114
Font settings for a text portion in a textbox.
Definition: vmltextbox.hxx:50
std::optional< sal_Int32 > monEscapement
Subscript or superscript.
Definition: vmltextbox.hxx:57
std::optional< sal_Int32 > monSize
Font size in twips.
Definition: vmltextbox.hxx:55
std::optional< sal_Int32 > monUnderline
Single or double underline.
Definition: vmltextbox.hxx:56
std::optional< OUString > moNameAsian
Asian font name.
Definition: vmltextbox.hxx:52
std::optional< OUString > moNameComplex
Complex font name.
Definition: vmltextbox.hxx:53
std::optional< bool > mobBold
Definition: vmltextbox.hxx:58
std::optional< bool > mobStrikeout
Definition: vmltextbox.hxx:60
std::optional< OUString > moName
Font name.
Definition: vmltextbox.hxx:51
std::optional< sal_Int32 > monSpacing
Definition: vmltextbox.hxx:61
std::optional< bool > mobItalic
Definition: vmltextbox.hxx:59
std::optional< OUString > moColor
Font color, HTML encoded, sort of.
Definition: vmltextbox.hxx:54
A text paragraph in a textbox.
Definition: vmltextbox.hxx:43
std::optional< OUString > moParaStyleName
Definition: vmltextbox.hxx:45
std::optional< OUString > moParaAdjust
Paragraph adjust (left, center, right, etc.)
Definition: vmltextbox.hxx:44