/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "modules/sksg/include/SkSGGroup.h" #include "include/core/SkCanvas.h" #include namespace sksg { Group::Group() = default; Group::Group(std::vector> children) : fChildren(std::move(children)) { for (const auto& child : fChildren) { this->observeInval(child); } } Group::~Group() { for (const auto& child : fChildren) { this->unobserveInval(child); } } void Group::clear() { for (const auto& child : fChildren) { this->unobserveInval(child); } fChildren.clear(); } void Group::addChild(sk_sp node) { // should we allow duplicates? for (const auto& child : fChildren) { if (child == node) { return; } } this->observeInval(node); fChildren.push_back(std::move(node)); this->invalidate(); } void Group::removeChild(const sk_sp& node) { SkDEBUGCODE(const auto origSize = fChildren.size()); fChildren.erase(std::remove(fChildren.begin(), fChildren.end(), node), fChildren.end()); SkASSERT(fChildren.size() == origSize - 1); this->unobserveInval(node); this->invalidate(); } void Group::onRender(SkCanvas* canvas, const RenderContext* ctx) const { const auto local_ctx = ScopedRenderContext(canvas, ctx).setIsolation(this->bounds(), canvas->getTotalMatrix(), fRequiresIsolation); for (const auto& child : fChildren) { child->render(canvas, local_ctx); } } const RenderNode* Group::onNodeAt(const SkPoint& p) const { for (auto it = fChildren.crbegin(); it != fChildren.crend(); ++it) { if (const auto* node = (*it)->nodeAt(p)) { return node; } } return nullptr; } SkRect Group::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { SkASSERT(this->hasInval()); SkRect bounds = SkRect::MakeEmpty(); fRequiresIsolation = false; for (size_t i = 0; i < fChildren.size(); ++i) { const auto child_bounds = fChildren[i]->revalidate(ic, ctm); // If any of the child nodes overlap, group effects require layer isolation. if (!fRequiresIsolation && i > 0 && child_bounds.intersects(bounds)) { #if 1 // Testing conservatively against the union of prev bounds is cheap and good enough. fRequiresIsolation = true; #else // Testing exhaustively doesn't seem to increase the layer elision rate in practice. for (size_t j = 0; j < i; ++ j) { if (child_bounds.intersects(fChildren[i]->bounds())) { fRequiresIsolation = true; break; } } #endif } bounds.join(child_bounds); } return bounds; } } // namespace sksg