| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CC_PAINT_RECORD_PAINT_CANVAS_H_ |
| #define CC_PAINT_RECORD_PAINT_CANVAS_H_ |
| |
| #include "base/compiler_specific.h" |
| #include "base/memory/raw_ptr.h" |
| #include "build/build_config.h" |
| #include "cc/paint/paint_canvas.h" |
| #include "cc/paint/paint_flags.h" |
| #include "cc/paint/paint_op_buffer.h" |
| #include "cc/paint/paint_record.h" |
| #include "cc/paint/skottie_color_map.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "third_party/skia/include/utils/SkNoDrawCanvas.h" |
| |
| namespace cc { |
| |
| // This implementation of PaintCanvas records paint operations into the given |
| // PaintOpBuffer. The methods that inspect the current clip or CTM are not |
| // implemented (DCHECK will fail if called). Use InspectableRecordPaintCanvas |
| // instead if the client needs to call those methods. |
| class CC_PAINT_EXPORT RecordPaintCanvas : public PaintCanvas { |
| public: |
| RecordPaintCanvas(); |
| ~RecordPaintCanvas() override; |
| |
| RecordPaintCanvas(const RecordPaintCanvas&) = delete; |
| RecordPaintCanvas& operator=(const RecordPaintCanvas&) = delete; |
| |
| virtual PaintRecord ReleaseAsRecord(); |
| |
| bool HasRecordedDrawOps() const { return buffer_.has_draw_ops(); } |
| size_t TotalOpCount() const { return buffer_.total_op_count(); } |
| size_t OpBytesUsed() const { return buffer_.paint_ops_size(); } |
| |
| void* accessTopLayerPixels(SkImageInfo* info, |
| size_t* rowBytes, |
| SkIPoint* origin = nullptr) override; |
| |
| void flush() override; |
| bool NeedsFlush() const override; |
| |
| int save() override; |
| int saveLayer(const SkRect* bounds, const PaintFlags* flags) final; |
| int saveLayerAlpha(const SkRect* bounds, uint8_t alpha) override; |
| void restore() override; |
| int getSaveCount() const final; |
| void restoreToCount(int save_count) override; |
| |
| void translate(SkScalar dx, SkScalar dy) override; |
| void scale(SkScalar sx, SkScalar sy) override; |
| void rotate(SkScalar degrees) override; |
| void concat(const SkM44& matrix) override; |
| void setMatrix(const SkM44& matrix) override; |
| |
| void clipRect(const SkRect& rect, SkClipOp op, bool antialias) override; |
| void clipRRect(const SkRRect& rrect, SkClipOp op, bool antialias) final; |
| void clipPath(const SkPath& path, |
| SkClipOp op, |
| bool antialias, |
| UsePaintCache use_paint_cache) final; |
| |
| // These state-query functions can be called only if `size` is not empty in |
| // the constructor. With this restriction, we don't need to create |
| // SkNoDrawCanvas for clients that only need recording. |
| SkImageInfo imageInfo() const override; |
| SkRect getLocalClipBounds() const override; |
| bool getLocalClipBounds(SkRect* bounds) const override; |
| SkIRect getDeviceClipBounds() const override; |
| bool getDeviceClipBounds(SkIRect* bounds) const override; |
| bool isClipEmpty() const override; |
| SkM44 getLocalToDevice() const override; |
| |
| void drawColor(SkColor4f color, SkBlendMode mode) override; |
| void clear(SkColor4f color) override; |
| void drawLine(SkScalar x0, |
| SkScalar y0, |
| SkScalar x1, |
| SkScalar y1, |
| const PaintFlags& flags) override; |
| void drawRect(const SkRect& rect, const PaintFlags& flags) override; |
| void drawIRect(const SkIRect& rect, const PaintFlags& flags) override; |
| void drawOval(const SkRect& oval, const PaintFlags& flags) override; |
| void drawRRect(const SkRRect& rrect, const PaintFlags& flags) override; |
| void drawDRRect(const SkRRect& outer, |
| const SkRRect& inner, |
| const PaintFlags& flags) override; |
| void drawRoundRect(const SkRect& rect, |
| SkScalar rx, |
| SkScalar ry, |
| const PaintFlags& flags) override; |
| void drawPath(const SkPath& path, |
| const PaintFlags& flags, |
| UsePaintCache use_paint_cache) override; |
| void drawImage(const PaintImage& image, |
| SkScalar left, |
| SkScalar top, |
| const SkSamplingOptions&, |
| const PaintFlags* flags) override; |
| void drawImageRect(const PaintImage& image, |
| const SkRect& src, |
| const SkRect& dst, |
| const SkSamplingOptions&, |
| const PaintFlags* flags, |
| SkCanvas::SrcRectConstraint constraint) override; |
| void drawSkottie(scoped_refptr<SkottieWrapper> skottie, |
| const SkRect& dst, |
| float t, |
| SkottieFrameDataMap images, |
| const SkottieColorMap& color_map, |
| SkottieTextPropertyValueMap text_map) override; |
| void drawTextBlob(sk_sp<SkTextBlob> blob, |
| SkScalar x, |
| SkScalar y, |
| const PaintFlags& flags) override; |
| void drawTextBlob(sk_sp<SkTextBlob> blob, |
| SkScalar x, |
| SkScalar y, |
| NodeId node_id, |
| const PaintFlags& flags) override; |
| void drawPicture(PaintRecord record) override; |
| |
| void Annotate(AnnotationType type, |
| const SkRect& rect, |
| sk_sp<SkData> data) override; |
| void recordCustomData(uint32_t id) override; |
| void setNodeId(int) override; |
| |
| // Don't shadow non-virtual helper functions. |
| using PaintCanvas::clipPath; |
| using PaintCanvas::clipRect; |
| using PaintCanvas::clipRRect; |
| using PaintCanvas::drawColor; |
| using PaintCanvas::drawImage; |
| using PaintCanvas::drawPath; |
| using PaintCanvas::drawPicture; |
| |
| #if DCHECK_IS_ON() |
| void EnterDisableFlushCheckScope() { ++disable_flush_check_scope_; } |
| void LeaveDisableFlushCheckScope() { DCHECK(disable_flush_check_scope_--); } |
| bool IsInDisableFlushCheckScope() { return disable_flush_check_scope_; } |
| #endif |
| |
| class DisableFlushCheckScope { |
| // Create an object of this type to temporarily allow draw commands to be |
| // recorded while the recording is marked as needing to be flushed. This is |
| // meant to be used to allow client code to issue the commands necessary to |
| // reach a state where the recording can be safely flushed before beginning |
| // to enforce a check that forbids recording additional draw commands after |
| // a flush was requested. |
| public: |
| explicit DisableFlushCheckScope(RecordPaintCanvas* canvas) { |
| #if DCHECK_IS_ON() |
| // We require that NeedsFlush be false upon entering a top-level scope |
| // to prevent consecutive scopes from evading evading flush checks |
| // indefinitely. |
| DCHECK(!canvas->NeedsFlush() || canvas->IsInDisableFlushCheckScope()); |
| canvas->EnterDisableFlushCheckScope(); |
| canvas_ = canvas; |
| #endif |
| } |
| ~DisableFlushCheckScope() { |
| #if DCHECK_IS_ON() |
| canvas_->LeaveDisableFlushCheckScope(); |
| #endif |
| } |
| |
| private: |
| #if DCHECK_IS_ON() |
| raw_ptr<RecordPaintCanvas> canvas_; |
| #endif |
| }; |
| |
| protected: |
| virtual int saveLayerInternal(const SkRect* bounds, const PaintFlags* flags); |
| virtual void clipRRectInternal(const SkRRect& rrect, |
| SkClipOp op, |
| bool antialias); |
| virtual void clipPathInternal(const SkPath& path, |
| SkClipOp op, |
| bool antialias, |
| UsePaintCache use_paint_cache); |
| |
| private: |
| template <typename T, typename... Args> |
| void push(Args&&... args); |
| |
| PaintOpBuffer buffer_; |
| int save_count_ = 1; |
| |
| bool needs_flush_ = false; |
| #if DCHECK_IS_ON() |
| unsigned disable_flush_check_scope_ = 0; |
| #endif |
| }; |
| |
| // Besides the recording functions, this implementation of PaintCanvas allows |
| // inspection of the current clip and CTM during recording. |
| class CC_PAINT_EXPORT InspectableRecordPaintCanvas : public RecordPaintCanvas { |
| public: |
| explicit InspectableRecordPaintCanvas(const gfx::Size& size); |
| ~InspectableRecordPaintCanvas() override; |
| |
| int save() override; |
| int saveLayerAlpha(const SkRect* bounds, uint8_t alpha) override; |
| void restore() override; |
| |
| void translate(SkScalar dx, SkScalar dy) override; |
| void scale(SkScalar sx, SkScalar sy) override; |
| void rotate(SkScalar degrees) override; |
| void concat(const SkM44& matrix) override; |
| void setMatrix(const SkM44& matrix) override; |
| |
| void clipRect(const SkRect& rect, SkClipOp op, bool antialias) override; |
| |
| SkImageInfo imageInfo() const override; |
| SkRect getLocalClipBounds() const override; |
| bool getLocalClipBounds(SkRect* bounds) const override; |
| SkIRect getDeviceClipBounds() const override; |
| bool getDeviceClipBounds(SkIRect* bounds) const override; |
| bool isClipEmpty() const override; |
| SkM44 getLocalToDevice() const override; |
| |
| // Don't shadow non-virtual helper functions. |
| using RecordPaintCanvas::clipRect; |
| |
| private: |
| int saveLayerInternal(const SkRect* bounds, const PaintFlags* flags) override; |
| void clipRRectInternal(const SkRRect& rrect, |
| SkClipOp op, |
| bool antialias) override; |
| void clipPathInternal(const SkPath& path, |
| SkClipOp op, |
| bool antialias, |
| UsePaintCache use_paint_cache) override; |
| |
| int CheckSaveCount(int super_prev_save_count, int canvas_prev_save_count); |
| |
| SkNoDrawCanvas canvas_; |
| }; |
| |
| } // namespace cc |
| |
| #endif // CC_PAINT_RECORD_PAINT_CANVAS_H_ |