aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gpu/GrAllocPool.h64
-rwxr-xr-xsrc/gpu/GrAllocator.h249
-rw-r--r--src/gpu/GrAtlas.h84
-rw-r--r--src/gpu/GrDrawMesh.cpp147
-rw-r--r--src/gpu/GrGLShaderVar.h1
-rw-r--r--src/gpu/GrGpuVertex.h97
-rw-r--r--src/gpu/GrPlotMgr.h77
-rw-r--r--src/gpu/GrRandom.h55
-rw-r--r--src/gpu/GrRectanizer.h57
-rw-r--r--src/gpu/GrStencil.h211
-rw-r--r--src/gpu/GrStringBuilder.h19
-rw-r--r--src/gpu/GrTBSearch.h46
-rw-r--r--src/gpu/GrTDArray.h216
-rw-r--r--src/gpu/GrTHashCache.h219
-rw-r--r--src/gpu/GrTLList.h54
-rw-r--r--src/gpu/GrTextStrike.h115
-rw-r--r--src/gpu/ios/SkUIView.mm827
17 files changed, 1564 insertions, 974 deletions
diff --git a/src/gpu/GrAllocPool.h b/src/gpu/GrAllocPool.h
new file mode 100644
index 0000000000..3ecc4aa189
--- /dev/null
+++ b/src/gpu/GrAllocPool.h
@@ -0,0 +1,64 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrAllocPool_DEFINED
+#define GrAllocPool_DEFINED
+
+#include "GrNoncopyable.h"
+
+class GrAllocPool : GrNoncopyable {
+public:
+ GrAllocPool(size_t blockSize = 0);
+ ~GrAllocPool();
+
+ /**
+ * Frees all blocks that have been allocated with alloc().
+ */
+ void reset();
+
+ /**
+ * Returns a block of memory bytes size big. This address must not be
+ * passed to realloc/free/delete or any other function that assumes the
+ * address was allocated by malloc or new (because it hasn't).
+ */
+ void* alloc(size_t bytes);
+
+ /**
+ * Releases the most recently allocated bytes back to allocpool.
+ */
+ void release(size_t bytes);
+
+private:
+ struct Block;
+
+ Block* fBlock;
+ size_t fMinBlockSize;
+
+#if GR_DEBUG
+ int fBlocksAllocated;
+ void validate() const;
+#else
+ void validate() const {}
+#endif
+};
+
+template <typename T> class GrTAllocPool {
+public:
+ GrTAllocPool(int count) : fPool(count * sizeof(T)) {}
+
+ void reset() { fPool.reset(); }
+ T* alloc() { return (T*)fPool.alloc(sizeof(T)); }
+
+private:
+ GrAllocPool fPool;
+};
+
+#endif
+
diff --git a/src/gpu/GrAllocator.h b/src/gpu/GrAllocator.h
new file mode 100755
index 0000000000..21c79ec7aa
--- /dev/null
+++ b/src/gpu/GrAllocator.h
@@ -0,0 +1,249 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrAllocator_DEFINED
+#define GrAllocator_DEFINED
+
+#include "GrConfig.h"
+#include "SkTArray.h"
+
+class GrAllocator : GrNoncopyable {
+public:
+ ~GrAllocator() {
+ reset();
+ }
+
+ /**
+ * Create an allocator
+ *
+ * @param itemSize the size of each item to allocate
+ * @param itemsPerBlock the number of items to allocate at once
+ * @param initialBlock optional memory to use for the first block.
+ * Must be at least itemSize*itemsPerBlock sized.
+ * Caller is responsible for freeing this memory.
+ */
+ GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) :
+ fItemSize(itemSize),
+ fItemsPerBlock(itemsPerBlock),
+ fOwnFirstBlock(NULL == initialBlock),
+ fCount(0) {
+ GrAssert(itemsPerBlock > 0);
+ fBlockSize = fItemSize * fItemsPerBlock;
+ fBlocks.push_back() = initialBlock;
+ GR_DEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} );
+ }
+
+ /**
+ * Adds an item and returns pointer to it.
+ *
+ * @return pointer to the added item.
+ */
+ void* push_back() {
+ int indexInBlock = fCount % fItemsPerBlock;
+ // we always have at least one block
+ if (0 == indexInBlock) {
+ if (0 != fCount) {
+ fBlocks.push_back() = GrMalloc(fBlockSize);
+ } else if (fOwnFirstBlock) {
+ fBlocks[0] = GrMalloc(fBlockSize);
+ }
+ }
+ void* ret = (char*)fBlocks[fCount/fItemsPerBlock] +
+ fItemSize * indexInBlock;
+ ++fCount;
+ return ret;
+ }
+
+ /**
+ * removes all added items
+ */
+ void reset() {
+ int blockCount = GrMax((unsigned)1,
+ GrUIDivRoundUp(fCount, fItemsPerBlock));
+ for (int i = 1; i < blockCount; ++i) {
+ GrFree(fBlocks[i]);
+ }
+ if (fOwnFirstBlock) {
+ GrFree(fBlocks[0]);
+ fBlocks[0] = NULL;
+ }
+ fBlocks.pop_back_n(blockCount-1);
+ fCount = 0;
+ }
+
+ /**
+ * count of items
+ */
+ int count() const {
+ return fCount;
+ }
+
+ /**
+ * is the count 0
+ */
+ bool empty() const { return fCount == 0; }
+
+ /**
+ * access last item, only call if count() != 0
+ */
+ void* back() {
+ GrAssert(fCount);
+ return (*this)[fCount-1];
+ }
+
+ /**
+ * access last item, only call if count() != 0
+ */
+ const void* back() const {
+ GrAssert(fCount);
+ return (*this)[fCount-1];
+ }
+
+ /**
+ * access item by index.
+ */
+ void* operator[] (int i) {
+ GrAssert(i >= 0 && i < fCount);
+ return (char*)fBlocks[i / fItemsPerBlock] +
+ fItemSize * (i % fItemsPerBlock);
+ }
+
+ /**
+ * access item by index.
+ */
+ const void* operator[] (int i) const {
+ GrAssert(i >= 0 && i < fCount);
+ return (const char*)fBlocks[i / fItemsPerBlock] +
+ fItemSize * (i % fItemsPerBlock);
+ }
+
+private:
+ static const int NUM_INIT_BLOCK_PTRS = 8;
+
+ SkSTArray<NUM_INIT_BLOCK_PTRS, void*> fBlocks;
+ size_t fBlockSize;
+ size_t fItemSize;
+ int fItemsPerBlock;
+ bool fOwnFirstBlock;
+ int fCount;
+
+ typedef GrNoncopyable INHERITED;
+};
+
+template <typename T>
+class GrTAllocator : GrNoncopyable {
+
+public:
+ virtual ~GrTAllocator() {};
+
+ /**
+ * Create an allocator
+ *
+ * @param itemsPerBlock the number of items to allocate at once
+ * @param initialBlock optional memory to use for the first block.
+ * Must be at least size(T)*itemsPerBlock sized.
+ * Caller is responsible for freeing this memory.
+ */
+ explicit GrTAllocator(int itemsPerBlock)
+ : fAllocator(sizeof(T), itemsPerBlock, NULL) {}
+
+ /**
+ * Adds an item and returns it.
+ *
+ * @return the added item.
+ */
+ T& push_back() {
+ void* item = fAllocator.push_back();
+ GrAssert(NULL != item);
+ new (item) T;
+ return *(T*)item;
+ }
+
+ T& push_back(const T& t) {
+ void* item = fAllocator.push_back();
+ GrAssert(NULL != item);
+ new (item) T(t);
+ return *(T*)item;
+ }
+
+ /**
+ * removes all added items
+ */
+ void reset() {
+ int c = fAllocator.count();
+ for (int i = 0; i < c; ++i) {
+ ((T*)fAllocator[i])->~T();
+ }
+ fAllocator.reset();
+ }
+
+ /**
+ * count of items
+ */
+ int count() const {
+ return fAllocator.count();
+ }
+
+ /**
+ * is the count 0
+ */
+ bool empty() const { return fAllocator.empty(); }
+
+ /**
+ * access last item, only call if count() != 0
+ */
+ T& back() {
+ return *(T*)fAllocator.back();
+ }
+
+ /**
+ * access last item, only call if count() != 0
+ */
+ const T& back() const {
+ return *(const T*)fAllocator.back();
+ }
+
+ /**
+ * access item by index.
+ */
+ T& operator[] (int i) {
+ return *(T*)(fAllocator[i]);
+ }
+
+ /**
+ * access item by index.
+ */
+ const T& operator[] (int i) const {
+ return *(const T*)(fAllocator[i]);
+ }
+
+protected:
+ GrTAllocator(int itemsPerBlock, void* initialBlock)
+ : fAllocator(sizeof(T), itemsPerBlock, initialBlock) {
+ }
+
+private:
+ GrAllocator fAllocator;
+ typedef GrNoncopyable INHERITED;
+};
+
+template <int N, typename T> class GrSTAllocator : public GrTAllocator<T> {
+private:
+ typedef GrTAllocator<T> INHERITED;
+
+public:
+ GrSTAllocator() : INHERITED(N, fStorage.get()) {
+ }
+
+private:
+ SkAlignedSTStorage<N, T> fStorage;
+};
+
+#endif
diff --git a/src/gpu/GrAtlas.h b/src/gpu/GrAtlas.h
new file mode 100644
index 0000000000..f0114e399d
--- /dev/null
+++ b/src/gpu/GrAtlas.h
@@ -0,0 +1,84 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrAtlas_DEFINED
+#define GrAtlas_DEFINED
+
+#include "GrPoint.h"
+#include "GrTexture.h"
+#include "GrTDArray.h"
+
+class GrGpu;
+class GrRectanizer;
+class GrAtlasMgr;
+
+class GrAtlas {
+public:
+ GrAtlas(GrAtlasMgr*, int plotX, int plotY, GrMaskFormat);
+
+ int getPlotX() const { return fPlot.fX; }
+ int getPlotY() const { return fPlot.fY; }
+ GrMaskFormat getMaskFormat() const { return fMaskFormat; }
+
+ GrTexture* texture() const { return fTexture; }
+
+ bool addSubImage(int width, int height, const void*, GrIPoint16*);
+
+ static void FreeLList(GrAtlas* atlas) {
+ while (atlas) {
+ GrAtlas* next = atlas->fNext;
+ delete atlas;
+ atlas = next;
+ }
+ }
+
+ // testing
+ GrAtlas* nextAtlas() const { return fNext; }
+
+private:
+ ~GrAtlas(); // does not try to delete the fNext field
+
+ GrAtlas* fNext;
+ GrTexture* fTexture;
+ GrRectanizer* fRects;
+ GrAtlasMgr* fAtlasMgr;
+ GrIPoint16 fPlot;
+ GrMaskFormat fMaskFormat;
+
+ friend class GrAtlasMgr;
+};
+
+class GrPlotMgr;
+
+class GrAtlasMgr {
+public:
+ GrAtlasMgr(GrGpu*);
+ ~GrAtlasMgr();
+
+ GrAtlas* addToAtlas(GrAtlas*, int width, int height, const void*,
+ GrMaskFormat, GrIPoint16*);
+
+ GrTexture* getTexture(GrMaskFormat format) const {
+ GrAssert((unsigned)format < kCount_GrMaskFormats);
+ return fTexture[format];
+ }
+
+ // to be called by ~GrAtlas()
+ void freePlot(int x, int y);
+
+private:
+ GrGpu* fGpu;
+ GrTexture* fTexture[kCount_GrMaskFormats];
+ GrPlotMgr* fPlotMgr;
+};
+
+#endif
+
+
diff --git a/src/gpu/GrDrawMesh.cpp b/src/gpu/GrDrawMesh.cpp
deleted file mode 100644
index 75960e4f92..0000000000
--- a/src/gpu/GrDrawMesh.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include "GrMesh.h"
-#include "SkCanvas.h"
-
-GrMesh::GrMesh() : fPts(NULL), fCount(0), fIndices(NULL), fIndexCount(0) {}
-
-GrMesh::~GrMesh() {
- delete[] fPts;
- delete[] fIndices;
-}
-
-GrMesh& GrMesh::operator=(const GrMesh& src) {
- delete[] fPts;
- delete[] fIndices;
-
- fBounds = src.fBounds;
- fRows = src.fRows;
- fCols = src.fCols;
-
- fCount = src.fCount;
- fPts = new SkPoint[fCount * 2];
- fTex = fPts + fCount;
- memcpy(fPts, src.fPts, fCount * 2 * sizeof(SkPoint));
-
- delete[] fIndices;
- fIndexCount = src.fIndexCount;
- fIndices = new uint16_t[fIndexCount];
- memcpy(fIndices, src.fIndices, fIndexCount * sizeof(uint16_t));
-
- return *this;
-}
-
-void GrMesh::init(const SkRect& bounds, int rows, int cols,
- const SkRect& texture) {
- SkASSERT(rows > 0 && cols > 0);
-
- fBounds = bounds;
- fRows = rows;
- fCols = cols;
-
- delete[] fPts;
- fCount = (rows + 1) * (cols + 1);
- fPts = new SkPoint[fCount * 2];
- fTex = fPts + fCount;
-
- delete[] fIndices;
- fIndexCount = rows * cols * 6;
- fIndices = new uint16_t[fIndexCount];
-
- SkPoint* pts = fPts;
- const SkScalar dx = bounds.width() / rows;
- const SkScalar dy = bounds.height() / cols;
- SkPoint* tex = fTex;
- const SkScalar dtx = texture.width() / rows;
- const SkScalar dty = texture.height() / cols;
- uint16_t* idx = fIndices;
- int index = 0;
- for (int y = 0; y <= cols; y++) {
- for (int x = 0; x <= rows; x++) {
- pts->set(bounds.fLeft + x*dx, bounds.fTop + y*dy);
- pts += 1;
- tex->set(texture.fLeft + x*dtx, texture.fTop + y*dty);
- tex += 1;
-
- if (y < cols && x < rows) {
- *idx++ = index;
- *idx++ = index + rows + 1;
- *idx++ = index + 1;
-
- *idx++ = index + 1;
- *idx++ = index + rows + 1;
- *idx++ = index + rows + 2;
-
- index += 1;
- }
- }
- index += 1;
- }
-}
-
-void GrMesh::draw(SkCanvas* canvas, const SkPaint& paint) {
- canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount,
- fPts, fTex, NULL, NULL, fIndices, fIndexCount,
- paint);
-}
-
-/////////////////////////////////////////////
-
-#include "SkBoundaryPatch.h"
-#include "SkMeshUtils.h"
-
-static SkPoint SkPointInterp(const SkPoint& a, const SkPoint& b, SkScalar t) {
- return SkPoint::Make(SkScalarInterp(a.fX, b.fX, t),
- SkScalarInterp(a.fY, b.fY, t));
-}
-
-static void set_cubic(SkPoint pts[4], SkScalar x0, SkScalar y0,
- SkScalar x3, SkScalar y3, SkScalar scale = 1) {
- SkPoint tmp, tmp2;
-
- pts[0].set(x0, y0);
- pts[3].set(x3, y3);
-
- tmp = SkPointInterp(pts[0], pts[3], SK_Scalar1/3);
- tmp2 = pts[0] - tmp;
- tmp2.rotateCW();
- tmp2.scale(scale);
- pts[1] = tmp + tmp2;
-
- tmp = SkPointInterp(pts[0], pts[3], 2*SK_Scalar1/3);
- tmp2 = pts[3] - tmp;
- tmp2.rotateCW();
- tmp2.scale(scale);
- pts[2] = tmp + tmp2;
-}
-
-void test_patch(SkCanvas* canvas, const SkBitmap& bm, SkScalar scale) {
- const float w = bm.width();
- const float h = bm.height();
- SkCubicBoundary cubic;
- set_cubic(cubic.fPts + 0, 0, 0, w, 0, scale);
- set_cubic(cubic.fPts + 3, w, 0, w, h, scale);
- set_cubic(cubic.fPts + 6, w, h, 0, h, -scale);
- set_cubic(cubic.fPts + 9, 0, h, 0, 0, scale);
-
- SkBoundaryPatch patch;
- patch.setBoundary(&cubic);
-
- const int Rows = 16;
- const int Cols = 16;
- SkPoint pts[Rows * Cols];
- patch.evalPatch(pts, Rows, Cols);
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setFilterBitmap(true);
-
- SkMeshUtils::Draw(canvas, bm, Rows, Cols, pts, NULL, paint);
-}
-
-
diff --git a/src/gpu/GrGLShaderVar.h b/src/gpu/GrGLShaderVar.h
index 5c50079558..8eba7140c9 100644
--- a/src/gpu/GrGLShaderVar.h
+++ b/src/gpu/GrGLShaderVar.h
@@ -10,6 +10,7 @@
#define GrGLShaderVar_DEFINED
#include "GrGLInterface.h"
+#include "GrStringBuilder.h"
/**
* Represents a variable in a shader
diff --git a/src/gpu/GrGpuVertex.h b/src/gpu/GrGpuVertex.h
new file mode 100644
index 0000000000..2abc2f407e
--- /dev/null
+++ b/src/gpu/GrGpuVertex.h
@@ -0,0 +1,97 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrGpuVertex_DEFINED
+#define GrGpuVertex_DEFINED
+
+#include "GrGLConfig.h"
+#include "GrPoint.h"
+
+#if GR_TEXT_SCALAR_IS_USHORT
+ typedef uint16_t GrTextScalar;
+ #define GrIntToTextScalar(x) ((uint16_t)x)
+ #define GrFixedToTextScalar(x) (x)
+#elif GR_TEXT_SCALAR_IS_FIXED
+ typedef GrFixed GrTextScalar;
+ #define GrIntToTextScalar(x) GrIntToFixed(x)
+ #define GrFixedToTextScalar(x) (x)
+#elif GR_TEXT_SCALAR_IS_FLOAT
+ typedef float GrTextScalar;
+ #define GrIntToTextScalar(x) ((GrTextScalar)x)
+ #define GrFixedToTextScalar(x) GrFixedToFloat(x)
+#else
+ #error "Text scalar type not defined"
+#endif
+
+// text has its own vertex class, since it may want to be in fixed point (given)
+// that it starts with all integers) even when the default vertices are floats
+struct GrGpuTextVertex {
+ GrTextScalar fX;
+ GrTextScalar fY;
+
+ void set(GrTextScalar x, GrTextScalar y) {
+ fX = x;
+ fY = y;
+ }
+
+ void setI(int x, int y) {
+ fX = GrIntToTextScalar(x);
+ fY = GrIntToTextScalar(y);
+ }
+
+ void setX(GrFixed x, GrFixed y) {
+ fX = GrFixedToTextScalar(x);
+ fY = GrFixedToTextScalar(y);
+ }
+
+ // rect fan is counter-clockwise
+
+ void setRectFan(GrTextScalar l, GrTextScalar t, GrTextScalar r,
+ GrTextScalar b) {
+ GrGpuTextVertex* v = this;
+ v[0].set(l, t);
+ v[1].set(l, b);
+ v[2].set(r, b);
+ v[3].set(r, t);
+ }
+
+ void setIRectFan(int l, int t, int r, int b) {
+ this->setRectFan(GrIntToTextScalar(l), GrIntToTextScalar(t),
+ GrIntToTextScalar(r), GrIntToTextScalar(b));
+ }
+
+ void setIRectFan(int l, int t, int r, int b, size_t stride) {
+ GrAssert(stride > sizeof(GrGpuTextVertex));
+ char* v = (char*)this;
+ ((GrGpuTextVertex*)(v + 0*stride))->setI(l, t);
+ ((GrGpuTextVertex*)(v + 1*stride))->setI(l, b);
+ ((GrGpuTextVertex*)(v + 2*stride))->setI(r, b);
+ ((GrGpuTextVertex*)(v + 3*stride))->setI(r, t);
+ }
+
+ // counter-clockwise fan
+ void setXRectFan(GrFixed l, GrFixed t, GrFixed r, GrFixed b) {
+ this->setRectFan(GrFixedToTextScalar(l), GrFixedToTextScalar(t),
+ GrFixedToTextScalar(r), GrFixedToTextScalar(b));
+ }
+
+ void setXRectFan(GrFixed l, GrFixed t, GrFixed r, GrFixed b, size_t stride) {
+ GrAssert(stride > sizeof(GrGpuTextVertex));
+ char* v = (char*)this;
+ ((GrGpuTextVertex*)(v + 0*stride))->setX(l, t);
+ ((GrGpuTextVertex*)(v + 1*stride))->setX(l, b);
+ ((GrGpuTextVertex*)(v + 2*stride))->setX(r, b);
+ ((GrGpuTextVertex*)(v + 3*stride))->setX(r, t);
+ }
+
+};
+
+#endif
+
diff --git a/src/gpu/GrPlotMgr.h b/src/gpu/GrPlotMgr.h
new file mode 100644
index 0000000000..0e631a9ade
--- /dev/null
+++ b/src/gpu/GrPlotMgr.h
@@ -0,0 +1,77 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrPlotMgr_DEFINED
+#define GrPlotMgr_DEFINED
+
+#include "GrTypes.h"
+#include "GrPoint.h"
+
+class GrPlotMgr : GrNoncopyable {
+public:
+ GrPlotMgr(int width, int height) {
+ fDim.set(width, height);
+ size_t needed = width * height;
+ if (needed <= sizeof(fStorage)) {
+ fBusy = fStorage;
+ } else {
+ fBusy = new char[needed];
+ }
+ this->reset();
+ }
+
+ ~GrPlotMgr() {
+ if (fBusy != fStorage) {
+ delete[] fBusy;
+ }
+ }
+
+ void reset() {
+ Gr_bzero(fBusy, fDim.fX * fDim.fY);
+ }
+
+ bool newPlot(GrIPoint16* loc) {
+ char* busy = fBusy;
+ for (int y = 0; y < fDim.fY; y++) {
+ for (int x = 0; x < fDim.fX; x++) {
+ if (!*busy) {
+ *busy = true;
+ loc->set(x, y);
+ return true;
+ }
+ busy++;
+ }
+ }
+ return false;
+ }
+
+ bool isBusy(int x, int y) const {
+ GrAssert((unsigned)x < (unsigned)fDim.fX);
+ GrAssert((unsigned)y < (unsigned)fDim.fY);
+ return fBusy[y * fDim.fX + x] != 0;
+ }
+
+ void freePlot(int x, int y) {
+ GrAssert((unsigned)x < (unsigned)fDim.fX);
+ GrAssert((unsigned)y < (unsigned)fDim.fY);
+ fBusy[y * fDim.fX + x] = false;
+ }
+
+private:
+ enum {
+ STORAGE = 64
+ };
+ char fStorage[STORAGE];
+ char* fBusy;
+ GrIPoint16 fDim;
+};
+
+#endif
+
diff --git a/src/gpu/GrRandom.h b/src/gpu/GrRandom.h
new file mode 100644
index 0000000000..c98a8fbd94
--- /dev/null
+++ b/src/gpu/GrRandom.h
@@ -0,0 +1,55 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrRandom_DEFINED
+#define GrRandom_DEFINED
+
+class GrRandom {
+public:
+ GrRandom() : fSeed(0) {}
+ GrRandom(uint32_t seed) : fSeed(seed) {}
+
+ uint32_t seed() const { return fSeed; }
+
+ uint32_t nextU() {
+ fSeed = fSeed * kMUL + kADD;
+ return fSeed;
+ }
+
+ int32_t nextS() { return (int32_t)this->nextU(); }
+
+ /**
+ * Returns value [0...1) as a float
+ */
+ float nextF() {
+ // const is 1 / (2^32 - 1)
+ return (float)(this->nextU() * 2.32830644e-10);
+ }
+
+ /**
+ * Returns value [min...max) as a float
+ */
+ float nextF(float min, float max) {
+ return min + this->nextF() * (max - min);
+ }
+
+private:
+ /*
+ * These constants taken from "Numerical Recipes in C", reprinted 1999
+ */
+ enum {
+ kMUL = 1664525,
+ kADD = 1013904223
+ };
+ uint32_t fSeed;
+};
+
+#endif
+
diff --git a/src/gpu/GrRectanizer.h b/src/gpu/GrRectanizer.h
new file mode 100644
index 0000000000..d1f5033259
--- /dev/null
+++ b/src/gpu/GrRectanizer.h
@@ -0,0 +1,57 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrRectanizer_DEFINED
+#define GrRectanizer_DEFINED
+
+#include "GrRect.h"
+#include "GrTDArray.h"
+
+class GrRectanizerPurgeListener {
+public:
+ virtual ~GrRectanizerPurgeListener() {}
+
+ virtual void notifyPurgeStrip(void*, int yCoord) = 0;
+};
+
+class GrRectanizer {
+public:
+ GrRectanizer(int width, int height) : fWidth(width), fHeight(height) {
+ GrAssert(width >= 0);
+ GrAssert(height >= 0);
+ }
+
+ virtual ~GrRectanizer() {}
+
+ int width() const { return fWidth; }
+ int height() const { return fHeight; }
+
+ virtual bool addRect(int width, int height, GrIPoint16* loc) = 0;
+ virtual float percentFull() const = 0;
+
+ // return the Y-coordinate of a strip that should be purged, given height
+ // i.e. return the oldest such strip, or some other criteria. Return -1
+ // if there is no candidate
+ virtual int stripToPurge(int height) const = 0;
+ virtual void purgeStripAtY(int yCoord) = 0;
+
+ /**
+ * Our factory, which returns the subclass du jour
+ */
+ static GrRectanizer* Factory(int width, int height);
+
+private:
+ int fWidth;
+ int fHeight;
+};
+
+#endif
+
+
diff --git a/src/gpu/GrStencil.h b/src/gpu/GrStencil.h
new file mode 100644
index 0000000000..b8610f2017
--- /dev/null
+++ b/src/gpu/GrStencil.h
@@ -0,0 +1,211 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrStencil_DEFINED
+#define GrStencil_DEFINED
+
+#include "GrTypes.h"
+/**
+ * Gr uses the stencil buffer to implement complex clipping inside the
+ * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer
+ * bits available for other uses by external code (clients). Client code can
+ * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits
+ * provided by clients that overlap the bits used to implement clipping.
+ *
+ * When code outside the GrDrawTarget class uses the stencil buffer the contract
+ * is as follows:
+ *
+ * > Normal stencil funcs allow the client to pass / fail regardless of the
+ * reserved clip bits.
+ * > Additional functions allow a test against the clip along with a limited
+ * set of tests against the client bits.
+ * > Client can assume all client bits are zero initially.
+ * > Client must ensure that after all its passes are finished it has only
+ * written to the color buffer in the region inside the clip. Furthermore, it
+ * must zero all client bits that were modifed (both inside and outside the
+ * clip).
+ */
+
+/**
+ * Determines which pixels pass / fail the stencil test.
+ * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true
+ */
+enum GrStencilFunc {
+ kAlways_StencilFunc = 0,
+ kNever_StencilFunc,
+ kGreater_StencilFunc,
+ kGEqual_StencilFunc,
+ kLess_StencilFunc,
+ kLEqual_StencilFunc,
+ kEqual_StencilFunc,
+ kNotEqual_StencilFunc,
+
+ // Gr stores the current clip in the
+ // stencil buffer in the high bits that
+ // are not directly accessible modifiable
+ // via the GrDrawTarget interface. The below
+ // stencil funcs test against the current
+ // clip in addition to the GrDrawTarget
+ // client's stencil bits.
+
+ // pass if inside the clip
+ kAlwaysIfInClip_StencilFunc,
+ kEqualIfInClip_StencilFunc,
+ kLessIfInClip_StencilFunc,
+ kLEqualIfInClip_StencilFunc,
+ kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0
+
+ // counts
+ kStencilFuncCount,
+ kClipStencilFuncCount = kNonZeroIfInClip_StencilFunc -
+ kAlwaysIfInClip_StencilFunc + 1,
+ kBasicStencilFuncCount = kStencilFuncCount - kClipStencilFuncCount
+};
+
+/**
+ * Operations to perform based on whether stencil test passed failed.
+ */
+enum GrStencilOp {
+ kKeep_StencilOp = 0, // preserve existing stencil value
+ kReplace_StencilOp, // replace with reference value from stencl test
+ kIncWrap_StencilOp, // increment and wrap at max
+ kIncClamp_StencilOp, // increment and clamp at max
+ kDecWrap_StencilOp, // decrement and wrap at 0
+ kDecClamp_StencilOp, // decrement and clamp at 0
+ kZero_StencilOp, // zero stencil bits
+ kInvert_StencilOp, // invert stencil bits
+
+ kStencilOpCount
+};
+
+/**
+ * Struct representing stencil state.
+ */
+struct GrStencilSettings {
+ GrStencilOp fFrontPassOp; // op to perform when front faces pass
+ GrStencilOp fBackPassOp; // op to perform when back faces pass
+ GrStencilOp fFrontFailOp; // op to perform when front faces fail
+ GrStencilOp fBackFailOp; // op to perform when back faces fail
+ GrStencilFunc fFrontFunc; // test function for front faces
+ GrStencilFunc fBackFunc; // test function for back faces
+ unsigned int fFrontFuncMask; // mask for front face test
+ unsigned int fBackFuncMask; // mask for back face test
+ unsigned int fFrontFuncRef; // reference value for front face test
+ unsigned int fBackFuncRef; // reference value for back face test
+ unsigned int fFrontWriteMask; // stencil write mask for front faces
+ unsigned int fBackWriteMask; // stencil write mask for back faces
+
+ bool operator == (const GrStencilSettings& s) const {
+ // make sure this is tightly packed.
+ GR_STATIC_ASSERT(0 == sizeof(GrStencilOp)%4);
+ GR_STATIC_ASSERT(0 == sizeof(GrStencilFunc)%4);
+ GR_STATIC_ASSERT(sizeof(GrStencilSettings) ==
+ 4*sizeof(GrStencilOp) +
+ 2*sizeof(GrStencilFunc) +
+ 6*sizeof(unsigned int));
+ return 0 == memcmp(this, &s, sizeof(GrStencilSettings));
+ }
+
+ bool operator != (const GrStencilSettings& s) const {
+ return !(*this == s);
+ }
+
+ GrStencilSettings& operator =(const GrStencilSettings& s) {
+ memcpy(this, &s, sizeof(GrStencilSettings));
+ return *this;
+ }
+
+ void setSame(GrStencilOp passOp,
+ GrStencilOp failOp,
+ GrStencilFunc func,
+ unsigned int funcMask,
+ unsigned int funcRef,
+ unsigned int writeMask) {
+ fFrontPassOp = passOp;
+ fBackPassOp = passOp;
+ fFrontFailOp = failOp;
+ fBackFailOp = failOp;
+ fFrontFunc = func;
+ fBackFunc = func;
+ fFrontFuncMask = funcMask;
+ fBackFuncMask = funcMask;
+ fFrontFuncRef = funcRef;
+ fBackFuncRef = funcRef;
+ fFrontWriteMask = writeMask;
+ fBackWriteMask = writeMask;
+ }
+
+ // canonical value for disabled stenciling
+ static const GrStencilSettings gDisabled;
+ void setDisabled() {
+ *this = gDisabled;
+ }
+ bool isDisabled() const {
+ return kKeep_StencilOp == fFrontPassOp &&
+ kKeep_StencilOp == fBackPassOp &&
+ kKeep_StencilOp == fFrontFailOp &&
+ kKeep_StencilOp == fBackFailOp &&
+ kAlways_StencilFunc == fFrontFunc &&
+ kAlways_StencilFunc == fBackFunc;
+ }
+ bool doesWrite() const {
+ return !((kNever_StencilFunc == fFrontFunc ||
+ kKeep_StencilOp == fFrontPassOp) &&
+ (kNever_StencilFunc == fBackFunc ||
+ kKeep_StencilOp == fBackPassOp) &&
+ (kAlways_StencilFunc == fFrontFunc ||
+ kKeep_StencilOp == fFrontFailOp) &&
+ (kAlways_StencilFunc == fBackFunc ||
+ kKeep_StencilOp == fBackFailOp));
+ }
+ void invalidate() {
+ // just write an illegal value to the first member
+ fFrontPassOp = (GrStencilOp)-1;
+ }
+
+private:
+ friend class GrGpu;
+
+ enum {
+ kMaxStencilClipPasses = 2 // maximum number of passes to add a clip
+ // element to the stencil buffer.
+ };
+
+ /**
+ * Given a thing to draw into the stencil clip, a fill type, and a set op
+ * this function determines:
+ * 1. Whether the thing can be draw directly to the stencil clip or
+ * needs to be drawn to the client portion of the stencil first.
+ * 2. How many passes are needed.
+ * 3. What those passes are.
+ * 4. The fill rule that should actually be used to render (will
+ * always be non-inverted).
+ *
+ * @param op the set op to combine this element with the
+ * existing clip
+ * @param stencilClipMask mask with just the stencil bit used for clipping
+ * enabled.
+ * @param invertedFill is this path inverted
+ * @param numPasses out: the number of passes needed to add the
+ * element to the clip.
+ * @param settings out: the stencil settings to use for each pass
+ *
+ * @return true if the clip element's geometry can be drawn directly to the
+ * stencil clip bit. Will only be true if canBeDirect is true.
+ * numPasses will be 1 if return value is true.
+ */
+ static bool GetClipPasses(GrSetOp op,
+ bool canBeDirect,
+ unsigned int stencilClipMask,
+ bool invertedFill,
+ int* numPasses,
+ GrStencilSettings settings[kMaxStencilClipPasses]);
+};
+
+#endif
diff --git a/src/gpu/GrStringBuilder.h b/src/gpu/GrStringBuilder.h
new file mode 100644
index 0000000000..558d0419c0
--- /dev/null
+++ b/src/gpu/GrStringBuilder.h
@@ -0,0 +1,19 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrStringBuilder_DEFINED
+#define GrStringBuilder_DEFINED
+
+#include "SkString.h"
+
+typedef SkString GrStringBuilder;
+
+#endif
+
diff --git a/src/gpu/GrTBSearch.h b/src/gpu/GrTBSearch.h
new file mode 100644
index 0000000000..2697f3733b
--- /dev/null
+++ b/src/gpu/GrTBSearch.h
@@ -0,0 +1,46 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrTBSearch_DEFINED
+#define GrTBSearch_DEFINED
+
+template <typename ELEM, typename KEY>
+int GrTBSearch(const ELEM array[], int count, KEY target) {
+ GrAssert(count >= 0);
+ if (0 == count) {
+ // we should insert it at 0
+ return ~0;
+ }
+
+ int high = count - 1;
+ int low = 0;
+ while (high > low) {
+ int index = (low + high) >> 1;
+ if (LT(array[index], target)) {
+ low = index + 1;
+ } else {
+ high = index;
+ }
+ }
+
+ // check if we found it
+ if (EQ(array[high], target)) {
+ return high;
+ }
+
+ // now return the ~ of where we should insert it
+ if (LT(array[high], target)) {
+ high += 1;
+ }
+ return ~high;
+}
+
+#endif
+
diff --git a/src/gpu/GrTDArray.h b/src/gpu/GrTDArray.h
new file mode 100644
index 0000000000..731001a8c9
--- /dev/null
+++ b/src/gpu/GrTDArray.h
@@ -0,0 +1,216 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrTDArray_DEFINED
+#define GrTDArray_DEFINED
+
+#include "GrTypes.h"
+#include "GrRefCnt.h"
+
+static int GrInitialArrayAllocationCount() {
+ return 4;
+}
+
+static int GrNextArrayAllocationCount(int count) {
+ return count + ((count + 1) >> 1);
+}
+
+template <typename T> class GrTDArray {
+public:
+ GrTDArray() : fArray(NULL), fAllocated(0), fCount(0) {}
+ GrTDArray(const GrTDArray& src) {
+ fCount = fAllocated = src.fCount;
+ fArray = (T*)GrMalloc(fAllocated * sizeof(T));
+ memcpy(fArray, src.fArray, fCount * sizeof(T));
+ }
+ ~GrTDArray() {
+ if (fArray) {
+ GrFree(fArray);
+ }
+ }
+
+ bool isEmpty() const { return 0 == fCount; }
+ int count() const { return fCount; }
+
+ const T& at(int index) const {
+ GrAssert((unsigned)index < (unsigned)fCount);
+ return fArray[index];
+ }
+ T& at(int index) {
+ GrAssert((unsigned)index < (unsigned)fCount);
+ return fArray[index];
+ }
+
+ const T& operator[](int index) const { return this->at(index); }
+ T& operator[](int index) { return this->at(index); }
+
+ GrTDArray& operator=(const GrTDArray& src) {
+ if (fAllocated < src.fCount) {
+ fAllocated = src.fCount;
+ GrFree(fArray);
+ fArray = (T*)GrMalloc(fAllocated * sizeof(T));
+ }
+ fCount = src.fCount;
+ memcpy(fArray, src.fArray, fCount * sizeof(T));
+ return *this;
+ }
+
+ void reset() {
+ if (fArray) {
+ GrFree(fArray);
+ fArray = NULL;
+ }
+ fAllocated = fCount = 0;
+ }
+
+ T* begin() const { return fArray; }
+ T* end() const { return fArray + fCount; }
+ T* back() const { GrAssert(fCount); return fArray + (fCount - 1); }
+
+ T* prepend() {
+ this->growAt(0);
+ return fArray;
+ }
+
+ T* append() {
+ this->growAt(fCount);
+ return fArray + fCount - 1;
+ }
+
+ /**
+ * index may be [0..count], so that you can insert at the end (like append)
+ */
+ T* insert(int index) {
+ GrAssert((unsigned)index <= (unsigned)fCount);
+ this->growAt(index);
+ return fArray + index;
+ }
+
+ void remove(int index) {
+ GrAssert((unsigned)index < (unsigned)fCount);
+ fCount -= 1;
+ if (index < fCount) {
+ int remaining = fCount - index;
+ memmove(fArray + index, fArray + index + 1, remaining * sizeof(T));
+ }
+ }
+
+ void removeShuffle(int index) {
+ GrAssert((unsigned)index < (unsigned)fCount);
+ fCount -= 1;
+ if (index < fCount) {
+ memmove(fArray + index, fArray + fCount, sizeof(T));
+ }
+ }
+
+ // Utility iterators
+
+ /**
+ * Calls GrFree() on each element. Assumes each is NULL or was allocated
+ * with GrMalloc().
+ */
+ void freeAll() {
+ T* stop = this->end();
+ for (T* curr = this->begin(); curr < stop; curr++) {
+ GrFree(*curr);
+ }
+ this->reset();
+ }
+
+ /**
+ * Calls delete on each element. Assumes each is NULL or was allocated
+ * with new.
+ */
+ void deleteAll() {
+ T* stop = this->end();
+ for (T* curr = this->begin(); curr < stop; curr++) {
+ delete *curr;
+ }
+ this->reset();
+ }
+
+ /**
+ * Calls GrSafeUnref() on each element. Assumes each is NULL or is a
+ * subclass of GrRefCnt.
+ */
+ void unrefAll() {
+ T* stop = this->end();
+ for (T* curr = this->begin(); curr < stop; curr++) {
+ GrSafeUnref(*curr);
+ }
+ this->reset();
+ }
+
+ void visit(void visitor(T&)) const {
+ T* stop = this->end();
+ for (T* curr = this->begin(); curr < stop; curr++) {
+ if (*curr) {
+ visitor(*curr);
+ }
+ }
+ }
+
+ int find(const T& elem) const {
+ int count = this->count();
+ T* curr = this->begin();
+ for (int i = 0; i < count; i++) {
+ if (elem == curr[i]) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ friend bool operator==(const GrTDArray<T>& a, const GrTDArray<T>& b) {
+ return a.count() == b.count() &&
+ (0 == a.count() ||
+ 0 == memcmp(a.begin(), b.begin(), a.count() * sizeof(T)));
+ }
+ friend bool operator!=(const GrTDArray<T>& a, const GrTDArray<T>& b) {
+ return !(a == b);
+ }
+
+private:
+ T* fArray;
+ int fAllocated, fCount;
+
+ // growAt will increment fCount, reallocate fArray (as needed), and slide
+ // the contents of fArray to make a hole for new data at index.
+ void growAt(int index) {
+ GrAssert(fCount <= fAllocated);
+ if (0 == fAllocated) {
+ fAllocated = GrInitialArrayAllocationCount();
+ fArray = (T*)GrMalloc(fAllocated * sizeof(T));
+ } else if (fCount == fAllocated) {
+ fAllocated = GrNextArrayAllocationCount(fAllocated);
+ T* newArray = (T*)GrMalloc(fAllocated * sizeof(T));
+ memcpy(newArray, fArray, index * sizeof(T));
+ memcpy(newArray + index + 1, fArray + index,
+ (fCount - index) * sizeof(T));
+ GrFree(fArray);
+ fArray = newArray;
+ } else {
+ // check that we're not just appending
+ if (index < fCount) {
+ memmove(fArray + index + 1, fArray + index,
+ (fCount - index) * sizeof(T));
+ }
+ }
+ GrAssert(fCount < fAllocated);
+ fCount += 1;
+ }
+};
+
+extern void* GrTDArray_growAt(void*, int* allocated, int& count, int index,
+ size_t);
+
+
+#endif
+
diff --git a/src/gpu/GrTHashCache.h b/src/gpu/GrTHashCache.h
new file mode 100644
index 0000000000..8651c35c22
--- /dev/null
+++ b/src/gpu/GrTHashCache.h
@@ -0,0 +1,219 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrTHashCache_DEFINED
+#define GrTHashCache_DEFINED
+
+#include "GrTDArray.h"
+
+/**
+ * Key needs
+ * static bool EQ(const Entry&, const HashKey&);
+ * static bool LT(const Entry&, const HashKey&);
+ * uint32_t getHash() const;
+ *
+ * Allows duplicate key entries but on find you may get
+ * any of the duplicate entries returned.
+ */
+template <typename T, typename Key, size_t kHashBits> class GrTHashTable {
+public:
+ GrTHashTable() { Gr_bzero(fHash, sizeof(fHash)); }
+ ~GrTHashTable() {}
+
+ int count() const { return fSorted.count(); }
+ T* find(const Key&) const;
+ // return true if key was unique when inserted.
+ bool insert(const Key&, T*);
+ void remove(const Key&, const T*);
+ T* removeAt(int index, uint32_t hash);
+ void removeAll();
+ void deleteAll();
+ void unrefAll();
+
+ /**
+ * Return the index for the element, using a linear search.
+ */
+ int slowFindIndex(T* elem) const { return fSorted.find(elem); }
+
+#if GR_DEBUG
+ void validate() const;
+ bool contains(T*) const;
+#endif
+
+ // testing
+ const GrTDArray<T*>& getArray() const { return fSorted; }
+private:
+ enum {
+ kHashCount = 1 << kHashBits,
+ kHashMask = kHashCount - 1
+ };
+ static unsigned hash2Index(uint32_t hash) {
+ hash ^= hash >> 16;
+ if (kHashBits <= 8) {
+ hash ^= hash >> 8;
+ }
+ return hash & kHashMask;
+ }
+
+ mutable T* fHash[kHashCount];
+ GrTDArray<T*> fSorted;
+
+ // search fSorted, and return the found index, or ~index of where it
+ // should be inserted
+ int searchArray(const Key&) const;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename T, typename Key, size_t kHashBits>
+int GrTHashTable<T, Key, kHashBits>::searchArray(const Key& key) const {
+ int count = fSorted.count();
+ if (0 == count) {
+ // we should insert it at 0
+ return ~0;
+ }
+
+ const T* const* array = fSorted.begin();
+ int high = count - 1;
+ int low = 0;
+ while (high > low) {
+ int index = (low + high) >> 1;
+ if (Key::LT(*array[index], key)) {
+ low = index + 1;
+ } else {
+ high = index;
+ }
+ }
+
+ // check if we found it
+ if (Key::EQ(*array[high], key)) {
+ // above search should have found the first occurrence if there
+ // are multiple.
+ GrAssert(0 == high || Key::LT(*array[high - 1], key));
+ return high;
+ }
+
+ // now return the ~ of where we should insert it
+ if (Key::LT(*array[high], key)) {
+ high += 1;
+ }
+ return ~high;
+}
+
+template <typename T, typename Key, size_t kHashBits>
+T* GrTHashTable<T, Key, kHashBits>::find(const Key& key) const {
+ int hashIndex = hash2Index(key.getHash());
+ T* elem = fHash[hashIndex];
+
+ if (NULL == elem || !Key::EQ(*elem, key)) {
+ // bsearch for the key in our sorted array
+ int index = this->searchArray(key);
+ if (index < 0) {
+ return NULL;
+ }
+ elem = fSorted[index];
+ // update the hash
+ fHash[hashIndex] = elem;
+ }
+ return elem;
+}
+
+template <typename T, typename Key, size_t kHashBits>
+bool GrTHashTable<T, Key, kHashBits>::insert(const Key& key, T* elem) {
+ int index = this->searchArray(key);
+ bool first = index < 0;
+ if (first) {
+ // turn it into the actual index
+ index = ~index;
+ }
+ // add it to our array
+ *fSorted.insert(index) = elem;
+ // update our hash table (overwrites any dupe's position in the hash)
+ fHash[hash2Index(key.getHash())] = elem;
+ return first;
+}
+
+template <typename T, typename Key, size_t kHashBits>
+void GrTHashTable<T, Key, kHashBits>::remove(const Key& key, const T* elem) {
+ int index = hash2Index(key.getHash());
+ if (fHash[index] == elem) {
+ fHash[index] = NULL;
+ }
+
+ // remove from our sorted array
+ index = this->searchArray(key);
+ GrAssert(index >= 0);
+ // if there are multiple matches searchArray will give us the first match
+ // march forward until we find elem.
+ while (elem != fSorted[index]) {
+ ++index;
+ GrAssert(index < fSorted.count());
+ }
+ GrAssert(elem == fSorted[index]);
+ fSorted.remove(index);
+}
+
+template <typename T, typename Key, size_t kHashBits>
+T* GrTHashTable<T, Key, kHashBits>::removeAt(int elemIndex, uint32_t hash) {
+ int hashIndex = hash2Index(hash);
+ if (fHash[hashIndex] == fSorted[elemIndex]) {
+ fHash[hashIndex] = NULL;
+ }
+ // remove from our sorted array
+ T* elem = fSorted[elemIndex];
+ fSorted.remove(elemIndex);
+ return elem;
+}
+
+template <typename T, typename Key, size_t kHashBits>
+void GrTHashTable<T, Key, kHashBits>::removeAll() {
+ fSorted.reset();
+ Gr_bzero(fHash, sizeof(fHash));
+}
+
+template <typename T, typename Key, size_t kHashBits>
+void GrTHashTable<T, Key, kHashBits>::deleteAll() {
+ fSorted.deleteAll();
+ Gr_bzero(fHash, sizeof(fHash));
+}
+
+template <typename T, typename Key, size_t kHashBits>
+void GrTHashTable<T, Key, kHashBits>::unrefAll() {
+ fSorted.unrefAll();
+ Gr_bzero(fHash, sizeof(fHash));
+}
+
+#if GR_DEBUG
+template <typename T, typename Key, size_t kHashBits>
+void GrTHashTable<T, Key, kHashBits>::validate() const {
+ for (size_t i = 0; i < GR_ARRAY_COUNT(fHash); i++) {
+ if (fHash[i]) {
+ unsigned hashIndex = hash2Index(Key::GetHash(*fHash[i]));
+ GrAssert(hashIndex == i);
+ }
+ }
+
+ int count = fSorted.count();
+ for (int i = 1; i < count; i++) {
+ GrAssert(Key::LT(*fSorted[i - 1], *fSorted[i]) ||
+ Key::EQ(*fSorted[i - 1], *fSorted[i]));
+ }
+}
+
+template <typename T, typename Key, size_t kHashBits>
+bool GrTHashTable<T, Key, kHashBits>::contains(T* elem) const {
+ int index = fSorted.find(elem);
+ return index >= 0;
+}
+
+#endif
+
+#endif
+
diff --git a/src/gpu/GrTLList.h b/src/gpu/GrTLList.h
new file mode 100644
index 0000000000..ea310ac20e
--- /dev/null
+++ b/src/gpu/GrTLList.h
@@ -0,0 +1,54 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrTLList_DEFINED
+#define GrTLList_DEFINED
+
+#include "GrNoncopyable.h"
+
+template <typename T> class GrTLList : GrNoncopyable {
+public:
+ class Entry {
+ Entry* fPrev;
+ Entry* fNext;
+ };
+
+ GrTLList() : fHead(NULL), fTail(NULL) {}
+#if GR_DEBUG
+ ~GrTLList() {
+ GrAssert(NULL == fHead);
+ GrAssert(NULL == ftail);
+ }
+#endif
+
+ T* head() const { return fHead; }
+ T* tail() const { return fTail; }
+
+ void addToHead(T*);
+ void addToTail(T*);
+ void removeFromList(T*);
+
+private:
+ Entry* fHead;
+ Entry* fTail;
+
+ friend class Entry;
+};
+
+
+class Parent {
+ GrTDLList<Child> fList;
+};
+
+class Child : public GrTLList::Entry<Child> {
+};
+
+#endif
+
diff --git a/src/gpu/GrTextStrike.h b/src/gpu/GrTextStrike.h
new file mode 100644
index 0000000000..701acea7ab
--- /dev/null
+++ b/src/gpu/GrTextStrike.h
@@ -0,0 +1,115 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrTextStrike_DEFINED
+#define GrTextStrike_DEFINED
+
+#include "GrAllocPool.h"
+#include "GrFontScaler.h"
+#include "GrTHashCache.h"
+#include "GrPoint.h"
+#include "GrGlyph.h"
+
+class GrAtlasMgr;
+class GrFontCache;
+class GrGpu;
+class GrFontPurgeListener;
+
+/**
+ * The textcache maps a hostfontscaler instance to a dictionary of
+ * glyphid->strike
+ */
+class GrTextStrike {
+public:
+ GrTextStrike(GrFontCache*, const GrKey* fontScalerKey, GrMaskFormat,
+ GrAtlasMgr*);
+ ~GrTextStrike();
+
+ const GrKey* getFontScalerKey() const { return fFontScalerKey; }
+ GrFontCache* getFontCache() const { return fFontCache; }
+ GrMaskFormat getMaskFormat() const { return fMaskFormat; }
+
+ inline GrGlyph* getGlyph(GrGlyph::PackedID, GrFontScaler*);
+ bool getGlyphAtlas(GrGlyph*, GrFontScaler*);
+
+ // testing
+ int countGlyphs() const { return fCache.getArray().count(); }
+ const GrGlyph* glyphAt(int index) const {
+ return fCache.getArray()[index];
+ }
+ GrAtlas* getAtlas() const { return fAtlas; }
+
+public:
+ // for LRU
+ GrTextStrike* fPrev;
+ GrTextStrike* fNext;
+
+private:
+ class Key;
+ GrTHashTable<GrGlyph, Key, 7> fCache;
+ const GrKey* fFontScalerKey;
+ GrTAllocPool<GrGlyph> fPool;
+
+ GrFontCache* fFontCache;
+ GrAtlasMgr* fAtlasMgr;
+ GrAtlas* fAtlas; // linklist
+
+ GrMaskFormat fMaskFormat;
+
+ GrGlyph* generateGlyph(GrGlyph::PackedID packed, GrFontScaler* scaler);
+ // returns true if after the purge, the strike is empty
+ bool purgeAtlasAtY(GrAtlas* atlas, int yCoord);
+
+ friend class GrFontCache;
+};
+
+class GrFontCache {
+public:
+ GrFontCache(GrGpu*);
+ ~GrFontCache();
+
+ inline GrTextStrike* getStrike(GrFontScaler*);
+
+ void freeAll();
+
+ void purgeExceptFor(GrTextStrike*);
+
+ // testing
+ int countStrikes() const { return fCache.getArray().count(); }
+ const GrTextStrike* strikeAt(int index) const {
+ return fCache.getArray()[index];
+ }
+ GrTextStrike* getHeadStrike() const { return fHead; }
+
+#if GR_DEBUG
+ void validate() const;
+#else
+ void validate() const {}
+#endif
+
+private:
+ friend class GrFontPurgeListener;
+
+ class Key;
+ GrTHashTable<GrTextStrike, Key, 8> fCache;
+ // for LRU
+ GrTextStrike* fHead;
+ GrTextStrike* fTail;
+
+ GrGpu* fGpu;
+ GrAtlasMgr* fAtlasMgr;
+
+
+ GrTextStrike* generateStrike(GrFontScaler*, const Key&);
+ inline void detachStrikeFromList(GrTextStrike*);
+};
+
+#endif
+
diff --git a/src/gpu/ios/SkUIView.mm b/src/gpu/ios/SkUIView.mm
deleted file mode 100644
index 261ed9ca1f..0000000000
--- a/src/gpu/ios/SkUIView.mm
+++ /dev/null
@@ -1,827 +0,0 @@
-#import "SkUIView.h"
-#include <QuartzCore/QuartzCore.h>
-
-//#include "SkGpuCanvas.h"
-#include "SkGpuDevice.h"
-#include "SkCGUtils.h"
-#include "GrContext.h"
-
-#define SKWIND_CONFIG SkBitmap::kRGB_565_Config
-//#define SKWIND_CONFIG SkBitmap::kARGB_8888_Config
-#define SKGL_CONFIG kEAGLColorFormatRGB565
-//#define SKGL_CONFIG kEAGLColorFormatRGBA8
-
-#define SHOW_FPS
-#define FORCE_REDRAW
-//#define DUMP_FPS_TO_PRINTF
-
-//#define USE_ACCEL_TO_ROTATE
-
-//#define SHOULD_COUNTER_INIT 334
-static int gShouldCounter;
-static bool should_draw() {
- if (--gShouldCounter == 0) {
- // printf("\n");
- }
- return true;
- return gShouldCounter >= 0;
-}
-#ifdef SHOULD_COUNTER_INIT
- bool (*gShouldDrawProc)() = should_draw;
-#else
- bool (*gShouldDrawProc)() = NULL;
-#endif
-
-//#define USE_GL_1
-//#define USE_GL_2
-
-#if defined(USE_GL_1) || defined(USE_GL_2)
- #define USE_GL
-#endif
-
-@implementation SkUIView
-
-
-@synthesize fWind;
-@synthesize fTitle;
-@synthesize fBackend;
-@synthesize fComplexClip;
-@synthesize fUseWarp;
-
-#include "SkWindow.h"
-#include "SkEvent.h"
-
-static float gScreenScale = 1;
-
-extern SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv);
-
-#define kREDRAW_UIVIEW_GL "sk_redraw_uiview_gl_iOS"
-
-#define TITLE_HEIGHT 0
-
-static const float SCALE_FOR_ZOOM_LENS = 4.0;
-#define Y_OFFSET_FOR_ZOOM_LENS 200
-#define SIZE_FOR_ZOOM_LENS 250
-
-static const float MAX_ZOOM_SCALE = 4.0;
-static const float MIN_ZOOM_SCALE = 2.0 / MAX_ZOOM_SCALE;
-
-extern bool gDoTraceDraw;
-#define DO_TRACE_DRAW_MAX 100
-
-#ifdef SHOW_FPS
-struct FPSState {
- static const int FRAME_COUNT = 60;
-
- CFTimeInterval fNow0, fNow1;
- CFTimeInterval fTime0, fTime1, fTotalTime;
- int fFrameCounter;
- int fDrawCounter;
-
- FPSState() {
- fTime0 = fTime1 = fTotalTime = 0;
- fFrameCounter = 0;
- }
-
- void startDraw() {
- fNow0 = CACurrentMediaTime();
-
- if (0 == fDrawCounter && false) {
- gDoTraceDraw = true;
- SkDebugf("\n");
- }
- }
-
- void endDraw() {
- fNow1 = CACurrentMediaTime();
-
- if (0 == fDrawCounter) {
- gDoTraceDraw = true;
- }
- if (DO_TRACE_DRAW_MAX == ++fDrawCounter) {
- fDrawCounter = 0;
- }
- }
-
- void flush(SkOSWindow* wind) {
- CFTimeInterval now2 = CACurrentMediaTime();
-
- fTime0 += fNow1 - fNow0;
- fTime1 += now2 - fNow1;
-
- if (++fFrameCounter == FRAME_COUNT) {
- CFTimeInterval totalNow = CACurrentMediaTime();
- fTotalTime = totalNow - fTotalTime;
-
- SkMSec ms0 = (int)(1000 * fTime0 / FRAME_COUNT);
- SkMSec msTotal = (int)(1000 * fTotalTime / FRAME_COUNT);
-
- SkString str;
- str.printf("ms: %d [%d], fps: %3.1f", msTotal, ms0,
- FRAME_COUNT / fTotalTime);
-#ifdef DUMP_FPS_TO_PRINTF
- SkDebugf("%s\n", str.c_str());
-#else
- wind->setTitle(str.c_str());
-#endif
-
- fTotalTime = totalNow;
- fTime0 = fTime1 = 0;
- fFrameCounter = 0;
- }
- }
-};
-
-static FPSState gFPS;
-
- #define FPS_StartDraw() gFPS.startDraw()
- #define FPS_EndDraw() gFPS.endDraw()
- #define FPS_Flush(wind) gFPS.flush(wind)
-#else
- #define FPS_StartDraw()
- #define FPS_EndDraw()
- #define FPS_Flush(wind)
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-
-#ifdef USE_GL
-+ (Class) layerClass
-{
- return [CAEAGLLayer class];
-}
-#endif
-
-- (id)initWithMyDefaults {
- fBackend = kGL_Backend;
- fUseWarp = false;
- fRedrawRequestPending = false;
- // FIXME: If iOS has argc & argv, pass them here.
- //fWind = create_sk_window(self, 0, NULL);
- //fWind->setConfig(SKWIND_CONFIG);
- fMatrix.reset();
- fLocalMatrix.reset();
- fNeedGestureEnded = false;
- fNeedFirstPinch = true;
- fZoomAround = false;
- fComplexClip = false;
-
- [self initGestures];
-
-#ifdef USE_GL
- CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
- eaglLayer.opaque = TRUE;
- eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithBool:NO],
- kEAGLDrawablePropertyRetainedBacking,
- SKGL_CONFIG,
- kEAGLDrawablePropertyColorFormat,
- nil];
-
-#ifdef USE_GL_1
- fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
-#else
- fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
-#endif
-
- if (!fGL.fContext || ![EAGLContext setCurrentContext:fGL.fContext])
- {
- [self release];
- return nil;
- }
-
- // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
- glGenFramebuffersOES(1, &fGL.fFramebuffer);
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, fGL.fFramebuffer);
-
- glGenRenderbuffersOES(1, &fGL.fRenderbuffer);
- glGenRenderbuffersOES(1, &fGL.fStencilbuffer);
-
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fRenderbuffer);
- glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, fGL.fRenderbuffer);
-
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fStencilbuffer);
- glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, fGL.fStencilbuffer);
-#endif
-
-#ifdef USE_ACCEL_TO_ROTATE
- fRotateMatrix.reset();
- [UIAccelerometer sharedAccelerometer].delegate = self;
- [UIAccelerometer sharedAccelerometer].updateInterval = 1 / 30.0;
-#endif
- return self;
-}
-
-- (id)initWithCoder:(NSCoder*)coder {
- if ((self = [super initWithCoder:coder])) {
- self = [self initWithMyDefaults];
- }
- return self;
-}
-
-- (id)initWithFrame:(CGRect)frame {
- if (self = [super initWithFrame:frame]) {
- self = [self initWithMyDefaults];
- }
- return self;
-}
-
-#include "SkImageDecoder.h"
-#include "SkStream_NSData.h"
-
-static void zoom_around(SkCanvas* canvas, float cx, float cy, float zoom) {
- float clipW = SIZE_FOR_ZOOM_LENS;
- float clipH = SIZE_FOR_ZOOM_LENS;
-
- SkRect r;
- r.set(0, 0, clipW, clipH);
- r.offset(cx - clipW/2, cy - clipH/2);
-
- SkPaint paint;
- paint.setColor(0xFF66AAEE);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(10);
-
- // draw our "frame" around the zoom lens
- canvas->drawRect(r, paint);
-
- // now clip and scale the lens
- canvas->clipRect(r);
- canvas->translate(cx, cy);
- canvas->scale(zoom, zoom);
- canvas->translate(-cx, -cy);
-}
-
-- (void)drawWithCanvas:(SkCanvas*)canvas {
- if (fComplexClip) {
- canvas->drawColor(SK_ColorBLUE);
-
- SkPath path;
- static const SkRect r[] = {
- { 50, 50, 250, 250 },
- { 150, 150, 500, 600 }
- };
- for (size_t i = 0; i < GR_ARRAY_COUNT(r); i++) {
- path.addRect(r[i]);
- }
- canvas->clipPath(path);
- }
-
- // This is to consolidate multiple inval requests
- fRedrawRequestPending = false;
-
- if (fFlingState.isActive()) {
- if (!fFlingState.evaluateMatrix(&fLocalMatrix)) {
- [self flushLocalMatrix];
- }
- }
-
- SkMatrix localMatrix = fLocalMatrix;
-#ifdef USE_ACCEL_TO_ROTATE
- localMatrix.preConcat(fRotateMatrix);
-#endif
-
- SkMatrix matrix;
- matrix.setConcat(localMatrix, fMatrix);
-
- const SkMatrix* localM = NULL;
- if (localMatrix.getType() & SkMatrix::kScale_Mask) {
- localM = &localMatrix;
- }
-#ifdef USE_ACCEL_TO_ROTATE
- localM = &localMatrix;
-#endif
- canvas->setExternalMatrix(localM);
-
-#ifdef SHOULD_COUNTER_INIT
- gShouldCounter = SHOULD_COUNTER_INIT;
-#endif
- {
- int saveCount = canvas->save();
- canvas->concat(matrix);
- // SkRect r = { 10, 10, 500, 600 }; canvas->clipRect(r);
- fWind->draw(canvas);
- canvas->restoreToCount(saveCount);
- }
-
- if (fZoomAround) {
- zoom_around(canvas, fZoomAroundX, fZoomAroundY, SCALE_FOR_ZOOM_LENS);
- canvas->concat(matrix);
- fWind->draw(canvas);
- }
-
-#ifdef FORCE_REDRAW
- fWind->inval(NULL);
-#endif
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-- (void)layoutSubviews {
- int W, H;
-
- gScreenScale = [UIScreen mainScreen].scale;
-
-#ifdef USE_GL
-
- CAEAGLLayer* eaglLayer = (CAEAGLLayer*)self.layer;
- if ([self respondsToSelector:@selector(setContentScaleFactor:)]) {
- self.contentScaleFactor = gScreenScale;
- }
-
- // Allocate color buffer backing based on the current layer size
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fRenderbuffer);
- [fGL.fContext renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:eaglLayer];
-
- glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &fGL.fWidth);
- glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &fGL.fHeight);
-
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fStencilbuffer);
- glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_STENCIL_INDEX8_OES, fGL.fWidth, fGL.fHeight);
-
-
- if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
- {
- NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
- }
-
- W = fGL.fWidth;
- H = fGL.fHeight;
-#else
- CGRect rect = [self bounds];
- W = (int)CGRectGetWidth(rect);
- H = (int)CGRectGetHeight(rect) - TITLE_HEIGHT;
-#endif
-
- printf("---- layoutSubviews %d %d\n", W, H);
- fWind->resize(W, H);
- fWind->inval(NULL);
-}
-
-#ifdef USE_GL
-
-static GrContext* gCtx;
-static GrContext* get_global_grctx() {
- // should be pthread-local at least
- if (NULL == gCtx) {
-#ifdef USE_GL_1
- gCtx = GrContext::Create(kOpenGL_Fixed_GrEngine, 0);
-#else
- gCtx = GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
-#endif
- }
- return gCtx;
-}
-
-#include "SkDevice.h"
-#include "SkShader.h"
-#include "SkGrTexturePixelRef.h"
-#include "GrMesh.h"
-#include "SkRandom.h"
-
-#include "GrAtlas.h"
-#include "GrTextStrike.h"
-
-static void show_fontcache(GrContext* ctx, SkCanvas* canvas) {
-#if 0
- SkPaint paint;
- const int SIZE = 64;
- GrAtlas* plot[64][64];
-
- paint.setAntiAlias(true);
- paint.setTextSize(24);
- paint.setTextAlign(SkPaint::kCenter_Align);
-
- Gr_bzero(plot, sizeof(plot));
-
- GrFontCache* cache = ctx->getFontCache();
- GrTextStrike* strike = cache->getHeadStrike();
- int count = 0;
- while (strike) {
- GrAtlas* atlas = strike->getAtlas();
- while (atlas) {
- int x = atlas->getPlotX();
- int y = atlas->getPlotY();
-
- SkRandom rand((intptr_t)strike);
- SkColor c = rand.nextU() | 0x80808080;
- paint.setColor(c);
- paint.setAlpha(0x80);
-
- SkRect r;
- r.set(x * SIZE, y * SIZE, (x + 1)*SIZE, (y+1)*SIZE);
- r.inset(1, 1);
- canvas->drawRect(r, paint);
-
- paint.setColor(0xFF660000);
- SkString label;
- label.printf("%d", count);
- canvas->drawText(label.c_str(), label.size(), r.centerX(),
- r.fTop + r.height() * 2 / 3, paint);
-
- atlas = atlas->nextAtlas();
- }
- strike = strike->fNext;
- count += 1;
- }
-#endif
-}
-
-void test_patch(SkCanvas* canvas, const SkBitmap& bm, SkScalar scale);
-
-static void draw_mesh(SkCanvas* canvas, const SkBitmap& bm) {
- GrMesh fMesh;
-
- SkRect r;
- r.set(0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()));
-
- // fMesh.init(bounds, fBitmap.width() / 40, fBitmap.height() / 40, texture);
- fMesh.init(r, bm.width()/16, bm.height()/16, r);
-
- SkPaint paint;
- SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
- paint.setShader(s)->unref();
- fMesh.draw(canvas, paint);
-}
-
-static void scale_about(SkCanvas* canvas, float sx, float sy, float px, float py) {
- canvas->translate(px, py);
- canvas->scale(sx, sy);
- canvas->translate(-px, -py);
-}
-
-static float grInterp(float v0, float v1, float percent) {
- return v0 + percent * (v1 - v0);
-}
-
-static void draw_device(SkCanvas* canvas, SkDevice* dev, float w, float h, float warp) {
- canvas->save();
- float s = grInterp(1, 0.8, warp);
- scale_about(canvas, s, s, w/2, h/2);
- test_patch(canvas, dev->accessBitmap(false), warp);
- canvas->restore();
-}
-
-- (void)drawInGL {
-// printf("------ drawInGL\n");
- // This application only creates a single context which is already set current at this point.
- // This call is redundant, but needed if dealing with multiple contexts.
- [EAGLContext setCurrentContext:fGL.fContext];
-
- // This application only creates a single default framebuffer which is already bound at this point.
- // This call is redundant, but needed if dealing with multiple framebuffers.
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, fGL.fFramebuffer);
-
- GLint scissorEnable;
- glGetIntegerv(GL_SCISSOR_TEST, &scissorEnable);
- glDisable(GL_SCISSOR_TEST);
- glClearColor(0,0,0,0);
- glClear(GL_COLOR_BUFFER_BIT);
- if (scissorEnable) {
- glEnable(GL_SCISSOR_TEST);
- }
- glViewport(0, 0, fWind->width(), fWind->height());
-
- GrContext* ctx = get_global_grctx();
-
- //SkGpuCanvas origCanvas(ctx);
- //origCanvas.setBitmapDevice(fWind->getBitmap());
- //gl->reset();
-
- SkCanvas glCanvas;
- SkGpuDevice* dev = new SkGpuDevice(ctx, SkGpuDevice::Current3DApiRenderTarget());
- glCanvas.setDevice(dev)->unref();
-
- SkCanvas rasterCanvas;
-
- SkCanvas* canvas;
- //SkDevice* dev = NULL;
-
- switch (fBackend) {
- case kRaster_Backend:
- canvas = &rasterCanvas;
- break;
- case kGL_Backend:
- canvas = &glCanvas;
- break;
- }
-
-// if (fUseWarp || fWarpState.isActive()) {
-// if (kGL_Backend == fBackend) {
-// dev = origCanvas.createDevice(fWind->getBitmap(), true);
-// canvas->setDevice(dev)->unref();
-// } else {
-// canvas->setBitmapDevice(fWind->getBitmap());
-// dev = canvas->getDevice();
-// }
-// } else {
-// canvas->setBitmapDevice(fWind->getBitmap());
-// dev = NULL;
-// }
-
- canvas->translate(0, TITLE_HEIGHT);
-
- // if we're not "retained", then we have to always redraw everything.
- // This call forces us to ignore the fDirtyRgn, and draw everywhere.
- // If we are "retained", we can skip this call (as the raster case does)
- fWind->forceInvalAll();
-
- FPS_StartDraw();
- [self drawWithCanvas:canvas];
- FPS_EndDraw();
-
-// if (dev) {
-// draw_device(&origCanvas, dev, fWind->width(), fWind->height(),
-// fWarpState.evaluate());
-// } else {
-// if (kRaster_Backend == fBackend) {
-// origCanvas.drawBitmap(fWind->getBitmap(), 0, 0, NULL);
-// }
-// // else GL - we're already on screen
-// }
-
- show_fontcache(ctx, canvas);
- ctx->flush(false);
-
- // This application only creates a single color renderbuffer which is already bound at this point.
- // This call is redundant, but needed if dealing with multiple renderbuffers.
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fRenderbuffer);
- [fGL.fContext presentRenderbuffer:GL_RENDERBUFFER_OES];
-
-#if GR_COLLECT_STATS
- static int frame = 0;
- if (!(frame % 100)) {
- get_global_grctx()->printStats();
- }
- get_global_grctx()->resetStats();
- ++frame;
-#endif
-
- FPS_Flush(fWind);
-
-#if 0
- gCtx->deleteAllTextures(GrTextureCache::kAbandonTexture_DeleteMode);
- gCtx->unref();
- gCtx = NULL;
-#endif
-}
-
-#else // raster case
-
-- (void)drawRect:(CGRect)rect {
- SkCanvas canvas;
- canvas.setBitmapDevice(fWind->getBitmap());
- FPS_StartDraw();
- [self drawWithCanvas:&canvas];
- FPS_EndDraw();
-
- CGContextRef cg = UIGraphicsGetCurrentContext();
- SkCGDrawBitmap(cg, fWind->getBitmap(), 0, TITLE_HEIGHT);
-
- FPS_Flush(fWind);
-
-}
-#endif
-
-- (void)setWarpState:(bool)useWarp {
- fWarpState.stop(); // we should reverse from where we are if active...
-
- const float duration = 0.5;
- fUseWarp = useWarp;
- if (useWarp) {
- fWarpState.start(0, 1, duration);
- } else {
- fWarpState.start(1, 0, duration);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-- (void)flushLocalMatrix {
- fMatrix.postConcat(fLocalMatrix);
- fLocalMatrix.reset();
- fFlingState.stop();
- fNeedGestureEnded = false;
- fNeedFirstPinch = true;
-}
-
-- (void)localMatrixWithGesture:(UIGestureRecognizer*)gesture {
- fNeedGestureEnded = true;
-
- switch (gesture.state) {
- case UIGestureRecognizerStateCancelled:
- case UIGestureRecognizerStateEnded:
- [self flushLocalMatrix];
- break;
- case UIGestureRecognizerStateChanged: {
- SkMatrix matrix;
- matrix.setConcat(fLocalMatrix, fMatrix);
- } break;
- default:
- break;
- }
-}
-
-- (void)commonHandleGesture:(UIGestureRecognizer*)sender {
- if (fFlingState.isActive()) {
- [self flushLocalMatrix];
- }
-
- switch (sender.state) {
- case UIGestureRecognizerStateBegan:
- [self flushLocalMatrix];
- break;
- default:
- break;
- }
-}
-
-- (float)limitTotalZoom:(float)scale {
- // this query works 'cause we know that we're square-scale w/ no skew/rotation
- const float curr = fMatrix[0];
-
- if (scale > 1 && curr * scale > MAX_ZOOM_SCALE) {
- scale = MAX_ZOOM_SCALE / curr;
- } else if (scale < 1 && curr * scale < MIN_ZOOM_SCALE) {
- scale = MIN_ZOOM_SCALE / curr;
- }
- return scale;
-}
-
-- (void)handleLongPressGesture:(UILongPressGestureRecognizer*)sender {
- [self commonHandleGesture:sender];
-
- if ([sender numberOfTouches] == 0) {
- fZoomAround = false;
- return;
- }
-
- CGPoint pt = [sender locationOfTouch:0 inView:self];
- switch (sender.state) {
- case UIGestureRecognizerStateBegan:
- case UIGestureRecognizerStateChanged:
- fZoomAround = true;
- fZoomAroundX = pt.x;
- fZoomAroundY = pt.y - Y_OFFSET_FOR_ZOOM_LENS;
- break;
- case UIGestureRecognizerStateEnded:
- case UIGestureRecognizerStateCancelled:
- fZoomAround = false;
- break;
- default:
- break;
- }
-}
-
-- (void)addAndReleaseGesture:(UIGestureRecognizer*)gesture {
- [self addGestureRecognizer:gesture];
- [gesture release];
-}
-
-
-
-//Gesture Handlers
-- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
- for (UITouch *touch in touches) {
- CGPoint loc = [touch locationInView:self];
- fWind->handleClick(loc.x, loc.y, SkView::Click::kDown_State, touch);
- }
-}
-
-- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
- for (UITouch *touch in touches) {
- CGPoint loc = [touch locationInView:self];
- fWind->handleClick(loc.x, loc.y, SkView::Click::kMoved_State, touch);
- }
-}
-
-- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
- for (UITouch *touch in touches) {
- CGPoint loc = [touch locationInView:self];
- fWind->handleClick(loc.x, loc.y, SkView::Click::kUp_State, touch);
- }
-}
-
-- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
- for (UITouch *touch in touches) {
- CGPoint loc = [touch locationInView:self];
- fWind->handleClick(loc.x, loc.y, SkView::Click::kUp_State, touch);
- }
-}
-
-- (void)initGestures {
- UILongPressGestureRecognizer* longG = [UILongPressGestureRecognizer alloc];
- [longG initWithTarget:self action:@selector(handleLongPressGesture:)];
- [self addAndReleaseGesture:longG];
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static float abs(float x) { return x < 0 ? -x : x; }
-
-static bool normalize(UIAcceleration* acc, float xy[]) {
- float mag2 = acc.x*acc.x + acc.y*acc.y + acc.z*acc.z;
- if (mag2 < 0.000001) {
- return false;
- }
- if (abs((float)acc.z) > 0.9 * sqrt(mag2)) {
- return false;
- }
-
- mag2 = acc.x*acc.x + acc.y*acc.y;
- if (mag2 < 0.000001) {
- return false;
- }
- float scale = 1 / sqrt(mag2);
- xy[0] = acc.x * scale;
- xy[1] = acc.y * scale;
- return true;
-}
-
-static void normalize(float xy[]) {
- float scale = 1 / sqrt(xy[0]*xy[0] + xy[1]*xy[1]);
- xy[0] *= scale;
- xy[1] *= scale;
-}
-
-static float weighted_average(float newv, float oldv) {
- return newv * 0.25 + oldv * 0.75;
-}
-
-- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acc {
-
- float norm[2];
- if (normalize(acc, norm)) {
- float sinv = -norm[0];
- float cosv = -norm[1];
- // smooth
- norm[0] = weighted_average(sinv, -fRotateMatrix[1]);
- norm[1] = weighted_average(cosv, fRotateMatrix[0]);
- normalize(norm);
- fRotateMatrix.setSinCos(norm[0], norm[1], 400, 400);
- }
-#if 0
- NSDate *now = [NSDate date];
- NSTimeInterval intervalDate = [now timeIntervalSinceDate:now_prev];
-
- velX += (acceleration.x * intervalDate);
- distX += (velX * intervalDate);
- //do other axis here too
-
- // setup for next UIAccelerometer event
- now_prev = now;
-#endif
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-- (void)setSkTitle:(const char *)title {
- if (fTitle) {
- fTitle.title = [NSString stringWithUTF8String:title];
- }
-}
-
-- (BOOL)onHandleEvent:(const SkEvent&)evt {
- if (evt.isType(kREDRAW_UIVIEW_GL)) {
- [self drawInGL];
- return true;
- }
- return false;
-}
-
-- (void)postInvalWithRect:(const SkIRect*)r {
-#ifdef USE_GL
-
-#if 1
- if (!fRedrawRequestPending) {
- fRedrawRequestPending = true;
- /*
- performSelectorOnMainThread seems to starve updating other views
- (e.g. our FPS view in the titlebar), so we use the afterDelay
- version
- */
- if (0) {
- [self performSelectorOnMainThread:@selector(drawInGL) withObject:nil waitUntilDone:NO];
- } else {
- [self performSelector:@selector(drawInGL) withObject:nil afterDelay:0];
- }
- }
-#else
- if (!fRedrawRequestPending) {
- SkEvent* evt = new SkEvent(kREDRAW_UIVIEW_GL);
- evt->post(fWind->getSinkID());
- fRedrawRequestPending = true;
- }
-#endif
-
-#else
- if (r) {
- [self setNeedsDisplayInRect:CGRectMake(r->fLeft, r->fTop,
- r->width(), r->height())];
- } else {
- [self setNeedsDisplay];
- }
-#endif
-}
-
-@end