'<(skia_src_path)/core/SkStrokeRec.cpp',
'<(skia_src_path)/core/SkStrokerPriv.cpp',
'<(skia_src_path)/core/SkStrokerPriv.h',
- '<(skia_src_path)/core/SkTemplatesPriv.h',
'<(skia_src_path)/core/SkTextFormatParams.h',
'<(skia_src_path)/core/SkTileGrid.cpp',
'<(skia_src_path)/core/SkTileGrid.h',
+# Common gypi for unit tests.
{
'include_dirs': [
'../src/core',
'../tests/ShaderImageFilterTest.cpp',
'../tests/ShaderOpacityTest.cpp',
'../tests/SkBase64Test.cpp',
+ '../tests/SmallAllocatorTest.cpp',
'../tests/SortTest.cpp',
'../tests/SrcOverTest.cpp',
'../tests/StreamTest.cpp',
uint8_t fTotalInverseClass;
SkDEBUGCODE(SkBool8 fInSetContext;)
- static SkShader* CreateBitmapShader(const SkBitmap& src,
- TileMode, TileMode,
- void* storage, size_t storageSize);
- friend class SkAutoBitmapShaderInstall;
typedef SkFlattenable INHERITED;
};
return false;
}
-#include "SkTemplatesPriv.h"
-
static bool bitmapIsTooBig(const SkBitmap& bm) {
// SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
// communicates between its matrix-proc and its sampler-proc. Until we can
return bm.width() > maxSize || bm.height() > maxSize;
}
-SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
- TileMode tmx, TileMode tmy,
- void* storage, size_t storageSize) {
+SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
+ SkShader::TileMode tmy, SkTBlitterAllocator* allocator) {
SkShader* shader;
SkColor color;
if (src.isNull() || bitmapIsTooBig(src)) {
- SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
+ if (NULL == allocator) {
+ shader = SkNEW(SkEmptyShader);
+ } else {
+ shader = allocator->createT<SkEmptyShader>();
+ }
}
else if (canUseColorShader(src, &color)) {
- SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
- (color));
+ if (NULL == allocator) {
+ shader = SkNEW_ARGS(SkColorShader, (color));
+ } else {
+ shader = allocator->createT<SkColorShader>(color);
+ }
} else {
- SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
- storageSize, (src, tmx, tmy));
+ if (NULL == allocator) {
+ shader = SkNEW_ARGS(SkBitmapProcShader, (src, tmx, tmy));
+ } else {
+ shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy);
+ }
}
return shader;
}
#include "SkShader.h"
#include "SkBitmapProcState.h"
+#include "SkSmallAllocator.h"
class SkBitmapProcShader : public SkShader {
public:
typedef SkShader INHERITED;
};
+// Commonly used allocator. It currently is only used to allocate up to 2 objects. The total
+// bytes requested is calculated using one of our large shaders plus the size of an Sk3DBlitter
+// in SkDraw.cpp
+typedef SkSmallAllocator<2, sizeof(SkBitmapProcShader) + sizeof(void*) * 2> SkTBlitterAllocator;
+
+// If alloc is non-NULL, it will be used to allocate the returned SkShader, and MUST outlive
+// the SkShader.
+SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode, SkShader::TileMode,
+ SkTBlitterAllocator* alloc);
+
#endif
#include "SkAntiRun.h"
#include "SkColor.h"
#include "SkColorFilter.h"
+#include "SkCoreBlitters.h"
#include "SkFilterShader.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
#include "SkMask.h"
#include "SkMaskFilter.h"
-#include "SkTemplatesPriv.h"
+#include "SkString.h"
#include "SkTLazy.h"
#include "SkUtils.h"
#include "SkXfermode.h"
-#include "SkString.h"
SkBlitter::~SkBlitter() {}
class Sk3DBlitter : public SkBlitter {
public:
- Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader, void (*killProc)(void*))
- : fProxy(proxy), f3DShader(shader), fKillProc(killProc) {
- shader->ref();
- }
-
- virtual ~Sk3DBlitter() {
- f3DShader->unref();
- fKillProc(fProxy);
- }
+ Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader)
+ : fProxy(proxy)
+ , f3DShader(SkRef(shader))
+ {}
virtual void blitH(int x, int y, int width) {
fProxy->blitH(x, y, width);
}
private:
- SkBlitter* fProxy;
- Sk3DShader* f3DShader;
- void (*fKillProc)(void*);
+ // fProxy is unowned. It will be deleted by SkSmallAllocator.
+ SkBlitter* fProxy;
+ SkAutoTUnref<Sk3DShader> f3DShader;
};
///////////////////////////////////////////////////////////////////////////////
#include "SkCoreBlitters.h"
-class SkAutoCallProc {
-public:
- typedef void (*Proc)(void*);
-
- SkAutoCallProc(void* obj, Proc proc)
- : fObj(obj), fProc(proc) {}
-
- ~SkAutoCallProc() {
- if (fObj && fProc) {
- fProc(fObj);
- }
- }
-
- void* get() const { return fObj; }
-
- void* detach() {
- void* obj = fObj;
- fObj = NULL;
- return obj;
- }
-
-private:
- void* fObj;
- Proc fProc;
-};
-#define SkAutoCallProc(...) SK_REQUIRE_LOCAL_VAR(SkAutoCallProc)
-
-static void destroy_blitter(void* blitter) {
- ((SkBlitter*)blitter)->~SkBlitter();
-}
-
-static void delete_blitter(void* blitter) {
- SkDELETE((SkBlitter*)blitter);
-}
-
static bool just_solid_color(const SkPaint& paint) {
if (paint.getAlpha() == 0xFF && paint.getColorFilter() == NULL) {
SkShader* shader = paint.getShader();
SkBlitter* SkBlitter::Choose(const SkBitmap& device,
const SkMatrix& matrix,
const SkPaint& origPaint,
- void* storage, size_t storageSize,
+ SkTBlitterAllocator* allocator,
bool drawCoverage) {
- SkASSERT(storageSize == 0 || storage != NULL);
+ SkASSERT(allocator != NULL);
SkBlitter* blitter = NULL;
// (e.g. they have a bounder that always aborts the draw)
if (kUnknown_SkColorType == device.colorType() ||
(drawCoverage && (kAlpha_8_SkColorType != device.colorType()))) {
- SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
+ blitter = allocator->createT<SkNullBlitter>();
return blitter;
}
mode = NULL;
paint.writable()->setXfermode(NULL);
break;
- case kSkipDrawing_XferInterp:
- SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
+ case kSkipDrawing_XferInterp:{
+ blitter = allocator->createT<SkNullBlitter>();
return blitter;
+ }
default:
break;
}
* not fail) in its destructor.
*/
if (shader && !shader->setContext(device, *paint, matrix)) {
- SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
+ blitter = allocator->createT<SkNullBlitter>();
return blitter;
}
if (drawCoverage) {
SkASSERT(NULL == shader);
SkASSERT(NULL == paint->getXfermode());
- SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Coverage_Blitter,
- storage, storageSize, (device, *paint));
+ blitter = allocator->createT<SkA8_Coverage_Blitter>(device, *paint);
} else if (shader) {
- SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Shader_Blitter,
- storage, storageSize, (device, *paint));
+ blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint);
} else {
- SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Blitter,
- storage, storageSize, (device, *paint));
+ blitter = allocator->createT<SkA8_Blitter>(device, *paint);
}
break;
case kRGB_565_SkColorType:
- blitter = SkBlitter_ChooseD565(device, *paint, storage, storageSize);
+ blitter = SkBlitter_ChooseD565(device, *paint, allocator);
break;
case kPMColor_SkColorType:
if (shader) {
- SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Shader_Blitter,
- storage, storageSize, (device, *paint));
+ blitter = allocator->createT<SkARGB32_Shader_Blitter>(device, *paint);
} else if (paint->getColor() == SK_ColorBLACK) {
- SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Black_Blitter,
- storage, storageSize, (device, *paint));
+ blitter = allocator->createT<SkARGB32_Black_Blitter>(device, *paint);
} else if (paint->getAlpha() == 0xFF) {
- SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Opaque_Blitter,
- storage, storageSize, (device, *paint));
+ blitter = allocator->createT<SkARGB32_Opaque_Blitter>(device, *paint);
} else {
- SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Blitter,
- storage, storageSize, (device, *paint));
+ blitter = allocator->createT<SkARGB32_Blitter>(device, *paint);
}
break;
default:
SkDEBUGFAIL("unsupported device config");
- SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
+ blitter = allocator->createT<SkNullBlitter>();
break;
}
if (shader3D) {
- void (*proc)(void*) = ((void*)storage == (void*)blitter) ? destroy_blitter : delete_blitter;
- SkAutoCallProc tmp(blitter, proc);
-
- blitter = SkNEW_ARGS(Sk3DBlitter, (blitter, shader3D, proc));
- (void)tmp.detach();
+ SkBlitter* innerBlitter = blitter;
+ // innerBlitter was allocated by allocator, which will delete it.
+ blitter = allocator->createT<Sk3DBlitter>(innerBlitter, shader3D);
}
return blitter;
}
#define SkBlitter_DEFINED
#include "SkBitmap.h"
+#include "SkBitmapProcShader.h"
+#include "SkMask.h"
#include "SkMatrix.h"
#include "SkPaint.h"
#include "SkRefCnt.h"
#include "SkRegion.h"
-#include "SkMask.h"
+#include "SkShader.h"
+#include "SkSmallAllocator.h"
/** SkBlitter and its subclasses are responsible for actually writing pixels
into memory. Besides efficiency, they handle clipping and antialiasing.
/** @name Factories
Return the correct blitter to use given the specified context.
*/
- static SkBlitter* Choose(const SkBitmap& device,
- const SkMatrix& matrix,
- const SkPaint& paint) {
- return Choose(device, matrix, paint, NULL, 0);
- }
-
static SkBlitter* Choose(const SkBitmap& device,
const SkMatrix& matrix,
const SkPaint& paint,
- void* storage, size_t storageSize,
+ SkTBlitterAllocator*,
bool drawCoverage = false);
static SkBlitter* ChooseSprite(const SkBitmap& device,
const SkPaint&,
const SkBitmap& src,
int left, int top,
- void* storage, size_t storageSize);
+ SkTBlitterAllocator*);
///@}
private:
#include "SkColorPriv.h"
#include "SkDither.h"
#include "SkShader.h"
-#include "SkTemplatesPriv.h"
#include "SkUtils.h"
#include "SkXfermode.h"
///////////////////////////////////////////////////////////////////////////////
SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint,
- void* storage, size_t storageSize) {
+ SkTBlitterAllocator* allocator) {
+ SkASSERT(allocator != NULL);
+
SkBlitter* blitter;
SkShader* shader = paint.getShader();
SkXfermode* mode = paint.getXfermode();
if (shader) {
if (mode) {
- SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader_Xfermode_Blitter,
- storage, storageSize, (device, paint));
+ blitter = allocator->createT<SkRGB16_Shader_Xfermode_Blitter>(device, paint);
} else if (shader->canCallShadeSpan16()) {
- SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader16_Blitter,
- storage, storageSize, (device, paint));
+ blitter = allocator->createT<SkRGB16_Shader16_Blitter>(device, paint);
} else {
- SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader_Blitter,
- storage, storageSize, (device, paint));
+ blitter = allocator->createT<SkRGB16_Shader_Blitter>(device, paint);
}
} else {
// no shader, no xfermode, (and we always ignore colorfilter)
SkColor color = paint.getColor();
if (0 == SkColorGetA(color)) {
- SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
+ blitter = allocator->createT<SkNullBlitter>();
#ifdef USE_BLACK_BLITTER
} else if (SK_ColorBLACK == color) {
- SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Black_Blitter, storage,
- storageSize, (device, paint));
+ blitter = allocator->createT<SkRGB16_Black_Blitter>(device, paint);
#endif
} else if (0xFF == SkColorGetA(color)) {
- SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Opaque_Blitter, storage,
- storageSize, (device, paint));
+ blitter = allocator->createT<SkRGB16_Opaque_Blitter>(device, paint);
} else {
- SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Blitter, storage,
- storageSize, (device, paint));
+ blitter = allocator->createT<SkRGB16_Blitter>(device, paint);
}
}
-
/*
* Copyright 2006 The Android Open Source Project
*
* found in the LICENSE file.
*/
-
+#include "SkSmallAllocator.h"
#include "SkSpriteBlitter.h"
SkSpriteBlitter::SkSpriteBlitter(const SkBitmap& source)
// returning null means the caller will call SkBlitter::Choose() and
// have wrapped the source bitmap inside a shader
-SkBlitter* SkBlitter::ChooseSprite( const SkBitmap& device,
- const SkPaint& paint,
- const SkBitmap& source,
- int left, int top,
- void* storage, size_t storageSize) {
+SkBlitter* SkBlitter::ChooseSprite(const SkBitmap& device, const SkPaint& paint,
+ const SkBitmap& source, int left, int top, SkTBlitterAllocator* allocator) {
/* We currently ignore antialiasing and filtertype, meaning we will take our
special blitters regardless of these settings. Ignoring filtertype seems fine
since by definition there is no scale in the matrix. Ignoring antialiasing is
paint and return null if it is set, forcing the client to take the slow shader case
(which does respect soft edges).
*/
+ SkASSERT(allocator != NULL);
SkSpriteBlitter* blitter;
switch (device.colorType()) {
case kRGB_565_SkColorType:
- blitter = SkSpriteBlitter::ChooseD16(source, paint, storage,
- storageSize);
+ blitter = SkSpriteBlitter::ChooseD16(source, paint, allocator);
break;
case kPMColor_SkColorType:
- blitter = SkSpriteBlitter::ChooseD32(source, paint, storage,
- storageSize);
+ blitter = SkSpriteBlitter::ChooseD32(source, paint, allocator);
break;
default:
blitter = NULL;
#ifndef SkCoreBlitters_DEFINED
#define SkCoreBlitters_DEFINED
+#include "SkBitmapProcShader.h"
#include "SkBlitter.h"
#include "SkBlitRow.h"
+#include "SkShader.h"
+#include "SkSmallAllocator.h"
class SkRasterBlitter : public SkBlitter {
public:
SkBlitter::Choose(...)
*/
-extern SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device,
- const SkPaint& paint,
- void* storage, size_t storageSize);
+SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint,
+ SkTBlitterAllocator* allocator);
#endif
#include "SkRRect.h"
#include "SkScan.h"
#include "SkShader.h"
+#include "SkSmallAllocator.h"
#include "SkString.h"
#include "SkStroke.h"
-#include "SkTemplatesPriv.h"
#include "SkTLazy.h"
#include "SkUtils.h"
#include "SkDrawProcs.h"
#include "SkMatrixUtils.h"
+
//#define TRACE_BITMAP_DRAWS
-#define kBlitterStorageLongCount (sizeof(SkBitmapProcShader) >> 2)
/** Helper for allocating small blitters on the stack.
*/
}
SkAutoBlitterChoose(const SkBitmap& device, const SkMatrix& matrix,
const SkPaint& paint, bool drawCoverage = false) {
- fBlitter = SkBlitter::Choose(device, matrix, paint,
- fStorage, sizeof(fStorage), drawCoverage);
- }
-
- ~SkAutoBlitterChoose() {
- if ((void*)fBlitter == (void*)fStorage) {
- fBlitter->~SkBlitter();
- } else {
- SkDELETE(fBlitter);
- }
+ fBlitter = SkBlitter::Choose(device, matrix, paint, &fAllocator,
+ drawCoverage);
}
SkBlitter* operator->() { return fBlitter; }
void choose(const SkBitmap& device, const SkMatrix& matrix,
const SkPaint& paint) {
SkASSERT(!fBlitter);
- fBlitter = SkBlitter::Choose(device, matrix, paint,
- fStorage, sizeof(fStorage));
+ fBlitter = SkBlitter::Choose(device, matrix, paint, &fAllocator);
}
private:
- SkBlitter* fBlitter;
- uint32_t fStorage[kBlitterStorageLongCount];
+ // Owned by fAllocator, which will handle the delete.
+ SkBlitter* fBlitter;
+ SkTBlitterAllocator fAllocator;
};
#define SkAutoBlitterChoose(...) SK_REQUIRE_LOCAL_VAR(SkAutoBlitterChoose)
public:
SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint)
: fPaint(paint) /* makes a copy of the paint */ {
- fPaint.setShader(SkShader::CreateBitmapShader(src,
- SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
- fStorage, sizeof(fStorage)));
+ fPaint.setShader(CreateBitmapShader(src, SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode,
+ &fAllocator));
// we deliberately left the shader with an owner-count of 2
SkASSERT(2 == fPaint.getShader()->getRefCnt());
}
~SkAutoBitmapShaderInstall() {
- SkShader* shader = fPaint.getShader();
- // since we manually destroy shader, we insist that owners == 2
- SkASSERT(2 == shader->getRefCnt());
+ // since fAllocator will destroy shader, we insist that owners == 2
+ SkASSERT(2 == fPaint.getShader()->getRefCnt());
fPaint.setShader(NULL); // unref the shader by 1
- // now destroy to take care of the 2nd owner-count
- if ((void*)shader == (void*)fStorage) {
- shader->~SkShader();
- } else {
- SkDELETE(shader);
- }
}
// return the new paint that has the shader applied
const SkPaint& paintWithShader() const { return fPaint; }
private:
- SkPaint fPaint; // copy of caller's paint (which we then modify)
- uint32_t fStorage[kBlitterStorageLongCount];
+ // copy of caller's paint (which we then modify)
+ SkPaint fPaint;
+ // Stores the shader.
+ SkTBlitterAllocator fAllocator;
};
#define SkAutoBitmapShaderInstall(...) SK_REQUIRE_LOCAL_VAR(SkAutoBitmapShaderInstall)
int ix = SkScalarRoundToInt(matrix.getTranslateX());
int iy = SkScalarRoundToInt(matrix.getTranslateY());
if (clipHandlesSprite(*fRC, ix, iy, bitmap)) {
- uint32_t storage[kBlitterStorageLongCount];
- SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
- ix, iy, storage, sizeof(storage));
+ SkTBlitterAllocator allocator;
+ // blitter will be owned by the allocator.
+ SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
+ ix, iy, &allocator);
if (blitter) {
- SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage);
-
SkIRect ir;
ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
paint.setStyle(SkPaint::kFill_Style);
if (NULL == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, bitmap)) {
- uint32_t storage[kBlitterStorageLongCount];
- SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
- x, y, storage, sizeof(storage));
+ SkTBlitterAllocator allocator;
+ // blitter will be owned by the allocator.
+ SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
+ x, y, &allocator);
if (blitter) {
- SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage);
-
if (fBounder && !fBounder->doIRect(bounds)) {
return;
}
* found in the LICENSE file.
*/
-
+#include "SkBitmapProcShader.h"
+#include "SkReadBuffer.h"
+#include "SkMallocPixelRef.h"
+#include "SkPaint.h"
#include "SkScalar.h"
#include "SkShader.h"
-#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
-#include "SkPaint.h"
-#include "SkMallocPixelRef.h"
SkShader::SkShader() {
fLocalMatrix.reset();
SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
TileMode tmx, TileMode tmy) {
- return SkShader::CreateBitmapShader(src, tmx, tmy, NULL, 0);
+ return ::CreateBitmapShader(src, tmx, tmy, NULL);
}
#ifdef SK_DEVELOPER
--- /dev/null
+/*
+ * Copyright 2014 Google, Inc
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSmallAllocator_DEFINED
+#define SkSmallAllocator_DEFINED
+
+#include "SkTDArray.h"
+#include "SkTypes.h"
+
+// Used by SkSmallAllocator to call the destructor for objects it has
+// allocated.
+template<typename T> void destroyT(void* ptr) {
+ static_cast<T*>(ptr)->~T();
+}
+
+/*
+ * Template class for allocating small objects without additional heap memory
+ * allocations. kMaxObjects is a hard limit on the number of objects that can
+ * be allocated using this class. After that, attempts to create more objects
+ * with this class will assert and return NULL.
+ * kTotalBytes is the total number of bytes provided for storage for all
+ * objects created by this allocator. If an object to be created is larger
+ * than the storage (minus storage already used), it will be allocated on the
+ * heap. This class's destructor will handle calling the destructor for each
+ * object it allocated and freeing its memory.
+ */
+template<uint32_t kMaxObjects, size_t kTotalBytes>
+class SkSmallAllocator : public SkNoncopyable {
+public:
+ SkSmallAllocator()
+ : fStorageUsed(0)
+ , fNumObjects(0)
+ {}
+
+ ~SkSmallAllocator() {
+ // Destruct in reverse order, in case an earlier object points to a
+ // later object.
+ while (fNumObjects > 0) {
+ fNumObjects--;
+ Rec* rec = &fRecs[fNumObjects];
+ rec->fKillProc(rec->fObj);
+ // Safe to do if fObj is in fStorage, since fHeapStorage will
+ // point to NULL.
+ sk_free(rec->fHeapStorage);
+ }
+ }
+
+ /*
+ * Create a new object of type T. Its lifetime will be handled by this
+ * SkSmallAllocator.
+ * Each version behaves the same but takes a different number of
+ * arguments.
+ * Note: If kMaxObjects have been created by this SkSmallAllocator, NULL
+ * will be returned.
+ */
+ template<typename T>
+ T* createT() {
+ void* buf = this->reserveT<T>();
+ if (NULL == buf) {
+ return NULL;
+ }
+ SkNEW_PLACEMENT(buf, T);
+ return static_cast<T*>(buf);
+ }
+
+ template<typename T, typename A1> T* createT(const A1& a1) {
+ void* buf = this->reserveT<T>();
+ if (NULL == buf) {
+ return NULL;
+ }
+ SkNEW_PLACEMENT_ARGS(buf, T, (a1));
+ return static_cast<T*>(buf);
+ }
+
+ template<typename T, typename A1, typename A2>
+ T* createT(const A1& a1, const A2& a2) {
+ void* buf = this->reserveT<T>();
+ if (NULL == buf) {
+ return NULL;
+ }
+ SkNEW_PLACEMENT_ARGS(buf, T, (a1, a2));
+ return static_cast<T*>(buf);
+ }
+
+ template<typename T, typename A1, typename A2, typename A3>
+ T* createT(const A1& a1, const A2& a2, const A3& a3) {
+ void* buf = this->reserveT<T>();
+ if (NULL == buf) {
+ return NULL;
+ }
+ SkNEW_PLACEMENT_ARGS(buf, T, (a1, a2, a3));
+ 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.
+ */
+ template<typename T> void* reserveT() {
+ SkASSERT(fNumObjects < kMaxObjects);
+ if (kMaxObjects == fNumObjects) {
+ return NULL;
+ }
+ const size_t storageRemaining = SkAlign4(kTotalBytes) - fStorageUsed;
+ const size_t storageRequired = SkAlign4(sizeof(T));
+ Rec* rec = &fRecs[fNumObjects];
+ if (storageRequired > storageRemaining) {
+ // Allocate on the heap. Ideally we want to avoid this situation,
+ // but we're not sure we can catch all callers, so handle it but
+ // assert false in debug mode.
+ SkASSERT(false);
+ rec->fHeapStorage = sk_malloc_throw(storageRequired);
+ rec->fObj = static_cast<void*>(rec->fHeapStorage);
+ } else {
+ // There is space in fStorage.
+ rec->fHeapStorage = NULL;
+ SkASSERT(SkIsAlign4(fStorageUsed));
+ rec->fObj = static_cast<void*>(fStorage + (fStorageUsed / 4));
+ fStorageUsed += storageRequired;
+ }
+ rec->fKillProc = destroyT<T>;
+ fNumObjects++;
+ return rec->fObj;
+ }
+
+private:
+ struct Rec {
+ void* fObj;
+ void* fHeapStorage;
+ void (*fKillProc)(void*);
+ };
+
+ // Number of bytes used so far.
+ size_t fStorageUsed;
+ // Pad the storage size to be 4-byte aligned.
+ uint32_t fStorage[SkAlign4(kTotalBytes) >> 2];
+ uint32_t fNumObjects;
+ Rec fRecs[kMaxObjects];
+};
+
+#endif // SkSmallAllocator_DEFINED
#ifndef SkSpriteBlitter_DEFINED
#define SkSpriteBlitter_DEFINED
-#include "SkBlitter.h"
#include "SkBitmap.h"
+#include "SkBitmapProcShader.h"
+#include "SkBlitter.h"
+#include "SkShader.h"
+#include "SkSmallAllocator.h"
class SkPaint;
#endif
static SkSpriteBlitter* ChooseD16(const SkBitmap& source, const SkPaint&,
- void* storage, size_t storageSize);
+ SkTBlitterAllocator*);
static SkSpriteBlitter* ChooseD32(const SkBitmap& source, const SkPaint&,
- void* storage, size_t storageSize);
+ SkTBlitterAllocator*);
protected:
const SkBitmap* fDevice;
///////////////////////////////////////////////////////////////////////////////
-#include "SkTemplatesPriv.h"
+SkSpriteBlitter* SkSpriteBlitter::ChooseD32(const SkBitmap& source, const SkPaint& paint,
+ SkTBlitterAllocator* allocator) {
+ SkASSERT(allocator != NULL);
-SkSpriteBlitter* SkSpriteBlitter::ChooseD32(const SkBitmap& source,
- const SkPaint& paint,
- void* storage, size_t storageSize) {
if (paint.getMaskFilter() != NULL) {
return NULL;
}
return NULL; // we only have opaque sprites
}
if (xfermode || filter) {
- SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S4444_XferFilter,
- storage, storageSize, (source, paint));
+ blitter = allocator->createT<Sprite_D32_S4444_XferFilter>(source, paint);
} else if (source.isOpaque()) {
- SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S4444_Opaque,
- storage, storageSize, (source));
+ blitter = allocator->createT<Sprite_D32_S4444_Opaque>(source);
} else {
- SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S4444,
- storage, storageSize, (source));
+ blitter = allocator->createT<Sprite_D32_S4444>(source);
}
break;
case kPMColor_SkColorType:
if (xfermode || filter) {
if (255 == alpha) {
// this can handle xfermode or filter, but not alpha
- SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S32A_XferFilter,
- storage, storageSize, (source, paint));
+ blitter = allocator->createT<Sprite_D32_S32A_XferFilter>(source, paint);
}
} else {
// this can handle alpha, but not xfermode or filter
- SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S32,
- storage, storageSize, (source, alpha));
+ blitter = allocator->createT<Sprite_D32_S32>(source, alpha);
}
break;
default:
///////////////////////////////////////////////////////////////////////////////
-#include "SkTemplatesPriv.h"
+SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source, const SkPaint& paint,
+ SkTBlitterAllocator* allocator) {
+
+ SkASSERT(allocator != NULL);
-SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source,
- const SkPaint& paint,
- void* storage, size_t storageSize) {
if (paint.getMaskFilter() != NULL) { // may add cases for this
return NULL;
}
unsigned alpha = paint.getAlpha();
switch (source.colorType()) {
- case kPMColor_SkColorType:
- SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S32_BlitRowProc,
- storage, storageSize, (source));
+ case kPMColor_SkColorType: {
+ blitter = allocator->createT<Sprite_D16_S32_BlitRowProc>(source);
break;
+ }
case kARGB_4444_SkColorType:
if (255 == alpha) {
- SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S4444_Opaque,
- storage, storageSize, (source));
+ blitter = allocator->createT<Sprite_D16_S4444_Opaque>(source);
} else {
- SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S4444_Blend,
- storage, storageSize, (source, alpha >> 4));
+ blitter = allocator->createT<Sprite_D16_S4444_Blend>(source, alpha >> 4);
}
break;
case kRGB_565_SkColorType:
if (255 == alpha) {
- SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S16_Opaque,
- storage, storageSize, (source));
+ blitter = allocator->createT<Sprite_D16_S16_Opaque>(source);
} else {
- SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S16_Blend,
- storage, storageSize, (source, alpha));
+ blitter = allocator->createT<Sprite_D16_S16_Blend>(source, alpha);
}
break;
case kIndex_8_SkColorType:
}
if (source.isOpaque()) {
if (255 == alpha) {
- SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8_Opaque,
- storage, storageSize, (source));
+ blitter = allocator->createT<Sprite_D16_SIndex8_Opaque>(source);
} else {
- SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8_Blend,
- storage, storageSize, (source, alpha));
+ blitter = allocator->createT<Sprite_D16_SIndex8_Blend>(source, alpha);
}
} else {
if (255 == alpha) {
- SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8A_Opaque,
- storage, storageSize, (source));
+ blitter = allocator->createT<Sprite_D16_SIndex8A_Opaque>(source);
} else {
- SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8A_Blend,
- storage, storageSize, (source, alpha));
+ blitter = allocator->createT<Sprite_D16_SIndex8A_Blend>(source, alpha);
}
}
break;
+++ /dev/null
-
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#ifndef SkTemplatesPriv_DEFINED
-#define SkTemplatesPriv_DEFINED
-
-#include "SkTemplates.h"
-
-////////////////////////////////////////////////////////////////////////////////
-
-#ifdef SK_BUILD_FOR_WIN32
- #define SK_PLACEMENT_NEW(result, classname, storage, storageSize) \
- result = SkNEW(classname)
-
- #define SK_PLACEMENT_NEW_ARGS(result, classname, storage, storageSize, args) \
- result = SkNEW_ARGS(classname, args)
-#else
- #include <new>
- #define SK_PLACEMENT_NEW(result, classname, storage, storagesize) \
- do { \
- if (storagesize) \
- { \
- SkASSERT(storageSize >= sizeof(classname)); \
- result = new(storage) classname; \
- } \
- else \
- result = SkNEW(classname); \
- } while (0)
-
- #define SK_PLACEMENT_NEW_ARGS(result, classname, storage, storagesize, args) \
- do { \
- if (storagesize) \
- { \
- SkASSERT(storageSize >= sizeof(classname)); \
- result = new(storage) classname args; \
- } \
- else \
- result = SkNEW_ARGS(classname, args); \
- } while (0)
-#endif
-
-////////////////////////////////////////////////////////////////////////////////
-
-template <class T> class SkAutoTPlacementDelete {
-public:
- SkAutoTPlacementDelete(T* obj, void* storage) : fObj(obj), fStorage(storage)
- {
- }
- ~SkAutoTPlacementDelete()
- {
- if (fObj)
- {
- if (fObj == fStorage)
- fObj->~T();
- else
- delete fObj;
- }
- }
- T* detach()
- {
- T* obj = fObj;
- fObj = NULL;
- return obj;
- }
-private:
- T* fObj;
- void* fStorage;
-};
-
-#endif
--- /dev/null
+/*
+ * Copyright 2014 Google, Inc
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSmallAllocator.h"
+#include "SkTypes.h"
+#include "Test.h"
+
+class CountingClass {
+public:
+ CountingClass() {
+ kCount++;
+ }
+
+ ~CountingClass() {
+ kCount--;
+ }
+
+ static int GetCount() { return kCount; }
+
+private:
+ static int kCount;
+};
+
+int CountingClass::kCount;
+
+template<uint32_t kMaxObjects, size_t kBytes> void test_allocator(skiatest::Reporter* reporter) {
+ {
+ SkSmallAllocator<kMaxObjects, kBytes> alloc;
+ for (uint32_t i = 0; i < kMaxObjects; ++i) {
+ CountingClass* c = alloc.template createT<CountingClass>();
+ REPORTER_ASSERT(reporter, c != NULL);
+ REPORTER_ASSERT(reporter, CountingClass::GetCount() == static_cast<int>(i+1));
+ }
+ }
+ REPORTER_ASSERT(reporter, CountingClass::GetCount() == 0);
+}
+
+// Tests that ensure that the destructor is called, whether the objects
+// were created in fStorage or on the heap.
+DEF_TEST(SmallAllocator_destructor, reporter) {
+ // Four times as many bytes as objects will never require any heap
+ // allocations (since SkAlign4(sizeof(CountingClass)) == 4 and the allocator
+ // will stop once it reaches kMaxObjects).
+ test_allocator<5, 20>(reporter);
+ test_allocator<10, 40>(reporter);
+ test_allocator<20, 80>(reporter);
+
+#ifndef SK_DEBUG
+ // Allowing less bytes than objects means some will be allocated on the
+ // heap. Don't run these in debug where we assert.
+ test_allocator<50, 20>(reporter);
+ test_allocator<100, 20>(reporter);
+#endif
+}
+
+class Dummy {
+};
+
+class DummyContainer {
+public:
+ explicit DummyContainer(Dummy* d)
+ :fDummy(d)
+ {}
+
+ Dummy* getDummy() const { return fDummy; }
+
+private:
+ Dummy* fDummy;
+};
+
+// Test that using a createT with a constructor taking a pointer as a
+// parameter works as expected.
+DEF_TEST(SmallAllocator_pointer, reporter) {
+ SkSmallAllocator<1, 8> alloc;
+ Dummy d;
+ DummyContainer* container = alloc.createT<DummyContainer>(&d);
+ REPORTER_ASSERT(reporter, container != NULL);
+ REPORTER_ASSERT(reporter, container->getDummy() == &d);
+}