Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/xmloff/source/draw/XMLImageMapContext.cxx
Line
Count
Source (jump to first uncovered line)
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 <XMLImageMapContext.hxx>
21
#include <rtl/ustrbuf.hxx>
22
#include <com/sun/star/uno/Reference.h>
23
#include <com/sun/star/beans/XPropertySet.hpp>
24
#include <com/sun/star/beans/XPropertySetInfo.hpp>
25
#include <com/sun/star/frame/XModel.hpp>
26
#include <com/sun/star/container/XIndexContainer.hpp>
27
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
28
#include <com/sun/star/document/XEventsSupplier.hpp>
29
#include <com/sun/star/awt/Rectangle.hpp>
30
#include <xmloff/xmltoken.hxx>
31
#include <xmloff/xmlimp.hxx>
32
#include <xmloff/xmlnamespace.hxx>
33
#include <xmloff/xmluconv.hxx>
34
#include <xexptran.hxx>
35
#include <xmloff/xmlerror.hxx>
36
#include <xmloff/XMLEventsImportContext.hxx>
37
#include <XMLStringBufferImportContext.hxx>
38
#include <tools/debug.hxx>
39
#include <basegfx/polygon/b2dpolygon.hxx>
40
#include <basegfx/polygon/b2dpolygontools.hxx>
41
#include <sal/log.hxx>
42
43
using namespace ::com::sun::star;
44
using namespace ::xmloff::token;
45
46
using ::com::sun::star::beans::XPropertySet;
47
using ::com::sun::star::beans::XPropertySetInfo;
48
using ::com::sun::star::container::XIndexContainer;
49
using ::com::sun::star::lang::XMultiServiceFactory;
50
using ::com::sun::star::uno::Reference;
51
using ::com::sun::star::uno::UNO_QUERY;
52
using ::com::sun::star::uno::XInterface;
53
using ::com::sun::star::uno::Any;
54
using ::com::sun::star::document::XEventsSupplier;
55
56
namespace {
57
58
class XMLImageMapObjectContext : public SvXMLImportContext
59
{
60
61
protected:
62
63
    Reference<XIndexContainer> xImageMap;   /// the image map
64
    Reference<XPropertySet> xMapEntry;      /// one map-entry (one area)
65
66
    OUString sUrl;
67
    OUString sTargt;
68
    OUStringBuffer sDescriptionBuffer;
69
    OUStringBuffer sTitleBuffer;
70
    OUString sNam;
71
    bool bIsActive;
72
73
    bool bValid;
74
75
public:
76
77
    XMLImageMapObjectContext(
78
        SvXMLImport& rImport,
79
        css::uno::Reference<css::container::XIndexContainer> const & xMap,
80
        const char* pServiceName);
81
82
    virtual void SAL_CALL startFastElement( sal_Int32 nElement,
83
        const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
84
85
    virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
86
87
    virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
88
        sal_Int32 nElement,
89
        const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
90
91
protected:
92
93
    virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter &);
94
95
    virtual void Prepare(
96
        css::uno::Reference<css::beans::XPropertySet> & rPropertySet);
97
};
98
99
}
100
101
XMLImageMapObjectContext::XMLImageMapObjectContext(
102
    SvXMLImport& rImport,
103
    Reference<XIndexContainer> const & xMap,
104
    const char* pServiceName) :
105
0
        SvXMLImportContext(rImport),
106
0
        xImageMap(xMap),
107
0
        bIsActive(true),
108
0
        bValid(false)
109
0
{
110
0
    DBG_ASSERT(nullptr != pServiceName,
111
0
               "Please supply the image map object service name");
112
113
0
    Reference<XMultiServiceFactory> xFactory(GetImport().GetModel(),UNO_QUERY);
114
0
    if( !xFactory.is() )
115
0
        return;
116
117
0
    Reference<XInterface> xIfc = xFactory->createInstance(
118
0
        OUString::createFromAscii(pServiceName));
119
0
    DBG_ASSERT(xIfc.is(), "can't create image map object!");
120
0
    if (xIfc.is())
121
0
        xMapEntry.set(xIfc, UNO_QUERY);
122
    // else: can't create service -> ignore
123
    // else: can't even get factory -> ignore
124
0
}
125
126
void XMLImageMapObjectContext::startFastElement( sal_Int32 /*nElement*/,
127
    const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
128
0
{
129
0
    for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
130
0
        ProcessAttribute(aIter);
131
0
}
132
133
void XMLImageMapObjectContext::endFastElement(sal_Int32 )
134
0
{
135
    // only create and insert image map object if validity flag is set
136
    // (and we actually have an image map)
137
0
    if ( bValid && xImageMap.is() && xMapEntry.is() )
138
0
    {
139
        // set values
140
0
        Prepare( xMapEntry );
141
142
        // insert into image map
143
0
        xImageMap->insertByIndex( xImageMap->getCount(), Any(xMapEntry) );
144
0
    }
145
    // else: not valid -> don't create and insert
146
0
}
147
148
css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImageMapObjectContext::createFastChildContext(
149
    sal_Int32 nElement,
150
    const css::uno::Reference< css::xml::sax::XFastAttributeList >&  )
151
0
{
152
0
    switch (nElement)
153
0
    {
154
0
        case XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS):
155
0
        {
156
0
            Reference<XEventsSupplier> xEvents( xMapEntry, UNO_QUERY );
157
0
            return new XMLEventsImportContext(
158
0
                GetImport(), xEvents);
159
0
        }
160
0
        case XML_ELEMENT(SVG, XML_TITLE):
161
0
        case XML_ELEMENT(SVG_COMPAT, XML_TITLE):
162
0
            return new XMLStringBufferImportContext(
163
0
                GetImport(), sTitleBuffer);
164
0
        case XML_ELEMENT(SVG, XML_DESC):
165
0
        case XML_ELEMENT(SVG_COMPAT, XML_DESC):
166
0
            return new XMLStringBufferImportContext(
167
0
                GetImport(), sDescriptionBuffer);
168
0
    }
169
0
    XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
170
0
    return nullptr;
171
0
}
172
173
void XMLImageMapObjectContext::ProcessAttribute(
174
    const sax_fastparser::FastAttributeList::FastAttributeIter & aIter)
175
0
{
176
0
    switch (aIter.getToken())
177
0
    {
178
0
        case XML_ELEMENT(XLINK, XML_HREF):
179
0
            sUrl = GetImport().GetAbsoluteReference(aIter.toString());
180
0
            break;
181
182
0
        case XML_ELEMENT(OFFICE, XML_TARGET_FRAME_NAME):
183
0
            sTargt = aIter.toString();
184
0
            break;
185
186
0
        case XML_ELEMENT(DRAW, XML_NOHREF):
187
0
            bIsActive = ! IsXMLToken(aIter, XML_NOHREF);
188
0
            break;
189
190
0
        case XML_ELEMENT(OFFICE, XML_NAME):
191
0
            sNam = aIter.toString();
192
0
            break;
193
0
        default:
194
            // do nothing
195
0
            XMLOFF_WARN_UNKNOWN("xmloff", aIter);
196
0
            break;
197
0
    }
198
0
}
199
200
void XMLImageMapObjectContext::Prepare(
201
    Reference<XPropertySet> & rPropertySet)
202
0
{
203
0
    rPropertySet->setPropertyValue( u"URL"_ustr, Any( sUrl ) );
204
0
    rPropertySet->setPropertyValue( u"Title"_ustr, Any( sTitleBuffer.makeStringAndClear() ) );
205
0
    rPropertySet->setPropertyValue( u"Description"_ustr, Any( sDescriptionBuffer.makeStringAndClear() ) );
206
0
    rPropertySet->setPropertyValue( u"Target"_ustr, Any( sTargt ) );
207
0
    rPropertySet->setPropertyValue( u"IsActive"_ustr, Any( bIsActive ) );
208
0
    rPropertySet->setPropertyValue( u"Name"_ustr, Any( sNam ) );
209
0
}
210
211
namespace {
212
213
class XMLImageMapRectangleContext : public XMLImageMapObjectContext
214
{
215
    awt::Rectangle aRectangle;
216
217
    bool bXOK;
218
    bool bYOK;
219
    bool bWidthOK;
220
    bool bHeightOK;
221
222
public:
223
224
    XMLImageMapRectangleContext(
225
        SvXMLImport& rImport,
226
        css::uno::Reference<css::container::XIndexContainer> const & xMap);
227
228
protected:
229
    virtual void ProcessAttribute(
230
        const sax_fastparser::FastAttributeList::FastAttributeIter &) override;
231
232
    virtual void Prepare(
233
        css::uno::Reference<css::beans::XPropertySet> & rPropertySet) override;
234
};
235
236
}
237
238
XMLImageMapRectangleContext::XMLImageMapRectangleContext(
239
    SvXMLImport& rImport,
240
    Reference<XIndexContainer> const & xMap) :
241
0
        XMLImageMapObjectContext(rImport, xMap,
242
0
                                 "com.sun.star.image.ImageMapRectangleObject"),
243
0
        bXOK(false),
244
0
        bYOK(false),
245
0
        bWidthOK(false),
246
0
        bHeightOK(false)
247
0
{
248
0
}
249
250
void XMLImageMapRectangleContext::ProcessAttribute(
251
    const sax_fastparser::FastAttributeList::FastAttributeIter & aIter)
252
0
{
253
0
    sal_Int32 nTmp;
254
0
    switch (aIter.getToken())
255
0
    {
256
0
        case XML_ELEMENT(SVG, XML_X):
257
0
        case XML_ELEMENT(SVG_COMPAT, XML_X):
258
0
            if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp,
259
0
                                                                   aIter.toView()))
260
0
            {
261
0
                aRectangle.X = nTmp;
262
0
                bXOK = true;
263
0
            }
264
0
            break;
265
0
        case  XML_ELEMENT(SVG, XML_Y):
266
0
        case  XML_ELEMENT(SVG_COMPAT, XML_Y):
267
0
            if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp,
268
0
                                                                   aIter.toView()))
269
0
            {
270
0
                aRectangle.Y = nTmp;
271
0
                bYOK = true;
272
0
            }
273
0
            break;
274
0
        case XML_ELEMENT(SVG, XML_WIDTH):
275
0
        case XML_ELEMENT(SVG_COMPAT, XML_WIDTH):
276
0
            if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp,
277
0
                                                                   aIter.toView()))
278
0
            {
279
0
                aRectangle.Width = nTmp;
280
0
                bWidthOK = true;
281
0
            }
282
0
            break;
283
0
        case  XML_ELEMENT(SVG, XML_HEIGHT):
284
0
        case  XML_ELEMENT(SVG_COMPAT, XML_HEIGHT):
285
0
            if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp,
286
0
                                                                   aIter.toView()))
287
0
            {
288
0
                aRectangle.Height = nTmp;
289
0
                bHeightOK = true;
290
0
            }
291
0
            break;
292
0
        default:
293
0
            XMLImageMapObjectContext::ProcessAttribute(aIter);
294
0
    }
295
296
0
    bValid = bHeightOK && bXOK && bYOK && bWidthOK;
297
0
}
298
299
void XMLImageMapRectangleContext::Prepare(
300
    Reference<XPropertySet> & rPropertySet)
301
0
{
302
0
    rPropertySet->setPropertyValue( u"Boundary"_ustr, uno::Any(aRectangle) );
303
304
    // common properties handled by super class
305
0
    XMLImageMapObjectContext::Prepare(rPropertySet);
306
0
}
307
308
namespace {
309
310
class XMLImageMapPolygonContext : public XMLImageMapObjectContext
311
{
312
    OUString sViewBoxString;
313
    OUString sPointsString;
314
315
    bool bViewBoxOK;
316
    bool bPointsOK;
317
318
public:
319
320
    XMLImageMapPolygonContext(
321
        SvXMLImport& rImport,
322
        css::uno::Reference<css::container::XIndexContainer> const & xMap);
323
324
protected:
325
    virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter &) override;
326
327
    virtual void Prepare(
328
        css::uno::Reference<css::beans::XPropertySet> & rPropertySet) override;
329
};
330
331
}
332
333
XMLImageMapPolygonContext::XMLImageMapPolygonContext(
334
    SvXMLImport& rImport,
335
    Reference<XIndexContainer> const & xMap) :
336
0
        XMLImageMapObjectContext(rImport, xMap,
337
0
                                 "com.sun.star.image.ImageMapPolygonObject"),
338
0
        bViewBoxOK(false),
339
0
        bPointsOK(false)
340
0
{
341
0
}
342
343
void XMLImageMapPolygonContext::ProcessAttribute(
344
    const sax_fastparser::FastAttributeList::FastAttributeIter & aIter)
345
0
{
346
0
    switch (aIter.getToken())
347
0
    {
348
0
        case XML_ELEMENT(DRAW, XML_POINTS):
349
0
            sPointsString = aIter.toString();
350
0
            bPointsOK = true;
351
0
            break;
352
0
        case XML_ELEMENT(SVG, XML_VIEWBOX):
353
0
        case XML_ELEMENT(SVG_COMPAT, XML_VIEWBOX):
354
0
            sViewBoxString = aIter.toString();
355
0
            bViewBoxOK = true;
356
0
            break;
357
0
        default:
358
0
            XMLImageMapObjectContext::ProcessAttribute(aIter);
359
0
            break;
360
0
    }
361
362
0
    bValid = bViewBoxOK && bPointsOK;
363
0
}
364
365
void XMLImageMapPolygonContext::Prepare(Reference<XPropertySet> & rPropertySet)
366
0
{
367
    // process view box
368
0
    SdXMLImExViewBox aViewBox(sViewBoxString, GetImport().GetMM100UnitConverter());
369
370
    // get polygon sequence
371
0
    basegfx::B2DPolygon aPolygon;
372
373
0
    if(basegfx::utils::importFromSvgPoints(aPolygon, sPointsString))
374
0
    {
375
0
        if(aPolygon.count())
376
0
        {
377
0
            css::drawing::PointSequence aPointSequence;
378
0
            basegfx::utils::B2DPolygonToUnoPointSequence(aPolygon, aPointSequence);
379
0
            rPropertySet->setPropertyValue(u"Polygon"_ustr, Any(aPointSequence));
380
0
        }
381
0
    }
382
383
    // parent properties
384
0
    XMLImageMapObjectContext::Prepare(rPropertySet);
385
0
}
386
387
namespace {
388
389
class XMLImageMapCircleContext : public XMLImageMapObjectContext
390
{
391
    awt::Point aCenter;
392
    sal_Int32 nRadius;
393
394
    bool bXOK;
395
    bool bYOK;
396
    bool bRadiusOK;
397
398
public:
399
400
    XMLImageMapCircleContext(
401
        SvXMLImport& rImport,
402
        css::uno::Reference<css::container::XIndexContainer> const & xMap);
403
404
protected:
405
    virtual void ProcessAttribute(
406
        const sax_fastparser::FastAttributeList::FastAttributeIter &) override;
407
408
    virtual void Prepare(
409
        css::uno::Reference<css::beans::XPropertySet> & rPropertySet) override;
410
};
411
412
}
413
414
XMLImageMapCircleContext::XMLImageMapCircleContext(
415
    SvXMLImport& rImport,
416
    Reference<XIndexContainer> const & xMap)
417
0
    : XMLImageMapObjectContext(rImport, xMap,
418
0
          "com.sun.star.image.ImageMapCircleObject")
419
0
    , nRadius(0)
420
0
    , bXOK(false)
421
0
    , bYOK(false)
422
0
    , bRadiusOK(false)
423
0
{
424
0
}
425
426
void XMLImageMapCircleContext::ProcessAttribute(
427
    const sax_fastparser::FastAttributeList::FastAttributeIter & aIter)
428
0
{
429
0
    sal_Int32 nTmp;
430
0
    switch (aIter.getToken())
431
0
    {
432
0
        case XML_ELEMENT(SVG, XML_CX):
433
0
        case XML_ELEMENT(SVG_COMPAT, XML_CX):
434
0
            if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp,
435
0
                                                                   aIter.toView()))
436
0
            {
437
0
                aCenter.X = nTmp;
438
0
                bXOK = true;
439
0
            }
440
0
            break;
441
0
        case XML_ELEMENT(SVG, XML_CY):
442
0
        case XML_ELEMENT(SVG_COMPAT, XML_CY):
443
0
            if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp,
444
0
                                                                   aIter.toView()))
445
0
            {
446
0
                aCenter.Y = nTmp;
447
0
                bYOK = true;
448
0
            }
449
0
            break;
450
0
        case XML_ELEMENT(SVG, XML_R):
451
0
        case XML_ELEMENT(SVG_COMPAT, XML_R):
452
0
            if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp,
453
0
                                                                   aIter.toView()))
454
0
            {
455
0
                nRadius = nTmp;
456
0
                bRadiusOK = true;
457
0
            }
458
0
            break;
459
0
        default:
460
0
            XMLImageMapObjectContext::ProcessAttribute(aIter);
461
0
    }
462
463
0
    bValid = bRadiusOK && bXOK && bYOK;
464
0
}
465
466
void XMLImageMapCircleContext::Prepare(
467
    Reference<XPropertySet> & rPropertySet)
468
0
{
469
    // center (x,y)
470
0
    rPropertySet->setPropertyValue( u"Center"_ustr, uno::Any(aCenter) );
471
    // radius
472
0
    rPropertySet->setPropertyValue( u"Radius"_ustr, uno::Any(nRadius) );
473
474
    // common properties handled by super class
475
0
    XMLImageMapObjectContext::Prepare(rPropertySet);
476
0
}
477
478
479
constexpr OUString gsImageMap(u"ImageMap"_ustr);
480
481
XMLImageMapContext::XMLImageMapContext(
482
    SvXMLImport& rImport,
483
    Reference<XPropertySet> const & rPropertySet) :
484
0
        SvXMLImportContext(rImport),
485
0
        xPropertySet(rPropertySet)
486
0
{
487
0
    try
488
0
    {
489
0
        Reference < XPropertySetInfo > xInfo =
490
0
            xPropertySet->getPropertySetInfo();
491
0
        if( xInfo.is() && xInfo->hasPropertyByName( gsImageMap ) )
492
0
            xPropertySet->getPropertyValue(gsImageMap) >>= xImageMap;
493
0
    }
494
0
    catch(const css::uno::Exception& e)
495
0
    {
496
0
        rImport.SetError( XMLERROR_FLAG_WARNING | XMLERROR_API, {}, e.Message, nullptr );
497
0
    }
498
0
}
499
500
XMLImageMapContext::~XMLImageMapContext()
501
0
{
502
0
}
503
504
css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImageMapContext::createFastChildContext(
505
    sal_Int32 nElement,
506
    const css::uno::Reference< css::xml::sax::XFastAttributeList >&  )
507
0
{
508
0
    switch (nElement)
509
0
    {
510
0
        case XML_ELEMENT(DRAW, XML_AREA_RECTANGLE):
511
0
            return new XMLImageMapRectangleContext(
512
0
                GetImport(), xImageMap);
513
0
        case XML_ELEMENT(DRAW, XML_AREA_POLYGON):
514
0
            return new XMLImageMapPolygonContext(
515
0
                GetImport(), xImageMap);
516
0
        case XML_ELEMENT(DRAW, XML_AREA_CIRCLE):
517
0
            return new XMLImageMapCircleContext(
518
0
                GetImport(), xImageMap);
519
0
        default:
520
0
            XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
521
0
    }
522
523
0
    return nullptr;
524
0
}
525
526
void XMLImageMapContext::endFastElement(sal_Int32 )
527
0
{
528
0
    Reference < XPropertySetInfo > xInfo =
529
0
        xPropertySet->getPropertySetInfo();
530
0
    if( xInfo.is() && xInfo->hasPropertyByName( gsImageMap ) )
531
0
        xPropertySet->setPropertyValue(gsImageMap, uno::Any( xImageMap ) );
532
0
}
533
534
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */