summaryrefslogtreecommitdiffstats
path: root/drawinglayer/source/primitive2d/BufferedDecompositionPrimitive2D.cxx
blob: 22b6450e7f2d86a33a581722ca0db9be2345b7c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <sal/config.h>

#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
#include <drawinglayer/geometry/viewinformation2d.hxx>

namespace
{
class LocalCallbackTimer : public salhelper::Timer
{
protected:
    drawinglayer::primitive2d::BufferedDecompositionPrimitive2D* pCustomer;

public:
    explicit LocalCallbackTimer(
        drawinglayer::primitive2d::BufferedDecompositionPrimitive2D& rCustomer)
        : pCustomer(&rCustomer)
    {
    }

    void clearCallback() { pCustomer = nullptr; }

protected:
    virtual void SAL_CALL onShot() override;
};

void SAL_CALL LocalCallbackTimer::onShot()
{
    if (nullptr != pCustomer)
        flushBufferedDecomposition(*pCustomer);
}
}

namespace drawinglayer::primitive2d
{
void flushBufferedDecomposition(BufferedDecompositionPrimitive2D& rTarget)
{
    rTarget.setBuffered2DDecomposition(Primitive2DContainer());
}

const Primitive2DContainer& BufferedDecompositionPrimitive2D::getBuffered2DDecomposition() const
{
    if (0 != maCallbackSeconds && maCallbackTimer.is())
    {
        // decomposition was used, touch/restart time
        maCallbackTimer->setRemainingTime(salhelper::TTimeValue(maCallbackSeconds, 0));
    }

    return maBuffered2DDecomposition;
}

void BufferedDecompositionPrimitive2D::setBuffered2DDecomposition(Primitive2DContainer&& rNew)
{
    if (0 == maCallbackSeconds)
    {
        // no flush used, just set
        maBuffered2DDecomposition = std::move(rNew);
        return;
    }

    if (maCallbackTimer.is())
    {
        if (rNew.empty())
        {
            // stop timer
            maCallbackTimer->stop();
        }
        else
        {
            // decomposition changed, touch
            maCallbackTimer->setRemainingTime(salhelper::TTimeValue(maCallbackSeconds, 0));
            if (!maCallbackTimer->isTicking())
                maCallbackTimer->start();
        }
    }
    else if (!rNew.empty())
    {
        // decomposition defined/set/changed, init & start timer
        maCallbackTimer.set(new LocalCallbackTimer(*this));
        maCallbackTimer->setRemainingTime(salhelper::TTimeValue(maCallbackSeconds, 0));
        maCallbackTimer->start();
    }

    // tdf#158913 need to secure change when flush/multithreading is in use
    std::lock_guard Guard(maCallbackLock);
    maBuffered2DDecomposition = std::move(rNew);
}

BufferedDecompositionPrimitive2D::BufferedDecompositionPrimitive2D()
    : maBuffered2DDecomposition()
    , maCallbackTimer()
    , maCallbackLock()
    , maCallbackSeconds(0)
    , mnTransparenceForShadow(0)
{
}

BufferedDecompositionPrimitive2D::~BufferedDecompositionPrimitive2D()
{
    if (maCallbackTimer.is())
    {
        // no more decomposition, end callback
        static_cast<LocalCallbackTimer*>(maCallbackTimer.get())->clearCallback();
        maCallbackTimer->stop();
    }
}

void BufferedDecompositionPrimitive2D::get2DDecomposition(
    Primitive2DDecompositionVisitor& rVisitor,
    const geometry::ViewInformation2D& rViewInformation) const
{
    if (getBuffered2DDecomposition().empty())
    {
        Primitive2DContainer aNewSequence;
        create2DDecomposition(aNewSequence, rViewInformation);
        const_cast<BufferedDecompositionPrimitive2D*>(this)->setBuffered2DDecomposition(
            std::move(aNewSequence));
    }

    if (0 == maCallbackSeconds)
    {
        // no flush/multithreading is in use, just call
        rVisitor.visit(getBuffered2DDecomposition());
        return;
    }

    // tdf#158913 need to secure 'visit' when flush/multithreading is in use,
    // so that the local non-ref-Counted instance of the decomposition gets not
    // manipulated (e.g. deleted)
    std::lock_guard Guard(maCallbackLock);
    rVisitor.visit(getBuffered2DDecomposition());
}

} // end of namespace drawinglayer::primitive2d

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */