Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/comphelper/source/misc/lok.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
10
#include <comphelper/lok.hxx>
11
12
#include <com/sun/star/awt/Rectangle.hpp>
13
14
#include <osl/process.h>
15
#include <i18nlangtag/languagetag.hxx>
16
#include <sal/log.hxx>
17
#ifdef _WIN32
18
#include <tools/UnixWrappers.h>
19
#else
20
#include <limits.h>
21
#endif
22
#include <vcl/task.hxx>
23
24
#include <iostream>
25
26
using namespace com::sun::star;
27
28
namespace comphelper::LibreOfficeKit
29
{
30
31
static bool g_bActive(false);
32
33
static bool g_bForkedChild(false);
34
35
static bool g_bPartInInvalidation(false);
36
37
static bool g_bTiledPainting(false);
38
39
static bool g_bIdleLayouting(false);
40
41
static bool g_bDialogPainting(false);
42
43
static bool g_bTiledAnnotations(true);
44
45
static bool g_bRangeHeaders(false);
46
47
static bool g_bViewIdForVisCursorInvalidation(false);
48
49
static bool g_bLocalRendering(false);
50
51
static bool g_bSlideshowRendering(false);
52
53
static Compat g_eCompatFlags(Compat::none);
54
55
/// Used to set the DocId at ViewShell construction time.
56
static ViewShellDocId g_nCurrentDocId;
57
58
static std::function<bool(void*, int)> g_pAnyInputCallback;
59
static void* g_pAnyInputCallbackData;
60
static std::function<int()> g_pMostUrgentPriorityGetter;
61
62
static std::function<void(const char*, char*, size_t)> g_pFileSaveDialogCallback;
63
64
static std::function<void(int)> g_pViewSetter;
65
static std::function<int()> g_pViewGetter;
66
67
/// Visible area of the first view during document load.
68
static awt::Rectangle g_aInitialClientVisibleArea;
69
70
namespace
71
{
72
73
class LanguageAndLocale
74
{
75
private:
76
    LanguageTag maLanguageTag;
77
    LanguageTag maLocaleLanguageTag;
78
79
public:
80
81
    LanguageAndLocale()
82
108
        : maLanguageTag(LANGUAGE_NONE)
83
108
        , maLocaleLanguageTag(LANGUAGE_NONE)
84
108
    {}
85
86
    const LanguageTag& getLanguage() const
87
0
    {
88
0
        return maLanguageTag;
89
0
    }
90
91
    void setLanguage(const LanguageTag& rLanguageTag)
92
0
    {
93
0
        if (maLanguageTag != rLanguageTag)
94
0
        {
95
0
            SAL_INFO("comphelper.lok", "Setting language from " << maLanguageTag.getBcp47() << " to " << rLanguageTag.getBcp47());
96
0
            maLanguageTag = rLanguageTag;
97
0
        }
98
0
    }
99
100
    const LanguageTag& getLocale() const
101
0
    {
102
0
        return maLocaleLanguageTag;
103
0
    }
104
105
    void setLocale(const LanguageTag& rLocaleLanguageTag)
106
0
    {
107
0
        if (maLocaleLanguageTag != rLocaleLanguageTag)
108
0
        {
109
0
            SAL_INFO("comphelper.lok", "Setting locale from " << maLocaleLanguageTag.getBcp47() << " to " << rLocaleLanguageTag.getBcp47());
110
0
            maLocaleLanguageTag = rLocaleLanguageTag;
111
0
        }
112
0
    }
113
114
};
115
116
}
117
118
static LanguageAndLocale g_aLanguageAndLocale;
119
120
/// Scaling of the cairo canvas painting for hi-dpi
121
static double g_fDPIScale(1.0);
122
123
void setActive(bool bActive)
124
0
{
125
0
    g_bActive = bActive;
126
0
}
127
128
bool isActive()
129
113M
{
130
113M
    return g_bActive;
131
113M
}
132
133
void setForkedChild(bool bIsChild)
134
0
{
135
0
    g_bForkedChild = bIsChild;
136
0
}
137
138
bool isForkedChild()
139
251k
{
140
251k
    return g_bForkedChild;
141
251k
}
142
143
void setPartInInvalidation(bool bPartInInvalidation)
144
0
{
145
0
    g_bPartInInvalidation = bPartInInvalidation;
146
0
}
147
148
bool isPartInInvalidation()
149
0
{
150
0
    return g_bPartInInvalidation;
151
0
}
152
153
void setTiledPainting(bool bTiledPainting)
154
0
{
155
0
    g_bTiledPainting = bTiledPainting;
156
0
}
157
158
bool isTiledPainting()
159
172k
{
160
172k
    return g_bTiledPainting;
161
172k
}
162
163
void setIdleLayouting(bool bIdleLayouting)
164
0
{
165
0
    g_bIdleLayouting = bIdleLayouting;
166
0
}
167
168
void setDialogPainting(bool bDialogPainting)
169
0
{
170
0
    g_bDialogPainting = bDialogPainting;
171
0
}
172
173
bool isDialogPainting()
174
53.1k
{
175
53.1k
    return g_bDialogPainting;
176
53.1k
}
177
178
void setDPIScale(double fDPIScale)
179
0
{
180
0
    g_fDPIScale = fDPIScale;
181
0
}
182
183
double getDPIScale()
184
0
{
185
0
    return g_fDPIScale;
186
0
}
187
188
void setTiledAnnotations(bool bTiledAnnotations)
189
0
{
190
0
    g_bTiledAnnotations = bTiledAnnotations;
191
0
}
192
193
bool isTiledAnnotations()
194
184
{
195
184
    return g_bTiledAnnotations;
196
184
}
197
198
void setRangeHeaders(bool bRangeHeaders)
199
0
{
200
0
    g_bRangeHeaders = bRangeHeaders;
201
0
}
202
203
void setViewIdForVisCursorInvalidation(bool bViewIdForVisCursorInvalidation)
204
0
{
205
0
    g_bViewIdForVisCursorInvalidation = bViewIdForVisCursorInvalidation;
206
0
}
207
208
bool isViewIdForVisCursorInvalidation()
209
0
{
210
0
    return g_bViewIdForVisCursorInvalidation;
211
0
}
212
213
bool isRangeHeaders()
214
0
{
215
0
    return g_bRangeHeaders;
216
0
}
217
218
void setLocalRendering(bool bLocalRendering)
219
0
{
220
0
    g_bLocalRendering = bLocalRendering;
221
0
}
222
223
bool isLocalRendering()
224
0
{
225
0
    return g_bLocalRendering;
226
0
}
227
228
void setSlideshowRendering(bool bSlideshowRendering)
229
0
{
230
0
    g_bSlideshowRendering = bSlideshowRendering;
231
0
}
232
233
bool isSlideshowRendering()
234
0
{
235
0
    return g_bSlideshowRendering;
236
0
}
237
238
0
void setCompatFlag(Compat flag) { g_eCompatFlags = static_cast<Compat>(g_eCompatFlags | flag); }
239
240
0
bool isCompatFlagSet(Compat flag) { return (g_eCompatFlags & flag) == flag; }
241
242
0
void resetCompatFlag() { g_eCompatFlags = Compat::none; }
243
244
void setLocale(const LanguageTag& rLanguageTag)
245
0
{
246
0
    g_aLanguageAndLocale.setLocale(rLanguageTag);
247
0
}
248
249
const LanguageTag& getLocale()
250
0
{
251
0
    const LanguageTag& rLocale = g_aLanguageAndLocale.getLocale();
252
0
    SAL_INFO_IF(rLocale.getLanguageType() == LANGUAGE_NONE, "comphelper.lok", "Locale not set");
253
0
    return rLocale;
254
0
}
255
256
void setLanguageTag(const LanguageTag& rLanguageTag)
257
0
{
258
0
    g_aLanguageAndLocale.setLanguage(rLanguageTag);
259
0
}
260
261
const LanguageTag& getLanguageTag()
262
0
{
263
0
    const LanguageTag& rLanguage = g_aLanguageAndLocale.getLanguage();
264
0
    SAL_INFO_IF(rLanguage.getLanguageType() == LANGUAGE_NONE, "comphelper.lok", "Language not set");
265
0
    return rLanguage;
266
0
}
267
268
bool isAllowlistedLanguage(const OUString& lang)
269
0
{
270
0
    if (!isActive())
271
0
        return true;
272
273
#if defined ANDROID || defined IOS
274
    (void) lang;
275
    return true;
276
#else
277
0
    static const std::vector<OUString> aAllowlist = [] {
278
0
        std::vector<OUString> aList;
279
        // coverity[tainted_data] - we trust the contents of this variable
280
0
        const char* pAllowlist = getenv("LOK_ALLOWLIST_LANGUAGES");
281
0
        if (pAllowlist)
282
0
        {
283
0
            std::stringstream stream(pAllowlist);
284
0
            std::string s;
285
286
0
            std::cerr << "Allowlisted languages: ";
287
0
            while (getline(stream, s, ' ')) {
288
0
                if (s.length() == 0)
289
0
                    continue;
290
291
0
                std::cerr << s << " ";
292
0
                aList.emplace_back(OStringToOUString(s, RTL_TEXTENCODING_UTF8));
293
0
            }
294
0
            std::cerr << std::endl;
295
0
        }
296
0
        else
297
0
        {
298
0
            aList.emplace_back("*"); // LOK_ALLOWLIST_LANGUAGES not defined, allow all
299
0
        }
300
301
0
        if (aList.empty())
302
0
            std::cerr << "No language allowlisted, turning off the language support." << std::endl;
303
304
0
        return aList;
305
0
    }();
306
307
0
    if (aAllowlist.empty())
308
0
        return false;
309
310
0
    if (aAllowlist.size() == 1 && aAllowlist[0] == "*")
311
0
        return true;
312
313
0
    for (const auto& entry : aAllowlist)
314
0
    {
315
0
        if (lang.startsWith(entry))
316
0
            return true;
317
0
        if (lang.startsWith(entry.replace('_', '-')))
318
0
            return true;
319
0
    }
320
321
0
    return false;
322
0
#endif
323
0
}
324
325
void setTimezone(bool isSet, const OUString& rTimezone)
326
0
{
327
0
    if (isSet)
328
0
    {
329
        // Set the given timezone, even if empty.
330
0
        osl_setEnvironment(u"TZ"_ustr.pData, rTimezone.pData);
331
0
    }
332
0
    else
333
0
    {
334
        // Unset and empty aren't the same.
335
        // When unset, it means default to the system configured timezone.
336
0
        osl_clearEnvironment(u"TZ"_ustr.pData);
337
0
    }
338
339
    // Update the timezone data.
340
0
    ::tzset();
341
0
}
342
343
static void (*pStatusIndicatorCallback)(void *data, statusIndicatorCallbackType type, int percent, const char* pText)(nullptr);
344
static void *pStatusIndicatorCallbackData(nullptr);
345
346
void setStatusIndicatorCallback(void (*callback)(void *data, statusIndicatorCallbackType type, int percent, const char* pText), void *data)
347
0
{
348
0
    pStatusIndicatorCallback = callback;
349
0
    pStatusIndicatorCallbackData = data;
350
0
}
351
352
void statusIndicatorStart(const OUString& sText)
353
0
{
354
0
    if (pStatusIndicatorCallback)
355
0
        pStatusIndicatorCallback(pStatusIndicatorCallbackData, statusIndicatorCallbackType::Start, 0, sText.toUtf8().getStr());
356
0
}
357
358
void statusIndicatorSetValue(int percent)
359
0
{
360
0
    if (pStatusIndicatorCallback)
361
0
        pStatusIndicatorCallback(pStatusIndicatorCallbackData, statusIndicatorCallbackType::SetValue, percent, nullptr);
362
0
}
363
364
void statusIndicatorFinish()
365
0
{
366
0
    if (pStatusIndicatorCallback)
367
0
        pStatusIndicatorCallback(pStatusIndicatorCallbackData, statusIndicatorCallbackType::Finish, 0, nullptr);
368
0
}
369
370
void setAnyInputCallback(const std::function<bool(void*, int)>& pAnyInputCallback, void* pData,
371
                         const std::function<int()>& pMostUrgentPriorityGetter)
372
0
{
373
0
    g_pAnyInputCallback = pAnyInputCallback;
374
0
    g_pAnyInputCallbackData = pData;
375
0
    g_pMostUrgentPriorityGetter = pMostUrgentPriorityGetter;
376
0
}
377
378
bool anyInput()
379
14.0k
{
380
14.0k
    bool bRet = false;
381
382
    // Ignore input events during background save.
383
14.0k
    if (!g_bForkedChild && g_pAnyInputCallback && g_pAnyInputCallbackData)
384
0
    {
385
0
        int nMostUrgentPriority;
386
0
        if (g_bIdleLayouting)
387
0
        {
388
            // Report idle priority instead of querying the scheduler.  Various unrelated tasks
389
            // (timers, paint idles) may be queued at high priority, which would cause the LOK
390
            // client to not interrupt, preventing the idle layout from stopping.
391
0
            nMostUrgentPriority = static_cast<int>(TaskPriority::DEFAULT_IDLE);
392
0
        }
393
0
        else
394
0
        {
395
0
            nMostUrgentPriority = g_pMostUrgentPriorityGetter();
396
0
        }
397
0
        bRet = g_pAnyInputCallback(g_pAnyInputCallbackData, nMostUrgentPriority);
398
0
    }
399
400
14.0k
    return bRet;
401
14.0k
}
402
403
void setFileSaveDialogCallback(const std::function<void(const char*, char*, size_t)>& pFileSaveDialogCallback)
404
0
{
405
0
    g_pFileSaveDialogCallback = pFileSaveDialogCallback;
406
0
}
407
408
bool fileSaveDialog(const OUString& rSuggested, OUString& rResult)
409
0
{
410
0
    if (!g_pFileSaveDialogCallback)
411
0
    {
412
0
        return false;
413
0
    }
414
415
0
    OString aSuggested = rSuggested.toUtf8();
416
0
    char aResult[PATH_MAX];
417
0
    g_pFileSaveDialogCallback(aSuggested.getStr(), aResult, PATH_MAX);
418
0
    rResult = OUString::fromUtf8(aResult);
419
0
    return true;
420
0
}
421
422
void setViewSetter(const std::function<void(int)>& pViewSetter)
423
0
{
424
0
    g_pViewSetter = pViewSetter;
425
0
}
426
427
void setView(int nView)
428
0
{
429
0
    if (!g_pViewSetter)
430
0
    {
431
0
        return;
432
0
    }
433
434
0
    g_pViewSetter(nView);
435
0
}
436
437
void setViewGetter(const std::function<int()>& pViewGetter)
438
0
{
439
0
    g_pViewGetter = pViewGetter;
440
0
}
441
442
int getView()
443
0
{
444
0
    if (!g_pViewGetter)
445
0
    {
446
0
        return -1;
447
0
    }
448
449
0
    return g_pViewGetter();
450
0
}
451
452
ViewShellDocId getDocId()
453
4.08k
{
454
4.08k
    return g_nCurrentDocId;
455
4.08k
}
456
457
void setDocId(ViewShellDocId nDocId)
458
0
{
459
0
    g_nCurrentDocId = nDocId;
460
0
}
461
462
void setInitialClientVisibleArea(const awt::Rectangle& rClientVisibleArea)
463
0
{
464
0
    g_aInitialClientVisibleArea = rClientVisibleArea;
465
0
}
466
467
58.5k
const awt::Rectangle & getInitialClientVisibleArea() { return g_aInitialClientVisibleArea; }
468
469
} // namespace
470
471
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */