Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svtools/source/misc/embedhlp.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 <libxml/xmlwriter.h>
21
22
#include <svtools/embedhlp.hxx>
23
#include <vcl/graph.hxx>
24
#include <vcl/graphicfilter.hxx>
25
#include <vcl/gdimtf.hxx>
26
#include <vcl/outdev.hxx>
27
#include <vcl/gfxlink.hxx>
28
#include <vcl/TypeSerializer.hxx>
29
#include <rtl/ustrbuf.hxx>
30
#include <bitmaps.hlst>
31
32
#include <sal/log.hxx>
33
#include <comphelper/fileformat.h>
34
#include <comphelper/embeddedobjectcontainer.hxx>
35
#include <toolkit/helper/vclunohelper.hxx>
36
#include <unotools/ucbstreamhelper.hxx>
37
#include <unotools/streamwrap.hxx>
38
#include <com/sun/star/chart2/XChartDocument.hpp>
39
#include <com/sun/star/chart2/XCoordinateSystem.hpp>
40
#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
41
#include <com/sun/star/chart2/XDiagram.hpp>
42
#include <com/sun/star/chart2/XChartTypeContainer.hpp>
43
#include <com/sun/star/chart2/XChartType.hpp>
44
#include <tools/globname.hxx>
45
#include <tools/mapunit.hxx>
46
#include <tools/stream.hxx>
47
#include <comphelper/classids.hxx>
48
#include <com/sun/star/util/CloseVetoException.hpp>
49
#include <com/sun/star/util/XModifyListener.hpp>
50
#include <com/sun/star/util/XModifiable.hpp>
51
#include <com/sun/star/embed/Aspects.hpp>
52
#include <com/sun/star/embed/EmbedStates.hpp>
53
#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
54
#include <com/sun/star/embed/XEmbeddedObject.hpp>
55
#include <com/sun/star/embed/XStateChangeListener.hpp>
56
#include <com/sun/star/embed/XLinkageSupport.hpp>
57
#include <com/sun/star/chart2/XDefaultSizeTransmitter.hpp>
58
#include <com/sun/star/qa/XDumper.hpp>
59
#include <embeddedobj/embeddedupdate.hxx>
60
#include <cppuhelper/implbase.hxx>
61
#include <vcl/svapp.hxx>
62
#include <comphelper/diagnose_ex.hxx>
63
#include <tools/debug.hxx>
64
#include <memory>
65
66
using namespace com::sun::star;
67
68
namespace svt {
69
70
namespace {
71
72
class EmbedEventListener_Impl : public ::cppu::WeakImplHelper < embed::XStateChangeListener,
73
                                                                 document::XEventListener,
74
                                                                 util::XModifyListener,
75
                                                                 util::XCloseListener >
76
{
77
public:
78
    EmbeddedObjectRef*          pObject;
79
    sal_Int32                   nState;
80
81
                                explicit EmbedEventListener_Impl( EmbeddedObjectRef* p ) :
82
23.6k
                                    pObject(p)
83
23.6k
                                    , nState(-1)
84
23.6k
                                {}
85
86
    static rtl::Reference<EmbedEventListener_Impl> Create( EmbeddedObjectRef* );
87
88
    virtual void SAL_CALL changingState( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) override;
89
    virtual void SAL_CALL stateChanged( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) override;
90
    virtual void SAL_CALL queryClosing( const lang::EventObject& Source, sal_Bool GetsOwnership ) override;
91
    virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) override;
92
    virtual void SAL_CALL notifyEvent( const document::EventObject& aEvent ) override;
93
    virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) override;
94
    virtual void SAL_CALL modified( const css::lang::EventObject& aEvent ) override;
95
};
96
97
}
98
99
rtl::Reference<EmbedEventListener_Impl> EmbedEventListener_Impl::Create( EmbeddedObjectRef* p )
100
23.6k
{
101
23.6k
    rtl::Reference<EmbedEventListener_Impl> pRet(new EmbedEventListener_Impl( p ));
102
103
23.6k
    if ( p->GetObject().is() )
104
0
    {
105
0
        p->GetObject()->addStateChangeListener( pRet );
106
107
0
        uno::Reference < util::XCloseable > xClose = p->GetObject();
108
0
        DBG_ASSERT( xClose.is(), "Object does not support XCloseable!" );
109
0
        if ( xClose.is() )
110
0
            xClose->addCloseListener( pRet );
111
112
0
        uno::Reference < document::XEventBroadcaster > xBrd = p->GetObject();
113
0
        if ( xBrd.is() )
114
0
            xBrd->addEventListener( pRet );
115
116
0
        pRet->nState = p->GetObject()->getCurrentState();
117
0
        if ( pRet->nState == embed::EmbedStates::RUNNING )
118
0
        {
119
0
            uno::Reference < util::XModifiable > xMod( p->GetObject()->getComponent(), uno::UNO_QUERY );
120
0
            if ( xMod.is() )
121
                // listen for changes in running state (update replacements in case of changes)
122
0
                xMod->addModifyListener( pRet );
123
0
        }
124
0
    }
125
126
23.6k
    return pRet;
127
23.6k
}
128
129
void SAL_CALL EmbedEventListener_Impl::changingState( const lang::EventObject&,
130
                                                    ::sal_Int32,
131
                                                    ::sal_Int32 )
132
0
{
133
0
}
134
135
void SAL_CALL EmbedEventListener_Impl::stateChanged( const lang::EventObject&,
136
                                                    ::sal_Int32 nOldState,
137
                                                    ::sal_Int32 nNewState )
138
0
{
139
0
    SolarMutexGuard aGuard;
140
0
    nState = nNewState;
141
0
    if ( !pObject )
142
0
        return;
143
144
0
    uno::Reference < util::XModifiable > xMod( pObject->GetObject()->getComponent(), uno::UNO_QUERY );
145
0
    if ( nNewState == embed::EmbedStates::RUNNING )
146
0
    {
147
0
        bool bProtected = false;
148
0
        if (pObject->GetIsProtectedHdl().IsSet())
149
0
        {
150
0
            bProtected = pObject->GetIsProtectedHdl().Call(nullptr);
151
0
        }
152
153
        // TODO/LATER: container must be set before!
154
        // When is this event created? Who sets the new container when it changed?
155
0
        if ((pObject->GetViewAspect() != embed::Aspects::MSOLE_ICON)
156
0
            && nOldState != embed::EmbedStates::LOADED && !pObject->IsChart() && !bProtected)
157
            // get new replacement after deactivation
158
0
            pObject->UpdateReplacement();
159
160
0
        if( pObject->IsChart() && nOldState == embed::EmbedStates::UI_ACTIVE )
161
0
        {
162
            //create a new metafile replacement when leaving the edit mode
163
            //for buggy documents where the old image looks different from the correct one
164
0
            if( xMod.is() && !xMod->isModified() )//in case of modification a new replacement will be requested anyhow
165
0
                pObject->UpdateReplacementOnDemand();
166
0
        }
167
168
0
        if ( xMod.is() && nOldState == embed::EmbedStates::LOADED )
169
            // listen for changes (update replacements in case of changes)
170
0
            xMod->addModifyListener( this );
171
0
    }
172
0
    else if ( nNewState == embed::EmbedStates::LOADED )
173
0
    {
174
        // in loaded state we can't listen
175
0
        if ( xMod.is() )
176
0
            xMod->removeModifyListener( this );
177
0
    }
178
0
}
179
180
void SAL_CALL EmbedEventListener_Impl::modified( const lang::EventObject& )
181
0
{
182
0
    SolarMutexGuard aGuard;
183
0
    if ( !(pObject && pObject->GetViewAspect() != embed::Aspects::MSOLE_ICON) )
184
0
        return;
185
186
0
    if ( nState == embed::EmbedStates::RUNNING )
187
0
    {
188
        // updates only necessary in non-active states
189
0
        if( pObject->IsChart() )
190
0
            pObject->UpdateReplacementOnDemand();
191
0
        else
192
0
            pObject->UpdateReplacement();
193
0
    }
194
0
    else if ( nState == embed::EmbedStates::ACTIVE ||
195
0
              nState == embed::EmbedStates::UI_ACTIVE ||
196
0
              nState == embed::EmbedStates::INPLACE_ACTIVE )
197
0
    {
198
        // in case the object is inplace or UI active the replacement image should be updated on demand
199
0
        pObject->UpdateReplacementOnDemand();
200
0
    }
201
0
}
202
203
void SAL_CALL EmbedEventListener_Impl::notifyEvent( const document::EventObject& aEvent )
204
0
{
205
0
    SolarMutexGuard aGuard;
206
207
0
    if ( pObject && aEvent.EventName == "OnVisAreaChanged" && pObject->GetViewAspect() != embed::Aspects::MSOLE_ICON && !pObject->IsChart() )
208
0
    {
209
0
        pObject->UpdateReplacement();
210
0
    }
211
0
}
212
213
void SAL_CALL EmbedEventListener_Impl::queryClosing( const lang::EventObject& Source, sal_Bool )
214
0
{
215
    // An embedded object can be shared between several objects (f.e. for undo purposes)
216
    // the object will not be closed before the last "customer" is destroyed
217
    // Now the EmbeddedObjectRef helper class works like a "lock" on the object
218
0
    if ( pObject && pObject->IsLocked() && Source.Source == pObject->GetObject() )
219
0
        throw util::CloseVetoException();
220
0
}
221
222
void SAL_CALL EmbedEventListener_Impl::notifyClosing( const lang::EventObject& Source )
223
0
{
224
0
    if ( pObject && Source.Source == pObject->GetObject() )
225
0
    {
226
0
        pObject->Clear();
227
0
        pObject = nullptr;
228
0
    }
229
0
}
230
231
void SAL_CALL EmbedEventListener_Impl::disposing( const lang::EventObject& aEvent )
232
0
{
233
0
    if ( pObject && aEvent.Source == pObject->GetObject() )
234
0
    {
235
0
        pObject->Clear();
236
0
        pObject = nullptr;
237
0
    }
238
0
}
239
240
struct EmbeddedObjectRef_Impl
241
{
242
    uno::Reference <embed::XEmbeddedObject> mxObj;
243
244
    rtl::Reference<EmbedEventListener_Impl>     mxListener;
245
    OUString                                    aPersistName;
246
    OUString                                    aMediaType;
247
    comphelper::EmbeddedObjectContainer*        pContainer;
248
    std::optional<Graphic>                      oGraphic;
249
    sal_Int64                                   nViewAspect;
250
    bool                                        bIsLocked:1;
251
    bool                                        bNeedUpdate:1;
252
    bool                                        bUpdating:1;
253
254
    // #i104867#
255
    sal_uInt32                                  mnGraphicVersion;
256
    awt::Size                                   aDefaultSizeForChart_In_100TH_MM;//#i103460# charts do not necessarily have an own size within ODF files, in this case they need to use the size settings from the surrounding frame, which is made available with this member
257
258
    Link<LinkParamNone*, bool> m_aIsProtectedHdl;
259
260
    EmbeddedObjectRef_Impl() :
261
12.8k
        pContainer(nullptr),
262
12.8k
        nViewAspect(embed::Aspects::MSOLE_CONTENT),
263
12.8k
        bIsLocked(false),
264
12.8k
        bNeedUpdate(false),
265
12.8k
        bUpdating(false),
266
12.8k
        mnGraphicVersion(0),
267
12.8k
        aDefaultSizeForChart_In_100TH_MM(awt::Size(8000,7000))
268
12.8k
    {}
269
270
    EmbeddedObjectRef_Impl( const EmbeddedObjectRef_Impl& r ) :
271
11.8k
        mxObj(r.mxObj),
272
11.8k
        aPersistName(r.aPersistName),
273
11.8k
        aMediaType(r.aMediaType),
274
11.8k
        pContainer(r.pContainer),
275
11.8k
        nViewAspect(r.nViewAspect),
276
11.8k
        bIsLocked(r.bIsLocked),
277
11.8k
        bNeedUpdate(r.bNeedUpdate),
278
11.8k
        bUpdating(r.bUpdating),
279
11.8k
        mnGraphicVersion(0),
280
11.8k
        aDefaultSizeForChart_In_100TH_MM(r.aDefaultSizeForChart_In_100TH_MM)
281
11.8k
    {
282
11.8k
        if (r.oGraphic && !r.bNeedUpdate)
283
0
            oGraphic.emplace(*r.oGraphic);
284
11.8k
    }
285
286
    void dumpAsXml(xmlTextWriterPtr pWriter) const
287
0
    {
288
0
        (void)xmlTextWriterStartElement(pWriter, BAD_CAST("EmbeddedObjectRef_Impl"));
289
0
        (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
290
291
0
        (void)xmlTextWriterStartElement(pWriter, BAD_CAST("mxObj"));
292
0
        (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("symbol"),
293
0
                                          BAD_CAST(typeid(*mxObj).name()));
294
0
        css::uno::Reference<css::qa::XDumper> pComponent(
295
0
            mxObj->getComponent(), css::uno::UNO_QUERY);
296
0
        if (pComponent.is())
297
0
        {
298
0
            auto const s = pComponent->dump(u""_ustr);
299
0
            auto const s1 = OUStringToOString(s, RTL_TEXTENCODING_ISO_8859_1); //TODO
300
0
            (void)xmlTextWriterWriteRawLen(
301
0
                pWriter, reinterpret_cast<xmlChar const *>(s1.getStr()), s1.getLength());
302
0
        }
303
0
        (void)xmlTextWriterEndElement(pWriter);
304
305
0
        (void)xmlTextWriterStartElement(pWriter, BAD_CAST("pGraphic"));
306
0
        (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", oGraphic ? &*oGraphic : nullptr);
307
0
        if (oGraphic)
308
0
        {
309
0
            (void)xmlTextWriterWriteAttribute(
310
0
                pWriter, BAD_CAST("is-none"),
311
0
                BAD_CAST(OString::boolean(oGraphic->IsNone()).getStr()));
312
0
        }
313
0
        (void)xmlTextWriterEndElement(pWriter);
314
315
0
        (void)xmlTextWriterEndElement(pWriter);
316
0
    }
317
};
318
319
const uno::Reference <embed::XEmbeddedObject>& EmbeddedObjectRef::operator->() const
320
0
{
321
0
    return mpImpl->mxObj;
322
0
}
323
324
const uno::Reference <embed::XEmbeddedObject>& EmbeddedObjectRef::GetObject() const
325
100k
{
326
100k
    return mpImpl->mxObj;
327
100k
}
328
329
1.08k
EmbeddedObjectRef::EmbeddedObjectRef() : mpImpl(new EmbeddedObjectRef_Impl) {}
330
331
EmbeddedObjectRef::EmbeddedObjectRef( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Int64 nAspect ) :
332
11.7k
    mpImpl(new EmbeddedObjectRef_Impl)
333
11.7k
{
334
11.7k
    mpImpl->nViewAspect = nAspect;
335
11.7k
    mpImpl->mxObj = xObj;
336
11.7k
    mpImpl->mxListener = EmbedEventListener_Impl::Create( this );
337
11.7k
}
338
339
EmbeddedObjectRef::EmbeddedObjectRef( const EmbeddedObjectRef& rObj ) :
340
11.8k
    mpImpl(new EmbeddedObjectRef_Impl(*rObj.mpImpl))
341
11.8k
{
342
11.8k
    mpImpl->mxListener = EmbedEventListener_Impl::Create( this );
343
11.8k
}
344
345
EmbeddedObjectRef::~EmbeddedObjectRef()
346
24.6k
{
347
24.6k
    Clear();
348
24.6k
}
349
350
void EmbeddedObjectRef::Assign( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Int64 nAspect )
351
38
{
352
38
    DBG_ASSERT(!mpImpl->mxObj.is(), "Never assign an already assigned object!");
353
354
38
    Clear();
355
38
    mpImpl->nViewAspect = nAspect;
356
38
    mpImpl->mxObj = xObj;
357
38
    mpImpl->mxListener = EmbedEventListener_Impl::Create( this );
358
359
    //#i103460#
360
38
    if ( IsChart() )
361
0
    {
362
0
        uno::Reference < chart2::XDefaultSizeTransmitter > xSizeTransmitter( xObj, uno::UNO_QUERY );
363
0
        DBG_ASSERT( xSizeTransmitter.is(), "Object does not support XDefaultSizeTransmitter -> will cause #i103460#!" );
364
0
        if( xSizeTransmitter.is() )
365
0
            xSizeTransmitter->setDefaultSize( mpImpl->aDefaultSizeForChart_In_100TH_MM );
366
0
    }
367
38
}
368
369
void EmbeddedObjectRef::Clear()
370
24.7k
{
371
24.7k
    if (mpImpl->mxObj.is() && mpImpl->mxListener.is())
372
0
    {
373
0
        mpImpl->mxObj->removeStateChangeListener(mpImpl->mxListener);
374
375
0
        mpImpl->mxObj->removeCloseListener( mpImpl->mxListener );
376
0
        mpImpl->mxObj->removeEventListener( mpImpl->mxListener );
377
378
0
        if ( mpImpl->bIsLocked )
379
0
        {
380
0
            try
381
0
            {
382
0
                mpImpl->mxObj->changeState(embed::EmbedStates::LOADED);
383
0
                mpImpl->mxObj->close( true );
384
0
            }
385
0
            catch (const util::CloseVetoException&)
386
0
            {
387
                // there's still someone who needs the object!
388
0
            }
389
0
            catch (const uno::Exception&)
390
0
            {
391
0
                TOOLS_WARN_EXCEPTION("svtools.misc", "Error on switching of the object to loaded state and closing");
392
0
            }
393
0
        }
394
0
    }
395
396
24.7k
    if (mpImpl->mxListener.is())
397
23.6k
    {
398
23.6k
        mpImpl->mxListener->pObject = nullptr;
399
23.6k
        mpImpl->mxListener.clear();
400
23.6k
    }
401
402
24.7k
    mpImpl->mxObj = nullptr;
403
24.7k
    mpImpl->pContainer = nullptr;
404
24.7k
    mpImpl->bIsLocked = false;
405
24.7k
    mpImpl->bNeedUpdate = false;
406
24.7k
}
407
408
bool EmbeddedObjectRef::is() const
409
53.6k
{
410
53.6k
    return mpImpl->mxObj.is();
411
53.6k
}
412
413
void EmbeddedObjectRef::AssignToContainer( comphelper::EmbeddedObjectContainer* pContainer, const OUString& rPersistName )
414
12.3k
{
415
12.3k
    mpImpl->pContainer = pContainer;
416
12.3k
    mpImpl->aPersistName = rPersistName;
417
418
12.3k
    if ( mpImpl->oGraphic && !mpImpl->bNeedUpdate && pContainer )
419
0
        SetGraphicToContainer( *mpImpl->oGraphic, *pContainer, mpImpl->aPersistName, OUString() );
420
12.3k
}
421
422
comphelper::EmbeddedObjectContainer* EmbeddedObjectRef::GetContainer() const
423
576
{
424
576
    return mpImpl->pContainer;
425
576
}
426
427
sal_Int64 EmbeddedObjectRef::GetViewAspect() const
428
868
{
429
868
    return mpImpl->nViewAspect;
430
868
}
431
432
void EmbeddedObjectRef::SetViewAspect( sal_Int64 nAspect )
433
973
{
434
973
    mpImpl->nViewAspect = nAspect;
435
973
}
436
437
void EmbeddedObjectRef::Lock( bool bLock )
438
13.4k
{
439
13.4k
    mpImpl->bIsLocked = bLock;
440
13.4k
}
441
442
bool EmbeddedObjectRef::IsLocked() const
443
0
{
444
0
    return mpImpl->bIsLocked;
445
0
}
446
447
void EmbeddedObjectRef::SetIsProtectedHdl(const Link<LinkParamNone*, bool>& rProtectedHdl)
448
0
{
449
0
    mpImpl->m_aIsProtectedHdl = rProtectedHdl;
450
0
}
451
452
const Link<LinkParamNone*, bool> & EmbeddedObjectRef::GetIsProtectedHdl() const
453
0
{
454
0
    return mpImpl->m_aIsProtectedHdl;
455
0
}
456
457
void EmbeddedObjectRef::GetReplacement( bool bUpdate )
458
0
{
459
0
    if ( bUpdate )
460
0
    {
461
        // Do not clear / reset mpImpl->oGraphic, because it would appear as no replacement
462
        // on any call to getReplacementGraphic during the external calls to the OLE object,
463
        // which may release mutexes. Only replace it when done.
464
0
        mpImpl->aMediaType.clear();
465
0
    }
466
0
    else if (mpImpl->oGraphic)
467
0
    {
468
0
        OSL_FAIL("No update, but replacement exists already!");
469
0
        return;
470
0
    }
471
472
0
    std::unique_ptr<SvStream> pGraphicStream(GetGraphicStream( bUpdate ));
473
0
    if (!pGraphicStream && bUpdate && (!mpImpl->oGraphic || mpImpl->oGraphic->IsNone()))
474
0
    {
475
        // We have no old graphic, tried to get an updated one, but that failed. Try to get an old
476
        // graphic instead of having no graphic at all.
477
0
        pGraphicStream = GetGraphicStream(false);
478
0
        SAL_WARN("svtools.misc",
479
0
                 "EmbeddedObjectRef::GetReplacement: failed to get updated graphic stream");
480
0
    }
481
482
0
    if ( pGraphicStream )
483
0
    {
484
0
        GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
485
0
        Graphic aNewGraphic;
486
0
        rGF.ImportGraphic(aNewGraphic, u"", *pGraphicStream);
487
0
        if (!aNewGraphic.IsNone())
488
0
        {
489
0
            mpImpl->oGraphic.emplace(aNewGraphic);
490
0
            mpImpl->mnGraphicVersion++;
491
0
        }
492
0
    }
493
0
}
494
495
const Graphic* EmbeddedObjectRef::GetGraphic() const
496
8
{
497
8
    try
498
8
    {
499
8
        if ( mpImpl->bNeedUpdate )
500
            // bNeedUpdate will be set to false while retrieving new replacement
501
0
            const_cast < EmbeddedObjectRef* >(this)->GetReplacement(true);
502
8
        else if ( !mpImpl->oGraphic )
503
0
            const_cast < EmbeddedObjectRef* >(this)->GetReplacement(false);
504
8
    }
505
8
    catch( const uno::Exception& )
506
8
    {
507
0
        DBG_UNHANDLED_EXCEPTION("svtools.misc", "Something went wrong on getting the graphic");
508
0
    }
509
510
8
    return mpImpl->oGraphic ? &*mpImpl->oGraphic : nullptr;
511
8
}
512
513
Size EmbeddedObjectRef::GetSize( MapMode const * pTargetMapMode ) const
514
7
{
515
7
    MapMode aSourceMapMode( MapUnit::Map100thMM );
516
7
    Size aResult;
517
518
7
    if ( mpImpl->nViewAspect == embed::Aspects::MSOLE_ICON )
519
0
    {
520
0
        const Graphic* pGraphic = GetGraphic();
521
0
        if ( pGraphic )
522
0
        {
523
0
            aSourceMapMode = pGraphic->GetPrefMapMode();
524
0
            aResult = pGraphic->GetPrefSize();
525
0
        }
526
0
        else
527
0
            aResult = Size( 2500, 2500 );
528
0
    }
529
7
    else
530
7
    {
531
7
        awt::Size aSize;
532
533
7
        if (mpImpl->mxObj.is())
534
0
        {
535
0
            try
536
0
            {
537
0
                aSize = mpImpl->mxObj->getVisualAreaSize(mpImpl->nViewAspect);
538
0
            }
539
0
            catch(const embed::NoVisualAreaSizeException&)
540
0
            {
541
0
                SAL_WARN("svtools.misc", "EmbeddedObjectRef::GetSize: no visual area size");
542
0
            }
543
0
            catch (const uno::Exception&)
544
0
            {
545
0
                TOOLS_WARN_EXCEPTION("svtools.misc", "Something went wrong on getting of the size of the object");
546
0
            }
547
548
0
            try
549
0
            {
550
0
                aSourceMapMode = MapMode(VCLUnoHelper::UnoEmbed2VCLMapUnit(mpImpl->mxObj->getMapUnit(mpImpl->nViewAspect)));
551
0
            }
552
0
            catch (const uno::Exception&)
553
0
            {
554
0
                TOOLS_WARN_EXCEPTION("svtools.misc", "Can not get the map mode");
555
0
            }
556
0
        }
557
558
7
        if ( !aSize.Height && !aSize.Width )
559
7
        {
560
7
            SAL_WARN("svtools.misc", "EmbeddedObjectRef::GetSize: empty size, defaulting to 5x5cm");
561
7
            aSize.Width = 5000;
562
7
            aSize.Height = 5000;
563
7
        }
564
565
7
        aResult = Size( aSize.Width, aSize.Height );
566
7
    }
567
568
7
    if ( pTargetMapMode )
569
7
        aResult = OutputDevice::LogicToLogic( aResult, aSourceMapMode, *pTargetMapMode );
570
571
7
    return aResult;
572
7
}
573
574
void EmbeddedObjectRef::SetGraphicStream( const uno::Reference< io::XInputStream >& xInGrStream,
575
                                            const OUString& rMediaType )
576
0
{
577
0
    Graphic aNewGraphic;
578
0
    std::unique_ptr<SvStream> pGraphicStream(::utl::UcbStreamHelper::CreateStream( xInGrStream ));
579
580
0
    if ( pGraphicStream )
581
0
    {
582
0
        GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
583
0
        rGF.ImportGraphic(aNewGraphic, u"", *pGraphicStream);
584
585
0
        if ( mpImpl->pContainer )
586
0
        {
587
0
            pGraphicStream->Seek( 0 );
588
0
            uno::Reference< io::XInputStream > xInSeekGrStream = new ::utl::OSeekableInputStreamWrapper( pGraphicStream.get() );
589
590
0
            mpImpl->pContainer->InsertGraphicStream( xInSeekGrStream, mpImpl->aPersistName, rMediaType );
591
0
        }
592
0
    }
593
594
0
    mpImpl->oGraphic.emplace(aNewGraphic);
595
0
    mpImpl->aMediaType = rMediaType;
596
0
    mpImpl->mnGraphicVersion++;
597
0
    mpImpl->bNeedUpdate = false;
598
0
}
599
600
void EmbeddedObjectRef::SetGraphic( const Graphic& rGraphic, const OUString& rMediaType )
601
131
{
602
131
    mpImpl->oGraphic.emplace( rGraphic );
603
131
    mpImpl->aMediaType = rMediaType;
604
131
    mpImpl->mnGraphicVersion++;
605
606
131
    if ( mpImpl->pContainer )
607
0
        SetGraphicToContainer( rGraphic, *mpImpl->pContainer, mpImpl->aPersistName, rMediaType );
608
609
131
    mpImpl->bNeedUpdate = false;
610
131
}
611
612
std::unique_ptr<SvStream> EmbeddedObjectRef::GetGraphicStream( bool bUpdate ) const
613
0
{
614
0
    DBG_ASSERT( bUpdate || mpImpl->pContainer, "Can't retrieve current graphic!" );
615
0
    uno::Reference < io::XInputStream > xStream;
616
0
    if ( mpImpl->pContainer && !bUpdate )
617
0
    {
618
0
        SAL_INFO( "svtools.misc", "getting stream from container" );
619
        // try to get graphic stream from container storage
620
        // use persist name directly to avoid unordered_map lookup by Reference,
621
        // which can crash on dangling pointers in the map
622
0
        xStream = mpImpl->pContainer->GetGraphicStream(mpImpl->aPersistName, &mpImpl->aMediaType);
623
0
        if ( xStream.is() )
624
0
        {
625
0
            const sal_Int32 nConstBufferSize = 32000;
626
0
            std::unique_ptr<SvMemoryStream> pStream(new SvMemoryStream( 32000, 32000 ));
627
0
            try
628
0
            {
629
0
                sal_Int32 nRead=0;
630
0
                uno::Sequence < sal_Int8 > aSequence ( nConstBufferSize );
631
0
                do
632
0
                {
633
0
                    nRead = xStream->readBytes ( aSequence, nConstBufferSize );
634
0
                    pStream->WriteBytes(aSequence.getConstArray(), nRead);
635
0
                }
636
0
                while ( nRead == nConstBufferSize );
637
0
                pStream->Seek(0);
638
0
                pStream->MakeReadOnly();
639
0
                return pStream;
640
0
            }
641
0
            catch (const uno::Exception&)
642
0
            {
643
0
                DBG_UNHANDLED_EXCEPTION("svtools.misc", "discarding broken embedded object preview");
644
0
                xStream.clear();
645
0
            }
646
0
        }
647
0
    }
648
649
0
    if ( !xStream.is() )
650
0
    {
651
0
        SAL_INFO( "svtools.misc", "getting stream from object" );
652
0
        bool bUpdateAllowed(true);
653
0
        const comphelper::EmbeddedObjectContainer* pContainer = GetContainer();
654
655
0
        if(pContainer)
656
0
        {
657
0
            uno::Reference<embed::XLinkageSupport> const xLinkage(
658
0
                    mpImpl->mxObj, uno::UNO_QUERY);
659
0
            if (xLinkage.is() && xLinkage->isLink())
660
0
            {
661
0
                bUpdateAllowed = pContainer->getUserAllowsLinkUpdate();
662
663
0
            }
664
0
        }
665
666
0
        if (bUpdateAllowed)
667
0
        {
668
            // update wanted or no stream in container storage available
669
0
            xStream = GetGraphicReplacementStream(mpImpl->nViewAspect, mpImpl->mxObj, &mpImpl->aMediaType);
670
671
0
            if(xStream.is())
672
0
            {
673
0
                if (mpImpl->pContainer)
674
0
                {
675
0
                    bool bInsertGraphicStream = true;
676
0
                    uno::Reference<io::XSeekable> xSeekable(xStream, uno::UNO_QUERY);
677
0
                    std::optional<sal_Int64> oPosition;
678
0
                    if (xSeekable.is())
679
0
                    {
680
0
                        oPosition = xSeekable->getPosition();
681
0
                    }
682
0
                    if (bUpdate)
683
0
                    {
684
0
                        std::unique_ptr<SvStream> pResult = utl::UcbStreamHelper::CreateStream(xStream);
685
0
                        if (pResult)
686
0
                        {
687
0
                            GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
688
0
                            Graphic aGraphic;
689
0
                            rGF.ImportGraphic(aGraphic, u"", *pResult);
690
0
                            if (aGraphic.IsNone())
691
0
                            {
692
                                // The graphic is not something we can understand, don't overwrite a
693
                                // potentially working previous graphic.
694
0
                                SAL_WARN("svtools.misc", "EmbeddedObjectRef::GetGraphicStream: failed to parse xStream");
695
0
                                bInsertGraphicStream = false;
696
0
                            }
697
0
                        }
698
0
                    }
699
0
                    if (xSeekable.is() && oPosition.has_value())
700
0
                    {
701
0
                        xSeekable->seek(*oPosition);
702
0
                    }
703
0
                    if (bInsertGraphicStream)
704
0
                    {
705
0
                        mpImpl->pContainer->InsertGraphicStream(xStream,mpImpl->aPersistName,mpImpl->aMediaType);
706
0
                    }
707
0
                }
708
709
0
                std::unique_ptr<SvStream> pResult = ::utl::UcbStreamHelper::CreateStream( xStream );
710
0
                if (pResult && bUpdate)
711
0
                    mpImpl->bNeedUpdate = false;
712
713
0
                return pResult;
714
0
            }
715
0
        }
716
0
    }
717
718
0
    return nullptr;
719
0
}
720
721
void EmbeddedObjectRef::DrawPaintReplacement( const tools::Rectangle &rRect, const OUString &rText, OutputDevice *pOut )
722
0
{
723
0
    MapMode aMM( MapUnit::MapAppFont );
724
0
    Size aAppFontSz = pOut->LogicToLogic( Size( 0, 8 ), &aMM, nullptr );
725
0
    vcl::Font aFnt( u"Noto Sans"_ustr, aAppFontSz );
726
0
    aFnt.SetTransparent( true );
727
0
    aFnt.SetColor( COL_LIGHTRED );
728
0
    aFnt.SetWeight( WEIGHT_BOLD );
729
0
    aFnt.SetFamily( FAMILY_SWISS );
730
731
0
    auto popIt = pOut->ScopedPush();
732
0
    pOut->SetBackground();
733
0
    pOut->SetFont( aFnt );
734
735
0
    Point aPt;
736
737
    // Now scale text such that it fits in the rectangle
738
    // We start with the default size and decrease 1-AppFont
739
0
    for( sal_uInt16 i = 8; i > 2; i-- )
740
0
    {
741
0
        aPt.setX( (rRect.GetWidth()  - pOut->GetTextWidth( rText )) / 2 );
742
0
        aPt.setY( (rRect.GetHeight() - pOut->GetTextHeight()) / 2 );
743
744
0
        bool bTiny = false;
745
0
        if( aPt.X() < 0 )
746
0
        {
747
0
            bTiny = true;
748
0
            aPt.setX( 0 );
749
0
        }
750
0
        if( aPt.Y() < 0 )
751
0
        {
752
0
            bTiny = true;
753
0
            aPt.setY( 0 );
754
0
        }
755
0
        if( bTiny )
756
0
        {
757
            // decrease for small images
758
0
            aFnt.SetFontSize( Size( 0, aAppFontSz.Height() * i / 8 ) );
759
0
            pOut->SetFont( aFnt );
760
0
        }
761
0
        else
762
0
            break;
763
0
    }
764
765
0
    Bitmap aBmp(BMP_PLUGIN);
766
0
    tools::Long nHeight = rRect.GetHeight() - pOut->GetTextHeight();
767
0
    tools::Long nWidth = rRect.GetWidth();
768
0
    if(nHeight > 0 && nWidth > 0 && aBmp.GetSizePixel().Width() > 0)
769
0
    {
770
0
        aPt.setY( nHeight );
771
0
        Point   aP = rRect.TopLeft();
772
0
        Size    aBmpSize = aBmp.GetSizePixel();
773
        // fit bitmap in
774
0
        if( nHeight * 10 / nWidth
775
0
          > aBmpSize.Height() * 10 / aBmpSize.Width() )
776
0
        {
777
            // adjust to the width
778
            // keep proportions
779
0
            tools::Long nH = nWidth * aBmpSize.Height() / aBmpSize.Width();
780
            // center
781
0
            aP.AdjustY((nHeight - nH) / 2 );
782
0
            nHeight = nH;
783
0
        }
784
0
        else
785
0
        {
786
            // adjust to the height
787
            // keep proportions
788
0
            tools::Long nW = nHeight * aBmpSize.Width() / aBmpSize.Height();
789
            // center
790
0
            aP.AdjustX((nWidth - nW) / 2 );
791
0
            nWidth = nW;
792
0
        }
793
794
0
        pOut->DrawBitmap(aP, Size( nWidth, nHeight ), aBmp);
795
0
    }
796
797
0
    pOut->IntersectClipRegion( rRect );
798
0
    aPt += rRect.TopLeft();
799
0
    pOut->DrawText( aPt, rText );
800
0
}
801
802
void EmbeddedObjectRef::DrawShading( const tools::Rectangle &rRect, OutputDevice *pOut )
803
0
{
804
0
    GDIMetaFile * pMtf = pOut->GetConnectMetaFile();
805
0
    if( pMtf && pMtf->IsRecord() )
806
0
        return;
807
808
0
    auto popIt = pOut->ScopedPush();
809
0
    pOut->SetLineColor( COL_BLACK );
810
811
0
    Size aPixSize = pOut->LogicToPixel( rRect.GetSize() );
812
0
    aPixSize.AdjustWidth( -1 );
813
0
    aPixSize.AdjustHeight( -1 );
814
0
    Point aPixViewPos = pOut->LogicToPixel( rRect.TopLeft() );
815
0
    sal_Int32 nMax = aPixSize.Width() + aPixSize.Height();
816
0
    for( sal_Int32 i = 5; i < nMax; i += 5 )
817
0
    {
818
0
        Point a1( aPixViewPos ), a2( aPixViewPos );
819
0
        if( i > aPixSize.Width() )
820
0
            a1 += Point( aPixSize.Width(), i - aPixSize.Width() );
821
0
        else
822
0
            a1 += Point( i, 0 );
823
0
        if( i > aPixSize.Height() )
824
0
            a2 += Point( i - aPixSize.Height(), aPixSize.Height() );
825
0
        else
826
0
            a2 += Point( 0, i );
827
828
0
        pOut->DrawLine( pOut->PixelToLogic( a1 ), pOut->PixelToLogic( a2 ) );
829
0
    }
830
0
}
831
832
bool EmbeddedObjectRef::TryRunningState( const uno::Reference < embed::XEmbeddedObject >& xEmbObj )
833
11.7k
{
834
11.7k
    if ( !xEmbObj.is() )
835
11.7k
        return false;
836
837
0
    try
838
0
    {
839
0
        if ( xEmbObj->getCurrentState() == embed::EmbedStates::LOADED )
840
0
            xEmbObj->changeState( embed::EmbedStates::RUNNING );
841
0
    }
842
0
    catch (const uno::Exception&)
843
0
    {
844
0
        return false;
845
0
    }
846
847
0
    return true;
848
0
}
849
850
void EmbeddedObjectRef::SetGraphicToContainer( const Graphic& rGraphic,
851
                                                comphelper::EmbeddedObjectContainer& aContainer,
852
                                                const OUString& aName,
853
                                                const OUString& aMediaType )
854
0
{
855
0
    SvMemoryStream aStream;
856
0
    aStream.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
857
858
0
    const auto& pGfxLink = rGraphic.GetSharedGfxLink();
859
0
    if (pGfxLink && pGfxLink->IsNative())
860
0
    {
861
0
        if (pGfxLink->ExportNative(aStream))
862
0
        {
863
0
            aStream.Seek(0);
864
0
            uno::Reference <io::XInputStream> xStream = new ::utl::OSeekableInputStreamWrapper(aStream);
865
0
            aContainer.InsertGraphicStream(xStream, aName, aMediaType);
866
0
        }
867
0
        else
868
0
            OSL_FAIL("Export of graphic is failed!");
869
0
    }
870
0
    else
871
0
    {
872
0
        TypeSerializer aSerializer(aStream);
873
0
        aSerializer.writeGraphic(rGraphic);
874
0
        if (aStream.GetError() == ERRCODE_NONE)
875
0
        {
876
0
            aStream.Seek(0);
877
0
            uno::Reference <io::XInputStream> xStream = new ::utl::OSeekableInputStreamWrapper(aStream);
878
0
            aContainer.InsertGraphicStream(xStream, aName, aMediaType);
879
0
        }
880
0
        else
881
0
            OSL_FAIL("Export of graphic is failed!");
882
0
    }
883
0
}
884
885
uno::Reference< io::XInputStream > EmbeddedObjectRef::GetGraphicReplacementStream(
886
                                                                sal_Int64 nViewAspect,
887
                                                                const uno::Reference< embed::XEmbeddedObject >& xObj,
888
                                                                OUString* pMediaType )
889
    noexcept
890
0
{
891
0
    return ::comphelper::EmbeddedObjectContainer::GetGraphicReplacementStream(nViewAspect,xObj,pMediaType);
892
0
}
893
894
bool EmbeddedObjectRef::IsChart(const css::uno::Reference < css::embed::XEmbeddedObject >& xObj)
895
0
{
896
0
    SvGlobalName aObjClsId(xObj->getClassID());
897
0
    return SvGlobalName(SO3_SCH_CLASSID_30) == aObjClsId
898
0
        || SvGlobalName(SO3_SCH_CLASSID_40) == aObjClsId
899
0
        || SvGlobalName(SO3_SCH_CLASSID_50) == aObjClsId
900
0
        || SvGlobalName(SO3_SCH_CLASSID_60) == aObjClsId;
901
0
}
902
903
void EmbeddedObjectRef::UpdateReplacement( bool bUpdateOle )
904
0
{
905
0
    if (mpImpl->bUpdating)
906
0
    {
907
0
        SAL_WARN("svtools.misc", "UpdateReplacement called while UpdateReplacement already underway");
908
0
        return;
909
0
    }
910
0
    mpImpl->bUpdating = true;
911
0
    UpdateOleObject( bUpdateOle );
912
0
    GetReplacement(true);
913
0
    UpdateOleObject( false );
914
0
    mpImpl->bUpdating = false;
915
0
}
916
917
void EmbeddedObjectRef::UpdateOleObject( bool bUpdateOle )
918
0
{
919
0
    ::embeddedobj::EmbeddedUpdate* pObj = dynamic_cast<::embeddedobj::EmbeddedUpdate*> (GetObject().get());
920
0
    if( pObj )
921
0
        pObj->SetOleState( bUpdateOle );
922
0
}
923
924
925
void EmbeddedObjectRef::UpdateReplacementOnDemand()
926
0
{
927
0
    mpImpl->bNeedUpdate = true;
928
929
0
    if( mpImpl->pContainer )
930
0
    {
931
        //remove graphic from container thus a new up to date one is requested on save
932
0
        mpImpl->pContainer->RemoveGraphicStream( mpImpl->aPersistName );
933
0
    }
934
0
}
935
936
bool EmbeddedObjectRef::IsChart() const
937
56
{
938
    //todo maybe for 3.0:
939
    //if the changes work good for chart
940
    //we should apply them for all own ole objects
941
942
    //#i83708# #i81857# #i79578# request an ole replacement image only if really necessary
943
    //as this call can be very expensive and does block the user interface as long at it takes
944
945
56
    if (!mpImpl->mxObj.is())
946
56
        return false;
947
948
0
    return EmbeddedObjectRef::IsChart(mpImpl->mxObj);
949
56
}
950
951
// MT: Only used for getting accessible attributes, which are not localized
952
OUString EmbeddedObjectRef::GetChartType()
953
0
{
954
0
    OUStringBuffer Style;
955
0
    if ( mpImpl->mxObj.is() )
956
0
    {
957
0
        if ( IsChart() )
958
0
        {
959
0
            if ( svt::EmbeddedObjectRef::TryRunningState( mpImpl->mxObj ) )
960
0
            {
961
0
                uno::Reference< chart2::XChartDocument > xChart( mpImpl->mxObj->getComponent(), uno::UNO_QUERY );
962
0
                if (xChart.is())
963
0
                {
964
0
                    uno::Reference< chart2::XDiagram > xDiagram( xChart->getFirstDiagram());
965
0
                    if( ! xDiagram.is())
966
0
                        return OUString();
967
0
                    uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW );
968
0
                    const uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems());
969
                    // IA2 CWS. Unused: int nCoordinateCount = aCooSysSeq.getLength();
970
0
                    bool bGetChartType = false;
971
0
                    for( const auto& rCooSys : aCooSysSeq )
972
0
                    {
973
0
                        uno::Reference< chart2::XChartTypeContainer > xCTCnt( rCooSys, uno::UNO_QUERY_THROW );
974
0
                        const uno::Sequence< uno::Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes());
975
0
                        int nDimesionCount = rCooSys->getDimension();
976
0
                        if( nDimesionCount == 3 )
977
0
                            Style.append("3D ");
978
0
                        else
979
0
                            Style.append("2D ");
980
0
                        for( const auto& rChartType : aChartTypes )
981
0
                        {
982
0
                            OUString strChartType = rChartType->getChartType();
983
0
                            if (strChartType == "com.sun.star.chart2.AreaChartType")
984
0
                            {
985
0
                                Style.append("Areas");
986
0
                                bGetChartType = true;
987
0
                            }
988
0
                            else if (strChartType == "com.sun.star.chart2.BarChartType")
989
0
                            {
990
0
                                Style.append("Bars");
991
0
                                bGetChartType = true;
992
0
                            }
993
0
                            else if (strChartType == "com.sun.star.chart2.ColumnChartType")
994
0
                            {
995
0
                                uno::Reference< beans::XPropertySet > xProp( rCooSys, uno::UNO_QUERY );
996
0
                                if( xProp.is())
997
0
                                {
998
0
                                    bool bCurrent = false;
999
0
                                    if( xProp->getPropertyValue( u"SwapXAndYAxis"_ustr ) >>= bCurrent )
1000
0
                                    {
1001
0
                                        if (bCurrent)
1002
0
                                            Style.append("Bars");
1003
0
                                        else
1004
0
                                            Style.append("Columns");
1005
0
                                        bGetChartType = true;
1006
0
                                    }
1007
0
                                }
1008
0
                            }
1009
0
                            else if (strChartType == "com.sun.star.chart2.LineChartType")
1010
0
                            {
1011
0
                                Style.append("Lines");
1012
0
                                bGetChartType = true;
1013
0
                            }
1014
0
                            else if (strChartType == "com.sun.star.chart2.ScatterChartType")
1015
0
                            {
1016
0
                                Style.append("XY Chart");
1017
0
                                bGetChartType = true;
1018
0
                            }
1019
0
                            else if (strChartType == "com.sun.star.chart2.PieChartType")
1020
0
                            {
1021
0
                                Style.append("Pies");
1022
0
                                bGetChartType = true;
1023
0
                            }
1024
0
                            else if (strChartType == "com.sun.star.chart2.NetChartType")
1025
0
                            {
1026
0
                                Style.append("Radar");
1027
0
                                bGetChartType = true;
1028
0
                            }
1029
0
                            else if (strChartType == "com.sun.star.chart2.CandleStickChartType")
1030
0
                            {
1031
0
                                Style.append("Candle Stick Chart");
1032
0
                                bGetChartType = true;
1033
0
                            }
1034
0
                            if (bGetChartType)
1035
0
                                return Style.toString();
1036
0
                        }
1037
0
                    }
1038
0
                }
1039
0
            }
1040
0
        }
1041
0
    }
1042
0
    return Style.toString();
1043
0
}
1044
1045
// #i104867#
1046
sal_uInt32 EmbeddedObjectRef::getGraphicVersion() const
1047
0
{
1048
0
    return mpImpl->mnGraphicVersion;
1049
0
}
1050
1051
void EmbeddedObjectRef::SetDefaultSizeForChart( const Size& rSizeIn_100TH_MM )
1052
0
{
1053
    //#i103460# charts do not necessarily have an own size within ODF files,
1054
    //for this case they need to use the size settings from the surrounding frame,
1055
    //which is made available with this method
1056
1057
0
    mpImpl->aDefaultSizeForChart_In_100TH_MM = awt::Size( rSizeIn_100TH_MM.getWidth(), rSizeIn_100TH_MM.getHeight() );
1058
1059
0
    uno::Reference<chart2::XDefaultSizeTransmitter> xSizeTransmitter(mpImpl->mxObj, uno::UNO_QUERY);
1060
0
    DBG_ASSERT( xSizeTransmitter.is(), "Object does not support XDefaultSizeTransmitter -> will cause #i103460#!" );
1061
0
    if( xSizeTransmitter.is() )
1062
0
        xSizeTransmitter->setDefaultSize( mpImpl->aDefaultSizeForChart_In_100TH_MM );
1063
0
}
1064
1065
void EmbeddedObjectRef::dumpAsXml(xmlTextWriterPtr pWriter) const
1066
0
{
1067
0
    (void)xmlTextWriterStartElement(pWriter, BAD_CAST("EmbeddedObjectRef"));
1068
0
    (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
1069
1070
0
    mpImpl->dumpAsXml(pWriter);
1071
1072
0
    (void)xmlTextWriterEndElement(pWriter);
1073
0
}
1074
1075
} // namespace svt
1076
1077
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */