diff options
Diffstat (limited to 'xmloff/source/draw/XMLImageMapExport.cxx')
-rw-r--r-- | xmloff/source/draw/XMLImageMapExport.cxx | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/xmloff/source/draw/XMLImageMapExport.cxx b/xmloff/source/draw/XMLImageMapExport.cxx new file mode 100644 index 000000000..918d13ad0 --- /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 OUStringLiteral gsImageMap(u"ImageMap"); +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: */ |