Coverage Report

Created: 2024-09-14 07:19

/src/skia/modules/sksg/src/SkSGGroup.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2017 Google Inc.
3
 *
4
 * Use of this source code is governed by a BSD-style license that can be
5
 * found in the LICENSE file.
6
 */
7
8
#include "modules/sksg/include/SkSGGroup.h"
9
10
#include "include/core/SkCanvas.h"
11
#include "include/private/base/SkAssert.h"
12
#include "include/private/base/SkDebug.h"
13
#include "modules/sksg/include/SkSGNode.h"
14
15
#include <algorithm>
16
17
class SkMatrix;
18
struct SkPoint;
19
20
namespace sksg {
21
class InvalidationController;
22
23
0
Group::Group() = default;
24
25
Group::Group(std::vector<sk_sp<RenderNode>> children)
26
25.2k
    : fChildren(std::move(children)) {
27
183k
    for (const auto& child : fChildren) {
28
183k
        this->observeInval(child);
29
183k
    }
30
25.2k
}
31
32
25.2k
Group::~Group() {
33
183k
    for (const auto& child : fChildren) {
34
183k
        this->unobserveInval(child);
35
183k
    }
36
25.2k
}
37
38
0
void Group::clear() {
39
0
    for (const auto& child : fChildren) {
40
0
        this->unobserveInval(child);
41
0
    }
42
0
    fChildren.clear();
43
0
}
44
45
0
void Group::addChild(sk_sp<RenderNode> node) {
46
    // should we allow duplicates?
47
0
    for (const auto& child : fChildren) {
48
0
        if (child == node) {
49
0
            return;
50
0
        }
51
0
    }
52
53
0
    this->observeInval(node);
54
0
    fChildren.push_back(std::move(node));
55
56
0
    this->invalidate();
57
0
}
58
59
0
void Group::removeChild(const sk_sp<RenderNode>& node) {
60
0
    SkDEBUGCODE(const auto origSize = fChildren.size());
61
0
    fChildren.erase(std::remove(fChildren.begin(), fChildren.end(), node), fChildren.end());
62
0
    SkASSERT(fChildren.size() == origSize - 1);
63
64
0
    this->unobserveInval(node);
65
0
    this->invalidate();
66
0
}
67
68
4.88k
void Group::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
69
4.88k
    const auto local_ctx = ScopedRenderContext(canvas, ctx).setIsolation(this->bounds(),
70
4.88k
                                                                         canvas->getTotalMatrix(),
71
4.88k
                                                                         fRequiresIsolation);
72
73
38.4k
    for (const auto& child : fChildren) {
74
38.4k
        child->render(canvas, local_ctx);
75
38.4k
    }
76
4.88k
}
77
78
0
const RenderNode* Group::onNodeAt(const SkPoint& p) const {
79
0
    for (auto it = fChildren.crbegin(); it != fChildren.crend(); ++it) {
80
0
        if (const auto* node = (*it)->nodeAt(p)) {
81
0
            return node;
82
0
        }
83
0
    }
84
85
0
    return nullptr;
86
0
}
87
88
35.3k
SkRect Group::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
89
35.3k
    SkASSERT(this->hasInval());
90
91
35.3k
    SkRect bounds = SkRect::MakeEmpty();
92
35.3k
    fRequiresIsolation = false;
93
94
333k
    for (size_t i = 0; i < fChildren.size(); ++i) {
95
298k
        const auto child_bounds = fChildren[i]->revalidate(ic, ctm);
96
97
        // If any of the child nodes overlap, group effects require layer isolation.
98
298k
        if (!fRequiresIsolation && i > 0 && child_bounds.intersects(bounds)) {
99
24.2k
#if 1
100
            // Testing conservatively against the union of prev bounds is cheap and good enough.
101
24.2k
            fRequiresIsolation = true;
102
#else
103
            // Testing exhaustively doesn't seem to increase the layer elision rate in practice.
104
            for (size_t j = 0; j < i; ++ j) {
105
                if (child_bounds.intersects(fChildren[i]->bounds())) {
106
                    fRequiresIsolation = true;
107
                    break;
108
                }
109
            }
110
#endif
111
24.2k
        }
112
113
298k
        bounds.join(child_bounds);
114
298k
    }
115
116
35.3k
    return bounds;
117
35.3k
}
118
119
} // namespace sksg