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 "SkOncePtr.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     bool   hasText()              const override { return false; }
     27     int    numSlowPaths()         const override { return 0; }
     28     bool   willPlayBackBitmaps()  const override { return false; }
     29 };
     30 SK_DECLARE_STATIC_ONCE_PTR(SkEmptyPicture, gEmptyPicture);
     31 
     32 template <typename T>
     33 class SkMiniPicture final : public SkPicture {
     34 public:
     35     SkMiniPicture(SkRect cull, T* op) : fCull(cull) {
     36         memcpy(&fOp, op, sizeof(fOp));  // We take ownership of op's guts.
     37     }
     38 
     39     void playback(SkCanvas* c, AbortCallback*) const override {
     40         SkRecords::Draw(c, nullptr, nullptr, 0, nullptr)(fOp);
     41     }
     42 
     43     size_t approximateBytesUsed() const override { return sizeof(*this); }
     44     int    approximateOpCount()   const override { return 1; }
     45     SkRect cullRect()             const override { return fCull; }
     46     bool   hasText()              const override { return SkTextHunter()(fOp); }
     47     bool   willPlayBackBitmaps()  const override { return SkBitmapHunter()(fOp); }
     48     int    numSlowPaths()         const override {
     49         SkPathCounter counter;
     50         counter(fOp);
     51         return counter.fNumSlowPathsAndDashEffects;
     52     }
     53 
     54 private:
     55     SkRect fCull;
     56     T      fOp;
     57 };
     58 
     59 
     60 SkMiniRecorder::SkMiniRecorder() : fState(State::kEmpty) {}
     61 SkMiniRecorder::~SkMiniRecorder() {
     62     if (fState != State::kEmpty) {
     63         // We have internal state pending.
     64         // Detaching then deleting a picture is an easy way to clean up.
     65         delete this->detachAsPicture(SkRect::MakeEmpty());
     66     }
     67     SkASSERT(fState == State::kEmpty);
     68 }
     69 
     70 #define TRY_TO_STORE(Type, ...)                    \
     71     if (fState != State::kEmpty) { return false; } \
     72     fState = State::k##Type;                       \
     73     new (fBuffer.get()) Type{__VA_ARGS__};         \
     74     return true
     75 
     76 bool SkMiniRecorder::drawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst,
     77                                     const SkPaint* p, SkCanvas::SrcRectConstraint constraint) {
     78     SkRect bounds;
     79     if (!src) {
     80         bm.getBounds(&bounds);
     81         src = &bounds;
     82     }
     83     SkTLazy<SkPaint> defaultPaint;
     84     if (!p) {
     85         p = defaultPaint.init();
     86     }
     87     TRY_TO_STORE(DrawBitmapRectFixedSize, *p, bm, *src, dst, constraint);
     88 }
     89 
     90 bool SkMiniRecorder::drawRect(const SkRect& rect, const SkPaint& paint) {
     91     TRY_TO_STORE(DrawRect, paint, rect);
     92 }
     93 
     94 bool SkMiniRecorder::drawPath(const SkPath& path, const SkPaint& paint) {
     95     TRY_TO_STORE(DrawPath, paint, path);
     96 }
     97 
     98 bool SkMiniRecorder::drawTextBlob(const SkTextBlob* b, SkScalar x, SkScalar y, const SkPaint& p) {
     99     TRY_TO_STORE(DrawTextBlob, p, b, x, y);
    100 }
    101 #undef TRY_TO_STORE
    102 
    103 
    104 SkPicture* SkMiniRecorder::detachAsPicture(const SkRect& cull) {
    105 #define CASE(Type)              \
    106     case State::k##Type:        \
    107         fState = State::kEmpty; \
    108         return new SkMiniPicture<Type>(cull, reinterpret_cast<Type*>(fBuffer.get()))
    109 
    110     switch (fState) {
    111         case State::kEmpty: return SkRef(gEmptyPicture.get([]{ return new SkEmptyPicture; }));
    112         CASE(DrawBitmapRectFixedSize);
    113         CASE(DrawPath);
    114         CASE(DrawRect);
    115         CASE(DrawTextBlob);
    116     }
    117     SkASSERT(false);
    118     return nullptr;
    119 #undef CASE
    120 }
    121 
    122 void SkMiniRecorder::flushAndReset(SkCanvas* canvas) {
    123 #define CASE(Type)                                                  \
    124     case State::k##Type: {                                          \
    125         fState = State::kEmpty;                                     \
    126         Type* op = reinterpret_cast<Type*>(fBuffer.get());          \
    127         SkRecords::Draw(canvas, nullptr, nullptr, 0, nullptr)(*op); \
    128         op->~Type();                                                \
    129     } return
    130 
    131     switch (fState) {
    132         case State::kEmpty: return;
    133         CASE(DrawBitmapRectFixedSize);
    134         CASE(DrawPath);
    135         CASE(DrawRect);
    136         CASE(DrawTextBlob);
    137     }
    138     SkASSERT(false);
    139 #undef CASE
    140 }
    141