summaryrefslogtreecommitdiffstats
path: root/oox/source/vml/vmltextboxcontext.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'oox/source/vml/vmltextboxcontext.cxx')
-rw-r--r--oox/source/vml/vmltextboxcontext.cxx287
1 files changed, 287 insertions, 0 deletions
diff --git a/oox/source/vml/vmltextboxcontext.cxx b/oox/source/vml/vmltextboxcontext.cxx
new file mode 100644
index 000000000..d043ebc87
--- /dev/null
+++ b/oox/source/vml/vmltextboxcontext.cxx
@@ -0,0 +1,287 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <oox/helper/attributelist.hxx>
+#include <oox/vml/vmlformatting.hxx>
+#include <oox/vml/vmltextboxcontext.hxx>
+#include <oox/vml/vmlshape.hxx>
+#include <oox/token/namespaces.hxx>
+#include <oox/token/tokens.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <o3tl/string_view.hxx>
+
+namespace oox::vml {
+
+using ::oox::core::ContextHandler2;
+using ::oox::core::ContextHandler2Helper;
+using ::oox::core::ContextHandlerRef;
+
+TextPortionContext::TextPortionContext( ContextHandler2Helper const & rParent,
+ TextBox& rTextBox, TextParagraphModel const & rParagraph, const TextFontModel& rParentFont,
+ sal_Int32 nElement, const AttributeList& rAttribs ) :
+ ContextHandler2( rParent ),
+ mrTextBox( rTextBox ),
+ maParagraph( rParagraph ),
+ maFont( rParentFont ),
+ mnInitialPortions( rTextBox.getPortionCount() )
+{
+ switch( nElement )
+ {
+ case XML_font:
+ maFont.moName = rAttribs.getXString( XML_face );
+ maFont.moColor = rAttribs.getXString( XML_color );
+ maFont.monSize = rAttribs.getInteger( XML_size );
+ break;
+ case XML_u:
+ OSL_ENSURE( !maFont.monUnderline, "TextPortionContext::TextPortionContext - nested <u> elements" );
+ maFont.monUnderline = (rAttribs.getToken( XML_class, XML_TOKEN_INVALID ) == XML_font4) ? XML_double : XML_single;
+ break;
+ case XML_sub:
+ case XML_sup:
+ OSL_ENSURE( !maFont.monEscapement, "TextPortionContext::TextPortionContext - nested <sub> or <sup> elements" );
+ maFont.monEscapement = nElement;
+ break;
+ case XML_b:
+ OSL_ENSURE( !maFont.mobBold, "TextPortionContext::TextPortionContext - nested <b> elements" );
+ maFont.mobBold = true;
+ break;
+ case XML_i:
+ OSL_ENSURE( !maFont.mobItalic, "TextPortionContext::TextPortionContext - nested <i> elements" );
+ maFont.mobItalic = true;
+ break;
+ case XML_s:
+ OSL_ENSURE( !maFont.mobStrikeout, "TextPortionContext::TextPortionContext - nested <s> elements" );
+ maFont.mobStrikeout = true;
+ break;
+ case OOX_TOKEN(dml, blip):
+ {
+ OptValue<OUString> oRelId = rAttribs.getString(R_TOKEN(embed));
+ if (oRelId.has())
+ mrTextBox.mrTypeModel.moGraphicPath = getFragmentPathFromRelId(oRelId.get());
+ }
+ break;
+ case VML_TOKEN(imagedata):
+ {
+ OptValue<OUString> oRelId = rAttribs.getString(R_TOKEN(id));
+ if (oRelId.has())
+ mrTextBox.mrTypeModel.moGraphicPath = getFragmentPathFromRelId(oRelId.get());
+ }
+ break;
+ case XML_span:
+ case W_TOKEN(r):
+ break;
+ default:
+ OSL_ENSURE( false, "TextPortionContext::TextPortionContext - unknown element" );
+ }
+}
+
+ContextHandlerRef TextPortionContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ OSL_ENSURE( nElement != XML_font, "TextPortionContext::onCreateContext - nested <font> elements" );
+ if (getNamespace(getCurrentElement()) == NMSP_doc)
+ return this;
+ return new TextPortionContext( *this, mrTextBox, maParagraph, maFont, nElement, rAttribs );
+}
+
+void TextPortionContext::onCharacters( const OUString& rChars )
+{
+ if (getNamespace(getCurrentElement()) == NMSP_doc && getCurrentElement() != W_TOKEN(t))
+ return;
+
+ switch( getCurrentElement() )
+ {
+ case XML_span:
+ // replace all NBSP characters with SP
+ mrTextBox.appendPortion( maParagraph, maFont, rChars.replace( 0xA0, ' ' ) );
+ break;
+ default:
+ mrTextBox.appendPortion( maParagraph, maFont, rChars );
+ }
+}
+
+void TextPortionContext::onStartElement(const AttributeList& rAttribs)
+{
+ switch (getCurrentElement())
+ {
+ case W_TOKEN(b):
+ maFont.mobBold = true;
+ break;
+ case W_TOKEN(sz):
+ maFont.monSize = rAttribs.getInteger( W_TOKEN(val) );
+ break;
+ case W_TOKEN(br):
+ mrTextBox.appendPortion( maParagraph, maFont, "\n" );
+ break;
+ case W_TOKEN(color):
+ maFont.moColor = rAttribs.getString( W_TOKEN(val) );
+ break;
+ case W_TOKEN(spacing):
+ maFont.monSpacing = rAttribs.getInteger(W_TOKEN(val));
+ break;
+ case W_TOKEN(r):
+ case W_TOKEN(rPr):
+ case W_TOKEN(t):
+ break;
+ case W_TOKEN(rFonts):
+ // See https://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.runfonts(v=office.14).aspx
+ maFont.moName = rAttribs.getString(W_TOKEN(ascii));
+ maFont.moNameAsian = rAttribs.getString(W_TOKEN(eastAsia));
+ maFont.moNameComplex = rAttribs.getString(W_TOKEN(cs));
+ break;
+ default:
+ SAL_INFO("oox", "unhandled: 0x" << std::hex<< getCurrentElement());
+ break;
+ }
+}
+
+void TextPortionContext::onEndElement()
+{
+ if (getNamespace(getCurrentElement()) == NMSP_doc && getCurrentElement() != W_TOKEN(t))
+ return;
+
+ /* A child element without own child elements may contain a single space
+ character, for example:
+
+ <div>
+ <font><i>abc</i></font>
+ <font> </font>
+ <font><b>def</b></font>
+ </div>
+
+ represents the italic text 'abc', an unformatted space character, and
+ the bold text 'def'. Unfortunately, the XML parser skips the space
+ character without issuing a 'characters' event. The class member
+ 'mnInitialPortions' contains the number of text portions existing when
+ this context has been constructed. If no text has been added in the
+ meantime, the space character has to be added manually.
+ */
+ if( mrTextBox.getPortionCount() == mnInitialPortions )
+ mrTextBox.appendPortion( maParagraph, maFont, OUString( ' ' ) );
+}
+
+TextBoxContext::TextBoxContext( ContextHandler2Helper const & rParent, TextBox& rTextBox, const AttributeList& rAttribs,
+ const GraphicHelper& graphicHelper ) :
+ ContextHandler2( rParent ),
+ mrTextBox( rTextBox )
+{
+ if( rAttribs.getString( XML_insetmode ).get() != "auto" )
+ {
+ OUString inset = rAttribs.getString( XML_inset ).get();
+ std::u16string_view value;
+ std::u16string_view remainingStr;
+
+ ConversionHelper::separatePair( value, remainingStr, inset, ',' );
+ rTextBox.borderDistanceLeft = ConversionHelper::decodeMeasureToHmm( graphicHelper,
+ value.empty() ? u"0.1in" : value, 0, false, false );
+
+ inset = remainingStr;
+ ConversionHelper::separatePair( value, remainingStr, inset, ',' );
+ rTextBox.borderDistanceTop = ConversionHelper::decodeMeasureToHmm( graphicHelper,
+ value.empty() ? u"0.05in" : value, 0, false, false );
+
+ inset = remainingStr;
+ ConversionHelper::separatePair( value, remainingStr, inset, ',' );
+ rTextBox.borderDistanceRight = ConversionHelper::decodeMeasureToHmm( graphicHelper,
+ value.empty() ? u"0.1in" : value, 0, false, false );
+
+ inset = remainingStr;
+ ConversionHelper::separatePair( value, remainingStr, inset, ',' );
+ rTextBox.borderDistanceBottom = ConversionHelper::decodeMeasureToHmm( graphicHelper,
+ value.empty() ? u"0.05in" : value, 0, false, false );
+
+ rTextBox.borderDistanceSet = true;
+ }
+
+ OUString sStyle = rAttribs.getString( XML_style, OUString() );
+ sal_Int32 nIndex = 0;
+ while( nIndex >= 0 )
+ {
+ std::u16string_view aName, aValue;
+ if( ConversionHelper::separatePair( aName, aValue, o3tl::getToken(sStyle, 0, ';', nIndex ), ':' ) )
+ {
+ if( aName == u"layout-flow" ) rTextBox.maLayoutFlow = aValue;
+ else if (aName == u"mso-fit-shape-to-text")
+ rTextBox.mrTypeModel.mbAutoHeight = true;
+ else if (aName == u"mso-layout-flow-alt")
+ rTextBox.mrTypeModel.maLayoutFlowAlt = aValue;
+ else if (aName == u"mso-next-textbox")
+ rTextBox.msNextTextbox = aValue;
+ else
+ SAL_WARN("oox", "unhandled style property: " << OUString(aName));
+ }
+ }
+}
+
+ContextHandlerRef TextBoxContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+ switch( getCurrentElement() )
+ {
+ case VML_TOKEN( textbox ):
+ if( nElement == XML_div ) return this;
+ else if (nElement == W_TOKEN(txbxContent)) return this;
+ break;
+ case XML_div:
+ if( nElement == XML_font ) return new TextPortionContext( *this, mrTextBox, maParagraph, TextFontModel(), nElement, rAttribs );
+ break;
+ case W_TOKEN(txbxContent):
+ if (nElement == W_TOKEN(p)) return this;
+ break;
+ case W_TOKEN(p):
+ case W_TOKEN(sdtContent):
+ case W_TOKEN(smartTag):
+ if (nElement == W_TOKEN(r))
+ return new TextPortionContext( *this, mrTextBox, maParagraph, TextFontModel(), nElement, rAttribs );
+ else
+ return this;
+ case W_TOKEN(pPr):
+ case W_TOKEN(sdt):
+ return this;
+ default:
+ SAL_INFO("oox", "unhandled 0x" << std::hex << getCurrentElement());
+ break;
+ }
+ return nullptr;
+}
+
+void TextBoxContext::onStartElement(const AttributeList& rAttribs)
+{
+ switch (getCurrentElement())
+ {
+ case W_TOKEN(jc):
+ maParagraph.moParaAdjust = rAttribs.getString( W_TOKEN(val) );
+ break;
+ case W_TOKEN(pStyle):
+ maParagraph.moParaStyleName = rAttribs.getString( W_TOKEN(val) );
+ break;
+ }
+}
+
+void TextBoxContext::onEndElement()
+{
+ if (getCurrentElement() == W_TOKEN(p))
+ {
+ mrTextBox.appendPortion( maParagraph, TextFontModel(), "\n" );
+ maParagraph = TextParagraphModel();
+ }
+}
+
+} // namespace oox::vml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */