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
12 #include <algorithm>
13
14 namespace sksg {
15
Group(std::vector<sk_sp<RenderNode>> children)16 Group::Group(std::vector<sk_sp<RenderNode>> children)
17 : fChildren(std::move(children)) {
18 for (const auto& child : fChildren) {
19 this->observeInval(child);
20 }
21 }
22
~Group()23 Group::~Group() {
24 for (const auto& child : fChildren) {
25 this->unobserveInval(child);
26 }
27 }
28
clear()29 void Group::clear() {
30 for (const auto& child : fChildren) {
31 this->unobserveInval(child);
32 }
33 fChildren.clear();
34 }
35
addChild(sk_sp<RenderNode> node)36 void Group::addChild(sk_sp<RenderNode> node) {
37 // should we allow duplicates?
38 for (const auto& child : fChildren) {
39 if (child == node) {
40 return;
41 }
42 }
43
44 this->observeInval(node);
45 fChildren.push_back(std::move(node));
46
47 this->invalidate();
48 }
49
removeChild(const sk_sp<RenderNode> & node)50 void Group::removeChild(const sk_sp<RenderNode>& node) {
51 SkDEBUGCODE(const auto origSize = fChildren.size());
52 fChildren.erase(std::remove(fChildren.begin(), fChildren.end(), node), fChildren.end());
53 SkASSERT(fChildren.size() == origSize - 1);
54
55 this->unobserveInval(node);
56 this->invalidate();
57 }
58
onRender(SkCanvas * canvas,const RenderContext * ctx) const59 void Group::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
60 // TODO: this heuristic works at the moment, but:
61 // a) it is fragile because it relies on all leaf render nodes being atomic draws
62 // b) could be improved by e.g. detecting all leaf render draws are non-overlapping
63 const auto isolate = fChildren.size() > 1;
64 const auto local_ctx = ScopedRenderContext(canvas, ctx).setIsolation(this->bounds(),
65 canvas->getTotalMatrix(),
66 isolate);
67
68 for (const auto& child : fChildren) {
69 child->render(canvas, local_ctx);
70 }
71 }
72
onNodeAt(const SkPoint & p) const73 const RenderNode* Group::onNodeAt(const SkPoint& p) const {
74 for (auto it = fChildren.crbegin(); it != fChildren.crend(); ++it) {
75 if (const auto* node = (*it)->nodeAt(p)) {
76 return node;
77 }
78 }
79
80 return nullptr;
81 }
82
onRevalidate(InvalidationController * ic,const SkMatrix & ctm)83 SkRect Group::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
84 SkASSERT(this->hasInval());
85
86 SkRect bounds = SkRect::MakeEmpty();
87
88 for (const auto& child : fChildren) {
89 bounds.join(child->revalidate(ic, ctm));
90 }
91
92 return bounds;
93 }
94
95 } // namespace sksg
96