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

Commit fe02b4b3 authored by Chris Craik's avatar Chris Craik
Browse files

Add abort logging for huge scales and tessellation recursion depth

bug:15615144
Change-Id: I275732eb97f9d5179beed23eecd2ee3cc7112e10
parent 6b2df21e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -404,6 +404,9 @@ class GLES20Canvas extends HardwareCanvas {

    @Override
    public void scale(float sx, float sy) {
        // TODO: remove
        if (sx > 1000000 || sy > 1000000) throw new IllegalArgumentException("invalid scales passed " + sx + ", " + sy);

        nScale(mRenderer, sx, sy);
    }

+27 −11
Original line number Diff line number Diff line
@@ -57,17 +57,26 @@ namespace uirenderer {
#define ROUND_CAP_THRESH 0.25f
#define PI 3.1415926535897932f

// temporary error thresholds
#define ERROR_DEPTH 20
#define ERROR_SCALE 1e10
#define ERROR_SQR_INV_THRESH 1e-20

void PathTessellator::extractTessellationScales(const Matrix4& transform,
        float* scaleX, float* scaleY) {
    if (CC_LIKELY(transform.isPureTranslate())) {
        *scaleX = 1.0f;
        *scaleY = 1.0f;
    if (CC_UNLIKELY(!transform.isPureTranslate())) {
    } else {
        float m00 = transform.data[Matrix4::kScaleX];
        float m01 = transform.data[Matrix4::kSkewY];
        float m10 = transform.data[Matrix4::kSkewX];
        float m11 = transform.data[Matrix4::kScaleY];
        *scaleX = sqrt(m00 * m00 + m01 * m01);
        *scaleY = sqrt(m10 * m10 + m11 * m11);

        LOG_ALWAYS_FATAL_IF(*scaleX > ERROR_SCALE || *scaleY > ERROR_SCALE,
                "scales %e x %e too large for tessellation", *scaleX, *scaleY);
    }
}

@@ -92,10 +101,12 @@ struct PaintInfo {
public:
    PaintInfo(const SkPaint* paint, const mat4& transform) :
            style(paint->getStyle()), cap(paint->getStrokeCap()), isAA(paint->isAntiAlias()),
            inverseScaleX(1.0f), inverseScaleY(1.0f),
            halfStrokeWidth(paint->getStrokeWidth() * 0.5f), maxAlpha(1.0f) {
        // compute inverse scales
        if (CC_UNLIKELY(!transform.isPureTranslate())) {
        if (CC_LIKELY(transform.isPureTranslate())) {
            inverseScaleX = 1.0f;
            inverseScaleY = 1.0f;
        } else {
            float scaleX, scaleY;
            PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY);
            inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 1.0f;
@@ -922,6 +933,9 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
        Vector<Vertex>& outputVertices) {
    ATRACE_CALL();

    LOG_ALWAYS_FATAL_IF(sqrInvScaleX < ERROR_SQR_INV_THRESH || sqrInvScaleY < ERROR_SQR_INV_THRESH,
            "Invalid scale factors used for approx %e, %e", sqrInvScaleX, sqrInvScaleY);

    // TODO: to support joins other than sharp miter, join vertices should be labelled in the
    // perimeter, or resolved into more vertices. Reconsider forceClose-ing in that case.
    SkPath::Iter iter(path, forceClose);
@@ -975,14 +989,14 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
// Bezier approximation
///////////////////////////////////////////////////////////////////////////////

// Depth at which recursion is aborted
#define ABORT_DEPTH 20

void PathTessellator::recursiveCubicBezierVertices(
        float p1x, float p1y, float c1x, float c1y,
        float p2x, float p2y, float c2x, float c2y,
        float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
        Vector<Vertex>& outputVertices, int depth) {
    LOG_ALWAYS_FATAL_IF(depth >= ERROR_DEPTH, "ERROR DEPTH exceeded: cubic approx, invscale %e x %e, vertcount %d",
            sqrInvScaleX, sqrInvScaleY, outputVertices.size());

    float dx = p2x - p1x;
    float dy = p2y - p1y;
    float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx);
@@ -990,8 +1004,7 @@ void PathTessellator::recursiveCubicBezierVertices(
    float d = d1 + d2;

    // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors

    if (depth >= ABORT_DEPTH || d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
    if (d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
        // below thresh, draw line by adding endpoint
        pushToVector(outputVertices, p2x, p2y);
    } else {
@@ -1029,11 +1042,14 @@ void PathTessellator::recursiveQuadraticBezierVertices(
        float cx, float cy,
        float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
        Vector<Vertex>& outputVertices, int depth) {
    LOG_ALWAYS_FATAL_IF(depth >= ERROR_DEPTH, "ERROR_DEPTH exceeded: quadratic approx, invscale %e x %e, vertcount %d",
            sqrInvScaleX, sqrInvScaleY, outputVertices.size());

    float dx = bx - ax;
    float dy = by - ay;
    float d = (cx - bx) * dy - (cy - by) * dx;

    if (depth >= ABORT_DEPTH || d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
    if (d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
        // below thresh, draw line by adding endpoint
        pushToVector(outputVertices, bx, by);
    } else {
+3 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <vector>
#include <cutils/compiler.h>
#include <androidfw/ResourceTypes.h>
#include <utils/Log.h>

#include <SkCamera.h>
#include <SkMatrix.h>
@@ -281,6 +282,7 @@ public:
    }

    bool setScaleX(float scaleX) {
        LOG_ALWAYS_FATAL_IF(scaleX > 1000000, "invalid scaleX %e", scaleX);
        return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX);
    }

@@ -289,6 +291,7 @@ public:
    }

    bool setScaleY(float scaleY) {
        LOG_ALWAYS_FATAL_IF(scaleY > 1000000, "invalid scaleY %e", scaleY);
        return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY);
    }