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