@@ -57,24 +57,34 @@ void computeInverseScales(const mat4 *transform, float &inverseScaleX, float& in
5757 float m11 = transform->data [Matrix4::kScaleY ];
5858 float scaleX = sqrt (m00 * m00 + m01 * m01);
5959 float scaleY = sqrt (m10 * m10 + m11 * m11);
60- inverseScaleX = (scaleX != 0 ) ? (1 .0f / scaleX) : 0 ;
61- inverseScaleY = (scaleY != 0 ) ? (1 .0f / scaleY) : 0 ;
60+ inverseScaleX = (scaleX != 0 ) ? (1 .0f / scaleX) : 1 . 0f ;
61+ inverseScaleY = (scaleY != 0 ) ? (1 .0f / scaleY) : 1 . 0f ;
6262 } else {
6363 inverseScaleX = 1 .0f ;
6464 inverseScaleY = 1 .0f ;
6565 }
6666}
6767
68- inline void copyVertex (Vertex* destPtr, const Vertex* srcPtr)
69- {
68+ inline void copyVertex (Vertex* destPtr, const Vertex* srcPtr) {
7069 Vertex::set (destPtr, srcPtr->position [0 ], srcPtr->position [1 ]);
7170}
7271
73- inline void copyAlphaVertex (AlphaVertex* destPtr, const AlphaVertex* srcPtr)
74- {
72+ inline void copyAlphaVertex (AlphaVertex* destPtr, const AlphaVertex* srcPtr) {
7573 AlphaVertex::set (destPtr, srcPtr->position [0 ], srcPtr->position [1 ], srcPtr->alpha );
7674}
7775
76+ /* *
77+ * Produces a pseudo-normal for a vertex, given the normals of the two incoming lines. If the offset
78+ * from each vertex in a perimeter is calculated, the resultant lines connecting the offset vertices
79+ * will be offset by 1.0
80+ *
81+ * Note that we can't add and normalize the two vectors, that would result in a rectangle having an
82+ * offset of (sqrt(2)/2, sqrt(2)/2) at each corner, instead of (1, 1)
83+ */
84+ inline vec2 totalOffsetFromNormals (const vec2& normalA, const vec2& normalB) {
85+ return (normalA + normalB) / (1 + fabs (normalA.dot (normalB)));
86+ }
87+
7888void getFillVerticesFromPerimeter (const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) {
7989 Vertex* buffer = vertexBuffer.alloc <Vertex>(perimeter.size ());
8090
@@ -108,9 +118,7 @@ void getStrokeVerticesFromPerimeter(const Vector<Vertex>& perimeter, float halfS
108118 current->position [0 ] - next->position [0 ]);
109119 nextNormal.normalize ();
110120
111- // offset each point by its normal, out and in, by appropriate stroke offset
112- vec2 totalOffset = (lastNormal + nextNormal);
113- totalOffset.normalize ();
121+ vec2 totalOffset = totalOffsetFromNormals (lastNormal, nextNormal);
114122 if (halfStrokeWidth == 0 .0f ) {
115123 // hairline - compensate for scale
116124 totalOffset.x *= 0 .5f * inverseScaleX;
@@ -155,12 +163,11 @@ void getFillVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, VertexBuffe
155163 current->position [0 ] - next->position [0 ]);
156164 nextNormal.normalize ();
157165
158- // AA point offset from original point is that point's normal, such that
159- // each side is offset by .5 pixels
160- vec2 totalOffset = (lastNormal + nextNormal);
161- totalOffset.normalize ();
162- totalOffset.x *= inverseScaleX * 0 .5f ;
163- totalOffset.y *= inverseScaleY * 0 .5f ;
166+ // AA point offset from original point is that point's normal, such that each side is offset
167+ // by .5 pixels
168+ vec2 totalOffset = totalOffsetFromNormals (lastNormal, nextNormal);
169+ totalOffset.x *= 0 .5f * inverseScaleX;
170+ totalOffset.y *= 0 .5f * inverseScaleY;
164171
165172 AlphaVertex::set (&buffer[currentIndex++],
166173 current->position [0 ] + totalOffset.x ,
@@ -204,6 +211,15 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal
204211 VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) {
205212 AlphaVertex* buffer = vertexBuffer.alloc <AlphaVertex>(6 * perimeter.size () + 8 );
206213
214+ // avoid lines smaller than hairline since they break triangle based sampling. instead reducing
215+ // alpha value (TODO: support different X/Y scale)
216+ float maxAlpha = 1 .0f ;
217+ if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
218+ halfStrokeWidth * inverseScaleX < 1 .0f ) {
219+ maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
220+ halfStrokeWidth = 0 .0f ;
221+ }
222+
207223 int offset = 2 * perimeter.size () + 3 ;
208224 int currentAAOuterIndex = 0 ;
209225 int currentStrokeIndex = offset;
@@ -220,13 +236,12 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal
220236 current->position [0 ] - next->position [0 ]);
221237 nextNormal.normalize ();
222238
223- vec2 pointNormal = (lastNormal + nextNormal);
224- pointNormal.normalize ();
225- vec2 AAOffset = pointNormal * 0 .5f ;
226- AAOffset.x *= inverseScaleX;
227- AAOffset.y *= inverseScaleY;
239+ vec2 totalOffset = totalOffsetFromNormals (lastNormal, nextNormal);
240+ vec2 AAOffset = totalOffset;
241+ AAOffset.x *= 0 .5f * inverseScaleX;
242+ AAOffset.y *= 0 .5f * inverseScaleY;
228243
229- vec2 innerOffset = pointNormal ;
244+ vec2 innerOffset = totalOffset ;
230245 if (halfStrokeWidth == 0 .0f ) {
231246 // hairline! - compensate for scale
232247 innerOffset.x *= 0 .5f * inverseScaleX;
@@ -244,27 +259,26 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal
244259 AlphaVertex::set (&buffer[currentAAOuterIndex++],
245260 current->position [0 ] + innerOffset.x ,
246261 current->position [1 ] + innerOffset.y ,
247- 1 . 0f );
262+ maxAlpha );
248263
249264 AlphaVertex::set (&buffer[currentStrokeIndex++],
250265 current->position [0 ] + innerOffset.x ,
251266 current->position [1 ] + innerOffset.y ,
252- 1 . 0f );
267+ maxAlpha );
253268 AlphaVertex::set (&buffer[currentStrokeIndex++],
254269 current->position [0 ] - innerOffset.x ,
255270 current->position [1 ] - innerOffset.y ,
256- 1 . 0f );
271+ maxAlpha );
257272
258273 AlphaVertex::set (&buffer[currentAAInnerIndex++],
259274 current->position [0 ] - innerOffset.x ,
260275 current->position [1 ] - innerOffset.y ,
261- 1 . 0f );
276+ maxAlpha );
262277 AlphaVertex::set (&buffer[currentAAInnerIndex++],
263278 current->position [0 ] - outerOffset.x ,
264279 current->position [1 ] - outerOffset.y ,
265280 0 .0f );
266281
267- // TODO: current = next, copy last normal instead of recalculate
268282 last = current;
269283 current = next;
270284 lastNormal = nextNormal;
@@ -295,8 +309,19 @@ void PathRenderer::convexPathVertices(const SkPath &path, const SkPaint* paint,
295309 computeInverseScales (transform, inverseScaleX, inverseScaleY);
296310
297311 Vector<Vertex> tempVertices;
298- convexPathPerimeterVertices (path, inverseScaleX * inverseScaleX, inverseScaleY * inverseScaleY,
299- tempVertices);
312+ float threshInvScaleX = inverseScaleX;
313+ float threshInvScaleY = inverseScaleY;
314+ if (style == SkPaint::kStroke_Style ) {
315+ // alter the bezier recursion threshold values we calculate in order to compensate for
316+ // expansion done after the path vertices are found
317+ SkRect bounds = path.getBounds ();
318+ if (!bounds.isEmpty ()) {
319+ threshInvScaleX *= bounds.width () / (bounds.width () + paint->getStrokeWidth ());
320+ threshInvScaleY *= bounds.height () / (bounds.height () + paint->getStrokeWidth ());
321+ }
322+ }
323+ convexPathPerimeterVertices (path, threshInvScaleX * threshInvScaleX,
324+ threshInvScaleY * threshInvScaleY, tempVertices);
300325
301326#if VERTEX_DEBUG
302327 for (unsigned int i = 0 ; i < tempVertices.size (); i++) {
0 commit comments