Work-around for a Skia rasterization bug
Bug #6411457
Skia does not generates the bottom right pixel of a rect when
drawing a rect as an SkPath into an alpha8 bitmap.
Change-Id: Ifb5286ae67745c9e44ee387b6d6ad607a9a2e6ce
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
index f180e94..3a95b99 100644
--- a/libs/hwui/ShapeCache.h
+++ b/libs/hwui/ShapeCache.h
@@ -336,6 +336,19 @@
protected:
PathTexture* addTexture(const Entry& entry, const SkPath *path, const SkPaint* paint);
+ PathTexture* addTexture(const Entry& entry, SkBitmap* bitmap);
+ void addTexture(const Entry& entry, SkBitmap* bitmap, PathTexture* texture);
+
+ /**
+ * Ensures there is enough space in the cache for a texture of the specified
+ * dimensions.
+ */
+ void purgeCache(uint32_t width, uint32_t height);
+
+ void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height);
+ void initPaint(SkPaint& paint);
+
+ bool checkTextureSize(uint32_t width, uint32_t height);
PathTexture* get(Entry entry) {
return mCache.get(entry);
@@ -489,8 +502,63 @@
}
}
-void computePathBounds(const SkPath *path, const SkPaint* paint,
+void computePathBounds(const SkPath* path, const SkPaint* paint,
float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
+void computeBounds(const SkRect& bounds, const SkPaint* paint,
+ float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
+
+static PathTexture* createTexture(float left, float top, float offset,
+ uint32_t width, uint32_t height, uint32_t id) {
+ PathTexture* texture = new PathTexture;
+ texture->left = left;
+ texture->top = top;
+ texture->offset = offset;
+ texture->width = width;
+ texture->height = height;
+ texture->generation = id;
+ return texture;
+}
+
+template<class Entry>
+void ShapeCache<Entry>::purgeCache(uint32_t width, uint32_t height) {
+ const uint32_t size = width * height;
+ // Don't even try to cache a bitmap that's bigger than the cache
+ if (size < mMaxSize) {
+ while (mSize + size > mMaxSize) {
+ mCache.removeOldest();
+ }
+ }
+}
+
+template<class Entry>
+void ShapeCache<Entry>::initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) {
+ bitmap.setConfig(SkBitmap::kA8_Config, width, height);
+ bitmap.allocPixels();
+ bitmap.eraseColor(0);
+}
+
+template<class Entry>
+void ShapeCache<Entry>::initPaint(SkPaint& paint) {
+ // Make sure the paint is opaque, color, alpha, filter, etc.
+ // will be applied later when compositing the alpha8 texture
+ paint.setColor(0xff000000);
+ paint.setAlpha(255);
+ paint.setColorFilter(NULL);
+ paint.setMaskFilter(NULL);
+ paint.setShader(NULL);
+ SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode);
+ SkSafeUnref(paint.setXfermode(mode));
+}
+
+template<class Entry>
+bool ShapeCache<Entry>::checkTextureSize(uint32_t width, uint32_t height) {
+ if (width > mMaxTextureSize || height > mMaxTextureSize) {
+ ALOGW("Shape %s too large to be rendered into a texture (%dx%d, max=%dx%d)",
+ mName, width, height, mMaxTextureSize, mMaxTextureSize);
+ return false;
+ }
+ return true;
+}
template<class Entry>
PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *path,
@@ -500,51 +568,31 @@
uint32_t width, height;
computePathBounds(path, paint, left, top, offset, width, height);
- if (width > mMaxTextureSize || height > mMaxTextureSize) {
- ALOGW("Shape %s too large to be rendered into a texture (%dx%d, max=%dx%d)",
- mName, width, height, mMaxTextureSize, mMaxTextureSize);
- return NULL;
- }
+ if (!checkTextureSize(width, height)) return NULL;
- const uint32_t size = width * height;
- // Don't even try to cache a bitmap that's bigger than the cache
- if (size < mMaxSize) {
- while (mSize + size > mMaxSize) {
- mCache.removeOldest();
- }
- }
-
- PathTexture* texture = new PathTexture;
- texture->left = left;
- texture->top = top;
- texture->offset = offset;
- texture->width = width;
- texture->height = height;
- texture->generation = path->getGenerationID();
+ purgeCache(width, height);
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kA8_Config, width, height);
- bitmap.allocPixels();
- bitmap.eraseColor(0);
+ initBitmap(bitmap, width, height);
SkPaint pathPaint(*paint);
-
- // Make sure the paint is opaque, color, alpha, filter, etc.
- // will be applied later when compositing the alpha8 texture
- pathPaint.setColor(0xff000000);
- pathPaint.setAlpha(255);
- pathPaint.setColorFilter(NULL);
- pathPaint.setMaskFilter(NULL);
- pathPaint.setShader(NULL);
- SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode);
- SkSafeUnref(pathPaint.setXfermode(mode));
+ initPaint(pathPaint);
SkCanvas canvas(bitmap);
canvas.translate(-left + offset, -top + offset);
canvas.drawPath(*path, pathPaint);
- generateTexture(bitmap, texture);
+ PathTexture* texture = createTexture(left, top, offset, width, height, path->getGenerationID());
+ addTexture(entry, &bitmap, texture);
+ return texture;
+}
+
+template<class Entry>
+void ShapeCache<Entry>::addTexture(const Entry& entry, SkBitmap* bitmap, PathTexture* texture) {
+ generateTexture(*bitmap, texture);
+
+ uint32_t size = texture->width * texture->height;
if (size < mMaxSize) {
mSize += size;
SHAPE_LOGD("ShapeCache::get: create %s: name, size, mSize = %d, %d, %d",
@@ -556,8 +604,6 @@
} else {
texture->cleanup = true;
}
-
- return texture;
}
template<class Entry>