Coverage Report

Created: 2025-11-16 09:57

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