Index: src/core/SkLiteDL.cpp |
diff --git a/src/core/SkLiteDL.cpp b/src/core/SkLiteDL.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..90f62c28f54d66fd8c469c188d53d44395d78751 |
--- /dev/null |
+++ b/src/core/SkLiteDL.cpp |
@@ -0,0 +1,150 @@ |
+/* |
+ * Copyright 2016 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#include "SkCanvas.h" |
+#include "SkLiteDL.h" |
+#include "SkMutex.h" |
+#include "SkSpinlock.h" |
+ |
+namespace { |
+ struct Op { |
+ virtual ~Op() {} |
+ virtual void draw(SkCanvas*) = 0; |
+ |
+ size_t skip; |
+ }; |
+ |
+ struct Save final : Op { void draw(SkCanvas* c) override { c-> save(); } }; |
+ struct Restore final : Op { void draw(SkCanvas* c) override { c->restore(); } }; |
+ |
+ struct Concat final : Op { |
+ Concat(const SkMatrix& matrix) : matrix(matrix) {} |
+ SkMatrix matrix; |
+ void draw(SkCanvas* c) override { c->concat(matrix); } |
+ }; |
+ struct SetMatrix final : Op { |
+ SetMatrix(const SkMatrix& matrix) : matrix(matrix) {} |
+ SkMatrix matrix; |
+ void draw(SkCanvas* c) override { c->setMatrix(matrix); } |
+ }; |
+ |
+ struct ClipRect final : Op { |
+ ClipRect(const SkRect& rect, SkRegion::Op op, bool aa) : rect(rect), op(op), aa(aa) {} |
+ SkRect rect; |
+ SkRegion::Op op; |
+ bool aa; |
+ void draw(SkCanvas* c) override { c->clipRect(rect, op, aa); } |
+ }; |
+ |
+ struct DrawRect final : Op { |
+ DrawRect(const SkRect& rect, const SkPaint& paint) : rect(rect), paint(paint) {} |
+ SkRect rect; |
+ SkPaint paint; |
+ void draw(SkCanvas* c) override { c->drawRect(rect, paint); } |
+ }; |
+ |
+ struct DrawPath final : Op { |
+ DrawPath(const SkPath& path, const SkPaint& paint) : path(path), paint(paint) {} |
+ SkPath path; |
+ SkPaint paint; |
+ void draw(SkCanvas* c) override { c->drawPath(path, paint); } |
+ }; |
+ |
+ template <typename T, typename... Args> |
+ static void* push(SkTDArray<uint8_t>* bytes, size_t pod, Args&&... args) { |
+ size_t skip = SkAlignPtr(sizeof(T) + pod); |
+ auto op = (T*)bytes->append(skip); |
+ new (op) T{ std::forward<Args>(args)... }; |
+ op->skip = skip; |
+ return op+1; |
+ } |
+ |
+ template <typename Fn> |
+ static void map(SkTDArray<uint8_t>* bytes, Fn&& fn) { |
+ for (uint8_t* ptr = bytes->begin(); ptr < bytes->end(); ) { |
+ auto op = (Op*)ptr; |
+ fn(op); |
+ ptr += op->skip; |
+ } |
+ } |
+} |
+ |
+void SkLiteDL:: save() { push <Save>(&fBytes, 0); } |
+void SkLiteDL::restore() { push<Restore>(&fBytes, 0); } |
+ |
+void SkLiteDL:: concat(const SkMatrix& matrix) { push <Concat>(&fBytes, 0, matrix); } |
+void SkLiteDL::setMatrix(const SkMatrix& matrix) { push<SetMatrix>(&fBytes, 0, matrix); } |
+ |
+void SkLiteDL::clipRect(const SkRect& rect, SkRegion::Op op, bool aa) { |
+ push<ClipRect>(&fBytes, 0, rect, op, aa); |
+} |
+ |
+void SkLiteDL::drawRect(const SkRect& rect, const SkPaint& paint) { |
+ push<DrawRect>(&fBytes, 0, rect, paint); |
+} |
+void SkLiteDL::drawPath(const SkPath& path, const SkPaint& paint) { |
+ push<DrawPath>(&fBytes, 0, path, paint); |
+} |
+ |
+void SkLiteDL::onDraw(SkCanvas* canvas) { |
+ map(&fBytes, [canvas](Op* op) { op->draw(canvas); }); |
+} |
+ |
+SkRect SkLiteDL::onGetBounds() { |
+ return fBounds; |
+} |
+ |
+SkLiteDL:: SkLiteDL() {} |
+SkLiteDL::~SkLiteDL() {} |
+ |
+static const int kFreeStackByteLimit = 128*1024; |
+static const int kFreeStackCountLimit = 8; |
+ |
+static SkSpinlock gFreeStackLock; |
+static SkLiteDL* gFreeStack = nullptr; |
+static int gFreeStackCount = 0; |
+ |
+sk_sp<SkLiteDL> SkLiteDL::New(SkRect bounds) { |
+ sk_sp<SkLiteDL> dl; |
+ { |
+ SkAutoMutexAcquire lock(gFreeStackLock); |
+ if (gFreeStack) { |
+ dl.reset(gFreeStack); // Adopts the ref the stack's been holding. |
+ gFreeStack = gFreeStack->fNext; |
+ gFreeStackCount--; |
+ } |
+ } |
+ |
+ if (!dl) { |
+ dl.reset(new SkLiteDL); |
+ } |
+ |
+ dl->fBounds = bounds; |
+ return dl; |
+} |
+ |
+void SkLiteDL::internal_dispose() const { |
+ // Whether we delete this or leave it on the free stack, |
+ // we want its refcnt at 1. |
+ this->internal_dispose_restore_refcnt_to_1(); |
+ |
+ auto self = const_cast<SkLiteDL*>(this); |
+ map(&self->fBytes, [](Op* op) { op->~Op(); }); |
+ |
+ if (self->fBytes.reserved() < kFreeStackByteLimit) { |
+ self->fBytes.rewind(); |
+ SkAutoMutexAcquire lock(gFreeStackLock); |
+ if (gFreeStackCount < kFreeStackCountLimit) { |
+ self->fNext = gFreeStack; |
+ gFreeStack = self; |
+ gFreeStackCount++; |
+ return; |
+ } |
+ } |
+ |
+ delete this; |
+} |