Coverage Report

Created: 2026-07-10 11:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/include/svl/ondemand.hxx
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
#pragma once
21
22
#include <com/sun/star/uno/Reference.hxx>
23
#include <i18nlangtag/lang.h>
24
#include <i18nutil/transliteration.hxx>
25
#include <unotools/syslocale.hxx>
26
#include <unotools/localedatawrapper.hxx>
27
#include <unotools/calendarwrapper.hxx>
28
#include <unotools/transliterationwrapper.hxx>
29
#include <unotools/nativenumberwrapper.hxx>
30
#include <unotools/charclass.hxx>
31
#include <optional>
32
33
/*
34
    On demand instantiation and initialization of several i18n wrappers,
35
    helping the number formatter to not perform worse than it already does.
36
 */
37
38
/** @short
39
    Switch between LANGUAGE_SYSTEM and LANGUAGE_ENGLISH_US and any other
40
    LocaleDataWrapper.
41
    SvNumberformatter uses it upon switching locales.
42
43
    @descr
44
    Avoids reloading and analysing of locale data again and again.
45
46
    @ATTENTION
47
    If the default ctor is used the init() method MUST be called before
48
    accessing any locale data. The passed parameters Locale and LanguageType
49
    must match each other.
50
 */
51
52
class OnDemandLocaleDataWrapper
53
{
54
    SvtSysLocale aSysLocale;
55
    LanguageType eCurrentLanguage;
56
    LanguageType eLastAnyLanguage;
57
    const LocaleDataWrapper* mpEnglish{ nullptr };
58
    const LocaleDataWrapper* mpAny{ nullptr };
59
    int nCurrent; // 0 == system, 1 == english, 2 == any
60
    bool bInitialized;
61
62
public:
63
    OnDemandLocaleDataWrapper()
64
854k
        : eLastAnyLanguage(LANGUAGE_DONTKNOW)
65
854k
        , nCurrent(0)
66
854k
        , bInitialized(false)
67
854k
    {
68
854k
        eCurrentLanguage = LANGUAGE_SYSTEM;
69
854k
    }
70
71
0
    bool isInitialized() const { return bInitialized; }
72
73
    void init(const LanguageTag& rLanguageTag)
74
190k
    {
75
190k
        changeLocale(rLanguageTag);
76
190k
        bInitialized = true;
77
190k
    }
78
79
    void changeLocale(const LanguageTag& rLanguageTag)
80
1.93M
    {
81
1.93M
        LanguageType eLang = rLanguageTag.getLanguageType(false);
82
1.93M
        if (eLang == LANGUAGE_SYSTEM)
83
906k
            nCurrent = 0;
84
1.02M
        else if (eLang == LANGUAGE_ENGLISH_US)
85
596k
        {
86
596k
            if (!mpEnglish)
87
28.9k
                mpEnglish = LocaleDataWrapper::get(rLanguageTag);
88
596k
            nCurrent = 1;
89
596k
        }
90
428k
        else
91
428k
        {
92
428k
            if (!mpAny)
93
13.3k
            {
94
13.3k
                mpAny = LocaleDataWrapper::get(rLanguageTag);
95
13.3k
                eLastAnyLanguage = eLang;
96
13.3k
            }
97
415k
            else if (eLastAnyLanguage != eLang)
98
262k
            {
99
262k
                mpAny = LocaleDataWrapper::get(rLanguageTag);
100
262k
                eLastAnyLanguage = eLang;
101
262k
            }
102
428k
            nCurrent = 2;
103
428k
        }
104
1.93M
        eCurrentLanguage = eLang;
105
1.93M
    }
106
107
2.32k
    LanguageType getCurrentLanguage() const { return eCurrentLanguage; }
108
109
    const LocaleDataWrapper* get() const
110
262M
    {
111
262M
        switch (nCurrent)
112
262M
        {
113
163M
            case 0:
114
163M
                return &aSysLocale.GetLocaleData();
115
24.9M
            case 1:
116
24.9M
                return mpEnglish;
117
74.1M
            case 2:
118
74.1M
                return mpAny;
119
0
            default:
120
0
                assert(false);
121
0
                return nullptr;
122
262M
        }
123
262M
    }
124
1.77M
    const LocaleDataWrapper* operator->() const { return get(); }
125
277k
    const LocaleDataWrapper& operator*() const { return *get(); }
126
};
127
128
/** Load a calendar only if it's needed. Keep calendar for "en-US" locale
129
    separately, as there can be alternation between locale dependent and
130
    locale independent formats.
131
    SvNumberformatter uses it upon switching locales.
132
133
    @ATTENTION If the default ctor is used the init() method MUST be called
134
    before accessing the calendar.
135
 */
136
class OnDemandCalendarWrapper
137
{
138
    css::uno::Reference<css::uno::XComponentContext> m_xContext;
139
    css::lang::Locale aEnglishLocale;
140
    css::lang::Locale aLocale;
141
    mutable css::lang::Locale aLastAnyLocale;
142
    mutable std::optional<CalendarWrapper> moEnglish;
143
    mutable std::optional<CalendarWrapper> moAny;
144
145
public:
146
    OnDemandCalendarWrapper()
147
190k
    {
148
190k
        LanguageTag aEnglishLanguageTag(LANGUAGE_ENGLISH_US);
149
190k
        aEnglishLocale = aEnglishLanguageTag.getLocale();
150
190k
        aLastAnyLocale = aEnglishLocale;
151
190k
    }
152
153
    void init(const css::uno::Reference<css::uno::XComponentContext>& rxContext,
154
              const css::lang::Locale& rLocale)
155
190k
    {
156
190k
        m_xContext = rxContext;
157
190k
        changeLocale(rLocale);
158
190k
        moEnglish.reset();
159
190k
        moAny.reset();
160
190k
    }
161
162
1.84M
    void changeLocale(const css::lang::Locale& rLocale) { aLocale = rLocale; }
163
164
    CalendarWrapper* get() const
165
4.88M
    {
166
4.88M
        CalendarWrapper* pPtr;
167
4.88M
        if (aLocale == aEnglishLocale)
168
4.60M
        {
169
4.60M
            if (!moEnglish)
170
59.7k
            {
171
59.7k
                moEnglish.emplace(m_xContext);
172
59.7k
                moEnglish->loadDefaultCalendar(aEnglishLocale);
173
59.7k
            }
174
4.60M
            pPtr = &*moEnglish;
175
4.60M
        }
176
286k
        else
177
286k
        {
178
286k
            if (!moAny)
179
4.40k
            {
180
4.40k
                moAny.emplace(m_xContext);
181
4.40k
                moAny->loadDefaultCalendar(aLocale);
182
4.40k
                aLastAnyLocale = aLocale;
183
4.40k
            }
184
282k
            else if (aLocale != aLastAnyLocale)
185
50.2k
            {
186
50.2k
                moAny->loadDefaultCalendar(aLocale);
187
50.2k
                aLastAnyLocale = aLocale;
188
50.2k
            }
189
286k
            pPtr = &*moAny;
190
286k
        }
191
4.88M
        return pPtr;
192
4.88M
    }
193
};
194
195
/** Load a transliteration only if it's needed.
196
    SvNumberformatter uses it upon switching locales.
197
    @ATTENTION If the default ctor is used the init() method MUST be called
198
    before accessing the transliteration.
199
 */
200
class OnDemandTransliterationWrapper
201
{
202
    css::uno::Reference<css::uno::XComponentContext> m_xContext;
203
    LanguageType eLanguage;
204
    TransliterationFlags nType;
205
    mutable std::optional<::utl::TransliterationWrapper> moTransliterate;
206
    mutable bool bValid;
207
    bool bInitialized;
208
209
public:
210
    OnDemandTransliterationWrapper()
211
854k
        : eLanguage(LANGUAGE_SYSTEM)
212
854k
        , nType(TransliterationFlags::NONE)
213
854k
        , bValid(false)
214
854k
        , bInitialized(false)
215
854k
    {
216
854k
    }
217
218
0
    bool isInitialized() const { return bInitialized; }
219
220
    void init(const css::uno::Reference<css::uno::XComponentContext>& rxContext, LanguageType eLang)
221
190k
    {
222
190k
        m_xContext = rxContext;
223
190k
        nType = TransliterationFlags::IGNORE_CASE;
224
190k
        changeLocale(eLang);
225
190k
        moTransliterate.reset();
226
190k
        bInitialized = true;
227
190k
    }
228
229
    void changeLocale(LanguageType eLang)
230
1.84M
    {
231
1.84M
        bValid = false;
232
1.84M
        eLanguage = eLang;
233
1.84M
    }
234
235
    const ::utl::TransliterationWrapper* get() const
236
374k
    {
237
374k
        if (!bValid)
238
141k
        {
239
141k
            if (!moTransliterate)
240
7.34k
                moTransliterate.emplace(m_xContext, nType);
241
141k
            moTransliterate->loadModuleIfNeeded(eLanguage);
242
141k
            bValid = true;
243
141k
        }
244
374k
        return &*moTransliterate;
245
374k
    }
246
247
62.6k
    const ::utl::TransliterationWrapper* operator->() const { return get(); }
248
};
249
250
/** Load a native number service wrapper only if it's needed.
251
    SvNumberformatter uses it.
252
 */
253
class OnDemandNativeNumberWrapper
254
{
255
    css::uno::Reference<css::uno::XComponentContext> m_xContext;
256
    mutable std::optional<NativeNumberWrapper> moNativeNumber;
257
258
public:
259
    OnDemandNativeNumberWrapper(const css::uno::Reference<css::uno::XComponentContext>& rContext)
260
141k
        : m_xContext(rContext)
261
141k
    {
262
141k
    }
263
264
    NativeNumberWrapper& get() const
265
11.4M
    {
266
11.4M
        if (!moNativeNumber)
267
141k
            moNativeNumber.emplace(m_xContext);
268
11.4M
        return *moNativeNumber;
269
11.4M
    }
270
};
271
272
/** @short
273
    SvNumberformatter uses it upon switching locales.
274
275
    @descr
276
    Avoids reloading and analysing of locale data again and again.
277
278
    @ATTENTION
279
    If the default ctor is used the init() method MUST be called before
280
    accessing any locale data.
281
 */
282
283
class OnDemandCharClass
284
{
285
    std::optional<CharClass> moCharClass1;
286
    std::optional<CharClass> moCharClass2;
287
    int nCurrent; // -1 == uninitialised, 0 == class1, 1 == class2
288
289
public:
290
    OnDemandCharClass()
291
190k
        : nCurrent(-1)
292
190k
    {
293
190k
    }
294
295
    void changeLocale(const css::uno::Reference<css::uno::XComponentContext>& xContext,
296
                      const LanguageTag& rLanguageTag)
297
1.84M
    {
298
        // check for existing match
299
1.84M
        if (moCharClass1 && moCharClass1->getLanguageTag() == rLanguageTag)
300
628k
        {
301
628k
            nCurrent = 0;
302
628k
            return;
303
628k
        }
304
1.21M
        if (moCharClass2 && moCharClass2->getLanguageTag() == rLanguageTag)
305
607k
        {
306
607k
            nCurrent = 1;
307
607k
            return;
308
607k
        }
309
        // no match - update one the current entries
310
609k
        if (nCurrent == -1 || nCurrent == 1)
311
381k
        {
312
381k
            moCharClass1.emplace(xContext, rLanguageTag);
313
381k
            nCurrent = 0;
314
381k
        }
315
228k
        else
316
228k
        {
317
228k
            moCharClass2.emplace(xContext, rLanguageTag);
318
228k
            nCurrent = 1;
319
228k
        }
320
609k
    }
321
322
    const CharClass* get() const
323
321M
    {
324
321M
        switch (nCurrent)
325
321M
        {
326
240M
            case 0:
327
240M
                return &*moCharClass1;
328
80.4M
            case 1:
329
80.4M
                return &*moCharClass2;
330
0
            default:
331
0
                assert(false);
332
0
                return nullptr;
333
321M
        }
334
321M
    }
335
43.9k
    const CharClass* operator->() const { return get(); }
336
0
    const CharClass& operator*() const { return *get(); }
337
};
338
339
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */