/* -*- 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 .
*/
/** Returns the percentage value from the specified VML attribute (if present). The value will be normalized (1.0 is returned for 100%).
*/
std::optional< double > lclDecodePercent( const AttributeList& rAttribs, sal_Int32 nToken, double fDefValue )
{
std::optional< OUString > oValue = rAttribs.getString( nToken ); if( oValue.has_value() ) return std::optional< double >( ConversionHelper::decodePercent( oValue.value(), fDefValue ) ); return std::optional< double >();
}
/** #119750# Special method for opacity; it *should* be a percentage value, but there are cases where a value relative to 0xffff (65536) is used, ending with an 'f'
*/
std::optional< double > lclDecodeOpacity( const AttributeList& rAttribs, sal_Int32 nToken, double fDefValue )
{
std::optional< OUString > oValue = rAttribs.getString( nToken ); double fRetval(fDefValue);
/** Returns the boolean value from the passed string of an attribute in the x: namespace (VML for spreadsheets). Supported values: f, t, False, True. @param bDefaultForEmpty Default value for the empty string.
*/ bool lclDecodeVmlxBool( std::u16string_view rValue, bool bDefaultForEmpty )
{ if( rValue.empty() ) return bDefaultForEmpty;
sal_Int32 nToken = AttributeConversion::decodeToken( rValue ); // anything else than 't' or 'True' is considered to be false, as specified return (nToken == XML_t) || (nToken == XML_True);
}
void ClientDataContext::onCharacters( const OUString& rChars )
{ /* Empty but existing elements have special meaning, e.g. 'true'. Collect
existing text and convert it in onEndElement(). */
maElementText = rChars;
}
void ClientDataContext::onEndElement()
{ switch( getCurrentElement() )
{ case VMLX_TOKEN( Anchor ): mrClientData.maAnchor = maElementText; break; case VMLX_TOKEN( FmlaMacro ): mrClientData.maFmlaMacro = maElementText; break; case VMLX_TOKEN( FmlaPict ): mrClientData.maFmlaPict = maElementText; break; case VMLX_TOKEN( FmlaLink ): mrClientData.maFmlaLink = maElementText; break; case VMLX_TOKEN( FmlaRange ): mrClientData.maFmlaRange = maElementText; break; case VMLX_TOKEN( FmlaGroup ): mrClientData.maFmlaGroup = maElementText; break; case VMLX_TOKEN( TextHAlign ): mrClientData.mnTextHAlign = AttributeConversion::decodeToken( maElementText ); break; case VMLX_TOKEN( TextVAlign ): mrClientData.mnTextVAlign = AttributeConversion::decodeToken( maElementText ); break; case VMLX_TOKEN( Column ): mrClientData.mnCol = maElementText.toInt32(); break; case VMLX_TOKEN( Row ): mrClientData.mnRow = maElementText.toInt32(); break; case VMLX_TOKEN( Checked ): mrClientData.mnChecked = maElementText.toInt32(); break; case VMLX_TOKEN( DropStyle ): mrClientData.mnDropStyle = AttributeConversion::decodeToken( maElementText ); break; case VMLX_TOKEN( DropLines ): mrClientData.mnDropLines = maElementText.toInt32(); break; case VMLX_TOKEN( Val ): mrClientData.mnVal = maElementText.toInt32(); break; case VMLX_TOKEN( Min ): mrClientData.mnMin = maElementText.toInt32(); break; case VMLX_TOKEN( Max ): mrClientData.mnMax = maElementText.toInt32(); break; case VMLX_TOKEN( Inc ): mrClientData.mnInc = maElementText.toInt32(); break; case VMLX_TOKEN( Page ): mrClientData.mnPage = maElementText.toInt32(); break; case VMLX_TOKEN( SelType ): mrClientData.mnSelType = AttributeConversion::decodeToken( maElementText ); break; case VMLX_TOKEN( VTEdit ): mrClientData.mnVTEdit = maElementText.toInt32(); break; case VMLX_TOKEN( PrintObject ): mrClientData.mbPrintObject = lclDecodeVmlxBool( maElementText, true ); break; case VMLX_TOKEN( Visible ): mrClientData.mbVisible = lclDecodeVmlxBool( maElementText, true ); break; case VMLX_TOKEN( DDE ): mrClientData.mbDde = lclDecodeVmlxBool( maElementText, true ); break; case VMLX_TOKEN( NoThreeD ): mrClientData.mbNo3D = lclDecodeVmlxBool( maElementText, true ); break; case VMLX_TOKEN( NoThreeD2 ): mrClientData.mbNo3D2 = lclDecodeVmlxBool( maElementText, true ); break; case VMLX_TOKEN( MultiLine ): mrClientData.mbMultiLine = lclDecodeVmlxBool( maElementText, true ); break; case VMLX_TOKEN( VScroll ): mrClientData.mbVScroll = lclDecodeVmlxBool( maElementText, true ); break; case VMLX_TOKEN( SecretEdit ): mrClientData.mbSecretEdit = lclDecodeVmlxBool( maElementText, true ); break;
}
}
ShapeTypeContext::ShapeTypeContext(ContextHandler2Helper const & rParent,
std::shared_ptr<ShapeType> const& pShapeType, const AttributeList& rAttribs)
: ShapeContextBase(rParent)
, m_pShapeType(pShapeType) // tdf#112311 keep it alive
, mrTypeModel( pShapeType->getTypeModel() )
{ // shape identifier and shape name bool bHasOspid = rAttribs.hasAttribute( O_TOKEN( spid ) );
mrTypeModel.maShapeId = rAttribs.getXString( bHasOspid ? O_TOKEN( spid ) : XML_id, OUString() );
mrTypeModel.maLegacyId = rAttribs.getStringDefaulted( XML_id);
OSL_ENSURE( !mrTypeModel.maShapeId.isEmpty(), "ShapeTypeContext::ShapeTypeContext - missing shape identifier" ); // builtin shape type identifier
mrTypeModel.moShapeType = rAttribs.getInteger( O_TOKEN( spt ) ); // if the o:spid attribute exists, the id attribute contains the user-defined shape name if( bHasOspid )
{
mrTypeModel.maShapeName = rAttribs.getXString( XML_id, OUString() ); // get ShapeType and ShapeId from name for compatibility static constexpr OUString sShapeTypePrefix = u"shapetype_"_ustr;
std::u16string_view tmp; if( mrTypeModel.maShapeName.startsWith( sShapeTypePrefix ) )
{
mrTypeModel.maShapeId = mrTypeModel.maShapeName;
mrTypeModel.moShapeType = o3tl::toInt32(mrTypeModel.maShapeName.subView(sShapeTypePrefix.getLength()));
} elseif (mrTypeModel.maShapeName.startsWith("_x0000_t", &tmp))
{
mrTypeModel.maShapeId = mrTypeModel.maShapeName;
mrTypeModel.moShapeType = o3tl::toInt32(tmp);
}
}
// coordinate system position/size, CSS style
mrTypeModel.moCoordPos = lclDecodeInt32Pair( rAttribs, XML_coordorigin );
mrTypeModel.moCoordSize = lclDecodeInt32Pair( rAttribs, XML_coordsize );
setStyle( rAttribs.getStringDefaulted( XML_style) ); if( lclDecodeBool( rAttribs, O_TOKEN( hr )).value_or( false ))
{ // MSO's handling of o:hr width is nowhere near what the spec says: // - o:hrpct is not in % but in 0.1% // - if o:hrpct is not given, 100% width is assumed // - given width is used only if explicit o:hrpct="0" is given
OUString hrpct = rAttribs.getString( O_TOKEN( hrpct ), u"1000"_ustr ); if( hrpct != "0" )
mrTypeModel.maWidthPercent = OUString::number( hrpct.toInt32() );
mrTypeModel.maWrapDistanceLeft = "0";
mrTypeModel.maWrapDistanceRight = "0";
mrTypeModel.maPositionHorizontal = rAttribs.getString( O_TOKEN( hralign ), u"left"_ustr );
mrTypeModel.moWrapType = "topAndBottom";
}
// stroke settings (may be overridden by v:stroke element later)
mrTypeModel.maStrokeModel.moStroked = lclDecodeBool( rAttribs, XML_stroked );
mrTypeModel.maStrokeModel.moColor = rAttribs.getString( XML_strokecolor );
mrTypeModel.maStrokeModel.moWeight = rAttribs.getString( XML_strokeweight );
// fill settings (may be overridden by v:fill element later)
mrTypeModel.maFillModel.moFilled = lclDecodeBool( rAttribs, XML_filled );
mrTypeModel.maFillModel.moColor = rAttribs.getString( XML_fillcolor );
// For roundrect we may have an arcsize attribute to read
mrTypeModel.maArcsize = rAttribs.getStringDefaulted(XML_arcsize); // editas
mrTypeModel.maEditAs = rAttribs.getStringDefaulted(XML_editas);
ContextHandlerRef ShapeContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
{ // Excel specific shape client data if( isRootElement() ) switch( nElement )
{ case VML_TOKEN( textbox ):
{ // Calculate the shape type: map both <rect> and <v:shape> with a textbox shape type to // a TextShape.
sal_Int32 nShapeType = 0; if (ShapeContainer* pShapeContainer = mrShape.getContainer())
{
OUString aType = mrShapeModel.maType; if (!aType.isEmpty() && aType[0] == '#')
{
aType = aType.copy(1);
} if (const ShapeType* pShapeType = pShapeContainer->getShapeTypeById(aType))
{
nShapeType = pShapeType->getTypeModel().moShapeType.value();
}
}
mrShapeModel.mbInGroup = (getParentElement() == VML_TOKEN(group));
// FIXME: the shape with textbox should be used for the next cases if (getCurrentElement() == VML_TOKEN(rect) || nShapeType == ESCHER_ShpInst_TextBox)
{ if (mrShapeModel.mbInGroup) // FIXME: without this a text will be added into the group-shape instead of its // parent shape
{ if (mrShape.isTextBox()) dynamic_cast<SimpleShape&>(mrShape).setService(
u"com.sun.star.drawing.CustomShape"_ustr); else dynamic_cast<SimpleShape&>(mrShape).setService(
u"com.sun.star.drawing.TextShape"_ustr);
} else // FIXME: without this we does not handle some properties like shadow dynamic_cast<SimpleShape&>(mrShape).setService(u"com.sun.star.text.TextFrame"_ustr);
} returnnew TextBoxContext( *this, mrShapeModel.createTextBox(mrShape.getTypeModel()), rAttribs,
mrShape.getDrawing().getFilter().getGraphicHelper());
} case VMLX_TOKEN( ClientData ): // tdf#41466 ActiveX control shapes with a textbox are transformed into a frame // (see unit test testActiveXOptionButtonGroup) dynamic_cast<SimpleShape&>(mrShape).setService(u"com.sun.star.text.TextFrame"_ustr); returnnew ClientDataContext( *this, mrShapeModel.createClientData(), rAttribs ); case VMLPPT_TOKEN( textdata ): // Force RectangleShape, this is ugly :( // and is there because of the lines above which change it to TextFrame dynamic_cast< SimpleShape& >( mrShape ).setService(
u"com.sun.star.drawing.RectangleShape"_ustr);
mrShapeModel.maLegacyDiagramPath = getFragmentPathFromRelId(rAttribs.getStringDefaulted(XML_id)); break; case O_TOKEN( signatureline ):
mrShapeModel.mbIsSignatureLine = true;
mrShapeModel.maSignatureId = rAttribs.getStringDefaulted(XML_id);
mrShapeModel.maSignatureLineSuggestedSignerName
= rAttribs.getStringDefaulted(O_TOKEN(suggestedsigner));
mrShapeModel.maSignatureLineSuggestedSignerTitle
= rAttribs.getStringDefaulted(O_TOKEN(suggestedsigner2));
mrShapeModel.maSignatureLineSuggestedSignerEmail
= rAttribs.getStringDefaulted(O_TOKEN(suggestedsigneremail));
mrShapeModel.maSignatureLineSigningInstructions
= rAttribs.getStringDefaulted(O_TOKEN(signinginstructions));
mrShapeModel.mbSignatureLineShowSignDate = ConversionHelper::decodeBool(
rAttribs.getString(XML_showsigndate, u"t"_ustr)); // default is true
mrShapeModel.mbSignatureLineCanAddComment = ConversionHelper::decodeBool(
rAttribs.getString(XML_allowcomments, u"f"_ustr)); // default is false break; case O_TOKEN( lock ): // TODO break;
} // handle remaining stuff in base class return ShapeTypeContext::onCreateContext( nElement, rAttribs );
} void ShapeContext::setWriterShape()
{
mrShape.setTextBox(true);
}
while (nIndex >= 0)
{
sal_Int32 nX = ConversionHelper::decodeMeasureToTwip(
mrShape.getDrawing().getFilter().getGraphicHelper(), o3tl::getToken(rPoints, 0, ',', nIndex),
0, true, true);
sal_Int32 nY = ConversionHelper::decodeMeasureToTwip(
mrShape.getDrawing().getFilter().getGraphicHelper(), o3tl::getToken(rPoints, 0, ',', nIndex),
0, false, true);
mrShapeModel.maPoints.emplace_back(nX, nY);
} // VML polyline has no size in its style attribute. Word writes the size to attribute // coordsize with values in twip but without unit. For others we get size from points. if (!mrShape.getTypeModel().maWidth.isEmpty() || !mrShape.getTypeModel().maHeight.isEmpty()) return;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.