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

Commit 16b897c4 authored by Chris Craik's avatar Chris Craik
Browse files

Fix rectangle AA offset calculation

bug:4419017

Fixes compiler warning
Handle bezier thresholds with large stroke widths better
Fix sub-hairlines (for scaleX == scaleY)

Change-Id: Ida387483348ee61424b7fba729abca2a88bd68b3
parent 9a4a0376
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -294,7 +294,7 @@ private:
    GLuint mCurrentBuffer;
    GLuint mCurrentBuffer;
    GLuint mCurrentIndicesBuffer;
    GLuint mCurrentIndicesBuffer;
    void* mCurrentPositionPointer;
    void* mCurrentPositionPointer;
    GLuint mCurrentPositionStride;
    GLsizei mCurrentPositionStride;
    void* mCurrentTexCoordsPointer;
    void* mCurrentTexCoordsPointer;


    bool mTexCoordsArrayEnabled;
    bool mTexCoordsArrayEnabled;
+53 −28
Original line number Original line Diff line number Diff line
@@ -57,24 +57,34 @@ void computeInverseScales(const mat4 *transform, float &inverseScaleX, float& in
        float m11 = transform->data[Matrix4::kScaleY];
        float m11 = transform->data[Matrix4::kScaleY];
        float scaleX = sqrt(m00 * m00 + m01 * m01);
        float scaleX = sqrt(m00 * m00 + m01 * m01);
        float scaleY = sqrt(m10 * m10 + m11 * m11);
        float scaleY = sqrt(m10 * m10 + m11 * m11);
        inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 0;
        inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 1.0f;
        inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 0;
        inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 1.0f;
    } else {
    } else {
        inverseScaleX = 1.0f;
        inverseScaleX = 1.0f;
        inverseScaleY = 1.0f;
        inverseScaleY = 1.0f;
    }
    }
}
}


inline void copyVertex(Vertex* destPtr, const Vertex* srcPtr)
inline void copyVertex(Vertex* destPtr, const Vertex* srcPtr) {
{
    Vertex::set(destPtr, srcPtr->position[0], srcPtr->position[1]);
    Vertex::set(destPtr, srcPtr->position[0], srcPtr->position[1]);
}
}


inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr)
inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) {
{
    AlphaVertex::set(destPtr, srcPtr->position[0], srcPtr->position[1], srcPtr->alpha);
    AlphaVertex::set(destPtr, srcPtr->position[0], srcPtr->position[1], srcPtr->alpha);
}
}


/**
 * Produces a pseudo-normal for a vertex, given the normals of the two incoming lines. If the offset
 * from each vertex in a perimeter is calculated, the resultant lines connecting the offset vertices
 * will be offset by 1.0
 *
 * Note that we can't add and normalize the two vectors, that would result in a rectangle having an
 * offset of (sqrt(2)/2, sqrt(2)/2) at each corner, instead of (1, 1)
 */
inline vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) {
    return (normalA + normalB) / (1 + fabs(normalA.dot(normalB)));
}

void getFillVerticesFromPerimeter(const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) {
void getFillVerticesFromPerimeter(const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) {
    Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size());
    Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size());


@@ -108,9 +118,7 @@ void getStrokeVerticesFromPerimeter(const Vector<Vertex>& perimeter, float halfS
                current->position[0] - next->position[0]);
                current->position[0] - next->position[0]);
        nextNormal.normalize();
        nextNormal.normalize();


        // offset each point by its normal, out and in, by appropriate stroke offset
        vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
        vec2 totalOffset = (lastNormal + nextNormal);
        totalOffset.normalize();
        if (halfStrokeWidth == 0.0f) {
        if (halfStrokeWidth == 0.0f) {
            // hairline - compensate for scale
            // hairline - compensate for scale
            totalOffset.x *= 0.5f * inverseScaleX;
            totalOffset.x *= 0.5f * inverseScaleX;
@@ -155,12 +163,11 @@ void getFillVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, VertexBuffe
                current->position[0] - next->position[0]);
                current->position[0] - next->position[0]);
        nextNormal.normalize();
        nextNormal.normalize();


        // AA point offset from original point is that point's normal, such that
        // AA point offset from original point is that point's normal, such that each side is offset
        // each side is offset by .5 pixels
        // by .5 pixels
        vec2 totalOffset = (lastNormal + nextNormal);
        vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
        totalOffset.normalize();
        totalOffset.x *= 0.5f * inverseScaleX;
        totalOffset.x *= inverseScaleX * 0.5f;
        totalOffset.y *= 0.5f * inverseScaleY;
        totalOffset.y *= inverseScaleY * 0.5f;


        AlphaVertex::set(&buffer[currentIndex++],
        AlphaVertex::set(&buffer[currentIndex++],
                current->position[0] + totalOffset.x,
                current->position[0] + totalOffset.x,
@@ -204,6 +211,15 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal
        VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) {
        VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) {
    AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * perimeter.size() + 8);
    AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * perimeter.size() + 8);


    // avoid lines smaller than hairline since they break triangle based sampling. instead reducing
    // alpha value (TODO: support different X/Y scale)
    float maxAlpha = 1.0f;
    if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
            halfStrokeWidth * inverseScaleX < 1.0f) {
        maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
        halfStrokeWidth = 0.0f;
    }

    int offset = 2 * perimeter.size() + 3;
    int offset = 2 * perimeter.size() + 3;
    int currentAAOuterIndex = 0;
    int currentAAOuterIndex = 0;
    int currentStrokeIndex = offset;
    int currentStrokeIndex = offset;
@@ -220,13 +236,12 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal
                current->position[0] - next->position[0]);
                current->position[0] - next->position[0]);
        nextNormal.normalize();
        nextNormal.normalize();


        vec2 pointNormal = (lastNormal + nextNormal);
        vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
        pointNormal.normalize();
        vec2 AAOffset = totalOffset;
        vec2 AAOffset = pointNormal * 0.5f;
        AAOffset.x *= 0.5f * inverseScaleX;
        AAOffset.x *= inverseScaleX;
        AAOffset.y *= 0.5f * inverseScaleY;
        AAOffset.y *= inverseScaleY;


        vec2 innerOffset = pointNormal;
        vec2 innerOffset = totalOffset;
        if (halfStrokeWidth == 0.0f) {
        if (halfStrokeWidth == 0.0f) {
            // hairline! - compensate for scale
            // hairline! - compensate for scale
            innerOffset.x *= 0.5f * inverseScaleX;
            innerOffset.x *= 0.5f * inverseScaleX;
@@ -244,27 +259,26 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal
        AlphaVertex::set(&buffer[currentAAOuterIndex++],
        AlphaVertex::set(&buffer[currentAAOuterIndex++],
                current->position[0] + innerOffset.x,
                current->position[0] + innerOffset.x,
                current->position[1] + innerOffset.y,
                current->position[1] + innerOffset.y,
                1.0f);
                maxAlpha);


        AlphaVertex::set(&buffer[currentStrokeIndex++],
        AlphaVertex::set(&buffer[currentStrokeIndex++],
                current->position[0] + innerOffset.x,
                current->position[0] + innerOffset.x,
                current->position[1] + innerOffset.y,
                current->position[1] + innerOffset.y,
                1.0f);
                maxAlpha);
        AlphaVertex::set(&buffer[currentStrokeIndex++],
        AlphaVertex::set(&buffer[currentStrokeIndex++],
                current->position[0] - innerOffset.x,
                current->position[0] - innerOffset.x,
                current->position[1] - innerOffset.y,
                current->position[1] - innerOffset.y,
                1.0f);
                maxAlpha);


        AlphaVertex::set(&buffer[currentAAInnerIndex++],
        AlphaVertex::set(&buffer[currentAAInnerIndex++],
                current->position[0] - innerOffset.x,
                current->position[0] - innerOffset.x,
                current->position[1] - innerOffset.y,
                current->position[1] - innerOffset.y,
                1.0f);
                maxAlpha);
        AlphaVertex::set(&buffer[currentAAInnerIndex++],
        AlphaVertex::set(&buffer[currentAAInnerIndex++],
                current->position[0] - outerOffset.x,
                current->position[0] - outerOffset.x,
                current->position[1] - outerOffset.y,
                current->position[1] - outerOffset.y,
                0.0f);
                0.0f);


        // TODO: current = next, copy last normal instead of recalculate
        last = current;
        last = current;
        current = next;
        current = next;
        lastNormal = nextNormal;
        lastNormal = nextNormal;
@@ -295,8 +309,19 @@ void PathRenderer::convexPathVertices(const SkPath &path, const SkPaint* paint,
    computeInverseScales(transform, inverseScaleX, inverseScaleY);
    computeInverseScales(transform, inverseScaleX, inverseScaleY);


    Vector<Vertex> tempVertices;
    Vector<Vertex> tempVertices;
    convexPathPerimeterVertices(path, inverseScaleX * inverseScaleX, inverseScaleY * inverseScaleY,
    float threshInvScaleX = inverseScaleX;
            tempVertices);
    float threshInvScaleY = inverseScaleY;
    if (style == SkPaint::kStroke_Style) {
        // alter the bezier recursion threshold values we calculate in order to compensate for
        // expansion done after the path vertices are found
        SkRect bounds = path.getBounds();
        if (!bounds.isEmpty()) {
            threshInvScaleX *= bounds.width() / (bounds.width() + paint->getStrokeWidth());
            threshInvScaleY *= bounds.height() / (bounds.height() + paint->getStrokeWidth());
        }
    }
    convexPathPerimeterVertices(path, threshInvScaleX * threshInvScaleX,
            threshInvScaleY * threshInvScaleY, tempVertices);


#if VERTEX_DEBUG
#if VERTEX_DEBUG
    for (unsigned int i = 0; i < tempVertices.size(); i++) {
    for (unsigned int i = 0; i < tempVertices.size(); i++) {