PathTessellator.cpp revision 74cf7e6a25c6d7b331c231b7bc2512044f9d2950
14eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato/*
24eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * Copyright (C) 2012 The Android Open Source Project
34eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato *
44eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * Licensed under the Apache License, Version 2.0 (the "License");
54eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * you may not use this file except in compliance with the License.
64eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * You may obtain a copy of the License at
74eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato *
84eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato *      http://www.apache.org/licenses/LICENSE-2.0
94eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato *
104eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * Unless required by applicable law or agreed to in writing, software
114eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * distributed under the License is distributed on an "AS IS" BASIS,
124eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * See the License for the specific language governing permissions and
144eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * limitations under the License.
154eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato */
164eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
174eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#define LOG_TAG "OpenGLRenderer"
184eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#define LOG_NDEBUG 1
194eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#define ATRACE_TAG ATRACE_TAG_VIEW
204eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
214eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#define VERTEX_DEBUG 0
224eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
234eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#if VERTEX_DEBUG
244eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#define DEBUG_DUMP_ALPHA_BUFFER() \
254eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { \
264eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        ALOGD("point %d at %f %f, alpha %f", \
274eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        i, buffer[i].x, buffer[i].y, buffer[i].alpha); \
284eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    }
294eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#define DEBUG_DUMP_BUFFER() \
304eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { \
314eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        ALOGD("point %d at %f %f", i, buffer[i].x, buffer[i].y); \
324eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    }
334eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#else
344eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#define DEBUG_DUMP_ALPHA_BUFFER()
354eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#define DEBUG_DUMP_BUFFER()
364eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#endif
374eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
384eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#include <SkPath.h>
394eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#include <SkPaint.h>
404eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
414eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#include <stdlib.h>
424eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#include <stdint.h>
434eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#include <sys/types.h>
444eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
454eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#include <utils/Log.h>
464eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#include <utils/Trace.h>
474eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
484eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#include "PathTessellator.h"
494eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#include "Matrix.h"
504eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#include "Vector.h"
514eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#include "Vertex.h"
524eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#include "utils/MathUtils.h"
534eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
544eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onoratonamespace android {
554eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onoratonamespace uirenderer {
564eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
574eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#define OUTLINE_REFINE_THRESHOLD_SQUARED (0.5f * 0.5f)
584eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#define ROUND_CAP_THRESH 0.25f
594eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#define PI 3.1415926535897932f
604eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato#define MAX_DEPTH 15
614eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
624eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato/**
634eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * Extracts the x and y scale from the transform as positive values, and clamps them
644eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato */
654eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onoratovoid PathTessellator::extractTessellationScales(const Matrix4& transform,
664eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        float* scaleX, float* scaleY) {
674eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    if (CC_LIKELY(transform.isPureTranslate())) {
684eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        *scaleX = 1.0f;
694eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        *scaleY = 1.0f;
704eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    } else {
714eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        float m00 = transform.data[Matrix4::kScaleX];
724eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        float m01 = transform.data[Matrix4::kSkewY];
734eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        float m10 = transform.data[Matrix4::kSkewX];
744eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        float m11 = transform.data[Matrix4::kScaleY];
754eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        *scaleX = MathUtils::clampTessellationScale(sqrt(m00 * m00 + m01 * m01));
764eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        *scaleY = MathUtils::clampTessellationScale(sqrt(m10 * m10 + m11 * m11));
774eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    }
784eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato}
794eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
804eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato/**
814eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * Produces a pseudo-normal for a vertex, given the normals of the two incoming lines. If the offset
824eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * from each vertex in a perimeter is calculated, the resultant lines connecting the offset vertices
834eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * will be offset by 1.0
844eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato *
854eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * Note that we can't add and normalize the two vectors, that would result in a rectangle having an
864eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * offset of (sqrt(2)/2, sqrt(2)/2) at each corner, instead of (1, 1)
874eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato *
884eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * NOTE: assumes angles between normals 90 degrees or less
894eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato */
904eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onoratoinline static Vector2 totalOffsetFromNormals(const Vector2& normalA, const Vector2& normalB) {
914eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    return (normalA + normalB) / (1 + fabs(normalA.dot(normalB)));
924eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato}
934eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
944eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato/**
954eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato * Structure used for storing useful information about the SkPaint and scale used for tessellating
964eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato */
974eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onoratostruct PaintInfo {
984eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onoratopublic:
994eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    PaintInfo(const SkPaint* paint, const mat4& transform) :
1004eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            style(paint->getStyle()), cap(paint->getStrokeCap()), isAA(paint->isAntiAlias()),
1014eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            halfStrokeWidth(paint->getStrokeWidth() * 0.5f), maxAlpha(1.0f) {
1024eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        // compute inverse scales
1034eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        if (CC_LIKELY(transform.isPureTranslate())) {
1044eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            inverseScaleX = 1.0f;
1054eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            inverseScaleY = 1.0f;
1064eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        } else {
1074eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            float scaleX, scaleY;
1084eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY);
1094eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            inverseScaleX = 1.0f / scaleX;
1104eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            inverseScaleY = 1.0f / scaleY;
1114eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        }
1124eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
1134eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        if (isAA && halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
1144eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato                2 * halfStrokeWidth < inverseScaleX) {
1154eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            // AA, with non-hairline stroke, width < 1 pixel. Scale alpha and treat as hairline.
1164eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
1174eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            halfStrokeWidth = 0.0f;
1184eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        }
1194eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    }
1204eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
1214eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    SkPaint::Style style;
1224eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    SkPaint::Cap cap;
1234eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    bool isAA;
1244eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    float inverseScaleX;
1254eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    float inverseScaleY;
1264eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    float halfStrokeWidth;
1274eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    float maxAlpha;
1284eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
1294eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    inline void scaleOffsetForStrokeWidth(Vector2& offset) const {
1304eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        if (halfStrokeWidth == 0.0f) {
1314eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            // hairline - compensate for scale
1324eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            offset.x *= 0.5f * inverseScaleX;
1334eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            offset.y *= 0.5f * inverseScaleY;
1344eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        } else {
1354eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            offset *= halfStrokeWidth;
1364eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        }
1374eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    }
1384eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
1394eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    /**
1404eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato     * NOTE: the input will not always be a normal, especially for sharp edges - it should be the
1414eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato     * result of totalOffsetFromNormals (see documentation there)
1424eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato     */
1434eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    inline Vector2 deriveAAOffset(const Vector2& offset) const {
1444eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        return (Vector2){offset.x * 0.5f * inverseScaleX, offset.y * 0.5f * inverseScaleY};
1454eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    }
1464eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
1474eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    /**
1484eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato     * Returns the number of cap divisions beyond the minimum 2 (kButt_Cap/kSquareCap will return 0)
1494eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato     * Should only be used when stroking and drawing caps
1504eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato     */
1514eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    inline int capExtraDivisions() const {
1524eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        if (cap == SkPaint::kRound_Cap) {
1534eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            if (halfStrokeWidth == 0.0f) return 2;
1544eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
1554eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            // ROUND_CAP_THRESH is the maximum error for polygonal approximation of the round cap
1564eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            const float errConst = (-ROUND_CAP_THRESH / halfStrokeWidth + 1);
1574eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            const float targetCosVal = 2 * errConst * errConst - 1;
1584eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            int neededDivisions = (int)(ceilf(PI / acos(targetCosVal)/2)) * 2;
1594eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato            return neededDivisions;
1604eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        }
1614eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        return 0;
1624eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    }
1634eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
1644eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    /**
1654eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato     * Outset the bounds of point data (for line endpoints or points) to account for AA stroke
1664eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato     * geometry.
1674eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato     */
1684eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    void expandBoundsForStroke(Rect* bounds) const {
1694eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        float outset = halfStrokeWidth;
1704eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        if (outset == 0) outset = 0.5f;
1714eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        bounds->outset(outset * inverseScaleX + Vertex::GeometryFudgeFactor(),
1724eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato                outset * inverseScaleY + Vertex::GeometryFudgeFactor());
1734eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    }
1744eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato};
1754eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
1764eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onoratovoid getFillVerticesFromPerimeter(const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) {
1774eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size());
1784eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato
1794eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    int currentIndex = 0;
1804eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    // zig zag between all previous points on the inside of the hull to create a
1814eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    // triangle strip that fills the hull
1824eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    int srcAindex = 0;
1834eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    int srcBindex = perimeter.size() - 1;
1844eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato    while (srcAindex <= srcBindex) {
1854eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        buffer[currentIndex++] = perimeter[srcAindex];
1864eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        if (srcAindex == srcBindex) break;
1874eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        buffer[currentIndex++] = perimeter[srcBindex];
1884eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        srcAindex++;
1894eb64fdbcf899a81d0a6a04dc3658d03d9df8247Joe Onorato        srcBindex--;
190    }
191}
192
193/*
194 * Fills a vertexBuffer with non-alpha vertices, zig-zagging at each perimeter point to create a
195 * tri-strip as wide as the stroke.
196 *
197 * Uses an additional 2 vertices at the end to wrap around, closing the tri-strip
198 * (for a total of perimeter.size() * 2 + 2 vertices)
199 */
200void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo, const Vector<Vertex>& perimeter,
201        VertexBuffer& vertexBuffer) {
202    Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size() * 2 + 2);
203
204    int currentIndex = 0;
205    const Vertex* last = &(perimeter[perimeter.size() - 1]);
206    const Vertex* current = &(perimeter[0]);
207    Vector2 lastNormal = {current->y - last->y, last->x - current->x};
208    lastNormal.normalize();
209    for (unsigned int i = 0; i < perimeter.size(); i++) {
210        const Vertex* next = &(perimeter[i + 1 >= perimeter.size() ? 0 : i + 1]);
211        Vector2 nextNormal = {next->y - current->y, current->x - next->x};
212        nextNormal.normalize();
213
214        Vector2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
215        paintInfo.scaleOffsetForStrokeWidth(totalOffset);
216
217        Vertex::set(&buffer[currentIndex++],
218                current->x + totalOffset.x,
219                current->y + totalOffset.y);
220
221        Vertex::set(&buffer[currentIndex++],
222                current->x - totalOffset.x,
223                current->y - totalOffset.y);
224
225        last = current;
226        current = next;
227        lastNormal = nextNormal;
228    }
229
230    // wrap around to beginning
231    buffer[currentIndex++] = buffer[0];
232    buffer[currentIndex++] = buffer[1];
233
234    DEBUG_DUMP_BUFFER();
235}
236
237static inline void storeBeginEnd(const PaintInfo& paintInfo, const Vertex& center,
238        const Vector2& normal, Vertex* buffer, int& currentIndex, bool begin) {
239    Vector2 strokeOffset = normal;
240    paintInfo.scaleOffsetForStrokeWidth(strokeOffset);
241
242    Vector2 referencePoint = {center.x, center.y};
243    if (paintInfo.cap == SkPaint::kSquare_Cap) {
244        Vector2 rotated = {-strokeOffset.y, strokeOffset.x};
245        referencePoint += rotated * (begin ? -1 : 1);
246    }
247
248    Vertex::set(&buffer[currentIndex++], referencePoint + strokeOffset);
249    Vertex::set(&buffer[currentIndex++], referencePoint - strokeOffset);
250}
251
252/**
253 * Fills a vertexBuffer with non-alpha vertices similar to getStrokeVerticesFromPerimeter, except:
254 *
255 * 1 - Doesn't need to wrap around, since the input vertices are unclosed
256 *
257 * 2 - can zig-zag across 'extra' vertices at either end, to create round caps
258 */
259void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo,
260        const Vector<Vertex>& vertices, VertexBuffer& vertexBuffer) {
261    const int extra = paintInfo.capExtraDivisions();
262    const int allocSize = (vertices.size() + extra) * 2;
263    Vertex* buffer = vertexBuffer.alloc<Vertex>(allocSize);
264
265    const int lastIndex = vertices.size() - 1;
266    if (extra > 0) {
267        // tessellate both round caps
268        float beginTheta = atan2(
269                    - (vertices[0].x - vertices[1].x),
270                    vertices[0].y - vertices[1].y);
271        float endTheta = atan2(
272                    - (vertices[lastIndex].x - vertices[lastIndex - 1].x),
273                    vertices[lastIndex].y - vertices[lastIndex - 1].y);
274        const float dTheta = PI / (extra + 1);
275        const float radialScale = 2.0f / (1 + cos(dTheta));
276
277        int capOffset;
278        for (int i = 0; i < extra; i++) {
279            if (i < extra / 2) {
280                capOffset = extra - 2 * i - 1;
281            } else {
282                capOffset = 2 * i - extra;
283            }
284
285            beginTheta += dTheta;
286            Vector2 beginRadialOffset = {cos(beginTheta), sin(beginTheta)};
287            paintInfo.scaleOffsetForStrokeWidth(beginRadialOffset);
288            Vertex::set(&buffer[capOffset],
289                    vertices[0].x + beginRadialOffset.x,
290                    vertices[0].y + beginRadialOffset.y);
291
292            endTheta += dTheta;
293            Vector2 endRadialOffset = {cos(endTheta), sin(endTheta)};
294            paintInfo.scaleOffsetForStrokeWidth(endRadialOffset);
295            Vertex::set(&buffer[allocSize - 1 - capOffset],
296                    vertices[lastIndex].x + endRadialOffset.x,
297                    vertices[lastIndex].y + endRadialOffset.y);
298        }
299    }
300
301    int currentIndex = extra;
302    const Vertex* last = &(vertices[0]);
303    const Vertex* current = &(vertices[1]);
304    Vector2 lastNormal = {current->y - last->y, last->x - current->x};
305    lastNormal.normalize();
306
307    storeBeginEnd(paintInfo, vertices[0], lastNormal, buffer, currentIndex, true);
308
309    for (unsigned int i = 1; i < vertices.size() - 1; i++) {
310        const Vertex* next = &(vertices[i + 1]);
311        Vector2 nextNormal = {next->y - current->y, current->x - next->x};
312        nextNormal.normalize();
313
314        Vector2 strokeOffset  = totalOffsetFromNormals(lastNormal, nextNormal);
315        paintInfo.scaleOffsetForStrokeWidth(strokeOffset);
316
317        Vector2 center = {current->x, current->y};
318        Vertex::set(&buffer[currentIndex++], center + strokeOffset);
319        Vertex::set(&buffer[currentIndex++], center - strokeOffset);
320
321        current = next;
322        lastNormal = nextNormal;
323    }
324
325    storeBeginEnd(paintInfo, vertices[lastIndex], lastNormal, buffer, currentIndex, false);
326
327    DEBUG_DUMP_BUFFER();
328}
329
330/**
331 * Populates a vertexBuffer with AlphaVertices to create an anti-aliased fill shape tessellation
332 *
333 * 1 - create the AA perimeter of unit width, by zig-zagging at each point around the perimeter of
334 * the shape (using 2 * perimeter.size() vertices)
335 *
336 * 2 - wrap around to the beginning to complete the perimeter (2 vertices)
337 *
338 * 3 - zig zag back and forth inside the shape to fill it (using perimeter.size() vertices)
339 */
340void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo, const Vector<Vertex>& perimeter,
341        VertexBuffer& vertexBuffer, float maxAlpha = 1.0f) {
342    AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(perimeter.size() * 3 + 2);
343
344    // generate alpha points - fill Alpha vertex gaps in between each point with
345    // alpha 0 vertex, offset by a scaled normal.
346    int currentIndex = 0;
347    const Vertex* last = &(perimeter[perimeter.size() - 1]);
348    const Vertex* current = &(perimeter[0]);
349    Vector2 lastNormal = {current->y - last->y, last->x - current->x};
350    lastNormal.normalize();
351    for (unsigned int i = 0; i < perimeter.size(); i++) {
352        const Vertex* next = &(perimeter[i + 1 >= perimeter.size() ? 0 : i + 1]);
353        Vector2 nextNormal = {next->y - current->y, current->x - next->x};
354        nextNormal.normalize();
355
356        // AA point offset from original point is that point's normal, such that each side is offset
357        // by .5 pixels
358        Vector2 totalOffset = paintInfo.deriveAAOffset(totalOffsetFromNormals(lastNormal, nextNormal));
359
360        AlphaVertex::set(&buffer[currentIndex++],
361                current->x + totalOffset.x,
362                current->y + totalOffset.y,
363                0.0f);
364        AlphaVertex::set(&buffer[currentIndex++],
365                current->x - totalOffset.x,
366                current->y - totalOffset.y,
367                maxAlpha);
368
369        last = current;
370        current = next;
371        lastNormal = nextNormal;
372    }
373
374    // wrap around to beginning
375    buffer[currentIndex++] = buffer[0];
376    buffer[currentIndex++] = buffer[1];
377
378    // zig zag between all previous points on the inside of the hull to create a
379    // triangle strip that fills the hull, repeating the first inner point to
380    // create degenerate tris to start inside path
381    int srcAindex = 0;
382    int srcBindex = perimeter.size() - 1;
383    while (srcAindex <= srcBindex) {
384        buffer[currentIndex++] = buffer[srcAindex * 2 + 1];
385        if (srcAindex == srcBindex) break;
386        buffer[currentIndex++] = buffer[srcBindex * 2 + 1];
387        srcAindex++;
388        srcBindex--;
389    }
390
391    DEBUG_DUMP_BUFFER();
392}
393
394/**
395 * Stores geometry for a single, AA-perimeter (potentially rounded) cap
396 *
397 * For explanation of constants and general methodoloyg, see comments for
398 * getStrokeVerticesFromUnclosedVerticesAA() below.
399 */
400inline static void storeCapAA(const PaintInfo& paintInfo, const Vector<Vertex>& vertices,
401        AlphaVertex* buffer, bool isFirst, Vector2 normal, int offset) {
402    const int extra = paintInfo.capExtraDivisions();
403    const int extraOffset = (extra + 1) / 2;
404    const int capIndex = isFirst
405            ? 2 * offset + 6 + 2 * (extra + extraOffset)
406            : offset + 2 + 2 * extraOffset;
407    if (isFirst) normal *= -1;
408
409    // TODO: this normal should be scaled by radialScale if extra != 0, see totalOffsetFromNormals()
410    Vector2 AAOffset = paintInfo.deriveAAOffset(normal);
411
412    Vector2 strokeOffset = normal;
413    paintInfo.scaleOffsetForStrokeWidth(strokeOffset);
414    Vector2 outerOffset = strokeOffset + AAOffset;
415    Vector2 innerOffset = strokeOffset - AAOffset;
416
417    Vector2 capAAOffset = {0, 0};
418    if (paintInfo.cap != SkPaint::kRound_Cap) {
419        // if the cap is square or butt, the inside primary cap vertices will be inset in two
420        // directions - both normal to the stroke, and parallel to it.
421        capAAOffset = (Vector2){-AAOffset.y, AAOffset.x};
422    }
423
424    // determine referencePoint, the center point for the 4 primary cap vertices
425    const Vertex* point = isFirst ? vertices.begin() : (vertices.end() - 1);
426    Vector2 referencePoint = {point->x, point->y};
427    if (paintInfo.cap == SkPaint::kSquare_Cap) {
428        // To account for square cap, move the primary cap vertices (that create the AA edge) by the
429        // stroke offset vector (rotated to be parallel to the stroke)
430        Vector2 rotated = {-strokeOffset.y, strokeOffset.x};
431        referencePoint += rotated;
432    }
433
434    AlphaVertex::set(&buffer[capIndex + 0],
435            referencePoint.x + outerOffset.x + capAAOffset.x,
436            referencePoint.y + outerOffset.y + capAAOffset.y,
437            0.0f);
438    AlphaVertex::set(&buffer[capIndex + 1],
439            referencePoint.x + innerOffset.x - capAAOffset.x,
440            referencePoint.y + innerOffset.y - capAAOffset.y,
441            paintInfo.maxAlpha);
442
443    bool isRound = paintInfo.cap == SkPaint::kRound_Cap;
444
445    const int postCapIndex = (isRound && isFirst) ? (2 * extraOffset - 2) : capIndex + (2 * extra);
446    AlphaVertex::set(&buffer[postCapIndex + 2],
447            referencePoint.x - outerOffset.x + capAAOffset.x,
448            referencePoint.y - outerOffset.y + capAAOffset.y,
449            0.0f);
450    AlphaVertex::set(&buffer[postCapIndex + 3],
451            referencePoint.x - innerOffset.x - capAAOffset.x,
452            referencePoint.y - innerOffset.y - capAAOffset.y,
453            paintInfo.maxAlpha);
454
455    if (isRound) {
456        const float dTheta = PI / (extra + 1);
457        const float radialScale = 2.0f / (1 + cos(dTheta));
458        float theta = atan2(normal.y, normal.x);
459        int capPerimIndex = capIndex + 2;
460
461        for (int i = 0; i < extra; i++) {
462            theta += dTheta;
463
464            Vector2 radialOffset = {cos(theta), sin(theta)};
465
466            // scale to compensate for pinching at sharp angles, see totalOffsetFromNormals()
467            radialOffset *= radialScale;
468
469            AAOffset = paintInfo.deriveAAOffset(radialOffset);
470            paintInfo.scaleOffsetForStrokeWidth(radialOffset);
471            AlphaVertex::set(&buffer[capPerimIndex++],
472                    referencePoint.x + radialOffset.x + AAOffset.x,
473                    referencePoint.y + radialOffset.y + AAOffset.y,
474                    0.0f);
475            AlphaVertex::set(&buffer[capPerimIndex++],
476                    referencePoint.x + radialOffset.x - AAOffset.x,
477                    referencePoint.y + radialOffset.y - AAOffset.y,
478                    paintInfo.maxAlpha);
479
480            if (isFirst && i == extra - extraOffset) {
481                //copy most recent two points to first two points
482                buffer[0] = buffer[capPerimIndex - 2];
483                buffer[1] = buffer[capPerimIndex - 1];
484
485                capPerimIndex = 2; // start writing the rest of the round cap at index 2
486            }
487        }
488
489        if (isFirst) {
490            const int startCapFillIndex = capIndex + 2 * (extra - extraOffset) + 4;
491            int capFillIndex = startCapFillIndex;
492            for (int i = 0; i < extra + 2; i += 2) {
493                buffer[capFillIndex++] = buffer[1 + i];
494                // TODO: to support odd numbers of divisions, break here on the last iteration
495                buffer[capFillIndex++] = buffer[startCapFillIndex - 3 - i];
496            }
497        } else {
498            int capFillIndex = 6 * vertices.size() + 2 + 6 * extra - (extra + 2);
499            for (int i = 0; i < extra + 2; i += 2) {
500                buffer[capFillIndex++] = buffer[capIndex + 1 + i];
501                // TODO: to support odd numbers of divisions, break here on the last iteration
502                buffer[capFillIndex++] = buffer[capIndex + 3 + 2 * extra - i];
503            }
504        }
505        return;
506    }
507    if (isFirst) {
508        buffer[0] = buffer[postCapIndex + 2];
509        buffer[1] = buffer[postCapIndex + 3];
510        buffer[postCapIndex + 4] = buffer[1]; // degenerate tris (the only two!)
511        buffer[postCapIndex + 5] = buffer[postCapIndex + 1];
512    } else {
513        buffer[6 * vertices.size()] = buffer[postCapIndex + 1];
514        buffer[6 * vertices.size() + 1] = buffer[postCapIndex + 3];
515    }
516}
517
518/*
519the geometry for an aa, capped stroke consists of the following:
520
521       # vertices       |    function
522----------------------------------------------------------------------
523a) 2                    | Start AA perimeter
524b) 2, 2 * roundDivOff   | First half of begin cap's perimeter
525                        |
526   2 * middlePts        | 'Outer' or 'Top' AA perimeter half (between caps)
527                        |
528a) 4                    | End cap's
529b) 2, 2 * roundDivs, 2  |    AA perimeter
530                        |
531   2 * middlePts        | 'Inner' or 'bottom' AA perimeter half
532                        |
533a) 6                    | Begin cap's perimeter
534b) 2, 2*(rD - rDO + 1), | Last half of begin cap's perimeter
535       roundDivs, 2     |
536                        |
537   2 * middlePts        | Stroke's full opacity center strip
538                        |
539a) 2                    | end stroke
540b) 2, roundDivs         |    (and end cap fill, for round)
541
542Notes:
543* rows starting with 'a)' denote the Butt or Square cap vertex use, 'b)' denote Round
544
545* 'middlePts' is (number of points in the unclosed input vertex list, minus 2) times two
546
547* 'roundDivs' or 'rD' is the number of extra vertices (beyond the minimum of 2) that define the
548        round cap's shape, and is at least two. This will increase with cap size to sufficiently
549        define the cap's level of tessellation.
550
551* 'roundDivOffset' or 'rDO' is the point about halfway along the start cap's round perimeter, where
552        the stream of vertices for the AA perimeter starts. By starting and ending the perimeter at
553        this offset, the fill of the stroke is drawn from this point with minimal extra vertices.
554
555This means the outer perimeter starts at:
556    outerIndex = (2) OR (2 + 2 * roundDivOff)
557the inner perimeter (since it is filled in reverse) starts at:
558    innerIndex = outerIndex + (4 * middlePts) + ((4) OR (4 + 2 * roundDivs)) - 1
559the stroke starts at:
560    strokeIndex = innerIndex + 1 + ((6) OR (6 + 3 * roundDivs - 2 * roundDivOffset))
561
562The total needed allocated space is either:
563    2 + 4 + 6 + 2 + 3 * (2 * middlePts) = 14 + 6 * middlePts = 2 + 6 * pts
564or, for rounded caps:
565    (2 + 2 * rDO) + (4 + 2 * rD) + (2 * (rD - rDO + 1)
566            + roundDivs + 4) + (2 + roundDivs) + 3 * (2 * middlePts)
567    = 14 + 6 * middlePts + 6 * roundDivs
568    = 2 + 6 * pts + 6 * roundDivs
569 */
570void getStrokeVerticesFromUnclosedVerticesAA(const PaintInfo& paintInfo,
571        const Vector<Vertex>& vertices, VertexBuffer& vertexBuffer) {
572
573    const int extra = paintInfo.capExtraDivisions();
574    const int allocSize = 6 * vertices.size() + 2 + 6 * extra;
575
576    AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(allocSize);
577
578    const int extraOffset = (extra + 1) / 2;
579    int offset = 2 * (vertices.size() - 2);
580    // there is no outer/inner here, using them for consistency with below approach
581    int currentAAOuterIndex = 2 + 2 * extraOffset;
582    int currentAAInnerIndex = currentAAOuterIndex + (2 * offset) + 3 + (2 * extra);
583    int currentStrokeIndex = currentAAInnerIndex + 7 + (3 * extra - 2 * extraOffset);
584
585    const Vertex* last = &(vertices[0]);
586    const Vertex* current = &(vertices[1]);
587    Vector2 lastNormal = {current->y - last->y, last->x - current->x};
588    lastNormal.normalize();
589
590    // TODO: use normal from bezier traversal for cap, instead of from vertices
591    storeCapAA(paintInfo, vertices, buffer, true, lastNormal, offset);
592
593    for (unsigned int i = 1; i < vertices.size() - 1; i++) {
594        const Vertex* next = &(vertices[i + 1]);
595        Vector2 nextNormal = {next->y - current->y, current->x - next->x};
596        nextNormal.normalize();
597
598        Vector2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
599        Vector2 AAOffset = paintInfo.deriveAAOffset(totalOffset);
600
601        Vector2 innerOffset = totalOffset;
602        paintInfo.scaleOffsetForStrokeWidth(innerOffset);
603        Vector2 outerOffset = innerOffset + AAOffset;
604        innerOffset -= AAOffset;
605
606        AlphaVertex::set(&buffer[currentAAOuterIndex++],
607                current->x + outerOffset.x,
608                current->y + outerOffset.y,
609                0.0f);
610        AlphaVertex::set(&buffer[currentAAOuterIndex++],
611                current->x + innerOffset.x,
612                current->y + innerOffset.y,
613                paintInfo.maxAlpha);
614
615        AlphaVertex::set(&buffer[currentStrokeIndex++],
616                current->x + innerOffset.x,
617                current->y + innerOffset.y,
618                paintInfo.maxAlpha);
619        AlphaVertex::set(&buffer[currentStrokeIndex++],
620                current->x - innerOffset.x,
621                current->y - innerOffset.y,
622                paintInfo.maxAlpha);
623
624        AlphaVertex::set(&buffer[currentAAInnerIndex--],
625                current->x - innerOffset.x,
626                current->y - innerOffset.y,
627                paintInfo.maxAlpha);
628        AlphaVertex::set(&buffer[currentAAInnerIndex--],
629                current->x - outerOffset.x,
630                current->y - outerOffset.y,
631                0.0f);
632
633        current = next;
634        lastNormal = nextNormal;
635    }
636
637    // TODO: use normal from bezier traversal for cap, instead of from vertices
638    storeCapAA(paintInfo, vertices, buffer, false, lastNormal, offset);
639
640    DEBUG_DUMP_ALPHA_BUFFER();
641}
642
643
644void getStrokeVerticesFromPerimeterAA(const PaintInfo& paintInfo, const Vector<Vertex>& perimeter,
645        VertexBuffer& vertexBuffer) {
646    AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * perimeter.size() + 8);
647
648    int offset = 2 * perimeter.size() + 3;
649    int currentAAOuterIndex = 0;
650    int currentStrokeIndex = offset;
651    int currentAAInnerIndex = offset * 2;
652
653    const Vertex* last = &(perimeter[perimeter.size() - 1]);
654    const Vertex* current = &(perimeter[0]);
655    Vector2 lastNormal = {current->y - last->y, last->x - current->x};
656    lastNormal.normalize();
657    for (unsigned int i = 0; i < perimeter.size(); i++) {
658        const Vertex* next = &(perimeter[i + 1 >= perimeter.size() ? 0 : i + 1]);
659        Vector2 nextNormal = {next->y - current->y, current->x - next->x};
660        nextNormal.normalize();
661
662        Vector2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
663        Vector2 AAOffset = paintInfo.deriveAAOffset(totalOffset);
664
665        Vector2 innerOffset = totalOffset;
666        paintInfo.scaleOffsetForStrokeWidth(innerOffset);
667        Vector2 outerOffset = innerOffset + AAOffset;
668        innerOffset -= AAOffset;
669
670        AlphaVertex::set(&buffer[currentAAOuterIndex++],
671                current->x + outerOffset.x,
672                current->y + outerOffset.y,
673                0.0f);
674        AlphaVertex::set(&buffer[currentAAOuterIndex++],
675                current->x + innerOffset.x,
676                current->y + innerOffset.y,
677                paintInfo.maxAlpha);
678
679        AlphaVertex::set(&buffer[currentStrokeIndex++],
680                current->x + innerOffset.x,
681                current->y + innerOffset.y,
682                paintInfo.maxAlpha);
683        AlphaVertex::set(&buffer[currentStrokeIndex++],
684                current->x - innerOffset.x,
685                current->y - innerOffset.y,
686                paintInfo.maxAlpha);
687
688        AlphaVertex::set(&buffer[currentAAInnerIndex++],
689                current->x - innerOffset.x,
690                current->y - innerOffset.y,
691                paintInfo.maxAlpha);
692        AlphaVertex::set(&buffer[currentAAInnerIndex++],
693                current->x - outerOffset.x,
694                current->y - outerOffset.y,
695                0.0f);
696
697        last = current;
698        current = next;
699        lastNormal = nextNormal;
700    }
701
702    // wrap each strip around to beginning, creating degenerate tris to bridge strips
703    buffer[currentAAOuterIndex++] = buffer[0];
704    buffer[currentAAOuterIndex++] = buffer[1];
705    buffer[currentAAOuterIndex++] = buffer[1];
706
707    buffer[currentStrokeIndex++] = buffer[offset];
708    buffer[currentStrokeIndex++] = buffer[offset + 1];
709    buffer[currentStrokeIndex++] = buffer[offset + 1];
710
711    buffer[currentAAInnerIndex++] = buffer[2 * offset];
712    buffer[currentAAInnerIndex++] = buffer[2 * offset + 1];
713    // don't need to create last degenerate tri
714
715    DEBUG_DUMP_ALPHA_BUFFER();
716}
717
718void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint,
719        const mat4& transform, VertexBuffer& vertexBuffer) {
720    ATRACE_CALL();
721
722    const PaintInfo paintInfo(paint, transform);
723
724    Vector<Vertex> tempVertices;
725    float threshInvScaleX = paintInfo.inverseScaleX;
726    float threshInvScaleY = paintInfo.inverseScaleY;
727    if (paintInfo.style == SkPaint::kStroke_Style) {
728        // alter the bezier recursion threshold values we calculate in order to compensate for
729        // expansion done after the path vertices are found
730        SkRect bounds = path.getBounds();
731        if (!bounds.isEmpty()) {
732            threshInvScaleX *= bounds.width() / (bounds.width() + paint->getStrokeWidth());
733            threshInvScaleY *= bounds.height() / (bounds.height() + paint->getStrokeWidth());
734        }
735    }
736
737    // force close if we're filling the path, since fill path expects closed perimeter.
738    bool forceClose = paintInfo.style != SkPaint::kStroke_Style;
739    bool wasClosed = approximatePathOutlineVertices(path, forceClose,
740            threshInvScaleX * threshInvScaleX, threshInvScaleY * threshInvScaleY,
741            OUTLINE_REFINE_THRESHOLD_SQUARED, tempVertices);
742
743    if (!tempVertices.size()) {
744        // path was empty, return without allocating vertex buffer
745        return;
746    }
747
748#if VERTEX_DEBUG
749    for (unsigned int i = 0; i < tempVertices.size(); i++) {
750        ALOGD("orig path: point at %f %f",
751                tempVertices[i].x, tempVertices[i].y);
752    }
753#endif
754
755    if (paintInfo.style == SkPaint::kStroke_Style) {
756        if (!paintInfo.isAA) {
757            if (wasClosed) {
758                getStrokeVerticesFromPerimeter(paintInfo, tempVertices, vertexBuffer);
759            } else {
760                getStrokeVerticesFromUnclosedVertices(paintInfo, tempVertices, vertexBuffer);
761            }
762
763        } else {
764            if (wasClosed) {
765                getStrokeVerticesFromPerimeterAA(paintInfo, tempVertices, vertexBuffer);
766            } else {
767                getStrokeVerticesFromUnclosedVerticesAA(paintInfo, tempVertices, vertexBuffer);
768            }
769        }
770    } else {
771        // For kStrokeAndFill style, the path should be adjusted externally.
772        // It will be treated as a fill here.
773        if (!paintInfo.isAA) {
774            getFillVerticesFromPerimeter(tempVertices, vertexBuffer);
775        } else {
776            getFillVerticesFromPerimeterAA(paintInfo, tempVertices, vertexBuffer);
777        }
778    }
779
780    Rect bounds(path.getBounds());
781    paintInfo.expandBoundsForStroke(&bounds);
782    vertexBuffer.setBounds(bounds);
783}
784
785template <class TYPE>
786static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer,
787        const float* points, int count, Rect& bounds) {
788    bounds.set(points[0], points[1], points[0], points[1]);
789
790    int numPoints = count / 2;
791    int verticesPerPoint = srcBuffer.getVertexCount();
792    dstBuffer.alloc<TYPE>(numPoints * verticesPerPoint + (numPoints - 1) * 2);
793
794    for (int i = 0; i < count; i += 2) {
795        bounds.expandToCoverVertex(points[i + 0], points[i + 1]);
796        dstBuffer.copyInto<TYPE>(srcBuffer, points[i + 0], points[i + 1]);
797    }
798    dstBuffer.createDegenerateSeparators<TYPE>(verticesPerPoint);
799}
800
801void PathTessellator::tessellatePoints(const float* points, int count, const SkPaint* paint,
802        const mat4& transform, VertexBuffer& vertexBuffer) {
803    const PaintInfo paintInfo(paint, transform);
804
805    // determine point shape
806    SkPath path;
807    float radius = paintInfo.halfStrokeWidth;
808    if (radius == 0.0f) radius = 0.25f;
809
810    if (paintInfo.cap == SkPaint::kRound_Cap) {
811        path.addCircle(0, 0, radius);
812    } else {
813        path.addRect(-radius, -radius, radius, radius);
814    }
815
816    // calculate outline
817    Vector<Vertex> outlineVertices;
818    approximatePathOutlineVertices(path, true,
819            paintInfo.inverseScaleX * paintInfo.inverseScaleX,
820            paintInfo.inverseScaleY * paintInfo.inverseScaleY,
821            OUTLINE_REFINE_THRESHOLD_SQUARED, outlineVertices);
822
823    if (!outlineVertices.size()) return;
824
825    Rect bounds;
826    // tessellate, then duplicate outline across points
827    int numPoints = count / 2;
828    VertexBuffer tempBuffer;
829    if (!paintInfo.isAA) {
830        getFillVerticesFromPerimeter(outlineVertices, tempBuffer);
831        instanceVertices<Vertex>(tempBuffer, vertexBuffer, points, count, bounds);
832    } else {
833        // note: pass maxAlpha directly, since we want fill to be alpha modulated
834        getFillVerticesFromPerimeterAA(paintInfo, outlineVertices, tempBuffer, paintInfo.maxAlpha);
835        instanceVertices<AlphaVertex>(tempBuffer, vertexBuffer, points, count, bounds);
836    }
837
838    // expand bounds from vertex coords to pixel data
839    paintInfo.expandBoundsForStroke(&bounds);
840    vertexBuffer.setBounds(bounds);
841}
842
843void PathTessellator::tessellateLines(const float* points, int count, const SkPaint* paint,
844        const mat4& transform, VertexBuffer& vertexBuffer) {
845    ATRACE_CALL();
846    const PaintInfo paintInfo(paint, transform);
847
848    const int extra = paintInfo.capExtraDivisions();
849    int numLines = count / 4;
850    int lineAllocSize;
851    // pre-allocate space for lines in the buffer, and degenerate tris in between
852    if (paintInfo.isAA) {
853        lineAllocSize = 6 * (2) + 2 + 6 * extra;
854        vertexBuffer.alloc<AlphaVertex>(numLines * lineAllocSize + (numLines - 1) * 2);
855    } else {
856        lineAllocSize = 2 * ((2) + extra);
857        vertexBuffer.alloc<Vertex>(numLines * lineAllocSize + (numLines - 1) * 2);
858    }
859
860    Vector<Vertex> tempVertices;
861    tempVertices.push();
862    tempVertices.push();
863    Vertex* tempVerticesData = tempVertices.editArray();
864    Rect bounds;
865    bounds.set(points[0], points[1], points[0], points[1]);
866    for (int i = 0; i < count; i += 4) {
867        Vertex::set(&(tempVerticesData[0]), points[i + 0], points[i + 1]);
868        Vertex::set(&(tempVerticesData[1]), points[i + 2], points[i + 3]);
869
870        if (paintInfo.isAA) {
871            getStrokeVerticesFromUnclosedVerticesAA(paintInfo, tempVertices, vertexBuffer);
872        } else {
873            getStrokeVerticesFromUnclosedVertices(paintInfo, tempVertices, vertexBuffer);
874        }
875
876        // calculate bounds
877        bounds.expandToCoverVertex(tempVerticesData[0].x, tempVerticesData[0].y);
878        bounds.expandToCoverVertex(tempVerticesData[1].x, tempVerticesData[1].y);
879    }
880
881    // since multiple objects tessellated into buffer, separate them with degen tris
882    if (paintInfo.isAA) {
883        vertexBuffer.createDegenerateSeparators<AlphaVertex>(lineAllocSize);
884    } else {
885        vertexBuffer.createDegenerateSeparators<Vertex>(lineAllocSize);
886    }
887
888    // expand bounds from vertex coords to pixel data
889    paintInfo.expandBoundsForStroke(&bounds);
890    vertexBuffer.setBounds(bounds);
891}
892
893///////////////////////////////////////////////////////////////////////////////
894// Simple path line approximation
895///////////////////////////////////////////////////////////////////////////////
896
897bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, float thresholdSquared,
898        Vector<Vertex>& outputVertices) {
899    return approximatePathOutlineVertices(path, true, 1.0f, 1.0f, thresholdSquared, outputVertices);
900}
901
902void pushToVector(Vector<Vertex>& vertices, float x, float y) {
903    // TODO: make this not yuck
904    vertices.push();
905    Vertex* newVertex = &(vertices.editArray()[vertices.size() - 1]);
906    Vertex::set(newVertex, x, y);
907}
908
909bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool forceClose,
910        float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
911        Vector<Vertex>& outputVertices) {
912    ATRACE_CALL();
913
914    // TODO: to support joins other than sharp miter, join vertices should be labelled in the
915    // perimeter, or resolved into more vertices. Reconsider forceClose-ing in that case.
916    SkPath::Iter iter(path, forceClose);
917    SkPoint pts[4];
918    SkPath::Verb v;
919    while (SkPath::kDone_Verb != (v = iter.next(pts))) {
920            switch (v) {
921            case SkPath::kMove_Verb:
922                pushToVector(outputVertices, pts[0].x(), pts[0].y());
923                ALOGV("Move to pos %f %f", pts[0].x(), pts[0].y());
924                break;
925            case SkPath::kClose_Verb:
926                ALOGV("Close at pos %f %f", pts[0].x(), pts[0].y());
927                break;
928            case SkPath::kLine_Verb:
929                ALOGV("kLine_Verb %f %f -> %f %f", pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y());
930                pushToVector(outputVertices, pts[1].x(), pts[1].y());
931                break;
932            case SkPath::kQuad_Verb:
933                ALOGV("kQuad_Verb");
934                recursiveQuadraticBezierVertices(
935                        pts[0].x(), pts[0].y(),
936                        pts[2].x(), pts[2].y(),
937                        pts[1].x(), pts[1].y(),
938                        sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
939                break;
940            case SkPath::kCubic_Verb:
941                ALOGV("kCubic_Verb");
942                recursiveCubicBezierVertices(
943                        pts[0].x(), pts[0].y(),
944                        pts[1].x(), pts[1].y(),
945                        pts[3].x(), pts[3].y(),
946                        pts[2].x(), pts[2].y(),
947                        sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
948                break;
949            default:
950                break;
951            }
952    }
953
954    int size = outputVertices.size();
955    if (size >= 2 && outputVertices[0].x == outputVertices[size - 1].x &&
956            outputVertices[0].y == outputVertices[size - 1].y) {
957        outputVertices.pop();
958        return true;
959    }
960    return false;
961}
962
963///////////////////////////////////////////////////////////////////////////////
964// Bezier approximation
965///////////////////////////////////////////////////////////////////////////////
966
967void PathTessellator::recursiveCubicBezierVertices(
968        float p1x, float p1y, float c1x, float c1y,
969        float p2x, float p2y, float c2x, float c2y,
970        float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
971        Vector<Vertex>& outputVertices, int depth) {
972    float dx = p2x - p1x;
973    float dy = p2y - p1y;
974    float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx);
975    float d2 = fabs((c2x - p2x) * dy - (c2y - p2y) * dx);
976    float d = d1 + d2;
977
978    // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
979    if (depth >= MAX_DEPTH
980            || d * d <= thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
981        // below thresh, draw line by adding endpoint
982        pushToVector(outputVertices, p2x, p2y);
983    } else {
984        float p1c1x = (p1x + c1x) * 0.5f;
985        float p1c1y = (p1y + c1y) * 0.5f;
986        float p2c2x = (p2x + c2x) * 0.5f;
987        float p2c2y = (p2y + c2y) * 0.5f;
988
989        float c1c2x = (c1x + c2x) * 0.5f;
990        float c1c2y = (c1y + c2y) * 0.5f;
991
992        float p1c1c2x = (p1c1x + c1c2x) * 0.5f;
993        float p1c1c2y = (p1c1y + c1c2y) * 0.5f;
994
995        float p2c1c2x = (p2c2x + c1c2x) * 0.5f;
996        float p2c1c2y = (p2c2y + c1c2y) * 0.5f;
997
998        float mx = (p1c1c2x + p2c1c2x) * 0.5f;
999        float my = (p1c1c2y + p2c1c2y) * 0.5f;
1000
1001        recursiveCubicBezierVertices(
1002                p1x, p1y, p1c1x, p1c1y,
1003                mx, my, p1c1c2x, p1c1c2y,
1004                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
1005        recursiveCubicBezierVertices(
1006                mx, my, p2c1c2x, p2c1c2y,
1007                p2x, p2y, p2c2x, p2c2y,
1008                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
1009    }
1010}
1011
1012void PathTessellator::recursiveQuadraticBezierVertices(
1013        float ax, float ay,
1014        float bx, float by,
1015        float cx, float cy,
1016        float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
1017        Vector<Vertex>& outputVertices, int depth) {
1018    float dx = bx - ax;
1019    float dy = by - ay;
1020    float d = (cx - bx) * dy - (cy - by) * dx;
1021
1022    // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
1023    if (depth >= MAX_DEPTH
1024            || d * d <= thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
1025        // below thresh, draw line by adding endpoint
1026        pushToVector(outputVertices, bx, by);
1027    } else {
1028        float acx = (ax + cx) * 0.5f;
1029        float bcx = (bx + cx) * 0.5f;
1030        float acy = (ay + cy) * 0.5f;
1031        float bcy = (by + cy) * 0.5f;
1032
1033        // midpoint
1034        float mx = (acx + bcx) * 0.5f;
1035        float my = (acy + bcy) * 0.5f;
1036
1037        recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy,
1038                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
1039        recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy,
1040                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
1041    }
1042}
1043
1044}; // namespace uirenderer
1045}; // namespace android
1046