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

Commit bb4cb488 authored by Mike Reed's avatar Mike Reed
Browse files

Simplify paint filtering

Removes complication of copy-on-write intermediate class, and
allows for shaing a single applyLooper() function.

Test: make

Bug: 178700363
Change-Id: Ia74cb8e7c650e469b8429de1d7cf9204821d8f11
parent 7aa01124
Loading
Loading
Loading
Loading
+25 −37
Original line number Diff line number Diff line
@@ -188,7 +188,7 @@ void SkiaCanvas::restoreUnclippedLayer(int restoreCount, const SkPaint& paint) {
    }

    if (mCanvas->getSaveCount() == restoreCount + 1) {
        SkCanvasPriv::DrawBehind(mCanvas, *filterPaint(paint));
        SkCanvasPriv::DrawBehind(mCanvas, filterPaint(paint));
        this->restore();
    }
}
@@ -431,15 +431,14 @@ void SkiaCanvas::drawColor(int color, SkBlendMode mode) {
    mCanvas->drawColor(color, mode);
}

SkiaCanvas::PaintCoW&& SkiaCanvas::filterPaint(PaintCoW&& paint) const {
void SkiaCanvas::onFilterPaint(SkPaint& paint) {
    if (mPaintFilter) {
        mPaintFilter->filter(&paint.writeable());
        mPaintFilter->filter(&paint);
    }
    return std::move(paint);
}

void SkiaCanvas::drawPaint(const SkPaint& paint) {
    mCanvas->drawPaint(*filterPaint(paint));
    mCanvas->drawPaint(filterPaint(paint));
}

// ----------------------------------------------------------------------------
@@ -457,13 +456,11 @@ void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint,
        points += 2;
    }

    apply_looper(&paint, [&](const SkPaint& p) {
        mCanvas->drawPoints(mode, count, pts.get(), p);
    });
    applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPoints(mode, count, pts.get(), p); });
}

void SkiaCanvas::drawPoint(float x, float y, const Paint& paint) {
    apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawPoint(x, y, p); });
    applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPoint(x, y, p); });
}

void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint) {
@@ -472,9 +469,8 @@ void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint)

void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
                          const Paint& paint) {
    apply_looper(&paint, [&](const SkPaint& p) {
        mCanvas->drawLine(startX, startY, stopX, stopY, p);
    });
    applyLooper(&paint,
                [&](const SkPaint& p) { mCanvas->drawLine(startX, startY, stopX, stopY, p); });
}

void SkiaCanvas::drawLines(const float* points, int count, const Paint& paint) {
@@ -484,46 +480,44 @@ void SkiaCanvas::drawLines(const float* points, int count, const Paint& paint) {

void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const Paint& paint) {
    if (CC_UNLIKELY(paint.nothingToDraw())) return;
    apply_looper(&paint, [&](const SkPaint& p) {
    applyLooper(&paint, [&](const SkPaint& p) {
        mCanvas->drawRect({left, top, right, bottom}, p);
    });
}

void SkiaCanvas::drawRegion(const SkRegion& region, const Paint& paint) {
    if (CC_UNLIKELY(paint.nothingToDraw())) return;
    apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawRegion(region, p); });
    applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawRegion(region, p); });
}

void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
                               const Paint& paint) {
    if (CC_UNLIKELY(paint.nothingToDraw())) return;
    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
    apply_looper(&paint, [&](const SkPaint& p) {
        mCanvas->drawRoundRect(rect, rx, ry, p);
    });
    applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawRoundRect(rect, rx, ry, p); });
}

void SkiaCanvas::drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
                                const Paint& paint) {
    apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawDRRect(outer, inner, p); });
    applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawDRRect(outer, inner, p); });
}

void SkiaCanvas::drawCircle(float x, float y, float radius, const Paint& paint) {
    if (CC_UNLIKELY(radius <= 0 || paint.nothingToDraw())) return;
    apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawCircle(x, y, radius, p); });
    applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawCircle(x, y, radius, p); });
}

void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const Paint& paint) {
    if (CC_UNLIKELY(paint.nothingToDraw())) return;
    SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
    apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawOval(oval, p); });
    applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawOval(oval, p); });
}

void SkiaCanvas::drawArc(float left, float top, float right, float bottom, float startAngle,
                         float sweepAngle, bool useCenter, const Paint& paint) {
    if (CC_UNLIKELY(paint.nothingToDraw())) return;
    SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
    apply_looper(&paint, [&](const SkPaint& p) {
    applyLooper(&paint, [&](const SkPaint& p) {
        if (fabs(sweepAngle) >= 360.0f) {
            mCanvas->drawOval(arc, p);
        } else {
@@ -537,13 +531,11 @@ void SkiaCanvas::drawPath(const SkPath& path, const Paint& paint) {
    if (CC_UNLIKELY(path.isEmpty() && (!path.isInverseFillType()))) {
        return;
    }
    apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawPath(path, p); });
    applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPath(path, p); });
}

void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const Paint& paint) {
    apply_looper(&paint, [&](const SkPaint& p) {
        mCanvas->drawVertices(vertices, mode, p);
    });
    applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawVertices(vertices, mode, p); });
}

// ----------------------------------------------------------------------------
@@ -552,7 +544,7 @@ void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, cons

void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
    auto image = bitmap.makeImage();
    apply_looper(paint, [&](const SkPaint& p) {
    applyLooper(paint, [&](const SkPaint& p) {
        auto sampling = SkSamplingOptions(p.getFilterQuality());
        mCanvas->drawImage(image, left, top, sampling, &p);
    });
@@ -562,7 +554,7 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint*
    auto image = bitmap.makeImage();
    SkAutoCanvasRestore acr(mCanvas, true);
    mCanvas->concat(matrix);
    apply_looper(paint, [&](const SkPaint& p) {
    applyLooper(paint, [&](const SkPaint& p) {
        auto sampling = SkSamplingOptions(p.getFilterQuality());
        mCanvas->drawImage(image, 0, 0, sampling, &p);
    });
@@ -575,7 +567,7 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float s
    SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
    SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);

    apply_looper(paint, [&](const SkPaint& p) {
    applyLooper(paint, [&](const SkPaint& p) {
        auto sampling = SkSamplingOptions(p.getFilterQuality());
        mCanvas->drawImageRect(image, srcRect, dstRect, sampling, &p,
                               SkCanvas::kFast_SrcRectConstraint);
@@ -672,11 +664,11 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
    pnt.setShader(image->makeShader(sampling));

    auto v = builder.detach();
    apply_looper(&pnt, [&](const SkPaint& p) {
    applyLooper(&pnt, [&](const SkPaint& p) {
        SkPaint copy(p);
        auto s = SkSamplingOptions(p.getFilterQuality());
        if (s != sampling) {
            // apply_looper changed the quality?
            // applyLooper changed the quality?
            copy.setShader(image->makeShader(s));
        }
        mCanvas->drawVertices(v, SkBlendMode::kModulate, copy);
@@ -707,7 +699,7 @@ void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, floa
    lattice.fBounds = nullptr;
    SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
    auto image = bitmap.makeImage();
    apply_looper(paint, [&](const SkPaint& p) {
    applyLooper(paint, [&](const SkPaint& p) {
        auto filter = SkSamplingOptions(p.getFilterQuality()).filter;
        mCanvas->drawImageLattice(image.get(), lattice, dst, filter, &p);
    });
@@ -746,9 +738,7 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& pai

    sk_sp<SkTextBlob> textBlob(builder.make());

    apply_looper(&paintCopy, [&](const SkPaint& p) {
        mCanvas->drawTextBlob(textBlob, 0, 0, p);
    });
    applyLooper(&paintCopy, [&](const SkPaint& p) { mCanvas->drawTextBlob(textBlob, 0, 0, p); });
    drawTextDecorations(x, y, totalAdvance, paintCopy);
}

@@ -788,9 +778,7 @@ void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset,

    sk_sp<SkTextBlob> textBlob(builder.make());

    apply_looper(&paintCopy, [&](const SkPaint& p) {
        mCanvas->drawTextBlob(textBlob, 0, 0, p);
    });
    applyLooper(&paintCopy, [&](const SkPaint& p) { mCanvas->drawTextBlob(textBlob, 0, 0, p); });
}

// ----------------------------------------------------------------------------
+14 −44
Original line number Diff line number Diff line
@@ -169,53 +169,24 @@ protected:
                                  const Paint& paint, const SkPath& path, size_t start,
                                  size_t end) override;

    /** This class acts as a copy on write SkPaint.
     *
     *  Initially this will be the SkPaint passed to the contructor.
     *  The first time writable() is called this will become a copy of the
     *  initial SkPaint (or a default SkPaint if nullptr).
     */
    struct PaintCoW {
        PaintCoW(const SkPaint& that) : mPtr(&that) {}
        PaintCoW(const SkPaint* ptr) : mPtr(ptr) {}
        PaintCoW(const PaintCoW&) = delete;
        PaintCoW(PaintCoW&&) = delete;
        PaintCoW& operator=(const PaintCoW&) = delete;
        PaintCoW& operator=(PaintCoW&&) = delete;
        SkPaint& writeable() {
            if (!mStorage) {
                if (!mPtr) {
                    mStorage.emplace();
                } else {
                    mStorage.emplace(*mPtr);
                }
                mPtr = &*mStorage;
            }
            return *mStorage;
        }
        operator const SkPaint*() const { return mPtr; }
        const SkPaint* operator->() const { assert(mPtr); return mPtr; }
        explicit operator bool() { return mPtr != nullptr; }
    private:
        const SkPaint* mPtr;
        std::optional<SkPaint> mStorage;
    };
    void onFilterPaint(SkPaint& paint);

    /** Filters the paint using the current paint filter.
     *
     *  @param paint the paint to filter. Will be initialized with the default
     *      SkPaint before filtering if filtering is required.
     */
    PaintCoW&& filterPaint(PaintCoW&& paint) const;
    SkPaint filterPaint(const SkPaint& src) {
        SkPaint dst(src);
        this->onFilterPaint(dst);
        return dst;
    }

    // proc(const SkPaint& modifiedPaint)
    template <typename Proc> void apply_looper(const Paint* paint, Proc proc) {
        SkPaint skp;
        BlurDrawLooper* looper = nullptr;
        if (paint) {
            skp = *filterPaint(paint);
            looper = paint->getLooper();
    template <typename Proc>
    void applyLooper(const Paint* paint, Proc proc, void (*preFilter)(SkPaint&) = nullptr) {
        BlurDrawLooper* looper = paint ? paint->getLooper() : nullptr;
        const SkPaint* skpPtr = paint;
        SkPaint skp = skpPtr ? *skpPtr : SkPaint();
        if (preFilter) {
            preFilter(skp);
        }
        this->onFilterPaint(skp);
        if (looper) {
            looper->apply(skp, [&](SkPoint offset, const SkPaint& modifiedPaint) {
                mCanvas->save();
@@ -228,7 +199,6 @@ protected:
        }
    }


private:
    struct SaveRec {
        int saveCount;
+36 −38
Original line number Diff line number Diff line
@@ -170,36 +170,23 @@ void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
// Recording Canvas draw operations: Bitmaps
// ----------------------------------------------------------------------------

SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint) {
    bool fixBlending = false;
    bool fixAA = false;
    if (paint) {
void SkiaRecordingCanvas::FilterForImage(SkPaint& paint) {
    // kClear blend mode is drawn as kDstOut on HW for compatibility with Android O and
    // older.
        fixBlending = sApiLevel <= 27 && paint->getBlendMode() == SkBlendMode::kClear;
        fixAA = paint->isAntiAlias();
    }

    if (fixBlending || fixAA) {
        SkPaint& tmpPaint = paint.writeable();

        if (fixBlending) {
            tmpPaint.setBlendMode(SkBlendMode::kDstOut);
    if (sApiLevel <= 27 && paint.getBlendMode() == SkBlendMode::kClear) {
        paint.setBlendMode(SkBlendMode::kDstOut);
    }

    // disabling AA on bitmap draws matches legacy HWUI behavior
        tmpPaint.setAntiAlias(false);
    }

    return filterPaint(std::move(paint));
    paint.setAntiAlias(false);
}

static SkFilterMode Paint_to_filter(const SkPaint* paint) {
    return paint && paint->getFilterQuality() != kNone_SkFilterQuality ? SkFilterMode::kLinear
static SkFilterMode Paint_to_filter(const SkPaint& paint) {
    return paint.getFilterQuality() != kNone_SkFilterQuality ? SkFilterMode::kLinear
                                                             : SkFilterMode::kNearest;
}

static SkSamplingOptions Paint_to_sampling(const SkPaint* paint) {
static SkSamplingOptions Paint_to_sampling(const SkPaint& paint) {
    // Android only has 1-bit for "filter", so we don't try to cons-up mipmaps or cubics
    return SkSamplingOptions(Paint_to_filter(paint), SkMipmapMode::kNone);
}
@@ -207,9 +194,12 @@ static SkSamplingOptions Paint_to_sampling(const SkPaint* paint) {
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
    sk_sp<SkImage> image = bitmap.makeImage();

    applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
        mRecorder.drawImage(image, left + x, top + y, Paint_to_sampling(p), p, bitmap.palette());
    });
    applyLooper(
            paint,
            [&](const SkPaint& p) {
                mRecorder.drawImage(image, left, top, Paint_to_sampling(p), &p, bitmap.palette());
            },
            FilterForImage);

    // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
    // it is not safe to store a raw SkImage pointer, because the image object will be destroyed
@@ -225,9 +215,12 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, con

    sk_sp<SkImage> image = bitmap.makeImage();

    applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
        mRecorder.drawImage(image, x, y, Paint_to_sampling(p), p, bitmap.palette());
    });
    applyLooper(
            paint,
            [&](const SkPaint& p) {
                mRecorder.drawImage(image, 0, 0, Paint_to_sampling(p), &p, bitmap.palette());
            },
            FilterForImage);

    if (!bitmap.isImmutable() && image.get() && !image->unique()) {
        mDisplayList->mMutableImages.push_back(image.get());
@@ -242,10 +235,13 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop

    sk_sp<SkImage> image = bitmap.makeImage();

    applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
        mRecorder.drawImageRect(image, srcRect, dstRect.makeOffset(x, y), Paint_to_sampling(p),
                                p, SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
    });
    applyLooper(
            paint,
            [&](const SkPaint& p) {
                mRecorder.drawImageRect(image, srcRect, dstRect, Paint_to_sampling(p), &p,
                                        SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
            },
            FilterForImage);

    if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
        !dstRect.isEmpty()) {
@@ -281,10 +277,12 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch
    // HWUI always draws 9-patches with linear filtering, regardless of the Paint.
    const SkFilterMode filter = SkFilterMode::kLinear;

    applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
        mRecorder.drawImageLattice(image, lattice, dst.makeOffset(x, y), filter, p,
                                   bitmap.palette());
    });
    applyLooper(
            paint,
            [&](const SkPaint& p) {
                mRecorder.drawImageLattice(image, lattice, dst, filter, &p, bitmap.palette());
            },
            FilterForImage);

    if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
        mDisplayList->mMutableImages.push_back(image.get());
+2 −17
Original line number Diff line number Diff line
@@ -87,22 +87,7 @@ private:
    std::unique_ptr<SkiaDisplayList> mDisplayList;
    StartReorderBarrierDrawable* mCurrentBarrier;

    template <typename Proc>
    void applyLooper(const Paint* paint, Proc proc) {
        SkPaint skp;
        BlurDrawLooper* looper = nullptr;
        if (paint) {
            skp = *filterBitmap(paint);
            looper = paint->getLooper();
        }
        if (looper) {
            looper->apply(skp, [&](SkPoint offset, const SkPaint& modifiedPaint) {
                proc(offset.fX, offset.fY, &modifiedPaint);
            });
        } else {
            proc(0, 0, &skp);
        }
    }
    static void FilterForImage(SkPaint&);

    /**
     *  A new SkiaDisplayList is created or recycled if available.
@@ -113,7 +98,7 @@ private:
     */
    void initDisplayList(uirenderer::RenderNode* renderNode, int width, int height);

    PaintCoW&& filterBitmap(PaintCoW&& paint);
    using INHERITED = SkiaCanvas;
};

}  // namespace skiapipeline