/* -*- 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 .
*/
// postpone the output so that we are able to write even the elements // that we learn inside Commit()
m_pSerializer->mark(Tag_Container);
}
void VMLExport::CloseContainer()
{ if ( mRecTypes.back() == ESCHER_SpContainer )
{ // write the shape now when we have all the info
sal_Int32 nShapeElement = StartShape();
m_sShapeId = ShapeIdString( nShapeId ); if (m_sShapeId.startsWith("_x0000_"))
{ // xml_id must be set elsewhere. The id is critical for matching VBA macros etc, // and the spid is critical to link to the shape number elsewhere.
m_pShapeAttrList->addNS( XML_o, XML_spid, m_sShapeId );
} elseif (IsWaterMarkShape(m_pSdrObject->GetName()))
{ // Shape is a watermark object - keep the original shape's name // because Microsoft detects if it is a watermark by the actual name
m_pShapeAttrList->add( XML_id, m_pSdrObject->GetName() ); // also ('o:spid')
m_pShapeAttrList->addNS( XML_o, XML_spid, m_sShapeId );
} else
{
m_pShapeAttrList->add(XML_id, m_sShapeId);
}
}
bool VMLExport::IsWaterMarkShape(std::u16string_view rStr)
{ if (rStr.empty() ) returnfalse;
// properties // The numbers of defines ESCHER_Prop_foo and DFF_Prop_foo correspond to the PIDs in // 'Microsoft Office Drawing 97-2007 Binary Format Specification'. // The property values are set by EscherPropertyContainer::CreateCustomShapeProperties() method. bool bAlreadyWritten[ 0xFFF ] = {}; const EscherProperties &rOpts = rProps.GetOpts(); for (autoconst& opt : rOpts)
{
sal_uInt16 nId = ( opt.nPropId & 0x0FFF );
if ( bAlreadyWritten[ nId ] ) continue;
switch ( nId )
{ case ESCHER_Prop_WrapText: // 133
{ constchar *pWrapType = nullptr; switch ( opt.nPropValue )
{ case ESCHER_WrapSquare: case ESCHER_WrapByPoints: pWrapType = "square"; break; // these two are equivalent according to the docu case ESCHER_WrapNone: pWrapType = "none"; break; case ESCHER_WrapTopBottom: case ESCHER_WrapThrough: break; // last two are *undefined* in MS-ODRAW, don't exist in VML
} if ( pWrapType )
{
m_ShapeStyle.append(";mso-wrap-style:");
m_ShapeStyle.append(pWrapType);
}
}
bAlreadyWritten[ ESCHER_Prop_WrapText ] = true; break;
case ESCHER_Prop_AnchorText: // 135
{ charconst* pValue(nullptr); switch (opt.nPropValue)
{ case ESCHER_AnchorTop:
pValue = "top"; break; case ESCHER_AnchorMiddle:
pValue = "middle"; break; case ESCHER_AnchorBottom:
pValue = "bottom"; break; case ESCHER_AnchorTopCentered:
pValue = "top-center"; break; case ESCHER_AnchorMiddleCentered:
pValue = "middle-center"; break; case ESCHER_AnchorBottomCentered:
pValue = "bottom-center"; break; case ESCHER_AnchorTopBaseline:
pValue = "top-baseline"; break; case ESCHER_AnchorBottomBaseline:
pValue = "bottom-baseline"; break; case ESCHER_AnchorTopCenteredBaseline:
pValue = "top-center-baseline"; break; case ESCHER_AnchorBottomCenteredBaseline:
pValue = "bottom-center-baseline"; break;
}
m_ShapeStyle.append(";v-text-anchor:");
m_ShapeStyle.append(pValue);
} break;
case ESCHER_Prop_txflTextFlow: // 136
{ // at least "bottom-to-top" only has an effect when it's on the v:textbox element, not on v:shape
assert(m_TextboxStyle.isEmpty()); switch (opt.nPropValue)
{ case ESCHER_txflHorzN:
m_TextboxStyle.append("layout-flow:horizontal"); break; case ESCHER_txflTtoBA:
m_TextboxStyle.append("layout-flow:vertical"); break; case ESCHER_txflBtoT:
m_TextboxStyle.append("mso-layout-flow-alt:bottom-to-top"); break; default:
assert(false); // unimplemented in escher export break;
}
} break;
// coordorigin case ESCHER_Prop_geoLeft: // 320 case ESCHER_Prop_geoTop: // 321
{
sal_uInt32 nLeft = 0, nTop = 0;
// The segment type is stored in the upper 3 bits // and segment count is stored in the lower 13 // bits. unsignedchar nSegmentType = (nSeg & 0xE000) >> 13; unsignedshort nSegmentCount = nSeg & 0x03FF;
switch (nSegmentType)
{ case msopathMoveTo:
{
sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize ); if (nX >= 0 && nY >= 0 )
aPath.append( "m" + OString::number( nX ) + "," + OString::number( nY ) ); break;
} case msopathClientEscape: break; case msopathEscape:
{ // If the segment type is msopathEscape, the lower 13 bits are // divided in a 5 bit escape code and 8 bit // vertex count (not segment count!) unsignedchar nEscapeCode = (nSegmentCount & 0x1F00) >> 8; unsignedchar nVertexCount = nSegmentCount & 0x00FF;
pVerticesIt += nVertexCount;
switch (nEscapeCode)
{ case 0xa: // nofill
aPath.append( "nf" ); break; case 0xb: // nostroke
aPath.append( "ns" ); break;
}
if (rProps.GetOpt(ESCHER_Prop_fillOpacity, nValue)) // Partly undo the transformation at the end of EscherPropertyContainer::CreateFillProperties(): VML opacity is 0..1.
pAttrList->add(XML_opacity, OString::number(double((nValue * 100) >> 16) / 100));
m_pSerializer->singleElementNS( XML_v, XML_fill, pAttrList );
case ESCHER_Prop_lineColor: // 448 case ESCHER_Prop_lineWidth: // 459 case ESCHER_Prop_lineDashing: // 462 case ESCHER_Prop_lineStartArrowhead: // 464 case ESCHER_Prop_lineEndArrowhead: // 465 case ESCHER_Prop_lineStartArrowWidth: // 466 case ESCHER_Prop_lineStartArrowLength: // 467 case ESCHER_Prop_lineEndArrowWidth: // 468 case ESCHER_Prop_lineEndArrowLength: // 469 case ESCHER_Prop_lineJoinStyle: // 470 case ESCHER_Prop_lineEndCapStyle: // 471
{
sal_uInt32 nValue;
rtl::Reference<sax_fastparser::FastAttributeList> pAttrList = FastSerializerHelper::createAttrList();
sal_uInt32 nGtextFlags; if (rProps.GetOpt(DFF_Prop_gtextFStrikethrough /*255*/, nGtextFlags))
{ // The property is in fact a collection of flags. Two bytes contain the // fUsegtextF* flags and the other two bytes at same place the associated // On/Off flags. See '2.3.22.10 Geometry Text Boolean Properties' section // in [MS-ODRAW]. if ((nGtextFlags & 0x00200020) == 0x00200020) // DFF_Prop_gtextFBold = 250
aStyle += ";font-weight:bold"; if ((nGtextFlags & 0x00100010) == 0x00100010) // DFF_Prop_gtextFItalic = 251
aStyle += ";font-style:italic"; if ((nGtextFlags & 0x00800080) == 0x00800080) // no DFF, PID gtextFNormalize = 248
aStyle += ";v-same-letter-heights:t";
// The value 'Fontwork character spacing' in LO is bound to field 'Scaling' // not to 'Spacing' in character properties. In fact the characters are // rendered with changed distance and width. The method in escherex.cxx has // put a rounded value of 'CharScaleWidth' API property to // DFF_Prop_gtextSpacing (=196) as integer part of 16.16 fixed point format. // fUsegtextFTight and gtextFTight (244) of MS binary format are not used.
sal_uInt32 nGtextSpacing; if (rProps.GetOpt(DFF_Prop_gtextSpacing, nGtextSpacing))
aStyle += ";v-text-spacing:" + OUString::number(nGtextSpacing) + "f";
}
if (!aStyle.isEmpty())
pAttrList->add(XML_style, aStyle);
// tdf#153260. LO renders all Fontwork shapes as if trim="t" is set. Default // value is "f". So always write out "t", otherwise import will reduce the // shape height as workaround for "f".
pAttrList->add(XML_trim, "t");
bAlreadyWritten[ESCHER_Prop_gtextUNICODE] = true;
bAlreadyWritten[ESCHER_Prop_gtextFont] = true;
} break; case DFF_Prop_adjustValue: case DFF_Prop_adjust2Value:
{ // FIXME: tdf#153296: The currently exported markup for <v:shapetype> is based on // OOXML presets and unusable in regard to handles. Fontwork shapes use dedicated // own markup, see FontworkHelpers::GetVMLFontworkShapetypeMarkup. // Thus this is restricted to preset Fontwork shapes. Such have maximal two // adjustment values. if ((mso_sptTextSimple <= m_nShapeType && m_nShapeType <= mso_sptTextOnRing)
|| (mso_sptTextPlainText <= m_nShapeType && m_nShapeType <= mso_sptTextCanDown))
{
sal_uInt32 nValue;
OString sAdj; if (rProps.GetOpt(DFF_Prop_adjustValue, nValue))
{
sAdj = OString::number(static_cast<sal_Int32>(nValue)); if (rProps.GetOpt(DFF_Prop_adjust2Value, nValue))
sAdj += "," + OString::number(static_cast<sal_Int32>(nValue));
} if (!sAdj.isEmpty())
m_pShapeAttrList->add(XML_adj, sAdj);
bAlreadyWritten[DFF_Prop_adjustValue] = true;
bAlreadyWritten[DFF_Prop_adjust2Value] = true;
}
} break; case ESCHER_Prop_Rotation:
{ // The higher half of the variable contains the angle.
m_ShapeStyle.append(";rotation:" + OString::number(double(opt.nPropValue >> 16)));
bAlreadyWritten[ESCHER_Prop_Rotation] = true;
} break; case ESCHER_Prop_fNoLineDrawDash:
{ // See DffPropertyReader::ApplyLineAttributes().
impl_AddBool( m_pShapeAttrList.get(), XML_stroked, (opt.nPropValue & 8) != 0 );
bAlreadyWritten[ESCHER_Prop_fNoLineDrawDash] = true;
} break; case ESCHER_Prop_wzName:
{
SvMemoryStream aStream;
uno::Reference<beans::XPropertySet> xShape(const_cast<SdrObject*>(pSdrObject)->getUnoShape(), uno::UNO_QUERY); if (xShape->getPropertySetInfo()->hasPropertyByName(u"InteropGrabBag"_ustr))
{
comphelper::SequenceAsHashMap aInteropGrabBag(xShape->getPropertyValue(u"InteropGrabBag"_ustr)); auto it = aInteropGrabBag.find(u"AnchorId"_ustr); if (it != aInteropGrabBag.end())
it->second >>= aResult;
}
// some of the shapes have their own name ;-)
sal_Int32 nShapeElement = -1; bool bReferToShapeType = false; switch ( m_nShapeType )
{ case ESCHER_ShpInst_NotPrimitive: nShapeElement = XML_shape; break; case ESCHER_ShpInst_Rectangle: nShapeElement = XML_rect; break; case ESCHER_ShpInst_RoundRectangle: nShapeElement = XML_roundrect; break; case ESCHER_ShpInst_Ellipse: nShapeElement = XML_oval; break; case ESCHER_ShpInst_Arc: nShapeElement = XML_arc; break; case ESCHER_ShpInst_Line: nShapeElement = XML_line; break; case ESCHER_ShpInst_HostControl:
{
bReferToShapeType = true;
nShapeElement = XML_shape; if ( !m_aShapeTypeWritten[ m_nShapeType ] )
{
m_pSerializer->write(GetVMLShapeTypeDefinition(OString::number(m_nShapeType), false));
m_aShapeTypeWritten[ m_nShapeType ] = true;
} break;
} case ESCHER_ShpInst_PictureFrame:
{
bReferToShapeType = true;
nShapeElement = XML_shape; if ( !m_aShapeTypeWritten[ m_nShapeType ] )
{
m_pSerializer->write(GetVMLShapeTypeDefinition(OString::number(m_nShapeType), true));
m_aShapeTypeWritten[ m_nShapeType ] = true;
} break;
} default:
nShapeElement = XML_shape; if (m_pSdrObject->IsTextPath())
{
bReferToShapeType = m_aShapeTypeWritten[m_nShapeType]; if (!bReferToShapeType)
{ // Does a predefined markup exist at all?
OString sMarkup = FontworkHelpers::GetVMLFontworkShapetypeMarkup( static_cast<MSO_SPT>(m_nShapeType)); if (!sMarkup.isEmpty())
{
m_pSerializer->write(sMarkup);
m_aShapeTypeWritten[m_nShapeType] = true;
bReferToShapeType = true;
}
} // ToDo: The case bReferToShapeType==false happens for 'non-primitive' shapes for // example. We need to get the geometry from CustomShapeGeometry in these cases.
} elseif ( m_nShapeType < ESCHER_ShpInst_COUNT )
{ // a predefined shape? static std::vector<OString> aShapeTypes = lcl_getShapeTypes();
SAL_WARN_IF(m_nShapeType >= aShapeTypes.size(), "oox.vml", "Unknown shape type!"); if (m_nShapeType < aShapeTypes.size() && aShapeTypes[m_nShapeType] != "NULL")
{
bReferToShapeType = true; if ( !m_aShapeTypeWritten[ m_nShapeType ] )
{
m_pSerializer->write(aShapeTypes[m_nShapeType]);
m_aShapeTypeWritten[ m_nShapeType ] = true;
}
} else
{ // rectangle is probably the best fallback...
nShapeElement = XML_rect;
}
} break;
}
// anchoring switch (m_eHOri)
{ case text::HoriOrientation::LEFT:
m_ShapeStyle.append(";mso-position-horizontal:left"); break; case text::HoriOrientation::CENTER:
m_ShapeStyle.append(";mso-position-horizontal:center"); break; case text::HoriOrientation::RIGHT:
m_ShapeStyle.append(";mso-position-horizontal:right"); break; case text::HoriOrientation::INSIDE:
m_ShapeStyle.append(";mso-position-horizontal:inside"); break; case text::HoriOrientation::OUTSIDE:
m_ShapeStyle.append(";mso-position-horizontal:outside"); break; default: case text::HoriOrientation::NONE: break;
} switch (m_eHRel)
{ case text::RelOrientation::PAGE_PRINT_AREA:
m_ShapeStyle.append(";mso-position-horizontal-relative:margin"); break; case text::RelOrientation::PAGE_FRAME: case text::RelOrientation::PAGE_LEFT: case text::RelOrientation::PAGE_RIGHT:
m_ShapeStyle.append(";mso-position-horizontal-relative:page"); break; case text::RelOrientation::CHAR:
m_ShapeStyle.append(";mso-position-horizontal-relative:char"); break; default: break;
}
switch (m_eVOri)
{ case text::VertOrientation::TOP: case text::VertOrientation::LINE_TOP: case text::VertOrientation::CHAR_TOP:
m_ShapeStyle.append(";mso-position-vertical:top"); break; case text::VertOrientation::CENTER: case text::VertOrientation::LINE_CENTER:
m_ShapeStyle.append(";mso-position-vertical:center"); break; case text::VertOrientation::BOTTOM: case text::VertOrientation::LINE_BOTTOM: case text::VertOrientation::CHAR_BOTTOM:
m_ShapeStyle.append(";mso-position-vertical:bottom"); break; default: case text::VertOrientation::NONE: break;
} switch (m_eVRel)
{ case text::RelOrientation::PAGE_PRINT_AREA:
m_ShapeStyle.append(";mso-position-vertical-relative:margin"); break; case text::RelOrientation::PAGE_FRAME:
m_ShapeStyle.append(";mso-position-vertical-relative:page"); break; default: break;
}
if (!m_pSdrObject->getHyperlink().isEmpty())
m_pShapeAttrList->add(
XML_href, m_pSdrObject->getHyperlink());
// allow legacy id (which in form controls and textboxes // by definition seems to have this otherwise illegal name).
m_pSerializer->setAllowXEscape(!m_sShapeIDPrefix.startsWith("_x0000_"));
// start of the shape
m_pSerializer->startElementNS( XML_v, nShapeElement, m_pShapeAttrList );
m_pSerializer->setAllowXEscape(true);
// now check if we have some editeng text (not associated textbox) and we have a text exporter registered const SdrTextObj* pTxtObj = DynCastSdrTextObj( m_pSdrObject ); if (pTxtObj && m_pTextExport && !m_pSdrObject->IsTextPath()
&& !IsWaterMarkShape(m_pSdrObject->GetName()) && !lcl_isTextBox(m_pSdrObject))
{
std::optional<OutlinerParaObject> pParaObj;
/* #i13885# When the object is actively being edited, that text is not set into the objects normal text object, but lives in a separate object.
*/ if (pTxtObj->IsTextEditActive())
{
pParaObj = pTxtObj->CreateEditOutlinerParaObject();
} elseif (pTxtObj->GetOutlinerParaObject())
{
pParaObj = *pTxtObj->GetOutlinerParaObject();
}
// this is reached only in case some text is attached to the shape
m_pSerializer->startElementNS(XML_v, XML_textbox, pTextboxAttrList);
m_pTextExport->WriteOutliner(*pParaObj);
m_pSerializer->endElementNS(XML_v, XML_textbox);
}
}
¤ 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.0.31Bemerkung:
(vorverarbeitet)
¤
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.