Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/drawinglayer/source/geometry/viewinformation2d.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 <drawinglayer/geometry/viewinformation2d.hxx>
21
#include <basegfx/matrix/b2dhommatrix.hxx>
22
#include <basegfx/range/b2drange.hxx>
23
#include <basegfx/utils/canvastools.hxx>
24
#include <com/sun/star/beans/PropertyValue.hpp>
25
#include <com/sun/star/drawing/XDrawPage.hpp>
26
#include <com/sun/star/geometry/AffineMatrix2D.hpp>
27
#include <com/sun/star/geometry/RealRectangle2D.hpp>
28
#include <o3tl/temporary.hxx>
29
#include <officecfg/Office/Common.hxx>
30
#include <tools/color.hxx>
31
#include <vcl/rendercontext/DrawModeFlags.hxx>
32
33
#include <atomic>
34
#include <utility>
35
36
using namespace com::sun::star;
37
38
namespace drawinglayer::geometry
39
{
40
namespace
41
{
42
constexpr OUStringLiteral g_PropertyName_ObjectTransformation = u"ObjectTransformation";
43
constexpr OUStringLiteral g_PropertyName_ViewTransformation = u"ViewTransformation";
44
constexpr OUStringLiteral g_PropertyName_Viewport = u"Viewport";
45
constexpr OUStringLiteral g_PropertyName_Time = u"Time";
46
constexpr OUStringLiteral g_PropertyName_VisualizedPage = u"VisualizedPage";
47
constexpr OUStringLiteral g_PropertyName_ReducedDisplayQuality = u"ReducedDisplayQuality";
48
constexpr OUStringLiteral g_PropertyName_UseAntiAliasing = u"UseAntiAliasing";
49
constexpr OUStringLiteral g_PropertyName_PixelSnapHairline = u"PixelSnapHairline";
50
}
51
52
class ImpViewInformation2D
53
{
54
private:
55
    // ViewInformation2D implementation can change refcount, so we have only
56
    // two memory regions for pairs of ViewInformation2D/ImpViewInformation2D
57
    friend class ::drawinglayer::geometry::ViewInformation2D;
58
59
protected:
60
    // the object transformation
61
    basegfx::B2DHomMatrix maObjectTransformation;
62
63
    // the view transformation
64
    basegfx::B2DHomMatrix maViewTransformation;
65
66
    // the ObjectToView and it's inverse, both on demand from ObjectTransformation
67
    // and ViewTransformation
68
    basegfx::B2DHomMatrix maObjectToViewTransformation;
69
    basegfx::B2DHomMatrix maInverseObjectToViewTransformation;
70
71
    // the visible range and the on-demand one in ViewCoordinates
72
    basegfx::B2DRange maViewport;
73
    basegfx::B2DRange maDiscreteViewport;
74
75
    // the DrawPage which is target of visualisation. This is needed e.g. for
76
    // the view-dependent decomposition of PageNumber TextFields.
77
    // This parameter is buffered here, but mainly resides in mxExtendedInformation,
78
    // so it will be interpreted, but held there. It will also not be added
79
    // to mxExtendedInformation in impFillViewInformationFromContent (it's there already)
80
    uno::Reference<drawing::XDrawPage> mxVisualizedPage;
81
82
    // the point in time
83
    double mfViewTime;
84
85
    // color to use for automatic color
86
    Color maAutoColor;
87
88
    // DrawModeFlags to use, these may ask to modify the
89
    // colors/Bitmap paint according to the flags
90
    DrawModeFlags maDrawModeFlags;
91
92
    // a hint that the View that is being painted has an active TextEdit. This
93
    // is important for handling of TextHierarchyEditPrimitive2D to suppress
94
    // the text for objects in TextEdit - the text is visualized by the
95
    // active EditEngine/Outliner overlay, so it would be double visualized
96
    bool mbTextEditActive : 1;
97
98
    // processed view is an EditView
99
    bool mbEditViewActive : 1;
100
101
    // allow to reduce DisplayQuality (e.g. sw 3d fallback renderer for interactions)
102
    bool mbReducedDisplayQuality : 1;
103
104
    // determine if to use AntiAliasing on target pixel device
105
    bool mbUseAntiAliasing : 1;
106
107
    // determine if to use PixelSnapHairline on target pixel device
108
    bool mbPixelSnapHairline : 1;
109
110
public:
111
    ImpViewInformation2D()
112
9
        : maObjectTransformation()
113
9
        , maViewTransformation()
114
9
        , maObjectToViewTransformation()
115
9
        , maInverseObjectToViewTransformation()
116
9
        , maViewport()
117
9
        , maDiscreteViewport()
118
9
        , mxVisualizedPage()
119
9
        , mfViewTime(0.0)
120
9
        , maAutoColor(COL_AUTO)
121
9
        , maDrawModeFlags(DrawModeFlags::Default)
122
9
        , mbTextEditActive(false)
123
9
        , mbEditViewActive(false)
124
9
        , mbReducedDisplayQuality(false)
125
9
        , mbUseAntiAliasing(ViewInformation2D::getGlobalAntiAliasing())
126
9
    {
127
9
        if (comphelper::IsFuzzing())
128
9
            mbPixelSnapHairline = false;
129
0
        else
130
0
            mbPixelSnapHairline
131
0
                = mbUseAntiAliasing
132
0
                  && officecfg::Office::Common::Drawinglayer::SnapHorVerLinesToDiscrete::get();
133
9
    }
134
135
78.1k
    const basegfx::B2DHomMatrix& getObjectTransformation() const { return maObjectTransformation; }
136
    void setObjectTransformation(const basegfx::B2DHomMatrix& rNew)
137
371
    {
138
371
        maObjectTransformation = rNew;
139
371
        maObjectToViewTransformation.identity();
140
371
        maInverseObjectToViewTransformation.identity();
141
371
    }
142
143
296k
    const basegfx::B2DHomMatrix& getViewTransformation() const { return maViewTransformation; }
144
    void setViewTransformation(const basegfx::B2DHomMatrix& rNew)
145
296k
    {
146
296k
        maViewTransformation = rNew;
147
296k
        maDiscreteViewport.reset();
148
296k
        maObjectToViewTransformation.identity();
149
296k
        maInverseObjectToViewTransformation.identity();
150
296k
    }
151
152
300k
    const basegfx::B2DRange& getViewport() const { return maViewport; }
153
    void setViewport(const basegfx::B2DRange& rNew)
154
223k
    {
155
223k
        maViewport = rNew;
156
223k
        maDiscreteViewport.reset();
157
223k
    }
158
159
    const basegfx::B2DRange& getDiscreteViewport() const
160
0
    {
161
0
        if (maDiscreteViewport.isEmpty() && !maViewport.isEmpty())
162
0
        {
163
0
            basegfx::B2DRange aDiscreteViewport(maViewport);
164
0
            aDiscreteViewport.transform(getViewTransformation());
165
0
            const_cast<ImpViewInformation2D*>(this)->maDiscreteViewport = aDiscreteViewport;
166
0
        }
167
168
0
        return maDiscreteViewport;
169
0
    }
170
171
    const basegfx::B2DHomMatrix& getObjectToViewTransformation() const
172
330
    {
173
330
        if (maObjectToViewTransformation.isIdentity()
174
72
            && (!maObjectTransformation.isIdentity() || !maViewTransformation.isIdentity()))
175
72
        {
176
72
            basegfx::B2DHomMatrix aObjectToView(maViewTransformation * maObjectTransformation);
177
72
            const_cast<ImpViewInformation2D*>(this)->maObjectToViewTransformation = aObjectToView;
178
72
        }
179
180
330
        return maObjectToViewTransformation;
181
330
    }
182
183
    const basegfx::B2DHomMatrix& getInverseObjectToViewTransformation() const
184
27.7k
    {
185
27.7k
        if (maInverseObjectToViewTransformation.isIdentity()
186
23.0k
            && (!maObjectTransformation.isIdentity() || !maViewTransformation.isIdentity()))
187
1.33k
        {
188
1.33k
            basegfx::B2DHomMatrix aInverseObjectToView(maViewTransformation
189
1.33k
                                                       * maObjectTransformation);
190
1.33k
            aInverseObjectToView.invert();
191
1.33k
            const_cast<ImpViewInformation2D*>(this)->maInverseObjectToViewTransformation
192
1.33k
                = aInverseObjectToView;
193
1.33k
        }
194
195
27.7k
        return maInverseObjectToViewTransformation;
196
27.7k
    }
197
198
221k
    double getViewTime() const { return mfViewTime; }
199
    void setViewTime(double fNew)
200
0
    {
201
0
        if (fNew >= 0.0)
202
0
        {
203
0
            mfViewTime = fNew;
204
0
        }
205
0
    }
206
207
294k
    const uno::Reference<drawing::XDrawPage>& getVisualizedPage() const { return mxVisualizedPage; }
208
    void setVisualizedPage(const uno::Reference<drawing::XDrawPage>& rNew)
209
294k
    {
210
294k
        mxVisualizedPage = rNew;
211
294k
    }
212
213
0
    Color getAutoColor() const { return maAutoColor; }
214
221k
    void setAutoColor(Color aNew) { maAutoColor = aNew; }
215
216
1.04k
    DrawModeFlags getDrawModeFlags() const { return maDrawModeFlags; }
217
0
    void setDrawModeFlags(DrawModeFlags aNew) { maDrawModeFlags = aNew; }
218
219
0
    bool getTextEditActive() const { return mbTextEditActive; }
220
0
    void setTextEditActive(bool bNew) { mbTextEditActive = bNew; }
221
222
0
    bool getEditViewActive() const { return mbEditViewActive; }
223
70.4k
    void setEditViewActive(bool bNew) { mbEditViewActive = bNew; }
224
225
2
    bool getReducedDisplayQuality() const { return mbReducedDisplayQuality; }
226
2
    void setReducedDisplayQuality(bool bNew) { mbReducedDisplayQuality = bNew; }
227
228
384k
    bool getUseAntiAliasing() const { return mbUseAntiAliasing; }
229
0
    void setUseAntiAliasing(bool bNew) { mbUseAntiAliasing = bNew; }
230
231
76
    bool getPixelSnapHairline() const { return mbPixelSnapHairline; }
232
0
    void setPixelSnapHairline(bool bNew) { mbPixelSnapHairline = bNew; }
233
234
    bool operator==(const ImpViewInformation2D& rCandidate) const
235
742
    {
236
742
        return (maObjectTransformation == rCandidate.maObjectTransformation
237
0
                && maViewTransformation == rCandidate.maViewTransformation
238
0
                && maViewport == rCandidate.maViewport
239
0
                && mxVisualizedPage == rCandidate.mxVisualizedPage
240
0
                && mfViewTime == rCandidate.mfViewTime && maAutoColor == rCandidate.maAutoColor
241
0
                && maDrawModeFlags == rCandidate.maDrawModeFlags
242
0
                && mbTextEditActive == rCandidate.mbTextEditActive
243
0
                && mbEditViewActive == rCandidate.mbEditViewActive
244
0
                && mbReducedDisplayQuality == rCandidate.mbReducedDisplayQuality
245
0
                && mbUseAntiAliasing == rCandidate.mbUseAntiAliasing
246
0
                && mbPixelSnapHairline == rCandidate.mbPixelSnapHairline);
247
742
    }
248
};
249
250
namespace
251
{
252
ViewInformation2D::ImplType& theGlobalDefault()
253
383k
{
254
383k
    static ViewInformation2D::ImplType SINGLETON;
255
383k
    return SINGLETON;
256
383k
}
257
}
258
259
ViewInformation2D::ViewInformation2D()
260
383k
    : mpViewInformation2D(theGlobalDefault())
261
383k
{
262
383k
    setUseAntiAliasing(ViewInformation2D::getGlobalAntiAliasing());
263
383k
    if (!comphelper::IsFuzzing())
264
0
        setPixelSnapHairline(
265
0
            getUseAntiAliasing()
266
0
            && officecfg::Office::Common::Drawinglayer::SnapHorVerLinesToDiscrete::get());
267
383k
}
268
269
82.0k
ViewInformation2D::ViewInformation2D(const ViewInformation2D&) = default;
270
271
81.3k
ViewInformation2D::ViewInformation2D(ViewInformation2D&&) = default;
272
273
547k
ViewInformation2D::~ViewInformation2D() = default;
274
275
222k
ViewInformation2D& ViewInformation2D::operator=(const ViewInformation2D&) = default;
276
277
2
ViewInformation2D& ViewInformation2D::operator=(ViewInformation2D&&) = default;
278
279
bool ViewInformation2D::operator==(const ViewInformation2D& rCandidate) const
280
742
{
281
742
    return rCandidate.mpViewInformation2D == mpViewInformation2D;
282
742
}
283
284
const basegfx::B2DHomMatrix& ViewInformation2D::getObjectTransformation() const
285
77.5k
{
286
77.5k
    return mpViewInformation2D->getObjectTransformation();
287
77.5k
}
288
289
void ViewInformation2D::setObjectTransformation(const basegfx::B2DHomMatrix& rNew)
290
576
{
291
576
    if (std::as_const(mpViewInformation2D)->getObjectTransformation() != rNew)
292
371
        mpViewInformation2D->setObjectTransformation(rNew);
293
576
}
294
295
const basegfx::B2DHomMatrix& ViewInformation2D::getViewTransformation() const
296
75
{
297
75
    return mpViewInformation2D->getViewTransformation();
298
75
}
299
300
void ViewInformation2D::setViewTransformation(const basegfx::B2DHomMatrix& rNew)
301
296k
{
302
296k
    if (std::as_const(mpViewInformation2D)->getViewTransformation() != rNew)
303
296k
        mpViewInformation2D->setViewTransformation(rNew);
304
296k
}
305
306
const basegfx::B2DRange& ViewInformation2D::getViewport() const
307
3.59k
{
308
3.59k
    return mpViewInformation2D->getViewport();
309
3.59k
}
310
311
void ViewInformation2D::setViewport(const basegfx::B2DRange& rNew)
312
296k
{
313
296k
    if (rNew != std::as_const(mpViewInformation2D)->getViewport())
314
223k
        mpViewInformation2D->setViewport(rNew);
315
296k
}
316
317
0
double ViewInformation2D::getViewTime() const { return mpViewInformation2D->getViewTime(); }
318
319
void ViewInformation2D::setViewTime(double fNew)
320
221k
{
321
221k
    if (fNew != std::as_const(mpViewInformation2D)->getViewTime())
322
0
        mpViewInformation2D->setViewTime(fNew);
323
221k
}
324
325
const uno::Reference<drawing::XDrawPage>& ViewInformation2D::getVisualizedPage() const
326
565
{
327
565
    return mpViewInformation2D->getVisualizedPage();
328
565
}
329
330
void ViewInformation2D::setVisualizedPage(const uno::Reference<drawing::XDrawPage>& rNew)
331
294k
{
332
294k
    if (rNew != std::as_const(mpViewInformation2D)->getVisualizedPage())
333
294k
        mpViewInformation2D->setVisualizedPage(rNew);
334
294k
}
335
336
const basegfx::B2DHomMatrix& ViewInformation2D::getObjectToViewTransformation() const
337
330
{
338
330
    return mpViewInformation2D->getObjectToViewTransformation();
339
330
}
340
341
const basegfx::B2DHomMatrix& ViewInformation2D::getInverseObjectToViewTransformation() const
342
27.7k
{
343
27.7k
    return mpViewInformation2D->getInverseObjectToViewTransformation();
344
27.7k
}
345
346
const basegfx::B2DRange& ViewInformation2D::getDiscreteViewport() const
347
0
{
348
0
    return mpViewInformation2D->getDiscreteViewport();
349
0
}
350
351
bool ViewInformation2D::getReducedDisplayQuality() const
352
0
{
353
0
    return mpViewInformation2D->getReducedDisplayQuality();
354
0
}
355
356
void ViewInformation2D::setReducedDisplayQuality(bool bNew)
357
2
{
358
2
    if (bNew != std::as_const(mpViewInformation2D)->getReducedDisplayQuality())
359
2
        mpViewInformation2D->setReducedDisplayQuality(bNew);
360
2
}
361
362
bool ViewInformation2D::getUseAntiAliasing() const
363
969
{
364
969
    return mpViewInformation2D->getUseAntiAliasing();
365
969
}
366
367
void ViewInformation2D::setUseAntiAliasing(bool bNew)
368
383k
{
369
383k
    if (bNew != std::as_const(mpViewInformation2D)->getUseAntiAliasing())
370
0
        mpViewInformation2D->setUseAntiAliasing(bNew);
371
383k
}
372
373
0
Color ViewInformation2D::getAutoColor() const { return mpViewInformation2D->getAutoColor(); }
374
375
221k
void ViewInformation2D::setAutoColor(Color aNew) { mpViewInformation2D->setAutoColor(aNew); }
376
377
DrawModeFlags ViewInformation2D::getDrawModeFlags() const
378
1.04k
{
379
1.04k
    return mpViewInformation2D->getDrawModeFlags();
380
1.04k
}
381
382
void ViewInformation2D::setDrawModeFlags(DrawModeFlags aNew)
383
0
{
384
0
    mpViewInformation2D->setDrawModeFlags(aNew);
385
0
}
386
387
bool ViewInformation2D::getTextEditActive() const
388
0
{
389
0
    return mpViewInformation2D->getTextEditActive();
390
0
}
391
392
void ViewInformation2D::setTextEditActive(bool bNew)
393
0
{
394
0
    mpViewInformation2D->setTextEditActive(bNew);
395
0
}
396
397
bool ViewInformation2D::getEditViewActive() const
398
0
{
399
0
    return mpViewInformation2D->getEditViewActive();
400
0
}
401
402
void ViewInformation2D::setEditViewActive(bool bNew)
403
70.4k
{
404
70.4k
    mpViewInformation2D->setEditViewActive(bNew);
405
70.4k
}
406
407
bool ViewInformation2D::getPixelSnapHairline() const
408
76
{
409
76
    return mpViewInformation2D->getPixelSnapHairline();
410
76
}
411
412
void ViewInformation2D::setPixelSnapHairline(bool bNew)
413
0
{
414
0
    if (bNew != std::as_const(mpViewInformation2D)->getPixelSnapHairline())
415
0
        mpViewInformation2D->setPixelSnapHairline(bNew);
416
0
}
417
418
static std::atomic<bool>& globalAntiAliasing()
419
384k
{
420
384k
    static std::atomic<bool> g_GlobalAntiAliasing
421
384k
        = comphelper::IsFuzzing() || officecfg::Office::Common::Drawinglayer::AntiAliasing::get();
422
384k
    return g_GlobalAntiAliasing;
423
384k
}
424
425
/**
426
  * Some code like to turn this stuff on and off during a drawing operation
427
  * so it can "tunnel" information down through several layers,
428
  * so we don't want to actually do a config write all the time.
429
  */
430
void ViewInformation2D::setGlobalAntiAliasing(bool bAntiAliasing, bool bTemporary)
431
0
{
432
0
    if (globalAntiAliasing().compare_exchange_strong(o3tl::temporary(!bAntiAliasing), bAntiAliasing)
433
0
        && !bTemporary)
434
0
    {
435
0
        auto batch = comphelper::ConfigurationChanges::create();
436
0
        officecfg::Office::Common::Drawinglayer::AntiAliasing::set(bAntiAliasing, batch);
437
0
        batch->commit();
438
0
    }
439
0
}
440
384k
bool ViewInformation2D::getGlobalAntiAliasing() { return globalAntiAliasing(); }
441
442
ViewInformation2D
443
createViewInformation2D(const css::uno::Sequence<css::beans::PropertyValue>& rViewParameters)
444
2.87k
{
445
2.87k
    if (!rViewParameters.hasElements())
446
2.87k
        return ViewInformation2D();
447
448
5
    ViewInformation2D aRetval;
449
450
5
    for (auto const& rPropertyValue : rViewParameters)
451
5
    {
452
5
        if (rPropertyValue.Name == g_PropertyName_ReducedDisplayQuality)
453
2
        {
454
2
            bool bNew(false);
455
2
            rPropertyValue.Value >>= bNew;
456
2
            aRetval.setReducedDisplayQuality(bNew);
457
2
        }
458
3
        else if (rPropertyValue.Name == g_PropertyName_PixelSnapHairline)
459
0
        {
460
0
            bool bNew(
461
0
                true); //SvtOptionsDrawinglayer::IsAntiAliasing() && SvtOptionsDrawinglayer::IsSnapHorVerLinesToDiscrete());
462
0
            rPropertyValue.Value >>= bNew;
463
0
            aRetval.setPixelSnapHairline(bNew);
464
0
        }
465
3
        else if (rPropertyValue.Name == g_PropertyName_UseAntiAliasing)
466
0
        {
467
0
            bool bNew(true); //SvtOptionsDrawinglayer::IsAntiAliasing());
468
0
            rPropertyValue.Value >>= bNew;
469
0
            aRetval.setUseAntiAliasing(bNew);
470
0
        }
471
3
        else if (rPropertyValue.Name == g_PropertyName_ObjectTransformation)
472
0
        {
473
0
            css::geometry::AffineMatrix2D aAffineMatrix2D;
474
0
            rPropertyValue.Value >>= aAffineMatrix2D;
475
0
            basegfx::B2DHomMatrix aTransformation;
476
0
            basegfx::unotools::homMatrixFromAffineMatrix(aTransformation, aAffineMatrix2D);
477
0
            aRetval.setObjectTransformation(aTransformation);
478
0
        }
479
3
        else if (rPropertyValue.Name == g_PropertyName_ViewTransformation)
480
0
        {
481
0
            css::geometry::AffineMatrix2D aAffineMatrix2D;
482
0
            rPropertyValue.Value >>= aAffineMatrix2D;
483
0
            basegfx::B2DHomMatrix aTransformation;
484
0
            basegfx::unotools::homMatrixFromAffineMatrix(aTransformation, aAffineMatrix2D);
485
0
            aRetval.setViewTransformation(aTransformation);
486
0
        }
487
3
        else if (rPropertyValue.Name == g_PropertyName_Viewport)
488
0
        {
489
0
            css::geometry::RealRectangle2D aUnoViewport;
490
0
            rPropertyValue.Value >>= aUnoViewport;
491
0
            const basegfx::B2DRange aViewport(
492
0
                basegfx::unotools::b2DRectangleFromRealRectangle2D(aUnoViewport));
493
0
            aRetval.setViewport(aViewport);
494
0
        }
495
3
        else if (rPropertyValue.Name == g_PropertyName_Time)
496
0
        {
497
0
            double fViewTime(0.0);
498
0
            rPropertyValue.Value >>= fViewTime;
499
0
            aRetval.setViewTime(fViewTime);
500
0
        }
501
3
        else if (rPropertyValue.Name == g_PropertyName_VisualizedPage)
502
0
        {
503
0
            css::uno::Reference<css::drawing::XDrawPage> xVisualizedPage;
504
0
            rPropertyValue.Value >>= xVisualizedPage;
505
0
            aRetval.setVisualizedPage(xVisualizedPage);
506
0
        }
507
5
    }
508
509
5
    return aRetval;
510
2.87k
}
511
512
} // end of namespace drawinglayer::geometry
513
514
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */