| /* |
| * Copyright 2019 Google LLC. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "experimental/xform/SkXform.h" |
| |
| static std::atomic<uint32_t> gGenID{1}; |
| Xform::GenID Xform::NextGenID() { |
| return gGenID++; |
| } |
| |
| #ifdef SK_DEBUG |
| void Xform::debugValidate() const { |
| if (this->isCached() && fParent) { |
| SkASSERT(fParent->isCached()); |
| } |
| for (auto c : fChildren) { |
| SkASSERT(c->parent() == this); |
| c->debugValidate(); |
| } |
| } |
| #endif |
| |
| void Xform::setParent(sk_sp<Xform> parent) { |
| if (parent == fParent) { |
| return; |
| } |
| |
| if (fParent) { |
| fParent->internalRemoveChild(this); |
| } |
| if (parent) { |
| parent->internalAddChild(this); |
| } |
| fParent = std::move(parent); |
| |
| // Potentially we could skip this if knew that our old and new parents |
| // were both cached, and they started us in the same state... |
| // For now, we conservatively always inval |
| this->invalidateCaches(); |
| |
| this->debugValidate(); |
| } |
| |
| void Xform::internalAddChild(Xform* child) { |
| SkASSERT(fChildren.find(child) < 0); |
| fChildren.push_back(child); |
| } |
| |
| void Xform::internalRemoveChild(Xform* child) { |
| int index = fChildren.find(child); |
| SkASSERT(index >= 0); |
| fChildren.removeShuffle(index); |
| } |
| |
| void Xform::invalidateCaches() { |
| fGenID = 0; |
| if (this->isCached()) { |
| this->internalInvalidateCaches(); |
| for (auto c : fChildren) { |
| c->invalidateCaches(); |
| } |
| } |
| } |
| |
| void Xform::visit(XformResolver* resolver) { |
| this->onVisit(resolver); |
| } |
| |
| void Xform::setCache(const SkMatrix& ctm, sk_sp<ClipCache> clip) { |
| fCTM = ctm; |
| fClip = std::move(clip); |
| fGenID = NextGenID(); |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| void MatrixXF::onVisit(XformResolver* resolver) { |
| resolver->concat(fLocalMatrix); |
| } |
| |
| void ClipXF::onVisit(XformResolver* resolver) { |
| resolver->clipRect(fRect, fOp); |
| } |