18ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com/*
28ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com * Copyright 2012 The Android Open Source Project
38ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com *
48ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com * Use of this source code is governed by a BSD-style license that can be
58ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com * found in the LICENSE file.
68ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com */
78ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
88ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#define LOG_TAG "PathRenderer"
98ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#define LOG_NDEBUG 1
108ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#define ATRACE_TAG ATRACE_TAG_GRAPHICS
118ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
128ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#define VERTEX_DEBUG 0
138ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
148ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#include <SkPath.h>
1574dda9018e8bdd650698e763404f19144c6d0a42jvanverth@google.com#include <SkStrokeRec.h>
168ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
178ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#include <stdlib.h>
188ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#include <stdint.h>
198ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#include <sys/types.h>
208ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
2124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com#include <SkTypes.h>
22933e65d914eb86b1fbbf8ea9cf1da58ac7c42500commit-bot@chromium.org#include <SkTraceEvent.h>
2324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com#include <SkMatrix.h>
2424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com#include <SkPoint.h>
2524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com
2624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com#ifdef VERBOSE
2724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com#define ALOGV SkDebugf
2824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com#else
2924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com#define ALOGV(x, ...)
3024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com#endif
318ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
3224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com#include "AndroidPathRenderer.h"
338ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#include "Vertex.h"
348ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
358ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.comnamespace android {
368ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.comnamespace uirenderer {
378ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
388ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#define THRESHOLD 0.5f
398ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
4024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.comSkRect PathRenderer::ComputePathBounds(const SkPath& path, const SkPaint* paint) {
418ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    SkRect bounds = path.getBounds();
428ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    if (paint->getStyle() != SkPaint::kFill_Style) {
438ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float outset = paint->getStrokeWidth() * 0.5f;
448ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        bounds.outset(outset, outset);
458ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
468ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    return bounds;
478ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
488ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
4905af1afd429808913683da75644e48bece12e820humper@google.cominline void computeInverseScales(const SkMatrix* transform, float &inverseScaleX, float& inverseScaleY) {
5077734b890de4299861d29b7d3b509b4f3e199b58jvanverth@google.com    if (transform && transform->getType() & (SkMatrix::kScale_Mask|SkMatrix::kAffine_Mask|SkMatrix::kPerspective_Mask)) {
5124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        float m00 = transform->getScaleX();
5224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        float m01 = transform->getSkewY();
5324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        float m10 = transform->getSkewX();
5424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        float m11 = transform->getScaleY();
55140d7286c5a40058932696eaa28818c313bd2ddfreed@google.com        float scaleX = sk_float_sqrt(m00 * m00 + m01 * m01);
56140d7286c5a40058932696eaa28818c313bd2ddfreed@google.com        float scaleY = sk_float_sqrt(m10 * m10 + m11 * m11);
578ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 1.0f;
588ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 1.0f;
598ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    } else {
608ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        inverseScaleX = 1.0f;
618ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        inverseScaleY = 1.0f;
628ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
638ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
648ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
658ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.cominline void copyVertex(Vertex* destPtr, const Vertex* srcPtr) {
668ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    Vertex::set(destPtr, srcPtr->position[0], srcPtr->position[1]);
678ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
688ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
698ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.cominline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) {
708ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    AlphaVertex::set(destPtr, srcPtr->position[0], srcPtr->position[1], srcPtr->alpha);
718ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
728ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
738ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com/**
748ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com * Produces a pseudo-normal for a vertex, given the normals of the two incoming lines. If the offset
758ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com * from each vertex in a perimeter is calculated, the resultant lines connecting the offset vertices
768ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com * will be offset by 1.0
778ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com *
788ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com * Note that we can't add and normalize the two vectors, that would result in a rectangle having an
798ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com * offset of (sqrt(2)/2, sqrt(2)/2) at each corner, instead of (1, 1)
808ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com *
818ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com * NOTE: assumes angles between normals 90 degrees or less
828ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com */
8324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.cominline SkVector totalOffsetFromNormals(const SkVector& normalA, const SkVector& normalB) {
8424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    SkVector pseudoNormal = normalA + normalB;
85140d7286c5a40058932696eaa28818c313bd2ddfreed@google.com    pseudoNormal.scale(1.0f / (1.0f + sk_float_abs(normalA.dot(normalB))));
8624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    return pseudoNormal;
878ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
888ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
8924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.cominline void scaleOffsetForStrokeWidth(SkVector& offset, float halfStrokeWidth,
908ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float inverseScaleX, float inverseScaleY) {
918ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    if (halfStrokeWidth == 0.0f) {
928ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        // hairline - compensate for scale
9324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        offset.fX *= 0.5f * inverseScaleX;
9424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        offset.fY *= 0.5f * inverseScaleY;
958ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    } else {
9624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        offset.scale(halfStrokeWidth);
978ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
988ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
998ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
10005af1afd429808913683da75644e48bece12e820humper@google.comstatic void getFillVerticesFromPerimeter(const SkTArray<Vertex, true>& perimeter, VertexBuffer* vertexBuffer) {
10124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    Vertex* buffer = vertexBuffer->alloc<Vertex>(perimeter.count());
1028ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
1038ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    int currentIndex = 0;
1048ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // zig zag between all previous points on the inside of the hull to create a
1058ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // triangle strip that fills the hull
1068ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    int srcAindex = 0;
10724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    int srcBindex = perimeter.count() - 1;
1088ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    while (srcAindex <= srcBindex) {
1098ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        copyVertex(&buffer[currentIndex++], &perimeter[srcAindex]);
1108ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        if (srcAindex == srcBindex) break;
1118ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        copyVertex(&buffer[currentIndex++], &perimeter[srcBindex]);
1128ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        srcAindex++;
1138ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        srcBindex--;
1148ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
1158ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
1168ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
11705af1afd429808913683da75644e48bece12e820humper@google.comstatic void getStrokeVerticesFromPerimeter(const SkTArray<Vertex, true>& perimeter, float halfStrokeWidth,
11824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        VertexBuffer* vertexBuffer, float inverseScaleX, float inverseScaleY) {
11924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    Vertex* buffer = vertexBuffer->alloc<Vertex>(perimeter.count() * 2 + 2);
1208ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
1218ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    int currentIndex = 0;
12224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    const Vertex* last = &(perimeter[perimeter.count() - 1]);
1238ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    const Vertex* current = &(perimeter[0]);
12424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    SkVector lastNormal;
12524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    lastNormal.set(current->position[1] - last->position[1],
12624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                   last->position[0] - current->position[0]);
1278ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    lastNormal.normalize();
12824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    for (int i = 0; i < perimeter.count(); i++) {
12924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        const Vertex* next = &(perimeter[i + 1 >= perimeter.count() ? 0 : i + 1]);
13024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector nextNormal;
13124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        nextNormal.set(next->position[1] - current->position[1],
13224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                       current->position[0] - next->position[0]);
1338ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        nextNormal.normalize();
1348ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
13524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
1368ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
1378ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
1388ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        Vertex::set(&buffer[currentIndex++],
13924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] + totalOffset.fX,
14024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] + totalOffset.fY);
1418ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
1428ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        Vertex::set(&buffer[currentIndex++],
14324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] - totalOffset.fX,
14424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] - totalOffset.fY);
1458ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
1468ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        last = current;
1478ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        current = next;
1488ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        lastNormal = nextNormal;
1498ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
1508ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
1518ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // wrap around to beginning
1528ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    copyVertex(&buffer[currentIndex++], &buffer[0]);
1538ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    copyVertex(&buffer[currentIndex++], &buffer[1]);
1548ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
1558ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
15605af1afd429808913683da75644e48bece12e820humper@google.comstatic void getStrokeVerticesFromUnclosedVertices(const SkTArray<Vertex, true>& vertices, float halfStrokeWidth,
15724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        VertexBuffer* vertexBuffer, float inverseScaleX, float inverseScaleY) {
15824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    Vertex* buffer = vertexBuffer->alloc<Vertex>(vertices.count() * 2);
1598ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
1608ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    int currentIndex = 0;
1618ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    const Vertex* current = &(vertices[0]);
16224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    SkVector lastNormal;
16324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    for (int i = 0; i < vertices.count() - 1; i++) {
1648ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        const Vertex* next = &(vertices[i + 1]);
16524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector nextNormal;
16624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        nextNormal.set(next->position[1] - current->position[1],
16724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                       current->position[0] - next->position[0]);
1688ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        nextNormal.normalize();
1698ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
17024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector totalOffset;
1718ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        if (i == 0) {
1728ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com            totalOffset = nextNormal;
1738ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        } else {
1748ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com            totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
1758ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        }
1768ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
1778ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
1788ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        Vertex::set(&buffer[currentIndex++],
17924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] + totalOffset.fX,
18024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] + totalOffset.fY);
1818ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
1828ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        Vertex::set(&buffer[currentIndex++],
18324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] - totalOffset.fX,
18424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] - totalOffset.fY);
1858ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
1868ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        current = next;
1878ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        lastNormal = nextNormal;
1888ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
1898ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
19024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    SkVector totalOffset = lastNormal;
1918ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
1928ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
1938ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    Vertex::set(&buffer[currentIndex++],
19424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com            current->position[0] + totalOffset.fX,
19524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com            current->position[1] + totalOffset.fY);
1968ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    Vertex::set(&buffer[currentIndex++],
19724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com            current->position[0] - totalOffset.fX,
19824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com            current->position[1] - totalOffset.fY);
1998ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#if VERTEX_DEBUG
2008ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
20124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkDebugf("point at %f %f", buffer[i].position[0], buffer[i].position[1]);
2028ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
2038ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#endif
2048ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
2058ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
20605af1afd429808913683da75644e48bece12e820humper@google.comstatic void getFillVerticesFromPerimeterAA(const SkTArray<Vertex, true>& perimeter, VertexBuffer* vertexBuffer,
2078ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com         float inverseScaleX, float inverseScaleY) {
20824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    AlphaVertex* buffer = vertexBuffer->alloc<AlphaVertex>(perimeter.count() * 3 + 2);
2098ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
2108ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // generate alpha points - fill Alpha vertex gaps in between each point with
2118ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // alpha 0 vertex, offset by a scaled normal.
2128ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    int currentIndex = 0;
21324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    const Vertex* last = &(perimeter[perimeter.count() - 1]);
2148ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    const Vertex* current = &(perimeter[0]);
21524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    SkVector lastNormal;
21624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    lastNormal.set(current->position[1] - last->position[1],
21724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                   last->position[0] - current->position[0]);
2188ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    lastNormal.normalize();
21924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    for (int i = 0; i < perimeter.count(); i++) {
22024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        const Vertex* next = &(perimeter[i + 1 >= perimeter.count() ? 0 : i + 1]);
22124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector nextNormal;
22224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        nextNormal.set(next->position[1] - current->position[1],
22324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                       current->position[0] - next->position[0]);
2248ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        nextNormal.normalize();
2258ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
2268ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        // AA point offset from original point is that point's normal, such that each side is offset
2278ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        // by .5 pixels
22824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
22924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        totalOffset.fX *= 0.5f * inverseScaleX;
23024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        totalOffset.fY *= 0.5f * inverseScaleY;
2318ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
2328ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[currentIndex++],
23324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] + totalOffset.fX,
23424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] + totalOffset.fY,
2358ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                0.0f);
2368ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[currentIndex++],
23724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] - totalOffset.fX,
23824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] - totalOffset.fY,
2398ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                1.0f);
2408ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
2418ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        last = current;
2428ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        current = next;
2438ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        lastNormal = nextNormal;
2448ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
2458ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
2468ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // wrap around to beginning
2478ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    copyAlphaVertex(&buffer[currentIndex++], &buffer[0]);
2488ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    copyAlphaVertex(&buffer[currentIndex++], &buffer[1]);
2498ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
2508ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // zig zag between all previous points on the inside of the hull to create a
2518ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // triangle strip that fills the hull, repeating the first inner point to
2528ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // create degenerate tris to start inside path
2538ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    int srcAindex = 0;
25424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    int srcBindex = perimeter.count() - 1;
2558ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    while (srcAindex <= srcBindex) {
2568ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        copyAlphaVertex(&buffer[currentIndex++], &buffer[srcAindex * 2 + 1]);
2578ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        if (srcAindex == srcBindex) break;
2588ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        copyAlphaVertex(&buffer[currentIndex++], &buffer[srcBindex * 2 + 1]);
2598ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        srcAindex++;
2608ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        srcBindex--;
2618ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
2628ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
2638ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#if VERTEX_DEBUG
2648ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
26524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkDebugf("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha);
2668ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
2678ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#endif
2688ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
2698ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
2708ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
27105af1afd429808913683da75644e48bece12e820humper@google.comstatic void getStrokeVerticesFromUnclosedVerticesAA(const SkTArray<Vertex, true>& vertices, float halfStrokeWidth,
27224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        VertexBuffer* vertexBuffer, float inverseScaleX, float inverseScaleY) {
27324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    AlphaVertex* buffer = vertexBuffer->alloc<AlphaVertex>(6 * vertices.count() + 2);
2748ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
2758ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // avoid lines smaller than hairline since they break triangle based sampling. instead reducing
2768ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // alpha value (TODO: support different X/Y scale)
2778ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    float maxAlpha = 1.0f;
2788ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
2798ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com            halfStrokeWidth * inverseScaleX < 0.5f) {
2808ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
2818ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        halfStrokeWidth = 0.0f;
2828ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
2838ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
2848ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // there is no outer/inner here, using them for consistency with below approach
28524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    int offset = 2 * (vertices.count() - 2);
2868ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    int currentAAOuterIndex = 2;
2878ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    int currentAAInnerIndex = 2 * offset + 5; // reversed
2888ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    int currentStrokeIndex = currentAAInnerIndex + 7;
2898ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
2908ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    const Vertex* last = &(vertices[0]);
2918ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    const Vertex* current = &(vertices[1]);
29224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    SkVector lastNormal;
29324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    lastNormal.set(current->position[1] - last->position[1],
29424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                   last->position[0] - current->position[0]);
2958ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    lastNormal.normalize();
2968ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
2978ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    {
2988ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        // start cap
29924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector totalOffset = lastNormal;
30024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector AAOffset = totalOffset;
30124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        AAOffset.fX *= 0.5f * inverseScaleX;
30224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        AAOffset.fY *= 0.5f * inverseScaleY;
3038ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
30424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector innerOffset = totalOffset;
3058ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
30624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector outerOffset = innerOffset + AAOffset;
3078ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        innerOffset -= AAOffset;
3088ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
3098ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        // TODO: support square cap by changing this offset to incorporate halfStrokeWidth
31024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector capAAOffset;
31124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        capAAOffset.set(AAOffset.fY, -AAOffset.fX);
3128ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[0],
31324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                last->position[0] + outerOffset.fX + capAAOffset.fX,
31424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                last->position[1] + outerOffset.fY + capAAOffset.fY,
3158ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                0.0f);
3168ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[1],
31724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                last->position[0] + innerOffset.fX - capAAOffset.fX,
31824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                last->position[1] + innerOffset.fY - capAAOffset.fY,
3198ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                maxAlpha);
3208ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
3218ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[2 * offset + 6],
32224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                last->position[0] - outerOffset.fX + capAAOffset.fX,
32324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                last->position[1] - outerOffset.fY + capAAOffset.fY,
3248ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                0.0f);
3258ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[2 * offset + 7],
32624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                last->position[0] - innerOffset.fX - capAAOffset.fX,
32724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                last->position[1] - innerOffset.fY - capAAOffset.fY,
3288ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                maxAlpha);
3298ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        copyAlphaVertex(&buffer[2 * offset + 8], &buffer[0]);
3308ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        copyAlphaVertex(&buffer[2 * offset + 9], &buffer[1]);
3318ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        copyAlphaVertex(&buffer[2 * offset + 10], &buffer[1]); // degenerate tris (the only two!)
3328ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        copyAlphaVertex(&buffer[2 * offset + 11], &buffer[2 * offset + 7]);
3338ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
3348ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
33524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    for (int i = 1; i < vertices.count() - 1; i++) {
3368ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        const Vertex* next = &(vertices[i + 1]);
33724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector nextNormal;
33824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        nextNormal.set(next->position[1] - current->position[1],
33924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                       current->position[0] - next->position[0]);
3408ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        nextNormal.normalize();
3418ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
34224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
34324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector AAOffset = totalOffset;
34424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        AAOffset.fX *= 0.5f * inverseScaleX;
34524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        AAOffset.fY *= 0.5f * inverseScaleY;
3468ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
34724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector innerOffset = totalOffset;
3488ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
34924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector outerOffset = innerOffset + AAOffset;
3508ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        innerOffset -= AAOffset;
3518ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
3528ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[currentAAOuterIndex++],
35324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] + outerOffset.fX,
35424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] + outerOffset.fY,
3558ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                0.0f);
3568ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[currentAAOuterIndex++],
35724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] + innerOffset.fX,
35824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] + innerOffset.fY,
3598ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                maxAlpha);
3608ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
3618ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[currentStrokeIndex++],
36224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] + innerOffset.fX,
36324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] + innerOffset.fY,
3648ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                maxAlpha);
3658ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[currentStrokeIndex++],
36624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] - innerOffset.fX,
36724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] - innerOffset.fY,
3688ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                maxAlpha);
3698ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
3708ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[currentAAInnerIndex--],
37124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] - innerOffset.fX,
37224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] - innerOffset.fY,
3738ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                maxAlpha);
3748ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[currentAAInnerIndex--],
37524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] - outerOffset.fX,
37624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] - outerOffset.fY,
3778ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                0.0f);
3788ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
3798ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        last = current;
3808ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        current = next;
3818ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        lastNormal = nextNormal;
3828ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
3838ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
3848ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    {
3858ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        // end cap
38624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector totalOffset = lastNormal;
38724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector AAOffset = totalOffset;
38824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        AAOffset.fX *= 0.5f * inverseScaleX;
38924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        AAOffset.fY *= 0.5f * inverseScaleY;
3908ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
39124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector innerOffset = totalOffset;
3928ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
39324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector outerOffset = innerOffset + AAOffset;
3948ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        innerOffset -= AAOffset;
3958ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
3968ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        // TODO: support square cap by changing this offset to incorporate halfStrokeWidth
39724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector capAAOffset;
39824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        capAAOffset.set(-AAOffset.fY, AAOffset.fX);
3998ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
4008ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[offset + 2],
40124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] + outerOffset.fX + capAAOffset.fX,
40224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] + outerOffset.fY + capAAOffset.fY,
4038ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                0.0f);
4048ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[offset + 3],
40524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] + innerOffset.fX - capAAOffset.fX,
40624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] + innerOffset.fY - capAAOffset.fY,
4078ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                maxAlpha);
4088ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
4098ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[offset + 4],
41024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] - outerOffset.fX + capAAOffset.fX,
41124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] - outerOffset.fY + capAAOffset.fY,
4128ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                0.0f);
4138ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[offset + 5],
41424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] - innerOffset.fX - capAAOffset.fX,
41524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] - innerOffset.fY - capAAOffset.fY,
4168ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                maxAlpha);
4178ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
41824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        copyAlphaVertex(&buffer[vertexBuffer->getSize() - 2], &buffer[offset + 3]);
41924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        copyAlphaVertex(&buffer[vertexBuffer->getSize() - 1], &buffer[offset + 5]);
4208ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
4218ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
4228ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#if VERTEX_DEBUG
4238ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
42424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkDebugf("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha);
4258ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
4268ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#endif
4278ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
4288ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
4298ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
43005af1afd429808913683da75644e48bece12e820humper@google.comstatic void getStrokeVerticesFromPerimeterAA(const SkTArray<Vertex, true>& perimeter, float halfStrokeWidth,
43124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        VertexBuffer* vertexBuffer, float inverseScaleX, float inverseScaleY) {
43224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    AlphaVertex* buffer = vertexBuffer->alloc<AlphaVertex>(6 * perimeter.count() + 8);
4338ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
4348ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // avoid lines smaller than hairline since they break triangle based sampling. instead reducing
4358ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // alpha value (TODO: support different X/Y scale)
4368ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    float maxAlpha = 1.0f;
4378ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
4388ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com            halfStrokeWidth * inverseScaleX < 0.5f) {
4398ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
4408ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        halfStrokeWidth = 0.0f;
4418ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
4428ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
44324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    int offset = 2 * perimeter.count() + 3;
4448ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    int currentAAOuterIndex = 0;
4458ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    int currentStrokeIndex = offset;
4468ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    int currentAAInnerIndex = offset * 2;
4478ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
44824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    const Vertex* last = &(perimeter[perimeter.count() - 1]);
4498ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    const Vertex* current = &(perimeter[0]);
45024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    SkVector lastNormal;
45124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    lastNormal.set(current->position[1] - last->position[1],
45224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                   last->position[0] - current->position[0]);
4538ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    lastNormal.normalize();
45424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    for (int i = 0; i < perimeter.count(); i++) {
45524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        const Vertex* next = &(perimeter[i + 1 >= perimeter.count() ? 0 : i + 1]);
45624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector nextNormal;
45724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        nextNormal.set(next->position[1] - current->position[1],
45824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                       current->position[0] - next->position[0]);
4598ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        nextNormal.normalize();
4608ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
46124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
46224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector AAOffset = totalOffset;
46324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        AAOffset.fX *= 0.5f * inverseScaleX;
46424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        AAOffset.fY *= 0.5f * inverseScaleY;
4658ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
46624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector innerOffset = totalOffset;
4678ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
46824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkVector outerOffset = innerOffset + AAOffset;
4698ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        innerOffset -= AAOffset;
4708ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
4718ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[currentAAOuterIndex++],
47224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] + outerOffset.fX,
47324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] + outerOffset.fY,
4748ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                0.0f);
4758ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[currentAAOuterIndex++],
47624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] + innerOffset.fX,
47724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] + innerOffset.fY,
4788ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                maxAlpha);
4798ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
4808ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[currentStrokeIndex++],
48124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] + innerOffset.fX,
48224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] + innerOffset.fY,
4838ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                maxAlpha);
4848ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[currentStrokeIndex++],
48524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] - innerOffset.fX,
48624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] - innerOffset.fY,
4878ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                maxAlpha);
4888ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
4898ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[currentAAInnerIndex++],
49024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] - innerOffset.fX,
49124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] - innerOffset.fY,
4928ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                maxAlpha);
4938ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        AlphaVertex::set(&buffer[currentAAInnerIndex++],
49424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[0] - outerOffset.fX,
49524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                current->position[1] - outerOffset.fY,
4968ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                0.0f);
4978ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
4988ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        last = current;
4998ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        current = next;
5008ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        lastNormal = nextNormal;
5018ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
5028ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
5038ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // wrap each strip around to beginning, creating degenerate tris to bridge strips
5048ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    copyAlphaVertex(&buffer[currentAAOuterIndex++], &buffer[0]);
5058ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    copyAlphaVertex(&buffer[currentAAOuterIndex++], &buffer[1]);
5068ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    copyAlphaVertex(&buffer[currentAAOuterIndex++], &buffer[1]);
5078ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
5088ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    copyAlphaVertex(&buffer[currentStrokeIndex++], &buffer[offset]);
5098ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    copyAlphaVertex(&buffer[currentStrokeIndex++], &buffer[offset + 1]);
5108ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    copyAlphaVertex(&buffer[currentStrokeIndex++], &buffer[offset + 1]);
5118ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
5128ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    copyAlphaVertex(&buffer[currentAAInnerIndex++], &buffer[2 * offset]);
5138ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    copyAlphaVertex(&buffer[currentAAInnerIndex++], &buffer[2 * offset + 1]);
5148ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // don't need to create last degenerate tri
5158ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
5168ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#if VERTEX_DEBUG
5178ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
51824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkDebugf("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha);
5198ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
5208ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#endif
5218ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
5228ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
52374dda9018e8bdd650698e763404f19144c6d0a42jvanverth@google.comvoid PathRenderer::ConvexPathVertices(const SkPath &path, const SkStrokeRec& stroke, bool isAA,
52424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        const SkMatrix* transform, VertexBuffer* vertexBuffer) {
5258ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
52674dda9018e8bdd650698e763404f19144c6d0a42jvanverth@google.com    SkStrokeRec::Style style = stroke.getStyle();
5278ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
5288ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    float inverseScaleX, inverseScaleY;
5298ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    computeInverseScales(transform, inverseScaleX, inverseScaleY);
5308ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
53124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    SkTArray<Vertex, true> tempVertices;
5328ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    float threshInvScaleX = inverseScaleX;
5338ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    float threshInvScaleY = inverseScaleY;
53474dda9018e8bdd650698e763404f19144c6d0a42jvanverth@google.com    if (style == SkStrokeRec::kStroke_Style) {
5358ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        // alter the bezier recursion threshold values we calculate in order to compensate for
5368ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        // expansion done after the path vertices are found
5378ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        SkRect bounds = path.getBounds();
5388ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        if (!bounds.isEmpty()) {
53974dda9018e8bdd650698e763404f19144c6d0a42jvanverth@google.com            threshInvScaleX *= bounds.width() / (bounds.width() + stroke.getWidth());
54074dda9018e8bdd650698e763404f19144c6d0a42jvanverth@google.com            threshInvScaleY *= bounds.height() / (bounds.height() + stroke.getWidth());
5418ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        }
5428ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
5438ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
5448ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // force close if we're filling the path, since fill path expects closed perimeter.
54574dda9018e8bdd650698e763404f19144c6d0a42jvanverth@google.com    bool forceClose = style != SkStrokeRec::kStroke_Style;
54624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    bool wasClosed = ConvexPathPerimeterVertices(path, forceClose, threshInvScaleX * threshInvScaleX,
54724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com            threshInvScaleY * threshInvScaleY, &tempVertices);
5488ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
54924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    if (!tempVertices.count()) {
5508ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        // path was empty, return without allocating vertex buffer
5518ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        return;
5528ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
5538ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
5548ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#if VERTEX_DEBUG
55524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    for (unsigned int i = 0; i < tempVertices.count(); i++) {
55624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        SkDebugf("orig path: point at %f %f", tempVertices[i].position[0], tempVertices[i].position[1]);
5578ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
5588ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com#endif
5598ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
56074dda9018e8bdd650698e763404f19144c6d0a42jvanverth@google.com    if (style == SkStrokeRec::kStroke_Style) {
56174dda9018e8bdd650698e763404f19144c6d0a42jvanverth@google.com        float halfStrokeWidth = stroke.getWidth() * 0.5f;
5628ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        if (!isAA) {
5638ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com            if (wasClosed) {
5648ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                getStrokeVerticesFromPerimeter(tempVertices, halfStrokeWidth, vertexBuffer,
5658ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                        inverseScaleX, inverseScaleY);
5668ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com            } else {
5678ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                getStrokeVerticesFromUnclosedVertices(tempVertices, halfStrokeWidth, vertexBuffer,
5688ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                        inverseScaleX, inverseScaleY);
5698ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com            }
5708ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
5718ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        } else {
5728ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com            if (wasClosed) {
5738ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                getStrokeVerticesFromPerimeterAA(tempVertices, halfStrokeWidth, vertexBuffer,
5748ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                        inverseScaleX, inverseScaleY);
5758ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com            } else {
5768ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                getStrokeVerticesFromUnclosedVerticesAA(tempVertices, halfStrokeWidth, vertexBuffer,
5778ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                        inverseScaleX, inverseScaleY);
5788ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com            }
5798ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        }
5808ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    } else {
5818ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        // For kStrokeAndFill style, the path should be adjusted externally, as it will be treated as a fill here.
5828ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        if (!isAA) {
5838ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com            getFillVerticesFromPerimeter(tempVertices, vertexBuffer);
5848ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        } else {
5858ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com            getFillVerticesFromPerimeterAA(tempVertices, vertexBuffer, inverseScaleX, inverseScaleY);
5868ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        }
5878ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
5888ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
5898ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
5908ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
59105af1afd429808913683da75644e48bece12e820humper@google.comstatic void pushToVector(SkTArray<Vertex, true>* vertices, float x, float y) {
5928ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // TODO: make this not yuck
59324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    vertices->push_back();
59424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    Vertex* newVertex = &((*vertices)[vertices->count() - 1]);
5958ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    Vertex::set(newVertex, x, y);
5968ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
5978ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
59824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.combool PathRenderer::ConvexPathPerimeterVertices(const SkPath& path, bool forceClose,
59924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        float sqrInvScaleX, float sqrInvScaleY, SkTArray<Vertex, true>* outputVertices) {
60024b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com
6018ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
6028ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // TODO: to support joins other than sharp miter, join vertices should be labelled in the
6038ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // perimeter, or resolved into more vertices. Reconsider forceClose-ing in that case.
6048ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    SkPath::Iter iter(path, forceClose);
6058ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    SkPoint pts[4];
6068ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    SkPath::Verb v;
60705af1afd429808913683da75644e48bece12e820humper@google.com
6088ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    while (SkPath::kDone_Verb != (v = iter.next(pts))) {
6098ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com            switch (v) {
6108ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                case SkPath::kMove_Verb:
6118ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                    pushToVector(outputVertices, pts[0].x(), pts[0].y());
6128ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                    ALOGV("Move to pos %f %f", pts[0].x(), pts[0].y());
6138ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                    break;
6148ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                case SkPath::kClose_Verb:
6158ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                    ALOGV("Close at pos %f %f", pts[0].x(), pts[0].y());
6168ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                    break;
6178ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                case SkPath::kLine_Verb:
6188ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                    ALOGV("kLine_Verb %f %f -> %f %f",
6198ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                            pts[0].x(), pts[0].y(),
6208ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                            pts[1].x(), pts[1].y());
6218ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
6228ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                    pushToVector(outputVertices, pts[1].x(), pts[1].y());
6238ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                    break;
6248ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                case SkPath::kQuad_Verb:
6258ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                    ALOGV("kQuad_Verb");
62624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                    RecursiveQuadraticBezierVertices(
6278ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                            pts[0].x(), pts[0].y(),
6288ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                            pts[2].x(), pts[2].y(),
6298ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                            pts[1].x(), pts[1].y(),
6308ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                            sqrInvScaleX, sqrInvScaleY, outputVertices);
6318ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                    break;
6328ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                case SkPath::kCubic_Verb:
6338ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                    ALOGV("kCubic_Verb");
63424b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com                    RecursiveCubicBezierVertices(
6358ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                            pts[0].x(), pts[0].y(),
6368ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                            pts[1].x(), pts[1].y(),
6378ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                            pts[3].x(), pts[3].y(),
6388ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                            pts[2].x(), pts[2].y(),
6398ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                        sqrInvScaleX, sqrInvScaleY, outputVertices);
6408ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                    break;
6418ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                default:
6428ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                    break;
6438ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com            }
6448ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
6458ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
64624b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    int size = outputVertices->count();
64724b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com    if (size >= 2 && (*outputVertices)[0].position[0] == (*outputVertices)[size - 1].position[0] &&
64824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com            (*outputVertices)[0].position[1] == (*outputVertices)[size - 1].position[1]) {
64924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        outputVertices->pop_back();
6508ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        return true;
6518ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
6528ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    return false;
6538ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
6548ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
65524b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.comvoid PathRenderer::RecursiveCubicBezierVertices(
6568ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float p1x, float p1y, float c1x, float c1y,
6578ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float p2x, float p2y, float c2x, float c2y,
65824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        float sqrInvScaleX, float sqrInvScaleY, SkTArray<Vertex, true>* outputVertices) {
6598ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    float dx = p2x - p1x;
6608ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    float dy = p2y - p1y;
661140d7286c5a40058932696eaa28818c313bd2ddfreed@google.com    float d1 = sk_float_abs((c1x - p2x) * dy - (c1y - p2y) * dx);
662140d7286c5a40058932696eaa28818c313bd2ddfreed@google.com    float d2 = sk_float_abs((c2x - p2x) * dy - (c2y - p2y) * dx);
6638ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    float d = d1 + d2;
6648ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
6658ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
6668ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
6678ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
6688ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        // below thresh, draw line by adding endpoint
6698ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        pushToVector(outputVertices, p2x, p2y);
6708ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    } else {
6718ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float p1c1x = (p1x + c1x) * 0.5f;
6728ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float p1c1y = (p1y + c1y) * 0.5f;
6738ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float p2c2x = (p2x + c2x) * 0.5f;
6748ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float p2c2y = (p2y + c2y) * 0.5f;
6758ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
6768ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float c1c2x = (c1x + c2x) * 0.5f;
6778ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float c1c2y = (c1y + c2y) * 0.5f;
6788ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
6798ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float p1c1c2x = (p1c1x + c1c2x) * 0.5f;
6808ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float p1c1c2y = (p1c1y + c1c2y) * 0.5f;
6818ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
6828ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float p2c1c2x = (p2c2x + c1c2x) * 0.5f;
6838ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float p2c1c2y = (p2c2y + c1c2y) * 0.5f;
6848ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
6858ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float mx = (p1c1c2x + p2c1c2x) * 0.5f;
6868ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float my = (p1c1c2y + p2c1c2y) * 0.5f;
6878ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
68824b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        RecursiveCubicBezierVertices(
6898ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                p1x, p1y, p1c1x, p1c1y,
6908ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                mx, my, p1c1c2x, p1c1c2y,
6918ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                sqrInvScaleX, sqrInvScaleY, outputVertices);
69224b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        RecursiveCubicBezierVertices(
6938ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                mx, my, p2c1c2x, p2c1c2y,
6948ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                p2x, p2y, p2c2x, p2c2y,
6958ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                sqrInvScaleX, sqrInvScaleY, outputVertices);
6968ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
6978ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
6988ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
69924b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.comvoid PathRenderer::RecursiveQuadraticBezierVertices(
7008ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float ax, float ay,
7018ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float bx, float by,
7028ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float cx, float cy,
70324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        float sqrInvScaleX, float sqrInvScaleY, SkTArray<Vertex, true>* outputVertices) {
7048ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    float dx = bx - ax;
7058ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    float dy = by - ay;
7068ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    float d = (cx - bx) * dy - (cy - by) * dx;
7078ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
7088ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
7098ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        // below thresh, draw line by adding endpoint
7108ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        pushToVector(outputVertices, bx, by);
7118ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    } else {
7128ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float acx = (ax + cx) * 0.5f;
7138ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float bcx = (bx + cx) * 0.5f;
7148ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float acy = (ay + cy) * 0.5f;
7158ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float bcy = (by + cy) * 0.5f;
7168ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
7178ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        // midpoint
7188ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float mx = (acx + bcx) * 0.5f;
7198ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com        float my = (acy + bcy) * 0.5f;
7208ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
72124b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        RecursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy,
7228ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                sqrInvScaleX, sqrInvScaleY, outputVertices);
72324b4f97d00988efefb856abdbd4357cafdc36c86jvanverth@google.com        RecursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy,
7248ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com                sqrInvScaleX, sqrInvScaleY, outputVertices);
7258ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com    }
7268ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}
7278ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com
7288ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}; // namespace uirenderer
7298ffb7046cb789ade4dde1ad588fb8ae995fd3f9ajvanverth@google.com}; // namespace android
730