[WIP] Add Context to SkDrawLooper.
SkDrawLooper carries some state during draws. This CL extracts this state into
a separate class Context, which is then passed by the users of SkDrawLooper
into the appropriate methods.
This is a step towards making SkDrawLooper immutable.
BUG=skia:2141
R=scroggo@google.com, reed@google.com, sugoi@google.com
Author: dominikg@chromium.org
Review URL: https://codereview.chromium.org/155513012
git-svn-id: http://skia.googlecode.com/svn/trunk@13760 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index bd75f7d..3b7cc5b 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -19,6 +19,7 @@
#include "SkPicture.h"
#include "SkRasterClip.h"
#include "SkRRect.h"
+#include "SkSmallAllocator.h"
#include "SkSurface_Base.h"
#include "SkTemplates.h"
#include "SkTextFormatParams.h"
@@ -337,7 +338,6 @@
bool skipLayerForImageFilter = false,
const SkRect* bounds = NULL) : fOrigPaint(paint) {
fCanvas = canvas;
- fLooper = paint.getLooper();
fFilter = canvas->getDrawFilter();
fPaint = NULL;
fSaveCount = canvas->getSaveCount();
@@ -354,10 +354,13 @@
fDoClearImageFilter = true;
}
- if (fLooper) {
- fLooper->init(canvas);
+ if (SkDrawLooper* looper = paint.getLooper()) {
+ void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
+ looper->contextSize());
+ fLooperContext = looper->createContext(canvas, buffer);
fIsSimple = false;
} else {
+ fLooperContext = NULL;
// can we be marked as simple?
fIsSimple = !fFilter && !fDoClearImageFilter;
}
@@ -391,13 +394,14 @@
SkLazyPaint fLazyPaint;
SkCanvas* fCanvas;
const SkPaint& fOrigPaint;
- SkDrawLooper* fLooper;
SkDrawFilter* fFilter;
const SkPaint* fPaint;
int fSaveCount;
bool fDoClearImageFilter;
bool fDone;
bool fIsSimple;
+ SkDrawLooper::Context* fLooperContext;
+ SkSmallAllocator<1, 32> fLooperContextAllocator;
bool doNext(SkDrawFilter::Type drawType);
};
@@ -405,7 +409,7 @@
bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
fPaint = NULL;
SkASSERT(!fIsSimple);
- SkASSERT(fLooper || fFilter || fDoClearImageFilter);
+ SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
SkPaint* paint = fLazyPaint.set(fOrigPaint);
@@ -413,7 +417,7 @@
paint->setImageFilter(NULL);
}
- if (fLooper && !fLooper->next(fCanvas, paint)) {
+ if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
fDone = true;
return false;
}
@@ -422,7 +426,7 @@
fDone = true;
return false;
}
- if (NULL == fLooper) {
+ if (NULL == fLooperContext) {
// no looper means we only draw once
fDone = true;
}
@@ -430,7 +434,7 @@
fPaint = paint;
// if we only came in here for the imagefilter, mark us as done
- if (!fLooper && !fFilter) {
+ if (!fLooperContext && !fFilter) {
fDone = true;
}
diff --git a/src/core/SkDrawLooper.cpp b/src/core/SkDrawLooper.cpp
index bac2d96..c620cd0 100644
--- a/src/core/SkDrawLooper.cpp
+++ b/src/core/SkDrawLooper.cpp
@@ -10,14 +10,17 @@
#include "SkMatrix.h"
#include "SkPaint.h"
#include "SkRect.h"
+#include "SkSmallAllocator.h"
-bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) {
+bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) const {
SkCanvas canvas;
+ SkSmallAllocator<1, 32> allocator;
+ void* buffer = allocator.reserveT<SkDrawLooper::Context>(this->contextSize());
- this->init(&canvas);
+ SkDrawLooper::Context* context = this->createContext(&canvas, buffer);
for (;;) {
SkPaint p(paint);
- if (this->next(&canvas, &p)) {
+ if (context->next(&canvas, &p)) {
p.setLooper(NULL);
if (!p.canComputeFastBounds()) {
return false;
@@ -30,14 +33,16 @@
}
void SkDrawLooper::computeFastBounds(const SkPaint& paint, const SkRect& src,
- SkRect* dst) {
+ SkRect* dst) const {
SkCanvas canvas;
+ SkSmallAllocator<1, 32> allocator;
+ void* buffer = allocator.reserveT<SkDrawLooper::Context>(this->contextSize());
*dst = src; // catch case where there are no loops
- this->init(&canvas);
+ SkDrawLooper::Context* context = this->createContext(&canvas, buffer);
for (bool firstTime = true;; firstTime = false) {
SkPaint p(paint);
- if (this->next(&canvas, &p)) {
+ if (context->next(&canvas, &p)) {
SkRect r(src);
p.setLooper(NULL);
diff --git a/src/core/SkSmallAllocator.h b/src/core/SkSmallAllocator.h
index d5ebf3b..2eddb51 100644
--- a/src/core/SkSmallAllocator.h
+++ b/src/core/SkSmallAllocator.h
@@ -96,20 +96,21 @@
return static_cast<T*>(buf);
}
-private:
/*
- * Helper function to provide space for one T. The space will be in
- * fStorage if there is room, or on the heap otherwise. Either way, this
- * class will call ~T() in its destructor and free the heap allocation if
- * necessary.
+ * Reserve a specified amount of space (must be enough space for one T).
+ * The space will be in fStorage if there is room, or on the heap otherwise.
+ * Either way, this class will call ~T() in its destructor and free the heap
+ * allocation if necessary.
+ * Unlike createT(), this method will not call the constructor of T.
*/
- template<typename T> void* reserveT() {
+ template<typename T> void* reserveT(size_t storageRequired = sizeof(T)) {
SkASSERT(fNumObjects < kMaxObjects);
+ SkASSERT(storageRequired >= sizeof(T));
if (kMaxObjects == fNumObjects) {
return NULL;
}
const size_t storageRemaining = SkAlign4(kTotalBytes) - fStorageUsed;
- const size_t storageRequired = SkAlign4(sizeof(T));
+ storageRequired = SkAlign4(storageRequired);
Rec* rec = &fRecs[fNumObjects];
if (storageRequired > storageRemaining) {
// Allocate on the heap. Ideally we want to avoid this situation,