Avoid potential negative array index access to cached text.
[LibreOffice.git] / xmloff / source / draw / ximp3dscene.cxx
blob31da3652e3b023cf28ab300561a625ef535e1826
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sax/tools/converter.hxx>
21 #include <rtl/math.hxx>
22 #include <sal/log.hxx>
24 #include "ximp3dscene.hxx"
25 #include <xmloff/xmluconv.hxx>
26 #include <xexptran.hxx>
27 #include <xmloff/xmltoken.hxx>
28 #include <xmloff/xmlnamespace.hxx>
29 #include <com/sun/star/beans/XPropertySet.hpp>
30 #include <com/sun/star/drawing/Direction3D.hpp>
31 #include <com/sun/star/drawing/CameraGeometry.hpp>
32 #include "eventimp.hxx"
33 #include "descriptionimp.hxx"
35 using namespace ::com::sun::star;
36 using namespace ::xmloff::token;
38 // dr3d:3dlight context
40 SdXML3DLightContext::SdXML3DLightContext(
41 SvXMLImport& rImport,
42 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList)
43 : SvXMLImportContext( rImport ),
44 maDiffuseColor(0x00000000),
45 maDirection(0.0, 0.0, 1.0),
46 mbEnabled(false),
47 mbSpecular(false)
49 // read attributes for the 3DScene
50 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
52 switch(aIter.getToken())
54 case XML_ELEMENT(DR3D, XML_DIFFUSE_COLOR):
56 ::sax::Converter::convertColor(maDiffuseColor, aIter.toView());
57 break;
59 case XML_ELEMENT(DR3D, XML_DIRECTION):
61 ::basegfx::B3DVector aVal;
62 SvXMLUnitConverter::convertB3DVector(aVal, aIter.toView());
63 if (!std::isnan(aVal.getX()) && !std::isnan(aVal.getY()) && !std::isnan(aVal.getZ()))
65 maDirection = aVal;
67 else
69 SAL_WARN("xmloff", "NaNs found in light direction: " << aIter.toString());
71 break;
73 case XML_ELEMENT(DR3D, XML_ENABLED):
75 (void)::sax::Converter::convertBool(mbEnabled, aIter.toView());
76 break;
78 case XML_ELEMENT(DR3D, XML_SPECULAR):
80 (void)::sax::Converter::convertBool(mbSpecular, aIter.toView());
81 break;
83 default:
84 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
89 SdXML3DLightContext::~SdXML3DLightContext()
94 SdXML3DSceneShapeContext::SdXML3DSceneShapeContext(
95 SvXMLImport& rImport,
96 const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList,
97 uno::Reference< drawing::XShapes > const & rShapes,
98 bool bTemporaryShapes)
99 : SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShapes ), SdXML3DSceneAttributesHelper( rImport )
103 SdXML3DSceneShapeContext::~SdXML3DSceneShapeContext()
107 void SdXML3DSceneShapeContext::startFastElement(
108 sal_Int32 nElement,
109 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
111 // create new 3DScene shape and add it to rShapes, use it
112 // as base for the new 3DScene import
113 AddShape( "com.sun.star.drawing.Shape3DSceneObject" );
114 if( mxShape.is() )
116 SetStyle();
118 mxChildren.set( mxShape, uno::UNO_QUERY );
119 if( mxChildren.is() )
120 GetImport().GetShapeImport()->pushGroupForPostProcessing( mxChildren );
122 SetLayer();
124 // set pos, size, shear and rotate
125 SetTransformation();
128 // read attributes for the 3DScene
129 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
130 processSceneAttribute( aIter );
132 // #91047# call parent function is missing here, added it
133 if(mxShape.is())
135 // call parent
136 SdXMLShapeContext::startFastElement(nElement, xAttrList);
140 void SdXML3DSceneShapeContext::endFastElement(sal_Int32 nElement)
142 if(!mxShape.is())
143 return;
145 uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY);
146 if(xPropSet.is())
148 setSceneAttributes( xPropSet );
151 if( mxChildren.is() )
152 GetImport().GetShapeImport()->popGroupAndPostProcess();
154 // call parent
155 SdXMLShapeContext::endFastElement(nElement);
158 css::uno::Reference< css::xml::sax::XFastContextHandler > SdXML3DSceneShapeContext::createFastChildContext(
159 sal_Int32 nElement,
160 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
162 SvXMLImportContextRef xContext;
163 switch (nElement)
165 // #i68101#
166 case XML_ELEMENT(SVG, XML_TITLE):
167 case XML_ELEMENT(SVG_COMPAT, XML_TITLE):
168 case XML_ELEMENT(SVG, XML_DESC):
169 case XML_ELEMENT(SVG_COMPAT, XML_DESC):
170 xContext = new SdXMLDescriptionContext( GetImport(), nElement, mxShape );
171 break;
172 case XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS):
173 xContext = new SdXMLEventsContext( GetImport(), mxShape );
174 break;
175 // look for local light context first
176 case XML_ELEMENT(DR3D, XML_LIGHT):
177 // dr3d:light inside dr3d:scene context
178 xContext = create3DLightContext( xAttrList );
179 break;
180 default:
181 // call GroupChildContext function at common ShapeImport
182 return XMLShapeImportHelper::Create3DSceneChildContext(
183 GetImport(), nElement, xAttrList, mxChildren);
185 return xContext;
188 SdXML3DSceneAttributesHelper::SdXML3DSceneAttributesHelper( SvXMLImport& rImporter )
189 : mrImport( rImporter ),
190 mbSetTransform( false ),
191 mxPrjMode(drawing::ProjectionMode_PERSPECTIVE),
192 mnDistance(1000),
193 mnFocalLength(1000),
194 mnShadowSlant(0),
195 mxShadeMode(drawing::ShadeMode_SMOOTH),
196 maAmbientColor(0x00666666),
197 mbLightingMode(false),
198 maVRP(0.0, 0.0, 1.0),
199 maVPN(0.0, 0.0, 1.0),
200 maVUP(0.0, 1.0, 0.0),
201 mbVRPUsed(false)
205 /** creates a 3d light context and adds it to the internal list for later processing */
206 SvXMLImportContext * SdXML3DSceneAttributesHelper::create3DLightContext( const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList)
208 const rtl::Reference<SdXML3DLightContext> xContext{new SdXML3DLightContext(mrImport, xAttrList)};
210 // remember SdXML3DLightContext for later evaluation
211 maList.push_back(xContext);
213 return xContext.get();
216 /** this should be called for each scene attribute */
217 void SdXML3DSceneAttributesHelper::processSceneAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter )
219 auto nAttributeToken = aIter.getToken();
220 if( !IsTokenInNamespace(nAttributeToken, XML_NAMESPACE_DR3D) )
221 return;
223 switch(nAttributeToken & TOKEN_MASK)
225 case XML_TRANSFORM:
227 SdXMLImExTransform3D aTransform(aIter.toString(), mrImport.GetMM100UnitConverter());
228 if(aTransform.NeedsAction())
229 mbSetTransform = aTransform.GetFullHomogenTransform(mxHomMat);
230 return;
232 case XML_VRP:
234 ::basegfx::B3DVector aNewVec;
235 SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView());
237 if(aNewVec != maVRP)
239 maVRP = aNewVec;
240 mbVRPUsed = true;
242 return;
244 case XML_VPN:
246 ::basegfx::B3DVector aNewVec;
247 SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView());
249 if(aNewVec != maVPN)
251 maVPN = aNewVec;
253 return;
255 case XML_VUP:
257 ::basegfx::B3DVector aNewVec;
258 SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView());
260 if(aNewVec != maVUP)
262 maVUP = aNewVec;
264 return;
266 case XML_PROJECTION:
268 if( IsXMLToken( aIter, XML_PARALLEL ) )
269 mxPrjMode = drawing::ProjectionMode_PARALLEL;
270 else
271 mxPrjMode = drawing::ProjectionMode_PERSPECTIVE;
272 return;
274 case XML_DISTANCE:
276 mrImport.GetMM100UnitConverter().convertMeasureToCore(mnDistance,
277 aIter.toView());
278 return;
280 case XML_FOCAL_LENGTH:
282 mrImport.GetMM100UnitConverter().convertMeasureToCore(mnFocalLength,
283 aIter.toView());
284 return;
286 case XML_SHADOW_SLANT:
288 ::sax::Converter::convertNumber(mnShadowSlant, aIter.toView());
289 return;
291 case XML_SHADE_MODE:
293 if( IsXMLToken( aIter, XML_FLAT ) )
294 mxShadeMode = drawing::ShadeMode_FLAT;
295 else if( IsXMLToken( aIter, XML_PHONG ) )
296 mxShadeMode = drawing::ShadeMode_PHONG;
297 else if( IsXMLToken( aIter, XML_GOURAUD ) )
298 mxShadeMode = drawing::ShadeMode_SMOOTH;
299 else
300 mxShadeMode = drawing::ShadeMode_DRAFT;
301 return;
303 case XML_AMBIENT_COLOR:
305 ::sax::Converter::convertColor(maAmbientColor, aIter.toView());
306 return;
308 case XML_LIGHTING_MODE:
310 (void)::sax::Converter::convertBool(mbLightingMode, aIter.toView());
311 return;
313 default:
314 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
318 /** this sets the scene attributes at this propertyset */
319 void SdXML3DSceneAttributesHelper::setSceneAttributes( const css::uno::Reference< css::beans::XPropertySet >& xPropSet )
321 uno::Any aAny;
323 // world transformation
324 if(mbSetTransform)
326 xPropSet->setPropertyValue("D3DTransformMatrix", uno::Any(mxHomMat));
329 // distance
330 xPropSet->setPropertyValue("D3DSceneDistance", uno::Any(mnDistance));
331 // focalLength
332 xPropSet->setPropertyValue("D3DSceneFocalLength", uno::Any(mnFocalLength));
333 // shadowSlant
334 xPropSet->setPropertyValue("D3DSceneShadowSlant", uno::Any(static_cast<sal_Int16>(mnShadowSlant)));
335 // shadeMode
336 xPropSet->setPropertyValue("D3DSceneShadeMode", uno::Any(mxShadeMode));
337 // ambientColor
338 xPropSet->setPropertyValue("D3DSceneAmbientColor", uno::Any(maAmbientColor));
339 // lightingMode
340 xPropSet->setPropertyValue("D3DSceneTwoSidedLighting", uno::Any(mbLightingMode));
342 if( !maList.empty() )
344 uno::Any aAny2;
345 uno::Any aAny3;
347 // set lights
348 for( size_t a = 0; a < maList.size(); a++)
350 SdXML3DLightContext* pCtx = maList[ a ].get();
352 // set anys
353 aAny <<= pCtx->GetDiffuseColor();
354 drawing::Direction3D aLightDir;
355 aLightDir.DirectionX = pCtx->GetDirection().getX();
356 aLightDir.DirectionY = pCtx->GetDirection().getY();
357 aLightDir.DirectionZ = pCtx->GetDirection().getZ();
358 aAny2 <<= aLightDir;
359 aAny3 <<= pCtx->GetEnabled();
361 switch(a)
363 case 0:
365 xPropSet->setPropertyValue("D3DSceneLightColor1", aAny);
366 xPropSet->setPropertyValue("D3DSceneLightDirection1", aAny2);
367 xPropSet->setPropertyValue("D3DSceneLightOn1", aAny3);
368 break;
370 case 1:
372 xPropSet->setPropertyValue("D3DSceneLightColor2", aAny);
373 xPropSet->setPropertyValue("D3DSceneLightDirection2", aAny2);
374 xPropSet->setPropertyValue("D3DSceneLightOn2", aAny3);
375 break;
377 case 2:
379 xPropSet->setPropertyValue("D3DSceneLightColor3", aAny);
380 xPropSet->setPropertyValue("D3DSceneLightDirection3", aAny2);
381 xPropSet->setPropertyValue("D3DSceneLightOn3", aAny3);
382 break;
384 case 3:
386 xPropSet->setPropertyValue("D3DSceneLightColor4", aAny);
387 xPropSet->setPropertyValue("D3DSceneLightDirection4", aAny2);
388 xPropSet->setPropertyValue("D3DSceneLightOn4", aAny3);
389 break;
391 case 4:
393 xPropSet->setPropertyValue("D3DSceneLightColor5", aAny);
394 xPropSet->setPropertyValue("D3DSceneLightDirection5", aAny2);
395 xPropSet->setPropertyValue("D3DSceneLightOn5", aAny3);
396 break;
398 case 5:
400 xPropSet->setPropertyValue("D3DSceneLightColor6", aAny);
401 xPropSet->setPropertyValue("D3DSceneLightDirection6", aAny2);
402 xPropSet->setPropertyValue("D3DSceneLightOn6", aAny3);
403 break;
405 case 6:
407 xPropSet->setPropertyValue("D3DSceneLightColor7", aAny);
408 xPropSet->setPropertyValue("D3DSceneLightDirection7", aAny2);
409 xPropSet->setPropertyValue("D3DSceneLightOn7", aAny3);
410 break;
412 case 7:
414 xPropSet->setPropertyValue("D3DSceneLightColor8", aAny);
415 xPropSet->setPropertyValue("D3DSceneLightDirection8", aAny2);
416 xPropSet->setPropertyValue("D3DSceneLightOn8", aAny3);
417 break;
423 // CameraGeometry and camera settings
424 drawing::CameraGeometry aCamGeo;
425 aCamGeo.vrp.PositionX = maVRP.getX();
426 aCamGeo.vrp.PositionY = maVRP.getY();
427 aCamGeo.vrp.PositionZ = maVRP.getZ();
428 aCamGeo.vpn.DirectionX = maVPN.getX();
429 aCamGeo.vpn.DirectionY = maVPN.getY();
430 aCamGeo.vpn.DirectionZ = maVPN.getZ();
431 aCamGeo.vup.DirectionX = maVUP.getX();
432 aCamGeo.vup.DirectionY = maVUP.getY();
433 aCamGeo.vup.DirectionZ = maVUP.getZ();
434 xPropSet->setPropertyValue("D3DCameraGeometry", uno::Any(aCamGeo));
436 // #91047# set drawing::ProjectionMode AFTER camera geometry is set
437 // projection "D3DScenePerspective" drawing::ProjectionMode
438 xPropSet->setPropertyValue("D3DScenePerspective", uno::Any(mxPrjMode));
441 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */