Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svl/source/items/poolitem.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 <svl/poolitem.hxx>
21
#include <tools/mapunit.hxx>
22
#include <unotools/intlwrapper.hxx>
23
#include <unotools/syslocale.hxx>
24
#include <osl/diagnose.h>
25
#include <sal/log.hxx>
26
#include <libxml/xmlwriter.h>
27
#include <tools/XmlWriter.hxx>
28
#include <typeinfo>
29
#include <boost/property_tree/ptree.hpp>
30
31
#ifdef DBG_UTIL
32
#include <unordered_set>
33
#endif
34
35
//////////////////////////////////////////////////////////////////////////////
36
// list of classes derived from SfxPoolItem
37
// removed, but use 'grep DECLARE_ITEM_TYPE_FUNCTION' to get a complete list
38
// of Items that may get incarnated during office runtime
39
//////////////////////////////////////////////////////////////////////////////
40
41
#ifdef DBG_UTIL
42
// static size_t nAllocatedSfxPoolItemCount(0);
43
static size_t nUsedSfxPoolItemCount(0);
44
size_t getUsedSfxPoolItemCount() { return nUsedSfxPoolItemCount; }
45
static std::unordered_set<const SfxPoolItem*>& incarnatedSfxPoolItems()
46
{
47
    // Deferred instantiation to avoid initialization-order-fiasco:
48
    static std::unordered_set<const SfxPoolItem*> items;
49
    return items;
50
}
51
size_t getAllocatedSfxPoolItemCount()
52
{
53
    size_t aRetval(0);
54
55
    // count globally allocated Items. Exclude Static/DynamicDefaults to
56
    // get the number without the PoolDefaultItems that will be freed with
57
    // the Pool. This also excludes the two InvalidOrDisabledItem's used
58
    // for INVALID_POOL_ITEM/DISABLED_POOL_ITEM
59
    for (const auto& rCandidate : incarnatedSfxPoolItems())
60
        if (!rCandidate->isStaticDefault() && !rCandidate->isDynamicDefault())
61
            aRetval++;
62
    return aRetval;
63
}
64
void listAllocatedSfxPoolItems()
65
{
66
    SAL_INFO("svl.items", "ITEM: List of still allocated SfxPoolItems:");
67
    for (const auto& rCandidate : incarnatedSfxPoolItems())
68
    {
69
        if (!rCandidate->isStaticDefault() && !rCandidate->isDynamicDefault())
70
            SAL_INFO("svl.items", "  ITEM: WhichID: " << rCandidate->Which() << "  SerialNumber: "
71
                                                      << rCandidate->getSerialNumber()
72
                                                      << "  Class: " << typeid(*rCandidate).name());
73
    }
74
}
75
#endif
76
77
const SfxPoolItem* DefaultItemInstanceManager::find(const SfxPoolItem& rItem) const
78
30.9M
{
79
30.9M
    auto it = maRegistered.find(rItem.Which());
80
30.9M
    if (it == maRegistered.end())
81
639
        return nullptr;
82
30.9M
    for (const auto& rCandidate : it->second)
83
68.0M
        if (*rCandidate == rItem)
84
26.2M
            return rCandidate;
85
86
4.75M
    return nullptr;
87
30.9M
}
88
89
115M
ItemInstanceManager* SfxPoolItem::getItemInstanceManager() const { return nullptr; }
90
91
SfxPoolItem::SfxPoolItem(sal_uInt16 const nWhich)
92
777M
    : m_nRefCount(0)
93
777M
    , m_nWhich(nWhich)
94
// , m_eItemType(eType)
95
#ifdef DBG_UTIL
96
    , m_nSerialNumber(nUsedSfxPoolItemCount)
97
#endif
98
777M
    , m_bStaticDefault(false)
99
777M
    , m_bDynamicDefault(false)
100
777M
    , m_bIsSetItem(false)
101
777M
    , m_bShareable(true)
102
777M
    , m_bNameOrIndex(false)
103
#ifdef DBG_UTIL
104
    , m_bDeleted(false)
105
#endif
106
777M
{
107
#ifdef DBG_UTIL
108
    // nAllocatedSfxPoolItemCount++;
109
    nUsedSfxPoolItemCount++;
110
    incarnatedSfxPoolItems().insert(this);
111
#endif
112
777M
    assert(nWhich <= SHRT_MAX);
113
777M
}
114
115
SfxPoolItem::~SfxPoolItem()
116
777M
{
117
#ifdef DBG_UTIL
118
    // nAllocatedSfxPoolItemCount--;
119
    incarnatedSfxPoolItems().erase(this);
120
    m_bDeleted = true;
121
#endif
122
777M
    assert((m_nRefCount == 0) && "destroying item in use");
123
777M
}
124
125
bool SfxPoolItem::operator==(const SfxPoolItem& rCmp) const
126
9.70M
{
127
9.70M
    SAL_WARN_IF(rCmp.ItemType() != ItemType(), "svl",
128
9.70M
                "comparing different pool item subclasses " << typeid(rCmp).name() << " && "
129
9.70M
                                                            << typeid(*this).name());
130
9.70M
    assert(rCmp.ItemType() == ItemType() && "comparing different pool item subclasses");
131
9.70M
    return true;
132
9.70M
}
133
134
8.77M
bool SfxPoolItem::supportsHashCode() const { return false; }
135
136
size_t SfxPoolItem::hashCode() const
137
0
{
138
0
    assert(false
139
0
           && "this should never be called, classes should implement both supportsHashCode() and "
140
0
              "hashCode(), or neither");
141
0
    return 0;
142
0
}
143
144
/**
145
 * This virtual method allows to get a textual representation of the value
146
 * for the SfxPoolItem subclasses. It should be overridden by all UI-relevant
147
 * SfxPoolItem subclasses.
148
 *
149
 * Because the unit of measure of the value in the SfxItemPool is only
150
 * queryable via @see SfxItemPool::GetMetric(sal_uInt16) const (and not
151
 * via the SfxPoolItem instance or subclass, the own unit of measure is
152
 * passed to 'eCoreMetric'.
153
 *
154
 * The corresponding unit of measure is passed as 'ePresentationMetric'.
155
 *
156
 *
157
 * @return SfxItemPresentation     SfxItemPresentation::Nameless
158
 *                                 A textual representation (if applicable
159
 *                                 with a unit of measure) could be created,
160
 *                                 but it doesn't contain any semantic meaning
161
 *
162
 *                                 SfxItemPresentation::Complete
163
 *                                 A complete textual representation could be
164
 *                                 created with semantic meaning (if applicable
165
 *                                 with unit of measure)
166
 *
167
 * Example:
168
 *
169
 *    pSvxFontItem->GetPresentation( SFX_PRESENTATION_NAMELESS, ... )
170
 *      "12pt" with return SfxItemPresentation::Nameless
171
 *
172
 *    pSvxColorItem->GetPresentation( SFX_PRESENTATION_COMPLETE, ... )
173
 *        "red" with return SfxItemPresentation::Nameless
174
 *        Because the SvxColorItem does not know which color it represents
175
 *        it cannot provide a name, which is communicated by the return value
176
 *
177
 *    pSvxBorderItem->GetPresentation( SFX_PRESENTATION_COMPLETE, ... )
178
 *        "1cm top border, 2cm left border, 0.2cm bottom border, ..."
179
 */
180
bool SfxPoolItem::GetPresentation(
181
    SfxItemPresentation /*ePresentation*/, // IN:  how we should format
182
    MapUnit /*eCoreMetric*/, // IN:  current metric of the SfxPoolItems
183
    MapUnit /*ePresentationMetric*/, // IN:  target metric of the presentation
184
    OUString& /*rText*/, // OUT: textual representation
185
    const IntlWrapper&) const
186
0
{
187
0
    return false;
188
0
}
189
190
void SfxPoolItem::dumpAsXml(xmlTextWriterPtr pWriter) const
191
0
{
192
0
    tools::XmlWriter aWriter(pWriter);
193
0
    aWriter.startElement("SfxPoolItem");
194
0
    aWriter.attribute("ptr", reinterpret_cast<sal_IntPtr>(this));
195
0
    aWriter.attribute("whichId", Which());
196
0
    aWriter.attribute("typeName", typeid(*this).name());
197
198
0
    OUString rText;
199
0
    IntlWrapper aIntlWrapper(SvtSysLocale().GetUILanguageTag());
200
0
    if (GetPresentation(SfxItemPresentation::Complete, MapUnit::Map100thMM, MapUnit::Map100thMM,
201
0
                        rText, aIntlWrapper))
202
0
    {
203
0
        aWriter.attribute("presentation", rText);
204
0
    }
205
0
    aWriter.endElement();
206
0
}
207
208
boost::property_tree::ptree SfxPoolItem::dumpAsJSON() const
209
0
{
210
0
    boost::property_tree::ptree aTree;
211
0
    return aTree;
212
0
}
213
214
std::unique_ptr<SfxPoolItem> SfxPoolItem::CloneSetWhich(sal_uInt16 nNewWhich) const
215
10.8M
{
216
10.8M
    std::unique_ptr<SfxPoolItem> pItem(Clone());
217
10.8M
    pItem->SetWhich(nNewWhich);
218
10.8M
    return pItem;
219
10.8M
}
220
221
0
void SfxPoolItem::ScaleMetrics(tools::Long /*lMult*/, tools::Long /*lDiv*/) {}
222
223
0
bool SfxPoolItem::HasMetrics() const { return false; }
224
225
bool SfxPoolItem::QueryValue(css::uno::Any&, sal_uInt8) const
226
0
{
227
0
    OSL_FAIL("There is no implementation for QueryValue for this item!");
228
0
    return false;
229
0
}
230
231
bool SfxPoolItem::PutValue(const css::uno::Any&, sal_uInt8)
232
0
{
233
0
    OSL_FAIL("There is no implementation for PutValue for this item!");
234
0
    return false;
235
0
}
236
237
bool areSfxPoolItemPtrsEqual(const SfxPoolItem* pItem1, const SfxPoolItem* pItem2)
238
18.0k
{
239
#ifdef DBG_UTIL
240
    if (nullptr != pItem1 && nullptr != pItem2 && pItem1->Which() == pItem2->Which()
241
        && static_cast<const void*>(pItem1) != static_cast<const void*>(pItem2)
242
        && typeid(*pItem1) == typeid(*pItem2) && *pItem1 == *pItem2)
243
    {
244
        SAL_INFO("svl.items", "ITEM: PtrCompare != ContentCompare (!)");
245
    }
246
#endif
247
248
    // cast to void* to not trigger [loplugin:itemcompare]
249
18.0k
    return (static_cast<const void*>(pItem1) == static_cast<const void*>(pItem2));
250
18.0k
}
251
252
bool SfxPoolItem::areSame(const SfxPoolItem* pItem1, const SfxPoolItem* pItem2)
253
132M
{
254
132M
    if (pItem1 == pItem2)
255
        // pointer compare, this handles already
256
        // nullptr, INVALID_POOL_ITEM, DISABLED_POOL_ITEM
257
        // and if any Item is indeed handed over twice
258
98.9M
        return true;
259
260
33.2M
    if (nullptr == pItem1 || nullptr == pItem2)
261
        // one ptr is nullptr, not both, that would
262
        // have triggered above
263
1.00k
        return false;
264
265
33.2M
    if (pItem1->Which() != pItem2->Which())
266
        // WhichIDs differ (fast)
267
0
        return false;
268
269
33.2M
    if (pItem1->ItemType() != pItem2->ItemType())
270
        // types differ (fast)
271
0
        return false;
272
273
    // return content compare using operator== at last
274
33.2M
    return *pItem1 == *pItem2;
275
33.2M
}
276
277
bool SfxPoolItem::areSame(const SfxPoolItem& rItem1, const SfxPoolItem& rItem2)
278
115M
{
279
115M
    if (&rItem1 == &rItem2)
280
        // still use pointer compare, this handles already
281
        // nullptr, INVALID_POOL_ITEM, SfxVoidItem
282
        // and if any Item is indeed handed over twice
283
59.4M
        return true;
284
285
55.7M
    if (rItem1.Which() != rItem2.Which())
286
        // WhichIDs differ (fast)
287
17.5M
        return false;
288
289
38.2M
    if (rItem1.ItemType() != rItem2.ItemType())
290
        // types differ (fast)
291
0
        return false;
292
293
    // return content compare using operator== at last
294
38.2M
    return rItem1 == rItem2;
295
38.2M
}
296
297
namespace
298
{
299
// tdf#164745 make InvalidItem and DisabledItem two classes to
300
// avoid that op== sees them as equal
301
class InvalidItem final : public SfxPoolItem
302
{
303
0
    virtual bool operator==(const SfxPoolItem&) const override { return true; }
304
0
    virtual SfxPoolItem* Clone(SfxItemPool*) const override { return nullptr; }
305
306
public:
307
    // make it StaticDefaultItem to process similar to these
308
    // which is plausible (never change and are not allowed to)
309
    DECLARE_ITEM_TYPE_FUNCTION(InvalidItem)
310
    InvalidItem()
311
110
        : SfxPoolItem(0)
312
110
    {
313
110
        setStaticDefault();
314
110
    }
315
};
316
class DisabledItem final : public SfxPoolItem
317
{
318
0
    virtual bool operator==(const SfxPoolItem&) const override { return true; }
319
0
    virtual SfxPoolItem* Clone(SfxItemPool*) const override { return nullptr; }
320
321
public:
322
    // make it StaticDefaultItem to process similar to these
323
    // which is plausible (never change and are not allowed to)
324
    DECLARE_ITEM_TYPE_FUNCTION(DisabledItem)
325
    DisabledItem()
326
110
        : SfxPoolItem(0)
327
110
    {
328
110
        setStaticDefault();
329
110
    }
330
};
331
InvalidItem aInvalidItem;
332
DisabledItem aDisabledItem;
333
}
334
335
SfxPoolItem const* const INVALID_POOL_ITEM = &aInvalidItem;
336
SfxPoolItem const* const DISABLED_POOL_ITEM = &aDisabledItem;
337
338
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */