Coverage Report

Created: 2026-02-14 09:37

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
1.13M
        : eLastAnyLanguage(LANGUAGE_DONTKNOW)
65
1.13M
        , nCurrent(0)
66
1.13M
        , bInitialized(false)
67
1.13M
    {
68
1.13M
        eCurrentLanguage = LANGUAGE_SYSTEM;
69
1.13M
    }
70
71
0
    bool isInitialized() const { return bInitialized; }
72
73
    void init(const LanguageTag& rLanguageTag)
74
214k
    {
75
214k
        changeLocale(rLanguageTag);
76
214k
        bInitialized = true;
77
214k
    }
78
79
    void changeLocale(const LanguageTag& rLanguageTag)
80
1.81M
    {
81
1.81M
        LanguageType eLang = rLanguageTag.getLanguageType(false);
82
1.81M
        if (eLang == LANGUAGE_SYSTEM)
83
867k
            nCurrent = 0;
84
946k
        else if (eLang == LANGUAGE_ENGLISH_US)
85
541k
        {
86
541k
            if (!mpEnglish)
87
36.0k
                mpEnglish = LocaleDataWrapper::get(rLanguageTag);
88
541k
            nCurrent = 1;
89
541k
        }
90
405k
        else
91
405k
        {
92
405k
            if (!mpAny)
93
12.9k
            {
94
12.9k
                mpAny = LocaleDataWrapper::get(rLanguageTag);
95
12.9k
                eLastAnyLanguage = eLang;
96
12.9k
            }
97
392k
            else if (eLastAnyLanguage != eLang)
98
247k
            {
99
247k
                mpAny = LocaleDataWrapper::get(rLanguageTag);
100
247k
                eLastAnyLanguage = eLang;
101
247k
            }
102
405k
            nCurrent = 2;
103
405k
        }
104
1.81M
        eCurrentLanguage = eLang;
105
1.81M
    }
106
107
2.64k
    LanguageType getCurrentLanguage() const { return eCurrentLanguage; }
108
109
    const LocaleDataWrapper* get() const
110
271M
    {
111
271M
        switch (nCurrent)
112
271M
        {
113
174M
            case 0:
114
174M
                return &aSysLocale.GetLocaleData();
115
27.5M
            case 1:
116
27.5M
                return mpEnglish;
117
69.4M
            case 2:
118
69.4M
                return mpAny;
119
0
            default:
120
0
                assert(false);
121
0
                return nullptr;
122
271M
        }
123
271M
    }
124
1.65M
    const LocaleDataWrapper* operator->() const { return get(); }
125
329k
    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
214k
    {
148
214k
        LanguageTag aEnglishLanguageTag(LANGUAGE_ENGLISH_US);
149
214k
        aEnglishLocale = aEnglishLanguageTag.getLocale();
150
214k
        aLastAnyLocale = aEnglishLocale;
151
214k
    }
152
153
    void init(const css::uno::Reference<css::uno::XComponentContext>& rxContext,
154
              const css::lang::Locale& rLocale)
155
214k
    {
156
214k
        m_xContext = rxContext;
157
214k
        changeLocale(rLocale);
158
214k
        moEnglish.reset();
159
214k
        moAny.reset();
160
214k
    }
161
162
1.73M
    void changeLocale(const css::lang::Locale& rLocale) { aLocale = rLocale; }
163
164
    CalendarWrapper* get() const
165
4.82M
    {
166
4.82M
        CalendarWrapper* pPtr;
167
4.82M
        if (aLocale == aEnglishLocale)
168
4.55M
        {
169
4.55M
            if (!moEnglish)
170
59.0k
            {
171
59.0k
                moEnglish.emplace(m_xContext);
172
59.0k
                moEnglish->loadDefaultCalendar(aEnglishLocale);
173
59.0k
            }
174
4.55M
            pPtr = &*moEnglish;
175
4.55M
        }
176
273k
        else
177
273k
        {
178
273k
            if (!moAny)
179
4.20k
            {
180
4.20k
                moAny.emplace(m_xContext);
181
4.20k
                moAny->loadDefaultCalendar(aLocale);
182
4.20k
                aLastAnyLocale = aLocale;
183
4.20k
            }
184
269k
            else if (aLocale != aLastAnyLocale)
185
46.4k
            {
186
46.4k
                moAny->loadDefaultCalendar(aLocale);
187
46.4k
                aLastAnyLocale = aLocale;
188
46.4k
            }
189
273k
            pPtr = &*moAny;
190
273k
        }
191
4.82M
        return pPtr;
192
4.82M
    }
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
1.13M
        : eLanguage(LANGUAGE_SYSTEM)
212
1.13M
        , nType(TransliterationFlags::NONE)
213
1.13M
        , bValid(false)
214
1.13M
        , bInitialized(false)
215
1.13M
    {
216
1.13M
    }
217
218
0
    bool isInitialized() const { return bInitialized; }
219
220
    void init(const css::uno::Reference<css::uno::XComponentContext>& rxContext, LanguageType eLang)
221
214k
    {
222
214k
        m_xContext = rxContext;
223
214k
        nType = TransliterationFlags::IGNORE_CASE;
224
214k
        changeLocale(eLang);
225
214k
        moTransliterate.reset();
226
214k
        bInitialized = true;
227
214k
    }
228
229
    void changeLocale(LanguageType eLang)
230
1.73M
    {
231
1.73M
        bValid = false;
232
1.73M
        eLanguage = eLang;
233
1.73M
    }
234
235
    const ::utl::TransliterationWrapper* get() const
236
358k
    {
237
358k
        if (!bValid)
238
132k
        {
239
132k
            if (!moTransliterate)
240
7.31k
                moTransliterate.emplace(m_xContext, nType);
241
132k
            moTransliterate->loadModuleIfNeeded(eLanguage);
242
132k
            bValid = true;
243
132k
        }
244
358k
        return &*moTransliterate;
245
358k
    }
246
247
58.5k
    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
151k
        : m_xContext(rContext)
261
151k
    {
262
151k
    }
263
264
    NativeNumberWrapper& get() const
265
10.7M
    {
266
10.7M
        if (!moNativeNumber)
267
151k
            moNativeNumber.emplace(m_xContext);
268
10.7M
        return *moNativeNumber;
269
10.7M
    }
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
214k
        : nCurrent(-1)
292
214k
    {
293
214k
    }
294
295
    void changeLocale(const css::uno::Reference<css::uno::XComponentContext>& xContext,
296
                      const LanguageTag& rLanguageTag)
297
1.73M
    {
298
        // check for existing match
299
1.73M
        if (moCharClass1 && moCharClass1->getLanguageTag() == rLanguageTag)
300
580k
        {
301
580k
            nCurrent = 0;
302
580k
            return;
303
580k
        }
304
1.15M
        if (moCharClass2 && moCharClass2->getLanguageTag() == rLanguageTag)
305
559k
        {
306
559k
            nCurrent = 1;
307
559k
            return;
308
559k
        }
309
        // no match - update one the current entries
310
594k
        if (nCurrent == -1 || nCurrent == 1)
311
384k
        {
312
384k
            moCharClass1.emplace(xContext, rLanguageTag);
313
384k
            nCurrent = 0;
314
384k
        }
315
210k
        else
316
210k
        {
317
210k
            moCharClass2.emplace(xContext, rLanguageTag);
318
210k
            nCurrent = 1;
319
210k
        }
320
594k
    }
321
322
    const CharClass* get() const
323
330M
    {
324
330M
        switch (nCurrent)
325
330M
        {
326
250M
            case 0:
327
250M
                return &*moCharClass1;
328
80.5M
            case 1:
329
80.5M
                return &*moCharClass2;
330
0
            default:
331
0
                assert(false);
332
0
                return nullptr;
333
330M
        }
334
330M
    }
335
41.7k
    const CharClass* operator->() const { return get(); }
336
0
    const CharClass& operator*() const { return *get(); }
337
};
338
339
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */