Home | History | Annotate | Download | only in core
      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 
      8 #include "SkCanvas.h"
      9 #include "SkTLazy.h"
     10 #include "SkMiniRecorder.h"
     11 #include "SkOnce.h"
     12 #include "SkPicture.h"
     13 #include "SkPictureCommon.h"
     14 #include "SkRecordDraw.h"
     15 #include "SkTextBlob.h"
     16 
     17 using namespace SkRecords;
     18 
     19 class SkEmptyPicture final : public SkPicture {
     20 public:
     21     void playback(SkCanvas*, AbortCallback*) const override { }
     22 
     23     size_t approximateBytesUsed() const override { return sizeof(*this); }
     24     int    approximateOpCount()   const override { return 0; }
     25     SkRect cullRect()             const override { return SkRect::MakeEmpty(); }
     26     int    numSlowPaths()         const override { return 0; }
     27     bool   willPlayBackBitmaps()  const override { return false; }
     28 };
     29 
     30 template <typename T>
     31 class SkMiniPicture final : public SkPicture {
     32 public:
     33     SkMiniPicture(SkRect cull, T* op) : fCull(cull) {
     34         memcpy(&fOp, op, sizeof(fOp));  // We take ownership of op's guts.
     35     }
     36 
     37     void playback(SkCanvas* c, AbortCallback*) const override {
     38         SkRecords::Draw(c, nullptr, nullptr, 0, nullptr)(fOp);
     39     }
     40 
     41     size_t approximateBytesUsed() const override { return sizeof(*this); }
     42     int    approximateOpCount()   const override { return 1; }
     43     SkRect cullRect()             const override { return fCull; }
     44     bool   willPlayBackBitmaps()  const override { return SkBitmapHunter()(fOp); }
     45     int    numSlowPaths()         const override {
     46         SkPathCounter counter;
     47         counter(fOp);
     48         return counter.fNumSlowPathsAndDashEffects;
     49     }
     50 
     51 private:
     52     SkRect fCull;
     53     T      fOp;
     54 };
     55 
     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(SkRect::MakeEmpty());
     63     }
     64     SkASSERT(fState == State::kEmpty);
     65 }
     66 
     67 #define TRY_TO_STORE(Type, ...)                    \
     68     if (fState != State::kEmpty) { return false; } \
     69     fState = State::k##Type;                       \
     70     new (fBuffer.get()) Type{__VA_ARGS__};         \
     71     return true
     72 
     73 bool SkMiniRecorder::drawRect(const SkRect& rect, const SkPaint& paint) {
     74     TRY_TO_STORE(DrawRect, paint, rect);
     75 }
     76 
     77 bool SkMiniRecorder::drawPath(const SkPath& path, const SkPaint& paint) {
     78     TRY_TO_STORE(DrawPath, paint, path);
     79 }
     80 
     81 bool SkMiniRecorder::drawTextBlob(const SkTextBlob* b, SkScalar x, SkScalar y, const SkPaint& p) {
     82     TRY_TO_STORE(DrawTextBlob, p, sk_ref_sp(b), x, y);
     83 }
     84 #undef TRY_TO_STORE
     85 
     86 
     87 sk_sp<SkPicture> SkMiniRecorder::detachAsPicture(const SkRect& cull) {
     88 #define CASE(Type)              \
     89     case State::k##Type:        \
     90         fState = State::kEmpty; \
     91         return sk_make_sp<SkMiniPicture<Type>>(cull, reinterpret_cast<Type*>(fBuffer.get()))
     92 
     93     static SkOnce once;
     94     static SkPicture* empty;
     95 
     96     switch (fState) {
     97         case State::kEmpty:
     98             once([]{ empty = new SkEmptyPicture; });
     99             return sk_ref_sp(empty);
    100         CASE(DrawPath);
    101         CASE(DrawRect);
    102         CASE(DrawTextBlob);
    103     }
    104     SkASSERT(false);
    105     return nullptr;
    106 #undef CASE
    107 }
    108 
    109 void SkMiniRecorder::flushAndReset(SkCanvas* canvas) {
    110 #define CASE(Type)                                                  \
    111     case State::k##Type: {                                          \
    112         fState = State::kEmpty;                                     \
    113         Type* op = reinterpret_cast<Type*>(fBuffer.get());          \
    114         SkRecords::Draw(canvas, nullptr, nullptr, 0, nullptr)(*op); \
    115         op->~Type();                                                \
    116     } return
    117 
    118     switch (fState) {
    119         case State::kEmpty: return;
    120         CASE(DrawPath);
    121         CASE(DrawRect);
    122         CASE(DrawTextBlob);
    123     }
    124     SkASSERT(false);
    125 #undef CASE
    126 }
    127