text: /*
   * Copyright 2017 Google Inc.
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  #ifndef SkSGTransform_DEFINED
  #define SkSGTransform_DEFINED
  
  #include "modules/sksg/include/SkSGEffectNode.h"
  
  class SkM44;
  class SkMatrix;
  
  namespace sksg {
  
  /**
   * Transformations base class.
   */
  class Transform : public Node {
   public:
    // Compose T' = A x B
    static sk_sp<Transform> MakeConcat(sk_sp<Transform> a, sk_sp<Transform> b);
  
    // T' = Inv(T)
    static sk_sp<Transform> MakeInverse(sk_sp<Transform> t);
  
   protected:
    Transform();
  
    virtual bool is44() const = 0;
  
    virtual SkMatrix asMatrix() const = 0;
    virtual SkM44 asM44() const = 0;
  
   private:
    friend class TransformPriv;
  
    using INHERITED = Node;
  };
  
  /**
   * Concrete, matrix-backed Transform.
   *
   * Supported instantiations: SkMatrix, SkM44.
   *
   * Sample use:
   *
   *   auto m33 = Matrix<SkMatrix>::Make(SkMatrix::I());
   *   ...
   *   m33->setMatrix(SkMatrix::Translate(10, 10));
   *
   */
  template <typename T>
  class Matrix final : public Transform {
   public:
    template <
        typename = std::enable_if<std::is_same<T, SkMatrix>::value || std::is_same<T, SkM44>::value>>
    static sk_sp<Matrix> Make(const T& m) {
      return sk_sp<Matrix>(new Matrix(m));
    }
  
    SG_ATTRIBUTE(Matrix, T, fMatrix)
  
   protected:
    explicit Matrix(const T& m) : fMatrix(m) {}
  
    SkRect onRevalidate(InvalidationController*, const SkMatrix&) override {
      return SkRect::MakeEmpty();
    }
  
    bool is44() const override { return std::is_same<T, SkM44>::value; }
  
    SkMatrix asMatrix() const override;
    SkM44 asM44() const override;
  
   private:
    T fMatrix;
  
    using INHERITED = Transform;
  };
  
  /**
   * Concrete Effect node, binding a Transform to a RenderNode.
   */
  class TransformEffect final : public EffectNode {
   public:
    static sk_sp<TransformEffect> Make(sk_sp<RenderNode> child, sk_sp<Transform> transform) {
      return child && transform
                 ? sk_sp<TransformEffect>(new TransformEffect(std::move(child), std::move(transform)))
                 : nullptr;
    }
  
    static sk_sp<TransformEffect> Make(sk_sp<RenderNode> child, const SkMatrix& m) {
      return Make(std::move(child), Matrix<SkMatrix>::Make(m));
    }
  
    ~TransformEffect() override;
  
    const sk_sp<Transform>& getTransform() const { return fTransform; }
  
   protected:
    void onRender(SkCanvas*, const RenderContext*) const override;
    const RenderNode* onNodeAt(const SkPoint&) const override;
  
    SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;
  
   private:
    TransformEffect(sk_sp<RenderNode>, sk_sp<Transform>);
  
    const sk_sp<Transform> fTransform;
  
    using INHERITED = EffectNode;
  };
  
  }  // namespace sksg
  
  #endif  // SkSGTransform_DEFINED
  