diff options
Diffstat (limited to 'xmloff/source/draw')
59 files changed, 32169 insertions, 0 deletions
diff --git a/xmloff/source/draw/EnhancedCustomShapeToken.cxx b/xmloff/source/draw/EnhancedCustomShapeToken.cxx new file mode 100644 index 0000000000..d8c54a3704 --- /dev/null +++ b/xmloff/source/draw/EnhancedCustomShapeToken.cxx @@ -0,0 +1,214 @@ +/* -*- 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 <EnhancedCustomShapeToken.hxx> +#include <xmloff/xmlimp.hxx> +#include <unordered_map> +#include <memory> + +namespace xmloff::EnhancedCustomShapeToken { + + +namespace { + +struct TokenTable +{ + const char* pS; + EnhancedCustomShapeTokenEnum pE; +}; + +} + +const TokenTable pTokenTableArray[] = +{ + { "type", EAS_type }, + { "name", EAS_name }, + { "mirror-horizontal", EAS_mirror_horizontal }, + { "mirror-vertical", EAS_mirror_vertical }, + { "viewBox", EAS_viewBox }, + { "text-rotate-angle", EAS_text_rotate_angle }, + { "extrusion-allowed", EAS_extrusion_allowed }, + { "extrusion-text-path-allowed", EAS_text_path_allowed }, + { "extrusion-concentric-gradient-fill", EAS_concentric_gradient_fill_allowed }, + { "extrusion", EAS_extrusion }, + { "extrusion-brightness", EAS_extrusion_brightness }, + { "extrusion-depth", EAS_extrusion_depth }, + { "extrusion-diffusion", EAS_extrusion_diffusion }, + { "extrusion-number-of-line-segments", EAS_extrusion_number_of_line_segments }, + { "extrusion-light-face", EAS_extrusion_light_face }, + { "extrusion-first-light-harsh", EAS_extrusion_first_light_harsh }, + { "extrusion-second-light-harsh", EAS_extrusion_second_light_harsh }, + { "extrusion-first-light-level", EAS_extrusion_first_light_level }, + { "extrusion-second-light-level", EAS_extrusion_second_light_level }, + { "extrusion-first-light-direction", EAS_extrusion_first_light_direction }, + { "extrusion-second-light-direction", EAS_extrusion_second_light_direction }, + { "extrusion-metal", EAS_extrusion_metal }, + { "extrusion-metal-type", EAS_extrusion_metal_type }, + { "shade-mode", EAS_shade_mode }, + { "extrusion-rotation-angle", EAS_extrusion_rotation_angle }, + { "extrusion-rotation-center", EAS_extrusion_rotation_center }, + { "extrusion-shininess", EAS_extrusion_shininess }, + { "extrusion-skew", EAS_extrusion_skew }, + { "extrusion-specularity", EAS_extrusion_specularity }, + { "extrusion-specularity-loext", EAS_extrusion_specularity_loext }, + { "projection", EAS_projection }, + { "extrusion-viewpoint", EAS_extrusion_viewpoint }, + { "extrusion-origin", EAS_extrusion_origin }, + { "extrusion-color", EAS_extrusion_color }, + { "enhanced-path", EAS_enhanced_path }, + { "path-stretchpoint-x", EAS_path_stretchpoint_x }, + { "path-stretchpoint-y", EAS_path_stretchpoint_y }, + { "text-areas", EAS_text_areas }, + { "glue-points", EAS_glue_points }, + { "glue-point-type", EAS_glue_point_type }, + { "glue-point-leaving-directions", EAS_glue_point_leaving_directions }, + { "text-path", EAS_text_path }, + { "text-path-mode", EAS_text_path_mode }, + { "text-path-scale", EAS_text_path_scale }, + { "text-path-same-letter-heights", EAS_text_path_same_letter_heights }, + { "modifiers", EAS_modifiers }, + { "equation", EAS_equation }, + { "formula", EAS_formula }, + { "handle", EAS_handle }, + { "handle-mirror-horizontal", EAS_handle_mirror_horizontal }, + { "handle-mirror-vertical", EAS_handle_mirror_vertical }, + { "handle-switched", EAS_handle_switched }, + { "handle-position", EAS_handle_position }, + { "handle-range-x-minimum", EAS_handle_range_x_minimum }, + { "handle-range-x-maximum", EAS_handle_range_x_maximum }, + { "handle-range-y-minimum", EAS_handle_range_y_minimum }, + { "handle-range-y-maximum", EAS_handle_range_y_maximum }, + { "handle-polar", EAS_handle_polar }, + { "handle-radius-range-minimum", EAS_handle_radius_range_minimum }, + { "handle-radius-range-maximum", EAS_handle_radius_range_maximum }, + { "sub-view-size", EAS_sub_view_size }, + + { "CustomShapeEngine", EAS_CustomShapeEngine }, + { "CustomShapeData", EAS_CustomShapeData }, + { "Type", EAS_Type }, + { "MirroredX", EAS_MirroredX }, + { "MirroredY", EAS_MirroredY }, + { "ViewBox", EAS_ViewBox }, + { "TextRotateAngle", EAS_TextRotateAngle }, + { "TextPreRotateAngle", EAS_TextPreRotateAngle }, + { "ExtrusionAllowed", EAS_ExtrusionAllowed }, + { "TextPathAllowed", EAS_TextPathAllowed }, + { "ConcentricGradientFillAllowed", EAS_ConcentricGradientFillAllowed }, + { "Extrusion", EAS_Extrusion }, + { "Equations", EAS_Equations }, + { "Equation", EAS_Equation }, + { "Path", EAS_Path }, + { "TextPath", EAS_TextPath }, + { "Handles", EAS_Handles }, + { "Handle", EAS_Handle }, + { "Brightness", EAS_Brightness }, + { "Depth", EAS_Depth }, + { "Diffusion", EAS_Diffusion }, + { "NumberOfLineSegments", EAS_NumberOfLineSegments }, + { "LightFace", EAS_LightFace }, + { "FirstLightHarsh", EAS_FirstLightHarsh }, + { "SecondLightHarsh", EAS_SecondLightHarsh }, + { "FirstLightLevel", EAS_FirstLightLevel }, + { "SecondLightLevel", EAS_SecondLightLevel }, + { "FirstLightDirection", EAS_FirstLightDirection }, + { "SecondLightDirection", EAS_SecondLightDirection }, + { "Metal", EAS_Metal }, + { "MetalType", EAS_MetalType }, + { "ShadeMode", EAS_ShadeMode }, + { "RotateAngle", EAS_RotateAngle }, + { "RotationCenter", EAS_RotationCenter }, + { "Shininess", EAS_Shininess }, + { "Skew", EAS_Skew }, + { "Specularity", EAS_Specularity }, + { "ProjectionMode", EAS_ProjectionMode }, + { "ViewPoint", EAS_ViewPoint }, + { "Origin", EAS_Origin }, + { "Color", EAS_Color }, + { "Switched", EAS_Switched }, + { "Polar", EAS_Polar }, + { "RangeXMinimum", EAS_RangeXMinimum }, + { "RangeXMaximum", EAS_RangeXMaximum }, + { "RangeYMinimum", EAS_RangeYMinimum }, + { "RangeYMaximum", EAS_RangeYMaximum }, + { "RadiusRangeMinimum", EAS_RadiusRangeMinimum }, + { "RadiusRangeMaximum", EAS_RadiusRangeMaximum }, + { "Coordinates", EAS_Coordinates }, + { "Segments", EAS_Segments }, + { "StretchX", EAS_StretchX }, + { "StretchY", EAS_StretchY }, + { "TextFrames", EAS_TextFrames }, + { "GluePoints", EAS_GluePoints }, + { "GluePointLeavingDirections", EAS_GluePointLeavingDirections }, + { "GluePointType", EAS_GluePointType }, + { "TextPathMode", EAS_TextPathMode }, + { "ScaleX", EAS_ScaleX }, + { "SameLetterHeights", EAS_SameLetterHeights }, + { "Position", EAS_Position }, + { "AdjustmentValues", EAS_AdjustmentValues }, + { "SubViewSize", EAS_SubViewSize }, + + { "Last", EAS_Last }, + { "NotFound", EAS_NotFound } +}; + +typedef std::unordered_map< const char*, EnhancedCustomShapeTokenEnum, rtl::CStringHash, rtl::CStringEqual> TypeNameHashMap; +static const TypeNameHashMap& GetNameHashMap() +{ + static TypeNameHashMap aHashMap = []() + { // init hash map + TypeNameHashMap res; + for (auto const & pair : pTokenTableArray) + res[pair.pS] = pair.pE; + return res; + }(); + + return aHashMap; +} + +EnhancedCustomShapeTokenEnum EASGet( std::u16string_view rShapeType ) +{ + EnhancedCustomShapeTokenEnum eRetValue = EAS_NotFound; + size_t i, nLen = rShapeType.size(); + std::unique_ptr<char[]> pBuf(new char[ nLen + 1 ]); + for ( i = 0; i < nLen; i++ ) + pBuf[ i ] = static_cast<char>(rShapeType[ i ]); + pBuf[ i ] = 0; + auto& rHashMap = GetNameHashMap(); + TypeNameHashMap::const_iterator aHashIter( rHashMap.find( pBuf.get() ) ); + if ( aHashIter != rHashMap.end() ) + eRetValue = (*aHashIter).second; + return eRetValue; +} + +EnhancedCustomShapeTokenEnum EASGet( sal_Int32 nToken ) +{ + return EASGet(SvXMLImport::getNameFromToken(nToken)); +} + +OUString EASGet( const EnhancedCustomShapeTokenEnum eToken ) +{ + sal_uInt32 i = eToken >= EAS_Last + ? sal_uInt32(EAS_NotFound) + : static_cast<sal_uInt32>(eToken); + return OUString::createFromAscii( pTokenTableArray[ i ].pS ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/QRCodeContext.cxx b/xmloff/source/draw/QRCodeContext.cxx new file mode 100644 index 0000000000..597838f78c --- /dev/null +++ b/xmloff/source/draw/QRCodeContext.cxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#include "QRCodeContext.hxx" + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/drawing/BarCode.hpp> +#include <com/sun/star/drawing/BarCodeErrorCorrection.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> + +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <sax/tools/converter.hxx> + +#include <rtl/ustring.hxx> + +using namespace css; +using namespace css::xml::sax; +using namespace css::uno; +using namespace css::drawing; +using namespace css::embed; +using namespace css::frame; +using namespace css::io; +using namespace css::graphic; +using namespace xmloff::token; + +QRCodeContext::QRCodeContext(SvXMLImport& rImport, sal_Int32 /*nElement*/, + const Reference<XFastAttributeList>& xAttrList, + const Reference<XShape>& rxShape) + : SvXMLImportContext(rImport) +{ + Reference<beans::XPropertySet> xPropSet(rxShape, UNO_QUERY_THROW); + + css::drawing::BarCode aBarCode; + + for (auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_QRCODE_ERROR_CORRECTION): + { + OUString aErrorCorrValue = aIter.toString(); + + if (aErrorCorrValue == "low") + aBarCode.ErrorCorrection = css::drawing::BarCodeErrorCorrection::LOW; + else if (aErrorCorrValue == "medium") + aBarCode.ErrorCorrection = css::drawing::BarCodeErrorCorrection::MEDIUM; + else if (aErrorCorrValue == "quartile") + aBarCode.ErrorCorrection = css::drawing::BarCodeErrorCorrection::QUARTILE; + else + aBarCode.ErrorCorrection = css::drawing::BarCodeErrorCorrection::HIGH; + break; + } + case XML_ELEMENT(LO_EXT, XML_QRCODE_BORDER): + { + sal_Int32 nAttrVal; + if (sax::Converter::convertNumber(nAttrVal, aIter.toView(), 0)) + aBarCode.Border = nAttrVal; + break; + } + case XML_ELEMENT(OFFICE, XML_STRING_VALUE): + { + aBarCode.Payload = aIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_QRCODE_TYPE): + { + sal_Int32 nAttrVal; + if (sax::Converter::convertNumber(nAttrVal, aIter.toView(), 0)) + aBarCode.Type = nAttrVal; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + xPropSet->setPropertyValue("BarCodeProperties", Any(aBarCode)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/xmloff/source/draw/QRCodeContext.hxx b/xmloff/source/draw/QRCodeContext.hxx new file mode 100644 index 0000000000..c35c6f9bd9 --- /dev/null +++ b/xmloff/source/draw/QRCodeContext.hxx @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#pragma once + +#include <com/sun/star/drawing/XShape.hpp> +#include <xmloff/xmlictxt.hxx> + +// Used to import QR code properties from a QR code in ODF document +// @see ximpshap + +class QRCodeContext : public SvXMLImportContext +{ +public: + QRCodeContext(SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList, + const css::uno::Reference<css::drawing::XShape>& rxShape); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/xmloff/source/draw/SignatureLineContext.cxx b/xmloff/source/draw/SignatureLineContext.cxx new file mode 100644 index 0000000000..0217156e35 --- /dev/null +++ b/xmloff/source/draw/SignatureLineContext.cxx @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#include "SignatureLineContext.hxx" + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/security/DocumentDigitalSignatures.hpp> +#include <com/sun/star/security/XDocumentDigitalSignatures.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> + +#include <sal/log.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/storagehelper.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> + +using namespace css; +using namespace css::xml::sax; +using namespace css::uno; +using namespace css::drawing; +using namespace css::embed; +using namespace css::frame; +using namespace css::io; +using namespace css::graphic; +using namespace css::security; +using namespace xmloff::token; + +SignatureLineContext::SignatureLineContext(SvXMLImport& rImport, sal_Int32 /*nElement*/, + const Reference<XFastAttributeList>& xAttrList, + const Reference<XShape>& rxShape) + : SvXMLImportContext(rImport) +{ + Reference<beans::XPropertySet> xPropSet(rxShape, UNO_QUERY_THROW); + + xPropSet->setPropertyValue("IsSignatureLine", Any(true)); + + xPropSet->setPropertyValue("SignatureLineId", + Any(xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_ID)))); + xPropSet->setPropertyValue( + "SignatureLineSuggestedSignerName", + Any(xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_SUGGESTED_SIGNER_NAME)))); + xPropSet->setPropertyValue( + "SignatureLineSuggestedSignerTitle", + Any(xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_SUGGESTED_SIGNER_TITLE)))); + xPropSet->setPropertyValue( + "SignatureLineSuggestedSignerEmail", + Any(xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_SUGGESTED_SIGNER_EMAIL)))); + xPropSet->setPropertyValue( + "SignatureLineSigningInstructions", + Any(xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_SIGNING_INSTRUCTIONS)))); + + bool bShowSignDate = xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_SHOW_SIGN_DATE)) + == GetXMLToken(XML_TRUE); + bool bCanAddComment = xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_CAN_ADD_COMMENT)) + == GetXMLToken(XML_TRUE); + xPropSet->setPropertyValue("SignatureLineShowSignDate", Any(bShowSignDate)); + xPropSet->setPropertyValue("SignatureLineCanAddComment", Any(bCanAddComment)); + + // Save unsigned graphic (need it when exporting) + Reference<XGraphic> xUnsignedGraphic; + xPropSet->getPropertyValue("Graphic") >>= xUnsignedGraphic; + if (xUnsignedGraphic.is()) + xPropSet->setPropertyValue("SignatureLineUnsignedImage", Any(xUnsignedGraphic)); + + Reference<XGraphic> xGraphic; + try + { + // Get the document signatures + css::uno::Reference<XStorable> xStorable(GetImport().GetModel(), UNO_QUERY_THROW); + Reference<XStorage> xStorage = comphelper::OStorageHelper::GetStorageOfFormatFromURL( + ZIP_STORAGE_FORMAT_STRING, xStorable->getLocation(), ElementModes::READ); + + if (!xStorage.is()) + { + SAL_WARN("xmloff", "No xStorage!"); + return; + } + + OUString const aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(xStorage)); + Reference<XDocumentDigitalSignatures> xSignatures( + security::DocumentDigitalSignatures::createWithVersion( + comphelper::getProcessComponentContext(), aODFVersion)); + + const Sequence<DocumentSignatureInformation> xSignatureInfo + = xSignatures->verifyDocumentContentSignatures(xStorage, Reference<XInputStream>()); + + // Try to find matching signature line image - if none exists that is fine, + // then the signature line is not digitally signed. + auto pSignatureInfo + = std::find_if(xSignatureInfo.begin(), xSignatureInfo.end(), + [&xAttrList](const DocumentSignatureInformation& rSignatureInfo) { + return rSignatureInfo.SignatureLineId + == xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_ID)); + }); + bool bIsSigned(false); + if (pSignatureInfo != xSignatureInfo.end()) + { + bIsSigned = true; + if (pSignatureInfo->SignatureIsValid) + { + // Signature is valid, use the 'valid' image + SAL_WARN_IF(!pSignatureInfo->ValidSignatureLineImage.is(), "xmloff", + "No ValidSignatureLineImage!"); + xGraphic = pSignatureInfo->ValidSignatureLineImage; + } + else + { + // Signature is invalid, use the 'invalid' image + SAL_WARN_IF(!pSignatureInfo->InvalidSignatureLineImage.is(), "xmloff", + "No InvalidSignatureLineImage!"); + xGraphic = pSignatureInfo->InvalidSignatureLineImage; + } + + xPropSet->setPropertyValue("Graphic", Any(xGraphic)); + } + xPropSet->setPropertyValue("SignatureLineIsSigned", Any(bIsSigned)); + } + catch (css::uno::Exception&) + { + // DocumentDigitalSignatures service not available. + // We render the "unsigned" shape instead. + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/xmloff/source/draw/SignatureLineContext.hxx b/xmloff/source/draw/SignatureLineContext.hxx new file mode 100644 index 0000000000..68a9373ae7 --- /dev/null +++ b/xmloff/source/draw/SignatureLineContext.hxx @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#pragma once + +#include <com/sun/star/drawing/XShape.hpp> +#include <xmloff/xmlictxt.hxx> + +// signatureline inside a shape + +class SignatureLineContext : public SvXMLImportContext +{ +public: + SignatureLineContext(SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList, + const css::uno::Reference<css::drawing::XShape>& rxShape); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/xmloff/source/draw/XMLGraphicsDefaultStyle.cxx b/xmloff/source/draw/XMLGraphicsDefaultStyle.cxx new file mode 100644 index 0000000000..de6b50a147 --- /dev/null +++ b/xmloff/source/draw/XMLGraphicsDefaultStyle.cxx @@ -0,0 +1,188 @@ +/* -*- 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 <xmloff/XMLGraphicsDefaultStyle.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#include <tools/color.hxx> + +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/families.hxx> +#include <xmloff/xmltypes.hxx> +#include <xmloff/maptype.hxx> +#include <xmloff/xmlimppr.hxx> +#include <xmloff/xmlprmap.hxx> + +#include <XMLShapePropertySetContext.hxx> +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::xml::sax; + +using ::xmloff::token::XML_TEXT_PROPERTIES; +using ::xmloff::token::XML_GRAPHIC_PROPERTIES; +using ::xmloff::token::XML_PARAGRAPH_PROPERTIES; + + +XMLGraphicsDefaultStyle::XMLGraphicsDefaultStyle( SvXMLImport& rImport, SvXMLStylesContext& rStyles ) +: XMLPropStyleContext( rImport, rStyles, XmlStyleFamily::SD_GRAPHICS_ID, true ) +{ +} + +XMLGraphicsDefaultStyle::~XMLGraphicsDefaultStyle() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLGraphicsDefaultStyle::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( IsTokenInNamespace(nElement, XML_NAMESPACE_STYLE) || + IsTokenInNamespace(nElement, XML_NAMESPACE_LO_EXT) ) + { + sal_Int32 nLocalName = nElement & TOKEN_MASK; + sal_uInt32 nFamily = 0; + if( nLocalName == XML_TEXT_PROPERTIES ) + nFamily = XML_TYPE_PROP_TEXT; + else if( nLocalName == XML_PARAGRAPH_PROPERTIES ) + nFamily = XML_TYPE_PROP_PARAGRAPH; + else if( nLocalName == XML_GRAPHIC_PROPERTIES ) + nFamily = XML_TYPE_PROP_GRAPHIC; + if( nFamily ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + return new XMLShapePropertySetContext( GetImport(), nElement, xAttrList, nFamily, GetProperties(), xImpPrMap ); + } + } + + return XMLPropStyleContext::createFastChildContext( nElement, xAttrList ); +} + +namespace { + +struct XMLPropertyByIndex { + sal_Int32 const m_nIndex; + explicit XMLPropertyByIndex(sal_Int32 const nIndex) : m_nIndex(nIndex) {} + bool operator()(XMLPropertyState const& rProp) { + return m_nIndex == rProp.mnIndex; + } +}; + +} + +// This method is called for every default style +void XMLGraphicsDefaultStyle::SetDefaults() +{ + Reference< XMultiServiceFactory > xFact( GetImport().GetModel(), UNO_QUERY ); + if( !xFact.is() ) + return; + + Reference< XPropertySet > xDefaults( xFact->createInstance( "com.sun.star.drawing.Defaults" ), UNO_QUERY ); + if( !xDefaults.is() ) + return; + // SJ: #i114750# + bool bWordWrapDefault = true; // initializing with correct ODF fo:wrap-option default + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild ); + if ( bBuildIdFound && ( + ((nUPD >= 600) && (nUPD < 700)) + || + ((nUPD == 300) && (nBuild <= 9535)) + || + ((nUPD > 300) && (nUPD <= 330)) + ) ) + bWordWrapDefault = false; + + static constexpr OUString sTextWordWrap( u"TextWordWrap"_ustr ); + Reference< XPropertySetInfo > xInfo( xDefaults->getPropertySetInfo() ); + if ( xInfo->hasPropertyByName( sTextWordWrap ) ) + xDefaults->setPropertyValue( sTextWordWrap, Any( bWordWrapDefault ) ); + + if (GetImport().IsOOoXML() + && xInfo->hasPropertyByName("IsFollowingTextFlow")) + { + // OOo 1.x only supported "true" so that is the more appropriate + // default for OOoXML format documents. + xDefaults->setPropertyValue("IsFollowingTextFlow", uno::Any(true)); + } + + // NOTE: the only reason why it's legal to check "==" (not "<") against + // arbitrary versions here is that the default value of these attributes + // is not defined by ODF, therefore it is implementation-defined + // (and we of course must not override any attributes that are actually + // in the document, so check for that) + bool const bIsAOO4( + GetImport().getGeneratorVersion() >= SvXMLImport::AOO_40x + && GetImport().getGeneratorVersion() <= SvXMLImport::AOO_4x); + + // fdo#75872: backward compatibility for pool defaults change + if (GetImport().isGeneratorVersionOlderThan( + SvXMLImport::AOO_40x, SvXMLImport::LO_42x) + // argh... it turns out that LO has also changed defaults for these + // since LO 4.0, and so even the _new_ AOO 4.0+ default needs + // special handling since AOO still does _not_ write it into the file + || bIsAOO4) + { + rtl::Reference<XMLPropertySetMapper> const pImpPrMap( + GetStyles()->GetImportPropertyMapper(GetFamily()) + ->getPropertySetMapper()); + sal_Int32 const nStrokeIndex( + pImpPrMap->GetEntryIndex(XML_NAMESPACE_SVG, u"stroke-color", 0)); + if (std::none_of(GetProperties().begin(), GetProperties().end(), + XMLPropertyByIndex(nStrokeIndex))) + { + Color const nStroke( + bIsAOO4 ? Color(128, 128, 128) : COL_BLACK); + xDefaults->setPropertyValue("LineColor", Any(nStroke)); + } + Color const nFillColor( bIsAOO4 + ? Color(0xCF, 0xE7, 0xF5) : Color(153, 204, 255)); + sal_Int32 const nFillIndex( + pImpPrMap->GetEntryIndex(XML_NAMESPACE_DRAW, u"fill-color", 0)); + if (std::none_of(GetProperties().begin(), GetProperties().end(), + XMLPropertyByIndex(nFillIndex))) + { + xDefaults->setPropertyValue("FillColor", Any(nFillColor)); + } + if (xInfo->hasPropertyByName("FillColor2")) + { + sal_Int32 const nFill2Index(pImpPrMap->GetEntryIndex( + XML_NAMESPACE_DRAW, u"secondary-fill-color", 0)); + if (std::none_of(GetProperties().begin(), GetProperties().end(), + XMLPropertyByIndex(nFill2Index))) + { + xDefaults->setPropertyValue("FillColor2", Any(sal_Int32(nFillColor))); + } + } + } + + FillPropertySet( xDefaults ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLImageMapContext.cxx b/xmloff/source/draw/XMLImageMapContext.cxx new file mode 100644 index 0000000000..e3a16c0863 --- /dev/null +++ b/xmloff/source/draw/XMLImageMapContext.cxx @@ -0,0 +1,541 @@ +/* -*- 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 <XMLImageMapContext.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmluconv.hxx> +#include <xexptran.hxx> +#include <xmloff/xmlerror.hxx> +#include <xmloff/XMLEventsImportContext.hxx> +#include <XMLStringBufferImportContext.hxx> +#include <tools/debug.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <sal/log.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::XPropertySetInfo; +using ::com::sun::star::container::XIndexContainer; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::uno::Any; +using ::com::sun::star::document::XEventsSupplier; + +namespace { + +class XMLImageMapObjectContext : public SvXMLImportContext +{ + +protected: + + Reference<XIndexContainer> xImageMap; /// the image map + Reference<XPropertySet> xMapEntry; /// one map-entry (one area) + + OUString sUrl; + OUString sTargt; + OUStringBuffer sDescriptionBuffer; + OUStringBuffer sTitleBuffer; + OUString sNam; + bool bIsActive; + + bool bValid; + +public: + + XMLImageMapObjectContext( + SvXMLImport& rImport, + css::uno::Reference<css::container::XIndexContainer> const & xMap, + const char* pServiceName); + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + +protected: + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter &); + + virtual void Prepare( + css::uno::Reference<css::beans::XPropertySet> & rPropertySet); +}; + +} + +XMLImageMapObjectContext::XMLImageMapObjectContext( + SvXMLImport& rImport, + Reference<XIndexContainer> const & xMap, + const char* pServiceName) : + SvXMLImportContext(rImport), + xImageMap(xMap), + bIsActive(true), + bValid(false) +{ + DBG_ASSERT(nullptr != pServiceName, + "Please supply the image map object service name"); + + Reference<XMultiServiceFactory> xFactory(GetImport().GetModel(),UNO_QUERY); + if( !xFactory.is() ) + return; + + Reference<XInterface> xIfc = xFactory->createInstance( + OUString::createFromAscii(pServiceName)); + DBG_ASSERT(xIfc.is(), "can't create image map object!"); + if( xIfc.is() ) + { + Reference<XPropertySet> xPropertySet( xIfc, UNO_QUERY ); + + xMapEntry = xPropertySet; + } + // else: can't create service -> ignore + // else: can't even get factory -> ignore +} + +void XMLImageMapObjectContext::startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + ProcessAttribute(aIter); +} + +void XMLImageMapObjectContext::endFastElement(sal_Int32 ) +{ + // only create and insert image map object if validity flag is set + // (and we actually have an image map) + if ( bValid && xImageMap.is() && xMapEntry.is() ) + { + // set values + Prepare( xMapEntry ); + + // insert into image map + xImageMap->insertByIndex( xImageMap->getCount(), Any(xMapEntry) ); + } + // else: not valid -> don't create and insert +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImageMapObjectContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + switch (nElement) + { + case XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS): + { + Reference<XEventsSupplier> xEvents( xMapEntry, UNO_QUERY ); + return new XMLEventsImportContext( + GetImport(), xEvents); + } + case XML_ELEMENT(SVG, XML_TITLE): + case XML_ELEMENT(SVG_COMPAT, XML_TITLE): + return new XMLStringBufferImportContext( + GetImport(), sTitleBuffer); + case XML_ELEMENT(SVG, XML_DESC): + case XML_ELEMENT(SVG_COMPAT, XML_DESC): + return new XMLStringBufferImportContext( + GetImport(), sDescriptionBuffer); + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void XMLImageMapObjectContext::ProcessAttribute( + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(XLINK, XML_HREF): + sUrl = GetImport().GetAbsoluteReference(aIter.toString()); + break; + + case XML_ELEMENT(OFFICE, XML_TARGET_FRAME_NAME): + sTargt = aIter.toString(); + break; + + case XML_ELEMENT(DRAW, XML_NOHREF): + bIsActive = ! IsXMLToken(aIter, XML_NOHREF); + break; + + case XML_ELEMENT(OFFICE, XML_NAME): + sNam = aIter.toString(); + break; + default: + // do nothing + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } +} + +void XMLImageMapObjectContext::Prepare( + Reference<XPropertySet> & rPropertySet) +{ + rPropertySet->setPropertyValue( "URL", Any( sUrl ) ); + rPropertySet->setPropertyValue( "Title", Any( sTitleBuffer.makeStringAndClear() ) ); + rPropertySet->setPropertyValue( "Description", Any( sDescriptionBuffer.makeStringAndClear() ) ); + rPropertySet->setPropertyValue( "Target", Any( sTargt ) ); + rPropertySet->setPropertyValue( "IsActive", Any( bIsActive ) ); + rPropertySet->setPropertyValue( "Name", Any( sNam ) ); +} + +namespace { + +class XMLImageMapRectangleContext : public XMLImageMapObjectContext +{ + awt::Rectangle aRectangle; + + bool bXOK; + bool bYOK; + bool bWidthOK; + bool bHeightOK; + +public: + + XMLImageMapRectangleContext( + SvXMLImport& rImport, + css::uno::Reference<css::container::XIndexContainer> const & xMap); + +protected: + virtual void ProcessAttribute( + const sax_fastparser::FastAttributeList::FastAttributeIter &) override; + + virtual void Prepare( + css::uno::Reference<css::beans::XPropertySet> & rPropertySet) override; +}; + +} + +XMLImageMapRectangleContext::XMLImageMapRectangleContext( + SvXMLImport& rImport, + Reference<XIndexContainer> const & xMap) : + XMLImageMapObjectContext(rImport, xMap, + "com.sun.star.image.ImageMapRectangleObject"), + bXOK(false), + bYOK(false), + bWidthOK(false), + bHeightOK(false) +{ +} + +void XMLImageMapRectangleContext::ProcessAttribute( + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + sal_Int32 nTmp; + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp, + aIter.toView())) + { + aRectangle.X = nTmp; + bXOK = true; + } + break; + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp, + aIter.toView())) + { + aRectangle.Y = nTmp; + bYOK = true; + } + break; + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp, + aIter.toView())) + { + aRectangle.Width = nTmp; + bWidthOK = true; + } + break; + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp, + aIter.toView())) + { + aRectangle.Height = nTmp; + bHeightOK = true; + } + break; + default: + XMLImageMapObjectContext::ProcessAttribute(aIter); + } + + bValid = bHeightOK && bXOK && bYOK && bWidthOK; +} + +void XMLImageMapRectangleContext::Prepare( + Reference<XPropertySet> & rPropertySet) +{ + rPropertySet->setPropertyValue( "Boundary", uno::Any(aRectangle) ); + + // common properties handled by super class + XMLImageMapObjectContext::Prepare(rPropertySet); +} + +namespace { + +class XMLImageMapPolygonContext : public XMLImageMapObjectContext +{ + OUString sViewBoxString; + OUString sPointsString; + + bool bViewBoxOK; + bool bPointsOK; + +public: + + XMLImageMapPolygonContext( + SvXMLImport& rImport, + css::uno::Reference<css::container::XIndexContainer> const & xMap); + +protected: + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter &) override; + + virtual void Prepare( + css::uno::Reference<css::beans::XPropertySet> & rPropertySet) override; +}; + +} + +XMLImageMapPolygonContext::XMLImageMapPolygonContext( + SvXMLImport& rImport, + Reference<XIndexContainer> const & xMap) : + XMLImageMapObjectContext(rImport, xMap, + "com.sun.star.image.ImageMapPolygonObject"), + bViewBoxOK(false), + bPointsOK(false) +{ +} + +void XMLImageMapPolygonContext::ProcessAttribute( + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_POINTS): + sPointsString = aIter.toString(); + bPointsOK = true; + break; + case XML_ELEMENT(SVG, XML_VIEWBOX): + case XML_ELEMENT(SVG_COMPAT, XML_VIEWBOX): + sViewBoxString = aIter.toString(); + bViewBoxOK = true; + break; + default: + XMLImageMapObjectContext::ProcessAttribute(aIter); + break; + } + + bValid = bViewBoxOK && bPointsOK; +} + +void XMLImageMapPolygonContext::Prepare(Reference<XPropertySet> & rPropertySet) +{ + // process view box + SdXMLImExViewBox aViewBox(sViewBoxString, GetImport().GetMM100UnitConverter()); + + // get polygon sequence + basegfx::B2DPolygon aPolygon; + + if(basegfx::utils::importFromSvgPoints(aPolygon, sPointsString)) + { + if(aPolygon.count()) + { + css::drawing::PointSequence aPointSequence; + basegfx::utils::B2DPolygonToUnoPointSequence(aPolygon, aPointSequence); + rPropertySet->setPropertyValue("Polygon", Any(aPointSequence)); + } + } + + // parent properties + XMLImageMapObjectContext::Prepare(rPropertySet); +} + +namespace { + +class XMLImageMapCircleContext : public XMLImageMapObjectContext +{ + awt::Point aCenter; + sal_Int32 nRadius; + + bool bXOK; + bool bYOK; + bool bRadiusOK; + +public: + + XMLImageMapCircleContext( + SvXMLImport& rImport, + css::uno::Reference<css::container::XIndexContainer> const & xMap); + +protected: + virtual void ProcessAttribute( + const sax_fastparser::FastAttributeList::FastAttributeIter &) override; + + virtual void Prepare( + css::uno::Reference<css::beans::XPropertySet> & rPropertySet) override; +}; + +} + +XMLImageMapCircleContext::XMLImageMapCircleContext( + SvXMLImport& rImport, + Reference<XIndexContainer> const & xMap) + : XMLImageMapObjectContext(rImport, xMap, + "com.sun.star.image.ImageMapCircleObject") + , nRadius(0) + , bXOK(false) + , bYOK(false) + , bRadiusOK(false) +{ +} + +void XMLImageMapCircleContext::ProcessAttribute( + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + sal_Int32 nTmp; + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_CX): + case XML_ELEMENT(SVG_COMPAT, XML_CX): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp, + aIter.toView())) + { + aCenter.X = nTmp; + bXOK = true; + } + break; + case XML_ELEMENT(SVG, XML_CY): + case XML_ELEMENT(SVG_COMPAT, XML_CY): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp, + aIter.toView())) + { + aCenter.Y = nTmp; + bYOK = true; + } + break; + case XML_ELEMENT(SVG, XML_R): + case XML_ELEMENT(SVG_COMPAT, XML_R): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp, + aIter.toView())) + { + nRadius = nTmp; + bRadiusOK = true; + } + break; + default: + XMLImageMapObjectContext::ProcessAttribute(aIter); + } + + bValid = bRadiusOK && bXOK && bYOK; +} + +void XMLImageMapCircleContext::Prepare( + Reference<XPropertySet> & rPropertySet) +{ + // center (x,y) + rPropertySet->setPropertyValue( "Center", uno::Any(aCenter) ); + // radius + rPropertySet->setPropertyValue( "Radius", uno::Any(nRadius) ); + + // common properties handled by super class + XMLImageMapObjectContext::Prepare(rPropertySet); +} + + +constexpr OUString gsImageMap(u"ImageMap"_ustr); + +XMLImageMapContext::XMLImageMapContext( + SvXMLImport& rImport, + Reference<XPropertySet> const & rPropertySet) : + SvXMLImportContext(rImport), + xPropertySet(rPropertySet) +{ + try + { + Reference < XPropertySetInfo > xInfo = + xPropertySet->getPropertySetInfo(); + if( xInfo.is() && xInfo->hasPropertyByName( gsImageMap ) ) + xPropertySet->getPropertyValue(gsImageMap) >>= xImageMap; + } + catch(const css::uno::Exception& e) + { + rImport.SetError( XMLERROR_FLAG_WARNING | XMLERROR_API, {}, e.Message, nullptr ); + } +} + +XMLImageMapContext::~XMLImageMapContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImageMapContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + switch (nElement) + { + case XML_ELEMENT(DRAW, XML_AREA_RECTANGLE): + return new XMLImageMapRectangleContext( + GetImport(), xImageMap); + case XML_ELEMENT(DRAW, XML_AREA_POLYGON): + return new XMLImageMapPolygonContext( + GetImport(), xImageMap); + case XML_ELEMENT(DRAW, XML_AREA_CIRCLE): + return new XMLImageMapCircleContext( + GetImport(), xImageMap); + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return nullptr; +} + +void XMLImageMapContext::endFastElement(sal_Int32 ) +{ + Reference < XPropertySetInfo > xInfo = + xPropertySet->getPropertySetInfo(); + if( xInfo.is() && xInfo->hasPropertyByName( gsImageMap ) ) + xPropertySet->setPropertyValue(gsImageMap, uno::Any( xImageMap ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLImageMapExport.cxx b/xmloff/source/draw/XMLImageMapExport.cxx new file mode 100644 index 0000000000..833df40af2 --- /dev/null +++ b/xmloff/source/draw/XMLImageMapExport.cxx @@ -0,0 +1,339 @@ +/* -*- 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 <XMLImageMapExport.hxx> +#include <o3tl/any.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/awt/Point.hpp> +#include <com/sun/star/drawing/PointSequence.hpp> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/XMLEventExport.hxx> +#include <xmloff/xmluconv.hxx> +#include <xexptran.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::container::XIndexContainer; +using ::com::sun::star::document::XEventsSupplier; +using ::com::sun::star::lang::XServiceInfo; +using ::com::sun::star::drawing::PointSequence; + +constexpr OUStringLiteral gsBoundary(u"Boundary"); +constexpr OUStringLiteral gsCenter(u"Center"); +constexpr OUStringLiteral gsDescription(u"Description"); +constexpr OUString gsImageMap(u"ImageMap"_ustr); +constexpr OUStringLiteral gsIsActive(u"IsActive"); +constexpr OUStringLiteral gsName(u"Name"); +constexpr OUStringLiteral gsPolygon(u"Polygon"); +constexpr OUStringLiteral gsRadius(u"Radius"); +constexpr OUStringLiteral gsTarget(u"Target"); +constexpr OUStringLiteral gsURL(u"URL"); +constexpr OUStringLiteral gsTitle(u"Title"); + +XMLImageMapExport::XMLImageMapExport(SvXMLExport& rExp) : + mrExport(rExp) +{ +} + +void XMLImageMapExport::Export( + const Reference<XPropertySet> & rPropertySet) +{ + if (rPropertySet->getPropertySetInfo()->hasPropertyByName(gsImageMap)) + { + Any aAny = rPropertySet->getPropertyValue(gsImageMap); + Reference<XIndexContainer> aContainer; + aAny >>= aContainer; + + Export(aContainer); + } + // else: no ImageMap property -> nothing to do +} + +void XMLImageMapExport::Export( + const Reference<XIndexContainer> & rContainer) +{ + if (!rContainer.is()) + return; + + if (!rContainer->hasElements()) + return; + + // image map container element + SvXMLElementExport aImageMapElement( + mrExport, XML_NAMESPACE_DRAW, XML_IMAGE_MAP, + true/*bWhiteSpace*/, true/*bWhiteSpace*/); + + // iterate over image map elements and call ExportMapEntry(...) + // for each + sal_Int32 nLength = rContainer->getCount(); + for(sal_Int32 i = 0; i < nLength; i++) + { + Any aAny = rContainer->getByIndex(i); + Reference<XPropertySet> rElement; + aAny >>= rElement; + + DBG_ASSERT(rElement.is(), "Image map element is empty!"); + if (rElement.is()) + { + ExportMapEntry(rElement); + } + } + // else: container is empty -> nothing to do + // else: no container -> nothing to do +} + + +void XMLImageMapExport::ExportMapEntry( + const Reference<XPropertySet> & rPropertySet) +{ + Reference<XServiceInfo> xServiceInfo(rPropertySet, UNO_QUERY); + if (!xServiceInfo.is()) + return; + + enum XMLTokenEnum eType = XML_TOKEN_INVALID; + + // distinguish map entries by their service name + const Sequence<OUString> sServiceNames = + xServiceInfo->getSupportedServiceNames(); + for( const OUString& rName : sServiceNames ) + { + if ( rName == "com.sun.star.image.ImageMapRectangleObject" ) + { + eType = XML_AREA_RECTANGLE; + break; + } + else if ( rName == "com.sun.star.image.ImageMapCircleObject" ) + { + eType = XML_AREA_CIRCLE; + break; + } + else if ( rName == "com.sun.star.image.ImageMapPolygonObject" ) + { + eType = XML_AREA_POLYGON; + break; + } + } + + // return from method if no proper service is found! + DBG_ASSERT(XML_TOKEN_INVALID != eType, + "Image map element doesn't support appropriate service!"); + if (XML_TOKEN_INVALID == eType) + return; + + // now: handle ImageMapObject properties (those for all types) + + // XLINK (URL property) + Any aAny = rPropertySet->getPropertyValue(gsURL); + OUString sHref; + aAny >>= sHref; + if (!sHref.isEmpty()) + { + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, mrExport.GetRelativeReference(sHref)); + } + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + + // Target property (and xlink:show) + aAny = rPropertySet->getPropertyValue(gsTarget); + OUString sTargt; + aAny >>= sTargt; + if (!sTargt.isEmpty()) + { + mrExport.AddAttribute( + XML_NAMESPACE_OFFICE, XML_TARGET_FRAME_NAME, sTargt); + + mrExport.AddAttribute( + XML_NAMESPACE_XLINK, XML_SHOW, + sTargt == "_blank" ? XML_NEW : XML_REPLACE ); + } + + // name + aAny = rPropertySet->getPropertyValue(gsName); + OUString sItemName; + aAny >>= sItemName; + if (!sItemName.isEmpty()) + { + mrExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, sItemName); + } + + // is-active + aAny = rPropertySet->getPropertyValue(gsIsActive); + if (! *o3tl::doAccess<bool>(aAny)) + { + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_NOHREF, XML_NOHREF); + } + + // call specific rectangle/circle/... method + // also prepare element name + switch (eType) + { + case XML_AREA_RECTANGLE: + ExportRectangle(rPropertySet); + break; + case XML_AREA_CIRCLE: + ExportCircle(rPropertySet); + break; + case XML_AREA_POLYGON: + ExportPolygon(rPropertySet); + break; + default: + break; + } + + // write element + DBG_ASSERT(XML_TOKEN_INVALID != eType, + "No name?! How did this happen?"); + SvXMLElementExport aAreaElement(mrExport, XML_NAMESPACE_DRAW, eType, + true/*bWhiteSpace*/, true/*bWhiteSpace*/); + + // title property (as <svg:title> element) + OUString sTitle; + rPropertySet->getPropertyValue(gsTitle) >>= sTitle; + if(!sTitle.isEmpty()) + { + SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_TITLE, true/*bWhiteSpace*/, false); + mrExport.Characters(sTitle); + } + + // description property (as <svg:desc> element) + OUString sDescription; + rPropertySet->getPropertyValue(gsDescription) >>= sDescription; + if (!sDescription.isEmpty()) + { + SvXMLElementExport aDesc(mrExport, XML_NAMESPACE_SVG, XML_DESC, true/*bWhiteSpace*/, false); + mrExport.Characters(sDescription); + } + + // export events attached to this + Reference<XEventsSupplier> xSupplier(rPropertySet, UNO_QUERY); + mrExport.GetEventExport().Export(xSupplier); + + // else: no service info -> can't determine type -> ignore entry +} + +void XMLImageMapExport::ExportRectangle( + const Reference<XPropertySet> & rPropertySet) +{ + // get boundary rectangle + Any aAny = rPropertySet->getPropertyValue(gsBoundary); + awt::Rectangle aRectangle; + aAny >>= aRectangle; + + // parameters svg:x, svg:y, svg:width, svg:height + OUStringBuffer aBuffer; + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, aRectangle.X); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_X, + aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, aRectangle.Y); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_Y, + aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, + aRectangle.Width); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH, + aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, + aRectangle.Height); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT, + aBuffer.makeStringAndClear() ); +} + +void XMLImageMapExport::ExportCircle( + const Reference<XPropertySet> & rPropertySet) +{ + // get boundary rectangle + Any aAny = rPropertySet->getPropertyValue(gsCenter); + awt::Point aCenter; + aAny >>= aCenter; + + // parameters svg:cx, svg:cy + OUStringBuffer aBuffer; + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, aCenter.X); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_CX, + aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, aCenter.Y); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_CY, + aBuffer.makeStringAndClear() ); + + // radius + aAny = rPropertySet->getPropertyValue(gsRadius); + sal_Int32 nRadius = 0; + aAny >>= nRadius; + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, nRadius); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_R, + aBuffer.makeStringAndClear() ); +} + +void XMLImageMapExport::ExportPolygon(const Reference<XPropertySet> & rPropertySet) +{ + // polygons get exported as bounding box, viewbox, and coordinate + // pair sequence. The bounding box is always the entire image. + + // get polygon point sequence + Any aAny = rPropertySet->getPropertyValue(gsPolygon); + PointSequence aPoly; + aAny >>= aPoly; + + const basegfx::B2DPolygon aPolygon( + basegfx::utils::UnoPointSequenceToB2DPolygon( + aPoly)); + const basegfx::B2DRange aPolygonRange(aPolygon.getB2DRange()); + + // parameters svg:x, svg:y, svg:width, svg:height + OUStringBuffer aBuffer; + + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, 0); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_X, aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, 0); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_Y, aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, basegfx::fround(aPolygonRange.getWidth())); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH, aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, basegfx::fround(aPolygonRange.getHeight())); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT, aBuffer.makeStringAndClear() ); + + // svg:viewbox + SdXMLImExViewBox aViewBox(0.0, 0.0, aPolygonRange.getWidth(), aPolygonRange.getHeight()); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString()); + + // export point sequence + const OUString aPointString( + basegfx::utils::exportToSvgPoints( + aPolygon)); + + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLNumberStyles.cxx b/xmloff/source/draw/XMLNumberStyles.cxx new file mode 100644 index 0000000000..e97414b914 --- /dev/null +++ b/xmloff/source/draw/XMLNumberStyles.cxx @@ -0,0 +1,712 @@ +/* -*- 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 "XMLNumberStylesExport.hxx" +#include <XMLNumberStylesImport.hxx> +#include <utility> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmltoken.hxx> + +#include <o3tl/string_view.hxx> +#include <sal/log.hxx> + +#include "sdxmlexp_impl.hxx" +#include "sdxmlimp_impl.hxx" + +using namespace ::xmloff::token; + +namespace { + +struct SdXMLDataStyleNumber +{ + enum XMLTokenEnum meNumberStyle; + bool mbLong; + bool mbTextual; + bool mbDecimal02; + const char* mpText; +}; + +} + +SdXMLDataStyleNumber const aSdXMLDataStyleNumbers[] = +{ + { XML_DAY, false, false, false, nullptr }, + { XML_DAY, true, false, false, nullptr }, + { XML_MONTH, true, false, false, nullptr }, + { XML_MONTH, false, true, false, nullptr }, + { XML_MONTH, true, true, false, nullptr }, + { XML_YEAR, false, false, false, nullptr }, + { XML_YEAR, true, false, false, nullptr }, + { XML_DAY_OF_WEEK, false, false, false, nullptr }, + { XML_DAY_OF_WEEK, true, false, false, nullptr }, + { XML_TEXT, false, false, false, "." }, + { XML_TEXT, false, false, false, " " }, + { XML_TEXT, false, false, false, ", " }, + { XML_TEXT, false, false, false, ". " }, + { XML_HOURS, false, false, false, nullptr }, + { XML_MINUTES, false, false, false, nullptr }, + { XML_TEXT, false, false, false, ":" }, + { XML_AM_PM, false, false, false, nullptr }, + { XML_SECONDS, false, false, false, nullptr }, + { XML_SECONDS, false, false, true, nullptr }, + { XML_TOKEN_INVALID, false, false, false, nullptr } +}; + +// date +enum class DataStyleNumber : sal_uInt8 +{ + NONE = 0, + Day = 1, // <number:day/> + DayLong = 2, // <number:day number:style="long"/> + MonthLong = 3, // <number:month number:style="long"/> + MonthText = 4, // <number:month number:textual="true"/> + MonthLongText = 5, // <number:month number:style="long" number:textual="true"/> + Year = 6, // <number:year/> + YearLong = 7, // <number:year number:style="long"/> + DayOfWeek = 8, // <number:day-of-week/> + DayOfWeekLong = 9, // <number:day-of-week number:style="long"/> + TextPoint = 10, // <number:text>.</number:text> + TextSpace = 11, // <number:text> </number:text> + TextCommaSpace = 12, // <number:text>, </number:text> + TextPointSpace = 13, // <number:text>. </number:text> + Hours = 14, // <number:hours/> + Minutes = 15, // <number:minutes/> + TextColon = 16, // <number:text>:</number:text> + AmPm = 17, // <number:am-pm/> + Seconds = 18, // <number:seconds/> + Seconds_02 = 19, // <number:seconds number:/> +}; + +struct SdXMLFixedDataStyle +{ + const char* mpName; + bool mbAutomatic; + bool mbDateStyle; + DataStyleNumber mpFormat[8]; +}; + +const SdXMLFixedDataStyle aSdXML_Standard_Short = +{ + "D1", true, true, + { + DataStyleNumber::DayLong, + DataStyleNumber::TextPoint, + DataStyleNumber::MonthLong, + DataStyleNumber::TextPoint, + DataStyleNumber::YearLong, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_Standard_Long = +{ + "D2", true, true, + { + DataStyleNumber::DayOfWeekLong, + DataStyleNumber::TextCommaSpace, + DataStyleNumber::Day, + DataStyleNumber::TextPointSpace, + DataStyleNumber::MonthLongText, + DataStyleNumber::TextSpace, + DataStyleNumber::YearLong, + DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_DateStyle_1 = +{ + "D3", false, true, + { + DataStyleNumber::DayLong, + DataStyleNumber::TextPoint, + DataStyleNumber::MonthLong, + DataStyleNumber::TextPoint, + DataStyleNumber::Year, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_DateStyle_2 = +{ + "D4", false, true, + { + DataStyleNumber::DayLong, + DataStyleNumber::TextPoint, + DataStyleNumber::MonthLong, + DataStyleNumber::TextPoint, + DataStyleNumber::YearLong, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_DateStyle_3 = +{ + "D5", false, true, + { + DataStyleNumber::Day, + DataStyleNumber::TextPointSpace, + DataStyleNumber::MonthText, + DataStyleNumber::TextSpace, + DataStyleNumber::YearLong, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_DateStyle_4 = +{ + "D6", false, true, + { + DataStyleNumber::Day, + DataStyleNumber::TextPointSpace, + DataStyleNumber::MonthLongText, + DataStyleNumber::TextSpace, + DataStyleNumber::YearLong, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_DateStyle_5 = +{ + "D7", false, true, + { + DataStyleNumber::DayOfWeek, + DataStyleNumber::TextCommaSpace, + DataStyleNumber::Day, + DataStyleNumber::TextPointSpace, + DataStyleNumber::MonthLongText, + DataStyleNumber::TextSpace, + DataStyleNumber::YearLong, + DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_DateStyle_6 = +{ + "D8", false, true, + { + DataStyleNumber::DayOfWeekLong, + DataStyleNumber::TextCommaSpace, + DataStyleNumber::Day, + DataStyleNumber::TextPointSpace, + DataStyleNumber::MonthLongText, + DataStyleNumber::TextSpace, + DataStyleNumber::YearLong, + DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_TimeStyle_1 = +{ "T1", true, false, + { + DataStyleNumber::Hours, + DataStyleNumber::TextColon, + DataStyleNumber::Minutes, + DataStyleNumber::TextColon, + DataStyleNumber::Seconds, + DataStyleNumber::AmPm, + DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_TimeStyle_2 = +{ "T2", false, false, + { + DataStyleNumber::Hours, + DataStyleNumber::TextColon, + DataStyleNumber::Minutes, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_TimeStyle_3 = +{ "T3", false, false, + { + DataStyleNumber::Hours, + DataStyleNumber::TextColon, + DataStyleNumber::Minutes, + DataStyleNumber::TextColon, + DataStyleNumber::Seconds, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_TimeStyle_4 = +{ "T4", false, false, + { + DataStyleNumber::Hours, + DataStyleNumber::TextColon, + DataStyleNumber::Minutes, + DataStyleNumber::TextColon, + DataStyleNumber::Seconds_02, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_TimeStyle_5 = +{ "T5", false, false, + { + DataStyleNumber::Hours, + DataStyleNumber::TextColon, + DataStyleNumber::Minutes, + DataStyleNumber::AmPm, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_TimeStyle_6 = +{ "T6", false, false, + { + DataStyleNumber::Hours, + DataStyleNumber::TextColon, + DataStyleNumber::Minutes, + DataStyleNumber::TextColon, + DataStyleNumber::Seconds, + DataStyleNumber::AmPm, + DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_TimeStyle_7 = +{ "T7", false, false, + { + DataStyleNumber::Hours, + DataStyleNumber::TextColon, + DataStyleNumber::Minutes, + DataStyleNumber::TextColon, + DataStyleNumber::Seconds_02, + DataStyleNumber::AmPm, + DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle* const aSdXMLFixedDateFormats[SdXMLDateFormatCount] = +{ + &aSdXML_Standard_Short, + &aSdXML_Standard_Long, + &aSdXML_DateStyle_1, + &aSdXML_DateStyle_2, + &aSdXML_DateStyle_3, + &aSdXML_DateStyle_4, + &aSdXML_DateStyle_5, + &aSdXML_DateStyle_6, +}; + +const SdXMLFixedDataStyle* const aSdXMLFixedTimeFormats[SdXMLTimeFormatCount] = +{ + &aSdXML_TimeStyle_1, + &aSdXML_TimeStyle_2, + &aSdXML_TimeStyle_3, + &aSdXML_TimeStyle_4, + &aSdXML_TimeStyle_5, + &aSdXML_TimeStyle_6, + &aSdXML_TimeStyle_7 +}; + +// export + +static void SdXMLExportDataStyleNumber( SdXMLExport& rExport, SdXMLDataStyleNumber const & rElement ) +{ + if( rElement.mbDecimal02 ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, XML_2 ); + } + + if( rElement.mbLong ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_STYLE, XML_LONG ); + } + + if( rElement.mbTextual ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TEXTUAL, XML_TRUE ); + } + + SvXMLElementExport aNumberStyle( rExport, XML_NAMESPACE_NUMBER, rElement.meNumberStyle, true, false ); + if( rElement.mpText ) + { + OUString sAttrValue( OUString::createFromAscii( rElement.mpText ) ); + rExport.GetDocHandler()->characters( sAttrValue ); + } +} + +static void SdXMLExportStyle( SdXMLExport& rExport, const SdXMLFixedDataStyle* pStyle, const SdXMLFixedDataStyle* pStyle2 = nullptr ) +{ + // name + OUString sAttrValue = OUString::createFromAscii( pStyle->mpName ); + if( pStyle2 ) + sAttrValue += OUString::createFromAscii( pStyle2->mpName ); + + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, sAttrValue ); + + if( pStyle->mbAutomatic ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER, XML_TRUE ); + } + + SvXMLElementExport aElement( rExport, XML_NAMESPACE_NUMBER, pStyle->mbDateStyle ? XML_DATE_STYLE : XML_TIME_STYLE, true, true ); + + do + { + + const DataStyleNumber* pElements = &pStyle->mpFormat[0]; + + while( *pElements != DataStyleNumber::NONE ) + { + SdXMLDataStyleNumber const & rElement = aSdXMLDataStyleNumbers[ static_cast<int>(*pElements++) - 1 ]; + SdXMLExportDataStyleNumber( rExport, rElement ); + } + + if( pStyle2 ) + { + SdXMLDataStyleNumber const & rElement = aSdXMLDataStyleNumbers[ static_cast<int>(DataStyleNumber::TextSpace) - 1 ]; + SdXMLExportDataStyleNumber( rExport, rElement ); + } + + pStyle = pStyle2; + pStyle2 = nullptr; + } + while( pStyle ); +} + +void SdXMLNumberStylesExporter::exportTimeStyle( SdXMLExport& rExport, sal_Int32 nStyle ) +{ + SAL_WARN_IF( (nStyle < 0) || (nStyle >= SdXMLTimeFormatCount), "xmloff", "Unknown time style!" ); + if( (nStyle >= 0) && (nStyle < SdXMLTimeFormatCount) ) + SdXMLExportStyle( rExport, aSdXMLFixedTimeFormats[ nStyle ] ); +} + +void SdXMLNumberStylesExporter::exportDateStyle( SdXMLExport& rExport, sal_Int32 nStyle ) +{ + if( nStyle > 0x0f ) + { + int nDateStyle = nStyle & 0x0f; + bool bHasDate = nDateStyle != 0; + + if( nDateStyle > 1 ) + nDateStyle -= 2; + + SAL_WARN_IF(nDateStyle >= SdXMLDateFormatCount, "xmloff", "unknown date style!"); + + int nTimeStyle = (nStyle >> 4) & 0x0f; + bool bHasTime = nTimeStyle != 0; + + if( nTimeStyle > 1 ) + nTimeStyle -= 2; + + SAL_WARN_IF(nTimeStyle >= SdXMLTimeFormatCount, "xmloff", "Unknown time style!"); + + if ((nDateStyle < SdXMLDateFormatCount) && (nTimeStyle < SdXMLTimeFormatCount)) + { + if( bHasDate ) + { + if( bHasTime ) + { + SdXMLExportStyle( rExport, aSdXMLFixedDateFormats[ nDateStyle ], aSdXMLFixedTimeFormats[ nTimeStyle ] ); + } + else + { + SdXMLExportStyle( rExport, aSdXMLFixedDateFormats[ nDateStyle ] ); + } + } + else if( bHasTime ) + { + SdXMLExportStyle( rExport, aSdXMLFixedTimeFormats[ nTimeStyle ] ); + } + } + } + else + { + SAL_WARN_IF( (nStyle < 0) || (nStyle >= SdXMLDateFormatCount), "xmloff", "unknown date style!" ); + if( (nStyle >= 0) && (nStyle < SdXMLDateFormatCount) ) + SdXMLExportStyle( rExport, aSdXMLFixedDateFormats[ nStyle ] ); + } +} + +OUString SdXMLNumberStylesExporter::getTimeStyleName(const sal_Int32 nTimeFormat ) +{ + sal_Int32 nFormat = nTimeFormat; + if( nFormat > 1 ) + nFormat -= 2; + + if( (nFormat >= 0) && (nFormat < SdXMLTimeFormatCount) ) + { + return OUString::createFromAscii(aSdXMLFixedTimeFormats[nFormat]->mpName ); + } + else + { + return OUString(); + } +} + +OUString SdXMLNumberStylesExporter::getDateStyleName(const sal_Int32 nDateFormat ) +{ + sal_Int32 nFormat = nDateFormat; + + if( nFormat > 0x0f ) + { + OUString aStr; + if( nFormat & 0x0f ) + aStr = getDateStyleName( nFormat & 0x0f ); + aStr += getTimeStyleName( (nFormat >> 4) & 0x0f ); + return aStr; + } + + if( nFormat > 1 ) + nFormat -= 2; + + if( (nFormat >= 0) && (nFormat < SdXMLDateFormatCount) ) + { + return OUString::createFromAscii(aSdXMLFixedDateFormats[nFormat]->mpName ); + } + else + { + return OUString(); + } +} + +// import + +class SdXMLNumberFormatMemberImportContext : public SvXMLImportContext +{ +private: + SdXMLNumberFormatImportContext* mpParent; + + OUString maNumberStyle; + bool mbLong; + bool mbTextual; + bool mbDecimal02; + OUString maText; + SvXMLImportContextRef mxSlaveContext; + +public: + + SdXMLNumberFormatMemberImportContext( SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + SdXMLNumberFormatImportContext* pParent, + SvXMLImportContextRef xSlaveContext ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + + +SdXMLNumberFormatMemberImportContext::SdXMLNumberFormatMemberImportContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + SdXMLNumberFormatImportContext* pParent, + SvXMLImportContextRef xSlaveContext ) +: SvXMLImportContext(rImport), + mpParent( pParent ), + maNumberStyle( SvXMLImport::getNameFromToken(nElement) ), + mxSlaveContext(std::move( xSlaveContext )) +{ + mbLong = false; + mbTextual = false; + mbDecimal02 = false; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(NUMBER, XML_DECIMAL_PLACES): + mbDecimal02 = IsXMLToken( aIter, XML_2 ); + break; + case XML_ELEMENT(NUMBER, XML_STYLE): + mbLong = IsXMLToken( aIter, XML_LONG ); + break; + case XML_ELEMENT(NUMBER, XML_TEXTUAL): + mbTextual = IsXMLToken( aIter, XML_TRUE ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLNumberFormatMemberImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return mxSlaveContext->createFastChildContext( nElement, xAttrList ); +} + +void SdXMLNumberFormatMemberImportContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + mxSlaveContext->startFastElement( nElement, xAttrList ); +} + +void SdXMLNumberFormatMemberImportContext::endFastElement(sal_Int32 nElement) +{ + mxSlaveContext->endFastElement(nElement); + + if( mpParent ) + mpParent->add( maNumberStyle, mbLong, mbTextual, mbDecimal02, maText ); +} + +void SdXMLNumberFormatMemberImportContext::characters( const OUString& rChars ) +{ + mxSlaveContext->characters( rChars ); + maText += rChars; +} + + +SdXMLNumberFormatImportContext::SdXMLNumberFormatImportContext( SdXMLImport& rImport, sal_Int32 nElement, SvXMLNumImpData* pNewData, SvXMLStylesTokens nNewType, const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, SvXMLStylesContext& rStyles) +: SvXMLNumFormatContext(rImport, nElement, pNewData, nNewType, xAttrList, rStyles), + mbAutomatic( false ), + mnElements{}, + mnIndex(0), + mnKey( -1 ) +{ + mbTimeStyle = (nElement & TOKEN_MASK) == XML_TIME_STYLE; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( aIter.getToken() == XML_ELEMENT(NUMBER, XML_AUTOMATIC_ORDER) ) + mbAutomatic = IsXMLToken( aIter, XML_TRUE ); + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +SdXMLNumberFormatImportContext::~SdXMLNumberFormatImportContext() +{ +} + +void SdXMLNumberFormatImportContext::add( std::u16string_view rNumberStyle, bool bLong, bool bTextual, bool bDecimal02, std::u16string_view rText ) +{ + if (mnIndex == 16) + return; + + const SdXMLDataStyleNumber* pStyleMember = aSdXMLDataStyleNumbers; + for( sal_uInt8 nIndex = 0; pStyleMember->meNumberStyle != XML_TOKEN_INVALID; nIndex++, pStyleMember++ ) + { + if( IsXMLToken(rNumberStyle, pStyleMember->meNumberStyle) && + (pStyleMember->mbLong == bLong) && + (pStyleMember->mbTextual == bTextual) && + (pStyleMember->mbDecimal02 == bDecimal02) && + ( ( (pStyleMember->mpText == nullptr) && (rText.empty()) ) || + ( pStyleMember->mpText && (o3tl::equalsAscii( rText, pStyleMember->mpText ) ) ) ) ) + { + mnElements[mnIndex++] = static_cast<DataStyleNumber>(nIndex + 1); + return; + } + } +} + +bool SdXMLNumberFormatImportContext::compareStyle( const SdXMLFixedDataStyle* pStyle, sal_Int16& nIndex ) const +{ + if( (pStyle->mbAutomatic != mbAutomatic) && (nIndex == 0)) + return false; + + sal_Int16 nCompareIndex; + for( nCompareIndex = 0; nCompareIndex < 8; nIndex++, nCompareIndex++ ) + { + if( pStyle->mpFormat[nCompareIndex] != mnElements[nIndex] ) + return false; + } + + return true; +} + +void SdXMLNumberFormatImportContext::endFastElement(sal_Int32 ) +{ + for( ; mnIndex < 16; mnIndex++ ) + { + mnElements[mnIndex] = DataStyleNumber::NONE; + } + + if( mbTimeStyle ) + { + // compare import with all time styles + for( sal_Int16 nFormat = 0; nFormat < SdXMLTimeFormatCount; nFormat++ ) + { + sal_Int16 nIndex = 0; + if( compareStyle( aSdXMLFixedTimeFormats[nFormat], nIndex ) ) + { + mnKey = nFormat + 2; + break; + } + } + } + else + { + // compare import with all date styles + for( sal_Int16 nFormat = 0; nFormat < SdXMLDateFormatCount; nFormat++ ) + { + sal_Int16 nIndex = 0; + if( compareStyle( aSdXMLFixedDateFormats[nFormat], nIndex ) ) + { + mnKey = nFormat + 2; + break; + } + else if( mnElements[nIndex] == DataStyleNumber::TextSpace ) + { + // if it's a valid date ending with a space, see if a time style follows + for( sal_Int16 nTimeFormat = 0; nTimeFormat < SdXMLTimeFormatCount; nTimeFormat++ ) + { + sal_Int16 nIndex2 = nIndex + 1; + if( compareStyle( aSdXMLFixedTimeFormats[nTimeFormat], nIndex2 ) ) + { + mnKey = (nFormat + 2) | ((nTimeFormat + 2) << 4); + break; + } + } + } + } + + // no date style found? maybe it's an extended time style + if( mnKey == -1 ) + { + // compare import with all time styles + for( sal_Int16 nFormat = 0; nFormat < SdXMLTimeFormatCount; nFormat++ ) + { + sal_Int16 nIndex = 0; + if( compareStyle( aSdXMLFixedTimeFormats[nFormat], nIndex ) ) + { + mnKey = (nFormat + 2) << 4; + break; + } + } + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLNumberFormatImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return new SdXMLNumberFormatMemberImportContext( GetImport(), nElement, xAttrList, + this, static_cast<SvXMLImportContext*>(SvXMLNumFormatContext::createFastChildContext( nElement, xAttrList ).get()) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLNumberStylesExport.hxx b/xmloff/source/draw/XMLNumberStylesExport.hxx new file mode 100644 index 0000000000..8b4f39dc5a --- /dev/null +++ b/xmloff/source/draw/XMLNumberStylesExport.hxx @@ -0,0 +1,40 @@ +/* -*- 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 . + */ + +#pragma once + +#include <sal/types.h> +#include <rtl/ustring.hxx> + +class SdXMLExport; + +const sal_Int16 SdXMLDateFormatCount = 8; +const sal_Int16 SdXMLTimeFormatCount = 7; + +class SdXMLNumberStylesExporter +{ +public: + static void exportTimeStyle(SdXMLExport& rExport, sal_Int32 nStyle); + static void exportDateStyle(SdXMLExport& rExport, sal_Int32 nStyle); + + static OUString getTimeStyleName(const sal_Int32 nTimeFormat); + static OUString getDateStyleName(const sal_Int32 nDateFormat); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLReplacementImageContext.cxx b/xmloff/source/draw/XMLReplacementImageContext.cxx new file mode 100644 index 0000000000..5321d55788 --- /dev/null +++ b/xmloff/source/draw/XMLReplacementImageContext.cxx @@ -0,0 +1,99 @@ +/* -*- 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 <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <osl/diagnose.h> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/XMLBase64ImportContext.hxx> +#include <XMLReplacementImageContext.hxx> +#include <sal/log.hxx> + +using ::com::sun::star::uno::Reference; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::beans; +using namespace css; +using namespace ::xmloff::token; + +XMLReplacementImageContext::XMLReplacementImageContext( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< XFastAttributeList > & rAttrList, + const Reference< XPropertySet > & rPropSet ) : + SvXMLImportContext( rImport ), + m_xPropSet( rPropSet ) +{ + m_sHRef = rAttrList->getOptionalValue(XML_ELEMENT(XLINK, XML_HREF)); +} + +XMLReplacementImageContext::~XMLReplacementImageContext() +{ +} + +void XMLReplacementImageContext::endFastElement(sal_Int32 ) +{ + OSL_ENSURE( !m_sHRef.isEmpty() || m_xBase64Stream.is(), + "neither URL nor base64 image data given" ); + uno::Reference<graphic::XGraphic> xGraphic; + + try + { + if( !m_sHRef.isEmpty() ) + { + xGraphic = GetImport().loadGraphicByURL(m_sHRef); + } + else if( m_xBase64Stream.is() ) + { + xGraphic = GetImport().loadGraphicFromBase64(m_xBase64Stream); + m_xBase64Stream = nullptr; + } + } + catch (uno::Exception const &) + {} + + Reference < XPropertySetInfo > xPropSetInfo = m_xPropSet->getPropertySetInfo(); + + if (xGraphic.is() && xPropSetInfo->hasPropertyByName("Graphic")) + { + m_xPropSet->setPropertyValue("Graphic", uno::Any(xGraphic)); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLReplacementImageContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if( nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA) && + !m_xBase64Stream.is() ) + { + m_xBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64(); + if( m_xBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), + m_xBase64Stream ); + } + + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLShapePropertySetContext.cxx b/xmloff/source/draw/XMLShapePropertySetContext.cxx new file mode 100644 index 0000000000..79b56b37c0 --- /dev/null +++ b/xmloff/source/draw/XMLShapePropertySetContext.cxx @@ -0,0 +1,94 @@ +/* -*- 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 <XMLShapePropertySetContext.hxx> +#include <XMLTextColumnsContext.hxx> +#include <xmloff/XMLComplexColorContext.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnumi.hxx> +#include <xmltabi.hxx> +#include <xmlsdtypes.hxx> +#include <xmloff/txtprmap.hxx> +#include <xmloff/xmlimppr.hxx> + +#include <com/sun/star/container/XIndexReplace.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +XMLShapePropertySetContext::XMLShapePropertySetContext( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + sal_uInt32 nFam, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap ) : + SvXMLPropertySetContext( rImport, nElement, xAttrList, nFam, + rProps, rMap ), + mnBulletIndex(-1) +{ +} + +XMLShapePropertySetContext::~XMLShapePropertySetContext() +{ +} + +void XMLShapePropertySetContext::endFastElement(sal_Int32 ) +{ + Reference< container::XIndexReplace > xNumRule; + if( mxBulletStyle.is() ) + { + xNumRule = SvxXMLListStyleContext::CreateNumRule( GetImport().GetModel() ); + if( xNumRule.is() ) + mxBulletStyle->FillUnoNumRule(xNumRule); + } + + XMLPropertyState aPropState( mnBulletIndex, Any(xNumRule) ); + mrProperties.push_back( aPropState ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLShapePropertySetContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) +{ + switch( mxMapper->getPropertySetMapper()->GetEntryContextId( rProp.mnIndex ) ) + { + case CTF_NUMBERINGRULES: + mnBulletIndex = rProp.mnIndex; + mxBulletStyle = new SvxXMLListStyleContext( GetImport() ); + return mxBulletStyle; + case CTF_TABSTOP: + return new SvxXMLTabStopImportContext( GetImport(), nElement, + rProp, + rProperties ); + case CTF_TEXTCOLUMNS: + return new XMLTextColumnsContext(GetImport(), nElement, xAttrList, rProp, rProperties); + + case CTF_COMPLEX_COLOR: + return new XMLPropertyComplexColorContext(GetImport(), nElement, xAttrList, rProp, rProperties); + } + + return SvXMLPropertySetContext::createFastChildContext( nElement, + xAttrList, + rProperties, rProp ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLShapeStyleContext.cxx b/xmloff/source/draw/XMLShapeStyleContext.cxx new file mode 100644 index 0000000000..da4341731b --- /dev/null +++ b/xmloff/source/draw/XMLShapeStyleContext.cxx @@ -0,0 +1,323 @@ +/* -*- 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 <tools/debug.hxx> +#include <sal/log.hxx> +#include <xmloff/XMLShapeStyleContext.hxx> +#include <XMLShapePropertySetContext.hxx> +#include <xmloff/contextid.hxx> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/XControlShape.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnumi.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlprmap.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlerror.hxx> +#include <xmloff/maptype.hxx> +#include <xmloff/xmlimppr.hxx> + +#include <xmlsdtypes.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::drawing; +using namespace ::xmloff::token; + + +XMLShapeStyleContext::XMLShapeStyleContext( + SvXMLImport& rImport, + SvXMLStylesContext& rStyles, + XmlStyleFamily nFamily) +: XMLPropStyleContext(rImport, rStyles, nFamily ), + m_bIsNumRuleAlreadyConverted( false ) +{ +} + +XMLShapeStyleContext::~XMLShapeStyleContext() +{ +} + +void XMLShapeStyleContext::SetAttribute( sal_Int32 nElement, const OUString& rValue ) +{ + if (m_sControlDataStyleName.isEmpty() && (nElement & TOKEN_MASK) == XML_DATA_STYLE_NAME) + { + m_sControlDataStyleName = rValue; + } + else if( nElement == XML_ELEMENT(STYLE, XML_LIST_STYLE_NAME) ) + { + m_sListStyleName = rValue; + } + else + { + XMLPropStyleContext::SetAttribute( nElement, rValue ); + + if( nElement == XML_ELEMENT(STYLE, XML_NAME) || nElement == XML_ELEMENT(STYLE, XML_DISPLAY_NAME) ) + { + if( !GetName().isEmpty() && !GetDisplayName().isEmpty() && GetName() != GetDisplayName() ) + { + GetImport(). + AddStyleDisplayName( GetFamily(), GetName(), GetDisplayName() ); + } + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLShapeStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( IsTokenInNamespace(nElement, XML_NAMESPACE_STYLE) || + IsTokenInNamespace(nElement, XML_NAMESPACE_LO_EXT) ) + { + sal_Int32 nLocalName = nElement & TOKEN_MASK; + sal_uInt32 nFamily = 0; + if( nLocalName == XML_TEXT_PROPERTIES ) + nFamily = XML_TYPE_PROP_TEXT; + else if( nLocalName == XML_PARAGRAPH_PROPERTIES ) + nFamily = XML_TYPE_PROP_PARAGRAPH; + else if( nLocalName == XML_GRAPHIC_PROPERTIES ) + nFamily = XML_TYPE_PROP_GRAPHIC; + if( nFamily ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + return new XMLShapePropertySetContext( GetImport(), nElement, xAttrList, + nFamily, + GetProperties(), + xImpPrMap ); + } + } + + return XMLPropStyleContext::createFastChildContext( nElement, xAttrList ); +} + +void XMLShapeStyleContext::FillPropertySet( const Reference< beans::XPropertySet > & rPropSet ) +{ + if( !m_bIsNumRuleAlreadyConverted ) + { + m_bIsNumRuleAlreadyConverted = true; + + // for compatibility to beta files, search for CTF_SD_NUMBERINGRULES_NAME to + // import numbering rules from the style:properties element + const rtl::Reference< XMLPropertySetMapper >&rMapper = GetStyles()->GetImportPropertyMapper( GetFamily() )->getPropertySetMapper(); + + ::std::vector< XMLPropertyState > &rProperties = GetProperties(); + ::std::vector< XMLPropertyState >::iterator end( rProperties.end() ); + + // first, look for the old format, where we had a text:list-style-name + // attribute in the style:properties element + auto property = std::find_if(rProperties.begin(), end, [&rMapper](XMLPropertyState& rProp) { + // find properties with context + return (rProp.mnIndex != -1) && (rMapper->GetEntryContextId( rProp.mnIndex ) == CTF_SD_NUMBERINGRULES_NAME); }); + + // if we did not find an old list-style-name in the properties, and we need one + // because we got a style:list-style attribute in the style-style element + // we generate one + if( (property == end) && ( !m_sListStyleName.isEmpty() ) ) + { + sal_Int32 nIndex = rMapper->FindEntryIndex( CTF_SD_NUMBERINGRULES_NAME ); + SAL_WARN_IF( -1 == nIndex, "xmloff", "can't find numbering rules property entry, can't set numbering rule!" ); + + XMLPropertyState aNewState( nIndex ); + rProperties.push_back( aNewState ); + end = rProperties.end(); + property = end - 1; + } + + // so, if we have an old or a new list style name, we set its value to + // a numbering rule + if( property != end ) + { + if( m_sListStyleName.isEmpty() ) + { + property->maValue >>= m_sListStyleName; + } + + const SvxXMLListStyleContext *pListStyle = GetImport().GetTextImport()->FindAutoListStyle( m_sListStyleName ); + + SAL_WARN_IF( !pListStyle, "xmloff", "list-style not found for shape style" ); + if( pListStyle ) + { + uno::Reference< container::XIndexReplace > xNumRule( SvxXMLListStyleContext::CreateNumRule( GetImport().GetModel() ) ); + pListStyle->FillUnoNumRule(xNumRule); + property->maValue <<= xNumRule; + } + else + { + property->mnIndex = -1; + } + } + } + + struct ContextID_Index_Pair aContextIDs[] = + { + { CTF_DASHNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_LINESTARTNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_LINEENDNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT }, + { CTF_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH }, + { CTF_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP }, + { CTF_SD_OLE_VIS_AREA_IMPORT_LEFT, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_SD_OLE_VIS_AREA_IMPORT_TOP, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_SD_OLE_VIS_AREA_IMPORT_WIDTH, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_SD_OLE_VIS_AREA_IMPORT_HEIGHT, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { -1, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE } + }; + static const XmlStyleFamily aFamilies[] = + { + XmlStyleFamily::SD_STROKE_DASH_ID, + XmlStyleFamily::SD_MARKER_ID, + XmlStyleFamily::SD_MARKER_ID, + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_HATCH_ID, + XmlStyleFamily::SD_FILL_IMAGE_ID + }; + + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + SAL_WARN_IF( !xImpPrMap.is(), "xmloff", "There is the import prop mapper" ); + if( xImpPrMap.is() ) + xImpPrMap->FillPropertySet( GetProperties(), rPropSet, aContextIDs ); + + Reference< XPropertySetInfo > xInfo; + // get property set mapper + rtl::Reference<XMLPropertySetMapper> xPropMapper( xImpPrMap->getPropertySetMapper() ); + + for( sal_uInt16 i=0; aContextIDs[i].nContextID != -1; i++ ) + { + sal_Int32 nIndex = aContextIDs[i].nIndex; + if( nIndex != -1 ) switch( aContextIDs[i].nContextID ) + { + case CTF_DASHNAME: + case CTF_LINESTARTNAME: + case CTF_LINEENDNAME: + case CTF_FILLGRADIENTNAME: + case CTF_FILLTRANSNAME: + case CTF_FILLHATCHNAME: + case CTF_FILLBITMAPNAME: + { + struct XMLPropertyState& rState = GetProperties()[nIndex]; + OUString sStyleName; + rState.maValue >>= sStyleName; + sStyleName = GetImport().GetStyleDisplayName( aFamilies[i], sStyleName ); + // All of these attributes refer to something with draw:name + // of type styleName = NCName which is non-empty. + // tdf#89802: for Writer frames there would be no exception here but + // it will fail later on attach() and take out the entire frame + if (sStyleName.isEmpty() && + ( CTF_FILLGRADIENTNAME == aContextIDs[i].nContextID + || CTF_FILLTRANSNAME == aContextIDs[i].nContextID + || CTF_FILLHATCHNAME == aContextIDs[i].nContextID + || CTF_FILLBITMAPNAME == aContextIDs[i].nContextID)) + { + Sequence<OUString> const seq{ sStyleName }; + GetImport().SetError( + XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING, + seq, "empty style name reference", nullptr ); + break; + } + + if (::xmloff::IsIgnoreFillStyleNamedItem(rPropSet, aContextIDs[i].nExpectedFillStyle)) + { + SAL_INFO("xmloff.style", "ShapeStyleContext: dropping fill named item: " << sStyleName); + break; // ignore it, it's not used + } + + try + { + + // set property + const OUString& rPropertyName = xPropMapper->GetEntryAPIName(rState.mnIndex); + if( !xInfo.is() ) + xInfo = rPropSet->getPropertySetInfo(); + if ( xInfo->hasPropertyByName( rPropertyName ) ) + { + rPropSet->setPropertyValue( rPropertyName, Any( sStyleName ) ); + } + } + catch ( const css::lang::IllegalArgumentException& e ) + { + Sequence<OUString> aSeq { sStyleName }; + GetImport().SetError( + XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING, + aSeq, e.Message, nullptr ); + } + break; + } + case CTF_SD_OLE_VIS_AREA_IMPORT_LEFT: + case CTF_SD_OLE_VIS_AREA_IMPORT_TOP: + case CTF_SD_OLE_VIS_AREA_IMPORT_WIDTH: + case CTF_SD_OLE_VIS_AREA_IMPORT_HEIGHT: + { + struct XMLPropertyState& rState = GetProperties()[nIndex]; + const OUString& rPropertyName = xPropMapper->GetEntryAPIName(rState.mnIndex); + try + { + if( !xInfo.is() ) + xInfo = rPropSet->getPropertySetInfo(); + if ( xInfo->hasPropertyByName( rPropertyName ) ) + { + rPropSet->setPropertyValue( rPropertyName, rState.maValue ); + } + } + catch ( const css::lang::IllegalArgumentException& e ) + { + Sequence<OUString> aSeq; + GetImport().SetError( + XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING, + aSeq, e.Message, nullptr ); + } + break; + } + } + } + + if (m_sControlDataStyleName.isEmpty()) + return; + + // we had a data-style-name attribute + + // set the formatting on the control model of the control shape + uno::Reference< drawing::XControlShape > xControlShape(rPropSet, uno::UNO_QUERY); + DBG_ASSERT(xControlShape.is(), "XMLShapeStyleContext::FillPropertySet: data style for a non-control shape!"); + if (xControlShape.is()) + { + uno::Reference< beans::XPropertySet > xControlModel(xControlShape->getControl(), uno::UNO_QUERY); + DBG_ASSERT(xControlModel.is(), "XMLShapeStyleContext::FillPropertySet: no control model for the shape!"); + if (xControlModel.is()) + { + GetImport().GetFormImport()->applyControlNumberStyle(xControlModel, m_sControlDataStyleName); + } + } +} + +void XMLShapeStyleContext::Finish( bool /*bOverwrite*/ ) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/animationexport.cxx b/xmloff/source/draw/animationexport.cxx new file mode 100644 index 0000000000..fee665930b --- /dev/null +++ b/xmloff/source/draw/animationexport.cxx @@ -0,0 +1,1742 @@ +/* -*- 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 <com/sun/star/animations/XAnimateColor.hpp> +#include <com/sun/star/animations/XCommand.hpp> +#include <com/sun/star/animations/Timing.hpp> +#include <com/sun/star/animations/Event.hpp> +#include <com/sun/star/animations/XAnimateMotion.hpp> +#include <com/sun/star/animations/XAnimatePhysics.hpp> +#include <com/sun/star/animations/XAnimateTransform.hpp> +#include <com/sun/star/animations/XTransitionFilter.hpp> +#include <com/sun/star/animations/XIterateContainer.hpp> +#include <com/sun/star/animations/XAudio.hpp> +#include <com/sun/star/animations/AnimationColorSpace.hpp> +#include <com/sun/star/animations/AnimationNodeType.hpp> +#include <com/sun/star/animations/AnimationRestart.hpp> +#include <com/sun/star/animations/EventTrigger.hpp> +#include <com/sun/star/animations/AnimationFill.hpp> +#include <com/sun/star/animations/AnimationEndSync.hpp> +#include <com/sun/star/animations/AnimationCalcMode.hpp> +#include <com/sun/star/animations/AnimationAdditiveMode.hpp> +#include <com/sun/star/animations/AnimationTransformType.hpp> +#include <com/sun/star/animations/TransitionType.hpp> +#include <com/sun/star/animations/TransitionSubType.hpp> +#include <com/sun/star/animations/ValuePair.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/document/XStorageBasedDocument.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/presentation/EffectNodeType.hpp> +#include <com/sun/star/presentation/EffectPresetClass.hpp> +#include <com/sun/star/presentation/ParagraphTarget.hpp> +#include <com/sun/star/presentation/TextAnimationType.hpp> +#include <com/sun/star/presentation/ShapeAnimationSubType.hpp> +#include <com/sun/star/presentation/EffectCommands.hpp> +#include <o3tl/any.hxx> +#include <sax/tools/converter.hxx> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include <xmloff/unointerfacetouniqueidentifiermapper.hxx> +#include "sdpropls.hxx" +#include <xmlsdtypes.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlement.hxx> +#include <xmloff/xmlprhdl.hxx> + +#include <animations.hxx> +#include <xmloff/animationexport.hxx> + +using namespace css; +using namespace ::cppu; +using namespace ::com::sun::star::animations; +using namespace ::com::sun::star::presentation; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::beans::NamedValue; +using ::com::sun::star::container::XEnumerationAccess; +using ::com::sun::star::container::XEnumeration; + +namespace xmloff +{ + +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_Fill[] = +{ + { XML_DEFAULT, AnimationFill::DEFAULT }, + { XML_REMOVE, AnimationFill::REMOVE }, + { XML_FREEZE, AnimationFill::FREEZE }, + { XML_HOLD, AnimationFill::HOLD }, + { XML_TRANSITION, AnimationFill::TRANSITION }, + { XML_AUTO, AnimationFill::AUTO }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_FillDefault[] = +{ + { XML_INHERIT, AnimationFill::INHERIT }, + { XML_REMOVE, AnimationFill::REMOVE }, + { XML_FREEZE, AnimationFill::FREEZE }, + { XML_HOLD, AnimationFill::HOLD }, + { XML_TRANSITION, AnimationFill::TRANSITION }, + { XML_AUTO, AnimationFill::AUTO }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_Restart[] = +{ + { XML_DEFAULT, AnimationRestart::DEFAULT }, + { XML_ALWAYS, AnimationRestart::ALWAYS }, + { XML_WHENNOTACTIVE,AnimationRestart::WHEN_NOT_ACTIVE }, + { XML_NEVER, AnimationRestart::NEVER }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_RestartDefault[] = +{ + { XML_INHERIT, AnimationRestart::INHERIT }, + { XML_ALWAYS, AnimationRestart::ALWAYS }, + { XML_WHENNOTACTIVE,AnimationRestart::WHEN_NOT_ACTIVE }, + { XML_NEVER, AnimationRestart::NEVER }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_Endsync[] = +{ + { XML_FIRST, AnimationEndSync::FIRST }, + { XML_LAST, AnimationEndSync::LAST }, + { XML_ALL, AnimationEndSync::ALL }, + { XML_MEDIA, AnimationEndSync::MEDIA }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_CalcMode[] = +{ + { XML_DISCRETE, AnimationCalcMode::DISCRETE }, + { XML_LINEAR, AnimationCalcMode::LINEAR }, + { XML_PACED, AnimationCalcMode::PACED }, + { XML_SPLINE, AnimationCalcMode::SPLINE }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_AdditiveMode[] = +{ + { XML_BASE, AnimationAdditiveMode::BASE }, + { XML_SUM, AnimationAdditiveMode::SUM }, + { XML_REPLACE, AnimationAdditiveMode::REPLACE }, + { XML_MULTIPLY, AnimationAdditiveMode::MULTIPLY }, + { XML_NONE, AnimationAdditiveMode::NONE }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_TransformType[] = +{ + { XML_TRANSLATE, AnimationTransformType::TRANSLATE }, + { XML_SCALE, AnimationTransformType::SCALE }, + { XML_ROTATE, AnimationTransformType::ROTATE }, + { XML_SKEWX, AnimationTransformType::SKEWX }, + { XML_SKEWY, AnimationTransformType::SKEWY }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_TransitionType[] = +{ + { XML_BARWIPE, TransitionType::BARWIPE }, + { XML_BOXWIPE, TransitionType::BOXWIPE }, + { XML_FOURBOXWIPE, TransitionType::FOURBOXWIPE }, + { XML_BARNDOORWIPE, TransitionType::BARNDOORWIPE }, + { XML_DIAGONALWIPE, TransitionType::DIAGONALWIPE }, + { XML_BOWTIEWIPE, TransitionType::BOWTIEWIPE }, + { XML_MISCDIAGONALWIPE, TransitionType::MISCDIAGONALWIPE }, + { XML_VEEWIPE, TransitionType::VEEWIPE }, + { XML_BARNVEEWIPE, TransitionType::BARNVEEWIPE }, + { XML_ZIGZAGWIPE, TransitionType::ZIGZAGWIPE }, + { XML_BARNZIGZAGWIPE, TransitionType::BARNZIGZAGWIPE }, + { XML_IRISWIPE, TransitionType::IRISWIPE }, + { XML_TRIANGLEWIPE, TransitionType::TRIANGLEWIPE }, + { XML_ARROWHEADWIPE, TransitionType::ARROWHEADWIPE }, + { XML_PENTAGONWIPE, TransitionType::PENTAGONWIPE }, + { XML_HEXAGONWIPE, TransitionType::HEXAGONWIPE }, + { XML_ELLIPSEWIPE, TransitionType::ELLIPSEWIPE }, + { XML_EYEWIPE, TransitionType::EYEWIPE }, + { XML_ROUNDRECTWIPE, TransitionType::ROUNDRECTWIPE }, + { XML_STARWIPE, TransitionType::STARWIPE }, + { XML_MISCSHAPEWIPE, TransitionType::MISCSHAPEWIPE }, + { XML_CLOCKWIPE, TransitionType::CLOCKWIPE }, + { XML_PINWHEELWIPE, TransitionType::PINWHEELWIPE }, + { XML_SINGLESWEEPWIPE, TransitionType::SINGLESWEEPWIPE }, + { XML_FANWIPE, TransitionType::FANWIPE }, + { XML_DOUBLEFANWIPE, TransitionType::DOUBLEFANWIPE }, + { XML_DOUBLESWEEPWIPE, TransitionType::DOUBLESWEEPWIPE }, + { XML_SALOONDOORWIPE, TransitionType::SALOONDOORWIPE }, + { XML_WINDSHIELDWIPE, TransitionType::WINDSHIELDWIPE }, + { XML_SNAKEWIPE, TransitionType::SNAKEWIPE }, + { XML_SPIRALWIPE, TransitionType::SPIRALWIPE }, + { XML_PARALLELSNAKESWIPE,TransitionType::PARALLELSNAKESWIPE }, + { XML_BOXSNAKESWIPE, TransitionType::BOXSNAKESWIPE }, + { XML_WATERFALLWIPE, TransitionType::WATERFALLWIPE }, + { XML_PUSHWIPE, TransitionType::PUSHWIPE }, + { XML_SLIDEWIPE, TransitionType::SLIDEWIPE }, + { XML_FADE, TransitionType::FADE }, + { XML_RANDOMBARWIPE, TransitionType::RANDOMBARWIPE }, + { XML_CHECKERBOARDWIPE, TransitionType::CHECKERBOARDWIPE }, + { XML_DISSOLVE, TransitionType::DISSOLVE }, + { XML_BLINDSWIPE, TransitionType::BLINDSWIPE }, + { XML_RANDOM, TransitionType::RANDOM }, + { XML_ZOOM, TransitionType::ZOOM }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_TransitionSubType[] = +{ + { XML_DEFAULT, TransitionSubType::DEFAULT }, + { XML_LEFTTORIGHT, TransitionSubType::LEFTTORIGHT }, + { XML_TOPTOBOTTOM, TransitionSubType::TOPTOBOTTOM }, + { XML_TOPLEFT, TransitionSubType::TOPLEFT }, + { XML_TOPRIGHT, TransitionSubType::TOPRIGHT }, + { XML_BOTTOMRIGHT, TransitionSubType::BOTTOMRIGHT }, + { XML_BOTTOMLEFT, TransitionSubType::BOTTOMLEFT }, + { XML_TOPCENTER, TransitionSubType::TOPCENTER }, + { XML_RIGHTCENTER, TransitionSubType::RIGHTCENTER }, + { XML_BOTTOMCENTER, TransitionSubType::BOTTOMCENTER }, + { XML_LEFTCENTER, TransitionSubType::LEFTCENTER }, + { XML_CORNERSIN, TransitionSubType::CORNERSIN }, + { XML_CORNERSOUT, TransitionSubType::CORNERSOUT }, + { XML_VERTICAL, TransitionSubType::VERTICAL }, + { XML_HORIZONTAL, TransitionSubType::HORIZONTAL }, + { XML_DIAGONALBOTTOMLEFT, TransitionSubType::DIAGONALBOTTOMLEFT }, + { XML_DIAGONALTOPLEFT, TransitionSubType::DIAGONALTOPLEFT }, + { XML_DOUBLEBARNDOOR, TransitionSubType::DOUBLEBARNDOOR }, + { XML_DOUBLEDIAMOND, TransitionSubType::DOUBLEDIAMOND }, + { XML_DOWN, TransitionSubType::DOWN }, + { XML_LEFT, TransitionSubType::LEFT }, + { XML_UP, TransitionSubType::UP }, + { XML_RIGHT, TransitionSubType::RIGHT }, + { XML_RECTANGLE, TransitionSubType::RECTANGLE }, + { XML_DIAMOND, TransitionSubType::DIAMOND }, + { XML_CIRCLE, TransitionSubType::CIRCLE }, + { XML_FOURPOINT, TransitionSubType::FOURPOINT }, + { XML_FIVEPOINT, TransitionSubType::FIVEPOINT }, + { XML_SIXPOINT, TransitionSubType::SIXPOINT }, + { XML_HEART, TransitionSubType::HEART }, + { XML_KEYHOLE, TransitionSubType::KEYHOLE }, + { XML_CLOCKWISETWELVE, TransitionSubType::CLOCKWISETWELVE }, + { XML_CLOCKWISETHREE, TransitionSubType::CLOCKWISETHREE }, + { XML_CLOCKWISESIX, TransitionSubType::CLOCKWISESIX }, + { XML_CLOCKWISENINE, TransitionSubType::CLOCKWISENINE }, + { XML_TWOBLADEVERTICAL, TransitionSubType::TWOBLADEVERTICAL }, + { XML_TWOBLADEHORIZONTAL, TransitionSubType::TWOBLADEHORIZONTAL }, + { XML_FOURBLADE, TransitionSubType::FOURBLADE }, + { XML_CLOCKWISETOP, TransitionSubType::CLOCKWISETOP }, + { XML_CLOCKWISERIGHT, TransitionSubType::CLOCKWISERIGHT }, + { XML_CLOCKWISEBOTTOM, TransitionSubType::CLOCKWISEBOTTOM }, + { XML_CLOCKWISELEFT, TransitionSubType::CLOCKWISELEFT }, + { XML_CLOCKWISETOPLEFT, TransitionSubType::CLOCKWISETOPLEFT }, + { XML_COUNTERCLOCKWISEBOTTOMLEFT,TransitionSubType::COUNTERCLOCKWISEBOTTOMLEFT }, + { XML_CLOCKWISEBOTTOMRIGHT, TransitionSubType::CLOCKWISEBOTTOMRIGHT }, + { XML_COUNTERCLOCKWISETOPRIGHT,TransitionSubType::COUNTERCLOCKWISETOPRIGHT }, + { XML_CENTERTOP, TransitionSubType::CENTERTOP }, + { XML_CENTERRIGHT, TransitionSubType::CENTERRIGHT }, + { XML_TOP, TransitionSubType::TOP }, + { XML_BOTTOM, TransitionSubType::BOTTOM }, + { XML_FANOUTVERTICAL, TransitionSubType::FANOUTVERTICAL }, + { XML_FANOUTHORIZONTAL, TransitionSubType::FANOUTHORIZONTAL }, + { XML_FANINVERTICAL, TransitionSubType::FANINVERTICAL }, + { XML_FANINHORIZONTAL, TransitionSubType::FANINHORIZONTAL }, + { XML_PARALLELVERTICAL, TransitionSubType::PARALLELVERTICAL }, + { XML_PARALLELDIAGONAL, TransitionSubType::PARALLELDIAGONAL }, + { XML_OPPOSITEVERTICAL, TransitionSubType::OPPOSITEVERTICAL }, + { XML_OPPOSITEHORIZONTAL, TransitionSubType::OPPOSITEHORIZONTAL }, + { XML_PARALLELDIAGONALTOPLEFT,TransitionSubType::PARALLELDIAGONALTOPLEFT }, + { XML_PARALLELDIAGONALBOTTOMLEFT,TransitionSubType::PARALLELDIAGONALBOTTOMLEFT }, + { XML_TOPLEFTHORIZONTAL, TransitionSubType::TOPLEFTHORIZONTAL }, + { XML_TOPLEFTDIAGONAL, TransitionSubType::TOPLEFTDIAGONAL }, + { XML_TOPRIGHTDIAGONAL, TransitionSubType::TOPRIGHTDIAGONAL }, + { XML_BOTTOMRIGHTDIAGONAL, TransitionSubType::BOTTOMRIGHTDIAGONAL }, + { XML_BOTTOMLEFTDIAGONAL, TransitionSubType::BOTTOMLEFTDIAGONAL }, + { XML_TOPLEFTCLOCKWISE, TransitionSubType::TOPLEFTCLOCKWISE }, + { XML_TOPRIGHTCLOCKWISE, TransitionSubType::TOPRIGHTCLOCKWISE }, + { XML_BOTTOMRIGHTCLOCKWISE, TransitionSubType::BOTTOMRIGHTCLOCKWISE }, + { XML_BOTTOMLEFTCLOCKWISE, TransitionSubType::BOTTOMLEFTCLOCKWISE }, + { XML_TOPLEFTCOUNTERCLOCKWISE,TransitionSubType::TOPLEFTCOUNTERCLOCKWISE }, + { XML_TOPRIGHTCOUNTERCLOCKWISE,TransitionSubType::TOPRIGHTCOUNTERCLOCKWISE }, + { XML_BOTTOMRIGHTCOUNTERCLOCKWISE,TransitionSubType::BOTTOMRIGHTCOUNTERCLOCKWISE }, + { XML_BOTTOMLEFTCOUNTERCLOCKWISE,TransitionSubType::BOTTOMLEFTCOUNTERCLOCKWISE }, + { XML_VERTICALTOPSAME, TransitionSubType::VERTICALTOPSAME }, + { XML_VERTICALBOTTOMSAME, TransitionSubType::VERTICALBOTTOMSAME }, + { XML_VERTICALTOPLEFTOPPOSITE,TransitionSubType::VERTICALTOPLEFTOPPOSITE }, + { XML_VERTICALBOTTOMLEFTOPPOSITE,TransitionSubType::VERTICALBOTTOMLEFTOPPOSITE }, + { XML_HORIZONTALLEFTSAME, TransitionSubType::HORIZONTALLEFTSAME }, + { XML_HORIZONTALRIGHTSAME, TransitionSubType::HORIZONTALRIGHTSAME }, + { XML_HORIZONTALTOPLEFTOPPOSITE,TransitionSubType::HORIZONTALTOPLEFTOPPOSITE }, + { XML_HORIZONTALTOPRIGHTOPPOSITE,TransitionSubType::HORIZONTALTOPRIGHTOPPOSITE }, + { XML_DIAGONALBOTTOMLEFTOPPOSITE,TransitionSubType::DIAGONALBOTTOMLEFTOPPOSITE }, + { XML_DIAGONALTOPLEFTOPPOSITE,TransitionSubType::DIAGONALTOPLEFTOPPOSITE }, + { XML_TWOBOXTOP, TransitionSubType::TWOBOXTOP }, + { XML_TWOBOXBOTTOM, TransitionSubType::TWOBOXBOTTOM }, + { XML_TWOBOXLEFT, TransitionSubType::TWOBOXLEFT }, + { XML_TWOBOXRIGHT, TransitionSubType::TWOBOXRIGHT }, + { XML_FOURBOXVERTICAL, TransitionSubType::FOURBOXVERTICAL }, + { XML_FOURBOXHORIZONTAL, TransitionSubType::FOURBOXHORIZONTAL }, + { XML_VERTICALLEFT, TransitionSubType::VERTICALLEFT }, + { XML_VERTICALRIGHT, TransitionSubType::VERTICALRIGHT }, + { XML_HORIZONTALLEFT, TransitionSubType::HORIZONTALLEFT }, + { XML_HORIZONTALRIGHT, TransitionSubType::HORIZONTALRIGHT }, + { XML_FROMLEFT, TransitionSubType::FROMLEFT }, + { XML_FROMTOP, TransitionSubType::FROMTOP }, + { XML_FROMRIGHT, TransitionSubType::FROMRIGHT }, + { XML_FROMBOTTOM, TransitionSubType::FROMBOTTOM }, + { XML_CROSSFADE, TransitionSubType::CROSSFADE }, + { XML_FADETOCOLOR, TransitionSubType::FADETOCOLOR }, + { XML_FADEFROMCOLOR, TransitionSubType::FADEFROMCOLOR }, + { XML_FADEOVERCOLOR, TransitionSubType::FADEOVERCOLOR }, + { XML_THREEBLADE, TransitionSubType::THREEBLADE }, + { XML_EIGHTBLADE, TransitionSubType::EIGHTBLADE }, + { XML_ONEBLADE, TransitionSubType::ONEBLADE }, + { XML_ACROSS, TransitionSubType::ACROSS }, + { XML_TOPLEFTVERTICAL, TransitionSubType::TOPLEFTVERTICAL }, + { XML_COMBHORIZONTAL, TransitionSubType::COMBHORIZONTAL }, + { XML_COMBVERTICAL, TransitionSubType::COMBVERTICAL }, + { XML_IN, TransitionSubType::IN }, + { XML_OUT, TransitionSubType::OUT }, + { XML_ROTATEIN, TransitionSubType::ROTATEIN }, + { XML_ROTATEOUT, TransitionSubType::ROTATEOUT }, + { XML_FROMTOPLEFT, TransitionSubType::FROMTOPLEFT }, + { XML_FROMTOPRIGHT, TransitionSubType::FROMTOPRIGHT }, + { XML_FROMBOTTOMLEFT, TransitionSubType::FROMBOTTOMLEFT }, + { XML_FROMBOTTOMRIGHT, TransitionSubType::FROMBOTTOMRIGHT }, + + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_EventTrigger[] = +{ + { XML_ONBEGIN, EventTrigger::ON_BEGIN }, + { XML_ONEND, EventTrigger::ON_END }, + { XML_BEGIN, EventTrigger::BEGIN_EVENT }, + { XML_END, EventTrigger::END_EVENT }, + { XML_CLICK, EventTrigger::ON_CLICK }, + { XML_DOUBLECLICK, EventTrigger::ON_DBL_CLICK }, + { XML_MOUSEOVER, EventTrigger::ON_MOUSE_ENTER }, + { XML_MOUSEOUT, EventTrigger::ON_MOUSE_LEAVE }, + { XML_NEXT, EventTrigger::ON_NEXT }, + { XML_PREVIOUS, EventTrigger::ON_PREV }, + { XML_STOP_AUDIO, EventTrigger::ON_STOP_AUDIO }, + { XML_REPEAT, EventTrigger::REPEAT }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_EffectPresetClass[] = +{ + { XML_CUSTOM, EffectPresetClass::CUSTOM }, + { XML_ENTRANCE, EffectPresetClass::ENTRANCE }, + { XML_EXIT, EffectPresetClass::EXIT }, + { XML_EMPHASIS, EffectPresetClass::EMPHASIS }, + { XML_MOTION_PATH, EffectPresetClass::MOTIONPATH }, + { XML_OLE_ACTION, EffectPresetClass::OLEACTION }, + { XML_MEDIA_CALL, EffectPresetClass::MEDIACALL }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_EffectNodeType[] = +{ + { XML_DEFAULT, EffectNodeType::DEFAULT }, + { XML_ON_CLICK, EffectNodeType::ON_CLICK }, + { XML_WITH_PREVIOUS, EffectNodeType::WITH_PREVIOUS }, + { XML_AFTER_PREVIOUS, EffectNodeType::AFTER_PREVIOUS }, + { XML_MAIN_SEQUENCE, EffectNodeType::MAIN_SEQUENCE }, + { XML_TIMING_ROOT, EffectNodeType::TIMING_ROOT }, + { XML_INTERACTIVE_SEQUENCE, EffectNodeType::INTERACTIVE_SEQUENCE }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_SubItem[] = +{ + { XML_WHOLE, ShapeAnimationSubType::AS_WHOLE }, + { XML_BACKGROUND, ShapeAnimationSubType::ONLY_BACKGROUND }, + { XML_TEXT, ShapeAnimationSubType::ONLY_TEXT }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_IterateType[] = +{ + { XML_BY_PARAGRAPH, TextAnimationType::BY_PARAGRAPH }, + { XML_BY_WORD, TextAnimationType::BY_WORD }, + { XML_BY_LETTER, TextAnimationType::BY_LETTER }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry<sal_Int16> aAnimations_EnumMap_Command[] = +{ + { XML_CUSTOM, EffectCommands::CUSTOM }, + { XML_VERB, EffectCommands::VERB }, + { XML_PLAY, EffectCommands::PLAY }, + { XML_TOGGLE_PAUSE, EffectCommands::TOGGLEPAUSE }, + { XML_STOP, EffectCommands::STOP }, + { XML_STOP_AUDIO, EffectCommands::STOPAUDIO }, + { XML_TOKEN_INVALID, 0 } +}; + +const struct ImplAttributeNameConversion* getAnimationAttributeNamesConversionList() +{ + static const struct ImplAttributeNameConversion gImplConversionList[] = + { + { XML_X, "X" }, + { XML_Y, "Y" }, + { XML_WIDTH, "Width" }, + { XML_HEIGHT, "Height" }, + { XML_ROTATE, "Rotate" }, + { XML_SKEWX, "SkewX" }, + { XML_FILL_COLOR, "FillColor" }, + { XML_FILL, "FillStyle" }, + { XML_STROKE_COLOR, "LineColor" }, + { XML_STROKE, "LineStyle" }, + { XML_COLOR, "CharColor" }, + { XML_TEXT_ROTATION_ANGLE, "CharRotation" }, + { XML_FONT_WEIGHT, "CharWeight" }, + { XML_TEXT_UNDERLINE, "CharUnderline" }, + { XML_FONT_FAMILY, "CharFontName" }, + { XML_FONT_SIZE, "CharHeight" }, + { XML_FONT_STYLE, "CharPosture" }, + { XML_VISIBILITY, "Visibility" }, + { XML_OPACITY, "Opacity" }, + { XML_DIM, "DimColor" }, + { XML_TOKEN_INVALID, nullptr } + }; + + return gImplConversionList; +} + + +class AnimationsExporterImpl +{ +public: + AnimationsExporterImpl( SvXMLExport& rExport, const Reference< XPropertySet >& xPageProps ); + + void prepareNode( const Reference< XAnimationNode >& xNode ); + void exportNode( const Reference< XAnimationNode >& xNode ); + + void exportContainer( const Reference< XTimeContainer >& xNode, sal_Int16 nContainerNodeType ); + void exportAnimate( const Reference< XAnimate >& xNode ); + void exportAudio( const Reference< XAudio >& xAudio ); + void exportCommand( const Reference< XCommand >& xCommand ); + + static Reference< XInterface > getParagraphTarget( const ParagraphTarget& pTarget ); + + static void convertPath( OUStringBuffer& sTmp, const Any& rPath ); + void convertValue( XMLTokenEnum eAttributeName, OUStringBuffer& sTmp, const Any& rValue ) const; + void convertTiming( OUStringBuffer& sTmp, const Any& rTiming ) const; + void convertTarget( OUStringBuffer& sTmp, const Any& rTarget ) const; + + void prepareValue( const Any& rValue ); + + void exportTransitionNode(); + void prepareTransitionNode(); + + bool mbHasTransition; +private: + rtl::Reference<SvXMLExport> mxExport; + Reference< XPropertySet > mxPageProps; + rtl::Reference<XMLSdPropHdlFactory> mxSdPropHdlFactory; +}; + +AnimationsExporterImpl::AnimationsExporterImpl( SvXMLExport& rExport, const Reference< XPropertySet >& xPageProps ) +: mbHasTransition(false) +, mxExport( &rExport ) +, mxPageProps( xPageProps ) +, mxSdPropHdlFactory(new XMLSdPropHdlFactory( rExport.GetModel(), rExport )) +{ +} + + +/** split a uri hierarchy into first segment and rest */ +static bool splitPath(OUString const & i_rPath, + OUString & o_rDir, OUString& o_rRest) +{ + const sal_Int32 idx(i_rPath.indexOf(u'/')); + if (idx < 0 || idx >= i_rPath.getLength()) { + o_rDir = OUString(); + o_rRest = i_rPath; + return true; + } else if (idx == 0 || idx == i_rPath.getLength() - 1) { + // input must not start or end with '/' + return false; + } else { + o_rDir = i_rPath.copy(0, idx); + o_rRest = i_rPath.copy(idx+1); + return true; + } +} + +static void lcl_CopyStream( + uno::Reference<embed::XStorage> const& xSource, + uno::Reference<embed::XStorage> const& xTarget, + OUString const& rPath) +{ + OUString dir; + OUString rest; + if (!splitPath(rPath, dir, rest)) + throw uno::RuntimeException(); + + if (dir.getLength() == 0) + xSource->copyElementTo(rPath, xTarget, rPath); + else + { + uno::Reference<embed::XStorage> const xSubSource( + xSource->openStorageElement(dir, embed::ElementModes::READ)); + uno::Reference<embed::XStorage> const xSubTarget( + xTarget->openStorageElement(dir, embed::ElementModes::WRITE)); + lcl_CopyStream(xSubSource, xSubTarget, rest); + } + uno::Reference<embed::XTransactedObject> const xTransaction(xTarget, uno::UNO_QUERY); + if (xTransaction.is()) + xTransaction->commit(); +} + +char const s_PkgScheme[] = "vnd.sun.star.Package:"; + +static OUString lcl_StoreMediaAndGetURL(SvXMLExport & rExport, OUString const& rURL) +{ + OUString urlPath; + if (rURL.startsWithIgnoreAsciiCase(s_PkgScheme, &urlPath)) + { + try // video is embedded + { + // copy the media stream from document storage to target storage + // (not sure if this is the best way to store these?) + uno::Reference<document::XStorageBasedDocument> const xSBD( + rExport.GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<embed::XStorage> const xSource( + xSBD->getDocumentStorage(), uno::UNO_SET_THROW); + uno::Reference<embed::XStorage> const xTarget( + rExport.GetTargetStorage(), uno::UNO_SET_THROW); + + urlPath = rURL.copy(SAL_N_ELEMENTS(s_PkgScheme)-1); + + lcl_CopyStream(xSource, xTarget, urlPath); + + return urlPath; + } + catch (uno::Exception const&) + { + TOOLS_INFO_EXCEPTION("xmloff", "exception while storing embedded media"); + } + return OUString(); + } + else + { + return rExport.GetRelativeReference(rURL); // linked + } +} + +void AnimationsExporterImpl::exportTransitionNode() +{ + if( !(mbHasTransition && mxPageProps.is()) ) + return; + + sal_Int16 nTransition = 0; + mxPageProps->getPropertyValue("TransitionType") >>= nTransition; + + Any aSound( mxPageProps->getPropertyValue("Sound") ); + OUString sSoundURL; + aSound >>= sSoundURL; + bool bStopSound = false; + if( !(aSound >>= bStopSound) ) + bStopSound = false; + + + OUStringBuffer sTmp; + if( !((nTransition != 0) || !sSoundURL.isEmpty() || bStopSound) ) + return; + + Reference< XInterface > xSource( mxPageProps ); + Event aEvent; + aEvent.Source <<= xSource; + aEvent.Trigger = EventTrigger::BEGIN_EVENT; + aEvent.Repeat = 0; + + convertTiming( sTmp, Any( aEvent ) ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_BEGIN, sTmp.makeStringAndClear() ); + + SvXMLElementExport aElement( *mxExport, XML_NAMESPACE_ANIMATION, XML_PAR, true, true ); + + if( nTransition != 0 ) + { + sal_Int16 nSubtype = 0; + bool bDirection = false; + sal_Int32 nFadeColor = 0; + double fDuration = 0.0; + mxPageProps->getPropertyValue("TransitionSubtype") >>= nSubtype; + mxPageProps->getPropertyValue("TransitionDirection") >>= bDirection; + mxPageProps->getPropertyValue("TransitionFadeColor") >>= nFadeColor; + mxPageProps->getPropertyValue("TransitionDuration") >>= fDuration; + + ::sax::Converter::convertDouble( sTmp, fDuration ); + sTmp.append( 's'); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_DUR, sTmp.makeStringAndClear() ); + + SvXMLUnitConverter::convertEnum( sTmp, nTransition, aAnimations_EnumMap_TransitionType ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_TYPE, sTmp.makeStringAndClear() ); + + if( nSubtype != TransitionSubType::DEFAULT ) + { + SvXMLUnitConverter::convertEnum( sTmp, nSubtype, aAnimations_EnumMap_TransitionSubType ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_SUBTYPE, sTmp.makeStringAndClear() ); + } + + if( !bDirection ) + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_DIRECTION, XML_REVERSE ); + + if( (nTransition == TransitionType::FADE) + && ((nSubtype == TransitionSubType::FADETOCOLOR) || (nSubtype == TransitionSubType::FADEFROMCOLOR) + || (nSubtype == TransitionSubType::FADEOVERCOLOR))) + { + ::sax::Converter::convertColor( sTmp, nFadeColor ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_FADECOLOR, sTmp.makeStringAndClear() ); + } + SvXMLElementExport aElement2( *mxExport, XML_NAMESPACE_ANIMATION, XML_TRANSITIONFILTER, true, true ); + } + + if( bStopSound ) + { + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_COMMAND, XML_STOP_AUDIO ); + SvXMLElementExport aElement2( *mxExport, XML_NAMESPACE_ANIMATION, XML_COMMAND, true, true ); + } + else if( !sSoundURL.isEmpty()) + { + sSoundURL = lcl_StoreMediaAndGetURL(*mxExport, sSoundURL); + mxExport->AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sSoundURL ); + + bool bLoopSound = false; + mxPageProps->getPropertyValue("LoopSound") >>= bLoopSound; + + if( bLoopSound ) + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_REPEATCOUNT, XML_INDEFINITE ); + SvXMLElementExport aElement2( *mxExport, XML_NAMESPACE_ANIMATION, XML_AUDIO, true, true ); + } +} + +void AnimationsExporterImpl::prepareTransitionNode() +{ + if( !mxPageProps.is() ) + return; + + try + { + sal_Int16 nTransition = 0; + mxPageProps->getPropertyValue("TransitionType") >>= nTransition; + + bool bStopSound = false; + OUString sSoundURL; + + if( nTransition == 0 ) + { + Any aSound( mxPageProps->getPropertyValue("Sound") ); + aSound >>= sSoundURL; + + if( !(aSound >>= bStopSound) ) + bStopSound = false; + } + + if( (nTransition != 0) || !sSoundURL.isEmpty() || bStopSound ) + { + mbHasTransition = true; + Reference< XInterface > xInt( mxPageProps ); + mxExport->getInterfaceToIdentifierMapper().registerReference( xInt ); + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void AnimationsExporterImpl::prepareNode( const Reference< XAnimationNode >& xNode ) +{ + try + { + prepareValue( xNode->getBegin() ); + prepareValue( xNode->getEnd() ); + + sal_Int16 nNodeType = xNode->getType(); + switch( nNodeType ) + { + case AnimationNodeType::ITERATE: + { + Reference< XIterateContainer > xIter( xNode, UNO_QUERY_THROW ); + prepareValue( xIter->getTarget() ); + [[fallthrough]]; + } + case AnimationNodeType::PAR: + case AnimationNodeType::SEQ: + { + Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW ); + while( xEnumeration->hasMoreElements() ) + { + Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); + prepareNode( xChildNode ); + } + } + break; + + case AnimationNodeType::ANIMATE: + case AnimationNodeType::SET: + case AnimationNodeType::ANIMATEMOTION: + case AnimationNodeType::ANIMATEPHYSICS: + case AnimationNodeType::ANIMATECOLOR: + case AnimationNodeType::ANIMATETRANSFORM: + case AnimationNodeType::TRANSITIONFILTER: + { + Reference< XAnimate > xAnimate( xNode, UNO_QUERY_THROW ); + prepareValue( xAnimate->getTarget() ); + } + break; + + case AnimationNodeType::COMMAND: + { + Reference< XCommand > xCommand( xNode, UNO_QUERY_THROW ); + prepareValue( xCommand->getTarget() ); + } + break; + + case AnimationNodeType::AUDIO: + { + Reference< XAudio > xAudio( xNode, UNO_QUERY_THROW ); + prepareValue( xAudio->getSource() ); + } + break; + } + + const Sequence< NamedValue > aUserData( xNode->getUserData() ); + for( const auto& rValue : aUserData ) + { + if( IsXMLToken( rValue.Name, XML_MASTER_ELEMENT ) ) + { + Reference< XInterface > xMaster; + rValue.Value >>= xMaster; + if( xMaster.is() ) + mxExport->getInterfaceToIdentifierMapper().registerReference( xMaster ); + } + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void AnimationsExporterImpl::exportNode( const Reference< XAnimationNode >& xNode ) +{ + try + { + OUStringBuffer sTmp; + + const OUString& rExportIdentifier = mxExport->getInterfaceToIdentifierMapper().getIdentifier( xNode ); + if( !rExportIdentifier.isEmpty() ) + { + mxExport->AddAttributeIdLegacy( + XML_NAMESPACE_ANIMATION, rExportIdentifier); + } + + Any aTemp( xNode->getBegin() ); + if( aTemp.hasValue() ) + { + convertTiming( sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_BEGIN, sTmp.makeStringAndClear() ); + } + + double fTemp = 0; + sal_Int16 nTemp; + + aTemp = xNode->getDuration(); + if( aTemp.hasValue() ) + { + if( aTemp >>= fTemp ) + { + ::sax::Converter::convertDouble( sTmp, fTemp ); + sTmp.append( 's'); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_DUR, sTmp.makeStringAndClear() ); + } + else + { + Timing eTiming; + if( aTemp >>= eTiming ) + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_DUR, eTiming == Timing_INDEFINITE ? XML_INDEFINITE : XML_MEDIA ); + } + } + + aTemp = xNode->getEnd(); + if( aTemp.hasValue() ) + { + convertTiming( sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_END, sTmp.makeStringAndClear() ); + } + + nTemp = xNode->getFill(); + if( nTemp != AnimationFill::DEFAULT ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_Fill ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_FILL, sTmp.makeStringAndClear() ); + } + + nTemp = xNode->getFillDefault(); + if( nTemp != AnimationFill::INHERIT ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_FillDefault ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_FILLDEFAULT, sTmp.makeStringAndClear() ); + } + + nTemp = xNode->getRestart(); + if( nTemp != AnimationRestart::DEFAULT ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_Restart ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_RESTART, sTmp.makeStringAndClear() ); + } + + nTemp = xNode->getRestartDefault(); + if( nTemp != AnimationRestart::INHERIT ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_RestartDefault ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_RESTARTDEFAULT, sTmp.makeStringAndClear() ); + } + + fTemp = xNode->getAcceleration(); + if( fTemp != 0.0 ) + { + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_ACCELERATE, sTmp.makeStringAndClear() ); + } + + fTemp = xNode->getDecelerate(); + if( fTemp != 0.0 ) + { + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_DECELERATE, sTmp.makeStringAndClear() ); + } + + bool bTemp = xNode->getAutoReverse(); + if( bTemp ) + { + ::sax::Converter::convertBool( sTmp, bTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_AUTOREVERSE, sTmp.makeStringAndClear() ); + } + + aTemp = xNode->getRepeatCount(); + if( aTemp.hasValue() ) + { + Timing eTiming; + if( (aTemp >>= eTiming ) && (eTiming == Timing_INDEFINITE ) ) + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_REPEATCOUNT, XML_INDEFINITE ); + else if( aTemp >>= fTemp ) + { + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_REPEATCOUNT, sTmp.makeStringAndClear() ); + } + } + + aTemp = xNode->getRepeatDuration(); + if( aTemp.hasValue() ) + { + Timing eTiming; + if( ( aTemp >>= eTiming ) && (eTiming == Timing_INDEFINITE) ) + { + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_REPEATDUR, XML_INDEFINITE ); + } + else if( aTemp >>= fTemp ) + { + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_REPEATDUR, sTmp.makeStringAndClear() ); + } + } + + aTemp = xNode->getEndSync(); + if( aTemp.hasValue() && (aTemp >>= nTemp) ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_Endsync ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_ENDSYNC, sTmp.makeStringAndClear() ); + } + + sal_Int16 nContainerNodeType = EffectNodeType::DEFAULT; + OUString aPresetId; + const Sequence< NamedValue > aUserData( xNode->getUserData() ); + for( const auto& rValue : aUserData ) + { + if( IsXMLToken( rValue.Name, XML_NODE_TYPE ) ) + { + if( (rValue.Value >>= nContainerNodeType) && (nContainerNodeType != EffectNodeType::DEFAULT) ) + { + SvXMLUnitConverter::convertEnum( sTmp, nContainerNodeType, aAnimations_EnumMap_EffectNodeType ); + mxExport->AddAttribute( XML_NAMESPACE_PRESENTATION, XML_NODE_TYPE, sTmp.makeStringAndClear() ); + } + } + else if( IsXMLToken( rValue.Name, XML_PRESET_ID ) ) + { + if( rValue.Value >>= aPresetId ) + { + mxExport->AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PRESET_ID, aPresetId ); + } + } + else if( IsXMLToken( rValue.Name, XML_PRESET_SUB_TYPE ) ) + { + OUString aPresetSubType; + if( rValue.Value >>= aPresetSubType ) + { + mxExport->AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PRESET_SUB_TYPE, aPresetSubType ); + } + } + else if( IsXMLToken( rValue.Name, XML_PRESET_CLASS ) ) + { + sal_Int16 nEffectPresetClass = sal_uInt16(); + if( rValue.Value >>= nEffectPresetClass ) + { + SvXMLUnitConverter::convertEnum( sTmp, nEffectPresetClass, aAnimations_EnumMap_EffectPresetClass ); + mxExport->AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PRESET_CLASS, sTmp.makeStringAndClear() ); + } + } + else if( IsXMLToken( rValue.Name, XML_MASTER_ELEMENT ) ) + { + Reference< XInterface > xMaster; + rValue.Value >>= xMaster; + if( xMaster.is() ) + { + const OUString& rIdentifier = mxExport->getInterfaceToIdentifierMapper().getIdentifier(xMaster); + if( !rIdentifier.isEmpty() ) + mxExport->AddAttribute( XML_NAMESPACE_PRESENTATION, XML_MASTER_ELEMENT, rIdentifier ); + } + } + else if( IsXMLToken( rValue.Name, XML_GROUP_ID ) ) + { + sal_Int32 nGroupId = 0; + if( rValue.Value >>= nGroupId ) + mxExport->AddAttribute( XML_NAMESPACE_PRESENTATION, XML_GROUP_ID, OUString::number( nGroupId ) ); + } + else + { + OUString aTmp; + if( rValue.Value >>= aTmp ) + mxExport->AddAttribute( XML_NAMESPACE_PRESENTATION, rValue.Name, aTmp ); + } + } + + nTemp = xNode->getType(); + switch( nTemp ) + { + case AnimationNodeType::PAR: + case AnimationNodeType::SEQ: + case AnimationNodeType::ITERATE: + { + Reference< XTimeContainer > xContainer( xNode, UNO_QUERY_THROW ); + exportContainer( xContainer, nContainerNodeType ); + } + break; + + case AnimationNodeType::ANIMATE: + case AnimationNodeType::SET: + case AnimationNodeType::ANIMATEMOTION: + case AnimationNodeType::ANIMATEPHYSICS: + case AnimationNodeType::ANIMATECOLOR: + case AnimationNodeType::ANIMATETRANSFORM: + case AnimationNodeType::TRANSITIONFILTER: + { + Reference< XAnimate > xAnimate( xNode, UNO_QUERY_THROW ); + exportAnimate( xAnimate ); + } + break; + case AnimationNodeType::AUDIO: + { + Reference< XAudio > xAudio( xNode, UNO_QUERY_THROW ); + exportAudio( xAudio ); + } + break; + case AnimationNodeType::COMMAND: + { + Reference< XCommand > xCommand( xNode, UNO_QUERY_THROW ); + exportCommand( xCommand ); + } + break; + default: + OSL_FAIL( "xmloff::AnimationsExporterImpl::exportNode(), invalid AnimationNodeType!" ); + } + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } + + // if something goes wrong, its always a good idea to clear the attribute list + mxExport->ClearAttrList(); +} + +void AnimationsExporterImpl::exportContainer( const Reference< XTimeContainer >& xContainer, sal_Int16 nContainerNodeType ) +{ + try + { + const sal_Int32 nNodeType = xContainer->getType(); + + if( nNodeType == AnimationNodeType::ITERATE ) + { + OUStringBuffer sTmp; + Reference< XIterateContainer > xIter( xContainer, UNO_QUERY_THROW ); + + Any aTemp( xIter->getTarget() ); + if( aTemp.hasValue() ) + { + convertTarget( sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_TARGETELEMENT, sTmp.makeStringAndClear() ); + } + + sal_Int16 nTemp = xIter->getSubItem(); + if( nTemp ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_SubItem ); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_SUB_ITEM, sTmp.makeStringAndClear() ); + } + + nTemp = xIter->getIterateType(); + if( nTemp ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_IterateType ); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_ITERATE_TYPE, sTmp.makeStringAndClear() ); + } + + double fTemp = xIter->getIterateInterval(); + if( fTemp ) + { + OUStringBuffer buf; + ::sax::Converter::convertDuration(buf, fTemp / (24*60*60)); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, + XML_ITERATE_INTERVAL, buf.makeStringAndClear()); + } + } + + XMLTokenEnum eElementToken; + switch( nNodeType ) + { + case AnimationNodeType::PAR: eElementToken = XML_PAR; break; + case AnimationNodeType::SEQ: eElementToken = XML_SEQ; break; + case AnimationNodeType::ITERATE:eElementToken = XML_ITERATE; break; + default: + OSL_FAIL( "xmloff::AnimationsExporterImpl::exportContainer(), invalid TimeContainerType!" ); + return; + } + SvXMLElementExport aElement( *mxExport, XML_NAMESPACE_ANIMATION, eElementToken, true, true ); + + if( nContainerNodeType == EffectNodeType::TIMING_ROOT ) + exportTransitionNode(); + + Reference< XEnumerationAccess > xEnumerationAccess( xContainer, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW ); + while( xEnumeration->hasMoreElements() ) + { + Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); + exportNode( xChildNode ); + } + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void AnimationsExporterImpl::exportAnimate( const Reference< XAnimate >& xAnimate ) +{ + try + { + const sal_Int16 nNodeType = xAnimate->getType(); + + OUStringBuffer sTmp; + sal_Int16 nTemp; + bool bTemp; + + Any aTemp( xAnimate->getTarget() ); + if( aTemp.hasValue() ) + { + convertTarget( sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_TARGETELEMENT, sTmp.makeStringAndClear() ); + } + + nTemp = xAnimate->getSubItem(); + if( nTemp ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_SubItem ); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_SUB_ITEM, sTmp.makeStringAndClear() ); + } + + XMLTokenEnum eAttributeName = XML_TOKEN_INVALID; + + if( nNodeType == AnimationNodeType::TRANSITIONFILTER ) + { + eAttributeName = XML_TRANSITIONFILTER; + } + else if( nNodeType == AnimationNodeType::ANIMATETRANSFORM ) + { + eAttributeName = XML_ANIMATETRANSFORM; + } + else if( nNodeType == AnimationNodeType::ANIMATEMOTION ) + { + eAttributeName = XML_ANIMATEMOTION; + } + else if( nNodeType == AnimationNodeType::ANIMATEPHYSICS ) + { + eAttributeName = XML_ANIMATEPHYSICS; + } + else + { + OUString sTemp( xAnimate->getAttributeName() ); + if( !sTemp.isEmpty() ) + { + const struct ImplAttributeNameConversion* p = getAnimationAttributeNamesConversionList(); + while( p->mpAPIName ) + { + if( sTemp.equalsAscii( p->mpAPIName ) ) + { + sTemp = GetXMLToken( p->meXMLToken ); + eAttributeName = p->meXMLToken; + break; + } + + p++; + } + + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_ATTRIBUTENAME, sTemp ); + } + else + { + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_ATTRIBUTENAME, "invalid" ); + } + } + + Sequence< Any > aValues( xAnimate->getValues() ); + if( aValues.hasElements() ) + { + aTemp <<= aValues; + convertValue( eAttributeName, sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_VALUES, sTmp.makeStringAndClear() ); + } + else + { + aTemp = xAnimate->getFrom(); + if( aTemp.hasValue() ) + { + convertValue( eAttributeName, sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_FROM, sTmp.makeStringAndClear() ); + } + + aTemp = xAnimate->getBy(); + if( aTemp.hasValue() ) + { + convertValue( eAttributeName, sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_BY, sTmp.makeStringAndClear() ); + } + + aTemp = xAnimate->getTo(); + if( aTemp.hasValue() ) + { + convertValue( eAttributeName, sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_TO, sTmp.makeStringAndClear() ); + } + } + + if(nNodeType != AnimationNodeType::SET) + { + const Sequence< double > aKeyTimes( xAnimate->getKeyTimes() ); + if( aKeyTimes.hasElements() ) + { + for( const auto& rKeyTime : aKeyTimes ) + { + if( !sTmp.isEmpty() ) + sTmp.append( ';' ); + + sTmp.append( rKeyTime ); + } + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_KEYTIMES, sTmp.makeStringAndClear() ); + } + + OUString sTemp( xAnimate->getFormula() ); + if( !sTemp.isEmpty() ) + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_FORMULA, sTemp ); + + if( (nNodeType != AnimationNodeType::TRANSITIONFILTER) && + (nNodeType != AnimationNodeType::AUDIO ) ) + { + // calcMode = "discrete | linear | paced | spline" + nTemp = xAnimate->getCalcMode(); + if( ((nNodeType == AnimationNodeType::ANIMATEMOTION ) && (nTemp != AnimationCalcMode::PACED)) || + ((nNodeType != AnimationNodeType::ANIMATEMOTION ) && (nTemp != AnimationCalcMode::LINEAR)) ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_CalcMode ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_CALCMODE, sTmp.makeStringAndClear() ); + } + + bTemp = xAnimate->getAccumulate(); + if( bTemp ) + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_ACCUMULATE, XML_SUM ); + + nTemp = xAnimate->getAdditive(); + if( nTemp != AnimationAdditiveMode::REPLACE ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_AdditiveMode ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_ADDITIVE, sTmp.makeStringAndClear() ); + } + } + + const Sequence< TimeFilterPair > aTimeFilter( xAnimate->getTimeFilter() ); + if( aTimeFilter.hasElements() ) + { + for( const auto& rPair : aTimeFilter ) + { + if( !sTmp.isEmpty() ) + sTmp.append( ';' ); + + sTmp.append(OUString::number(rPair.Time) + "," + OUString::number(rPair.Progress)); + } + + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_KEYSPLINES, sTmp.makeStringAndClear() ); + } + } + + XMLTokenEnum eElementToken = XML_ANIMATE; + + switch( nNodeType ) + { + case AnimationNodeType::ANIMATE: + eElementToken = XML_ANIMATE; + break; + + case AnimationNodeType::SET: + eElementToken = XML_SET; + break; + + case AnimationNodeType::ANIMATEMOTION: + { + eElementToken = XML_ANIMATEMOTION; + + Reference< XAnimateMotion > xAnimateMotion( xAnimate, UNO_QUERY_THROW ); + + aTemp = xAnimateMotion->getPath(); + if( aTemp.hasValue() ) + { + convertPath( sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SVG, XML_PATH, sTmp.makeStringAndClear() ); + } + + // TODO: origin = ( parent | layout ) + aTemp = xAnimateMotion->getOrigin(); + } + break; + + case AnimationNodeType::ANIMATEPHYSICS: + { + eElementToken = XML_ANIMATEPHYSICS; + double fTemp = 0; + + Reference< XAnimatePhysics > xAnimatePhysics( xAnimate, UNO_QUERY_THROW ); + aTemp = xAnimatePhysics->getStartVelocityX(); + if( aTemp.hasValue() ) + { + aTemp >>= fTemp; + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_LO_EXT, XML_PHYSICS_ANIMATION_START_VELOCITY_X, sTmp.makeStringAndClear() ); + } + + aTemp = xAnimatePhysics->getStartVelocityY(); + if( aTemp.hasValue() ) + { + aTemp >>= fTemp; + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_LO_EXT, XML_PHYSICS_ANIMATION_START_VELOCITY_Y, sTmp.makeStringAndClear() ); + } + + aTemp = xAnimatePhysics->getDensity(); + if( aTemp.hasValue() ) + { + aTemp >>= fTemp; + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_LO_EXT, XML_PHYSICS_ANIMATION_DENSITY, sTmp.makeStringAndClear() ); + } + + aTemp = xAnimatePhysics->getBounciness(); + if( aTemp.hasValue() ) + { + aTemp >>= fTemp; + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_LO_EXT, XML_PHYSICS_ANIMATION_BOUNCINESS, sTmp.makeStringAndClear() ); + } + } + break; + + case AnimationNodeType::ANIMATECOLOR: + { + eElementToken = XML_ANIMATECOLOR; + + Reference< XAnimateColor > xAnimateColor( xAnimate, UNO_QUERY_THROW ); + + nTemp = xAnimateColor->getColorInterpolation(); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_COLOR_INTERPOLATION, (nTemp == AnimationColorSpace::RGB) ? XML_RGB : XML_HSL ); + + bTemp = xAnimateColor->getDirection(); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_COLOR_INTERPOLATION_DIRECTION, bTemp ? XML_CLOCKWISE : XML_COUNTER_CLOCKWISE ); + } + break; + + case AnimationNodeType::ANIMATETRANSFORM: + { + eElementToken = XML_ANIMATETRANSFORM; + + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_ATTRIBUTENAME, XML_TRANSFORM ); + + Reference< XAnimateTransform > xTransform( xAnimate, UNO_QUERY_THROW ); + nTemp = xTransform->getTransformType(); + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_TransformType ); + mxExport->AddAttribute( XML_NAMESPACE_SVG, XML_TYPE, sTmp.makeStringAndClear() ); + } + break; + + case AnimationNodeType::TRANSITIONFILTER: + { + Reference< XTransitionFilter > xTransitionFilter( xAnimate, UNO_QUERY ); + eElementToken = XML_TRANSITIONFILTER; + + sal_Int16 nTransition = xTransitionFilter->getTransition(); + SvXMLUnitConverter::convertEnum( sTmp, nTransition, aAnimations_EnumMap_TransitionType ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_TYPE, sTmp.makeStringAndClear() ); + + sal_Int16 nSubtype = xTransitionFilter->getSubtype(); + if( nSubtype != TransitionSubType::DEFAULT ) + { + SvXMLUnitConverter::convertEnum( sTmp, nSubtype, aAnimations_EnumMap_TransitionSubType ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_SUBTYPE, sTmp.makeStringAndClear() ); + } + + bTemp = xTransitionFilter->getMode(); + if( !bTemp ) + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_MODE, XML_OUT ); + + bTemp = xTransitionFilter->getDirection(); + if( !bTemp ) + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_DIRECTION, XML_REVERSE ); + + if( (nTransition == TransitionType::FADE) && ((nSubtype == TransitionSubType::FADETOCOLOR) || (nSubtype == TransitionSubType::FADEFROMCOLOR) )) + { + nTemp = xTransitionFilter->getFadeColor(); + ::sax::Converter::convertColor( sTmp, nTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_FADECOLOR, sTmp.makeStringAndClear() ); + } + } + break; + } + + if( eElementToken == XML_ANIMATEPHYSICS ) // not a standard should use the extension namespace + { + SvXMLElementExport aElement( *mxExport, XML_NAMESPACE_LO_EXT, eElementToken, true, true ); + } + else + { + SvXMLElementExport aElement( *mxExport, XML_NAMESPACE_ANIMATION, eElementToken, true, true ); + } + + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void AnimationsExporterImpl::exportAudio( const Reference< XAudio >& xAudio ) +{ + if( !xAudio.is() ) + return; + + try + { + OUString aSourceURL; + xAudio->getSource() >>= aSourceURL; + if( !aSourceURL.isEmpty() ) + mxExport->AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, mxExport->GetRelativeReference( aSourceURL ) ); + + const double fVolume = xAudio->getVolume(); + if( fVolume != 1.0 ) + { + OUStringBuffer sTmp; + ::sax::Converter::convertDouble( sTmp, fVolume ); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_AUDIO_LEVEL, sTmp.makeStringAndClear() ); + } + + /* todo? + sal_Int32 nEndAfterSlide = 0; + xAudio->getEndAfterSlide() >>= nEndAfterSlide; + if( nEndAfterSlide != 0 ) + mxExport->AddAttribute( ); + */ + SvXMLElementExport aElement( *mxExport, XML_NAMESPACE_ANIMATION, XML_AUDIO, true, true ); + + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void AnimationsExporterImpl::exportCommand( const Reference< XCommand >& xCommand ) +{ + if( !xCommand.is() ) + return; + + try + { + OUStringBuffer sTmp; + Any aTemp( xCommand->getTarget() ); + if( aTemp.hasValue() ) + { + convertTarget( sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_TARGETELEMENT, sTmp.makeStringAndClear() ); + } + + sal_Int16 nCommand = xCommand->getCommand(); + SvXMLUnitConverter::convertEnum( sTmp, nCommand, aAnimations_EnumMap_Command ); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_COMMAND, sTmp.makeStringAndClear() ); + + // todo virtual css::uno::Any SAL_CALL getParameter() throw (css::uno::RuntimeException) = 0; + + SvXMLElementExport aElement( *mxExport, XML_NAMESPACE_ANIMATION, XML_COMMAND, true, true ); + + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +Reference< XInterface > AnimationsExporterImpl::getParagraphTarget( const ParagraphTarget& pTarget ) +{ + try + { + Reference< XEnumerationAccess > xParaEnumAccess( pTarget.Shape, UNO_QUERY_THROW ); + + Reference< XEnumeration > xEnumeration( xParaEnumAccess->createEnumeration(), css::uno::UNO_SET_THROW ); + sal_Int32 nParagraph = pTarget.Paragraph; + + while( xEnumeration->hasMoreElements() ) + { + Reference< XInterface > xRef( xEnumeration->nextElement(), UNO_QUERY ); + if( nParagraph-- == 0 ) + return xRef; + } + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } + + Reference< XInterface > xRef; + return xRef; +} + +void AnimationsExporterImpl::convertPath( OUStringBuffer& sTmp, const Any& rPath ) +{ + OUString aStr; + rPath >>= aStr; + + sTmp = aStr; +} + +void AnimationsExporterImpl::convertValue( XMLTokenEnum eAttributeName, OUStringBuffer& sTmp, const Any& rValue ) const +{ + if( !rValue.hasValue() ) + return; + + if( auto pValuePair = o3tl::tryAccess<ValuePair>(rValue) ) + { + OUStringBuffer sTmp2; + convertValue( eAttributeName, sTmp, pValuePair->First ); + sTmp.append( ',' ); + convertValue( eAttributeName, sTmp2, pValuePair->Second ); + sTmp.append( sTmp2 ); + } + else if( auto pSequence = o3tl::tryAccess<Sequence<Any>>(rValue) ) + { + const sal_Int32 nLength = pSequence->getLength(); + sal_Int32 nElement; + const Any* pAny = pSequence->getConstArray(); + + OUStringBuffer sTmp2; + + for( nElement = 0; nElement < nLength; nElement++, pAny++ ) + { + if( !sTmp.isEmpty() ) + sTmp.append( ';' ); + convertValue( eAttributeName, sTmp2, *pAny ); + sTmp.append( sTmp2 ); + sTmp2.setLength(0); + } + } + else + { + sal_Int32 nType; + + switch( eAttributeName ) + { + case XML_X: + case XML_Y: + case XML_WIDTH: + case XML_HEIGHT: + case XML_ANIMATETRANSFORM: + case XML_ANIMATEMOTION: + case XML_ANIMATEPHYSICS: + { + if( auto aString = o3tl::tryAccess<OUString>(rValue) ) + { + sTmp.append( *aString ); + } + else if( auto x = o3tl::tryAccess<double>(rValue) ) + { + sTmp.append( *x ); + } + else + { + OSL_FAIL( "xmloff::AnimationsExporterImpl::convertValue(), invalid value type!" ); + } + return; + } + + case XML_SKEWX: + case XML_ROTATE: nType = XML_TYPE_DOUBLE; break; + case XML_TEXT_ROTATION_ANGLE: nType = XML_TYPE_NUMBER16; break; + case XML_FILL_COLOR: + case XML_STROKE_COLOR: + case XML_DIM: + case XML_COLOR: nType = XML_TYPE_COLOR; break; + case XML_FILL: nType = XML_SD_TYPE_FILLSTYLE; break; + case XML_STROKE: nType = XML_SD_TYPE_STROKE; break; + case XML_FONT_WEIGHT: nType = XML_TYPE_TEXT_WEIGHT; break; + case XML_FONT_STYLE: nType = XML_TYPE_TEXT_POSTURE; break; + case XML_TEXT_UNDERLINE: nType = XML_TYPE_TEXT_UNDERLINE_STYLE; break; + case XML_FONT_SIZE: nType = XML_TYPE_DOUBLE_PERCENT; break; + case XML_VISIBILITY: nType = XML_SD_TYPE_PRESPAGE_VISIBILITY; break; + case XML_OPACITY: + case XML_TRANSITIONFILTER: nType = XML_TYPE_DOUBLE; break; + default: + OSL_FAIL( "xmloff::AnimationsExporterImpl::convertValue(), invalid AttributeName!" ); + nType = XML_TYPE_STRING; + } + + //const XMLPropertyHandler* pHandler = static_cast<SdXMLExport*>(&mrExport)->GetSdPropHdlFactory()->GetPropertyHandler( nType ); + const XMLPropertyHandler* pHandler = mxSdPropHdlFactory->GetPropertyHandler( nType ); + if( pHandler ) + { + OUString aString; + pHandler->exportXML( aString, rValue, mxExport->GetMM100UnitConverter() ); + sTmp.append( aString ); + } + } +} + +void AnimationsExporterImpl::convertTiming( OUStringBuffer& sTmp, const Any& rValue ) const +{ + if( !rValue.hasValue() ) + return; + + if( auto pSequence = o3tl::tryAccess<Sequence<Any>>(rValue) ) + { + const sal_Int32 nLength = pSequence->getLength(); + sal_Int32 nElement; + const Any* pAny = pSequence->getConstArray(); + + OUStringBuffer sTmp2; + + for( nElement = 0; nElement < nLength; nElement++, pAny++ ) + { + if( !sTmp.isEmpty() ) + sTmp.append( ';' ); + convertTiming( sTmp2, *pAny ); + sTmp.append( sTmp2 ); + sTmp2.setLength(0); + } + } + else if( auto x = o3tl::tryAccess<double>(rValue) ) + { + sTmp.append( *x ); + sTmp.append( 's'); + } + else if( auto pTiming = o3tl::tryAccess<Timing>(rValue) ) + { + sTmp.append( GetXMLToken( (*pTiming == Timing_MEDIA) ? XML_MEDIA : XML_INDEFINITE ) ); + } + else if( auto pEvent = o3tl::tryAccess<Event>(rValue) ) + { + OUStringBuffer sTmp2; + + if( pEvent->Trigger != EventTrigger::NONE ) + { + if( pEvent->Source.hasValue() ) + { + convertTarget( sTmp, pEvent->Source ); + sTmp.append( '.' ); + } + + SvXMLUnitConverter::convertEnum( sTmp2, pEvent->Trigger, aAnimations_EnumMap_EventTrigger ); + + sTmp.append( sTmp2 ); + sTmp2.setLength(0); + } + + if( pEvent->Offset.hasValue() ) + { + convertTiming( sTmp2, pEvent->Offset ); + + if( !sTmp.isEmpty() ) + sTmp.append( '+' ); + + sTmp.append( sTmp2 ); + sTmp2.setLength(0); + } + } + else + { + OSL_FAIL( "xmloff::AnimationsExporterImpl::convertTiming(), invalid value type!" ); + } +} + +void AnimationsExporterImpl::convertTarget( OUStringBuffer& sTmp, const Any& rTarget ) const +{ + if( !rTarget.hasValue() ) + return; + + Reference< XInterface > xRef; + + if( !(rTarget >>= xRef) ) + { + if( auto pt = o3tl::tryAccess<ParagraphTarget>(rTarget) ) + { + xRef = getParagraphTarget( *pt ); + } + } + + SAL_WARN_IF( !xRef.is(), "xmloff", "xmloff::AnimationsExporterImpl::convertTarget(), invalid target type!" ); + if( xRef.is() ) + { + const OUString& rIdentifier = mxExport->getInterfaceToIdentifierMapper().getIdentifier(xRef); + if( !rIdentifier.isEmpty() ) + sTmp.append( rIdentifier ); + } +} + +void AnimationsExporterImpl::prepareValue( const Any& rValue ) +{ + if( !rValue.hasValue() ) + return; + + if( auto pValuePair = o3tl::tryAccess<ValuePair>(rValue) ) + { + prepareValue( pValuePair->First ); + prepareValue( pValuePair->Second ); + } + else if( auto pSequence = o3tl::tryAccess<Sequence<Any>>(rValue) ) + { + const sal_Int32 nLength = pSequence->getLength(); + sal_Int32 nElement; + const Any* pAny = pSequence->getConstArray(); + + for( nElement = 0; nElement < nLength; nElement++, pAny++ ) + prepareValue( *pAny ); + } + else if( rValue.getValueTypeClass() == css::uno::TypeClass_INTERFACE ) + { + Reference< XInterface> xRef( rValue, UNO_QUERY ); + if( xRef.is() ) + mxExport->getInterfaceToIdentifierMapper().registerReference( xRef ); + } + else if( auto pt = o3tl::tryAccess<ParagraphTarget>(rValue) ) + { + Reference< XInterface> xRef( getParagraphTarget( *pt ) ); + if( xRef.is() ) + mxExport->getInterfaceToIdentifierMapper().registerReference( xRef ); + } + else if( auto pEvent = o3tl::tryAccess<Event>(rValue) ) + { + prepareValue( pEvent->Source ); + } +} + +AnimationsExporter::AnimationsExporter( SvXMLExport& rExport, const Reference< XPropertySet >& xPageProps ) + : mpImpl( new AnimationsExporterImpl( rExport, xPageProps ) ) +{ +} + +AnimationsExporter::~AnimationsExporter() +{ +} + +void AnimationsExporter::prepare( const Reference< XAnimationNode >& xRootNode ) +{ + try + { + if( xRootNode.is() ) + { + mpImpl->prepareTransitionNode(); + mpImpl->prepareNode( xRootNode ); + } + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void AnimationsExporter::exportAnimations( const Reference< XAnimationNode >& xRootNode ) +{ + try + { + if( xRootNode.is() ) + { + bool bHasEffects = mpImpl->mbHasTransition; + + if( !bHasEffects ) + { + // first check if there are no animations + Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW ); + if( xEnumeration->hasMoreElements() ) + { + // first child node may be an empty main sequence, check this + Reference< XAnimationNode > xMainNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); + Reference< XEnumerationAccess > xMainEnumerationAccess( xMainNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xMainEnumeration( xMainEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW ); + + // only export if the main sequence is not empty or if there are additional + // trigger sequences + bHasEffects = xMainEnumeration->hasMoreElements() || xEnumeration->hasMoreElements(); + } + } + + if( bHasEffects ) + mpImpl->exportNode( xRootNode ); + } + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/animationimport.cxx b/xmloff/source/draw/animationimport.cxx new file mode 100644 index 0000000000..519c3288cd --- /dev/null +++ b/xmloff/source/draw/animationimport.cxx @@ -0,0 +1,1356 @@ +/* -*- 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 <memory> +#include <xmloff/unointerfacetouniqueidentifiermapper.hxx> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/animations/AnimationTransformType.hpp> +#include <com/sun/star/animations/XAnimationNodeSupplier.hpp> +#include <com/sun/star/animations/AnimationNodeType.hpp> +#include <com/sun/star/animations/SequenceTimeContainer.hpp> +#include <com/sun/star/animations/XIterateContainer.hpp> +#include <com/sun/star/animations/XAnimateMotion.hpp> +#include <com/sun/star/animations/XAnimatePhysics.hpp> +#include <com/sun/star/animations/XAnimateColor.hpp> +#include <com/sun/star/animations/XAnimateTransform.hpp> +#include <com/sun/star/animations/XTransitionFilter.hpp> +#include <com/sun/star/animations/XCommand.hpp> +#include <com/sun/star/animations/XAudio.hpp> +#include <com/sun/star/animations/ValuePair.hpp> +#include <com/sun/star/animations/AnimationColorSpace.hpp> +#include <com/sun/star/presentation/EffectPresetClass.hpp> +#include <com/sun/star/animations/Timing.hpp> +#include <com/sun/star/animations/Event.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/io/WrongFormatException.hpp> +#include <com/sun/star/xml/sax/XFastAttributeList.hpp> +#include <com/sun/star/text/XTextCursor.hpp> +#include <com/sun/star/text/XTextRangeCompare.hpp> +#include <com/sun/star/presentation/ParagraphTarget.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/animations/EventTrigger.hpp> +#include <com/sun/star/presentation/EffectCommands.hpp> +#include <com/sun/star/util/Duration.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/string.hxx> + +#include <rtl/math.h> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <o3tl/string_view.hxx> +#include <sax/tools/converter.hxx> + +#include <vector> + +#include <xmloff/xmltypes.hxx> +#include "sdpropls.hxx" +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlprhdl.hxx> +#include <xmlsdtypes.hxx> + +#include <animations.hxx> +#include <animationimport.hxx> + +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::animations; +using namespace ::com::sun::star::presentation; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +using ::com::sun::star::xml::sax::XFastAttributeList; +using ::com::sun::star::beans::NamedValue; +using ::com::sun::star::text::XTextRange; +using ::com::sun::star::text::XTextCursor; +using ::com::sun::star::text::XTextRangeCompare; +using ::com::sun::star::container::XEnumerationAccess; +using ::com::sun::star::container::XEnumeration; +using ::com::sun::star::lang::XInitialization; + +static OUString +lcl_GetMediaReference(SvXMLImport const& rImport, OUString const& rURL) +{ + if (rImport.IsPackageURL(rURL)) + return "vnd.sun.star.Package:" + rURL; + + return rImport.GetAbsoluteReference(rURL); +} + +namespace xmloff +{ + +class AnimationsImportHelperImpl +{ +private: + SvXMLImport& mrImport; + +public: + explicit AnimationsImportHelperImpl( SvXMLImport& rImport ); + + Any convertValue( XMLTokenEnum eAttributeName, const OUString& rValue ); + Sequence< Any > convertValueSequence( XMLTokenEnum eAttributeName, std::u16string_view rValue ); + + Any convertTarget( const OUString& rValue ); + static Any convertPath( const OUString& rValue ); + Any convertTiming( const OUString& rValue ); + static Sequence< double > convertKeyTimes( std::string_view rValue ); + static Sequence< TimeFilterPair > convertTimeFilter( std::string_view rValue ); +}; + +AnimationsImportHelperImpl::AnimationsImportHelperImpl( SvXMLImport& rImport ) +: mrImport( rImport ) +{ +} + +static bool isDouble( std::string_view rValue ) +{ + sal_Int32 nLength = rValue.size(); + const char * pStr = rValue.data(); + while( nLength ) + { + if( (*pStr >= '0' && *pStr <= '9') || *pStr == '-' || *pStr == '.' || *pStr == '+' || *pStr == 'e' || *pStr == 'E' ) + { + pStr++; + nLength--; + } + else + { + return false; + } + } + + return true; +} + +static bool isTime( const OUString& rValue ) +{ + sal_Int32 nLength = rValue.getLength(); + const sal_Unicode * pStr; + for( pStr = rValue.getStr(); nLength; pStr++, nLength-- ) + { + if( !( (*pStr >= '0' && *pStr <= '9') || *pStr == '-' || *pStr == '.' || *pStr == '+' || *pStr == 'e' || *pStr == 'E' ) ) + break; + } + + // return true if this is a double (if someone forgot the 's' we silently ignore it) + // or if it's a double that ends with a 's' or 'S' + return (nLength == 0) || ((*pStr == 's' || *pStr == 'S') && (nLength == 1)); +} + +Any AnimationsImportHelperImpl::convertTarget( const OUString& rValue ) +{ + try + { + Reference< XInterface > xRef( mrImport.getInterfaceToIdentifierMapper().getReference( rValue ) ); + + Reference< XShape > _xShape( xRef, UNO_QUERY ); + if( _xShape.is() ) + return Any( _xShape ); + + Reference< XTextCursor > xTextCursor( xRef, UNO_QUERY ); + if( xTextCursor.is() ) + { + Reference< XTextRange > xStart( xTextCursor->getStart() ), xRange; + Reference< XShape > xShape( xTextCursor->getText(), UNO_QUERY_THROW ); + Reference< XTextRangeCompare > xTextRangeCompare( xShape, UNO_QUERY_THROW ); + + Reference< XEnumerationAccess > xParaEnumAccess( xShape, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration( xParaEnumAccess->createEnumeration(), UNO_SET_THROW ); + sal_Int16 nParagraph = 0; + + while( xEnumeration->hasMoreElements() ) + { + xEnumeration->nextElement() >>= xRange; + + // break if start of selection is prior to end of current paragraph + if( xRange.is() && (xTextRangeCompare->compareRegionEnds( xStart, xRange ) >= 0 ) ) + { + return Any( ParagraphTarget( xShape, nParagraph ) ); + } + + nParagraph++; + } + } + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } + + Any aAny; + return aAny; +} + +Any AnimationsImportHelperImpl::convertValue( XMLTokenEnum eAttributeName, const OUString& rValue ) +{ + sal_Int32 nCommaPos = -1, nPos; + sal_Int32 nOpenBrackets = 0; + for( nPos = 0; (nPos < rValue.getLength()) && (nCommaPos == -1); nPos++ ) + { + switch( rValue[nPos] ) + { + case ',': + if( nOpenBrackets == 0 ) + nCommaPos = nPos; + break; + case '(': + case '[': + case '{': + nOpenBrackets++; + break; + case ')': + case ']': + case '}': + nOpenBrackets--; + break; + } + } + + if( nCommaPos >= 0 ) + { + ValuePair aPair; + aPair.First = convertValue( eAttributeName, rValue.copy( 0, nCommaPos ) ); + aPair.Second = convertValue( eAttributeName, rValue.copy( nCommaPos+1 ) ); + return Any( aPair ); + } + else + { + Any aAny; + sal_Int32 nType = XML_TYPE_STRING; + + if( rValue.getLength() ) switch( eAttributeName ) + { + case XML_X: + case XML_Y: + case XML_WIDTH: + case XML_HEIGHT: + case XML_TRANSLATE: + { + return Any( rValue ); + } + + case XML_SCALE: + case XML_SKEWY: + case XML_SKEWX: + case XML_OPACITY: + case XML_ROTATE: nType = XML_TYPE_DOUBLE; break; + case XML_TEXT_ROTATION_ANGLE:nType = XML_TYPE_TEXT_ROTATION_ANGLE; break; + case XML_FILL_COLOR: + case XML_STROKE_COLOR: + case XML_DIM: + case XML_COLOR: nType = XML_TYPE_COLOR; break; + case XML_FILL: nType = XML_SD_TYPE_FILLSTYLE; break; + case XML_STROKE: nType = XML_SD_TYPE_STROKE; break; + case XML_FONT_WEIGHT: nType = XML_TYPE_TEXT_WEIGHT; break; + case XML_FONT_STYLE: nType = XML_TYPE_TEXT_POSTURE; break; + case XML_TEXT_UNDERLINE: nType = XML_TYPE_TEXT_UNDERLINE_STYLE; break; + case XML_FONT_SIZE: nType = XML_TYPE_DOUBLE_PERCENT; break; + case XML_VISIBILITY: nType = XML_SD_TYPE_PRESPAGE_VISIBILITY; break; + + default: + if( !rValue.isEmpty() ) + aAny <<= rValue; + return aAny; + } + + const XMLPropertyHandler* pHandler = mrImport.GetShapeImport()->GetSdPropHdlFactory()->GetPropertyHandler( nType ); + if( pHandler ) + pHandler->importXML( rValue, aAny, mrImport.GetMM100UnitConverter() ); + + return aAny; + } +} + +Sequence< Any > AnimationsImportHelperImpl::convertValueSequence( XMLTokenEnum eAttributeName, std::u16string_view rValue ) +{ + Sequence< Any > aValues; + + const sal_Int32 nElements { comphelper::string::getTokenCount(rValue, ';') }; + if ( nElements>0 ) + { + // prepare the sequence + aValues.realloc( nElements ); + + // fill the sequence + Any* pValues = aValues.getArray(); + for (sal_Int32 nIndex = 0; nIndex >= 0; ) + *pValues++ = convertValue( eAttributeName, OUString(o3tl::getToken(rValue, 0, ';', nIndex )) ); + } + + return aValues; +} + +Any AnimationsImportHelperImpl::convertTiming( const OUString& rValue ) +{ + Any aAny; + + const sal_Int32 nElements { comphelper::string::getTokenCount(rValue, ';') }; + if ( nElements>0 ) + { + if( nElements == 1 ) + { + if( IsXMLToken( rValue, XML_MEDIA ) ) + { + aAny <<= Timing_MEDIA; + } + else if( IsXMLToken( rValue, XML_INDEFINITE ) ) + { + aAny <<= Timing_INDEFINITE; + } + else if( isTime( rValue ) ) + { + aAny <<= rValue.toDouble(); + } + else + { + Event aEvent; + aEvent.Repeat = 0; + aEvent.Trigger = 0; + + OUString aEventTrigger; + + sal_Int32 nPos = rValue.indexOf( '+' ); + if( nPos == -1 ) + { + aEventTrigger = rValue; + } + else + { + aEventTrigger = rValue.copy( 0, nPos ); + + // convert offset + aEvent.Offset = convertTiming( rValue.copy( nPos + 1 ) ); + } + + nPos = aEventTrigger.indexOf( '.' ); + if( nPos != -1 ) + { + aEvent.Source <<= mrImport.getInterfaceToIdentifierMapper().getReference( aEventTrigger.copy( 0, nPos ) ); + aEventTrigger = aEventTrigger.copy( nPos + 1 ); + } + + sal_Int16 nEnum; + if( SvXMLUnitConverter::convertEnum( nEnum, aEventTrigger, aAnimations_EnumMap_EventTrigger ) ) + { + aEvent.Trigger = nEnum; + } + else + { + OSL_FAIL("AnimationsImportHelperImpl::convertTiming(), unknown event trigger!"); + } + + aAny <<= aEvent; + } + } + else + { + // fill the sequence + Sequence< Any > aValues( nElements ); + Any* pValues = aValues.getArray(); + for (sal_Int32 nIndex = 0; nIndex >= 0; ) + *pValues++ = convertTiming( rValue.getToken( 0, ';', nIndex ) ); + + aAny <<= aValues; + } + } + return aAny; +} + +Sequence< double > AnimationsImportHelperImpl::convertKeyTimes( std::string_view rValue ) +{ + const sal_Int32 nElements { comphelper::string::getTokenCount(rValue, ';') }; + + Sequence< double > aKeyTimes( nElements ); + + if( nElements ) + { + double* pValues = aKeyTimes.getArray(); + for (sal_Int32 nIndex = 0; nIndex >= 0; ) + *pValues++ = o3tl::toDouble(o3tl::getToken(rValue, 0, ';', nIndex )); + } + + return aKeyTimes; +} + +Sequence< TimeFilterPair > AnimationsImportHelperImpl::convertTimeFilter( std::string_view rValue ) +{ + const sal_Int32 nElements { comphelper::string::getTokenCount(rValue, ';') }; + + Sequence< TimeFilterPair > aTimeFilter( nElements ); + + if( nElements ) + { + TimeFilterPair* pValues = aTimeFilter.getArray(); + for (sal_Int32 nIndex = 0; nIndex >= 0; ) + { + const std::string_view aToken( o3tl::getToken(rValue, 0, ';', nIndex ) ); + + size_t nPos = aToken.find( ',' ); + if( nPos != std::string_view::npos ) + { + pValues->Time = rtl_math_stringToDouble( + aToken.data(), aToken.data() + nPos, '.', 0, nullptr, nullptr); + pValues->Progress = rtl_math_stringToDouble( + aToken.data() + nPos + 1, aToken.data() + aToken.size(), '.', 0, + nullptr, nullptr); + } + pValues++; + } + } + + return aTimeFilter; +} + +Any AnimationsImportHelperImpl::convertPath( const OUString& rValue ) +{ + return Any( rValue ); +} + + +AnimationNodeContext::AnimationNodeContext( + const Reference< XAnimationNode >& xParentNode, + SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + const std::shared_ptr<AnimationsImportHelperImpl>& pHelper ) +: SvXMLImportContext(rImport), + mpHelper( pHelper ) +{ + bool bRootContext = !pHelper; + try + { + if( bRootContext ) + { + mpHelper = std::make_shared<AnimationsImportHelperImpl>( rImport ); + mxNode = xParentNode; + } + else + { + sal_Int16 nPresetClass = EffectPresetClass::CUSTOM; + + const char* pServiceName = nullptr; + + // we see namespace ANIMATION and ANIMATION_OOO and PRESENTATION_OASIS and PRESENTATION_SO52 and PRESENTATION_OOO + switch( nElement & TOKEN_MASK ) + { + case XML_SEQ: + pServiceName = "com.sun.star.animations.SequenceTimeContainer"; break; + case XML_ITERATE: + pServiceName = "com.sun.star.animations.IterateContainer"; break; + case XML_ANIMATE: + pServiceName = "com.sun.star.animations.Animate"; break; + case XML_SET: + pServiceName = "com.sun.star.animations.AnimateSet"; break; + case XML_ANIMATEMOTION: + pServiceName = "com.sun.star.animations.AnimateMotion"; break; + case XML_ANIMATEPHYSICS: + pServiceName = "com.sun.star.animations.AnimatePhysics"; break; + case XML_ANIMATECOLOR: + pServiceName = "com.sun.star.animations.AnimateColor"; break; + case XML_ANIMATETRANSFORM: + pServiceName = "com.sun.star.animations.AnimateTransform"; break; + case XML_TRANSITIONFILTER: + pServiceName = "com.sun.star.animations.TransitionFilter"; break; + case XML_AUDIO: + pServiceName = "com.sun.star.animations.Audio"; break; + case XML_COMMAND: + pServiceName = "com.sun.star.animations.Command"; break; + case XML_PAR: + { + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( (aIter.getToken() & TOKEN_MASK) == XML_PRESET_ID) + { + const OUString& rValue = aIter.toString(); + if ( rValue == "ooo-entrance-random" ) + { + nPresetClass = EffectPresetClass::ENTRANCE; + } + else if ( rValue == "ooo-exit-random" ) + { + nPresetClass = EffectPresetClass::EXIT; + } + + if( nPresetClass != EffectPresetClass::CUSTOM ) + { + pServiceName = "com.sun.star.comp.sd.RandomAnimationNode"; + break; + } + } + } + if( !pServiceName ) + pServiceName = "com.sun.star.animations.ParallelTimeContainer"; + } + break; + default: + SAL_WARN("xmloff", "unexpected token '" + SvXMLImport::getNameFromToken(nElement) + << "' 0x" << std::hex << nElement); + break; + } + + if( pServiceName ) + { + Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + + mxNode.set( + xContext->getServiceManager()->createInstanceWithContext(OUString::createFromAscii(pServiceName), xContext), + UNO_QUERY_THROW ); + + if( nPresetClass != EffectPresetClass::CUSTOM ) + { + Reference< XInitialization > xInit( mxNode, UNO_QUERY_THROW ); + const Any aAny( nPresetClass ); + Sequence< Any > aArgs( &aAny, 1 ) ; + xInit->initialize( aArgs ); + } + + init_node( xAttrList ); + + Reference< XTimeContainer > xParentContainer( xParentNode, UNO_QUERY_THROW ); + xParentContainer->appendChild( mxNode ); + } + } + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void AnimationNodeContext::init_node( const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( !mxNode.is() ) + return; + + try + { + const sal_Int16 nNodeType = mxNode->getType(); + + // query for optional interfaces that are often used later + Reference< XAnimate > xAnimate( mxNode, UNO_QUERY ); + Reference< XCommand > xCommand( mxNode, UNO_QUERY ); + Reference< XTransitionFilter > xTransitionFilter( mxNode, UNO_QUERY ); + Reference< XIterateContainer > xIter( mxNode, UNO_QUERY ); + + std::vector< NamedValue > aUserData; + XMLTokenEnum meAttributeName = XML_TOKEN_INVALID; + OUString aFrom, aBy, aTo, aValues; + bool bHaveXmlId( false ); + OUString sXmlId; + + sal_Int16 nEnum; + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + auto nToken = aIter.getToken(); + switch( nToken ) + { + case XML_ELEMENT(SMIL, XML_BEGIN): + case XML_ELEMENT(SMIL_COMPAT, XML_BEGIN): + case XML_ELEMENT(SMIL_SO52, XML_BEGIN): + { + mxNode->setBegin( mpHelper->convertTiming( aIter.toString() ) ); + } + break; + case XML_ELEMENT(SMIL, XML_DUR): + case XML_ELEMENT(SMIL_COMPAT, XML_DUR): + case XML_ELEMENT(SMIL_SO52, XML_DUR): + { + mxNode->setDuration( mpHelper->convertTiming( aIter.toString() ) ); + } + break; + case XML_ELEMENT(SMIL, XML_END): + case XML_ELEMENT(SMIL_COMPAT, XML_END): + case XML_ELEMENT(SMIL_SO52, XML_END): + { + mxNode->setEnd( mpHelper->convertTiming( aIter.toString() ) ); + } + break; + case XML_ELEMENT(SMIL, XML_FILL): + case XML_ELEMENT(SMIL_COMPAT, XML_FILL): + case XML_ELEMENT(SMIL_SO52, XML_FILL): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_Fill ) ) + mxNode->setFill( nEnum ); + } + break; + case XML_ELEMENT(SMIL, XML_FILLDEFAULT): + case XML_ELEMENT(SMIL_COMPAT, XML_FILLDEFAULT): + case XML_ELEMENT(SMIL_SO52, XML_FILLDEFAULT): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_FillDefault ) ) + mxNode->setFillDefault( nEnum ); + } + break; + case XML_ELEMENT(SMIL, XML_RESTART): + case XML_ELEMENT(SMIL_COMPAT, XML_RESTART): + case XML_ELEMENT(SMIL_SO52, XML_RESTART): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_Restart ) ) + mxNode->setRestart( nEnum ); + } + break; + case XML_ELEMENT(SMIL, XML_RESTARTDEFAULT): + case XML_ELEMENT(SMIL_COMPAT, XML_RESTARTDEFAULT): + case XML_ELEMENT(SMIL_SO52, XML_RESTARTDEFAULT): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_RestartDefault ) ) + mxNode->setRestartDefault( nEnum ); + } + break; + case XML_ELEMENT(SMIL, XML_ACCELERATE): + case XML_ELEMENT(SMIL_COMPAT, XML_ACCELERATE): + case XML_ELEMENT(SMIL_SO52, XML_ACCELERATE): + { + if( isDouble( aIter.toView() ) ) + mxNode->setAcceleration( aIter.toDouble() ); + } + break; + case XML_ELEMENT(SMIL, XML_DECELERATE): + case XML_ELEMENT(SMIL_COMPAT, XML_DECELERATE): + case XML_ELEMENT(SMIL_SO52, XML_DECELERATE): + { + if( isDouble( aIter.toView() ) ) + mxNode->setDecelerate( aIter.toDouble() ); + } + break; + case XML_ELEMENT(SMIL, XML_AUTOREVERSE): + case XML_ELEMENT(SMIL_COMPAT, XML_AUTOREVERSE): + case XML_ELEMENT(SMIL_SO52, XML_AUTOREVERSE): + { + bool bTemp; + if (::sax::Converter::convertBool( bTemp, aIter.toView() )) + mxNode->setAutoReverse( bTemp ); + } + break; + case XML_ELEMENT(SMIL, XML_REPEATCOUNT): + case XML_ELEMENT(SMIL_COMPAT, XML_REPEATCOUNT): + case XML_ELEMENT(SMIL_SO52, XML_REPEATCOUNT): + { + mxNode->setRepeatCount( mpHelper->convertTiming( aIter.toString() ) ); + } + break; + case XML_ELEMENT(SMIL, XML_REPEATDUR): + case XML_ELEMENT(SMIL_COMPAT, XML_REPEATDUR): + case XML_ELEMENT(SMIL_SO52, XML_REPEATDUR): + { + mxNode->setRepeatDuration( mpHelper->convertTiming( aIter.toString() ) ); + } + break; + case XML_ELEMENT(SMIL, XML_ENDSYNC): + case XML_ELEMENT(SMIL_COMPAT, XML_ENDSYNC): + case XML_ELEMENT(SMIL_SO52, XML_ENDSYNC): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_Endsync ) ) + mxNode->setEndSync( Any( nEnum ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_NODE_TYPE): + case XML_ELEMENT(PRESENTATION_SO52, XML_NODE_TYPE): + case XML_ELEMENT(PRESENTATION_OOO, XML_NODE_TYPE): + case XML_ELEMENT(PRESENTATION_OASIS, XML_NODE_TYPE): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_EffectNodeType ) ) + aUserData.emplace_back( GetXMLToken( XML_NODE_TYPE ), Any( nEnum ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_PRESET_ID): + case XML_ELEMENT(PRESENTATION_SO52, XML_PRESET_ID): + case XML_ELEMENT(PRESENTATION_OOO, XML_PRESET_ID): + case XML_ELEMENT(PRESENTATION_OASIS, XML_PRESET_ID): + { + aUserData.emplace_back( GetXMLToken( XML_PRESET_ID ), Any( aIter.toString() ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_PRESET_SUB_TYPE): + case XML_ELEMENT(PRESENTATION_SO52, XML_PRESET_SUB_TYPE): + case XML_ELEMENT(PRESENTATION_OOO, XML_PRESET_SUB_TYPE): + case XML_ELEMENT(PRESENTATION_OASIS, XML_PRESET_SUB_TYPE): + { + aUserData.emplace_back( GetXMLToken( XML_PRESET_SUB_TYPE ), Any( aIter.toString() ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_PRESET_CLASS): + case XML_ELEMENT(PRESENTATION_SO52, XML_PRESET_CLASS): + case XML_ELEMENT(PRESENTATION_OOO, XML_PRESET_CLASS): + case XML_ELEMENT(PRESENTATION_OASIS, XML_PRESET_CLASS): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_EffectPresetClass ) ) + aUserData.emplace_back( GetXMLToken( XML_PRESET_CLASS ), Any( nEnum ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_AFTER_EFFECT): + case XML_ELEMENT(PRESENTATION_SO52, XML_AFTER_EFFECT): + case XML_ELEMENT(PRESENTATION_OOO, XML_AFTER_EFFECT): + { + bool bTemp; + if (::sax::Converter::convertBool( bTemp, aIter.toView() )) + aUserData.emplace_back( GetXMLToken( XML_AFTER_EFFECT ), Any( bTemp ) ); + } + break; + case XML_ELEMENT(XLINK, XML_HREF): + { + if( nNodeType == AnimationNodeType::AUDIO ) + { + Reference< XAudio > xAudio( mxNode, UNO_QUERY_THROW ); + xAudio->setSource( Any(lcl_GetMediaReference(GetImport(), aIter.toString())) ); + break; + } + [[fallthrough]]; + } + case XML_ELEMENT(SMIL, XML_TARGETELEMENT): + case XML_ELEMENT(SMIL_COMPAT, XML_TARGETELEMENT): + case XML_ELEMENT(SMIL_SO52, XML_TARGETELEMENT): + { + Any aTarget( mpHelper->convertTarget( aIter.toString() ) ); + + if( xAnimate.is() ) + { + xAnimate->setTarget( aTarget ); + } + else if( xIter.is() ) + { + xIter->setTarget( aTarget ); + } + else if( xCommand.is() ) + { + xCommand->setTarget( aTarget ); + } + } + break; + + case XML_ELEMENT(ANIMATION, XML_AUDIO_LEVEL): + case XML_ELEMENT(ANIMATION_OOO, XML_AUDIO_LEVEL): + { + if( nNodeType == AnimationNodeType::AUDIO ) + { + if( isDouble( aIter.toView() ) ) + { + Reference< XAudio > xAudio( mxNode, UNO_QUERY_THROW ); + xAudio->setVolume( aIter.toDouble() ); + } + } + } + break; + + case XML_ELEMENT(PRESENTATION, XML_MASTER_ELEMENT): + case XML_ELEMENT(PRESENTATION_SO52, XML_MASTER_ELEMENT): + case XML_ELEMENT(PRESENTATION_OOO, XML_MASTER_ELEMENT): + { + Reference< XAnimationNode > xMaster( GetImport().getInterfaceToIdentifierMapper().getReference( aIter.toString() ), UNO_QUERY ); + aUserData.emplace_back( GetXMLToken( XML_MASTER_ELEMENT ), Any( xMaster ) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_SUB_ITEM): + case XML_ELEMENT(ANIMATION_OOO, XML_SUB_ITEM): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_SubItem ) ) + { + if( xAnimate.is() ) + { + xAnimate->setSubItem( nEnum ); + } + else if( xIter.is() ) + { + xIter->setSubItem( nEnum ); + } + } + } + break; + + case XML_ELEMENT(SMIL, XML_ATTRIBUTENAME): + case XML_ELEMENT(SMIL_COMPAT, XML_ATTRIBUTENAME): + case XML_ELEMENT(SMIL_SO52, XML_ATTRIBUTENAME): + { + if( xAnimate.is() ) + { + OUString aName( aIter.toString() ); + + const struct ImplAttributeNameConversion* p = getAnimationAttributeNamesConversionList(); + while( p->mpAPIName ) + { + if( IsXMLToken( aIter, p->meXMLToken ) ) + { + aName = OUString::createFromAscii( p->mpAPIName ); + meAttributeName = p->meXMLToken; + break; + } + + p++; + } + + xAnimate->setAttributeName( aName ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_VALUES): + case XML_ELEMENT(SMIL_COMPAT, XML_VALUES): + case XML_ELEMENT(SMIL_SO52, XML_VALUES): + { + aValues = aIter.toString(); + } + break; + + case XML_ELEMENT(SMIL, XML_FROM): + case XML_ELEMENT(SMIL_COMPAT, XML_FROM): + case XML_ELEMENT(SMIL_SO52, XML_FROM): + { + aFrom = aIter.toString(); + } + break; + + case XML_ELEMENT(SMIL, XML_BY): + case XML_ELEMENT(SMIL_COMPAT, XML_BY): + case XML_ELEMENT(SMIL_SO52, XML_BY): + { + aBy = aIter.toString(); + } + break; + + case XML_ELEMENT(SMIL, XML_TO): + case XML_ELEMENT(SMIL_COMPAT, XML_TO): + case XML_ELEMENT(SMIL_SO52, XML_TO): + { + aTo = aIter.toString(); + } + break; + + case XML_ELEMENT(SMIL, XML_KEYTIMES): + case XML_ELEMENT(SMIL_COMPAT, XML_KEYTIMES): + case XML_ELEMENT(SMIL_SO52, XML_KEYTIMES): + { + if( xAnimate.is() ) + xAnimate->setKeyTimes( AnimationsImportHelperImpl::convertKeyTimes( aIter.toView() ) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_FORMULA): + case XML_ELEMENT(ANIMATION_OOO, XML_FORMULA): + { + if( xAnimate.is() ) + xAnimate->setFormula( aIter.toString() ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_ID): + case XML_ELEMENT(ANIMATION_OOO, XML_ID): + { + if (!bHaveXmlId) { sXmlId = aIter.toString(); } + } + break; + case XML_ELEMENT(XML, XML_ID): + { + sXmlId = aIter.toString(); + bHaveXmlId = true; + } + break; + + case XML_ELEMENT(SMIL, XML_CALCMODE): + case XML_ELEMENT(SMIL_COMPAT, XML_CALCMODE): + case XML_ELEMENT(SMIL_SO52, XML_CALCMODE): + { + if( xAnimate.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_CalcMode ) ) + xAnimate->setCalcMode( nEnum ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_ACCUMULATE): + case XML_ELEMENT(SMIL_COMPAT, XML_ACCUMULATE): + case XML_ELEMENT(SMIL_SO52, XML_ACCUMULATE): + { + if( xAnimate.is() ) + xAnimate->setAccumulate( IsXMLToken( aIter, XML_SUM ) ); + } + break; + + case XML_ELEMENT(PRESENTATION, XML_ADDITIVE): + case XML_ELEMENT(PRESENTATION_SO52, XML_ADDITIVE): + case XML_ELEMENT(PRESENTATION_OOO, XML_ADDITIVE): + case XML_ELEMENT(SMIL, XML_ADDITIVE): + case XML_ELEMENT(SMIL_COMPAT, XML_ADDITIVE): + case XML_ELEMENT(SMIL_SO52, XML_ADDITIVE): + { + if( xAnimate.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_AdditiveMode ) ) + xAnimate->setAdditive( nEnum ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_KEYSPLINES): + case XML_ELEMENT(SMIL_COMPAT, XML_KEYSPLINES): + case XML_ELEMENT(SMIL_SO52, XML_KEYSPLINES): + { + if( xAnimate.is() ) + xAnimate->setTimeFilter( AnimationsImportHelperImpl::convertTimeFilter( aIter.toView() ) ); + } + break; + + case XML_ELEMENT(SVG, XML_PATH): + case XML_ELEMENT(SVG_COMPAT, XML_PATH): + { + Reference< XAnimateMotion > xAnimateMotion( mxNode, UNO_QUERY ); + if( xAnimateMotion.is() ) + xAnimateMotion->setPath( AnimationsImportHelperImpl::convertPath( aIter.toString() ) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_PHYSICS_ANIMATION_START_VELOCITY_X): + case XML_ELEMENT(ANIMATION_OOO, XML_PHYSICS_ANIMATION_START_VELOCITY_X): + case XML_ELEMENT(LO_EXT, XML_PHYSICS_ANIMATION_START_VELOCITY_X): + { + Reference< XAnimatePhysics > xAnimatePhysics( mxNode, UNO_QUERY ); + if( xAnimatePhysics.is() ) + xAnimatePhysics->setStartVelocityX( Any(aIter.toDouble()) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_PHYSICS_ANIMATION_START_VELOCITY_Y): + case XML_ELEMENT(ANIMATION_OOO, XML_PHYSICS_ANIMATION_START_VELOCITY_Y): + case XML_ELEMENT(LO_EXT, XML_PHYSICS_ANIMATION_START_VELOCITY_Y): + { + Reference< XAnimatePhysics > xAnimatePhysics( mxNode, UNO_QUERY ); + if( xAnimatePhysics.is() ) + xAnimatePhysics->setStartVelocityY( Any(aIter.toDouble()) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_PHYSICS_ANIMATION_DENSITY): + case XML_ELEMENT(ANIMATION_OOO, XML_PHYSICS_ANIMATION_DENSITY): + case XML_ELEMENT(LO_EXT, XML_PHYSICS_ANIMATION_DENSITY): + { + Reference< XAnimatePhysics > xAnimatePhysics( mxNode, UNO_QUERY ); + if( xAnimatePhysics.is() ) + xAnimatePhysics->setDensity( Any(aIter.toDouble()) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_PHYSICS_ANIMATION_BOUNCINESS): + case XML_ELEMENT(ANIMATION_OOO, XML_PHYSICS_ANIMATION_BOUNCINESS): + case XML_ELEMENT(LO_EXT, XML_PHYSICS_ANIMATION_BOUNCINESS): + { + Reference< XAnimatePhysics > xAnimatePhysics( mxNode, UNO_QUERY ); + if( xAnimatePhysics.is() ) + xAnimatePhysics->setBounciness( Any(aIter.toDouble()) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_COLOR_INTERPOLATION): + case XML_ELEMENT(ANIMATION_OOO, XML_COLOR_INTERPOLATION): + { + Reference< XAnimateColor > xAnimateColor( mxNode, UNO_QUERY ); + if( xAnimateColor.is() ) + xAnimateColor->setColorInterpolation( IsXMLToken( aIter, XML_HSL ) ? AnimationColorSpace::HSL : AnimationColorSpace::RGB ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_COLOR_INTERPOLATION_DIRECTION): + case XML_ELEMENT(ANIMATION_OOO, XML_COLOR_INTERPOLATION_DIRECTION): + { + Reference< XAnimateColor > xAnimateColor( mxNode, UNO_QUERY ); + if( xAnimateColor.is() ) + xAnimateColor->setDirection( IsXMLToken( aIter, XML_CLOCKWISE ) ); + } + break; + + case XML_ELEMENT(SVG, XML_TYPE): + case XML_ELEMENT(SVG_COMPAT, XML_TYPE): + { + Reference< XAnimateTransform > xTransform( mxNode, UNO_QUERY ); + if( xTransform.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_TransformType ) ) + { + xTransform->setTransformType( nEnum ); + switch( nEnum ) + { + case AnimationTransformType::SCALE: meAttributeName = XML_SCALE; break; + case AnimationTransformType::ROTATE: meAttributeName = XML_ROTATE; break; + case AnimationTransformType::SKEWX: meAttributeName = XML_SKEWX; break; + case AnimationTransformType::SKEWY: meAttributeName = XML_SKEWY; break; + //case AnimationTransformType::TRANSLATE: + default: + meAttributeName = XML_TRANSLATE; break; + } + } + } + } + break; + + case XML_ELEMENT(SMIL, XML_TYPE): + case XML_ELEMENT(SMIL_COMPAT, XML_TYPE): + case XML_ELEMENT(SMIL_SO52, XML_TYPE): + { + if( xTransitionFilter.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_TransitionType ) ) + xTransitionFilter->setTransition( nEnum ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_SUBTYPE): + case XML_ELEMENT(SMIL_COMPAT, XML_SUBTYPE): + case XML_ELEMENT(SMIL_SO52, XML_SUBTYPE): + { + if( xTransitionFilter.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_TransitionSubType ) ) + xTransitionFilter->setSubtype( nEnum ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_MODE): + case XML_ELEMENT(SMIL_COMPAT, XML_MODE): + case XML_ELEMENT(SMIL_SO52, XML_MODE): + { + if( xTransitionFilter.is() ) + xTransitionFilter->setMode( IsXMLToken( aIter, XML_IN ) ); + } + break; + + case XML_ELEMENT(SMIL, XML_DIRECTION): + case XML_ELEMENT(SMIL_COMPAT, XML_DIRECTION): + case XML_ELEMENT(SMIL_SO52, XML_DIRECTION): + { + if( xTransitionFilter.is() ) + xTransitionFilter->setDirection( IsXMLToken( aIter, XML_FORWARD ) ); + } + break; + + case XML_ELEMENT(SMIL, XML_FADECOLOR): + case XML_ELEMENT(SMIL_COMPAT, XML_FADECOLOR): + case XML_ELEMENT(SMIL_SO52, XML_FADECOLOR): + { + if( xTransitionFilter.is() ) + { + sal_Int32 nColor(0); + ::sax::Converter::convertColor(nColor, aIter.toView()); + xTransitionFilter->setFadeColor(nColor); + } + } + break; + + case XML_ELEMENT(ANIMATION, XML_ITERATE_TYPE): + case XML_ELEMENT(ANIMATION_OOO, XML_ITERATE_TYPE): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_IterateType ) ) + { + if( xIter.is() ) + xIter->setIterateType( nEnum ); + } + } + break; + + case XML_ELEMENT(ANIMATION, XML_ITERATE_INTERVAL): + case XML_ELEMENT(ANIMATION_OOO, XML_ITERATE_INTERVAL): + { + if( xIter.is() ) + { + OUString rValue = aIter.toString(); + double fInterval = 0.0; + if( rValue.match("P") ) + { + css::util::Duration aDuration; + if (::sax::Converter::convertDuration(aDuration, rValue)) + { + fInterval = ((((aDuration.Hours * 60) + + aDuration.Minutes) * 60) + aDuration.Seconds) + + (aDuration.NanoSeconds / 1000000000.0); + } + } + else + { + fInterval = aIter.toDouble(); + } + + xIter->setIterateInterval( fInterval ); + } + } + break; + + case XML_ELEMENT(PRESENTATION, XML_GROUP_ID): + case XML_ELEMENT(PRESENTATION_SO52, XML_GROUP_ID): + case XML_ELEMENT(PRESENTATION_OOO, XML_GROUP_ID): + { + aUserData.emplace_back( "group-id", Any( aIter.toInt32() ) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_COMMAND): + case XML_ELEMENT(ANIMATION_OOO, XML_COMMAND): + { + if( xCommand.is() && nNodeType == AnimationNodeType::COMMAND ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_Command ) ) + { + xCommand->setCommand( nEnum ); + } + } + } + break; + + default: + { + // push all unknown attributes within the presentation namespace as user data + if (IsTokenInNamespace(nToken, XML_NAMESPACE_PRESENTATION) + || IsTokenInNamespace(nToken, XML_NAMESPACE_PRESENTATION_SO52) + || IsTokenInNamespace(nToken, XML_NAMESPACE_PRESENTATION_OASIS) + || IsTokenInNamespace(nToken, XML_NAMESPACE_PRESENTATION_OOO)) + { + aUserData.emplace_back( SvXMLImport::getNameFromToken(aIter.getToken()), Any( aIter.toString() ) ); + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + } + + if (!sXmlId.isEmpty()) + { + Reference< XInterface > const xRef( mxNode, UNO_QUERY ); + GetImport().getInterfaceToIdentifierMapper().registerReference( + sXmlId, xRef ); + } + + sal_Int32 nUserDataCount = aUserData.size(); + if( nUserDataCount ) + { + Sequence< NamedValue > aUnoUserData( nUserDataCount ); + NamedValue* pData = aUnoUserData.getArray(); + for (auto const& item : aUserData) + *pData++ = item; + + mxNode->setUserData( aUnoUserData ); + } + + // convert values + if( xAnimate.is() ) + { + if( !aFrom.isEmpty() ) + xAnimate->setFrom( mpHelper->convertValue( meAttributeName, aFrom ) ); + + if( !aBy.isEmpty() ) + xAnimate->setBy( mpHelper->convertValue( meAttributeName, aBy ) ); + + if( !aTo.isEmpty() ) + xAnimate->setTo( mpHelper->convertValue( meAttributeName, aTo ) ); + + if( !aValues.isEmpty() ) + xAnimate->setValues( mpHelper->convertValueSequence( meAttributeName, aValues ) ); + + if (xAnimate->getValues().getLength() != xAnimate->getKeyTimes().getLength()) + throw css::io::WrongFormatException(); + } + } + catch (const css::io::WrongFormatException&) + { + throw; + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > AnimationNodeContext::createFastChildContext(sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) +{ + if( mxNode.is()) + return new AnimationNodeContext( mxNode, GetImport(), nElement, xAttrList, mpHelper ); + return nullptr; +} + +namespace { + +class AnimationsImport: public SvXMLImport, public XAnimationNodeSupplier +{ +public: + explicit AnimationsImport( const Reference< XComponentContext > & rxContext ); + + SvXMLImportContext* CreateFastContext(sal_Int32 nElement, + const Reference<XFastAttributeList>& xAttrList) override; + + // XInterface + virtual Any SAL_CALL queryInterface( const Type& aType ) override; + virtual void SAL_CALL acquire() noexcept override; + virtual void SAL_CALL release() noexcept override; + + // XAnimationNodeSupplier + Reference< XAnimationNode > SAL_CALL getAnimationNode() override; + +private: + Reference< XAnimationNode > mxRootNode; +}; + +} + +AnimationsImport::AnimationsImport( const Reference< XComponentContext > & rxContext ) +: SvXMLImport( rxContext, "xmloff::AnimationsImport", SvXMLImportFlags::META ) + //FIXME: the above "IMPORT_META" used to be a nonsensical "true", question + // remains whether this should be IMPORT_META (same numerical value as + // true) or default IMPORT_ALL +{ + mxRootNode.set( SequenceTimeContainer::create(rxContext), UNO_QUERY_THROW ); +} + +// XInterface +Any SAL_CALL AnimationsImport::queryInterface( const Type& aType ) +{ + if ( aType == cppu::UnoType<XAnimationNodeSupplier>::get()) + { + return Any( Reference<XAnimationNodeSupplier>( this ) ); + } + else + { + return SvXMLImport::queryInterface( aType ); + } +} + +void SAL_CALL AnimationsImport::acquire() noexcept +{ + SvXMLImport::acquire(); +} + +void SAL_CALL AnimationsImport::release() noexcept +{ + SvXMLImport::release(); +} + +SvXMLImportContext *AnimationsImport::CreateFastContext( + sal_Int32 nElement, + const Reference<XFastAttributeList>& xAttrList) +{ + SvXMLImportContext* pContext = nullptr; + + if( nElement == XML_ELEMENT(ANIMATION, XML_SEQ) || nElement == XML_ELEMENT(ANIMATION_OOO, XML_SEQ) ) + { + pContext = new AnimationNodeContext( mxRootNode, *this, nElement, xAttrList ); + } + + return pContext; +} + +// XAnimationNodeSupplier +Reference< XAnimationNode > SAL_CALL AnimationsImport::getAnimationNode() +{ + return mxRootNode; +} + +void AnimationNodeContext::postProcessRootNode( const Reference< XAnimationNode >& xRootNode, Reference< XPropertySet > const & xPageProps ) +{ + if( !(xRootNode.is() && xPageProps.is()) ) + return; + + try + { + Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW ); + if( xEnumeration->hasMoreElements() ) + { + Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); + if( xNode->getType() == AnimationNodeType::PAR ) + { + Event aEvent; + if( (xNode->getBegin() >>= aEvent) && (aEvent.Trigger == EventTrigger::BEGIN_EVENT) ) + { + // found transition node + Reference< XEnumerationAccess > xChildEnumerationAccess( xNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xChildEnumeration( xChildEnumerationAccess->createEnumeration(), UNO_SET_THROW ); + while( xChildEnumeration->hasMoreElements() ) + { + Reference< XAnimationNode > xChildNode( xChildEnumeration->nextElement(), UNO_QUERY_THROW ); + switch( xChildNode->getType() ) + { + case AnimationNodeType::TRANSITIONFILTER: + { + Reference< XTransitionFilter > xTransFilter( xChildNode, UNO_QUERY_THROW ); + + xPageProps->setPropertyValue("TransitionType", Any( xTransFilter->getTransition() ) ); + xPageProps->setPropertyValue("TransitionSubtype", Any( xTransFilter->getSubtype() ) ); + xPageProps->setPropertyValue("TransitionDirection", Any( xTransFilter->getDirection() ) ); + xPageProps->setPropertyValue("TransitionFadeColor", Any( xTransFilter->getFadeColor() ) ); + + double fDuration; + if( xTransFilter->getDuration() >>= fDuration ) + xPageProps->setPropertyValue("TransitionDuration", Any( fDuration ) ); + + } + break; + + case AnimationNodeType::COMMAND: + { + Reference< XCommand > xCommand( xChildNode, UNO_QUERY_THROW ); + if( xCommand->getCommand() == EffectCommands::STOPAUDIO ) + { + xPageProps->setPropertyValue("Sound", Any(true) ); + } + } + break; + + case AnimationNodeType::AUDIO: + { + Reference< XAudio > xAudio( xChildNode, UNO_QUERY_THROW ); + OUString sSoundURL; + if( (xAudio->getSource() >>= sSoundURL) && !sSoundURL.isEmpty() ) + { + xPageProps->setPropertyValue("Sound", Any(sSoundURL) ); + + Timing eTiming; + if( (xAudio->getRepeatCount() >>= eTiming) && (eTiming == Timing_INDEFINITE) ) + xPageProps->setPropertyValue("LoopSound", Any( true ) ); + } + } + break; + + } + } + + Reference< XTimeContainer > xRootContainer( xRootNode, UNO_QUERY_THROW ); + xRootContainer->removeChild( xNode ); + } + } + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +} // namespace xmloff + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Xmloff_AnimationsImport(uno::XComponentContext* pCtx, + uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new xmloff::AnimationsImport(pCtx)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/animexp.cxx b/xmloff/source/draw/animexp.cxx new file mode 100644 index 0000000000..0c78f4f1d8 --- /dev/null +++ b/xmloff/source/draw/animexp.cxx @@ -0,0 +1,511 @@ +/* -*- 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 <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/presentation/AnimationSpeed.hpp> +#include <xmloff/unointerfacetouniqueidentifiermapper.hxx> + +#include <sax/tools/converter.hxx> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include <list> +#include <comphelper/extract.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlexp.hxx> +#include <anim.hxx> + + +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::presentation; +using namespace ::xmloff::token; + +namespace { + +struct Effect +{ + XMLEffect meKind; + XMLEffectDirection meDirection; + sal_Int16 mnStartScale; + bool mbIn; +}; + +} + +const Effect AnimationEffectMap[] = +{ + { EK_none, ED_none, -1, true }, // AnimationEffect_NONE + { EK_fade, ED_from_left, -1, true }, // AnimationEffect_FADE_FROM_LEFT + { EK_fade, ED_from_top, -1, true }, // AnimationEffect_FADE_FROM_TOP + { EK_fade, ED_from_right, -1, true }, // AnimationEffect_FADE_FROM_RIGHT + { EK_fade, ED_from_bottom, -1, true }, // AnimationEffect_FADE_FROM_BOTTOM + { EK_fade, ED_to_center, -1, true }, // AnimationEffect_FADE_TO_CENTER + { EK_fade, ED_from_center, -1, true }, // AnimationEffect_FADE_FROM_CENTER + { EK_move, ED_from_left, -1, true }, // AnimationEffect_MOVE_FROM_LEFT + { EK_move, ED_from_top, -1, true }, // AnimationEffect_MOVE_FROM_TOP + { EK_move, ED_from_right, -1, true }, // AnimationEffect_MOVE_FROM_RIGHT + { EK_move, ED_from_bottom, -1, true }, // AnimationEffect_MOVE_FROM_BOTTOM + { EK_stripes, ED_vertical, -1, true }, // AnimationEffect_VERTICAL_STRIPES + { EK_stripes, ED_horizontal, -1, true }, // AnimationEffect_HORIZONTAL_STRIPES + { EK_fade, ED_clockwise, -1, true }, // AnimationEffect_CLOCKWISE + { EK_fade, ED_cclockwise, -1, true }, // AnimationEffect_COUNTERCLOCKWISE + { EK_fade, ED_from_upperleft, -1, true }, // AnimationEffect_FADE_FROM_UPPERLEFT + { EK_fade, ED_from_upperright, -1, true }, // AnimationEffect_FADE_FROM_UPPERRIGHT + { EK_fade, ED_from_lowerleft, -1, true }, // AnimationEffect_FADE_FROM_LOWERLEFT + { EK_fade, ED_from_lowerright, -1, true }, // AnimationEffect_FADE_FROM_LOWERRIGHT + { EK_close,ED_vertical, -1, true }, // AnimationEffect_CLOSE_VERTICAL + { EK_close,ED_horizontal, -1, true }, // AnimationEffect_CLOSE_HORIZONTAL + { EK_open, ED_vertical, -1, true }, // AnimationEffect_OPEN_VERTICAL + { EK_open, ED_horizontal, -1, true }, // AnimationEffect_OPEN_HORIZONTAL + { EK_move, ED_path, -1, true }, // AnimationEffect_PATH + { EK_move, ED_to_left, -1, false },// AnimationEffect_MOVE_TO_LEFT + { EK_move, ED_to_top, -1, false },// AnimationEffect_MOVE_TO_TOP + { EK_move, ED_to_right, -1, false },// AnimationEffect_MOVE_TO_RIGHT + { EK_move, ED_to_bottom, -1, false },// AnimationEffect_MOVE_TO_BOTTOM + { EK_fade, ED_spiral_inward_left, -1, true }, // AnimationEffect_SPIRALIN_LEFT + { EK_fade, ED_spiral_inward_right, -1, true }, // AnimationEffect_SPIRALIN_RIGHT + { EK_fade, ED_spiral_outward_left, -1, true }, // AnimationEffect_SPIRALOUT_LEFT + { EK_fade, ED_spiral_outward_right, -1, true }, // AnimationEffect_SPIRALOUT_RIGHT + { EK_dissolve, ED_none, -1, true }, // AnimationEffect_DISSOLVE + { EK_wavyline, ED_from_left, -1, true }, // AnimationEffect_WAVYLINE_FROM_LEFT + { EK_wavyline, ED_from_top, -1, true }, // AnimationEffect_WAVYLINE_FROM_TOP + { EK_wavyline, ED_from_right, -1, true }, // AnimationEffect_WAVYLINE_FROM_RIGHT + { EK_wavyline, ED_from_bottom, -1, true }, // AnimationEffect_WAVYLINE_FROM_BOTTOM + { EK_random, ED_none, -1, true }, // AnimationEffect_RANDOM + { EK_lines, ED_vertical, -1, true }, // AnimationEffect_VERTICAL_LINES + { EK_lines, ED_horizontal, -1, true }, // AnimationEffect_HORIZONTAL_LINES + { EK_laser, ED_from_left, -1, true }, // AnimationEffect_LASER_FROM_LEFT + { EK_laser, ED_from_top, -1, true }, // AnimationEffect_LASER_FROM_TOP + { EK_laser, ED_from_right, -1, true }, // AnimationEffect_LASER_FROM_RIGHT + { EK_laser, ED_from_bottom, -1, true }, // AnimationEffect_LASER_FROM_BOTTOM + { EK_laser, ED_from_upperleft, -1, true }, // AnimationEffect_LASER_FROM_UPPERLEFT + { EK_laser, ED_from_upperright, -1, true }, // AnimationEffect_LASER_FROM_UPPERRIGHT + { EK_laser, ED_from_lowerleft, -1, true }, // AnimationEffect_LASER_FROM_LOWERLEFT + { EK_laser, ED_from_lowerright, -1, true }, // AnimationEffect_LASER_FROM_LOWERRIGHT + { EK_appear,ED_none, -1, true }, // AnimationEffect_APPEAR + { EK_hide, ED_none, -1, false },// AnimationEffect_HIDE + { EK_move, ED_from_upperleft, -1, true }, // AnimationEffect_MOVE_FROM_UPPERLEFT + { EK_move, ED_from_upperright, -1, true }, // AnimationEffect_MOVE_FROM_UPPERRIGHT + { EK_move, ED_from_lowerright, -1, true }, // AnimationEffect_MOVE_FROM_LOWERRIGHT + { EK_move, ED_from_lowerleft, -1, true }, // AnimationEffect_MOVE_FROM_LOWERLEFT + { EK_move, ED_to_upperleft, -1, false },// AnimationEffect_MOVE_TO_UPPERLEFT + { EK_move, ED_to_upperright, -1, false },// AnimationEffect_MOVE_TO_UPPERRIGHT + { EK_move, ED_to_lowerright, -1, false },// AnimationEffect_MOVE_TO_LOWERRIGHT + { EK_move, ED_to_lowerleft, -1, false },// AnimationEffect_MOVE_TO_LOWERLEFT + { EK_move_short, ED_from_left, -1, true }, // AnimationEffect_MOVE_SHORT_FROM_LEFT + { EK_move_short, ED_from_upperleft, -1, true }, // AnimationEffect_MOVE_SHORT_FROM_UPPERLEFT + { EK_move_short, ED_from_top, -1, true }, // AnimationEffect_MOVE_SHORT_FROM_TOP + { EK_move_short, ED_from_upperright,-1, true }, // AnimationEffect_MOVE_SHORT_FROM_UPPERRIGHT + { EK_move_short, ED_from_right, -1, true }, // AnimationEffect_MOVE_SHORT_FROM_RIGHT + { EK_move_short, ED_from_lowerright,-1, true }, // AnimationEffect_MOVE_SHORT_FROM_LOWERRIGHT + { EK_move_short, ED_from_bottom, -1, true }, // AnimationEffect_MOVE_SHORT_FROM_BOTTOM + { EK_move_short, ED_from_lowerleft, -1, true }, // AnimationEffect_MOVE_SHORT_FROM_LOWERLEFT + { EK_move_short, ED_to_left, -1, false },// AnimationEffect_MOVE_SHORT_TO_LEFT + { EK_move_short, ED_to_upperleft, -1, false },// AnimationEffect_MOVE_SHORT_TO_UPPERLEFT + { EK_move_short, ED_to_top, -1, false },// AnimationEffect_MOVE_SHORT_TO_TOP + { EK_move_short, ED_to_upperright, -1, false },// AnimationEffect_MOVE_SHORT_TO_UPPERRIGHT + { EK_move_short, ED_to_right, -1, false },// AnimationEffect_MOVE_SHORT_TO_RIGHT + { EK_move_short, ED_to_lowerright, -1, false },// AnimationEffect_MOVE_SHORT_TO_LOWERRIGHT + { EK_move_short, ED_to_bottom, -1, false },// AnimationEffect_MOVE_SHORT_TO_BOTTOM + { EK_move_short, ED_to_lowerleft, -1, false },// AnimationEffect_MOVE_SHORT_TO_LOWERLEFT + { EK_checkerboard, ED_vertical, -1, true }, // AnimationEffect_VERTICAL_CHECKERBOARD + { EK_checkerboard, ED_horizontal, -1, true }, // AnimationEffect_HORIZONTAL_CHECKERBOARD + { EK_rotate, ED_horizontal, -1, true }, // AnimationEffect_HORIZONTAL_ROTATE + { EK_rotate, ED_vertical, -1, true }, // AnimationEffect_VERTICAL_ROTATE + { EK_stretch,ED_horizontal, -1, true }, // AnimationEffect_HORIZONTAL_STRETCH + { EK_stretch,ED_vertical, -1, true }, // AnimationEffect_VERTICAL_STRETCH + { EK_stretch,ED_from_left, -1, true }, // AnimationEffect_STRETCH_FROM_LEFT + { EK_stretch,ED_from_upperleft, -1, true }, // AnimationEffect_STRETCH_FROM_UPPERLEFT + { EK_stretch,ED_from_top, -1, true }, // AnimationEffect_STRETCH_FROM_TOP + { EK_stretch,ED_from_upperright,-1, true }, // AnimationEffect_STRETCH_FROM_UPPERRIGHT + { EK_stretch,ED_from_right, -1, true }, // AnimationEffect_STRETCH_FROM_RIGHT + { EK_stretch,ED_from_lowerright,-1, true }, // AnimationEffect_STRETCH_FROM_LOWERRIGHT + { EK_stretch,ED_from_bottom, -1, true }, // AnimationEffect_STRETCH_FROM_BOTTOM + { EK_stretch,ED_from_lowerleft, -1, true }, // AnimationEffect_STRETCH_FROM_LOWERLEFT + { EK_move, ED_none, 0, true }, // AnimationEffect_ZOOM_IN + { EK_move, ED_none, 50, true }, // AnimationEffect_ZOOM_IN_SMALL + { EK_move, ED_spiral_inward_left, 0, true }, // AnimationEffect_ZOOM_IN_SPIRAL + { EK_move, ED_none, 400, true }, // AnimationEffect_ZOOM_OUT + { EK_move, ED_none, 200, true }, // AnimationEffect_ZOOM_OUT_SMALL + { EK_move, ED_spiral_inward_left, 400, true }, // AnimationEffect_ZOOM_OUT_SPIRAL + { EK_move, ED_from_left, 0, true }, // AnimationEffect_ZOOM_IN_FROM_LEFT + { EK_move, ED_from_upperleft, 0, true }, // AnimationEffect_ZOOM_IN_FROM_UPPERLEFT + { EK_move, ED_from_top, 0, true }, // AnimationEffect_ZOOM_IN_FROM_TOP + { EK_move, ED_from_upperright, 0, true }, // AnimationEffect_ZOOM_IN_FROM_UPPERRIGHT + { EK_move, ED_from_right, 0, true }, // AnimationEffect_ZOOM_IN_FROM_RIGHT + { EK_move, ED_from_lowerright, 0, true }, // AnimationEffect_ZOOM_IN_FROM_LOWERRIGHT + { EK_move, ED_from_bottom, 0, true }, // AnimationEffect_ZOOM_IN_FROM_BOTTOM + { EK_move, ED_from_lowerleft, 0, true }, // AnimationEffect_ZOOM_IN_FROM_LOWERLEFT + { EK_move, ED_from_center, 0, true }, // AnimationEffect_ZOOM_IN_FROM_CENTER + { EK_move, ED_from_left, 400, true }, // AnimationEffect_ZOOM_OUT_FROM_LEFT + { EK_move, ED_from_upperleft, 400, true }, // AnimationEffect_ZOOM_OUT_FROM_UPPERLEFT + { EK_move, ED_from_top, 400, true }, // AnimationEffect_ZOOM_OUT_FROM_TOP + { EK_move, ED_from_upperright,400, true }, // AnimationEffect_ZOOM_OUT_FROM_UPPERRIGHT + { EK_move, ED_from_right, 400, true }, // AnimationEffect_ZOOM_OUT_FROM_RIGHT + { EK_move, ED_from_lowerright,400, true }, // AnimationEffect_ZOOM_OUT_FROM_LOWERRIGHT + { EK_move, ED_from_bottom, 400, true }, // AnimationEffect_ZOOM_OUT_FROM_BOTTOM + { EK_move, ED_from_lowerleft, 400, true }, // AnimationEffect_ZOOM_OUT_FROM_LOWERLEFT + { EK_move, ED_from_center, 400, true } // AnimationEffect_ZOOM_OUT_FROM_CENTER +}; + +void SdXMLImplSetEffect( AnimationEffect eEffect, XMLEffect& eKind, XMLEffectDirection& eDirection, sal_Int16& nStartScale, bool& bIn ) +{ + if( eEffect < AnimationEffect_NONE || eEffect > AnimationEffect_ZOOM_OUT_FROM_CENTER ) + { + OSL_FAIL( "unknown animation effect!" ); + eEffect = AnimationEffect_NONE; + } + + const Effect& rEffect = AnimationEffectMap[static_cast<int>(eEffect)]; + eKind = rEffect.meKind; + eDirection = rEffect.meDirection; + nStartScale = rEffect.mnStartScale; + bIn = rEffect.mbIn; +} + +namespace { + +enum XMLActionKind : sal_Int8 +{ + XMLE_SHOW, + XMLE_HIDE, + XMLE_DIM, + XMLE_PLAY +}; + +struct XMLEffectHint +{ + Reference<XShape> mxShape; + XMLActionKind meKind; + bool mbTextEffect; + + XMLEffect meEffect; + XMLEffectDirection meDirection; + sal_Int16 mnStartScale; + + AnimationSpeed meSpeed; + OUString maSoundURL; + sal_Int32 maDimColor; + sal_Int32 mnPresId; + bool mbPlayFull; + + bool operator<(const XMLEffectHint& rComp) const { return mnPresId < rComp.mnPresId; } + + XMLEffectHint() + : meKind( XMLE_SHOW ), mbTextEffect( false ), + meEffect( EK_none ), meDirection( ED_none ), mnStartScale( -1 ), + meSpeed( AnimationSpeed_SLOW ), maDimColor(0), + mnPresId( 0 ), mbPlayFull( false ) + {} +}; + +} + +class AnimExpImpl +{ +public: + std::list<XMLEffectHint> maEffects; + + static constexpr OUString gsDimColor = u"DimColor"_ustr; + static constexpr OUString gsDimHide = u"DimHide"_ustr; + static constexpr OUString gsDimPrev = u"DimPrevious"_ustr; + static constexpr OUString gsEffect = u"Effect"_ustr; + static constexpr OUString gsPlayFull = u"PlayFull"_ustr; + static constexpr OUString gsPresOrder = u"PresentationOrder"_ustr; + static constexpr OUString gsSound = u"Sound"_ustr; + static constexpr OUString gsSoundOn = u"SoundOn"_ustr; + static constexpr OUString gsSpeed = u"Speed"_ustr; + static constexpr OUString gsTextEffect = u"TextEffect"_ustr; + static constexpr OUString gsIsAnimation = u"IsAnimation"_ustr; + static constexpr OUString gsAnimPath = u"AnimationPath"_ustr; +}; + +XMLAnimationsExporter::XMLAnimationsExporter() + : mpImpl( new AnimExpImpl ) +{ +} + +XMLAnimationsExporter::~XMLAnimationsExporter() +{ +} + +void XMLAnimationsExporter::prepare( const Reference< XShape >& xShape ) +{ + try + { + // check for presentation shape service + { + Reference< XServiceInfo > xServiceInfo( xShape, UNO_QUERY ); + if( !xServiceInfo.is() || !xServiceInfo->supportsService("com.sun.star.presentation.Shape") ) + return; + } + + Reference< XPropertySet > xProps( xShape, UNO_QUERY ); + if( xProps.is() ) + { + AnimationEffect eEffect; + xProps->getPropertyValue( AnimExpImpl::gsEffect ) >>= eEffect; + if( eEffect == AnimationEffect_PATH ) + { + Reference< XShape > xPath; + xProps->getPropertyValue( AnimExpImpl::gsAnimPath ) >>= xPath; + } + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", + "exception caught while collection animation information!"); + } +} + +void XMLAnimationsExporter::collect( const Reference< XShape >& xShape, SvXMLExport& rExport ) +{ + try + { + // check for presentation shape service + { + Reference< XServiceInfo > xServiceInfo( xShape, UNO_QUERY ); + if( !xServiceInfo.is() || !xServiceInfo->supportsService("com.sun.star.presentation.Shape") ) + return; + } + + Reference< XPropertySet > xProps( xShape, UNO_QUERY ); + if( xProps.is() ) + { + XMLEffectHint aEffect; + + if( any2bool( xProps->getPropertyValue( AnimExpImpl::gsSoundOn ) ) ) + { + xProps->getPropertyValue( AnimExpImpl::gsSound ) >>= aEffect.maSoundURL; + xProps->getPropertyValue( AnimExpImpl::gsPlayFull ) >>= aEffect.mbPlayFull; + } + + xProps->getPropertyValue( AnimExpImpl::gsPresOrder ) >>= aEffect.mnPresId; + xProps->getPropertyValue( AnimExpImpl::gsSpeed ) >>= aEffect.meSpeed; + + + bool bIsAnimation = false; + xProps->getPropertyValue( AnimExpImpl::gsIsAnimation ) >>= bIsAnimation; + if( bIsAnimation ) + { + aEffect.meKind = XMLE_PLAY; + + if( !aEffect.mxShape.is() ) + { + rExport.getInterfaceToIdentifierMapper().registerReference( xShape ); + aEffect.mxShape = xShape; + } + + mpImpl->maEffects.push_back( aEffect ); + } + + { + AnimationEffect eEffect; + xProps->getPropertyValue( AnimExpImpl::gsEffect ) >>= eEffect; + if( eEffect != AnimationEffect_NONE ) + { + bool bIn = true; + SdXMLImplSetEffect( eEffect, aEffect.meEffect, aEffect.meDirection, aEffect.mnStartScale, bIn ); + + aEffect.meKind = bIn ? XMLE_SHOW : XMLE_HIDE; + + if( !aEffect.mxShape.is() ) + { + rExport.getInterfaceToIdentifierMapper().registerReference( xShape ); + aEffect.mxShape = xShape; + } + + if( eEffect == AnimationEffect_PATH ) + { + Reference< XShape > xPath; + xProps->getPropertyValue( AnimExpImpl::gsAnimPath ) >>= xPath; + if( xPath.is() ) + { +// strip mpImpl->mxShapeExp->createShapeId( xPath ); +// strip aEffect.mnPathShapeId = mpImpl->mxShapeExp->getShapeId( xPath ); + } + } + mpImpl->maEffects.push_back( aEffect ); + + aEffect.maSoundURL.clear(); + } + + xProps->getPropertyValue( AnimExpImpl::gsTextEffect ) >>= eEffect; + if( eEffect != AnimationEffect_NONE ) + { + bool bIn = true; + SdXMLImplSetEffect( eEffect, aEffect.meEffect, aEffect.meDirection, aEffect.mnStartScale, bIn ); + aEffect.meKind = bIn ? XMLE_SHOW : XMLE_HIDE; + aEffect.mbTextEffect = true; + + if( !aEffect.mxShape.is() ) + { + rExport.getInterfaceToIdentifierMapper().registerReference( xShape ); + aEffect.mxShape = xShape; + } + + mpImpl->maEffects.push_back( aEffect ); + aEffect.mbTextEffect = false; + aEffect.maSoundURL.clear(); + } + + bool bDimPrev = false; + bool bDimHide = false; + xProps->getPropertyValue( AnimExpImpl::gsDimPrev ) >>= bDimPrev; + xProps->getPropertyValue( AnimExpImpl::gsDimHide ) >>= bDimHide; + if( bDimPrev || bDimHide ) + { + aEffect.meKind = bDimPrev ? XMLE_DIM : XMLE_HIDE; + aEffect.meEffect = EK_none; + aEffect.meDirection = ED_none; + aEffect.meSpeed = AnimationSpeed_MEDIUM; + if( bDimPrev ) + { + xProps->getPropertyValue( AnimExpImpl::gsDimColor ) + >>= aEffect.maDimColor; + } + + if( !aEffect.mxShape.is() ) + { + rExport.getInterfaceToIdentifierMapper().registerReference( xShape ); + aEffect.mxShape = xShape; + } + + mpImpl->maEffects.push_back( aEffect ); + aEffect.maSoundURL.clear(); + } + } + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", + "exception caught while collection animation information!"); + } +} + +void XMLAnimationsExporter::exportAnimations( SvXMLExport& rExport ) +{ + mpImpl->maEffects.sort(); + + OUStringBuffer sTmp; + + if( !mpImpl->maEffects.empty() ) + { + SvXMLElementExport aElement( rExport, XML_NAMESPACE_PRESENTATION, XML_ANIMATIONS, true, true ); + + for (const auto& rEffect : mpImpl->maEffects) + { + SAL_WARN_IF( !rEffect.mxShape.is(), "xmloff", "shape id creation failed for animation effect?" ); + + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_SHAPE_ID, rExport.getInterfaceToIdentifierMapper().getIdentifier( rEffect.mxShape ) ); + + if( rEffect.meKind == XMLE_DIM ) + { + // export a dim action; + + ::sax::Converter::convertColor( sTmp, rEffect.maDimColor ); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_COLOR, sTmp.makeStringAndClear() ); + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_PRESENTATION, XML_DIM, true, true ); + } + else if( rEffect.meKind == XMLE_PLAY ) + { + if( rEffect.meSpeed != AnimationSpeed_MEDIUM ) + { + SvXMLUnitConverter::convertEnum( sTmp, rEffect.meSpeed, aXML_AnimationSpeed_EnumMap ); + rExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SPEED, sTmp.makeStringAndClear() ); + } + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_PRESENTATION, XML_PLAY, true, true ); + } + else + { + + if( rEffect.meEffect != EK_none ) + { + SvXMLUnitConverter::convertEnum( sTmp, rEffect.meEffect, aXML_AnimationEffect_EnumMap ); + rExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_EFFECT, sTmp.makeStringAndClear() ); + } + + if( rEffect.meDirection != ED_none ) + { + SvXMLUnitConverter::convertEnum( sTmp, rEffect.meDirection, aXML_AnimationDirection_EnumMap ); + rExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_DIRECTION, sTmp.makeStringAndClear() ); + } + + if( rEffect.mnStartScale != -1 ) + { + ::sax::Converter::convertPercent(sTmp, rEffect.mnStartScale); + rExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_START_SCALE, sTmp.makeStringAndClear() ); + } + + if( rEffect.meSpeed != AnimationSpeed_MEDIUM ) + { + SvXMLUnitConverter::convertEnum( sTmp, rEffect.meSpeed, aXML_AnimationSpeed_EnumMap ); + rExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SPEED, sTmp.makeStringAndClear() ); + } + + enum XMLTokenEnum eLocalName; + if( rEffect.meKind == XMLE_SHOW ) + { + if( rEffect.mbTextEffect ) + eLocalName = XML_SHOW_TEXT; + else + eLocalName = XML_SHOW_SHAPE; + } + else + { + if( rEffect.mbTextEffect ) + eLocalName = XML_HIDE_TEXT; + else + eLocalName = XML_HIDE_SHAPE; + } + + SvXMLElementExport aEle( rExport, XML_NAMESPACE_PRESENTATION, eLocalName, true, true ); + if( !rEffect.maSoundURL.isEmpty() ) + { + rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, rExport.GetRelativeReference(rEffect.maSoundURL) ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_NEW ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST ); + if( rEffect.mbPlayFull ) + rExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PLAY_FULL, XML_TRUE ); + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_PRESENTATION, XML_SOUND, true, true ); + } + } + } + } + + mpImpl->maEffects.clear(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/animimp.cxx b/xmloff/source/draw/animimp.cxx new file mode 100644 index 0000000000..90f5a5a609 --- /dev/null +++ b/xmloff/source/draw/animimp.cxx @@ -0,0 +1,597 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <xmloff/unointerfacetouniqueidentifiermapper.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/presentation/AnimationEffect.hpp> +#include <com/sun/star/presentation/AnimationSpeed.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> + +#include <sax/tools/converter.hxx> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/namespacemap.hxx> +#include <anim.hxx> +#include <animimp.hxx> + +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::xml; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::presentation; +using namespace ::xmloff::token; + +const SvXMLEnumMapEntry<XMLEffect> aXML_AnimationEffect_EnumMap[] = +{ + { XML_NONE, EK_none }, + { XML_FADE, EK_fade }, + { XML_MOVE, EK_move }, + { XML_STRIPES, EK_stripes }, + { XML_OPEN, EK_open }, + { XML_CLOSE, EK_close }, + { XML_DISSOLVE, EK_dissolve }, + { XML_WAVYLINE, EK_wavyline }, + { XML_RANDOM, EK_random }, + { XML_LINES, EK_lines }, + { XML_LASER, EK_laser }, + { XML_APPEAR, EK_appear }, + { XML_HIDE, EK_hide }, + { XML_MOVE_SHORT, EK_move_short }, + { XML_CHECKERBOARD, EK_checkerboard }, + { XML_ROTATE, EK_rotate }, + { XML_STRETCH, EK_stretch }, + { XML_TOKEN_INVALID, XMLEffect(0) } +}; + +const SvXMLEnumMapEntry<XMLEffectDirection> aXML_AnimationDirection_EnumMap[] = +{ + { XML_NONE, ED_none }, + { XML_FROM_LEFT, ED_from_left }, + { XML_FROM_TOP, ED_from_top }, + { XML_FROM_RIGHT, ED_from_right }, + { XML_FROM_BOTTOM, ED_from_bottom }, + { XML_FROM_CENTER, ED_from_center }, + { XML_FROM_UPPER_LEFT, ED_from_upperleft }, + { XML_FROM_UPPER_RIGHT, ED_from_upperright }, + { XML_FROM_LOWER_LEFT, ED_from_lowerleft }, + { XML_FROM_LOWER_RIGHT, ED_from_lowerright }, + { XML_TO_LEFT, ED_to_left }, + { XML_TO_TOP, ED_to_top }, + { XML_TO_RIGHT, ED_to_right }, + { XML_TO_BOTTOM, ED_to_bottom }, + { XML_TO_UPPER_LEFT, ED_to_upperleft }, + { XML_TO_UPPER_RIGHT, ED_to_upperright }, + { XML_TO_LOWER_RIGHT, ED_to_lowerright }, + { XML_TO_LOWER_LEFT, ED_to_lowerleft }, + { XML_PATH, ED_path }, + { XML_SPIRAL_INWARD_LEFT, ED_spiral_inward_left }, + { XML_SPIRAL_INWARD_RIGHT,ED_spiral_inward_right }, + { XML_SPIRAL_OUTWARD_LEFT, ED_spiral_outward_left }, + { XML_SPIRAL_OUTWARD_RIGHT, ED_spiral_outward_right }, + { XML_VERTICAL, ED_vertical }, + { XML_HORIZONTAL, ED_horizontal }, + { XML_TO_CENTER, ED_to_center }, + { XML_CLOCKWISE, ED_clockwise }, + { XML_COUNTER_CLOCKWISE,ED_cclockwise }, + { XML_TOKEN_INVALID, XMLEffectDirection(0) } +}; + +const SvXMLEnumMapEntry<AnimationSpeed> aXML_AnimationSpeed_EnumMap[] = +{ + { XML_SLOW, AnimationSpeed_SLOW }, + { XML_MEDIUM, AnimationSpeed_MEDIUM }, + { XML_FAST, AnimationSpeed_FAST }, + { XML_TOKEN_INVALID, AnimationSpeed(0) } +}; + +AnimationEffect ImplSdXMLgetEffect( XMLEffect eKind, XMLEffectDirection eDirection, sal_Int16 nStartScale, bool /*bIn*/ ) +{ + switch( eKind ) + { + case EK_fade: + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_FADE_FROM_LEFT; + case ED_from_top: return AnimationEffect_FADE_FROM_TOP; + case ED_from_right: return AnimationEffect_FADE_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_FADE_FROM_BOTTOM; + case ED_from_center: return AnimationEffect_FADE_FROM_CENTER; + case ED_from_upperleft: return AnimationEffect_FADE_FROM_UPPERLEFT; + case ED_from_upperright: return AnimationEffect_FADE_FROM_UPPERRIGHT; + case ED_from_lowerleft: return AnimationEffect_FADE_FROM_LOWERLEFT; + case ED_from_lowerright: return AnimationEffect_FADE_FROM_LOWERRIGHT; + case ED_to_center: return AnimationEffect_FADE_TO_CENTER; + case ED_clockwise: return AnimationEffect_CLOCKWISE; + case ED_cclockwise: return AnimationEffect_COUNTERCLOCKWISE; + case ED_spiral_inward_left: return AnimationEffect_SPIRALIN_LEFT; + case ED_spiral_inward_right:return AnimationEffect_SPIRALIN_RIGHT; + case ED_spiral_outward_left:return AnimationEffect_SPIRALOUT_LEFT; + case ED_spiral_outward_right:return AnimationEffect_SPIRALOUT_RIGHT; + default: return AnimationEffect_FADE_FROM_LEFT; + } + case EK_move: + if( nStartScale == 200 ) + { + return AnimationEffect_ZOOM_OUT_SMALL; + } + else if( nStartScale == 50 ) + { + return AnimationEffect_ZOOM_IN_SMALL; + } + else if( nStartScale < 100 ) + { + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_ZOOM_IN_FROM_LEFT; + case ED_from_top: return AnimationEffect_ZOOM_IN_FROM_TOP; + case ED_from_right: return AnimationEffect_ZOOM_IN_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_ZOOM_IN_FROM_BOTTOM; + case ED_from_upperleft: return AnimationEffect_ZOOM_IN_FROM_UPPERLEFT; + case ED_from_upperright: return AnimationEffect_ZOOM_IN_FROM_UPPERRIGHT; + case ED_from_lowerleft: return AnimationEffect_ZOOM_IN_FROM_LOWERLEFT; + case ED_from_lowerright: return AnimationEffect_ZOOM_IN_FROM_LOWERRIGHT; + case ED_from_center: return AnimationEffect_ZOOM_IN_FROM_CENTER; + case ED_spiral_inward_left: return AnimationEffect_ZOOM_IN_SPIRAL; + case ED_to_left: return AnimationEffect_MOVE_TO_LEFT; + case ED_to_top: return AnimationEffect_MOVE_TO_TOP; + case ED_to_right: return AnimationEffect_MOVE_TO_RIGHT; + case ED_to_bottom: return AnimationEffect_MOVE_TO_BOTTOM; + case ED_to_upperleft: return AnimationEffect_MOVE_TO_UPPERLEFT; + case ED_to_upperright: return AnimationEffect_MOVE_TO_UPPERRIGHT; + case ED_to_lowerright: return AnimationEffect_MOVE_TO_LOWERRIGHT; + case ED_to_lowerleft: return AnimationEffect_MOVE_TO_LOWERLEFT; + default: return AnimationEffect_ZOOM_IN; + } + } + else if( nStartScale > 100 ) + { + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_ZOOM_OUT_FROM_LEFT; + case ED_from_top: return AnimationEffect_ZOOM_OUT_FROM_TOP; + case ED_from_right: return AnimationEffect_ZOOM_OUT_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_ZOOM_OUT_FROM_BOTTOM; + case ED_from_upperleft: return AnimationEffect_ZOOM_OUT_FROM_UPPERLEFT; + case ED_from_upperright: return AnimationEffect_ZOOM_OUT_FROM_UPPERRIGHT; + case ED_from_lowerleft: return AnimationEffect_ZOOM_OUT_FROM_LOWERLEFT; + case ED_from_lowerright: return AnimationEffect_ZOOM_OUT_FROM_LOWERRIGHT; + case ED_from_center: return AnimationEffect_ZOOM_OUT_FROM_CENTER; + case ED_spiral_inward_left: return AnimationEffect_ZOOM_OUT_SPIRAL; + default: return AnimationEffect_ZOOM_OUT; + } + } + else + { + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_MOVE_FROM_LEFT; + case ED_from_top: return AnimationEffect_MOVE_FROM_TOP; + case ED_from_right: return AnimationEffect_MOVE_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_MOVE_FROM_BOTTOM; + case ED_from_upperleft: return AnimationEffect_MOVE_FROM_UPPERLEFT; + case ED_from_upperright: return AnimationEffect_MOVE_FROM_UPPERRIGHT; + case ED_from_lowerleft: return AnimationEffect_MOVE_FROM_LOWERLEFT; + case ED_from_lowerright: return AnimationEffect_MOVE_FROM_LOWERRIGHT; + case ED_path: return AnimationEffect_PATH; + case ED_to_top: return AnimationEffect_MOVE_TO_TOP; + case ED_to_right: return AnimationEffect_MOVE_TO_RIGHT; + case ED_to_bottom: return AnimationEffect_MOVE_TO_BOTTOM; + case ED_to_upperleft: return AnimationEffect_MOVE_TO_UPPERLEFT; + case ED_to_upperright: return AnimationEffect_MOVE_TO_UPPERRIGHT; + case ED_to_lowerright: return AnimationEffect_MOVE_TO_LOWERRIGHT; + case ED_to_lowerleft: return AnimationEffect_MOVE_TO_LOWERLEFT; + default: + break; + } + } + return AnimationEffect_MOVE_FROM_LEFT; + case EK_stripes: + if( eDirection == ED_vertical ) + return AnimationEffect_VERTICAL_STRIPES; + else + return AnimationEffect_HORIZONTAL_STRIPES; + case EK_open: + if( eDirection == ED_vertical ) + return AnimationEffect_OPEN_VERTICAL; + else + return AnimationEffect_OPEN_HORIZONTAL; + case EK_close: + if( eDirection == ED_vertical ) + return AnimationEffect_CLOSE_VERTICAL; + else + return AnimationEffect_CLOSE_HORIZONTAL; + case EK_dissolve: + return AnimationEffect_DISSOLVE; + case EK_wavyline: + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_WAVYLINE_FROM_LEFT; + case ED_from_top: return AnimationEffect_WAVYLINE_FROM_TOP; + case ED_from_right: return AnimationEffect_WAVYLINE_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_WAVYLINE_FROM_BOTTOM; + default: return AnimationEffect_WAVYLINE_FROM_LEFT; + } + case EK_random: + return AnimationEffect_RANDOM; + case EK_lines: + if( eDirection == ED_vertical ) + return AnimationEffect_VERTICAL_LINES; + else + return AnimationEffect_HORIZONTAL_LINES; + case EK_laser: + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_LASER_FROM_LEFT; + case ED_from_top: return AnimationEffect_LASER_FROM_TOP; + case ED_from_right: return AnimationEffect_LASER_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_LASER_FROM_BOTTOM; + case ED_from_upperleft: return AnimationEffect_LASER_FROM_UPPERLEFT; + case ED_from_upperright: return AnimationEffect_LASER_FROM_UPPERRIGHT; + case ED_from_lowerleft: return AnimationEffect_LASER_FROM_LOWERLEFT; + case ED_from_lowerright: return AnimationEffect_LASER_FROM_LOWERRIGHT; + default: return AnimationEffect_LASER_FROM_LEFT; + } + case EK_appear: + return AnimationEffect_APPEAR; + case EK_hide: + return AnimationEffect_HIDE; + case EK_move_short: + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_MOVE_SHORT_FROM_LEFT; + case ED_from_top: return AnimationEffect_MOVE_SHORT_FROM_TOP; + case ED_from_right: return AnimationEffect_MOVE_SHORT_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_MOVE_SHORT_FROM_BOTTOM; + case ED_from_upperleft: return AnimationEffect_MOVE_SHORT_FROM_UPPERLEFT; + case ED_from_upperright: return AnimationEffect_MOVE_SHORT_FROM_UPPERRIGHT; + case ED_from_lowerleft: return AnimationEffect_MOVE_SHORT_FROM_LOWERLEFT; + case ED_from_lowerright: return AnimationEffect_MOVE_SHORT_FROM_LOWERRIGHT; + case ED_to_left: return AnimationEffect_MOVE_SHORT_TO_LEFT; + case ED_to_upperleft: return AnimationEffect_MOVE_SHORT_TO_UPPERLEFT; + case ED_to_top: return AnimationEffect_MOVE_SHORT_TO_TOP; + case ED_to_upperright: return AnimationEffect_MOVE_SHORT_TO_UPPERRIGHT; + case ED_to_right: return AnimationEffect_MOVE_SHORT_TO_RIGHT; + case ED_to_lowerright: return AnimationEffect_MOVE_SHORT_TO_LOWERRIGHT; + case ED_to_bottom: return AnimationEffect_MOVE_SHORT_TO_BOTTOM; + case ED_to_lowerleft: return AnimationEffect_MOVE_SHORT_TO_LOWERLEFT; + default: return AnimationEffect_MOVE_SHORT_FROM_LEFT; + } + case EK_checkerboard: + if( eDirection == ED_vertical ) + return AnimationEffect_VERTICAL_CHECKERBOARD; + else + return AnimationEffect_HORIZONTAL_CHECKERBOARD; + case EK_rotate: + if( eDirection == ED_vertical ) + return AnimationEffect_VERTICAL_ROTATE; + else + return AnimationEffect_HORIZONTAL_ROTATE; + case EK_stretch: + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_STRETCH_FROM_LEFT; + case ED_from_top: return AnimationEffect_STRETCH_FROM_TOP; + case ED_from_right: return AnimationEffect_STRETCH_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_STRETCH_FROM_BOTTOM; + case ED_from_upperleft: return AnimationEffect_STRETCH_FROM_UPPERLEFT; + case ED_from_upperright: return AnimationEffect_STRETCH_FROM_UPPERRIGHT; + case ED_from_lowerleft: return AnimationEffect_STRETCH_FROM_LOWERLEFT; + case ED_from_lowerright: return AnimationEffect_STRETCH_FROM_LOWERRIGHT; + case ED_vertical: return AnimationEffect_VERTICAL_STRETCH; + case ED_horizontal: return AnimationEffect_HORIZONTAL_STRETCH; + default: + break; + } + return AnimationEffect_STRETCH_FROM_LEFT; + default: + return AnimationEffect_NONE; + } +} + +namespace +{ + constexpr OUStringLiteral gsDimColor = u"DimColor"; + constexpr OUStringLiteral gsDimHide = u"DimHide"; + constexpr OUStringLiteral gsDimPrev = u"DimPrevious"; + constexpr OUStringLiteral gsEffect = u"Effect"; + constexpr OUStringLiteral gsPlayFull = u"PlayFull"; + constexpr OUStringLiteral gsSound = u"Sound"; + constexpr OUStringLiteral gsSoundOn = u"SoundOn"; + constexpr OUStringLiteral gsSpeed = u"Speed"; + constexpr OUStringLiteral gsTextEffect = u"TextEffect"; + constexpr OUStringLiteral gsPresShapeService = u"com.sun.star.presentation.Shape"; + constexpr OUStringLiteral gsAnimPath = u"AnimationPath"; + constexpr OUStringLiteral gsIsAnimation = u"IsAnimation"; +}; + +namespace { + +enum XMLActionKind +{ + XMLE_SHOW, + XMLE_HIDE, + XMLE_DIM, + XMLE_PLAY +}; + +class XMLAnimationsEffectContext : public SvXMLImportContext +{ +public: + rtl::Reference<XMLAnimationsContext> mxAnimationsContext; + + XMLActionKind meKind; + bool mbTextEffect; + OUString maShapeId; + + XMLEffect meEffect; + XMLEffectDirection meDirection; + sal_Int16 mnStartScale; + + AnimationSpeed meSpeed; + sal_Int32 maDimColor; + OUString maSoundURL; + bool mbPlayFull; + OUString maPathShapeId; + +public: + + XMLAnimationsEffectContext( SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< XFastAttributeList >& xAttrList, + XMLAnimationsContext& rAnimationsContext); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +class XMLAnimationsSoundContext : public SvXMLImportContext +{ +public: + + XMLAnimationsSoundContext( SvXMLImport& rImport, sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList, XMLAnimationsEffectContext* pParent ); +}; + +} + +XMLAnimationsSoundContext::XMLAnimationsSoundContext( SvXMLImport& rImport, sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList, XMLAnimationsEffectContext* pParent ) +: SvXMLImportContext( rImport ) +{ + if( !pParent || nElement != XML_ELEMENT(PRESENTATION, XML_SOUND) ) + return; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(XLINK, XML_HREF): + pParent->maSoundURL = rImport.GetAbsoluteReference(aIter.toString()); + break; + case XML_ELEMENT(PRESENTATION, XML_PLAY_FULL): + pParent->mbPlayFull = IsXMLToken( aIter, XML_TRUE ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +XMLAnimationsEffectContext::XMLAnimationsEffectContext( SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< XFastAttributeList >& xAttrList, + XMLAnimationsContext& rAnimationsContext ) +: SvXMLImportContext(rImport), + mxAnimationsContext( &rAnimationsContext ), + meKind( XMLE_SHOW ), mbTextEffect( false ), + meEffect( EK_none ), meDirection( ED_none ), mnStartScale( 100 ), + meSpeed( AnimationSpeed_MEDIUM ), maDimColor(0), mbPlayFull( false ) +{ + switch(nElement & TOKEN_MASK) + { + case XML_SHOW_SHAPE: + meKind = XMLE_SHOW; + break; + case XML_SHOW_TEXT: + meKind = XMLE_SHOW; + mbTextEffect = true; + break; + case XML_HIDE_SHAPE: + meKind = XMLE_HIDE; + break; + case XML_HIDE_TEXT: + meKind = XMLE_HIDE; + mbTextEffect = true; + break; + case XML_DIM: + meKind = XMLE_DIM; + break; + case XML_PLAY: + meKind = XMLE_PLAY; + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + // unknown action, overread + return; + } + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_SHAPE_ID): + maShapeId = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_COLOR): + ::sax::Converter::convertColor(maDimColor, aIter.toView()); + break; + + case XML_ELEMENT(PRESENTATION, XML_EFFECT): + SvXMLUnitConverter::convertEnum( meEffect, aIter.toView(), aXML_AnimationEffect_EnumMap ); + break; + case XML_ELEMENT(PRESENTATION, XML_DIRECTION): + SvXMLUnitConverter::convertEnum( meDirection, aIter.toView(), aXML_AnimationDirection_EnumMap ); + break; + case XML_ELEMENT(PRESENTATION, XML_START_SCALE): + { + sal_Int32 nScale; + if (::sax::Converter::convertPercent( nScale, aIter.toView() )) + mnStartScale = static_cast<sal_Int16>(nScale); + break; + } + case XML_ELEMENT(PRESENTATION, XML_SPEED): + SvXMLUnitConverter::convertEnum( meSpeed, aIter.toView(), aXML_AnimationSpeed_EnumMap ); + break; + case XML_ELEMENT(PRESENTATION, XML_PATH_ID): + maPathShapeId = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLAnimationsEffectContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return new XMLAnimationsSoundContext( GetImport(), nElement, xAttrList, this ); +} + +void XMLAnimationsEffectContext::endFastElement(sal_Int32 ) +{ + // set effect on shape + + try + { + if( !maShapeId.isEmpty() ) + { + Reference< XPropertySet > xSet; + if( mxAnimationsContext->maLastShapeId != maShapeId ) + { + xSet.set( GetImport().getInterfaceToIdentifierMapper().getReference( maShapeId ), UNO_QUERY ); + if( xSet.is() ) + { + // check for presentation shape service + { + Reference< XServiceInfo > xServiceInfo( xSet, UNO_QUERY ); + if( !xServiceInfo.is() || !xServiceInfo->supportsService( gsPresShapeService ) ) + return; + } + + mxAnimationsContext->maLastShapeId = maShapeId; + mxAnimationsContext->mxLastShape = xSet; + } + } + else + { + xSet = mxAnimationsContext->mxLastShape; + } + + if( xSet.is() ) + { + if( meKind == XMLE_DIM ) + { + xSet->setPropertyValue( gsDimPrev, Any(true) ); + + xSet->setPropertyValue( gsDimColor, Any(maDimColor) ); + } + else if( meKind == XMLE_PLAY ) + { + xSet->setPropertyValue( gsIsAnimation, Any(true) ); + + // #i42894# speed is not supported for the old group animation fallback, so no need to set it + // aAny <<= meSpeed; + // xSet->setPropertyValue( mpImpl->msSpeed, aAny ); + } + else + { + if( meKind == XMLE_HIDE && !mbTextEffect && meEffect == EK_none ) + { + xSet->setPropertyValue( gsDimHide, Any(true) ); + } + else + { + const AnimationEffect eEffect = ImplSdXMLgetEffect( meEffect, meDirection, mnStartScale, meKind == XMLE_SHOW ); + + if (mbTextEffect) + xSet->setPropertyValue( gsTextEffect, Any( eEffect ) ); + else + xSet->setPropertyValue( gsEffect, Any( eEffect ) ); + xSet->setPropertyValue( gsSpeed, Any( meSpeed ) ); + + if( eEffect == AnimationEffect_PATH && !maPathShapeId.isEmpty() ) + { + Reference< XShape > xPath( GetImport().getInterfaceToIdentifierMapper().getReference( maPathShapeId ), UNO_QUERY ); + if( xPath.is() ) + xSet->setPropertyValue( gsAnimPath, Any( xPath ) ); + } + } + } + } + if( !maSoundURL.isEmpty() ) + { + if( xSet.is() ) + { + xSet->setPropertyValue( gsSound, Any(maSoundURL) ); + xSet->setPropertyValue( gsPlayFull, Any(mbPlayFull) ); + xSet->setPropertyValue( gsSoundOn, Any(true) ); + } + else + { + OSL_FAIL("XMLAnimationsEffectContext::EndElement - Sound URL without a XPropertySet!"); + } + } + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", + "exception caught while importing animation information!"); + } +} + + +XMLAnimationsContext::XMLAnimationsContext( SvXMLImport& rImport ) +: SvXMLImportContext(rImport) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLAnimationsContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return new XMLAnimationsEffectContext( GetImport(), nElement, xAttrList, *this ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/descriptionimp.cxx b/xmloff/source/draw/descriptionimp.cxx new file mode 100644 index 0000000000..c0187f9055 --- /dev/null +++ b/xmloff/source/draw/descriptionimp.cxx @@ -0,0 +1,75 @@ +/* -*- 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 <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlimp.hxx> + +#include "descriptionimp.hxx" + +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::xml; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + + +SdXMLDescriptionContext::SdXMLDescriptionContext( SvXMLImport& rImport, sal_Int32 nElement, const Reference< XShape >& rxShape) +: SvXMLImportContext(rImport), mxShape( rxShape ), mnElement(nElement) +{ +} + +SdXMLDescriptionContext::~SdXMLDescriptionContext() +{ +} + +void SdXMLDescriptionContext::endFastElement(sal_Int32 ) +{ + if( msText.isEmpty() ) + return; + + try + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY_THROW); + if( (mnElement & TOKEN_MASK) == XML_TITLE) + { + xPropSet->setPropertyValue("Title", Any(msText)); + } + else + { + xPropSet->setPropertyValue("Description", Any(msText)); + } + } + catch( uno::Exception& ) + { + } +} + +// This method is called for all characters that are contained in the +// current element. The default is to ignore them. +void SdXMLDescriptionContext::characters( const OUString& rChars ) +{ + msText += rChars; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/descriptionimp.hxx b/xmloff/source/draw/descriptionimp.hxx new file mode 100644 index 0000000000..cc94507727 --- /dev/null +++ b/xmloff/source/draw/descriptionimp.hxx @@ -0,0 +1,46 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/drawing/XShape.hpp> + +// office:events inside a shape + +class SdXMLDescriptionContext final : public SvXMLImportContext +{ +private: + css::uno::Reference< css::drawing::XShape > mxShape; + OUString msText; + sal_Int32 mnElement; +public: + + SdXMLDescriptionContext( SvXMLImport& rImport, sal_Int32 mnElement, + const css::uno::Reference< css::drawing::XShape >& rxShape ); + virtual ~SdXMLDescriptionContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + // This method is called for all characters that are contained in the + // current element. The default is to ignore them. + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/eventimp.cxx b/xmloff/source/draw/eventimp.cxx new file mode 100644 index 0000000000..2b8921ee27 --- /dev/null +++ b/xmloff/source/draw/eventimp.cxx @@ -0,0 +1,453 @@ +/* -*- 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 <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/container/XNameReplace.hpp> +#include <com/sun/star/presentation/AnimationSpeed.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <tools/urlobj.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <o3tl/string_view.hxx> + +#include <sax/tools/converter.hxx> + +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/namespacemap.hxx> +#include "eventimp.hxx" + +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::xml; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::presentation; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry<ClickAction> const aXML_EventActions_EnumMap[] = +{ + { XML_NONE, ClickAction_NONE }, + { XML_PREVIOUS_PAGE, ClickAction_PREVPAGE }, + { XML_NEXT_PAGE, ClickAction_NEXTPAGE }, + { XML_FIRST_PAGE, ClickAction_FIRSTPAGE }, + { XML_LAST_PAGE, ClickAction_LASTPAGE }, + { XML_HIDE, ClickAction_INVISIBLE }, + { XML_STOP, ClickAction_STOPPRESENTATION }, + { XML_EXECUTE, ClickAction_PROGRAM }, + { XML_SHOW, ClickAction_BOOKMARK }, + { XML_SHOW, ClickAction_DOCUMENT }, + { XML_EXECUTE_MACRO, ClickAction_MACRO }, + { XML_VERB, ClickAction_VERB }, + { XML_FADE_OUT, ClickAction_VANISH }, + { XML_SOUND, ClickAction_SOUND }, + { XML_TOKEN_INVALID, ClickAction(0) } +}; + +SdXMLEventContextData::SdXMLEventContextData(const Reference< XShape >& rxShape) + : mxShape(rxShape), mbValid(false), mbScript(false) + , meClickAction(ClickAction_NONE), meEffect(EK_none) + , meDirection(ED_none), mnStartScale(100), meSpeed(AnimationSpeed_MEDIUM) + , mnVerb(0), mbPlayFull(false) +{ +} + +namespace { + +class SdXMLEventContext : public SvXMLImportContext +{ +public: + SdXMLEventContextData maData; + +public: + + SdXMLEventContext( SvXMLImport& rImport, sal_Int32 nElement, const Reference< XFastAttributeList>& xAttrList, const Reference< XShape >& rxShape ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +class XMLEventSoundContext : public SvXMLImportContext +{ +public: + + XMLEventSoundContext( SvXMLImport& rImport, const Reference< XFastAttributeList >& xAttrList, SdXMLEventContext* pParent ); +}; + +} + +XMLEventSoundContext::XMLEventSoundContext( SvXMLImport& rImp, const Reference< XFastAttributeList >& xAttrList, SdXMLEventContext* pParent ) +: SvXMLImportContext( rImp ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(XLINK, XML_HREF): + pParent->maData.msSoundURL = rImp.GetAbsoluteReference(aIter.toString()); + break; + case XML_ELEMENT(PRESENTATION, XML_PLAY_FULL): + pParent->maData.mbPlayFull = IsXMLToken( aIter, XML_TRUE ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXMLEventContext::SdXMLEventContext( SvXMLImport& rImp, + sal_Int32 nElement, + const Reference< XFastAttributeList >& xAttrList, const Reference< XShape >& rxShape ) + : SvXMLImportContext(rImp) + , maData(rxShape) +{ + if( nElement == XML_ELEMENT(PRESENTATION, XML_EVENT_LISTENER) ) + { + maData.mbValid = true; + } + else if( nElement == XML_ELEMENT(SCRIPT, XML_EVENT_LISTENER) ) + { + maData.mbScript = true; + maData.mbValid = true; + } + else + { + return; + } + + // read attributes + OUString sEventName; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(PRESENTATION, XML_ACTION): + SvXMLUnitConverter::convertEnum( maData.meClickAction, aIter.toView(), aXML_EventActions_EnumMap ); + break; + case XML_ELEMENT(PRESENTATION, XML_EFFECT): + SvXMLUnitConverter::convertEnum( maData.meEffect, aIter.toView(), aXML_AnimationEffect_EnumMap ); + break; + case XML_ELEMENT(PRESENTATION, XML_DIRECTION): + SvXMLUnitConverter::convertEnum( maData.meDirection, aIter.toView(), aXML_AnimationDirection_EnumMap ); + break; + case XML_ELEMENT(PRESENTATION, XML_START_SCALE): + { + sal_Int32 nScale; + if (::sax::Converter::convertPercent( nScale, aIter.toView() )) + maData.mnStartScale = static_cast<sal_Int16>(nScale); + } + break; + case XML_ELEMENT(PRESENTATION, XML_SPEED): + SvXMLUnitConverter::convertEnum( maData.meSpeed, aIter.toView(), aXML_AnimationSpeed_EnumMap ); + break; + case XML_ELEMENT(PRESENTATION, XML_VERB): + ::sax::Converter::convertNumber( maData.mnVerb, aIter.toView() ); + break; + case XML_ELEMENT(SCRIPT, XML_EVENT_NAME): + { + sEventName = aIter.toString(); + sal_uInt16 nScriptPrefix = + GetImport().GetNamespaceMap().GetKeyByAttrValueQName(sEventName, &sEventName); + maData.mbValid = XML_NAMESPACE_DOM == nScriptPrefix && sEventName == "click"; + } + break; + case XML_ELEMENT(SCRIPT, XML_LANGUAGE): + { + // language is not evaluated! + OUString aScriptLanguage; + maData.msLanguage = aIter.toString(); + sal_uInt16 nScriptPrefix = rImp.GetNamespaceMap(). + GetKeyByAttrValueQName(maData.msLanguage, &aScriptLanguage); + if( XML_NAMESPACE_OOO == nScriptPrefix ) + maData.msLanguage = aScriptLanguage; + } + break; + case XML_ELEMENT(SCRIPT, XML_MACRO_NAME): + maData.msMacroName = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_HREF): + { + if ( maData.mbScript ) + { + maData.msMacroName = aIter.toString(); + } + else + { + const OUString &rTmp = + rImp.GetAbsoluteReference(aIter.toString()); + INetURLObject::translateToInternal( rTmp, maData.msBookmark, + INetURLObject::DecodeMechanism::Unambiguous ); + } + } + break; + } + } + + if( maData.mbValid ) + maData.mbValid = !sEventName.isEmpty(); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLEventContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(PRESENTATION, XML_SOUND) ) + return new XMLEventSoundContext( GetImport(), xAttrList, this ); + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void SdXMLEventContext::endFastElement(sal_Int32 ) +{ + GetImport().GetShapeImport()->addShapeEvents(maData); +} + +void SdXMLEventContextData::ApplyProperties() +{ + if( !mbValid ) + return; + + do + { + Reference< XEventsSupplier > xEventsSupplier( mxShape, UNO_QUERY ); + if( !xEventsSupplier.is() ) + break; + + Reference< XNameReplace > xEvents( xEventsSupplier->getEvents() ); + SAL_WARN_IF( !xEvents.is(), "xmloff", "XEventsSupplier::getEvents() returned NULL" ); + if( !xEvents.is() ) + break; + + OUString sAPIEventName; + uno::Sequence< beans::PropertyValue > aProperties; + + sAPIEventName = "OnClick"; + + if( mbScript ) + meClickAction = ClickAction_MACRO; + + sal_Int32 nPropertyCount = 2; + switch( meClickAction ) + { + case ClickAction_NONE: + case ClickAction_PREVPAGE: + case ClickAction_NEXTPAGE: + case ClickAction_FIRSTPAGE: + case ClickAction_LASTPAGE: + case ClickAction_INVISIBLE: + case ClickAction_STOPPRESENTATION: + break; + case ClickAction_PROGRAM: + case ClickAction_VERB: + case ClickAction_BOOKMARK: + case ClickAction_DOCUMENT: + nPropertyCount += 1; + break; + case ClickAction_MACRO: + if ( msLanguage.equalsIgnoreAsciiCase("starbasic") ) + nPropertyCount += 1; + break; + + case ClickAction_SOUND: + nPropertyCount += 2; + break; + + case ClickAction_VANISH: + nPropertyCount += 4; + break; + default: + break; + } + + aProperties.realloc( nPropertyCount ); + beans::PropertyValue* pProperties = aProperties.getArray(); + + if( ClickAction_MACRO == meClickAction ) + { + if ( msLanguage.equalsIgnoreAsciiCase("starbasic") ) + { + OUString sLibrary; + const OUString& rApp = GetXMLToken( XML_APPLICATION ); + const OUString& rDoc = GetXMLToken( XML_DOCUMENT ); + if( msMacroName.getLength() > rApp.getLength()+1 && + o3tl::equalsIgnoreAsciiCase(msMacroName.subView(0,rApp.getLength()), rApp) && + ':' == msMacroName[rApp.getLength()] ) + { + sLibrary = "StarOffice"; + msMacroName = msMacroName.copy( rApp.getLength()+1 ); + } + else if( msMacroName.getLength() > rDoc.getLength()+1 && + o3tl::equalsIgnoreAsciiCase(msMacroName.subView(0,rDoc.getLength()), rDoc) && + ':' == msMacroName[rDoc.getLength()] ) + { + sLibrary = rDoc; + msMacroName = msMacroName.copy( rDoc.getLength()+1 ); + } + + pProperties->Name = "EventType"; + pProperties->Handle = -1; + pProperties->Value <<= OUString( "StarBasic" ); + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + pProperties->Name = "MacroName"; + pProperties->Handle = -1; + pProperties->Value <<= msMacroName; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + pProperties->Name = "Library"; + pProperties->Handle = -1; + pProperties->Value <<= sLibrary; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + } + else + { + pProperties->Name = "EventType"; + pProperties->Handle = -1; + pProperties->Value <<= OUString( "Script" ); + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + pProperties->Name = "Script"; + pProperties->Handle = -1; + pProperties->Value <<= msMacroName; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + } + } + else + { + pProperties->Name = "EventType"; + pProperties->Handle = -1; + pProperties->Value <<= OUString( "Presentation" ); + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + // ClickAction_BOOKMARK and ClickAction_DOCUMENT share the same xml event + // so check here if it's really a bookmark or maybe a document + if( meClickAction == ClickAction_BOOKMARK ) + { + if( !msBookmark.startsWith( "#" ) ) + meClickAction = ClickAction_DOCUMENT; + } + + pProperties->Name = "ClickAction"; + pProperties->Handle = -1; + pProperties->Value <<= meClickAction; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + switch( meClickAction ) + { + case ClickAction_NONE: + case ClickAction_PREVPAGE: + case ClickAction_NEXTPAGE: + case ClickAction_FIRSTPAGE: + case ClickAction_LASTPAGE: + case ClickAction_INVISIBLE: + case ClickAction_STOPPRESENTATION: + break; + + case ClickAction_BOOKMARK: + msBookmark = msBookmark.copy(1); + + [[fallthrough]]; + + case ClickAction_DOCUMENT: + case ClickAction_PROGRAM: + pProperties->Name = "Bookmark"; + pProperties->Handle = -1; + pProperties->Value <<= msBookmark; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + break; + + case ClickAction_VANISH: + pProperties->Name = "Effect"; + pProperties->Handle = -1; + pProperties->Value <<= ImplSdXMLgetEffect( meEffect, meDirection, mnStartScale, true ); + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + pProperties->Name = "Speed"; + pProperties->Handle = -1; + pProperties->Value <<= meSpeed; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + [[fallthrough]]; + + case ClickAction_SOUND: + pProperties->Name = "SoundURL"; + pProperties->Handle = -1; + pProperties->Value <<= msSoundURL; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + pProperties->Name = "PlayFull"; + pProperties->Handle = -1; + pProperties->Value <<= mbPlayFull; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + break; + + case ClickAction_VERB: + pProperties->Name = "Verb"; + pProperties->Handle = -1; + pProperties->Value <<= mnVerb; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + break; + case ClickAction_MACRO: + OSL_FAIL("xmloff::SdXMLEventContext::EndElement(), ClickAction_MACRO must be handled in different if case"); + break; + default: + break; + } + } + xEvents->replaceByName( sAPIEventName, uno::Any( aProperties ) ); + + } while(false); +} + + +SdXMLEventsContext::SdXMLEventsContext( SvXMLImport& rImport, const Reference< XShape >& rxShape) +: SvXMLImportContext(rImport), mxShape( rxShape ) +{ +} + +SdXMLEventsContext::~SdXMLEventsContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLEventsContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return new SdXMLEventContext( GetImport(), nElement, xAttrList, mxShape ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/eventimp.hxx b/xmloff/source/draw/eventimp.hxx new file mode 100644 index 0000000000..bb14aea5ed --- /dev/null +++ b/xmloff/source/draw/eventimp.hxx @@ -0,0 +1,68 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/presentation/ClickAction.hpp> +#include <com/sun/star/presentation/AnimationSpeed.hpp> +#include <anim.hxx> + +// office:events inside a shape + +class SdXMLEventsContext : public SvXMLImportContext +{ +private: + css::uno::Reference< css::drawing::XShape > mxShape; + +public: + + SdXMLEventsContext( SvXMLImport& rImport, + const css::uno::Reference< css::drawing::XShape >& rxShape ); + virtual ~SdXMLEventsContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +struct SdXMLEventContextData +{ + SdXMLEventContextData(const css::uno::Reference<css::drawing::XShape>& rxShape); + void ApplyProperties(); + + css::uno::Reference<css::drawing::XShape> mxShape; + + bool mbValid; + bool mbScript; + css::presentation::ClickAction meClickAction; + XMLEffect meEffect; + XMLEffectDirection meDirection; + sal_Int16 mnStartScale; + css::presentation::AnimationSpeed meSpeed; + sal_Int32 mnVerb; + OUString msSoundURL; + bool mbPlayFull; + OUString msMacroName; + OUString msBookmark; + OUString msLanguage; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/layerexp.cxx b/xmloff/source/draw/layerexp.cxx new file mode 100644 index 0000000000..82a8dd410d --- /dev/null +++ b/xmloff/source/draw/layerexp.cxx @@ -0,0 +1,128 @@ +/* -*- 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 <com/sun/star/drawing/XLayerSupplier.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlexp.hxx> +#include "layerexp.hxx" +#include <comphelper/diagnose_ex.hxx> + +using ::com::sun::star::uno::Reference; + +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::xmloff::token; + +void SdXMLayerExporter::exportLayer( SvXMLExport& rExport ) +{ + Reference< XLayerSupplier > xLayerSupplier( rExport.GetModel(), UNO_QUERY ); + if( !xLayerSupplier.is() ) + return; + + Reference< XIndexAccess > xLayerManager( xLayerSupplier->getLayerManager(), UNO_QUERY ); + if( !xLayerManager.is() ) + return; + + const sal_Int32 nCount = xLayerManager->getCount(); + if( nCount == 0 ) + return; + + static constexpr OUStringLiteral strName( u"Name" ); + static constexpr OUStringLiteral strTitle( u"Title" ); + static constexpr OUStringLiteral strDescription( u"Description" ); + static constexpr OUStringLiteral strIsVisible( u"IsVisible"); + static constexpr OUStringLiteral strIsPrintable( u"IsPrintable"); + static constexpr OUStringLiteral strIsLocked( u"IsLocked" ); + + OUString sTmp; + + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_DRAW, XML_LAYER_SET, true, true ); + + for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ ) + { + try + { + Reference< XPropertySet> xLayer( xLayerManager->getByIndex( nIndex ), UNO_QUERY_THROW ); + xLayer->getPropertyValue( strName ) >>= sTmp; + if(!sTmp.isEmpty()) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, sTmp ); + + bool bTmpVisible( true ); + bool bTmpPrintable( true ); + xLayer->getPropertyValue( strIsVisible) >>= bTmpVisible; + xLayer->getPropertyValue( strIsPrintable) >>= bTmpPrintable; + // only write non-default values, default is "always" + if ( bTmpVisible ) + { + if ( !bTmpPrintable ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY, OUString("screen") ); + } + else + { + if ( bTmpPrintable) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY, OUString("printer") ); + else + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY, OUString("none") ); + } + + bool bTmpLocked( false ); + xLayer->getPropertyValue( strIsLocked ) >>= bTmpLocked; + // only write non-default value, default is "false" + if ( bTmpLocked ) + { + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PROTECTED, OUString("true") ); + } + + SvXMLElementExport aEle( rExport, XML_NAMESPACE_DRAW, XML_LAYER, true, true ); + + // title property (as <svg:title> element) + xLayer->getPropertyValue(strTitle) >>= sTmp; + if(!sTmp.isEmpty()) + { + SvXMLElementExport aEventElemt(rExport, XML_NAMESPACE_SVG, XML_TITLE, true, false); + rExport.Characters(sTmp); + } + + // description property (as <svg:desc> element) + xLayer->getPropertyValue(strDescription) >>= sTmp; + if(!sTmp.isEmpty()) + { + SvXMLElementExport aDesc(rExport, XML_NAMESPACE_SVG, XML_DESC, true, false); + rExport.Characters(sTmp); + } + } + catch( Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", "exception caught during export of one layer!"); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/layerexp.hxx b/xmloff/source/draw/layerexp.hxx new file mode 100644 index 0000000000..76c04e1570 --- /dev/null +++ b/xmloff/source/draw/layerexp.hxx @@ -0,0 +1,30 @@ +/* -*- 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 . + */ + +#pragma once + +class SvXMLExport; + +class SdXMLayerExporter +{ +public: + static void exportLayer(SvXMLExport& rExport); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/layerimp.cxx b/xmloff/source/draw/layerimp.cxx new file mode 100644 index 0000000000..eeffae04e9 --- /dev/null +++ b/xmloff/source/draw/layerimp.cxx @@ -0,0 +1,195 @@ +/* -*- 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 <sal/config.h> + +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <com/sun/star/drawing/XLayerManager.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/drawing/XLayerSupplier.hpp> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include "layerimp.hxx" + + +#include <XMLStringBufferImportContext.hxx> + +using namespace ::cppu; +using namespace ::xmloff::token; +using namespace ::com::sun::star; +using namespace ::com::sun::star::xml; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; + +namespace { + +class SdXMLLayerContext : public SvXMLImportContext +{ +public: + SdXMLLayerContext( SvXMLImport& rImport, const Reference< XFastAttributeList >& xAttrList, const Reference< XNameAccess >& xLayerManager ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +private: + css::uno::Reference< css::container::XNameAccess > mxLayerManager; + OUString msName; + OUStringBuffer sDescriptionBuffer; + OUStringBuffer sTitleBuffer; + OUString msDisplay; + OUString msProtected; +}; + +} + +SdXMLLayerContext::SdXMLLayerContext( SvXMLImport& rImport, const Reference< XFastAttributeList >& xAttrList, const Reference< XNameAccess >& xLayerManager ) +: SvXMLImportContext(rImport) +, mxLayerManager( xLayerManager ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + OUString sValue = aIter.toString(); + switch(aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_NAME): + msName = sValue; + break; + case XML_ELEMENT(DRAW, XML_DISPLAY): + msDisplay = sValue; + break; + case XML_ELEMENT(DRAW, XML_PROTECTED): + msProtected = sValue; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLLayerContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if( nElement == XML_ELEMENT(SVG, XML_TITLE) ) + { + return new XMLStringBufferImportContext( GetImport(), sTitleBuffer); + } + else if( nElement == XML_ELEMENT(SVG, XML_DESC) ) + { + return new XMLStringBufferImportContext( GetImport(), sDescriptionBuffer); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void SdXMLLayerContext::endFastElement(sal_Int32 ) +{ + SAL_WARN_IF( msName.isEmpty(), "xmloff", "xmloff::SdXMLLayerContext::EndElement(), draw:layer element without draw:name!" ); + if( msName.isEmpty() ) + return; + + try + { + Reference< XPropertySet > xLayer; + + if( mxLayerManager->hasByName( msName ) ) + { + mxLayerManager->getByName( msName ) >>= xLayer; + SAL_WARN_IF( !xLayer.is(), "xmloff", "xmloff::SdXMLLayerContext::EndElement(), failed to get existing XLayer!" ); + } + else + { + Reference< XLayerManager > xLayerManager( mxLayerManager, UNO_QUERY ); + if( xLayerManager.is() ) + xLayer = xLayerManager->insertNewByIndex( xLayerManager->getCount() ); + SAL_WARN_IF( !xLayer.is(), "xmloff", "xmloff::SdXMLLayerContext::EndElement(), failed to create new XLayer!" ); + + if( xLayer.is() ) + xLayer->setPropertyValue("Name", Any( msName ) ); + } + + if( xLayer.is() ) + { + xLayer->setPropertyValue("Title", Any( sTitleBuffer.makeStringAndClear() ) ); + xLayer->setPropertyValue("Description", Any( sDescriptionBuffer.makeStringAndClear() ) ); + bool bIsVisible( true ); + bool bIsPrintable( true ); + if ( !msDisplay.isEmpty() ) + { + bIsVisible = (msDisplay == "always") || (msDisplay == "screen"); + bIsPrintable = (msDisplay == "always") || (msDisplay == "printer"); + } + xLayer->setPropertyValue("IsVisible", Any( bIsVisible ) ); + xLayer->setPropertyValue("IsPrintable", Any( bIsPrintable ) ); + bool bIsLocked( false ); + if ( !msProtected.isEmpty() ) + bIsLocked = (msProtected == "true"); + xLayer->setPropertyValue("IsLocked", Any( bIsLocked ) ); + + // tdf#129898 repair layer "DrawnInSlideshow", which was wrongly written + // in LO 6.2 to 6.4. It should always have ODF defaults. + if (msName == "DrawnInSlideshow") + { + xLayer->setPropertyValue("IsVisible", Any(true)); + xLayer->setPropertyValue("IsPrintable", Any(true)); + xLayer->setPropertyValue("IsLocked", Any(false)); + } + } + } + catch( Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + + +SdXMLLayerSetContext::SdXMLLayerSetContext( SvXMLImport& rImport ) +: SvXMLImportContext(rImport) +{ + Reference< XLayerSupplier > xLayerSupplier( rImport.GetModel(), UNO_QUERY ); + SAL_WARN_IF( !xLayerSupplier.is(), "xmloff", "xmloff::SdXMLLayerSetContext::SdXMLLayerSetContext(), XModel is not supporting XLayerSupplier!" ); + if( xLayerSupplier.is() ) + mxLayerManager = xLayerSupplier->getLayerManager(); +} + +SdXMLLayerSetContext::~SdXMLLayerSetContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLLayerSetContext::createFastChildContext( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return new SdXMLLayerContext( GetImport(), xAttrList, mxLayerManager ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/layerimp.hxx b/xmloff/source/draw/layerimp.hxx new file mode 100644 index 0000000000..4d3b899419 --- /dev/null +++ b/xmloff/source/draw/layerimp.hxx @@ -0,0 +1,41 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/container/XNameAccess.hpp> + +// presentations:animations + +class SdXMLLayerSetContext : public SvXMLImportContext +{ +private: + css::uno::Reference< css::container::XNameAccess > mxLayerManager; + +public: + SdXMLLayerSetContext( SvXMLImport& rImport ); + virtual ~SdXMLLayerSetContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/numithdl.cxx b/xmloff/source/draw/numithdl.cxx new file mode 100644 index 0000000000..4797f6edf9 --- /dev/null +++ b/xmloff/source/draw/numithdl.cxx @@ -0,0 +1,54 @@ +/* -*- 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 <utility> + +#include "numithdl.hxx" + +using namespace ::com::sun::star; + + + + +XMLNumRulePropHdl::XMLNumRulePropHdl( css::uno::Reference< css::ucb::XAnyCompare > xNumRuleCompare ) +: mxNumRuleCompare(std::move( xNumRuleCompare )) +{ +} + +XMLNumRulePropHdl::~XMLNumRulePropHdl() +{ + // Nothing to do +} + +bool XMLNumRulePropHdl::equals( const uno::Any& r1, const uno::Any& r2 ) const +{ + return mxNumRuleCompare.is() && mxNumRuleCompare->compare( r1, r2 ) == 0; +} + +bool XMLNumRulePropHdl::importXML( const OUString& /*rStrImpValue*/, css::uno::Any& /*rValue*/, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + return false; +} + +bool XMLNumRulePropHdl::exportXML( OUString& /*rStrExpValue*/, const css::uno::Any& /*rValue*/, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/numithdl.hxx b/xmloff/source/draw/numithdl.hxx new file mode 100644 index 0000000000..503c4c7b6c --- /dev/null +++ b/xmloff/source/draw/numithdl.hxx @@ -0,0 +1,43 @@ +/* -*- 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 . + */ + +#pragma once + +#include <com/sun/star/ucb/XAnyCompare.hpp> +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the list-style +*/ +class XMLNumRulePropHdl : public XMLPropertyHandler +{ +private: + css::uno::Reference< css::ucb::XAnyCompare > mxNumRuleCompare; +public: + explicit XMLNumRulePropHdl( css::uno::Reference< css::ucb::XAnyCompare > xNumRuleCompare ); + virtual ~XMLNumRulePropHdl() override; + + virtual bool equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const override; + + /// NumRules will be imported/exported as XML-Elements. So the Import/Export-work must be done at another place. + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/propimp0.cxx b/xmloff/source/draw/propimp0.cxx new file mode 100644 index 0000000000..92bb46bdac --- /dev/null +++ b/xmloff/source/draw/propimp0.cxx @@ -0,0 +1,262 @@ +/* -*- 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 <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <propimp0.hxx> +#include <com/sun/star/util/Duration.hpp> +#include <com/sun/star/uno/Any.hxx> + +#include <sax/tools/converter.hxx> + +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlimp.hxx> + +#include <tools/time.hxx> + +using namespace ::com::sun::star; + +// implementation of graphic property Stroke + +// implementation of presentation page property Change + +// implementation of an effect duration property handler + +XMLDurationPropertyHdl::~XMLDurationPropertyHdl() +{ +} + +bool XMLDurationPropertyHdl::importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const +{ + util::Duration aDuration; + + if (::sax::Converter::convertDuration(aDuration, rStrImpValue)) + { + const double fSeconds = ((aDuration.Days * 24 + aDuration.Hours) * 60 + + aDuration.Minutes) * 60 + + aDuration.Seconds + + aDuration.NanoSeconds / static_cast<double>(::tools::Time::nanoSecPerSec); + rValue <<= fSeconds; + + return true; + } + + SAL_WARN_IF(!rStrImpValue.isEmpty(), "xmloff", "Invalid duration: " << rStrImpValue); + + return false; +} + +bool XMLDurationPropertyHdl::exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const +{ + double nVal = 0; + + if(rValue >>= nVal) + { + util::Duration aDuration; + aDuration.Seconds = static_cast<sal_uInt16>(nVal); + aDuration.NanoSeconds = static_cast<sal_uInt32>((nVal - aDuration.Seconds) * ::tools::Time::nanoSecPerSec); + + OUStringBuffer aOut; + ::sax::Converter::convertDuration(aOut, aDuration); + rStrExpValue = aOut.makeStringAndClear(); + return true; + } + + return false; +} + +// implementation of an opacity property handler + +XMLOpacityPropertyHdl::XMLOpacityPropertyHdl( SvXMLImport* pImport ) +: mpImport( pImport ) +{ +} + +XMLOpacityPropertyHdl::~XMLOpacityPropertyHdl() +{ +} + +bool XMLOpacityPropertyHdl::importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nValue = 0; + + if( rStrImpValue.indexOf( '%' ) != -1 ) + { + if (::sax::Converter::convertPercent( nValue, rStrImpValue )) + bRet = true; + } + else + { + nValue = sal_Int32( rStrImpValue.toDouble() * 100.0 ); + bRet = true; + } + + if( bRet ) + { + // check ranges + if( nValue < 0 ) + nValue = 0; + if( nValue > 100 ) + nValue = 100; + + // convert xml opacity to api transparency + nValue = 100 - nValue; + + // #i42959# + if( mpImport ) + { + sal_Int32 nUPD, nBuild; + if( mpImport->getBuildIds( nUPD, nBuild ) ) + { + // correct import of documents written prior to StarOffice 8/OOO 2.0 final + if( (nUPD == 680) && (nBuild < 8951) ) + nValue = 100 - nValue; + } + } + + rValue <<= sal_uInt16(nValue); + } + + return bRet; +} + +bool XMLOpacityPropertyHdl::exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nVal = sal_uInt16(); + + if( rValue >>= nVal ) + { + OUStringBuffer aOut; + + nVal = 100 - nVal; + ::sax::Converter::convertPercent( aOut, nVal ); + rStrExpValue = aOut.makeStringAndClear(); + bRet = true; + } + + return bRet; +} + +// implementation of a text animation step amount + +XMLTextAnimationStepPropertyHdl::~XMLTextAnimationStepPropertyHdl() +{ +} + +bool XMLTextAnimationStepPropertyHdl::importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + sal_Int32 nValue = 0; + + sal_Int32 nPos = rStrImpValue.indexOf( "px" ); + if( nPos != -1 ) + { + if (::sax::Converter::convertNumber(nValue, rStrImpValue.subView(0, nPos))) + { + rValue <<= sal_Int16( -nValue ); + bRet = true; + } + } + else + { + if (rUnitConverter.convertMeasureToCore( nValue, rStrImpValue )) + { + rValue <<= sal_Int16( nValue ); + bRet = true; + } + } + + return bRet; +} + +bool XMLTextAnimationStepPropertyHdl::exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + sal_Int16 nVal = sal_Int16(); + + if( rValue >>= nVal ) + { + OUStringBuffer aOut; + + if( nVal < 0 ) + { + aOut.append( OUString::number(static_cast<sal_Int32>(-nVal) ) + "px" ); + } + else + { + rUnitConverter.convertMeasureToXML( aOut, nVal ); + } + + rStrExpValue = aOut.makeStringAndClear(); + bRet = true; + } + + return bRet; +} + +XMLDateTimeFormatHdl::XMLDateTimeFormatHdl( SvXMLExport* pExport ) +: mpExport( pExport ) +{ +} + +XMLDateTimeFormatHdl::~XMLDateTimeFormatHdl() +{ +} + +bool XMLDateTimeFormatHdl::importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + rValue <<= rStrImpValue; + return true; +} + +bool XMLDateTimeFormatHdl::exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nNumberFormat = 0; + if( mpExport && (rValue >>= nNumberFormat) ) + { + mpExport->addDataStyle( nNumberFormat ); + rStrExpValue = mpExport->getDataStyleName( nNumberFormat ); + return true; + } + + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/sdpropls.cxx b/xmloff/source/draw/sdpropls.cxx new file mode 100644 index 0000000000..50ccd70a49 --- /dev/null +++ b/xmloff/source/draw/sdpropls.cxx @@ -0,0 +1,1923 @@ +/* -*- 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 <com/sun/star/animations/TransitionType.hpp> +#include <com/sun/star/ucb/XAnyCompareFactory.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/LineJoint.hpp> +#include <com/sun/star/drawing/LineCap.hpp> +#include <com/sun/star/presentation/AnimationSpeed.hpp> +#include <com/sun/star/presentation/FadeEffect.hpp> + +#include <com/sun/star/text/WritingMode.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <utility> +#include <xmloff/EnumPropertyHdl.hxx> +#include <xmloff/NamedBoolPropertyHdl.hxx> +#include <WordWrapPropertyHdl.hxx> +#include <enummaps.hxx> +#include "numithdl.hxx" +#include <XMLBitmapRepeatOffsetPropertyHandler.hxx> +#include <XMLFillBitmapSizePropertyHandler.hxx> +#include <XMLBitmapLogicalSizePropertyHandler.hxx> +#include <com/sun/star/drawing/TextAnimationKind.hpp> +#include <com/sun/star/drawing/TextAnimationDirection.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> +#include <com/sun/star/drawing/TextVerticalAdjust.hpp> +#include <com/sun/star/drawing/TextFitToSizeType.hpp> +#include <com/sun/star/drawing/MeasureTextHorzPos.hpp> +#include <com/sun/star/drawing/MeasureTextVertPos.hpp> +#include <xmloff/controlpropertyhdl.hxx> +#include <xmloff/xmltoken.hxx> +#include "sdpropls.hxx" +#include <propimp0.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <com/sun/star/drawing/NormalsKind.hpp> +#include <com/sun/star/drawing/TextureProjectionMode.hpp> +#include <com/sun/star/drawing/TextureKind.hpp> +#include <com/sun/star/drawing/TextureMode.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <xmloff/txtprmap.hxx> +#include <XMLClipPropertyHandler.hxx> +#include <XMLIsPercentagePropertyHandler.hxx> +#include <XMLPercentOrMeasurePropertyHandler.hxx> +#include <XMLTextColumnsPropertyHandler.hxx> +#include <xmloff/XMLComplexColorHandler.hxx> +#include <animations.hxx> +#include <sax/tools/converter.hxx> +#include <xmlsdtypes.hxx> +#include <xmlprop.hxx> + +using ::com::sun::star::uno::Any; + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +#define MAP_(name,prefix,token,type,context) { name, prefix, token, type, context, SvtSaveOptions::ODFSVER_010, false } +#define MAPV_(name,prefix,token,type,context,version) { name, prefix, token, type, context, version, false } +#define GMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_GRAPHIC,context) +#define GMAP_D(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_GRAPHIC|MID_FLAG_DEFAULT_ITEM_EXPORT,context) +#define GMAPV(name,prefix,token,type,context,version) MAPV_(name,prefix,token,type|XML_TYPE_PROP_GRAPHIC,context,version) +#define DPMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_DRAWING_PAGE,context) +#define TMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_TEXT,context) +#define PMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_PARAGRAPH,context) +#define MAP_END() { nullptr } + +// entry list for graphic properties + +const XMLPropertyMapEntry aXMLSDProperties[] = +{ + // this entry must be first! this is needed for XMLShapeImportHelper::CreateExternalShapePropMapper + + // ^^^though CreateExternalShapePropMapper is gone now, hmm^^^ + GMAP( PROP_UserDefinedAttributes, XML_NAMESPACE_TEXT, XML_XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), + + // stroke attributes + GMAP( PROP_LineStyle, XML_NAMESPACE_DRAW, XML_STROKE, XML_SD_TYPE_STROKE, 0 ), + GMAP( PROP_LineDashName, XML_NAMESPACE_DRAW, XML_STROKE_DASH, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT , CTF_DASHNAME ), + GMAP( PROP_LineWidth, XML_NAMESPACE_SVG, XML_STROKE_WIDTH, XML_TYPE_MEASURE, 0 ), + GMAP_D( PROP_LineColor, XML_NAMESPACE_SVG, XML_STROKE_COLOR, XML_TYPE_COLOR, 0), + GMAPV( PROP_LineComplexColor, XML_NAMESPACE_LO_EXT, XML_STROKE_COMPLEX_COLOR, XML_TYPE_COMPLEX_COLOR|MID_FLAG_ELEMENT_ITEM, CTF_COMPLEX_COLOR, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAP( PROP_LineStartName, XML_NAMESPACE_DRAW, XML_MARKER_START, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_LINESTARTNAME ), + GMAP( PROP_LineStartWidth, XML_NAMESPACE_DRAW, XML_MARKER_START_WIDTH, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_LineStartCenter, XML_NAMESPACE_DRAW, XML_MARKER_START_CENTER, XML_TYPE_BOOL, 0 ), + GMAP( PROP_LineEndName, XML_NAMESPACE_DRAW, XML_MARKER_END, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_LINEENDNAME ), + GMAP( PROP_LineEndWidth, XML_NAMESPACE_DRAW, XML_MARKER_END_WIDTH, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_LineEndCenter, XML_NAMESPACE_DRAW, XML_MARKER_END_CENTER, XML_TYPE_BOOL, 0 ), + GMAP( PROP_LineTransparence, XML_NAMESPACE_SVG, XML_STROKE_OPACITY, XML_SD_TYPE_OPACITY, 0 ), + GMAP( PROP_LineJoint, XML_NAMESPACE_DRAW, XML_STROKE_LINEJOIN, XML_SD_TYPE_LINEJOIN, 0 ), + GMAP( PROP_LineCap, XML_NAMESPACE_SVG , XML_STROKE_LINECAP, XML_SD_TYPE_LINECAP, 0 ), + + // fill attributes + GMAP( PROP_FillStyle, XML_NAMESPACE_DRAW, XML_FILL, XML_SD_TYPE_FILLSTYLE, CTF_FILLSTYLE ), + GMAP_D(PROP_FillColor, XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, CTF_FILLCOLOR ), + GMAP_D(PROP_FillColor2, XML_NAMESPACE_DRAW, XML_SECONDARY_FILL_COLOR, XML_TYPE_COLOR, 0), + GMAPV( PROP_FillComplexColor, XML_NAMESPACE_LO_EXT, XML_FILL_COMPLEX_COLOR, XML_TYPE_COMPLEX_COLOR|MID_FLAG_ELEMENT_ITEM, CTF_COMPLEX_COLOR, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAP( PROP_FillGradientName, XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLGRADIENTNAME ), + GMAP( PROP_FillGradientStepCount, XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER16, 0 ), + GMAP( PROP_FillHatchName, XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLHATCHNAME ), + GMAP( PROP_FillBackground, XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, 0 ), + GMAPV( PROP_FillUseSlideBackground, XML_NAMESPACE_LO_EXT, XML_FILL_USE_SLIDE_BACKGROUND, XML_TYPE_BOOL, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAP( PROP_FillBitmapName, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLBITMAPNAME ), + GMAP( PROP_FillTransparence, XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + GMAP( PROP_FillTransparenceGradientName, XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLTRANSNAME ), + GMAP( PROP_FillBitmapSizeX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SD_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SD_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapSizeY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SD_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SD_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapMode, XML_NAMESPACE_STYLE,XML_REPEAT, XML_SD_TYPE_BITMAP_MODE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_FillBitmapPositionOffsetX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, 0 ), + GMAP( PROP_FillBitmapPositionOffsetY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, 0 ), + GMAP( PROP_FillBitmapRectanglePoint, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SD_TYPE_BITMAP_REFPOINT, 0 ), + GMAP( PROP_FillBitmapOffsetX, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SD_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_X ), + GMAP( PROP_FillBitmapOffsetY, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SD_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_Y ), + + // text frame attributes + GMAP( PROP_TextHorizontalAdjust, XML_NAMESPACE_DRAW, XML_TEXTAREA_HORIZONTAL_ALIGN, XML_SD_TYPE_TEXT_ALIGN, 0 ), + GMAP( PROP_TextVerticalAdjust, XML_NAMESPACE_DRAW, XML_TEXTAREA_VERTICAL_ALIGN, XML_SD_TYPE_VERTICAL_ALIGN, 0 ), + GMAP( PROP_TextAutoGrowHeight, XML_NAMESPACE_DRAW, XML_AUTO_GROW_HEIGHT, XML_TYPE_BOOL, 0 ), + GMAP( PROP_TextAutoGrowWidth, XML_NAMESPACE_DRAW, XML_AUTO_GROW_WIDTH, XML_TYPE_BOOL, 0 ), + GMAP( PROP_TextFitToSize, XML_NAMESPACE_DRAW, XML_FIT_TO_SIZE, XML_SD_TYPE_FITTOSIZE|MID_FLAG_MERGE_PROPERTY, 0), + GMAPV( PROP_TextFitToSize, XML_NAMESPACE_STYLE, XML_SHRINK_TO_FIT, XML_SD_TYPE_FITTOSIZE_AUTOFIT|MID_FLAG_MERGE_PROPERTY, 0, SvtSaveOptions::ODFSVER_012 ), + GMAP( PROP_TextContourFrame, XML_NAMESPACE_DRAW, XML_FIT_TO_CONTOUR, XML_TYPE_BOOL, 0 ), + GMAP( PROP_TextMaximumFrameHeight, XML_NAMESPACE_FO, XML_MAX_HEIGHT, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_TextMaximumFrameWidth, XML_NAMESPACE_FO, XML_MAX_WIDTH, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_TextMinimumFrameHeight, XML_NAMESPACE_FO, XML_MIN_HEIGHT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + GMAP( PROP_TextMinimumFrameWidth, XML_NAMESPACE_FO, XML_MIN_WIDTH, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_TextUpperDistance, XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + GMAP( PROP_TextLowerDistance, XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + GMAP( PROP_TextLeftDistance, XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + GMAP( PROP_TextRightDistance, XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + PMAP( PROP_TextWritingMode, XML_NAMESPACE_STYLE,XML_WRITING_MODE, XML_SD_TYPE_WRITINGMODE|MID_FLAG_MULTI_PROPERTY, CTF_WRITINGMODE ), + GMAP( PROP_NumberingRules, XML_NAMESPACE_TEXT, XML_LIST_STYLE, XML_SD_TYPE_NUMBULLET|MID_FLAG_ELEMENT_ITEM, CTF_NUMBERINGRULES ), + GMAP( PROP_NumberingRules, XML_NAMESPACE_TEXT, XML_LIST_STYLE_NAME, XML_TYPE_STRING, CTF_SD_NUMBERINGRULES_NAME ), + GMAP( PROP_TextWordWrap, XML_NAMESPACE_FO, XML_WRAP_OPTION, XML_TYPE_WRAP_OPTION, 0 ), + GMAP( PROP_TextChainNextName, XML_NAMESPACE_DRAW, XML_CHAIN_NEXT_NAME, XML_TYPE_STRING, 0 ), + GMAP( PROP_TextClipVerticalOverflow, XML_NAMESPACE_STYLE, XML_OVERFLOW_BEHAVIOR, XML_TYPE_TEXT_OVERFLOW_BEHAVIOR, 0 ), + + GMAP( PROP_TextColumns, XML_NAMESPACE_STYLE, XML_COLUMNS, XML_TYPE_TEXT_COLUMNS|MID_FLAG_ELEMENT_ITEM, CTF_TEXTCOLUMNS ), + + // shadow attributes + GMAP( PROP_Shadow, XML_NAMESPACE_DRAW, XML_SHADOW, XML_SD_TYPE_VISIBLE_HIDDEN, 0 ), + GMAP( PROP_ShadowXDistance, XML_NAMESPACE_DRAW, XML_SHADOW_OFFSET_X, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_ShadowYDistance, XML_NAMESPACE_DRAW, XML_SHADOW_OFFSET_Y, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_ShadowColor, XML_NAMESPACE_DRAW, XML_SHADOW_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( PROP_ShadowTransparence, XML_NAMESPACE_DRAW, XML_SHADOW_OPACITY, XML_TYPE_NEG_PERCENT, 0 ), + GMAPV( PROP_ShadowBlur, XML_NAMESPACE_LO_EXT, XML_SHADOW_BLUR, XML_TYPE_MEASURE, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + + // glow attributes + GMAPV( PROP_GlowEffectRadius, XML_NAMESPACE_LO_EXT, XML_GLOW_RADIUS, XML_TYPE_MEASURE , 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( PROP_GlowEffectColor, XML_NAMESPACE_LO_EXT, XML_GLOW_COLOR, XML_TYPE_COLOR , 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( PROP_GlowEffectTransparency, XML_NAMESPACE_LO_EXT, XML_GLOW_TRANSPARENCY, XML_TYPE_PERCENT16, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + + // soft edge attributes + GMAPV( PROP_SoftEdgeRadius, XML_NAMESPACE_LO_EXT, XML_SOFTEDGE_RADIUS, XML_TYPE_MEASURE , 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + + // graphic attributes + GMAP( PROP_GraphicColorMode, XML_NAMESPACE_DRAW, XML_COLOR_MODE, XML_TYPE_COLOR_MODE, 0 ), // exists in SW, too, with same property name + GMAP( PROP_AdjustLuminance, XML_NAMESPACE_DRAW, XML_LUMINANCE, XML_TYPE_PERCENT16, 0 ), // signed? exists in SW, too, with same property name + GMAP( PROP_AdjustContrast, XML_NAMESPACE_DRAW, XML_CONTRAST, XML_TYPE_PERCENT16, 0 ), // signed? exists in SW, too, with same property name + GMAP( PROP_Gamma, XML_NAMESPACE_DRAW, XML_GAMMA, XML_TYPE_DOUBLE_PERCENT, 0 ), // signed? exists in SW, too, with same property name + GMAP( PROP_AdjustRed, XML_NAMESPACE_DRAW, XML_RED, XML_TYPE_PERCENT16, 0 ), // signed? exists in SW, too, with same property name + GMAP( PROP_AdjustGreen, XML_NAMESPACE_DRAW, XML_GREEN, XML_TYPE_PERCENT16, 0 ), // signed? exists in SW, too, with same property name + GMAP( PROP_AdjustBlue, XML_NAMESPACE_DRAW, XML_BLUE, XML_TYPE_PERCENT16, 0 ), // signed? exists in SW, too, with same property name + GMAPV( PROP_GraphicCrop, XML_NAMESPACE_FO, XML_CLIP, XML_TYPE_TEXT_CLIP, CTF_TEXT_CLIP, SvtSaveOptions::ODFSVER_012), // exists in SW, too, with same property name + GMAP( PROP_GraphicCrop, XML_NAMESPACE_FO, XML_CLIP, XML_TYPE_TEXT_CLIP11, CTF_TEXT_CLIP11 ), // exists in SW, too, with same property name + GMAP( PROP_Transparency, XML_NAMESPACE_DRAW, XML_IMAGE_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too, with same property name // #i25616# + GMAP( PROP_IsMirrored, XML_NAMESPACE_STYLE, XML_MIRROR, XML_TYPE_SD_MIRROR|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too // #i40214# + + // animation text attributes + TMAP( PROP_TextAnimationKind, XML_NAMESPACE_STYLE,XML_TEXT_BLINKING, XML_TYPE_TEXT_ANIMATION_BLINKING, CTF_TEXTANIMATION_BLINKING ), + GMAP( PROP_TextAnimationKind, XML_NAMESPACE_TEXT, XML_ANIMATION, XML_TYPE_TEXT_ANIMATION, CTF_TEXTANIMATION_KIND ), + GMAP( PROP_TextAnimationDirection, XML_NAMESPACE_TEXT, XML_ANIMATION_DIRECTION, XML_TYPE_TEXT_ANIMATION_DIRECTION, 0 ), + GMAP( PROP_TextAnimationStartInside, XML_NAMESPACE_TEXT, XML_ANIMATION_START_INSIDE, XML_TYPE_BOOL, 0 ), + GMAP( PROP_TextAnimationStopInside, XML_NAMESPACE_TEXT, XML_ANIMATION_STOP_INSIDE, XML_TYPE_BOOL, 0 ), + GMAP( PROP_TextAnimationCount, XML_NAMESPACE_TEXT, XML_ANIMATION_REPEAT, XML_TYPE_NUMBER16, 0 ), + GMAP( PROP_TextAnimationDelay, XML_NAMESPACE_TEXT, XML_ANIMATION_DELAY, XML_TYPE_DURATION16_MS, 0 ), + GMAP( PROP_TextAnimationAmount, XML_NAMESPACE_TEXT, XML_ANIMATION_STEPS, XML_TYPE_TEXT_ANIMATION_STEPS, 0 ), + + // connector attributes + GMAP( PROP_EdgeNode1HorzDist, XML_NAMESPACE_DRAW, XML_START_LINE_SPACING_HORIZONTAL, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_EdgeNode1VertDist, XML_NAMESPACE_DRAW, XML_START_LINE_SPACING_VERTICAL, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_EdgeNode2HorzDist, XML_NAMESPACE_DRAW, XML_END_LINE_SPACING_HORIZONTAL, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_EdgeNode2VertDist, XML_NAMESPACE_DRAW, XML_END_LINE_SPACING_VERTICAL, XML_TYPE_MEASURE, 0 ), + + // measure attributes + GMAP( PROP_MeasureLineDistance, XML_NAMESPACE_DRAW, XML_LINE_DISTANCE, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_MeasureHelpLineOverhang, XML_NAMESPACE_DRAW, XML_GUIDE_OVERHANG, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_MeasureHelpLineDistance, XML_NAMESPACE_DRAW, XML_GUIDE_DISTANCE, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_MeasureHelpLine1Length, XML_NAMESPACE_DRAW, XML_START_GUIDE, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_MeasureHelpLine2Length, XML_NAMESPACE_DRAW, XML_END_GUIDE, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_MeasureTextHorizontalPosition, XML_NAMESPACE_DRAW, XML_MEASURE_ALIGN, XML_SD_TYPE_MEASURE_HALIGN, 0 ), + GMAP( PROP_MeasureTextVerticalPosition, XML_NAMESPACE_DRAW, XML_MEASURE_VERTICAL_ALIGN, XML_SD_TYPE_MEASURE_VALIGN, 0 ), + GMAP( PROP_MeasureUnit, XML_NAMESPACE_DRAW, XML_UNIT, XML_SD_TYPE_MEASURE_UNIT, 0 ), + GMAP( PROP_MeasureShowUnit, XML_NAMESPACE_DRAW, XML_SHOW_UNIT, XML_TYPE_BOOL, 0 ), + GMAP( PROP_MeasureBelowReferenceEdge, XML_NAMESPACE_DRAW, XML_PLACING, XML_SD_TYPE_MEASURE_PLACING, 0 ), + GMAP( PROP_MeasureTextRotate90, XML_NAMESPACE_DRAW, XML_PARALLEL, XML_TYPE_BOOL, 0 ), + GMAP( PROP_MeasureDecimalPlaces, XML_NAMESPACE_DRAW, XML_DECIMAL_PLACES, XML_TYPE_NUMBER16, 0 ), + + // 3D geometry attributes + GMAP( PROP_D3DHorizontalSegments, XML_NAMESPACE_DR3D, XML_HORIZONTAL_SEGMENTS, XML_TYPE_NUMBER, 0 ), + GMAP( PROP_D3DVerticalSegments, XML_NAMESPACE_DR3D, XML_VERTICAL_SEGMENTS, XML_TYPE_NUMBER, 0 ), + GMAP( PROP_D3DPercentDiagonal, XML_NAMESPACE_DR3D, XML_EDGE_ROUNDING, XML_TYPE_PERCENT, 0 ), + GMAP( PROP_D3DBackscale, XML_NAMESPACE_DR3D, XML_BACK_SCALE, XML_TYPE_PERCENT, 0 ), + GMAP( PROP_D3DEndAngle, XML_NAMESPACE_DR3D, XML_END_ANGLE, XML_TYPE_NUMBER, 0 ), + GMAP( PROP_D3DDepth, XML_NAMESPACE_DR3D, XML_DEPTH, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_D3DDoubleSided, XML_NAMESPACE_DR3D, XML_BACKFACE_CULLING, XML_SD_TYPE_BACKFACE_CULLING, 0 ), + + // #107245# New 3D properties which are possible for lathe and extrude 3d objects + GMAP( PROP_D3DCloseFront, XML_NAMESPACE_DR3D, XML_CLOSE_FRONT, XML_TYPE_BOOL, 0 ), + GMAP( PROP_D3DCloseBack, XML_NAMESPACE_DR3D, XML_CLOSE_BACK, XML_TYPE_BOOL, 0 ), + + // 3D lighting attributes + GMAP( PROP_D3DNormalsKind, XML_NAMESPACE_DR3D, XML_NORMALS_KIND, XML_SD_TYPE_NORMALS_KIND, 0 ), + GMAP( PROP_D3DNormalsInvert, XML_NAMESPACE_DR3D, XML_NORMALS_DIRECTION, XML_SD_TYPE_NORMALS_DIRECTION, 0 ), + + // 3D texture attributes + GMAP( PROP_D3DTextureProjectionX, XML_NAMESPACE_DR3D, XML_TEX_GENERATION_MODE_X, XML_SD_TYPE_TEX_GENERATION_MODE_X, 0 ), + GMAP( PROP_D3DTextureProjectionY, XML_NAMESPACE_DR3D, XML_TEX_GENERATION_MODE_Y, XML_SD_TYPE_TEX_GENERATION_MODE_Y, 0 ), + GMAP( PROP_D3DTextureKind, XML_NAMESPACE_DR3D, XML_TEX_KIND, XML_SD_TYPE_TEX_KIND, 0 ), + GMAP( PROP_D3DTextureMode, XML_NAMESPACE_DR3D, XML_TEX_MODE, XML_SD_TYPE_TEX_MODE, 0 ), + GMAP( PROP_D3DTextureFilter, XML_NAMESPACE_DR3D, XML_TEX_FILTER, XML_SD_TYPE_BACKFACE_CULLING, 0 ), + + // 3D material attributes + GMAP( PROP_D3DMaterialColor, XML_NAMESPACE_DR3D, XML_DIFFUSE_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( PROP_D3DMaterialEmission, XML_NAMESPACE_DR3D, XML_EMISSIVE_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( PROP_D3DMaterialSpecular, XML_NAMESPACE_DR3D, XML_SPECULAR_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( PROP_D3DMaterialSpecularIntensity, XML_NAMESPACE_DR3D, XML_SHININESS, XML_TYPE_PERCENT, 0 ), + + // 3D shadow attributes + GMAP( PROP_D3DShadow3D, XML_NAMESPACE_DR3D, XML_SHADOW, XML_SD_TYPE_VISIBLE_HIDDEN, 0 ), + + // #FontWork# attributes + GMAP( PROP_FontWorkStyle, XML_NAMESPACE_DRAW, XML_FONTWORK_STYLE, XML_SD_TYPE_FONTWORK_STYLE| MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_STYLE ), + GMAP( PROP_FontWorkAdjust, XML_NAMESPACE_DRAW, XML_FONTWORK_ADJUST, XML_SD_TYPE_FONTWORK_ADJUST | MID_FLAG_ELEMENT_ITEM_EXPORT,CTF_FONTWORK_ADJUST ), + GMAP( PROP_FontWorkDistance, XML_NAMESPACE_DRAW, XML_FONTWORK_DISTANCE, XML_TYPE_MEASURE | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_DISTANCE ), + GMAP( PROP_FontWorkStart, XML_NAMESPACE_DRAW, XML_FONTWORK_START, XML_TYPE_MEASURE | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_START ), + GMAP( PROP_FontWorkMirror, XML_NAMESPACE_DRAW, XML_FONTWORK_MIRROR, XML_TYPE_BOOL | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_MIRROR ), + GMAP( PROP_FontWorkOutline, XML_NAMESPACE_DRAW, XML_FONTWORK_OUTLINE, XML_TYPE_BOOL | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_OUTLINE ), + GMAP( PROP_FontWorkShadow, XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW, XML_SD_TYPE_FONTWORK_SHADOW | MID_FLAG_ELEMENT_ITEM_EXPORT,CTF_FONTWORK_SHADOW ), + GMAP( PROP_FontWorkShadowColor, XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW_COLOR, XML_TYPE_COLOR | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_SHADOWCOLOR ), + GMAP( PROP_FontWorkShadowOffsetX, XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW_OFFSET_X, XML_TYPE_MEASURE | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_SHADOWOFFSETX ), + GMAP( PROP_FontWorkShadowOffsetY, XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW_OFFSET_Y, XML_TYPE_MEASURE | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_SHADOWOFFSETY ), + GMAP( PROP_FontWorkForm, XML_NAMESPACE_DRAW, XML_FONTWORK_FORM, XML_SD_TYPE_FONTWORK_FORM | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_FORM ), + GMAP( PROP_FontWorkHideForm, XML_NAMESPACE_DRAW, XML_FONTWORK_HIDE_FORM, XML_TYPE_BOOL | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_HIDEFORM ), + GMAP( PROP_FontWorkShadowTransparence, XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW_TRANSPARENCE, XML_TYPE_PERCENT | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_SHADOWTRANSPARENCE ), + + // #FontWork# attributes + GMAPV( PROP_FontWorkStyle, XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_STYLE, XML_SD_TYPE_FONTWORK_STYLE, CTF_FONTWORK_STYLE, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( PROP_FontWorkAdjust, XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_ADJUST, XML_SD_TYPE_FONTWORK_ADJUST,CTF_FONTWORK_ADJUST, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( PROP_FontWorkDistance, XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_DISTANCE, XML_TYPE_MEASURE, CTF_FONTWORK_DISTANCE, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( PROP_FontWorkStart, XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_START, XML_TYPE_MEASURE, CTF_FONTWORK_START, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( PROP_FontWorkMirror, XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_MIRROR, XML_TYPE_BOOL, CTF_FONTWORK_MIRROR, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( PROP_FontWorkOutline, XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_OUTLINE, XML_TYPE_BOOL, CTF_FONTWORK_OUTLINE, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( PROP_FontWorkShadow, XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_SHADOW, XML_SD_TYPE_FONTWORK_SHADOW,CTF_FONTWORK_SHADOW, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( PROP_FontWorkShadowColor, XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_SHADOW_COLOR, XML_TYPE_COLOR, CTF_FONTWORK_SHADOWCOLOR, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( PROP_FontWorkShadowOffsetX, XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_SHADOW_OFFSET_X, XML_TYPE_MEASURE, CTF_FONTWORK_SHADOWOFFSETX, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( PROP_FontWorkShadowOffsetY, XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_SHADOW_OFFSET_Y, XML_TYPE_MEASURE, CTF_FONTWORK_SHADOWOFFSETY, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( PROP_FontWorkForm, XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_FORM, XML_SD_TYPE_FONTWORK_FORM, CTF_FONTWORK_FORM, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( PROP_FontWorkHideForm, XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_HIDE_FORM, XML_TYPE_BOOL, CTF_FONTWORK_HIDEFORM, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( PROP_FontWorkShadowTransparence, XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_SHADOW_TRANSPARENCE, XML_TYPE_PERCENT, CTF_FONTWORK_SHADOWTRANSPARENCE, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + + // control attributes (border exists one more time for the text additions of shapes) + GMAP( PROP_ControlSymbolColor, XML_NAMESPACE_DRAW, XML_SYMBOL_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( PROP_ControlBackground, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLOR|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_ControlBorder, XML_NAMESPACE_FO, XML_BORDER, XML_SD_TYPE_CONTROL_BORDER|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + GMAP( PROP_ControlBorderColor, XML_NAMESPACE_FO, XML_BORDER, XML_SD_TYPE_CONTROL_BORDER_COLOR|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + GMAP( PROP_ControlDataStyle, XML_NAMESPACE_STYLE,XML_DATA_STYLE_NAME, XML_TYPE_STRING|MID_FLAG_NO_PROPERTY_EXPORT|MID_FLAG_SPECIAL_ITEM, CTF_SD_CONTROL_SHAPE_DATA_STYLE ), + GMAP( PROP_ControlTextEmphasis, XML_NAMESPACE_STYLE,XML_TEXT_EMPHASIZE, XML_TYPE_CONTROL_TEXT_EMPHASIZE, 0 ), + GMAP( PROP_ImageScaleMode, XML_NAMESPACE_STYLE,XML_REPEAT, XML_SD_TYPE_IMAGE_SCALE_MODE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( PROP_ControlWritingMode, XML_NAMESPACE_STYLE,XML_WRITING_MODE, XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT|MID_FLAG_MULTI_PROPERTY, CTF_CONTROLWRITINGMODE ), + + // special entries for floating frames + GMAP( PROP_FrameIsAutoScroll, XML_NAMESPACE_DRAW, XML_FRAME_DISPLAY_SCROLLBAR, XML_TYPE_BOOL|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_DISPLAY_SCROLLBAR ), + GMAP( PROP_FrameIsBorder, XML_NAMESPACE_DRAW, XML_FRAME_DISPLAY_BORDER, XML_TYPE_BOOL|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_DISPLAY_BORDER ), + GMAP( PROP_FrameMarginWidth, XML_NAMESPACE_DRAW, XML_FRAME_MARGIN_HORIZONTAL, XML_TYPE_MEASURE_PX|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_MARGIN_HORI ), + GMAP( PROP_FrameMarginHeight, XML_NAMESPACE_DRAW, XML_FRAME_MARGIN_VERTICAL, XML_TYPE_MEASURE_PX|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_MARGIN_VERT ), + GMAP( PROP_VisibleArea, XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_LEFT, XML_TYPE_RECTANGLE_LEFT|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY, CTF_SD_OLE_VIS_AREA_IMPORT_LEFT ), + GMAP( PROP_VisibleArea, XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_TOP, XML_TYPE_RECTANGLE_TOP|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY, CTF_SD_OLE_VIS_AREA_IMPORT_TOP ), + GMAP( PROP_VisibleArea, XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_WIDTH, XML_TYPE_RECTANGLE_WIDTH|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY, CTF_SD_OLE_VIS_AREA_IMPORT_WIDTH ), + GMAP( PROP_VisibleArea, XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_HEIGHT, XML_TYPE_RECTANGLE_HEIGHT|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY, CTF_SD_OLE_VIS_AREA_IMPORT_HEIGHT ), + GMAP( PROP_IsInternal, XML_NAMESPACE_DRAW, XML__EMPTY, XML_TYPE_BUILDIN_CMP_ONLY, CTF_SD_OLE_ISINTERNAL ), + GMAP( PROP_IsInternal, XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_LEFT, XML_TYPE_RECTANGLE_LEFT|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY_IMPORT, CTF_SD_OLE_VIS_AREA_EXPORT_LEFT ), + GMAP( PROP_IsInternal, XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_TOP, XML_TYPE_RECTANGLE_TOP|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY_IMPORT, CTF_SD_OLE_VIS_AREA_EXPORT_TOP ), + GMAP( PROP_IsInternal, XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_WIDTH, XML_TYPE_RECTANGLE_WIDTH|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY_IMPORT, CTF_SD_OLE_VIS_AREA_EXPORT_WIDTH ), + GMAP( PROP_IsInternal, XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_HEIGHT, XML_TYPE_RECTANGLE_HEIGHT|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY_IMPORT, CTF_SD_OLE_VIS_AREA_EXPORT_HEIGHT ), + + GMAP( PROP_Aspect, XML_NAMESPACE_DRAW, XML_DRAW_ASPECT, XML_TYPE_TEXT_DRAW_ASPECT|MID_FLAG_MULTI_PROPERTY, CTF_SD_OLE_ASPECT ), + + // caption properties + GMAP( PROP_CaptionType, XML_NAMESPACE_DRAW, XML_CAPTION_TYPE, XML_SD_TYPE_CAPTION_TYPE, 0 ), + GMAP( PROP_CaptionIsFixedAngle, XML_NAMESPACE_DRAW, XML_CAPTION_ANGLE_TYPE, XML_SD_TYPE_CAPTION_ANGLE_TYPE, 0 ), + GMAP( PROP_CaptionAngle, XML_NAMESPACE_DRAW, XML_CAPTION_ANGLE, XML_TYPE_NUMBER, 0 ), + GMAP( PROP_CaptionGap, XML_NAMESPACE_DRAW, XML_CAPTION_GAP, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_CaptionEscapeDirection, XML_NAMESPACE_DRAW, XML_CAPTION_ESCAPE_DIRECTION, XML_SD_TYPE_CAPTION_ESC_DIR, 0 ), + GMAP( PROP_CaptionIsEscapeRelative, XML_NAMESPACE_DRAW, XML_CAPTION_ESCAPE, XML_SD_TYPE_CAPTION_IS_ESC_REL|MID_FLAG_MULTI_PROPERTY, CTF_CAPTION_ISESCREL ), + GMAP( PROP_CaptionEscapeRelative, XML_NAMESPACE_DRAW, XML_CAPTION_ESCAPE, XML_SD_TYPE_CAPTION_ESC_REL|MID_FLAG_MULTI_PROPERTY, CTF_CAPTION_ESCREL ), + GMAP( PROP_CaptionEscapeAbsolute, XML_NAMESPACE_DRAW, XML_CAPTION_ESCAPE, XML_SD_TYPE_CAPTION_ESC_ABS|MID_FLAG_MULTI_PROPERTY, CTF_CAPTION_ESCABS ), + GMAP( PROP_CaptionLineLength, XML_NAMESPACE_DRAW, XML_CAPTION_LINE_LENGTH, XML_TYPE_MEASURE, 0 ), + GMAP( PROP_CaptionIsFitLineLength, XML_NAMESPACE_DRAW, XML_CAPTION_FIT_LINE_LENGTH, XML_TYPE_BOOL, 0 ), + + // misc object properties + GMAP( PROP_MoveProtect, XML_NAMESPACE_STYLE, XML_PROTECT, XML_SD_TYPE_MOVE_PROTECT|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, CTF_SD_MOVE_PROTECT ), + GMAP( PROP_SizeProtect, XML_NAMESPACE_STYLE, XML_PROTECT, XML_SD_TYPE_SIZE_PROTECT|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, CTF_SD_SIZE_PROTECT ), + GMAP( PROP_WritingMode, XML_NAMESPACE_STYLE, XML_WRITING_MODE, XML_SD_TYPE_WRITINGMODE2, CTF_WRITINGMODE2 ), + { PROP_WritingMode, XML_NAMESPACE_LO_EXT, XML_WRITING_MODE, XML_SD_TYPE_WRITINGMODE2|XML_TYPE_PROP_GRAPHIC, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, true}, + { PROP_Decorative, XML_NAMESPACE_LO_EXT, XML_DECORATIVE, XML_TYPE_BOOL|XML_TYPE_PROP_GRAPHIC, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false }, + + MAP_END() +}; + +// entry list for presentation page properties + +const XMLPropertyMapEntry aXMLSDPresPageProps[] = +{ + DPMAP( PROP_UserDefinedAttributes, XML_NAMESPACE_TEXT, XML_XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), + + DPMAP( PROP_Change, XML_NAMESPACE_PRESENTATION, XML_TRANSITION_TYPE, XML_SD_TYPE_PRESPAGE_TYPE, CTF_PAGE_TRANS_TYPE ), + DPMAP( PROP_Effect, XML_NAMESPACE_PRESENTATION, XML_TRANSITION_STYLE, XML_SD_TYPE_PRESPAGE_STYLE, CTF_PAGE_TRANS_STYLE ), + DPMAP( PROP_Speed, XML_NAMESPACE_PRESENTATION, XML_TRANSITION_SPEED, XML_SD_TYPE_PRESPAGE_SPEED, CTF_PAGE_TRANS_SPEED ), + DPMAP( PROP_HighResDuration, XML_NAMESPACE_PRESENTATION, XML_DURATION, XML_SD_TYPE_PRESPAGE_DURATION, CTF_PAGE_TRANS_DURATION ), + DPMAP( PROP_Visible, XML_NAMESPACE_PRESENTATION, XML_VISIBILITY, XML_SD_TYPE_PRESPAGE_VISIBILITY, CTF_PAGE_VISIBLE ), + DPMAP( PROP_Sound, XML_NAMESPACE_PRESENTATION, XML_SOUND, XML_TYPE_STRING|MID_FLAG_ELEMENT_ITEM, CTF_PAGE_SOUND_URL ), + DPMAP( PROP_BackgroundFullSize, XML_NAMESPACE_DRAW, XML_BACKGROUND_SIZE, XML_SD_TYPE_PRESPAGE_BACKSIZE, CTF_PAGE_BACKSIZE ), + + DPMAP( PROP_IsBackgroundVisible, XML_NAMESPACE_PRESENTATION, XML_BACKGROUND_VISIBLE, XML_TYPE_BOOL, 0 ), + DPMAP( PROP_IsBackgroundObjectsVisible, XML_NAMESPACE_PRESENTATION, XML_BACKGROUND_OBJECTS_VISIBLE, XML_TYPE_BOOL, 0 ), + + DPMAP( PROP_FillStyle, XML_NAMESPACE_DRAW, XML_FILL, XML_SD_TYPE_FILLSTYLE, 0 ), + DPMAP( PROP_FillColor, XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, 0 ), + DPMAP( PROP_FillGradientName, XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLGRADIENTNAME ), + DPMAP( PROP_FillGradientStepCount, XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER, 0 ), + DPMAP( PROP_FillHatchName, XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLHATCHNAME ), + GMAP( PROP_FillBackground, XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, 0 ), + DPMAP( PROP_FillBitmapName, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLBITMAPNAME ), + DPMAP( PROP_FillTransparence, XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT|MID_FLAG_MULTI_PROPERTY, 0 ), + DPMAP( PROP_FillTransparenceGradientName, XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLTRANSNAME ), + DPMAP( PROP_FillBitmapSizeX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SD_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + DPMAP( PROP_FillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SD_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + DPMAP( PROP_FillBitmapSizeY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SD_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + DPMAP( PROP_FillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SD_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + DPMAP( PROP_FillBitmapMode, XML_NAMESPACE_STYLE,XML_REPEAT, XML_SD_TYPE_BITMAP_MODE, 0 ), + DPMAP( PROP_FillBitmapPositionOffsetX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, 0 ), + DPMAP( PROP_FillBitmapPositionOffsetY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, 0 ), + DPMAP( PROP_FillBitmapRectanglePoint, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SD_TYPE_BITMAP_REFPOINT, 0 ), + DPMAP( PROP_FillBitmapOffsetX, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SD_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_X ), + DPMAP( PROP_FillBitmapOffsetY, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SD_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_Y ), + + DPMAP( PROP_IsHeaderVisible, XML_NAMESPACE_PRESENTATION, XML_DISPLAY_HEADER, XML_SD_TYPE_HEADER_FOOTER_VISIBILITY_TYPE, CTF_HEADER_VISIBLE ), + DPMAP( PROP_IsFooterVisible, XML_NAMESPACE_PRESENTATION, XML_DISPLAY_FOOTER, XML_SD_TYPE_HEADER_FOOTER_VISIBILITY_TYPE, CTF_FOOTER_VISIBLE ), + DPMAP( PROP_IsPageNumberVisible, XML_NAMESPACE_PRESENTATION, XML_DISPLAY_PAGE_NUMBER, XML_SD_TYPE_HEADER_FOOTER_VISIBILITY_TYPE, CTF_PAGE_NUMBER_VISIBLE ), + DPMAP( PROP_IsDateTimeVisible, XML_NAMESPACE_PRESENTATION, XML_DISPLAY_DATE_TIME, XML_SD_TYPE_HEADER_FOOTER_VISIBILITY_TYPE, CTF_DATE_TIME_VISIBLE ), + + DPMAP( PROP_TransitionType, XML_NAMESPACE_SMIL, XML_TYPE, XML_SD_TYPE_TRANSITION_TYPE, CTF_PAGE_TRANSITION_TYPE ), + DPMAP( PROP_TransitionSubtype, XML_NAMESPACE_SMIL, XML_SUBTYPE, XML_SD_TYPE_TRANSTIION_SUBTYPE, CTF_PAGE_TRANSITION_SUBTYPE ), + DPMAP( PROP_TransitionDirection, XML_NAMESPACE_SMIL, XML_DIRECTION, XML_SD_TYPE_TRANSTIION_DIRECTION, CTF_PAGE_TRANSITION_DIRECTION ), + DPMAP( PROP_TransitionFadeColor, XML_NAMESPACE_SMIL, XML_FADECOLOR, XML_TYPE_COLOR, CTF_PAGE_TRANSITION_FADECOLOR ), + MAP_END() +}; + +/** contains the attribute to property mapping for a drawing layer table + WARNING: if attributes are added, SdXMLTableShapeContext::processAttribute needs to be updated! +*/ +const XMLPropertyMapEntry aXMLTableShapeAttributes[] = +{ + MAP_( PROP_UseFirstRowStyle, XML_NAMESPACE_TABLE, XML_USE_FIRST_ROW_STYLES, XML_TYPE_BOOL, 0 ), + MAP_( PROP_UseLastRowStyle, XML_NAMESPACE_TABLE, XML_USE_LAST_ROW_STYLES, XML_TYPE_BOOL, 0 ), + MAP_( PROP_UseFirstColumnStyle, XML_NAMESPACE_TABLE, XML_USE_FIRST_COLUMN_STYLES, XML_TYPE_BOOL, 0 ), + MAP_( PROP_UseLastColumnStyle, XML_NAMESPACE_TABLE, XML_USE_LAST_COLUMN_STYLES, XML_TYPE_BOOL, 0 ), + MAP_( PROP_UseBandingRowStyle, XML_NAMESPACE_TABLE, XML_USE_BANDING_ROWS_STYLES, XML_TYPE_BOOL, 0 ), + MAP_( PROP_UseBandingColumnStyle, XML_NAMESPACE_TABLE, XML_USE_BANDING_COLUMNS_STYLES, XML_TYPE_BOOL, 0 ), + MAP_END() +}; + +// implementation of factory for own graphic properties + +SvXMLEnumMapEntry<drawing::LineStyle> const aXML_LineStyle_EnumMap[] = +{ + { XML_NONE, drawing::LineStyle_NONE }, + { XML_SOLID, drawing::LineStyle_SOLID }, + { XML_DASH, drawing::LineStyle_DASH }, + { XML_TOKEN_INVALID, drawing::LineStyle(0) } +}; + +SvXMLEnumMapEntry<drawing::LineJoint> const aXML_LineJoint_EnumMap[] = +{ + { XML_NONE, drawing::LineJoint_NONE }, + { XML_MITER, drawing::LineJoint_MITER }, + { XML_ROUND, drawing::LineJoint_ROUND }, + { XML_BEVEL, drawing::LineJoint_BEVEL }, + { XML_MIDDLE, drawing::LineJoint_MIDDLE }, + { XML_TOKEN_INVALID, drawing::LineJoint(0) } +}; + +SvXMLEnumMapEntry<drawing::LineCap> const aXML_LineCap_EnumMap[] = +{ + { XML_BUTT, drawing::LineCap_BUTT }, + { XML_ROUND, drawing::LineCap_ROUND }, + // use XML_GRADIENTSTYLE_SQUARE as XML_SQUARE, is defined as "square" already + { XML_GRADIENTSTYLE_SQUARE, drawing::LineCap_SQUARE }, + { XML_TOKEN_INVALID, drawing::LineCap(0) } +}; + +SvXMLEnumMapEntry<drawing::FillStyle> const aXML_FillStyle_EnumMap[] = +{ + { XML_NONE, drawing::FillStyle_NONE }, + { XML_SOLID, drawing::FillStyle_SOLID }, + { XML_BITMAP, drawing::FillStyle_BITMAP }, + { XML_GRADIENT, drawing::FillStyle_GRADIENT }, + { XML_HATCH, drawing::FillStyle_HATCH }, + { XML_TOKEN_INVALID, drawing::FillStyle(0) } +}; + +SvXMLEnumMapEntry<sal_Int32> const aXML_PresChange_EnumMap[] = +{ + { XML_MANUAL, 0 }, + { XML_AUTOMATIC, 1 }, + { XML_SEMI_AUTOMATIC, 2 }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<presentation::AnimationSpeed> const aXML_TransSpeed_EnumMap[] = +{ + { XML_FAST, presentation::AnimationSpeed_FAST }, + { XML_MEDIUM, presentation::AnimationSpeed_MEDIUM }, + { XML_SLOW, presentation::AnimationSpeed_SLOW }, + { XML_TOKEN_INVALID, presentation::AnimationSpeed(0) } +}; + +SvXMLEnumMapEntry<presentation::FadeEffect> const aXML_FadeEffect_EnumMap[] = +{ + { XML_NONE, presentation::FadeEffect_NONE }, + { XML_FADE_FROM_LEFT, presentation::FadeEffect_FADE_FROM_LEFT }, + { XML_FADE_FROM_TOP, presentation::FadeEffect_FADE_FROM_TOP }, + { XML_FADE_FROM_RIGHT, presentation::FadeEffect_FADE_FROM_RIGHT }, + { XML_FADE_FROM_BOTTOM, presentation::FadeEffect_FADE_FROM_BOTTOM }, + { XML_FADE_TO_CENTER, presentation::FadeEffect_FADE_TO_CENTER }, + { XML_FADE_FROM_CENTER, presentation::FadeEffect_FADE_FROM_CENTER }, + { XML_MOVE_FROM_LEFT, presentation::FadeEffect_MOVE_FROM_LEFT }, + { XML_MOVE_FROM_TOP, presentation::FadeEffect_MOVE_FROM_TOP }, + { XML_MOVE_FROM_RIGHT, presentation::FadeEffect_MOVE_FROM_RIGHT }, + { XML_MOVE_FROM_BOTTOM, presentation::FadeEffect_MOVE_FROM_BOTTOM }, + { XML_ROLL_FROM_TOP, presentation::FadeEffect_ROLL_FROM_TOP }, + { XML_ROLL_FROM_LEFT, presentation::FadeEffect_ROLL_FROM_LEFT }, + { XML_ROLL_FROM_RIGHT, presentation::FadeEffect_ROLL_FROM_RIGHT }, + { XML_ROLL_FROM_BOTTOM, presentation::FadeEffect_ROLL_FROM_BOTTOM }, + { XML_VERTICAL_STRIPES, presentation::FadeEffect_VERTICAL_STRIPES }, + { XML_HORIZONTAL_STRIPES, presentation::FadeEffect_HORIZONTAL_STRIPES }, + { XML_CLOCKWISE, presentation::FadeEffect_CLOCKWISE }, + { XML_COUNTERCLOCKWISE, presentation::FadeEffect_COUNTERCLOCKWISE }, + { XML_FADE_FROM_UPPERLEFT, presentation::FadeEffect_FADE_FROM_UPPERLEFT }, + { XML_FADE_FROM_UPPERRIGHT, presentation::FadeEffect_FADE_FROM_UPPERRIGHT }, + { XML_FADE_FROM_LOWERLEFT, presentation::FadeEffect_FADE_FROM_LOWERLEFT }, + { XML_FADE_FROM_LOWERRIGHT, presentation::FadeEffect_FADE_FROM_LOWERRIGHT }, + { XML_CLOSE_VERTICAL, presentation::FadeEffect_CLOSE_VERTICAL }, + { XML_CLOSE_HORIZONTAL, presentation::FadeEffect_CLOSE_HORIZONTAL }, + { XML_OPEN_VERTICAL, presentation::FadeEffect_OPEN_VERTICAL }, + { XML_OPEN_HORIZONTAL, presentation::FadeEffect_OPEN_HORIZONTAL }, + { XML_SPIRALIN_LEFT, presentation::FadeEffect_SPIRALIN_LEFT }, + { XML_SPIRALIN_RIGHT, presentation::FadeEffect_SPIRALIN_RIGHT }, + { XML_SPIRALOUT_LEFT, presentation::FadeEffect_SPIRALOUT_LEFT }, + { XML_SPIRALOUT_RIGHT, presentation::FadeEffect_SPIRALOUT_RIGHT }, + { XML_DISSOLVE, presentation::FadeEffect_DISSOLVE }, + { XML_WAVYLINE_FROM_LEFT, presentation::FadeEffect_WAVYLINE_FROM_LEFT }, + { XML_WAVYLINE_FROM_TOP, presentation::FadeEffect_WAVYLINE_FROM_TOP }, + { XML_WAVYLINE_FROM_RIGHT, presentation::FadeEffect_WAVYLINE_FROM_RIGHT }, + { XML_WAVYLINE_FROM_BOTTOM, presentation::FadeEffect_WAVYLINE_FROM_BOTTOM }, + { XML_RANDOM, presentation::FadeEffect_RANDOM }, + { XML_STRETCH_FROM_LEFT, presentation::FadeEffect_STRETCH_FROM_LEFT }, + { XML_STRETCH_FROM_TOP, presentation::FadeEffect_STRETCH_FROM_TOP }, + { XML_STRETCH_FROM_RIGHT, presentation::FadeEffect_STRETCH_FROM_RIGHT }, + { XML_STRETCH_FROM_BOTTOM, presentation::FadeEffect_STRETCH_FROM_BOTTOM }, + { XML_VERTICAL_LINES, presentation::FadeEffect_VERTICAL_LINES }, + { XML_HORIZONTAL_LINES, presentation::FadeEffect_HORIZONTAL_LINES }, + { XML_MOVE_FROM_UPPERLEFT, presentation::FadeEffect_MOVE_FROM_UPPERLEFT }, + { XML_MOVE_FROM_UPPERRIGHT, presentation::FadeEffect_MOVE_FROM_UPPERRIGHT }, + { XML_MOVE_FROM_LOWERRIGHT, presentation::FadeEffect_MOVE_FROM_LOWERRIGHT }, + { XML_MOVE_FROM_LOWERLEFT, presentation::FadeEffect_MOVE_FROM_LOWERLEFT }, + { XML_UNCOVER_TO_LEFT, presentation::FadeEffect_UNCOVER_TO_LEFT }, + { XML_UNCOVER_TO_UPPERLEFT, presentation::FadeEffect_UNCOVER_TO_UPPERLEFT }, + { XML_UNCOVER_TO_TOP, presentation::FadeEffect_UNCOVER_TO_TOP }, + { XML_UNCOVER_TO_UPPERRIGHT,presentation::FadeEffect_UNCOVER_TO_UPPERRIGHT }, + { XML_UNCOVER_TO_RIGHT, presentation::FadeEffect_UNCOVER_TO_RIGHT }, + { XML_UNCOVER_TO_LOWERRIGHT,presentation::FadeEffect_UNCOVER_TO_LOWERRIGHT }, + { XML_UNCOVER_TO_BOTTOM, presentation::FadeEffect_UNCOVER_TO_BOTTOM }, + { XML_UNCOVER_TO_LOWERLEFT, presentation::FadeEffect_UNCOVER_TO_LOWERLEFT }, + { XML_VERTICAL_CHECKERBOARD,presentation::FadeEffect_VERTICAL_CHECKERBOARD }, + { XML_HORIZONTAL_CHECKERBOARD,presentation::FadeEffect_HORIZONTAL_CHECKERBOARD }, + { XML_TOKEN_INVALID, presentation::FadeEffect(0) } +}; + +SvXMLEnumMapEntry<drawing::ConnectorType> const aXML_ConnectionKind_EnumMap[] = +{ + { XML_STANDARD, drawing::ConnectorType_STANDARD }, + { XML_CURVE, drawing::ConnectorType_CURVE }, + { XML_LINE, drawing::ConnectorType_LINE }, + { XML_LINES, drawing::ConnectorType_LINES }, + { XML_TOKEN_INVALID, drawing::ConnectorType(0) } +}; + +SvXMLEnumMapEntry<drawing::BitmapMode> const aXML_BitmapMode_EnumMap[] = +{ + { XML_REPEAT, drawing::BitmapMode_REPEAT }, + { XML_STRETCH, drawing::BitmapMode_STRETCH }, + { XML_BACKGROUND_NO_REPEAT, drawing::BitmapMode_NO_REPEAT }, + { XML_TOKEN_INVALID, drawing::BitmapMode(0) } +}; + +// 3D EnumMaps + +SvXMLEnumMapEntry<drawing::NormalsKind> const aXML_NormalsKind_EnumMap[] = +{ + { XML_OBJECT, drawing::NormalsKind_SPECIFIC }, + { XML_FLAT, drawing::NormalsKind_FLAT }, + { XML_SPHERE, drawing::NormalsKind_SPHERE }, + { XML_TOKEN_INVALID, drawing::NormalsKind(0) } +}; + +SvXMLEnumMapEntry<drawing::TextureProjectionMode> const aXML_TexGenerationX_EnumMap[] = +{ + { XML_OBJECT, drawing::TextureProjectionMode_OBJECTSPECIFIC }, + { XML_PARALLEL, drawing::TextureProjectionMode_PARALLEL }, + { XML_SPHERE, drawing::TextureProjectionMode_SPHERE }, + { XML_TOKEN_INVALID, drawing::TextureProjectionMode(0) } +}; + +SvXMLEnumMapEntry<drawing::TextureProjectionMode> const aXML_TexGenerationY_EnumMap[] = +{ + { XML_OBJECT, drawing::TextureProjectionMode_OBJECTSPECIFIC }, + { XML_PARALLEL, drawing::TextureProjectionMode_PARALLEL }, + { XML_SPHERE, drawing::TextureProjectionMode_SPHERE }, + { XML_TOKEN_INVALID, drawing::TextureProjectionMode(0) } +}; + +SvXMLEnumMapEntry<drawing::TextureKind> const aXML_TexKind_EnumMap[] = +{ + { XML_LUMINANCE, drawing::TextureKind_LUMINANCE }, + { XML_COLOR, drawing::TextureKind_COLOR }, + { XML_TOKEN_INVALID, drawing::TextureKind(0) } +}; + +SvXMLEnumMapEntry<drawing::TextureMode> const aXML_TexMode_EnumMap[] = +{ + { XML_REPLACE, drawing::TextureMode_REPLACE }, + { XML_MODULATE, drawing::TextureMode_MODULATE }, + { XML_BLEND, drawing::TextureMode_BLEND }, + { XML_TOKEN_INVALID, drawing::TextureMode(0) } +}; + +SvXMLEnumMapEntry<drawing::RectanglePoint> const aXML_RefPoint_EnumMap[] = +{ + { XML_TOP_LEFT, drawing::RectanglePoint_LEFT_TOP }, + { XML_TOP, drawing::RectanglePoint_MIDDLE_TOP }, + { XML_TOP_RIGHT, drawing::RectanglePoint_RIGHT_TOP }, + { XML_LEFT, drawing::RectanglePoint_LEFT_MIDDLE }, + { XML_CENTER, drawing::RectanglePoint_MIDDLE_MIDDLE }, + { XML_RIGHT, drawing::RectanglePoint_RIGHT_MIDDLE }, + { XML_BOTTOM_LEFT, drawing::RectanglePoint_LEFT_BOTTOM }, + { XML_BOTTOM, drawing::RectanglePoint_MIDDLE_BOTTOM }, + { XML_BOTTOM_RIGHT, drawing::RectanglePoint_RIGHT_BOTTOM }, + { XML_TOKEN_INVALID, drawing::RectanglePoint(0) } +}; + +SvXMLEnumMapEntry<drawing::CircleKind> const aXML_CircleKind_EnumMap[] = +{ + { XML_FULL, drawing::CircleKind_FULL }, + { XML_SECTION, drawing::CircleKind_SECTION }, + { XML_CUT, drawing::CircleKind_CUT }, + { XML_ARC, drawing::CircleKind_ARC }, + { XML_TOKEN_INVALID, drawing::CircleKind(0) } +}; + +SvXMLEnumMapEntry<text::WritingMode> const aXML_WritingMode_EnumMap[] = +{ + { XML_TB_RL, text::WritingMode_TB_RL }, + { XML_LR_TB, text::WritingMode_LR_TB }, + { XML_TOKEN_INVALID, text::WritingMode(0) } +}; + +SvXMLEnumMapEntry<sal_Int16> const aXML_WritingMode2_EnumMap[] = +{ + { XML_LR_TB, text::WritingMode2::LR_TB }, + { XML_RL_TB, text::WritingMode2::RL_TB }, + { XML_TB_RL, text::WritingMode2::TB_RL }, + { XML_TB_LR, text::WritingMode2::TB_LR }, + { XML_PAGE, text::WritingMode2::CONTEXT }, + { XML_BT_LR, text::WritingMode2::BT_LR }, + { XML_TB_RL90, text::WritingMode2::TB_RL90 }, + { XML_TOKEN_INVALID, text::WritingMode2::LR_TB } +}; + +SvXMLEnumMapEntry<drawing::TextAnimationKind> const pXML_TextAnimation_Enum[] = +{ + { XML_NONE, drawing::TextAnimationKind_NONE }, + { XML_BLINKING, drawing::TextAnimationKind_BLINK }, // will be filtered + { XML_SCROLL, drawing::TextAnimationKind_SCROLL }, + { XML_ALTERNATE, drawing::TextAnimationKind_ALTERNATE }, + { XML_SLIDE, drawing::TextAnimationKind_SLIDE }, + { XML_TOKEN_INVALID, drawing::TextAnimationKind(0) } +}; + +SvXMLEnumMapEntry<drawing::TextAnimationKind> const pXML_TextAnimation_Blinking_Enum[] = +{ + { XML_FALSE, drawing::TextAnimationKind_NONE }, + { XML_TRUE, drawing::TextAnimationKind_BLINK }, + { XML_FALSE, drawing::TextAnimationKind_SCROLL }, + { XML_FALSE, drawing::TextAnimationKind_ALTERNATE }, + { XML_FALSE, drawing::TextAnimationKind_SLIDE }, + { XML_TOKEN_INVALID, drawing::TextAnimationKind(0) } +}; + +SvXMLEnumMapEntry<drawing::TextAnimationDirection> const pXML_TextAnimationDirection_Enum[] = +{ + { XML_LEFT, drawing::TextAnimationDirection_LEFT }, + { XML_RIGHT, drawing::TextAnimationDirection_RIGHT }, // will be filtered + { XML_UP, drawing::TextAnimationDirection_UP }, + { XML_DOWN, drawing::TextAnimationDirection_DOWN }, + { XML_TOKEN_INVALID, drawing::TextAnimationDirection(0) } +}; + +SvXMLEnumMapEntry<drawing::TextHorizontalAdjust> const pXML_TextAlign_Enum[] = +{ + { XML_LEFT, drawing::TextHorizontalAdjust_LEFT }, + { XML_CENTER, drawing::TextHorizontalAdjust_CENTER }, + { XML_RIGHT, drawing::TextHorizontalAdjust_RIGHT }, + { XML_JUSTIFY, drawing::TextHorizontalAdjust_BLOCK }, + { XML_TOKEN_INVALID, drawing::TextHorizontalAdjust(0) } +}; + +SvXMLEnumMapEntry<drawing::TextVerticalAdjust> const pXML_VerticalAlign_Enum[] = +{ + { XML_TOP, drawing::TextVerticalAdjust_TOP }, + { XML_MIDDLE, drawing::TextVerticalAdjust_CENTER }, + { XML_BOTTOM, drawing::TextVerticalAdjust_BOTTOM }, + { XML_JUSTIFY, drawing::TextVerticalAdjust_BLOCK }, + { XML_TOKEN_INVALID, drawing::TextVerticalAdjust(0) } +}; + +// note: PROPORTIONAL and ALLLINES are the same thing now! +SvXMLEnumMapEntry<drawing::TextFitToSizeType> const pXML_FitToSize_Enum_Odf12[] = +{ + { XML_FALSE, drawing::TextFitToSizeType_NONE }, + { XML_TRUE, drawing::TextFitToSizeType_PROPORTIONAL }, + { XML_TRUE, drawing::TextFitToSizeType_ALLLINES }, + { XML_FALSE, drawing::TextFitToSizeType_AUTOFIT }, + { XML_TOKEN_INVALID, drawing::TextFitToSizeType(0) } +}; + +SvXMLEnumMapEntry<drawing::TextFitToSizeType> const pXML_FitToSize_Enum[] = +{ + { XML_FALSE, drawing::TextFitToSizeType_NONE }, + { XML_TRUE, drawing::TextFitToSizeType_PROPORTIONAL }, + { XML_ALL, drawing::TextFitToSizeType_ALLLINES }, + { XML_SHRINK_TO_FIT,drawing::TextFitToSizeType_AUTOFIT }, + { XML_TOKEN_INVALID, drawing::TextFitToSizeType(0) } +}; + +SvXMLEnumMapEntry<drawing::TextFitToSizeType> const pXML_ShrinkToFit_Enum[] = +{ + { XML_FALSE, drawing::TextFitToSizeType_NONE }, + { XML_FALSE, drawing::TextFitToSizeType_PROPORTIONAL }, + { XML_FALSE, drawing::TextFitToSizeType_ALLLINES }, + { XML_TRUE, drawing::TextFitToSizeType_AUTOFIT }, + { XML_TOKEN_INVALID, drawing::TextFitToSizeType(0) } +}; + +SvXMLEnumMapEntry<sal_Int32> const pXML_MeasureUnit_Enum[] = +{ + { XML_AUTOMATIC, 0 }, + { XML_MM, 1 }, + { XML_UNIT_CM, 2 }, + { XML_UNIT_M, 3 }, + { XML_KM, 4 }, + { XML_UNIT_PT, 6 }, + { XML_UNIT_PC, 7 }, + { XML_IN, 8 }, + { XML_UNIT_FOOT, 9 }, + { XML_MI, 10 }, + { XML_TOKEN_INVALID,0 } +}; + +SvXMLEnumMapEntry<drawing::MeasureTextHorzPos> const pXML_Measure_HAlign_Enum[] = +{ + { XML_AUTOMATIC, drawing::MeasureTextHorzPos_AUTO }, + { XML_LEFT_OUTSIDE, drawing::MeasureTextHorzPos_LEFTOUTSIDE }, + { XML_INSIDE, drawing::MeasureTextHorzPos_INSIDE }, + { XML_RIGHT_OUTSIDE, drawing::MeasureTextHorzPos_RIGHTOUTSIDE}, + { XML_TOKEN_INVALID, drawing::MeasureTextHorzPos(0) } +}; + +SvXMLEnumMapEntry<drawing::MeasureTextVertPos> const pXML_Measure_VAlign_Enum[] = +{ + { XML_AUTOMATIC, drawing::MeasureTextVertPos_AUTO }, + { XML_ABOVE, drawing::MeasureTextVertPos_EAST }, + { XML_BELOW, drawing::MeasureTextVertPos_WEST }, + { XML_CENTER, drawing::MeasureTextVertPos_CENTERED }, + { XML_TOKEN_INVALID, drawing::MeasureTextVertPos(0) } +}; + +// #FontWork# +SvXMLEnumMapEntry<sal_Int32> const pXML_Fontwork_Style_Enum[] = +{ + { XML_ROTATE, 0 }, //XFormTextStyle::Rotate, + { XML_UPRIGHT, 1 }, //XFormTextStyle::Upright, + { XML_SLANT_X, 2 }, //XFormTextStyle::SlantX, + { XML_SLANT_Y, 3 }, //XFormTextStyle::SlantY, + { XML_NONE, 4 }, //XFormTextStyle::NONE + { XML_TOKEN_INVALID,0 } +}; + +SvXMLEnumMapEntry<sal_Int32> const pXML_Fontwork_Adjust_Enum[] = +{ + { XML_LEFT, 0 }, //XFormTextAdjust::Left, + { XML_RIGHT, 1 }, //XFormTextAdjust::Right, + { XML_AUTOSIZE, 2 }, //XFormTextAdjust::AutoSize, + { XML_CENTER, 3 }, //XFormTextAdjust::Center + { XML_TOKEN_INVALID,0 } +}; + +SvXMLEnumMapEntry<sal_Int32> const pXML_Fontwork_Shadow_Enum[] = +{ + { XML_NORMAL, 0 }, //XFormTextShadow::Normal, + { XML_SLANT, 1 }, //XFormTextShadow::Slant, + { XML_NONE, 2 }, //XFormTextShadow::NONE + { XML_TOKEN_INVALID,0 } +}; + +SvXMLEnumMapEntry<sal_Int32> const pXML_Fontwork_Form_Enum[] = +{ + { XML_NONE, 0 }, //XFTFORM_NONE, + { XML_TOPCIRCLE, 1 }, //XFTFORM_TOPCIRC, + { XML_BOTTOMCIRCLE, 2 }, //XFTFORM_BOTCIRC, + { XML_LEFTCIRCLE, 3 }, //XFTFORM_LFTCIRC, + { XML_RIGHTCIRCLE, 4 }, //XFTFORM_RGTCIRC, + { XML_TOPARC, 5 }, //XFTFORM_TOPARC, + { XML_BOTTOMARC, 6 }, //XFTFORM_BOTARC, + { XML_LEFTARC, 7 }, //XFTFORM_LFTARC, + { XML_RIGHTARC, 8 }, //XFTFORM_RGTARC, + { XML_BUTTON1, 9 }, //XFTFORM_BUTTON1, + { XML_BUTTON2, 10 }, //XFTFORM_BUTTON2, + { XML_BUTTON3, 11 }, //XFTFORM_BUTTON3, + { XML_BUTTON4, 12 }, //XFTFORM_BUTTON4 + { XML_TOKEN_INVALID,0 } +}; + +SvXMLEnumMapEntry<sal_Int32> const pXML_Caption_Esc_Dir_Enum[] = +{ + { XML_HORIZONTAL, 0 }, //SdrCaptionEscDir::Horizontal, + { XML_VERTICAL, 1 }, //SdrCaptionEscDir::Vertical, + { XML_AUTO, 2 }, //SdrCaptionEscDir::BestFit, + { XML_TOKEN_INVALID,0 } +}; + +SvXMLEnumMapEntry<sal_Int32> const pXML_Caption_Type_Enum[] = +{ + { XML_STRAIGHT_LINE, 0 }, //SdrCaptionType::Type1, + { XML_ANGLED_LINE, 1 }, //SdrCaptionType::Type2, + { XML_ANGLED_CONNECTOR_LINE, 2 }, //SdrCaptionType::Type3, + { XML_TOKEN_INVALID,0 } +}; + +namespace { + +class XMLCaptionEscapeRelative : public XMLPropertyHandler +{ +public: + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +} + +bool XMLCaptionEscapeRelative::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue; + + if (!::sax::Converter::convertPercent( nValue, rStrImpValue )) + return false; + + nValue *= 100; + rValue <<= nValue; + return true; +} + +bool XMLCaptionEscapeRelative::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + if( !(rValue >>= nValue ) ) + return false; + + nValue /= 100; + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, nValue ); + rStrExpValue = aOut.makeStringAndClear(); + return true; +} + +namespace { + +class XMLMoveSizeProtectHdl : public XMLPropertyHandler +{ +public: + explicit XMLMoveSizeProtectHdl( sal_Int32 nType ) : mnType( nType ) {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const override; +private: + const sal_Int32 mnType; +}; + +} + +bool XMLMoveSizeProtectHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + const bool bValue = rStrImpValue.indexOf( GetXMLToken( mnType == XML_SD_TYPE_MOVE_PROTECT ? XML_POSITION : XML_SIZE ) ) != -1; + rValue <<= bValue; + return true; +} + +bool XMLMoveSizeProtectHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bValue; + if( !(rValue >>= bValue ) ) + return false; + + if( bValue ) + { + if( !rStrExpValue.isEmpty() ) + rStrExpValue += " "; + + rStrExpValue += GetXMLToken( mnType == XML_SD_TYPE_MOVE_PROTECT ? XML_POSITION : XML_SIZE ); + } + + return true; +} + +namespace { + +class XMLSdHeaderFooterVisibilityTypeHdl : public XMLPropertyHandler +{ +public: + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +} + +bool XMLSdHeaderFooterVisibilityTypeHdl::importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const +{ + // #i38644# + // attributes with this type where saved with VISIBLE|HIDDEN prior + // to src680m67. So we have to import that correctly + const bool bBool = IsXMLToken(rStrImpValue, XML_TRUE) || IsXMLToken(rStrImpValue, XML_VISIBLE); + rValue <<= bBool; + return bBool || IsXMLToken(rStrImpValue, XML_FALSE) || IsXMLToken(rStrImpValue, XML_HIDDEN); +} + +bool XMLSdHeaderFooterVisibilityTypeHdl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + bool bValue; + + if (rValue >>= bValue) + { + OUStringBuffer aOut; + ::sax::Converter::convertBool( aOut, bValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + +namespace { + +class XMLSdRotationAngleTypeHdl : public XMLPropertyHandler +{ +public: + virtual bool importXML(const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter) const override; + virtual bool exportXML(OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter) const override; +}; + +} + +bool XMLSdRotationAngleTypeHdl::importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter&) const +{ + sal_Int32 nValue; + bool const bRet = ::sax::Converter::convertNumber(nValue, rStrImpValue); + if (bRet) + { + nValue = (nValue % 360); + if (nValue < 0) + nValue = 360 + nValue; + sal_Int32 nAngle; + if (nValue < 45 || nValue > 315) + nAngle = 0; + else if (nValue < 180) + nAngle = 9000; + else /* if nValue <= 315 ) */ + nAngle = 27000; + + rValue <<= nAngle; + } + return bRet; +} + +bool XMLSdRotationAngleTypeHdl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter&) const +{ + sal_Int32 nAngle; + bool bRet = (rValue >>= nAngle) && nAngle != 0; + if (bRet) + { + rStrExpValue = OUString::number(nAngle / 100); + } + return bRet; +} + +namespace { + +class XMLFitToSizeEnumPropertyHdl : public XMLEnumPropertyHdl +{ +public: + XMLFitToSizeEnumPropertyHdl( + const SvXMLEnumMapEntry<drawing::TextFitToSizeType> *const pMap) + : XMLEnumPropertyHdl(pMap) {} + + virtual bool importXML(const OUString& rStrImpValue, uno::Any& rValue, + const SvXMLUnitConverter& rUC) const override + { + // we don't know here what the actual attribute name is - + // but we can combine the 2 attributes by just taking the + // "largest" result value; this can never result in ALLLINES + // so the implementation has to interpret PROPORTIONAL as ALLLINES; + // both "true" is invalid anyway. + Any any; + auto const bRet = XMLEnumPropertyHdl::importXML(rStrImpValue, any, rUC); + if (!bRet) + { + return false; + } + assert(any.hasValue()); + if (!rValue.hasValue() || + rValue.get<drawing::TextFitToSizeType>() < any.get<drawing::TextFitToSizeType>()) + { + rValue = any; + } + return true; + } +}; + +} + +XMLSdPropHdlFactory::XMLSdPropHdlFactory( uno::Reference< frame::XModel > xModel, SvXMLImport& rImport ) +: mxModel(std::move( xModel )), mpExport(nullptr), mpImport( &rImport ) +{ +} + +XMLSdPropHdlFactory::XMLSdPropHdlFactory( uno::Reference< frame::XModel > xModel, SvXMLExport& rExport ) +: mxModel(std::move( xModel )), mpExport( &rExport ), mpImport(nullptr) +{ +} + +XMLSdPropHdlFactory::~XMLSdPropHdlFactory() +{ +} + +const XMLPropertyHandler* XMLSdPropHdlFactory::GetPropertyHandler( sal_Int32 nType ) const +{ + const XMLPropertyHandler* pHdl = XMLPropertyHandlerFactory::GetPropertyHandler( nType ); + if(!pHdl) + { + switch(nType) + { + case XML_SD_TYPE_STROKE : + { + pHdl = new XMLEnumPropertyHdl( aXML_LineStyle_EnumMap); + break; + } + case XML_SD_TYPE_LINEJOIN : + { + pHdl = new XMLEnumPropertyHdl( aXML_LineJoint_EnumMap); + break; + } + case XML_SD_TYPE_LINECAP : + { + pHdl = new XMLEnumPropertyHdl( aXML_LineCap_EnumMap ); + break; + } + case XML_SD_TYPE_FILLSTYLE : + { + pHdl = new XMLEnumPropertyHdl( aXML_FillStyle_EnumMap ); + break; + } + case XML_SD_TYPE_PRESPAGE_TYPE : + { + pHdl = new XMLEnumPropertyHdl( aXML_PresChange_EnumMap ); + break; + } + case XML_SD_TYPE_VISIBLE_HIDDEN: + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_VISIBLE), GetXMLToken(XML_HIDDEN) ); + break; + } + case XML_TYPE_SD_MIRROR: + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_HORIZONTAL), GetXMLToken(XML_NONE) ); + break; + } + case XML_SD_TYPE_PRESPAGE_STYLE : + { + pHdl = new XMLEnumPropertyHdl( aXML_FadeEffect_EnumMap ); + break; + } + case XML_SD_TYPE_PRESPAGE_SPEED : + { + pHdl = new XMLEnumPropertyHdl( aXML_TransSpeed_EnumMap ); + break; + } + case XML_SD_TYPE_PRESPAGE_DURATION : + { + pHdl = new XMLDurationPropertyHdl; + break; + } + case XML_SD_TYPE_TEXT_CROSSEDOUT : + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_SOLID), GetXMLToken(XML_NONE) ); + break; + } + case XML_SD_TYPE_OPACITY : + { + pHdl = new XMLOpacityPropertyHdl(mpImport); + break; + } + case XML_SD_TYPE_WRITINGMODE : + { + pHdl = new XMLEnumPropertyHdl( aXML_WritingMode_EnumMap ); + break; + } + case XML_SD_TYPE_WRITINGMODE2 : + { + pHdl = new XMLConstantsPropertyHandler ( aXML_WritingMode2_EnumMap, XML_LR_TB ); + break; + } + case XML_SD_TYPE_PRESPAGE_VISIBILITY : + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_VISIBLE), GetXMLToken(XML_HIDDEN) ); + break; + } + case XML_SD_TYPE_PRESPAGE_BACKSIZE: + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_FULL), GetXMLToken(XML_BORDER) ); + break; + } + + // 3D Properties + + case XML_SD_TYPE_BACKFACE_CULLING: + { + // #87922# DoubleSided -> BackfaceCulling + // This sal_Bool needs to be flipped, DoubleSided sal_True -> NO Backface culling + // and vice versa. + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_DISABLED), GetXMLToken(XML_ENABLED) ); + break; + } + + case XML_SD_TYPE_NORMALS_KIND: + { + pHdl = new XMLEnumPropertyHdl( aXML_NormalsKind_EnumMap ); + break; + } + case XML_SD_TYPE_NORMALS_DIRECTION: + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_NORMAL), GetXMLToken(XML_INVERSE) ); + break; + } + case XML_SD_TYPE_TEX_GENERATION_MODE_X: + { + pHdl = new XMLEnumPropertyHdl( aXML_TexGenerationX_EnumMap ); + break; + } + case XML_SD_TYPE_TEX_GENERATION_MODE_Y: + { + pHdl = new XMLEnumPropertyHdl( aXML_TexGenerationY_EnumMap ); + break; + } + case XML_SD_TYPE_TEX_KIND: + { + pHdl = new XMLEnumPropertyHdl( aXML_TexKind_EnumMap ); + break; + } + case XML_SD_TYPE_TEX_MODE: + { + pHdl = new XMLEnumPropertyHdl( aXML_TexMode_EnumMap ); + break; + } + case XML_SD_TYPE_NUMBULLET: + { + uno::Reference<ucb::XAnyCompareFactory> xCompareFac( mxModel, uno::UNO_QUERY ); + uno::Reference<ucb::XAnyCompare> xCompare; + if( xCompareFac.is() ) + xCompare = xCompareFac->createAnyCompareByName( "NumberingRules" ); + + pHdl = new XMLNumRulePropHdl( xCompare ); + break; + } + case XML_SD_TYPE_BITMAP_MODE: + { + pHdl = new XMLEnumPropertyHdl( aXML_BitmapMode_EnumMap ); + break; + } + case XML_SD_TYPE_BITMAPREPOFFSETX: + case XML_SD_TYPE_BITMAPREPOFFSETY: + { + pHdl = new XMLBitmapRepeatOffsetPropertyHandler( nType == XML_SD_TYPE_BITMAPREPOFFSETX ); + break; + } + case XML_SD_TYPE_FILLBITMAPSIZE: + { + pHdl = new XMLFillBitmapSizePropertyHandler(); + break; + } + case XML_SD_TYPE_LOGICAL_SIZE: + { + pHdl = new XMLBitmapLogicalSizePropertyHandler(); + break; + } + case XML_SD_TYPE_BITMAP_REFPOINT: + { + pHdl = new XMLEnumPropertyHdl( aXML_RefPoint_EnumMap); + break; + } + case XML_TYPE_TEXT_ANIMATION: + pHdl = new XMLEnumPropertyHdl( pXML_TextAnimation_Enum); + break; + case XML_TYPE_TEXT_ANIMATION_BLINKING: + pHdl = new XMLEnumPropertyHdl( pXML_TextAnimation_Blinking_Enum); + break; + case XML_TYPE_TEXT_ANIMATION_DIRECTION: + pHdl = new XMLEnumPropertyHdl( pXML_TextAnimationDirection_Enum); + break; + case XML_TYPE_TEXT_ANIMATION_STEPS: + pHdl = new XMLTextAnimationStepPropertyHdl; + break; + case XML_SD_TYPE_TEXT_ALIGN: + pHdl = new XMLEnumPropertyHdl( pXML_TextAlign_Enum); + break; + case XML_SD_TYPE_VERTICAL_ALIGN: + pHdl = new XMLEnumPropertyHdl( pXML_VerticalAlign_Enum); + break; + case XML_SD_TYPE_FITTOSIZE: + { + if (mpExport + && (mpExport->getSaneDefaultVersion() // tdf#97630 + != SvtSaveOptions::ODFSVER_012_EXT_COMPAT)) + { + pHdl = new XMLFitToSizeEnumPropertyHdl(pXML_FitToSize_Enum_Odf12); + } + else + { // import all values written by old LO + pHdl = new XMLFitToSizeEnumPropertyHdl(pXML_FitToSize_Enum); + } + } + break; + case XML_SD_TYPE_FITTOSIZE_AUTOFIT: + { + pHdl = new XMLFitToSizeEnumPropertyHdl(pXML_ShrinkToFit_Enum); + } + break; + case XML_SD_TYPE_MEASURE_UNIT: + pHdl = new XMLEnumPropertyHdl( pXML_MeasureUnit_Enum ); + break; + case XML_SD_TYPE_MEASURE_HALIGN: + pHdl = new XMLEnumPropertyHdl( pXML_Measure_HAlign_Enum); + break; + case XML_SD_TYPE_MEASURE_VALIGN: + pHdl = new XMLEnumPropertyHdl( pXML_Measure_VAlign_Enum); + break; + case XML_SD_TYPE_MEASURE_PLACING: + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_BELOW), GetXMLToken(XML_ABOVE) ); + } + break; + case XML_TYPE_TEXT_CLIP11: + pHdl = new XMLClipPropertyHandler( true ); + break; + case XML_TYPE_TEXT_CLIP: + pHdl = new XMLClipPropertyHandler( false ); + break; + + // #FontWork# + case XML_SD_TYPE_FONTWORK_STYLE : + pHdl = new XMLEnumPropertyHdl( pXML_Fontwork_Style_Enum ); + break; + case XML_SD_TYPE_FONTWORK_ADJUST : + pHdl = new XMLEnumPropertyHdl( pXML_Fontwork_Adjust_Enum ); + break; + case XML_SD_TYPE_FONTWORK_SHADOW : + pHdl = new XMLEnumPropertyHdl( pXML_Fontwork_Shadow_Enum ); + break; + case XML_SD_TYPE_FONTWORK_FORM : + pHdl = new XMLEnumPropertyHdl( pXML_Fontwork_Form_Enum ); + break; + + case XML_SD_TYPE_CONTROL_BORDER: + pHdl = new ::xmloff::OControlBorderHandler( ::xmloff::OControlBorderHandler::STYLE ); + break; + case XML_SD_TYPE_CONTROL_BORDER_COLOR: + pHdl = new ::xmloff::OControlBorderHandler( ::xmloff::OControlBorderHandler::COLOR ); + break; + case XML_SD_TYPE_IMAGE_SCALE_MODE: + pHdl = new ::xmloff::ImageScaleModeHandler; + break; + case XML_TYPE_CONTROL_TEXT_EMPHASIZE: + pHdl = new ::xmloff::OControlTextEmphasisHandler; + break; + + case XML_SD_TYPE_CAPTION_ANGLE_TYPE: + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_FIXED), GetXMLToken(XML_FREE) ); + break; + } + case XML_SD_TYPE_CAPTION_IS_ESC_REL: + pHdl = new XMLIsPercentagePropertyHandler; + break; + case XML_SD_TYPE_CAPTION_ESC_REL: + pHdl = new XMLCaptionEscapeRelative; + break; + case XML_SD_TYPE_CAPTION_ESC_ABS: + pHdl = new XMLPercentOrMeasurePropertyHandler; + break; + case XML_SD_TYPE_CAPTION_ESC_DIR: + pHdl = new XMLEnumPropertyHdl( pXML_Caption_Esc_Dir_Enum ); + break; + case XML_SD_TYPE_CAPTION_TYPE: + pHdl = new XMLEnumPropertyHdl( pXML_Caption_Type_Enum ); + break; + case XML_SD_TYPE_DATETIMEUPDATE: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_FIXED), GetXMLToken(XML_VARIABLE) ); + break; + case XML_SD_TYPE_DATETIME_FORMAT: + pHdl = new XMLDateTimeFormatHdl( mpExport ); + break; + case XML_SD_TYPE_TRANSITION_TYPE: + pHdl = new XMLEnumPropertyHdl( xmloff::aAnimations_EnumMap_TransitionType ); + break; + case XML_SD_TYPE_TRANSTIION_SUBTYPE: + pHdl = new XMLEnumPropertyHdl( xmloff::aAnimations_EnumMap_TransitionSubType ); + break; + case XML_SD_TYPE_TRANSTIION_DIRECTION: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_FORWARD), GetXMLToken(XML_REVERSE) ); + break; + case XML_TYPE_WRAP_OPTION: + pHdl = new XMLWordWrapPropertyHdl( mpImport ); + break; + + case XML_SD_TYPE_MOVE_PROTECT: + case XML_SD_TYPE_SIZE_PROTECT: + pHdl = new XMLMoveSizeProtectHdl( nType ); + break; + case XML_SD_TYPE_HEADER_FOOTER_VISIBILITY_TYPE: + pHdl = new XMLSdHeaderFooterVisibilityTypeHdl; + break; + case XML_SD_TYPE_CELL_ROTATION_ANGLE: + pHdl = new XMLSdRotationAngleTypeHdl; + break; + case XML_TYPE_TEXT_COLUMNS: + pHdl = new XMLTextColumnsPropertyHandler; + break; + case XML_TYPE_COMPLEX_COLOR: + pHdl = new XMLComplexColorHandler; + break; + } + + if(pHdl) + PutHdlCache(nType, pHdl); + } + + return pHdl; +} + +XMLShapePropertySetMapper::XMLShapePropertySetMapper(const rtl::Reference< XMLPropertyHandlerFactory >& rFactoryRef, + bool bForExport) +: XMLPropertySetMapper( aXMLSDProperties, rFactoryRef, bForExport ) +{ +} + +XMLShapePropertySetMapper::~XMLShapePropertySetMapper() +{ +} + +XMLShapeExportPropertyMapper::XMLShapeExportPropertyMapper( const rtl::Reference< XMLPropertySetMapper >& rMapper, SvXMLExport& rExport ) +: SvXMLExportPropertyMapper( rMapper ) +, maNumRuleExp( rExport ) +, mbIsInAutoStyles( true ) +{ +} + +XMLShapeExportPropertyMapper::~XMLShapeExportPropertyMapper() +{ +} + +void XMLShapeExportPropertyMapper::ContextFilter( + bool bEnableFoFontFamily, + std::vector< XMLPropertyState >& rProperties, + const uno::Reference< beans::XPropertySet >& rPropSet ) const +{ + XMLPropertyState* pRepeatOffsetX = nullptr; + XMLPropertyState* pRepeatOffsetY = nullptr; + XMLPropertyState* pTextAnimationBlinking = nullptr; + XMLPropertyState* pTextAnimationKind = nullptr; + + // #FontWork# + XMLPropertyState* pFontWorkStyle = nullptr; + XMLPropertyState* pFontWorkAdjust = nullptr; + XMLPropertyState* pFontWorkDistance = nullptr; + XMLPropertyState* pFontWorkStart = nullptr; + XMLPropertyState* pFontWorkMirror = nullptr; + XMLPropertyState* pFontWorkOutline = nullptr; + XMLPropertyState* pFontWorkShadow = nullptr; + XMLPropertyState* pFontWorkShadowColor = nullptr; + XMLPropertyState* pFontWorkShadowOffsetx = nullptr; + XMLPropertyState* pFontWorkShadowOffsety = nullptr; + XMLPropertyState* pFontWorkForm = nullptr; + XMLPropertyState* pFontWorkHideform = nullptr; + XMLPropertyState* pFontWorkShadowTransparence = nullptr; + + // OLE + XMLPropertyState* pOLEVisAreaLeft = nullptr; + XMLPropertyState* pOLEVisAreaTop = nullptr; + XMLPropertyState* pOLEVisAreaWidth = nullptr; + XMLPropertyState* pOLEVisAreaHeight = nullptr; + XMLPropertyState* pOLEIsInternal = nullptr; + + // caption + XMLPropertyState* pCaptionIsEscRel = nullptr; + XMLPropertyState* pCaptionEscRel = nullptr; + XMLPropertyState* pCaptionEscAbs = nullptr; + + // filter fo:clip + XMLPropertyState* pClip11State = nullptr; + XMLPropertyState* pClipState = nullptr; + + XMLPropertyState* pGraphicWritingMode2 = nullptr; + XMLPropertyState* pShapeWritingMode = nullptr; + XMLPropertyState* pTextWritingMode = nullptr; + XMLPropertyState* pControlWritingMode = nullptr; + + // filter properties + for( auto& rProp : rProperties ) + { + XMLPropertyState *property = &rProp; + if( property->mnIndex == -1 ) + continue; + + // find properties with context + // to prevent writing this property set mnIndex member to -1 + switch( getPropertySetMapper()->GetEntryContextId( property->mnIndex )) + { + case CTF_NUMBERINGRULES: + { + if( mbIsInAutoStyles ) + property->mnIndex = -1; + } + break; + case CTF_SD_NUMBERINGRULES_NAME: + { + // this property is not exported in the style:properties element + // because it's an XIndexAccess and not a string. + // This will be handled in SvXMLAutoStylePoolP::exportStyleAttributes + // This is suboptimal + if( !mbIsInAutoStyles ) + property->mnIndex = -1; + } + break; + case CTF_WRITINGMODE2: + pGraphicWritingMode2 = property; + break; + case CTF_WRITINGMODE: + pShapeWritingMode = property; + break; + case CTF_CONTROLWRITINGMODE: + pControlWritingMode = property; + break; + case CTF_TEXTWRITINGMODE: + pTextWritingMode = property; + break; + case CTF_REPEAT_OFFSET_X: + pRepeatOffsetX = property; + break; + + case CTF_REPEAT_OFFSET_Y: + pRepeatOffsetY = property; + break; + + case CTF_DASHNAME: + case CTF_FILLGRADIENTNAME: + case CTF_FILLHATCHNAME: + case CTF_FILLBITMAPNAME: + { + OUString aStr; + if( (property->maValue >>= aStr) && aStr.isEmpty() ) + property->mnIndex = -1; + } + break; + case CTF_TEXTANIMATION_BLINKING: + pTextAnimationBlinking = property; + break; + case CTF_TEXTANIMATION_KIND: + pTextAnimationKind = property; + break; + + // #FontWork# + case CTF_FONTWORK_STYLE: pFontWorkStyle = property; break; + case CTF_FONTWORK_ADJUST: pFontWorkAdjust = property; break; + case CTF_FONTWORK_DISTANCE: pFontWorkDistance = property; break; + case CTF_FONTWORK_START: pFontWorkStart = property; break; + case CTF_FONTWORK_MIRROR: pFontWorkMirror = property; break; + case CTF_FONTWORK_OUTLINE: pFontWorkOutline = property; break; + case CTF_FONTWORK_SHADOW: pFontWorkShadow = property; break; + case CTF_FONTWORK_SHADOWCOLOR: pFontWorkShadowColor = property; break; + case CTF_FONTWORK_SHADOWOFFSETX: pFontWorkShadowOffsetx = property; break; + case CTF_FONTWORK_SHADOWOFFSETY: pFontWorkShadowOffsety = property; break; + case CTF_FONTWORK_FORM: pFontWorkForm = property; break; + case CTF_FONTWORK_HIDEFORM: pFontWorkHideform = property; break; + case CTF_FONTWORK_SHADOWTRANSPARENCE: pFontWorkShadowTransparence = property; break; + + // OLE + case CTF_SD_OLE_VIS_AREA_EXPORT_LEFT: pOLEVisAreaLeft = property; break; + case CTF_SD_OLE_VIS_AREA_EXPORT_TOP: pOLEVisAreaTop = property; break; + case CTF_SD_OLE_VIS_AREA_EXPORT_WIDTH: pOLEVisAreaWidth = property; break; + case CTF_SD_OLE_VIS_AREA_EXPORT_HEIGHT: pOLEVisAreaHeight = property; break; + case CTF_SD_OLE_ISINTERNAL: pOLEIsInternal = property; break; + + case CTF_FRAME_DISPLAY_SCROLLBAR: + { + if( !property->maValue.hasValue() ) + property->mnIndex = -1; + } + break; + case CTF_FRAME_MARGIN_HORI: + case CTF_FRAME_MARGIN_VERT: + { + sal_Int32 nValue = 0; + if( (property->maValue >>= nValue) && (nValue < 0) ) + property->mnIndex = -1; + } + break; + + case CTF_SD_MOVE_PROTECT: + { + bool bProtected; + if( (property->maValue >>= bProtected) && !bProtected ) + property->mnIndex = -1; + } + break; + case CTF_SD_SIZE_PROTECT: + { + bool bProtected; + if( (property->maValue >>= bProtected) && !bProtected ) + property->mnIndex = -1; + } + break; + case CTF_CAPTION_ISESCREL: pCaptionIsEscRel = property; break; + case CTF_CAPTION_ESCREL: pCaptionEscRel = property; break; + case CTF_CAPTION_ESCABS: pCaptionEscAbs = property; break; + case CTF_TEXT_CLIP11: pClip11State = property; break; + case CTF_TEXT_CLIP: pClipState = property; break; + } + } + + if (pGraphicWritingMode2) + { + // A style:writing-mode attribute G in graphic-properties is only evaluated if there is no + // style:writing-mode attribute P in the paragraph-properties of the same graphic style. + // Otherwise the value of P is used. For values lr-tb, rl-tb and tb-rl the values G and P + // should be the same. But other values in G cannot be expressed in P and would produce default + // 0 value in P, preventing evaluation of G. + sal_Int16 eGraphicWritingMode; + if ((pGraphicWritingMode2->maValue >>= eGraphicWritingMode) + && eGraphicWritingMode >= text::WritingMode2::TB_LR && pShapeWritingMode) + pShapeWritingMode->mnIndex = -1; + } + + // check for duplicate writing mode + if( pShapeWritingMode && (pTextWritingMode || pControlWritingMode) ) + { + if( pTextWritingMode ) + pTextWritingMode->mnIndex = -1; + if( pControlWritingMode ) + pControlWritingMode->mnIndex = -1; + + text::WritingMode eWritingMode; + if( pShapeWritingMode->maValue >>= eWritingMode ) + { + if( text::WritingMode_LR_TB == eWritingMode ) + { + pShapeWritingMode->mnIndex = -1; + pShapeWritingMode = nullptr; + } + } + } + else if( pTextWritingMode && pControlWritingMode ) + { + pControlWritingMode->mnIndex = -1; + + sal_Int32 eWritingMode; + if (pTextWritingMode->maValue >>= eWritingMode) + { + if (text::WritingMode2::LR_TB == eWritingMode) + { + pTextWritingMode->mnIndex = -1; + pTextWritingMode = nullptr; + } + } + } + + // do not export visual area for internal ole objects + if( pOLEIsInternal ) + { + bool bInternal; + if( (pOLEIsInternal->maValue >>= bInternal) && !bInternal ) + { + try + { + awt::Rectangle aRect; + if( rPropSet->getPropertyValue( "VisibleArea" ) >>= aRect ) + { + if( pOLEVisAreaLeft ) + { + pOLEVisAreaLeft->mnIndex = getPropertySetMapper()->FindEntryIndex( CTF_SD_OLE_VIS_AREA_IMPORT_LEFT ); + pOLEVisAreaLeft->maValue <<= aRect; + } + if( pOLEVisAreaTop ) + { + pOLEVisAreaTop->mnIndex = getPropertySetMapper()->FindEntryIndex( CTF_SD_OLE_VIS_AREA_IMPORT_TOP ); + pOLEVisAreaTop->maValue <<= aRect; + } + if( pOLEVisAreaWidth ) + { + pOLEVisAreaWidth->mnIndex = getPropertySetMapper()->FindEntryIndex( CTF_SD_OLE_VIS_AREA_IMPORT_WIDTH ); + pOLEVisAreaWidth->maValue <<= aRect; + } + if( pOLEVisAreaHeight ) + { + pOLEVisAreaHeight->mnIndex = getPropertySetMapper()->FindEntryIndex( CTF_SD_OLE_VIS_AREA_IMPORT_HEIGHT ); + pOLEVisAreaHeight->maValue <<= aRect; + } + } + } + catch( uno::Exception& ) + { + } + } + else + { + if( pOLEVisAreaLeft ) pOLEVisAreaLeft->mnIndex = -1; + if( pOLEVisAreaTop ) pOLEVisAreaTop->mnIndex = -1; + if( pOLEVisAreaWidth ) pOLEVisAreaWidth->mnIndex = -1; + if( pOLEVisAreaHeight ) pOLEVisAreaHeight->mnIndex = -1; + } + + pOLEIsInternal->mnIndex = -1; + } + + if( pTextAnimationBlinking && pTextAnimationKind ) + { + drawing::TextAnimationKind eKind; + if( (pTextAnimationKind->maValue >>= eKind) && eKind != drawing::TextAnimationKind_BLINK ) + { + pTextAnimationBlinking->mnIndex = -1; + } + else + { + pTextAnimationKind->mnIndex = -1; + } + } + + if( pRepeatOffsetX && pRepeatOffsetY ) + { + sal_Int32 nOffset = 0; + if( ( pRepeatOffsetX->maValue >>= nOffset ) && ( nOffset == 0 ) ) + pRepeatOffsetX->mnIndex = -1; + else + pRepeatOffsetY->mnIndex = -1; + } + + if(pFontWorkStyle) + { + // #FontWork# + sal_Int32 nStyle = 0; + + if(pFontWorkStyle->maValue >>= nStyle) + { + if(/*XFormTextStyle::NONE*/4 == nStyle) + { + pFontWorkStyle->mnIndex = -1; + if(pFontWorkAdjust) + pFontWorkAdjust->mnIndex = -1; + if(pFontWorkDistance) + pFontWorkDistance->mnIndex = -1; + if(pFontWorkStart) + pFontWorkStart->mnIndex = -1; + if(pFontWorkMirror) + pFontWorkMirror->mnIndex = -1; + if(pFontWorkOutline) + pFontWorkOutline->mnIndex = -1; + if(pFontWorkShadow) + pFontWorkShadow->mnIndex = -1; + if(pFontWorkShadowColor) + pFontWorkShadowColor->mnIndex = -1; + if(pFontWorkShadowOffsetx) + pFontWorkShadowOffsetx->mnIndex = -1; + if(pFontWorkShadowOffsety) + pFontWorkShadowOffsety->mnIndex = -1; + if(pFontWorkForm) + pFontWorkForm->mnIndex = -1; + if(pFontWorkHideform) + pFontWorkHideform->mnIndex = -1; + if(pFontWorkShadowTransparence) + pFontWorkShadowTransparence->mnIndex = -1; + } + } + } + + if( pCaptionIsEscRel ) + { + bool bIsRel = false; + pCaptionIsEscRel->maValue >>= bIsRel; + + if( bIsRel ) + { + if( pCaptionEscAbs ) + pCaptionEscAbs->mnIndex = -1; + } + else + { + if( pCaptionEscRel ) + pCaptionEscRel->mnIndex = -1; + } + + pCaptionIsEscRel->mnIndex = -1; + } + + if( pClipState != nullptr && pClip11State != nullptr ) + pClip11State->mnIndex = -1; + + SvXMLExportPropertyMapper::ContextFilter(bEnableFoFontFamily, rProperties, rPropSet); +} + +void XMLShapeExportPropertyMapper::handleSpecialItem( + comphelper::AttributeList& rAttrList, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + switch( getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex ) ) + { + case CTF_SD_CONTROL_SHAPE_DATA_STYLE: + // not to be handled by the base class + break; + + default: + SvXMLExportPropertyMapper::handleSpecialItem( rAttrList, rProperty, rUnitConverter, rNamespaceMap, pProperties, nIdx ); + break; + } +} + +void XMLShapeExportPropertyMapper::handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx) const +{ + switch( getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex ) ) + { + case CTF_NUMBERINGRULES: + { + // only export list-styles as elements in styles section + if( !mbIsInAutoStyles ) + { + uno::Reference< container::XIndexReplace > xNumRule( rProperty.maValue, uno::UNO_QUERY ); + if( xNumRule.is() ) + const_cast<XMLShapeExportPropertyMapper*>(this)->maNumRuleExp.exportNumberingRule(GetStyleName(), false, xNumRule); + } + } + break; + default: + SvXMLExportPropertyMapper::handleElementItem( rExport, rProperty, nFlags, pProperties, nIdx ); + break; + } +} + +XMLPageExportPropertyMapper::XMLPageExportPropertyMapper( const rtl::Reference< XMLPropertySetMapper >& rMapper, SvXMLExport& rExport ) : + SvXMLExportPropertyMapper( rMapper ), + mrExport( rExport ) +{ +} + +XMLPageExportPropertyMapper::~XMLPageExportPropertyMapper() +{ +} + +void XMLPageExportPropertyMapper::ContextFilter( + bool bEnableFoFontFamily, + std::vector< XMLPropertyState >& rProperties, + const uno::Reference< beans::XPropertySet >& rPropSet ) const +{ + XMLPropertyState* pRepeatOffsetX = nullptr; + XMLPropertyState* pRepeatOffsetY = nullptr; + XMLPropertyState* pTransType = nullptr; + XMLPropertyState* pTransDuration = nullptr; + XMLPropertyState* pDateTimeUpdate = nullptr; + XMLPropertyState* pDateTimeFormat = nullptr; + XMLPropertyState* pTransitionFadeColor = nullptr; + + sal_Int16 nTransitionType = 0; + + // filter properties + for( auto& rProp : rProperties ) + { + XMLPropertyState *property = &rProp; + if( property->mnIndex == -1 ) + continue; + + // find properties with context + // to prevent writing this property set mnIndex member to -1 + switch( getPropertySetMapper()->GetEntryContextId( property->mnIndex )) + { + + case CTF_REPEAT_OFFSET_X: + pRepeatOffsetX = property; + break; + + case CTF_REPEAT_OFFSET_Y: + pRepeatOffsetY = property; + break; + case CTF_PAGE_TRANS_TYPE: + pTransType = property; + break; + case CTF_PAGE_TRANS_STYLE: + if( mrExport.getExportFlags() & SvXMLExportFlags::OASIS ) + (*property).mnIndex = -1; + break; + case CTF_PAGE_TRANSITION_TYPE: + { + if( (!(mrExport.getExportFlags() & SvXMLExportFlags::OASIS)) || + (((*property).maValue >>= nTransitionType) && (nTransitionType == 0)) ) + (*property).mnIndex = -1; + } + break; + case CTF_PAGE_TRANSITION_SUBTYPE: + { + sal_Int16 nTransitionSubtype = sal_Int16(); + if( (!(mrExport.getExportFlags() & SvXMLExportFlags::OASIS)) || + (((*property).maValue >>= nTransitionSubtype) && (nTransitionSubtype == 0)) ) + (*property).mnIndex = -1; + + } + break; + case CTF_PAGE_TRANSITION_DIRECTION: + { + bool bDirection; + if( (!(mrExport.getExportFlags() & SvXMLExportFlags::OASIS)) || + (((*property).maValue >>= bDirection) && bDirection) ) + (*property).mnIndex = -1; + } + break; + case CTF_PAGE_TRANSITION_FADECOLOR: + if( !(mrExport.getExportFlags() & SvXMLExportFlags::OASIS) ) + (*property).mnIndex = -1; + else + pTransitionFadeColor = property; + break; + case CTF_PAGE_TRANS_SPEED: + { + presentation::AnimationSpeed aEnum; + if( ((*property).maValue >>= aEnum) && aEnum == presentation::AnimationSpeed_MEDIUM ) + (*property).mnIndex = -1; + } + break; + case CTF_PAGE_VISIBLE: + { + bool bVisible = false; + (*property).maValue >>= bVisible; + if( bVisible ) + (*property).mnIndex = -1; + } + break; + case CTF_PAGE_TRANS_DURATION: + pTransDuration = property; + break; + case CTF_HEADER_TEXT: + case CTF_FOOTER_TEXT: + case CTF_DATE_TIME_TEXT: + { + OUString aValue; + (*property).maValue >>= aValue; + if( aValue.isEmpty() ) + (*property).mnIndex = -1; + } + break; + + case CTF_DATE_TIME_UPDATE: + pDateTimeUpdate = property; + break; + + case CTF_DATE_TIME_FORMAT: + pDateTimeFormat = property; + break; + } + } + + if( pTransitionFadeColor && nTransitionType != css::animations::TransitionType::FADE ) + pTransitionFadeColor->mnIndex = -1; + + if( pDateTimeFormat && pDateTimeUpdate ) + { + bool bIsFixed = false; + pDateTimeUpdate->maValue >>= bIsFixed; + if( bIsFixed ) + pDateTimeFormat->mnIndex = -1; + } + + if( pRepeatOffsetX && pRepeatOffsetY ) + { + sal_Int32 nOffset = 0; + if( ( pRepeatOffsetX->maValue >>= nOffset ) && ( nOffset == 0 ) ) + pRepeatOffsetX->mnIndex = -1; + else + pRepeatOffsetY->mnIndex = -1; + } + + if( pTransType && pTransDuration ) + { + sal_Int32 nChange = 0; + pTransType->maValue >>= nChange; + + // only export duration for automatic + if( nChange != 1 ) + pTransDuration->mnIndex = -1; + + // do not export default transition change + if( nChange == 0 ) + pTransType->mnIndex = -1; + } + + SvXMLExportPropertyMapper::ContextFilter(bEnableFoFontFamily, rProperties, rPropSet); +} + +void XMLPageExportPropertyMapper::handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx) const +{ + switch( getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex ) ) + { + case CTF_PAGE_SOUND_URL: + { + OUString aSoundURL; + if( (rProperty.maValue >>= aSoundURL) && !aSoundURL.isEmpty() ) + { + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, mrExport.GetRelativeReference(aSoundURL) ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_NEW ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST ); + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_PRESENTATION, XML_SOUND, true, true ); + } + } + break; + default: + SvXMLExportPropertyMapper::handleElementItem( rExport, rProperty, nFlags, pProperties, nIdx ); + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/sdpropls.hxx b/xmloff/source/draw/sdpropls.hxx new file mode 100644 index 0000000000..607fa3ace7 --- /dev/null +++ b/xmloff/source/draw/sdpropls.hxx @@ -0,0 +1,131 @@ +/* -*- 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 . + */ + +#pragma once + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/drawing/ConnectorType.hpp> +#include <com/sun/star/drawing/CircleKind.hpp> +#include <xmloff/xmlnume.hxx> +#include <xmloff/maptype.hxx> +#include <xmloff/xmlement.hxx> +#include <xmloff/prhdlfac.hxx> +#include <xmloff/xmlprmap.hxx> +#include <xmloff/xmlexppr.hxx> + +// entry list for graphic properties + +extern const XMLPropertyMapEntry aXMLSDProperties[]; + +// entry list for presentation page properties + +extern const XMLPropertyMapEntry aXMLSDPresPageProps[]; + +// enum maps for attributes + +extern SvXMLEnumMapEntry<css::drawing::ConnectorType> const aXML_ConnectionKind_EnumMap[]; +extern SvXMLEnumMapEntry<css::drawing::CircleKind> const aXML_CircleKind_EnumMap[]; + +/** contains the attribute to property mapping for a drawing layer table */ +extern const XMLPropertyMapEntry aXMLTableShapeAttributes[]; + +// factory for own graphic properties + +class SvXMLExport; +class SvXMLImport; + +class XMLSdPropHdlFactory : public XMLPropertyHandlerFactory +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + SvXMLExport* mpExport; + SvXMLImport* mpImport; + +public: + XMLSdPropHdlFactory( css::uno::Reference< css::frame::XModel > xModel, SvXMLExport& rExport ); + XMLSdPropHdlFactory( css::uno::Reference< css::frame::XModel > xModel, SvXMLImport& rImport ); + virtual ~XMLSdPropHdlFactory() override; + virtual const XMLPropertyHandler* GetPropertyHandler( sal_Int32 nType ) const override; +}; + +class XMLShapePropertySetMapper : public XMLPropertySetMapper +{ +public: + XMLShapePropertySetMapper(const rtl::Reference< XMLPropertyHandlerFactory >& rFactoryRef, bool bForExport); + virtual ~XMLShapePropertySetMapper() override; +}; + +class XMLShapeExportPropertyMapper : public SvXMLExportPropertyMapper +{ +private: + SvxXMLNumRuleExport maNumRuleExp; + bool mbIsInAutoStyles; + +protected: + virtual void ContextFilter( + bool bEnableFoFontFamily, + ::std::vector< XMLPropertyState >& rProperties, + const css::uno::Reference< css::beans::XPropertySet >& rPropSet ) const override; +public: + XMLShapeExportPropertyMapper( const rtl::Reference< XMLPropertySetMapper >& rMapper, SvXMLExport& rExport ); + virtual ~XMLShapeExportPropertyMapper() override; + + virtual void handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState >* pProperties, + sal_uInt32 nIdx + ) const override; + + void SetAutoStyles( bool bIsInAutoStyles ) { mbIsInAutoStyles = bIsInAutoStyles; } + + virtual void handleSpecialItem( + comphelper::AttributeList& rAttrList, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const override; +}; + +class XMLPageExportPropertyMapper : public SvXMLExportPropertyMapper +{ +private: + SvXMLExport& mrExport; + +protected: + virtual void ContextFilter( + bool bEnableFoFontFamily, + ::std::vector< XMLPropertyState >& rProperties, + const css::uno::Reference< css::beans::XPropertySet >& rPropSet ) const override; +public: + XMLPageExportPropertyMapper( const rtl::Reference< XMLPropertySetMapper >& rMapper, SvXMLExport& rExport ); + virtual ~XMLPageExportPropertyMapper() override; + + virtual void handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState >* pProperties, + sal_uInt32 nIdx + ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/sdxmlexp.cxx b/xmloff/source/draw/sdxmlexp.cxx new file mode 100644 index 0000000000..289f1a542e --- /dev/null +++ b/xmloff/source/draw/sdxmlexp.cxx @@ -0,0 +1,2853 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <xmloff/autolayout.hxx> +#include <xmloff/unointerfacetouniqueidentifiermapper.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmltoken.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/presentation/XPresentationSupplier.hpp> +#include <com/sun/star/presentation/XCustomPresentationSupplier.hpp> +#include <com/sun/star/geometry/RealPoint2D.hpp> +#include <com/sun/star/office/XAnnotationAccess.hpp> +#include <com/sun/star/uno/Any.hxx> +#include "sdxmlexp_impl.hxx" +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/drawing/XMasterPagesSupplier.hpp> +#include <com/sun/star/presentation/XHandoutMasterSupplier.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/view/PaperOrientation.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> + +#include <com/sun/star/form/XFormsSupplier2.hpp> +#include <com/sun/star/presentation/XPresentationPage.hpp> +#include <com/sun/star/drawing/XMasterPageTarget.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/animations/XAnimationNodeSupplier.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/util/Duration.hpp> +#include <com/sun/star/util/MeasureUnit.hpp> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <tools/gen.hxx> +#include <sax/tools/converter.hxx> +#include <xmloff/xmlaustp.hxx> +#include <xmloff/families.hxx> +#include <xmloff/styleexp.hxx> +#include <xmloff/settingsstore.hxx> +#include <xmloff/table/XMLTableExport.hxx> +#include <xmloff/ProgressBarHelper.hxx> +#include "sdpropls.hxx" +#include <xmloff/xmlexppr.hxx> + +#include <PropertySetMerger.hxx> +#include "layerexp.hxx" + +#include "XMLNumberStylesExport.hxx" + +#include <xmloff/animationexport.hxx> + +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/util/Color.hpp> +#include <docmodel/uno/UnoTheme.hxx> +#include <docmodel/theme/Theme.hxx> +#include <o3tl/enumrange.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::office; +using namespace ::com::sun::star::presentation; +using namespace ::com::sun::star::geometry; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +class ImpXMLEXPPageMasterInfo +{ + sal_Int32 mnBorderBottom; + sal_Int32 mnBorderLeft; + sal_Int32 mnBorderRight; + sal_Int32 mnBorderTop; + sal_Int32 mnWidth; + sal_Int32 mnHeight; + view::PaperOrientation meOrientation; + OUString msName; + OUString msMasterPageName; + +public: + ImpXMLEXPPageMasterInfo(const SdXMLExport& rExp, const Reference<XDrawPage>& xPage); + bool operator==(const ImpXMLEXPPageMasterInfo& rInfo) const; + void SetName(const OUString& rStr); + + const OUString& GetName() const { return msName; } + const OUString& GetMasterPageName() const { return msMasterPageName; } + + sal_Int32 GetBorderBottom() const { return mnBorderBottom; } + sal_Int32 GetBorderLeft() const { return mnBorderLeft; } + sal_Int32 GetBorderRight() const { return mnBorderRight; } + sal_Int32 GetBorderTop() const { return mnBorderTop; } + sal_Int32 GetWidth() const { return mnWidth; } + sal_Int32 GetHeight() const { return mnHeight; } + view::PaperOrientation GetOrientation() const { return meOrientation; } +}; + +ImpXMLEXPPageMasterInfo::ImpXMLEXPPageMasterInfo( + const SdXMLExport& rExp, + const Reference<XDrawPage>& xPage) +: mnBorderBottom(0), + mnBorderLeft(0), + mnBorderRight(0), + mnBorderTop(0), + mnWidth(0), + mnHeight(0), + meOrientation(rExp.IsDraw() ? view::PaperOrientation_PORTRAIT : view::PaperOrientation_LANDSCAPE) +{ + Reference <beans::XPropertySet> xPropSet(xPage, UNO_QUERY); + if(xPropSet.is()) + { + Any aAny; + + Reference< beans::XPropertySetInfo > xPropsInfo( xPropSet->getPropertySetInfo() ); + if( xPropsInfo.is() && xPropsInfo->hasPropertyByName("BorderBottom")) + { + aAny = xPropSet->getPropertyValue("BorderBottom"); + aAny >>= mnBorderBottom; + + aAny = xPropSet->getPropertyValue("BorderLeft"); + aAny >>= mnBorderLeft; + + aAny = xPropSet->getPropertyValue("BorderRight"); + aAny >>= mnBorderRight; + + aAny = xPropSet->getPropertyValue("BorderTop"); + aAny >>= mnBorderTop; + } + + if( xPropsInfo.is() && xPropsInfo->hasPropertyByName("Width")) + { + aAny = xPropSet->getPropertyValue("Width"); + aAny >>= mnWidth; + + aAny = xPropSet->getPropertyValue("Height"); + aAny >>= mnHeight; + } + + if( xPropsInfo.is() && xPropsInfo->hasPropertyByName("Orientation")) + { + aAny = xPropSet->getPropertyValue("Orientation"); + aAny >>= meOrientation; + } + } + + Reference <container::XNamed> xMasterNamed(xPage, UNO_QUERY); + if(xMasterNamed.is()) + { + msMasterPageName = xMasterNamed->getName(); + } +} + +bool ImpXMLEXPPageMasterInfo::operator==(const ImpXMLEXPPageMasterInfo& rInfo) const +{ + return ((mnBorderBottom == rInfo.mnBorderBottom) + && (mnBorderLeft == rInfo.mnBorderLeft) + && (mnBorderRight == rInfo.mnBorderRight) + && (mnBorderTop == rInfo.mnBorderTop) + && (mnWidth == rInfo.mnWidth) + && (mnHeight == rInfo.mnHeight) + && (meOrientation == rInfo.meOrientation)); +} + +void ImpXMLEXPPageMasterInfo::SetName(const OUString& rStr) +{ + msName = rStr; +} + +#define IMP_AUTOLAYOUT_INFO_MAX (35L) + +class ImpXMLAutoLayoutInfo +{ + sal_uInt16 mnType; + ImpXMLEXPPageMasterInfo* mpPageMasterInfo; + OUString msLayoutName; + tools::Rectangle maTitleRect; + tools::Rectangle maPresRect; + sal_Int32 mnGapX; + sal_Int32 mnGapY; + +public: + ImpXMLAutoLayoutInfo(sal_uInt16 nTyp, ImpXMLEXPPageMasterInfo* pInf); + + sal_uInt16 GetLayoutType() const { return mnType; } + ImpXMLEXPPageMasterInfo* GetPageMasterInfo() const { return mpPageMasterInfo; } + sal_Int32 GetGapX() const { return mnGapX; } + sal_Int32 GetGapY() const { return mnGapY; } + + const OUString& GetLayoutName() const { return msLayoutName; } + void SetLayoutName(const OUString& rNew) { msLayoutName = rNew; } + + const tools::Rectangle& GetTitleRectangle() const { return maTitleRect; } + const tools::Rectangle& GetPresRectangle() const { return maPresRect; } + + static bool IsCreateNecessary(sal_uInt16 nTyp); +}; + +bool ImpXMLAutoLayoutInfo::IsCreateNecessary(sal_uInt16 nTyp) +{ + if(nTyp == 5 /* AUTOLAYOUT_ORG */ + || nTyp == 20 /* AUTOLAYOUT_NONE */ + || nTyp >= IMP_AUTOLAYOUT_INFO_MAX) + return false; + return true; +} + +ImpXMLAutoLayoutInfo::ImpXMLAutoLayoutInfo(sal_uInt16 nTyp, ImpXMLEXPPageMasterInfo* pInf) + : mnType(nTyp) + , mpPageMasterInfo(pInf) + , mnGapX(0) + , mnGapY(0) +{ + // create full info (initialize with typical values) + Point aPagePos(0,0); + Size aPageSize(28000, 21000); + Size aPageInnerSize(28000, 21000); + + if(mpPageMasterInfo) + { + aPagePos = Point(mpPageMasterInfo->GetBorderLeft(), mpPageMasterInfo->GetBorderTop()); + aPageSize = Size(mpPageMasterInfo->GetWidth(), mpPageMasterInfo->GetHeight()); + aPageInnerSize = aPageSize; + aPageInnerSize.AdjustWidth(-(mpPageMasterInfo->GetBorderLeft() + mpPageMasterInfo->GetBorderRight())); + aPageInnerSize.AdjustHeight(-(mpPageMasterInfo->GetBorderTop() + mpPageMasterInfo->GetBorderBottom())); + } + + // title rectangle aligning + Point aTitlePos(aPagePos); + Size aTitleSize(aPageInnerSize); + + if(mnType == 21 /* AUTOLAYOUT_NOTES */) + { + aTitleSize.setHeight(static_cast<tools::Long>(aTitleSize.Height() / 2.5)); + Point aPos = aTitlePos; + aPos.AdjustY( tools::Long( aTitleSize.Height() * 0.083 ) ); + Size aPartArea = aTitleSize; + Size aSize; + + // scale handout rectangle using actual page size + double fH = static_cast<double>(aPartArea.Width()) / aPageSize.Width(); + double fV = static_cast<double>(aPartArea.Height()) / aPageSize.Height(); + + if ( fH > fV ) + fH = fV; + aSize.setWidth( static_cast<tools::Long>(fH * aPageSize.Width()) ); + aSize.setHeight( static_cast<tools::Long>(fH * aPageSize.Height()) ); + + aPos.AdjustX((aPartArea.Width() - aSize.Width()) / 2); + aPos.AdjustY((aPartArea.Height()- aSize.Height())/ 2); + + aTitlePos = aPos; + aTitleSize = aSize; + } + else if(mnType == AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT || mnType == AUTOLAYOUT_VTITLE_VCONTENT) + { + Point aClassicTPos( + aTitlePos.X() + tools::Long( aTitleSize.Width() * 0.0735 ), + aTitlePos.Y() + tools::Long( aTitleSize.Height() * 0.083 )); + Size aClassicTSize( + tools::Long( aTitleSize.Width() * 0.854 ), + tools::Long( aTitleSize.Height() * 0.167 )); + Point aLPos(aPagePos); + Size aLSize(aPageInnerSize); + Point aClassicLPos( + aLPos.X() + tools::Long( aLSize.Width() * 0.0735 ), + aLPos.Y() + tools::Long( aLSize.Height() * 0.472 )); + Size aClassicLSize( + tools::Long( aLSize.Width() * 0.854 ), + tools::Long( aLSize.Height() * 0.444 )); + + aTitlePos.setX( (aClassicTPos.X() + aClassicTSize.Width()) - aClassicTSize.Height() ); + aTitlePos.setY( aClassicTPos.Y() ); + aTitleSize.setWidth( aClassicTSize.Height() ); + aTitleSize.setHeight( (aClassicLPos.Y() + aClassicLSize.Height()) - aClassicTPos.Y() ); + } + else + { + aTitlePos.AdjustX( tools::Long( aTitleSize.Width() * 0.0735 ) ); + aTitlePos.AdjustY( tools::Long( aTitleSize.Height() * 0.083 ) ); + aTitleSize.setWidth( tools::Long( aTitleSize.Width() * 0.854 ) ); + aTitleSize.setHeight( tools::Long( aTitleSize.Height() * 0.167 ) ); + } + + maTitleRect.SetPos(aTitlePos); + maTitleRect.SetSize(aTitleSize); + + // layout rectangle aligning + Point aLayoutPos(aPagePos); + Size aLayoutSize(aPageInnerSize); + + if(mnType == 21 /* AUTOLAYOUT_NOTES */) + { + aLayoutPos.AdjustX( tools::Long( aLayoutSize.Width() * 0.0735 ) ); + aLayoutPos.AdjustY( tools::Long( aLayoutSize.Height() * 0.472 ) ); + aLayoutSize.setWidth( tools::Long( aLayoutSize.Width() * 0.854 ) ); + aLayoutSize.setHeight( tools::Long( aLayoutSize.Height() * 0.444 ) ); + } + else if((mnType >= 22 && mnType <= 26) || (mnType == 31)) // AUTOLAYOUT_HANDOUT* + { + // keep info for inner area in maPresRect, put info for gap size + // to maTitleRect position + mnGapX = (aPageSize.Width() - aPageInnerSize.Width()) / 2; + mnGapY = (aPageSize.Height() - aPageInnerSize.Height()) / 2; + + if(!mnGapX) + mnGapX = aPageSize.Width() / 10; + + if(!mnGapY) + mnGapY = aPageSize.Height() / 10; + + if(mnGapX < aPageInnerSize.Width() / 10) + mnGapX = aPageInnerSize.Width() / 10; + + if(mnGapY < aPageInnerSize.Height() / 10) + mnGapY = aPageInnerSize.Height() / 10; + } + else if(mnType == AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT || mnType == AUTOLAYOUT_VTITLE_VCONTENT) + { + Point aClassicTPos( + aTitlePos.X() + tools::Long( aTitleSize.Width() * 0.0735 ), + aTitlePos.Y() + tools::Long( aTitleSize.Height() * 0.083 )); + Size aClassicTSize( + tools::Long( aTitleSize.Width() * 0.854 ), + tools::Long( aTitleSize.Height() * 0.167 )); + Point aClassicLPos( + aLayoutPos.X() + tools::Long( aLayoutSize.Width() * 0.0735 ), + aLayoutPos.Y() + tools::Long( aLayoutSize.Height() * 0.472 )); + Size aClassicLSize( + tools::Long( aLayoutSize.Width() * 0.854 ), + tools::Long( aLayoutSize.Height() * 0.444 )); + + aLayoutPos.setX( aClassicLPos.X() ); + aLayoutPos.setY( aClassicTPos.Y() ); + aLayoutSize.setWidth( (aClassicLPos.X() + aClassicLSize.Width()) + - (aClassicTSize.Height() + (aClassicLPos.Y() - (aClassicTPos.Y() + aClassicTSize.Height())))); + aLayoutSize.setHeight( (aClassicLPos.Y() + aClassicLSize.Height()) - aClassicTPos.Y() ); + } + else if( mnType == AUTOLAYOUT_ONLY_TEXT ) + { + aLayoutPos = aTitlePos; + aLayoutSize.setWidth( aTitleSize.Width() ); + aLayoutSize.setHeight( tools::Long( aLayoutSize.Height() * 0.825 ) ); + } + else + { + aLayoutPos.AdjustX( tools::Long( aLayoutSize.Width() * 0.0735 ) ); + aLayoutPos.AdjustY( tools::Long( aLayoutSize.Height() * 0.278 ) ); + aLayoutSize.setWidth( tools::Long( aLayoutSize.Width() * 0.854 ) ); + aLayoutSize.setHeight( tools::Long( aLayoutSize.Height() * 0.630 ) ); + } + + maPresRect.SetPos(aLayoutPos); + maPresRect.SetSize(aLayoutSize); +} + +constexpr OUString gsPageLayoutNames( u"PageLayoutNames"_ustr ); + +SdXMLExport::SdXMLExport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, + bool bIsDraw, SvXMLExportFlags nExportFlags ) +: SvXMLExport( xContext, implementationName, util::MeasureUnit::CM, + bIsDraw ? XML_GRAPHICS : XML_PRESENTATION, nExportFlags ), + mnDocMasterPageCount(0), + mnDocDrawPageCount(0), + mnObjectCount(0), + mpHandoutPageMaster(nullptr), + mbIsDraw(bIsDraw) +{ + +} + +// XExporter +void SAL_CALL SdXMLExport::setSourceDocument( const Reference< lang::XComponent >& xDoc ) +{ + SvXMLExport::setSourceDocument( xDoc ); + + // prepare factory parts + mpSdPropHdlFactory = new XMLSdPropHdlFactory( GetModel(), *this ); + + // construct PropertySetMapper + rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( mpSdPropHdlFactory, true); + + // get or create text paragraph export + GetTextParagraphExport(); + mpPropertySetMapper = new XMLShapeExportPropertyMapper( xMapper, *this ); + + // chain text attributes + mpPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(*this)); + + // construct PresPagePropsMapper + xMapper = new XMLPropertySetMapper(aXMLSDPresPageProps, mpSdPropHdlFactory, true); + + mpPresPagePropsMapper = new XMLPageExportPropertyMapper( xMapper, *this ); + + // add family name + GetAutoStylePool()->AddFamily( + XmlStyleFamily::SD_GRAPHICS_ID, + XML_STYLE_FAMILY_SD_GRAPHICS_NAME, + GetPropertySetMapper(), + XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX); + GetAutoStylePool()->AddFamily( + XmlStyleFamily::SD_PRESENTATION_ID, + XML_STYLE_FAMILY_SD_PRESENTATION_NAME, + GetPropertySetMapper(), + XML_STYLE_FAMILY_SD_PRESENTATION_PREFIX); + GetAutoStylePool()->AddFamily( + XmlStyleFamily::SD_DRAWINGPAGE_ID, + XML_STYLE_FAMILY_SD_DRAWINGPAGE_NAME, + GetPresPagePropsMapper(), + XML_STYLE_FAMILY_SD_DRAWINGPAGE_PREFIX); + // prepare access to styles + Reference< style::XStyleFamiliesSupplier > xFamSup( GetModel(), UNO_QUERY ); + if(xFamSup.is()) + { + mxDocStyleFamilies = xFamSup->getStyleFamilies(); + } + + // prepare access to master pages + Reference < drawing::XMasterPagesSupplier > xMasterPagesSupplier(GetModel(), UNO_QUERY); + if(xMasterPagesSupplier.is()) + { + mxDocMasterPages = xMasterPagesSupplier->getMasterPages(); + if(mxDocMasterPages.is()) + { + mnDocMasterPageCount = mxDocMasterPages->getCount(); + maMasterPagesStyleNames.insert( maMasterPagesStyleNames.begin(), mnDocMasterPageCount, "" ); + } + } + + // prepare access to draw pages + Reference <XDrawPagesSupplier> xDrawPagesSupplier(GetModel(), UNO_QUERY); + if(xDrawPagesSupplier.is()) + { + mxDocDrawPages = xDrawPagesSupplier->getDrawPages(); + if(mxDocDrawPages.is()) + { + mnDocDrawPageCount = mxDocDrawPages->getCount(); + maDrawPagesStyleNames.insert( maDrawPagesStyleNames.begin(), mnDocDrawPageCount, "" ); + maDrawNotesPagesStyleNames.insert( maDrawNotesPagesStyleNames.begin(), mnDocDrawPageCount, "" ); + if( !mbIsDraw ) + maDrawPagesAutoLayoutNames.realloc( mnDocDrawPageCount + 1 ); + + HeaderFooterPageSettingsImpl aEmptySettings; + maDrawPagesHeaderFooterSettings.insert( maDrawPagesHeaderFooterSettings.begin(), mnDocDrawPageCount, aEmptySettings ); + maDrawNotesPagesHeaderFooterSettings.insert( maDrawNotesPagesHeaderFooterSettings.begin(), mnDocDrawPageCount, aEmptySettings ); + } + } + + // #82003# count all draw objects for use with progress bar. + // #88245# init mnObjectCount once, use counter itself as flag. It + // is initialized to 0. + if(!mnObjectCount) + { + if( IsImpress() ) + { + // #91587# add handout master count + Reference<presentation::XHandoutMasterSupplier> xHandoutSupp(GetModel(), UNO_QUERY); + if(xHandoutSupp.is()) + { + Reference<XDrawPage> xHandoutPage(xHandoutSupp->getHandoutMasterPage()); + if(xHandoutPage.is() && xHandoutPage->getCount()) + mnObjectCount += ImpRecursiveObjectCount(xHandoutPage); + } + } + + if(mxDocMasterPages.is()) + { + for(sal_Int32 a(0); a < mnDocMasterPageCount; a++) + { + Any aAny(mxDocMasterPages->getByIndex(a)); + Reference< drawing::XShapes > xMasterPage; + + if((aAny >>= xMasterPage) && xMasterPage.is()) + { + mnObjectCount += ImpRecursiveObjectCount(xMasterPage); + } + + if( IsImpress() ) + { + // #91587# take notes pages from master pages into account + Reference<presentation::XPresentationPage> xPresPage; + if((aAny >>= xPresPage) && xPresPage.is()) + { + Reference<XDrawPage> xNotesPage(xPresPage->getNotesPage()); + if(xNotesPage.is() && xNotesPage->getCount()) + mnObjectCount += ImpRecursiveObjectCount(xNotesPage); + } + } + } + } + + if(mxDocDrawPages.is()) + { + for(sal_Int32 a(0); a < mnDocDrawPageCount; a++) + { + Any aAny(mxDocDrawPages->getByIndex(a)); + Reference< drawing::XShapes > xPage; + + if((aAny >>= xPage) && xPage.is()) + { + mnObjectCount += ImpRecursiveObjectCount(xPage); + } + + if( IsImpress() ) + { + // #91587# take notes pages from draw pages into account + Reference<presentation::XPresentationPage> xPresPage; + if((aAny >>= xPresPage) && xPresPage.is()) + { + Reference<XDrawPage> xNotesPage(xPresPage->getNotesPage()); + if(xNotesPage.is() && xNotesPage->getCount()) + mnObjectCount += ImpRecursiveObjectCount(xNotesPage); + } + } + } + } + + // #82003# init progress bar + GetProgressBarHelper()->SetReference(mnObjectCount); + } + + // add namespaces + GetNamespaceMap_().Add( + GetXMLToken(XML_NP_PRESENTATION), + GetXMLToken(XML_N_PRESENTATION), + XML_NAMESPACE_PRESENTATION); + + GetNamespaceMap_().Add( + GetXMLToken(XML_NP_SMIL), + GetXMLToken(XML_N_SMIL_COMPAT), + XML_NAMESPACE_SMIL); + + GetNamespaceMap_().Add( + GetXMLToken(XML_NP_ANIMATION), + GetXMLToken(XML_N_ANIMATION), + XML_NAMESPACE_ANIMATION); + + if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + GetNamespaceMap_().Add( + GetXMLToken(XML_NP_OFFICE_EXT), + GetXMLToken(XML_N_OFFICE_EXT), + XML_NAMESPACE_OFFICE_EXT); + } + + GetShapeExport()->enableLayerExport(); + + // #88546# enable progress bar increments + GetShapeExport()->enableHandleProgressBar(); +} + +// #82003# helper function for recursive object count +sal_uInt32 SdXMLExport::ImpRecursiveObjectCount(const Reference< drawing::XShapes >& xShapes) +{ + sal_uInt32 nRetval(0); + + if(xShapes.is()) + { + sal_Int32 nCount = xShapes->getCount(); + + for(sal_Int32 a(0); a < nCount; a++) + { + Any aAny(xShapes->getByIndex(a)); + Reference< drawing::XShapes > xGroup; + + if((aAny >>= xGroup) && xGroup.is()) + { + // #93180# count group objects, too. + nRetval += 1 + ImpRecursiveObjectCount(xGroup); + } + else + { + nRetval++; + } + } + } + + return nRetval; +} + +SdXMLExport::~SdXMLExport() +{ + // cleanup factory, decrease refcount. Should lead to destruction. + mpSdPropHdlFactory.clear(); + + // cleanup mapper, decrease refcount. Should lead to destruction. + mpPropertySetMapper.clear(); + + // cleanup presPage mapper, decrease refcount. Should lead to destruction. + mpPresPagePropsMapper.clear(); + + mvPageMasterInfoList.clear(); + + // clear auto-layout infos + mvAutoLayoutInfoList.clear(); +} + +void SdXMLExport::ImpPrepAutoLayoutInfos() +{ + if(!IsImpress()) + return; + + OUString aStr; + auto DrawPagesAutoLayoutNamesRange = asNonConstRange(maDrawPagesAutoLayoutNames); + Reference< presentation::XHandoutMasterSupplier > xHandoutSupp( GetModel(), UNO_QUERY ); + if( xHandoutSupp.is() ) + { + Reference< XDrawPage > xHandoutPage( xHandoutSupp->getHandoutMasterPage() ); + if( xHandoutPage.is() ) + { + if(ImpPrepAutoLayoutInfo(xHandoutPage, aStr)) + DrawPagesAutoLayoutNamesRange[0] = aStr; + } + } + + // prepare name creation + for (sal_Int32 nCnt = 0; nCnt < mnDocDrawPageCount; nCnt++) + { + Any aAny(mxDocDrawPages->getByIndex(nCnt)); + Reference<XDrawPage> xDrawPage; + + if((aAny >>= xDrawPage) && xDrawPage.is()) + { + if(ImpPrepAutoLayoutInfo(xDrawPage, aStr)) + DrawPagesAutoLayoutNamesRange[nCnt+1] = aStr; + } + } +} + +bool SdXMLExport::ImpPrepAutoLayoutInfo(const Reference<XDrawPage>& xPage, OUString& rName) +{ + rName.clear(); + bool bRetval(false); + + Reference <beans::XPropertySet> xPropSet(xPage, UNO_QUERY); + if(xPropSet.is()) + { + sal_uInt16 nType = sal_uInt16(); + Any aAny = xPropSet->getPropertyValue("Layout"); + if(aAny >>= nType) + { + if(ImpXMLAutoLayoutInfo::IsCreateNecessary(nType)) + { + ImpXMLEXPPageMasterInfo* pInfo = nullptr; + + // get master-page info + Reference < drawing::XMasterPageTarget > xMasterPageInt(xPage, UNO_QUERY); + if(xMasterPageInt.is()) + { + Reference<XDrawPage> xUsedMasterPage(xMasterPageInt->getMasterPage()); + if(xUsedMasterPage.is()) + { + Reference < container::XNamed > xMasterNamed(xUsedMasterPage, UNO_QUERY); + if(xMasterNamed.is()) + { + OUString sMasterPageName = xMasterNamed->getName(); + pInfo = ImpGetPageMasterInfoByName(sMasterPageName); + } + } + } + + // create entry and look for existence + ImpXMLAutoLayoutInfo* pNew; + auto it = std::find_if(mvAutoLayoutInfoList.begin(), mvAutoLayoutInfoList.end(), + [=](std::unique_ptr<ImpXMLAutoLayoutInfo> const & rInfo) { return nType == rInfo->GetLayoutType() && pInfo == rInfo->GetPageMasterInfo(); }); + if (it != mvAutoLayoutInfoList.end()) + { + pNew = it->get(); + } + else + { + pNew = new ImpXMLAutoLayoutInfo(nType, pInfo); + mvAutoLayoutInfoList.emplace_back( pNew ); + OUString sNewName = + "AL" + OUString::number(mvAutoLayoutInfoList.size() - 1) + + "T" + OUString::number(nType); + pNew->SetLayoutName(sNewName); + } + + rName = pNew->GetLayoutName(); + bRetval = true; + } + } + } + + return bRetval; +} + +void SdXMLExport::ImpWriteAutoLayoutInfos() +{ + for(const auto & pInfo : mvAutoLayoutInfoList) + { + if(pInfo) + { + // prepare presentation-page layout attributes, style-name + AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, pInfo->GetLayoutName()); + + // write draw-style attributes + SvXMLElementExport aDSE(*this, XML_NAMESPACE_STYLE, XML_PRESENTATION_PAGE_LAYOUT, true, true); + + // write presentation placeholders + switch(pInfo->GetLayoutType()) + { + case AUTOLAYOUT_TITLE : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderSubtitle, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_TITLE_CONTENT : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_CHART : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderChart, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_TITLE_2CONTENT : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.AdjustLeft(aRight.GetWidth() * 1.05); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aRight); + break; + } + case AUTOLAYOUT_TEXTCHART : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.AdjustLeft(aRight.GetWidth() * 1.05); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderChart, aRight); + break; + } + case AUTOLAYOUT_TEXTCLIP : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.AdjustLeft(aRight.GetWidth() * 1.05); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aRight); + break; + } + case AUTOLAYOUT_CHARTTEXT : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.AdjustLeft(aRight.GetWidth() * 1.05); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderChart, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aRight); + break; + } + case AUTOLAYOUT_TAB : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTable, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_CLIPTEXT : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.AdjustLeft(aRight.GetWidth() * 1.05); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aRight); + break; + } + case AUTOLAYOUT_TEXTOBJ : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.AdjustLeft(aRight.GetWidth() * 1.05); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aRight); + break; + } + case AUTOLAYOUT_OBJ : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_TITLE_CONTENT_2CONTENT : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRightTop(aLeft); + aRightTop.AdjustLeft(aRightTop.GetWidth() * 1.05); + aRightTop.setHeight(tools::Long(aRightTop.GetHeight() * 0.477)); + tools::Rectangle aRightBottom(aRightTop); + aRightBottom.AdjustTop(aRightBottom.GetHeight() * 1.095); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aRightTop); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aRightBottom); + break; + } + case AUTOLAYOUT_OBJTEXT : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.AdjustLeft(aRight.GetWidth() * 1.05); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aRight); + break; + } + case AUTOLAYOUT_TITLE_CONTENT_OVER_CONTENT : + { + tools::Rectangle aTop(pInfo->GetPresRectangle()); + aTop.setHeight(tools::Long(aTop.GetHeight() * 0.477)); + tools::Rectangle aBottom(aTop); + aBottom.AdjustTop(aBottom.GetHeight() * 1.095); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aTop); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aBottom); + break; + } + case AUTOLAYOUT_TITLE_2CONTENT_CONTENT : + { + tools::Rectangle aLeftTop(pInfo->GetPresRectangle()); + aLeftTop.setWidth(tools::Long(aLeftTop.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeftTop); + aRight.AdjustLeft(aRight.GetWidth() * 1.05); + aLeftTop.setHeight(tools::Long(aLeftTop.GetHeight() * 0.477)); + tools::Rectangle aLeftBottom(aLeftTop); + aLeftBottom.AdjustTop(aLeftBottom.GetHeight() * 1.095); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aLeftTop); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aLeftBottom); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aRight); + break; + } + case AUTOLAYOUT_TITLE_2CONTENT_OVER_CONTENT : + { + tools::Rectangle aTopLeft(pInfo->GetPresRectangle()); + aTopLeft.setHeight(tools::Long(aTopLeft.GetHeight() * 0.477)); + tools::Rectangle aBottom(aTopLeft); + aBottom.AdjustTop(aBottom.GetHeight() * 1.095); + aTopLeft.setWidth(tools::Long(aTopLeft.GetWidth() * 0.488)); + tools::Rectangle aTopRight(aTopLeft); + aTopRight.AdjustLeft(aTopRight.GetWidth() * 1.05); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aTopLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aTopRight); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aBottom); + break; + } + case AUTOLAYOUT_TEXTOVEROBJ : + { + tools::Rectangle aTop(pInfo->GetPresRectangle()); + aTop.setHeight(tools::Long(aTop.GetHeight() * 0.477)); + tools::Rectangle aBottom(aTop); + aBottom.AdjustTop(aBottom.GetHeight() * 1.095); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aTop); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aBottom); + break; + } + case AUTOLAYOUT_TITLE_4CONTENT : + { + tools::Rectangle aTopLeft(pInfo->GetPresRectangle()); + aTopLeft.setHeight(tools::Long(aTopLeft.GetHeight() * 0.477)); + aTopLeft.setWidth(tools::Long(aTopLeft.GetWidth() * 0.488)); + tools::Rectangle aBottomLeft(aTopLeft); + aBottomLeft.AdjustTop(aBottomLeft.GetHeight() * 1.095); + tools::Rectangle aTopRight(aTopLeft); + aTopRight.AdjustLeft(aTopRight.GetWidth() * 1.05); + tools::Rectangle aBottomRight(aTopRight); + aBottomRight.AdjustTop(aBottomRight.GetHeight() * 1.095); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aTopLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aTopRight); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aBottomLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aBottomRight); + break; + } + case AUTOLAYOUT_TITLE_ONLY : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + break; + } + case AUTOLAYOUT_NOTES : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderPage, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderNotes, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_HANDOUT1 : + case AUTOLAYOUT_HANDOUT2 : + case AUTOLAYOUT_HANDOUT3 : + case AUTOLAYOUT_HANDOUT4 : + case AUTOLAYOUT_HANDOUT6 : + case AUTOLAYOUT_HANDOUT9 : + { + sal_Int32 nColCnt, nRowCnt; + sal_Int32 nGapX = pInfo->GetGapX(); + sal_Int32 nGapY = pInfo->GetGapY(); + + switch(pInfo->GetLayoutType()) + { + case 22 : nColCnt = 1; nRowCnt = 1; break; + case 23 : nColCnt = 1; nRowCnt = 2; break; + case 24 : nColCnt = 1; nRowCnt = 3; break; + case 25 : nColCnt = 2; nRowCnt = 2; break; + case 26 : nColCnt = 3; nRowCnt = 2; break; + case 31 : nColCnt = 3; nRowCnt = 3; break; + default: nColCnt = 0; nRowCnt = 0; break; // FIXME - What is correct values? + } + + Size aPartSize(pInfo->GetTitleRectangle().GetSize()); + Point aPartPos(pInfo->GetTitleRectangle().TopLeft()); + + if(aPartSize.Width() > aPartSize.Height()) + { + sal_Int32 nZwi(nColCnt); + nColCnt = nRowCnt; + nRowCnt = nZwi; + } + + if (nColCnt == 0 || nRowCnt == 0) + break; + + aPartSize.setWidth( (aPartSize.Width() - ((nColCnt - 1) * nGapX)) / nColCnt ); + aPartSize.setHeight( (aPartSize.Height() - ((nRowCnt - 1) * nGapY)) / nRowCnt ); + + Point aTmpPos(aPartPos); + + for (sal_Int32 a = 0; a < nRowCnt; a++) + { + aTmpPos.setX(aPartPos.X()); + + for (sal_Int32 b = 0; b < nColCnt; b++) + { + tools::Rectangle aTmpRect(aTmpPos, aPartSize); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderHandout, aTmpRect); + aTmpPos.AdjustX( aPartSize.Width() + nGapX ); + } + + aTmpPos.AdjustY( aPartSize.Height() + nGapY ); + } + break; + } + case AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT : + { + tools::Rectangle aTop(pInfo->GetPresRectangle()); + aTop.setHeight(tools::Long(aTop.GetHeight() * 0.488)); + tools::Rectangle aBottom(aTop); + aBottom.AdjustTop(aBottom.GetHeight() * 1.05); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderVerticalTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderVerticalOutline, aTop); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderChart, aBottom); + break; + } + case AUTOLAYOUT_VTITLE_VCONTENT : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderVerticalTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderVerticalOutline, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_TITLE_VCONTENT : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderVerticalOutline, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_TITLE_2VTEXT : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.AdjustLeft(aRight.GetWidth() * 1.05); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderVerticalOutline, aRight); + break; + } + case AUTOLAYOUT_ONLY_TEXT : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderSubtitle, pInfo->GetPresRectangle()); + break; + } + + case AUTOLAYOUT_4CLIPART : + { + tools::Rectangle aTopLeft(pInfo->GetPresRectangle()); + aTopLeft.setHeight(tools::Long(aTopLeft.GetHeight() * 0.477)); + aTopLeft.setWidth(tools::Long(aTopLeft.GetWidth() * 0.488)); + tools::Rectangle aBottomLeft(aTopLeft); + aBottomLeft.AdjustTop(aBottomLeft.GetHeight() * 1.095); + tools::Rectangle aTopRight(aTopLeft); + aTopRight.AdjustLeft(aTopRight.GetWidth() * 1.05); + tools::Rectangle aBottomRight(aTopRight); + aBottomRight.AdjustTop(aBottomRight.GetHeight() * 1.095); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aTopLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aTopRight); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aBottomLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aBottomRight); + break; + } + + case AUTOLAYOUT_TITLE_6CONTENT : + { + tools::Rectangle aTopLeft(pInfo->GetPresRectangle()); + aTopLeft.setHeight(tools::Long(aTopLeft.GetHeight() * 0.477)); + aTopLeft.setWidth(tools::Long(aTopLeft.GetWidth() * 0.322)); + tools::Rectangle aTopCenter(aTopLeft); + aTopCenter.AdjustLeft(aTopCenter.GetWidth() * 1.05); + tools::Rectangle aTopRight(aTopLeft); + aTopRight.AdjustLeft(aTopRight.GetWidth() * 2 * 1.05); + + tools::Rectangle aBottomLeft(aTopLeft); + aBottomLeft.AdjustTop(aBottomLeft.GetHeight() * 1.095); + tools::Rectangle aBottomCenter(aTopCenter); + aBottomCenter.AdjustTop(aBottomCenter.GetHeight() * 1.095); + tools::Rectangle aBottomRight(aTopRight); + aBottomRight.AdjustTop(aBottomRight.GetHeight() * 1.095); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aTopLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aTopCenter); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aTopRight); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aBottomLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aBottomCenter); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aBottomRight); + break; + } + default: + { + OSL_FAIL("XMLEXP: unknown autolayout export"); + break; + } + } + } + } +} + +void SdXMLExport::ImpWriteAutoLayoutPlaceholder(XmlPlaceholder ePl, const tools::Rectangle& rRect) +{ + OUString aStr; + OUStringBuffer sStringBuffer; + + // prepare presentation-placeholder attributes, presentation:object + switch(ePl) + { + case XmlPlaceholderTitle: aStr = "title"; break; + case XmlPlaceholderOutline: aStr = "outline"; break; + case XmlPlaceholderSubtitle: aStr = "subtitle"; break; + case XmlPlaceholderGraphic: aStr = "graphic"; break; + case XmlPlaceholderObject: aStr = "object"; break; + case XmlPlaceholderChart: aStr = "chart"; break; + case XmlPlaceholderTable: aStr = "table"; break; + case XmlPlaceholderPage: aStr = "page"; break; + case XmlPlaceholderNotes: aStr = "notes"; break; + case XmlPlaceholderHandout: aStr = "handout"; break; + case XmlPlaceholderVerticalTitle: aStr = "vertical_title"; break; + case XmlPlaceholderVerticalOutline: aStr = "vertical_outline"; break; + } + + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_OBJECT, aStr); + + // svg:x,y,width,height + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, rRect.Left()); + aStr = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_SVG, XML_X, aStr); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, rRect.Top()); + aStr = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_SVG, XML_Y, aStr); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + rRect.GetWidth()); + aStr = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStr); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + rRect.GetHeight()); + aStr = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStr); + + // write presentation-placeholder + SvXMLElementExport aPPL(*this, XML_NAMESPACE_PRESENTATION, XML_PLACEHOLDER, true, true); +} + +ImpXMLEXPPageMasterInfo* SdXMLExport::ImpGetOrCreatePageMasterInfo( const Reference< XDrawPage >& xMasterPage ) +{ + bool bDoesExist = false; + + ImpXMLEXPPageMasterInfo* pNewInfo = new ImpXMLEXPPageMasterInfo(*this, xMasterPage); + + // compare with prev page-master infos + for( size_t a = 0; !bDoesExist && a < mvPageMasterInfoList.size(); a++) + { + if ( mvPageMasterInfoList.at(a) + && *mvPageMasterInfoList.at(a) == *pNewInfo + ) + { + delete pNewInfo; + pNewInfo = mvPageMasterInfoList.at(a).get(); + bDoesExist = true; + } + } + // add entry when not found same page-master infos + if(!bDoesExist) + mvPageMasterInfoList.emplace_back( pNewInfo ); + + return pNewInfo; +} + +void SdXMLExport::ImpPrepPageMasterInfos() +{ + if( IsImpress() ) + { + // create page master info for handout master page + + Reference< XHandoutMasterSupplier > xHMS( GetModel(), UNO_QUERY ); + if( xHMS.is() ) + { + Reference< XDrawPage > xMasterPage( xHMS->getHandoutMasterPage() ); + if( xMasterPage.is() ) + mpHandoutPageMaster = ImpGetOrCreatePageMasterInfo(xMasterPage); + } + } + + // create page master infos for master pages + if(!mnDocMasterPageCount) + return; + + // look for needed page-masters, create these + for (sal_Int32 nMPageId = 0; nMPageId < mnDocMasterPageCount; nMPageId++) + { + Reference< XDrawPage > xMasterPage( mxDocMasterPages->getByIndex(nMPageId), UNO_QUERY ); + ImpXMLEXPPageMasterInfo* pNewInfo = nullptr; + + if(xMasterPage.is()) + pNewInfo = ImpGetOrCreatePageMasterInfo(xMasterPage); + + mvPageMasterUsageList.push_back( pNewInfo ); + + // look for page master of handout page + if(IsImpress()) + { + pNewInfo = nullptr; + Reference< presentation::XPresentationPage > xPresPage(xMasterPage, UNO_QUERY); + if(xPresPage.is()) + { + Reference< XDrawPage > xNotesPage(xPresPage->getNotesPage()); + if(xNotesPage.is()) + { + pNewInfo = ImpGetOrCreatePageMasterInfo(xNotesPage); + } + } + mvNotesPageMasterUsageList.push_back( pNewInfo ); + } + } +} + +void SdXMLExport::ImpWritePageMasterInfos() +{ + // write created page-masters, create names for these + for( size_t nCnt = 0; nCnt < mvPageMasterInfoList.size(); nCnt++) + { + ImpXMLEXPPageMasterInfo* pInfo = mvPageMasterInfoList.at(nCnt).get(); + if(pInfo) + { + // create name + OUString sNewName = "PM" + OUString::number(nCnt); + pInfo->SetName(sNewName); + + // prepare page-master attributes + OUString sString; + OUStringBuffer sStringBuffer; + + sString = sNewName; + AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, sString); + + // write page-layout + SvXMLElementExport aPME(*this, XML_NAMESPACE_STYLE, XML_PAGE_LAYOUT, true, true); + + // prepare style:properties inside page-master + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + pInfo->GetBorderTop()); + sString = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_FO, XML_MARGIN_TOP, sString); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + pInfo->GetBorderBottom()); + sString = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, sString); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + pInfo->GetBorderLeft()); + sString = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_FO, XML_MARGIN_LEFT, sString); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + pInfo->GetBorderRight()); + sString = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_FO, XML_MARGIN_RIGHT, sString); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + pInfo->GetWidth()); + sString = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_FO, XML_PAGE_WIDTH, sString); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + pInfo->GetHeight()); + sString = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_FO, XML_PAGE_HEIGHT, sString); + + if(pInfo->GetOrientation() == view::PaperOrientation_PORTRAIT) + AddAttribute(XML_NAMESPACE_STYLE, XML_PRINT_ORIENTATION, XML_PORTRAIT); + else + AddAttribute(XML_NAMESPACE_STYLE, XML_PRINT_ORIENTATION, XML_LANDSCAPE); + + // write style:properties + SvXMLElementExport aPMF(*this, XML_NAMESPACE_STYLE, XML_PAGE_LAYOUT_PROPERTIES, true, true); + } + } +} + +ImpXMLEXPPageMasterInfo* SdXMLExport::ImpGetPageMasterInfoByName(std::u16string_view rName) +{ + if(!rName.empty()) + { + for(const auto & pInfo : mvPageMasterInfoList) + { + if(pInfo) + { + if(!pInfo->GetMasterPageName().isEmpty() && rName == pInfo->GetMasterPageName()) + { + return pInfo.get(); + } + } + } + } + return nullptr; +} + +void SdXMLExport::ImpPrepDrawPageInfos() +{ + // create draw:style-name entries for page export + // containing presentation page attributes AND background attributes + // fixed family for page-styles is "drawing-page" (XML_STYLE_FAMILY_SD_DRAWINGPAGE_NAME) + + sal_Int32 nCnt; + for(nCnt = 0; nCnt < mnDocDrawPageCount; nCnt++) + { + Reference<XDrawPage> xDrawPage; + mxDocDrawPages->getByIndex(nCnt) >>= xDrawPage; + maDrawPagesStyleNames[nCnt] = ImpCreatePresPageStyleName( xDrawPage ); + + Reference< presentation::XPresentationPage > xPresPage(xDrawPage, UNO_QUERY); + if(xPresPage.is()) + { + maDrawNotesPagesStyleNames[nCnt] = ImpCreatePresPageStyleName( xPresPage->getNotesPage(), false ); + + maDrawPagesHeaderFooterSettings[nCnt] = ImpPrepDrawPageHeaderFooterDecls( xDrawPage ); + maDrawNotesPagesHeaderFooterSettings[nCnt] = ImpPrepDrawPageHeaderFooterDecls( xPresPage->getNotesPage() ); + } + } +} + +static OUString findOrAppendImpl( std::vector< OUString >& rVector, const OUString& rText, std::u16string_view pPrefix ) +{ + // search rVector if there is already a string that equals rText + auto aIter = std::find(rVector.begin(), rVector.end(), rText); + sal_Int32 nIndex = std::distance(rVector.begin(), aIter) + 1; + + // if nothing is found, append the string at the end of rVector + if( aIter == rVector.end() ) + rVector.push_back( rText ); + + // create a reference string with pPrefix and the index of the + // found or created rText + return pPrefix + OUString::number( nIndex ); +} + +static OUString findOrAppendImpl( std::vector< DateTimeDeclImpl >& rVector, const OUString& rText, bool bFixed, sal_Int32 nFormat, std::u16string_view pPrefix ) +{ + // search rVector if there is already a DateTimeDeclImpl with rText,bFixed and nFormat + auto aIter = std::find_if(rVector.begin(), rVector.end(), + [bFixed, &rText, nFormat](const DateTimeDeclImpl& rDecl) { + return (rDecl.mbFixed == bFixed) && + (!bFixed || (rDecl.maStrText == rText)) && + (bFixed || (rDecl.mnFormat == nFormat)); + }); + sal_Int32 nIndex = std::distance(rVector.begin(), aIter) + 1; + + // if nothing is found, append a new DateTimeDeclImpl + if( aIter == rVector.end() ) + { + DateTimeDeclImpl aDecl; + aDecl.maStrText = rText; + aDecl.mbFixed = bFixed; + aDecl.mnFormat = nFormat; + rVector.push_back( aDecl ); + } + + // create a reference string with pPrefix and the index of the + // found or created DateTimeDeclImpl + return pPrefix + OUString::number( nIndex ); +} + +constexpr OUString gpStrHeaderTextPrefix = u"hdr"_ustr; +constexpr OUString gpStrFooterTextPrefix = u"ftr"_ustr; +constexpr OUString gpStrDateTimeTextPrefix = u"dtd"_ustr; + +HeaderFooterPageSettingsImpl SdXMLExport::ImpPrepDrawPageHeaderFooterDecls( const Reference<XDrawPage>& xDrawPage ) +{ + HeaderFooterPageSettingsImpl aSettings; + + if( xDrawPage.is() ) try + { + Reference< XPropertySet > xSet( xDrawPage, UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xInfo( xSet->getPropertySetInfo() ); + + OUString aStrText; + + static constexpr OUString aStrHeaderTextProp( u"HeaderText"_ustr ); + if( xInfo->hasPropertyByName( aStrHeaderTextProp ) ) + { + xSet->getPropertyValue( aStrHeaderTextProp ) >>= aStrText; + if( !aStrText.isEmpty() ) + aSettings.maStrHeaderDeclName = findOrAppendImpl( maHeaderDeclsVector, aStrText, gpStrHeaderTextPrefix ); + } + + static constexpr OUString aStrFooterTextProp( u"FooterText"_ustr ); + if( xInfo->hasPropertyByName( aStrFooterTextProp ) ) + { + xSet->getPropertyValue( aStrFooterTextProp ) >>= aStrText; + if( !aStrText.isEmpty() ) + aSettings.maStrFooterDeclName = findOrAppendImpl( maFooterDeclsVector, aStrText, gpStrFooterTextPrefix ); + } + + static constexpr OUString aStrDateTimeTextProp( u"DateTimeText"_ustr ); + if( xInfo->hasPropertyByName( aStrDateTimeTextProp ) ) + { + bool bFixed = false; + sal_Int32 nFormat = 0; + xSet->getPropertyValue( aStrDateTimeTextProp ) >>= aStrText; + xSet->getPropertyValue("IsDateTimeFixed") >>= bFixed; + xSet->getPropertyValue("DateTimeFormat") >>= nFormat; + + if( !bFixed || !aStrText.isEmpty() ) + { + aSettings.maStrDateTimeDeclName = findOrAppendImpl( maDateTimeDeclsVector, aStrText, bFixed, nFormat, gpStrDateTimeTextPrefix ); + if( !bFixed ) + addDataStyle( nFormat ); + } + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } + + return aSettings; +} + +void SdXMLExport::ImpWriteHeaderFooterDecls() +{ + OUStringBuffer sBuffer; + + if( !maHeaderDeclsVector.empty() ) + { + // export header decls + const OUString aPrefix( gpStrHeaderTextPrefix ); + sal_Int32 nIndex = 1; + for( const auto& rDecl : maHeaderDeclsVector ) + { + sBuffer.append( aPrefix + OUString::number( nIndex ) ); + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_NAME, sBuffer.makeStringAndClear()); + + SvXMLElementExport aElem(*this, XML_NAMESPACE_PRESENTATION, XML_HEADER_DECL, true, true); + Characters(rDecl); + ++nIndex; + } + } + + if( !maFooterDeclsVector.empty() ) + { + // export footer decls + const OUString aPrefix( gpStrFooterTextPrefix ); + sal_Int32 nIndex = 1; + for( const auto& rDecl : maFooterDeclsVector ) + { + sBuffer.append( aPrefix + OUString::number( nIndex ) ); + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_NAME, sBuffer.makeStringAndClear()); + + SvXMLElementExport aElem(*this, XML_NAMESPACE_PRESENTATION, XML_FOOTER_DECL, false, false); + Characters(rDecl); + ++nIndex; + } + } + + if( maDateTimeDeclsVector.empty() ) + return; + + // export footer decls + const OUString aPrefix( gpStrDateTimeTextPrefix ); + sal_Int32 nIndex = 1; + for( const auto& rDecl : maDateTimeDeclsVector ) + { + sBuffer.append( aPrefix + OUString::number( nIndex ) ); + AddAttribute( XML_NAMESPACE_PRESENTATION, XML_NAME, sBuffer.makeStringAndClear()); + + AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SOURCE, rDecl.mbFixed ? XML_FIXED : XML_CURRENT_DATE ); + + if( !rDecl.mbFixed ) + AddAttribute( XML_NAMESPACE_STYLE, XML_DATA_STYLE_NAME, getDataStyleName( rDecl.mnFormat ) ); + + SvXMLElementExport aElem(*this, XML_NAMESPACE_PRESENTATION, XML_DATE_TIME_DECL, false, false); + if( rDecl.mbFixed ) + Characters(rDecl.maStrText); + + ++nIndex; + } +} + +void SdXMLExport::ImplExportHeaderFooterDeclAttributes( const HeaderFooterPageSettingsImpl& aSettings ) +{ + if( !aSettings.maStrHeaderDeclName.isEmpty() ) + AddAttribute( XML_NAMESPACE_PRESENTATION, XML_USE_HEADER_NAME, aSettings.maStrHeaderDeclName ); + + if( !aSettings.maStrFooterDeclName.isEmpty() ) + AddAttribute( XML_NAMESPACE_PRESENTATION, XML_USE_FOOTER_NAME, aSettings.maStrFooterDeclName ); + + if( !aSettings.maStrDateTimeDeclName.isEmpty() ) + AddAttribute( XML_NAMESPACE_PRESENTATION, XML_USE_DATE_TIME_NAME, aSettings.maStrDateTimeDeclName ); +} + +OUString SdXMLExport::ImpCreatePresPageStyleName( const Reference<XDrawPage>& xDrawPage, bool bExportBackground /* = true */ ) +{ + // create name + OUString sStyleName; + + // create style for this page and add to auto style pool + + Reference< beans::XPropertySet > xPropSet1(xDrawPage, UNO_QUERY); + if(xPropSet1.is()) + { + Reference< beans::XPropertySet > xPropSet; + + if( bExportBackground ) + { + // since the background items are in a different propertyset + // which itself is a property of the pages property set + // we now merge these two propertysets if possible to simulate + // a single propertyset with all draw page properties + static constexpr OUString aBackground(u"Background"_ustr); + Reference< beans::XPropertySet > xPropSet2; + Reference< beans::XPropertySetInfo > xInfo( xPropSet1->getPropertySetInfo() ); + if( xInfo.is() && xInfo->hasPropertyByName( aBackground ) ) + { + Any aAny( xPropSet1->getPropertyValue( aBackground ) ); + aAny >>= xPropSet2; + } + + if( xPropSet2.is() ) + xPropSet = PropertySetMerger_CreateInstance( xPropSet1, xPropSet2 ); + else + xPropSet = xPropSet1; + } + else + { + xPropSet = xPropSet1; + } + + const rtl::Reference< SvXMLExportPropertyMapper > aMapperRef( GetPresPagePropsMapper() ); + + std::vector<XMLPropertyState> aPropStates(aMapperRef->Filter(*this, xPropSet)); + + if( !aPropStates.empty() ) + { + // there are filtered properties -> hard attributes + // try to find this style in AutoStylePool + sStyleName = GetAutoStylePool()->Find(XmlStyleFamily::SD_DRAWINGPAGE_ID, sStyleName, aPropStates); + + if(sStyleName.isEmpty()) + { + // Style did not exist, add it to AutoStalePool + sStyleName = GetAutoStylePool()->Add(XmlStyleFamily::SD_DRAWINGPAGE_ID, sStyleName, std::move(aPropStates)); + } + } + } + + return sStyleName; +} + +void SdXMLExport::ImpPrepMasterPageInfos() +{ + // create draw:style-name entries for master page export + // containing only background attributes + // fixed family for page-styles is "drawing-page" (XML_STYLE_FAMILY_SD_DRAWINGPAGE_NAME) + + sal_Int32 nCnt; + for( nCnt = 0; nCnt < mnDocMasterPageCount; nCnt++) + { + Reference<XDrawPage> xDrawPage; + mxDocMasterPages->getByIndex(nCnt) >>= xDrawPage; + maMasterPagesStyleNames[nCnt] = ImpCreatePresPageStyleName( xDrawPage ); + } + + if( !IsImpress() ) + return; + + Reference< presentation::XHandoutMasterSupplier > xHandoutSupp( GetModel(), UNO_QUERY ); + if( xHandoutSupp.is() ) + { + Reference< XDrawPage > xHandoutPage( xHandoutSupp->getHandoutMasterPage() ); + if( xHandoutPage.is() ) + { + maHandoutPageHeaderFooterSettings = ImpPrepDrawPageHeaderFooterDecls( xHandoutPage ); + maHandoutMasterStyleName = ImpCreatePresPageStyleName( xHandoutPage, false ); + } + } +} + +void SdXMLExport::ImpWritePresentationStyles() +{ + if(!IsImpress()) + return; + + for (sal_Int32 nCnt = 0; nCnt < mnDocMasterPageCount; nCnt++) + { + Any aAny(mxDocMasterPages->getByIndex(nCnt)); + Reference<container::XNamed> xNamed; + + if(aAny >>= xNamed) + { + // write presentation styles (ONLY if presentation) + if(IsImpress() && mxDocStyleFamilies.is() && xNamed.is()) + { + rtl::Reference<XMLStyleExport> aStEx(new XMLStyleExport(*this, GetAutoStylePool().get())); + const rtl::Reference< SvXMLExportPropertyMapper > aMapperRef( GetPropertySetMapper() ); + + OUString aPrefix( xNamed->getName() + "-" ); + + aStEx->exportStyleFamily(xNamed->getName(), + XML_STYLE_FAMILY_SD_PRESENTATION_NAME, + aMapperRef, false, + XmlStyleFamily::SD_PRESENTATION_ID, &aPrefix); + } + } + } +} + +void SdXMLExport::ExportMeta_() +{ + uno::Sequence<beans::NamedValue> stats { { "ObjectCount", uno::Any(mnObjectCount) } }; + + // update document statistics at the model + uno::Reference<document::XDocumentPropertiesSupplier> xPropSup(GetModel(), + uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xPropSup->getDocumentProperties()); + if (xDocProps.is()) { + xDocProps->setDocumentStatistics(stats); + } + + // call parent + SvXMLExport::ExportMeta_(); +} + +void SdXMLExport::ExportFontDecls_() +{ + GetFontAutoStylePool(); // make sure the pool is created + SvXMLExport::ExportFontDecls_(); +} + +void SdXMLExport::ExportContent_() +{ + // export <pres:header-decl>, <pres:footer-decl> and <pres:date-time-decl> elements + ImpWriteHeaderFooterDecls(); + + // page export + for(sal_Int32 nPageInd(0); nPageInd < mnDocDrawPageCount; nPageInd++) + { + uno::Reference<drawing::XDrawPage> xDrawPage( mxDocDrawPages->getByIndex(nPageInd), uno::UNO_QUERY ); + + // set progress view + if(GetStatusIndicator().is()) + GetStatusIndicator()->setValue(((nPageInd + 1) * 100) / mnDocDrawPageCount); + + if(xDrawPage.is()) + { + // prepare page attributes, name of page + Reference < container::XNamed > xNamed(xDrawPage, UNO_QUERY); + if(xNamed.is()) + AddAttribute(XML_NAMESPACE_DRAW, XML_NAME, xNamed->getName()); + + // draw:style-name (presentation page attributes AND background attributes) + if( !maDrawPagesStyleNames[nPageInd].isEmpty() ) + AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, + maDrawPagesStyleNames[nPageInd]); + + // draw:master-page-name + Reference < drawing::XMasterPageTarget > xMasterPageInt(xDrawPage, UNO_QUERY); + if(xMasterPageInt.is()) + { + Reference<XDrawPage> xUsedMasterPage(xMasterPageInt->getMasterPage()); + if(xUsedMasterPage.is()) + { + Reference < container::XNamed > xMasterNamed(xUsedMasterPage, UNO_QUERY); + if(xMasterNamed.is()) + { + AddAttribute(XML_NAMESPACE_DRAW, XML_MASTER_PAGE_NAME, + EncodeStyleName( xMasterNamed->getName()) ); + } + } + } + + // presentation:page-layout-name + if( IsImpress() && !maDrawPagesAutoLayoutNames[nPageInd+1].isEmpty()) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PRESENTATION_PAGE_LAYOUT_NAME, maDrawPagesAutoLayoutNames[nPageInd+1] ); + } + + Reference< beans::XPropertySet > xProps( xDrawPage, UNO_QUERY ); + if( xProps.is() ) + { + try + { + OUString aBookmarkURL; + xProps->getPropertyValue("BookmarkURL") >>= aBookmarkURL; + + if( !aBookmarkURL.isEmpty() ) + { + sal_Int32 nIndex = aBookmarkURL.lastIndexOf( '#' ); + if( nIndex != -1 ) + { + OUString aFileName( aBookmarkURL.copy( 0, nIndex ) ); + std::u16string_view aBookmarkName( aBookmarkURL.subView( nIndex+1 ) ); + + aBookmarkURL = GetRelativeReference( aFileName ) + "#" + aBookmarkName; + } + + AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, aBookmarkURL); + AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_REPLACE ); + AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST ); + } + } + catch(const Exception&) + { + OSL_FAIL(" no \"BookmarkURL\" property at page?" ); + } + } + + if( IsImpress() ) + ImplExportHeaderFooterDeclAttributes( maDrawPagesHeaderFooterSettings[nPageInd] ); + + OUString sNavigationOrder( getNavigationOrder( xDrawPage ) ); + if( !sNavigationOrder.isEmpty() ) + AddAttribute ( XML_NAMESPACE_DRAW, XML_NAV_ORDER, sNavigationOrder ); + + rtl::Reference< xmloff::AnimationsExporter > xAnimationsExporter; + uno::Reference< css::animations::XAnimationNodeSupplier > xAnimNodeSupplier; + + // prepare animation export + if(IsImpress()) + { + if( getExportFlags() & SvXMLExportFlags::OASIS ) + { + // export new animations for oasis format + xAnimNodeSupplier.set( xDrawPage, UNO_QUERY ); + + // prepare animations exporter if impress + if(xAnimNodeSupplier.is()) + { + xAnimationsExporter = new xmloff::AnimationsExporter( *this, xProps ); + xAnimationsExporter->prepare( xAnimNodeSupplier->getAnimationNode() ); + } + } + else + { + // export old animations for ooo format + rtl::Reference< XMLAnimationsExporter > xAnimExport = new XMLAnimationsExporter(); + GetShapeExport()->setAnimationsExporter( xAnimExport ); + } + } + + // write draw:id + const OUString aPageId = getInterfaceToIdentifierMapper().getIdentifier( xDrawPage ); + if( !aPageId.isEmpty() ) + { + AddAttributeIdLegacy(XML_NAMESPACE_DRAW, aPageId); + } + + // write page + SvXMLElementExport aDPG(*this, XML_NAMESPACE_DRAW, XML_PAGE, true, true); + + // write optional office:forms + exportFormsElement( xDrawPage ); + + // write graphic objects on this page (if any) + if(xDrawPage.is() && xDrawPage->getCount()) + GetShapeExport()->exportShapes( xDrawPage ); + + // write animations and presentation notes (ONLY if presentation) + if(IsImpress()) + { + if(xAnimNodeSupplier.is()) + { + xAnimationsExporter->exportAnimations( xAnimNodeSupplier->getAnimationNode() ); + } + else + { + // animations + rtl::Reference< XMLAnimationsExporter > xAnimExport( GetShapeExport()->getAnimationsExporter() ); + if( xAnimExport.is() ) + xAnimExport->exportAnimations( *this ); + + xAnimExport = nullptr; + GetShapeExport()->setAnimationsExporter( xAnimExport ); + } + + // presentations + Reference< presentation::XPresentationPage > xPresPage(xDrawPage, UNO_QUERY); + if(xPresPage.is()) + { + Reference< XDrawPage > xNotesPage(xPresPage->getNotesPage()); + if(xNotesPage.is()) + { + if( !maDrawNotesPagesStyleNames[nPageInd].isEmpty() ) + AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, maDrawNotesPagesStyleNames[nPageInd]); + + ImplExportHeaderFooterDeclAttributes( maDrawNotesPagesHeaderFooterSettings[nPageInd] ); + + // write presentation notes + SvXMLElementExport aPSY(*this, XML_NAMESPACE_PRESENTATION, XML_NOTES, true, true); + + // write optional office:forms + exportFormsElement( xNotesPage ); + + // write shapes per se + GetShapeExport()->exportShapes( xNotesPage ); + } + } + } + + exportAnnotations( xDrawPage ); + } + } + + if( IsImpress() ) + exportPresentationSettings(); +} + +void SdXMLExport::exportPresentationSettings() +{ + try + { + Reference< XPresentationSupplier > xPresSupplier( GetModel(), UNO_QUERY ); + if( !xPresSupplier.is() ) + return; + + Reference< XPropertySet > xPresProps( xPresSupplier->getPresentation(), UNO_QUERY ); + if( !xPresProps.is() ) + return; + + bool bHasAttr = false; + + bool bTemp = false; + + // export range + xPresProps->getPropertyValue("IsShowAll") >>= bTemp; + if( !bTemp ) + { + OUString aFirstPage; + xPresProps->getPropertyValue("FirstPage") >>= aFirstPage; + if( !aFirstPage.isEmpty() ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_START_PAGE, aFirstPage ); + bHasAttr = true; + } + else + { + OUString aCustomShow; + xPresProps->getPropertyValue("CustomShow") >>= aCustomShow; + if( !aCustomShow.isEmpty() ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_SHOW, aCustomShow ); + bHasAttr = true; + } + } + } + + xPresProps->getPropertyValue("IsEndless") >>= bTemp; + if( bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_ENDLESS, XML_TRUE ); + bHasAttr = true; + + sal_Int32 nPause = 0; + xPresProps->getPropertyValue("Pause") >>= nPause; + + util::Duration aDuration; + aDuration.Seconds = static_cast<sal_uInt16>(nPause); + + OUStringBuffer aOut; + ::sax::Converter::convertDuration(aOut, aDuration); + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PAUSE, aOut.makeStringAndClear() ); + } + + xPresProps->getPropertyValue("AllowAnimations") >>= bTemp; + if( !bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_ANIMATIONS, XML_DISABLED ); + bHasAttr = true; + } + + xPresProps->getPropertyValue("IsAlwaysOnTop") >>= bTemp; + if( bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_STAY_ON_TOP, XML_TRUE ); + bHasAttr = true; + } + + xPresProps->getPropertyValue("IsAutomatic") >>= bTemp; + if( bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_FORCE_MANUAL, XML_TRUE ); + bHasAttr = true; + } + + xPresProps->getPropertyValue("IsFullScreen") >>= bTemp; + if( !bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_FULL_SCREEN, XML_FALSE ); + bHasAttr = true; + } + + // We need to always export this attribute, because the import had the wrong default (tdf#108824) + xPresProps->getPropertyValue("IsMouseVisible") >>= bTemp; + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_MOUSE_VISIBLE, bTemp ? XML_TRUE : XML_FALSE); + bHasAttr = true; + + xPresProps->getPropertyValue("StartWithNavigator") >>= bTemp; + if( bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_START_WITH_NAVIGATOR, XML_TRUE ); + bHasAttr = true; + } + + xPresProps->getPropertyValue("UsePen") >>= bTemp; + if( bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_MOUSE_AS_PEN, XML_TRUE ); + bHasAttr = true; + } + + xPresProps->getPropertyValue("IsTransitionOnClick") >>= bTemp; + if( !bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_TRANSITION_ON_CLICK, XML_DISABLED ); + bHasAttr = true; + } + + xPresProps->getPropertyValue("IsShowLogo") >>= bTemp; + if( bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_SHOW_LOGO, XML_TRUE ); + bHasAttr = true; + } + + Reference< container::XNameContainer > xShows; + Sequence< OUString > aShowNames; + bool bHasNames = false; + + Reference< XCustomPresentationSupplier > xSup( GetModel(), UNO_QUERY ); + if( xSup.is() ) + { + xShows = xSup->getCustomPresentations(); + if( xShows.is() ) + { + aShowNames = xShows->getElementNames(); + bHasNames = aShowNames.hasElements(); + } + } + + if( bHasAttr || bHasNames ) + { + SvXMLElementExport aSettings(*this, XML_NAMESPACE_PRESENTATION, XML_SETTINGS, true, true); + + if( !bHasNames ) + return; + + Reference< XIndexContainer > xShow; + Reference< XNamed > xPageName; + + OUStringBuffer sTmp; + + for( const auto& rShowName : std::as_const(aShowNames) ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_NAME, rShowName ); + + xShows->getByName( rShowName ) >>= xShow; + SAL_WARN_IF( !xShow.is(), "xmloff", "invalid custom show!" ); + if( !xShow.is() ) + continue; + + const sal_Int32 nPageCount = xShow->getCount(); + for( sal_Int32 nPage = 0; nPage < nPageCount; nPage++ ) + { + xShow->getByIndex( nPage ) >>= xPageName; + + if( !xPageName.is() ) + continue; + + if( !sTmp.isEmpty() ) + sTmp.append( ',' ); + sTmp.append( xPageName->getName() ); + + } + + if( !sTmp.isEmpty() ) + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PAGES, sTmp.makeStringAndClear() ); + + SvXMLElementExport aShows(*this, XML_NAMESPACE_PRESENTATION, XML_SHOW, true, true); + } + } + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", "while exporting <presentation:settings>"); + } +} + +void SdXMLExport::ExportStyles_(bool bUsed) +{ + GetPropertySetMapper()->SetAutoStyles( false ); + + // export fill styles + SvXMLExport::ExportStyles_( bUsed ); + + // write draw:style-name for object graphic-styles + GetShapeExport()->ExportGraphicDefaults(); + + // do not export in ODF 1.1 or older + if (getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + GetShapeExport()->GetShapeTableExport()->exportTableStyles(); + + // write presentation styles + ImpWritePresentationStyles(); + + // prepare draw:auto-layout-name for page export + ImpPrepAutoLayoutInfos(); + + // write draw:auto-layout-name for page export + ImpWriteAutoLayoutInfos(); + + Reference< beans::XPropertySet > xInfoSet( getExportInfo() ); + if( xInfoSet.is() ) + { + Reference< beans::XPropertySetInfo > xInfoSetInfo( xInfoSet->getPropertySetInfo() ); + + if( xInfoSetInfo->hasPropertyByName( gsPageLayoutNames ) ) + { + xInfoSet->setPropertyValue( gsPageLayoutNames, Any(maDrawPagesAutoLayoutNames) ); + } + } +} + +void SdXMLExport::collectAutoStyles() +{ + SvXMLExport::collectAutoStyles(); + if (mbAutoStylesCollected) + return; + + Reference< beans::XPropertySet > xInfoSet( getExportInfo() ); + if( xInfoSet.is() ) + { + Reference< beans::XPropertySetInfo > xInfoSetInfo( xInfoSet->getPropertySetInfo() ); + + if( xInfoSetInfo->hasPropertyByName( gsPageLayoutNames ) ) + { + xInfoSet->getPropertyValue( gsPageLayoutNames ) >>= maDrawPagesAutoLayoutNames; + } + } + + GetPropertySetMapper()->SetAutoStyles( true ); + + if( getExportFlags() & SvXMLExportFlags::STYLES ) + { + // #80012# PageMaster export moved from _ExportStyles + // prepare page-master infos + ImpPrepPageMasterInfos(); + + // prepare draw:style-name for master page export + ImpPrepMasterPageInfos(); + } + + if( getExportFlags() & SvXMLExportFlags::CONTENT ) + { + // prepare draw:style-name for page export + ImpPrepDrawPageInfos(); + } + + if( getExportFlags() & SvXMLExportFlags::STYLES ) + { + // create auto style infos for shapes on master handout page + if( IsImpress() ) + { + Reference< presentation::XHandoutMasterSupplier > xHandoutSupp( GetModel(), UNO_QUERY ); + if( xHandoutSupp.is() ) + { + Reference< XDrawPage > xHandoutPage( xHandoutSupp->getHandoutMasterPage() ); + if( xHandoutPage.is() && xHandoutPage->getCount()) + GetShapeExport()->collectShapesAutoStyles( xHandoutPage ); + } + } + + // create auto style infos for objects on master pages + for(sal_Int32 nMPageId(0); nMPageId < mnDocMasterPageCount; nMPageId++) + { + Reference< XDrawPage > xMasterPage(mxDocMasterPages->getByIndex(nMPageId), UNO_QUERY ); + + if( xMasterPage.is() ) + { + // collect layer information + GetFormExport()->examineForms( xMasterPage ); + + // get MasterPage Name + OUString aMasterPageNamePrefix; + Reference < container::XNamed > xNamed(xMasterPage, UNO_QUERY); + if(xNamed.is()) + { + aMasterPageNamePrefix = xNamed->getName(); + } + if(!aMasterPageNamePrefix.isEmpty()) + { + aMasterPageNamePrefix += "-"; + } + GetShapeExport()->setPresentationStylePrefix( aMasterPageNamePrefix ); + + if(xMasterPage.is() && xMasterPage->getCount()) + GetShapeExport()->collectShapesAutoStyles( xMasterPage ); + + if(IsImpress()) + { + Reference< presentation::XPresentationPage > xPresPage(xMasterPage, UNO_QUERY); + if(xPresPage.is()) + { + Reference< XDrawPage > xNotesPage(xPresPage->getNotesPage()); + if(xNotesPage.is()) + { + // collect layer information + GetFormExport()->examineForms( xNotesPage ); + + if(xNotesPage->getCount()) + GetShapeExport()->collectShapesAutoStyles( xNotesPage ); + } + } + } + collectAnnotationAutoStyles(xMasterPage); + } + } + } + + if( getExportFlags() & SvXMLExportFlags::CONTENT ) + { + // prepare animations exporter if impress + if(IsImpress() && (!(getExportFlags() & SvXMLExportFlags::OASIS)) ) + { + rtl::Reference< XMLAnimationsExporter > xAnimExport = new XMLAnimationsExporter(); + GetShapeExport()->setAnimationsExporter( xAnimExport ); + } + + // create auto style infos for objects on pages + for(sal_Int32 nPageInd(0); nPageInd < mnDocDrawPageCount; nPageInd++) + { + Reference<XDrawPage> xDrawPage( mxDocDrawPages->getByIndex(nPageInd), UNO_QUERY ); + if( xDrawPage.is() ) + { + // collect layer information + GetFormExport()->examineForms( xDrawPage ); + + // get MasterPage Name + OUString aMasterPageNamePrefix; + Reference < drawing::XMasterPageTarget > xMasterPageInt(xDrawPage, UNO_QUERY); + if(xMasterPageInt.is()) + { + Reference<XDrawPage> xUsedMasterPage(xMasterPageInt->getMasterPage()); + if(xUsedMasterPage.is()) + { + Reference < container::XNamed > xMasterNamed(xUsedMasterPage, UNO_QUERY); + if(xMasterNamed.is()) + { + aMasterPageNamePrefix = xMasterNamed->getName(); + } + } + } + if(!aMasterPageNamePrefix.isEmpty()) + { + aMasterPageNamePrefix += "-"; + } + + GetShapeExport()->setPresentationStylePrefix( aMasterPageNamePrefix ); + + // prepare object infos + if(xDrawPage.is() && xDrawPage->getCount()) + GetShapeExport()->collectShapesAutoStyles( xDrawPage ); + + // prepare presentation notes page object infos (ONLY if presentation) + if(IsImpress()) + { + Reference< presentation::XPresentationPage > xPresPage(xDrawPage, UNO_QUERY); + if(xPresPage.is()) + { + Reference< XDrawPage > xNotesPage(xPresPage->getNotesPage()); + if(xNotesPage.is()) + { + // collect layer information + GetFormExport()->examineForms( xNotesPage ); + + if(xNotesPage->getCount()) + GetShapeExport()->collectShapesAutoStyles( xNotesPage ); + } + } + } + + collectAnnotationAutoStyles( xDrawPage ); + } + } + if (IsImpress()) + { + rtl::Reference< XMLAnimationsExporter > xAnimExport; + GetShapeExport()->setAnimationsExporter( xAnimExport ); + } + } + + mbAutoStylesCollected = true; +} + +void SdXMLExport::ExportAutoStyles_() +{ + collectAutoStyles(); + + if( getExportFlags() & SvXMLExportFlags::STYLES ) + { + // write page-master infos + ImpWritePageMasterInfos(); + } + + // export draw-page styles + GetAutoStylePool()->exportXML( XmlStyleFamily::SD_DRAWINGPAGE_ID ); + + exportAutoDataStyles(); + + GetShapeExport()->exportAutoStyles(); + + SvXMLExportFlags nContentAutostyles = SvXMLExportFlags::CONTENT | SvXMLExportFlags::AUTOSTYLES; + if ( ( getExportFlags() & nContentAutostyles ) == nContentAutostyles ) + GetFormExport()->exportAutoStyles( ); + + // ...for text + GetTextParagraphExport()->exportTextAutoStyles(); +} + +void SdXMLExport::ExportMasterStyles_() +{ + // export layer + SdXMLayerExporter::exportLayer( *this ); + + // export handout master page if impress + if( IsImpress() ) + { + Reference< presentation::XHandoutMasterSupplier > xHandoutSupp( GetModel(), UNO_QUERY ); + if( xHandoutSupp.is() ) + { + Reference< XDrawPage > xHandoutPage( xHandoutSupp->getHandoutMasterPage() ); + if( xHandoutPage.is() ) + { + // presentation:page-layout-name + if( IsImpress() && !maDrawPagesAutoLayoutNames[0].isEmpty()) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PRESENTATION_PAGE_LAYOUT_NAME, EncodeStyleName( maDrawPagesAutoLayoutNames[0] )); + } + + ImpXMLEXPPageMasterInfo* pInfo = mpHandoutPageMaster; + if(pInfo) + { + const OUString& sString = pInfo->GetName(); + AddAttribute(XML_NAMESPACE_STYLE, XML_PAGE_LAYOUT_NAME, sString ); + } + + // draw:style-name + if( !maHandoutMasterStyleName.isEmpty() ) + AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, maHandoutMasterStyleName); + + ImplExportHeaderFooterDeclAttributes( maHandoutPageHeaderFooterSettings ); + + // write masterpage + SvXMLElementExport aMPG(*this, XML_NAMESPACE_STYLE, XML_HANDOUT_MASTER, true, true); + + // write graphic objects on this master page (if any) + if(xHandoutPage.is() && xHandoutPage->getCount()) + GetShapeExport()->exportShapes( xHandoutPage ); + } + } + } + + // export MasterPages in master-styles section + for (sal_Int32 nMPageId = 0; nMPageId < mnDocMasterPageCount; nMPageId++) + { + Reference< XDrawPage > xMasterPage( mxDocMasterPages->getByIndex(nMPageId), UNO_QUERY ); + if(xMasterPage.is()) + { + // prepare masterpage attributes + Reference < container::XNamed > xNamed(xMasterPage, UNO_QUERY); + if(xNamed.is()) + { + bool bEncoded = false; + OUString sMasterPageName = xNamed->getName(); + AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, + EncodeStyleName( sMasterPageName, &bEncoded )); + if( bEncoded ) + AddAttribute( + XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, + sMasterPageName ); + } + + ImpXMLEXPPageMasterInfo* pInfo = mvPageMasterUsageList.at( nMPageId ); + if(pInfo) + { + const OUString& sString = pInfo->GetName(); + AddAttribute(XML_NAMESPACE_STYLE, XML_PAGE_LAYOUT_NAME, sString ); + } + + // draw:style-name (background attributes) + if( !maMasterPagesStyleNames[nMPageId].isEmpty() ) + AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, + maMasterPagesStyleNames[nMPageId]); + + // write masterpage + SvXMLElementExport aMPG(*this, XML_NAMESPACE_STYLE, XML_MASTER_PAGE, true, true); + + // write optional office:forms + exportFormsElement( xMasterPage ); + + // write optional loext:theme + exportTheme(xMasterPage); + + // write graphic objects on this master page (if any) + if(xMasterPage.is() && xMasterPage->getCount()) + GetShapeExport()->exportShapes( xMasterPage ); + + // write presentation notes (ONLY if presentation) + if(IsImpress()) + { + Reference< presentation::XPresentationPage > xPresPage(xMasterPage, UNO_QUERY); + if(xPresPage.is()) + { + Reference< XDrawPage > xNotesPage(xPresPage->getNotesPage()); + if(xNotesPage.is()) + { + ImpXMLEXPPageMasterInfo* pMasterInfo = mvNotesPageMasterUsageList.at( nMPageId ); + if(pMasterInfo) + { + const OUString& sString = pMasterInfo->GetName(); + AddAttribute(XML_NAMESPACE_STYLE, XML_PAGE_LAYOUT_NAME, sString); + } + + // write presentation notes + SvXMLElementExport aPSY(*this, XML_NAMESPACE_PRESENTATION, XML_NOTES, true, true); + + // write optional office:forms + exportFormsElement( xNotesPage ); + + // write shapes per se + GetShapeExport()->exportShapes( xNotesPage ); + } + } + } + exportAnnotations( xMasterPage ); + } + } +} + +void SdXMLExport::exportFormsElement( const Reference< XDrawPage >& xDrawPage ) +{ + if( !xDrawPage.is() ) + return; + + Reference< form::XFormsSupplier2 > xFormsSupplier( xDrawPage, UNO_QUERY ); + if ( xFormsSupplier.is() && xFormsSupplier->hasForms() ) + { + // write masterpage + ::xmloff::OOfficeFormsExport aForms(*this); + GetFormExport()->exportForms( xDrawPage ); + } + + if(! GetFormExport()->seekPage( xDrawPage ) ) + { + OSL_FAIL( "OFormLayerXMLExport::seekPage failed!" ); + } +} + +void SdXMLExport::exportTheme(const uno::Reference<drawing::XDrawPage>& xDrawPage) +{ + if ((getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + { + // Do not export in standard ODF 1.3 or older. + return; + } + + uno::Reference<beans::XPropertySet> xPropertySet(xDrawPage, uno::UNO_QUERY); + if (!xPropertySet.is()) + return; + + uno::Reference<util::XTheme> xTheme; + xPropertySet->getPropertyValue("Theme") >>= xTheme; + if (!xTheme.is()) + return; + + auto* pUnoTheme = dynamic_cast<UnoTheme*>(xTheme.get()); + if (!pUnoTheme) + return; + + auto pTheme = pUnoTheme->getTheme(); + if (!pTheme) + return; + + ExportThemeElement(pTheme); +} + +void SdXMLExport::GetViewSettings(uno::Sequence<beans::PropertyValue>& rProps) +{ + Reference< beans::XPropertySet > xPropSet( GetModel(), UNO_QUERY ); + if( !xPropSet.is() ) + return; + + awt::Rectangle aVisArea; + xPropSet->getPropertyValue("VisibleArea") >>= aVisArea; + + rProps.realloc(4); + beans::PropertyValue* pProps = rProps.getArray(); + + pProps[0].Name = "VisibleAreaTop"; + pProps[0].Value <<= aVisArea.Y; + pProps[1].Name = "VisibleAreaLeft"; + pProps[1].Value <<= aVisArea.X; + pProps[2].Name = "VisibleAreaWidth"; + pProps[2].Value <<= aVisArea.Width; + pProps[3].Name = "VisibleAreaHeight"; + pProps[3].Value <<= aVisArea.Height; + +} + +void SdXMLExport::GetConfigurationSettings(uno::Sequence<beans::PropertyValue>& rProps) +{ + Reference< lang::XMultiServiceFactory > xFac( GetModel(), UNO_QUERY ); + if( !xFac.is() ) + return; + + Reference< beans::XPropertySet > xProps( xFac->createInstance("com.sun.star.document.Settings"), UNO_QUERY ); + if( xProps.is() ) + SvXMLUnitConverter::convertPropertySet( rProps, xProps ); + DocumentSettingsSerializer *pFilter(dynamic_cast<DocumentSettingsSerializer *>(xProps.get())); + if (!pFilter) + return; + const uno::Reference< embed::XStorage > xStorage(GetTargetStorage()); + if (!xStorage.is()) + return; + rProps = pFilter->filterStreamsToStorage(xStorage, rProps); +} + +void SdXMLExport::addDataStyle(const sal_Int32 nNumberFormat, bool bTimeFormat ) +{ + sal_Int32 nFormat = nNumberFormat; + if( (nNumberFormat > 1) && (nNumberFormat <= 0x0f) ) + nFormat -= 2; + + if( bTimeFormat ) + { + maUsedTimeStyles.insert( nFormat ); + } + else + { + maUsedDateStyles.insert( nFormat ); + } +} + +void SdXMLExport::exportDataStyles() +{ + // there are no data styles to export in draw/impress yet +} + +void SdXMLExport::exportAutoDataStyles() +{ + for( const auto& rUsedDateStyle : maUsedDateStyles ) + SdXMLNumberStylesExporter::exportDateStyle( *this, rUsedDateStyle ); + + for( const auto& rUsedTimeStyle : maUsedTimeStyles ) + SdXMLNumberStylesExporter::exportTimeStyle( *this, rUsedTimeStyle ); + + if(HasFormExport()) + GetFormExport()->exportAutoControlNumberStyles(); +} + +OUString SdXMLExport::getDataStyleName(const sal_Int32 nNumberFormat, bool bTimeFormat ) const +{ + if( bTimeFormat ) + { + return SdXMLNumberStylesExporter::getTimeStyleName( nNumberFormat ); + } + else + { + return SdXMLNumberStylesExporter::getDateStyleName( nNumberFormat ); + } +} + +OUString SdXMLExport::getNavigationOrder( const Reference< XDrawPage >& xDrawPage ) +{ + OUStringBuffer sNavOrder; + try + { + Reference< XPropertySet > xSet( xDrawPage, UNO_QUERY_THROW ); + Reference< XIndexAccess > xNavOrder( xSet->getPropertyValue("NavigationOrder"), UNO_QUERY_THROW ); + + Reference< XIndexAccess > xZOrderAccess = xDrawPage; + + // only export navigation order if it is different from the z-order + if( (xNavOrder.get() != xZOrderAccess.get()) && (xNavOrder->getCount() == xDrawPage->getCount()) ) + { + sal_Int32 nIndex; + const sal_Int32 nCount = xNavOrder->getCount(); + for( nIndex = 0; nIndex < nCount; ++nIndex ) + { + OUString sId( getInterfaceToIdentifierMapper().registerReference( Reference< XInterface >( xNavOrder->getByIndex( nIndex ), UNO_QUERY ) ) ); + if( !sId.isEmpty() ) + { + if( !sNavOrder.isEmpty() ) + sNavOrder.append( ' ' ); + sNavOrder.append( sId ); + } + } + } + } + catch(const Exception&) + { + } + return sNavOrder.makeStringAndClear(); +} + +void SdXMLExport::collectAnnotationAutoStyles( const Reference<XDrawPage>& xDrawPage ) +{ + Reference< XAnnotationAccess > xAnnotationAccess( xDrawPage, UNO_QUERY ); + if( !xAnnotationAccess.is() ) return; + + try + { + Reference< XAnnotationEnumeration > xAnnotationEnumeration( xAnnotationAccess->createAnnotationEnumeration() ); + if( xAnnotationEnumeration.is() ) + { + while( xAnnotationEnumeration->hasMoreElements() ) + { + Reference< XAnnotation > xAnnotation( xAnnotationEnumeration->nextElement(), UNO_SET_THROW ); + Reference< XText > xText( xAnnotation->getTextRange() ); + if(xText.is() && !xText->getString().isEmpty()) + GetTextParagraphExport()->collectTextAutoStyles( xText ); + } + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", + "exception caught during export of annotation auto styles"); + } +} + +void SdXMLExport::exportAnnotations( const Reference<XDrawPage>& xDrawPage ) +{ + // do not export in standard ODF 1.3 or older + if ((getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + { + return; + } + + Reference< XAnnotationAccess > xAnnotationAccess( xDrawPage, UNO_QUERY ); + if( !xAnnotationAccess.is() ) + return; + + try + { + Reference< XAnnotationEnumeration > xAnnotationEnumeration( xAnnotationAccess->createAnnotationEnumeration() ); + if( xAnnotationEnumeration.is() && xAnnotationEnumeration->hasMoreElements() ) + { + bool bRemovePersonalInfo = SvtSecurityOptions::IsOptionSet( + SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ) && !SvtSecurityOptions::IsOptionSet( + SvtSecurityOptions::EOption::DocWarnKeepNoteAuthorDateInfo); + + OUStringBuffer sStringBuffer; + do + { + Reference< XAnnotation > xAnnotation( xAnnotationEnumeration->nextElement(), UNO_SET_THROW ); + + RealPoint2D aPosition( xAnnotation->getPosition() ); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + static_cast<sal_Int32>( aPosition.X * 100 ) ); + AddAttribute(XML_NAMESPACE_SVG, XML_X, sStringBuffer.makeStringAndClear()); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + static_cast<sal_Int32>( aPosition.Y * 100 ) ); + AddAttribute(XML_NAMESPACE_SVG, XML_Y, sStringBuffer.makeStringAndClear()); + + RealSize2D aSize( xAnnotation->getSize() ); + + if( aSize.Width || aSize.Height ) + { + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + static_cast<sal_Int32>( aSize.Width * 100 ) ); + AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, sStringBuffer.makeStringAndClear()); + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + static_cast<sal_Int32>( aSize.Height * 100 ) ); + AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, sStringBuffer.makeStringAndClear()); + } + + // annotation element + content + SvXMLElementExport aElem(*this, XML_NAMESPACE_OFFICE_EXT, XML_ANNOTATION, false, true); + + // author + OUString aAuthor( xAnnotation->getAuthor() ); + if( !aAuthor.isEmpty() ) + { + SvXMLElementExport aCreatorElem( *this, XML_NAMESPACE_DC, XML_CREATOR, true, false ); + Characters( bRemovePersonalInfo + ? "Author" + OUString::number( SvXMLExport::GetInfoID(aAuthor) ) + : aAuthor ); + } + + // initials + OUString aInitials( xAnnotation->getInitials() ); + if( !aInitials.isEmpty() ) + { + // OFFICE-3776 export meta:creator-initials for ODF 1.3 + SvXMLElementExport aInitialsElem( *this, + (SvtSaveOptions::ODFSVER_013 <= getSaneDefaultVersion()) + ? XML_NAMESPACE_META + : XML_NAMESPACE_LO_EXT, + (SvtSaveOptions::ODFSVER_013 <= getSaneDefaultVersion()) + ? XML_CREATOR_INITIALS + : XML_SENDER_INITIALS, + true, false ); + Characters( bRemovePersonalInfo + ? OUString::number( SvXMLExport::GetInfoID(aInitials) ) + : aInitials ); + } + + { + // date time + css::util::DateTime aDate( bRemovePersonalInfo + ? css::util::DateTime(0, 0, 0, 0, 1, 1, 1970, true) // Epoch time + : xAnnotation->getDateTime() ); + ::sax::Converter::convertDateTime(sStringBuffer, aDate, nullptr, true); + SvXMLElementExport aDateElem( *this, XML_NAMESPACE_DC, XML_DATE, true, false ); + Characters( sStringBuffer.makeStringAndClear() ); + } + + css::uno::Reference < css::text::XText > xText( xAnnotation->getTextRange() ); + if( xText.is() ) + GetTextParagraphExport()->exportText( xText ); + } + while( xAnnotationEnumeration->hasMoreElements() ); + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", "exception caught during export of annotations"); + } +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport( + pCtx, "XMLImpressExportOasis", false, + SvXMLExportFlags::OASIS | SvXMLExportFlags::META | SvXMLExportFlags::STYLES + | SvXMLExportFlags::MASTERSTYLES | SvXMLExportFlags::AUTOSTYLES + | SvXMLExportFlags::CONTENT | SvXMLExportFlags::SCRIPTS | SvXMLExportFlags::SETTINGS + | SvXMLExportFlags::FONTDECLS | SvXMLExportFlags::EMBEDDED)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisStylesExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport( + pCtx, "XMLImpressStylesExportOasis", false, + SvXMLExportFlags::OASIS | SvXMLExportFlags::STYLES | SvXMLExportFlags::MASTERSTYLES + | SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisContentExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport(pCtx, "XMLImpressContentExportOasis", false, + SvXMLExportFlags::OASIS | SvXMLExportFlags::AUTOSTYLES + | SvXMLExportFlags::CONTENT | SvXMLExportFlags::SCRIPTS + | SvXMLExportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisMetaExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport(pCtx, "XMLImpressMetaExportOasis", false, + SvXMLExportFlags::OASIS | SvXMLExportFlags::META)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisSettingsExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport(pCtx, "XMLImpressSettingsExportOasis", false, + SvXMLExportFlags::OASIS | SvXMLExportFlags::SETTINGS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLExporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport( + pCtx, "XMLImpressExportOOO", false, + SvXMLExportFlags::META | SvXMLExportFlags::STYLES | SvXMLExportFlags::MASTERSTYLES + | SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT | SvXMLExportFlags::SCRIPTS + | SvXMLExportFlags::SETTINGS | SvXMLExportFlags::FONTDECLS + | SvXMLExportFlags::EMBEDDED)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLExporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport( + pCtx, "XMLDrawExportOOO", true, + SvXMLExportFlags::META | SvXMLExportFlags::STYLES | SvXMLExportFlags::MASTERSTYLES + | SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT | SvXMLExportFlags::SCRIPTS + | SvXMLExportFlags::SETTINGS | SvXMLExportFlags::FONTDECLS + | SvXMLExportFlags::EMBEDDED)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisSettingsExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport(pCtx, "XMLDrawSettingsExportOasis", true, + SvXMLExportFlags::OASIS | SvXMLExportFlags::SETTINGS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisMetaExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport(pCtx, "XMLDrawMetaExportOasis", true, + SvXMLExportFlags::OASIS | SvXMLExportFlags::META)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisContentExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport(pCtx, "XMLDrawContentExportOasis", true, + SvXMLExportFlags::OASIS | SvXMLExportFlags::AUTOSTYLES + | SvXMLExportFlags::CONTENT | SvXMLExportFlags::SCRIPTS + | SvXMLExportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisStylesExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport( + pCtx, "XMLDrawStylesExportOasis", true, + SvXMLExportFlags::OASIS | SvXMLExportFlags::STYLES | SvXMLExportFlags::MASTERSTYLES + | SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisExporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport( + pCtx, "XMLDrawExportOasis", true, + SvXMLExportFlags::OASIS | SvXMLExportFlags::META | SvXMLExportFlags::STYLES + | SvXMLExportFlags::MASTERSTYLES | SvXMLExportFlags::AUTOSTYLES + | SvXMLExportFlags::CONTENT | SvXMLExportFlags::SCRIPTS | SvXMLExportFlags::SETTINGS + | SvXMLExportFlags::FONTDECLS | SvXMLExportFlags::EMBEDDED)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_DrawingLayer_XMLExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire( + new SdXMLExport(pCtx, "XMLDrawingLayerExport", true, + SvXMLExportFlags::OASIS | SvXMLExportFlags::STYLES + | SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT + | SvXMLExportFlags::FONTDECLS | SvXMLExportFlags::EMBEDDED)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLClipboardExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire( + new SdXMLExport(pCtx, "XMLImpressClipboardExport", /*bIsDraw=*/false, + SvXMLExportFlags::OASIS | SvXMLExportFlags::STYLES + | SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT + | SvXMLExportFlags::FONTDECLS | SvXMLExportFlags::EMBEDDED)); +} + +XMLFontAutoStylePool* SdXMLExport::CreateFontAutoStylePool() +{ + bool bEmbedFonts = false; + bool bEmbedUsedOnly = false; + bool bEmbedLatinScript = true; + bool bEmbedAsianScript = true; + bool bEmbedComplexScript = true; + + if (getExportFlags() & SvXMLExportFlags::CONTENT) + { + try + { + Reference<lang::XMultiServiceFactory> xFactory(GetModel(), UNO_QUERY); + Reference<beans::XPropertySet> xProps; + Reference<beans::XPropertySetInfo> xInfo; + + if (xFactory.is()) + xProps.set(xFactory->createInstance("com.sun.star.document.Settings"), UNO_QUERY); + if (xProps.is()) + xInfo = xProps->getPropertySetInfo(); + if (xInfo.is() && xProps.is()) + { + if (xInfo->hasPropertyByName("EmbedFonts")) + xProps->getPropertyValue("EmbedFonts") >>= bEmbedFonts; + if (xInfo->hasPropertyByName("EmbedOnlyUsedFonts")) + xProps->getPropertyValue("EmbedOnlyUsedFonts") >>= bEmbedUsedOnly; + if (xInfo->hasPropertyByName("EmbedLatinScriptFonts")) + xProps->getPropertyValue("EmbedLatinScriptFonts") >>= bEmbedLatinScript; + if (xInfo->hasPropertyByName("EmbedAsianScriptFonts")) + xProps->getPropertyValue("EmbedAsianScriptFonts") >>= bEmbedAsianScript; + if (xInfo->hasPropertyByName("EmbedComplexScriptFonts")) + xProps->getPropertyValue("EmbedComplexScriptFonts") >>= bEmbedComplexScript; + } + } catch(...) + { + // clipboard document doesn't have shell so throws from getPropertyValue + // gallery elements may not support com.sun.star.document.Settings so throws from createInstance + } + } + + XMLFontAutoStylePool *pPool = new XMLFontAutoStylePool( *this, bEmbedFonts ); + pPool->setEmbedOnlyUsedFonts(bEmbedUsedOnly); + pPool->setEmbedFontScripts(bEmbedLatinScript, bEmbedAsianScript, bEmbedComplexScript); + + Reference< beans::XPropertySet > xProps( GetModel(), UNO_QUERY ); + if ( xProps.is() ) { + Sequence<Any> aAnySeq; + if( xProps->getPropertyValue("Fonts") >>= aAnySeq ) + { + if( aAnySeq.getLength() % 5 == 0 ) + { + int nLen = aAnySeq.getLength() / 5; + int nSeqIndex = 0; + for( int i = 0; i < nLen; i++ ) + { + OUString sFamilyName, sStyleName; + sal_Int16 eFamily(FAMILY_DONTKNOW), + ePitch(PITCH_DONTKNOW), + eCharSet(RTL_TEXTENCODING_DONTKNOW); + + aAnySeq[nSeqIndex++] >>= sFamilyName; + aAnySeq[nSeqIndex++] >>= sStyleName; + aAnySeq[nSeqIndex++] >>= eFamily; + aAnySeq[nSeqIndex++] >>= ePitch; + aAnySeq[nSeqIndex++] >>= eCharSet; + + pPool->Add( sFamilyName, sStyleName, FontFamily( eFamily ), FontPitch( ePitch ), rtl_TextEncoding( eCharSet ) ); + } + } + } + } + + return pPool; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/sdxmlexp_impl.hxx b/xmloff/source/draw/sdxmlexp_impl.hxx new file mode 100644 index 0000000000..8207d64e3b --- /dev/null +++ b/xmloff/source/draw/sdxmlexp_impl.hxx @@ -0,0 +1,179 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlexp.hxx> + +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> + +#include <o3tl/sorted_vector.hxx> +#include <vector> + +namespace tools { class Rectangle; } + +class ImpXMLEXPPageMasterInfo; +class ImpXMLAutoLayoutInfo; +class XMLSdPropHdlFactory; +class XMLShapeExportPropertyMapper; +class XMLPageExportPropertyMapper; + +typedef ::std::vector< ImpXMLEXPPageMasterInfo* > ImpXMLEXPPageMasterList; + +enum XmlPlaceholder +{ + XmlPlaceholderTitle, + XmlPlaceholderOutline, + XmlPlaceholderSubtitle, + XmlPlaceholderGraphic, + XmlPlaceholderObject, + XmlPlaceholderChart, + XmlPlaceholderTable, + XmlPlaceholderPage, + XmlPlaceholderNotes, + XmlPlaceholderHandout, + XmlPlaceholderVerticalTitle, + XmlPlaceholderVerticalOutline +}; + +typedef o3tl::sorted_vector<sal_Int32> SdXMLFormatMap; + +struct HeaderFooterPageSettingsImpl +{ + OUString maStrHeaderDeclName; + OUString maStrFooterDeclName; + OUString maStrDateTimeDeclName; +}; + +struct DateTimeDeclImpl +{ + OUString maStrText; + bool mbFixed; + sal_Int32 mnFormat; +}; + +class SdXMLExport : public SvXMLExport +{ + css::uno::Reference< css::container::XNameAccess > mxDocStyleFamilies; + css::uno::Reference< css::container::XIndexAccess > mxDocMasterPages; + css::uno::Reference< css::container::XIndexAccess > mxDocDrawPages; + sal_Int32 mnDocMasterPageCount; + sal_Int32 mnDocDrawPageCount; + sal_uInt32 mnObjectCount; + + // temporary infos + std::vector< std::unique_ptr<ImpXMLEXPPageMasterInfo> > mvPageMasterInfoList; + ImpXMLEXPPageMasterList mvPageMasterUsageList; + ImpXMLEXPPageMasterList mvNotesPageMasterUsageList; + ImpXMLEXPPageMasterInfo* mpHandoutPageMaster; + std::vector< std::unique_ptr<ImpXMLAutoLayoutInfo> > mvAutoLayoutInfoList; + + css::uno::Sequence< OUString > maDrawPagesAutoLayoutNames; + + ::std::vector< OUString > maDrawPagesStyleNames; + ::std::vector< OUString > maDrawNotesPagesStyleNames; + ::std::vector< OUString > maMasterPagesStyleNames; + OUString maHandoutMasterStyleName; + ::std::vector< HeaderFooterPageSettingsImpl > maDrawPagesHeaderFooterSettings; + ::std::vector< HeaderFooterPageSettingsImpl > maDrawNotesPagesHeaderFooterSettings; + + ::std::vector< OUString > maHeaderDeclsVector; + ::std::vector< OUString > maFooterDeclsVector; + ::std::vector< DateTimeDeclImpl > maDateTimeDeclsVector; + + HeaderFooterPageSettingsImpl maHandoutPageHeaderFooterSettings; + + rtl::Reference<XMLSdPropHdlFactory> mpSdPropHdlFactory; + rtl::Reference<XMLShapeExportPropertyMapper> mpPropertySetMapper; + rtl::Reference<XMLPageExportPropertyMapper> mpPresPagePropsMapper; + + SdXMLFormatMap maUsedDateStyles; // this is a vector with the used formattings for date fields + SdXMLFormatMap maUsedTimeStyles; // this is a vector with the used formattings for time fields + + bool mbIsDraw; + + virtual void ExportStyles_(bool bUsed) override; + virtual void ExportAutoStyles_() override; + virtual void ExportFontDecls_() override; + virtual void ExportMasterStyles_() override; + virtual void ExportContent_() override; + virtual void ExportMeta_() override; + + ImpXMLEXPPageMasterInfo* ImpGetOrCreatePageMasterInfo( const css::uno::Reference< css::drawing::XDrawPage >& xMasterPage ); + void ImpPrepPageMasterInfos(); + void ImpWritePageMasterInfos(); + void ImpPrepAutoLayoutInfos(); + HeaderFooterPageSettingsImpl ImpPrepDrawPageHeaderFooterDecls( const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage ); + ImpXMLEXPPageMasterInfo* ImpGetPageMasterInfoByName(std::u16string_view rName); + + void ImpPrepDrawPageInfos(); + void ImpPrepMasterPageInfos(); + void ImpWritePresentationStyles(); + OUString ImpCreatePresPageStyleName( const css::uno::Reference<css::drawing::XDrawPage>& xDrawPage, bool bExportBackground = true ); + + bool ImpPrepAutoLayoutInfo(const css::uno::Reference< css::drawing::XDrawPage >& xPage, OUString& rName); + void ImpWriteAutoLayoutInfos(); + void ImpWriteAutoLayoutPlaceholder(XmlPlaceholder ePl, const tools::Rectangle& rRect); + void ImpWriteHeaderFooterDecls(); + void ImplExportHeaderFooterDeclAttributes( const HeaderFooterPageSettingsImpl& aSettings ); + + void exportFormsElement( const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage ); + void exportTheme(const css::uno::Reference<css::drawing::XDrawPage>& xDrawPage); + void exportPresentationSettings(); + + // #82003# helper function for recursive object count + sal_uInt32 ImpRecursiveObjectCount( const css::uno::Reference< css::drawing::XShapes >& xShapes); + + OUString getNavigationOrder( const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage ); + + void collectAnnotationAutoStyles( const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage ); + void exportAnnotations( const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage ); + +protected: + virtual void GetViewSettings(css::uno::Sequence<css::beans::PropertyValue>& aProps) override; + virtual void GetConfigurationSettings(css::uno::Sequence<css::beans::PropertyValue>& aProps) override; + virtual XMLFontAutoStylePool* CreateFontAutoStylePool() override; + +public: + SdXMLExport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, + bool bIsDraw, SvXMLExportFlags nExportFlags ); + virtual ~SdXMLExport() override; + + void collectAutoStyles() override; + + // XExporter + virtual void SAL_CALL setSourceDocument( const css::uno::Reference< css::lang::XComponent >& xDoc ) override; + + // get factories and mappers + XMLShapeExportPropertyMapper* GetPropertySetMapper() const { return mpPropertySetMapper.get(); } + XMLPageExportPropertyMapper* GetPresPagePropsMapper() const { return mpPresPagePropsMapper.get(); } + + bool IsDraw() const { return mbIsDraw; } + bool IsImpress() const { return !mbIsDraw; } + + virtual void addDataStyle(const sal_Int32 nNumberFormat, bool bTimeFormat = false ) override; + virtual void exportDataStyles() override; + virtual void exportAutoDataStyles() override; + virtual OUString getDataStyleName(const sal_Int32 nNumberFormat, bool bTimeFormat = false ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/sdxmlimp.cxx b/xmloff/source/draw/sdxmlimp.cxx new file mode 100644 index 0000000000..19fd66d5a3 --- /dev/null +++ b/xmloff/source/draw/sdxmlimp.cxx @@ -0,0 +1,678 @@ +/* -*- 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 <osl/thread.h> +#include <sal/log.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/sequence.hxx> + +#include <xmloff/xmlscripti.hxx> +#include "sdxmlimp_impl.hxx" +#include "ximpbody.hxx" + +#include <xmloff/xmlmetai.hxx> +#include "ximpstyl.hxx" +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/DocumentSettingsContext.hxx> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/form/XFormsSupplier.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/drawing/XMasterPagesSupplier.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <xmloff/settingsstore.hxx> +#include <xmloff/ProgressBarHelper.hxx> + +#include <xmloff/XMLFontStylesContext.hxx> + +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +namespace { + +class SdXMLBodyContext_Impl : public SvXMLImportContext +{ + SdXMLImport& GetSdImport() { return static_cast<SdXMLImport&>(GetImport()); } + +public: + + SdXMLBodyContext_Impl( SdXMLImport& rImport ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +} + +SdXMLBodyContext_Impl::SdXMLBodyContext_Impl( SdXMLImport& rImport ) : + SvXMLImportContext( rImport ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLBodyContext_Impl::createFastChildContext( + sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList > & /*xAttrList*/ ) +{ + return new SdXMLBodyContext(GetSdImport()); +} + +namespace { + +// NB: virtually inherit so we can multiply inherit properly +// in SdXMLFlatDocContext_Impl +class SdXMLDocContext_Impl : public virtual SvXMLImportContext +{ +protected: + SdXMLImport& GetSdImport() { return static_cast<SdXMLImport&>(GetImport()); } + +public: + SdXMLDocContext_Impl( SdXMLImport& rImport ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +} + +SdXMLDocContext_Impl::SdXMLDocContext_Impl( + SdXMLImport& rImport ) +: SvXMLImportContext(rImport) +{ +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SdXMLDocContext_Impl::createFastChildContext( + sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + switch (nElement) + { + case XML_ELEMENT(OFFICE, XML_SCRIPTS): + { + if( GetImport().getImportFlags() & SvXMLImportFlags::SCRIPTS ) + { + // office:script inside office:document + return new XMLScriptContext( GetSdImport(), GetSdImport().GetModel() ); + } + break; + } + case XML_ELEMENT(OFFICE, XML_MASTER_STYLES): + { + if( GetImport().getImportFlags() & SvXMLImportFlags::MASTERSTYLES ) + { + // office:master-styles inside office:document + return GetSdImport().CreateMasterStylesContext(); + } + break; + } + case XML_ELEMENT(OFFICE, XML_BODY): + { + if( GetImport().getImportFlags() & SvXMLImportFlags::CONTENT ) + { + // office:body inside office:document + return new SdXMLBodyContext_Impl(GetSdImport()); + } + break; + } + case XML_ELEMENT(OFFICE, XML_SETTINGS): + { + if( GetImport().getImportFlags() & SvXMLImportFlags::SETTINGS ) + { + return new XMLDocumentSettingsContext(GetImport()); + } + break; + } + case XML_ELEMENT(OFFICE, XML_STYLES): + { + if( GetImport().getImportFlags() & SvXMLImportFlags::STYLES ) + { + // office:styles inside office:document + return GetSdImport().CreateStylesContext(); + } + break; + } + case XML_ELEMENT(OFFICE, XML_AUTOMATIC_STYLES): + { + if( GetImport().getImportFlags() & SvXMLImportFlags::AUTOSTYLES ) + { + // office:automatic-styles inside office:document + return GetSdImport().CreateAutoStylesContext(); + } + break; + } + case XML_ELEMENT(OFFICE, XML_FONT_FACE_DECLS): + { + return GetSdImport().CreateFontDeclsContext(); + } + case XML_ELEMENT(OFFICE, XML_META): + { + SAL_INFO("xmloff.draw", "XML_ELEMENT(OFFICE, XML_META): should not have come here, maybe document is invalid?"); + break; + } + } + return nullptr; +} + +namespace { + +// context for flat file xml format +class SdXMLFlatDocContext_Impl + : public SdXMLDocContext_Impl, public SvXMLMetaDocumentContext +{ +public: + SdXMLFlatDocContext_Impl( SdXMLImport& i_rImport, + const uno::Reference<document::XDocumentProperties>& i_xDocProps ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +} + +SdXMLFlatDocContext_Impl::SdXMLFlatDocContext_Impl( SdXMLImport& i_rImport, + const uno::Reference<document::XDocumentProperties>& i_xDocProps) : + SvXMLImportContext(i_rImport), + SdXMLDocContext_Impl(i_rImport), + SvXMLMetaDocumentContext(i_rImport, i_xDocProps) +{ +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SdXMLFlatDocContext_Impl::createFastChildContext( + sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + // behave like meta base class iff we encounter office:meta + if ( nElement == XML_ELEMENT( OFFICE, XML_META ) ) { + return SvXMLMetaDocumentContext::createFastChildContext( + nElement, xAttrList ); + } else { + return SdXMLDocContext_Impl::createFastChildContext( + nElement, xAttrList ); + } +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire( + new SdXMLImport(pCtx, "XMLImpressImportOasis", false, SvXMLImportFlags::ALL)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisImporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLImport(pCtx, "XMLDrawImportOasis", true, SvXMLImportFlags::ALL)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisStylesImporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLImport(pCtx, "XMLDrawStylesImportOasis", true, + SvXMLImportFlags::STYLES | SvXMLImportFlags::AUTOSTYLES + | SvXMLImportFlags::MASTERSTYLES)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisContentImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLImport(pCtx, "XMLDrawContentImportOasis", true, + SvXMLImportFlags::AUTOSTYLES | SvXMLImportFlags::CONTENT + | SvXMLImportFlags::SCRIPTS + | SvXMLImportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisMetaImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire( + new SdXMLImport(pCtx, "XMLDrawMetaImportOasis", true, SvXMLImportFlags::META)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisSettingsImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire( + new SdXMLImport(pCtx, "XMLDrawSettingsImportOasis", true, SvXMLImportFlags::SETTINGS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisStylesImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLImport(pCtx, "XMLImpressStylesImportOasis", false, + SvXMLImportFlags::STYLES | SvXMLImportFlags::AUTOSTYLES + | SvXMLImportFlags::MASTERSTYLES)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisContentImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLImport(pCtx, "XMLImpressContentImportOasis", false, + SvXMLImportFlags::AUTOSTYLES | SvXMLImportFlags::CONTENT + | SvXMLImportFlags::SCRIPTS + | SvXMLImportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisMetaImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire( + new SdXMLImport(pCtx, "XMLImpressMetaImportOasis", false, SvXMLImportFlags::META)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisSettingsImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire( + new SdXMLImport(pCtx, "XMLImpressSettingsImportOasis", false, SvXMLImportFlags::SETTINGS)); +} + +SdXMLImport::SdXMLImport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, + bool bIsDraw, SvXMLImportFlags nImportFlags ) +: SvXMLImport( xContext, implementationName, nImportFlags ), + mnNewPageCount(0), + mnNewMasterPageCount(0), + mbIsDraw(bIsDraw), + mbLoadDoc(true), + mbPreview(false) +{ + // add namespaces + GetNamespaceMap().Add( + GetXMLToken(XML_NP_PRESENTATION), + GetXMLToken(XML_N_PRESENTATION), + XML_NAMESPACE_PRESENTATION); + + GetNamespaceMap().Add( + GetXMLToken(XML_NP_SMIL), + GetXMLToken(XML_N_SMIL_COMPAT), + XML_NAMESPACE_SMIL); +} + +// XImporter +void SAL_CALL SdXMLImport::setTargetDocument( const uno::Reference< lang::XComponent >& xDoc ) +{ + SvXMLImport::setTargetDocument( xDoc ); + + uno::Reference< lang::XServiceInfo > xDocServices( GetModel(), uno::UNO_QUERY ); + if( !xDocServices.is() ) + throw lang::IllegalArgumentException(); + + mbIsDraw = !xDocServices->supportsService("com.sun.star.presentation.PresentationDocument"); + + // prepare access to styles + uno::Reference< style::XStyleFamiliesSupplier > xFamSup( GetModel(), uno::UNO_QUERY ); + if(xFamSup.is()) + mxDocStyleFamilies = xFamSup->getStyleFamilies(); + + if (!mbLoadDoc) + return; + + // prepare access to master pages + uno::Reference < drawing::XMasterPagesSupplier > xMasterPagesSupplier(GetModel(), uno::UNO_QUERY); + if(xMasterPagesSupplier.is()) + mxDocMasterPages = xMasterPagesSupplier->getMasterPages(); + + // prepare access to draw pages + uno::Reference <drawing::XDrawPagesSupplier> xDrawPagesSupplier(GetModel(), uno::UNO_QUERY); + if(!xDrawPagesSupplier.is()) + throw lang::IllegalArgumentException(); + + mxDocDrawPages = xDrawPagesSupplier->getDrawPages(); + if(!mxDocDrawPages.is()) + throw lang::IllegalArgumentException(); + + if( mxDocDrawPages.is() && mxDocDrawPages->getCount() > 0 ) + { + uno::Reference< form::XFormsSupplier > xFormsSupp; + mxDocDrawPages->getByIndex(0) >>= xFormsSupp; + mbIsFormsSupported = xFormsSupp.is(); + } + + // #88546# enable progress bar increments, SdXMLImport is only used for + // draw/impress import + GetShapeImport()->enableHandleProgressBar(); + + uno::Reference< lang::XMultiServiceFactory > xFac( GetModel(), uno::UNO_QUERY ); + if( xFac.is() ) + { + uno::Sequence< OUString > sSNS( xFac->getAvailableServiceNames() ); + if (comphelper::findValue(sSNS, "com.sun.star.drawing.TableShape") != -1) + mbIsTableShapeSupported = true; + } +} + +// XInitialization +void SAL_CALL SdXMLImport::initialize( const uno::Sequence< uno::Any >& aArguments ) +{ + SvXMLImport::initialize( aArguments ); + + static constexpr OUString sOrganizerMode(u"OrganizerMode"_ustr); + bool bStyleOnly(false); + + css::beans::PropertyValue aPropValue; + if (aArguments.hasElements() && (aArguments[0] >>= aPropValue) && aPropValue.Name == sOrganizerMode) + { + aPropValue.Value >>= bStyleOnly; + mbLoadDoc = !bStyleOnly; + } + + uno::Reference< beans::XPropertySet > xInfoSet( getImportInfo() ); + if( !xInfoSet.is() ) + return; + + uno::Reference< beans::XPropertySetInfo > xInfoSetInfo( xInfoSet->getPropertySetInfo() ); + + if( xInfoSetInfo->hasPropertyByName( gsPageLayouts ) ) + xInfoSet->getPropertyValue( gsPageLayouts ) >>= mxPageLayouts; + + if( xInfoSetInfo->hasPropertyByName( gsPreview ) ) + xInfoSet->getPropertyValue( gsPreview ) >>= mbPreview; + + if (xInfoSetInfo->hasPropertyByName(sOrganizerMode)) + { + if (xInfoSet->getPropertyValue(sOrganizerMode) >>= bStyleOnly) + { + mbLoadDoc = !bStyleOnly; + } + } +} + +SvXMLImportContext *SdXMLImport::CreateFastContext( sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext* pContext = nullptr; + + switch (nElement) + { + case XML_ELEMENT( OFFICE, XML_DOCUMENT_STYLES ): + case XML_ELEMENT( OFFICE, XML_DOCUMENT_CONTENT ): + case XML_ELEMENT( OFFICE, XML_DOCUMENT_SETTINGS ): + pContext = new SdXMLDocContext_Impl(*this); + break; + case XML_ELEMENT( OFFICE, XML_DOCUMENT_META ): + pContext = CreateMetaContext(nElement, xAttrList); + break; + case XML_ELEMENT( OFFICE, XML_DOCUMENT ): + { + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + GetModel(), uno::UNO_QUERY_THROW); + // flat OpenDocument file format + pContext = new SdXMLFlatDocContext_Impl( *this, xDPS->getDocumentProperties()); + } + break; + case XML_ELEMENT( OFFICE, XML_STYLES ): + // internal xml file for built in styles + if (!mbLoadDoc) + pContext = CreateStylesContext(); + break; + } + return pContext; +} + +SvXMLImportContext *SdXMLImport::CreateMetaContext(const sal_Int32 /*nElement*/, + const uno::Reference<xml::sax::XFastAttributeList>&) +{ + SvXMLImportContext* pContext = nullptr; + + if (getImportFlags() & SvXMLImportFlags::META) + { + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> const xDocProps( + !mbLoadDoc ? nullptr : xDPS->getDocumentProperties()); + pContext = new SvXMLMetaDocumentContext(*this, xDocProps); + } + + return pContext; +} + +SvXMLStylesContext *SdXMLImport::CreateStylesContext() +{ + if(GetShapeImport()->GetStylesContext()) + return GetShapeImport()->GetStylesContext(); + + GetShapeImport()->SetStylesContext(new SdXMLStylesContext( + *this, false)); + + return GetShapeImport()->GetStylesContext(); +} + +SvXMLStylesContext *SdXMLImport::CreateAutoStylesContext() +{ + if(GetShapeImport()->GetAutoStylesContext()) + return GetShapeImport()->GetAutoStylesContext(); + + GetShapeImport()->SetAutoStylesContext(new SdXMLStylesContext( + *this, true)); + + return GetShapeImport()->GetAutoStylesContext(); +} + +SvXMLImportContext* SdXMLImport::CreateMasterStylesContext() +{ + if (!mxMasterStylesContext.is()) + mxMasterStylesContext.set(new SdXMLMasterStylesContext(*this)); + return mxMasterStylesContext.get(); +} + +SvXMLImportContext *SdXMLImport::CreateFontDeclsContext() +{ + XMLFontStylesContext *pFSContext = + new XMLFontStylesContext( *this, osl_getThreadTextEncoding() ); + SetFontDecls( pFSContext ); + return pFSContext; +} + +void SdXMLImport::SetViewSettings(const css::uno::Sequence<css::beans::PropertyValue>& aViewProps) +{ + uno::Reference< beans::XPropertySet > xPropSet( GetModel(), uno::UNO_QUERY ); + if( !xPropSet.is() ) + return; + + awt::Rectangle aVisArea( 0,0, 28000, 21000 ); + + for( const auto& rViewProp : aViewProps ) + { + const OUString& rName = rViewProp.Name; + const uno::Any rValue = rViewProp.Value; + + if ( rName == "VisibleAreaTop" ) + { + rValue >>= aVisArea.Y; + } + else if ( rName == "VisibleAreaLeft" ) + { + rValue >>= aVisArea.X; + } + else if ( rName == "VisibleAreaWidth" ) + { + rValue >>= aVisArea.Width; + } + else if ( rName == "VisibleAreaHeight" ) + { + rValue >>= aVisArea.Height; + } + } + + try + { + xPropSet->setPropertyValue("VisibleArea", uno::Any( aVisArea ) ); + } + catch(const css::uno::Exception&) + { +/* #i79978# since old documents may contain invalid view settings, this is nothing to worry the user about. + SetError( XMLERROR_FLAG_WARNING | XMLERROR_API, {}, e.Message, NULL ); +*/ + } +} + +void SdXMLImport::SetConfigurationSettings(const css::uno::Sequence<css::beans::PropertyValue>& aConfigProps) +{ + uno::Reference< lang::XMultiServiceFactory > xFac( GetModel(), uno::UNO_QUERY ); + if( !xFac.is() ) + return; + + uno::Reference< beans::XPropertySet > xProps( xFac->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY ); + if( !xProps.is() ) + return; + + uno::Reference< beans::XPropertySetInfo > xInfo( xProps->getPropertySetInfo() ); + if( !xInfo.is() ) + return; + + const uno::Sequence<beans::PropertyValue>* pValues = &aConfigProps; + + DocumentSettingsSerializer *pFilter; + pFilter = dynamic_cast<DocumentSettingsSerializer *>(xProps.get()); + uno::Sequence<beans::PropertyValue> aFiltered; + if( pFilter ) + { + aFiltered = pFilter->filterStreamsFromStorage( GetDocumentBase(), GetSourceStorage(), aConfigProps ); + pValues = &aFiltered; + } + + for( const auto& rValue : *pValues ) + { + try + { + const OUString& rProperty = rValue.Name; + if( xInfo->hasPropertyByName( rProperty ) ) + xProps->setPropertyValue( rProperty, rValue.Value ); + } + catch(const uno::Exception&) + { + SAL_INFO("xmloff.draw", "#SdXMLImport::SetConfigurationSettings: Exception!" ); + } + } +} + +// #80365# override this method to read and use the hint value from the +// written meta information. If no info is found, guess 10 draw objects +//void SdXMLImport::SetStatisticAttributes(const uno::Reference<xml::sax::XAttributeList>& xAttrList) +void SdXMLImport::SetStatistics( + const uno::Sequence<beans::NamedValue> & i_rStats) +{ + static const char* s_stats[] = + { "ObjectCount", nullptr }; + + SvXMLImport::SetStatistics(i_rStats); + + sal_uInt32 nCount(10); + for (const auto& rStat : i_rStats) { + for (const char** pStat = s_stats; *pStat != nullptr; ++pStat) { + if (rStat.Name.equalsAscii(*pStat)) { + sal_Int32 val = 0; + if (rStat.Value >>= val) { + nCount = val; + } else { + SAL_WARN("xmloff.draw", "SdXMLImport::SetStatistics: invalid entry"); + } + } + } + } + + if(nCount) + { + GetProgressBarHelper()->SetReference(nCount); + GetProgressBarHelper()->SetValue(0); + } +} + +void SdXMLImport::AddHeaderDecl( const OUString& rName, const OUString& rText ) +{ + if( !rName.isEmpty() && !rText.isEmpty() ) + maHeaderDeclsMap[rName] = rText; +} + +void SdXMLImport::AddFooterDecl( const OUString& rName, const OUString& rText ) +{ + if( !rName.isEmpty() && !rText.isEmpty() ) + maFooterDeclsMap[rName] = rText; +} + +void SdXMLImport::AddDateTimeDecl( const OUString& rName, const OUString& rText, bool bFixed, const OUString& rDateTimeFormat ) +{ + if( !rName.isEmpty() && (!rText.isEmpty() || !bFixed) ) + { + DateTimeDeclContextImpl aDecl; + aDecl.maStrText = rText; + aDecl.mbFixed = bFixed; + aDecl.maStrDateTimeFormat = rDateTimeFormat; + maDateTimeDeclsMap[rName] = aDecl; + } +} + +OUString SdXMLImport::GetHeaderDecl( const OUString& rName ) const +{ + OUString aRet; + HeaderFooterDeclMap::const_iterator aIter( maHeaderDeclsMap.find( rName ) ); + if( aIter != maHeaderDeclsMap.end() ) + aRet = (*aIter).second; + + return aRet; +} + +OUString SdXMLImport::GetFooterDecl( const OUString& rName ) const +{ + OUString aRet; + HeaderFooterDeclMap::const_iterator aIter( maFooterDeclsMap.find( rName ) ); + if( aIter != maFooterDeclsMap.end() ) + aRet = (*aIter).second; + + return aRet; +} + +OUString SdXMLImport::GetDateTimeDecl( const OUString& rName, bool& rbFixed, OUString& rDateTimeFormat ) +{ + DateTimeDeclContextImpl aDecl; + + DateTimeDeclMap::const_iterator aIter( maDateTimeDeclsMap.find( rName ) ); + if( aIter != maDateTimeDeclsMap.end() ) + aDecl = (*aIter).second; + + rbFixed = aDecl.mbFixed; + rDateTimeFormat = aDecl.maStrDateTimeFormat; + return aDecl.maStrText; +} + +void SdXMLImport::NotifyContainsEmbeddedFont() +{ + uno::Reference< lang::XMultiServiceFactory > xFac( GetModel(), uno::UNO_QUERY ); + if( xFac.is() ) + { + uno::Reference< beans::XPropertySet > xProps( xFac->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY ); + if( xProps.is() ) + xProps->setPropertyValue("EmbedFonts", uno::Any( true ) ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/sdxmlimp_impl.hxx b/xmloff/source/draw/sdxmlimp_impl.hxx new file mode 100644 index 0000000000..60641601a9 --- /dev/null +++ b/xmloff/source/draw/sdxmlimp_impl.hxx @@ -0,0 +1,135 @@ +/* -*- 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 . + */ + +#pragma once + +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/task/XStatusIndicator.hpp> +#include <xmloff/xmltkmap.hxx> +#include <com/sun/star/container/XNameAccess.hpp> + +#include <map> +#include <memory> +#include <vector> +#include <xmloff/xmlimp.hxx> + +class SvXMLUnitConverter; +class SvXMLTokenMap; +class SdXMLMasterStylesContext; + +struct DateTimeDeclContextImpl +{ + OUString maStrText; + bool mbFixed; + OUString maStrDateTimeFormat; + + DateTimeDeclContextImpl() : mbFixed(true) {} +}; + +typedef std::map<OUString, OUString> HeaderFooterDeclMap; +typedef std::map<OUString, DateTimeDeclContextImpl> DateTimeDeclMap; + +class SdXMLImport: public SvXMLImport +{ + css::uno::Reference< css::container::XNameAccess > mxDocStyleFamilies; + css::uno::Reference< css::container::XIndexAccess > mxDocMasterPages; + css::uno::Reference< css::container::XIndexAccess > mxDocDrawPages; + css::uno::Reference< css::container::XNameAccess > mxPageLayouts; + + // contexts for Style and AutoStyle import + rtl::Reference<SdXMLMasterStylesContext> mxMasterStylesContext; + + sal_Int32 mnNewPageCount; + sal_Int32 mnNewMasterPageCount; + + bool mbIsDraw; + bool mbLoadDoc; + bool mbPreview; + + static constexpr OUString gsPageLayouts = u"PageLayouts"_ustr; + static constexpr OUString gsPreview = u"Preview"_ustr; + + HeaderFooterDeclMap maHeaderDeclsMap; + HeaderFooterDeclMap maFooterDeclsMap; + DateTimeDeclMap maDateTimeDeclsMap; + +protected: + + // This method is called after the namespace map has been updated, but + // before a context for the current element has been pushed. + virtual SvXMLImportContext *CreateFastContext( sal_Int32 nElement, + const ::css::uno::Reference< ::css::xml::sax::XFastAttributeList >& xAttrList ) override; + +public: + SdXMLImport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, + bool bIsDraw, SvXMLImportFlags nImportFlags ); + + // XImporter + virtual void SAL_CALL setTargetDocument( const css::uno::Reference< css::lang::XComponent >& xDoc ) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + virtual void SetViewSettings(const css::uno::Sequence<css::beans::PropertyValue>& aViewProps) override; + virtual void SetConfigurationSettings(const css::uno::Sequence<css::beans::PropertyValue>& aConfigProps) override; + + // namespace office + // NB: in contrast to other CreateFooContexts, this particular one handles + // the root element (i.e. office:document-meta) + SvXMLImportContext* CreateMetaContext(const sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList); + SvXMLStylesContext* CreateStylesContext(); + SvXMLStylesContext* CreateAutoStylesContext(); + SvXMLImportContext* CreateMasterStylesContext(); + SvXMLImportContext *CreateFontDeclsContext(); + + // export local parameters concerning page access and similar + const css::uno::Reference< css::container::XNameAccess >& GetLocalDocStyleFamilies() const { return mxDocStyleFamilies; } + const css::uno::Reference< css::container::XIndexAccess >& GetLocalMasterPages() const { return mxDocMasterPages; } + const css::uno::Reference< css::container::XIndexAccess >& GetLocalDrawPages() const { return mxDocDrawPages; } + + sal_Int32 GetNewPageCount() const { return mnNewPageCount; } + void IncrementNewPageCount() { mnNewPageCount++; } + sal_Int32 GetNewMasterPageCount() const { return mnNewMasterPageCount; } + void IncrementNewMasterPageCount() { mnNewMasterPageCount++; } + + const css::uno::Reference< css::container::XNameAccess >& getPageLayouts() const { return mxPageLayouts; } + + bool IsDraw() const { return mbIsDraw; } + bool IsImpress() const { return !mbIsDraw; } + + virtual void SetStatistics( + const css::uno::Sequence< css::beans::NamedValue> & i_rStats) override; + + bool IsPreview() const { return mbPreview; } + + void AddHeaderDecl( const OUString& rName, const OUString& rText ); + void AddFooterDecl( const OUString& rName, const OUString& rText ); + void AddDateTimeDecl( const OUString& rName, const OUString& rText, bool bFixed, const OUString& rDateTimeFormat ); + + OUString GetHeaderDecl( const OUString& rName ) const; + OUString GetFooterDecl( const OUString& rName ) const; + OUString GetDateTimeDecl( const OUString& rName, bool& rbFixed, OUString& rDateTimeFormat ); + + virtual void NotifyContainsEmbeddedFont() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/shapeexport.cxx b/xmloff/source/draw/shapeexport.cxx new file mode 100644 index 0000000000..cbb0278297 --- /dev/null +++ b/xmloff/source/draw/shapeexport.cxx @@ -0,0 +1,5183 @@ +/* -*- 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 <config_wasm_strip.h> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b3dpolypolygon.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <basegfx/tuple/b2dtuple.hxx> +#include <basegfx/vector/b3dvector.hxx> + +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/beans/PropertyValues.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/container/XIdentifierAccess.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/drawing/Alignment.hpp> +#include <com/sun/star/drawing/CameraGeometry.hpp> +#include <com/sun/star/drawing/CircleKind.hpp> +#include <com/sun/star/drawing/ConnectorType.hpp> +#include <com/sun/star/drawing/Direction3D.hpp> +#include <com/sun/star/drawing/EscapeDirection.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeGluePointType.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp> +#include <com/sun/star/drawing/GluePoint2.hpp> +#include <com/sun/star/drawing/HomogenMatrix.hpp> +#include <com/sun/star/drawing/HomogenMatrix3.hpp> +#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp> +#include <com/sun/star/drawing/PolyPolygonShape3D.hpp> +#include <com/sun/star/drawing/Position3D.hpp> +#include <com/sun/star/drawing/ProjectionMode.hpp> +#include <com/sun/star/drawing/ShadeMode.hpp> +#include <com/sun/star/drawing/XControlShape.hpp> +#include <com/sun/star/drawing/XCustomShapeEngine.hpp> +#include <com/sun/star/drawing/XGluePointsSupplier.hpp> +#include <com/sun/star/drawing/BarCode.hpp> +#include <com/sun/star/drawing/BarCodeErrorCorrection.hpp> +#include <com/sun/star/drawing/XShapes3.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/graphic/GraphicProvider.hpp> +#include <com/sun/star/graphic/XGraphicProvider.hpp> +#include <com/sun/star/io/XSeekableInputStream.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/lang/ServiceNotRegisteredException.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/media/ZoomLevel.hpp> +#include <com/sun/star/presentation/AnimationSpeed.hpp> +#include <com/sun/star/presentation/ClickAction.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/table/XColumnRowRange.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <com/sun/star/text/XText.hpp> + +#include <comphelper/classids.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/storagehelper.hxx> +#include <officecfg/Office/Common.hxx> + +#include <o3tl/any.hxx> +#include <o3tl/typed_flags_set.hxx> +#include <o3tl/string_view.hxx> + +#include <rtl/math.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> + +#include <sax/tools/converter.hxx> + +#include <tools/debug.hxx> +#include <tools/globname.hxx> +#include <tools/helpers.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <vcl/graph.hxx> + +#include <xmloff/contextid.hxx> +#include <xmloff/families.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/shapeexport.hxx> +#include <xmloff/unointerfacetouniqueidentifiermapper.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/table/XMLTableExport.hxx> +#include <xmloff/ProgressBarHelper.hxx> + +#include <anim.hxx> +#include <EnhancedCustomShapeToken.hxx> +#include "sdpropls.hxx" +#include <xexptran.hxx> +#include "ximpshap.hxx" +#include <XMLBase64Export.hxx> +#include <XMLImageMapExport.hxx> +#include <memory> + +using namespace ::com::sun::star; +using namespace ::xmloff::EnhancedCustomShapeToken; +using namespace ::xmloff::token; + +constexpr OUStringLiteral XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE = u"vnd.sun.star.GraphicObject:"; + +namespace { + +bool supportsText(XmlShapeType eShapeType) +{ + return eShapeType != XmlShapeType::PresChartShape && + eShapeType != XmlShapeType::PresOLE2Shape && + eShapeType != XmlShapeType::DrawSheetShape && + eShapeType != XmlShapeType::PresSheetShape && + eShapeType != XmlShapeType::Draw3DSceneObject && + eShapeType != XmlShapeType::Draw3DCubeObject && + eShapeType != XmlShapeType::Draw3DSphereObject && + eShapeType != XmlShapeType::Draw3DLatheObject && + eShapeType != XmlShapeType::Draw3DExtrudeObject && + eShapeType != XmlShapeType::DrawPageShape && + eShapeType != XmlShapeType::PresPageShape && + eShapeType != XmlShapeType::DrawGroupShape; + +} + +} + +constexpr OUString gsZIndex( u"ZOrder"_ustr ); +constexpr OUStringLiteral gsPrintable( u"Printable" ); +constexpr OUStringLiteral gsVisible( u"Visible" ); +constexpr OUString gsModel( u"Model"_ustr ); +constexpr OUStringLiteral gsStartShape( u"StartShape" ); +constexpr OUStringLiteral gsEndShape( u"EndShape" ); +constexpr OUString gsOnClick( u"OnClick"_ustr ); +constexpr OUStringLiteral gsEventType( u"EventType" ); +constexpr OUStringLiteral gsPresentation( u"Presentation" ); +constexpr OUStringLiteral gsMacroName( u"MacroName" ); +constexpr OUString gsScript( u"Script"_ustr ); +constexpr OUStringLiteral gsLibrary( u"Library" ); +constexpr OUStringLiteral gsClickAction( u"ClickAction" ); +constexpr OUString gsBookmark( u"Bookmark"_ustr ); +constexpr OUStringLiteral gsEffect( u"Effect" ); +constexpr OUStringLiteral gsPlayFull( u"PlayFull" ); +constexpr OUStringLiteral gsVerb( u"Verb" ); +constexpr OUStringLiteral gsSoundURL( u"SoundURL" ); +constexpr OUStringLiteral gsSpeed( u"Speed" ); +constexpr OUStringLiteral gsStarBasic( u"StarBasic" ); +constexpr OUStringLiteral gsHyperlink( u"Hyperlink" ); + +XMLShapeExport::XMLShapeExport(SvXMLExport& rExp, + SvXMLExportPropertyMapper *pExtMapper ) +: mrExport( rExp ), + maCurrentShapesIter(maShapesInfos.end()), + mbExportLayer( false ), + // #88546# init to sal_False + mbHandleProgressBar( false ) +{ + // construct PropertySetMapper + mxPropertySetMapper = CreateShapePropMapper( mrExport ); + if( pExtMapper ) + { + rtl::Reference < SvXMLExportPropertyMapper > xExtMapper( pExtMapper ); + mxPropertySetMapper->ChainExportMapper( xExtMapper ); + } + +/* + // chain text attributes + xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(rExp)); +*/ + + mrExport.GetAutoStylePool()->AddFamily( + XmlStyleFamily::SD_GRAPHICS_ID, + XML_STYLE_FAMILY_SD_GRAPHICS_NAME, + GetPropertySetMapper(), + XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX); + mrExport.GetAutoStylePool()->AddFamily( + XmlStyleFamily::SD_PRESENTATION_ID, + XML_STYLE_FAMILY_SD_PRESENTATION_NAME, + GetPropertySetMapper(), + XML_STYLE_FAMILY_SD_PRESENTATION_PREFIX); + + // create table export helper and let him add his families in time + GetShapeTableExport(); +} + +XMLShapeExport::~XMLShapeExport() +{ +} + +// sj: replacing CustomShapes with standard objects that are also supported in OpenOffice.org format +uno::Reference< drawing::XShape > XMLShapeExport::checkForCustomShapeReplacement( const uno::Reference< drawing::XShape >& xShape ) +{ + uno::Reference< drawing::XShape > xCustomShapeReplacement; + + if( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) ) + { + OUString aType( xShape->getShapeType() ); + if( aType == "com.sun.star.drawing.CustomShape" ) + { + uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY ); + if( xSet.is() ) + { + OUString aEngine; + xSet->getPropertyValue("CustomShapeEngine") >>= aEngine; + if ( aEngine.isEmpty() ) + { + aEngine = "com.sun.star.drawing.EnhancedCustomShapeEngine"; + } + uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + + if ( !aEngine.isEmpty() ) + { + uno::Sequence< beans::PropertyValue > aPropValues{ + comphelper::makePropertyValue("CustomShape", xShape), + comphelper::makePropertyValue("ForceGroupWithText", true) + }; + uno::Sequence< uno::Any > aArgument = { uno::Any(aPropValues) }; + uno::Reference< uno::XInterface > xInterface( + xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aEngine, aArgument, xContext) ); + if ( xInterface.is() ) + { + uno::Reference< drawing::XCustomShapeEngine > xCustomShapeEngine( + uno::Reference< drawing::XCustomShapeEngine >( xInterface, uno::UNO_QUERY ) ); + if ( xCustomShapeEngine.is() ) + xCustomShapeReplacement = xCustomShapeEngine->render(); + } + } + } + } + } + return xCustomShapeReplacement; +} + +// This method collects all automatic styles for the given XShape +void XMLShapeExport::collectShapeAutoStyles(const uno::Reference< drawing::XShape >& xShape ) +{ + if( maCurrentShapesIter == maShapesInfos.end() ) + { + OSL_FAIL( "XMLShapeExport::collectShapeAutoStyles(): no call to seekShapes()!" ); + return; + } + sal_Int32 nZIndex = 0; + uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if( xPropSet.is() ) + xPropSet->getPropertyValue(gsZIndex) >>= nZIndex; + + ImplXMLShapeExportInfoVector& aShapeInfoVector = (*maCurrentShapesIter).second; + + if( static_cast<sal_Int32>(aShapeInfoVector.size()) <= nZIndex ) + { + OSL_FAIL( "XMLShapeExport::collectShapeAutoStyles(): no shape info allocated for a given shape" ); + return; + } + + ImplXMLShapeExportInfo& aShapeInfo = aShapeInfoVector[nZIndex]; + + uno::Reference< drawing::XShape > xCustomShapeReplacement = checkForCustomShapeReplacement( xShape ); + if ( xCustomShapeReplacement.is() ) + aShapeInfo.xCustomShapeReplacement = xCustomShapeReplacement; + + // first compute the shapes type + ImpCalcShapeType(xShape, aShapeInfo.meShapeType); + + // #i118485# enabled XmlShapeType::DrawChartShape and XmlShapeType::DrawOLE2Shape + // to have text + const bool bObjSupportsText = + supportsText(aShapeInfo.meShapeType); + + const bool bObjSupportsStyle = + aShapeInfo.meShapeType != XmlShapeType::DrawGroupShape; + + bool bIsEmptyPresObj = false; + + if ( aShapeInfo.xCustomShapeReplacement.is() ) + xPropSet.clear(); + + // prep text styles + if( xPropSet.is() && bObjSupportsText ) + { + uno::Reference< text::XText > xText(xShape, uno::UNO_QUERY); + if (xText.is()) + { + try + { + // tdf#153161: it seems that the call to XTextRange::getString flushes the changes + // for some objects, that otherwise fail to get exported correctly. Maybe at some + // point it would make sense to find a better place for more targeted flush. + xText->getString(); + } + catch (uno::RuntimeException const&) + { + // E.g., SwXTextFrame that contains only a table will throw; this is not an error + } + + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsEmptyPresentationObject") ) + { + uno::Any aAny = xPropSet->getPropertyValue("IsEmptyPresentationObject"); + aAny >>= bIsEmptyPresObj; + } + + if(!bIsEmptyPresObj) + { + GetExport().GetTextParagraphExport()->collectTextAutoStyles( xText ); + } + } + } + + // compute the shape parent style + if( xPropSet.is() ) + { + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( xPropSet->getPropertySetInfo() ); + + OUString aParentName; + uno::Reference< style::XStyle > xStyle; + + if( bObjSupportsStyle ) + { + if( xPropertySetInfo.is() && xPropertySetInfo->hasPropertyByName("Style") ) + xPropSet->getPropertyValue("Style") >>= xStyle; + + if(xStyle.is()) + { + // get family ID + uno::Reference< beans::XPropertySet > xStylePropSet(xStyle, uno::UNO_QUERY); + SAL_WARN_IF( !xStylePropSet.is(), "xmloff", "style without a XPropertySet?" ); + try + { + if(xStylePropSet.is()) + { + OUString aFamilyName; + xStylePropSet->getPropertyValue("Family") >>= aFamilyName; + if( !aFamilyName.isEmpty() && aFamilyName != "graphics" ) + aShapeInfo.mnFamily = XmlStyleFamily::SD_PRESENTATION_ID; + } + } + catch(const beans::UnknownPropertyException&) + { + // Ignored. + SAL_WARN( "xmloff", + "XMLShapeExport::collectShapeAutoStyles: style has no 'Family' property"); + } + + // get parent-style name + if(XmlStyleFamily::SD_PRESENTATION_ID == aShapeInfo.mnFamily) + { + aParentName = msPresentationStylePrefix; + } + + aParentName += xStyle->getName(); + } + } + + if (aParentName.isEmpty() && xPropertySetInfo->hasPropertyByName("TextBox") && xPropSet->getPropertyValue("TextBox").hasValue() && xPropSet->getPropertyValue("TextBox").get<bool>()) + { + // Shapes with a Writer TextBox always have a parent style. + // If there would be none, then assign the default one. + aParentName = "Frame"; + } + + // filter propset + std::vector< XMLPropertyState > aPropStates; + + sal_Int32 nCount = 0; + if( !bIsEmptyPresObj || (aShapeInfo.meShapeType != XmlShapeType::PresPageShape) ) + { + aPropStates = GetPropertySetMapper()->Filter(mrExport, xPropSet); + + if (XmlShapeType::DrawControlShape == aShapeInfo.meShapeType) + { + // for control shapes, we additionally need the number format style (if any) + uno::Reference< drawing::XControlShape > xControl(xShape, uno::UNO_QUERY); + DBG_ASSERT(xControl.is(), "XMLShapeExport::collectShapeAutoStyles: ShapeType control, but no XControlShape!"); + if (xControl.is()) + { + uno::Reference< beans::XPropertySet > xControlModel(xControl->getControl(), uno::UNO_QUERY); + DBG_ASSERT(xControlModel.is(), "XMLShapeExport::collectShapeAutoStyles: no control model on the control shape!"); + + OUString sNumberStyle = mrExport.GetFormExport()->getControlNumberStyle(xControlModel); + if (!sNumberStyle.isEmpty()) + { + sal_Int32 nIndex = GetPropertySetMapper()->getPropertySetMapper()->FindEntryIndex(CTF_SD_CONTROL_SHAPE_DATA_STYLE); + // TODO : this retrieval of the index could be moved into the ctor, holding the index + // as member, thus saving time. + DBG_ASSERT(-1 != nIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for our context id!"); + + XMLPropertyState aNewState(nIndex, uno::Any(sNumberStyle)); + aPropStates.push_back(aNewState); + } + } + } + + nCount = std::count_if(aPropStates.cbegin(), aPropStates.cend(), + [](const XMLPropertyState& rProp) { return rProp.mnIndex != -1; }); + } + + if(nCount == 0) + { + // no hard attributes, use parent style name for export + aShapeInfo.msStyleName = aParentName; + } + else + { + // there are filtered properties -> hard attributes + // try to find this style in AutoStylePool + aShapeInfo.msStyleName = mrExport.GetAutoStylePool()->Find(aShapeInfo.mnFamily, aParentName, aPropStates); + + if(aShapeInfo.msStyleName.isEmpty()) + { + // Style did not exist, add it to AutoStalePool + aShapeInfo.msStyleName = mrExport.GetAutoStylePool()->Add(aShapeInfo.mnFamily, aParentName, std::move(aPropStates)); + } + } + + // optionally generate auto style for text attributes + if( (!bIsEmptyPresObj || (aShapeInfo.meShapeType != XmlShapeType::PresPageShape)) && bObjSupportsText ) + { + aPropStates = GetExport().GetTextParagraphExport()->GetParagraphPropertyMapper()->Filter(mrExport, xPropSet); + + // yet more additionally, we need to care for the ParaAdjust property + if ( XmlShapeType::DrawControlShape == aShapeInfo.meShapeType ) + { + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + uno::Reference< beans::XPropertyState > xPropState( xPropSet, uno::UNO_QUERY ); + if ( xPropSetInfo.is() && xPropState.is() ) + { + // this is because: + // * if controls shapes have a ParaAdjust property, then this is the Align property of the control model + // * control models are allowed to have an Align of "void" + // * the Default for control model's Align is TextAlign_LEFT + // * defaults for style properties are not written, but we need to write the "left", + // because we need to distinguish this "left" from the case where not align attribute + // is present which means "void" + if ( xPropSetInfo->hasPropertyByName( "ParaAdjust" ) + && ( beans::PropertyState_DEFAULT_VALUE == xPropState->getPropertyState( "ParaAdjust" ) ) + ) + { + sal_Int32 nIndex = GetExport().GetTextParagraphExport()->GetParagraphPropertyMapper()->getPropertySetMapper()->FindEntryIndex( CTF_SD_SHAPE_PARA_ADJUST ); + // TODO : this retrieval of the index should be moved into the ctor, holding the index + // as member, thus saving time. + DBG_ASSERT(-1 != nIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for the ParaAdjust context id!"); + + uno::Any aParaAdjustValue = xPropSet->getPropertyValue( "ParaAdjust" ); + XMLPropertyState aAlignDefaultState( nIndex, aParaAdjustValue ); + + aPropStates.push_back( aAlignDefaultState ); + } + } + } + + nCount = std::count_if(aPropStates.cbegin(), aPropStates.cend(), + [](const XMLPropertyState& rProp) { return rProp.mnIndex != -1; }); + + if( nCount ) + { + aShapeInfo.msTextStyleName = mrExport.GetAutoStylePool()->Find( XmlStyleFamily::TEXT_PARAGRAPH, "", aPropStates ); + if(aShapeInfo.msTextStyleName.isEmpty()) + { + // Style did not exist, add it to AutoStalePool + aShapeInfo.msTextStyleName = mrExport.GetAutoStylePool()->Add(XmlStyleFamily::TEXT_PARAGRAPH, "", std::move(aPropStates)); + } + } + } + } + + // prepare animation information if needed + if( mxAnimationsExporter.is() ) + XMLAnimationsExporter::prepare( xShape ); + + // check for special shapes + + switch( aShapeInfo.meShapeType ) + { + case XmlShapeType::DrawConnectorShape: + { + uno::Reference< uno::XInterface > xConnection; + + // create shape ids for export later + xPropSet->getPropertyValue( gsStartShape ) >>= xConnection; + if( xConnection.is() ) + mrExport.getInterfaceToIdentifierMapper().registerReference( xConnection ); + + xPropSet->getPropertyValue( gsEndShape ) >>= xConnection; + if( xConnection.is() ) + mrExport.getInterfaceToIdentifierMapper().registerReference( xConnection ); + break; + } + case XmlShapeType::PresTableShape: + case XmlShapeType::DrawTableShape: + { + try + { + uno::Reference< table::XColumnRowRange > xRange( xPropSet->getPropertyValue( gsModel ), uno::UNO_QUERY_THROW ); + GetShapeTableExport()->collectTableAutoStyles( xRange ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "collecting auto styles for a table" ); + } + break; + } + default: + break; + } + + // check for shape collections (group shape or 3d scene) + // and collect contained shapes style infos + const uno::Reference< drawing::XShape >& xCollection = aShapeInfo.xCustomShapeReplacement.is() + ? aShapeInfo.xCustomShapeReplacement : xShape; + { + uno::Reference< drawing::XShapes > xShapes( xCollection, uno::UNO_QUERY ); + if( xShapes.is() ) + { + collectShapesAutoStyles( xShapes ); + } + } +} + +namespace +{ + class NewTextListsHelper + { + public: + explicit NewTextListsHelper( SvXMLExport& rExp ) + : mrExport( rExp ) + { + mrExport.GetTextParagraphExport()->PushNewTextListsHelper(); + } + + ~NewTextListsHelper() + { + mrExport.GetTextParagraphExport()->PopTextListsHelper(); + } + + private: + SvXMLExport& mrExport; + }; +} +// This method exports the given XShape +void XMLShapeExport::exportShape(const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, + css::awt::Point* pRefPoint /* = NULL */, + comphelper::AttributeList* pAttrList /* = NULL */ ) +{ + SAL_INFO("xmloff", xShape->getShapeType()); + if( maCurrentShapesIter == maShapesInfos.end() ) + { + SAL_WARN( "xmloff", "XMLShapeExport::exportShape(): no auto styles where collected before export" ); + return; + } + sal_Int32 nZIndex = 0; + uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY ); + OUString sHyperlink; + try + { + xSet->getPropertyValue(gsHyperlink) >>= sHyperlink; + } + catch (beans::UnknownPropertyException) + { + } + + std::unique_ptr< SvXMLElementExport > pHyperlinkElement; + + // Need to stash the attributes that are pre-loaded for the shape export + // (otherwise they will become attributes of the draw:a element) + uno::Reference<xml::sax::XAttributeList> xSaveAttribs( + new comphelper::AttributeList(GetExport().GetAttrList())); + GetExport().ClearAttrList(); + if( xSet.is() && (GetExport().GetModelType() == SvtModuleOptions::EFactory::DRAW) ) + { + // export hyperlinks with <a><shape/></a>. Currently only in draw since draw + // does not support document events + try + { + presentation::ClickAction eAction = presentation::ClickAction_NONE; + xSet->getPropertyValue(gsOnClick) >>= eAction; + + if( (eAction == presentation::ClickAction_DOCUMENT) || + (eAction == presentation::ClickAction_BOOKMARK) ) + { + OUString sURL; + xSet->getPropertyValue(gsBookmark) >>= sURL; + + if( !sURL.isEmpty() ) + { + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sURL ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + pHyperlinkElement.reset( new SvXMLElementExport(mrExport, XML_NAMESPACE_DRAW, XML_A, true, true) ); + } + } + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff", "XMLShapeExport::exportShape(): exception during hyperlink export"); + } + } + else if (xSet.is() && !sHyperlink.isEmpty()) + { + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sHyperlink ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + pHyperlinkElement.reset( new SvXMLElementExport(mrExport, XML_NAMESPACE_DRAW, XML_A, true, true) ); + } + // re-add stashed attributes + GetExport().AddAttributeList(xSaveAttribs); + + if( xSet.is() ) + xSet->getPropertyValue(gsZIndex) >>= nZIndex; + + ImplXMLShapeExportInfoVector& aShapeInfoVector = (*maCurrentShapesIter).second; + + if( static_cast<sal_Int32>(aShapeInfoVector.size()) <= nZIndex ) + { + SAL_WARN( "xmloff", "XMLShapeExport::exportShape(): no shape info collected for a given shape" ); + return; + } + + NewTextListsHelper aNewTextListsHelper( mrExport ); + + const ImplXMLShapeExportInfo& aShapeInfo = aShapeInfoVector[nZIndex]; + +#ifdef DBG_UTIL + // check if this is the correct ShapesInfo + uno::Reference< container::XChild > xChild( xShape, uno::UNO_QUERY ); + if( xChild.is() ) + { + uno::Reference< drawing::XShapes > xParent( xChild->getParent(), uno::UNO_QUERY ); + SAL_WARN_IF( !xParent.is() && xParent.get() == (*maCurrentShapesIter).first.get(), "xmloff", "XMLShapeExport::exportShape(): Wrong call to XMLShapeExport::seekShapes()" ); + } + + // first compute the shapes type + { + XmlShapeType eShapeType(XmlShapeType::NotYetSet); + ImpCalcShapeType(xShape, eShapeType); + + SAL_WARN_IF( eShapeType != aShapeInfo.meShapeType, "xmloff", "exportShape callings do not correspond to collectShapeAutoStyles calls!: " << xShape->getShapeType() ); + } +#endif + + // collect animation information if needed + if( mxAnimationsExporter.is() ) + mxAnimationsExporter->collect( xShape, mrExport ); + + /* Export shapes name if he has one (#i51726#) + Export of the shape name for text documents only if the OpenDocument + file format is written - exceptions are group shapes. + Note: Writer documents in OpenOffice.org file format doesn't contain + any names for shapes, except for group shapes. + */ + { + if ( ( GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITER && + GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITERWEB && + GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITERGLOBAL ) || + ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) || + aShapeInfo.meShapeType == XmlShapeType::DrawGroupShape || + ( aShapeInfo.meShapeType == XmlShapeType::DrawCustomShape && + aShapeInfo.xCustomShapeReplacement.is() ) ) + { + uno::Reference< container::XNamed > xNamed( xShape, uno::UNO_QUERY ); + if( xNamed.is() ) + { + const OUString aName( xNamed->getName() ); + if( !aName.isEmpty() ) + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_NAME, aName ); + } + } + } + + // export style name + if( !aShapeInfo.msStyleName.isEmpty() ) + { + if(XmlStyleFamily::SD_GRAPHICS_ID == aShapeInfo.mnFamily) + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, mrExport.EncodeStyleName( aShapeInfo.msStyleName) ); + else + mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_STYLE_NAME, mrExport.EncodeStyleName( aShapeInfo.msStyleName) ); + } + + // export text style name + if( !aShapeInfo.msTextStyleName.isEmpty() ) + { + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TEXT_STYLE_NAME, aShapeInfo.msTextStyleName ); + } + + // export shapes id if needed + { + uno::Reference< uno::XInterface > xRef( xShape, uno::UNO_QUERY ); + const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRef ); + if( !rShapeId.isEmpty() ) + { + mrExport.AddAttributeIdLegacy(XML_NAMESPACE_DRAW, rShapeId); + } + } + + // export layer information + if( mbExportLayer ) + { + // check for group or scene shape and not export layer if this is one + uno::Reference< drawing::XShapes > xShapes( xShape, uno::UNO_QUERY ); + if( !xShapes.is() ) + { + try + { + uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY ); + OUString aLayerName; + xProps->getPropertyValue("LayerName") >>= aLayerName; + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LAYER, aLayerName ); + + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "exporting layer name for shape" ); + } + } + } + + // export draw:display (do not export in ODF 1.3 or older) + if (xSet.is() && (mrExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)) + { + if( aShapeInfo.meShapeType != XmlShapeType::DrawPageShape && aShapeInfo.meShapeType != XmlShapeType::PresPageShape && + aShapeInfo.meShapeType != XmlShapeType::HandoutShape && aShapeInfo.meShapeType != XmlShapeType::DrawChartShape ) + try + { + bool bVisible = true; + bool bPrintable = true; + + xSet->getPropertyValue(gsVisible) >>= bVisible; + xSet->getPropertyValue(gsPrintable) >>= bPrintable; + + XMLTokenEnum eDisplayToken = XML_TOKEN_INVALID; + const unsigned short nDisplay = (bVisible ? 2 : 0) | (bPrintable ? 1 : 0); + switch( nDisplay ) + { + case 0: eDisplayToken = XML_NONE; break; + case 1: eDisplayToken = XML_PRINTER; break; + case 2: eDisplayToken = XML_SCREEN; break; + // case 3: eDisplayToken = XML_ALWAYS break; this is the default + } + + if( eDisplayToken != XML_TOKEN_INVALID ) + mrExport.AddAttribute(XML_NAMESPACE_DRAW_EXT, XML_DISPLAY, eDisplayToken ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.draw"); + } + } + + // #82003# test export count + // #91587# ALWAYS increment since now ALL to be exported shapes are counted. + if(mrExport.GetShapeExport()->IsHandleProgressBarEnabled()) + { + mrExport.GetProgressBarHelper()->Increment(); + } + + onExport( xShape ); + + // export shape element + switch(aShapeInfo.meShapeType) + { + case XmlShapeType::DrawRectangleShape: + { + ImpExportRectangleShape(xShape, nFeatures, pRefPoint ); + break; + } + case XmlShapeType::DrawEllipseShape: + { + ImpExportEllipseShape(xShape, nFeatures, pRefPoint ); + break; + } + case XmlShapeType::DrawLineShape: + { + ImpExportLineShape(xShape, nFeatures, pRefPoint ); + break; + } + case XmlShapeType::DrawPolyPolygonShape: // closed PolyPolygon + case XmlShapeType::DrawPolyLineShape: // open PolyPolygon + case XmlShapeType::DrawClosedBezierShape: // closed tools::PolyPolygon containing curves + case XmlShapeType::DrawOpenBezierShape: // open tools::PolyPolygon containing curves + { + ImpExportPolygonShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::DrawTextShape: + case XmlShapeType::PresTitleTextShape: + case XmlShapeType::PresOutlinerShape: + case XmlShapeType::PresSubtitleShape: + case XmlShapeType::PresNotesShape: + case XmlShapeType::PresHeaderShape: + case XmlShapeType::PresFooterShape: + case XmlShapeType::PresSlideNumberShape: + case XmlShapeType::PresDateTimeShape: + { + ImpExportTextBoxShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::DrawGraphicObjectShape: + case XmlShapeType::PresGraphicObjectShape: + { + ImpExportGraphicObjectShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::DrawChartShape: + case XmlShapeType::PresChartShape: + { + ImpExportChartShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint, pAttrList ); + break; + } + + case XmlShapeType::DrawControlShape: + { + ImpExportControlShape(xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::DrawConnectorShape: + { + ImpExportConnectorShape(xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::DrawMeasureShape: + { + ImpExportMeasureShape(xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::DrawOLE2Shape: + case XmlShapeType::PresOLE2Shape: + case XmlShapeType::DrawSheetShape: + case XmlShapeType::PresSheetShape: + { + ImpExportOLE2Shape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::PresTableShape: + case XmlShapeType::DrawTableShape: + { + ImpExportTableShape( xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::DrawPageShape: + case XmlShapeType::PresPageShape: + case XmlShapeType::HandoutShape: + { + ImpExportPageShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::DrawCaptionShape: + { + ImpExportCaptionShape(xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::Draw3DCubeObject: + case XmlShapeType::Draw3DSphereObject: + case XmlShapeType::Draw3DLatheObject: + case XmlShapeType::Draw3DExtrudeObject: + { + ImpExport3DShape(xShape, aShapeInfo.meShapeType); + break; + } + + case XmlShapeType::Draw3DSceneObject: + { + ImpExport3DSceneShape( xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::DrawGroupShape: + { + // empty group + ImpExportGroupShape( xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::DrawFrameShape: + { + ImpExportFrameShape(xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::DrawAppletShape: + { + ImpExportAppletShape(xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::DrawPluginShape: + { + ImpExportPluginShape(xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::DrawCustomShape: + { + if ( aShapeInfo.xCustomShapeReplacement.is() ) + ImpExportGroupShape( aShapeInfo.xCustomShapeReplacement, nFeatures, pRefPoint ); + else + ImpExportCustomShape( xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::PresMediaShape: + case XmlShapeType::DrawMediaShape: + { + ImpExportMediaShape( xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + break; + } + + case XmlShapeType::PresOrgChartShape: + case XmlShapeType::Unknown: + case XmlShapeType::NotYetSet: + default: + { + // this should never happen and is an error + OSL_FAIL("XMLEXP: WriteShape: unknown or unexpected type of shape in export!"); + break; + } + } + + pHyperlinkElement.reset(); + + // #97489# #97111# + // if there was an error and no element for the shape was exported + // we need to clear the attribute list or the attributes will be + // set on the next exported element, which can result in corrupt + // xml files due to duplicate attributes + + mrExport.CheckAttrList(); // asserts in non pro if we have attributes left + mrExport.ClearAttrList(); // clears the attributes +} + +// This method collects all automatic styles for the shapes inside the given XShapes collection +void XMLShapeExport::collectShapesAutoStyles( const uno::Reference < drawing::XShapes >& xShapes ) +{ + ShapesInfos::iterator aOldCurrentShapesIter = maCurrentShapesIter; + seekShapes( xShapes ); + + uno::Reference< drawing::XShape > xShape; + const sal_Int32 nShapeCount(xShapes->getCount()); + for(sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++) + { + xShapes->getByIndex(nShapeId) >>= xShape; + SAL_WARN_IF( !xShape.is(), "xmloff", "Shape without a XShape?" ); + if(!xShape.is()) + continue; + + collectShapeAutoStyles( xShape ); + } + + maCurrentShapesIter = aOldCurrentShapesIter; +} + +// This method exports all XShape inside the given XShapes collection +void XMLShapeExport::exportShapes( const uno::Reference < drawing::XShapes >& xShapes, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */ ) +{ + ShapesInfos::iterator aOldCurrentShapesIter = maCurrentShapesIter; + seekShapes( xShapes ); + + uno::Reference< drawing::XShape > xShape; + const sal_Int32 nShapeCount(xShapes->getCount()); + for(sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++) + { + xShapes->getByIndex(nShapeId) >>= xShape; + SAL_WARN_IF( !xShape.is(), "xmloff", "Shape without a XShape?" ); + if(!xShape.is()) + continue; + + exportShape( xShape, nFeatures, pRefPoint ); + } + + maCurrentShapesIter = aOldCurrentShapesIter; +} + +namespace xmloff { + +void FixZOrder(uno::Reference<drawing::XShapes> const& xShapes, + std::function<unsigned int (uno::Reference<beans::XPropertySet> const&)> const& rGetLayer) +{ + uno::Reference<drawing::XShapes3> const xShapes3(xShapes, uno::UNO_QUERY); + assert(xShapes3.is()); + if (!xShapes3.is()) + { + return; // only SvxDrawPage implements this + } + struct Layer { std::vector<sal_Int32> shapes; sal_Int32 nMin = SAL_MAX_INT32; sal_Int32 nMax = 0; }; + std::vector<Layer> layers; + // shapes are sorted by ZOrder + sal_Int32 const nCount(xShapes->getCount()); + for (sal_Int32 i = 0; i < nCount; ++i) + { + uno::Reference<beans::XPropertySet> const xShape(xShapes->getByIndex(i), uno::UNO_QUERY); + if (!xShape.is()) + { + SAL_WARN("xmloff", "FixZOrder: null shape, cannot sort"); + return; + } + unsigned int const nLayer(rGetLayer(xShape)); + if (layers.size() <= nLayer) + { + layers.resize(nLayer + 1); + } + layers[nLayer].shapes.emplace_back(i); + if (i < layers[nLayer].nMin) + { + layers[nLayer].nMin = i; + } + if (layers[nLayer].nMax < i) + { + layers[nLayer].nMax = i; + } + } + std::erase_if(layers, [](Layer const& rLayer) { return rLayer.shapes.empty(); }); + bool isSorted(true); + for (size_t i = 1; i < layers.size(); ++i) + { + assert(layers[i].nMin != layers[i-1].nMax); // unique! + if (layers[i].nMin < layers[i-1].nMax) + { + isSorted = false; + break; + } + } + if (isSorted) + { + return; // nothing to do + } + uno::Sequence<sal_Int32> aNewOrder(nCount); + auto iterInsert(aNewOrder.getArray()); + for (auto const& rLayer : layers) + { + assert(rLayer.nMin <= rLayer.nMax); // empty layers have been removed + iterInsert = std::copy(rLayer.shapes.begin(), rLayer.shapes.end(), iterInsert); + } + try + { + xShapes3->sort(aNewOrder); + } + catch (uno::Exception const&) + { + SAL_WARN("xmloff", "FixZOrder: exception"); + } +} + +} // namespace xmloff + +void XMLShapeExport::seekShapes( const uno::Reference< drawing::XShapes >& xShapes ) noexcept +{ + if( xShapes.is() ) + { + maCurrentShapesIter = maShapesInfos.find( xShapes ); + if( maCurrentShapesIter == maShapesInfos.end() ) + { + auto itPair = maShapesInfos.emplace( xShapes, ImplXMLShapeExportInfoVector( static_cast<ShapesInfos::size_type>(xShapes->getCount()) ) ); + + maCurrentShapesIter = itPair.first; + + SAL_WARN_IF( maCurrentShapesIter == maShapesInfos.end(), "xmloff", "XMLShapeExport::seekShapes(): insert into stl::map failed" ); + } + + SAL_WARN_IF( (*maCurrentShapesIter).second.size() != static_cast<ShapesInfos::size_type>(xShapes->getCount()), "xmloff", "XMLShapeExport::seekShapes(): XShapes size varied between calls" ); + + } + else + { + maCurrentShapesIter = maShapesInfos.end(); + } +} + +void XMLShapeExport::exportAutoStyles() +{ + // export all autostyle infos + + // ...for graphic + { + GetExport().GetAutoStylePool()->exportXML( XmlStyleFamily::SD_GRAPHICS_ID ); + } + + // ...for presentation + { + GetExport().GetAutoStylePool()->exportXML( XmlStyleFamily::SD_PRESENTATION_ID ); + } + + if( mxShapeTableExport.is() ) + mxShapeTableExport->exportAutoStyles(); +} + +/// returns the export property mapper for external chaining +SvXMLExportPropertyMapper* XMLShapeExport::CreateShapePropMapper( + SvXMLExport& rExport ) +{ + rtl::Reference< XMLPropertyHandlerFactory > xFactory = new XMLSdPropHdlFactory( rExport.GetModel(), rExport ); + rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory, true ); + rExport.GetTextParagraphExport(); // get or create text paragraph export + SvXMLExportPropertyMapper* pResult = + new XMLShapeExportPropertyMapper( xMapper, rExport ); + // chain text attributes + return pResult; +} + +void XMLShapeExport::ImpCalcShapeType(const uno::Reference< drawing::XShape >& xShape, + XmlShapeType& eShapeType) +{ + // set in every case, so init here + eShapeType = XmlShapeType::Unknown; + + if(!xShape.is()) + return; + + OUString aType(xShape->getShapeType()); + + if(!aType.match("com.sun.star.")) + return; + + if(aType.match("drawing.", 13)) + { + // drawing shapes + if (aType.match("Rectangle", 21)) { eShapeType = XmlShapeType::DrawRectangleShape; } + + // #i72177# Note: Correcting CustomShape, CustomShape->Custom, len from 9 (was wrong anyways) to 6. + // As can be seen at the other compares, the appendix "Shape" is left out of the comparison. + else if(aType.match("Custom", 21)) { eShapeType = XmlShapeType::DrawCustomShape; } + + else if(aType.match("Ellipse", 21)) { eShapeType = XmlShapeType::DrawEllipseShape; } + else if(aType.match("Control", 21)) { eShapeType = XmlShapeType::DrawControlShape; } + else if(aType.match("Connector", 21)) { eShapeType = XmlShapeType::DrawConnectorShape; } + else if(aType.match("Measure", 21)) { eShapeType = XmlShapeType::DrawMeasureShape; } + else if(aType.match("Line", 21)) { eShapeType = XmlShapeType::DrawLineShape; } + + // #i72177# Note: This covers two types by purpose, PolyPolygonShape and PolyPolygonPathShape + else if(aType.match("PolyPolygon", 21)) { eShapeType = XmlShapeType::DrawPolyPolygonShape; } + + // #i72177# Note: This covers two types by purpose, PolyLineShape and PolyLinePathShape + else if(aType.match("PolyLine", 21)) { eShapeType = XmlShapeType::DrawPolyLineShape; } + + else if(aType.match("OpenBezier", 21)) { eShapeType = XmlShapeType::DrawOpenBezierShape; } + else if(aType.match("ClosedBezier", 21)) { eShapeType = XmlShapeType::DrawClosedBezierShape; } + + // #i72177# FreeHand (opened and closed) now supports the types OpenFreeHandShape and + // ClosedFreeHandShape respectively. Represent them as bezier shapes + else if(aType.match("OpenFreeHand", 21)) { eShapeType = XmlShapeType::DrawOpenBezierShape; } + else if(aType.match("ClosedFreeHand", 21)) { eShapeType = XmlShapeType::DrawClosedBezierShape; } + + else if(aType.match("GraphicObject", 21)) { eShapeType = XmlShapeType::DrawGraphicObjectShape; } + else if(aType.match("Group", 21)) { eShapeType = XmlShapeType::DrawGroupShape; } + else if(aType.match("Text", 21)) { eShapeType = XmlShapeType::DrawTextShape; } + else if(aType.match("OLE2", 21)) + { + eShapeType = XmlShapeType::DrawOLE2Shape; + + // get info about presentation shape + uno::Reference <beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY); + + if(xPropSet.is()) + { + OUString sCLSID; + if(xPropSet->getPropertyValue("CLSID") >>= sCLSID) + { +#if !ENABLE_WASM_STRIP_CHART + // WASM_CHART change + // TODO: With Chart extracted this cannot really happen since + // no Chart could've been added at all + if (sCLSID == mrExport.GetChartExport()->getChartCLSID() || +#else + if( +#endif + sCLSID == SvGlobalName( SO3_RPTCH_CLASSID ).GetHexName() ) + { + eShapeType = XmlShapeType::DrawChartShape; + } + else if (sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() ) + { + eShapeType = XmlShapeType::DrawSheetShape; + } + else + { + // general OLE2 Object + } + } + } + } + else if(aType.match("Page", 21)) { eShapeType = XmlShapeType::DrawPageShape; } + else if(aType.match("Frame", 21)) { eShapeType = XmlShapeType::DrawFrameShape; } + else if(aType.match("Caption", 21)) { eShapeType = XmlShapeType::DrawCaptionShape; } + else if(aType.match("Plugin", 21)) { eShapeType = XmlShapeType::DrawPluginShape; } + else if(aType.match("Applet", 21)) { eShapeType = XmlShapeType::DrawAppletShape; } + else if(aType.match("MediaShape", 21)) { eShapeType = XmlShapeType::DrawMediaShape; } + else if(aType.match("TableShape", 21)) { eShapeType = XmlShapeType::DrawTableShape; } + + // 3D shapes + else if(aType.match("Scene", 21 + 7)) { eShapeType = XmlShapeType::Draw3DSceneObject; } + else if(aType.match("Cube", 21 + 7)) { eShapeType = XmlShapeType::Draw3DCubeObject; } + else if(aType.match("Sphere", 21 + 7)) { eShapeType = XmlShapeType::Draw3DSphereObject; } + else if(aType.match("Lathe", 21 + 7)) { eShapeType = XmlShapeType::Draw3DLatheObject; } + else if(aType.match("Extrude", 21 + 7)) { eShapeType = XmlShapeType::Draw3DExtrudeObject; } + } + else if(aType.match("presentation.", 13)) + { + // presentation shapes + if (aType.match("TitleText", 26)) { eShapeType = XmlShapeType::PresTitleTextShape; } + else if(aType.match("Outliner", 26)) { eShapeType = XmlShapeType::PresOutlinerShape; } + else if(aType.match("Subtitle", 26)) { eShapeType = XmlShapeType::PresSubtitleShape; } + else if(aType.match("GraphicObject", 26)) { eShapeType = XmlShapeType::PresGraphicObjectShape; } + else if(aType.match("Page", 26)) { eShapeType = XmlShapeType::PresPageShape; } + else if(aType.match("OLE2", 26)) + { + eShapeType = XmlShapeType::PresOLE2Shape; + + // get info about presentation shape + uno::Reference <beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY); + + if(xPropSet.is()) try + { + OUString sCLSID; + if(xPropSet->getPropertyValue("CLSID") >>= sCLSID) + { + if( sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() ) + { + eShapeType = XmlShapeType::PresSheetShape; + } + } + } + catch(const uno::Exception&) + { + SAL_WARN( "xmloff", "XMLShapeExport::ImpCalcShapeType(), expected ole shape to have the CLSID property?" ); + } + } + else if(aType.match("Chart", 26)) { eShapeType = XmlShapeType::PresChartShape; } + else if(aType.match("OrgChart", 26)) { eShapeType = XmlShapeType::PresOrgChartShape; } + else if(aType.match("CalcShape", 26)) { eShapeType = XmlShapeType::PresSheetShape; } + else if(aType.match("TableShape", 26)) { eShapeType = XmlShapeType::PresTableShape; } + else if(aType.match("Notes", 26)) { eShapeType = XmlShapeType::PresNotesShape; } + else if(aType.match("HandoutShape", 26)) { eShapeType = XmlShapeType::HandoutShape; } + else if(aType.match("HeaderShape", 26)) { eShapeType = XmlShapeType::PresHeaderShape; } + else if(aType.match("FooterShape", 26)) { eShapeType = XmlShapeType::PresFooterShape; } + else if(aType.match("SlideNumberShape", 26)) { eShapeType = XmlShapeType::PresSlideNumberShape; } + else if(aType.match("DateTimeShape", 26)) { eShapeType = XmlShapeType::PresDateTimeShape; } + else if(aType.match("MediaShape", 26)) { eShapeType = XmlShapeType::PresMediaShape; } + } +} + +/** exports all user defined gluepoints */ +void XMLShapeExport::ImpExportGluePoints( const uno::Reference< drawing::XShape >& xShape ) +{ + uno::Reference< drawing::XGluePointsSupplier > xSupplier( xShape, uno::UNO_QUERY ); + if( !xSupplier.is() ) + return; + + uno::Reference< container::XIdentifierAccess > xGluePoints( xSupplier->getGluePoints(), uno::UNO_QUERY ); + if( !xGluePoints.is() ) + return; + + drawing::GluePoint2 aGluePoint; + + const uno::Sequence< sal_Int32 > aIdSequence( xGluePoints->getIdentifiers() ); + + for( const sal_Int32 nIdentifier : aIdSequence ) + { + if( (xGluePoints->getByIdentifier( nIdentifier ) >>= aGluePoint) && aGluePoint.IsUserDefined ) + { + // export only user defined gluepoints + + const OUString sId( OUString::number( nIdentifier ) ); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_ID, sId ); + + mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer, + aGluePoint.Position.X); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, msBuffer.makeStringAndClear()); + + mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer, + aGluePoint.Position.Y); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, msBuffer.makeStringAndClear()); + + if( !aGluePoint.IsRelative ) + { + SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.PositionAlignment, aXML_GlueAlignment_EnumMap ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ALIGN, msBuffer.makeStringAndClear() ); + } + + if( aGluePoint.Escape != drawing::EscapeDirection_SMART ) + { + SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.Escape, aXML_GlueEscapeDirection_EnumMap ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ESCAPE_DIRECTION, msBuffer.makeStringAndClear() ); + } + + SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_DRAW, XML_GLUE_POINT, true, true); + } + } +} + +void XMLShapeExport::ImpExportSignatureLine(const uno::Reference<drawing::XShape>& xShape) +{ + uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY); + + bool bIsSignatureLine = false; + xPropSet->getPropertyValue("IsSignatureLine") >>= bIsSignatureLine; + if (!bIsSignatureLine) + return; + + OUString aSignatureLineId; + xPropSet->getPropertyValue("SignatureLineId") >>= aSignatureLineId; + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_ID, aSignatureLineId); + + OUString aSuggestedSignerName; + xPropSet->getPropertyValue("SignatureLineSuggestedSignerName") >>= aSuggestedSignerName; + if (!aSuggestedSignerName.isEmpty()) + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_NAME, aSuggestedSignerName); + + OUString aSuggestedSignerTitle; + xPropSet->getPropertyValue("SignatureLineSuggestedSignerTitle") >>= aSuggestedSignerTitle; + if (!aSuggestedSignerTitle.isEmpty()) + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_TITLE, aSuggestedSignerTitle); + + OUString aSuggestedSignerEmail; + xPropSet->getPropertyValue("SignatureLineSuggestedSignerEmail") >>= aSuggestedSignerEmail; + if (!aSuggestedSignerEmail.isEmpty()) + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_EMAIL, aSuggestedSignerEmail); + + OUString aSigningInstructions; + xPropSet->getPropertyValue("SignatureLineSigningInstructions") >>= aSigningInstructions; + if (!aSigningInstructions.isEmpty()) + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SIGNING_INSTRUCTIONS, aSigningInstructions); + + bool bShowSignDate = false; + xPropSet->getPropertyValue("SignatureLineShowSignDate") >>= bShowSignDate; + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SHOW_SIGN_DATE, + bShowSignDate ? XML_TRUE : XML_FALSE); + + bool bCanAddComment = false; + xPropSet->getPropertyValue("SignatureLineCanAddComment") >>= bCanAddComment; + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CAN_ADD_COMMENT, + bCanAddComment ? XML_TRUE : XML_FALSE); + + SvXMLElementExport aSignatureLineElement(mrExport, XML_NAMESPACE_LO_EXT, XML_SIGNATURELINE, true, + true); +} + +void XMLShapeExport::ImpExportQRCode(const uno::Reference<drawing::XShape>& xShape) +{ + uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY); + + uno::Any aAny = xPropSet->getPropertyValue("BarCodeProperties"); + + css::drawing::BarCode aBarCode; + if(!(aAny >>= aBarCode)) + return; + + mrExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_STRING_VALUE, aBarCode.Payload); + /* Export QR Code as per customised schema, @see OpenDocument-schema-v1.3+libreoffice */ + OUString temp; + switch(aBarCode.ErrorCorrection){ + case css::drawing::BarCodeErrorCorrection::LOW : + temp = "low"; + break; + case css::drawing::BarCodeErrorCorrection::MEDIUM: + temp = "medium"; + break; + case css::drawing::BarCodeErrorCorrection::QUARTILE: + temp = "quartile"; + break; + case css::drawing::BarCodeErrorCorrection::HIGH: + temp = "high"; + break; + } + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_ERROR_CORRECTION, temp); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_BORDER, OUStringBuffer(20).append(aBarCode.Border).makeStringAndClear()); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_TYPE, OUStringBuffer(20).append(aBarCode.Type).makeStringAndClear()); + + SvXMLElementExport aBarCodeElement(mrExport, XML_NAMESPACE_LO_EXT, XML_QRCODE, true, + true); +} + +void XMLShapeExport::ExportGraphicDefaults() +{ + rtl::Reference<XMLStyleExport> aStEx(new XMLStyleExport(mrExport, mrExport.GetAutoStylePool().get())); + + // construct PropertySetMapper + rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( CreateShapePropMapper( mrExport ) ); + static_cast<XMLShapeExportPropertyMapper*>(xPropertySetMapper.get())->SetAutoStyles( false ); + + // chain text attributes + xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(mrExport)); + + // chain special Writer/text frame default attributes + xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaDefaultExtPropMapper(mrExport)); + + // write graphic family default style + uno::Reference< lang::XMultiServiceFactory > xFact( mrExport.GetModel(), uno::UNO_QUERY ); + if( !xFact.is() ) + return; + + try + { + uno::Reference< beans::XPropertySet > xDefaults( xFact->createInstance("com.sun.star.drawing.Defaults"), uno::UNO_QUERY ); + if( xDefaults.is() ) + { + aStEx->exportDefaultStyle( xDefaults, XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper ); + + // write graphic styles (family name differs depending on the module) + aStEx->exportStyleFamily("graphics", XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper, false, XmlStyleFamily::SD_GRAPHICS_ID); + aStEx->exportStyleFamily("GraphicStyles", XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper, false, XmlStyleFamily::SD_GRAPHICS_ID); + } + } + catch(const lang::ServiceNotRegisteredException&) + { + } +} + +void XMLShapeExport::onExport( const css::uno::Reference < css::drawing::XShape >& ) +{ +} + +const rtl::Reference< XMLTableExport >& XMLShapeExport::GetShapeTableExport() +{ + if( !mxShapeTableExport.is() ) + { + rtl::Reference< XMLPropertyHandlerFactory > xFactory( new XMLSdPropHdlFactory( mrExport.GetModel(), mrExport ) ); + rtl::Reference < XMLPropertySetMapper > xMapper( new XMLShapePropertySetMapper( xFactory, true ) ); + mrExport.GetTextParagraphExport(); // get or create text paragraph export + rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( new XMLShapeExportPropertyMapper( xMapper, mrExport ) ); + mxShapeTableExport = new XMLTableExport( mrExport, xPropertySetMapper, xFactory ); + } + + return mxShapeTableExport; +} + +void XMLShapeExport::ImpExportNewTrans(const uno::Reference< beans::XPropertySet >& xPropSet, + XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + // get matrix + ::basegfx::B2DHomMatrix aMatrix; + ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet); + + // decompose and correct about pRefPoint + ::basegfx::B2DTuple aTRScale; + double fTRShear(0.0); + double fTRRotate(0.0); + ::basegfx::B2DTuple aTRTranslate; + ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint); + + // use features and write + ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures); +} + +void XMLShapeExport::ImpExportNewTrans_GetB2DHomMatrix(::basegfx::B2DHomMatrix& rMatrix, + const uno::Reference< beans::XPropertySet >& xPropSet) +{ + /* Get <TransformationInHoriL2R>, if it exist + and if the document is exported into the OpenOffice.org file format. + This property only exists at service css::text::Shape - the + Writer UNO service for shapes. + This code is needed, because the positioning attributes in the + OpenOffice.org file format are given in horizontal left-to-right layout + regardless the layout direction the shape is in. In the OASIS Open Office + file format the positioning attributes are correctly given in the layout + direction the shape is in. Thus, this code provides the conversion from + the OASIS Open Office file format to the OpenOffice.org file format. (#i28749#) + */ + uno::Any aAny; + if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) && + xPropSet->getPropertySetInfo()->hasPropertyByName("TransformationInHoriL2R") ) + { + aAny = xPropSet->getPropertyValue("TransformationInHoriL2R"); + } + else + { + aAny = xPropSet->getPropertyValue("Transformation"); + } + drawing::HomogenMatrix3 aMatrix; + aAny >>= aMatrix; + + rMatrix.set(0, 0, aMatrix.Line1.Column1); + rMatrix.set(0, 1, aMatrix.Line1.Column2); + rMatrix.set(0, 2, aMatrix.Line1.Column3); + rMatrix.set(1, 0, aMatrix.Line2.Column1); + rMatrix.set(1, 1, aMatrix.Line2.Column2); + rMatrix.set(1, 2, aMatrix.Line2.Column3); + // For this to be a valid 2D transform matrix, the last row must be [0,0,1] + assert( aMatrix.Line3.Column1 == 0 ); + assert( aMatrix.Line3.Column2 == 0 ); + assert( aMatrix.Line3.Column3 == 1 ); +} + +void XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint(const ::basegfx::B2DHomMatrix& rMatrix, ::basegfx::B2DTuple& rTRScale, + double& fTRShear, double& fTRRotate, ::basegfx::B2DTuple& rTRTranslate, css::awt::Point* pRefPoint) +{ + // decompose matrix + rMatrix.decompose(rTRScale, rTRTranslate, fTRRotate, fTRShear); + + // correct translation about pRefPoint + if(pRefPoint) + { + rTRTranslate -= ::basegfx::B2DTuple(pRefPoint->X, pRefPoint->Y); + } +} + +void XMLShapeExport::ImpExportNewTrans_FeaturesAndWrite(::basegfx::B2DTuple const & rTRScale, double fTRShear, + double fTRRotate, ::basegfx::B2DTuple const & rTRTranslate, const XMLShapeExportFlags nFeatures) +{ + // always write Size (rTRScale) since this statement carries the union + // of the object + OUString aStr; + OUStringBuffer sStringBuffer; + ::basegfx::B2DTuple aTRScale(rTRScale); + + // svg: width + if(!(nFeatures & XMLShapeExportFlags::WIDTH)) + { + aTRScale.setX(1.0); + } + else + { + if( aTRScale.getX() > 0.0 ) + aTRScale.setX(aTRScale.getX() - 1.0); + else if( aTRScale.getX() < 0.0 ) + aTRScale.setX(aTRScale.getX() + 1.0); + } + + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + FRound(aTRScale.getX())); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStr); + + // svg: height + if(!(nFeatures & XMLShapeExportFlags::HEIGHT)) + { + aTRScale.setY(1.0); + } + else + { + if( aTRScale.getY() > 0.0 ) + aTRScale.setY(aTRScale.getY() - 1.0); + else if( aTRScale.getY() < 0.0 ) + aTRScale.setY(aTRScale.getY() + 1.0); + } + + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + FRound(aTRScale.getY())); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStr); + + // decide if transformation is necessary + bool bTransformationIsNecessary(fTRShear != 0.0 || fTRRotate != 0.0); + + if(bTransformationIsNecessary) + { + // write transformation, but WITHOUT scale which is exported as size above + SdXMLImExTransform2D aTransform; + + aTransform.AddSkewX(atan(fTRShear)); + + // #i78696# + // fTRRotate is mathematically correct, but due to the error + // we export/import it mirrored. Since the API implementation is fixed and + // uses the correctly oriented angle, it is necessary for compatibility to + // mirror the angle here to stay at the old behaviour. There is a follow-up + // task (#i78698#) to fix this in the next ODF FileFormat version + aTransform.AddRotate(-fTRRotate); + + aTransform.AddTranslate(rTRTranslate); + + // does transformation need to be exported? + if(aTransform.NeedsAction()) + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter())); + } + else + { + // no shear, no rotate; just add object position to export and we are done + if(nFeatures & XMLShapeExportFlags::X) + { + // svg: x + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + FRound(rTRTranslate.getX())); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, aStr); + } + + if(nFeatures & XMLShapeExportFlags::Y) + { + // svg: y + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + FRound(rTRTranslate.getY())); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, aStr); + } + } +} + +bool XMLShapeExport::ImpExportPresentationAttributes( const uno::Reference< beans::XPropertySet >& xPropSet, const OUString& rClass ) +{ + bool bIsEmpty = false; + + // write presentation class entry + mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS, rClass); + + if( xPropSet.is() ) + { + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + + + // is empty pres. shape? + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsEmptyPresentationObject")) + { + xPropSet->getPropertyValue("IsEmptyPresentationObject") >>= bIsEmpty; + if( bIsEmpty ) + mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PLACEHOLDER, XML_TRUE); + } + + // is user-transformed? + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsPlaceholderDependent")) + { + bool bTemp = false; + xPropSet->getPropertyValue("IsPlaceholderDependent") >>= bTemp; + if(!bTemp) + mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_USER_TRANSFORMED, XML_TRUE); + } + } + + return bIsEmpty; +} + +void XMLShapeExport::ImpExportText( const uno::Reference< drawing::XShape >& xShape, TextPNS eExtensionNS ) +{ + if (eExtensionNS == TextPNS::EXTENSION) + { + if ((mrExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + { + return; // do not export to ODF 1.1/1.2/1.3 + } + } + uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY ); + if( xText.is() ) + { + uno::Reference< container::XEnumerationAccess > xEnumAccess( xShape, uno::UNO_QUERY ); + if( xEnumAccess.is() && xEnumAccess->hasElements() ) + mrExport.GetTextParagraphExport()->exportText( xText, false, true, eExtensionNS ); + } +} + +namespace { + +enum class Found { + NONE = 0x0000, + CLICKACTION = 0x0001, + BOOKMARK = 0x0002, + EFFECT = 0x0004, + PLAYFULL = 0x0008, + VERB = 0x0010, + SOUNDURL = 0x0020, + SPEED = 0x0040, + CLICKEVENTTYPE = 0x0080, + MACRO = 0x0100, + LIBRARY = 0x0200, +}; + +} + +namespace o3tl { + template<> struct typed_flags<Found> : is_typed_flags<Found, 0x03ff> {}; +} + +void XMLShapeExport::ImpExportEvents( const uno::Reference< drawing::XShape >& xShape ) +{ + uno::Reference< document::XEventsSupplier > xEventsSupplier( xShape, uno::UNO_QUERY ); + if( !xEventsSupplier.is() ) + return; + + uno::Reference< container::XNameAccess > xEvents = xEventsSupplier->getEvents(); + SAL_WARN_IF( !xEvents.is(), "xmloff", "XEventsSupplier::getEvents() returned NULL" ); + if( !xEvents.is() ) + return; + + Found nFound = Found::NONE; + + OUString aClickEventType; + presentation::ClickAction eClickAction = presentation::ClickAction_NONE; + presentation::AnimationEffect eEffect = presentation::AnimationEffect_NONE; + presentation::AnimationSpeed eSpeed = presentation::AnimationSpeed_SLOW; + OUString aStrSoundURL; + bool bPlayFull = false; + sal_Int32 nVerb = 0; + OUString aStrMacro; + OUString aStrLibrary; + OUString aStrBookmark; + + uno::Sequence< beans::PropertyValue > aClickProperties; + if( xEvents->hasByName( gsOnClick ) && (xEvents->getByName( gsOnClick ) >>= aClickProperties) ) + { + for( const auto& rProperty : std::as_const(aClickProperties) ) + { + if( !( nFound & Found::CLICKEVENTTYPE ) && rProperty.Name == gsEventType ) + { + if( rProperty.Value >>= aClickEventType ) + nFound |= Found::CLICKEVENTTYPE; + } + else if( !( nFound & Found::CLICKACTION ) && rProperty.Name == gsClickAction ) + { + if( rProperty.Value >>= eClickAction ) + nFound |= Found::CLICKACTION; + } + else if( !( nFound & Found::MACRO ) && ( rProperty.Name == gsMacroName || rProperty.Name == gsScript ) ) + { + if( rProperty.Value >>= aStrMacro ) + nFound |= Found::MACRO; + } + else if( !( nFound & Found::LIBRARY ) && rProperty.Name == gsLibrary ) + { + if( rProperty.Value >>= aStrLibrary ) + nFound |= Found::LIBRARY; + } + else if( !( nFound & Found::EFFECT ) && rProperty.Name == gsEffect ) + { + if( rProperty.Value >>= eEffect ) + nFound |= Found::EFFECT; + } + else if( !( nFound & Found::BOOKMARK ) && rProperty.Name == gsBookmark ) + { + if( rProperty.Value >>= aStrBookmark ) + nFound |= Found::BOOKMARK; + } + else if( !( nFound & Found::SPEED ) && rProperty.Name == gsSpeed ) + { + if( rProperty.Value >>= eSpeed ) + nFound |= Found::SPEED; + } + else if( !( nFound & Found::SOUNDURL ) && rProperty.Name == gsSoundURL ) + { + if( rProperty.Value >>= aStrSoundURL ) + nFound |= Found::SOUNDURL; + } + else if( !( nFound & Found::PLAYFULL ) && rProperty.Name == gsPlayFull ) + { + if( rProperty.Value >>= bPlayFull ) + nFound |= Found::PLAYFULL; + } + else if( !( nFound & Found::VERB ) && rProperty.Name == gsVerb ) + { + if( rProperty.Value >>= nVerb ) + nFound |= Found::VERB; + } + } + } + + // create the XML elements + + if( aClickEventType == gsPresentation ) + { + if( !(nFound & Found::CLICKACTION) || (eClickAction == presentation::ClickAction_NONE) ) + return; + + SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true); + + enum XMLTokenEnum eStrAction; + + switch( eClickAction ) + { + case presentation::ClickAction_PREVPAGE: eStrAction = XML_PREVIOUS_PAGE; break; + case presentation::ClickAction_NEXTPAGE: eStrAction = XML_NEXT_PAGE; break; + case presentation::ClickAction_FIRSTPAGE: eStrAction = XML_FIRST_PAGE; break; + case presentation::ClickAction_LASTPAGE: eStrAction = XML_LAST_PAGE; break; + case presentation::ClickAction_INVISIBLE: eStrAction = XML_HIDE; break; + case presentation::ClickAction_STOPPRESENTATION:eStrAction = XML_STOP; break; + case presentation::ClickAction_PROGRAM: eStrAction = XML_EXECUTE; break; + case presentation::ClickAction_BOOKMARK: eStrAction = XML_SHOW; break; + case presentation::ClickAction_DOCUMENT: eStrAction = XML_SHOW; break; + case presentation::ClickAction_MACRO: eStrAction = XML_EXECUTE_MACRO; break; + case presentation::ClickAction_VERB: eStrAction = XML_VERB; break; + case presentation::ClickAction_VANISH: eStrAction = XML_FADE_OUT; break; + case presentation::ClickAction_SOUND: eStrAction = XML_SOUND; break; + default: + OSL_FAIL( "unknown presentation::ClickAction found!" ); + eStrAction = XML_UNKNOWN; + } + + OUString aEventQName( + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_DOM, "click" ) ); + mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName ); + mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_ACTION, eStrAction ); + + if( eClickAction == presentation::ClickAction_VANISH ) + { + if( nFound & Found::EFFECT ) + { + XMLEffect eKind; + XMLEffectDirection eDirection; + sal_Int16 nStartScale; + bool bIn; + + SdXMLImplSetEffect( eEffect, eKind, eDirection, nStartScale, bIn ); + + if( eKind != EK_none ) + { + SvXMLUnitConverter::convertEnum( msBuffer, eKind, aXML_AnimationEffect_EnumMap ); + mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_EFFECT, msBuffer.makeStringAndClear() ); + } + + if( eDirection != ED_none ) + { + SvXMLUnitConverter::convertEnum( msBuffer, eDirection, aXML_AnimationDirection_EnumMap ); + mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_DIRECTION, msBuffer.makeStringAndClear() ); + } + + if( nStartScale != -1 ) + { + ::sax::Converter::convertPercent( msBuffer, nStartScale ); + mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_START_SCALE, msBuffer.makeStringAndClear() ); + } + } + + if( nFound & Found::SPEED && eEffect != presentation::AnimationEffect_NONE ) + { + if( eSpeed != presentation::AnimationSpeed_MEDIUM ) + { + SvXMLUnitConverter::convertEnum( msBuffer, eSpeed, aXML_AnimationSpeed_EnumMap ); + mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SPEED, msBuffer.makeStringAndClear() ); + } + } + } + + if( eClickAction == presentation::ClickAction_PROGRAM || + eClickAction == presentation::ClickAction_BOOKMARK || + eClickAction == presentation::ClickAction_DOCUMENT ) + { + if( eClickAction == presentation::ClickAction_BOOKMARK ) + msBuffer.append( '#' ); + + msBuffer.append( aStrBookmark ); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(msBuffer.makeStringAndClear()) ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST ); + } + + if( ( nFound & Found::VERB ) && eClickAction == presentation::ClickAction_VERB ) + { + msBuffer.append( nVerb ); + mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_VERB, msBuffer.makeStringAndClear()); + } + + SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_PRESENTATION, XML_EVENT_LISTENER, true, true); + + if( eClickAction == presentation::ClickAction_VANISH || eClickAction == presentation::ClickAction_SOUND ) + { + if( ( nFound & Found::SOUNDURL ) && !aStrSoundURL.isEmpty() ) + { + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStrSoundURL) ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_NEW ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST ); + if( nFound & Found::PLAYFULL && bPlayFull ) + mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PLAY_FULL, XML_TRUE ); + + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_PRESENTATION, XML_SOUND, true, true ); + } + } + } + else if( aClickEventType == gsStarBasic ) + { + if( nFound & Found::MACRO ) + { + SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true); + + mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE, + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_OOO, + "starbasic" ) ); + OUString aEventQName( + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_DOM, "click" ) ); + mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName ); + + if( nFound & Found::LIBRARY ) + { + const OUString& sLocation( GetXMLToken( + (aStrLibrary.equalsIgnoreAsciiCase("StarOffice") || + aStrLibrary.equalsIgnoreAsciiCase("application") ) ? XML_APPLICATION + : XML_DOCUMENT ) ); + mrExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_MACRO_NAME, + sLocation + ":" + aStrMacro); + } + else + { + mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_MACRO_NAME, aStrMacro ); + } + + SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true); + } + } + else if( aClickEventType == gsScript ) + { + if( nFound & Found::MACRO ) + { + SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true); + + mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE, mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_OOO, GetXMLToken(XML_SCRIPT) ) ); + OUString aEventQName( + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_DOM, "click" ) ); + mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aStrMacro ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, "simple" ); + + SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true); + } + } +} + +/** #i68101# export shape Title and Description */ +void XMLShapeExport::ImpExportDescription( const uno::Reference< drawing::XShape >& xShape ) +{ + try + { + OUString aTitle; + OUString aDescription; + + uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY_THROW ); + xProps->getPropertyValue("Title") >>= aTitle; + xProps->getPropertyValue("Description") >>= aDescription; + + if(!aTitle.isEmpty()) + { + SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_TITLE, true, false); + mrExport.Characters( aTitle ); + } + + if(!aDescription.isEmpty()) + { + SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_DESC, true, false ); + mrExport.Characters( aDescription ); + } + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "exporting Title and/or Description for shape" ); + } +} + +void XMLShapeExport::ImpExportGroupShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY); + if(!(xShapes.is() && xShapes->getCount())) + return; + + // write group shape + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aPGR(mrExport, XML_NAMESPACE_DRAW, XML_G, bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + + // #89764# if export of position is suppressed for group shape, + // positions of contained objects should be written relative to + // the upper left edge of the group. + awt::Point aUpperLeft; + + if(!(nFeatures & XMLShapeExportFlags::POSITION)) + { + nFeatures |= XMLShapeExportFlags::POSITION; + aUpperLeft = xShape->getPosition(); + pRefPoint = &aUpperLeft; + } + + // write members + exportShapes( xShapes, nFeatures, pRefPoint ); +} + +void XMLShapeExport::ImpExportTextBoxShape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // presentation attribute (if presentation) + bool bIsPresShape(false); + bool bIsEmptyPresObj(false); + OUString aStr; + + switch(eShapeType) + { + case XmlShapeType::PresSubtitleShape: + { + aStr = GetXMLToken(XML_SUBTITLE); + bIsPresShape = true; + break; + } + case XmlShapeType::PresTitleTextShape: + { + aStr = GetXMLToken(XML_TITLE); + bIsPresShape = true; + break; + } + case XmlShapeType::PresOutlinerShape: + { + aStr = GetXMLToken(XML_PRESENTATION_OUTLINE); + bIsPresShape = true; + break; + } + case XmlShapeType::PresNotesShape: + { + aStr = GetXMLToken(XML_NOTES); + bIsPresShape = true; + break; + } + case XmlShapeType::PresHeaderShape: + { + aStr = GetXMLToken(XML_HEADER); + bIsPresShape = true; + break; + } + case XmlShapeType::PresFooterShape: + { + aStr = GetXMLToken(XML_FOOTER); + bIsPresShape = true; + break; + } + case XmlShapeType::PresSlideNumberShape: + { + aStr = GetXMLToken(XML_PAGE_NUMBER); + bIsPresShape = true; + break; + } + case XmlShapeType::PresDateTimeShape: + { + aStr = GetXMLToken(XML_DATE_TIME); + bIsPresShape = true; + break; + } + default: + break; + } + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + if(bIsPresShape) + bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, aStr ); + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, + XML_FRAME, bCreateNewline, true ); + + // evtl. corner radius? + sal_Int32 nCornerRadius(0); + xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius; + if(nCornerRadius) + { + OUStringBuffer sStringBuffer; + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + nCornerRadius); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear()); + } + + { + // write text-box + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_TEXT_BOX, true, true); + if(!bIsEmptyPresObj) + ImpExportText( xShape ); + } + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + +} + +void XMLShapeExport::ImpExportRectangleShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + // evtl. corner radius? + sal_Int32 nCornerRadius(0); + xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius; + if(nCornerRadius) + { + OUStringBuffer sStringBuffer; + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + nCornerRadius); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear()); + } + + // write rectangle + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_RECT, bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportText( xShape ); +} + +void XMLShapeExport::ImpExportLineShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + OUString aStr; + OUStringBuffer sStringBuffer; + awt::Point aStart(0,0); + awt::Point aEnd(1,1); + + // #85920# use 'Geometry' to get the points of the line + // since this slot take anchor pos into account. + + // get matrix + ::basegfx::B2DHomMatrix aMatrix; + ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet); + + // decompose and correct about pRefPoint + ::basegfx::B2DTuple aTRScale; + double fTRShear(0.0); + double fTRRotate(0.0); + ::basegfx::B2DTuple aTRTranslate; + ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint); + + // create base position + awt::Point aBasePosition(FRound(aTRTranslate.getX()), FRound(aTRTranslate.getY())); + + if (xPropSet->getPropertySetInfo()->hasPropertyByName("Geometry")) + { + // get the two points + uno::Any aAny(xPropSet->getPropertyValue("Geometry")); + if (auto pSourcePolyPolygon + = o3tl::tryAccess<drawing::PointSequenceSequence>(aAny)) + { + if (pSourcePolyPolygon->getLength() > 0) + { + const drawing::PointSequence& rInnerSequence = (*pSourcePolyPolygon)[0]; + if (rInnerSequence.hasElements()) + { + const awt::Point& rPoint = rInnerSequence[0]; + aStart = awt::Point(rPoint.X + aBasePosition.X, rPoint.Y + aBasePosition.Y); + } + if (rInnerSequence.getLength() > 1) + { + const awt::Point& rPoint = rInnerSequence[1]; + aEnd = awt::Point(rPoint.X + aBasePosition.X, rPoint.Y + aBasePosition.Y); + } + } + } + } + + if( nFeatures & XMLShapeExportFlags::X ) + { + // svg: x1 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aStart.X); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr); + } + else + { + aEnd.X -= aStart.X; + } + + if( nFeatures & XMLShapeExportFlags::Y ) + { + // svg: y1 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aStart.Y); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr); + } + else + { + aEnd.Y -= aStart.Y; + } + + // svg: x2 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aEnd.X); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr); + + // svg: y2 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aEnd.Y); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr); + + // write line + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_LINE, bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportText( xShape ); + +} + +void XMLShapeExport::ImpExportEllipseShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // get size to decide between Circle and Ellipse + awt::Size aSize = xShape->getSize(); + sal_Int32 nRx((aSize.Width + 1) / 2); + sal_Int32 nRy((aSize.Height + 1) / 2); + bool bCircle(nRx == nRy); + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + drawing::CircleKind eKind = drawing::CircleKind_FULL; + xPropSet->getPropertyValue("CircleKind") >>= eKind; + if( eKind != drawing::CircleKind_FULL ) + { + OUStringBuffer sStringBuffer; + sal_Int32 nStartAngle = 0; + sal_Int32 nEndAngle = 0; + xPropSet->getPropertyValue("CircleStartAngle") >>= nStartAngle; + xPropSet->getPropertyValue("CircleEndAngle") >>= nEndAngle; + + const double dStartAngle = nStartAngle / 100.0; + const double dEndAngle = nEndAngle / 100.0; + + // export circle kind + SvXMLUnitConverter::convertEnum( sStringBuffer, eKind, aXML_CircleKind_EnumMap ); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_KIND, sStringBuffer.makeStringAndClear() ); + + // export start angle + ::sax::Converter::convertDouble( sStringBuffer, dStartAngle ); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_ANGLE, sStringBuffer.makeStringAndClear() ); + + // export end angle + ::sax::Converter::convertDouble( sStringBuffer, dEndAngle ); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_ANGLE, sStringBuffer.makeStringAndClear() ); + } + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + + // write ellipse or circle + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, + bCircle ? XML_CIRCLE : XML_ELLIPSE, + bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportText( xShape ); + +} + +void XMLShapeExport::ImpExportPolygonShape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + bool bBezier(eShapeType == XmlShapeType::DrawClosedBezierShape + || eShapeType == XmlShapeType::DrawOpenBezierShape); + + // get matrix + ::basegfx::B2DHomMatrix aMatrix; + ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet); + + // decompose and correct about pRefPoint + ::basegfx::B2DTuple aTRScale; + double fTRShear(0.0); + double fTRRotate(0.0); + ::basegfx::B2DTuple aTRTranslate; + ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint); + + // use features and write + ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures); + + // create and export ViewBox + awt::Size aSize(FRound(aTRScale.getX()), FRound(aTRScale.getY())); + SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString()); + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + + // prepare name (with most used) + enum ::xmloff::token::XMLTokenEnum eName(XML_PATH); + + uno::Any aAny( xPropSet->getPropertyValue("Geometry") ); + basegfx::B2DPolyPolygon aPolyPolygon; + + // tdf#145240 the Any can contain PolyPolygonBezierCoords or PointSequenceSequence + // (see OWN_ATTR_BASE_GEOMETRY in SvxShapePolyPolygon::getPropertyValueImpl), + // so be more flexible in interpreting it. Try to access bezier first: + { + auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(aAny); + + if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength()) + { + aPolyPolygon = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(*pSourcePolyPolygon); + } + } + + // if received no data, try to access point sequence second: + if(0 == aPolyPolygon.count()) + { + auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PointSequenceSequence>(aAny); + + if(pSourcePolyPolygon) + { + aPolyPolygon = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(*pSourcePolyPolygon); + } + } + + if(aPolyPolygon.count()) + { + if(!bBezier && !aPolyPolygon.areControlPointsUsed() && 1 == aPolyPolygon.count()) + { + // simple polygon shape, can be written as svg:points sequence + const basegfx::B2DPolygon& aPolygon(aPolyPolygon.getB2DPolygon(0)); + const OUString aPointString(basegfx::utils::exportToSvgPoints(aPolygon)); + + // write point array + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString); + + // set name + eName = aPolygon.isClosed() ? XML_POLYGON : XML_POLYLINE; + } + else + { + // complex polygon shape, write as svg:d + const OUString aPolygonString( + basegfx::utils::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible + + // write point array + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString); + } + } + + // write object, but after attributes are added since this call will + // consume all of these added attributes and the destructor will close the + // scope. Also before text is added; this may add sub-scopes as needed + SvXMLElementExport aOBJ( + mrExport, + XML_NAMESPACE_DRAW, + eName, + bCreateNewline, + true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportText( xShape ); + +} + +namespace +{ + +OUString getNameFromStreamURL(std::u16string_view rURL) +{ + static constexpr std::u16string_view sPackageURL(u"vnd.sun.star.Package:"); + + OUString sResult; + + if (o3tl::starts_with(rURL, sPackageURL)) + { + std::u16string_view sRequestedName = rURL.substr(sPackageURL.size()); + size_t nLastIndex = sRequestedName.rfind('/') + 1; + if ((nLastIndex > 0) && (nLastIndex < sRequestedName.size())) + sRequestedName = sRequestedName.substr(nLastIndex); + nLastIndex = sRequestedName.rfind('.'); + if (nLastIndex != std::u16string_view::npos) + sRequestedName = sRequestedName.substr(0, nLastIndex); + if (!sRequestedName.empty()) + sResult = sRequestedName; + } + + return sResult; +} + +} // end anonymous namespace + +void XMLShapeExport::ImpExportGraphicObjectShape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + bool bIsEmptyPresObj = false; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + if(eShapeType == XmlShapeType::PresGraphicObjectShape) + bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_GRAPHIC) ); + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, + XML_FRAME, bCreateNewline, true ); + + if (!bIsEmptyPresObj) + { + uno::Reference<graphic::XGraphic> xGraphic; + OUString sOutMimeType; + + { + OUString aStreamURL; + xPropSet->getPropertyValue("GraphicStreamURL") >>= aStreamURL; + OUString sRequestedName = getNameFromStreamURL(aStreamURL); + + xPropSet->getPropertyValue("Graphic") >>= xGraphic; + + OUString sInternalURL; + + if (xGraphic.is()) + sInternalURL = mrExport.AddEmbeddedXGraphic(xGraphic, sOutMimeType, sRequestedName); + + if (!sInternalURL.isEmpty()) + { + // apply possible changed stream URL to embedded image object + if (!sRequestedName.isEmpty()) + { + OUString newStreamURL = "vnd.sun.star.Package:"; + if (sInternalURL[0] == '#') + { + newStreamURL += sInternalURL.subView(1, sInternalURL.getLength() - 1); + } + else + { + newStreamURL += sInternalURL; + } + + if (newStreamURL != aStreamURL) + { + xPropSet->setPropertyValue("GraphicStreamURL", uno::Any(newStreamURL)); + } + } + + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD); + } + } + + { + if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012) + { + if (sOutMimeType.isEmpty()) + { + GetExport().GetGraphicMimeTypeFromStream(xGraphic, sOutMimeType); + } + if (!sOutMimeType.isEmpty()) + { // ODF 1.3 OFFICE-3943 + GetExport().AddAttribute( + SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion() + ? XML_NAMESPACE_DRAW + : XML_NAMESPACE_LO_EXT, + "mime-type", sOutMimeType); + } + } + + SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true); + + // optional office:binary-data + if (xGraphic.is()) + { + mrExport.AddEmbeddedXGraphicAsBase64(xGraphic); + } + if (!bIsEmptyPresObj) + ImpExportText(xShape); + } + + //Resolves: fdo#62461 put preferred image first above, followed by + //fallback here + const bool bAddReplacementImages = officecfg::Office::Common::Save::Graphic::AddReplacementImages::get(); + if( !bIsEmptyPresObj && bAddReplacementImages) + { + uno::Reference<graphic::XGraphic> xReplacementGraphic; + xPropSet->getPropertyValue("ReplacementGraphic") >>= xReplacementGraphic; + + // If there is no url, then the graphic is empty + if (xReplacementGraphic.is()) + { + OUString aMimeType; + const OUString aHref = mrExport.AddEmbeddedXGraphic(xReplacementGraphic, aMimeType); + + if (aMimeType.isEmpty()) + mrExport.GetGraphicMimeTypeFromStream(xReplacementGraphic, aMimeType); + + if (!aHref.isEmpty()) + { + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + } + + if (!aMimeType.isEmpty() && GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012) + { // ODF 1.3 OFFICE-3943 + mrExport.AddAttribute( + SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion() + ? XML_NAMESPACE_DRAW + : XML_NAMESPACE_LO_EXT, + "mime-type", aMimeType); + } + + SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true); + + // optional office:binary-data + mrExport.AddEmbeddedXGraphicAsBase64(xReplacementGraphic); + } + } + } + + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + + // image map + GetExport().GetImageMapExport().Export( xPropSet ); + ImpExportDescription( xShape ); // #i68101# + + // Signature Line, QR Code - needs to be after the images! + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + ImpExportSignatureLine(xShape); + ImpExportQRCode(xShape); + } +} + +void XMLShapeExport::ImpExportChartShape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint, + comphelper::AttributeList* pAttrList ) +{ + ImpExportOLE2Shape( xShape, eShapeType, nFeatures, pRefPoint, pAttrList ); +} + +void XMLShapeExport::ImpExportControlShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + } + + uno::Reference< drawing::XControlShape > xControl( xShape, uno::UNO_QUERY ); + SAL_WARN_IF( !xControl.is(), "xmloff", "Control shape is not supporting XControlShape" ); + if( xControl.is() ) + { + uno::Reference< beans::XPropertySet > xControlModel( xControl->getControl(), uno::UNO_QUERY ); + SAL_WARN_IF( !xControlModel.is(), "xmloff", "Control shape has not XControlModel" ); + if( xControlModel.is() ) + { + OUString sControlId = mrExport.GetFormExport()->getControlId( xControlModel ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONTROL, sControlId ); + } + } + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONTROL, bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# +} + +void XMLShapeExport::ImpExportConnectorShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */) +{ + uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY ); + + OUString aStr; + OUStringBuffer sStringBuffer; + + // export connection kind + drawing::ConnectorType eType = drawing::ConnectorType_STANDARD; + uno::Any aAny = xProps->getPropertyValue("EdgeKind"); + aAny >>= eType; + + if( eType != drawing::ConnectorType_STANDARD ) + { + SvXMLUnitConverter::convertEnum( sStringBuffer, eType, aXML_ConnectionKind_EnumMap ); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TYPE, aStr); + } + + // export line skew + sal_Int32 nDelta1 = 0, nDelta2 = 0, nDelta3 = 0; + + aAny = xProps->getPropertyValue("EdgeLine1Delta"); + aAny >>= nDelta1; + aAny = xProps->getPropertyValue("EdgeLine2Delta"); + aAny >>= nDelta2; + aAny = xProps->getPropertyValue("EdgeLine3Delta"); + aAny >>= nDelta3; + + if( nDelta1 != 0 || nDelta2 != 0 || nDelta3 != 0 ) + { + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + nDelta1); + if( nDelta2 != 0 || nDelta3 != 0 ) + { + sStringBuffer.append( ' ' ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + nDelta2); + if( nDelta3 != 0 ) + { + sStringBuffer.append( ' ' ); + mrExport.GetMM100UnitConverter().convertMeasureToXML( + sStringBuffer, nDelta3); + } + } + + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LINE_SKEW, aStr); + } + + // export start and end point + awt::Point aStart(0,0); + awt::Point aEnd(1,1); + + /* Get <StartPositionInHoriL2R> and + <EndPositionInHoriL2R>, if they exist and if the document is exported + into the OpenOffice.org file format. + These properties only exist at service css::text::Shape - the + Writer UNO service for shapes. + This code is needed, because the positioning attributes in the + OpenOffice.org file format are given in horizontal left-to-right layout + regardless the layout direction the shape is in. In the OASIS Open Office + file format the positioning attributes are correctly given in the layout + direction the shape is in. Thus, this code provides the conversion from + the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#) + */ + if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) && + xProps->getPropertySetInfo()->hasPropertyByName("StartPositionInHoriL2R") && + xProps->getPropertySetInfo()->hasPropertyByName("EndPositionInHoriL2R") ) + { + xProps->getPropertyValue("StartPositionInHoriL2R") >>= aStart; + xProps->getPropertyValue("EndPositionInHoriL2R") >>= aEnd; + } + else + { + xProps->getPropertyValue("StartPosition") >>= aStart; + xProps->getPropertyValue("EndPosition") >>= aEnd; + } + + if( pRefPoint ) + { + aStart.X -= pRefPoint->X; + aStart.Y -= pRefPoint->Y; + aEnd.X -= pRefPoint->X; + aEnd.Y -= pRefPoint->Y; + } + + if( nFeatures & XMLShapeExportFlags::X ) + { + // svg: x1 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aStart.X); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr); + } + else + { + aEnd.X -= aStart.X; + } + + if( nFeatures & XMLShapeExportFlags::Y ) + { + // svg: y1 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aStart.Y); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr); + } + else + { + aEnd.Y -= aStart.Y; + } + + // svg: x2 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr); + + // svg: y2 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr); + + // #i39320# + uno::Reference< uno::XInterface > xRefS; + uno::Reference< uno::XInterface > xRefE; + + // export start connection + xProps->getPropertyValue("StartShape") >>= xRefS; + if( xRefS.is() ) + { + const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefS ); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_SHAPE, rShapeId); + + aAny = xProps->getPropertyValue("StartGluePointIndex"); + sal_Int32 nGluePointId = 0; + if( aAny >>= nGluePointId ) + { + if( nGluePointId != -1 ) + { + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_GLUE_POINT, OUString::number( nGluePointId )); + } + } + } + + // export end connection + xProps->getPropertyValue("EndShape") >>= xRefE; + if( xRefE.is() ) + { + const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefE ); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_SHAPE, rShapeId); + + aAny = xProps->getPropertyValue("EndGluePointIndex"); + sal_Int32 nGluePointId = 0; + if( aAny >>= nGluePointId ) + { + if( nGluePointId != -1 ) + { + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_GLUE_POINT, OUString::number( nGluePointId )); + } + } + } + + // get PolygonBezier + aAny = xProps->getPropertyValue("PolyPolygonBezier"); + auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(aAny); + if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength()) + { + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( + *pSourcePolyPolygon)); + const OUString aPolygonString( + basegfx::utils::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible + + // write point array + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString); + } + + // get matrix + ::basegfx::B2DHomMatrix aMatrix; + ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xProps); + + // decompose and correct about pRefPoint + ::basegfx::B2DTuple aTRScale; + double fTRShear(0.0); + double fTRRotate(0.0); + ::basegfx::B2DTuple aTRTranslate; + ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, + fTRRotate, aTRTranslate, pRefPoint); + + // fdo#49678: create and export ViewBox + awt::Size aSize(FRound(aTRScale.getX()), FRound(aTRScale.getY())); + SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString()); + + // write connector shape. Add Export later. + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONNECTOR, bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportText( xShape ); +} + +void XMLShapeExport::ImpExportMeasureShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point const * pRefPoint /* = NULL */) +{ + uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY ); + + OUString aStr; + OUStringBuffer sStringBuffer; + + // export start and end point + awt::Point aStart(0,0); + awt::Point aEnd(1,1); + + /* Get <StartPositionInHoriL2R> and + <EndPositionInHoriL2R>, if they exist and if the document is exported + into the OpenOffice.org file format. + These properties only exist at service css::text::Shape - the + Writer UNO service for shapes. + This code is needed, because the positioning attributes in the + OpenOffice.org file format are given in horizontal left-to-right layout + regardless the layout direction the shape is in. In the OASIS Open Office + file format the positioning attributes are correctly given in the layout + direction the shape is in. Thus, this code provides the conversion from + the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#) + */ + if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) && + xProps->getPropertySetInfo()->hasPropertyByName("StartPositionInHoriL2R") && + xProps->getPropertySetInfo()->hasPropertyByName("EndPositionInHoriL2R") ) + { + xProps->getPropertyValue("StartPositionInHoriL2R") >>= aStart; + xProps->getPropertyValue("EndPositionInHoriL2R") >>= aEnd; + } + else + { + xProps->getPropertyValue("StartPosition") >>= aStart; + xProps->getPropertyValue("EndPosition") >>= aEnd; + } + + if( pRefPoint ) + { + aStart.X -= pRefPoint->X; + aStart.Y -= pRefPoint->Y; + aEnd.X -= pRefPoint->X; + aEnd.Y -= pRefPoint->Y; + } + + if( nFeatures & XMLShapeExportFlags::X ) + { + // svg: x1 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aStart.X); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr); + } + else + { + aEnd.X -= aStart.X; + } + + if( nFeatures & XMLShapeExportFlags::Y ) + { + // svg: y1 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aStart.Y); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr); + } + else + { + aEnd.Y -= aStart.Y; + } + + // svg: x2 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr); + + // svg: y2 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr); + + // write measure shape + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_MEASURE, bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + + uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY ); + if( xText.is() ) + mrExport.GetTextParagraphExport()->exportText( xText ); +} + +void XMLShapeExport::ImpExportOLE2Shape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */, + comphelper::AttributeList* pAttrList /* = NULL */ ) +{ + uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY); + + SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "ole shape is not implementing needed interfaces"); + if(!(xPropSet.is() && xNamed.is())) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + bool bIsEmptyPresObj = false; + + // presentation settings + if(eShapeType == XmlShapeType::PresOLE2Shape) + bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_OBJECT) ); + else if(eShapeType == XmlShapeType::PresChartShape) + bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_CHART) ); + else if(eShapeType == XmlShapeType::PresSheetShape) + bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_TABLE) ); + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + bool bExportEmbedded(mrExport.getExportFlags() & SvXMLExportFlags::EMBEDDED); + OUString sPersistName; + SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW, + XML_FRAME, bCreateNewline, true ); + + if (!bIsEmptyPresObj) + { + if (pAttrList) + { + mrExport.AddAttributeList(pAttrList); + } + + OUString sClassId; + OUString sURL; + bool bInternal = false; + xPropSet->getPropertyValue("IsInternal") >>= bInternal; + + { + + if ( bInternal ) + { + // OOo internal links have no storage persistence, URL is stored in the XML file + // the result LinkURL is empty in case the object is not a link + xPropSet->getPropertyValue("LinkURL") >>= sURL; + } + + xPropSet->getPropertyValue("PersistName") >>= sPersistName; + if ( sURL.isEmpty() ) + { + if( !sPersistName.isEmpty() ) + { + sURL = "vnd.sun.star.EmbeddedObject:" + sPersistName; + } + } + + if( !bInternal ) + xPropSet->getPropertyValue("CLSID") >>= sClassId; + + if( !sClassId.isEmpty() ) + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CLASS_ID, sClassId ); + + if(!bExportEmbedded) + { + // xlink:href + if( !sURL.isEmpty() ) + { + // #96717# in theorie, if we don't have a URL we shouldn't even + // export this OLE shape. But practically it's too risky right now + // to change this so we better dispose this on load + sURL = mrExport.AddEmbeddedObject( sURL ); + + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + } + else + { + // tdf#153179 Export the preview graphic of the object if the object is missing. + uno::Reference<graphic::XGraphic> xGraphic; + xPropSet->getPropertyValue("Graphic") >>= xGraphic; + + if (xGraphic.is()) + { + OUString aMimeType; + const OUString aHref = mrExport.AddEmbeddedXGraphic(xGraphic, aMimeType); + + if (aMimeType.isEmpty()) + mrExport.GetGraphicMimeTypeFromStream(xGraphic, aMimeType); + + if (!aHref.isEmpty()) + { + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD); + } + + if (!aMimeType.isEmpty() + && GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012) + { // ODF 1.3 OFFICE-3943 + mrExport.AddAttribute(SvtSaveOptions::ODFSVER_013 + <= GetExport().getSaneDefaultVersion() + ? XML_NAMESPACE_DRAW + : XML_NAMESPACE_LO_EXT, + "mime-type", aMimeType); + } + + SvXMLElementExport aImageElem(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, + true); + + // optional office:binary-data + mrExport.AddEmbeddedXGraphicAsBase64(xGraphic); + + ImpExportEvents(xShape); + ImpExportGluePoints(xShape); + ImpExportDescription(xShape); + + return; + } + } + } + } + + enum XMLTokenEnum eElem = sClassId.isEmpty() ? XML_OBJECT : XML_OBJECT_OLE ; + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, eElem, true, true ); + + // tdf#112547 export text as child of draw:object, where import expects it + if (!bIsEmptyPresObj && supportsText(eShapeType)) + { + // #i118485# Add text export, the draw OLE shape allows text now + ImpExportText( xShape, TextPNS::EXTENSION ); + } + + if(bExportEmbedded && !bIsEmptyPresObj) + { + if(bInternal) + { + // embedded XML + uno::Reference< lang::XComponent > xComp; + xPropSet->getPropertyValue("Model") >>= xComp; + SAL_WARN_IF( !xComp.is(), "xmloff", "no xModel for own OLE format" ); + mrExport.ExportEmbeddedOwnObject( xComp ); + } + else + { + // embed as Base64 + // this is an alien object ( currently MSOLE is the only supported type of such objects ) + // in case it is not an OASIS format the object should be asked to store replacement image if possible + + OUString sURLRequest( sURL ); + if ( !( mrExport.getExportFlags() & SvXMLExportFlags::OASIS ) ) + sURLRequest += "?oasis=false"; + mrExport.AddEmbeddedObjectAsBase64( sURLRequest ); + } + } + } + if( !bIsEmptyPresObj ) + { + OUString sURL = XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE + sPersistName; + if( !bExportEmbedded ) + { + sURL = GetExport().AddEmbeddedObject( sURL ); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + } + + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW, + XML_IMAGE, false, true ); + + if( bExportEmbedded ) + GetExport().AddEmbeddedObjectAsBase64( sURL ); + } + + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportDescription( xShape ); // #i68101# + +} + +void XMLShapeExport::ImpExportPageShape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // #86163# Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + // export page number used for this page + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + static constexpr OUString aPageNumberStr(u"PageNumber"_ustr); + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(aPageNumberStr)) + { + sal_Int32 nPageNumber = 0; + xPropSet->getPropertyValue(aPageNumberStr) >>= nPageNumber; + if( nPageNumber ) + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_PAGE_NUMBER, OUString::number(nPageNumber)); + } + + // a presentation page shape, normally used on notes pages only. If + // it is used not as presentation shape, it may have been created with + // copy-paste exchange between draw and impress (this IS possible...) + if(eShapeType == XmlShapeType::PresPageShape) + { + mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS, + XML_PAGE); + } + + // write Page shape + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PAGE_THUMBNAIL, bCreateNewline, true); +} + +void XMLShapeExport::ImpExportCaptionShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + // evtl. corner radius? + sal_Int32 nCornerRadius(0); + xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius; + if(nCornerRadius) + { + OUStringBuffer sStringBuffer; + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + nCornerRadius); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear()); + } + + awt::Point aCaptionPoint; + xPropSet->getPropertyValue("CaptionPoint") >>= aCaptionPoint; + + mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer, + aCaptionPoint.X); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_X, msBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer, + aCaptionPoint.Y); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_Y, msBuffer.makeStringAndClear() ); + + // write Caption shape. Add export later. + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + bool bAnnotation( (nFeatures & XMLShapeExportFlags::ANNOTATION) == XMLShapeExportFlags::ANNOTATION ); + + SvXMLElementExport aObj( mrExport, + (bAnnotation ? XML_NAMESPACE_OFFICE + : XML_NAMESPACE_DRAW), + (bAnnotation ? XML_ANNOTATION : XML_CAPTION), + bCreateNewline, true ); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + if( bAnnotation ) + mrExport.exportAnnotationMeta( xShape ); + ImpExportText( xShape ); + +} + +void XMLShapeExport::ImpExportFrameShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, + XML_FRAME, bCreateNewline, true ); + + // export frame url + OUString aStr; + xPropSet->getPropertyValue("FrameURL") >>= aStr; + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + + // export name + xPropSet->getPropertyValue("FrameName") >>= aStr; + if( !aStr.isEmpty() ) + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FRAME_NAME, aStr ); + + // write floating frame + { + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_FLOATING_FRAME, true, true); + } + + ImpExportDescription(xShape); +} + +void XMLShapeExport::ImpExportAppletShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW, + XML_FRAME, bCreateNewline, true ); + + // export frame url + OUString aStr; + xPropSet->getPropertyValue("AppletCodeBase") >>= aStr; + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + + // export draw:applet-name + xPropSet->getPropertyValue("AppletName") >>= aStr; + if( !aStr.isEmpty() ) + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_APPLET_NAME, aStr ); + + // export draw:code + xPropSet->getPropertyValue("AppletCode") >>= aStr; + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CODE, aStr ); + + // export draw:may-script + bool bIsScript = false; + xPropSet->getPropertyValue("AppletIsScript") >>= bIsScript; + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MAY_SCRIPT, bIsScript ? XML_TRUE : XML_FALSE ); + + { + // write applet + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_APPLET, true, true); + + // export parameters + uno::Sequence< beans::PropertyValue > aCommands; + xPropSet->getPropertyValue("AppletCommands") >>= aCommands; + for( const auto& rCommand : std::as_const(aCommands) ) + { + rCommand.Value >>= aStr; + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr ); + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true ); + } + } + + ImpExportDescription(xShape); +} + +void XMLShapeExport::ImpExportPluginShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW, + XML_FRAME, bCreateNewline, true ); + + // export plugin url + OUString aStr; + xPropSet->getPropertyValue("PluginURL") >>= aStr; + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + + // export mime-type + xPropSet->getPropertyValue("PluginMimeType") >>= aStr; + if(!aStr.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, aStr ); + + { + // write plugin + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, true, true); + + // export parameters + uno::Sequence< beans::PropertyValue > aCommands; + xPropSet->getPropertyValue("PluginCommands") >>= aCommands; + for( const auto& rCommand : std::as_const(aCommands) ) + { + rCommand.Value >>= aStr; + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr ); + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true ); + } + } + + ImpExportDescription(xShape); +} + +static void lcl_CopyStream( + uno::Reference<io::XInputStream> const& xInStream, + uno::Reference<embed::XStorage> const& xTarget, + OUString const& rPath, const OUString& rMimeType) +{ + ::comphelper::LifecycleProxy proxy; + uno::Reference<io::XStream> const xStream( + ::comphelper::OStorageHelper::GetStreamAtPackageURL(xTarget, rPath, + embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE, proxy)); + uno::Reference<io::XOutputStream> const xOutStream( + (xStream.is()) ? xStream->getOutputStream() : nullptr); + if (!xOutStream.is()) + { + SAL_WARN("xmloff", "no output stream"); + throw uno::Exception("no output stream",nullptr); + } + uno::Reference< beans::XPropertySet > const xStreamProps(xStream, + uno::UNO_QUERY); + if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage + xStreamProps->setPropertyValue("MediaType", + uno::Any(rMimeType)); + xStreamProps->setPropertyValue( // turn off compression + "Compressed", + uno::Any(false)); + } + ::comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream); + xOutStream->closeOutput(); + proxy.commitStorages(); +} + +static OUString +lcl_StoreMediaAndGetURL(SvXMLExport & rExport, + uno::Reference<beans::XPropertySet> const& xPropSet, + OUString const& rURL, const OUString& rMimeType) +{ + OUString urlPath; + if (rURL.startsWithIgnoreAsciiCase("vnd.sun.star.Package:", &urlPath)) + { + try // video is embedded + { + uno::Reference<embed::XStorage> const xTarget( + rExport.GetTargetStorage(), uno::UNO_SET_THROW); + uno::Reference<io::XInputStream> xInStream; + xPropSet->getPropertyValue("PrivateStream") + >>= xInStream; + + if (!xInStream.is()) + { + SAL_WARN("xmloff", "no input stream"); + return OUString(); + } + + lcl_CopyStream(xInStream, xTarget, rURL, rMimeType); + + return urlPath; + } + catch (uno::Exception const&) + { + TOOLS_INFO_EXCEPTION("xmloff", "exception while storing embedded media"); + } + return OUString(); + } + else + { + return rExport.GetRelativeReference(rURL); // linked + } +} + +namespace +{ +void ExportGraphicPreview(const uno::Reference<graphic::XGraphic>& xGraphic, SvXMLExport& rExport, const std::u16string_view& rPrefix, const std::u16string_view& rExtension, const OUString& rMimeType) +{ + const bool bExportEmbedded(rExport.getExportFlags() & SvXMLExportFlags::EMBEDDED); + + if( xGraphic.is() ) try + { + uno::Reference< uno::XComponentContext > xContext = rExport.getComponentContext(); + + uno::Reference< embed::XStorage > xPictureStorage; + uno::Reference< embed::XStorage > xStorage; + uno::Reference< io::XStream > xPictureStream; + + OUString sPictureName; + if( bExportEmbedded ) + { + xPictureStream.set( xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.comp.MemoryStream", xContext), uno::UNO_QUERY_THROW ); + } + else + { + xStorage.set( rExport.GetTargetStorage(), uno::UNO_SET_THROW ); + + xPictureStorage.set( xStorage->openStorageElement( "Pictures" , ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW ); + + sal_Int32 nIndex = 0; + do + { + sPictureName = rPrefix + OUString::number( ++nIndex ) + rExtension; + } + while( xPictureStorage->hasByName( sPictureName ) ); + + xPictureStream.set( xPictureStorage->openStreamElement( sPictureName, ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW ); + } + + uno::Reference< graphic::XGraphicProvider > xProvider( graphic::GraphicProvider::create(xContext) ); + uno::Sequence< beans::PropertyValue > aArgs{ + comphelper::makePropertyValue("MimeType", rMimeType ), + comphelper::makePropertyValue("OutputStream", xPictureStream->getOutputStream()) + }; + xProvider->storeGraphic( xGraphic, aArgs ); + + if( xPictureStorage.is() ) + { + uno::Reference< embed::XTransactedObject > xTrans( xPictureStorage, uno::UNO_QUERY ); + if( xTrans.is() ) + xTrans->commit(); + } + + if( !bExportEmbedded ) + { + OUString sURL = "Pictures/" + sPictureName; + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sURL ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + } + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_DRAW, XML_IMAGE, false, true ); + + if( bExportEmbedded ) + { + uno::Reference< io::XSeekableInputStream > xSeekable( xPictureStream, uno::UNO_QUERY_THROW ); + xSeekable->seek(0); + + XMLBase64Export aBase64Exp( rExport ); + aBase64Exp.exportOfficeBinaryDataElement( uno::Reference < io::XInputStream >( xPictureStream, uno::UNO_QUERY_THROW ) ); + } + } + catch( uno::Exception const & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.draw"); + } +} +} + +void XMLShapeExport::ImpExportMediaShape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + if(eShapeType == XmlShapeType::PresMediaShape) + { + (void)ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_OBJECT) ); + } + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, + XML_FRAME, bCreateNewline, true ); + + // export media url + OUString aMediaURL; + xPropSet->getPropertyValue("MediaURL") >>= aMediaURL; + OUString sMimeType; + xPropSet->getPropertyValue("MediaMimeType") >>= sMimeType; + + OUString const persistentURL = + lcl_StoreMediaAndGetURL(GetExport(), xPropSet, aMediaURL, sMimeType); + + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, persistentURL ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + + // export mime-type + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, sMimeType ); + + // write plugin + auto pPluginOBJ = std::make_unique<SvXMLElementExport>(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, !( nFeatures & XMLShapeExportFlags::NO_WS ), true); + + // export parameters + static constexpr OUString aFalseStr( u"false"_ustr ); + static constexpr OUString aTrueStr( u"true"_ustr ); + + bool bLoop = false; + static constexpr OUString aLoopStr( u"Loop"_ustr ); + xPropSet->getPropertyValue( aLoopStr ) >>= bLoop; + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aLoopStr ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bLoop ? aTrueStr : aFalseStr ); + delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true ); + + bool bMute = false; + static constexpr OUString aMuteStr( u"Mute"_ustr ); + xPropSet->getPropertyValue( aMuteStr ) >>= bMute; + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aMuteStr ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bMute ? aTrueStr : aFalseStr ); + delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true ); + + sal_Int16 nVolumeDB = 0; + xPropSet->getPropertyValue("VolumeDB") >>= nVolumeDB; + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, "VolumeDB" ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, OUString::number( nVolumeDB ) ); + delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true ); + + media::ZoomLevel eZoom; + OUString aZoomValue; + xPropSet->getPropertyValue("Zoom") >>= eZoom; + switch( eZoom ) + { + case media::ZoomLevel_ZOOM_1_TO_4 : aZoomValue = "25%"; break; + case media::ZoomLevel_ZOOM_1_TO_2 : aZoomValue = "50%"; break; + case media::ZoomLevel_ORIGINAL : aZoomValue = "100%"; break; + case media::ZoomLevel_ZOOM_2_TO_1 : aZoomValue = "200%"; break; + case media::ZoomLevel_ZOOM_4_TO_1 : aZoomValue = "400%"; break; + case media::ZoomLevel_FIT_TO_WINDOW: aZoomValue = "fit"; break; + case media::ZoomLevel_FIT_TO_WINDOW_FIXED_ASPECT: aZoomValue = "fixedfit"; break; + case media::ZoomLevel_FULLSCREEN : aZoomValue = "fullscreen"; break; + + default: + break; + } + + if( !aZoomValue.isEmpty() ) + { + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, "Zoom" ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aZoomValue ); + delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true ); + } + + pPluginOBJ.reset(); + + uno::Reference<graphic::XGraphic> xGraphic; + xPropSet->getPropertyValue("Graphic") >>= xGraphic; + Graphic aGraphic(xGraphic); + if (!aGraphic.IsNone()) + { + // The media has a preview, export it. + ExportGraphicPreview(xGraphic, mrExport, u"MediaPreview", u".png", "image/png"); + } + + ImpExportDescription(xShape); +} + +void XMLShapeExport::ImpExport3DSceneShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY); + if(!(xShapes.is() && xShapes->getCount())) + return; + + uno::Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); + SAL_WARN_IF( !xPropSet.is(), "xmloff", "XMLShapeExport::ImpExport3DSceneShape can't export a scene without a propertyset" ); + if( !xPropSet.is() ) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + // 3d attributes + export3DSceneAttributes( xPropSet ); + + // write 3DScene shape + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DR3D, XML_SCENE, bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + + // write 3DSceneLights + export3DLamps( xPropSet ); + + // #89764# if export of position is suppressed for group shape, + // positions of contained objects should be written relative to + // the upper left edge of the group. + awt::Point aUpperLeft; + + if(!(nFeatures & XMLShapeExportFlags::POSITION)) + { + nFeatures |= XMLShapeExportFlags::POSITION; + aUpperLeft = xShape->getPosition(); + pRefPoint = &aUpperLeft; + } + + // write members + exportShapes( xShapes, nFeatures, pRefPoint ); +} + +void XMLShapeExport::ImpExport3DShape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + OUString aStr; + OUStringBuffer sStringBuffer; + + // transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix") + uno::Any aAny = xPropSet->getPropertyValue("D3DTransformMatrix"); + drawing::HomogenMatrix aHomMat; + aAny >>= aHomMat; + SdXMLImExTransform3D aTransform; + aTransform.AddHomogenMatrix(aHomMat); + if(aTransform.NeedsAction()) + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter())); + + switch(eShapeType) + { + case XmlShapeType::Draw3DCubeObject: + { + // minEdge + aAny = xPropSet->getPropertyValue("D3DPosition"); + drawing::Position3D aPosition3D; + aAny >>= aPosition3D; + ::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ); + + // maxEdge + aAny = xPropSet->getPropertyValue("D3DSize"); + drawing::Direction3D aDirection3D; + aAny >>= aDirection3D; + ::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ); + + // transform maxEdge from distance to pos + aDir3D = aPos3D + aDir3D; + + // write minEdge + if(aPos3D != ::basegfx::B3DVector(-2500.0, -2500.0, -2500.0)) // write only when not default + { + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aPos3D); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MIN_EDGE, aStr); + } + + // write maxEdge + if(aDir3D != ::basegfx::B3DVector(2500.0, 2500.0, 2500.0)) // write only when not default + { + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aDir3D); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MAX_EDGE, aStr); + } + + // write 3DCube shape + // #i123542# Do this *after* the attributes are added, else these will be lost since opening + // the scope will clear the global attribute list at the exporter + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_CUBE, true, true); + + break; + } + case XmlShapeType::Draw3DSphereObject: + { + // Center + aAny = xPropSet->getPropertyValue("D3DPosition"); + drawing::Position3D aPosition3D; + aAny >>= aPosition3D; + ::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ); + + // Size + aAny = xPropSet->getPropertyValue("D3DSize"); + drawing::Direction3D aDirection3D; + aAny >>= aDirection3D; + ::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ); + + // write Center + if(aPos3D != ::basegfx::B3DVector(0.0, 0.0, 0.0)) // write only when not default + { + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aPos3D); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_CENTER, aStr); + } + + // write Size + if(aDir3D != ::basegfx::B3DVector(5000.0, 5000.0, 5000.0)) // write only when not default + { + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aDir3D); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SIZE, aStr); + } + + // write 3DSphere shape + // #i123542# Do this *after* the attributes are added, else these will be lost since opening + // the scope will clear the global attribute list at the exporter + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_SPHERE, true, true); + + break; + } + case XmlShapeType::Draw3DLatheObject: + case XmlShapeType::Draw3DExtrudeObject: + { + // write special 3DLathe/3DExtrude attributes, get 3D tools::PolyPolygon as drawing::PolyPolygonShape3D + aAny = xPropSet->getPropertyValue("D3DPolyPolygon3D"); + drawing::PolyPolygonShape3D aUnoPolyPolygon3D; + aAny >>= aUnoPolyPolygon3D; + + // convert to 3D PolyPolygon + const basegfx::B3DPolyPolygon aPolyPolygon3D( + basegfx::utils::UnoPolyPolygonShape3DToB3DPolyPolygon( + aUnoPolyPolygon3D)); + + // convert to 2D tools::PolyPolygon using identity 3D transformation (just grep X and Y) + const basegfx::B3DHomMatrix aB3DHomMatrixFor2DConversion; + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon( + aPolyPolygon3D, + aB3DHomMatrixFor2DConversion)); + + // get 2D range of it + const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange()); + + // export ViewBox + SdXMLImExViewBox aViewBox( + aPolyPolygonRange.getMinX(), + aPolyPolygonRange.getMinY(), + aPolyPolygonRange.getWidth(), + aPolyPolygonRange.getHeight()); + + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString()); + + // prepare svg:d string + const OUString aPolygonString( + basegfx::utils::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers TTTT: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible + + // write point array + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString); + + if(eShapeType == XmlShapeType::Draw3DLatheObject) + { + // write 3DLathe shape + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_ROTATE, true, true); + } + else + { + // write 3DExtrude shape + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_EXTRUDE, true, true); + } + break; + } + default: + break; + } +} + +/** helper for chart that adds all attributes of a 3d scene element to the export */ +void XMLShapeExport::export3DSceneAttributes( const css::uno::Reference< css::beans::XPropertySet >& xPropSet ) +{ + OUString aStr; + OUStringBuffer sStringBuffer; + + // world transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix") + uno::Any aAny = xPropSet->getPropertyValue("D3DTransformMatrix"); + drawing::HomogenMatrix aHomMat; + aAny >>= aHomMat; + SdXMLImExTransform3D aTransform; + aTransform.AddHomogenMatrix(aHomMat); + if(aTransform.NeedsAction()) + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter())); + + // VRP, VPN, VUP + aAny = xPropSet->getPropertyValue("D3DCameraGeometry"); + drawing::CameraGeometry aCamGeo; + aAny >>= aCamGeo; + + ::basegfx::B3DVector aVRP(aCamGeo.vrp.PositionX, aCamGeo.vrp.PositionY, aCamGeo.vrp.PositionZ); + if(aVRP != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default + { + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVRP); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VRP, aStr); + } + + ::basegfx::B3DVector aVPN(aCamGeo.vpn.DirectionX, aCamGeo.vpn.DirectionY, aCamGeo.vpn.DirectionZ); + if(aVPN != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default + { + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVPN); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VPN, aStr); + } + + ::basegfx::B3DVector aVUP(aCamGeo.vup.DirectionX, aCamGeo.vup.DirectionY, aCamGeo.vup.DirectionZ); + if(aVUP != ::basegfx::B3DVector(0.0, 1.0, 0.0)) // write only when not default + { + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVUP); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VUP, aStr); + } + + // projection "D3DScenePerspective" drawing::ProjectionMode + aAny = xPropSet->getPropertyValue("D3DScenePerspective"); + drawing::ProjectionMode aPrjMode; + aAny >>= aPrjMode; + if(aPrjMode == drawing::ProjectionMode_PARALLEL) + aStr = GetXMLToken(XML_PARALLEL); + else + aStr = GetXMLToken(XML_PERSPECTIVE); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_PROJECTION, aStr); + + // distance + aAny = xPropSet->getPropertyValue("D3DSceneDistance"); + sal_Int32 nDistance = 0; + aAny >>= nDistance; + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + nDistance); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DISTANCE, aStr); + + // focalLength + aAny = xPropSet->getPropertyValue("D3DSceneFocalLength"); + sal_Int32 nFocalLength = 0; + aAny >>= nFocalLength; + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + nFocalLength); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_FOCAL_LENGTH, aStr); + + // shadowSlant + aAny = xPropSet->getPropertyValue("D3DSceneShadowSlant"); + sal_Int16 nShadowSlant = 0; + aAny >>= nShadowSlant; + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADOW_SLANT, OUString::number(static_cast<sal_Int32>(nShadowSlant))); + + // shadeMode + aAny = xPropSet->getPropertyValue("D3DSceneShadeMode"); + drawing::ShadeMode aShadeMode; + if(aAny >>= aShadeMode) + { + if(aShadeMode == drawing::ShadeMode_FLAT) + aStr = GetXMLToken(XML_FLAT); + else if(aShadeMode == drawing::ShadeMode_PHONG) + aStr = GetXMLToken(XML_PHONG); + else if(aShadeMode == drawing::ShadeMode_SMOOTH) + aStr = GetXMLToken(XML_GOURAUD); + else + aStr = GetXMLToken(XML_DRAFT); + } + else + { + // ShadeMode enum not there, write default + aStr = GetXMLToken(XML_GOURAUD); + } + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr); + + // ambientColor + aAny = xPropSet->getPropertyValue("D3DSceneAmbientColor"); + sal_Int32 nAmbientColor = 0; + aAny >>= nAmbientColor; + ::sax::Converter::convertColor(sStringBuffer, nAmbientColor); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_AMBIENT_COLOR, aStr); + + // lightingMode + aAny = xPropSet->getPropertyValue("D3DSceneTwoSidedLighting"); + bool bTwoSidedLighting = false; + aAny >>= bTwoSidedLighting; + ::sax::Converter::convertBool(sStringBuffer, bTwoSidedLighting); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_LIGHTING_MODE, aStr); +} + +/** helper for chart that exports all lamps from the propertyset */ +void XMLShapeExport::export3DLamps( const css::uno::Reference< css::beans::XPropertySet >& xPropSet ) +{ + // write lamps 1..8 as content + OUString aStr; + OUStringBuffer sStringBuffer; + + static constexpr OUStringLiteral aColorPropName(u"D3DSceneLightColor"); + static constexpr OUStringLiteral aDirectionPropName(u"D3DSceneLightDirection"); + static constexpr OUStringLiteral aLightOnPropName(u"D3DSceneLightOn"); + + ::basegfx::B3DVector aLightDirection; + drawing::Direction3D aLightDir; + bool bLightOnOff = false; + for(sal_Int32 nLamp = 1; nLamp <= 8; nLamp++) + { + OUString aIndexStr = OUString::number( nLamp ); + + // lightcolor + OUString aPropName = aColorPropName + aIndexStr; + sal_Int32 nLightColor = 0; + xPropSet->getPropertyValue( aPropName ) >>= nLightColor; + ::sax::Converter::convertColor(sStringBuffer, nLightColor); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIFFUSE_COLOR, aStr); + + // lightdirection + aPropName = aDirectionPropName + aIndexStr; + xPropSet->getPropertyValue(aPropName) >>= aLightDir; + aLightDirection = ::basegfx::B3DVector(aLightDir.DirectionX, aLightDir.DirectionY, aLightDir.DirectionZ); + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aLightDirection); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIRECTION, aStr); + + // lighton + aPropName = aLightOnPropName + aIndexStr; + xPropSet->getPropertyValue(aPropName) >>= bLightOnOff; + ::sax::Converter::convertBool(sStringBuffer, bLightOnOff); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_ENABLED, aStr); + + // specular + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SPECULAR, + nLamp == 1 ? XML_TRUE : XML_FALSE); + + // write light entry + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_LIGHT, true, true); + } +} + + +// using namespace css::io; +// using namespace ::xmloff::EnhancedCustomShapeToken; + + +static void ExportParameter( OUStringBuffer& rStrBuffer, const css::drawing::EnhancedCustomShapeParameter& rParameter ) +{ + if ( !rStrBuffer.isEmpty() ) + rStrBuffer.append( ' ' ); + if ( rParameter.Value.getValueTypeClass() == uno::TypeClass_DOUBLE ) + { + double fNumber = 0.0; + rParameter.Value >>= fNumber; + ::rtl::math::doubleToUStringBuffer( rStrBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true ); + } + else + { + sal_Int32 nValue = 0; + rParameter.Value >>= nValue; + + switch( rParameter.Type ) + { + case css::drawing::EnhancedCustomShapeParameterType::EQUATION : + { + rStrBuffer.append( "?f" + OUString::number( nValue ) ); + } + break; + + case css::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT : + { + rStrBuffer.append( '$' ); + rStrBuffer.append( nValue ); + } + break; + + case css::drawing::EnhancedCustomShapeParameterType::BOTTOM : + rStrBuffer.append( GetXMLToken( XML_BOTTOM ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::RIGHT : + rStrBuffer.append( GetXMLToken( XML_RIGHT ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::TOP : + rStrBuffer.append( GetXMLToken( XML_TOP ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::LEFT : + rStrBuffer.append( GetXMLToken( XML_LEFT ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::XSTRETCH : + rStrBuffer.append( GetXMLToken( XML_XSTRETCH ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::YSTRETCH : + rStrBuffer.append( GetXMLToken( XML_YSTRETCH ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::HASSTROKE : + rStrBuffer.append( GetXMLToken( XML_HASSTROKE ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::HASFILL : + rStrBuffer.append( GetXMLToken( XML_HASFILL ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::WIDTH : + rStrBuffer.append( GetXMLToken( XML_WIDTH ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::HEIGHT : + rStrBuffer.append( GetXMLToken( XML_HEIGHT ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::LOGWIDTH : + rStrBuffer.append( GetXMLToken( XML_LOGWIDTH ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::LOGHEIGHT : + rStrBuffer.append( GetXMLToken( XML_LOGHEIGHT ) ); break; + default : + rStrBuffer.append( nValue ); + } + } +} + +static void ImpExportEquations( SvXMLExport& rExport, const uno::Sequence< OUString >& rEquations ) +{ + sal_Int32 i; + for ( i = 0; i < rEquations.getLength(); i++ ) + { + OUString aStr= "f" + OUString::number( i ); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aStr ); + + aStr = rEquations[ i ]; + sal_Int32 nIndex = 0; + do + { + nIndex = aStr.indexOf( '?', nIndex ); + if ( nIndex != -1 ) + { + aStr = OUString::Concat(aStr.subView(0, nIndex + 1)) + "f" + + aStr.subView(nIndex + 1, aStr.getLength() - nIndex - 1); + nIndex++; + } + } while( nIndex != -1 ); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FORMULA, aStr ); + SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_EQUATION, true, true ); + } +} + +static void ImpExportHandles( SvXMLExport& rExport, const uno::Sequence< beans::PropertyValues >& rHandles ) +{ + if ( !rHandles.hasElements() ) + return; + + OUString aStr; + OUStringBuffer aStrBuffer; + + for ( const uno::Sequence< beans::PropertyValue >& rPropSeq : rHandles ) + { + bool bPosition = false; + for ( const beans::PropertyValue& rPropVal : rPropSeq ) + { + switch( EASGet( rPropVal.Name ) ) + { + case EAS_Position : + { + css::drawing::EnhancedCustomShapeParameterPair aPosition; + if ( rPropVal.Value >>= aPosition ) + { + ExportParameter( aStrBuffer, aPosition.First ); + ExportParameter( aStrBuffer, aPosition.Second ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POSITION, aStr ); + bPosition = true; + } + } + break; + case EAS_MirroredX : + { + bool bMirroredX; + if ( rPropVal.Value >>= bMirroredX ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_MIRROR_HORIZONTAL, + bMirroredX ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_MirroredY : + { + bool bMirroredY; + if ( rPropVal.Value >>= bMirroredY ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_MIRROR_VERTICAL, + bMirroredY ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_Switched : + { + bool bSwitched; + if ( rPropVal.Value >>= bSwitched ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_SWITCHED, + bSwitched ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_Polar : + { + css::drawing::EnhancedCustomShapeParameterPair aPolar; + if ( rPropVal.Value >>= aPolar ) + { + ExportParameter( aStrBuffer, aPolar.First ); + ExportParameter( aStrBuffer, aPolar.Second ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POLAR, aStr ); + } + } + break; + case EAS_RadiusRangeMinimum : + { + css::drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum; + if ( rPropVal.Value >>= aRadiusRangeMinimum ) + { + ExportParameter( aStrBuffer, aRadiusRangeMinimum ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RADIUS_RANGE_MINIMUM, aStr ); + } + } + break; + case EAS_RadiusRangeMaximum : + { + css::drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum; + if ( rPropVal.Value >>= aRadiusRangeMaximum ) + { + ExportParameter( aStrBuffer, aRadiusRangeMaximum ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RADIUS_RANGE_MAXIMUM, aStr ); + } + } + break; + case EAS_RangeXMinimum : + { + css::drawing::EnhancedCustomShapeParameter aXRangeMinimum; + if ( rPropVal.Value >>= aXRangeMinimum ) + { + ExportParameter( aStrBuffer, aXRangeMinimum ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_X_MINIMUM, aStr ); + } + } + break; + case EAS_RangeXMaximum : + { + css::drawing::EnhancedCustomShapeParameter aXRangeMaximum; + if ( rPropVal.Value >>= aXRangeMaximum ) + { + ExportParameter( aStrBuffer, aXRangeMaximum ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_X_MAXIMUM, aStr ); + } + } + break; + case EAS_RangeYMinimum : + { + css::drawing::EnhancedCustomShapeParameter aYRangeMinimum; + if ( rPropVal.Value >>= aYRangeMinimum ) + { + ExportParameter( aStrBuffer, aYRangeMinimum ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_Y_MINIMUM, aStr ); + } + } + break; + case EAS_RangeYMaximum : + { + css::drawing::EnhancedCustomShapeParameter aYRangeMaximum; + if ( rPropVal.Value >>= aYRangeMaximum ) + { + ExportParameter( aStrBuffer, aYRangeMaximum ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_Y_MAXIMUM, aStr ); + } + } + break; + default: + break; + } + } + if ( bPosition ) + SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_HANDLE, true, true ); + else + rExport.ClearAttrList(); + } +} + +static void ImpExportEnhancedPath( SvXMLExport& rExport, + const uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair >& rCoordinates, + const uno::Sequence< css::drawing::EnhancedCustomShapeSegment >& rSegments, + bool bExtended = false ) +{ + + OUString aStr; + OUStringBuffer aStrBuffer; + bool bNeedExtended = false; + + sal_Int32 i, j, k, l; + + sal_Int32 nCoords = rCoordinates.getLength(); + sal_Int32 nSegments = rSegments.getLength(); + bool bSimpleSegments = nSegments == 0; + if ( bSimpleSegments ) + nSegments = 4; + for ( j = i = 0; j < nSegments; j++ ) + { + css::drawing::EnhancedCustomShapeSegment aSegment; + if ( bSimpleSegments ) + { + // if there are not enough segments we will default them + switch( j ) + { + case 0 : + { + aSegment.Count = 1; + aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO; + } + break; + case 1 : + { + aSegment.Count = static_cast<sal_Int16>(std::min( nCoords - 1, sal_Int32(32767) )); + aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO; + } + break; + case 2 : + { + aSegment.Count = 1; + aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH; + } + break; + case 3 : + { + aSegment.Count = 1; + aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH; + } + break; + } + } + else + aSegment = rSegments[ j ]; + + if ( !aStrBuffer.isEmpty() ) + aStrBuffer.append( ' ' ); + + sal_Int32 nParameter = 0; + switch( aSegment.Command ) + { + case css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH : + aStrBuffer.append( 'Z' ); break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH : + aStrBuffer.append( 'N' ); break; + case css::drawing::EnhancedCustomShapeSegmentCommand::NOFILL : + aStrBuffer.append( 'F' ); break; + case css::drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE : + aStrBuffer.append( 'S' ); break; + + case css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO : + aStrBuffer.append( 'M' ); nParameter = 1; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::LINETO : + aStrBuffer.append( 'L' ); nParameter = 1; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::CURVETO : + aStrBuffer.append( 'C' ); nParameter = 3; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO : + aStrBuffer.append( 'T' ); nParameter = 3; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE : + aStrBuffer.append( 'U' ); nParameter = 3; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ARCTO : + aStrBuffer.append( 'A' ); nParameter = 4; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ARC : + aStrBuffer.append( 'B' ); nParameter = 4; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO : + aStrBuffer.append( 'W' ); nParameter = 4; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC : + aStrBuffer.append( 'V' ); nParameter = 4; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX : + aStrBuffer.append( 'X' ); nParameter = 1; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY : + aStrBuffer.append( 'Y' ); nParameter = 1; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::QUADRATICCURVETO : + aStrBuffer.append( 'Q' ); nParameter = 2; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ARCANGLETO : + if ( bExtended ) { + aStrBuffer.append( 'G' ); + nParameter = 2; + } else { + aStrBuffer.setLength( aStrBuffer.getLength() - 1); + bNeedExtended = true; + i += 2; + } + break; + case css::drawing::EnhancedCustomShapeSegmentCommand::DARKEN : + if ( bExtended ) + aStrBuffer.append( 'H' ); + else + bNeedExtended = true; + break; + case css::drawing::EnhancedCustomShapeSegmentCommand::DARKENLESS : + if ( bExtended ) + aStrBuffer.append( 'I' ); + else + bNeedExtended = true; + break; + case css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTEN : + if ( bExtended ) + aStrBuffer.append( 'J' ); + else + bNeedExtended = true; + break; + case css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTENLESS : + if ( bExtended ) + aStrBuffer.append( 'K' ); + else + bNeedExtended = true; + break; + default : // ups, seems to be something wrong + { + aSegment.Count = 1; + aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO; + } + break; + } + if ( nParameter ) + { + for ( k = 0; k < aSegment.Count; k++ ) + { + if ( ( i + nParameter ) <= nCoords ) + { + for ( l = 0; l < nParameter; l++ ) + { + ExportParameter( aStrBuffer, rCoordinates[ i ].First ); + ExportParameter( aStrBuffer, rCoordinates[ i++ ].Second ); + } + } + else + { + j = nSegments; // error -> exiting + break; + } + } + } + } + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( bExtended ? XML_NAMESPACE_DRAW_EXT : XML_NAMESPACE_DRAW, XML_ENHANCED_PATH, aStr ); + if (!bExtended && bNeedExtended && (rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)) + ImpExportEnhancedPath( rExport, rCoordinates, rSegments, true ); +} + +static void ImpExportEnhancedGeometry( SvXMLExport& rExport, const uno::Reference< beans::XPropertySet >& xPropSet ) +{ + bool bEquations = false; + uno::Sequence< OUString > aEquations; + + bool bHandles = false; + uno::Sequence< beans::PropertyValues > aHandles; + + uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments; + uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates; + + uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentValues; + + OUString aStr; + OUStringBuffer aStrBuffer; + double fTextRotateAngle(0.0); + double fTextPreRotateAngle(0.0); // will be consolidated with fTextRotateAngle at the end + SvXMLUnitConverter& rUnitConverter = rExport.GetMM100UnitConverter(); + + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + + // geometry + static constexpr OUString sCustomShapeGeometry( u"CustomShapeGeometry"_ustr ); + if ( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName( sCustomShapeGeometry ) ) + { + uno::Any aGeoPropSet( xPropSet->getPropertyValue( sCustomShapeGeometry ) ); + uno::Sequence< beans::PropertyValue > aGeoPropSeq; + + if ( aGeoPropSet >>= aGeoPropSeq ) + { + bool bCoordinates = false; + OUString aCustomShapeType( "non-primitive" ); + + for ( const beans::PropertyValue& rGeoProp : std::as_const(aGeoPropSeq) ) + { + switch( EASGet( rGeoProp.Name ) ) + { + case EAS_Type : + { + rGeoProp.Value >>= aCustomShapeType; + } + break; + case EAS_MirroredX : + { + bool bMirroredX; + if ( rGeoProp.Value >>= bMirroredX ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIRROR_HORIZONTAL, + bMirroredX ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_MirroredY : + { + bool bMirroredY; + if ( rGeoProp.Value >>= bMirroredY ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIRROR_VERTICAL, + bMirroredY ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_ViewBox : + { + awt::Rectangle aRect; + if ( rGeoProp.Value >>= aRect ) + { + SdXMLImExViewBox aViewBox( aRect.X, aRect.Y, aRect.Width, aRect.Height ); + rExport.AddAttribute( XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString() ); + } + } + break; + case EAS_TextPreRotateAngle : + { + rGeoProp.Value >>= fTextPreRotateAngle; + } + break; + case EAS_TextRotateAngle : + { + rGeoProp.Value >>= fTextRotateAngle; + } + break; + case EAS_Extrusion : + { + uno::Sequence< beans::PropertyValue > aExtrusionPropSeq; + if ( rGeoProp.Value >>= aExtrusionPropSeq ) + { + bool bSkewValuesProvided = false; + for ( const beans::PropertyValue& rProp : std::as_const(aExtrusionPropSeq) ) + { + switch( EASGet( rProp.Name ) ) + { + case EAS_Extrusion : + { + bool bExtrusionOn; + if ( rProp.Value >>= bExtrusionOn ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION, + bExtrusionOn ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_Brightness : + { + double fExtrusionBrightness = 0; + if ( rProp.Value >>= fExtrusionBrightness ) + { + ::sax::Converter::convertDouble( + aStrBuffer, + fExtrusionBrightness, + false, + util::MeasureUnit::PERCENT, + util::MeasureUnit::PERCENT); + aStrBuffer.append( '%' ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_BRIGHTNESS, aStr ); + } + } + break; + case EAS_Depth : + { + css::drawing::EnhancedCustomShapeParameterPair aDepthParaPair; + if ( rProp.Value >>= aDepthParaPair ) + { + double fDepth = 0; + if ( aDepthParaPair.First.Value >>= fDepth ) + { + rExport.GetMM100UnitConverter().convertDouble( aStrBuffer, fDepth ); + ExportParameter( aStrBuffer, aDepthParaPair.Second ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_DEPTH, aStr ); + } + } + } + break; + case EAS_Diffusion : + { + double fExtrusionDiffusion = 0; + if ( rProp.Value >>= fExtrusionDiffusion ) + { + ::sax::Converter::convertDouble( + aStrBuffer, + fExtrusionDiffusion, + false, + util::MeasureUnit::PERCENT, + util::MeasureUnit::PERCENT); + aStrBuffer.append( '%' ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_DIFFUSION, aStr ); + } + } + break; + case EAS_NumberOfLineSegments : + { + sal_Int32 nExtrusionNumberOfLineSegments = 0; + if ( rProp.Value >>= nExtrusionNumberOfLineSegments ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_NUMBER_OF_LINE_SEGMENTS, OUString::number( nExtrusionNumberOfLineSegments ) ); + } + break; + case EAS_LightFace : + { + bool bExtrusionLightFace; + if ( rProp.Value >>= bExtrusionLightFace ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_LIGHT_FACE, + bExtrusionLightFace ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_FirstLightHarsh : + { + bool bExtrusionFirstLightHarsh; + if ( rProp.Value >>= bExtrusionFirstLightHarsh ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_HARSH, + bExtrusionFirstLightHarsh ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_SecondLightHarsh : + { + bool bExtrusionSecondLightHarsh; + if ( rProp.Value >>= bExtrusionSecondLightHarsh ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_HARSH, + bExtrusionSecondLightHarsh ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_FirstLightLevel : + { + double fExtrusionFirstLightLevel = 0; + if ( rProp.Value >>= fExtrusionFirstLightLevel ) + { + ::sax::Converter::convertDouble( + aStrBuffer, + fExtrusionFirstLightLevel, + false, + util::MeasureUnit::PERCENT, + util::MeasureUnit::PERCENT); + aStrBuffer.append( '%' ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_LEVEL, aStr ); + } + } + break; + case EAS_SecondLightLevel : + { + double fExtrusionSecondLightLevel = 0; + if ( rProp.Value >>= fExtrusionSecondLightLevel ) + { + ::sax::Converter::convertDouble( + aStrBuffer, + fExtrusionSecondLightLevel, + false, + util::MeasureUnit::PERCENT, + util::MeasureUnit::PERCENT); + aStrBuffer.append( '%' ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_LEVEL, aStr ); + } + } + break; + case EAS_FirstLightDirection : + { + drawing::Direction3D aExtrusionFirstLightDirection; + if ( rProp.Value >>= aExtrusionFirstLightDirection ) + { + ::basegfx::B3DVector aVec3D( aExtrusionFirstLightDirection.DirectionX, aExtrusionFirstLightDirection.DirectionY, + aExtrusionFirstLightDirection.DirectionZ ); + SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_DIRECTION, aStr ); + } + } + break; + case EAS_SecondLightDirection : + { + drawing::Direction3D aExtrusionSecondLightDirection; + if ( rProp.Value >>= aExtrusionSecondLightDirection ) + { + ::basegfx::B3DVector aVec3D( aExtrusionSecondLightDirection.DirectionX, aExtrusionSecondLightDirection.DirectionY, + aExtrusionSecondLightDirection.DirectionZ ); + SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_DIRECTION, aStr ); + } + } + break; + case EAS_Metal : + { + bool bExtrusionMetal; + if ( rProp.Value >>= bExtrusionMetal ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_METAL, + bExtrusionMetal ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_MetalType : + { + // export only if ODF extensions are enabled + sal_Int16 eMetalType; + if (rProp.Value >>= eMetalType) + { + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); + if (eVersion > SvtSaveOptions::ODFSVER_013 + && (eVersion & SvtSaveOptions::ODFSVER_EXTENDED)) + { + if (eMetalType == drawing::EnhancedCustomShapeMetalType::MetalMSCompatible) + aStr = "loext:MetalMSCompatible"; + else + aStr = "draw:MetalODF"; + rExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_EXTRUSION_METAL_TYPE, aStr); + } + } + } + break; + case EAS_ShadeMode : + { + // shadeMode + drawing::ShadeMode eShadeMode; + if( rProp.Value >>= eShadeMode ) + { + if( eShadeMode == drawing::ShadeMode_FLAT ) + aStr = GetXMLToken( XML_FLAT ); + else if( eShadeMode == drawing::ShadeMode_PHONG ) + aStr = GetXMLToken( XML_PHONG ); + else if( eShadeMode == drawing::ShadeMode_SMOOTH ) + aStr = GetXMLToken( XML_GOURAUD ); + else + aStr = GetXMLToken( XML_DRAFT ); + } + else + { + // ShadeMode enum not there, write default + aStr = GetXMLToken( XML_FLAT); + } + rExport.AddAttribute( XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr ); + } + break; + case EAS_RotateAngle : + { + css::drawing::EnhancedCustomShapeParameterPair aRotateAngleParaPair; + if ( rProp.Value >>= aRotateAngleParaPair ) + { + ExportParameter( aStrBuffer, aRotateAngleParaPair.First ); + ExportParameter( aStrBuffer, aRotateAngleParaPair.Second ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ROTATION_ANGLE, aStr ); + } + } + break; + case EAS_RotationCenter : + { + drawing::Direction3D aExtrusionRotationCenter; + if ( rProp.Value >>= aExtrusionRotationCenter ) + { + ::basegfx::B3DVector aVec3D( aExtrusionRotationCenter.DirectionX, aExtrusionRotationCenter.DirectionY, + aExtrusionRotationCenter.DirectionZ ); + SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ROTATION_CENTER, aStr ); + } + } + break; + case EAS_Shininess : + { + double fExtrusionShininess = 0; + if ( rProp.Value >>= fExtrusionShininess ) + { + ::sax::Converter::convertDouble( + aStrBuffer, + fExtrusionShininess, + false, + util::MeasureUnit::PERCENT, + util::MeasureUnit::PERCENT); + aStrBuffer.append( '%' ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SHININESS, aStr ); + } + } + break; + case EAS_Skew : + { + css::drawing::EnhancedCustomShapeParameterPair aSkewParaPair; + if ( rProp.Value >>= aSkewParaPair ) + { + bSkewValuesProvided = true; + ExportParameter( aStrBuffer, aSkewParaPair.First ); + ExportParameter( aStrBuffer, aSkewParaPair.Second ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SKEW, aStr ); + } + } + break; + case EAS_Specularity : + { + double fExtrusionSpecularity = 0; + if ( rProp.Value >>= fExtrusionSpecularity ) + { + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); + if (fExtrusionSpecularity > 100.0 && eVersion >= SvtSaveOptions::ODFSVER_012 + && (eVersion & SvtSaveOptions::ODFSVER_EXTENDED)) + { + // tdf#147580 write values > 100% in loext + ::sax::Converter::convertDouble( + aStrBuffer, + fExtrusionSpecularity, + false, + util::MeasureUnit::PERCENT, + util::MeasureUnit::PERCENT); + aStrBuffer.append( '%' ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_EXTRUSION_SPECULARITY_LOEXT, aStr ); + } + // tdf#147580 ODF 1 allows arbitrary percent, later versions not + if (eVersion >= SvtSaveOptions::ODFSVER_012) + { + fExtrusionSpecularity = std::clamp<double>(fExtrusionSpecularity, 0.0, 100.0); + } + ::sax::Converter::convertDouble( + aStrBuffer, + fExtrusionSpecularity, + false, + util::MeasureUnit::PERCENT, + util::MeasureUnit::PERCENT); + aStrBuffer.append( '%' ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SPECULARITY, aStr ); + } + } + break; + case EAS_ProjectionMode : + { + drawing::ProjectionMode eProjectionMode; + if ( rProp.Value >>= eProjectionMode ) + rExport.AddAttribute( XML_NAMESPACE_DR3D, XML_PROJECTION, + eProjectionMode == drawing::ProjectionMode_PARALLEL ? GetXMLToken( XML_PARALLEL ) : GetXMLToken( XML_PERSPECTIVE ) ); + } + break; + case EAS_ViewPoint : + { + drawing::Position3D aExtrusionViewPoint; + if ( rProp.Value >>= aExtrusionViewPoint ) + { + rUnitConverter.convertPosition3D( aStrBuffer, aExtrusionViewPoint ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_VIEWPOINT, aStr ); + } + } + break; + case EAS_Origin : + { + css::drawing::EnhancedCustomShapeParameterPair aOriginParaPair; + if ( rProp.Value >>= aOriginParaPair ) + { + ExportParameter( aStrBuffer, aOriginParaPair.First ); + ExportParameter( aStrBuffer, aOriginParaPair.Second ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ORIGIN, aStr ); + } + } + break; + case EAS_Color : + { + bool bExtrusionColor; + if ( rProp.Value >>= bExtrusionColor ) + { + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_COLOR, + bExtrusionColor ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + } + break; + default: + break; + } + } + // tdf#141301: no specific skew values provided + if (!bSkewValuesProvided) + { + // so we need to export default values explicitly + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SKEW, "50 -135"); + } + } + } + break; + case EAS_TextPath : + { + uno::Sequence< beans::PropertyValue > aTextPathPropSeq; + if ( rGeoProp.Value >>= aTextPathPropSeq ) + { + for ( const beans::PropertyValue& rProp : std::as_const(aTextPathPropSeq) ) + { + switch( EASGet( rProp.Name ) ) + { + case EAS_TextPath : + { + bool bTextPathOn; + if ( rProp.Value >>= bTextPathOn ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH, + bTextPathOn ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_TextPathMode : + { + css::drawing::EnhancedCustomShapeTextPathMode eTextPathMode; + if ( rProp.Value >>= eTextPathMode ) + { + switch ( eTextPathMode ) + { + case css::drawing::EnhancedCustomShapeTextPathMode_NORMAL: aStr = GetXMLToken( XML_NORMAL ); break; + case css::drawing::EnhancedCustomShapeTextPathMode_PATH : aStr = GetXMLToken( XML_PATH ); break; + case css::drawing::EnhancedCustomShapeTextPathMode_SHAPE : aStr = GetXMLToken( XML_SHAPE ); break; + default: + break; + } + if ( !aStr.isEmpty() ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_MODE, aStr ); + } + } + break; + case EAS_ScaleX : + { + bool bScaleX; + if ( rProp.Value >>= bScaleX ) + { + aStr = bScaleX ? GetXMLToken( XML_SHAPE ) : GetXMLToken( XML_PATH ); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_SCALE, aStr ); + } + } + break; + case EAS_SameLetterHeights : + { + bool bSameLetterHeights; + if ( rProp.Value >>= bSameLetterHeights ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_SAME_LETTER_HEIGHTS, + bSameLetterHeights ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + default: + break; + } + } + } + } + break; + case EAS_Path : + { + uno::Sequence< beans::PropertyValue > aPathPropSeq; + if ( rGeoProp.Value >>= aPathPropSeq ) + { + for ( const beans::PropertyValue& rProp : std::as_const(aPathPropSeq) ) + { + switch( EASGet( rProp.Name ) ) + { + case EAS_SubViewSize: + { + // export draw:sub-view-size (do not export in ODF 1.3 or older) + if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + { + continue; + } + uno::Sequence< awt::Size > aSubViewSizes; + rProp.Value >>= aSubViewSizes; + + for ( int nIdx = 0; nIdx < aSubViewSizes.getLength(); nIdx++ ) + { + if ( nIdx ) + aStrBuffer.append(' '); + aStrBuffer.append( aSubViewSizes[nIdx].Width ); + aStrBuffer.append(' '); + aStrBuffer.append( aSubViewSizes[nIdx].Height ); + } + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW_EXT, XML_SUB_VIEW_SIZE, aStr ); + } + break; + case EAS_ExtrusionAllowed : + { + bool bExtrusionAllowed; + if ( rProp.Value >>= bExtrusionAllowed ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ALLOWED, + bExtrusionAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_ConcentricGradientFillAllowed : + { + bool bConcentricGradientFillAllowed; + if ( rProp.Value >>= bConcentricGradientFillAllowed ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONCENTRIC_GRADIENT_FILL_ALLOWED, + bConcentricGradientFillAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_TextPathAllowed : + { + bool bTextPathAllowed; + if ( rProp.Value >>= bTextPathAllowed ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_ALLOWED, + bTextPathAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_GluePoints : + { + css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> aGluePoints; + if ( rProp.Value >>= aGluePoints ) + { + if ( aGluePoints.hasElements() ) + { + for( const auto& rGluePoint : std::as_const(aGluePoints) ) + { + ExportParameter( aStrBuffer, rGluePoint.First ); + ExportParameter( aStrBuffer, rGluePoint.Second ); + } + aStr = aStrBuffer.makeStringAndClear(); + } + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GLUE_POINTS, aStr ); + } + } + break; + case EAS_GluePointType : + { + sal_Int16 nGluePointType = sal_Int16(); + if ( rProp.Value >>= nGluePointType ) + { + switch ( nGluePointType ) + { + case css::drawing::EnhancedCustomShapeGluePointType::NONE : aStr = GetXMLToken( XML_NONE ); break; + case css::drawing::EnhancedCustomShapeGluePointType::SEGMENTS : aStr = GetXMLToken( XML_SEGMENTS ); break; + case css::drawing::EnhancedCustomShapeGluePointType::RECT : aStr = GetXMLToken( XML_RECTANGLE ); break; + } + if ( !aStr.isEmpty() ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GLUE_POINT_TYPE, aStr ); + } + } + break; + case EAS_Coordinates : + { + bCoordinates = ( rProp.Value >>= aCoordinates ); + } + break; + case EAS_Segments : + { + rProp.Value >>= aSegments; + } + break; + case EAS_StretchX : + { + sal_Int32 nStretchPoint = 0; + if ( rProp.Value >>= nStretchPoint ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PATH_STRETCHPOINT_X, OUString::number( nStretchPoint ) ); + } + break; + case EAS_StretchY : + { + sal_Int32 nStretchPoint = 0; + if ( rProp.Value >>= nStretchPoint ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PATH_STRETCHPOINT_Y, OUString::number( nStretchPoint ) ); + } + break; + case EAS_TextFrames : + { + css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aPathTextFrames; + if ( rProp.Value >>= aPathTextFrames ) + { + if ( aPathTextFrames.hasElements() ) + { + for ( const auto& rPathTextFrame : std::as_const(aPathTextFrames) ) + { + ExportParameter( aStrBuffer, rPathTextFrame.TopLeft.First ); + ExportParameter( aStrBuffer, rPathTextFrame.TopLeft.Second ); + ExportParameter( aStrBuffer, rPathTextFrame.BottomRight.First ); + ExportParameter( aStrBuffer, rPathTextFrame.BottomRight.Second ); + } + aStr = aStrBuffer.makeStringAndClear(); + } + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_AREAS, aStr ); + } + } + break; + default: + break; + } + } + } + } + break; + case EAS_Equations : + { + bEquations = ( rGeoProp.Value >>= aEquations ); + } + break; + case EAS_Handles : + { + bHandles = ( rGeoProp.Value >>= aHandles ); + } + break; + case EAS_AdjustmentValues : + { + rGeoProp.Value >>= aAdjustmentValues; + } + break; + default: + break; + } + } // for + + // ToDo: Where is TextPreRotateAngle still used? We cannot save it in ODF. + fTextRotateAngle += fTextPreRotateAngle; + // Workaround for writing-mode bt-lr and tb-rl90 in ODF strict, + // otherwise loext:writing-mode is used in style export. + if (!(rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)) + { + if (xPropSetInfo->hasPropertyByName(u"WritingMode"_ustr)) + { + sal_Int16 nDirection = -1; + xPropSet->getPropertyValue(u"WritingMode"_ustr) >>= nDirection; + if (nDirection == text::WritingMode2::TB_RL90) + fTextRotateAngle -= 90; + else if (nDirection == text::WritingMode2::BT_LR) + fTextRotateAngle -= 270; + } + } + if (fTextRotateAngle != 0) + { + ::sax::Converter::convertDouble( aStrBuffer, fTextRotateAngle ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_ROTATE_ANGLE, aStr ); + } + + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TYPE, aCustomShapeType ); + + // adjustments + sal_Int32 nAdjustmentValues = aAdjustmentValues.getLength(); + if ( nAdjustmentValues ) + { + sal_Int32 i, nValue = 0; + for ( i = 0; i < nAdjustmentValues; i++ ) + { + if ( i ) + aStrBuffer.append( ' ' ); + + const css::drawing::EnhancedCustomShapeAdjustmentValue& rAdj = aAdjustmentValues[ i ]; + if ( rAdj.State == beans::PropertyState_DIRECT_VALUE ) + { + if ( rAdj.Value.getValueTypeClass() == uno::TypeClass_DOUBLE ) + { + double fValue = 0.0; + rAdj.Value >>= fValue; + ::sax::Converter::convertDouble(aStrBuffer, fValue); + } + else + { + rAdj.Value >>= nValue; + aStrBuffer.append(nValue); + } + } + else + { + // this should not be, but better than setting nothing + aStrBuffer.append("0"); + } + } + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MODIFIERS, aStr ); + } + if ( bCoordinates ) + ImpExportEnhancedPath( rExport, aCoordinates, aSegments ); + } + } + SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_ENHANCED_GEOMETRY, true, true ); + if ( bEquations ) + ImpExportEquations( rExport, aEquations ); + if ( bHandles ) + ImpExportHandles( rExport, aHandles ); +} + +void XMLShapeExport::ImpExportCustomShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint ) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if ( !xPropSet.is() ) + return; + + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + + // Transformation + ImpExportNewTrans( xPropSet, nFeatures, pRefPoint ); + + if ( xPropSetInfo.is() ) + { + OUString aStr; + if ( xPropSetInfo->hasPropertyByName( "CustomShapeEngine" ) ) + { + uno::Any aEngine( xPropSet->getPropertyValue( "CustomShapeEngine" ) ); + if ( ( aEngine >>= aStr ) && !aStr.isEmpty() ) + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ENGINE, aStr ); + } + if ( xPropSetInfo->hasPropertyByName( "CustomShapeData" ) ) + { + uno::Any aData( xPropSet->getPropertyValue( "CustomShapeData" ) ); + if ( ( aData >>= aStr ) && !aStr.isEmpty() ) + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DATA, aStr ); + } + } + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DRAW, XML_CUSTOM_SHAPE, bCreateNewline, true ); + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportText( xShape ); + ImpExportEnhancedGeometry( mrExport, xPropSet ); + +} + +void XMLShapeExport::ImpExportTableShape( const uno::Reference< drawing::XShape >& xShape, XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint ) +{ + uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY); + + SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "xmloff::XMLShapeExport::ImpExportTableShape(), table shape is not implementing needed interfaces"); + if(!(xPropSet.is() && xNamed.is())) + return; + + try + { + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + bool bIsEmptyPresObj = false; + + // presentation settings + if(eShapeType == XmlShapeType::PresTableShape) + bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_TABLE) ); + + const bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); + + SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW, XML_FRAME, bCreateNewline, true ); + + // do not export in ODF 1.1 or older + if (mrExport.getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + { + if( !bIsEmptyPresObj ) + { + uno::Reference< container::XNamed > xTemplate( xPropSet->getPropertyValue("TableTemplate"), uno::UNO_QUERY ); + if( xTemplate.is() ) + { + const OUString sTemplate( xTemplate->getName() ); + if( !sTemplate.isEmpty() ) + { + mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TEMPLATE_NAME, sTemplate ); + + for( const XMLPropertyMapEntry* pEntry = &aXMLTableShapeAttributes[0]; !pEntry->IsEnd(); pEntry++ ) + { + try + { + bool bBool = false; + xPropSet->getPropertyValue( pEntry->getApiName() ) >>= bBool; + if( bBool ) + mrExport.AddAttribute(pEntry->mnNameSpace, pEntry->meXMLName, XML_TRUE ); + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.draw"); + } + } + } + } + + uno::Reference< table::XColumnRowRange > xRange( xPropSet->getPropertyValue( gsModel ), uno::UNO_QUERY_THROW ); + GetShapeTableExport()->exportTable( xRange ); + } + } + + if( !bIsEmptyPresObj ) + { + uno::Reference< graphic::XGraphic > xGraphic( xPropSet->getPropertyValue("ReplacementGraphic"), uno::UNO_QUERY ); + ExportGraphicPreview(xGraphic, mrExport, u"TablePreview", u".svm", "image/x-vclgraphic"); + } + + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportDescription( xShape ); // #i68101# + } + catch( uno::Exception const & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.draw"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/shapeimport.cxx b/xmloff/source/draw/shapeimport.cxx new file mode 100644 index 0000000000..5186c8be2b --- /dev/null +++ b/xmloff/source/draw/shapeimport.cxx @@ -0,0 +1,951 @@ +/* -*- 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 <tools/debug.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <sal/log.hxx> +#include <comphelper/attributelist.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/text/PositionLayoutDir.hpp> +#include <com/sun/star/drawing/XShapes3.hpp> + +#include <utility> +#include <xmloff/unointerfacetouniqueidentifiermapper.hxx> + +#include <xmloff/shapeimport.hxx> +#include <xmloff/xmlstyle.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/table/XMLTableImport.hxx> +#include "eventimp.hxx" +#include "ximpshap.hxx" +#include "sdpropls.hxx" +#include <xmloff/xmlprmap.hxx> +#include "ximp3dscene.hxx" +#include "ximp3dobject.hxx" +#include "ximpgrp.hxx" +#include "ximplink.hxx" + +#include <unordered_map> +#include <string_view> +#include <vector> + +namespace { + +class ShapeGroupContext; + +} + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +namespace { + +struct ConnectionHint +{ + css::uno::Reference< css::drawing::XShape > mxConnector; + OUString aDestShapeId; + sal_Int32 nDestGlueId; + bool bStart; +}; + +} + +/** this map store all gluepoint id mappings for shapes that had user defined gluepoints. This + is needed because on insertion the gluepoints will get a new and unique id */ +typedef std::map<sal_Int32,sal_Int32> GluePointIdMap; +typedef std::unordered_map< css::uno::Reference < css::drawing::XShape >, GluePointIdMap > ShapeGluePointsMap; + +/** this struct is created for each startPage() call and stores information that is needed during + import of shapes for one page. Since pages could be nested ( notes pages inside impress ) there + is a pointer so one can build up a stack of this structs */ +struct XMLShapeImportPageContextImpl +{ + ShapeGluePointsMap maShapeGluePointsMap; + + uno::Reference < drawing::XShapes > mxShapes; + + std::shared_ptr<XMLShapeImportPageContextImpl> mpNext; +}; + +/** this class is to enable adding members to the XMLShapeImportHelper without getting incompatible */ +struct XMLShapeImportHelperImpl +{ + // context for sorting shapes + std::shared_ptr<ShapeGroupContext> mpGroupContext; + + std::vector<ConnectionHint> maConnections; + + // #88546# possibility to switch progress bar handling on/off + bool mbHandleProgressBar; + + // stores the capability of the current model to create presentation shapes + bool mbIsPresentationShapesSupported; +}; + +constexpr OUStringLiteral gsStartShape(u"StartShape"); +constexpr OUStringLiteral gsEndShape(u"EndShape"); +constexpr OUStringLiteral gsStartGluePointIndex(u"StartGluePointIndex"); +constexpr OUStringLiteral gsEndGluePointIndex(u"EndGluePointIndex"); + +XMLShapeImportHelper::XMLShapeImportHelper( + SvXMLImport& rImporter, + const uno::Reference< frame::XModel>& rModel, + SvXMLImportPropertyMapper *pExtMapper ) +: mpImpl( new XMLShapeImportHelperImpl ), + mrImporter( rImporter ) +{ + mpImpl->mpGroupContext = nullptr; + + // #88546# init to sal_False + mpImpl->mbHandleProgressBar = false; + + mpSdPropHdlFactory = new XMLSdPropHdlFactory( rModel, rImporter ); + + // construct PropertySetMapper + rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper(mpSdPropHdlFactory, false); + mpPropertySetMapper = new SvXMLImportPropertyMapper( xMapper, rImporter ); + + if( pExtMapper ) + { + rtl::Reference < SvXMLImportPropertyMapper > xExtMapper( pExtMapper ); + mpPropertySetMapper->ChainImportMapper( xExtMapper ); + } + + // chain text attributes + mpPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaExtPropMapper(rImporter)); + mpPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaDefaultExtPropMapper(rImporter)); + + // construct PresPagePropsMapper + xMapper = new XMLPropertySetMapper(aXMLSDPresPageProps, mpSdPropHdlFactory, false); + mpPresPagePropsMapper = new SvXMLImportPropertyMapper( xMapper, rImporter ); + + uno::Reference< lang::XServiceInfo > xInfo( rImporter.GetModel(), uno::UNO_QUERY ); + mpImpl->mbIsPresentationShapesSupported = xInfo.is() && xInfo->supportsService( "com.sun.star.presentation.PresentationDocument" ); +} + +XMLShapeImportHelper::~XMLShapeImportHelper() +{ + SAL_WARN_IF( !mpImpl->maConnections.empty(), "xmloff", "XMLShapeImportHelper::restoreConnections() was not called!" ); + + // cleanup factory, decrease refcount. Should lead to destruction. + mpSdPropHdlFactory.clear(); + + // cleanup mapper, decrease refcount. Should lead to destruction. + mpPropertySetMapper.clear(); + + // cleanup presPage mapper, decrease refcount. Should lead to destruction. + mpPresPagePropsMapper.clear(); + + // Styles or AutoStyles context? + if(mxStylesContext.is()) + mxStylesContext->dispose(); + + if(mxAutoStylesContext.is()) + mxAutoStylesContext->dispose(); +} + + +SvXMLShapeContext* XMLShapeImportHelper::Create3DSceneChildContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +{ + SdXMLShapeContext *pContext = nullptr; + + if(rShapes.is()) + { + switch(nElement) + { + case XML_ELEMENT(DR3D, XML_SCENE): + { + // dr3d:3dscene inside dr3d:3dscene context + pContext = new SdXML3DSceneShapeContext( rImport, xAttrList, rShapes, false); + break; + } + case XML_ELEMENT(DR3D, XML_CUBE): + { + // dr3d:3dcube inside dr3d:3dscene context + pContext = new SdXML3DCubeObjectShapeContext( rImport, xAttrList, rShapes); + break; + } + case XML_ELEMENT(DR3D, XML_SPHERE): + { + // dr3d:3dsphere inside dr3d:3dscene context + pContext = new SdXML3DSphereObjectShapeContext( rImport, xAttrList, rShapes); + break; + } + case XML_ELEMENT(DR3D, XML_ROTATE): + { + // dr3d:3dlathe inside dr3d:3dscene context + pContext = new SdXML3DLatheObjectShapeContext( rImport, xAttrList, rShapes); + break; + } + case XML_ELEMENT(DR3D, XML_EXTRUDE): + { + // dr3d:3dextrude inside dr3d:3dscene context + pContext = new SdXML3DExtrudeObjectShapeContext( rImport, xAttrList, rShapes); + break; + } + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + } + + if (!pContext) + return nullptr; + + // now parse the attribute list and call the child context for each unknown attribute + for(auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + if (!pContext->processAttribute( aIter )) + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + + } + + return pContext; +} + +void XMLShapeImportHelper::SetStylesContext(SvXMLStylesContext* pNew) +{ + mxStylesContext.set(pNew); +} + +void XMLShapeImportHelper::SetAutoStylesContext(SvXMLStylesContext* pNew) +{ + mxAutoStylesContext.set(pNew); +} + +SvXMLShapeContext* XMLShapeImportHelper::CreateGroupChildContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +{ + SdXMLShapeContext *pContext = nullptr; + switch (nElement) + { + case XML_ELEMENT(DRAW, XML_G): + // draw:g inside group context (RECURSIVE) + pContext = new SdXMLGroupShapeContext( rImport, xAttrList, rShapes, bTemporaryShape); + break; + case XML_ELEMENT(DR3D, XML_SCENE): + { + // dr3d:3dscene inside group context + pContext = new SdXML3DSceneShapeContext( rImport, xAttrList, rShapes, bTemporaryShape); + break; + } + case XML_ELEMENT(DRAW, XML_RECT): + { + // draw:rect inside group context + pContext = new SdXMLRectShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_LINE): + { + // draw:line inside group context + pContext = new SdXMLLineShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_CIRCLE): + case XML_ELEMENT(DRAW, XML_ELLIPSE): + { + // draw:circle or draw:ellipse inside group context + pContext = new SdXMLEllipseShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_POLYGON): + case XML_ELEMENT(DRAW, XML_POLYLINE): + { + // draw:polygon or draw:polyline inside group context + pContext = new SdXMLPolygonShapeContext( rImport, xAttrList, rShapes, + nElement == XML_ELEMENT(DRAW, XML_POLYGON), bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_PATH): + { + // draw:path inside group context + pContext = new SdXMLPathShapeContext( rImport, xAttrList, rShapes, bTemporaryShape); + break; + } + case XML_ELEMENT(DRAW, XML_FRAME): + { + // text:text-box inside group context + pContext = new SdXMLFrameShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_CONTROL): + { + // draw:control inside group context + pContext = new SdXMLControlShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_CONNECTOR): + { + // draw:connector inside group context + pContext = new SdXMLConnectorShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_MEASURE): + { + // draw:measure inside group context + pContext = new SdXMLMeasureShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_PAGE_THUMBNAIL): + { + // draw:page inside group context + pContext = new SdXMLPageShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_CAPTION): + case XML_ELEMENT(OFFICE, XML_ANNOTATION): + { + // draw:caption inside group context + pContext = new SdXMLCaptionShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(CHART, XML_CHART): + { + // chart:chart inside group context + pContext = new SdXMLChartShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_CUSTOM_SHAPE): + { + // draw:customshape + pContext = new SdXMLCustomShapeContext( rImport, xAttrList, rShapes ); + break; + } + case XML_ELEMENT(DRAW, XML_A): + return new SdXMLShapeLinkContext( rImport, xAttrList, rShapes ); + // add other shapes here... + default: + XMLOFF_INFO_UNKNOWN_ELEMENT("xmloff", nElement); + return new SvXMLShapeContext( rImport, bTemporaryShape ); + } + + // now parse the attribute list and call the child context for each unknown attribute + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if (!pContext->processAttribute( aIter )) + XMLOFF_INFO_UNKNOWN("xmloff", aIter); + } + return pContext; +} + +// This method is called from SdXMLFrameShapeContext to create children of draw:frame +SvXMLShapeContext* XMLShapeImportHelper::CreateFrameChildContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& rAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + const uno::Reference< xml::sax::XFastAttributeList>& rFrameAttrList) +{ + SdXMLShapeContext *pContext = nullptr; + + rtl::Reference<sax_fastparser::FastAttributeList> xCombinedAttrList = new sax_fastparser::FastAttributeList(rAttrList); + if( rFrameAttrList.is() ) + xCombinedAttrList->add(rFrameAttrList); + + switch(nElement) + { + case XML_ELEMENT(DRAW, XML_TEXT_BOX): + { + // text:text-box inside group context + pContext = new SdXMLTextBoxShapeContext( rImport, xCombinedAttrList, rShapes ); + break; + } + case XML_ELEMENT(DRAW, XML_IMAGE): + { + // office:image inside group context + pContext = new SdXMLGraphicObjectShapeContext( rImport, xCombinedAttrList, rShapes ); + break; + } + case XML_ELEMENT(DRAW, XML_OBJECT): + case XML_ELEMENT(DRAW, XML_OBJECT_OLE): + { + // draw:object or draw:object_ole + pContext = new SdXMLObjectShapeContext( rImport, xCombinedAttrList, rShapes ); + break; + } + case XML_ELEMENT(TABLE, XML_TABLE): + { + // draw:object or draw:object_ole + if( rImport.IsTableShapeSupported() ) + pContext = new SdXMLTableShapeContext( rImport, xCombinedAttrList, rShapes ); + break; + + } + case XML_ELEMENT(DRAW, XML_PLUGIN): + { + // draw:plugin + pContext = new SdXMLPluginShapeContext( rImport, xCombinedAttrList, rShapes ); + break; + } + case XML_ELEMENT(DRAW, XML_FLOATING_FRAME): + { + // draw:floating-frame + pContext = new SdXMLFloatingFrameShapeContext( rImport, xCombinedAttrList, rShapes ); + break; + } + case XML_ELEMENT(DRAW, XML_APPLET): + { + // draw:applet + pContext = new SdXMLAppletShapeContext( rImport, xCombinedAttrList, rShapes ); + break; + } + // add other shapes here... + default: + SAL_INFO("xmloff", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement)); + break; + } + + if( pContext ) + { + // now parse the attribute list and call the child context for each unknown attribute + for(auto& aIter : *xCombinedAttrList) + { + if (!pContext->processAttribute( aIter )) + SAL_INFO("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << " value=" << aIter.toString()); + } + } + + return pContext; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLShapeImportHelper::CreateFrameChildContext( + SvXMLImportContext *pThisContext, + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + css::uno::Reference< css::xml::sax::XFastContextHandler > xContext; + SdXMLFrameShapeContext *pFrameContext = dynamic_cast<SdXMLFrameShapeContext*>( pThisContext ); + if (pFrameContext) + xContext = pFrameContext->createFastChildContext( nElement, xAttrList ); + + if (!xContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return xContext; +} + +/** this function is called whenever the implementation classes like to add this new + shape to the given XShapes. +*/ +void XMLShapeImportHelper::addShape( uno::Reference< drawing::XShape >& rShape, + const uno::Reference< xml::sax::XFastAttributeList >&, + uno::Reference< drawing::XShapes >& rShapes) +{ + if( rShape.is() && rShapes.is() ) + { + // add new shape to parent + rShapes->add( rShape ); + + uno::Reference<beans::XPropertySet> xPropertySet(rShape, uno::UNO_QUERY); + if (xPropertySet.is()) + { + static constexpr OUStringLiteral sHandlePathObjScale = u"HandlePathObjScale"; + xPropertySet->setPropertyValue(sHandlePathObjScale, uno::Any(true)); + } + } +} + +/** this function is called whenever the implementation classes have finished importing + a shape to the given XShapes. The shape is already inserted into its XShapes and + all properties and styles are set. +*/ +void XMLShapeImportHelper::finishShape( + css::uno::Reference< css::drawing::XShape >& rShape, + const css::uno::Reference< css::xml::sax::XFastAttributeList >&, + css::uno::Reference< css::drawing::XShapes >&) +{ + /* Set property <PositionLayoutDir> + to <PositionInHoriL2R>, if it exists and the import states that + the shape positioning attributes are in horizontal left-to-right + layout. This is the case for the OpenOffice.org file format. + This setting is done for Writer documents, because the property + only exists at service css::text::Shape - the Writer + UNO service for shapes. + The value indicates that the positioning attributes are given + in horizontal left-to-right layout. The property is evaluated + during the first positioning of the shape in order to convert + the shape position given in the OpenOffice.org file format to + the one for the OASIS Open Office file format. (#i28749#, #i36248#) + */ + uno::Reference< beans::XPropertySet > xPropSet(rShape, uno::UNO_QUERY); + if ( xPropSet.is() ) + { + if ( mrImporter.IsShapePositionInHoriL2R() && + xPropSet->getPropertySetInfo()->hasPropertyByName( + "PositionLayoutDir") ) + { + uno::Any aPosLayoutDir; + aPosLayoutDir <<= text::PositionLayoutDir::PositionInHoriL2R; + xPropSet->setPropertyValue( "PositionLayoutDir", aPosLayoutDir ); + } + } +} + +namespace { + +// helper functions for z-order sorting +struct ZOrderHint +{ + sal_Int32 nIs; + sal_Int32 nShould; + /// The hint is for this shape. We don't use uno::Reference here to speed up + /// some operations, and because this shape is always held by mxShapes + drawing::XShape* pShape; + + bool operator<(const ZOrderHint& rComp) const { return nShould < rComp.nShould; } +}; + +// a) handle z-order of group contents after it has been imported +// b) apply group events over group contents after it has been imported +class ShapeGroupContext +{ +public: + uno::Reference< drawing::XShapes > mxShapes; + std::vector<SdXMLEventContextData> maEventData; + std::vector<ZOrderHint> maZOrderList; + std::vector<ZOrderHint> maUnsortedList; + + sal_Int32 mnCurrentZ; + std::shared_ptr<ShapeGroupContext> mpParentContext; + + ShapeGroupContext( uno::Reference< drawing::XShapes > xShapes, std::shared_ptr<ShapeGroupContext> pParentContext ); + + void popGroupAndPostProcess(); +private: + void moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos ); +}; + +} + +ShapeGroupContext::ShapeGroupContext( uno::Reference< drawing::XShapes > xShapes, std::shared_ptr<ShapeGroupContext> pParentContext ) +: mxShapes(std::move( xShapes )), mnCurrentZ( 0 ), mpParentContext( std::move(pParentContext) ) +{ +} + +void ShapeGroupContext::moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos ) +{ + uno::Any aAny( mxShapes->getByIndex( nSourcePos ) ); + uno::Reference< beans::XPropertySet > xPropSet; + aAny >>= xPropSet; + + if( !(xPropSet.is() && xPropSet->getPropertySetInfo()->hasPropertyByName( "ZOrder" )) ) + return; + + xPropSet->setPropertyValue( "ZOrder", uno::Any(nDestPos) ); + + for( ZOrderHint& rHint : maZOrderList ) + { + if( rHint.nIs < nSourcePos ) + { + DBG_ASSERT(rHint.nIs >= nDestPos, "Shape sorting failed" ); + rHint.nIs++; + } + } + + for( ZOrderHint& rHint : maUnsortedList ) + { + if( rHint.nIs < nSourcePos ) + { + SAL_WARN_IF( rHint.nIs < nDestPos, "xmloff", "shape sorting failed" ); + rHint.nIs++; + } + } +} + +// sort shapes +void ShapeGroupContext::popGroupAndPostProcess() +{ + if (!maEventData.empty()) + { + // tdf#127791 wait until a group is popped to set its event data + for (auto& event : maEventData) + event.ApplyProperties(); + maEventData.clear(); + } + + // only do something if we have shapes to sort + if( maZOrderList.empty() ) + return; + + // check if there are more shapes than inserted with ::shapeWithZIndexAdded() + // This can happen if there where already shapes on the page before import + // Since the writer may delete some of this shapes during import, we need + // to do this here and not in our c'tor anymore + + // check if we have more shapes than we know of + sal_Int32 nCount = mxShapes->getCount(); + + nCount -= maZOrderList.size(); + nCount -= maUnsortedList.size(); + + if( nCount > 0 ) + { + // first update offsets of added shapes + for (ZOrderHint& rHint : maZOrderList) + rHint.nIs += nCount; + for (ZOrderHint& rHint : maUnsortedList) + rHint.nIs += nCount; + + // second add the already existing shapes in the unsorted list + ZOrderHint aNewHint; + aNewHint.pShape = nullptr; + do + { + nCount--; + + aNewHint.nIs = nCount; + aNewHint.nShould = -1; + + maUnsortedList.insert(maUnsortedList.begin(), aNewHint); + } + while( nCount ); + } + + bool bSorted = std::is_sorted(maZOrderList.begin(), maZOrderList.end(), + [](const ZOrderHint& rLeft, const ZOrderHint& rRight) + { return rLeft.nShould < rRight.nShould; } ); + + if (bSorted) + return; // nothin' to do + + // sort z-ordered shapes by nShould field + std::sort(maZOrderList.begin(), maZOrderList.end()); + + uno::Reference<drawing::XShapes3> xShapes3(mxShapes, uno::UNO_QUERY); + if( xShapes3.is()) + { + uno::Sequence<sal_Int32> aNewOrder(maZOrderList.size() + maUnsortedList.size()); + auto pNewOrder = aNewOrder.getArray(); + sal_Int32 nIndex = 0; + + for (const ZOrderHint& rHint : maZOrderList) + { + // fill in the gaps from unordered list + for (std::vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; ) + { + pNewOrder[nIndex++] = (*aIt).nIs; + aIt = maUnsortedList.erase(aIt); + } + + pNewOrder[nIndex] = rHint.nIs; + nIndex++; + } + + try + { + xShapes3->sort(aNewOrder); + maZOrderList.clear(); + return; + } + catch (const css::lang::IllegalArgumentException& /*e*/) + {} + } + + // this is the current index, all shapes before that + // index are finished + sal_Int32 nIndex = 0; + for (const ZOrderHint& rHint : maZOrderList) + { + for (std::vector<ZOrderHint>::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; ) + { + moveShape( (*aIt).nIs, nIndex++ ); + aIt = maUnsortedList.erase(aIt); + + } + + if(rHint.nIs != nIndex ) + moveShape( rHint.nIs, nIndex ); + + nIndex++; + } + maZOrderList.clear(); +} + +void XMLShapeImportHelper::pushGroupForPostProcessing( uno::Reference< drawing::XShapes >& rShapes ) +{ + mpImpl->mpGroupContext = std::make_shared<ShapeGroupContext>( rShapes, mpImpl->mpGroupContext ); +} + +void XMLShapeImportHelper::addShapeEvents(SdXMLEventContextData& rData) +{ + if (mpImpl->mpGroupContext && mpImpl->mpGroupContext->mxShapes == rData.mxShape) + { + // tdf#127791 wait until a group is popped to set its event data so + // that the events are applied to all its children, which are not available + // at the start of the group tag + mpImpl->mpGroupContext->maEventData.push_back(rData); + } + else + rData.ApplyProperties(); +} + +void XMLShapeImportHelper::popGroupAndPostProcess() +{ + SAL_WARN_IF( !mpImpl->mpGroupContext, "xmloff", "No context to sort!" ); + if( !mpImpl->mpGroupContext ) + return; + + try + { + mpImpl->mpGroupContext->popGroupAndPostProcess(); + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff", "exception while sorting shapes, sorting failed"); + } + + // put parent on top and drop current context, we are done + mpImpl->mpGroupContext = mpImpl->mpGroupContext->mpParentContext; +} + +void XMLShapeImportHelper::shapeWithZIndexAdded( css::uno::Reference< css::drawing::XShape > const & xShape, sal_Int32 nZIndex ) +{ + if( !mpImpl->mpGroupContext) + return; + + ZOrderHint aNewHint; + aNewHint.nIs = mpImpl->mpGroupContext->mnCurrentZ++; + aNewHint.nShould = nZIndex; + aNewHint.pShape = xShape.get(); + + if( nZIndex == -1 ) + { + // don't care, so add to unsorted list + mpImpl->mpGroupContext->maUnsortedList.push_back(aNewHint); + } + else + { + // insert into sort list + mpImpl->mpGroupContext->maZOrderList.push_back(aNewHint); + } +} + +void XMLShapeImportHelper::shapeRemoved(const uno::Reference<drawing::XShape>& xShape) +{ + auto it = std::find_if(mpImpl->mpGroupContext->maZOrderList.begin(), mpImpl->mpGroupContext->maZOrderList.end(), [&xShape](const ZOrderHint& rHint) + { + return rHint.pShape == xShape.get(); + }); + if (it == mpImpl->mpGroupContext->maZOrderList.end()) + // Part of the unsorted list, nothing to do. + return; + + sal_Int32 nZIndex = it->nIs; + + for (it = mpImpl->mpGroupContext->maZOrderList.begin(); it != mpImpl->mpGroupContext->maZOrderList.end();) + { + if (it->nIs == nZIndex) + { + // This is xShape: remove it and adjust the max of indexes + // accordingly. + it = mpImpl->mpGroupContext->maZOrderList.erase(it); + mpImpl->mpGroupContext->mnCurrentZ--; + continue; + } + else if (it->nIs > nZIndex) + // On top of xShape: adjust actual index to reflect removal. + it->nIs--; + + // On top of or below xShape. + ++it; + } +} + +void XMLShapeImportHelper::addShapeConnection( css::uno::Reference< css::drawing::XShape > const & rConnectorShape, + bool bStart, + const OUString& rDestShapeId, + sal_Int32 nDestGlueId ) +{ + ConnectionHint aHint; + aHint.mxConnector = rConnectorShape; + aHint.bStart = bStart; + aHint.aDestShapeId = rDestShapeId; + aHint.nDestGlueId = nDestGlueId; + + mpImpl->maConnections.push_back( aHint ); +} + +void XMLShapeImportHelper::restoreConnections() +{ + const std::vector<ConnectionHint>::size_type nCount = mpImpl->maConnections.size(); + for( std::vector<ConnectionHint>::size_type i = 0; i < nCount; i++ ) + { + ConnectionHint& rHint = mpImpl->maConnections[i]; + uno::Reference< beans::XPropertySet > xConnector( rHint.mxConnector, uno::UNO_QUERY ); + if( xConnector.is() ) + { + // #86637# remember line deltas + uno::Any aLine1Delta; + uno::Any aLine2Delta; + uno::Any aLine3Delta; + OUString aStr1("EdgeLine1Delta"); + OUString aStr2("EdgeLine2Delta"); + OUString aStr3("EdgeLine3Delta"); + aLine1Delta = xConnector->getPropertyValue(aStr1); + aLine2Delta = xConnector->getPropertyValue(aStr2); + aLine3Delta = xConnector->getPropertyValue(aStr3); + + // #86637# simply setting these values WILL force the connector to do + // a new layout promptly. So the line delta values have to be rescued + // and restored around connector changes. + uno::Reference< drawing::XShape > xShape( + mrImporter.getInterfaceToIdentifierMapper().getReference( rHint.aDestShapeId ), uno::UNO_QUERY ); + if( xShape.is() ) + { + if (rHint.bStart) + xConnector->setPropertyValue( gsStartShape, uno::Any(xShape) ); + else + xConnector->setPropertyValue( gsEndShape, uno::Any(xShape) ); + + sal_Int32 nGlueId = rHint.nDestGlueId < 4 ? rHint.nDestGlueId : getGluePointId( xShape, rHint.nDestGlueId ); + if(rHint.bStart) + xConnector->setPropertyValue( gsStartGluePointIndex, uno::Any(nGlueId) ); + else + xConnector->setPropertyValue( gsEndGluePointIndex, uno::Any(nGlueId) ); + } + + // #86637# restore line deltas + xConnector->setPropertyValue(aStr1, aLine1Delta ); + xConnector->setPropertyValue(aStr2, aLine2Delta ); + xConnector->setPropertyValue(aStr3, aLine3Delta ); + } + } + mpImpl->maConnections.clear(); +} + +SvXMLImportPropertyMapper* XMLShapeImportHelper::CreateShapePropMapper( const uno::Reference< frame::XModel>& rModel, SvXMLImport& rImport ) +{ + rtl::Reference< XMLPropertyHandlerFactory > xFactory = new XMLSdPropHdlFactory( rModel, rImport ); + rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory, false ); + SvXMLImportPropertyMapper* pResult = new SvXMLImportPropertyMapper( xMapper, rImport ); + + // chain text attributes + pResult->ChainImportMapper( XMLTextImportHelper::CreateParaExtPropMapper( rImport ) ); + return pResult; +} + +/** adds a mapping for a gluepoint identifier from an xml file to the identifier created after inserting + the new gluepoint into the core. The saved mappings can be retrieved by getGluePointId() */ +void XMLShapeImportHelper::addGluePointMapping( css::uno::Reference< css::drawing::XShape > const & xShape, + sal_Int32 nSourceId, sal_Int32 nDestinnationId ) +{ + if( mpPageContext ) + mpPageContext->maShapeGluePointsMap[xShape][nSourceId] = nDestinnationId; +} + +/** moves all current DestinationId's by n */ +void XMLShapeImportHelper::moveGluePointMapping( const css::uno::Reference< css::drawing::XShape >& xShape, const sal_Int32 n ) +{ + if( mpPageContext ) + { + ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) ); + if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() ) + { + for ( auto& rShapeId : (*aShapeIter).second ) + { + if ( rShapeId.second != -1 ) + rShapeId.second += n; + } + } + } +} + +/** retrieves a mapping for a gluepoint identifier from the current xml file to the identifier created after + inserting the new gluepoint into the core. The mapping must be initialized first with addGluePointMapping() */ +sal_Int32 XMLShapeImportHelper::getGluePointId( const css::uno::Reference< css::drawing::XShape >& xShape, sal_Int32 nSourceId ) +{ + if( mpPageContext ) + { + ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) ); + if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() ) + { + GluePointIdMap::iterator aIdIter = (*aShapeIter).second.find(nSourceId); + if( aIdIter != (*aShapeIter).second.end() ) + return (*aIdIter).second; + } + } + + return -1; +} + +/** this method must be calling before the first shape is imported for the given page */ +void XMLShapeImportHelper::startPage( css::uno::Reference< css::drawing::XShapes > const & rShapes ) +{ + const std::shared_ptr<XMLShapeImportPageContextImpl> pOldContext = mpPageContext; + mpPageContext = std::make_shared<XMLShapeImportPageContextImpl>(); + mpPageContext->mpNext = pOldContext; + mpPageContext->mxShapes = rShapes; +} + +/** this method must be calling after the last shape is imported for the given page */ +void XMLShapeImportHelper::endPage( css::uno::Reference< css::drawing::XShapes > const & rShapes ) +{ + SAL_WARN_IF( !mpPageContext || (mpPageContext->mxShapes != rShapes), "xmloff", "wrong call to endPage(), no startPage called or wrong page" ); + if( nullptr == mpPageContext ) + return; + + restoreConnections(); + + mpPageContext = mpPageContext->mpNext; +} + +/** defines if the import should increment the progress bar or not */ +void XMLShapeImportHelper::enableHandleProgressBar() +{ + mpImpl->mbHandleProgressBar = true; +} + +bool XMLShapeImportHelper::IsHandleProgressBarEnabled() const +{ + return mpImpl->mbHandleProgressBar; +} + +/** queries the capability of the current model to create presentation shapes */ +bool XMLShapeImportHelper::IsPresentationShapesSupported() const +{ + return mpImpl->mbIsPresentationShapesSupported; +} + +const rtl::Reference< XMLTableImport >& XMLShapeImportHelper::GetShapeTableImport() +{ + if( !mxShapeTableImport.is() ) + { + rtl::Reference< XMLPropertyHandlerFactory > xFactory( new XMLSdPropHdlFactory( mrImporter.GetModel(), mrImporter ) ); + rtl::Reference< XMLPropertySetMapper > xPropertySetMapper( new XMLShapePropertySetMapper( xFactory, false ) ); + mxShapeTableImport = new XMLTableImport( mrImporter, xPropertySetMapper, xFactory ); + } + + return mxShapeTableImport; +} + +void SvXMLShapeContext::setHyperlink( const OUString& rHyperlink ) +{ + msHyperlink = rHyperlink; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/xexptran.cxx b/xmloff/source/draw/xexptran.cxx new file mode 100644 index 0000000000..c3ea5a4b0f --- /dev/null +++ b/xmloff/source/draw/xexptran.cxx @@ -0,0 +1,1056 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <utility> +#include <xexptran.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/diagnose.h> +#include <sax/tools/converter.hxx> +#include <xmloff/xmluconv.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/tuple/b2dtuple.hxx> +#include <basegfx/tuple/b3dtuple.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/matrix/b3dhommatrixtools.hxx> + +using namespace ::com::sun::star; + +// parsing help functions for simple chars +static void Imp_SkipSpaces(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen) +{ + while(rPos < nLen + && ' ' == rStr[rPos]) + rPos++; +} + +static void Imp_SkipSpacesAndOpeningBraces(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen) +{ + while(rPos < nLen + && (' ' == rStr[rPos] || '(' == rStr[rPos])) + rPos++; +} + +static void Imp_SkipSpacesAndCommas(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen) +{ + while(rPos < nLen + && (' ' == rStr[rPos] || ',' == rStr[rPos])) + rPos++; +} + +static void Imp_SkipSpacesAndClosingBraces(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen) +{ + while(rPos < nLen + && (' ' == rStr[rPos] || ')' == rStr[rPos])) + rPos++; +} + +// parsing help functions for integer numbers + +static bool Imp_IsOnUnitChar(std::u16string_view rStr, const sal_Int32 nPos) +{ + sal_Unicode aChar(rStr[nPos]); + + return ('a' <= aChar && 'z' >= aChar) + || ('A' <= aChar && 'Z' >= aChar) + || '%' == aChar; +} + +static double Imp_GetDoubleChar(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen, + const SvXMLUnitConverter& rConv, double fRetval, bool bLookForUnits = false) +{ + sal_Unicode aChar(rStr[rPos]); + OUStringBuffer sNumberString(32); + + if('+' == aChar || '-' == aChar) + { + sNumberString.append(rStr[rPos]); + ++rPos; + aChar = rPos >= nLen ? 0 : rStr[rPos]; + } + + while(('0' <= aChar && '9' >= aChar) + || '.' == aChar) + { + sNumberString.append(rStr[rPos]); + ++rPos; + aChar = rPos >= nLen ? 0 : rStr[rPos]; + } + + if('e' == aChar || 'E' == aChar) + { + sNumberString.append(rStr[rPos]); + ++rPos; + aChar = rPos >= nLen ? 0 : rStr[rPos]; + + if('+' == aChar || '-' == aChar) + { + sNumberString.append(rStr[rPos]); + ++rPos; + aChar = rPos >= nLen ? 0 : rStr[rPos]; + } + + while('0' <= aChar && '9' >= aChar) + { + sNumberString.append(rStr[rPos]); + ++rPos; + aChar = rPos >= nLen ? 0 : rStr[rPos]; + } + } + + if(bLookForUnits) + { + Imp_SkipSpaces(rStr, rPos, nLen); + while(rPos < nLen && Imp_IsOnUnitChar(rStr, rPos)) + sNumberString.append(rStr[rPos++]); + } + + if(!sNumberString.isEmpty()) + { + if(bLookForUnits) + rConv.convertDouble(fRetval, sNumberString); + else + { + ::sax::Converter::convertDouble(fRetval, sNumberString); + } + } + + return fRetval; +} + +static void Imp_PutDoubleChar(OUString& rStr, double fValue) +{ + OUStringBuffer sStringBuffer; + ::sax::Converter::convertDouble(sStringBuffer, fValue); + rStr += sStringBuffer; +} + +static void Imp_PutDoubleChar(OUStringBuffer& rStr, const SvXMLUnitConverter& rConv, double fValue, + bool bConvertUnits = false) +{ + OUStringBuffer sStringBuffer; + + if(bConvertUnits) + rConv.convertDouble(sStringBuffer, fValue); + else + { + ::sax::Converter::convertDouble(sStringBuffer, fValue); + } + + rStr.append(sStringBuffer); +} + +// base class of all 2D transform objects + +struct ImpSdXMLExpTransObj2DBase +{ + sal_uInt16 mnType; + explicit ImpSdXMLExpTransObj2DBase(sal_uInt16 nType) + : mnType(nType) {} +}; + +// possible object types for 2D + +#define IMP_SDXMLEXP_TRANSOBJ2D_ROTATE 0x0000 +#define IMP_SDXMLEXP_TRANSOBJ2D_SCALE 0x0001 +#define IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE 0x0002 +#define IMP_SDXMLEXP_TRANSOBJ2D_SKEWX 0x0003 +#define IMP_SDXMLEXP_TRANSOBJ2D_SKEWY 0x0004 +#define IMP_SDXMLEXP_TRANSOBJ2D_MATRIX 0x0005 + +// classes of objects, different sizes + +namespace { + +struct ImpSdXMLExpTransObj2DRotate : public ImpSdXMLExpTransObj2DBase +{ + double mfRotate; + explicit ImpSdXMLExpTransObj2DRotate(double fVal) + : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_ROTATE), mfRotate(fVal) {} +}; +struct ImpSdXMLExpTransObj2DScale : public ImpSdXMLExpTransObj2DBase +{ + ::basegfx::B2DTuple maScale; + explicit ImpSdXMLExpTransObj2DScale(const ::basegfx::B2DTuple& rNew) + : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SCALE), maScale(rNew) {} +}; +struct ImpSdXMLExpTransObj2DTranslate : public ImpSdXMLExpTransObj2DBase +{ + ::basegfx::B2DTuple maTranslate; + explicit ImpSdXMLExpTransObj2DTranslate(const ::basegfx::B2DTuple& rNew) + : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE), maTranslate(rNew) {} +}; +struct ImpSdXMLExpTransObj2DSkewX : public ImpSdXMLExpTransObj2DBase +{ + double mfSkewX; + explicit ImpSdXMLExpTransObj2DSkewX(double fVal) + : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWX), mfSkewX(fVal) {} +}; +struct ImpSdXMLExpTransObj2DSkewY : public ImpSdXMLExpTransObj2DBase +{ + double mfSkewY; + explicit ImpSdXMLExpTransObj2DSkewY(double fVal) + : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWY), mfSkewY(fVal) {} +}; +struct ImpSdXMLExpTransObj2DMatrix : public ImpSdXMLExpTransObj2DBase +{ + ::basegfx::B2DHomMatrix maMatrix; + explicit ImpSdXMLExpTransObj2DMatrix(::basegfx::B2DHomMatrix aNew) + : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_MATRIX), maMatrix(std::move(aNew)) {} +}; + +} + +// add members + +void SdXMLImExTransform2D::AddRotate(double fNew) +{ + if(fNew != 0.0) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DRotate>(fNew)); +} + +void SdXMLImExTransform2D::AddTranslate(const ::basegfx::B2DTuple& rNew) +{ + if(!rNew.equalZero()) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DTranslate>(rNew)); +} + +void SdXMLImExTransform2D::AddSkewX(double fNew) +{ + if(fNew != 0.0) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DSkewX>(fNew)); +} + +// gen string for export +const OUString& SdXMLImExTransform2D::GetExportString(const SvXMLUnitConverter& rConv) +{ + OUStringBuffer aNewString; + OUString aClosingBrace(")"); + OUString aEmptySpace(" "); + + const sal_uInt32 nCount = maList.size(); + for(sal_uInt32 a(0); a < nCount; a++) + { + ImpSdXMLExpTransObj2DBase* pObj = maList[a].get(); + switch(pObj->mnType) + { + case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE : + { + aNewString.append("rotate ("); + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DRotate*>(pObj)->mfRotate); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_SCALE : + { + aNewString.append("scale ("); + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DScale*>(pObj)->maScale.getX()); + aNewString.append(aEmptySpace); + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DScale*>(pObj)->maScale.getY()); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE : + { + aNewString.append("translate ("); + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DTranslate*>(pObj)->maTranslate.getX(), true); + aNewString.append(aEmptySpace); + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DTranslate*>(pObj)->maTranslate.getY(), true); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX : + { + aNewString.append("skewX ("); + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DSkewX*>(pObj)->mfSkewX); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY : + { + aNewString.append("skewY ("); + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DSkewY*>(pObj)->mfSkewY); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX : + { + aNewString.append("matrix ("); + + // a + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DMatrix*>(pObj)->maMatrix.get(0, 0)); + aNewString.append(aEmptySpace); + + // b + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DMatrix*>(pObj)->maMatrix.get(1, 0)); + aNewString.append(aEmptySpace); + + // c + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DMatrix*>(pObj)->maMatrix.get(0, 1)); + aNewString.append(aEmptySpace); + + // d + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DMatrix*>(pObj)->maMatrix.get(1, 1)); + aNewString.append(aEmptySpace); + + // e + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DMatrix*>(pObj)->maMatrix.get(0, 2), true); + aNewString.append(aEmptySpace); + + // f + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DMatrix*>(pObj)->maMatrix.get(1, 2), true); + + aNewString.append(aClosingBrace); + break; + } + default : + { + OSL_FAIL("SdXMLImExTransform2D: impossible entry!"); + break; + } + } + + // if not the last entry, add one space to next tag + if(a + 1 != maList.size()) + { + aNewString.append(aEmptySpace); + } + } + + // fill string form OUString + msString = aNewString.makeStringAndClear(); + + return msString; +} + +// sets new string, parses it and generates entries +void SdXMLImExTransform2D::SetString(const OUString& rNew, const SvXMLUnitConverter& rConv) +{ + msString = rNew; + maList.clear(); + + if(msString.isEmpty()) + return; + + const OUString aStr = msString; + const sal_Int32 nLen(aStr.getLength()); + + static constexpr OUStringLiteral aString_rotate( u"rotate" ); + static constexpr OUStringLiteral aString_scale( u"scale" ); + static constexpr OUStringLiteral aString_translate( u"translate" ); + static constexpr OUStringLiteral aString_skewX( u"skewX" ); + static constexpr OUStringLiteral aString_skewY( u"skewY" ); + static constexpr OUStringLiteral aString_matrix( u"matrix" ); + + sal_Int32 nPos(0); + + while(nPos < nLen) + { + // skip spaces + Imp_SkipSpaces(aStr, nPos, nLen); + + // look for tag + if(nPos < nLen) + { + if(nPos == aStr.indexOf(aString_rotate, nPos)) + { + double fValue(0.0); + nPos += 6; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue); + if(fValue != 0.0) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DRotate>(fValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_scale, nPos)) + { + ::basegfx::B2DTuple aValue(1.0, 1.0); + nPos += 5; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX())); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY())); + + if(aValue.getX() != 1.0 || aValue.getY() != 1.0) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DScale>(aValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_translate, nPos)) + { + ::basegfx::B2DTuple aValue; + nPos += 9; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX(), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY(), true)); + + if(!aValue.equalZero()) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DTranslate>(aValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_skewX, nPos)) + { + double fValue(0.0); + nPos += 5; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue); + if(fValue != 0.0) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DSkewX>(fValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_skewY, nPos)) + { + double fValue(0.0); + nPos += 5; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue); + if(fValue != 0.0) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DSkewY>(fValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_matrix, nPos)) + { + ::basegfx::B2DHomMatrix aValue; + + nPos += 6; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + + // a + aValue.set(0, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 0))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // b + aValue.set(1, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 0))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // c + aValue.set(0, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 1))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // d + aValue.set(1, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 1))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // e + aValue.set(0, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 2), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // f + aValue.set(1, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 2), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + if(!aValue.isIdentity()) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DMatrix>(aValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else + { + nPos++; + } + } + } +} + +void SdXMLImExTransform2D::GetFullTransform(::basegfx::B2DHomMatrix& rFullTrans) +{ + rFullTrans.identity(); + + const sal_uInt32 nCount = maList.size(); + for(sal_uInt32 a(0); a < nCount; a++) + { + ImpSdXMLExpTransObj2DBase* pObj = maList[a].get(); + switch(pObj->mnType) + { + case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE : + { + // #i78696# + // mfRotate is mathematically wrong oriented since we export/import the angle + // values mirrored. This error is fixed in the API, but not yet in the FileFormat. + // For the FileFormat there is a follow-up task (#i78698#) to fix this in the next + // ODF FileFormat version. For now - to emulate the old behaviour - it is necessary + // to mirror the value here + rFullTrans.rotate(static_cast<ImpSdXMLExpTransObj2DRotate*>(pObj)->mfRotate * -1.0); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_SCALE : + { + const ::basegfx::B2DTuple& rScale = static_cast<ImpSdXMLExpTransObj2DScale*>(pObj)->maScale; + rFullTrans.scale(rScale.getX(), rScale.getY()); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE : + { + const ::basegfx::B2DTuple& rTranslate = static_cast<ImpSdXMLExpTransObj2DTranslate*>(pObj)->maTranslate; + rFullTrans.translate(rTranslate.getX(), rTranslate.getY()); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX : + { + // For to get a mathematical correct matrix from already existing documents, + // mirror the value here. ODF spec is unclear about direction. + rFullTrans.shearX(-tan(static_cast<ImpSdXMLExpTransObj2DSkewX*>(pObj)->mfSkewX)); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY : + { + // LibreOffice does not write skewY, OOo neither. Such files are foreign documents + // or manually set transformations. OOo had used the value as -tan(value) before + // errors were introduced, Scribus 1.5.4 uses it as -tan(value) too, MS Office does + // not shear at all. ODF spec is unclear about direction. + rFullTrans.shearY(-tan(static_cast<ImpSdXMLExpTransObj2DSkewY*>(pObj)->mfSkewY)); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX : + { + rFullTrans *= static_cast<ImpSdXMLExpTransObj2DMatrix*>(pObj)->maMatrix; + break; + } + default : + { + OSL_FAIL("SdXMLImExTransform2D: impossible entry!"); + break; + } + } + } +} + +// base class of all 3D transform objects + +struct ImpSdXMLExpTransObj3DBase +{ + sal_uInt16 mnType; + explicit ImpSdXMLExpTransObj3DBase(sal_uInt16 nType) + : mnType(nType) {} +}; + +// possible object types for 3D + +#define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X 0x0000 +#define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y 0x0001 +#define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z 0x0002 +#define IMP_SDXMLEXP_TRANSOBJ3D_SCALE 0x0003 +#define IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE 0x0004 +#define IMP_SDXMLEXP_TRANSOBJ3D_MATRIX 0x0005 + +// classes of objects, different sizes + +namespace { + +struct ImpSdXMLExpTransObj3DRotateX : public ImpSdXMLExpTransObj3DBase +{ + double mfRotateX; + explicit ImpSdXMLExpTransObj3DRotateX(double fVal) + : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X), mfRotateX(fVal) {} +}; +struct ImpSdXMLExpTransObj3DRotateY : public ImpSdXMLExpTransObj3DBase +{ + double mfRotateY; + explicit ImpSdXMLExpTransObj3DRotateY(double fVal) + : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y), mfRotateY(fVal) {} +}; +struct ImpSdXMLExpTransObj3DRotateZ : public ImpSdXMLExpTransObj3DBase +{ + double mfRotateZ; + explicit ImpSdXMLExpTransObj3DRotateZ(double fVal) + : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z), mfRotateZ(fVal) {} +}; +struct ImpSdXMLExpTransObj3DScale : public ImpSdXMLExpTransObj3DBase +{ + ::basegfx::B3DTuple maScale; + explicit ImpSdXMLExpTransObj3DScale(const ::basegfx::B3DTuple& rNew) + : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_SCALE), maScale(rNew) {} +}; +struct ImpSdXMLExpTransObj3DTranslate : public ImpSdXMLExpTransObj3DBase +{ + ::basegfx::B3DTuple maTranslate; + explicit ImpSdXMLExpTransObj3DTranslate(const ::basegfx::B3DTuple& rNew) + : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE), maTranslate(rNew) {} +}; +struct ImpSdXMLExpTransObj3DMatrix : public ImpSdXMLExpTransObj3DBase +{ + ::basegfx::B3DHomMatrix maMatrix; + explicit ImpSdXMLExpTransObj3DMatrix(::basegfx::B3DHomMatrix aNew) + : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_MATRIX), maMatrix(std::move(aNew)) {} +}; + +} + +// add members + +void SdXMLImExTransform3D::AddMatrix(const ::basegfx::B3DHomMatrix& rNew) +{ + if(!rNew.isIdentity()) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj3DMatrix>(rNew)); +} + +void SdXMLImExTransform3D::AddHomogenMatrix(const drawing::HomogenMatrix& xHomMat) +{ + AddMatrix(basegfx::utils::UnoHomogenMatrixToB3DHomMatrix(xHomMat)); +} + +// gen string for export +const OUString& SdXMLImExTransform3D::GetExportString(const SvXMLUnitConverter& rConv) +{ + OUStringBuffer aNewString; + OUString aClosingBrace(")"); + OUString aEmptySpace(" "); + + const sal_uInt32 nCount = maList.size(); + for(sal_uInt32 a(0); a < nCount; a++) + { + ImpSdXMLExpTransObj3DBase* pObj = maList[a].get(); + switch(pObj->mnType) + { + case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X : + { + aNewString.append("rotatex ("); + Imp_PutDoubleChar(aNewString, rConv, basegfx::rad2deg( static_cast<ImpSdXMLExpTransObj3DRotateX*>(pObj)->mfRotateX) ); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y : + { + aNewString.append("rotatey ("); + Imp_PutDoubleChar(aNewString, rConv, basegfx::rad2deg( static_cast<ImpSdXMLExpTransObj3DRotateY*>(pObj)->mfRotateY) ); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z : + { + aNewString.append("rotatez ("); + Imp_PutDoubleChar(aNewString, rConv, basegfx::rad2deg( static_cast<ImpSdXMLExpTransObj3DRotateZ*>(pObj)->mfRotateZ) ); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_SCALE : + { + aNewString.append("scale ("); + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DScale*>(pObj)->maScale.getX()); + aNewString.append(aEmptySpace); + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DScale*>(pObj)->maScale.getY()); + aNewString.append(aEmptySpace); + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DScale*>(pObj)->maScale.getZ()); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE : + { + aNewString.append("translate ("); + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DTranslate*>(pObj)->maTranslate.getX(), true); + aNewString.append(aEmptySpace); + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DTranslate*>(pObj)->maTranslate.getY(), true); + aNewString.append(aEmptySpace); + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DTranslate*>(pObj)->maTranslate.getZ(), true); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX : + { + aNewString.append("matrix ("); + + // a + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(0, 0)); + aNewString.append(aEmptySpace); + + // b + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(1, 0)); + aNewString.append(aEmptySpace); + + // c + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(2, 0)); + aNewString.append(aEmptySpace); + + // d + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(0, 1)); + aNewString.append(aEmptySpace); + + // e + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(1, 1)); + aNewString.append(aEmptySpace); + + // f + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(2, 1)); + aNewString.append(aEmptySpace); + + // g + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(0, 2)); + aNewString.append(aEmptySpace); + + // h + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(1, 2)); + aNewString.append(aEmptySpace); + + // i + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(2, 2)); + aNewString.append(aEmptySpace); + + // j + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(0, 3), true); + aNewString.append(aEmptySpace); + + // k + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(1, 3), true); + aNewString.append(aEmptySpace); + + // l + Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(2, 3), true); + + aNewString.append(aClosingBrace); + break; + } + default : + { + OSL_FAIL("SdXMLImExTransform3D: impossible entry!"); + break; + } + } + + // if not the last entry, add one space to next tag + if(a + 1 != maList.size()) + { + aNewString.append(aEmptySpace); + } + } + + // fill string form OUString + msString = aNewString.makeStringAndClear(); + + return msString; +} + +// for Import: constructor with string, parses it and generates entries +SdXMLImExTransform3D::SdXMLImExTransform3D(const OUString& rNew, const SvXMLUnitConverter& rConv) +{ + SetString(rNew, rConv); +} + +// sets new string, parses it and generates entries +void SdXMLImExTransform3D::SetString(const OUString& rNew, const SvXMLUnitConverter& rConv) +{ + msString = rNew; + maList.clear(); + + if(msString.isEmpty()) + return; + + const OUString aStr = msString; + const sal_Int32 nLen(aStr.getLength()); + + static constexpr OUStringLiteral aString_rotatex( u"rotatex" ); + static constexpr OUStringLiteral aString_rotatey( u"rotatey" ); + static constexpr OUStringLiteral aString_rotatez( u"rotatez" ); + static constexpr OUStringLiteral aString_scale( u"scale" ); + static constexpr OUStringLiteral aString_translate( u"translate" ); + static constexpr OUStringLiteral aString_matrix( u"matrix" ); + + sal_Int32 nPos(0); + + while(nPos < nLen) + { + // skip spaces + Imp_SkipSpaces(aStr, nPos, nLen); + + // look for tag + if(nPos < nLen) + { + if(nPos == aStr.indexOf(aString_rotatex, nPos)) + { + double fValue(0.0); + + nPos += 7; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue); + if(fValue != 0.0) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj3DRotateX>(basegfx::deg2rad(fValue))); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_rotatey, nPos)) + { + double fValue(0.0); + + nPos += 7; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue); + if(fValue != 0.0) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj3DRotateY>(basegfx::deg2rad(fValue))); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_rotatez, nPos)) + { + double fValue(0.0); + + nPos += 7; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue); + if(fValue != 0.0) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj3DRotateZ>(basegfx::deg2rad(fValue))); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_scale, nPos)) + { + ::basegfx::B3DTuple aValue(1.0, 1.0, 1.0); + + nPos += 5; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX())); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY())); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + aValue.setZ(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getZ())); + + if(1.0 != aValue.getX() || 1.0 != aValue.getY() || 1.0 != aValue.getZ()) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj3DScale>(aValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_translate, nPos)) + { + ::basegfx::B3DTuple aValue; + + nPos += 9; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX(), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY(), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + aValue.setZ(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getZ(), true)); + + if(!aValue.equalZero()) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj3DTranslate>(aValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_matrix, nPos)) + { + ::basegfx::B3DHomMatrix aValue; + + nPos += 6; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + + // a + aValue.set(0, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 0))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // b + aValue.set(1, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 0))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // c + aValue.set(2, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 0))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // d + aValue.set(0, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 1))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // e + aValue.set(1, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 1))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // f + aValue.set(2, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 1))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // g + aValue.set(0, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 2))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // h + aValue.set(1, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 2))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // i + aValue.set(2, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 2))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // j + aValue.set(0, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 3), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // k + aValue.set(1, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 3), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // l + aValue.set(2, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 3), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + if(!aValue.isIdentity()) + maList.push_back(std::make_shared<ImpSdXMLExpTransObj3DMatrix>(aValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else + { + nPos++; + } + } + } +} + +bool SdXMLImExTransform3D::GetFullHomogenTransform(css::drawing::HomogenMatrix& xHomMat) +{ + ::basegfx::B3DHomMatrix aFullTransform; + GetFullTransform(aFullTransform); + + if(!aFullTransform.isIdentity()) + { + basegfx::utils::B3DHomMatrixToUnoHomogenMatrix(aFullTransform, xHomMat); + return true; + } + + return false; +} + +void SdXMLImExTransform3D::GetFullTransform(::basegfx::B3DHomMatrix& rFullTrans) +{ + rFullTrans.identity(); + + const sal_uInt32 nCount = maList.size(); + for(sal_uInt32 a(0); a < nCount; a++) + { + ImpSdXMLExpTransObj3DBase* pObj = maList[a].get(); + switch(pObj->mnType) + { + case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X : + { + rFullTrans.rotate(static_cast<ImpSdXMLExpTransObj3DRotateX*>(pObj)->mfRotateX, 0.0, 0.0); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y : + { + rFullTrans.rotate(0.0, static_cast<ImpSdXMLExpTransObj3DRotateY*>(pObj)->mfRotateY, 0.0); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z : + { + rFullTrans.rotate(0.0, 0.0, static_cast<ImpSdXMLExpTransObj3DRotateZ*>(pObj)->mfRotateZ); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_SCALE : + { + const ::basegfx::B3DTuple& rScale = static_cast<ImpSdXMLExpTransObj3DScale*>(pObj)->maScale; + rFullTrans.scale(rScale.getX(), rScale.getY(), rScale.getZ()); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE : + { + const ::basegfx::B3DTuple& rTranslate = static_cast<ImpSdXMLExpTransObj3DTranslate*>(pObj)->maTranslate; + rFullTrans.translate(rTranslate.getX(), rTranslate.getY(), rTranslate.getZ()); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX : + { + rFullTrans *= static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix; + break; + } + default : + { + OSL_FAIL("SdXMLImExTransform3D: impossible entry!"); + break; + } + } + } +} + +SdXMLImExViewBox::SdXMLImExViewBox(double fX, double fY, double fW, double fH) +: mfX( fX ), + mfY( fY ), + mfW( fW ), + mfH( fH ) +{ +} + +// #100617# Asked vincent hardy: svg:viewBox values may be double precision. +SdXMLImExViewBox::SdXMLImExViewBox(OUString aNew, const SvXMLUnitConverter& rConv) +: msString(std::move(aNew)), + mfX( 0.0 ), + mfY( 0.0 ), + mfW( 1000.0 ), + mfH( 1000.0 ) +{ + if(msString.isEmpty()) + return; + + const OUString aStr = msString; + const sal_Int32 nLen(aStr.getLength()); + sal_Int32 nPos(0); + + // skip starting spaces + Imp_SkipSpaces(aStr, nPos, nLen); + + // get mX, #100617# be prepared for doubles + mfX = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfX); + + // skip spaces and commas + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // get mY, #100617# be prepared for doubles + mfY = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfY); + + // skip spaces and commas + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // get mW, #100617# be prepared for doubles + mfW = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfW); + + // skip spaces and commas + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // get mH, #100617# be prepared for doubles + mfH = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfH); + +} + +const OUString& SdXMLImExViewBox::GetExportString() +{ + OUString aNewString; + OUString aEmptySpace(" "); + + Imp_PutDoubleChar(aNewString, mfX); + aNewString += aEmptySpace; + + Imp_PutDoubleChar(aNewString, mfY); + aNewString += aEmptySpace; + + Imp_PutDoubleChar(aNewString, mfW); + aNewString += aEmptySpace; + + Imp_PutDoubleChar(aNewString, mfH); + + // set new string + msString = aNewString; + + return msString; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximp3dobject.cxx b/xmloff/source/draw/ximp3dobject.cxx new file mode 100644 index 0000000000..c17defc242 --- /dev/null +++ b/xmloff/source/draw/ximp3dobject.cxx @@ -0,0 +1,369 @@ +/* -*- 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 "ximp3dobject.hxx" +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <xexptran.hxx> +#include <com/sun/star/drawing/PolyPolygonShape3D.hpp> +#include <com/sun/star/drawing/Direction3D.hpp> +#include <com/sun/star/drawing/Position3D.hpp> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + + +SdXML3DObjectContext::SdXML3DObjectContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ), + mbSetTransform( false ) +{ + for(auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + const OUString sValue = aIter.toString(); + switch(aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + { + maDrawStyleName = sValue; + break; + } + case XML_ELEMENT(DR3D, XML_TRANSFORM): + { + SdXMLImExTransform3D aTransform(sValue, GetImport().GetMM100UnitConverter()); + if(aTransform.NeedsAction()) + mbSetTransform = aTransform.GetFullHomogenTransform(mxHomMat); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXML3DObjectContext::~SdXML3DObjectContext() +{ +} + +void SdXML3DObjectContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + // set parameters + if(mbSetTransform) + { + xPropSet->setPropertyValue("D3DTransformMatrix", uno::Any(mxHomMat)); + } + + // call parent + SdXMLShapeContext::startFastElement(nElement, xAttrList); + } +} + +SdXML3DCubeObjectShapeContext::SdXML3DCubeObjectShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXML3DObjectContext( rImport, xAttrList, rShapes ), + maMinEdge(-2500.0, -2500.0, -2500.0), + maMaxEdge(2500.0, 2500.0, 2500.0) +{ + for(auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(DR3D, XML_MIN_EDGE): + { + ::basegfx::B3DVector aNewVec; + SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); + + if(aNewVec != maMinEdge) + maMinEdge = aNewVec; + break; + } + case XML_ELEMENT(DR3D, XML_MAX_EDGE): + { + ::basegfx::B3DVector aNewVec; + SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); + + if(aNewVec != maMaxEdge) + maMaxEdge = aNewVec; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXML3DCubeObjectShapeContext::~SdXML3DCubeObjectShapeContext() +{ +} + +void SdXML3DCubeObjectShapeContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // create shape + AddShape( "com.sun.star.drawing.Shape3DCubeObject" ); + if(!mxShape.is()) + return; + + // add, set style and properties from base shape + SetStyle(); + SdXML3DObjectContext::startFastElement(nElement, xAttrList); + + // set local parameters on shape + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // set parameters + drawing::Position3D aPosition3D; + drawing::Direction3D aDirection3D; + + // convert from min, max to size to be set + maMaxEdge = maMaxEdge - maMinEdge; + + aPosition3D.PositionX = maMinEdge.getX(); + aPosition3D.PositionY = maMinEdge.getY(); + aPosition3D.PositionZ = maMinEdge.getZ(); + + aDirection3D.DirectionX = maMaxEdge.getX(); + aDirection3D.DirectionY = maMaxEdge.getY(); + aDirection3D.DirectionZ = maMaxEdge.getZ(); + + xPropSet->setPropertyValue("D3DPosition", uno::Any(aPosition3D)); + xPropSet->setPropertyValue("D3DSize", uno::Any(aDirection3D)); +} + +SdXML3DSphereObjectShapeContext::SdXML3DSphereObjectShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXML3DObjectContext( rImport, xAttrList, rShapes ), + maCenter(0.0, 0.0, 0.0), + maSphereSize(5000.0, 5000.0, 5000.0) +{ + for(auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(DR3D, XML_CENTER): + { + ::basegfx::B3DVector aNewVec; + SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); + + if(aNewVec != maCenter) + maCenter = aNewVec; + break; + } + case XML_ELEMENT(DR3D, XML_SIZE): + { + ::basegfx::B3DVector aNewVec; + SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); + + if(aNewVec != maSphereSize) + maSphereSize = aNewVec; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXML3DSphereObjectShapeContext::~SdXML3DSphereObjectShapeContext() +{ +} + +void SdXML3DSphereObjectShapeContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // create shape + AddShape( "com.sun.star.drawing.Shape3DSphereObject" ); + if(!mxShape.is()) + return; + + // add, set style and properties from base shape + SetStyle(); + SdXML3DObjectContext::startFastElement(nElement, xAttrList); + + // set local parameters on shape + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // set parameters + drawing::Position3D aPosition3D; + drawing::Direction3D aDirection3D; + + aPosition3D.PositionX = maCenter.getX(); + aPosition3D.PositionY = maCenter.getY(); + aPosition3D.PositionZ = maCenter.getZ(); + + aDirection3D.DirectionX = maSphereSize.getX(); + aDirection3D.DirectionY = maSphereSize.getY(); + aDirection3D.DirectionZ = maSphereSize.getZ(); + + xPropSet->setPropertyValue("D3DPosition", uno::Any(aPosition3D)); + xPropSet->setPropertyValue("D3DSize", uno::Any(aDirection3D)); +} + +SdXML3DPolygonBasedShapeContext::SdXML3DPolygonBasedShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXML3DObjectContext( rImport, xAttrList, rShapes ) +{ + for(auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + OUString sValue = aIter.toString(); + + switch(aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_VIEWBOX): + case XML_ELEMENT(SVG_COMPAT, XML_VIEWBOX): + { + maViewBox = sValue; + break; + } + case XML_ELEMENT(SVG, XML_D): + case XML_ELEMENT(SVG_COMPAT, XML_D): + { + maPoints = sValue; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXML3DPolygonBasedShapeContext::~SdXML3DPolygonBasedShapeContext() +{ +} + +void SdXML3DPolygonBasedShapeContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + + if(!xPropSet.is()) + return; + + // set parameters + if(!maPoints.isEmpty() && !maViewBox.isEmpty()) + { + // import 2d tools::PolyPolygon from svg:d + basegfx::B2DPolyPolygon aPolyPolygon; + + if(basegfx::utils::importFromSvgD(aPolyPolygon, maPoints, GetImport().needFixPositionAfterZ(), nullptr)) + { + // convert to 3D PolyPolygon + const basegfx::B3DPolyPolygon aB3DPolyPolygon( + basegfx::utils::createB3DPolyPolygonFromB2DPolyPolygon( + aPolyPolygon)); + + // convert to UNO API class PolyPolygonShape3D + drawing::PolyPolygonShape3D aPolyPolygon3D; + basegfx::utils::B3DPolyPolygonToUnoPolyPolygonShape3D( + aB3DPolyPolygon, + aPolyPolygon3D); + + // set polygon data + xPropSet->setPropertyValue("D3DPolyPolygon3D", uno::Any(aPolyPolygon3D)); + } + else + { + OSL_ENSURE(false, "Error on importing svg:d for 3D tools::PolyPolygon (!)"); + } + } + + // call parent + SdXML3DObjectContext::startFastElement(nElement, xAttrList); +} + + +SdXML3DLatheObjectShapeContext::SdXML3DLatheObjectShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXML3DPolygonBasedShapeContext( rImport, xAttrList, rShapes ) +{ +} + +SdXML3DLatheObjectShapeContext::~SdXML3DLatheObjectShapeContext() +{ +} + +void SdXML3DLatheObjectShapeContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // create shape + AddShape( "com.sun.star.drawing.Shape3DLatheObject" ); + if(mxShape.is()) + { + // add, set style and properties from base shape + SetStyle(); + SdXML3DPolygonBasedShapeContext::startFastElement(nElement, xAttrList); + } +} + +SdXML3DExtrudeObjectShapeContext::SdXML3DExtrudeObjectShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXML3DPolygonBasedShapeContext( rImport, xAttrList, rShapes ) +{ +} + +SdXML3DExtrudeObjectShapeContext::~SdXML3DExtrudeObjectShapeContext() +{ +} + +void SdXML3DExtrudeObjectShapeContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + AddShape( "com.sun.star.drawing.Shape3DExtrudeObject" ); + if(mxShape.is()) + { + // add, set style and properties from base shape + SetStyle(); + SdXML3DPolygonBasedShapeContext::startFastElement(nElement, xAttrList); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximp3dobject.hxx b/xmloff/source/draw/ximp3dobject.hxx new file mode 100644 index 0000000000..2862d094db --- /dev/null +++ b/xmloff/source/draw/ximp3dobject.hxx @@ -0,0 +1,136 @@ +/* -*- 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 . + */ + +#pragma once + +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/drawing/HomogenMatrix.hpp> +#include "ximpshap.hxx" + +// common shape context + +class SdXML3DObjectContext : public SdXMLShapeContext +{ + // the shape group this object should be created inside + + css::drawing::HomogenMatrix mxHomMat; + bool mbSetTransform; + +public: + + SdXML3DObjectContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXML3DObjectContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +// dr3d:3dcube context + +class SdXML3DCubeObjectShapeContext : public SdXML3DObjectContext +{ + ::basegfx::B3DVector maMinEdge; + ::basegfx::B3DVector maMaxEdge; + +public: + + SdXML3DCubeObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXML3DCubeObjectShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +// dr3d:3dsphere context + +class SdXML3DSphereObjectShapeContext : public SdXML3DObjectContext +{ + ::basegfx::B3DVector maCenter; + ::basegfx::B3DVector maSphereSize; + +public: + + SdXML3DSphereObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXML3DSphereObjectShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +// polygonbased context + +class SdXML3DPolygonBasedShapeContext : public SdXML3DObjectContext +{ + OUString maPoints; + OUString maViewBox; + +public: + + SdXML3DPolygonBasedShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXML3DPolygonBasedShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +// dr3d:3dlathe context + +class SdXML3DLatheObjectShapeContext : public SdXML3DPolygonBasedShapeContext +{ +public: + + SdXML3DLatheObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXML3DLatheObjectShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +// dr3d:3dextrude context + +class SdXML3DExtrudeObjectShapeContext : public SdXML3DPolygonBasedShapeContext +{ +public: + + SdXML3DExtrudeObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXML3DExtrudeObjectShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximp3dscene.cxx b/xmloff/source/draw/ximp3dscene.cxx new file mode 100644 index 0000000000..31da3652e3 --- /dev/null +++ b/xmloff/source/draw/ximp3dscene.cxx @@ -0,0 +1,441 @@ +/* -*- 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 <sax/tools/converter.hxx> +#include <rtl/math.hxx> +#include <sal/log.hxx> + +#include "ximp3dscene.hxx" +#include <xmloff/xmluconv.hxx> +#include <xexptran.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/Direction3D.hpp> +#include <com/sun/star/drawing/CameraGeometry.hpp> +#include "eventimp.hxx" +#include "descriptionimp.hxx" + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +// dr3d:3dlight context + +SdXML3DLightContext::SdXML3DLightContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +: SvXMLImportContext( rImport ), + maDiffuseColor(0x00000000), + maDirection(0.0, 0.0, 1.0), + mbEnabled(false), + mbSpecular(false) +{ + // read attributes for the 3DScene + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(DR3D, XML_DIFFUSE_COLOR): + { + ::sax::Converter::convertColor(maDiffuseColor, aIter.toView()); + break; + } + case XML_ELEMENT(DR3D, XML_DIRECTION): + { + ::basegfx::B3DVector aVal; + SvXMLUnitConverter::convertB3DVector(aVal, aIter.toView()); + if (!std::isnan(aVal.getX()) && !std::isnan(aVal.getY()) && !std::isnan(aVal.getZ())) + { + maDirection = aVal; + } + else + { + SAL_WARN("xmloff", "NaNs found in light direction: " << aIter.toString()); + } + break; + } + case XML_ELEMENT(DR3D, XML_ENABLED): + { + (void)::sax::Converter::convertBool(mbEnabled, aIter.toView()); + break; + } + case XML_ELEMENT(DR3D, XML_SPECULAR): + { + (void)::sax::Converter::convertBool(mbSpecular, aIter.toView()); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXML3DLightContext::~SdXML3DLightContext() +{ +} + + +SdXML3DSceneShapeContext::SdXML3DSceneShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShapes ), SdXML3DSceneAttributesHelper( rImport ) +{ +} + +SdXML3DSceneShapeContext::~SdXML3DSceneShapeContext() +{ +} + +void SdXML3DSceneShapeContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // create new 3DScene shape and add it to rShapes, use it + // as base for the new 3DScene import + AddShape( "com.sun.star.drawing.Shape3DSceneObject" ); + if( mxShape.is() ) + { + SetStyle(); + + mxChildren.set( mxShape, uno::UNO_QUERY ); + if( mxChildren.is() ) + GetImport().GetShapeImport()->pushGroupForPostProcessing( mxChildren ); + + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + } + + // read attributes for the 3DScene + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + processSceneAttribute( aIter ); + + // #91047# call parent function is missing here, added it + if(mxShape.is()) + { + // call parent + SdXMLShapeContext::startFastElement(nElement, xAttrList); + } +} + +void SdXML3DSceneShapeContext::endFastElement(sal_Int32 nElement) +{ + if(!mxShape.is()) + return; + + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + setSceneAttributes( xPropSet ); + } + + if( mxChildren.is() ) + GetImport().GetShapeImport()->popGroupAndPostProcess(); + + // call parent + SdXMLShapeContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXML3DSceneShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + switch (nElement) + { + // #i68101# + case XML_ELEMENT(SVG, XML_TITLE): + case XML_ELEMENT(SVG_COMPAT, XML_TITLE): + case XML_ELEMENT(SVG, XML_DESC): + case XML_ELEMENT(SVG_COMPAT, XML_DESC): + xContext = new SdXMLDescriptionContext( GetImport(), nElement, mxShape ); + break; + case XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS): + xContext = new SdXMLEventsContext( GetImport(), mxShape ); + break; + // look for local light context first + case XML_ELEMENT(DR3D, XML_LIGHT): + // dr3d:light inside dr3d:scene context + xContext = create3DLightContext( xAttrList ); + break; + default: + // call GroupChildContext function at common ShapeImport + return XMLShapeImportHelper::Create3DSceneChildContext( + GetImport(), nElement, xAttrList, mxChildren); + } + return xContext; +} + +SdXML3DSceneAttributesHelper::SdXML3DSceneAttributesHelper( SvXMLImport& rImporter ) +: mrImport( rImporter ), + mbSetTransform( false ), + mxPrjMode(drawing::ProjectionMode_PERSPECTIVE), + mnDistance(1000), + mnFocalLength(1000), + mnShadowSlant(0), + mxShadeMode(drawing::ShadeMode_SMOOTH), + maAmbientColor(0x00666666), + mbLightingMode(false), + maVRP(0.0, 0.0, 1.0), + maVPN(0.0, 0.0, 1.0), + maVUP(0.0, 1.0, 0.0), + mbVRPUsed(false) +{ +} + +/** creates a 3d light context and adds it to the internal list for later processing */ +SvXMLImportContext * SdXML3DSceneAttributesHelper::create3DLightContext( const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + const rtl::Reference<SdXML3DLightContext> xContext{new SdXML3DLightContext(mrImport, xAttrList)}; + + // remember SdXML3DLightContext for later evaluation + maList.push_back(xContext); + + return xContext.get(); +} + +/** this should be called for each scene attribute */ +void SdXML3DSceneAttributesHelper::processSceneAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + auto nAttributeToken = aIter.getToken(); + if( !IsTokenInNamespace(nAttributeToken, XML_NAMESPACE_DR3D) ) + return; + + switch(nAttributeToken & TOKEN_MASK) + { + case XML_TRANSFORM: + { + SdXMLImExTransform3D aTransform(aIter.toString(), mrImport.GetMM100UnitConverter()); + if(aTransform.NeedsAction()) + mbSetTransform = aTransform.GetFullHomogenTransform(mxHomMat); + return; + } + case XML_VRP: + { + ::basegfx::B3DVector aNewVec; + SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); + + if(aNewVec != maVRP) + { + maVRP = aNewVec; + mbVRPUsed = true; + } + return; + } + case XML_VPN: + { + ::basegfx::B3DVector aNewVec; + SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); + + if(aNewVec != maVPN) + { + maVPN = aNewVec; + } + return; + } + case XML_VUP: + { + ::basegfx::B3DVector aNewVec; + SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); + + if(aNewVec != maVUP) + { + maVUP = aNewVec; + } + return; + } + case XML_PROJECTION: + { + if( IsXMLToken( aIter, XML_PARALLEL ) ) + mxPrjMode = drawing::ProjectionMode_PARALLEL; + else + mxPrjMode = drawing::ProjectionMode_PERSPECTIVE; + return; + } + case XML_DISTANCE: + { + mrImport.GetMM100UnitConverter().convertMeasureToCore(mnDistance, + aIter.toView()); + return; + } + case XML_FOCAL_LENGTH: + { + mrImport.GetMM100UnitConverter().convertMeasureToCore(mnFocalLength, + aIter.toView()); + return; + } + case XML_SHADOW_SLANT: + { + ::sax::Converter::convertNumber(mnShadowSlant, aIter.toView()); + return; + } + case XML_SHADE_MODE: + { + if( IsXMLToken( aIter, XML_FLAT ) ) + mxShadeMode = drawing::ShadeMode_FLAT; + else if( IsXMLToken( aIter, XML_PHONG ) ) + mxShadeMode = drawing::ShadeMode_PHONG; + else if( IsXMLToken( aIter, XML_GOURAUD ) ) + mxShadeMode = drawing::ShadeMode_SMOOTH; + else + mxShadeMode = drawing::ShadeMode_DRAFT; + return; + } + case XML_AMBIENT_COLOR: + { + ::sax::Converter::convertColor(maAmbientColor, aIter.toView()); + return; + } + case XML_LIGHTING_MODE: + { + (void)::sax::Converter::convertBool(mbLightingMode, aIter.toView()); + return; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +/** this sets the scene attributes at this propertyset */ +void SdXML3DSceneAttributesHelper::setSceneAttributes( const css::uno::Reference< css::beans::XPropertySet >& xPropSet ) +{ + uno::Any aAny; + + // world transformation + if(mbSetTransform) + { + xPropSet->setPropertyValue("D3DTransformMatrix", uno::Any(mxHomMat)); + } + + // distance + xPropSet->setPropertyValue("D3DSceneDistance", uno::Any(mnDistance)); + // focalLength + xPropSet->setPropertyValue("D3DSceneFocalLength", uno::Any(mnFocalLength)); + // shadowSlant + xPropSet->setPropertyValue("D3DSceneShadowSlant", uno::Any(static_cast<sal_Int16>(mnShadowSlant))); + // shadeMode + xPropSet->setPropertyValue("D3DSceneShadeMode", uno::Any(mxShadeMode)); + // ambientColor + xPropSet->setPropertyValue("D3DSceneAmbientColor", uno::Any(maAmbientColor)); + // lightingMode + xPropSet->setPropertyValue("D3DSceneTwoSidedLighting", uno::Any(mbLightingMode)); + + if( !maList.empty() ) + { + uno::Any aAny2; + uno::Any aAny3; + + // set lights + for( size_t a = 0; a < maList.size(); a++) + { + SdXML3DLightContext* pCtx = maList[ a ].get(); + + // set anys + aAny <<= pCtx->GetDiffuseColor(); + drawing::Direction3D aLightDir; + aLightDir.DirectionX = pCtx->GetDirection().getX(); + aLightDir.DirectionY = pCtx->GetDirection().getY(); + aLightDir.DirectionZ = pCtx->GetDirection().getZ(); + aAny2 <<= aLightDir; + aAny3 <<= pCtx->GetEnabled(); + + switch(a) + { + case 0: + { + xPropSet->setPropertyValue("D3DSceneLightColor1", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection1", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn1", aAny3); + break; + } + case 1: + { + xPropSet->setPropertyValue("D3DSceneLightColor2", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection2", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn2", aAny3); + break; + } + case 2: + { + xPropSet->setPropertyValue("D3DSceneLightColor3", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection3", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn3", aAny3); + break; + } + case 3: + { + xPropSet->setPropertyValue("D3DSceneLightColor4", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection4", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn4", aAny3); + break; + } + case 4: + { + xPropSet->setPropertyValue("D3DSceneLightColor5", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection5", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn5", aAny3); + break; + } + case 5: + { + xPropSet->setPropertyValue("D3DSceneLightColor6", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection6", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn6", aAny3); + break; + } + case 6: + { + xPropSet->setPropertyValue("D3DSceneLightColor7", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection7", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn7", aAny3); + break; + } + case 7: + { + xPropSet->setPropertyValue("D3DSceneLightColor8", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection8", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn8", aAny3); + break; + } + } + } + } + + // CameraGeometry and camera settings + drawing::CameraGeometry aCamGeo; + aCamGeo.vrp.PositionX = maVRP.getX(); + aCamGeo.vrp.PositionY = maVRP.getY(); + aCamGeo.vrp.PositionZ = maVRP.getZ(); + aCamGeo.vpn.DirectionX = maVPN.getX(); + aCamGeo.vpn.DirectionY = maVPN.getY(); + aCamGeo.vpn.DirectionZ = maVPN.getZ(); + aCamGeo.vup.DirectionX = maVUP.getX(); + aCamGeo.vup.DirectionY = maVUP.getY(); + aCamGeo.vup.DirectionZ = maVUP.getZ(); + xPropSet->setPropertyValue("D3DCameraGeometry", uno::Any(aCamGeo)); + + // #91047# set drawing::ProjectionMode AFTER camera geometry is set + // projection "D3DScenePerspective" drawing::ProjectionMode + xPropSet->setPropertyValue("D3DScenePerspective", uno::Any(mxPrjMode)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximp3dscene.hxx b/xmloff/source/draw/ximp3dscene.hxx new file mode 100644 index 0000000000..b0155591e3 --- /dev/null +++ b/xmloff/source/draw/ximp3dscene.hxx @@ -0,0 +1,52 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/drawing/XShapes.hpp> +#include "ximpshap.hxx" + +// dr3d:3dscene context + +class SdXML3DSceneShapeContext : public SdXMLShapeContext, public SdXML3DSceneAttributesHelper +{ + // the shape group this group is working on + // this is the scene at the same time + css::uno::Reference< css::drawing::XShapes > mxChildren; + +public: + + SdXML3DSceneShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXML3DSceneShapeContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpbody.cxx b/xmloff/source/draw/ximpbody.cxx new file mode 100644 index 0000000000..764c011eec --- /dev/null +++ b/xmloff/source/draw/ximpbody.cxx @@ -0,0 +1,365 @@ +/* -*- 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 "ximpbody.hxx" +#include <xmloff/xmlnamespace.hxx> +#include "ximpnote.hxx" +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/drawing/XDrawPages.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/presentation/XPresentationPage.hpp> +#include "ximpstyl.hxx" +#include <com/sun/star/drawing/XMasterPageTarget.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/animations/XAnimationNodeSupplier.hpp> + +#include <xmloff/unointerfacetouniqueidentifiermapper.hxx> +#include <xmloff/families.hxx> +#include "ximpshow.hxx" +#include "layerimp.hxx" +#include <animationimport.hxx> +#include <sal/log.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SdXMLDrawPageContext::SdXMLDrawPageContext( SdXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLGenericPageContext( rImport, xAttrList, rShapes ) +, mbHadSMILNodes( false ) +{ + bool bHaveXmlId( false ); + OUString sXmlId, sStyleName, sContextName, sMasterPageName, sHREF; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + OUString sValue = aIter.toString(); + switch(aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_NAME): + { + sContextName = sValue; + break; + } + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + { + sStyleName = sValue; + break; + } + case XML_ELEMENT(DRAW, XML_MASTER_PAGE_NAME): + { + sMasterPageName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_PRESENTATION_PAGE_LAYOUT_NAME): + case XML_ELEMENT(PRESENTATION_SO52, XML_PRESENTATION_PAGE_LAYOUT_NAME): + case XML_ELEMENT(PRESENTATION_OOO, XML_PRESENTATION_PAGE_LAYOUT_NAME): + { + maPageLayoutName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_HEADER_NAME): + case XML_ELEMENT(PRESENTATION_SO52, XML_USE_HEADER_NAME): + case XML_ELEMENT(PRESENTATION_OOO, XML_USE_HEADER_NAME): + { + maUseHeaderDeclName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_FOOTER_NAME): + case XML_ELEMENT(PRESENTATION_SO52, XML_USE_FOOTER_NAME): + case XML_ELEMENT(PRESENTATION_OOO, XML_USE_FOOTER_NAME): + { + maUseFooterDeclName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_DATE_TIME_NAME): + case XML_ELEMENT(PRESENTATION_SO52, XML_USE_DATE_TIME_NAME): + case XML_ELEMENT(PRESENTATION_OOO, XML_USE_DATE_TIME_NAME): + { + maUseDateTimeDeclName = sValue; + break; + } + case XML_ELEMENT(DRAW, XML_ID): + { + if (!bHaveXmlId) { sXmlId = sValue; } + } + break; + case XML_ELEMENT(XML, XML_ID): + { + sXmlId = sValue; + bHaveXmlId = true; + } + break; + case XML_ELEMENT(XLINK, XML_HREF): + { + sHREF = sValue; + break; + } + } + } + + if (!sXmlId.isEmpty()) + { + uno::Reference< uno::XInterface > const xRef( rShapes ); + GetImport().getInterfaceToIdentifierMapper().registerReference( + sXmlId, xRef ); + } + GetImport().GetShapeImport()->startPage( rShapes ); + + uno::Reference< drawing::XDrawPage > xShapeDrawPage(rShapes, uno::UNO_QUERY); + + // set PageName? + if(!sContextName.isEmpty()) + { + if(xShapeDrawPage.is()) + { + uno::Reference < container::XNamed > xNamed(xShapeDrawPage, uno::UNO_QUERY); + if(xNamed.is()) + xNamed->setName(sContextName); + } + } + + // set MasterPage? + if(!sMasterPageName.isEmpty()) + { + // #85906# Code for setting masterpage needs complete rework + // since GetSdImport().GetMasterStylesContext() gives always ZERO + // because of content/style file split. Now the mechanism is to + // compare the wanted masterpage-name with the existing masterpages + // which were loaded and created in the styles section loading. + uno::Reference< drawing::XDrawPages > xMasterPages(GetSdImport().GetLocalMasterPages(), uno::UNO_QUERY); + uno::Reference < drawing::XMasterPageTarget > xDrawPage(rShapes, uno::UNO_QUERY); + uno::Reference< drawing::XDrawPage > xMasterPage; + + if(xDrawPage.is() && xMasterPages.is()) + { + bool bDone(false); + OUString sDisplayName( rImport.GetStyleDisplayName( + XmlStyleFamily::MASTER_PAGE, sMasterPageName ) ); + + for(sal_Int32 a = 0; !bDone && a < xMasterPages->getCount(); a++) + { + uno::Any aAny(xMasterPages->getByIndex(a)); + aAny >>= xMasterPage; + + if(xMasterPage.is()) + { + uno::Reference< beans::XPropertySet > xPropSet(xMasterPage, uno::UNO_QUERY_THROW); + if (xPropSet.is()) + { + OUString aPropName("SlideLayout"); + uno::Reference< beans::XPropertySetInfo > xInfo(xPropSet->getPropertySetInfo()); + if (xInfo.is() && xInfo->hasPropertyByName(aPropName)) + { + sal_Int32 nType = -1; + uno::Reference< container::XNameAccess > xPageLayouts(GetSdImport().getPageLayouts()); + if (xPageLayouts.is()) + { + if (xPageLayouts->hasByName(maPageLayoutName)) + xPageLayouts->getByName(maPageLayoutName) >>= nType; + } + if (-1 != nType) + xPropSet->setPropertyValue(aPropName, uno::Any(static_cast<sal_Int16>(nType))); + } + } + + uno::Reference < container::XNamed > xMasterNamed(xMasterPage, uno::UNO_QUERY); + if(xMasterNamed.is()) + { + OUString sLoopMasterPageName = xMasterNamed->getName(); + + if(!sLoopMasterPageName.isEmpty() && sLoopMasterPageName == sDisplayName) + { + xDrawPage->setMasterPage(xMasterPage); + bDone = true; + } + } + } + } + + SAL_WARN_IF( !bDone, "xmloff", "xmloff::SdXMLDrawPageContext::SdXMLDrawPageContext(), could not find a master slide!" ); + } + } + + SetStyle( sStyleName ); + + if( !sHREF.isEmpty() ) + { + uno::Reference< beans::XPropertySet > xProps( xShapeDrawPage, uno::UNO_QUERY ); + if( xProps.is() ) + { + sal_Int32 nIndex = sHREF.lastIndexOf( '#' ); + if( nIndex != -1 ) + { + OUString aFileName( sHREF.copy( 0, nIndex ) ); + std::u16string_view aBookmarkName( sHREF.subView( nIndex+1 ) ); + + sHREF = GetImport().GetAbsoluteReference( aFileName ) + "#" + + aBookmarkName; + } + + xProps->setPropertyValue("BookmarkURL", uno::Any( sHREF ) ); + } + } + + SetLayout(); + + DeleteAllShapes(); +} + +SdXMLDrawPageContext::~SdXMLDrawPageContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLDrawPageContext::createFastChildContext(sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) +{ + // some special objects inside draw:page context + switch(nElement) + { + case XML_ELEMENT(PRESENTATION, XML_NOTES): + case XML_ELEMENT(PRESENTATION_SO52, XML_NOTES): + case XML_ELEMENT(PRESENTATION_OOO, XML_NOTES): + { + if( GetSdImport().IsImpress() ) + { + // get notes page + uno::Reference< presentation::XPresentationPage > xPresPage(GetLocalShapesContext(), uno::UNO_QUERY); + if(xPresPage.is()) + { + uno::Reference< drawing::XDrawPage > xNotesDrawPage = xPresPage->getNotesPage(); + if(xNotesDrawPage.is()) + { + // presentation:notes inside draw:page context + return new SdXMLNotesContext( GetSdImport(), xAttrList, xNotesDrawPage); + } + } + } + break; + } + case XML_ELEMENT(ANIMATION, XML_PAR): + case XML_ELEMENT(ANIMATION_OOO, XML_PAR): + case XML_ELEMENT(ANIMATION, XML_SEQ): + case XML_ELEMENT(ANIMATION_OOO, XML_SEQ): + { + if( GetSdImport().IsImpress() ) + { + uno::Reference< animations::XAnimationNodeSupplier > xNodeSupplier(GetLocalShapesContext(), uno::UNO_QUERY); + if(xNodeSupplier.is()) + { + mbHadSMILNodes = true; + return new xmloff::AnimationNodeContext( xNodeSupplier->getAnimationNode(), GetSdImport(), nElement, xAttrList ); + } + } + break; + } + case XML_ELEMENT(DRAW, XML_LAYER_SET): + { + return new SdXMLLayerSetContext( GetSdImport() ); + } + } + + // call parent when no own context was created + return SdXMLGenericPageContext::createFastChildContext(nElement, xAttrList); +} + +void SdXMLDrawPageContext::endFastElement(sal_Int32 nElement) +{ + SdXMLGenericPageContext::endFastElement(nElement); + GetImport().GetShapeImport()->endPage(GetLocalShapesContext()); + + if( mbHadSMILNodes ) + { + uno::Reference< animations::XAnimationNodeSupplier > xNodeSupplier(GetLocalShapesContext(), uno::UNO_QUERY); + uno::Reference< beans::XPropertySet > xPageProps( GetLocalShapesContext(), uno::UNO_QUERY ); + if(xNodeSupplier.is()) + xmloff::AnimationNodeContext::postProcessRootNode( xNodeSupplier->getAnimationNode(), xPageProps ); + } +} + +SdXMLBodyContext::SdXMLBodyContext( SdXMLImport& rImport ) +: SvXMLImportContext( rImport ) +{ +} + +SdXMLBodyContext::~SdXMLBodyContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLBodyContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + switch (nElement) + { + case XML_ELEMENT(PRESENTATION, XML_SETTINGS): + case XML_ELEMENT(PRESENTATION_SO52, XML_SETTINGS): + case XML_ELEMENT(PRESENTATION_OOO, XML_SETTINGS): + { + return new SdXMLShowsContext( GetSdImport(), xAttrList ); + } + case XML_ELEMENT(DRAW, XML_PAGE): + { + // only read the first page in preview mode + if( (GetSdImport().GetNewPageCount() == 0) || !GetSdImport().IsPreview() ) + { + // import this page + uno::Reference< drawing::XDrawPage > xNewDrawPage; + uno::Reference< drawing::XDrawPages > xDrawPages(GetSdImport().GetLocalDrawPages(), uno::UNO_QUERY); + + if( !xDrawPages.is() ) + break; + + if(GetSdImport().GetNewPageCount() + 1 > xDrawPages->getCount()) + { + // new page, create and insert + xNewDrawPage = xDrawPages->insertNewByIndex(xDrawPages->getCount()); + } + else + { + // existing page, use it + uno::Any aAny(xDrawPages->getByIndex(GetSdImport().GetNewPageCount())); + aAny >>= xNewDrawPage; + } + + // increment global import page counter + GetSdImport().IncrementNewPageCount(); + + if(xNewDrawPage.is()) + { + // draw:page inside office:body context + return new SdXMLDrawPageContext(GetSdImport(), xAttrList, xNewDrawPage); + } + } + break; + } + case XML_ELEMENT(PRESENTATION, XML_HEADER_DECL): + case XML_ELEMENT(PRESENTATION, XML_FOOTER_DECL): + case XML_ELEMENT(PRESENTATION, XML_DATE_TIME_DECL): + { + return new SdXMLHeaderFooterDeclContext( GetImport(), xAttrList ); + } + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpbody.hxx b/xmloff/source/draw/ximpbody.hxx new file mode 100644 index 0000000000..95d411385c --- /dev/null +++ b/xmloff/source/draw/ximpbody.hxx @@ -0,0 +1,59 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include "sdxmlimp_impl.hxx" +#include "ximppage.hxx" + +// draw:page context + +class SdXMLDrawPageContext : public SdXMLGenericPageContext +{ + bool mbHadSMILNodes; + +public: + SdXMLDrawPageContext( SdXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLDrawPageContext() override; + + virtual css::uno::Reference< XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 Element, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& Attribs) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +}; + +// office:body context + +class SdXMLBodyContext : public SvXMLImportContext +{ + const SdXMLImport& GetSdImport() const { return static_cast<const SdXMLImport&>(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast<SdXMLImport&>(GetImport()); } + +public: + SdXMLBodyContext( SdXMLImport& rImport ); + virtual ~SdXMLBodyContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpcustomshape.cxx b/xmloff/source/draw/ximpcustomshape.cxx new file mode 100644 index 0000000000..56b9fd4cc4 --- /dev/null +++ b/xmloff/source/draw/ximpcustomshape.cxx @@ -0,0 +1,1421 @@ +/* -*- 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 "ximpcustomshape.hxx" +#include <o3tl/any.hxx> +#include <rtl/math.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <xmloff/xmltoken.hxx> +#include <EnhancedCustomShapeToken.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <xexptran.hxx> +#include <com/sun/star/drawing/Direction3D.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp> +#include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp> +#include <com/sun/star/drawing/ProjectionMode.hpp> +#include <com/sun/star/drawing/Position3D.hpp> +#include <sax/tools/converter.hxx> +#include <comphelper/sequence.hxx> +#include <o3tl/string_view.hxx> +#include <memory> +#include <string_view> +#include <unordered_map> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using namespace ::xmloff::EnhancedCustomShapeToken; + + +XMLEnhancedCustomShapeContext::XMLEnhancedCustomShapeContext( SvXMLImport& rImport, + css::uno::Reference< css::drawing::XShape >& rxShape, + std::vector< css::beans::PropertyValue >& rCustomShapeGeometry ) : + SvXMLImportContext( rImport ), + mrUnitConverter( rImport.GetMM100UnitConverter() ), + mrxShape( rxShape ), + mrCustomShapeGeometry( rCustomShapeGeometry ) +{ +} + +const SvXMLEnumMapEntry<sal_uInt16> aXML_GluePointEnumMap[] = +{ + { XML_NONE, 0 }, + { XML_SEGMENTS, 1 }, + { XML_NONE, 2 }, + { XML_RECTANGLE, 3 }, + { XML_TOKEN_INVALID, 0 } +}; +static void GetBool( std::vector< css::beans::PropertyValue >& rDest, + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + bool bAttrBool; + if (::sax::Converter::convertBool( bAttrBool, rValue )) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= bAttrBool; + rDest.push_back( aProp ); + } +} + +static void GetInt32( std::vector< css::beans::PropertyValue >& rDest, + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + sal_Int32 nAttrNumber; + if (::sax::Converter::convertNumber( nAttrNumber, rValue )) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= nAttrNumber; + rDest.push_back( aProp ); + } +} + +static void GetDouble( std::vector< css::beans::PropertyValue >& rDest, + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + double fAttrDouble; + if (::sax::Converter::convertDouble( fAttrDouble, rValue )) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= fAttrDouble; + rDest.push_back( aProp ); + } +} + +static void GetString( std::vector< css::beans::PropertyValue >& rDest, + const OUString& rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= rValue; + rDest.push_back( aProp ); +} + +template<typename EnumT> +static void GetEnum( std::vector< css::beans::PropertyValue >& rDest, + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp, + const SvXMLEnumMapEntry<EnumT>& rMap ) +{ + EnumT eKind; + if( SvXMLUnitConverter::convertEnum( eKind, rValue, &rMap ) ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= static_cast<sal_Int16>(eKind); + rDest.push_back( aProp ); + } +} + +static void GetDoublePercentage( std::vector< css::beans::PropertyValue >& rDest, + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + sal_Int16 const eSrcUnit = ::sax::Converter::GetUnitFromString( + rValue, util::MeasureUnit::MM_100TH); + if (util::MeasureUnit::PERCENT != eSrcUnit) + return; + + rtl_math_ConversionStatus eStatus; + double fAttrDouble = rtl_math_stringToDouble(rValue.data(), + rValue.data() + rValue.size(), + '.', ',', &eStatus, nullptr); + if ( eStatus == rtl_math_ConversionStatus_Ok ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= fAttrDouble; + rDest.push_back( aProp ); + } +} + +static void GetB3DVector( std::vector< css::beans::PropertyValue >& rDest, + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + ::basegfx::B3DVector aB3DVector; + if ( SvXMLUnitConverter::convertB3DVector( aB3DVector, rValue ) ) + { + drawing::Direction3D aDirection3D( aB3DVector.getX(), aB3DVector.getY(), aB3DVector.getZ() ); + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= aDirection3D; + rDest.push_back( aProp ); + } +} + +static bool GetEquationName( std::u16string_view rEquation, const sal_Int32 nStart, OUString& rEquationName ) +{ + sal_Int32 nIndex = nStart; + while( nIndex < static_cast<sal_Int32>(rEquation.size()) ) + { + sal_Unicode nChar = rEquation[ nIndex ]; + if ( + ( ( nChar >= 'a' ) && ( nChar <= 'z' ) ) + || ( ( nChar >= 'A' ) && ( nChar <= 'Z' ) ) + || ( ( nChar >= '0' ) && ( nChar <= '9' ) ) + ) + { + nIndex++; + } + else + break; + } + bool bValid = ( nIndex - nStart ) != 0; + if ( bValid ) + rEquationName = rEquation.substr( nStart, nIndex - nStart ); + return bValid; +} + +static bool GetNextParameter( css::drawing::EnhancedCustomShapeParameter& rParameter, sal_Int32& nIndex, std::u16string_view rParaString ) +{ + if ( nIndex >= static_cast<sal_Int32>(rParaString.size()) ) + return false; + + bool bValid = true; + bool bNumberRequired = true; + bool bMustBePositiveWholeNumbered = false; + + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::NORMAL; + if ( rParaString[ nIndex ] == '$' ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT; + bMustBePositiveWholeNumbered = true; + nIndex++; + } + else if ( rParaString[ nIndex ] == '?' ) + { + nIndex++; + bNumberRequired = false; + OUString aEquationName; + bValid = GetEquationName( rParaString, nIndex, aEquationName ); + if ( bValid ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::EQUATION; + rParameter.Value <<= aEquationName; + nIndex += aEquationName.getLength(); + } + } + else if ( rParaString[ nIndex ] > '9' ) + { + bNumberRequired = false; + if ( o3tl::matchIgnoreAsciiCase( rParaString, u"left", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::LEFT; + nIndex += 4; + } + else if ( o3tl::matchIgnoreAsciiCase( rParaString, u"top", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::TOP; + nIndex += 3; + } + else if ( o3tl::matchIgnoreAsciiCase( rParaString, u"right", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::RIGHT; + nIndex += 5; + } + else if ( o3tl::matchIgnoreAsciiCase( rParaString, u"bottom", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::BOTTOM; + nIndex += 6; + } + else if ( o3tl::matchIgnoreAsciiCase( rParaString, u"xstretch", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::XSTRETCH; + nIndex += 8; + } + else if ( o3tl::matchIgnoreAsciiCase( rParaString, u"ystretch", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::YSTRETCH; + nIndex += 8; + } + else if ( o3tl::matchIgnoreAsciiCase( rParaString, u"hasstroke", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::HASSTROKE; + nIndex += 9; + } + else if ( o3tl::matchIgnoreAsciiCase( rParaString, u"hasfill", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::HASFILL; + nIndex += 7; + } + else if ( o3tl::matchIgnoreAsciiCase( rParaString, u"width", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::WIDTH; + nIndex += 5; + } + else if ( o3tl::matchIgnoreAsciiCase( rParaString, u"height", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::HEIGHT; + nIndex += 6; + } + else if ( o3tl::matchIgnoreAsciiCase( rParaString, u"logwidth", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::LOGWIDTH; + nIndex += 8; + } + else if ( o3tl::matchIgnoreAsciiCase( rParaString, u"logheight", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::LOGHEIGHT; + nIndex += 9; + } + else + bValid = false; + } + if ( bValid ) + { + if ( bNumberRequired ) + { + sal_Int32 nStartIndex = nIndex; + sal_Int32 nEIndex = 0; // index of "E" in double + + bool bE = false; // set if a double is including a "E" statement + bool bENum = false; // there is at least one number after "E" + bool bDot = false; // set if there is a dot included + bool bEnd = false; // set for each value that can not be part of a double/integer + + while( ( nIndex < static_cast<sal_Int32>(rParaString.size()) ) && bValid ) + { + switch( rParaString[ nIndex ] ) + { + case '.' : + { + if ( bMustBePositiveWholeNumbered ) + bValid = false; + else + { + if ( bDot ) + bValid = false; + else + bDot = true; + } + } + break; + case '-' : + { + if ( bMustBePositiveWholeNumbered ) + bValid = false; + else + { + if ( nStartIndex == nIndex ) + bValid = true; + else if ( bE ) + { + if ( nEIndex + 1 == nIndex ) + bValid = true; + else if ( bENum ) + bEnd = true; + else + bValid = false; + } + } + } + break; + + case 'e' : + case 'E' : + { + if ( bMustBePositiveWholeNumbered ) + bEnd = true; + else + { + if ( !bE ) + { + bE = true; + nEIndex = nIndex; + } + else + bEnd = true; + } + } + break; + case '0' : + case '1' : + case '2' : + case '3' : + case '4' : + case '5' : + case '6' : + case '7' : + case '8' : + case '9' : + { + if ( bE && ! bENum ) + bENum = true; + } + break; + default: + bEnd = true; + } + if ( !bEnd ) + nIndex++; + else + break; + } + if ( nIndex == nStartIndex ) + bValid = false; + if ( bValid ) + { + std::u16string_view aNumber( rParaString.substr( nStartIndex, nIndex - nStartIndex ) ); + if ( bE || bDot ) + { + double fAttrDouble; + if (::sax::Converter::convertDouble(fAttrDouble, aNumber)) + rParameter.Value <<= fAttrDouble; + else + bValid = false; + } + else + { + sal_Int32 nValue; + if (::sax::Converter::convertNumber(nValue, aNumber)) + rParameter.Value <<= nValue; + else + bValid = false; + } + } + } + } + if ( bValid ) + { + // skipping white spaces and commas (#i121507#) + const sal_Unicode aSpace(' '); + const sal_Unicode aCommata(','); + + while(nIndex < static_cast<sal_Int32>(rParaString.size())) + { + const sal_Unicode aCandidate(rParaString[nIndex]); + + if(aSpace == aCandidate || aCommata == aCandidate) + { + nIndex++; + } + else + { + break; + } + } + } + return bValid; +} + +static void GetPosition3D( std::vector< css::beans::PropertyValue >& rDest, // e.g. draw:extrusion-viewpoint + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp, + const SvXMLUnitConverter& rUnitConverter ) +{ + drawing::Position3D aPosition3D; + if ( rUnitConverter.convertPosition3D( aPosition3D, rValue ) ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= aPosition3D; + rDest.push_back( aProp ); + } +} + +static void GetDoubleSequence( std::vector< css::beans::PropertyValue >& rDest, // e.g. draw:glue-point-leaving-directions + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + std::vector< double > vDirection; + sal_Int32 nIndex = 0; + do + { + double fAttrDouble; + std::string_view aToken( o3tl::getToken(rValue, 0, ',', nIndex ) ); + if (!::sax::Converter::convertDouble( fAttrDouble, aToken )) + break; + else + vDirection.push_back( fAttrDouble ); + } + while ( nIndex >= 0 ); + + if ( !vDirection.empty() ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= comphelper::containerToSequence(vDirection); + rDest.push_back( aProp ); + } +} + +static void GetSizeSequence( std::vector< css::beans::PropertyValue >& rDest, + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + std::vector< sal_Int32 > vNum; + sal_Int32 nIndex = 0; + do + { + sal_Int32 n; + std::string_view aToken( o3tl::getToken(rValue, 0, ' ', nIndex ) ); + if (!::sax::Converter::convertNumber( n, aToken )) + break; + else + vNum.push_back( n ); + } + while ( nIndex >= 0 ); + + if ( vNum.empty() ) + return; + + uno::Sequence< awt::Size > aSizeSeq((vNum.size() + 1) / 2); + std::vector< sal_Int32 >::const_iterator aIter = vNum.begin(); + std::vector< sal_Int32 >::const_iterator aEnd = vNum.end(); + awt::Size* pValues = aSizeSeq.getArray(); + + while ( aIter != aEnd ) { + pValues->Width = *aIter++; + if ( aIter != aEnd ) + pValues->Height = *aIter++; + pValues ++; + } + + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= aSizeSeq; + rDest.push_back( aProp ); +} + +static void GetEnhancedParameter( std::vector< css::beans::PropertyValue >& rDest, // e.g. draw:handle-position + std::u16string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + sal_Int32 nIndex = 0; + css::drawing::EnhancedCustomShapeParameter aParameter; + if ( GetNextParameter( aParameter, nIndex, rValue ) ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= aParameter; + rDest.push_back( aProp ); + } +} + +static void GetEnhancedParameterPair( std::vector< css::beans::PropertyValue >& rDest, // e.g. draw:handle-position + std::u16string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + sal_Int32 nIndex = 0; + css::drawing::EnhancedCustomShapeParameterPair aParameterPair; + if ( GetNextParameter( aParameterPair.First, nIndex, rValue ) + && GetNextParameter( aParameterPair.Second, nIndex, rValue ) ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= aParameterPair; + rDest.push_back( aProp ); + } +} + +static sal_Int32 GetEnhancedParameterPairSequence( std::vector< css::beans::PropertyValue >& rDest, // e.g. draw:glue-points + std::u16string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + std::vector< css::drawing::EnhancedCustomShapeParameterPair > vParameter; + css::drawing::EnhancedCustomShapeParameterPair aParameter; + + sal_Int32 nIndex = 0; + while ( GetNextParameter( aParameter.First, nIndex, rValue ) + && GetNextParameter( aParameter.Second, nIndex, rValue ) ) + { + vParameter.push_back( aParameter ); + } + if ( !vParameter.empty() ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= comphelper::containerToSequence(vParameter); + rDest.push_back( aProp ); + } + return vParameter.size(); +} + +static void GetEnhancedRectangleSequence( std::vector< css::beans::PropertyValue >& rDest, // e.g. draw:text-areas + std::u16string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + std::vector< css::drawing::EnhancedCustomShapeTextFrame > vTextFrame; + css::drawing::EnhancedCustomShapeTextFrame aParameter; + + sal_Int32 nIndex = 0; + + while ( GetNextParameter( aParameter.TopLeft.First, nIndex, rValue ) + && GetNextParameter( aParameter.TopLeft.Second, nIndex, rValue ) + && GetNextParameter( aParameter.BottomRight.First, nIndex, rValue ) + && GetNextParameter( aParameter.BottomRight.Second, nIndex, rValue ) ) + { + vTextFrame.push_back( aParameter ); + } + if ( !vTextFrame.empty() ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= comphelper::containerToSequence(vTextFrame); + rDest.push_back( aProp ); + } +} + +static void +GetEnhancedPath(std::vector<css::beans::PropertyValue>& rDest, // e.g. draw:enhanced-path + std::u16string_view rValue, std::u16string_view rType) +{ + std::vector< css::drawing::EnhancedCustomShapeParameterPair > vCoordinates; + std::vector< css::drawing::EnhancedCustomShapeSegment > vSegments; + + sal_Int32 nIndex = 0; + sal_Int32 nParameterCount = 0; + + sal_Int32 nParametersNeeded = 1; + sal_Int16 nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO; + + bool bValid = true; + + while( bValid && ( nIndex < static_cast<sal_Int32>(rValue.size()) ) ) + { + switch( rValue[ nIndex ] ) + { + case 'M' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO; + nParametersNeeded = 1; + nIndex++; + } + break; + case 'L' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO; + nParametersNeeded = 1; + nIndex++; + } + break; + case 'C' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::CURVETO; + nParametersNeeded = 3; + nIndex++; + } + break; + case 'Z' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'N' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'F' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::NOFILL; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'S' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'T' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO; + nParametersNeeded = 3; + nIndex++; + } + break; + case 'U' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE; + nParametersNeeded = 3; + nIndex++; + } + break; + case 'A' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ARCTO; + nParametersNeeded = 4; + nIndex++; + } + break; + case 'B' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ARC; + nParametersNeeded = 4; + nIndex++; + } + break; + case 'G' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ARCANGLETO; + nParametersNeeded = 2; + nIndex++; + } + break; + case 'H' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::DARKEN; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'I' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::DARKENLESS; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'J' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTEN; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'K' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTENLESS; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'W' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO; + nParametersNeeded = 4; + nIndex++; + } + break; + case 'V' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC; + nParametersNeeded = 4; + nIndex++; + } + break; + case 'X' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX; + nParametersNeeded = 1; + nIndex++; + } + break; + case 'Y' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY; + nParametersNeeded = 1; + nIndex++; + } + break; + case 'Q' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::QUADRATICCURVETO; + nParametersNeeded = 2; + nIndex++; + } + break; + case ' ' : + { + nIndex++; + } + break; + + case '$' : + case '?' : + case '0' : + case '1' : + case '2' : + case '3' : + case '4' : + case '5' : + case '6' : + case '7' : + case '8' : + case '9' : + case '.' : + case '-' : + { + css::drawing::EnhancedCustomShapeParameterPair aPair; + if ( GetNextParameter( aPair.First, nIndex, rValue ) && + GetNextParameter( aPair.Second, nIndex, rValue ) ) + { + vCoordinates.push_back( aPair ); + nParameterCount++; + } + else + bValid = false; + } + break; + default: + nIndex++; + break; + } + if ( !nParameterCount && !nParametersNeeded ) + { + css::drawing::EnhancedCustomShapeSegment aSegment; + aSegment.Command = nLatestSegmentCommand; + aSegment.Count = 0; + vSegments.push_back( aSegment ); + nParametersNeeded = 0x7fffffff; + } + else if ( nParameterCount >= nParametersNeeded ) + { + // Special rule for moveto in ODF 1.2 section 19.145 + // "If a moveto is followed by multiple pairs of coordinates, they are treated as lineto." + if ( nLatestSegmentCommand == css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO ) + { + css::drawing::EnhancedCustomShapeSegment aSegment; + aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO; + aSegment.Count = 1; + vSegments.push_back( aSegment ); + nIndex--; + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO; + nParametersNeeded = 1; + } + else + { + // General rule in ODF 1.2. section 19.145 + // "If a command is repeated multiple times, all repeated command characters + // except the first one may be omitted." Thus check if the last command is identical, + // if so, we just need to increment the count + if ( !vSegments.empty() && ( vSegments[ vSegments.size() - 1 ].Command == nLatestSegmentCommand ) ) + vSegments[ vSegments.size() -1 ].Count++; + else + { + css::drawing::EnhancedCustomShapeSegment aSegment; + aSegment.Command = nLatestSegmentCommand; + aSegment.Count = 1; + vSegments.push_back( aSegment ); + } + } + nParameterCount = 0; + } + } + + // Corrections for wrong paths in curvedArrow shapes written by older LO versions + if (!vSegments.empty() + && (rType == u"mso-spt102" || rType == u"mso-spt103" || rType == u"mso-spt104" + || rType == u"mso-spt105") + && vSegments[0].Count == 2) + { + vSegments[0].Count = 1; + css::drawing::EnhancedCustomShapeSegment aSegment; + aSegment.Count = 1; + aSegment.Command + = vSegments[0].Command == css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC + ? css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO + : css::drawing::EnhancedCustomShapeSegmentCommand::ARCTO; + vSegments.insert(vSegments.begin() + 1, aSegment); + } + + // adding the Coordinates property + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_Coordinates ); + aProp.Value <<= comphelper::containerToSequence(vCoordinates); + rDest.push_back( aProp ); + + // adding the Segments property + aProp.Name = EASGet( EAS_Segments ); + aProp.Value <<= comphelper::containerToSequence(vSegments); + rDest.push_back( aProp ); +} + +static void GetAdjustmentValues( std::vector< css::beans::PropertyValue >& rDest, // draw:adjustments + std::u16string_view rValue ) +{ + std::vector< css::drawing::EnhancedCustomShapeAdjustmentValue > vAdjustmentValue; + css::drawing::EnhancedCustomShapeParameter aParameter; + sal_Int32 nIndex = 0; + while ( GetNextParameter( aParameter, nIndex, rValue ) ) + { + css::drawing::EnhancedCustomShapeAdjustmentValue aAdj; + if ( aParameter.Type == css::drawing::EnhancedCustomShapeParameterType::NORMAL ) + { + aAdj.Value = aParameter.Value; + aAdj.State = beans::PropertyState_DIRECT_VALUE; + } + else + aAdj.State = beans::PropertyState_DEFAULT_VALUE; // this should not be, but better than setting nothing + + vAdjustmentValue.push_back( aAdj ); + } + + sal_Int32 nAdjustmentValues = vAdjustmentValue.size(); + if ( nAdjustmentValues ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_AdjustmentValues ); + aProp.Value <<= comphelper::containerToSequence(vAdjustmentValue); + rDest.push_back( aProp ); + } +} + +void XMLEnhancedCustomShapeContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + sal_Int32 nAttrNumber; + std::optional<std::string_view> oSpecularityValue; // for postpone extrusion-specularity + std::optional<OUString> oPathValue; // for postpone GetEnhancedPath; + OUString sType("non-primitive"); // default in ODF + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( EASGet( aIter.getToken() ) ) + { + case EAS_type : + { + sType = aIter.toString(); + GetString( mrCustomShapeGeometry, sType, EAS_Type ); + } + break; + case EAS_mirror_horizontal : + GetBool( mrCustomShapeGeometry, aIter.toView(), EAS_MirroredX ); + break; + case EAS_mirror_vertical : + GetBool( mrCustomShapeGeometry, aIter.toView(), EAS_MirroredY ); + break; + case EAS_viewBox : + { + SdXMLImExViewBox aViewBox( aIter.toString(), GetImport().GetMM100UnitConverter() ); + awt::Rectangle aRect( aViewBox.GetX(), aViewBox.GetY(), aViewBox.GetWidth(), aViewBox.GetHeight() ); + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_ViewBox ); + aProp.Value <<= aRect; + mrCustomShapeGeometry.push_back( aProp ); + } + break; + case EAS_sub_view_size: + GetSizeSequence( maPath, aIter.toView(), EAS_SubViewSize ); + break; + case EAS_text_rotate_angle : + GetDouble( mrCustomShapeGeometry, aIter.toView(), EAS_TextRotateAngle ); + break; + case EAS_extrusion_allowed : + GetBool( maPath, aIter.toView(), EAS_ExtrusionAllowed ); + break; + case EAS_text_path_allowed : + GetBool( maPath, aIter.toView(), EAS_TextPathAllowed ); + break; + case EAS_concentric_gradient_fill_allowed : + GetBool( maPath, aIter.toView(), EAS_ConcentricGradientFillAllowed ); + break; + case EAS_extrusion : + GetBool( maExtrusion, aIter.toView(), EAS_Extrusion ); + break; + case EAS_extrusion_brightness : + GetDoublePercentage( maExtrusion, aIter.toView(), EAS_Brightness ); + break; + case EAS_extrusion_depth : + { + OUString rValue = aIter.toString(); + sal_Int32 nIndex = 0; + css::drawing::EnhancedCustomShapeParameterPair aParameterPair; + css::drawing::EnhancedCustomShapeParameter& rDepth = aParameterPair.First; + if ( GetNextParameter( rDepth, nIndex, rValue ) ) + { + css::drawing::EnhancedCustomShapeParameter& rFraction = aParameterPair.Second; + // try to catch the unit for the depth + sal_Int16 const eSrcUnit( + ::sax::Converter::GetUnitFromString( + rValue, util::MeasureUnit::MM_100TH)); + + OUStringBuffer aUnitStr; + double fFactor = ::sax::Converter::GetConversionFactor( + aUnitStr, util::MeasureUnit::MM_100TH, eSrcUnit); + if ( ( fFactor != 1.0 ) && ( fFactor != 0.0 ) ) + { + double fDepth(0.0); + if ( rDepth.Value >>= fDepth ) + { + fDepth /= fFactor; + rDepth.Value <<= fDepth; + } + } + if ( rValue.matchIgnoreAsciiCase( aUnitStr, nIndex ) ) + nIndex += aUnitStr.getLength(); + + // skipping white spaces + while( ( nIndex < rValue.getLength() ) && rValue[ nIndex ] == ' ' ) + nIndex++; + + if ( GetNextParameter( rFraction, nIndex, rValue ) ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_Depth ); + aProp.Value <<= aParameterPair; + maExtrusion.push_back( aProp ); + } + } + } + break; + case EAS_extrusion_diffusion : + GetDoublePercentage( maExtrusion, aIter.toView(), EAS_Diffusion ); + break; + case EAS_extrusion_number_of_line_segments : + GetInt32( maExtrusion, aIter.toView(), EAS_NumberOfLineSegments ); + break; + case EAS_extrusion_light_face : + GetBool( maExtrusion, aIter.toView(), EAS_LightFace ); + break; + case EAS_extrusion_first_light_harsh : + GetBool( maExtrusion, aIter.toView(), EAS_FirstLightHarsh ); + break; + case EAS_extrusion_second_light_harsh : + GetBool( maExtrusion, aIter.toView(), EAS_SecondLightHarsh ); + break; + case EAS_extrusion_first_light_level : + GetDoublePercentage( maExtrusion, aIter.toView(), EAS_FirstLightLevel ); + break; + case EAS_extrusion_second_light_level : + GetDoublePercentage( maExtrusion, aIter.toView(), EAS_SecondLightLevel ); + break; + case EAS_extrusion_first_light_direction : + GetB3DVector( maExtrusion, aIter.toView(), EAS_FirstLightDirection ); + break; + case EAS_extrusion_second_light_direction : + GetB3DVector( maExtrusion, aIter.toView(), EAS_SecondLightDirection ); + break; + case EAS_extrusion_metal : + GetBool( maExtrusion, aIter.toView(), EAS_Metal ); + break; + case EAS_extrusion_metal_type : + { + OUString rValue = aIter.toString(); + sal_Int16 eMetalType(drawing::EnhancedCustomShapeMetalType::MetalODF); + if (rValue == "loext:MetalMSCompatible") + eMetalType = drawing::EnhancedCustomShapeMetalType::MetalMSCompatible; + beans::PropertyValue aProp; + aProp.Name = EASGet(EAS_MetalType); + aProp.Value <<= eMetalType; + maExtrusion.push_back(aProp); + } + break; + case EAS_shade_mode : + { + drawing::ShadeMode eShadeMode( drawing::ShadeMode_FLAT ); + if( IsXMLToken( aIter, XML_PHONG ) ) + eShadeMode = drawing::ShadeMode_PHONG; + else if ( IsXMLToken( aIter, XML_GOURAUD ) ) + eShadeMode = drawing::ShadeMode_SMOOTH; + else if ( IsXMLToken( aIter, XML_DRAFT ) ) + eShadeMode = drawing::ShadeMode_DRAFT; + + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_ShadeMode ); + aProp.Value <<= eShadeMode; + maExtrusion.push_back( aProp ); + } + break; + case EAS_extrusion_rotation_angle : + GetEnhancedParameterPair( maExtrusion, aIter.toString(), EAS_RotateAngle ); + break; + case EAS_extrusion_rotation_center : + GetB3DVector( maExtrusion, aIter.toView(), EAS_RotationCenter ); + break; + case EAS_extrusion_shininess : + GetDoublePercentage( maExtrusion, aIter.toView(), EAS_Shininess ); + break; + case EAS_extrusion_skew : + GetEnhancedParameterPair( maExtrusion, aIter.toString(), EAS_Skew ); + break; + case EAS_extrusion_specularity : + if (!oSpecularityValue) + oSpecularityValue = aIter.toView(); + break; + case EAS_extrusion_specularity_loext : + oSpecularityValue = aIter.toView(); + break; + case EAS_projection : + { + drawing::ProjectionMode eProjectionMode( drawing::ProjectionMode_PERSPECTIVE ); + if( IsXMLToken( aIter, XML_PARALLEL ) ) + eProjectionMode = drawing::ProjectionMode_PARALLEL; + + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_ProjectionMode ); + aProp.Value <<= eProjectionMode; + maExtrusion.push_back( aProp ); + } + break; + case EAS_extrusion_viewpoint : + GetPosition3D( maExtrusion, aIter.toView(), EAS_ViewPoint, mrUnitConverter ); + break; + case EAS_extrusion_origin : + GetEnhancedParameterPair( maExtrusion, aIter.toString(), EAS_Origin ); + break; + case EAS_extrusion_color : + GetBool( maExtrusion, aIter.toView(), EAS_Color ); + break; + case EAS_enhanced_path : + oPathValue = aIter.toString(); + break; + case EAS_path_stretchpoint_x : + { + if (::sax::Converter::convertNumber(nAttrNumber, aIter.toView())) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_StretchX ); + aProp.Value <<= nAttrNumber; + maPath.push_back( aProp ); + } + } + break; + case EAS_path_stretchpoint_y : + { + if (::sax::Converter::convertNumber(nAttrNumber, aIter.toView())) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_StretchY ); + aProp.Value <<= nAttrNumber; + maPath.push_back( aProp ); + } + } + break; + case EAS_text_areas : + GetEnhancedRectangleSequence( maPath, aIter.toString(), EAS_TextFrames ); + break; + case EAS_glue_points : + { + sal_Int32 i, nPairs = GetEnhancedParameterPairSequence( maPath, aIter.toString(), EAS_GluePoints ); + GetImport().GetShapeImport()->moveGluePointMapping( mrxShape, nPairs ); + for ( i = 0; i < nPairs; i++ ) + GetImport().GetShapeImport()->addGluePointMapping( mrxShape, i + 4, i + 4 ); + } + break; + case EAS_glue_point_type : + GetEnum( maPath, aIter.toView(), EAS_GluePointType, *aXML_GluePointEnumMap ); + break; + case EAS_glue_point_leaving_directions : + GetDoubleSequence( maPath, aIter.toView(), EAS_GluePointLeavingDirections ); + break; + case EAS_text_path : + GetBool( maTextPath, aIter.toView(), EAS_TextPath ); + break; + case EAS_text_path_mode : + { + css::drawing::EnhancedCustomShapeTextPathMode eTextPathMode( css::drawing::EnhancedCustomShapeTextPathMode_NORMAL ); + if( IsXMLToken( aIter, XML_PATH ) ) + eTextPathMode = css::drawing::EnhancedCustomShapeTextPathMode_PATH; + else if ( IsXMLToken( aIter, XML_SHAPE ) ) + eTextPathMode = css::drawing::EnhancedCustomShapeTextPathMode_SHAPE; + + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_TextPathMode ); + aProp.Value <<= eTextPathMode; + maTextPath.push_back( aProp ); + } + break; + case EAS_text_path_scale : + { + bool bScaleX = IsXMLToken( aIter, XML_SHAPE ); + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_ScaleX ); + aProp.Value <<= bScaleX; + maTextPath.push_back( aProp ); + } + break; + case EAS_text_path_same_letter_heights : + GetBool( maTextPath, aIter.toView(), EAS_SameLetterHeights ); + break; + case EAS_modifiers : + GetAdjustmentValues( mrCustomShapeGeometry, aIter.toString() ); + break; + default: + break; + } + } + if (oSpecularityValue) + GetDoublePercentage( maExtrusion, *oSpecularityValue, EAS_Specularity ); + if (oPathValue) + GetEnhancedPath(maPath, *oPathValue, sType); +} + +static void SdXMLCustomShapePropertyMerge( std::vector< css::beans::PropertyValue >& rPropVec, + const std::vector< beans::PropertyValues >& rElement, + const OUString& rElementName ) +{ + if ( !rElement.empty() ) + { + beans::PropertyValue aProp; + aProp.Name = rElementName; + aProp.Value <<= comphelper::containerToSequence(rElement); + rPropVec.push_back( aProp ); + } +} + +static void SdXMLCustomShapePropertyMerge( std::vector< css::beans::PropertyValue >& rPropVec, + const std::vector< OUString >& rElement, + const OUString& rElementName ) +{ + if ( !rElement.empty() ) + { + beans::PropertyValue aProp; + aProp.Name = rElementName; + aProp.Value <<= comphelper::containerToSequence(rElement); + rPropVec.push_back( aProp ); + } +} + +static void SdXMLCustomShapePropertyMerge( std::vector< css::beans::PropertyValue >& rPropVec, + const std::vector< css::beans::PropertyValue >& rElement, + const OUString& rElementName ) +{ + if ( !rElement.empty() ) + { + beans::PropertyValue aProp; + aProp.Name = rElementName; + aProp.Value <<= comphelper::containerToSequence(rElement); + rPropVec.push_back( aProp ); + } +} + +typedef std::unordered_map< OUString, sal_Int32 > EquationHashMap; + +/* if rPara.Type is from type EnhancedCustomShapeParameterType::EQUATION, the name of the equation + will be converted from OUString to index */ +static void CheckAndResolveEquationParameter( css::drawing::EnhancedCustomShapeParameter& rPara, EquationHashMap* pH ) +{ + if ( rPara.Type == css::drawing::EnhancedCustomShapeParameterType::EQUATION ) + { + OUString aEquationName; + if ( rPara.Value >>= aEquationName ) + { + sal_Int32 nIndex = 0; + EquationHashMap::iterator aHashIter( pH->find( aEquationName ) ); + if ( aHashIter != pH->end() ) + nIndex = (*aHashIter).second; + rPara.Value <<= nIndex; + } + } +} + +void XMLEnhancedCustomShapeContext::endFastElement(sal_Int32 ) +{ + // resolve properties that are indexing an Equation + if ( !maEquations.empty() ) + { + // creating hash map containing the name and index of each equation + EquationHashMap aH; + std::vector< OUString >::iterator aEquationNameIter = maEquationNames.begin(); + std::vector< OUString >::iterator aEquationNameEnd = maEquationNames.end(); + while( aEquationNameIter != aEquationNameEnd ) + { + aH[ *aEquationNameIter ] = static_cast<sal_Int32>( aEquationNameIter - maEquationNames.begin() ); + ++aEquationNameIter; + } + + // resolve equation + for( auto& rEquation : maEquations ) + { + sal_Int32 nIndexOf = 0; + do + { + nIndexOf = rEquation.indexOf( '?', nIndexOf ); + if ( nIndexOf != -1 ) + { + OUString aEquationName; + if ( GetEquationName( rEquation, nIndexOf + 1, aEquationName ) ) + { + // copying first characters inclusive '?' + sal_Int32 nIndex = 0; + EquationHashMap::iterator aHashIter( aH.find( aEquationName ) ); + if ( aHashIter != aH.end() ) + nIndex = (*aHashIter).second; + OUString aNew = rEquation.subView( 0, nIndexOf + 1 ) + + OUString::number( nIndex ) + + rEquation.subView( nIndexOf + aEquationName.getLength() + 1 ); + rEquation = aNew; + } + nIndexOf++; + } + } + while( nIndexOf != -1 ); + } + + // Path + for ( const beans::PropertyValue& rPathItem : maPath ) + { + switch( EASGet( rPathItem.Name ) ) + { + case EAS_Coordinates : + case EAS_GluePoints : + { + uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > const & rSeq = + *o3tl::doAccess<uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > >( + rPathItem.Value); + for ( const auto& rElem : rSeq ) + { + CheckAndResolveEquationParameter( const_cast<css::drawing::EnhancedCustomShapeParameter &>(rElem.First), &aH ); + CheckAndResolveEquationParameter( const_cast<css::drawing::EnhancedCustomShapeParameter &>(rElem.Second), &aH ); + } + } + break; + case EAS_TextFrames : + { + uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > const & rSeq = + *o3tl::doAccess<uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > >( + rPathItem.Value); + for ( const auto& rElem : rSeq ) + { + CheckAndResolveEquationParameter( const_cast<css::drawing::EnhancedCustomShapeParameter &>(rElem.TopLeft.First), &aH ); + CheckAndResolveEquationParameter( const_cast<css::drawing::EnhancedCustomShapeParameter &>(rElem.TopLeft.Second), &aH ); + CheckAndResolveEquationParameter( const_cast<css::drawing::EnhancedCustomShapeParameter &>(rElem.BottomRight.First), &aH ); + CheckAndResolveEquationParameter( const_cast<css::drawing::EnhancedCustomShapeParameter &>(rElem.BottomRight.Second), &aH ); + } + } + break; + default: + break; + } + } + for ( css::beans::PropertyValues const & aHandle : maHandles ) + { + for ( beans::PropertyValue const & propValue : aHandle ) + { + switch( EASGet( propValue.Name ) ) + { + case EAS_RangeYMinimum : + case EAS_RangeYMaximum : + case EAS_RangeXMinimum : + case EAS_RangeXMaximum : + case EAS_RadiusRangeMinimum : + case EAS_RadiusRangeMaximum : + { + CheckAndResolveEquationParameter( const_cast<css::drawing::EnhancedCustomShapeParameter &>(*o3tl::doAccess<css::drawing::EnhancedCustomShapeParameter>( + propValue.Value)), &aH ); + } + break; + + case EAS_Position : + case EAS_Polar : + { + CheckAndResolveEquationParameter( const_cast<css::drawing::EnhancedCustomShapeParameter &>((*o3tl::doAccess<css::drawing::EnhancedCustomShapeParameterPair>( + propValue.Value)).First), &aH ); + CheckAndResolveEquationParameter( const_cast<css::drawing::EnhancedCustomShapeParameter &>((*o3tl::doAccess<css::drawing::EnhancedCustomShapeParameterPair>( + propValue.Value)).Second), &aH ); + } + break; + default: + break; + } + } + } + } + + SdXMLCustomShapePropertyMerge( mrCustomShapeGeometry, maExtrusion, EASGet( EAS_Extrusion ) ); + SdXMLCustomShapePropertyMerge( mrCustomShapeGeometry, maPath, EASGet( EAS_Path ) ); + SdXMLCustomShapePropertyMerge( mrCustomShapeGeometry, maTextPath, EASGet( EAS_TextPath ) ); + SdXMLCustomShapePropertyMerge( mrCustomShapeGeometry, maEquations, EASGet( EAS_Equations ) ); + if ( !maHandles.empty() ) + SdXMLCustomShapePropertyMerge( mrCustomShapeGeometry, maHandles, EASGet( EAS_Handles ) ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLEnhancedCustomShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + EnhancedCustomShapeTokenEnum aTokenEnum = EASGet( nElement ); + if ( aTokenEnum == EAS_equation ) + { + OUString aFormula; + OUString aFormulaName; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + OUString sValue = aIter.toString(); + switch( EASGet( aIter.getToken() ) ) + { + case EAS_formula : + aFormula = sValue; + break; + case EAS_name : + aFormulaName = sValue; + break; + default: + break; + } + } + if ( !aFormulaName.isEmpty() || !aFormula.isEmpty() ) + { + maEquations.push_back( aFormula ); + maEquationNames.push_back( aFormulaName ); + } + } + else if ( aTokenEnum == EAS_handle ) + { + std::vector< css::beans::PropertyValue > aHandle; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( EASGet( aIter.getToken() ) ) + { + case EAS_handle_mirror_vertical : + GetBool( aHandle, aIter.toView(), EAS_MirroredY ); + break; + case EAS_handle_mirror_horizontal : + GetBool( aHandle, aIter.toView(), EAS_MirroredX ); + break; + case EAS_handle_switched : + GetBool( aHandle, aIter.toView(), EAS_Switched ); + break; + case EAS_handle_position : + GetEnhancedParameterPair( aHandle, aIter.toString(), EAS_Position ); + break; + case EAS_handle_range_x_minimum : + GetEnhancedParameter( aHandle, aIter.toString(), EAS_RangeXMinimum ); + break; + case EAS_handle_range_x_maximum : + GetEnhancedParameter( aHandle, aIter.toString(), EAS_RangeXMaximum ); + break; + case EAS_handle_range_y_minimum : + GetEnhancedParameter( aHandle, aIter.toString(), EAS_RangeYMinimum ); + break; + case EAS_handle_range_y_maximum : + GetEnhancedParameter( aHandle, aIter.toString(), EAS_RangeYMaximum ); + break; + case EAS_handle_polar : + GetEnhancedParameterPair( aHandle, aIter.toString(), EAS_Polar ); + break; + case EAS_handle_radius_range_minimum : + GetEnhancedParameter( aHandle, aIter.toString(), EAS_RadiusRangeMinimum ); + break; + case EAS_handle_radius_range_maximum : + GetEnhancedParameter( aHandle, aIter.toString(), EAS_RadiusRangeMaximum ); + break; + default: + break; + } + } + maHandles.push_back( comphelper::containerToSequence(aHandle) ); + } + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpcustomshape.hxx b/xmloff/source/draw/ximpcustomshape.hxx new file mode 100644 index 0000000000..f7e14765a1 --- /dev/null +++ b/xmloff/source/draw/ximpcustomshape.hxx @@ -0,0 +1,66 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmluconv.hxx> +#include <rtl/ustring.hxx> +#include <vector> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/PropertyValues.hpp> +#include <com/sun/star/drawing/XShape.hpp> + +namespace com::sun::star { + namespace container { class XIndexContainer; } + namespace beans { class XPropertySet; } + namespace xml::sax { class XAttributeList; } +} + +class XMLEnhancedCustomShapeContext : public SvXMLImportContext +{ + SvXMLUnitConverter& mrUnitConverter; + css::uno::Reference< css::drawing::XShape >& mrxShape; + std::vector< css::beans::PropertyValue >& mrCustomShapeGeometry; + + std::vector< css::beans::PropertyValue > maExtrusion; + std::vector< css::beans::PropertyValue > maPath; + std::vector< css::beans::PropertyValue > maTextPath; + std::vector< css::beans::PropertyValues > maHandles; + std::vector< OUString > maEquations; + std::vector< OUString > maEquationNames; + +public: + + + XMLEnhancedCustomShapeContext( SvXMLImport& rImport, css::uno::Reference< css::drawing::XShape > &, + std::vector< css::beans::PropertyValue >& rCustomShapeGeometry ); + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpgrp.cxx b/xmloff/source/draw/ximpgrp.cxx new file mode 100644 index 0000000000..c9cf7e218a --- /dev/null +++ b/xmloff/source/draw/ximpgrp.cxx @@ -0,0 +1,100 @@ +/* -*- 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<xmloff/xmlnamespace.hxx> +#include "ximpgrp.hxx" +#include <xmloff/xmltoken.hxx> +#include "ximpshap.hxx" +#include "eventimp.hxx" +#include "descriptionimp.hxx" + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + + +SdXMLGroupShapeContext::SdXMLGroupShapeContext( + SvXMLImport& rImport, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ) +{ +} + +SdXMLGroupShapeContext::~SdXMLGroupShapeContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLGroupShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // #i68101# + if( nElement == XML_ELEMENT(SVG, XML_TITLE) || + nElement == XML_ELEMENT(SVG, XML_DESC ) || + nElement == XML_ELEMENT(SVG_COMPAT, XML_TITLE) || + nElement == XML_ELEMENT(SVG_COMPAT, XML_DESC ) ) + { + return new SdXMLDescriptionContext( GetImport(), nElement, mxShape ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + return new SdXMLEventsContext( GetImport(), mxShape ); + } + else if( nElement == XML_ELEMENT(DRAW, XML_GLUE_POINT) ) + { + addGluePoint( xAttrList ); + } + else + { + // call GroupChildContext function at common ShapeImport + return XMLShapeImportHelper::CreateGroupChildContext( + GetImport(), nElement, xAttrList, mxChildren); + } + return nullptr; +} + +void SdXMLGroupShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + // create new group shape and add it to rShapes, use it + // as base for the new group import + AddShape( "com.sun.star.drawing.GroupShape" ); + + if(mxShape.is()) + { + SetStyle( false ); + + mxChildren.set( mxShape, uno::UNO_QUERY ); + if( mxChildren.is() ) + GetImport().GetShapeImport()->pushGroupForPostProcessing( mxChildren ); + } + + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); +} + +void SdXMLGroupShapeContext::endFastElement(sal_Int32 nElement) +{ + if( mxChildren.is() ) + GetImport().GetShapeImport()->popGroupAndPostProcess(); + + SdXMLShapeContext::endFastElement(nElement); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpgrp.hxx b/xmloff/source/draw/ximpgrp.hxx new file mode 100644 index 0000000000..8dda1b9ba1 --- /dev/null +++ b/xmloff/source/draw/ximpgrp.hxx @@ -0,0 +1,49 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/drawing/XShapes.hpp> +#include "ximpshap.hxx" + +// draw:g context (RECURSIVE) + +class SdXMLGroupShapeContext : public SdXMLShapeContext +{ + // the shape group this group is working on + css::uno::Reference< css::drawing::XShapes > mxChildren; + +public: + + SdXMLGroupShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLGroupShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximplink.cxx b/xmloff/source/draw/ximplink.cxx new file mode 100644 index 0000000000..24672f9a74 --- /dev/null +++ b/xmloff/source/draw/ximplink.cxx @@ -0,0 +1,67 @@ +/* -*- 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 <sal/log.hxx> +#include <utility> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include "ximplink.hxx" +#include <xmloff/xmltoken.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + + +SdXMLShapeLinkContext::SdXMLShapeLinkContext( SvXMLImport& rImport, const uno::Reference< xml::sax::XFastAttributeList>& xAttrList, uno::Reference< drawing::XShapes > xShapes) +: SvXMLShapeContext( rImport, false ) +, mxParent(std::move( xShapes )) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( aIter.getToken() == XML_ELEMENT(XLINK, XML_HREF) ) + { + assert(msHyperlink.pData); + msHyperlink = aIter.toString(); + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +SdXMLShapeLinkContext::~SdXMLShapeLinkContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLShapeLinkContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLShapeContext* pContext = XMLShapeImportHelper::CreateGroupChildContext( GetImport(), nElement, xAttrList, mxParent); + + if( pContext ) + { + pContext->setHyperlink( msHyperlink ); + return pContext; + } + + return nullptr; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximplink.hxx b/xmloff/source/draw/ximplink.hxx new file mode 100644 index 0000000000..017c638402 --- /dev/null +++ b/xmloff/source/draw/ximplink.hxx @@ -0,0 +1,47 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <xmloff/shapeimport.hxx> +#include <com/sun/star/drawing/XShapes.hpp> + +// draw:a context + +// this should have been a SvXMLImportContext but CreateGroupChildContext() returns +// an unneeded derivation. Should be changed sometime during refactoring. + +class SdXMLShapeLinkContext : public SvXMLShapeContext +{ + // the parent shape group this link is placed in + css::uno::Reference< css::drawing::XShapes > mxParent; + +public: + + SdXMLShapeLinkContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > xShapes); + virtual ~SdXMLShapeLinkContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpnote.cxx b/xmloff/source/draw/ximpnote.cxx new file mode 100644 index 0000000000..d855e85bf4 --- /dev/null +++ b/xmloff/source/draw/ximpnote.cxx @@ -0,0 +1,92 @@ +/* -*- 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 "ximpnote.hxx" +#include <xmloff/xmlnamespace.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SdXMLNotesContext::SdXMLNotesContext( + SdXMLImport& rImport, const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference<drawing::XShapes> const& rShapes) + : SdXMLGenericPageContext(rImport, xAttrList, rShapes) +{ + OUString sStyleName, sPageMasterName; + + for (auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + OUString sValue = aIter.toString(); + switch (aIter.getToken()) + { + case XML_ELEMENT(STYLE, XML_PAGE_LAYOUT_NAME): + { + sPageMasterName = sValue; + break; + } + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + { + sStyleName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_HEADER_NAME): + case XML_ELEMENT(PRESENTATION_SO52, XML_USE_HEADER_NAME): + case XML_ELEMENT(PRESENTATION_OOO, XML_USE_HEADER_NAME): + { + maUseHeaderDeclName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_FOOTER_NAME): + case XML_ELEMENT(PRESENTATION_SO52, XML_USE_FOOTER_NAME): + case XML_ELEMENT(PRESENTATION_OOO, XML_USE_FOOTER_NAME): + { + maUseFooterDeclName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_DATE_TIME_NAME): + case XML_ELEMENT(PRESENTATION_SO52, XML_USE_DATE_TIME_NAME): + case XML_ELEMENT(PRESENTATION_OOO, XML_USE_DATE_TIME_NAME): + { + maUseDateTimeDeclName = sValue; + break; + } + } + } + + SetStyle(sStyleName); + + // now delete all up-to-now contained shapes from this notes page + uno::Reference<drawing::XShape> xShape; + while (rShapes->getCount()) + { + rShapes->getByIndex(0) >>= xShape; + if (xShape.is()) + rShapes->remove(xShape); + } + + // set page-master? + if (!sPageMasterName.isEmpty()) + { + SetPageMaster(sPageMasterName); + } +} + +SdXMLNotesContext::~SdXMLNotesContext() {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpnote.hxx b/xmloff/source/draw/ximpnote.hxx new file mode 100644 index 0000000000..d7fe276b84 --- /dev/null +++ b/xmloff/source/draw/ximpnote.hxx @@ -0,0 +1,36 @@ +/* -*- 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 . + */ + +#pragma once + +#include "sdxmlimp_impl.hxx" +#include "ximppage.hxx" + +// presentation:notes context + +class SdXMLNotesContext : public SdXMLGenericPageContext +{ +public: + SdXMLNotesContext( SdXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLNotesContext() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximppage.cxx b/xmloff/source/draw/ximppage.cxx new file mode 100644 index 0000000000..37619c72ce --- /dev/null +++ b/xmloff/source/draw/ximppage.cxx @@ -0,0 +1,600 @@ +/* -*- 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 <sal/config.h> + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/geometry/RealPoint2D.hpp> +#include <com/sun/star/text/XTextCursor.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <cppuhelper/implbase.hxx> +#include <sax/tools/converter.hxx> +#include <XMLNumberStylesImport.hxx> +#include <xmloff/xmlstyle.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include "ximppage.hxx" +#include <animimp.hxx> +#include <XMLStringBufferImportContext.hxx> +#include <xmloff/xmlictxt.hxx> +#include "ximpstyl.hxx" +#include <xmloff/prstylei.hxx> +#include <PropertySetMerger.hxx> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include <xmloff/unointerfacetouniqueidentifiermapper.hxx> +#include <xmloff/xmluconv.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::office; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::geometry; + +namespace { + +class DrawAnnotationContext : public SvXMLImportContext +{ + +public: + DrawAnnotationContext( SvXMLImport& rImport, const Reference< xml::sax::XFastAttributeList>& xAttrList, const Reference< XAnnotationAccess >& xAnnotationAccess ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +private: + Reference< XAnnotation > mxAnnotation; + Reference< XTextCursor > mxCursor; + + OUStringBuffer maAuthorBuffer; + OUStringBuffer maInitialsBuffer; + OUStringBuffer maDateBuffer; +}; + +} + +DrawAnnotationContext::DrawAnnotationContext( SvXMLImport& rImport, const Reference< xml::sax::XFastAttributeList>& xAttrList, const Reference< XAnnotationAccess >& xAnnotationAccess ) +: SvXMLImportContext( rImport ) +, mxAnnotation( xAnnotationAccess->createAndInsertAnnotation() ) +{ + if( !mxAnnotation.is() ) + return; + + RealPoint2D aPosition; + RealSize2D aSize; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + { + sal_Int32 x; + GetImport().GetMM100UnitConverter().convertMeasureToCore( + x, aIter.toView()); + aPosition.X = static_cast<double>(x) / 100.0; + break; + } + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + { + sal_Int32 y; + GetImport().GetMM100UnitConverter().convertMeasureToCore( + y, aIter.toView()); + aPosition.Y = static_cast<double>(y) / 100.0; + break; + } + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + { + sal_Int32 w; + GetImport().GetMM100UnitConverter().convertMeasureToCore( + w, aIter.toView()); + aSize.Width = static_cast<double>(w) / 100.0; + break; + } + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + { + sal_Int32 h; + GetImport().GetMM100UnitConverter().convertMeasureToCore( + h, aIter.toView()); + aSize.Height = static_cast<double>(h) / 100.0; + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + mxAnnotation->setPosition( aPosition ); + mxAnnotation->setSize( aSize ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > DrawAnnotationContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( mxAnnotation.is() ) + { + if (nElement == XML_ELEMENT(DC, XML_CREATOR) ) + return new XMLStringBufferImportContext(GetImport(), maAuthorBuffer); + else if( nElement == XML_ELEMENT(DC, XML_DATE) ) + return new XMLStringBufferImportContext(GetImport(), maDateBuffer); + else if ( nElement == XML_ELEMENT(TEXT, XML_SENDER_INITIALS) + || nElement == XML_ELEMENT(LO_EXT, XML_SENDER_INITIALS) + || nElement == XML_ELEMENT(META, XML_CREATOR_INITIALS)) + { + return new XMLStringBufferImportContext(GetImport(), maInitialsBuffer); + } + else + { + // create text cursor on demand + if( !mxCursor.is() ) + { + uno::Reference< text::XText > xText( mxAnnotation->getTextRange() ); + if( xText.is() ) + { + rtl::Reference < XMLTextImportHelper > xTxtImport = GetImport().GetTextImport(); + mxCursor = xText->createTextCursor(); + if( mxCursor.is() ) + xTxtImport->SetCursor( mxCursor ); + } + } + + // if we have a text cursor, lets try to import some text + if( mxCursor.is() ) + { + auto p = GetImport().GetTextImport()->CreateTextChildContext( GetImport(), nElement, xAttrList ); + if (p) + return p; + } + } + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void DrawAnnotationContext::endFastElement(sal_Int32) +{ + if(mxCursor.is()) + { + // delete addition newline + mxCursor->gotoEnd( false ); + mxCursor->goLeft( 1, true ); + mxCursor->setString( "" ); + + // reset cursor + GetImport().GetTextImport()->ResetCursor(); + } + + if( mxAnnotation.is() ) + { + mxAnnotation->setAuthor( maAuthorBuffer.makeStringAndClear() ); + mxAnnotation->setInitials( maInitialsBuffer.makeStringAndClear() ); + + util::DateTime aDateTime; + if (::sax::Converter::parseDateTime(aDateTime, maDateBuffer)) + { + mxAnnotation->setDateTime(aDateTime); + } + maDateBuffer.setLength(0); + } +} + + +SdXMLGenericPageContext::SdXMLGenericPageContext( + SvXMLImport& rImport, + const Reference< xml::sax::XFastAttributeList>& xAttrList, + Reference< drawing::XShapes > const & rShapes) +: SvXMLImportContext( rImport ) +, mxShapes( rShapes ) +, mxAnnotationAccess( rShapes, UNO_QUERY ) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_NAV_ORDER) ) + { + msNavOrder = aIter.toString(); + break; + } + } +} + +SdXMLGenericPageContext::~SdXMLGenericPageContext() +{ +} + +void SdXMLGenericPageContext::startFastElement( sal_Int32 /*nElement*/, const Reference< css::xml::sax::XFastAttributeList >& ) +{ + GetImport().GetShapeImport()->pushGroupForPostProcessing( mxShapes ); + + if( GetImport().IsFormsSupported() ) + GetImport().GetFormImport()->startPage( Reference< drawing::XDrawPage >::query( mxShapes ) ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLGenericPageContext::createFastChildContext( + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + if( nElement == XML_ELEMENT(PRESENTATION, XML_ANIMATIONS) ) + { + return new XMLAnimationsContext( GetImport() ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_FORMS) ) + { + if( GetImport().IsFormsSupported() ) + return xmloff::OFormLayerXMLImport::createOfficeFormsContext( GetImport() ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_ANNOTATION) || nElement == XML_ELEMENT(OFFICE_EXT, XML_ANNOTATION) ) + { + if( mxAnnotationAccess.is() ) + return new DrawAnnotationContext( GetImport(), xAttrList, mxAnnotationAccess ); + } + else + { + // call GroupChildContext function at common ShapeImport + auto p = XMLShapeImportHelper::CreateGroupChildContext(GetImport(), nElement, xAttrList, mxShapes); + if (p) + return p; + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void SdXMLGenericPageContext::endFastElement(sal_Int32 ) +{ + GetImport().GetShapeImport()->popGroupAndPostProcess(); + + if( GetImport().IsFormsSupported() ) + GetImport().GetFormImport()->endPage(); + + if( !maUseHeaderDeclName.isEmpty() || !maUseFooterDeclName.isEmpty() || !maUseDateTimeDeclName.isEmpty() ) + { + try + { + Reference <beans::XPropertySet> xSet(mxShapes, uno::UNO_QUERY_THROW ); + Reference< beans::XPropertySetInfo > xInfo( xSet->getPropertySetInfo() ); + + if( !maUseHeaderDeclName.isEmpty() ) + { + static constexpr OUString aStrHeaderTextProp( u"HeaderText"_ustr ); + if( xInfo->hasPropertyByName( aStrHeaderTextProp ) ) + xSet->setPropertyValue( aStrHeaderTextProp, + Any( GetSdImport().GetHeaderDecl( maUseHeaderDeclName ) ) ); + } + + if( !maUseFooterDeclName.isEmpty() ) + { + static constexpr OUString aStrFooterTextProp( u"FooterText"_ustr ); + if( xInfo->hasPropertyByName( aStrFooterTextProp ) ) + xSet->setPropertyValue( aStrFooterTextProp, + Any( GetSdImport().GetFooterDecl( maUseFooterDeclName ) ) ); + } + + if( !maUseDateTimeDeclName.isEmpty() ) + { + static constexpr OUString aStrDateTimeTextProp( u"DateTimeText"_ustr ); + if( xInfo->hasPropertyByName( aStrDateTimeTextProp ) ) + { + bool bFixed; + OUString aDateTimeFormat; + const OUString aText( GetSdImport().GetDateTimeDecl( maUseDateTimeDeclName, bFixed, aDateTimeFormat ) ); + + xSet->setPropertyValue("IsDateTimeFixed", + Any( bFixed ) ); + + if( bFixed ) + { + xSet->setPropertyValue( aStrDateTimeTextProp, Any( aText ) ); + } + else if( !aDateTimeFormat.isEmpty() ) + { + const SdXMLStylesContext* pStyles = dynamic_cast< const SdXMLStylesContext* >( GetSdImport().GetShapeImport()->GetStylesContext() ); + if( !pStyles ) + pStyles = dynamic_cast< const SdXMLStylesContext* >( GetSdImport().GetShapeImport()->GetAutoStylesContext() ); + + if( pStyles ) + { + const SdXMLNumberFormatImportContext* pSdNumStyle = + dynamic_cast< const SdXMLNumberFormatImportContext* >( pStyles->FindStyleChildContext( XmlStyleFamily::DATA_STYLE, aDateTimeFormat, true ) ); + + if( pSdNumStyle ) + { + xSet->setPropertyValue("DateTimeFormat", + Any( pSdNumStyle->GetDrawKey() ) ); + } + } + } + } + } + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } + } + + SetNavigationOrder(); +} + +void SdXMLGenericPageContext::SetStyle( OUString const & rStyleName ) +{ + // set PageProperties? + if(rStyleName.isEmpty()) + return; + + try + { + const SvXMLImportContext* pContext = GetSdImport().GetShapeImport()->GetAutoStylesContext(); + + if (const SdXMLStylesContext* pStyles = dynamic_cast<const SdXMLStylesContext *>(pContext)) + { + const SvXMLStyleContext* pStyle = pStyles->FindStyleChildContext( + XmlStyleFamily::SD_DRAWINGPAGE_ID, rStyleName); + + if (const XMLPropStyleContext* pPropStyle = dynamic_cast<const XMLPropStyleContext*>(pStyle)) + { + Reference <beans::XPropertySet> xPropSet1(mxShapes, uno::UNO_QUERY); + if(xPropSet1.is()) + { + Reference< beans::XPropertySet > xPropSet( xPropSet1 ); + Reference< beans::XPropertySet > xBackgroundSet; + + static constexpr OUString aBackground(u"Background"_ustr); + if( xPropSet1->getPropertySetInfo()->hasPropertyByName( aBackground ) ) + { + Reference< beans::XPropertySetInfo > xInfo( xPropSet1->getPropertySetInfo() ); + if( xInfo.is() && xInfo->hasPropertyByName( aBackground ) ) + { + Reference< lang::XMultiServiceFactory > xServiceFact(GetSdImport().GetModel(), uno::UNO_QUERY); + if(xServiceFact.is()) + { + xBackgroundSet.set(xServiceFact->createInstance("com.sun.star.drawing.Background"), UNO_QUERY); + } + } + + if( xBackgroundSet.is() ) + xPropSet = PropertySetMerger_CreateInstance( xPropSet1, xBackgroundSet ); + } + + if(xPropSet.is()) + { + const_cast<XMLPropStyleContext*>(pPropStyle)->FillPropertySet(xPropSet); + + if( xBackgroundSet.is() ) + xPropSet1->setPropertyValue( aBackground, uno::Any( xBackgroundSet ) ); + } + } + } + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void SdXMLGenericPageContext::SetLayout() +{ + // set PresentationPageLayout? + if(!GetSdImport().IsImpress() || maPageLayoutName.isEmpty()) + return; + + sal_Int32 nType = -1; + + const SvXMLImportContext* pContext = GetSdImport().GetShapeImport()->GetStylesContext(); + + if (const SdXMLStylesContext* pStyles = dynamic_cast<const SdXMLStylesContext *>(pContext)) + { + const SvXMLStyleContext* pStyle = pStyles->FindStyleChildContext( XmlStyleFamily::SD_PRESENTATIONPAGELAYOUT_ID, maPageLayoutName); + + if (const SdXMLPresentationPageLayoutContext* pLayout = dynamic_cast<const SdXMLPresentationPageLayoutContext*>(pStyle)) + { + nType = pLayout->GetTypeId(); + } + } + + if( -1 == nType ) + { + Reference< container::XNameAccess > xPageLayouts( GetSdImport().getPageLayouts() ); + if( xPageLayouts.is() ) + { + if( xPageLayouts->hasByName( maPageLayoutName ) ) + xPageLayouts->getByName( maPageLayoutName ) >>= nType; + } + + } + + if( -1 != nType ) + { + Reference <beans::XPropertySet> xPropSet(mxShapes, uno::UNO_QUERY); + if(xPropSet.is()) + { + OUString aPropName("Layout"); + Reference< beans::XPropertySetInfo > xInfo( xPropSet->getPropertySetInfo() ); + if( xInfo.is() && xInfo->hasPropertyByName( aPropName ) ) + xPropSet->setPropertyValue(aPropName, uno::Any( static_cast<sal_Int16>(nType) ) ); + } + } +} + +void SdXMLGenericPageContext::DeleteAllShapes() +{ + // now delete all up-to-now contained shapes; they have been created + // when setting the presentation page layout. + while(mxShapes->getCount()) + { + Reference< drawing::XShape > xShape; + uno::Any aAny(mxShapes->getByIndex(0)); + + aAny >>= xShape; + + if(xShape.is()) + { + mxShapes->remove(xShape); + } + } +} + +void SdXMLGenericPageContext::SetPageMaster( OUString const & rsPageMasterName ) +{ + if (!GetSdImport().GetShapeImport()->GetStylesContext()) + return; + + // look for PageMaster with this name + + // #80012# GetStylesContext() replaced with GetAutoStylesContext() + const SvXMLStylesContext* pAutoStyles = GetSdImport().GetShapeImport()->GetAutoStylesContext(); + + const SvXMLStyleContext* pStyle = pAutoStyles ? pAutoStyles->FindStyleChildContext(XmlStyleFamily::SD_PAGEMASTERCONTEXT_ID, rsPageMasterName) : nullptr; + + const SdXMLPageMasterContext* pPageMaster = dynamic_cast<const SdXMLPageMasterContext*>(pStyle); + if (!pPageMaster) + return; + + const SdXMLPageMasterStyleContext* pPageMasterContext = pPageMaster->GetPageMasterStyle(); + + if (!pPageMasterContext) + return; + + Reference< drawing::XDrawPage > xMasterPage(GetLocalShapesContext(), uno::UNO_QUERY); + if (!xMasterPage.is()) + return; + + // set sizes for this masterpage + Reference <beans::XPropertySet> xPropSet(xMasterPage, uno::UNO_QUERY); + if (xPropSet.is()) + { + xPropSet->setPropertyValue("BorderBottom", Any(pPageMasterContext->GetBorderBottom())); + xPropSet->setPropertyValue("BorderLeft", Any(pPageMasterContext->GetBorderLeft())); + xPropSet->setPropertyValue("BorderRight", Any(pPageMasterContext->GetBorderRight())); + xPropSet->setPropertyValue("BorderTop", Any(pPageMasterContext->GetBorderTop())); + xPropSet->setPropertyValue("Width", Any(pPageMasterContext->GetWidth())); + xPropSet->setPropertyValue("Height", Any(pPageMasterContext->GetHeight())); + xPropSet->setPropertyValue("Orientation", Any(pPageMasterContext->GetOrientation())); + } +} + +namespace { + +class XoNavigationOrderAccess : public ::cppu::WeakImplHelper< XIndexAccess > +{ +public: + explicit XoNavigationOrderAccess( std::vector< Reference< XShape > >& rShapes ); + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount( ) override; + virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override; + + // XElementAccess + virtual Type SAL_CALL getElementType( ) override; + virtual sal_Bool SAL_CALL hasElements( ) override; + +private: + std::vector< Reference< XShape > > maShapes; +}; + +} + +XoNavigationOrderAccess::XoNavigationOrderAccess( std::vector< Reference< XShape > >& rShapes ) +{ + maShapes.swap( rShapes ); +} + +// XIndexAccess +sal_Int32 SAL_CALL XoNavigationOrderAccess::getCount( ) +{ + return static_cast< sal_Int32 >( maShapes.size() ); +} + +Any SAL_CALL XoNavigationOrderAccess::getByIndex( sal_Int32 Index ) +{ + if( (Index < 0) || (Index > getCount()) ) + throw IndexOutOfBoundsException(); + + return Any( maShapes[Index] ); +} + +// XElementAccess +Type SAL_CALL XoNavigationOrderAccess::getElementType( ) +{ + return cppu::UnoType<XShape>::get(); +} + +sal_Bool SAL_CALL XoNavigationOrderAccess::hasElements( ) +{ + return !maShapes.empty(); +} + +void SdXMLGenericPageContext::SetNavigationOrder() +{ + if( msNavOrder.isEmpty() ) + return; + + try + { + sal_uInt32 nIndex; + const sal_uInt32 nCount = static_cast< sal_uInt32 >( mxShapes->getCount() ); + std::vector< Reference< XShape > > aShapes( nCount ); + + ::comphelper::UnoInterfaceToUniqueIdentifierMapper& rIdMapper = GetSdImport().getInterfaceToIdentifierMapper(); + SvXMLTokenEnumerator aEnumerator( msNavOrder ); + std::u16string_view sId; + for( nIndex = 0; nIndex < nCount; ++nIndex ) + { + if( !aEnumerator.getNextToken(sId) ) + break; + + aShapes[nIndex].set( rIdMapper.getReference( OUString(sId) ), UNO_QUERY ); + } + + for( nIndex = 0; nIndex < nCount; ++nIndex ) + { + if( !aShapes[nIndex].is() ) + { + OSL_FAIL("xmloff::SdXMLGenericPageContext::SetNavigationOrder(), draw:nav-order attribute incomplete!"); + // todo: warning? + return; + } + } + + Reference< XPropertySet > xSet( mxShapes, UNO_QUERY_THROW ); + xSet->setPropertyValue("NavigationOrder", Any( Reference< XIndexAccess >( new XoNavigationOrderAccess( aShapes ) ) ) ); + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", + "unexpected exception caught while importing shape navigation order!"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximppage.hxx b/xmloff/source/draw/ximppage.hxx new file mode 100644 index 0000000000..5303458dd1 --- /dev/null +++ b/xmloff/source/draw/ximppage.hxx @@ -0,0 +1,77 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include "sdxmlimp_impl.hxx" +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/office/XAnnotationAccess.hpp> + +// draw:g context (RECURSIVE) + +class SdXMLGenericPageContext : public SvXMLImportContext +{ + // the shape group this group is working on + css::uno::Reference< css::drawing::XShapes > mxShapes; + css::uno::Reference< css::office::XAnnotationAccess > mxAnnotationAccess; + +protected: + OUString maPageLayoutName; + OUString maUseHeaderDeclName; + OUString maUseFooterDeclName; + OUString maUseDateTimeDeclName; + OUString msNavOrder; + + /** sets the page style on this page */ + void SetStyle( OUString const & rStyleName ); + + /** sets the presentation layout at this page. It is used for drawing pages and for the handout master */ + void SetLayout(); + + /** deletes all shapes on this drawing page */ + void DeleteAllShapes(); + + const SdXMLImport& GetSdImport() const { return static_cast<const SdXMLImport&>(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast<SdXMLImport&>(GetImport()); } + + /** sets the properties from a page master style with the given name on this contexts page */ + void SetPageMaster( OUString const & rsPageMasterName ); + + void SetNavigationOrder(); + +public: + + SdXMLGenericPageContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLGenericPageContext() override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + const css::uno::Reference< css::drawing::XShapes >& GetLocalShapesContext() const + { return mxShapes; } + css::uno::Reference< css::drawing::XShapes >& GetLocalShapesContext() + { return mxShapes; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpshap.cxx b/xmloff/source/draw/ximpshap.cxx new file mode 100644 index 0000000000..aaee9668fa --- /dev/null +++ b/xmloff/source/draw/ximpshap.cxx @@ -0,0 +1,4021 @@ +/* -*- 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 <config_wasm_strip.h> + +#include <cassert> + +#include <sal/log.hxx> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/container/XNameReplace.hpp> +#include <com/sun/star/presentation/ClickAction.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <utility> +#include <xmloff/unointerfacetouniqueidentifiermapper.hxx> +#include <com/sun/star/drawing/XGluePointsSupplier.hpp> +#include <com/sun/star/drawing/GluePoint2.hpp> +#include <com/sun/star/drawing/Alignment.hpp> +#include <com/sun/star/drawing/EscapeDirection.hpp> +#include <com/sun/star/media/ZoomLevel.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include "ximpshap.hxx" +#include <xmloff/XMLBase64ImportContext.hxx> +#include <xmloff/XMLShapeStyleContext.hxx> +#include <xmloff/xmluconv.hxx> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/awt/XControlModel.hpp> +#include <com/sun/star/drawing/XControlShape.hpp> +#include <com/sun/star/drawing/PointSequenceSequence.hpp> +#include <com/sun/star/drawing/PointSequence.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/util/XCloneable.hpp> +#include <com/sun/star/beans/XMultiPropertyStates.hpp> +#include <xexptran.hxx> +#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/drawing/HomogenMatrix3.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/style/XStyle.hpp> + +#include <sax/tools/converter.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <comphelper/mediamimetype.hxx> + +#include <xmloff/families.hxx> +#include<xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <EnhancedCustomShapeToken.hxx> +#include <XMLReplacementImageContext.hxx> +#include <XMLImageMapContext.hxx> +#include "sdpropls.hxx" +#include "eventimp.hxx" +#include "descriptionimp.hxx" +#include "SignatureLineContext.hxx" +#include "QRCodeContext.hxx" +#include "ximpcustomshape.hxx" +#include <XMLEmbeddedObjectImportContext.hxx> +#include <xmloff/xmlerror.hxx> +#include <xmloff/table/XMLTableImport.hxx> +#include <xmloff/ProgressBarHelper.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/vector/b2dvector.hxx> +#include <tools/urlobj.hxx> +#include <o3tl/any.hxx> +#include <o3tl/safeint.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::document; +using namespace ::xmloff::token; +using namespace ::xmloff::EnhancedCustomShapeToken; + +SvXMLEnumMapEntry<drawing::Alignment> const aXML_GlueAlignment_EnumMap[] = +{ + { XML_TOP_LEFT, drawing::Alignment_TOP_LEFT }, + { XML_TOP, drawing::Alignment_TOP }, + { XML_TOP_RIGHT, drawing::Alignment_TOP_RIGHT }, + { XML_LEFT, drawing::Alignment_LEFT }, + { XML_CENTER, drawing::Alignment_CENTER }, + { XML_RIGHT, drawing::Alignment_RIGHT }, + { XML_BOTTOM_LEFT, drawing::Alignment_BOTTOM_LEFT }, + { XML_BOTTOM, drawing::Alignment_BOTTOM }, + { XML_BOTTOM_RIGHT, drawing::Alignment_BOTTOM_RIGHT }, + { XML_TOKEN_INVALID, drawing::Alignment(0) } +}; + +SvXMLEnumMapEntry<drawing::EscapeDirection> const aXML_GlueEscapeDirection_EnumMap[] = +{ + { XML_AUTO, drawing::EscapeDirection_SMART }, + { XML_LEFT, drawing::EscapeDirection_LEFT }, + { XML_RIGHT, drawing::EscapeDirection_RIGHT }, + { XML_UP, drawing::EscapeDirection_UP }, + { XML_DOWN, drawing::EscapeDirection_DOWN }, + { XML_HORIZONTAL, drawing::EscapeDirection_HORIZONTAL }, + { XML_VERTICAL, drawing::EscapeDirection_VERTICAL }, + { XML_TOKEN_INVALID, drawing::EscapeDirection(0) } +}; + +static bool ImpIsEmptyURL( std::u16string_view rURL ) +{ + if( rURL.empty() ) + return true; + + // #i13140# Also compare against 'toplevel' URLs. which also + // result in empty filename strings. + if( rURL == u"#./" ) + return true; + + return false; +} + + +SdXMLShapeContext::SdXMLShapeContext( + SvXMLImport& rImport, + css::uno::Reference< css::xml::sax::XFastAttributeList> xAttrList, + uno::Reference< drawing::XShapes > xShapes, + bool bTemporaryShape) + : SvXMLShapeContext( rImport, bTemporaryShape ) + , mxShapes(std::move( xShapes )) + , mxAttrList(std::move(xAttrList)) + , mbListContextPushed( false ) + , mnStyleFamily(XmlStyleFamily::SD_GRAPHICS_ID) + , mbIsPlaceholder(false) + , mbClearDefaultAttributes( true ) + , mbIsUserTransformed(false) + , mnZOrder(-1) + , maSize(1, 1) + , mnRelWidth(0) + , mnRelHeight(0) + , maPosition(0, 0) + , mbVisible(true) + , mbPrintable(true) + , mbHaveXmlId(false) + , mbTextBox(false) +{ +} + +SdXMLShapeContext::~SdXMLShapeContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + // #i68101# + if( nElement == XML_ELEMENT(SVG, XML_TITLE) || nElement == XML_ELEMENT(SVG, XML_DESC) + || nElement == XML_ELEMENT(SVG_COMPAT, XML_TITLE) || nElement == XML_ELEMENT(SVG_COMPAT, XML_DESC) ) + { + xContext = new SdXMLDescriptionContext( GetImport(), nElement, mxShape ); + } + else if( nElement == XML_ELEMENT(LO_EXT, XML_SIGNATURELINE) ) + { + xContext = new SignatureLineContext( GetImport(), nElement, xAttrList, mxShape ); + } + else if( nElement == XML_ELEMENT(LO_EXT, XML_QRCODE) ) + { + xContext = new QRCodeContext( GetImport(), nElement, xAttrList, mxShape ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + xContext = new SdXMLEventsContext( GetImport(), mxShape ); + } + else if( nElement == XML_ELEMENT(DRAW, XML_GLUE_POINT) ) + { + addGluePoint( xAttrList ); + } + else if( nElement == XML_ELEMENT(DRAW, XML_THUMBNAIL) ) + { + // search attributes for xlink:href + maThumbnailURL = xAttrList->getOptionalValue(XML_ELEMENT(XLINK, XML_HREF)); + } + else + { + // create text cursor on demand + if( !mxCursor.is() ) + { + uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY ); + if( xText.is() ) + { + rtl::Reference < XMLTextImportHelper > xTxtImport = + GetImport().GetTextImport(); + mxOldCursor = xTxtImport->GetCursor(); + mxCursor = xText->createTextCursor(); + if( mxCursor.is() ) + { + xTxtImport->SetCursor( mxCursor ); + } + + // remember old list item and block (#91964#) and reset them + // for the text frame + xTxtImport->PushListContext(); + mbListContextPushed = true; + } + } + + // if we have a text cursor, lets try to import some text + if( mxCursor.is() ) + { + xContext = GetImport().GetTextImport()->CreateTextChildContext( + GetImport(), nElement, xAttrList, + ( mbTextBox ? XMLTextType::TextBox : XMLTextType::Shape ) ); + } + } + + if (!xContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return xContext; +} + +void SdXMLShapeContext::addGluePoint( const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + // get the gluepoints container for this shape if it's not already there + if( !mxGluePoints.is() ) + { + uno::Reference< drawing::XGluePointsSupplier > xSupplier( mxShape, uno::UNO_QUERY ); + if( !xSupplier.is() ) + return; + + mxGluePoints.set( xSupplier->getGluePoints(), UNO_QUERY ); + + if( !mxGluePoints.is() ) + return; + } + + drawing::GluePoint2 aGluePoint; + aGluePoint.IsUserDefined = true; + aGluePoint.Position.X = 0; + aGluePoint.Position.Y = 0; + aGluePoint.Escape = drawing::EscapeDirection_SMART; + aGluePoint.PositionAlignment = drawing::Alignment_CENTER; + aGluePoint.IsRelative = true; + + sal_Int32 nId = -1; + + // read attributes for the 3DScene + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aGluePoint.Position.X, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aGluePoint.Position.Y, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_ID): + nId = aIter.toInt32(); + break; + case XML_ELEMENT(DRAW, XML_ALIGN): + { + drawing::Alignment eKind; + if( SvXMLUnitConverter::convertEnum( eKind, aIter.toView(), aXML_GlueAlignment_EnumMap ) ) + { + aGluePoint.PositionAlignment = eKind; + aGluePoint.IsRelative = false; + } + break; + } + case XML_ELEMENT(DRAW, XML_ESCAPE_DIRECTION): + { + SvXMLUnitConverter::convertEnum( aGluePoint.Escape, aIter.toView(), aXML_GlueEscapeDirection_EnumMap ); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( nId != -1 ) + { + try + { + sal_Int32 nInternalId = mxGluePoints->insert( uno::Any( aGluePoint ) ); + GetImport().GetShapeImport()->addGluePointMapping( mxShape, nId, nInternalId ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "during setting of gluepoints"); + } + } +} + +void SdXMLShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); +} + +void SdXMLShapeContext::endFastElement(sal_Int32 ) +{ + if(mxCursor.is()) + { + // tdf#72776 force UpdateData in the EditSource so we will not override text in SdrOutliner + if( mxLockable.is() ) + { + mxLockable->removeActionLock(); + mxLockable->addActionLock(); + } + + // delete addition newline + mxCursor->gotoEnd( false ); + mxCursor->goLeft( 1, true ); + mxCursor->setString( "" ); + + // reset cursor + GetImport().GetTextImport()->ResetCursor(); + } + + if(mxOldCursor.is()) + GetImport().GetTextImport()->SetCursor( mxOldCursor ); + + // reinstall old list item (if necessary) #91964# + if (mbListContextPushed) { + GetImport().GetTextImport()->PopListContext(); + } + + if( !msHyperlink.isEmpty() ) try + { + uno::Reference< beans::XPropertySet > xProp( mxShape, uno::UNO_QUERY ); + + if ( xProp.is() && xProp->getPropertySetInfo()->hasPropertyByName( "Hyperlink" ) ) + xProp->setPropertyValue( "Hyperlink", uno::Any( msHyperlink ) ); + Reference< XEventsSupplier > xEventsSupplier( mxShape, UNO_QUERY ); + + if( xEventsSupplier.is() ) + { + Reference< XNameReplace > xEvents( xEventsSupplier->getEvents(), UNO_SET_THROW ); + + uno::Sequence< beans::PropertyValue > aProperties{ + { /* Name */ "EventType", + /* Handle */ -1, + /* Value */ uno::Any(OUString( "Presentation" )), + /* State */ beans::PropertyState_DIRECT_VALUE }, + + { /* Name */ "ClickAction", + /* Handle */ -1, + /* Value */ uno::Any(css::presentation::ClickAction_DOCUMENT), + /* State */ beans::PropertyState_DIRECT_VALUE }, + + { /* Name */ "Bookmark", + /* Handle */ -1, + /* Value */ uno::Any(msHyperlink), + /* State */ beans::PropertyState_DIRECT_VALUE } + }; + + xEvents->replaceByName( "OnClick", Any( aProperties ) ); + } + else + { + // in draw use the Bookmark property + Reference< beans::XPropertySet > xSet( mxShape, UNO_QUERY_THROW ); + xSet->setPropertyValue( "Bookmark", Any( msHyperlink ) ); + xSet->setPropertyValue("OnClick", Any( css::presentation::ClickAction_DOCUMENT ) ); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff", "while setting hyperlink"); + } + + if( mxLockable.is() ) + mxLockable->removeActionLock(); +} + +void SdXMLShapeContext::AddShape(uno::Reference< drawing::XShape >& xShape) +{ + if(xShape.is()) + { + // set shape local + mxShape = xShape; + + if(!maShapeName.isEmpty()) + { + uno::Reference< container::XNamed > xNamed( mxShape, uno::UNO_QUERY ); + if( xNamed.is() ) + xNamed->setName( maShapeName ); + } + + rtl::Reference< XMLShapeImportHelper > xImp( GetImport().GetShapeImport() ); + xImp->addShape( xShape, mxAttrList, mxShapes ); + + if( mbClearDefaultAttributes ) + { + uno::Reference<beans::XMultiPropertyStates> xMultiPropertyStates(xShape, uno::UNO_QUERY ); + if (xMultiPropertyStates.is()) + xMultiPropertyStates->setAllPropertiesToDefault(); + } + + if( !mbVisible || !mbPrintable ) try + { + uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY_THROW ); + if( !mbVisible ) + xSet->setPropertyValue("Visible", uno::Any( false ) ); + + if( !mbPrintable ) + xSet->setPropertyValue("Printable", uno::Any( false ) ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "while setting visible or printable" ); + } + + if(!mbTemporaryShape && (!GetImport().HasTextImport() + || !GetImport().GetTextImport()->IsInsideDeleteContext())) + { + xImp->shapeWithZIndexAdded( xShape, mnZOrder ); + } + + if (mnRelWidth || mnRelHeight) + { + uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY); + uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo(); + if (mnRelWidth && xPropertySetInfo->hasPropertyByName("RelativeWidth")) + xPropertySet->setPropertyValue("RelativeWidth", uno::Any(mnRelWidth)); + if (mnRelHeight && xPropertySetInfo->hasPropertyByName("RelativeHeight")) + xPropertySet->setPropertyValue("RelativeHeight", uno::Any(mnRelHeight)); + } + + if( !maShapeId.isEmpty() ) + { + uno::Reference< uno::XInterface > xRef( static_cast<uno::XInterface *>(xShape.get()) ); + GetImport().getInterfaceToIdentifierMapper().registerReference( maShapeId, xRef ); + } + + // #91065# count only if counting for shape import is enabled + if(GetImport().GetShapeImport()->IsHandleProgressBarEnabled()) + { + // #80365# increment progress bar at load once for each draw object + GetImport().GetProgressBarHelper()->Increment(); + } + } + + mxLockable.set( xShape, UNO_QUERY ); + + if( mxLockable.is() ) + mxLockable->addActionLock(); + +} + +void SdXMLShapeContext::AddShape(OUString const & serviceName) +{ + uno::Reference< lang::XMultiServiceFactory > xServiceFact(GetImport().GetModel(), uno::UNO_QUERY); + if(!xServiceFact.is()) + return; + + try + { + /* Since fix for issue i33294 the Writer model doesn't support + com.sun.star.drawing.OLE2Shape anymore. + To handle Draw OLE objects it's decided to import these + objects as com.sun.star.drawing.OLE2Shape and convert these + objects after the import into com.sun.star.drawing.GraphicObjectShape. + */ + uno::Reference< drawing::XShape > xShape; + if ( serviceName == "com.sun.star.drawing.OLE2Shape" && + uno::Reference< text::XTextDocument >(GetImport().GetModel(), uno::UNO_QUERY).is() ) + { + xShape.set(xServiceFact->createInstance("com.sun.star.drawing.temporaryForXMLImportOLE2Shape"), uno::UNO_QUERY); + } + else if (serviceName == "com.sun.star.drawing.GraphicObjectShape" + || serviceName == "com.sun.star.drawing.AppletShape" + || serviceName == "com.sun.star.drawing.FrameShape" + || serviceName == "com.sun.star.drawing.MediaShape" + || serviceName == "com.sun.star.drawing.OLE2Shape" + || serviceName == "com.sun.star.drawing.PluginShape" + || serviceName == "com.sun.star.presentation.MediaShape") + { + // On adding another entry to this list of service names to pass an argument via the WithArguments variant + // you may need to adjust the more obscure OReportDefinition::createInstanceWithArguments as well as the + // more obvious SvxUnoDrawMSFactory::createInstanceWithArguments + xShape.set( xServiceFact->createInstanceWithArguments(serviceName, { css::uno::Any(GetImport().GetDocumentBase()) }), + css::uno::UNO_QUERY); + } + else + { + xShape.set(xServiceFact->createInstance(serviceName), uno::UNO_QUERY); + } + if( xShape.is() ) + AddShape( xShape ); + } + catch(const uno::Exception& e) + { + TOOLS_WARN_EXCEPTION("xmloff", "AddShape " << serviceName); + uno::Sequence<OUString> aSeq { serviceName }; + GetImport().SetError( XMLERROR_FLAG_ERROR | XMLERROR_API, + aSeq, e.Message, nullptr ); + } +} + +void SdXMLShapeContext::SetTransformation() +{ + if(!mxShape.is()) + return; + + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + maUsedTransformation.identity(); + + if(maSize.Width != 1 || maSize.Height != 1) + { + // take care there are no zeros used by error + if(0 == maSize.Width) + maSize.Width = 1; + if(0 == maSize.Height) + maSize.Height = 1; + + // set global size. This should always be used. + maUsedTransformation.scale(maSize.Width, maSize.Height); + } + + if(maPosition.X != 0 || maPosition.Y != 0) + { + // if global position is used, add it to transformation + maUsedTransformation.translate(maPosition.X, maPosition.Y); + } + + if(mnTransform.NeedsAction()) + { + // transformation is used, apply to object. + // NOTICE: The transformation is applied AFTER evtl. used + // global positioning and scaling is used, so any shear or + // rotate used herein is applied around the (0,0) position + // of the PAGE object !!! + ::basegfx::B2DHomMatrix aMat; + mnTransform.GetFullTransform(aMat); + + // now add to transformation + maUsedTransformation *= aMat; + } + + // now set transformation for this object + + // maUsedTransformtion contains the mathematical correct matrix, which if + // applied to a unit square would generate the transformed shape. But the property + // "Transformation" contains a matrix, which can be used in TRSetBaseGeometry + // and would be created by TRGetBaseGeometry. And those use a mathematically wrong + // sign for the shearing angle. So we need to adapt the matrix here. + basegfx::B2DTuple aScale; + basegfx::B2DTuple aTranslate; + double fRotate; + double fShearX; + maUsedTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + basegfx::B2DHomMatrix aB2DHomMatrix; + aB2DHomMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( + aScale, + basegfx::fTools::equalZero(fShearX) ? 0.0 : -fShearX, + basegfx::fTools::equalZero(fRotate) ? 0.0 : fRotate, + aTranslate); + drawing::HomogenMatrix3 aUnoMatrix; + + aUnoMatrix.Line1.Column1 = aB2DHomMatrix.get(0, 0); + aUnoMatrix.Line1.Column2 = aB2DHomMatrix.get(0, 1); + aUnoMatrix.Line1.Column3 = aB2DHomMatrix.get(0, 2); + + aUnoMatrix.Line2.Column1 = aB2DHomMatrix.get(1, 0); + aUnoMatrix.Line2.Column2 = aB2DHomMatrix.get(1, 1); + aUnoMatrix.Line2.Column3 = aB2DHomMatrix.get(1, 2); + + aUnoMatrix.Line3.Column1 = 0; + aUnoMatrix.Line3.Column2 = 0; + aUnoMatrix.Line3.Column3 = 1; + + xPropSet->setPropertyValue("Transformation", Any(aUnoMatrix)); +} + +void SdXMLShapeContext::SetStyle( bool bSupportsStyle /* = true */) +{ + try + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if( !xPropSet.is() ) + return; + + do + { + // set style on shape + if(maDrawStyleName.isEmpty()) + break; + + const SvXMLStyleContext* pStyle = nullptr; + bool bAutoStyle(false); + + if(GetImport().GetShapeImport()->GetAutoStylesContext()) + pStyle = GetImport().GetShapeImport()->GetAutoStylesContext()->FindStyleChildContext(mnStyleFamily, maDrawStyleName); + + if(pStyle) + bAutoStyle = true; + + if(!pStyle && GetImport().GetShapeImport()->GetStylesContext()) + pStyle = GetImport().GetShapeImport()->GetStylesContext()->FindStyleChildContext(mnStyleFamily, maDrawStyleName); + + OUString aStyleName = maDrawStyleName; + uno::Reference< style::XStyle > xStyle; + + XMLPropStyleContext* pDocStyle + = dynamic_cast<XMLShapeStyleContext*>(const_cast<SvXMLStyleContext*>(pStyle)); + if (pDocStyle) + { + if( pDocStyle->GetStyle().is() ) + { + xStyle = pDocStyle->GetStyle(); + } + else + { + aStyleName = pDocStyle->GetParentName(); + } + } + + if( !xStyle.is() && !aStyleName.isEmpty() ) + { + try + { + + uno::Reference< style::XStyleFamiliesSupplier > xFamiliesSupplier( GetImport().GetModel(), uno::UNO_QUERY ); + + if( xFamiliesSupplier.is() ) + { + uno::Reference< container::XNameAccess > xFamilies( xFamiliesSupplier->getStyleFamilies() ); + if( xFamilies.is() ) + { + + uno::Reference< container::XNameAccess > xFamily; + + if( XmlStyleFamily::SD_PRESENTATION_ID == mnStyleFamily ) + { + aStyleName = GetImport().GetStyleDisplayName( + XmlStyleFamily::SD_PRESENTATION_ID, + aStyleName ); + sal_Int32 nPos = aStyleName.lastIndexOf( '-' ); + if( -1 != nPos ) + { + OUString aFamily( aStyleName.copy( 0, nPos ) ); + + xFamilies->getByName( aFamily ) >>= xFamily; + aStyleName = aStyleName.copy( nPos + 1 ); + } + } + else + { + // get graphics family + if (xFamilies->hasByName("graphics")) + xFamilies->getByName("graphics") >>= xFamily; + else + xFamilies->getByName("GraphicStyles") >>= xFamily; + + aStyleName = GetImport().GetStyleDisplayName( + XmlStyleFamily::SD_GRAPHICS_ID, + aStyleName ); + } + + if( xFamily.is() ) + xFamily->getByName( aStyleName ) >>= xStyle; + } + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "finding style for shape" ); + } + } + + if( bSupportsStyle && xStyle.is() ) + { + try + { + // set style on object + xPropSet->setPropertyValue("Style", Any(xStyle)); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting style for shape" ); + } + } + + // Writer shapes: if this one has a TextBox, set it here. We need to do it before + // pDocStyle->FillPropertySet, because setting some properties depend on the format + // having RES_CNTNT attribute (e.g., UNO_NAME_TEXT_(LEFT|RIGHT|UPPER|LOWER)DIST; see + // SwTextBoxHelper::syncProperty, which indirectly calls SwTextBoxHelper::isTextBox) + uno::Reference<beans::XPropertySetInfo> xPropertySetInfo + = xPropSet->getPropertySetInfo(); + static constexpr OUString sTextBox = u"TextBox"_ustr; + if (xPropertySetInfo->hasPropertyByName(sTextBox)) + xPropSet->setPropertyValue(sTextBox, uno::Any(mbTextBox)); + + // if this is an auto style, set its properties + if(bAutoStyle && pDocStyle) + { + // set PropertySet on object + pDocStyle->FillPropertySet(xPropSet); + } + + } while(false); + + // try to set text auto style + do + { + // set style on shape + if( maTextStyleName.isEmpty() ) + break; + + if( nullptr == GetImport().GetShapeImport()->GetAutoStylesContext()) + break; + + const SvXMLStyleContext* pTempStyle = GetImport().GetShapeImport()->GetAutoStylesContext()->FindStyleChildContext(XmlStyleFamily::TEXT_PARAGRAPH, maTextStyleName); + XMLPropStyleContext* pStyle = const_cast<XMLPropStyleContext*>(dynamic_cast<const XMLPropStyleContext*>( pTempStyle ) ); // use temp var, PTR_CAST is a bad macro, FindStyleChildContext will be called twice + if( pStyle == nullptr ) + break; + + // set PropertySet on object + pStyle->FillPropertySet(xPropSet); + + } while(false); + } + catch(const uno::Exception&) + { + } +} + +void SdXMLShapeContext::SetLayer() +{ + if( maLayerName.isEmpty() ) + return; + + try + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is() ) + { + xPropSet->setPropertyValue("LayerName", Any(maLayerName)); + return; + } + } + catch(const uno::Exception&) + { + } +} + +void SdXMLShapeContext::SetThumbnail() +{ + if( maThumbnailURL.isEmpty() ) + return; + + try + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if( !xPropSet.is() ) + return; + + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName( "ThumbnailGraphic" ) ) + { + // load the thumbnail graphic and export it to a wmf stream so we can set + // it at the api + + uno::Reference<graphic::XGraphic> xGraphic = GetImport().loadGraphicByURL(maThumbnailURL); + xPropSet->setPropertyValue("ThumbnailGraphic", uno::Any(xGraphic)); + } + } + catch(const uno::Exception&) + { + } +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + sal_Int32 nTmp; + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_ZINDEX): + case XML_ELEMENT(DRAW_EXT, XML_ZINDEX): + mnZOrder = aIter.toInt32(); + break; + case XML_ELEMENT(DRAW, XML_ID): + case XML_ELEMENT(DRAW_EXT, XML_ID): + if (!mbHaveXmlId) { maShapeId = aIter.toString(); } + break; + case XML_ELEMENT(DRAW, XML_NAME): + case XML_ELEMENT(DRAW_EXT, XML_NAME): + maShapeName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + case XML_ELEMENT(DRAW_EXT, XML_STYLE_NAME): + maDrawStyleName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_TEXT_STYLE_NAME): + case XML_ELEMENT(DRAW_EXT, XML_TEXT_STYLE_NAME): + maTextStyleName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_LAYER): + case XML_ELEMENT(DRAW_EXT, XML_LAYER): + maLayerName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_TRANSFORM): + case XML_ELEMENT(DRAW_EXT, XML_TRANSFORM): + mnTransform.SetString(aIter.toString(), GetImport().GetMM100UnitConverter()); + break; + case XML_ELEMENT(DRAW, XML_DISPLAY): + case XML_ELEMENT(DRAW_EXT, XML_DISPLAY): + mbVisible = IsXMLToken( aIter, XML_ALWAYS ) || IsXMLToken( aIter, XML_SCREEN ); + mbPrintable = IsXMLToken( aIter, XML_ALWAYS ) || IsXMLToken( aIter, XML_PRINTER ); + break; + case XML_ELEMENT(PRESENTATION, XML_USER_TRANSFORMED): + mbIsUserTransformed = IsXMLToken( aIter, XML_TRUE ); + break; + case XML_ELEMENT(PRESENTATION, XML_PLACEHOLDER): + mbIsPlaceholder = IsXMLToken( aIter, XML_TRUE ); + if( mbIsPlaceholder ) + mbClearDefaultAttributes = false; + break; + case XML_ELEMENT(PRESENTATION, XML_CLASS): + maPresentationClass = aIter.toString(); + break; + case XML_ELEMENT(PRESENTATION, XML_STYLE_NAME): + maDrawStyleName = aIter.toString(); + mnStyleFamily = XmlStyleFamily::SD_PRESENTATION_ID; + break; + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maPosition.X, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maPosition.Y, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maSize.Width, aIter.toView()); + if (maSize.Width > 0) + maSize.Width = o3tl::saturating_add<sal_Int32>(maSize.Width, 1); + else if (maSize.Width < 0) + maSize.Width = o3tl::saturating_add<sal_Int32>(maSize.Width, -1); + break; + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maSize.Height, aIter.toView()); + if (maSize.Height > 0) + maSize.Height = o3tl::saturating_add<sal_Int32>(maSize.Height, 1); + else if (maSize.Height < 0) + maSize.Height = o3tl::saturating_add<sal_Int32>(maSize.Height, -1); + break; + case XML_ELEMENT(SVG, XML_TRANSFORM): + case XML_ELEMENT(SVG_COMPAT, XML_TRANSFORM): + // because of #85127# take svg:transform into account and handle like + // draw:transform for compatibility + mnTransform.SetString(aIter.toString(), GetImport().GetMM100UnitConverter()); + break; + case XML_ELEMENT(STYLE, XML_REL_WIDTH): + if (sax::Converter::convertPercent(nTmp, aIter.toView())) + mnRelWidth = static_cast<sal_Int16>(nTmp); + break; + case XML_ELEMENT(STYLE, XML_REL_HEIGHT): + if (sax::Converter::convertPercent(nTmp, aIter.toView())) + mnRelHeight = static_cast<sal_Int16>(nTmp); + break; + case XML_ELEMENT(NONE, XML_ID): + case XML_ELEMENT(XML, XML_ID): + maShapeId = aIter.toString(); + mbHaveXmlId = true; + break; + default: + return false; + } + return true; +} + +bool SdXMLShapeContext::isPresentationShape() const +{ + if( !maPresentationClass.isEmpty() && const_cast<SdXMLShapeContext*>(this)->GetImport().GetShapeImport()->IsPresentationShapesSupported() ) + { + if(XmlStyleFamily::SD_PRESENTATION_ID == mnStyleFamily) + { + return true; + } + + if( IsXMLToken( maPresentationClass, XML_HEADER ) || IsXMLToken( maPresentationClass, XML_FOOTER ) || + IsXMLToken( maPresentationClass, XML_PAGE_NUMBER ) || IsXMLToken( maPresentationClass, XML_DATE_TIME ) ) + { + return true; + } + } + + return false; +} + +SdXMLRectShapeContext::SdXMLRectShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mnRadius( 0 ) +{ +} + +SdXMLRectShapeContext::~SdXMLRectShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLRectShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_CORNER_RADIUS): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRadius, aIter.toView()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLRectShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create rectangle shape + AddShape("com.sun.star.drawing.RectangleShape"); + if(!mxShape.is()) + return; + + // Add, set Style and properties from base shape + SetStyle(); + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + if(mnRadius) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + try + { + xPropSet->setPropertyValue("CornerRadius", uno::Any( mnRadius ) ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting corner radius"); + } + } + } + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLLineShapeContext::SdXMLLineShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mnX1( 0 ), + mnY1( 0 ), + mnX2( 1 ), + mnY2( 1 ) +{ +} + +SdXMLLineShapeContext::~SdXMLLineShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLLineShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_X1): + case XML_ELEMENT(SVG_COMPAT, XML_X1): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnX1, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y1): + case XML_ELEMENT(SVG_COMPAT, XML_Y1): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnY1, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_X2): + case XML_ELEMENT(SVG_COMPAT, XML_X2): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnX2, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y2): + case XML_ELEMENT(SVG_COMPAT, XML_Y2): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnY2, aIter.toView()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLLineShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // #85920# use SetTransformation() to handle import of simple lines. + // This is necessary to take into account all anchor positions and + // other things. All shape imports use the same import schemata now. + // create necessary shape (Line Shape) + AddShape("com.sun.star.drawing.PolyLineShape"); + + if(!mxShape.is()) + return; + + // Add, set Style and properties from base shape + SetStyle(); + SetLayer(); + + // get sizes and offsets + awt::Point aTopLeft(mnX1, mnY1); + awt::Point aBottomRight(mnX2, mnY2); + + if(mnX1 > mnX2) + { + aTopLeft.X = mnX2; + aBottomRight.X = mnX1; + } + + if(mnY1 > mnY2) + { + aTopLeft.Y = mnY2; + aBottomRight.Y = mnY1; + } + + // set local parameters on shape + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + drawing::PointSequenceSequence aPolyPoly(1); + drawing::PointSequence* pOuterSequence = aPolyPoly.getArray(); + pOuterSequence->realloc(2); + awt::Point* pInnerSequence = pOuterSequence->getArray(); + + *pInnerSequence = awt::Point(o3tl::saturating_sub(mnX1, aTopLeft.X), o3tl::saturating_sub(mnY1, aTopLeft.Y)); + pInnerSequence++; + *pInnerSequence = awt::Point(o3tl::saturating_sub(mnX2, aTopLeft.X), o3tl::saturating_sub(mnY2, aTopLeft.Y)); + + xPropSet->setPropertyValue("Geometry", Any(aPolyPoly)); + } + + // Size is included in point coordinates + maSize.Width = 1; + maSize.Height = 1; + maPosition.X = aTopLeft.X; + maPosition.Y = aTopLeft.Y; + + // set pos, size, shear and rotate and get copy of matrix + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLEllipseShapeContext::SdXMLEllipseShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mnCX( 0 ), + mnCY( 0 ), + mnRX( 1 ), + mnRY( 1 ), + meKind( drawing::CircleKind_FULL ), + mnStartAngle( 0 ), + mnEndAngle( 0 ) +{ +} + +SdXMLEllipseShapeContext::~SdXMLEllipseShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLEllipseShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_RX): + case XML_ELEMENT(SVG_COMPAT, XML_RX): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRX, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_RY): + case XML_ELEMENT(SVG_COMPAT, XML_RY): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRY, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_CX): + case XML_ELEMENT(SVG_COMPAT, XML_CX): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnCX, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_CY): + case XML_ELEMENT(SVG_COMPAT, XML_CY): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnCY, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_R): + case XML_ELEMENT(SVG_COMPAT, XML_R): + // single radius, it's a circle and both radii are the same + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRX, aIter.toView()); + mnRY = mnRX; + break; + case XML_ELEMENT(DRAW, XML_KIND): + SvXMLUnitConverter::convertEnum( meKind, aIter.toView(), aXML_CircleKind_EnumMap ); + break; + case XML_ELEMENT(DRAW, XML_START_ANGLE): + { + double dStartAngle; + if (::sax::Converter::convertDouble( dStartAngle, aIter.toView() )) + mnStartAngle = static_cast<sal_Int32>(dStartAngle * 100.0); + break; + } + case XML_ELEMENT(DRAW, XML_END_ANGLE): + { + double dEndAngle; + if (::sax::Converter::convertDouble( dEndAngle, aIter.toView() )) + mnEndAngle = static_cast<sal_Int32>(dEndAngle * 100.0); + break; + } + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLEllipseShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create rectangle shape + AddShape("com.sun.star.drawing.EllipseShape"); + if(!mxShape.is()) + return; + + // Add, set Style and properties from base shape + SetStyle(); + SetLayer(); + + if(mnCX != 0 || mnCY != 0 || mnRX != 1 || mnRY != 1) + { + // #i121972# center/radius is used, put to pos and size + maSize.Width = 2 * mnRX; + maSize.Height = 2 * mnRY; + maPosition.X = mnCX - mnRX; + maPosition.Y = mnCY - mnRY; + } + // set pos, size, shear and rotate + SetTransformation(); + + if( meKind != drawing::CircleKind_FULL ) + { + uno::Reference< beans::XPropertySet > xPropSet( mxShape, uno::UNO_QUERY ); + if( xPropSet.is() ) + { + // calculate the correct start and end angle + sal_Int32 mnOldStartAngle = mnStartAngle; + sal_Int32 mnOldEndAngle = mnEndAngle; + basegfx::B2DTuple aScale; + basegfx::B2DTuple aTranslate; + double fRotate; + double fShearX; + maUsedTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + if (aScale.getX() < 0 || aScale.getY() < 0) + { + // The angle for a horizontal flip is the same as the angle for a + // vertical flip because a vertical flip is treated as a horizontal + // flip plus a rotation. + + // To perform the flip, the start and end angle are switched and we + // use the fact performing a horizontal flip on a shape will change + // the angle that a radius makes with the origin to 180 degrees + // minus that angle (we use 54000 hundredths of a degree to get the + // modulus operation to give a value between 0 and 36000). + + mnStartAngle = (54000 - mnOldEndAngle) % 36000; + mnEndAngle = (54000 - mnOldStartAngle) % 36000; + } + + xPropSet->setPropertyValue("CircleKind", Any( meKind) ); + xPropSet->setPropertyValue("CircleStartAngle", Any(mnStartAngle) ); + xPropSet->setPropertyValue("CircleEndAngle", Any(mnEndAngle) ); + } + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLPolygonShapeContext::SdXMLPolygonShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, bool bClosed, bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mbClosed( bClosed ) +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLPolygonShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_VIEWBOX): + case XML_ELEMENT(SVG_COMPAT, XML_VIEWBOX): + maViewBox = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_POINTS): + maPoints = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter); + } + return true; +} + +SdXMLPolygonShapeContext::~SdXMLPolygonShapeContext() +{ +} + +void SdXMLPolygonShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // Add, set Style and properties from base shape + if(mbClosed) + AddShape("com.sun.star.drawing.PolyPolygonShape"); + else + AddShape("com.sun.star.drawing.PolyLineShape"); + + if( !mxShape.is() ) + return; + + SetStyle(); + SetLayer(); + + // set local parameters on shape + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + // set polygon + if(!maPoints.isEmpty() && !maViewBox.isEmpty()) + { + const SdXMLImExViewBox aViewBox(maViewBox, GetImport().GetMM100UnitConverter()); + basegfx::B2DVector aSize(aViewBox.GetWidth(), aViewBox.GetHeight()); + + // Is this correct? It overrides ViewBox stuff; OTOH it makes no + // sense to have the geometry content size different from object size + if(maSize.Width != 0 && maSize.Height != 0) + { + aSize = basegfx::B2DVector(maSize.Width, maSize.Height); + } + + basegfx::B2DPolygon aPolygon; + + if(basegfx::utils::importFromSvgPoints(aPolygon, maPoints)) + { + if(aPolygon.count()) + { + const basegfx::B2DRange aSourceRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aViewBox.GetWidth(), aViewBox.GetY() + aViewBox.GetHeight()); + const basegfx::B2DRange aTargetRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aSize.getX(), aViewBox.GetY() + aSize.getY()); + + if(!aSourceRange.equal(aTargetRange)) + { + aPolygon.transform( + basegfx::utils::createSourceRangeTargetRangeTransform( + aSourceRange, + aTargetRange)); + } + + css::drawing::PointSequenceSequence aPointSequenceSequence; + basegfx::utils::B2DPolyPolygonToUnoPointSequenceSequence(basegfx::B2DPolyPolygon(aPolygon), aPointSequenceSequence); + xPropSet->setPropertyValue("Geometry", Any(aPointSequenceSequence)); + // Size is now contained in the point coordinates, adapt maSize for + // to use the correct transformation matrix in SetTransformation() + maSize.Width = 1; + maSize.Height = 1; + } + } + } + } + + // set pos, size, shear and rotate and get copy of matrix + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLPathShapeContext::SdXMLPathShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ) +{ +} + +SdXMLPathShapeContext::~SdXMLPathShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLPathShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_VIEWBOX): + case XML_ELEMENT(SVG_COMPAT, XML_VIEWBOX): + maViewBox = aIter.toString(); + break; + case XML_ELEMENT(SVG, XML_D): + case XML_ELEMENT(SVG_COMPAT, XML_D): + maD = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLPathShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create polygon shape + if(maD.isEmpty()) + return; + + const SdXMLImExViewBox aViewBox(maViewBox, GetImport().GetMM100UnitConverter()); + basegfx::B2DVector aSize(aViewBox.GetWidth(), aViewBox.GetHeight()); + + // Is this correct? It overrides ViewBox stuff; OTOH it makes no + // sense to have the geometry content size different from object size + if(maSize.Width != 0 && maSize.Height != 0) + { + aSize = basegfx::B2DVector(maSize.Width, maSize.Height); + } + + basegfx::B2DPolyPolygon aPolyPolygon; + + if(!basegfx::utils::importFromSvgD(aPolyPolygon, maD, GetImport().needFixPositionAfterZ(), nullptr)) + return; + + if(!aPolyPolygon.count()) + return; + + const basegfx::B2DRange aSourceRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aViewBox.GetWidth(), aViewBox.GetY() + aViewBox.GetHeight()); + const basegfx::B2DRange aTargetRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aSize.getX(), aViewBox.GetY() + aSize.getY()); + + if(!aSourceRange.equal(aTargetRange)) + { + aPolyPolygon.transform( + basegfx::utils::createSourceRangeTargetRangeTransform( + aSourceRange, + aTargetRange)); + } + + // create shape + OUString service; + + if(aPolyPolygon.areControlPointsUsed()) + { + if(aPolyPolygon.isClosed()) + { + service = "com.sun.star.drawing.ClosedBezierShape"; + } + else + { + service = "com.sun.star.drawing.OpenBezierShape"; + } + } + else + { + if(aPolyPolygon.isClosed()) + { + service = "com.sun.star.drawing.PolyPolygonShape"; + } + else + { + service = "com.sun.star.drawing.PolyLineShape"; + } + } + + // Add, set Style and properties from base shape + AddShape(service); + + // #89344# test for mxShape.is() and not for mxShapes.is() to support + // shape import helper classes WITHOUT XShapes (member mxShapes). This + // is used by the writer. + if( !mxShape.is() ) + return; + + SetStyle(); + SetLayer(); + + // set local parameters on shape + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + + if(xPropSet.is()) + { + uno::Any aAny; + + // set polygon data + if(aPolyPolygon.areControlPointsUsed()) + { + drawing::PolyPolygonBezierCoords aSourcePolyPolygon; + + basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( + aPolyPolygon, + aSourcePolyPolygon); + aAny <<= aSourcePolyPolygon; + } + else + { + drawing::PointSequenceSequence aSourcePolyPolygon; + + basegfx::utils::B2DPolyPolygonToUnoPointSequenceSequence( + aPolyPolygon, + aSourcePolyPolygon); + aAny <<= aSourcePolyPolygon; + } + + xPropSet->setPropertyValue("Geometry", aAny); + // Size is now contained in the point coordinates, adapt maSize for + // to use the correct transformation matrix in SetTransformation() + maSize.Width = 1; + maSize.Height = 1; + } + + // set pos, size, shear and rotate + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLTextBoxShapeContext::SdXMLTextBoxShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ), + mnRadius(0), + maChainNextName("") +{ +} + +SdXMLTextBoxShapeContext::~SdXMLTextBoxShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLTextBoxShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_CORNER_RADIUS): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRadius, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_CHAIN_NEXT_NAME): + maChainNextName = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLTextBoxShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create textbox shape + bool bIsPresShape = false; + bool bClearText = false; + + OUString service; + + if( isPresentationShape() ) + { + // check if the current document supports presentation shapes + if( GetImport().GetShapeImport()->IsPresentationShapesSupported() ) + { + if( IsXMLToken( maPresentationClass, XML_SUBTITLE )) + { + // XmlShapeType::PresSubtitleShape + service = "com.sun.star.presentation.SubtitleShape"; + } + else if( IsXMLToken( maPresentationClass, XML_PRESENTATION_OUTLINE ) ) + { + // XmlShapeType::PresOutlinerShape + service = "com.sun.star.presentation.OutlinerShape"; + } + else if( IsXMLToken( maPresentationClass, XML_NOTES ) ) + { + // XmlShapeType::PresNotesShape + service = "com.sun.star.presentation.NotesShape"; + } + else if( IsXMLToken( maPresentationClass, XML_HEADER ) ) + { + // XmlShapeType::PresHeaderShape + service = "com.sun.star.presentation.HeaderShape"; + bClearText = true; + } + else if( IsXMLToken( maPresentationClass, XML_FOOTER ) ) + { + // XmlShapeType::PresFooterShape + service = "com.sun.star.presentation.FooterShape"; + bClearText = true; + } + else if( IsXMLToken( maPresentationClass, XML_PAGE_NUMBER ) ) + { + // XmlShapeType::PresSlideNumberShape + service = "com.sun.star.presentation.SlideNumberShape"; + bClearText = true; + } + else if( IsXMLToken( maPresentationClass, XML_DATE_TIME ) ) + { + // XmlShapeType::PresDateTimeShape + service = "com.sun.star.presentation.DateTimeShape"; + bClearText = true; + } + else // IsXMLToken( maPresentationClass, XML_TITLE ) ) + { + // XmlShapeType::PresTitleTextShape + service = "com.sun.star.presentation.TitleTextShape"; + } + bIsPresShape = true; + } + } + + if( service.isEmpty() ) + { + // normal text shape + service = "com.sun.star.drawing.TextShape"; + } + + // Add, set Style and properties from base shape + AddShape(service); + + if( !mxShape.is() ) + return; + + SetStyle(); + SetLayer(); + + if(bIsPresShape) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( !mbIsPlaceholder && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + if( mbIsUserTransformed && xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + if( bClearText ) + { + uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY ); + xText->setString( "" ); + } + + // set parameters on shape +//A AW->CL: Eventually You need to strip scale and translate from the transformation +//A to reach the same goal again. +//A if(!bIsPresShape || mbIsUserTransformed) +//A { +//A // set pos and size on shape, this should remove binding +//A // to presentation object on masterpage +//A SetSizeAndPosition(); +//A } + + // set pos, size, shear and rotate + SetTransformation(); + + if(mnRadius) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + try + { + xPropSet->setPropertyValue("CornerRadius", uno::Any( mnRadius ) ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting corner radius"); + } + } + } + + if(!maChainNextName.isEmpty()) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + try + { + xPropSet->setPropertyValue("TextChainNextName", + uno::Any( maChainNextName ) ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting name of next chain link"); + } + } + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLControlShapeContext::SdXMLControlShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ) +{ +} + +SdXMLControlShapeContext::~SdXMLControlShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLControlShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_CONTROL): + maFormId = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLControlShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create Control shape + // add, set style and properties from base shape + AddShape("com.sun.star.drawing.ControlShape"); + if( !mxShape.is() ) + return; + + SAL_WARN_IF( !!maFormId.isEmpty(), "xmloff", "draw:control without a form:id attribute!" ); + if( !maFormId.isEmpty() ) + { + if( GetImport().IsFormsSupported() ) + { + uno::Reference< awt::XControlModel > xControlModel( GetImport().GetFormImport()->lookupControl( maFormId ), uno::UNO_QUERY ); + if( xControlModel.is() ) + { + uno::Reference< drawing::XControlShape > xControl( mxShape, uno::UNO_QUERY ); + if( xControl.is() ) + xControl->setControl( xControlModel ); + + } + } + } + + SetStyle(); + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLConnectorShapeContext::SdXMLConnectorShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + maStart(0,0), + maEnd(1,1), + mnType( drawing::ConnectorType_STANDARD ), + mnStartGlueId(-1), + mnEndGlueId(-1), + mnDelta1(0), + mnDelta2(0), + mnDelta3(0), + mbLikelyOOXMLCurve(true) +{ +} + +SdXMLConnectorShapeContext::~SdXMLConnectorShapeContext() +{ +} + +bool SvXMLImport::needFixPositionAfterZ() const +{ + bool bWrongPositionAfterZ( false ); + sal_Int32 nUPD( 0 ); + sal_Int32 nBuildId( 0 ); + if ( getBuildIds( nUPD, nBuildId ) && // test OOo and old versions of LibO and AOO + ( ( ( nUPD == 641 ) || ( nUPD == 645 ) || ( nUPD == 680 ) || ( nUPD == 300 ) || + ( nUPD == 310 ) || ( nUPD == 320 ) || ( nUPD == 330 ) || ( nUPD == 340 ) || + ( nUPD == 350 && nBuildId < 202 ) ) + || (getGeneratorVersion() == SvXMLImport::AOO_40x))) // test if AOO 4.0.x + // apparently bug was fixed in AOO by i#123433 f15874d8f976f3874bdbcb53429eeefa65c28841 + { + bWrongPositionAfterZ = true; + } + return bWrongPositionAfterZ; +} + +namespace +{ +bool lcl_IsLikelyOOXMLCurve(const basegfx::B2DPolygon& rPolygon) +{ + sal_uInt32 nCount = rPolygon.count(); + if (!rPolygon.areControlPointsUsed() or nCount < 2) + return false; // no curve at all + + basegfx::B2DVector aStartVec(rPolygon.getNextControlPoint(0) - rPolygon.getB2DPoint(0)); + basegfx::B2DVector aEndVec(rPolygon.getPrevControlPoint(nCount-1) - rPolygon.getB2DPoint(nCount - 1)); + // LibreOffice uses one point less than OOXML for the same underlying bentConnector or + // STANDARD connector, respectively. A deeper inspection is only needed in case of 2 resulting + // points. Those connector paths look like a quarter ellipse. + switch (nCount) + { + case 2: + { + // In case start and end direction are parallel, it cannot be OOXML because that case + // introduces a handle on the path and the curve has three points then. + if (basegfx::areParallel(aStartVec, aEndVec)) + return false; + // OOXML sets the control point at 1/2, LibreOffice at 2/3 of width or height. + // A tolerance is used because +-1 deviations due to integer arithmetic in many places. + basegfx::B2DRange aRect(rPolygon.getB2DPoint(0), rPolygon.getB2DPoint(1)); + if ((basegfx::fTools::equalZero(aStartVec.getX()) + && basegfx::fTools::equal(aStartVec.getLength() * 2.0, aRect.getHeight(), 2.0)) + || (basegfx::fTools::equalZero(aStartVec.getY()) + && basegfx::fTools::equal(aStartVec.getLength() * 2.0, aRect.getWidth(), 2.0))) + return true; + } + break; + case 3: + case 5: + return basegfx::areParallel(aStartVec, aEndVec); + break; + case 4: // start and end direction are orthogonal + return basegfx::fTools::equalZero(aStartVec.scalar( aEndVec)); + break; + default: + return false; + } + return false; +} +} // end namespace + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLConnectorShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_START_SHAPE): + maStartShapeId = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_START_GLUE_POINT): + mnStartGlueId = aIter.toInt32(); + break; + case XML_ELEMENT(DRAW, XML_END_SHAPE): + maEndShapeId = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_END_GLUE_POINT): + mnEndGlueId = aIter.toInt32(); + break; + case XML_ELEMENT(DRAW, XML_LINE_SKEW): + { + OUString sValue = aIter.toString(); + SvXMLTokenEnumerator aTokenEnum( sValue ); + std::u16string_view aToken; + if( aTokenEnum.getNextToken( aToken ) ) + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnDelta1, aToken); + if( aTokenEnum.getNextToken( aToken ) ) + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnDelta2, aToken); + if( aTokenEnum.getNextToken( aToken ) ) + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnDelta3, aToken); + } + } + } + break; + } + case XML_ELEMENT(DRAW, XML_TYPE): + { + (void)SvXMLUnitConverter::convertEnum( mnType, aIter.toView(), aXML_ConnectionKind_EnumMap ); + break; + } + // #121965# draw:transform may be used in ODF1.2, e.g. exports from MS seem to use these + case XML_ELEMENT(DRAW, XML_TRANSFORM): + mnTransform.SetString(aIter.toString(), GetImport().GetMM100UnitConverter()); + break; + + case XML_ELEMENT(SVG, XML_X1): + case XML_ELEMENT(SVG_COMPAT, XML_X1): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maStart.X, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y1): + case XML_ELEMENT(SVG_COMPAT, XML_Y1): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maStart.Y, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_X2): + case XML_ELEMENT(SVG_COMPAT, XML_X2): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maEnd.X, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y2): + case XML_ELEMENT(SVG_COMPAT, XML_Y2): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maEnd.Y, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_D): + case XML_ELEMENT(SVG_COMPAT, XML_D): + { + basegfx::B2DPolyPolygon aPolyPolygon; + + if(basegfx::utils::importFromSvgD(aPolyPolygon, aIter.toString(), GetImport().needFixPositionAfterZ(), nullptr)) + { + if(aPolyPolygon.count()) + { + drawing::PolyPolygonBezierCoords aSourcePolyPolygon; + + basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( + aPolyPolygon, + aSourcePolyPolygon); + maPath <<= aSourcePolyPolygon; + + mbLikelyOOXMLCurve = lcl_IsLikelyOOXMLCurve(aPolyPolygon.getB2DPolygon(0)); + } + } + break; + } + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLConnectorShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // For security reasons, do not add empty connectors. There may have been an error in EA2 + // that created empty, far set off connectors (e.g. 63 meters below top of document). This + // is not guaranteed, but it's definitely safe to not add empty connectors. + bool bDoAdd(true); + + if( maStartShapeId.isEmpty() + && maEndShapeId.isEmpty() + && maStart.X == maEnd.X + && maStart.Y == maEnd.Y + && 0 == mnDelta1 + && 0 == mnDelta2 + && 0 == mnDelta3 + ) + { + bDoAdd = false; + } + + if(!bDoAdd) + return; + + // create Connector shape + // add, set style and properties from base shape + AddShape("com.sun.star.drawing.ConnectorShape"); + if(!mxShape.is()) + return; + + // #121965# if draw:transform is used, apply directly to the start + // and end positions before using these + if(mnTransform.NeedsAction()) + { + // transformation is used, apply to object. + ::basegfx::B2DHomMatrix aMat; + mnTransform.GetFullTransform(aMat); + + if(!aMat.isIdentity()) + { + basegfx::B2DPoint aStart(maStart.X, maStart.Y); + basegfx::B2DPoint aEnd(maEnd.X, maEnd.Y); + + aStart = aMat * aStart; + aEnd = aMat * aEnd; + + maStart.X = basegfx::fround(aStart.getX()); + maStart.Y = basegfx::fround(aStart.getY()); + maEnd.X = basegfx::fround(aEnd.getX()); + maEnd.Y = basegfx::fround(aEnd.getY()); + } + } + + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + if (xProps.is()) + xProps->setPropertyValue("EdgeOOXMLCurve", Any(mbLikelyOOXMLCurve)); + + // add connection ids + if( !maStartShapeId.isEmpty() ) + GetImport().GetShapeImport()->addShapeConnection( mxShape, true, maStartShapeId, mnStartGlueId ); + if( !maEndShapeId.isEmpty() ) + GetImport().GetShapeImport()->addShapeConnection( mxShape, false, maEndShapeId, mnEndGlueId ); + + if( xProps.is() ) + { + xProps->setPropertyValue("StartPosition", Any(maStart)); + xProps->setPropertyValue("EndPosition", Any(maEnd) ); + xProps->setPropertyValue("EdgeKind", Any(mnType) ); + xProps->setPropertyValue("EdgeLine1Delta", Any(mnDelta1) ); + xProps->setPropertyValue("EdgeLine2Delta", Any(mnDelta2) ); + xProps->setPropertyValue("EdgeLine3Delta", Any(mnDelta3) ); + } + SetStyle(); + SetLayer(); + + if ( maPath.hasValue() ) + { + // #i115492# + // Ignore svg:d attribute for text documents created by OpenOffice.org + // versions before OOo 3.3, because these OOo versions are storing + // svg:d values not using the correct unit. + bool bApplySVGD( true ); + if ( uno::Reference< text::XTextDocument >(GetImport().GetModel(), uno::UNO_QUERY).is() ) + { + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild ); + if ( GetImport().IsTextDocInOOoFileFormat() || + ( bBuildIdFound && + ( ( nUPD == 641 ) || ( nUPD == 645 ) || // prior OOo 2.0 + ( nUPD == 680 ) || // OOo 2.x + ( nUPD == 300 ) || // OOo 3.0 - OOo 3.0.1 + ( nUPD == 310 ) || // OOo 3.1 - OOo 3.1.1 + ( nUPD == 320 ) ) ) ) // OOo 3.2 - OOo 3.2.1 + { + bApplySVGD = false; + } + } + + if ( bApplySVGD ) + { + // tdf#83360 use path data only when redundant data of start and end point coordinates of + // path start/end and connector start/end is equal. This is to avoid using erroneous + // or inconsistent path data at import of foreign formats. Office itself always + // writes out a consistent data set. Not using it when there is inconsistency + // is okay since the path data is redundant, buffered data just to avoid recalculation + // of the connector's layout at load time, no real information would be lost. + // A 'connected' end has prio to direct coordinate data in Start/EndPosition + // to the path data (which should have the start/end redundant in the path) + const drawing::PolyPolygonBezierCoords* pSource = static_cast< const drawing::PolyPolygonBezierCoords* >(maPath.getValue()); + const sal_uInt32 nSequenceCount(pSource->Coordinates.getLength()); + bool bStartEqual(false); + bool bEndEqual(false); + + if(nSequenceCount) + { + const drawing::PointSequence& rStartSeq = pSource->Coordinates[0]; + const sal_uInt32 nStartCount = rStartSeq.getLength(); + + if(nStartCount) + { + const awt::Point& rStartPoint = rStartSeq.getConstArray()[0]; + + if(rStartPoint.X == maStart.X && rStartPoint.Y == maStart.Y) + { + bStartEqual = true; + } + } + + const drawing::PointSequence& rEndSeq = pSource->Coordinates[nSequenceCount - 1]; + const sal_uInt32 nEndCount = rEndSeq.getLength(); + + if(nEndCount) + { + const awt::Point& rEndPoint = rEndSeq.getConstArray()[nEndCount - 1]; + + if(rEndPoint.X == maEnd.X && rEndPoint.Y == maEnd.Y) + { + bEndEqual = true; + } + } + } + + if(!bStartEqual || !bEndEqual) + { + bApplySVGD = false; + } + } + + if ( bApplySVGD ) + { + assert(maPath.getValueType() == cppu::UnoType<drawing::PolyPolygonBezierCoords>::get()); + xProps->setPropertyValue("PolyPolygonBezier", maPath); + } + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLMeasureShapeContext::SdXMLMeasureShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + maStart(0,0), + maEnd(1,1) +{ +} + +SdXMLMeasureShapeContext::~SdXMLMeasureShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLMeasureShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(SVG, XML_X1): + case XML_ELEMENT(SVG_COMPAT, XML_X1): + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maStart.X, aIter.toView()); + break; + } + case XML_ELEMENT(SVG, XML_Y1): + case XML_ELEMENT(SVG_COMPAT, XML_Y1): + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maStart.Y, aIter.toView()); + break; + } + case XML_ELEMENT(SVG, XML_X2): + case XML_ELEMENT(SVG_COMPAT, XML_X2): + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maEnd.X, aIter.toView()); + break; + } + case XML_ELEMENT(SVG, XML_Y2): + case XML_ELEMENT(SVG_COMPAT, XML_Y2): + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maEnd.Y, aIter.toView()); + break; + } + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLMeasureShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create Measure shape + // add, set style and properties from base shape + AddShape("com.sun.star.drawing.MeasureShape"); + if(!mxShape.is()) + return; + + SetStyle(); + SetLayer(); + + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + if( xProps.is() ) + { + xProps->setPropertyValue("StartPosition", Any(maStart)); + xProps->setPropertyValue("EndPosition", Any(maEnd) ); + } + + // delete pre created fields + uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY ); + if( xText.is() ) + { + xText->setString( " " ); + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + +void SdXMLMeasureShapeContext::endFastElement(sal_Int32 nElement) +{ + do + { + // delete pre created fields + uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY ); + if( !xText.is() ) + break; + + uno::Reference< text::XTextCursor > xCursor( xText->createTextCursor() ); + if( !xCursor.is() ) + break; + + xCursor->collapseToStart(); + xCursor->goRight( 1, true ); + xCursor->setString( "" ); + } + while(false); + + SdXMLShapeContext::endFastElement(nElement); +} + + +SdXMLPageShapeContext::SdXMLPageShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), mnPageNumber(0) +{ + mbClearDefaultAttributes = false; +} + +SdXMLPageShapeContext::~SdXMLPageShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLPageShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_PAGE_NUMBER) ) + mnPageNumber = aIter.toInt32(); + else + return SdXMLShapeContext::processAttribute( aIter ); + return true; +} + +void SdXMLPageShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create Page shape + // add, set style and properties from base shape + + // #86163# take into account which type of PageShape needs to + // be constructed. It's a presentation shape if presentation:XML_CLASS == XML_PAGE. + bool bIsPresentation = !maPresentationClass.isEmpty() && + GetImport().GetShapeImport()->IsPresentationShapesSupported(); + + uno::Reference< lang::XServiceInfo > xInfo( mxShapes, uno::UNO_QUERY ); + const bool bIsOnHandoutPage = xInfo.is() && xInfo->supportsService("com.sun.star.presentation.HandoutMasterPage"); + + if( bIsOnHandoutPage ) + { + AddShape("com.sun.star.presentation.HandoutShape"); + } + else + { + if(bIsPresentation && !IsXMLToken( maPresentationClass, XML_PAGE ) ) + { + bIsPresentation = false; + } + + if(bIsPresentation) + { + AddShape("com.sun.star.presentation.PageShape"); + } + else + { + AddShape("com.sun.star.drawing.PageShape"); + } + } + + if(!mxShape.is()) + return; + + SetStyle(); + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + static constexpr OUString aPageNumberStr(u"PageNumber"_ustr); + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(aPageNumberStr)) + xPropSet->setPropertyValue(aPageNumberStr, uno::Any( mnPageNumber )); + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLCaptionShapeContext::SdXMLCaptionShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + // #86616# for correct edge rounding import mnRadius needs to be initialized + mnRadius( 0 ) +{ +} + +SdXMLCaptionShapeContext::~SdXMLCaptionShapeContext() +{ +} + +void SdXMLCaptionShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create Caption shape + // add, set style and properties from base shape + AddShape("com.sun.star.drawing.CaptionShape"); + if( !mxShape.is() ) + return; + + SetStyle(); + SetLayer(); + + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + + // SJ: If AutoGrowWidthItem is set, SetTransformation will lead to the wrong SnapRect + // because NbcAdjustTextFrameWidthAndHeight() is called (text is set later and center alignment + // is the default setting, so the top left reference point that is used by the caption point is + // no longer correct) There are two ways to solve this problem, temporarily disabling the + // autogrowwidth as we are doing here or to apply the CaptionPoint after setting text + bool bIsAutoGrowWidth = false; + if ( xProps.is() ) + { + uno::Any aAny( xProps->getPropertyValue("TextAutoGrowWidth") ); + aAny >>= bIsAutoGrowWidth; + + if ( bIsAutoGrowWidth ) + xProps->setPropertyValue("TextAutoGrowWidth", uno::Any( false ) ); + } + + // set pos, size, shear and rotate + SetTransformation(); + if( xProps.is() ) + xProps->setPropertyValue("CaptionPoint", uno::Any( maCaptionPoint ) ); + + if ( bIsAutoGrowWidth ) + xProps->setPropertyValue("TextAutoGrowWidth", uno::Any( true ) ); + + if(mnRadius) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + try + { + xPropSet->setPropertyValue("CornerRadius", uno::Any( mnRadius ) ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting corner radius"); + } + } + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLCaptionShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_CAPTION_POINT_X): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maCaptionPoint.X, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_CAPTION_POINT_Y): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maCaptionPoint.Y, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_CORNER_RADIUS): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRadius, aIter.toView()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + + +SdXMLGraphicObjectShapeContext::SdXMLGraphicObjectShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ) +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLGraphicObjectShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(XLINK, XML_HREF): + maURL = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_MIME_TYPE): + case XML_ELEMENT(LO_EXT, XML_MIME_TYPE): + msMimeType = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute(aIter); + } + return true; +} + +void SdXMLGraphicObjectShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create graphic object shape + OUString service; + + if( IsXMLToken( maPresentationClass, XML_GRAPHIC ) && GetImport().GetShapeImport()->IsPresentationShapesSupported() ) + { + service = "com.sun.star.presentation.GraphicObjectShape"; + } + else + { + service = "com.sun.star.drawing.GraphicObjectShape"; + } + + AddShape(service); + + if(!mxShape.is()) + return; + + SetStyle(); + SetLayer(); + + uno::Reference< beans::XPropertySet > xPropset(mxShape, uno::UNO_QUERY); + if(xPropset.is()) + { + // since OOo 1.x had no line or fill style for graphics, but may create + // documents with them, we have to override them here + sal_Int32 nUPD, nBuildId; + if( GetImport().getBuildIds( nUPD, nBuildId ) && (nUPD == 645) ) try + { + xPropset->setPropertyValue("FillStyle", Any( FillStyle_NONE ) ); + xPropset->setPropertyValue("LineStyle", Any( LineStyle_NONE ) ); + } + catch(const Exception&) + { + } + + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xPropset->getPropertySetInfo() ); + if( xPropsInfo.is() && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xPropset->setPropertyValue("IsEmptyPresentationObject", css::uno::Any( mbIsPlaceholder ) ); + + if( !mbIsPlaceholder ) + { + if( !maURL.isEmpty() ) + { + uno::Reference<graphic::XGraphic> xGraphic = GetImport().loadGraphicByURL(maURL); + if (xGraphic.is()) + { + xPropset->setPropertyValue("Graphic", uno::Any(xGraphic)); + } + } + } + } + + if(mbIsUserTransformed) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + // set pos, size, shear and rotate + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + +void SdXMLGraphicObjectShapeContext::endFastElement(sal_Int32 nElement) +{ + if (mxBase64Stream.is()) + { + uno::Reference<graphic::XGraphic> xGraphic(GetImport().loadGraphicFromBase64(mxBase64Stream)); + if (xGraphic.is()) + { + uno::Reference<beans::XPropertySet> xProperties(mxShape, uno::UNO_QUERY); + if (xProperties.is()) + { + xProperties->setPropertyValue("Graphic", uno::Any(xGraphic)); + } + } + } + + SdXMLShapeContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLGraphicObjectShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + css::uno::Reference< css::xml::sax::XFastContextHandler > xContext; + + if( nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA) ) + { + if( maURL.isEmpty() && !mxBase64Stream.is() ) + { + mxBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64(); + if( mxBase64Stream.is() ) + xContext = new XMLBase64ImportContext( GetImport(), + mxBase64Stream ); + } + } + + // delegate to parent class if no context could be created + if (!xContext) + xContext = SdXMLShapeContext::createFastChildContext(nElement, + xAttrList); + + if (!xContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return xContext; +} + +SdXMLGraphicObjectShapeContext::~SdXMLGraphicObjectShapeContext() +{ + +} + + +SdXMLChartShapeContext::SdXMLChartShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ) +{ +} + +void SdXMLChartShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + const bool bIsPresentation = isPresentationShape(); + + AddShape( + bIsPresentation + ? OUString("com.sun.star.presentation.ChartShape") + : OUString("com.sun.star.drawing.OLE2Shape")); + + if(!mxShape.is()) + return; + + SetStyle(); + SetLayer(); + + if( !mbIsPlaceholder ) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + uno::Any aAny; + + xProps->setPropertyValue("CLSID", Any(OUString("12DCAE26-281F-416F-a234-c3086127382e")) ); + + aAny = xProps->getPropertyValue("Model"); + uno::Reference< frame::XModel > xChartModel; + if( aAny >>= xChartModel ) + { +#if !ENABLE_WASM_STRIP_CHART + // WASM_CHART change + // TODO: Maybe use SdXMLGraphicObjectShapeContext completely instead + // or try to create as mbIsPlaceholder object adding a Chart visualization + // that should be available somehow + mxChartContext.set( GetImport().GetChartImport()->CreateChartContext( GetImport(), xChartModel ) ); +#endif + } + } + } + + if(mbIsUserTransformed) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + // set pos, size, shear and rotate + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); + + if( mxChartContext.is() ) + mxChartContext->startFastElement( nElement, xAttrList ); +} + +void SdXMLChartShapeContext::endFastElement(sal_Int32 nElement) +{ + if( mxChartContext.is() ) + mxChartContext->endFastElement(nElement); + + SdXMLShapeContext::endFastElement(nElement); +} + +void SdXMLChartShapeContext::characters( const OUString& rChars ) +{ + if( mxChartContext.is() ) + mxChartContext->characters( rChars ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLChartShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( mxChartContext.is() ) + return mxChartContext->createFastChildContext( nElement, xAttrList ); + + return nullptr; +} + + +SdXMLObjectShapeContext::SdXMLObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ) +{ +} + +SdXMLObjectShapeContext::~SdXMLObjectShapeContext() +{ +} + +void SdXMLObjectShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + // #96717# in theorie, if we don't have a URL we shouldn't even + // export this OLE shape. But practically it's too risky right now + // to change this so we better dispose this on load + //if( !mbIsPlaceholder && ImpIsEmptyURL(maHref) ) + // return; + + // #100592# this BugFix prevents that a shape is created. CL + // is thinking about an alternative. + // #i13140# Check for more than empty string in maHref, there are + // other possibilities that maHref results in empty container + // storage names + if( !(GetImport().getImportFlags() & SvXMLImportFlags::EMBEDDED) && !mbIsPlaceholder && ImpIsEmptyURL(maHref) ) + return; + + OUString service("com.sun.star.drawing.OLE2Shape"); + + bool bIsPresShape = !maPresentationClass.isEmpty() && GetImport().GetShapeImport()->IsPresentationShapesSupported(); + + if( bIsPresShape ) + { + if( IsXMLToken( maPresentationClass, XML_CHART ) ) + { + service = "com.sun.star.presentation.ChartShape"; + } + else if( IsXMLToken( maPresentationClass, XML_TABLE ) ) + { + service = "com.sun.star.presentation.CalcShape"; + } + else if( IsXMLToken( maPresentationClass, XML_OBJECT ) ) + { + service = "com.sun.star.presentation.OLE2Shape"; + } + } + + AddShape(service); + + if( !mxShape.is() ) + return; + + SetLayer(); + + if(bIsPresShape) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( !mbIsPlaceholder && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + if( mbIsUserTransformed && xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + if( !mbIsPlaceholder && !maHref.isEmpty() ) + { + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + + if( xProps.is() ) + { + OUString aPersistName = GetImport().ResolveEmbeddedObjectURL( maHref, maCLSID ); + + if ( GetImport().IsPackageURL( maHref ) ) + { + static constexpr OUString sURL( u"vnd.sun.star.EmbeddedObject:"_ustr ); + + if ( aPersistName.startsWith( sURL ) ) + aPersistName = aPersistName.copy( sURL.getLength() ); + + xProps->setPropertyValue("PersistName", + uno::Any( aPersistName ) ); + } + else + { + // this is OOo link object + xProps->setPropertyValue("LinkURL", + uno::Any( aPersistName ) ); + } + } + } + + // set pos, size, shear and rotate + SetTransformation(); + + SetStyle(); + + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); +} + +void SdXMLObjectShapeContext::endFastElement(sal_Int32 nElement) +{ + if (GetImport().isGeneratorVersionOlderThan( + SvXMLImport::OOo_34x, SvXMLImport::LO_41x)) // < LO 4.0 + { + // #i118485# + // If it's an old file from us written before OOo3.4, we need to correct + // FillStyle and LineStyle for OLE2 objects. The error was that the old paint + // implementations just ignored added fill/linestyles completely, thus + // those objects need to be corrected to not show blue and hairline which + // always was the default, but would be shown now + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + + if( xProps.is() ) + { + xProps->setPropertyValue("FillStyle", uno::Any(drawing::FillStyle_NONE)); + xProps->setPropertyValue("LineStyle", uno::Any(drawing::LineStyle_NONE)); + } + } + + if( mxBase64Stream.is() ) + { + OUString aPersistName( GetImport().ResolveEmbeddedObjectURLFromBase64() ); + static constexpr OUStringLiteral sURL( u"vnd.sun.star.EmbeddedObject:" ); + + aPersistName = aPersistName.copy( sURL.getLength() ); + + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if( xProps.is() ) + xProps->setPropertyValue("PersistName", uno::Any( aPersistName ) ); + } + + SdXMLShapeContext::endFastElement(nElement); +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLObjectShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_CLASS_ID): + maCLSID = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_HREF): + maHref = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLObjectShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if(nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA)) + { + mxBase64Stream = GetImport().GetStreamForEmbeddedObjectURLFromBase64(); + if( mxBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), mxBase64Stream ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_DOCUMENT) || + nElement == XML_ELEMENT(MATH, XML_MATH) ) + { + rtl::Reference<XMLEmbeddedObjectImportContext> xEContext( + new XMLEmbeddedObjectImportContext(GetImport(), nElement, xAttrList)); + maCLSID = xEContext->GetFilterCLSID(); + if( !maCLSID.isEmpty() ) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if( xPropSet.is() ) + { + xPropSet->setPropertyValue("CLSID", uno::Any( maCLSID ) ); + + uno::Reference< lang::XComponent > xComp; + xPropSet->getPropertyValue("Model") >>= xComp; + SAL_WARN_IF( !xComp.is(), "xmloff", "no xModel for own OLE format" ); + xEContext->SetComponent(xComp); + } + } + return xEContext; + } + + // delegate to parent class if no context could be created + return SdXMLShapeContext::createFastChildContext(nElement, xAttrList); +} + +SdXMLAppletShapeContext::SdXMLAppletShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ), + mbIsScript( false ) +{ +} + +SdXMLAppletShapeContext::~SdXMLAppletShapeContext() +{ +} + +void SdXMLAppletShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + AddShape("com.sun.star.drawing.AppletShape"); + + if( mxShape.is() ) + { + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); + } +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLAppletShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_APPLET_NAME): + maAppletName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_CODE): + maAppletCode = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_MAY_SCRIPT): + mbIsScript = IsXMLToken( aIter, XML_TRUE ); + break; + case XML_ELEMENT(XLINK, XML_HREF): + maHref = GetImport().GetAbsoluteReference(aIter.toString()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLAppletShapeContext::endFastElement(sal_Int32 nElement) +{ + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + if( xProps.is() ) + { + if ( maSize.Width && maSize.Height ) + { + // the visual area for applet must be set on loading + awt::Rectangle aRect( 0, 0, maSize.Width, maSize.Height ); + xProps->setPropertyValue("VisibleArea", Any(aRect) ); + } + + if( maParams.hasElements() ) + { + xProps->setPropertyValue("AppletCommands", Any(maParams) ); + } + + if( !maHref.isEmpty() ) + { + xProps->setPropertyValue("AppletCodeBase", Any(maHref) ); + } + + if( !maAppletName.isEmpty() ) + { + xProps->setPropertyValue("AppletName", Any(maAppletName) ); + } + + if( mbIsScript ) + { + xProps->setPropertyValue("AppletIsScript", Any(mbIsScript) ); + + } + + if( !maAppletCode.isEmpty() ) + { + xProps->setPropertyValue("AppletCode", Any(maAppletCode) ); + } + + xProps->setPropertyValue("AppletDocBase", Any(GetImport().GetDocumentBase()) ); + + SetThumbnail(); + } + + SdXMLShapeContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLAppletShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(DRAW, XML_PARAM) ) + { + OUString aParamName, aParamValue; + // now parse the attribute list and look for draw:name and draw:value + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_NAME) ) + aParamName = aIter.toString(); + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_VALUE) ) + aParamValue = aIter.toString(); + } + + if( !aParamName.isEmpty() ) + { + sal_Int32 nIndex = maParams.getLength(); + maParams.realloc( nIndex + 1 ); + auto pParams = maParams.getArray(); + pParams[nIndex].Name = aParamName; + pParams[nIndex].Handle = -1; + pParams[nIndex].Value <<= aParamValue; + pParams[nIndex].State = beans::PropertyState_DIRECT_VALUE; + } + + return new SvXMLImportContext( GetImport() ); + } + + return SdXMLShapeContext::createFastChildContext( nElement, xAttrList ); +} + + +SdXMLPluginShapeContext::SdXMLPluginShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes) : +SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ), +mbMedia( false ) +{ +} + +SdXMLPluginShapeContext::~SdXMLPluginShapeContext() +{ +} + +void SdXMLPluginShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + + // watch for MimeType attribute to see if we have a media object + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_MIME_TYPE) ) + { + if (::comphelper::IsMediaMimeType(aIter.toView())) + mbMedia = true; + // leave this loop + break; + } + } + + OUString service; + + bool bIsPresShape = false; + + if( mbMedia ) + { + service = "com.sun.star.drawing.MediaShape"; + + bIsPresShape = !maPresentationClass.isEmpty() && GetImport().GetShapeImport()->IsPresentationShapesSupported(); + if( bIsPresShape ) + { + if( IsXMLToken( maPresentationClass, XML_OBJECT ) ) + { + service = "com.sun.star.presentation.MediaShape"; + } + } + } + else + service = "com.sun.star.drawing.PluginShape"; + + AddShape(service); + + if( !mxShape.is() ) + return; + + if (mbMedia) + { + // The media may have a crop, apply it. + SetStyle(/*bSupportsStyle=*/false); + } + + SetLayer(); + + if(bIsPresShape) + { + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( !mbIsPlaceholder && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + if( mbIsUserTransformed && xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + // set pos, size, shear and rotate + SetTransformation(); + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); +} + +static OUString +lcl_GetMediaReference(SvXMLImport const& rImport, OUString const& rURL) +{ + if (rImport.IsPackageURL(rURL)) + { + return "vnd.sun.star.Package:" + rURL; + } + else + { + return rImport.GetAbsoluteReference(rURL); + } +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLPluginShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_MIME_TYPE): + maMimeType = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_HREF): + maHref = lcl_GetMediaReference(GetImport(), aIter.toString()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLPluginShapeContext::endFastElement(sal_Int32 nElement) +{ + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + + if( xProps.is() ) + { + if ( maSize.Width && maSize.Height ) + { + static constexpr OUString sVisibleArea( u"VisibleArea"_ustr ); + uno::Reference< beans::XPropertySetInfo > aXPropSetInfo( xProps->getPropertySetInfo() ); + if ( !aXPropSetInfo.is() || aXPropSetInfo->hasPropertyByName( sVisibleArea ) ) + { + // the visual area for a plugin must be set on loading + awt::Rectangle aRect( 0, 0, maSize.Width, maSize.Height ); + xProps->setPropertyValue( sVisibleArea, Any(aRect) ); + } + } + + if( !mbMedia ) + { + // in case we have a plugin object + if( maParams.hasElements() ) + { + xProps->setPropertyValue("PluginCommands", Any(maParams) ); + } + + if( !maMimeType.isEmpty() ) + { + xProps->setPropertyValue("PluginMimeType", Any(maMimeType) ); + } + + if( !maHref.isEmpty() ) + { + xProps->setPropertyValue("PluginURL", Any(maHref) ); + } + } + else + { + // in case we have a media object + xProps->setPropertyValue( "MediaURL", uno::Any(maHref)); + + xProps->setPropertyValue("MediaMimeType", uno::Any(maMimeType) ); + + for( const auto& rParam : std::as_const(maParams) ) + { + const OUString& rName = rParam.Name; + + if( rName == "Loop" ) + { + OUString aValueStr; + rParam.Value >>= aValueStr; + xProps->setPropertyValue("Loop", + uno::Any( aValueStr == "true" ) ); + } + else if( rName == "Mute" ) + { + OUString aValueStr; + rParam.Value >>= aValueStr; + xProps->setPropertyValue("Mute", + uno::Any( aValueStr == "true" ) ); + } + else if( rName == "VolumeDB" ) + { + OUString aValueStr; + rParam.Value >>= aValueStr; + xProps->setPropertyValue("VolumeDB", + uno::Any( static_cast< sal_Int16 >( aValueStr.toInt32() ) ) ); + } + else if( rName == "Zoom" ) + { + OUString aZoomStr; + media::ZoomLevel eZoomLevel; + + rParam.Value >>= aZoomStr; + + if( aZoomStr == "25%" ) + eZoomLevel = media::ZoomLevel_ZOOM_1_TO_4; + else if( aZoomStr == "50%" ) + eZoomLevel = media::ZoomLevel_ZOOM_1_TO_2; + else if( aZoomStr == "100%" ) + eZoomLevel = media::ZoomLevel_ORIGINAL; + else if( aZoomStr == "200%" ) + eZoomLevel = media::ZoomLevel_ZOOM_2_TO_1; + else if( aZoomStr == "400%" ) + eZoomLevel = media::ZoomLevel_ZOOM_4_TO_1; + else if( aZoomStr == "fit" ) + eZoomLevel = media::ZoomLevel_FIT_TO_WINDOW; + else if( aZoomStr == "fixedfit" ) + eZoomLevel = media::ZoomLevel_FIT_TO_WINDOW_FIXED_ASPECT; + else if( aZoomStr == "fullscreen" ) + eZoomLevel = media::ZoomLevel_FULLSCREEN; + else + eZoomLevel = media::ZoomLevel_NOT_AVAILABLE; + + xProps->setPropertyValue("Zoom", uno::Any( eZoomLevel ) ); + } + } + } + + SetThumbnail(); + } + + SdXMLShapeContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLPluginShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(DRAW, XML_PARAM) ) + { + OUString aParamName, aParamValue; + // now parse the attribute list and look for draw:name and draw:value + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_NAME) ) + aParamName = aIter.toString(); + else if( aIter.getToken() == XML_ELEMENT(DRAW, XML_VALUE) ) + aParamValue = aIter.toString(); + } + + if( !aParamName.isEmpty() ) + { + sal_Int32 nIndex = maParams.getLength(); + maParams.realloc( nIndex + 1 ); + auto pParams = maParams.getArray(); + pParams[nIndex].Name = aParamName; + pParams[nIndex].Handle = -1; + pParams[nIndex].Value <<= aParamValue; + pParams[nIndex].State = beans::PropertyState_DIRECT_VALUE; + } + + return new SvXMLImportContext( GetImport() ); + } + + return SdXMLShapeContext::createFastChildContext( nElement, xAttrList ); +} + + +SdXMLFloatingFrameShapeContext::SdXMLFloatingFrameShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ) +{ +} + +SdXMLFloatingFrameShapeContext::~SdXMLFloatingFrameShapeContext() +{ +} + +uno::Reference<drawing::XShape> SdXMLFloatingFrameShapeContext::CreateFloatingFrameShape() const +{ + uno::Reference<lang::XMultiServiceFactory> xServiceFact(GetImport().GetModel(), uno::UNO_QUERY); + if (!xServiceFact.is()) + return nullptr; + uno::Reference<drawing::XShape> xShape( + xServiceFact->createInstance("com.sun.star.drawing.FrameShape"), uno::UNO_QUERY); + return xShape; +} + +void SdXMLFloatingFrameShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + uno::Reference<drawing::XShape> xShape(SdXMLFloatingFrameShapeContext::CreateFloatingFrameShape()); + + uno::Reference< beans::XPropertySet > xProps(xShape, uno::UNO_QUERY); + // set FrameURL before AddShape, we have to do it again later because it + // gets cleared when the SdrOle2Obj is attached to the XShape. But we want + // FrameURL to exist when AddShape triggers SetPersistName which itself + // triggers SdrOle2Obj::CheckFileLink_Impl and at that point we want to + // know what URL will end up being used. So bodge this by setting FrameURL + // to the temp pre-SdrOle2Obj attached properties and we can smuggle it + // eventually into SdrOle2Obj::SetPersistName at the right point after + // PersistName is set but before SdrOle2Obj::CheckFileLink_Impl is called + // in order to inform the link manager that this is an IFrame that links to + // a URL + if (xProps && !maHref.isEmpty()) + xProps->setPropertyValue("FrameURL", Any(maHref)); + + AddShape(xShape); + + if( !mxShape.is() ) + return; + + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + if( xProps.is() ) + { + if( !maFrameName.isEmpty() ) + { + xProps->setPropertyValue("FrameName", Any(maFrameName) ); + } + + if( !maHref.isEmpty() ) + { + if (INetURLObject(maHref).IsExoticProtocol()) + GetImport().NotifyMacroEventRead(); + + xProps->setPropertyValue("FrameURL", Any(maHref) ); + } + } + + SetStyle(); + + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLFloatingFrameShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_FRAME_NAME): + maFrameName = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_HREF): + maHref = GetImport().GetAbsoluteReference(aIter.toString()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLFloatingFrameShapeContext::endFastElement(sal_Int32 nElement) +{ + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + + if( xProps.is() ) + { + if ( maSize.Width && maSize.Height ) + { + // the visual area for a floating frame must be set on loading + awt::Rectangle aRect( 0, 0, maSize.Width, maSize.Height ); + xProps->setPropertyValue("VisibleArea", Any(aRect) ); + } + } + + SetThumbnail(); + SdXMLShapeContext::endFastElement(nElement); +} + + +SdXMLFrameShapeContext::SdXMLFrameShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mbSupportsReplacement( false ) +{ + uno::Reference < util::XCloneable > xClone( xAttrList, uno::UNO_QUERY ); + if( xClone.is() ) + mxAttrList.set( xClone->createClone(), uno::UNO_QUERY ); + else + mxAttrList = new sax_fastparser::FastAttributeList(xAttrList); +} + +SdXMLFrameShapeContext::~SdXMLFrameShapeContext() +{ +} + +void SdXMLFrameShapeContext::removeGraphicFromImportContext(const SvXMLImportContext& rContext) +{ + const SdXMLGraphicObjectShapeContext* pSdXMLGraphicObjectShapeContext = dynamic_cast< const SdXMLGraphicObjectShapeContext* >(&rContext); + + if(!pSdXMLGraphicObjectShapeContext) + return; + + try + { + uno::Reference< container::XChild > xChild(pSdXMLGraphicObjectShapeContext->getShape(), uno::UNO_QUERY_THROW); + + uno::Reference< drawing::XShapes > xParent(xChild->getParent(), uno::UNO_QUERY_THROW); + + // remove from parent + xParent->remove(pSdXMLGraphicObjectShapeContext->getShape()); + + // dispose + uno::Reference< lang::XComponent > xComp(pSdXMLGraphicObjectShapeContext->getShape(), UNO_QUERY); + + if(xComp.is()) + { + xComp->dispose(); + } + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "Error in cleanup of multiple graphic object import." ); + } +} + +namespace +{ +uno::Reference<beans::XPropertySet> getGraphicPropertySetFromImportContext(const SvXMLImportContext& rContext) +{ + uno::Reference<beans::XPropertySet> aPropertySet; + const SdXMLGraphicObjectShapeContext* pSdXMLGraphicObjectShapeContext = dynamic_cast<const SdXMLGraphicObjectShapeContext*>(&rContext); + + if (pSdXMLGraphicObjectShapeContext) + aPropertySet.set(pSdXMLGraphicObjectShapeContext->getShape(), uno::UNO_QUERY); + + return aPropertySet; +} + +} // end anonymous namespace + +uno::Reference<graphic::XGraphic> SdXMLFrameShapeContext::getGraphicFromImportContext(const SvXMLImportContext& rContext) const +{ + uno::Reference<graphic::XGraphic> xGraphic; + try + { + const uno::Reference<beans::XPropertySet> xPropertySet = getGraphicPropertySetFromImportContext(rContext); + + if (xPropertySet.is()) + { + xPropertySet->getPropertyValue("Graphic") >>= xGraphic; + } + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff", "Error in cleanup of multiple graphic object import."); + } + + return xGraphic; +} + +OUString SdXMLFrameShapeContext::getMimeTypeFromImportContext(const SvXMLImportContext& rContext) const +{ + OUString aMimeType; + const SdXMLGraphicObjectShapeContext* pSdXMLGraphicObjectShapeContext = dynamic_cast<const SdXMLGraphicObjectShapeContext*>(&rContext); + + if (pSdXMLGraphicObjectShapeContext) + aMimeType = pSdXMLGraphicObjectShapeContext->getMimeType(); + return aMimeType; +} + +OUString SdXMLFrameShapeContext::getGraphicPackageURLFromImportContext(const SvXMLImportContext& rContext) const +{ + OUString aRetval; + const SdXMLGraphicObjectShapeContext* pSdXMLGraphicObjectShapeContext = dynamic_cast< const SdXMLGraphicObjectShapeContext* >(&rContext); + + if(pSdXMLGraphicObjectShapeContext) + { + try + { + const uno::Reference< beans::XPropertySet > xPropSet(pSdXMLGraphicObjectShapeContext->getShape(), uno::UNO_QUERY_THROW); + + xPropSet->getPropertyValue("GraphicStreamURL") >>= aRetval; + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "Error in cleanup of multiple graphic object import." ); + } + } + + return aRetval; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLFrameShapeContext::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + SvXMLImportContextRef xContext; + if( !mxImplContext.is() ) + { + SvXMLShapeContext* pShapeContext = XMLShapeImportHelper::CreateFrameChildContext( + GetImport(), nElement, xAttrList, mxShapes, mxAttrList ); + + xContext = pShapeContext; + + // propagate the hyperlink to child context + if ( !msHyperlink.isEmpty() ) + pShapeContext->setHyperlink( msHyperlink ); + + auto nToken = nElement & TOKEN_MASK; + bool bMedia = false; + // Ignore gltf model if necessary and so the fallback image will be imported + if( nToken == XML_PLUGIN ) + { + SdXMLPluginShapeContext* pPluginContext = dynamic_cast<SdXMLPluginShapeContext*>(pShapeContext); + if( pPluginContext && pPluginContext->getMimeType() == "model/vnd.gltf+json" ) + { + mxImplContext = nullptr; + return new SvXMLImportContext(GetImport()); + } + else if (pPluginContext && ::comphelper::IsMediaMimeType(pPluginContext->getMimeType())) + { + // The media may have a preview, import it. + bMedia = true; + } + } + + mxImplContext = xContext; + mbSupportsReplacement = (nToken == XML_OBJECT ) || (nToken == XML_OBJECT_OLE) || bMedia; + setSupportsMultipleContents(nToken == XML_IMAGE); + + if(getSupportsMultipleContents() && dynamic_cast< SdXMLGraphicObjectShapeContext* >(xContext.get())) + { + if ( !maShapeId.isEmpty() ) + GetImport().getInterfaceToIdentifierMapper().reserveIdentifier( maShapeId ); + + addContent(*mxImplContext); + } + } + else if(getSupportsMultipleContents() && nElement == XML_ELEMENT(DRAW, XML_IMAGE)) + { + // read another image + xContext = XMLShapeImportHelper::CreateFrameChildContext( + GetImport(), nElement, xAttrList, mxShapes, mxAttrList); + mxImplContext = xContext; + + if(dynamic_cast< SdXMLGraphicObjectShapeContext* >(xContext.get())) + { + addContent(*mxImplContext); + } + } + else if( mbSupportsReplacement && !mxReplImplContext.is() && + nElement == XML_ELEMENT(DRAW, XML_IMAGE) ) + { + // read replacement image + SvXMLImportContext *pImplContext = mxImplContext.get(); + SdXMLShapeContext *pSContext = + dynamic_cast<SdXMLShapeContext*>( pImplContext ); + if( pSContext ) + { + uno::Reference < beans::XPropertySet > xPropSet( + pSContext->getShape(), uno::UNO_QUERY ); + if( xPropSet.is() ) + { + xContext = new XMLReplacementImageContext( GetImport(), + nElement, xAttrList, xPropSet ); + mxReplImplContext = xContext; + } + } + } + else if( nElement == XML_ELEMENT(SVG, XML_TITLE) || // #i68101# + nElement == XML_ELEMENT(SVG_COMPAT, XML_TITLE) || + nElement == XML_ELEMENT(SVG, XML_DESC) || + nElement == XML_ELEMENT(SVG_COMPAT, XML_DESC) || + nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) || + nElement == XML_ELEMENT(DRAW, XML_GLUE_POINT) || + nElement == XML_ELEMENT(DRAW, XML_THUMBNAIL) ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + // note: no more draw:image can be added once we get here + mxImplContext = solveMultipleImages(); + } + SvXMLImportContext *pImplContext = mxImplContext.get(); + xContext = static_cast<SvXMLImportContext*>(dynamic_cast<SdXMLShapeContext&>(*pImplContext).createFastChildContext( nElement, + xAttrList ).get()); + } + else if ( nElement == XML_ELEMENT(DRAW, XML_IMAGE_MAP) ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + // note: no more draw:image can be added once we get here + mxImplContext = solveMultipleImages(); + } + SdXMLShapeContext *pSContext = dynamic_cast< SdXMLShapeContext* >( mxImplContext.get() ); + if( pSContext ) + { + uno::Reference < beans::XPropertySet > xPropSet( pSContext->getShape(), uno::UNO_QUERY ); + if (xPropSet.is()) + { + xContext = new XMLImageMapContext(GetImport(), xPropSet); + } + } + } + else if ( nElement == XML_ELEMENT(LO_EXT, XML_SIGNATURELINE) ) + { + SdXMLShapeContext* pSContext = dynamic_cast<SdXMLShapeContext*>(mxImplContext.get()); + if (pSContext) + { + uno::Reference<beans::XPropertySet> xPropSet(pSContext->getShape(), uno::UNO_QUERY); + if (xPropSet.is()) + { + xContext = new SignatureLineContext(GetImport(), nElement, xAttrList, + pSContext->getShape()); + } + } + } + else if ( nElement == XML_ELEMENT(LO_EXT, XML_QRCODE)) + { + SdXMLShapeContext* pSContext = dynamic_cast<SdXMLShapeContext*>(mxImplContext.get()); + if (pSContext) + { + uno::Reference<beans::XPropertySet> xPropSet(pSContext->getShape(), uno::UNO_QUERY); + if (xPropSet.is()) + { + xContext = new QRCodeContext(GetImport(), nElement, xAttrList, + pSContext->getShape()); + } + } + } + + return xContext; +} + +void SdXMLFrameShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + // ignore +} + +void SdXMLFrameShapeContext::endFastElement(sal_Int32 nElement) +{ + // solve if multiple image child contexts were imported + SvXMLImportContextRef const pSelectedContext(solveMultipleImages()); + const SdXMLGraphicObjectShapeContext* pShapeContext( + dynamic_cast<const SdXMLGraphicObjectShapeContext*>(pSelectedContext.get())); + if ( pShapeContext ) + { + assert( mxImplContext.is() ); + const uno::Reference< uno::XInterface > xShape( pShapeContext->getShape() ); + GetImport().getInterfaceToIdentifierMapper().registerReservedReference( maShapeId, xShape ); + } + + if( !mxImplContext.is() ) + { + // now check if this is an empty presentation object + for( auto& aIter : sax_fastparser::castToFastAttributeList(mxAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(PRESENTATION, XML_PLACEHOLDER): + mbIsPlaceholder = IsXMLToken( aIter, XML_TRUE ); + break; + case XML_ELEMENT(PRESENTATION, XML_CLASS): + maPresentationClass = aIter.toString(); + break; + default:; + } + } + + if( (!maPresentationClass.isEmpty()) && mbIsPlaceholder ) + { + uno::Reference< xml::sax::XFastAttributeList> xEmpty; + + enum XMLTokenEnum eToken = XML_TEXT_BOX; + + if( IsXMLToken( maPresentationClass, XML_GRAPHIC ) ) + { + eToken = XML_IMAGE; + + } + else if( IsXMLToken( maPresentationClass, XML_PAGE ) ) + { + eToken = XML_PAGE_THUMBNAIL; + } + else if( IsXMLToken( maPresentationClass, XML_CHART ) || + IsXMLToken( maPresentationClass, XML_TABLE ) || + IsXMLToken( maPresentationClass, XML_OBJECT ) ) + { + eToken = XML_OBJECT; + } + + auto x = XML_ELEMENT(DRAW, eToken); + mxImplContext = XMLShapeImportHelper::CreateFrameChildContext( + GetImport(), x, mxAttrList, mxShapes, xEmpty ); + + if( mxImplContext.is() ) + { + mxImplContext->startFastElement( x, mxAttrList ); + mxImplContext->endFastElement(x); + } + } + } + + mxImplContext = nullptr; + SdXMLShapeContext::endFastElement(nElement); +} + +bool SdXMLFrameShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + bool bId( false ); + + switch ( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_ID): + case XML_ELEMENT(DRAW_EXT, XML_ID): + case XML_ELEMENT(NONE, XML_ID): + case XML_ELEMENT(XML, XML_ID) : + bId = true; + break; + default:; + } + + if ( bId ) + return SdXMLShapeContext::processAttribute( aIter ); + return true; // deliberately ignoring other attributes +} + + +SdXMLCustomShapeContext::SdXMLCustomShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ) +{ + // See the XMLTextFrameContext ctor, a frame has Writer content (and not + // editeng) if its autostyle has a parent style. Do the same for shapes as well. + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if (aIter.getToken() == XML_ELEMENT(DRAW, XML_STYLE_NAME)) + { + OUString aStyleName = aIter.toString(); + if(!aStyleName.isEmpty()) + { + rtl::Reference<XMLTextImportHelper> xTxtImport = GetImport().GetTextImport(); + XMLPropStyleContext* pStyle = xTxtImport->FindAutoFrameStyle(aStyleName); + // Note that this an API name, so intentionally not localized. + // Also allow other Frame styles with the same prefix, we just want to reject + // Graphics after all. + if (pStyle && pStyle->GetParentName().startsWith("Frame")) + { + mbTextBox = true; + break; + } + } + } + } +} + +SdXMLCustomShapeContext::~SdXMLCustomShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLCustomShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_ENGINE) ) + { + maCustomShapeEngine = aIter.toString(); + } + else if (aIter.getToken() == XML_ELEMENT(DRAW, XML_DATA) ) + { + maCustomShapeData = aIter.toString(); + } + else + return SdXMLShapeContext::processAttribute( aIter ); + return true; +} + +void SdXMLCustomShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create rectangle shape + AddShape("com.sun.star.drawing.CustomShape"); + if ( !mxShape.is() ) + return; + + // Add, set Style and properties from base shape + SetStyle(); + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + try + { + uno::Reference< beans::XPropertySet > xPropSet( mxShape, uno::UNO_QUERY ); + if( xPropSet.is() ) + { + if ( !maCustomShapeEngine.isEmpty() ) + { + xPropSet->setPropertyValue( EASGet( EAS_CustomShapeEngine ), Any(maCustomShapeEngine) ); + } + if ( !maCustomShapeData.isEmpty() ) + { + xPropSet->setPropertyValue( EASGet( EAS_CustomShapeData ), Any(maCustomShapeData) ); + } + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting enhanced customshape geometry" ); + } + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + +void SdXMLCustomShapeContext::endFastElement(sal_Int32 nElement) +{ + // Customshapes remember mirror state in its enhanced geometry. + // SetTransformation() in StartElement() may have applied mirroring, but that is not yet + // contained. Merge that information here before writing the property. + if(!maUsedTransformation.isIdentity()) + { + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + + maUsedTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + + if (aScale.getX() < 0.0) + { + static constexpr OUString sName(u"MirroredX"_ustr); + //fdo#84043 Merge, if property exists, otherwise append it + auto aI = std::find_if(maCustomShapeGeometry.begin(), maCustomShapeGeometry.end(), + [](beans::PropertyValue& rValue) { return rValue.Name == sName; }); + if (aI != maCustomShapeGeometry.end()) + { + beans::PropertyValue& rItem = *aI; + bool bMirroredX = *o3tl::doAccess<bool>(rItem.Value); + rItem.Value <<= !bMirroredX; + rItem.Handle = -1; + rItem.State = beans::PropertyState_DIRECT_VALUE; + } + else + { + beans::PropertyValue* pItem; + maCustomShapeGeometry.emplace_back(); + pItem = &maCustomShapeGeometry.back(); + pItem->Name = sName; + pItem->Handle = -1; + pItem->Value <<= true; + pItem->State = beans::PropertyState_DIRECT_VALUE; + } + } + + if (aScale.getY() < 0.0) + { + static constexpr OUString sName(u"MirroredY"_ustr); + //fdo#84043 Merge, if property exists, otherwise append it + auto aI = std::find_if(maCustomShapeGeometry.begin(), maCustomShapeGeometry.end(), + [](beans::PropertyValue& rValue) { return rValue.Name == sName; }); + if (aI != maCustomShapeGeometry.end()) + { + beans::PropertyValue& rItem = *aI; + bool bMirroredY = *o3tl::doAccess<bool>(rItem.Value); + rItem.Value <<= !bMirroredY; + rItem.Handle = -1; + rItem.State = beans::PropertyState_DIRECT_VALUE; + } + else + { + beans::PropertyValue* pItem; + maCustomShapeGeometry.emplace_back(); + pItem = &maCustomShapeGeometry.back(); + pItem->Name = sName; + pItem->Handle = -1; + pItem->Value <<= true; + pItem->State = beans::PropertyState_DIRECT_VALUE; + } + } + } + + if ( !maCustomShapeGeometry.empty() ) + { + // converting the vector to a sequence + uno::Sequence< beans::PropertyValue > aSeq( comphelper::containerToSequence(maCustomShapeGeometry) ); + + try + { + uno::Reference< beans::XPropertySet > xPropSet( mxShape, uno::UNO_QUERY ); + if( xPropSet.is() ) + { + xPropSet->setPropertyValue( "CustomShapeGeometry", Any(aSeq) ); + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting enhanced customshape geometry" ); + } + + sal_Int32 nUPD; + sal_Int32 nBuild; + if (GetImport().getBuildIds(nUPD, nBuild)) + { + if( ((nUPD >= 640 && nUPD <= 645) || (nUPD == 680)) && (nBuild <= 9221) ) + { + Reference< drawing::XEnhancedCustomShapeDefaulter > xDefaulter( mxShape, UNO_QUERY ); + if( xDefaulter.is() ) + { + xDefaulter->createCustomShapeDefaults( "" ); + } + } + } + } + + SdXMLShapeContext::endFastElement(nElement); + + // tdf#98163 call a custom slot to be able to reset the UNO API + // implementations held on the SdrObjects of type + // SdrObjCustomShape - those tend to linger until the entire file + // is loaded. For large files with a lot of these, 32bit systems + // may crash due to being out of resources after ca. 4200 + // Outliners and VirtualDevices used there as RefDevice + try + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + + if(xPropSet.is()) + { + xPropSet->setPropertyValue( + "FlushCustomShapeUnoApiObjects", css::uno::Any(true)); + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff", "flushing after load"); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLCustomShapeContext::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + css::uno::Reference< css::xml::sax::XFastContextHandler > xContext; + if ( nElement == XML_ELEMENT(DRAW, XML_ENHANCED_GEOMETRY) ) + { + uno::Reference< beans::XPropertySet > xPropSet( mxShape,uno::UNO_QUERY ); + if ( xPropSet.is() ) + xContext = new XMLEnhancedCustomShapeContext( GetImport(), mxShape, maCustomShapeGeometry ); + } + // delegate to parent class if no context could be created + if (!xContext) + xContext = SdXMLShapeContext::createFastChildContext( nElement, + xAttrList); + return xContext; +} + +SdXMLTableShapeContext::SdXMLTableShapeContext( SvXMLImport& rImport, const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, css::uno::Reference< css::drawing::XShapes > const & rShapes ) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false ) +{ +} + +SdXMLTableShapeContext::~SdXMLTableShapeContext() +{ +} + +void SdXMLTableShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + OUString service("com.sun.star.drawing.TableShape"); + + bool bIsPresShape = !maPresentationClass.isEmpty() && GetImport().GetShapeImport()->IsPresentationShapesSupported(); + if( bIsPresShape ) + { + if( IsXMLToken( maPresentationClass, XML_TABLE ) ) + { + service = "com.sun.star.presentation.TableShape"; + } + } + + AddShape(service); + + if( !mxShape.is() ) + return; + + SetLayer(); + + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + + if(bIsPresShape && xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( !mbIsPlaceholder && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + if( mbIsUserTransformed && xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + + SetStyle(); + + if( xProps.is() ) + { + if( !msTemplateStyleName.isEmpty() ) try + { + Reference< XStyleFamiliesSupplier > xFamiliesSupp( GetImport().GetModel(), UNO_QUERY_THROW ); + Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() ); + Reference< XNameAccess > xTableFamily( xFamilies->getByName( "table" ), UNO_QUERY_THROW ); + Reference< XStyle > xTableStyle( xTableFamily->getByName( msTemplateStyleName ), UNO_QUERY_THROW ); + xProps->setPropertyValue("TableTemplate", Any( xTableStyle ) ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.draw"); + } + + const XMLPropertyMapEntry* pEntry = &aXMLTableShapeAttributes[0]; + for( int i = 0; !pEntry->IsEnd() && (i < 6); i++, pEntry++ ) + { + try + { + xProps->setPropertyValue( pEntry->getApiName(), Any( maTemplateStylesUsed[i] ) ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.draw"); + } + } + } + + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); + + const rtl::Reference< XMLTableImport >& xTableImport( GetImport().GetShapeImport()->GetShapeTableImport() ); + if( xTableImport.is() && xProps.is() ) + { + uno::Reference< table::XColumnRowRange > xColumnRowRange( + xProps->getPropertyValue("Model"), uno::UNO_QUERY ); + + if( xColumnRowRange.is() ) + mxTableImportContext = xTableImport->CreateTableContext( xColumnRowRange ); + + if( mxTableImportContext.is() ) + mxTableImportContext->startFastElement( nElement, xAttrList ); + } +} + +void SdXMLTableShapeContext::endFastElement(sal_Int32 nElement) +{ + if( mxTableImportContext.is() ) + mxTableImportContext->endFastElement(nElement); + + SdXMLShapeContext::endFastElement(nElement); + + if( mxShape.is() ) + { + // set pos, size, shear and rotate + SetTransformation(); + } +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLTableShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + auto nElement = aIter.getToken(); + if( IsTokenInNamespace(nElement, XML_NAMESPACE_TABLE) ) + { + if( (nElement & TOKEN_MASK) == XML_TEMPLATE_NAME ) + { + msTemplateStyleName = aIter.toString(); + } + else + { + int i = 0; + const XMLPropertyMapEntry* pEntry = &aXMLTableShapeAttributes[0]; + while( !pEntry->IsEnd() && (i < 6) ) + { + if( (nElement & TOKEN_MASK) == pEntry->meXMLName ) + { + if( IsXMLToken( aIter, XML_TRUE ) ) + maTemplateStylesUsed[i] = true; + break; + } + pEntry++; + i++; + } + } + } + return SdXMLShapeContext::processAttribute( aIter ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLTableShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( mxTableImportContext.is() && IsTokenInNamespace(nElement, XML_NAMESPACE_TABLE) ) + return mxTableImportContext->createFastChildContext(nElement, xAttrList); + return SdXMLShapeContext::createFastChildContext(nElement, xAttrList); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpshap.hxx b/xmloff/source/draw/ximpshap.hxx new file mode 100644 index 0000000000..9a61f4b594 --- /dev/null +++ b/xmloff/source/draw/ximpshap.hxx @@ -0,0 +1,648 @@ +/* -*- 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 . + */ + +#pragma once + +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/document/XActionLockable.hpp> +#include <com/sun/star/drawing/Alignment.hpp> +#include <com/sun/star/drawing/CircleKind.hpp> +#include <com/sun/star/drawing/ConnectorType.hpp> +#include <com/sun/star/drawing/EscapeDirection.hpp> +#include <com/sun/star/container/XIdentifierContainer.hpp> +#include <xmloff/xmlictxt.hxx> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/text/XTextCursor.hpp> +#include <com/sun/star/awt/Point.hpp> +#include <xexptran.hxx> +#include <vector> +#include <xmloff/shapeimport.hxx> +#include <xmlmultiimagehelper.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + +template<typename EnumT> struct SvXMLEnumMapEntry; + +// common shape context + +class SdXMLShapeContext : public SvXMLShapeContext +{ +protected: + // the shape group this object should be created inside + css::uno::Reference< css::drawing::XShapes > mxShapes; + css::uno::Reference< css::text::XTextCursor > mxCursor; + css::uno::Reference< css::text::XTextCursor > mxOldCursor; + css::uno::Reference< css::xml::sax::XFastAttributeList> mxAttrList; + css::uno::Reference< css::container::XIdentifierContainer > mxGluePoints; + css::uno::Reference< css::document::XActionLockable > mxLockable; + + OUString maDrawStyleName; + OUString maTextStyleName; + OUString maPresentationClass; + OUString maShapeName; + OUString maThumbnailURL; + + /// whether to restore list context (#91964#) + bool mbListContextPushed; + + XmlStyleFamily mnStyleFamily; + bool mbIsPlaceholder; + bool mbClearDefaultAttributes; + bool mbIsUserTransformed; + sal_Int32 mnZOrder; + OUString maShapeId; + OUString maLayerName; + + SdXMLImExTransform2D mnTransform; + css::awt::Size maSize; + sal_Int16 mnRelWidth; + sal_Int16 mnRelHeight; + css::awt::Point maPosition; + basegfx::B2DHomMatrix maUsedTransformation; + + bool mbVisible; + bool mbPrintable; + bool mbHaveXmlId; + bool mbTextBox; ///< If the text of this shape is handled by a Writer TextFrame. + + /** if bSupportsStyle is false, auto styles will be set but not a style */ + void SetStyle( bool bSupportsStyle = true ); + void SetLayer(); + void SetThumbnail(); + + void AddShape(css::uno::Reference< css::drawing::XShape >& xShape); + void AddShape(OUString const & serviceName); + void SetTransformation(); + + using SvXMLImportContext::GetImport; + + void addGluePoint( const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ); + + bool isPresentationShape() const; + +public: + + SdXMLShapeContext( SvXMLImport& rImport, + css::uno::Reference< css::xml::sax::XFastAttributeList> xAttrList, + css::uno::Reference< css::drawing::XShapes > xShapes, + bool bTemporaryShape); + virtual ~SdXMLShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ); + +}; + +// draw:rect context + +class SdXMLRectShapeContext : public SdXMLShapeContext +{ + sal_Int32 mnRadius; + +public: + + SdXMLRectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLRectShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:line context + +class SdXMLLineShapeContext : public SdXMLShapeContext +{ + sal_Int32 mnX1; + sal_Int32 mnY1; + sal_Int32 mnX2; + sal_Int32 mnY2; + +public: + + SdXMLLineShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLLineShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:ellipse and draw:circle context + +class SdXMLEllipseShapeContext : public SdXMLShapeContext +{ + sal_Int32 mnCX; + sal_Int32 mnCY; + sal_Int32 mnRX; + sal_Int32 mnRY; + + css::drawing::CircleKind meKind; + sal_Int32 mnStartAngle; + sal_Int32 mnEndAngle; +public: + + SdXMLEllipseShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLEllipseShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:polyline and draw:polygon context + +class SdXMLPolygonShapeContext : public SdXMLShapeContext +{ + OUString maPoints; + OUString maViewBox; + bool mbClosed; + +public: + + SdXMLPolygonShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, bool bClosed, bool bTemporaryShape); + virtual ~SdXMLPolygonShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:path context + +class SdXMLPathShapeContext : public SdXMLShapeContext +{ + OUString maD; + OUString maViewBox; + +public: + + SdXMLPathShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLPathShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:text-box context + +class SdXMLTextBoxShapeContext : public SdXMLShapeContext +{ + sal_Int32 mnRadius; + OUString maChainNextName; + +public: + + SdXMLTextBoxShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLTextBoxShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:control context + +class SdXMLControlShapeContext : public SdXMLShapeContext +{ +private: + OUString maFormId; + +public: + + SdXMLControlShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLControlShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:connector context + +class SdXMLConnectorShapeContext : public SdXMLShapeContext +{ +private: + css::awt::Point maStart; + css::awt::Point maEnd; + + css::drawing::ConnectorType + mnType; + + OUString maStartShapeId; + sal_Int32 mnStartGlueId; + OUString maEndShapeId; + sal_Int32 mnEndGlueId; + + sal_Int32 mnDelta1; + sal_Int32 mnDelta2; + sal_Int32 mnDelta3; + + css::uno::Any maPath; + + // Guess from the svg:d attribute whether the shape was rendered using OOXML definition. The + // default value is true to cover files exported to ODF by MS Office, which does not write a + // svg:d attribute. LibreOffice has always written a svg:d attribute. + bool mbLikelyOOXMLCurve; + +public: + + SdXMLConnectorShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLConnectorShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:measure context + +class SdXMLMeasureShapeContext : public SdXMLShapeContext +{ +private: + css::awt::Point maStart; + css::awt::Point maEnd; + +public: + + SdXMLMeasureShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLMeasureShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:page context + +class SdXMLPageShapeContext : public SdXMLShapeContext +{ +private: + sal_Int32 mnPageNumber; +public: + + SdXMLPageShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLPageShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:caption context + +class SdXMLCaptionShapeContext : public SdXMLShapeContext +{ +private: + css::awt::Point maCaptionPoint; + sal_Int32 mnRadius; + +public: + + SdXMLCaptionShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLCaptionShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// office:image context + +class SdXMLGraphicObjectShapeContext : public SdXMLShapeContext +{ +private: + OUString maURL; + OUString msMimeType; + css::uno::Reference < css::io::XOutputStream > mxBase64Stream; + +public: + OUString const& getMimeType() const { return msMimeType; } + + SdXMLGraphicObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLGraphicObjectShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// chart:chart context + +class SdXMLChartShapeContext : public SdXMLShapeContext +{ + SvXMLImportContextRef mxChartContext; + +public: + + SdXMLChartShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual void SAL_CALL characters( const OUString& rChars ) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +// draw:object and draw:object_ole context + +class SdXMLObjectShapeContext : public SdXMLShapeContext +{ +private: + OUString maCLSID; + OUString maHref; + + css::uno::Reference < css::io::XOutputStream > mxBase64Stream; + +public: + + SdXMLObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLObjectShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:applet + +class SdXMLAppletShapeContext : public SdXMLShapeContext +{ +private: + OUString maAppletName; + OUString maAppletCode; + OUString maHref; + bool mbIsScript; + + css::uno::Sequence< css::beans::PropertyValue > maParams; + +public: + + SdXMLAppletShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLAppletShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:plugin + +class SdXMLPluginShapeContext : public SdXMLShapeContext +{ +private: + OUString maMimeType; + OUString maHref; + bool mbMedia; + + css::uno::Sequence< css::beans::PropertyValue > maParams; + +public: + + SdXMLPluginShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLPluginShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; + + const OUString& getMimeType() const { return maMimeType; } +}; + +// draw:floating-frame + +class SdXMLFloatingFrameShapeContext : public SdXMLShapeContext +{ +private: + OUString maFrameName; + OUString maHref; + + css::uno::Reference<css::drawing::XShape> CreateFloatingFrameShape() const; + +public: + + SdXMLFloatingFrameShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLFloatingFrameShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:-frame + +class SdXMLFrameShapeContext : public SdXMLShapeContext, public MultiImageImportHelper +{ +private: + bool mbSupportsReplacement; + SvXMLImportContextRef mxImplContext; + SvXMLImportContextRef mxReplImplContext; + +protected: + /// helper to get the created xShape instance, needs to be overridden + void removeGraphicFromImportContext(const SvXMLImportContext& rContext) override; + OUString getGraphicPackageURLFromImportContext(const SvXMLImportContext& rContext) const override; + OUString getMimeTypeFromImportContext(const SvXMLImportContext& rContext) const override; + css::uno::Reference<css::graphic::XGraphic> getGraphicFromImportContext(const SvXMLImportContext& rContext) const override; + +public: + + SdXMLFrameShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLFrameShapeContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +class SdXMLCustomShapeContext : public SdXMLShapeContext +{ + OUString maCustomShapeEngine; + OUString maCustomShapeData; + + std::vector< css::beans::PropertyValue > maCustomShapeGeometry; + +public: + + + SdXMLCustomShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLCustomShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:table + +class SdXMLTableShapeContext : public SdXMLShapeContext +{ +public: + + SdXMLTableShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes ); + virtual ~SdXMLTableShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; + +private: + SvXMLImportContextRef mxTableImportContext; + OUString msTemplateStyleName; + bool maTemplateStylesUsed[6] = {}; +}; + +extern SvXMLEnumMapEntry<css::drawing::Alignment> const aXML_GlueAlignment_EnumMap[]; +extern SvXMLEnumMapEntry<css::drawing::EscapeDirection> const aXML_GlueEscapeDirection_EnumMap[]; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpshow.cxx b/xmloff/source/draw/ximpshow.cxx new file mode 100644 index 0000000000..117511f77c --- /dev/null +++ b/xmloff/source/draw/ximpshow.cxx @@ -0,0 +1,243 @@ +/* -*- 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 <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/util/Duration.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/presentation/XCustomPresentationSupplier.hpp> +#include <com/sun/star/presentation/XPresentationSupplier.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <sax/tools/converter.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmluconv.hxx> +#include "ximpshow.hxx" + +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::xml; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::presentation; +using namespace ::xmloff::token; + +SdXMLShowsContext::SdXMLShowsContext( SdXMLImport& rImport, const Reference< XFastAttributeList >& xAttrList ) +: SvXMLImportContext(rImport) +{ + + Reference< XCustomPresentationSupplier > xShowsSupplier( rImport.GetModel(), UNO_QUERY ); + if( xShowsSupplier.is() ) + { + mxShows = xShowsSupplier->getCustomPresentations(); + mxShowFactory.set( mxShows, UNO_QUERY ); + } + + Reference< XDrawPagesSupplier > xDrawPagesSupplier( rImport.GetModel(), UNO_QUERY ); + if( xDrawPagesSupplier.is() ) + mxPages.set( xDrawPagesSupplier->getDrawPages(), UNO_QUERY ); + + Reference< XPresentationSupplier > xPresentationSupplier( rImport.GetModel(), UNO_QUERY ); + if( xPresentationSupplier.is() ) + mxPresProps.set( xPresentationSupplier->getPresentation(), UNO_QUERY ); + + if( !mxPresProps.is() ) + return; + + bool bAll = true; + uno::Any aAny; + // Per ODF this is default, but we did it wrong before LO 6.0 (tdf#108824) + bool bIsMouseVisible = true; + if (rImport.getGeneratorVersion() < SvXMLImport::LO_6x) + bIsMouseVisible = false; + + // read attributes + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(PRESENTATION, XML_START_PAGE): + { + mxPresProps->setPropertyValue("FirstPage", Any(aIter.toString()) ); + bAll = false; + break; + } + case XML_ELEMENT(PRESENTATION, XML_SHOW): + { + maCustomShowName = aIter.toString(); + bAll = false; + break; + } + case XML_ELEMENT(PRESENTATION, XML_PAUSE): + { + Duration aDuration; + if (!::sax::Converter::convertDuration(aDuration, aIter.toView())) + continue; + + const sal_Int32 nMS = (aDuration.Hours * 60 + + aDuration.Minutes) * 60 + aDuration.Seconds; + mxPresProps->setPropertyValue("Pause", Any(nMS) ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_ANIMATIONS): + { + aAny <<= IsXMLToken( aIter, XML_ENABLED ); + mxPresProps->setPropertyValue("AllowAnimations", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_STAY_ON_TOP): + { + aAny <<= IsXMLToken( aIter, XML_TRUE ); + mxPresProps->setPropertyValue("IsAlwaysOnTop", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_FORCE_MANUAL): + { + aAny <<= IsXMLToken( aIter, XML_TRUE ); + mxPresProps->setPropertyValue("IsAutomatic", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_ENDLESS): + { + aAny <<= IsXMLToken( aIter, XML_TRUE ); + mxPresProps->setPropertyValue("IsEndless", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_FULL_SCREEN): + { + aAny <<= IsXMLToken( aIter, XML_TRUE ); + mxPresProps->setPropertyValue("IsFullScreen", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_MOUSE_VISIBLE): + { + bIsMouseVisible = IsXMLToken( aIter, XML_TRUE ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_START_WITH_NAVIGATOR): + { + aAny <<= IsXMLToken( aIter, XML_TRUE ); + mxPresProps->setPropertyValue("StartWithNavigator", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_MOUSE_AS_PEN): + { + aAny <<= IsXMLToken( aIter, XML_TRUE ); + mxPresProps->setPropertyValue("UsePen", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_TRANSITION_ON_CLICK): + { + aAny <<= IsXMLToken( aIter, XML_ENABLED ); + mxPresProps->setPropertyValue("IsTransitionOnClick", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_SHOW_LOGO): + { + aAny <<= IsXMLToken( aIter, XML_TRUE ); + mxPresProps->setPropertyValue("IsShowLogo", aAny ); + break; + } + } + } + mxPresProps->setPropertyValue("IsShowAll", Any(bAll) ); + mxPresProps->setPropertyValue("IsMouseVisible", Any(bIsMouseVisible) ); +} + +SdXMLShowsContext::~SdXMLShowsContext() +{ + if( !maCustomShowName.isEmpty() ) + { + uno::Any aAny; + aAny <<= maCustomShowName; + mxPresProps->setPropertyValue("CustomShow", aAny ); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLShowsContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(PRESENTATION, XML_SHOW) ) + { + OUString aName; + OUString aPages; + + // read attributes + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + OUString sValue = aIter.toString(); + + switch( aIter.getToken() ) + { + case XML_ELEMENT(PRESENTATION, XML_NAME): + aName = sValue; + break; + case XML_ELEMENT(PRESENTATION, XML_PAGES): + aPages = sValue; + break; + } + } + + if( !aName.isEmpty() && !aPages.isEmpty() ) + { + Reference< XIndexContainer > xShow( mxShowFactory->createInstance(), UNO_QUERY ); + if( xShow.is() ) + { + SvXMLTokenEnumerator aPageNames( aPages, ',' ); + std::u16string_view sPageNameView; + + while( aPageNames.getNextToken( sPageNameView ) ) + { + OUString sPageName(sPageNameView); + if( !mxPages->hasByName( sPageName ) ) + continue; + + Reference< XDrawPage > xPage; + mxPages->getByName( sPageName ) >>= xPage; + if( xPage.is() ) + { + xShow->insertByIndex( xShow->getCount(), Any(xPage) ); + } + } + + Any aAny; + aAny <<= xShow; + if( mxShows->hasByName( aName ) ) + { + mxShows->replaceByName( aName, aAny ); + } + else + { + mxShows->insertByName( aName, aAny ); + } + } + } + } + + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpshow.hxx b/xmloff/source/draw/ximpshow.hxx new file mode 100644 index 0000000000..33948c3a64 --- /dev/null +++ b/xmloff/source/draw/ximpshow.hxx @@ -0,0 +1,49 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include "sdxmlimp_impl.hxx" +#include <memory> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/container/XNameContainer.hpp> + +// presentations:animations + +class SdXMLShowsContext : public SvXMLImportContext +{ +public: + + SdXMLShowsContext( SdXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList); + virtual ~SdXMLShowsContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +private: + css::uno::Reference< css::lang::XSingleServiceFactory > mxShowFactory; + css::uno::Reference< css::container::XNameContainer > mxShows; + css::uno::Reference< css::beans::XPropertySet > mxPresProps; + css::uno::Reference< css::container::XNameAccess > mxPages; + OUString maCustomShowName; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpstyl.cxx b/xmloff/source/draw/ximpstyl.cxx new file mode 100644 index 0000000000..8e68544764 --- /dev/null +++ b/xmloff/source/draw/ximpstyl.cxx @@ -0,0 +1,1466 @@ +/* -*- 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 "ximpstyl.hxx" +#include <utility> +#include <xmloff/maptype.hxx> +#include <xmloff/XMLDrawingPageStyleContext.hxx> +#include <xmloff/XMLShapeStyleContext.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlprmap.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include "ximpnote.hxx" +#include <xmlsdtypes.hxx> +#include <tools/debug.hxx> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/presentation/XPresentationPage.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/XDrawPages.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/presentation/XHandoutMasterSupplier.hpp> +#include <com/sun/star/util/Color.hpp> +#include <comphelper/namecontainer.hxx> +#include <xmloff/autolayout.hxx> +#include <xmloff/xmlprcon.hxx> +#include <xmloff/families.hxx> +#include <com/sun/star/container/XNameContainer.hpp> +#include <svl/numformat.hxx> +#include <svl/zforlist.hxx> +#include "layerimp.hxx" +#include <xmloff/XMLGraphicsDefaultStyle.hxx> +#include <XMLNumberStylesImport.hxx> +#include <XMLThemeContext.hxx> +#include <unotools/configmgr.hxx> +#include <xmloff/xmlerror.hxx> +#include <xmloff/table/XMLTableImport.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <sax/tools/converter.hxx> +#include <comphelper/sequence.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +namespace { + +class SdXMLDrawingPagePropertySetContext : public SvXMLPropertySetContext +{ +public: + + SdXMLDrawingPagePropertySetContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap ); + + using SvXMLPropertySetContext::createFastChildContext; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) override; +}; +} // end anonymous namespace + +SdXMLDrawingPagePropertySetContext::SdXMLDrawingPagePropertySetContext( + SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList > & xAttrList, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap ) : + SvXMLPropertySetContext( rImport, nElement, xAttrList, + XML_TYPE_PROP_DRAWING_PAGE, rProps, rMap ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLDrawingPagePropertySetContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) +{ + switch( mxMapper->getPropertySetMapper()->GetEntryContextId( rProp.mnIndex ) ) + { + case CTF_PAGE_SOUND_URL: + { + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + if( aIter.getToken() == XML_ELEMENT(XLINK, XML_HREF) ) + { + uno::Any aAny( GetImport().GetAbsoluteReference( aIter.toString() ) ); + XMLPropertyState aPropState( rProp.mnIndex, aAny ); + rProperties.push_back( aPropState ); + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + break; + } + } + + return SvXMLPropertySetContext::createFastChildContext( nElement, + xAttrList, + rProperties, rProp ); +} + +namespace { + + +class SdXMLDrawingPageStyleContext : public XMLDrawingPageStyleContext +{ +public: + + SdXMLDrawingPageStyleContext( + SvXMLImport& rImport, + SvXMLStylesContext& rStyles); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void Finish( bool bOverwrite ) override; +}; + +const sal_uInt16 MAX_SPECIAL_DRAW_STYLES = 7; +ContextID_Index_Pair const g_ContextIDs[MAX_SPECIAL_DRAW_STYLES+1] = +{ + { CTF_DASHNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_LINESTARTNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_LINEENDNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT}, + { CTF_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH }, + { CTF_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP }, + { -1, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE } +}; +XmlStyleFamily const g_Families[MAX_SPECIAL_DRAW_STYLES] = +{ + XmlStyleFamily::SD_STROKE_DASH_ID, + XmlStyleFamily::SD_MARKER_ID, + XmlStyleFamily::SD_MARKER_ID, + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_HATCH_ID, + XmlStyleFamily::SD_FILL_IMAGE_ID +}; + +} + +XMLDrawingPageStyleContext::XMLDrawingPageStyleContext( + SvXMLImport& rImport, + SvXMLStylesContext& rStyles, + ContextID_Index_Pair const pContextIDs[], + XmlStyleFamily const pFamilies[]) + : XMLPropStyleContext(rImport, rStyles, XmlStyleFamily::SD_DRAWINGPAGE_ID) + , m_pFamilies(pFamilies) +{ + size_t size(1); // for the -1 entry + for (ContextID_Index_Pair const* pTemp(pContextIDs); pTemp->nContextID != -1; ++size, ++pTemp); + m_pContextIDs.reset(new ContextID_Index_Pair[size]); + std::memcpy(m_pContextIDs.get(), pContextIDs, size * sizeof(ContextID_Index_Pair)); +} + +SdXMLDrawingPageStyleContext::SdXMLDrawingPageStyleContext( + SvXMLImport& rImport, + SvXMLStylesContext& rStyles) + : XMLDrawingPageStyleContext(rImport, rStyles, g_ContextIDs, g_Families) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLDrawingPageStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_DRAWING_PAGE_PROPERTIES) ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + return new SdXMLDrawingPagePropertySetContext( GetImport(), nElement, + xAttrList, + GetProperties(), + xImpPrMap ); + } + + return XMLPropStyleContext::createFastChildContext( nElement, xAttrList ); +} + +void SdXMLDrawingPageStyleContext::Finish( bool bOverwrite ) +{ + XMLPropStyleContext::Finish( bOverwrite ); + + ::std::vector< XMLPropertyState > &rProperties = GetProperties(); + + const rtl::Reference< XMLPropertySetMapper >& rImpPrMap = GetStyles()->GetImportPropertyMapper( GetFamily() )->getPropertySetMapper(); + + for(auto& property : rProperties) + { + if( property.mnIndex == -1 ) + continue; + + sal_Int16 nContextID = rImpPrMap->GetEntryContextId(property.mnIndex); + switch( nContextID ) + { + case CTF_DATE_TIME_FORMAT: + { + OUString sStyleName; + property.maValue >>= sStyleName; + + sal_Int32 nStyle = 0; + + const SdXMLNumberFormatImportContext* pSdNumStyle = + dynamic_cast< const SdXMLNumberFormatImportContext*> ( + GetStyles()->FindStyleChildContext( XmlStyleFamily::DATA_STYLE, sStyleName, true ) ); + + if( pSdNumStyle ) + nStyle = pSdNumStyle->GetDrawKey(); + + property.maValue <<= nStyle; + } + break; + } + } + +} + + +// #i35918# +void XMLDrawingPageStyleContext::FillPropertySet( + const Reference< beans::XPropertySet > & rPropSet ) +{ + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + SAL_WARN_IF( !xImpPrMap.is(), "xmloff", "There is the import prop mapper" ); + if( xImpPrMap.is() ) + xImpPrMap->FillPropertySet(GetProperties(), rPropSet, m_pContextIDs.get()); + + Reference< beans::XPropertySetInfo > xInfo; + for (size_t i=0; m_pContextIDs[i].nContextID != -1; ++i) + { + sal_Int32 nIndex = m_pContextIDs[i].nIndex; + if( nIndex != -1 ) + { + struct XMLPropertyState& rState = GetProperties()[nIndex]; + OUString sStyleName; + rState.maValue >>= sStyleName; + + if (::xmloff::IsIgnoreFillStyleNamedItem(rPropSet, m_pContextIDs[i].nExpectedFillStyle)) + { + SAL_INFO("xmloff.style", "XMLDrawingPageStyleContext: dropping fill named item: " << sStyleName); + break; // ignore it, it's not used + } + + sStyleName = GetImport().GetStyleDisplayName( m_pFamilies[i], + sStyleName ); + // get property set mapper + rtl::Reference<XMLPropertySetMapper> rPropMapper = + xImpPrMap->getPropertySetMapper(); + + // set property + const OUString& rPropertyName = + rPropMapper->GetEntryAPIName(rState.mnIndex); + if( !xInfo.is() ) + xInfo = rPropSet->getPropertySetInfo(); + if ( xInfo->hasPropertyByName( rPropertyName ) ) + { + rPropSet->setPropertyValue( rPropertyName, Any( sStyleName ) ); + } + } + } +} + + +SdXMLPageMasterStyleContext::SdXMLPageMasterStyleContext( + SdXMLImport& rImport, + sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList) +: SvXMLStyleContext(rImport, XmlStyleFamily::SD_PAGEMASTERSTYLECONTEXT_ID), + mnBorderBottom( 0 ), + mnBorderLeft( 0 ), + mnBorderRight( 0 ), + mnBorderTop( 0 ), + mnWidth( 0 ), + mnHeight( 0 ), + meOrientation(GetSdImport().IsDraw() ? view::PaperOrientation_PORTRAIT : view::PaperOrientation_LANDSCAPE) +{ + // set family to something special at SvXMLStyleContext + // for differences in search-methods + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(FO, XML_MARGIN_TOP): + case XML_ELEMENT(FO_COMPAT, XML_MARGIN_TOP): + { + GetSdImport().GetMM100UnitConverter().convertMeasureToCore( + mnBorderTop, aIter.toView()); + break; + } + case XML_ELEMENT(FO, XML_MARGIN_BOTTOM): + case XML_ELEMENT(FO_COMPAT, XML_MARGIN_BOTTOM): + { + GetSdImport().GetMM100UnitConverter().convertMeasureToCore( + mnBorderBottom, aIter.toView()); + break; + } + case XML_ELEMENT(FO, XML_MARGIN_LEFT): + case XML_ELEMENT(FO_COMPAT, XML_MARGIN_LEFT): + { + GetSdImport().GetMM100UnitConverter().convertMeasureToCore( + mnBorderLeft, aIter.toView()); + break; + } + case XML_ELEMENT(FO, XML_MARGIN_RIGHT): + case XML_ELEMENT(FO_COMPAT, XML_MARGIN_RIGHT): + { + GetSdImport().GetMM100UnitConverter().convertMeasureToCore( + mnBorderRight, aIter.toView()); + break; + } + case XML_ELEMENT(FO, XML_PAGE_WIDTH): + case XML_ELEMENT(FO_COMPAT, XML_PAGE_WIDTH): + { + GetSdImport().GetMM100UnitConverter().convertMeasureToCore( + mnWidth, aIter.toView()); + break; + } + case XML_ELEMENT(FO, XML_PAGE_HEIGHT): + case XML_ELEMENT(FO_COMPAT, XML_PAGE_HEIGHT): + { + GetSdImport().GetMM100UnitConverter().convertMeasureToCore( + mnHeight, aIter.toView()); + break; + } + case XML_ELEMENT(STYLE, XML_PRINT_ORIENTATION): + { + if( IsXMLToken( aIter, XML_PORTRAIT ) ) + meOrientation = view::PaperOrientation_PORTRAIT; + else + meOrientation = view::PaperOrientation_LANDSCAPE; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXMLPageMasterStyleContext::~SdXMLPageMasterStyleContext() +{ +} + + +SdXMLPageMasterContext::SdXMLPageMasterContext( + SdXMLImport& rImport, + sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList>& /*xAttrList*/) +: SvXMLStyleContext(rImport, XmlStyleFamily::SD_PAGEMASTERCONTEXT_ID) +{ + // set family to something special at SvXMLStyleContext + // for differences in search-methods + +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLPageMasterContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if(nElement == XML_ELEMENT(STYLE, XML_PAGE_LAYOUT_PROPERTIES)) + { + DBG_ASSERT(!mxPageMasterStyle.is(), "PageMasterStyle is set, there seem to be two of them (!)"); + mxPageMasterStyle.set(new SdXMLPageMasterStyleContext(GetSdImport(), nElement, xAttrList)); + return mxPageMasterStyle; + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +SdXMLPresentationPageLayoutContext::SdXMLPresentationPageLayoutContext( + SdXMLImport& rImport, + sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/) +: SvXMLStyleContext(rImport, XmlStyleFamily::SD_PRESENTATIONPAGELAYOUT_ID), + mnTypeId( AUTOLAYOUT_NONE ) +{ + // set family to something special at SvXMLStyleContext + // for differences in search-methods +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLPresentationPageLayoutContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + + if(nElement == XML_ELEMENT(PRESENTATION, XML_PLACEHOLDER)) + { + const rtl::Reference< SdXMLPresentationPlaceholderContext > xLclContext{ + new SdXMLPresentationPlaceholderContext(GetSdImport(), nElement, xAttrList)}; + // presentation:placeholder inside style:presentation-page-layout context + xContext = xLclContext.get(); + + // remember SdXMLPresentationPlaceholderContext for later evaluation + maList.push_back(xLclContext); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return xContext; +} + +void SdXMLPresentationPageLayoutContext::endFastElement(sal_Int32 ) +{ + // build presentation page layout type here + // calc mnTpeId due to content of maList + // at the moment only use number of types used there + if( maList.empty() ) + return; + + SdXMLPresentationPlaceholderContext* pObj0 = maList[ 0 ].get(); + if( pObj0->GetName() == "handout" ) + { + switch( maList.size() ) + { + case 1: + mnTypeId = AUTOLAYOUT_HANDOUT1; + break; + case 2: + mnTypeId = AUTOLAYOUT_HANDOUT2; + break; + case 3: + mnTypeId = AUTOLAYOUT_HANDOUT3; + break; + case 4: + mnTypeId = AUTOLAYOUT_HANDOUT4; + break; + case 9: + mnTypeId = AUTOLAYOUT_HANDOUT9; + break; + default: + mnTypeId = AUTOLAYOUT_HANDOUT6; + } + } + else + { + switch( maList.size() ) + { + case 1: + { + if( pObj0->GetName() == "title" ) + { + mnTypeId = AUTOLAYOUT_TITLE_ONLY; + } + else + { + mnTypeId = AUTOLAYOUT_ONLY_TEXT; + } + break; + } + case 2: + { + SdXMLPresentationPlaceholderContext* pObj1 = maList[ 1 ].get(); + + if( pObj1->GetName() == "subtitle" ) + { + mnTypeId = AUTOLAYOUT_TITLE; + } + else if( pObj1->GetName() == "outline" ) + { + mnTypeId = AUTOLAYOUT_TITLE_CONTENT; + } + else if( pObj1->GetName() == "chart" ) + { + mnTypeId = AUTOLAYOUT_CHART; + } + else if( pObj1->GetName() == "table" ) + { + mnTypeId = AUTOLAYOUT_TAB; + } + else if( pObj1->GetName() == "object" ) + { + mnTypeId = AUTOLAYOUT_OBJ; + } + else if( pObj1->GetName() == "vertical_outline" ) + { + if( pObj0->GetName() == "vertical_title" ) + { + mnTypeId = AUTOLAYOUT_VTITLE_VCONTENT; + } + else + { + mnTypeId = AUTOLAYOUT_TITLE_VCONTENT; + } + } + else + { + mnTypeId = AUTOLAYOUT_NOTES; + } + break; + } + case 3: + { + SdXMLPresentationPlaceholderContext* pObj1 = maList[ 1 ].get(); + SdXMLPresentationPlaceholderContext* pObj2 = maList[ 2 ].get(); + + if( pObj1->GetName() == "outline" ) + { + if( pObj2->GetName() == "outline" ) + { + mnTypeId = AUTOLAYOUT_TITLE_2CONTENT; + } + else if( pObj2->GetName() == "chart" ) + { + mnTypeId = AUTOLAYOUT_TEXTCHART; + } + else if( pObj2->GetName() == "graphic" ) + { + mnTypeId = AUTOLAYOUT_TEXTCLIP; + } + else + { + if(pObj1->GetX() < pObj2->GetX()) + { + mnTypeId = AUTOLAYOUT_TEXTOBJ; // outline left, object right + } + else + { + mnTypeId = AUTOLAYOUT_TEXTOVEROBJ; // outline top, object right + } + } + } + else if( pObj1->GetName() == "chart" ) + { + mnTypeId = AUTOLAYOUT_CHARTTEXT; + } + else if( pObj1->GetName() == "graphic" ) + { + if( pObj2->GetName() == "vertical_outline" ) + { + mnTypeId = AUTOLAYOUT_TITLE_2VTEXT; + } + else + { + mnTypeId = AUTOLAYOUT_CLIPTEXT; + } + } + else if( pObj1->GetName() == "vertical_outline" ) + { + mnTypeId = AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT; + } + else + { + if(pObj1->GetX() < pObj2->GetX()) + { + mnTypeId = AUTOLAYOUT_OBJTEXT; // left, right + } + else + { + mnTypeId = AUTOLAYOUT_TITLE_CONTENT_OVER_CONTENT; // top, bottom + } + } + break; + } + case 4: + { + SdXMLPresentationPlaceholderContext* pObj1 = maList[ 1 ].get(); + SdXMLPresentationPlaceholderContext* pObj2 = maList[ 2 ].get(); + + if( pObj1->GetName() == "object" ) + { + if(pObj1->GetX() < pObj2->GetX()) + { + mnTypeId = AUTOLAYOUT_TITLE_2CONTENT_OVER_CONTENT; + } + else + { + mnTypeId = AUTOLAYOUT_TITLE_2CONTENT_CONTENT; + } + } + else + { + mnTypeId = AUTOLAYOUT_TITLE_CONTENT_2CONTENT; + } + break; + } + case 5: + { + SdXMLPresentationPlaceholderContext* pObj1 = maList[ 1 ].get(); + + if( pObj1->GetName() == "object" ) + { + mnTypeId = AUTOLAYOUT_TITLE_4CONTENT; + } + else + { + mnTypeId = AUTOLAYOUT_4CLIPART; + } + break; + + } + case 7: + { + mnTypeId = AUTOLAYOUT_TITLE_6CONTENT; // tdf#141978: Apply 6content layout + break; + } + default: + { + mnTypeId = AUTOLAYOUT_NONE; + break; + } + } + } + + // release remembered contexts, they are no longer needed + maList.clear(); +} + +SdXMLPresentationPlaceholderContext::SdXMLPresentationPlaceholderContext( + SdXMLImport& rImport, + sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList) +: SvXMLImportContext( rImport ), + mnX(0) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(PRESENTATION, XML_OBJECT): + { + msName = aIter.toString(); + break; + } + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + { + GetSdImport().GetMM100UnitConverter().convertMeasureToCore( + mnX, aIter.toView()); + break; + } + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + { + break; + } + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + { + break; + } + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + { + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXMLPresentationPlaceholderContext::~SdXMLPresentationPlaceholderContext() +{ +} + + +SdXMLMasterPageContext::SdXMLMasterPageContext( + SdXMLImport& rImport, + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLGenericPageContext( rImport, xAttrList, rShapes ) +{ + const bool bHandoutMaster = (nElement & TOKEN_MASK) == XML_HANDOUT_MASTER; + OUString sStyleName, sPageMasterName; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + const OUString sValue = aIter.toString(); + switch(aIter.getToken()) + { + case XML_ELEMENT(STYLE, XML_NAME): + { + msName = sValue; + break; + } + case XML_ELEMENT(STYLE, XML_DISPLAY_NAME): + { + msDisplayName = sValue; + break; + } + case XML_ELEMENT(STYLE, XML_PAGE_LAYOUT_NAME): + { + sPageMasterName = sValue; + break; + } + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + { + sStyleName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_PRESENTATION_PAGE_LAYOUT_NAME): + { + maPageLayoutName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_HEADER_NAME): + { + maUseHeaderDeclName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_FOOTER_NAME): + { + maUseFooterDeclName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_DATE_TIME_NAME): + { + maUseDateTimeDeclName = sValue; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( msDisplayName.isEmpty() ) + msDisplayName = msName; + else if( msDisplayName != msName ) + GetImport().AddStyleDisplayName( XmlStyleFamily::MASTER_PAGE, msName, msDisplayName ); + + GetImport().GetShapeImport()->startPage( GetLocalShapesContext() ); + + // set page name? + if(!bHandoutMaster && !msDisplayName.isEmpty() && GetLocalShapesContext().is()) + { + uno::Reference < container::XNamed > xNamed(GetLocalShapesContext(), uno::UNO_QUERY); + if(xNamed.is()) + xNamed->setName(msDisplayName); + } + + // set page-master? + if(!sPageMasterName.isEmpty()) + { + SetPageMaster( sPageMasterName ); + } + + SetStyle( sStyleName ); + + SetLayout(); + + DeleteAllShapes(); +} + +SdXMLMasterPageContext::~SdXMLMasterPageContext() +{ +} + +void SdXMLMasterPageContext::endFastElement(sal_Int32 nElement) +{ + // set styles on master-page + if(!msName.isEmpty() && GetSdImport().GetShapeImport()->GetStylesContext()) + { + SvXMLImportContext* pContext = GetSdImport().GetShapeImport()->GetStylesContext(); + if (SdXMLStylesContext* pSdContext = dynamic_cast<SdXMLStylesContext*>(pContext)) + pSdContext->SetMasterPageStyles(*this); + } + + SdXMLGenericPageContext::endFastElement(nElement); + GetImport().GetShapeImport()->endPage(GetLocalShapesContext()); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLMasterPageContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + switch (nElement) + { + // some special objects inside style:masterpage context + case XML_ELEMENT(STYLE, XML_STYLE): + { + if(GetSdImport().GetShapeImport()->GetStylesContext()) + { + // style:style inside master-page context -> presentation style + XMLShapeStyleContext* pNew = new XMLShapeStyleContext( + GetSdImport(), + *GetSdImport().GetShapeImport()->GetStylesContext(), + XmlStyleFamily::SD_PRESENTATION_ID); + + // add this style to the outer StylesContext class for later processing + GetSdImport().GetShapeImport()->GetStylesContext()->AddStyle(*pNew); + return pNew; + } + break; + } + case XML_ELEMENT(PRESENTATION, XML_NOTES): + { + if( GetSdImport().IsImpress() ) + { + // get notes page + uno::Reference< presentation::XPresentationPage > xPresPage(GetLocalShapesContext(), uno::UNO_QUERY); + if(xPresPage.is()) + { + uno::Reference< drawing::XDrawPage > xNotesDrawPage = xPresPage->getNotesPage(); + if(xNotesDrawPage.is()) + { + // presentation:notes inside master-page context + return new SdXMLNotesContext( GetSdImport(), xAttrList, xNotesDrawPage); + } + } + } + break; + } + case XML_ELEMENT(LO_EXT, XML_THEME): + { + uno::Reference<drawing::XDrawPage> xMasterPage(GetLocalShapesContext(), uno::UNO_QUERY); + return new XMLThemeContext(GetSdImport(), xAttrList, xMasterPage); + break; + } + } + return SdXMLGenericPageContext::createFastChildContext(nElement, xAttrList); +} + +SdXMLStylesContext::SdXMLStylesContext( + SdXMLImport& rImport, + bool bIsAutoStyle) +: SvXMLStylesContext(rImport), + mbIsAutoStyle(bIsAutoStyle) +{ + Reference< uno::XComponentContext > xContext = rImport.GetComponentContext(); + mpNumFormatter = std::make_unique<SvNumberFormatter>( xContext, LANGUAGE_SYSTEM ); + mpNumFmtHelper = std::make_unique<SvXMLNumFmtHelper>( mpNumFormatter.get(), xContext ); +} + +SvXMLStyleContext* SdXMLStylesContext::CreateStyleChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) +{ + switch (nElement) + { + case XML_ELEMENT(TABLE, XML_TABLE_TEMPLATE): + { + auto pContext = GetImport().GetShapeImport()->GetShapeTableImport()->CreateTableTemplateContext(nElement, xAttrList ); + if (pContext) + return pContext; + break; + } + case XML_ELEMENT(STYLE, XML_PAGE_LAYOUT): + // style:page-master inside office:styles context + return new SdXMLPageMasterContext(GetSdImport(), nElement, xAttrList); + case XML_ELEMENT(STYLE, XML_PRESENTATION_PAGE_LAYOUT): + // style:presentation-page-layout inside office:styles context + return new SdXMLPresentationPageLayoutContext(GetSdImport(), nElement, xAttrList); + case XML_ELEMENT(NUMBER, XML_DATE_STYLE): + // number:date-style or number:time-style + return new SdXMLNumberFormatImportContext( GetSdImport(), nElement, mpNumFmtHelper->getData(), SvXMLStylesTokens::DATE_STYLE, xAttrList, *this ); + case XML_ELEMENT(NUMBER, XML_TIME_STYLE): + // number:date-style or number:time-style + return new SdXMLNumberFormatImportContext( GetSdImport(), nElement, mpNumFmtHelper->getData(), SvXMLStylesTokens::TIME_STYLE, xAttrList, *this ); + case XML_ELEMENT(NUMBER, XML_NUMBER_STYLE): + return new SvXMLNumFormatContext( GetSdImport(), nElement, + mpNumFmtHelper->getData(), SvXMLStylesTokens::NUMBER_STYLE, xAttrList, *this ); + case XML_ELEMENT(NUMBER, XML_CURRENCY_STYLE): + return new SvXMLNumFormatContext( GetSdImport(), nElement, + mpNumFmtHelper->getData(), SvXMLStylesTokens::CURRENCY_STYLE, xAttrList, *this ); + case XML_ELEMENT(NUMBER, XML_PERCENTAGE_STYLE): + return new SvXMLNumFormatContext( GetSdImport(), nElement, + mpNumFmtHelper->getData(), SvXMLStylesTokens::PERCENTAGE_STYLE, xAttrList, *this ); + case XML_ELEMENT(NUMBER, XML_BOOLEAN_STYLE): + return new SvXMLNumFormatContext( GetSdImport(), nElement, + mpNumFmtHelper->getData(), SvXMLStylesTokens::BOOLEAN_STYLE, xAttrList, *this ); + case XML_ELEMENT(NUMBER, XML_TEXT_STYLE): + return new SvXMLNumFormatContext( GetSdImport(), nElement, + mpNumFmtHelper->getData(), SvXMLStylesTokens::TEXT_STYLE, xAttrList, *this ); + case XML_ELEMENT(PRESENTATION, XML_HEADER_DECL): + case XML_ELEMENT(PRESENTATION, XML_FOOTER_DECL): + case XML_ELEMENT(PRESENTATION, XML_DATE_TIME_DECL): + return new SdXMLHeaderFooterDeclContext( GetImport(), xAttrList ); + case XML_ELEMENT(STYLE, XML_STYLE): + break; // ignore + default: + XMLOFF_INFO_UNKNOWN_ELEMENT("xmloff", nElement); + } + + // call base class + return SvXMLStylesContext::CreateStyleChildContext(nElement, xAttrList); +} + +SvXMLStyleContext* SdXMLStylesContext::CreateStyleStyleChildContext( + XmlStyleFamily nFamily, + sal_Int32 nElement, + const uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + switch( nFamily ) + { + case XmlStyleFamily::SD_DRAWINGPAGE_ID: + return new SdXMLDrawingPageStyleContext(GetSdImport(), *this ); + case XmlStyleFamily::TABLE_CELL: + case XmlStyleFamily::TABLE_COLUMN: + case XmlStyleFamily::TABLE_ROW: + return new XMLShapeStyleContext( GetSdImport(), *this, nFamily ); + default: break; + } + + // call base class + return SvXMLStylesContext::CreateStyleStyleChildContext(nFamily, nElement, xAttrList); +} + +SvXMLStyleContext* SdXMLStylesContext::CreateDefaultStyleStyleChildContext( + XmlStyleFamily nFamily, + sal_Int32 nElement, + const Reference< XFastAttributeList > & xAttrList ) +{ + switch( nFamily ) + { + case XmlStyleFamily::SD_GRAPHICS_ID: + return new XMLGraphicsDefaultStyle(GetSdImport(), *this ); + default: break; + } + + // call base class + return SvXMLStylesContext::CreateDefaultStyleStyleChildContext(nFamily, nElement, xAttrList); +} + +rtl::Reference< SvXMLImportPropertyMapper > SdXMLStylesContext::GetImportPropertyMapper( + XmlStyleFamily nFamily) const +{ + rtl::Reference < SvXMLImportPropertyMapper > xMapper; + + switch( nFamily ) + { + case XmlStyleFamily::SD_DRAWINGPAGE_ID: + { + if(!xPresImpPropMapper.is()) + { + rtl::Reference< XMLShapeImportHelper > aImpHelper = const_cast<SvXMLImport&>(GetImport()).GetShapeImport(); + const_cast<SdXMLStylesContext*>(this)->xPresImpPropMapper = + aImpHelper->GetPresPagePropsMapper(); + } + xMapper = xPresImpPropMapper; + break; + } + + case XmlStyleFamily::TABLE_COLUMN: + case XmlStyleFamily::TABLE_ROW: + case XmlStyleFamily::TABLE_CELL: + { + const rtl::Reference< XMLTableImport >& xTableImport( const_cast< SvXMLImport& >( GetImport() ).GetShapeImport()->GetShapeTableImport() ); + + switch( nFamily ) + { + case XmlStyleFamily::TABLE_COLUMN: xMapper = xTableImport->GetColumnImportPropertySetMapper().get(); break; + case XmlStyleFamily::TABLE_ROW: xMapper = xTableImport->GetRowImportPropertySetMapper().get(); break; + case XmlStyleFamily::TABLE_CELL: xMapper = xTableImport->GetCellImportPropertySetMapper().get(); break; + default: break; + } + break; + } + default: break; + } + + // call base class + if( !xMapper.is() ) + xMapper = SvXMLStylesContext::GetImportPropertyMapper(nFamily); + return xMapper; +} + +// Process all style and object info + +void SdXMLStylesContext::endFastElement(sal_Int32 ) +{ + if(mbIsAutoStyle) + { + // AutoStyles for text import + GetImport().GetTextImport()->SetAutoStyles( this ); + + // AutoStyles for chart + GetImport().GetChartImport()->SetAutoStylesContext( this ); + + // AutoStyles for forms + GetImport().GetFormImport()->setAutoStyleContext( this ); + + // associate AutoStyles with styles in preparation to setting Styles on shapes + for(sal_uInt32 a(0); a < GetStyleCount(); a++) + { + const SvXMLStyleContext* pStyle = GetStyle(a); + if (const XMLShapeStyleContext* pDocStyle = dynamic_cast<const XMLShapeStyleContext*>(pStyle)) + { + SvXMLStylesContext* pStylesContext = GetSdImport().GetShapeImport()->GetStylesContext(); + if (pStylesContext) + { + pStyle = pStylesContext->FindStyleChildContext(pStyle->GetFamily(), pStyle->GetParentName()); + + if (const XMLShapeStyleContext* pParentStyle = dynamic_cast<const XMLShapeStyleContext*>(pStyle)) + { + if(pParentStyle->GetStyle().is()) + { + const_cast<XMLShapeStyleContext*>(pDocStyle)->SetStyle(pParentStyle->GetStyle()); + } + } + } + } + } + + FinishStyles( false ); + } + else + { + // Process styles list + ImpSetGraphicStyles(); + ImpSetCellStyles(); + GetImport().GetShapeImport()->GetShapeTableImport()->finishStyles(); + + // put style infos in the info set for other components ( content import f.e. ) + uno::Reference< beans::XPropertySet > xInfoSet( GetImport().getImportInfo() ); + if( xInfoSet.is() ) + { + uno::Reference< beans::XPropertySetInfo > xInfoSetInfo( xInfoSet->getPropertySetInfo() ); + + if( xInfoSetInfo->hasPropertyByName("PageLayouts") ) + xInfoSet->setPropertyValue("PageLayouts", uno::Any( getPageLayouts() ) ); + } + + } +} + +// set master-page styles (all with family="presentation" and a special +// prefix) on given master-page. + +void SdXMLStylesContext::SetMasterPageStyles(SdXMLMasterPageContext const & rMaster) const +{ + const uno::Reference<container::XNameAccess>& rStyleFamilies = + GetSdImport().GetLocalDocStyleFamilies(); + + if (!rStyleFamilies.is()) + return; + + if (!rStyleFamilies->hasByName(rMaster.GetDisplayName())) + return; + + try + { + uno::Reference< container::XNameAccess > xMasterPageStyles( rStyleFamilies->getByName(rMaster.GetDisplayName()), UNO_QUERY_THROW ); + OUString sPrefix(rMaster.GetDisplayName() + "-"); + ImpSetGraphicStyles(xMasterPageStyles, XmlStyleFamily::SD_PRESENTATION_ID, sPrefix); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +// Process styles list: +// set graphic styles (all with family="graphics"). Remember xStyle at list element. + +void SdXMLStylesContext::ImpSetGraphicStyles() const +{ + if(GetSdImport().GetLocalDocStyleFamilies().is()) try + { + uno::Reference< container::XNameAccess > xGraphicPageStyles( GetSdImport().GetLocalDocStyleFamilies()->getByName("graphics"), uno::UNO_QUERY_THROW ); + + ImpSetGraphicStyles(xGraphicPageStyles, XmlStyleFamily::SD_GRAPHICS_ID, u""); + } + catch( uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void SdXMLStylesContext::ImpSetCellStyles() const +{ + if(GetSdImport().GetLocalDocStyleFamilies().is()) try + { + uno::Reference< container::XNameAccess > xGraphicPageStyles( GetSdImport().GetLocalDocStyleFamilies()->getByName("cell"), uno::UNO_QUERY_THROW ); + + ImpSetGraphicStyles(xGraphicPageStyles, XmlStyleFamily::TABLE_CELL, u""); + } + catch( uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +//Resolves: fdo#34987 if the style's auto height before and after is the same +//then don't reset it back to the underlying default of true for the small +//period before it's going to be reset to false again. Doing this avoids the +//master page shapes from resizing themselves due to autoheight becoming +//enabled before having autoheight turned off again and getting stuck on that +//autosized height +static bool canSkipReset(std::u16string_view rName, const XMLPropStyleContext* pPropStyle, + const uno::Reference< beans::XPropertySet > &rPropSet, const rtl::Reference < XMLPropertySetMapper >& rPrMap) +{ + bool bCanSkipReset = false; + if (pPropStyle && rName == u"TextAutoGrowHeight") + { + bool bOldStyleTextAutoGrowHeight(false); + rPropSet->getPropertyValue("TextAutoGrowHeight") >>= bOldStyleTextAutoGrowHeight; + + sal_Int32 nIndexStyle = rPrMap->GetEntryIndex(XML_NAMESPACE_DRAW, u"auto-grow-height", 0); + if (nIndexStyle != -1) + { + const ::std::vector< XMLPropertyState > &rProperties = pPropStyle->GetProperties(); + auto property = std::find_if(rProperties.cbegin(), rProperties.cend(), + [nIndexStyle](const XMLPropertyState& rProp) { return rProp.mnIndex == nIndexStyle; }); + if (property != rProperties.cend()) + { + bool bNewStyleTextAutoGrowHeight(false); + property->maValue >>= bNewStyleTextAutoGrowHeight; + bCanSkipReset = (bNewStyleTextAutoGrowHeight == bOldStyleTextAutoGrowHeight); + } + } + } + return bCanSkipReset; +} + +// help function used by ImpSetGraphicStyles() and ImpSetMasterPageStyles() + +void SdXMLStylesContext::ImpSetGraphicStyles( uno::Reference< container::XNameAccess > const & xPageStyles, XmlStyleFamily nFamily, std::u16string_view rPrefix) const +{ + sal_Int32 nPrefLen(rPrefix.size()); + + sal_uInt32 a; + + // set defaults + for( a = 0; a < GetStyleCount(); a++) + { + const SvXMLStyleContext* pStyle = GetStyle(a); + + if(nFamily == pStyle->GetFamily() && pStyle->IsDefaultStyle()) + { + const_cast<SvXMLStyleContext*>(pStyle)->SetDefaults(); + } + } + + // create all styles and set properties + for( a = 0; a < GetStyleCount(); a++) + { + try + { + const SvXMLStyleContext* pStyle = GetStyle(a); + if(nFamily == pStyle->GetFamily() && !pStyle->IsDefaultStyle()) + { + OUString aStyleName(pStyle->GetDisplayName()); + + if( nPrefLen ) + { + sal_Int32 nStylePrefLen = aStyleName.lastIndexOf( '-' ) + 1; + if( (nPrefLen != nStylePrefLen) || !aStyleName.startsWith(rPrefix) ) + continue; + + aStyleName = aStyleName.copy( nPrefLen ); + } + + XMLPropStyleContext* pPropStyle = dynamic_cast< XMLPropStyleContext* >(const_cast< SvXMLStyleContext* >( pStyle ) ); + + uno::Reference< style::XStyle > xStyle; + if(xPageStyles->hasByName(aStyleName)) + { + xPageStyles->getByName(aStyleName) >>= xStyle; + + // set properties of existing styles to default + uno::Reference< beans::XPropertySet > xPropSet( xStyle, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySetInfo > xPropSetInfo; + if( xPropSet.is() ) + xPropSetInfo = xPropSet->getPropertySetInfo(); + + uno::Reference< beans::XPropertyState > xPropState( xStyle, uno::UNO_QUERY ); + + if( xPropState.is() ) + { + rtl::Reference < XMLPropertySetMapper > xPrMap; + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = GetImportPropertyMapper( nFamily ); + SAL_WARN_IF( !xImpPrMap.is(), "xmloff", "There is the import prop mapper" ); + if( xImpPrMap.is() ) + xPrMap = xImpPrMap->getPropertySetMapper(); + if( xPrMap.is() ) + { + const sal_Int32 nCount = xPrMap->GetEntryCount(); + for( sal_Int32 i = 0; i < nCount; i++ ) + { + const OUString& rName = xPrMap->GetEntryAPIName( i ); + if( xPropSetInfo->hasPropertyByName( rName ) && beans::PropertyState_DIRECT_VALUE == xPropState->getPropertyState( rName ) ) + { + bool bCanSkipReset = canSkipReset(rName, pPropStyle, xPropSet, xPrMap); + if (bCanSkipReset) + continue; + xPropState->setPropertyToDefault( rName ); + } + } + } + } + } + else + { + // graphics style does not exist, create and add it + uno::Reference< lang::XSingleServiceFactory > xServiceFact(xPageStyles, uno::UNO_QUERY); + if(xServiceFact.is()) + { + uno::Reference< style::XStyle > xNewStyle( xServiceFact->createInstance(), uno::UNO_QUERY); + + if(xNewStyle.is()) + { + // remember style + xStyle = xNewStyle; + + // add new style to graphics style pool + uno::Reference< container::XNameContainer > xInsertContainer(xPageStyles, uno::UNO_QUERY); + if(xInsertContainer.is()) + xInsertContainer->insertByName(aStyleName, uno::Any( xStyle ) ); + } + } + } + + if(xStyle.is()) + { + // set properties at style + uno::Reference< beans::XPropertySet > xPropSet(xStyle, uno::UNO_QUERY); + if(xPropSet.is() && pPropStyle) + { + pPropStyle->FillPropertySet(xPropSet); + pPropStyle->SetStyle(xStyle); + } + } + } + } + catch(const Exception& e) + { + const_cast<SdXMLImport*>(&GetSdImport())->SetError( XMLERROR_FLAG_WARNING | XMLERROR_API, {}, e.Message, nullptr ); + } + } + + // now set parents for all styles (when necessary) + for(a = 0; a < GetStyleCount(); a++) + { + const SvXMLStyleContext* pStyle = GetStyle(a); + + if(pStyle && !pStyle->GetDisplayName().isEmpty() && (nFamily == pStyle->GetFamily())) try + { + OUString aStyleName(pStyle->GetDisplayName()); + if( nPrefLen ) + { + sal_Int32 nStylePrefLen = aStyleName.lastIndexOf( '-' ) + 1; + if( (nPrefLen != nStylePrefLen) || !aStyleName.startsWith( rPrefix ) ) + continue; + + aStyleName = aStyleName.copy( nPrefLen ); + } + + uno::Reference< style::XStyle > xStyle( xPageStyles->getByName(aStyleName), UNO_QUERY ); + if(xStyle.is()) + { + // set parent style name + OUString sParentStyleDisplayName( GetImport().GetStyleDisplayName( pStyle->GetFamily(), pStyle->GetParentName() ) ); + if( nPrefLen ) + { + sal_Int32 nStylePrefLen = sParentStyleDisplayName.lastIndexOf( '-' ) + 1; + if( (nPrefLen != nStylePrefLen) || !sParentStyleDisplayName.startsWith( rPrefix ) ) + continue; + + sParentStyleDisplayName = sParentStyleDisplayName.copy( nPrefLen ); + } + xStyle->setParentStyle( sParentStyleDisplayName ); + } + } + catch( const Exception& e ) + { + const_cast<SdXMLImport*>(&GetSdImport())->SetError( XMLERROR_FLAG_WARNING | XMLERROR_API, {}, e.Message, nullptr ); + } + } +} + +// helper function to create the uno component that hold the mappings from +// xml auto layout name to internal autolayout id + +uno::Reference< container::XNameAccess > SdXMLStylesContext::getPageLayouts() const +{ + uno::Reference< container::XNameContainer > xLayouts( comphelper::NameContainer_createInstance( ::cppu::UnoType<sal_Int32>::get()) ); + + for(sal_uInt32 a(0); a < GetStyleCount(); a++) + { + const SvXMLStyleContext* pStyle = GetStyle(a); + if (const SdXMLPresentationPageLayoutContext* pContext = dynamic_cast<const SdXMLPresentationPageLayoutContext*>(pStyle)) + { + xLayouts->insertByName(pStyle->GetName(), uno::Any(static_cast<sal_Int32>(pContext->GetTypeId()))); + } + } + + return xLayouts; +} + + +SdXMLMasterStylesContext::SdXMLMasterStylesContext( + SdXMLImport& rImport) +: SvXMLImportContext( rImport ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLMasterStylesContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(DRAW, XML_LAYER_SET) ) + { + return new SdXMLLayerSetContext( GetImport() ); + } + else if( nElement == XML_ELEMENT(STYLE, XML_MASTER_PAGE) ) + { + // style:masterpage inside office:styles context + uno::Reference< drawing::XDrawPage > xNewMasterPage; + uno::Reference< drawing::XDrawPages > xMasterPages(GetSdImport().GetLocalMasterPages(), uno::UNO_QUERY); + + if( xMasterPages.is() ) + { + sal_Int32 nNewMasterPageCount = GetSdImport().GetNewMasterPageCount(); + sal_Int32 nMasterPageCount = xMasterPages->getCount(); + if (nNewMasterPageCount + 1 > nMasterPageCount) + { + // arbitrary limit to master pages when fuzzing to avoid deadend timeouts + if (nMasterPageCount >= 64 && utl::ConfigManager::IsFuzzing()) + return nullptr; + + // new page, create and insert + xNewMasterPage = xMasterPages->insertNewByIndex(nMasterPageCount); + } + else + { + // existing page, use it + xMasterPages->getByIndex(nNewMasterPageCount) >>= xNewMasterPage; + } + + // increment global import page counter + GetSdImport().IncrementNewMasterPageCount(); + + if(xNewMasterPage.is()) + { + if(GetSdImport().GetShapeImport()->GetStylesContext()) + { + const rtl::Reference<SdXMLMasterPageContext> xLclContext{ + new SdXMLMasterPageContext(GetSdImport(), + nElement, xAttrList, xNewMasterPage)}; + maMasterPageList.push_back(xLclContext); + return xLclContext; + } + } + } + } + else if( nElement == XML_ELEMENT(STYLE, XML_HANDOUT_MASTER) ) + { + uno::Reference< presentation::XHandoutMasterSupplier > xHandoutSupp( GetSdImport().GetModel(), uno::UNO_QUERY ); + if( xHandoutSupp.is() ) + { + uno::Reference< drawing::XShapes > xHandoutPage = xHandoutSupp->getHandoutMasterPage(); + if(xHandoutPage.is() && GetSdImport().GetShapeImport()->GetStylesContext()) + { + return new SdXMLMasterPageContext(GetSdImport(), + nElement, xAttrList, xHandoutPage); + } + } + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +SdXMLHeaderFooterDeclContext::SdXMLHeaderFooterDeclContext(SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) + : SvXMLStyleContext( rImport ) + , mbFixed(false) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( aIter.getToken() == XML_ELEMENT(PRESENTATION, XML_NAME) ) + { + maStrName = aIter.toString(); + } + else if( aIter.getToken() == XML_ELEMENT(PRESENTATION, XML_SOURCE) ) + { + mbFixed = IsXMLToken( aIter, XML_FIXED ); + } + else if( aIter.getToken() == XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME) ) + { + maStrDateTimeFormat = aIter.toString(); + } + else + { + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +bool SdXMLHeaderFooterDeclContext::IsTransient() const +{ + return true; +} + +void SdXMLHeaderFooterDeclContext::endFastElement(sal_Int32 nToken) +{ + SdXMLImport& rImport = dynamic_cast<SdXMLImport&>(GetImport()); + auto nElement = nToken & TOKEN_MASK; + if( nElement == XML_HEADER_DECL ) + { + rImport.AddHeaderDecl( maStrName, maStrText ); + } + else if( nElement == XML_FOOTER_DECL ) + { + rImport.AddFooterDecl( maStrName, maStrText ); + } + else if( nElement == XML_DATE_TIME_DECL ) + { + rImport.AddDateTimeDecl( maStrName, maStrText, mbFixed, maStrDateTimeFormat ); + } + else + { + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nToken); + } +} + +void SdXMLHeaderFooterDeclContext::characters( const OUString& rChars ) +{ + maStrText += rChars; +} + +namespace xmloff { + +bool IsIgnoreFillStyleNamedItem( + css::uno::Reference<css::beans::XPropertySet> const& xProps, + drawing::FillStyle const nExpectedFillStyle) +{ + assert(xProps.is()); + if (nExpectedFillStyle == drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE) + { + return false; + } + + // note: the caller must have called FillPropertySet() previously + drawing::FillStyle fillStyle{drawing::FillStyle_NONE}; + xProps->getPropertyValue("FillStyle") >>= fillStyle; + return fillStyle != nExpectedFillStyle; +} + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpstyl.hxx b/xmloff/source/draw/ximpstyl.hxx new file mode 100644 index 0000000000..b26e46eacd --- /dev/null +++ b/xmloff/source/draw/ximpstyl.hxx @@ -0,0 +1,247 @@ +/* -*- 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 . + */ + +#pragma once + +#include <svl/zforlist.hxx> +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimppr.hxx> +#include <xmloff/xmlnumfi.hxx> +#include "sdxmlimp_impl.hxx" +#include "ximppage.hxx" +#include <xmloff/xmlstyle.hxx> +#include <com/sun/star/view/PaperOrientation.hpp> +#include <memory> +#include <vector> + +class SvNumberFormatter; +class SvXMLNumFmtHelper; + +// special style:style context inside style:page-master context + +class SdXMLPageMasterStyleContext: public SvXMLStyleContext +{ + sal_Int32 mnBorderBottom; + sal_Int32 mnBorderLeft; + sal_Int32 mnBorderRight; + sal_Int32 mnBorderTop; + sal_Int32 mnWidth; + sal_Int32 mnHeight; + css::view::PaperOrientation meOrientation; + + const SdXMLImport& GetSdImport() const { return static_cast<const SdXMLImport&>(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast<SdXMLImport&>(GetImport()); } + +public: + + SdXMLPageMasterStyleContext( + SdXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList); + virtual ~SdXMLPageMasterStyleContext() override; + + sal_Int32 GetBorderBottom() const { return mnBorderBottom; } + sal_Int32 GetBorderLeft() const { return mnBorderLeft; } + sal_Int32 GetBorderRight() const { return mnBorderRight; } + sal_Int32 GetBorderTop() const { return mnBorderTop; } + sal_Int32 GetWidth() const { return mnWidth; } + sal_Int32 GetHeight() const { return mnHeight; } + css::view::PaperOrientation GetOrientation() const { return meOrientation; } +}; + +// style:page-master context + +class SdXMLPageMasterContext: public SvXMLStyleContext +{ + rtl::Reference<SdXMLPageMasterStyleContext> mxPageMasterStyle; + + const SdXMLImport& GetSdImport() const { return static_cast<const SdXMLImport&>(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast<SdXMLImport&>(GetImport()); } + +public: + + SdXMLPageMasterContext( + SdXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + const SdXMLPageMasterStyleContext* GetPageMasterStyle() const { return mxPageMasterStyle.get(); } +}; + +// style:masterpage context + +class SdXMLMasterPageContext: public SdXMLGenericPageContext +{ + OUString msName; + OUString msDisplayName; + +public: + + SdXMLMasterPageContext( + SdXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLMasterPageContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + const OUString& GetDisplayName() const { return msDisplayName; } + +}; + +// presentation:placeholder context + +class SdXMLPresentationPlaceholderContext: public SvXMLImportContext +{ + OUString msName; + sal_Int32 mnX; + + const SdXMLImport& GetSdImport() const { return static_cast<const SdXMLImport&>(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast<SdXMLImport&>(GetImport()); } + +public: + SdXMLPresentationPlaceholderContext( + SdXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList); + virtual ~SdXMLPresentationPlaceholderContext() override; + + const OUString& GetName() const { return msName; } + sal_Int32 GetX() const { return mnX; } +}; + +// style:presentation-page-layout context + +class SdXMLPresentationPageLayoutContext: public SvXMLStyleContext +{ + std::vector< rtl::Reference< SdXMLPresentationPlaceholderContext > > + maList; + sal_uInt16 mnTypeId; + + const SdXMLImport& GetSdImport() const { return static_cast<const SdXMLImport&>(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast<SdXMLImport&>(GetImport()); } + +public: + + SdXMLPresentationPageLayoutContext( + SdXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + sal_uInt16 GetTypeId() const { return mnTypeId; } +}; + +// office:styles context + +class SdXMLStylesContext : public SvXMLStylesContext +{ + rtl::Reference< SvXMLImportPropertyMapper > xPresImpPropMapper; + bool mbIsAutoStyle; + std::unique_ptr<SvXMLNumFmtHelper> mpNumFmtHelper; + std::unique_ptr<SvNumberFormatter> mpNumFormatter; + + const SdXMLImport& GetSdImport() const { return static_cast<const SdXMLImport&>(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast<SdXMLImport&>(GetImport()); } + + void ImpSetGraphicStyles() const; + void ImpSetCellStyles() const; + void ImpSetGraphicStyles( css::uno::Reference< css::container::XNameAccess > const & xPageStyles, + XmlStyleFamily nFamily, std::u16string_view rPrefix) const; + +protected: + using SvXMLStylesContext::CreateStyleChildContext; + virtual SvXMLStyleContext* CreateStyleChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) override; + + using SvXMLStylesContext::CreateStyleStyleChildContext; + virtual SvXMLStyleContext *CreateStyleStyleChildContext( + XmlStyleFamily nFamily, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) override; + + using SvXMLStylesContext::CreateDefaultStyleStyleChildContext; + virtual SvXMLStyleContext *CreateDefaultStyleStyleChildContext( + XmlStyleFamily nFamily, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) override; +public: + + SdXMLStylesContext( + SdXMLImport& rImport, + bool bIsAutoStyle); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual rtl::Reference< SvXMLImportPropertyMapper > GetImportPropertyMapper(XmlStyleFamily nFamily) const override; + + void SetMasterPageStyles(SdXMLMasterPageContext const & rMaster) const; + + css::uno::Reference< css::container::XNameAccess > getPageLayouts() const; +}; + +// office:master-styles context + +class SdXMLMasterStylesContext : public SvXMLImportContext +{ + std::vector< rtl::Reference< SdXMLMasterPageContext > > maMasterPageList; + + const SdXMLImport& GetSdImport() const { return static_cast<const SdXMLImport&>(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast<SdXMLImport&>(GetImport()); } + +public: + + SdXMLMasterStylesContext(SdXMLImport& rImport); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +// <pres:header-decl>, <pres:footer-decl> and <pres:date-time-decl> + +class SdXMLHeaderFooterDeclContext : public SvXMLStyleContext +{ +public: + SdXMLHeaderFooterDeclContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + + virtual bool IsTransient() const override; + virtual void SAL_CALL endFastElement(sal_Int32 ) override; + virtual void SAL_CALL characters( const OUString& rChars ) override; + +private: + OUString maStrName; + OUString maStrText; + OUString maStrDateTimeFormat; + bool mbFixed; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |