SkMiniRecorder.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*
  2. * Copyright 2015 Google Inc.
  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. #include "include/core/SkCanvas.h"
  8. #include "include/core/SkPicture.h"
  9. #include "include/core/SkTextBlob.h"
  10. #include "include/private/SkOnce.h"
  11. #include "src/core/SkMiniRecorder.h"
  12. #include "src/core/SkPictureCommon.h"
  13. #include "src/core/SkRecordDraw.h"
  14. #include "src/core/SkRectPriv.h"
  15. #include "src/core/SkTLazy.h"
  16. #include <new>
  17. using namespace SkRecords;
  18. class SkEmptyPicture final : public SkPicture {
  19. public:
  20. void playback(SkCanvas*, AbortCallback*) const override { }
  21. size_t approximateBytesUsed() const override { return sizeof(*this); }
  22. int approximateOpCount() const override { return 0; }
  23. SkRect cullRect() const override { return SkRect::MakeEmpty(); }
  24. };
  25. // Calculate conservative bounds for each type of draw op that can be its own mini picture.
  26. // These are fairly easy because we know they can't be affected by any matrix or saveLayers.
  27. static SkRect adjust_for_paint(SkRect bounds, const SkPaint& paint) {
  28. return paint.canComputeFastBounds() ? paint.computeFastBounds(bounds, &bounds)
  29. : SkRectPriv::MakeLargest();
  30. }
  31. static SkRect bounds(const DrawRect& op) {
  32. return adjust_for_paint(op.rect, op.paint);
  33. }
  34. static SkRect bounds(const DrawPath& op) {
  35. return op.path.isInverseFillType() ? SkRectPriv::MakeLargest()
  36. : adjust_for_paint(op.path.getBounds(), op.paint);
  37. }
  38. static SkRect bounds(const DrawTextBlob& op) {
  39. return adjust_for_paint(op.blob->bounds().makeOffset(op.x, op.y), op.paint);
  40. }
  41. template <typename T>
  42. class SkMiniPicture final : public SkPicture {
  43. public:
  44. SkMiniPicture(const SkRect* cull, T* op) : fCull(cull ? *cull : bounds(*op)) {
  45. memcpy(&fOp, op, sizeof(fOp)); // We take ownership of op's guts.
  46. }
  47. void playback(SkCanvas* c, AbortCallback*) const override {
  48. SkRecords::Draw(c, nullptr, nullptr, 0, nullptr)(fOp);
  49. }
  50. size_t approximateBytesUsed() const override { return sizeof(*this); }
  51. int approximateOpCount() const override { return 1; }
  52. SkRect cullRect() const override { return fCull; }
  53. private:
  54. SkRect fCull;
  55. T fOp;
  56. };
  57. SkMiniRecorder::SkMiniRecorder() : fState(State::kEmpty) {}
  58. SkMiniRecorder::~SkMiniRecorder() {
  59. if (fState != State::kEmpty) {
  60. // We have internal state pending.
  61. // Detaching then deleting a picture is an easy way to clean up.
  62. (void)this->detachAsPicture(nullptr);
  63. }
  64. SkASSERT(fState == State::kEmpty);
  65. }
  66. #define TRY_TO_STORE(Type, ...) \
  67. if (fState != State::kEmpty) { return false; } \
  68. fState = State::k##Type; \
  69. new (fBuffer.get()) Type{__VA_ARGS__}; \
  70. return true
  71. bool SkMiniRecorder::drawRect(const SkRect& rect, const SkPaint& paint) {
  72. TRY_TO_STORE(DrawRect, paint, rect);
  73. }
  74. bool SkMiniRecorder::drawPath(const SkPath& path, const SkPaint& paint) {
  75. TRY_TO_STORE(DrawPath, paint, path);
  76. }
  77. bool SkMiniRecorder::drawTextBlob(const SkTextBlob* b, SkScalar x, SkScalar y, const SkPaint& p) {
  78. TRY_TO_STORE(DrawTextBlob, p, sk_ref_sp(b), x, y);
  79. }
  80. #undef TRY_TO_STORE
  81. sk_sp<SkPicture> SkMiniRecorder::detachAsPicture(const SkRect* cull) {
  82. #define CASE(Type) \
  83. case State::k##Type: \
  84. fState = State::kEmpty; \
  85. return sk_make_sp<SkMiniPicture<Type>>(cull, reinterpret_cast<Type*>(fBuffer.get()))
  86. static SkOnce once;
  87. static SkPicture* empty;
  88. switch (fState) {
  89. case State::kEmpty:
  90. once([]{ empty = new SkEmptyPicture; });
  91. return sk_ref_sp(empty);
  92. CASE(DrawPath);
  93. CASE(DrawRect);
  94. CASE(DrawTextBlob);
  95. }
  96. SkASSERT(false);
  97. return nullptr;
  98. #undef CASE
  99. }
  100. void SkMiniRecorder::flushAndReset(SkCanvas* canvas) {
  101. #define CASE(Type) \
  102. case State::k##Type: { \
  103. fState = State::kEmpty; \
  104. Type* op = reinterpret_cast<Type*>(fBuffer.get()); \
  105. SkRecords::Draw(canvas, nullptr, nullptr, 0, nullptr)(*op); \
  106. op->~Type(); \
  107. } return
  108. switch (fState) {
  109. case State::kEmpty: return;
  110. CASE(DrawPath);
  111. CASE(DrawRect);
  112. CASE(DrawTextBlob);
  113. }
  114. SkASSERT(false);
  115. #undef CASE
  116. }