Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/xmloff/source/draw/ximp3dscene.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
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 .
18
 */
19
20
#include <sax/tools/converter.hxx>
21
#include <sal/log.hxx>
22
23
#include "ximp3dscene.hxx"
24
#include <xmloff/xmluconv.hxx>
25
#include <xexptran.hxx>
26
#include <xmloff/xmltoken.hxx>
27
#include <xmloff/xmlnamespace.hxx>
28
#include <com/sun/star/beans/XPropertySet.hpp>
29
#include <com/sun/star/drawing/Direction3D.hpp>
30
#include <com/sun/star/drawing/CameraGeometry.hpp>
31
#include <com/sun/star/drawing/ProjectionMode.hpp>
32
#include <com/sun/star/drawing/ShadeMode.hpp>
33
#include "eventimp.hxx"
34
#include "descriptionimp.hxx"
35
36
using namespace ::com::sun::star;
37
using namespace ::xmloff::token;
38
39
// dr3d:3dlight context
40
41
SdXML3DLightContext::SdXML3DLightContext(
42
    SvXMLImport& rImport,
43
    const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList)
44
0
:   SvXMLImportContext( rImport ),
45
0
    maDiffuseColor(0x00000000),
46
0
    maDirection(0.0, 0.0, 1.0),
47
0
    mbEnabled(false),
48
0
    mbSpecular(false)
49
0
{
50
    // read attributes for the 3DScene
51
0
    for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
52
0
    {
53
0
        switch(aIter.getToken())
54
0
        {
55
0
            case XML_ELEMENT(DR3D, XML_DIFFUSE_COLOR):
56
0
            {
57
0
                ::sax::Converter::convertColor(maDiffuseColor, aIter.toView());
58
0
                break;
59
0
            }
60
0
            case XML_ELEMENT(DR3D, XML_DIRECTION):
61
0
            {
62
0
                ::basegfx::B3DVector aVal;
63
0
                SvXMLUnitConverter::convertB3DVector(aVal, aIter.toView());
64
0
                if (!std::isnan(aVal.getX()) && !std::isnan(aVal.getY()) && !std::isnan(aVal.getZ()))
65
0
                {
66
0
                    maDirection = aVal;
67
0
                }
68
0
                else
69
0
                {
70
0
                    SAL_WARN("xmloff", "NaNs found in light direction: " << aIter.toString());
71
0
                }
72
0
                break;
73
0
            }
74
0
            case XML_ELEMENT(DR3D, XML_ENABLED):
75
0
            {
76
0
                (void)::sax::Converter::convertBool(mbEnabled, aIter.toView());
77
0
                break;
78
0
            }
79
0
            case XML_ELEMENT(DR3D, XML_SPECULAR):
80
0
            {
81
0
                (void)::sax::Converter::convertBool(mbSpecular, aIter.toView());
82
0
                break;
83
0
            }
84
0
            default:
85
0
                XMLOFF_WARN_UNKNOWN("xmloff", aIter);
86
0
        }
87
0
    }
88
0
}
89
90
SdXML3DLightContext::~SdXML3DLightContext()
91
0
{
92
0
}
93
94
95
SdXML3DSceneShapeContext::SdXML3DSceneShapeContext(
96
    SvXMLImport& rImport,
97
    const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList,
98
    uno::Reference< drawing::XShapes > const & rShapes,
99
    bool bTemporaryShapes)
100
0
:   SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShapes ), SdXML3DSceneAttributesHelper( rImport )
101
0
{
102
0
}
103
104
SdXML3DSceneShapeContext::~SdXML3DSceneShapeContext()
105
0
{
106
0
}
107
108
void SdXML3DSceneShapeContext::startFastElement(
109
    sal_Int32 nElement,
110
    const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
111
0
{
112
    // create new 3DScene shape and add it to rShapes, use it
113
    // as base for the new 3DScene import
114
0
    AddShape( u"com.sun.star.drawing.Shape3DSceneObject"_ustr );
115
0
    if( mxShape.is() )
116
0
    {
117
0
        SetStyle();
118
119
0
        mxChildren.set( mxShape, uno::UNO_QUERY );
120
0
        if( mxChildren.is() )
121
0
            GetImport().GetShapeImport()->pushGroupForPostProcessing( mxChildren );
122
123
0
        SetLayer();
124
125
        // set pos, size, shear and rotate
126
0
        SetTransformation();
127
0
    }
128
129
    // read attributes for the 3DScene
130
0
    for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
131
0
        processSceneAttribute( aIter );
132
133
    // #91047# call parent function is missing here, added it
134
0
    if(mxShape.is())
135
0
    {
136
        // call parent
137
0
        SdXMLShapeContext::startFastElement(nElement, xAttrList);
138
0
    }
139
0
}
140
141
void SdXML3DSceneShapeContext::endFastElement(sal_Int32 nElement)
142
0
{
143
0
    if(!mxShape.is())
144
0
        return;
145
146
0
    uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY);
147
0
    if(xPropSet.is())
148
0
    {
149
0
        setSceneAttributes( xPropSet );
150
0
    }
151
152
0
    if( mxChildren.is() )
153
0
        GetImport().GetShapeImport()->popGroupAndPostProcess();
154
155
    // call parent
156
0
    SdXMLShapeContext::endFastElement(nElement);
157
0
}
158
159
css::uno::Reference< css::xml::sax::XFastContextHandler > SdXML3DSceneShapeContext::createFastChildContext(
160
    sal_Int32 nElement,
161
    const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
162
0
{
163
0
    SvXMLImportContextRef xContext;
164
0
    switch (nElement)
165
0
    {
166
        // #i68101#
167
0
        case XML_ELEMENT(SVG, XML_TITLE):
168
0
        case XML_ELEMENT(SVG_COMPAT, XML_TITLE):
169
0
        case XML_ELEMENT(SVG, XML_DESC):
170
0
        case XML_ELEMENT(SVG_COMPAT, XML_DESC):
171
0
            xContext = new SdXMLDescriptionContext( GetImport(), nElement, mxShape );
172
0
            break;
173
0
        case XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS):
174
0
            xContext = new SdXMLEventsContext( GetImport(), mxShape );
175
0
            break;
176
        // look for local light context first
177
0
        case XML_ELEMENT(DR3D, XML_LIGHT):
178
            // dr3d:light inside dr3d:scene context
179
0
            xContext = create3DLightContext( xAttrList );
180
0
            break;
181
0
        default:
182
            // call GroupChildContext function at common ShapeImport
183
0
            return XMLShapeImportHelper::Create3DSceneChildContext(
184
0
                GetImport(), nElement, xAttrList, mxChildren);
185
0
    }
186
0
    return xContext;
187
0
}
188
189
SdXML3DSceneAttributesHelper::SdXML3DSceneAttributesHelper( SvXMLImport& rImporter )
190
0
:   mrImport( rImporter ),
191
0
    mbSetTransform( false ),
192
0
    mxPrjMode(drawing::ProjectionMode_PERSPECTIVE),
193
0
    mnDistance(1000),
194
0
    mnFocalLength(1000),
195
0
    mnShadowSlant(0),
196
0
    mxShadeMode(drawing::ShadeMode_SMOOTH),
197
0
    maAmbientColor(0x00666666),
198
0
    mbLightingMode(false),
199
0
    maVRP(0.0, 0.0, 1.0),
200
0
    maVPN(0.0, 0.0, 1.0),
201
0
    maVUP(0.0, 1.0, 0.0),
202
0
    mbVRPUsed(false)
203
0
{
204
0
}
205
206
/** creates a 3d light context and adds it to the internal list for later processing */
207
SvXMLImportContext * SdXML3DSceneAttributesHelper::create3DLightContext( const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList)
208
0
{
209
0
    const rtl::Reference<SdXML3DLightContext> xContext{new SdXML3DLightContext(mrImport, xAttrList)};
210
211
    // remember SdXML3DLightContext for later evaluation
212
0
    maList.push_back(xContext);
213
214
0
    return xContext.get();
215
0
}
216
217
/** this should be called for each scene attribute */
218
void SdXML3DSceneAttributesHelper::processSceneAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter )
219
0
{
220
0
    auto nAttributeToken = aIter.getToken();
221
0
    if( !IsTokenInNamespace(nAttributeToken, XML_NAMESPACE_DR3D) )
222
0
        return;
223
224
0
    switch(nAttributeToken & TOKEN_MASK)
225
0
    {
226
0
        case XML_TRANSFORM:
227
0
        {
228
0
            SdXMLImExTransform3D aTransform(aIter.toString(), mrImport.GetMM100UnitConverter());
229
0
            if(aTransform.NeedsAction())
230
0
                mbSetTransform = aTransform.GetFullHomogenTransform(mxHomMat);
231
0
            return;
232
0
        }
233
0
        case XML_VRP:
234
0
        {
235
0
            ::basegfx::B3DVector aNewVec;
236
0
            SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView());
237
238
0
            if(aNewVec != maVRP)
239
0
            {
240
0
                maVRP = aNewVec;
241
0
                mbVRPUsed = true;
242
0
            }
243
0
            return;
244
0
        }
245
0
        case XML_VPN:
246
0
        {
247
0
            ::basegfx::B3DVector aNewVec;
248
0
            SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView());
249
250
0
            if(aNewVec != maVPN)
251
0
            {
252
0
                maVPN = aNewVec;
253
0
            }
254
0
            return;
255
0
        }
256
0
        case XML_VUP:
257
0
        {
258
0
            ::basegfx::B3DVector aNewVec;
259
0
            SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView());
260
261
0
            if(aNewVec != maVUP)
262
0
            {
263
0
                maVUP = aNewVec;
264
0
            }
265
0
            return;
266
0
        }
267
0
        case XML_PROJECTION:
268
0
        {
269
0
            if( IsXMLToken( aIter, XML_PARALLEL ) )
270
0
                mxPrjMode = drawing::ProjectionMode_PARALLEL;
271
0
            else
272
0
                mxPrjMode = drawing::ProjectionMode_PERSPECTIVE;
273
0
            return;
274
0
        }
275
0
        case XML_DISTANCE:
276
0
        {
277
0
            mrImport.GetMM100UnitConverter().convertMeasureToCore(mnDistance,
278
0
                    aIter.toView());
279
0
            return;
280
0
        }
281
0
        case XML_FOCAL_LENGTH:
282
0
        {
283
0
            mrImport.GetMM100UnitConverter().convertMeasureToCore(mnFocalLength,
284
0
                    aIter.toView());
285
0
            return;
286
0
        }
287
0
        case XML_SHADOW_SLANT:
288
0
        {
289
0
            double fAngle = 0.0;
290
0
            if (::sax::Converter::convertAngle(fAngle, aIter.toView()))
291
0
                mnShadowSlant = static_cast<sal_Int32>(basegfx::fround(fAngle));
292
0
            else
293
0
                mnShadowSlant = 0;
294
0
            return;
295
0
        }
296
0
        case XML_SHADE_MODE:
297
0
        {
298
0
            if( IsXMLToken( aIter, XML_FLAT ) )
299
0
                mxShadeMode = drawing::ShadeMode_FLAT;
300
0
            else if( IsXMLToken( aIter, XML_PHONG ) )
301
0
                mxShadeMode = drawing::ShadeMode_PHONG;
302
0
            else if( IsXMLToken( aIter, XML_GOURAUD ) )
303
0
                mxShadeMode = drawing::ShadeMode_SMOOTH;
304
0
            else
305
0
                mxShadeMode = drawing::ShadeMode_DRAFT;
306
0
            return;
307
0
        }
308
0
        case XML_AMBIENT_COLOR:
309
0
        {
310
0
            ::sax::Converter::convertColor(maAmbientColor, aIter.toView());
311
0
            return;
312
0
        }
313
0
        case XML_LIGHTING_MODE:
314
0
        {
315
0
            (void)::sax::Converter::convertBool(mbLightingMode, aIter.toView());
316
0
            return;
317
0
        }
318
0
        default:
319
0
            XMLOFF_WARN_UNKNOWN("xmloff", aIter);
320
0
    }
321
0
}
322
323
/** this sets the scene attributes at this propertyset */
324
void SdXML3DSceneAttributesHelper::setSceneAttributes( const css::uno::Reference< css::beans::XPropertySet >& xPropSet )
325
0
{
326
0
    uno::Any aAny;
327
328
    // world transformation
329
0
    if(mbSetTransform)
330
0
    {
331
0
        xPropSet->setPropertyValue(u"D3DTransformMatrix"_ustr, uno::Any(mxHomMat));
332
0
    }
333
334
    // distance
335
0
    xPropSet->setPropertyValue(u"D3DSceneDistance"_ustr, uno::Any(mnDistance));
336
    // focalLength
337
0
    xPropSet->setPropertyValue(u"D3DSceneFocalLength"_ustr, uno::Any(mnFocalLength));
338
    // shadowSlant
339
0
    xPropSet->setPropertyValue(u"D3DSceneShadowSlant"_ustr, uno::Any(static_cast<sal_Int16>(mnShadowSlant)));
340
    // shadeMode
341
0
    xPropSet->setPropertyValue(u"D3DSceneShadeMode"_ustr, uno::Any(mxShadeMode));
342
    // ambientColor
343
0
    xPropSet->setPropertyValue(u"D3DSceneAmbientColor"_ustr, uno::Any(maAmbientColor));
344
    // lightingMode
345
0
    xPropSet->setPropertyValue(u"D3DSceneTwoSidedLighting"_ustr, uno::Any(mbLightingMode));
346
347
0
    if( !maList.empty() )
348
0
    {
349
0
        uno::Any aAny2;
350
0
        uno::Any aAny3;
351
352
        // set lights
353
0
        for( size_t a = 0; a < maList.size(); a++)
354
0
        {
355
0
            SdXML3DLightContext* pCtx = maList[ a ].get();
356
357
            // set anys
358
0
            aAny <<= pCtx->GetDiffuseColor();
359
0
            drawing::Direction3D aLightDir;
360
0
            aLightDir.DirectionX = pCtx->GetDirection().getX();
361
0
            aLightDir.DirectionY = pCtx->GetDirection().getY();
362
0
            aLightDir.DirectionZ = pCtx->GetDirection().getZ();
363
0
            aAny2 <<= aLightDir;
364
0
            aAny3 <<= pCtx->GetEnabled();
365
366
0
            switch(a)
367
0
            {
368
0
                case 0:
369
0
                {
370
0
                    xPropSet->setPropertyValue(u"D3DSceneLightColor1"_ustr, aAny);
371
0
                    xPropSet->setPropertyValue(u"D3DSceneLightDirection1"_ustr, aAny2);
372
0
                    xPropSet->setPropertyValue(u"D3DSceneLightOn1"_ustr, aAny3);
373
0
                    break;
374
0
                }
375
0
                case 1:
376
0
                {
377
0
                    xPropSet->setPropertyValue(u"D3DSceneLightColor2"_ustr, aAny);
378
0
                    xPropSet->setPropertyValue(u"D3DSceneLightDirection2"_ustr, aAny2);
379
0
                    xPropSet->setPropertyValue(u"D3DSceneLightOn2"_ustr, aAny3);
380
0
                    break;
381
0
                }
382
0
                case 2:
383
0
                {
384
0
                    xPropSet->setPropertyValue(u"D3DSceneLightColor3"_ustr, aAny);
385
0
                    xPropSet->setPropertyValue(u"D3DSceneLightDirection3"_ustr, aAny2);
386
0
                    xPropSet->setPropertyValue(u"D3DSceneLightOn3"_ustr, aAny3);
387
0
                    break;
388
0
                }
389
0
                case 3:
390
0
                {
391
0
                    xPropSet->setPropertyValue(u"D3DSceneLightColor4"_ustr, aAny);
392
0
                    xPropSet->setPropertyValue(u"D3DSceneLightDirection4"_ustr, aAny2);
393
0
                    xPropSet->setPropertyValue(u"D3DSceneLightOn4"_ustr, aAny3);
394
0
                    break;
395
0
                }
396
0
                case 4:
397
0
                {
398
0
                    xPropSet->setPropertyValue(u"D3DSceneLightColor5"_ustr, aAny);
399
0
                    xPropSet->setPropertyValue(u"D3DSceneLightDirection5"_ustr, aAny2);
400
0
                    xPropSet->setPropertyValue(u"D3DSceneLightOn5"_ustr, aAny3);
401
0
                    break;
402
0
                }
403
0
                case 5:
404
0
                {
405
0
                    xPropSet->setPropertyValue(u"D3DSceneLightColor6"_ustr, aAny);
406
0
                    xPropSet->setPropertyValue(u"D3DSceneLightDirection6"_ustr, aAny2);
407
0
                    xPropSet->setPropertyValue(u"D3DSceneLightOn6"_ustr, aAny3);
408
0
                    break;
409
0
                }
410
0
                case 6:
411
0
                {
412
0
                    xPropSet->setPropertyValue(u"D3DSceneLightColor7"_ustr, aAny);
413
0
                    xPropSet->setPropertyValue(u"D3DSceneLightDirection7"_ustr, aAny2);
414
0
                    xPropSet->setPropertyValue(u"D3DSceneLightOn7"_ustr, aAny3);
415
0
                    break;
416
0
                }
417
0
                case 7:
418
0
                {
419
0
                    xPropSet->setPropertyValue(u"D3DSceneLightColor8"_ustr, aAny);
420
0
                    xPropSet->setPropertyValue(u"D3DSceneLightDirection8"_ustr, aAny2);
421
0
                    xPropSet->setPropertyValue(u"D3DSceneLightOn8"_ustr, aAny3);
422
0
                    break;
423
0
                }
424
0
            }
425
0
        }
426
0
    }
427
428
    // CameraGeometry and camera settings
429
0
    drawing::CameraGeometry aCamGeo;
430
0
    aCamGeo.vrp.PositionX = maVRP.getX();
431
0
    aCamGeo.vrp.PositionY = maVRP.getY();
432
0
    aCamGeo.vrp.PositionZ = maVRP.getZ();
433
0
    aCamGeo.vpn.DirectionX = maVPN.getX();
434
0
    aCamGeo.vpn.DirectionY = maVPN.getY();
435
0
    aCamGeo.vpn.DirectionZ = maVPN.getZ();
436
0
    aCamGeo.vup.DirectionX = maVUP.getX();
437
0
    aCamGeo.vup.DirectionY = maVUP.getY();
438
0
    aCamGeo.vup.DirectionZ = maVUP.getZ();
439
0
    xPropSet->setPropertyValue(u"D3DCameraGeometry"_ustr, uno::Any(aCamGeo));
440
441
    // #91047# set drawing::ProjectionMode AFTER camera geometry is set
442
    // projection "D3DScenePerspective" drawing::ProjectionMode
443
0
    xPropSet->setPropertyValue(u"D3DScenePerspective"_ustr, uno::Any(mxPrjMode));
444
0
}
445
446
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */