| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef FLUTTER_DISPLAY_LIST_UTILS_DL_MATRIX_CLIP_TRACKER_H_ |
| #define FLUTTER_DISPLAY_LIST_UTILS_DL_MATRIX_CLIP_TRACKER_H_ |
| |
| #include <vector> |
| |
| #include "flutter/display_list/dl_canvas.h" |
| #include "flutter/fml/logging.h" |
| |
| #include "third_party/skia/include/core/SkM44.h" |
| #include "third_party/skia/include/core/SkMatrix.h" |
| #include "third_party/skia/include/core/SkPath.h" |
| #include "third_party/skia/include/core/SkRRect.h" |
| #include "third_party/skia/include/core/SkRect.h" |
| #include "third_party/skia/include/core/SkScalar.h" |
| |
| namespace flutter { |
| |
| class DisplayListMatrixClipTracker { |
| private: |
| using ClipOp = DlCanvas::ClipOp; |
| |
| public: |
| DisplayListMatrixClipTracker(const SkRect& cull_rect, const SkMatrix& matrix); |
| DisplayListMatrixClipTracker(const SkRect& cull_rect, const SkM44& matrix); |
| |
| // This method should almost never be used as it breaks the encapsulation |
| // of the enclosing clips. However it is needed for practical purposes in |
| // some rare cases - such as when a saveLayer is collecting rendering |
| // operations prior to applying a filter on the entire layer bounds and |
| // some of those operations fall outside the enclosing clip, but their |
| // filtered content will spread out from where they were rendered on the |
| // layer into the enclosing clipped area. |
| // Omitting the |cull_rect| argument, or passing nullptr, will restore the |
| // cull rect to the initial value it had when the tracker was constructed. |
| void resetCullRect(const SkRect* cull_rect = nullptr) { |
| current_->resetBounds(cull_rect ? *cull_rect : original_cull_rect_); |
| } |
| |
| static bool is_3x3(const SkM44& m44); |
| |
| SkRect base_device_cull_rect() const { return saved_[0]->device_cull_rect(); } |
| |
| bool using_4x4_matrix() const { return current_->is_4x4(); } |
| |
| SkM44 matrix_4x4() const { return current_->matrix_4x4(); } |
| SkMatrix matrix_3x3() const { return current_->matrix_3x3(); } |
| SkRect local_cull_rect() const { return current_->local_cull_rect(); } |
| SkRect device_cull_rect() const { return current_->device_cull_rect(); } |
| bool content_culled(const SkRect& content_bounds) const { |
| return current_->content_culled(content_bounds); |
| } |
| bool is_cull_rect_empty() const { return current_->is_cull_rect_empty(); } |
| |
| void save(); |
| void restore(); |
| void reset(); |
| int getSaveCount() { |
| // saved_[0] is always the untouched initial conditions |
| // saved_[1] is the first editable stack entry |
| return saved_.size() - 1; |
| } |
| void restoreToCount(int restore_count); |
| |
| void translate(SkScalar tx, SkScalar ty) { current_->translate(tx, ty); } |
| void scale(SkScalar sx, SkScalar sy) { current_->scale(sx, sy); } |
| void skew(SkScalar skx, SkScalar sky) { current_->skew(skx, sky); } |
| void rotate(SkScalar degrees) { current_->rotate(degrees); } |
| void transform(const SkM44& m44); |
| void transform(const SkMatrix& matrix) { current_->transform(matrix); } |
| // clang-format off |
| void transform2DAffine( |
| SkScalar mxx, SkScalar mxy, SkScalar mxt, |
| SkScalar myx, SkScalar myy, SkScalar myt); |
| void transformFullPerspective( |
| SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt, |
| SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt, |
| SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt, |
| SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt); |
| // clang-format on |
| void setTransform(const SkMatrix& matrix) { current_->setTransform(matrix); } |
| void setTransform(const SkM44& m44); |
| void setIdentity() { current_->setIdentity(); } |
| bool mapRect(SkRect* rect) const { return current_->mapRect(*rect, rect); } |
| |
| void clipRect(const SkRect& rect, ClipOp op, bool is_aa) { |
| current_->clipBounds(rect, op, is_aa); |
| } |
| void clipRRect(const SkRRect& rrect, ClipOp op, bool is_aa); |
| void clipPath(const SkPath& path, ClipOp op, bool is_aa); |
| |
| private: |
| class Data { |
| public: |
| virtual ~Data() = default; |
| |
| virtual bool is_4x4() const = 0; |
| |
| virtual SkMatrix matrix_3x3() const = 0; |
| virtual SkM44 matrix_4x4() const = 0; |
| |
| SkRect device_cull_rect() const { return cull_rect_; } |
| virtual SkRect local_cull_rect() const = 0; |
| virtual bool content_culled(const SkRect& content_bounds) const; |
| bool is_cull_rect_empty() const { return cull_rect_.isEmpty(); } |
| |
| virtual void translate(SkScalar tx, SkScalar ty) = 0; |
| virtual void scale(SkScalar sx, SkScalar sy) = 0; |
| virtual void skew(SkScalar skx, SkScalar sky) = 0; |
| virtual void rotate(SkScalar degrees) = 0; |
| virtual void transform(const SkMatrix& matrix) = 0; |
| virtual void transform(const SkM44& m44) = 0; |
| virtual void setTransform(const SkMatrix& matrix) = 0; |
| virtual void setTransform(const SkM44& m44) = 0; |
| virtual void setIdentity() = 0; |
| virtual bool mapRect(const SkRect& rect, SkRect* mapped) const = 0; |
| virtual bool canBeInverted() const = 0; |
| |
| virtual void clipBounds(const SkRect& clip, ClipOp op, bool is_aa); |
| |
| virtual void resetBounds(const SkRect& cull_rect); |
| |
| protected: |
| explicit Data(const SkRect& rect) : cull_rect_(rect) {} |
| |
| virtual bool has_perspective() const = 0; |
| |
| SkRect cull_rect_; |
| }; |
| friend class Data3x3; |
| friend class Data4x4; |
| |
| SkRect original_cull_rect_; |
| Data* current_; |
| std::vector<std::unique_ptr<Data>> saved_; |
| }; |
| |
| } // namespace flutter |
| |
| #endif // FLUTTER_DISPLAY_LIST_UTILS_DL_MATRIX_CLIP_TRACKER_H_ |