1/*
2 * Copyright 2019 Google LLC.
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 "experimental/xform/SkXform.h"
9
10static std::atomic<uint32_t> gGenID{1};
11Xform::GenID Xform::NextGenID() {
12    return gGenID++;
13}
14
15#ifdef SK_DEBUG
16void Xform::debugValidate() const {
17    if (this->isCached() && fParent) {
18        SkASSERT(fParent->isCached());
19    }
20    for (auto c : fChildren) {
21        SkASSERT(c->parent() == this);
22        c->debugValidate();
23    }
24}
25#endif
26
27void Xform::setParent(sk_sp<Xform> parent) {
28    if (parent == fParent) {
29        return;
30    }
31
32    if (fParent) {
33        fParent->internalRemoveChild(this);
34    }
35    if (parent) {
36        parent->internalAddChild(this);
37    }
38    fParent = std::move(parent);
39
40    // Potentially we could skip this if knew that our old and new parents
41    // were both cached, and they started us in the same state...
42    // For now, we conservatively always inval
43    this->invalidateCaches();
44
45    this->debugValidate();
46}
47
48void Xform::internalAddChild(Xform* child) {
49    SkASSERT(fChildren.find(child) < 0);
50    fChildren.push_back(child);
51}
52
53void Xform::internalRemoveChild(Xform* child) {
54    int index = fChildren.find(child);
55    SkASSERT(index >= 0);
56    fChildren.removeShuffle(index);
57}
58
59void Xform::invalidateCaches() {
60    fGenID = 0;
61    if (this->isCached()) {
62        this->internalInvalidateCaches();
63        for (auto c : fChildren) {
64            c->invalidateCaches();
65        }
66    }
67}
68
69void Xform::visit(XformResolver* resolver) {
70    this->onVisit(resolver);
71}
72
73void Xform::setCache(const SkMatrix& ctm, sk_sp<ClipCache> clip) {
74    fCTM = ctm;
75    fClip = std::move(clip);
76    fGenID = NextGenID();
77}
78
79//////////////////////////////////////////////////////////////////////////////////////////////////
80
81void MatrixXF::onVisit(XformResolver* resolver) {
82    resolver->concat(fLocalMatrix);
83}
84
85void ClipXF::onVisit(XformResolver* resolver) {
86    resolver->clipRect(fRect, fOp);
87}
88