Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dad10333 authored by Sergei Vasilinetc's avatar Sergei Vasilinetc Committed by Android (Google) Code Review
Browse files

Merge changes from topic 'path_snapping'

* changes:
  HWUI: Fix snapping in path rendering
  HWUI: Cleanup PathCache
parents b33468f3 89561e6e
Loading
Loading
Loading
Loading
+31 −53
Original line number Diff line number Diff line
@@ -121,29 +121,19 @@ bool PathDescription::operator==(const PathDescription& rhs) const {
// Utilities
///////////////////////////////////////////////////////////////////////////////

bool PathCache::canDrawAsConvexPath(SkPath* path, const SkPaint* paint) {
    // NOTE: This should only be used after PathTessellator handles joins properly
    return paint->getPathEffect() == nullptr && path->getConvexity() == SkPath::kConvex_Convexity;
}

void PathCache::computePathBounds(const SkPath* path, const SkPaint* paint,
        float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
static void computePathBounds(const SkPath* path, const SkPaint* paint, PathTexture* texture,
        uint32_t& width, uint32_t& height) {
    const SkRect& bounds = path->getBounds();
    PathCache::computeBounds(bounds, paint, left, top, offset, width, height);
}

void PathCache::computeBounds(const SkRect& bounds, const SkPaint* paint,
        float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
    const float pathWidth = std::max(bounds.width(), 1.0f);
    const float pathHeight = std::max(bounds.height(), 1.0f);

    left = bounds.fLeft;
    top = bounds.fTop;
    texture->left = floorf(bounds.fLeft);
    texture->top = floorf(bounds.fTop);

    offset = (int) floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
    texture->offset = (int) floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);

    width = uint32_t(pathWidth + offset * 2.0 + 0.5);
    height = uint32_t(pathHeight + offset * 2.0 + 0.5);
    width = uint32_t(pathWidth + texture->offset * 2.0 + 0.5);
    height = uint32_t(pathHeight + texture->offset * 2.0 + 0.5);
}

static void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) {
@@ -163,16 +153,26 @@ static void initPaint(SkPaint& paint) {
    SkSafeUnref(paint.setXfermode(mode));
}

static void drawPath(const SkPath *path, const SkPaint* paint, SkBitmap& bitmap,
        float left, float top, float offset, uint32_t width, uint32_t height) {
    initBitmap(bitmap, width, height);
static SkBitmap* drawPath(const SkPath* path, const SkPaint* paint, PathTexture* texture,
        uint32_t maxTextureSize) {
    uint32_t width, height;
    computePathBounds(path, paint, texture, width, height);
    if (width > maxTextureSize || height > maxTextureSize) {
        ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)",
                width, height, maxTextureSize, maxTextureSize);
        return nullptr;
    }

    SkBitmap* bitmap = new SkBitmap();
    initBitmap(*bitmap, width, height);

    SkPaint pathPaint(*paint);
    initPaint(pathPaint);

    SkCanvas canvas(bitmap);
    canvas.translate(-left + offset, -top + offset);
    SkCanvas canvas(*bitmap);
    canvas.translate(-texture->left + texture->offset, -texture->top + texture->offset);
    canvas.drawPath(*path, pathPaint);
    return bitmap;
}

///////////////////////////////////////////////////////////////////////////////
@@ -271,21 +271,15 @@ PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *p
        const SkPaint* paint) {
    ATRACE_NAME("Generate Path Texture");

    float left, top, offset;
    uint32_t width, height;
    computePathBounds(path, paint, left, top, offset, width, height);

    if (!checkTextureSize(width, height)) return nullptr;

    purgeCache(width, height);

    SkBitmap bitmap;
    drawPath(path, paint, bitmap, left, top, offset, width, height);

    PathTexture* texture = new PathTexture(Caches::getInstance(),
            left, top, offset, path->getGenerationID());
    generateTexture(entry, &bitmap, texture);
    PathTexture* texture = new PathTexture(Caches::getInstance(), path->getGenerationID());
    std::unique_ptr<SkBitmap> bitmap(drawPath(path, paint, texture, mMaxTextureSize));
    if (!bitmap.get()) {
        delete texture;
        return nullptr;
    }

    purgeCache(bitmap->width(), bitmap->height());
    generateTexture(entry, bitmap.get(), texture);
    return texture;
}

@@ -330,22 +324,7 @@ void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
    PathTask* t = static_cast<PathTask*>(task.get());
    ATRACE_NAME("pathPrecache");

    float left, top, offset;
    uint32_t width, height;
    PathCache::computePathBounds(&t->path, &t->paint, left, top, offset, width, height);

    PathTexture* texture = t->texture;
    texture->left = left;
    texture->top = top;
    texture->offset = offset;

    if (width <= mMaxTextureSize && height <= mMaxTextureSize) {
        SkBitmap* bitmap = new SkBitmap();
        drawPath(&t->path, &t->paint, *bitmap, left, top, offset, width, height);
        t->setResult(bitmap);
    } else {
        t->setResult(nullptr);
    }
    t->setResult(drawPath(&t->path, &t->paint, t->texture, mMaxTextureSize));
}

///////////////////////////////////////////////////////////////////////////////
@@ -399,7 +378,6 @@ PathTexture* PathCache::get(const SkPath* path, const SkPaint* paint) {
                generateTexture(entry, bitmap, texture, false);
                texture->clearTask();
            } else {
                ALOGW("Path too large to be rendered into a texture");
                texture->clearTask();
                texture = nullptr;
                mCache.remove(entry);
+0 −23
Original line number Diff line number Diff line
@@ -61,14 +61,6 @@ class Caches;
 * Alpha texture used to represent a path.
 */
struct PathTexture: public Texture {
    PathTexture(Caches& caches, float left, float top,
            float offset, int generation)
            : Texture(caches)
            , left(left)
            , top(top)
            , offset(offset) {
        this->generation = generation;
    }
    PathTexture(Caches& caches, int generation)
        : Texture(caches) {
        this->generation = generation;
@@ -227,12 +219,6 @@ public:
     */
    void precache(const SkPath* path, const SkPaint* paint);

    static bool canDrawAsConvexPath(SkPath* path, const SkPaint* paint);
    static void computePathBounds(const SkPath* path, const SkPaint* paint,
            float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
    static void computeBounds(const SkRect& bounds, const SkPaint* paint,
            float& left, float& top, float& offset, uint32_t& width, uint32_t& height);

private:
    PathTexture* addTexture(const PathDescription& entry,
            const SkPath *path, const SkPaint* paint);
@@ -257,15 +243,6 @@ private:

    void removeTexture(PathTexture* texture);

    bool checkTextureSize(uint32_t width, uint32_t height) {
        if (width > mMaxTextureSize || height > mMaxTextureSize) {
            ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)",
                    width, height, mMaxTextureSize, mMaxTextureSize);
            return false;
        }
        return true;
    }

    void init();

    class PathTask: public Task<SkBitmap*> {
+15 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@

#include <SkBlurDrawLooper.h>
#include <SkDashPathEffect.h>
#include <SkPath.h>

using namespace android::uirenderer;

@@ -273,3 +274,17 @@ RENDERTHREAD_TEST(BakedOpDispatcher, layerUpdateProperties) {
        }
    }
}

RENDERTHREAD_TEST(BakedOpDispatcher, pathTextureSnapping) {
    Rect bounds(10, 15, 20, 25);
    SkPaint paint;
    SkPath path;
    path.addRect(SkRect::MakeXYWH(1.5, 3.8, 100, 90));
    PathOp op(bounds, Matrix4::identity(), nullptr, &paint, &path);
    testUnmergedGlopDispatch(renderThread, &op, [] (const Glop& glop) {
        auto texture = glop.fill.texture.texture;
        ASSERT_NE(nullptr, texture);
        EXPECT_EQ(1, reinterpret_cast<PathTexture*>(texture)->left);
        EXPECT_EQ(3, reinterpret_cast<PathTexture*>(texture)->top);
    });
}
 No newline at end of file