diff options
author | Romain Guy <romainguy@google.com> | 2012-04-27 11:47:13 -0700 |
---|---|---|
committer | Romain Guy <romainguy@google.com> | 2012-04-27 11:47:13 -0700 |
commit | fdd6fc1beb5076a630c7066b8b1731995636c09f (patch) | |
tree | 8df0ddc48fda9ffb9015e3fb190e68ca806646d4 /libs/hwui | |
parent | a44a63ac5c29b2cc57df95ec495def8cdddd9c6f (diff) | |
download | frameworks_base-fdd6fc1beb5076a630c7066b8b1731995636c09f.zip frameworks_base-fdd6fc1beb5076a630c7066b8b1731995636c09f.tar.gz frameworks_base-fdd6fc1beb5076a630c7066b8b1731995636c09f.tar.bz2 |
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
Diffstat (limited to 'libs/hwui')
-rw-r--r-- | libs/hwui/PathCache.cpp | 7 | ||||
-rw-r--r-- | libs/hwui/ShapeCache.cpp | 25 | ||||
-rw-r--r-- | libs/hwui/ShapeCache.h | 114 |
3 files changed, 108 insertions, 38 deletions
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index e363b73..71a4ed7 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -25,10 +25,15 @@ namespace android { namespace uirenderer { // Defined in ShapeCache.h -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) { const SkRect& bounds = path->getBounds(); + computeBounds(bounds, paint, left, top, offset, width, height); +} +void computeBounds(const SkRect& bounds, const SkPaint* paint, + float& left, float& top, float& offset, uint32_t& width, uint32_t& height) { const float pathWidth = fmax(bounds.width(), 1.0f); const float pathHeight = fmax(bounds.height(), 1.0f); diff --git a/libs/hwui/ShapeCache.cpp b/libs/hwui/ShapeCache.cpp index 0d7cd9c..5a23235 100644 --- a/libs/hwui/ShapeCache.cpp +++ b/libs/hwui/ShapeCache.cpp @@ -105,10 +105,29 @@ PathTexture* RectShapeCache::getRect(float width, float height, SkPaint* paint) PathTexture* texture = get(entry); if (!texture) { - SkPath path; - path.addRect(0.0f, 0.0f, width, height, SkPath::kCW_Direction); + SkRect bounds; + bounds.set(0.0f, 0.0f, width, height); - texture = addTexture(entry, &path, paint); + float left, top, offset; + uint32_t rectWidth, rectHeight; + computeBounds(bounds, paint, left, top, offset, rectWidth, rectHeight); + + if (!checkTextureSize(rectWidth, rectHeight)) return NULL; + + purgeCache(rectWidth, rectHeight); + + SkBitmap bitmap; + initBitmap(bitmap, rectWidth, rectHeight); + + SkPaint pathPaint(*paint); + initPaint(pathPaint); + + SkCanvas canvas(bitmap); + canvas.translate(-left + offset, -top + offset); + canvas.drawRect(bounds, pathPaint); + + texture = createTexture(0, 0, offset, rectWidth, rectHeight, 0); + addTexture(entry, &bitmap, texture); } return texture; 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 @@ public: 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,23 +502,25 @@ void ShapeCache<Entry>::removeTexture(PathTexture* texture) { } } -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); -template<class Entry> -PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *path, - const SkPaint* paint) { - - float left, top, offset; - 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; - } +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) { @@ -513,38 +528,71 @@ PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *pat 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(); - - SkBitmap bitmap; +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); +} - SkPaint pathPaint(*paint); - +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 - pathPaint.setColor(0xff000000); - pathPaint.setAlpha(255); - pathPaint.setColorFilter(NULL); - pathPaint.setMaskFilter(NULL); - pathPaint.setShader(NULL); + paint.setColor(0xff000000); + paint.setAlpha(255); + paint.setColorFilter(NULL); + paint.setMaskFilter(NULL); + paint.setShader(NULL); SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode); - SkSafeUnref(pathPaint.setXfermode(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, + const SkPaint* paint) { + + float left, top, offset; + uint32_t width, height; + computePathBounds(path, paint, left, top, offset, width, height); + + if (!checkTextureSize(width, height)) return NULL; + + purgeCache(width, height); + + SkBitmap bitmap; + initBitmap(bitmap, width, height); + + SkPaint pathPaint(*paint); + 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 @@ PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *pat } else { texture->cleanup = true; } - - return texture; } template<class Entry> |