Merge "HW Acceleration support for stroked arcs with BUTT caps" into jb-mr1-dev
This commit is contained in:
@@ -2427,17 +2427,39 @@ status_t OpenGLRenderer::drawOval(float left, float top, float right, float bott
|
||||
}
|
||||
|
||||
status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
|
||||
float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) {
|
||||
if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
|
||||
|
||||
if (fabs(sweepAngle) >= 360.0f) {
|
||||
return drawOval(left, top, right, bottom, paint);
|
||||
float startAngle, float sweepAngle, bool useCenter, SkPaint* p) {
|
||||
if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) {
|
||||
return DrawGlInfo::kStatusDone;
|
||||
}
|
||||
|
||||
mCaches.activeTexture(0);
|
||||
const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top,
|
||||
startAngle, sweepAngle, useCenter, paint);
|
||||
return drawShape(left, top, texture, paint);
|
||||
if (fabs(sweepAngle) >= 360.0f) {
|
||||
return drawOval(left, top, right, bottom, p);
|
||||
}
|
||||
|
||||
// TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
|
||||
if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || p->getStrokeCap() != SkPaint::kButt_Cap) {
|
||||
mCaches.activeTexture(0);
|
||||
const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top,
|
||||
startAngle, sweepAngle, useCenter, p);
|
||||
return drawShape(left, top, texture, p);
|
||||
}
|
||||
|
||||
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
|
||||
if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
|
||||
rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
|
||||
}
|
||||
|
||||
SkPath path;
|
||||
if (useCenter) {
|
||||
path.moveTo(rect.centerX(), rect.centerY());
|
||||
}
|
||||
path.arcTo(rect, startAngle, sweepAngle, !useCenter);
|
||||
if (useCenter) {
|
||||
path.close();
|
||||
}
|
||||
drawConvexPath(path, p);
|
||||
|
||||
return DrawGlInfo::kStatusDrew;
|
||||
}
|
||||
|
||||
// See SkPaintDefaults.h
|
||||
|
||||
@@ -80,11 +80,24 @@ inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) {
|
||||
*
|
||||
* Note that we can't add and normalize the two vectors, that would result in a rectangle having an
|
||||
* offset of (sqrt(2)/2, sqrt(2)/2) at each corner, instead of (1, 1)
|
||||
*
|
||||
* NOTE: assumes angles between normals 90 degrees or less
|
||||
*/
|
||||
inline vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) {
|
||||
return (normalA + normalB) / (1 + fabs(normalA.dot(normalB)));
|
||||
}
|
||||
|
||||
inline void scaleOffsetForStrokeWidth(vec2& offset, float halfStrokeWidth,
|
||||
float inverseScaleX, float inverseScaleY) {
|
||||
if (halfStrokeWidth == 0.0f) {
|
||||
// hairline - compensate for scale
|
||||
offset.x *= 0.5f * inverseScaleX;
|
||||
offset.y *= 0.5f * inverseScaleY;
|
||||
} else {
|
||||
offset *= halfStrokeWidth;
|
||||
}
|
||||
}
|
||||
|
||||
void getFillVerticesFromPerimeter(const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) {
|
||||
Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size());
|
||||
|
||||
@@ -119,13 +132,7 @@ void getStrokeVerticesFromPerimeter(const Vector<Vertex>& perimeter, float halfS
|
||||
nextNormal.normalize();
|
||||
|
||||
vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
|
||||
if (halfStrokeWidth == 0.0f) {
|
||||
// hairline - compensate for scale
|
||||
totalOffset.x *= 0.5f * inverseScaleX;
|
||||
totalOffset.y *= 0.5f * inverseScaleY;
|
||||
} else {
|
||||
totalOffset *= halfStrokeWidth;
|
||||
}
|
||||
scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
|
||||
|
||||
Vertex::set(&buffer[currentIndex++],
|
||||
current->position[0] + totalOffset.x,
|
||||
@@ -145,6 +152,55 @@ void getStrokeVerticesFromPerimeter(const Vector<Vertex>& perimeter, float halfS
|
||||
copyVertex(&buffer[currentIndex++], &buffer[1]);
|
||||
}
|
||||
|
||||
void getStrokeVerticesFromUnclosedVertices(const Vector<Vertex>& vertices, float halfStrokeWidth,
|
||||
VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) {
|
||||
Vertex* buffer = vertexBuffer.alloc<Vertex>(vertices.size() * 2);
|
||||
|
||||
int currentIndex = 0;
|
||||
const Vertex* current = &(vertices[0]);
|
||||
vec2 lastNormal;
|
||||
for (unsigned int i = 0; i < vertices.size() - 1; i++) {
|
||||
const Vertex* next = &(vertices[i + 1]);
|
||||
vec2 nextNormal(next->position[1] - current->position[1],
|
||||
current->position[0] - next->position[0]);
|
||||
nextNormal.normalize();
|
||||
|
||||
vec2 totalOffset;
|
||||
if (i == 0) {
|
||||
totalOffset = nextNormal;
|
||||
} else {
|
||||
totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
|
||||
}
|
||||
scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
|
||||
|
||||
Vertex::set(&buffer[currentIndex++],
|
||||
current->position[0] + totalOffset.x,
|
||||
current->position[1] + totalOffset.y);
|
||||
|
||||
Vertex::set(&buffer[currentIndex++],
|
||||
current->position[0] - totalOffset.x,
|
||||
current->position[1] - totalOffset.y);
|
||||
|
||||
current = next;
|
||||
lastNormal = nextNormal;
|
||||
}
|
||||
|
||||
vec2 totalOffset = lastNormal;
|
||||
scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
|
||||
|
||||
Vertex::set(&buffer[currentIndex++],
|
||||
current->position[0] + totalOffset.x,
|
||||
current->position[1] + totalOffset.y);
|
||||
Vertex::set(&buffer[currentIndex++],
|
||||
current->position[0] - totalOffset.x,
|
||||
current->position[1] - totalOffset.y);
|
||||
#if VERTEX_DEBUG
|
||||
for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
|
||||
ALOGD("point at %f %f", buffer[i].position[0], buffer[i].position[1]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void getFillVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer,
|
||||
float inverseScaleX, float inverseScaleY) {
|
||||
AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(perimeter.size() * 3 + 2);
|
||||
@@ -202,11 +258,167 @@ void getFillVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, VertexBuffe
|
||||
|
||||
#if VERTEX_DEBUG
|
||||
for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
|
||||
ALOGD("point at %f %f", buffer[i].position[0], buffer[i].position[1]);
|
||||
ALOGD("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void getStrokeVerticesFromUnclosedVerticesAA(const Vector<Vertex>& vertices, float halfStrokeWidth,
|
||||
VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) {
|
||||
AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * vertices.size() + 2);
|
||||
|
||||
// avoid lines smaller than hairline since they break triangle based sampling. instead reducing
|
||||
// alpha value (TODO: support different X/Y scale)
|
||||
float maxAlpha = 1.0f;
|
||||
if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
|
||||
halfStrokeWidth * inverseScaleX < 0.5f) {
|
||||
maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
|
||||
halfStrokeWidth = 0.0f;
|
||||
}
|
||||
|
||||
// there is no outer/inner here, using them for consistency with below approach
|
||||
int offset = 2 * (vertices.size() - 2);
|
||||
int currentAAOuterIndex = 2;
|
||||
int currentAAInnerIndex = 2 * offset + 5; // reversed
|
||||
int currentStrokeIndex = currentAAInnerIndex + 7;
|
||||
|
||||
const Vertex* last = &(vertices[0]);
|
||||
const Vertex* current = &(vertices[1]);
|
||||
vec2 lastNormal(current->position[1] - last->position[1],
|
||||
last->position[0] - current->position[0]);
|
||||
lastNormal.normalize();
|
||||
|
||||
{
|
||||
// start cap
|
||||
vec2 totalOffset = lastNormal;
|
||||
vec2 AAOffset = totalOffset;
|
||||
AAOffset.x *= 0.5f * inverseScaleX;
|
||||
AAOffset.y *= 0.5f * inverseScaleY;
|
||||
|
||||
vec2 innerOffset = totalOffset;
|
||||
scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
|
||||
vec2 outerOffset = innerOffset + AAOffset;
|
||||
innerOffset -= AAOffset;
|
||||
|
||||
// TODO: support square cap by changing this offset to incorporate halfStrokeWidth
|
||||
vec2 capAAOffset(AAOffset.y, -AAOffset.x);
|
||||
AlphaVertex::set(&buffer[0],
|
||||
last->position[0] + outerOffset.x + capAAOffset.x,
|
||||
last->position[1] + outerOffset.y + capAAOffset.y,
|
||||
0.0f);
|
||||
AlphaVertex::set(&buffer[1],
|
||||
last->position[0] + innerOffset.x - capAAOffset.x,
|
||||
last->position[1] + innerOffset.y - capAAOffset.y,
|
||||
maxAlpha);
|
||||
|
||||
AlphaVertex::set(&buffer[2 * offset + 6],
|
||||
last->position[0] - outerOffset.x + capAAOffset.x,
|
||||
last->position[1] - outerOffset.y + capAAOffset.y,
|
||||
0.0f);
|
||||
AlphaVertex::set(&buffer[2 * offset + 7],
|
||||
last->position[0] - innerOffset.x - capAAOffset.x,
|
||||
last->position[1] - innerOffset.y - capAAOffset.y,
|
||||
maxAlpha);
|
||||
copyAlphaVertex(&buffer[2 * offset + 8], &buffer[0]);
|
||||
copyAlphaVertex(&buffer[2 * offset + 9], &buffer[1]);
|
||||
copyAlphaVertex(&buffer[2 * offset + 10], &buffer[1]); // degenerate tris (the only two!)
|
||||
copyAlphaVertex(&buffer[2 * offset + 11], &buffer[2 * offset + 7]);
|
||||
}
|
||||
|
||||
for (unsigned int i = 1; i < vertices.size() - 1; i++) {
|
||||
const Vertex* next = &(vertices[i + 1]);
|
||||
vec2 nextNormal(next->position[1] - current->position[1],
|
||||
current->position[0] - next->position[0]);
|
||||
nextNormal.normalize();
|
||||
|
||||
vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
|
||||
vec2 AAOffset = totalOffset;
|
||||
AAOffset.x *= 0.5f * inverseScaleX;
|
||||
AAOffset.y *= 0.5f * inverseScaleY;
|
||||
|
||||
vec2 innerOffset = totalOffset;
|
||||
scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
|
||||
vec2 outerOffset = innerOffset + AAOffset;
|
||||
innerOffset -= AAOffset;
|
||||
|
||||
AlphaVertex::set(&buffer[currentAAOuterIndex++],
|
||||
current->position[0] + outerOffset.x,
|
||||
current->position[1] + outerOffset.y,
|
||||
0.0f);
|
||||
AlphaVertex::set(&buffer[currentAAOuterIndex++],
|
||||
current->position[0] + innerOffset.x,
|
||||
current->position[1] + innerOffset.y,
|
||||
maxAlpha);
|
||||
|
||||
AlphaVertex::set(&buffer[currentStrokeIndex++],
|
||||
current->position[0] + innerOffset.x,
|
||||
current->position[1] + innerOffset.y,
|
||||
maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentStrokeIndex++],
|
||||
current->position[0] - innerOffset.x,
|
||||
current->position[1] - innerOffset.y,
|
||||
maxAlpha);
|
||||
|
||||
AlphaVertex::set(&buffer[currentAAInnerIndex--],
|
||||
current->position[0] - innerOffset.x,
|
||||
current->position[1] - innerOffset.y,
|
||||
maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentAAInnerIndex--],
|
||||
current->position[0] - outerOffset.x,
|
||||
current->position[1] - outerOffset.y,
|
||||
0.0f);
|
||||
|
||||
last = current;
|
||||
current = next;
|
||||
lastNormal = nextNormal;
|
||||
}
|
||||
|
||||
{
|
||||
// end cap
|
||||
vec2 totalOffset = lastNormal;
|
||||
vec2 AAOffset = totalOffset;
|
||||
AAOffset.x *= 0.5f * inverseScaleX;
|
||||
AAOffset.y *= 0.5f * inverseScaleY;
|
||||
|
||||
vec2 innerOffset = totalOffset;
|
||||
scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
|
||||
vec2 outerOffset = innerOffset + AAOffset;
|
||||
innerOffset -= AAOffset;
|
||||
|
||||
// TODO: support square cap by changing this offset to incorporate halfStrokeWidth
|
||||
vec2 capAAOffset(-AAOffset.y, AAOffset.x);
|
||||
|
||||
AlphaVertex::set(&buffer[offset + 2],
|
||||
current->position[0] + outerOffset.x + capAAOffset.x,
|
||||
current->position[1] + outerOffset.y + capAAOffset.y,
|
||||
0.0f);
|
||||
AlphaVertex::set(&buffer[offset + 3],
|
||||
current->position[0] + innerOffset.x - capAAOffset.x,
|
||||
current->position[1] + innerOffset.y - capAAOffset.y,
|
||||
maxAlpha);
|
||||
|
||||
AlphaVertex::set(&buffer[offset + 4],
|
||||
current->position[0] - outerOffset.x + capAAOffset.x,
|
||||
current->position[1] - outerOffset.y + capAAOffset.y,
|
||||
0.0f);
|
||||
AlphaVertex::set(&buffer[offset + 5],
|
||||
current->position[0] - innerOffset.x - capAAOffset.x,
|
||||
current->position[1] - innerOffset.y - capAAOffset.y,
|
||||
maxAlpha);
|
||||
|
||||
copyAlphaVertex(&buffer[vertexBuffer.getSize() - 2], &buffer[offset + 3]);
|
||||
copyAlphaVertex(&buffer[vertexBuffer.getSize() - 1], &buffer[offset + 5]);
|
||||
}
|
||||
|
||||
#if VERTEX_DEBUG
|
||||
for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
|
||||
ALOGD("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float halfStrokeWidth,
|
||||
VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) {
|
||||
AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * perimeter.size() + 8);
|
||||
@@ -242,13 +454,7 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal
|
||||
AAOffset.y *= 0.5f * inverseScaleY;
|
||||
|
||||
vec2 innerOffset = totalOffset;
|
||||
if (halfStrokeWidth == 0.0f) {
|
||||
// hairline! - compensate for scale
|
||||
innerOffset.x *= 0.5f * inverseScaleX;
|
||||
innerOffset.y *= 0.5f * inverseScaleY;
|
||||
} else {
|
||||
innerOffset *= halfStrokeWidth;
|
||||
}
|
||||
scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
|
||||
vec2 outerOffset = innerOffset + AAOffset;
|
||||
innerOffset -= AAOffset;
|
||||
|
||||
@@ -296,6 +502,12 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal
|
||||
copyAlphaVertex(&buffer[currentAAInnerIndex++], &buffer[2 * offset]);
|
||||
copyAlphaVertex(&buffer[currentAAInnerIndex++], &buffer[2 * offset + 1]);
|
||||
// don't need to create last degenerate tri
|
||||
|
||||
#if VERTEX_DEBUG
|
||||
for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
|
||||
ALOGD("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PathRenderer::convexPathVertices(const SkPath &path, const SkPaint* paint,
|
||||
@@ -320,7 +532,10 @@ void PathRenderer::convexPathVertices(const SkPath &path, const SkPaint* paint,
|
||||
threshInvScaleY *= bounds.height() / (bounds.height() + paint->getStrokeWidth());
|
||||
}
|
||||
}
|
||||
convexPathPerimeterVertices(path, threshInvScaleX * threshInvScaleX,
|
||||
|
||||
// force close if we're filling the path, since fill path expects closed perimeter.
|
||||
bool forceClose = style != SkPaint::kStroke_Style;
|
||||
bool wasClosed = convexPathPerimeterVertices(path, forceClose, threshInvScaleX * threshInvScaleX,
|
||||
threshInvScaleY * threshInvScaleY, tempVertices);
|
||||
|
||||
if (!tempVertices.size()) {
|
||||
@@ -337,11 +552,22 @@ void PathRenderer::convexPathVertices(const SkPath &path, const SkPaint* paint,
|
||||
if (style == SkPaint::kStroke_Style) {
|
||||
float halfStrokeWidth = paint->getStrokeWidth() * 0.5f;
|
||||
if (!isAA) {
|
||||
getStrokeVerticesFromPerimeter(tempVertices, halfStrokeWidth, vertexBuffer,
|
||||
inverseScaleX, inverseScaleY);
|
||||
if (wasClosed) {
|
||||
getStrokeVerticesFromPerimeter(tempVertices, halfStrokeWidth, vertexBuffer,
|
||||
inverseScaleX, inverseScaleY);
|
||||
} else {
|
||||
getStrokeVerticesFromUnclosedVertices(tempVertices, halfStrokeWidth, vertexBuffer,
|
||||
inverseScaleX, inverseScaleY);
|
||||
}
|
||||
|
||||
} else {
|
||||
getStrokeVerticesFromPerimeterAA(tempVertices, halfStrokeWidth, vertexBuffer,
|
||||
inverseScaleX, inverseScaleY);
|
||||
if (wasClosed) {
|
||||
getStrokeVerticesFromPerimeterAA(tempVertices, halfStrokeWidth, vertexBuffer,
|
||||
inverseScaleX, inverseScaleY);
|
||||
} else {
|
||||
getStrokeVerticesFromUnclosedVerticesAA(tempVertices, halfStrokeWidth, vertexBuffer,
|
||||
inverseScaleX, inverseScaleY);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// For kStrokeAndFill style, the path should be adjusted externally, as it will be treated as a fill here.
|
||||
@@ -354,19 +580,27 @@ void PathRenderer::convexPathVertices(const SkPath &path, const SkPaint* paint,
|
||||
}
|
||||
|
||||
|
||||
void PathRenderer::convexPathPerimeterVertices(const SkPath& path,
|
||||
void pushToVector(Vector<Vertex>& vertices, float x, float y) {
|
||||
// TODO: make this not yuck
|
||||
vertices.push();
|
||||
Vertex* newVertex = &(vertices.editArray()[vertices.size() - 1]);
|
||||
Vertex::set(newVertex, x, y);
|
||||
}
|
||||
|
||||
bool PathRenderer::convexPathPerimeterVertices(const SkPath& path, bool forceClose,
|
||||
float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex>& outputVertices) {
|
||||
ATRACE_CALL();
|
||||
|
||||
SkPath::Iter iter(path, true);
|
||||
SkPoint pos;
|
||||
// TODO: to support joins other than sharp miter, join vertices should be labelled in the
|
||||
// perimeter, or resolved into more vertices. Reconsider forceClose-ing in that case.
|
||||
SkPath::Iter iter(path, forceClose);
|
||||
SkPoint pts[4];
|
||||
SkPath::Verb v;
|
||||
Vertex* newVertex = 0;
|
||||
while (SkPath::kDone_Verb != (v = iter.next(pts))) {
|
||||
switch (v) {
|
||||
case SkPath::kMove_Verb:
|
||||
pos = pts[0];
|
||||
pushToVector(outputVertices, pts[0].x(), pts[0].y());
|
||||
ALOGV("Move to pos %f %f", pts[0].x(), pts[0].y());
|
||||
break;
|
||||
case SkPath::kClose_Verb:
|
||||
@@ -377,10 +611,7 @@ void PathRenderer::convexPathPerimeterVertices(const SkPath& path,
|
||||
pts[0].x(), pts[0].y(),
|
||||
pts[1].x(), pts[1].y());
|
||||
|
||||
// TODO: make this not yuck
|
||||
outputVertices.push();
|
||||
newVertex = &(outputVertices.editArray()[outputVertices.size() - 1]);
|
||||
Vertex::set(newVertex, pts[1].x(), pts[1].y());
|
||||
pushToVector(outputVertices, pts[1].x(), pts[1].y());
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
ALOGV("kQuad_Verb");
|
||||
@@ -403,6 +634,14 @@ void PathRenderer::convexPathPerimeterVertices(const SkPath& path,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int size = outputVertices.size();
|
||||
if (size >= 2 && outputVertices[0].position[0] == outputVertices[size - 1].position[0] &&
|
||||
outputVertices[0].position[1] == outputVertices[size - 1].position[1]) {
|
||||
outputVertices.pop();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PathRenderer::recursiveCubicBezierVertices(
|
||||
@@ -419,10 +658,7 @@ void PathRenderer::recursiveCubicBezierVertices(
|
||||
|
||||
if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
|
||||
// below thresh, draw line by adding endpoint
|
||||
// TODO: make this not yuck
|
||||
outputVertices.push();
|
||||
Vertex* newVertex = &(outputVertices.editArray()[outputVertices.size() - 1]);
|
||||
Vertex::set(newVertex, p2x, p2y);
|
||||
pushToVector(outputVertices, p2x, p2y);
|
||||
} else {
|
||||
float p1c1x = (p1x + c1x) * 0.5f;
|
||||
float p1c1y = (p1y + c1y) * 0.5f;
|
||||
@@ -463,10 +699,7 @@ void PathRenderer::recursiveQuadraticBezierVertices(
|
||||
|
||||
if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
|
||||
// below thresh, draw line by adding endpoint
|
||||
// TODO: make this not yuck
|
||||
outputVertices.push();
|
||||
Vertex* newVertex = &(outputVertices.editArray()[outputVertices.size() - 1]);
|
||||
Vertex::set(newVertex, bx, by);
|
||||
pushToVector(outputVertices, bx, by);
|
||||
} else {
|
||||
float acx = (ax + cx) * 0.5f;
|
||||
float bcx = (bx + cx) * 0.5f;
|
||||
|
||||
@@ -71,10 +71,8 @@ public:
|
||||
const mat4 *transform, VertexBuffer& vertexBuffer);
|
||||
|
||||
private:
|
||||
static void convexPathPerimeterVertices(
|
||||
const SkPath &path,
|
||||
float sqrInvScaleX, float sqrInvScaleY,
|
||||
Vector<Vertex> &outputVertices);
|
||||
static bool convexPathPerimeterVertices(const SkPath &path, bool forceClose,
|
||||
float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex> &outputVertices);
|
||||
|
||||
/*
|
||||
endpoints a & b,
|
||||
|
||||
Reference in New Issue
Block a user