summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorChris Craik <ccraik@google.com>2012-09-27 13:10:56 -0700
committerChris Craik <ccraik@google.com>2012-09-27 15:01:36 -0700
commit16b897c488a740e004bfce7d50b0d7602277fc0b (patch)
treeb187612cdce8ef819f3cf1ac561fefdab6b2931d /libs
parent9a4a0376a78f9b3bcfe6374660fbe7c28797b36a (diff)
downloadframeworks_base-16b897c488a740e004bfce7d50b0d7602277fc0b.zip
frameworks_base-16b897c488a740e004bfce7d50b0d7602277fc0b.tar.gz
frameworks_base-16b897c488a740e004bfce7d50b0d7602277fc0b.tar.bz2
Fix rectangle AA offset calculation
bug:4419017 Fixes compiler warning Handle bezier thresholds with large stroke widths better Fix sub-hairlines (for scaleX == scaleY) Change-Id: Ida387483348ee61424b7fba729abca2a88bd68b3
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/Caches.h2
-rw-r--r--libs/hwui/PathRenderer.cpp81
2 files changed, 54 insertions, 29 deletions
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 9f28409..4c292b6 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -294,7 +294,7 @@ private:
GLuint mCurrentBuffer;
GLuint mCurrentIndicesBuffer;
void* mCurrentPositionPointer;
- GLuint mCurrentPositionStride;
+ GLsizei mCurrentPositionStride;
void* mCurrentTexCoordsPointer;
bool mTexCoordsArrayEnabled;
diff --git a/libs/hwui/PathRenderer.cpp b/libs/hwui/PathRenderer.cpp
index 6893f9d..4a66c62 100644
--- a/libs/hwui/PathRenderer.cpp
+++ b/libs/hwui/PathRenderer.cpp
@@ -57,24 +57,34 @@ void computeInverseScales(const mat4 *transform, float &inverseScaleX, float& in
float m11 = transform->data[Matrix4::kScaleY];
float scaleX = sqrt(m00 * m00 + m01 * m01);
float scaleY = sqrt(m10 * m10 + m11 * m11);
- inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 0;
- inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 0;
+ inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 1.0f;
+ inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 1.0f;
} else {
inverseScaleX = 1.0f;
inverseScaleY = 1.0f;
}
}
-inline void copyVertex(Vertex* destPtr, const Vertex* srcPtr)
-{
+inline void copyVertex(Vertex* destPtr, const Vertex* srcPtr) {
Vertex::set(destPtr, srcPtr->position[0], srcPtr->position[1]);
}
-inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr)
-{
+inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) {
AlphaVertex::set(destPtr, srcPtr->position[0], srcPtr->position[1], srcPtr->alpha);
}
+/**
+ * Produces a pseudo-normal for a vertex, given the normals of the two incoming lines. If the offset
+ * from each vertex in a perimeter is calculated, the resultant lines connecting the offset vertices
+ * will be offset by 1.0
+ *
+ * Note that we can't add and normalize the two vectors, that would result in a rectangle having an
+ * offset of (sqrt(2)/2, sqrt(2)/2) at each corner, instead of (1, 1)
+ */
+inline vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) {
+ return (normalA + normalB) / (1 + fabs(normalA.dot(normalB)));
+}
+
void getFillVerticesFromPerimeter(const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) {
Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size());
@@ -108,9 +118,7 @@ void getStrokeVerticesFromPerimeter(const Vector<Vertex>& perimeter, float halfS
current->position[0] - next->position[0]);
nextNormal.normalize();
- // offset each point by its normal, out and in, by appropriate stroke offset
- vec2 totalOffset = (lastNormal + nextNormal);
- totalOffset.normalize();
+ vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
if (halfStrokeWidth == 0.0f) {
// hairline - compensate for scale
totalOffset.x *= 0.5f * inverseScaleX;
@@ -155,12 +163,11 @@ void getFillVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, VertexBuffe
current->position[0] - next->position[0]);
nextNormal.normalize();
- // AA point offset from original point is that point's normal, such that
- // each side is offset by .5 pixels
- vec2 totalOffset = (lastNormal + nextNormal);
- totalOffset.normalize();
- totalOffset.x *= inverseScaleX * 0.5f;
- totalOffset.y *= inverseScaleY * 0.5f;
+ // AA point offset from original point is that point's normal, such that each side is offset
+ // by .5 pixels
+ vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
+ totalOffset.x *= 0.5f * inverseScaleX;
+ totalOffset.y *= 0.5f * inverseScaleY;
AlphaVertex::set(&buffer[currentIndex++],
current->position[0] + totalOffset.x,
@@ -204,6 +211,15 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal
VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) {
AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * perimeter.size() + 8);
+ // avoid lines smaller than hairline since they break triangle based sampling. instead reducing
+ // alpha value (TODO: support different X/Y scale)
+ float maxAlpha = 1.0f;
+ if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
+ halfStrokeWidth * inverseScaleX < 1.0f) {
+ maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
+ halfStrokeWidth = 0.0f;
+ }
+
int offset = 2 * perimeter.size() + 3;
int currentAAOuterIndex = 0;
int currentStrokeIndex = offset;
@@ -220,13 +236,12 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal
current->position[0] - next->position[0]);
nextNormal.normalize();
- vec2 pointNormal = (lastNormal + nextNormal);
- pointNormal.normalize();
- vec2 AAOffset = pointNormal * 0.5f;
- AAOffset.x *= inverseScaleX;
- AAOffset.y *= inverseScaleY;
+ vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
+ vec2 AAOffset = totalOffset;
+ AAOffset.x *= 0.5f * inverseScaleX;
+ AAOffset.y *= 0.5f * inverseScaleY;
- vec2 innerOffset = pointNormal;
+ vec2 innerOffset = totalOffset;
if (halfStrokeWidth == 0.0f) {
// hairline! - compensate for scale
innerOffset.x *= 0.5f * inverseScaleX;
@@ -244,27 +259,26 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal
AlphaVertex::set(&buffer[currentAAOuterIndex++],
current->position[0] + innerOffset.x,
current->position[1] + innerOffset.y,
- 1.0f);
+ maxAlpha);
AlphaVertex::set(&buffer[currentStrokeIndex++],
current->position[0] + innerOffset.x,
current->position[1] + innerOffset.y,
- 1.0f);
+ maxAlpha);
AlphaVertex::set(&buffer[currentStrokeIndex++],
current->position[0] - innerOffset.x,
current->position[1] - innerOffset.y,
- 1.0f);
+ maxAlpha);
AlphaVertex::set(&buffer[currentAAInnerIndex++],
current->position[0] - innerOffset.x,
current->position[1] - innerOffset.y,
- 1.0f);
+ maxAlpha);
AlphaVertex::set(&buffer[currentAAInnerIndex++],
current->position[0] - outerOffset.x,
current->position[1] - outerOffset.y,
0.0f);
- // TODO: current = next, copy last normal instead of recalculate
last = current;
current = next;
lastNormal = nextNormal;
@@ -295,8 +309,19 @@ void PathRenderer::convexPathVertices(const SkPath &path, const SkPaint* paint,
computeInverseScales(transform, inverseScaleX, inverseScaleY);
Vector<Vertex> tempVertices;
- convexPathPerimeterVertices(path, inverseScaleX * inverseScaleX, inverseScaleY * inverseScaleY,
- tempVertices);
+ float threshInvScaleX = inverseScaleX;
+ float threshInvScaleY = inverseScaleY;
+ if (style == SkPaint::kStroke_Style) {
+ // alter the bezier recursion threshold values we calculate in order to compensate for
+ // expansion done after the path vertices are found
+ SkRect bounds = path.getBounds();
+ if (!bounds.isEmpty()) {
+ threshInvScaleX *= bounds.width() / (bounds.width() + paint->getStrokeWidth());
+ threshInvScaleY *= bounds.height() / (bounds.height() + paint->getStrokeWidth());
+ }
+ }
+ convexPathPerimeterVertices(path, threshInvScaleX * threshInvScaleX,
+ threshInvScaleY * threshInvScaleY, tempVertices);
#if VERTEX_DEBUG
for (unsigned int i = 0; i < tempVertices.size(); i++) {