office-gobmx/xmloff/source/draw/ximp3dscene.cxx
Regina Henschel 9f62c7a0f2 tdf#161483 enable LO to read ODF angle units
ODF uses in several places data type 'angle' (18.3.1, ODF 1.3). That is
a double followed by unit identifier 'deg', 'grad' or 'rad' or a unit
less value in degrees. LO uses in the API angles in degrees, 1/10 of
degrees and 1/100 of degrees in data types 'double', 'short' and 'long'.

Without the fix LO does not interpret the units, but takes only the
number part.

Change-Id: Ib3f2a518a25199e3cf7a7a8572e169785f75c427
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169360
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
Tested-by: Jenkins
Reviewed-by: Regina Henschel <rb.henschel@t-online.de>
2024-06-25 16:21:42 +02:00

444 lines
15 KiB
C++

/* -*- 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 <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( u"com.sun.star.drawing.Shape3DSceneObject"_ustr );
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:
{
double fAngle = 0.0;
if (::sax::Converter::convertAngle(fAngle, aIter.toView()))
mnShadowSlant = static_cast<sal_Int32>(basegfx::fround(fAngle));
else
mnShadowSlant = 0;
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(u"D3DTransformMatrix"_ustr, uno::Any(mxHomMat));
}
// distance
xPropSet->setPropertyValue(u"D3DSceneDistance"_ustr, uno::Any(mnDistance));
// focalLength
xPropSet->setPropertyValue(u"D3DSceneFocalLength"_ustr, uno::Any(mnFocalLength));
// shadowSlant
xPropSet->setPropertyValue(u"D3DSceneShadowSlant"_ustr, uno::Any(static_cast<sal_Int16>(mnShadowSlant)));
// shadeMode
xPropSet->setPropertyValue(u"D3DSceneShadeMode"_ustr, uno::Any(mxShadeMode));
// ambientColor
xPropSet->setPropertyValue(u"D3DSceneAmbientColor"_ustr, uno::Any(maAmbientColor));
// lightingMode
xPropSet->setPropertyValue(u"D3DSceneTwoSidedLighting"_ustr, 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(u"D3DSceneLightColor1"_ustr, aAny);
xPropSet->setPropertyValue(u"D3DSceneLightDirection1"_ustr, aAny2);
xPropSet->setPropertyValue(u"D3DSceneLightOn1"_ustr, aAny3);
break;
}
case 1:
{
xPropSet->setPropertyValue(u"D3DSceneLightColor2"_ustr, aAny);
xPropSet->setPropertyValue(u"D3DSceneLightDirection2"_ustr, aAny2);
xPropSet->setPropertyValue(u"D3DSceneLightOn2"_ustr, aAny3);
break;
}
case 2:
{
xPropSet->setPropertyValue(u"D3DSceneLightColor3"_ustr, aAny);
xPropSet->setPropertyValue(u"D3DSceneLightDirection3"_ustr, aAny2);
xPropSet->setPropertyValue(u"D3DSceneLightOn3"_ustr, aAny3);
break;
}
case 3:
{
xPropSet->setPropertyValue(u"D3DSceneLightColor4"_ustr, aAny);
xPropSet->setPropertyValue(u"D3DSceneLightDirection4"_ustr, aAny2);
xPropSet->setPropertyValue(u"D3DSceneLightOn4"_ustr, aAny3);
break;
}
case 4:
{
xPropSet->setPropertyValue(u"D3DSceneLightColor5"_ustr, aAny);
xPropSet->setPropertyValue(u"D3DSceneLightDirection5"_ustr, aAny2);
xPropSet->setPropertyValue(u"D3DSceneLightOn5"_ustr, aAny3);
break;
}
case 5:
{
xPropSet->setPropertyValue(u"D3DSceneLightColor6"_ustr, aAny);
xPropSet->setPropertyValue(u"D3DSceneLightDirection6"_ustr, aAny2);
xPropSet->setPropertyValue(u"D3DSceneLightOn6"_ustr, aAny3);
break;
}
case 6:
{
xPropSet->setPropertyValue(u"D3DSceneLightColor7"_ustr, aAny);
xPropSet->setPropertyValue(u"D3DSceneLightDirection7"_ustr, aAny2);
xPropSet->setPropertyValue(u"D3DSceneLightOn7"_ustr, aAny3);
break;
}
case 7:
{
xPropSet->setPropertyValue(u"D3DSceneLightColor8"_ustr, aAny);
xPropSet->setPropertyValue(u"D3DSceneLightDirection8"_ustr, aAny2);
xPropSet->setPropertyValue(u"D3DSceneLightOn8"_ustr, 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(u"D3DCameraGeometry"_ustr, uno::Any(aCamGeo));
// #91047# set drawing::ProjectionMode AFTER camera geometry is set
// projection "D3DScenePerspective" drawing::ProjectionMode
xPropSet->setPropertyValue(u"D3DScenePerspective"_ustr, uno::Any(mxPrjMode));
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */