The 'global isinf/isnan' compiler quirk required when using clang with libstdc++
[WebKit.git] / Source / WebCore / platform / graphics / gpu / LoopBlinnMathUtils.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if USE(ACCELERATED_COMPOSITING) || ENABLE(ACCELERATED_2D_CANVAS)
29
30 #include "LoopBlinnMathUtils.h"
31
32 #include "FloatPoint.h"
33 #include <algorithm>
34 #include <wtf/MathExtras.h>
35
36 namespace WebCore {
37 namespace LoopBlinnMathUtils {
38
39 namespace {
40
41 // Utility functions local to this file.
42 int orientation(const FloatPoint& p1,
43                 const FloatPoint& p2,
44                 const FloatPoint& p3)
45 {
46     float crossProduct = (p2.y() - p1.y()) * (p3.x() - p2.x()) - (p3.y() - p2.y()) * (p2.x() - p1.x());
47     return (crossProduct < 0.0f) ? -1 : ((crossProduct > 0.0f) ? 1 : 0);
48 }
49
50 bool edgeEdgeTest(const FloatSize& v0Delta,
51                   const FloatPoint& v0,
52                   const FloatPoint& u0,
53                   const FloatPoint& u1)
54 {
55     // This edge to edge test is based on Franlin Antonio's gem: "Faster
56     // Line Segment Intersection", in Graphics Gems III, pp. 199-202.
57     float ax = v0Delta.width();
58     float ay = v0Delta.height();
59     float bx = u0.x() - u1.x();
60     float by = u0.y() - u1.y();
61     float cx = v0.x() - u0.x();
62     float cy = v0.y() - u0.y();
63     float f = ay * bx - ax * by;
64     float d = by * cx - bx * cy;
65     if ((f > 0 && d >= 0 && d <= f) || (f < 0 && d <= 0 && d >= f)) {
66         float e = ax * cy - ay * cx;
67
68         // This additional test avoids reporting coincident edges, which
69         // is the behavior we want.
70         if (approxEqual(e, 0) || approxEqual(f, 0) || approxEqual(e, f))
71             return false;
72
73         if (f > 0)
74             return e >= 0 && e <= f;
75
76         return e <= 0 && e >= f;
77     }
78     return false;
79 }
80
81 bool edgeAgainstTriangleEdges(const FloatPoint& v0,
82                               const FloatPoint& v1,
83                               const FloatPoint& u0,
84                               const FloatPoint& u1,
85                               const FloatPoint& u2)
86 {
87     FloatSize delta = v1 - v0;
88     // Test edge u0, u1 against v0, v1.
89     if (edgeEdgeTest(delta, v0, u0, u1))
90         return true;
91     // Test edge u1, u2 against v0, v1.
92     if (edgeEdgeTest(delta, v0, u1, u2))
93         return true;
94     // Test edge u2, u1 against v0, v1.
95     if (edgeEdgeTest(delta, v0, u2, u0))
96         return true;
97     return false;
98 }
99
100 // A roundoff factor in the cubic classification and texture coordinate
101 // generation algorithms. It primarily determines the handling of corner
102 // cases during the classification process. Be careful when adjusting it;
103 // it has been determined empirically to work well. When changing it, you
104 // should look in particular at shapes that contain quadratic curves and
105 // ensure they still look smooth. Once pixel tests are running against this
106 // algorithm, they should provide sufficient coverage to ensure that
107 // adjusting the constant won't break anything.
108 const float Epsilon = 5.0e-4f;
109
110 } // anonymous namespace
111
112 // Exported routines
113
114 float roundToZero(float val)
115 {
116     if (val < Epsilon && val > -Epsilon)
117         return 0;
118     return val;
119 }
120
121 bool approxEqual(const FloatPoint& v0, const FloatPoint& v1)
122 {
123     return (v0 - v1).diagonalLengthSquared() < Epsilon * Epsilon;
124 }
125
126 bool approxEqual(const FloatPoint3D& v0, const FloatPoint3D& v1)
127 {
128     return (v0 - v1).lengthSquared() < Epsilon * Epsilon;
129 }
130
131 bool approxEqual(float f0, float f1)
132 {
133     return fabsf(f0 - f1) < Epsilon;
134 }
135
136 bool linesIntersect(const FloatPoint& p1,
137                     const FloatPoint& q1,
138                     const FloatPoint& p2,
139                     const FloatPoint& q2)
140 {
141     return (orientation(p1, q1, p2) != orientation(p1, q1, q2)
142             && orientation(p2, q2, p1) != orientation(p2, q2, q1));
143 }
144
145 bool pointInTriangle(const FloatPoint& point,
146                      const FloatPoint& a,
147                      const FloatPoint& b,
148                      const FloatPoint& c)
149 {
150     // Algorithm from http://www.blackpawn.com/texts/pointinpoly/default.html
151     float x0 = c.x() - a.x();
152     float y0 = c.y() - a.y();
153     float x1 = b.x() - a.x();
154     float y1 = b.y() - a.y();
155     float x2 = point.x() - a.x();
156     float y2 = point.y() - a.y();
157
158     float dot00 = x0 * x0 + y0 * y0;
159     float dot01 = x0 * x1 + y0 * y1;
160     float dot02 = x0 * x2 + y0 * y2;
161     float dot11 = x1 * x1 + y1 * y1;
162     float dot12 = x1 * x2 + y1 * y2;
163     float denominator = dot00 * dot11 - dot01 * dot01;
164     if (!denominator)
165         // Triangle is zero-area. Treat query point as not being inside.
166         return false;
167     // Compute
168     float inverseDenominator = 1.0f / denominator;
169     float u = (dot11 * dot02 - dot01 * dot12) * inverseDenominator;
170     float v = (dot00 * dot12 - dot01 * dot02) * inverseDenominator;
171
172     return (u > 0.0f) && (v > 0.0f) && (u + v < 1.0f);
173 }
174
175 bool trianglesOverlap(const FloatPoint& a1,
176                       const FloatPoint& b1,
177                       const FloatPoint& c1,
178                       const FloatPoint& a2,
179                       const FloatPoint& b2,
180                       const FloatPoint& c2)
181 {
182     // Derived from coplanar_tri_tri() at
183     // http://jgt.akpeters.com/papers/ShenHengTang03/tri_tri.html ,
184     // simplified for the 2D case and modified so that overlapping edges
185     // do not report overlapping triangles.
186
187     // Test all edges of triangle 1 against the edges of triangle 2.
188     if (edgeAgainstTriangleEdges(a1, b1, a2, b2, c2)
189         || edgeAgainstTriangleEdges(b1, c1, a2, b2, c2)
190         || edgeAgainstTriangleEdges(c1, a1, a2, b2, c2))
191         return true;
192     // Finally, test if tri1 is totally contained in tri2 or vice versa.
193     // The paper above only performs the first two point-in-triangle tests.
194     // Because we define that triangles sharing a vertex or edge don't
195     // overlap, we must perform additional tests to see whether one
196     // triangle is contained in the other.
197     if (pointInTriangle(a1, a2, b2, c2)
198         || pointInTriangle(a2, a1, b1, c1)
199         || pointInTriangle(b1, a2, b2, c2)
200         || pointInTriangle(b2, a1, b1, c1)
201         || pointInTriangle(c1, a2, b2, c2)
202         || pointInTriangle(c2, a1, b1, c1))
203         return true;
204     return false;
205 }
206
207 namespace {
208
209 // Helper routines for public XRay queries below. All of this code
210 // originated in Skia; see include/core/ and src/core/, SkScalar.h and
211 // SkGeometry.{cpp,h}.
212
213 const float NearlyZeroConstant = (1.0f / (1 << 12));
214
215 bool nearlyZero(float x, float tolerance = NearlyZeroConstant)
216 {
217     ASSERT(tolerance > 0.0f);
218     return ::fabsf(x) < tolerance;
219 }
220
221 // Linearly interpolate between a and b, based on t.
222 // If t is 0, return a; if t is 1, return b; else interpolate.
223 // t must be [0..1].
224 float interpolate(float a, float b, float t)
225 {
226     ASSERT(t >= 0 && t <= 1);
227     return a + (b - a) * t;
228 }
229
230 float evaluateCubic(float controlPoint0, float controlPoint1, float controlPoint2, float controlPoint3, float t)
231 {
232     ASSERT(t >= 0 && t <= 1);
233
234     if (!t)
235         return controlPoint0;
236
237     float ab = interpolate(controlPoint0, controlPoint1, t);
238     float bc = interpolate(controlPoint1, controlPoint2, t);
239     float cd = interpolate(controlPoint2, controlPoint3, t);
240     float abc = interpolate(ab, bc, t);
241     float bcd = interpolate(bc, cd, t);
242     return interpolate(abc, bcd, t);
243 }
244
245 // Evaluates the point on the source cubic specified by t, 0 <= t <= 1.0.
246 FloatPoint evaluateCubicAt(const FloatPoint cubic[4], float t)
247 {
248     return FloatPoint(evaluateCubic(cubic[0].x(), cubic[1].x(), cubic[2].x(), cubic[3].x(), t),
249                       evaluateCubic(cubic[0].y(), cubic[1].y(), cubic[2].y(), cubic[3].y(), t));
250 }
251
252 bool xRayCrossesMonotonicCubic(const XRay& xRay, const FloatPoint cubic[4], bool& ambiguous)
253 {
254     ambiguous = false;
255
256     // Find the minimum and maximum y of the extrema, which are the
257     // first and last points since this cubic is monotonic
258     float minY = std::min(cubic[0].y(), cubic[3].y());
259     float maxY = std::max(cubic[0].y(), cubic[3].y());
260
261     if (xRay.y() == cubic[0].y()
262         || xRay.y() < minY
263         || xRay.y() > maxY) {
264         // The query line definitely does not cross the curve
265         ambiguous = (xRay.y() == cubic[0].y());
266         return false;
267     }
268
269     const bool pointAtExtremum = (xRay.y() == cubic[3].y());
270
271     float minX = std::min(std::min(std::min(cubic[0].x(), cubic[1].x()),
272                                    cubic[2].x()),
273                           cubic[3].x());
274     if (xRay.x() < minX) {
275         // The query line definitely crosses the curve
276         ambiguous = pointAtExtremum;
277         return true;
278     }
279
280     float maxX = std::max(std::max(std::max(cubic[0].x(), cubic[1].x()),
281                                    cubic[2].x()),
282                           cubic[3].x());
283     if (xRay.x() > maxX)
284         // The query line definitely does not cross the curve
285         return false;
286
287     // Do a binary search to find the parameter value which makes y as
288     // close as possible to the query point. See whether the query
289     // line's origin is to the left of the associated x coordinate.
290
291     // MaxIterations is chosen as the number of mantissa bits for a float,
292     // since there's no way we are going to get more precision by
293     // iterating more times than that.
294     const int MaxIterations = 23;
295     FloatPoint evaluatedPoint;
296     int iter = 0;
297     float upperT;
298     float lowerT;
299     // Need to invert direction of t parameter if cubic goes up
300     // instead of down
301     if (cubic[3].y() > cubic[0].y()) {
302         upperT = 1;
303         lowerT = 0;
304     } else {
305         upperT = 0;
306         lowerT = 1;
307     }
308     do {
309         float t = 0.5f * (upperT + lowerT);
310         evaluatedPoint = evaluateCubicAt(cubic, t);
311         if (xRay.y() > evaluatedPoint.y())
312             lowerT = t;
313         else
314             upperT = t;
315     } while (++iter < MaxIterations && !nearlyZero(evaluatedPoint.y() - xRay.y()));
316
317     // FIXME: once we have more regression tests for this code,
318     // determine whether this should be using a fuzzy test.
319     if (xRay.x() <= evaluatedPoint.x()) {
320         ambiguous = pointAtExtremum;
321         return true;
322     }
323     return false;
324 }
325
326 // Divides the numerator by the denominator safely for the case where
327 // the result must lie in the range (0..1). Result indicates whether
328 // the result is valid.
329 bool safeUnitDivide(float numerator, float denominator, float& ratio)
330 {
331     if (numerator < 0) {
332         // Make the "numerator >= denominator" check below work.
333         numerator = -numerator;
334         denominator = -denominator;
335     }
336     if (!numerator || !denominator || numerator >= denominator)
337         return false;
338     float r = numerator / denominator;
339     if (std::isnan(r))
340         return false;
341     ASSERT(r >= 0 && r < 1);
342     if (!r) // catch underflow if numerator <<<< denominator
343         return false;
344     ratio = r;
345     return true;
346 }
347
348 // From Numerical Recipes in C.
349 //
350 //   q = -1/2 (b + sign(b) sqrt[b*b - 4*a*c])
351 //   x1 = q / a
352 //   x2 = c / q
353 //
354 // Returns the number of real roots of the equation [0..2]. Roots are
355 // returned in sorted order, smaller root first.
356 int findUnitQuadRoots(float a, float b, float c, float roots[2])
357 {
358     if (!a)
359         return safeUnitDivide(-c, b, roots[0]) ? 1 : 0;
360
361     float discriminant = b*b - 4*a*c;
362     if (discriminant < 0 || std::isnan(discriminant)) // complex roots
363         return 0;
364     discriminant = sqrtf(discriminant);
365
366     float q = (b < 0) ? -(b - discriminant) / 2 : -(b + discriminant) / 2;
367     int numberOfRoots = 0;
368     if (safeUnitDivide(q, a, roots[numberOfRoots]))
369         ++numberOfRoots;
370     if (safeUnitDivide(c, q, roots[numberOfRoots]))
371         ++numberOfRoots;
372     if (numberOfRoots == 2) {
373         // Seemingly have two roots. Check for equality and sort.
374         if (roots[0] == roots[1])
375             return 1;
376         if (roots[0] > roots[1])
377             std::swap(roots[0], roots[1]);
378     }
379     return numberOfRoots;
380 }
381
382 // Cubic'(t) = pt^2 + qt + r, where
383 //   p = 3(-a + 3(b - c) + d)
384 //   q = 6(a - 2b + c)
385 //   r = 3(b - a)
386 // Solve for t, keeping only those that fit between 0 < t < 1.
387 int findCubicExtrema(float a, float b, float c, float d, float tValues[2])
388 {
389     // Divide p, q, and r by 3 to simplify the equations.
390     float p = d - a + 3*(b - c);
391     float q = 2*(a - b - b + c);
392     float r = b - a;
393
394     return findUnitQuadRoots(p, q, r, tValues);
395 }
396
397 void interpolateCubicCoords(float controlPoint0, float controlPoint1, float controlPoint2, float controlPoint3, float* dst, float t)
398 {
399     float ab = interpolate(controlPoint0, controlPoint1, t);
400     float bc = interpolate(controlPoint1, controlPoint2, t);
401     float cd = interpolate(controlPoint2, controlPoint3, t);
402     float abc = interpolate(ab, bc, t);
403     float bcd = interpolate(bc, cd, t);
404     float abcd = interpolate(abc, bcd, t);
405
406     dst[0] = controlPoint0;
407     dst[2] = ab;
408     dst[4] = abc;
409     dst[6] = abcd;
410     dst[8] = bcd;
411     dst[10] = cd;
412     dst[12] = controlPoint3;
413 }
414
415 #ifndef NDEBUG
416 bool isUnitInterval(float x)
417 {
418     return x > 0 && x < 1;
419 }
420 #endif
421
422 void chopCubicAtTValues(const FloatPoint src[4], FloatPoint dst[], const float tValues[], int roots)
423 {
424 #ifndef NDEBUG
425     for (int i = 0; i < roots - 1; ++i) {
426         ASSERT(isUnitInterval(tValues[i]));
427         ASSERT(isUnitInterval(tValues[i+1]));
428         ASSERT(tValues[i] < tValues[i+1]);
429     }
430 #endif
431
432     if (!roots) {
433         // nothing to chop
434         for (int j = 0; j < 4; ++j)
435             dst[j] = src[j];
436         return;
437     }
438
439     float t = tValues[0];
440     FloatPoint tmp[4];
441     for (int j = 0; j < 4; ++j)
442         tmp[j] = src[j];
443
444     for (int i = 0; i < roots; ++i) {
445         chopCubicAt(tmp, dst, t);
446         if (i == roots - 1)
447             break;
448
449         dst += 3;
450         // Make tmp contain the remaining cubic (after the first chop).
451         for (int j = 0; j < 4; ++j)
452             tmp[j] = dst[j];
453
454         // Watch out for the case that the renormalized t isn't in range.
455         if (!safeUnitDivide(tValues[i+1] - tValues[i], 1.0f - tValues[i], t)) {
456             // If it isn't, just create a degenerate cubic.
457             dst[4] = dst[5] = dst[6] = tmp[3];
458             break;
459         }
460     }
461 }
462
463 void flattenDoubleCubicYExtrema(FloatPoint coords[7])
464 {
465     coords[2].setY(coords[3].y());
466     coords[4].setY(coords[3].y());
467 }
468
469 int chopCubicAtYExtrema(const FloatPoint src[4], FloatPoint dst[10])
470 {
471     float tValues[2];
472     int roots = findCubicExtrema(src[0].y(), src[1].y(), src[2].y(), src[3].y(), tValues);
473
474     chopCubicAtTValues(src, dst, tValues, roots);
475     if (roots) {
476         // we do some cleanup to ensure our Y extrema are flat
477         flattenDoubleCubicYExtrema(&dst[0]);
478         if (roots == 2)
479             flattenDoubleCubicYExtrema(&dst[3]);
480     }
481     return roots;
482 }
483
484 } // anonymous namespace
485
486 // Public cubic operations.
487
488 void chopCubicAt(const FloatPoint src[4], FloatPoint dst[7], float t)
489 {
490     ASSERT(t >= 0 && t <= 1);
491
492     float output[14];
493     interpolateCubicCoords(src[0].x(), src[1].x(), src[2].x(), src[3].x(), &output[0], t);
494     interpolateCubicCoords(src[0].y(), src[1].y(), src[2].y(), src[3].y(), &output[1], t);
495     for (int i = 0; i < 7; i++)
496         dst[i].set(output[2 * i], output[2 * i + 1]);
497 }
498
499 // Public XRay queries.
500
501 bool xRayCrossesLine(const XRay& xRay, const FloatPoint pts[2], bool& ambiguous)
502 {
503     ambiguous = false;
504
505     // Determine quick discards.
506     // Consider query line going exactly through point 0 to not
507     // intersect, for symmetry with xRayCrossesMonotonicCubic.
508     if (xRay.y() == pts[0].y()) {
509         ambiguous = true;
510         return false;
511     }
512     if (xRay.y() < pts[0].y() && xRay.y() < pts[1].y())
513         return false;
514     if (xRay.y() > pts[0].y() && xRay.y() > pts[1].y())
515         return false;
516     if (xRay.x() > pts[0].x() && xRay.x() > pts[1].x())
517         return false;
518     // Determine degenerate cases
519     if (nearlyZero(pts[0].y() - pts[1].y()))
520         return false;
521     if (nearlyZero(pts[0].x() - pts[1].x())) {
522         // We've already determined the query point lies within the
523         // vertical range of the line segment.
524         if (xRay.x() <= pts[0].x()) {
525             ambiguous = (xRay.y() == pts[1].y());
526             return true;
527         }
528         return false;
529     }
530     // Ambiguity check
531     if (xRay.y() == pts[1].y()) {
532         if (xRay.x() <= pts[1].x()) {
533             ambiguous = true;
534             return true;
535         }
536         return false;
537     }
538     // Full line segment evaluation
539     float deltaY = pts[1].y() - pts[0].y();
540     float deltaX = pts[1].x() - pts[0].x();
541     float slope = deltaY / deltaX;
542     float b = pts[0].y() - slope * pts[0].x();
543     // Solve for x coordinate at y = xRay.y()
544     float x = (xRay.y() - b) / slope;
545     return xRay.x() <= x;
546 }
547
548 int numXRayCrossingsForCubic(const XRay& xRay, const FloatPoint cubic[4], bool& ambiguous)
549 {
550     int numCrossings = 0;
551     FloatPoint monotonicCubics[10];
552     int numMonotonicCubics = 1 + chopCubicAtYExtrema(cubic, monotonicCubics);
553     ambiguous = false;
554     FloatPoint* monotonicCubicsPointer = &monotonicCubics[0];
555     for (int i = 0; i < numMonotonicCubics; ++i) {
556         if (xRayCrossesMonotonicCubic(xRay, monotonicCubicsPointer, ambiguous))
557             ++numCrossings;
558         if (ambiguous)
559             return 0;
560         monotonicCubicsPointer += 3;
561     }
562     return numCrossings;
563 }
564
565 /*
566  * Based on C code from the article
567  * "Testing the Convexity of a Polygon"
568  * by Peter Schorn and Frederick Fisher,
569  * (schorn@inf.ethz.ch, fred@kpc.com)
570  * in "Graphics Gems IV", Academic Press, 1994
571  */
572
573 static inline int convexCompare(const FloatSize& delta)
574 {
575     return (delta.width() > 0) ? -1 : /* x coord diff, second pt > first pt */
576            (delta.width() < 0) ?  1 : /* x coord diff, second pt < first pt */
577            (delta.height() > 0) ? -1 : /* x coord same, second pt > first pt */
578            (delta.height() < 0) ?  1 : /* x coord same, second pt > first pt */
579            0; /* second pt equals first point */
580 }
581
582 static inline float convexCross(const FloatSize& p, const FloatSize& q)
583 {
584     return p.width() * q.height() - p.height() * q.width();
585 }
586
587 static inline bool convexCheckTriple(const FloatSize& dcur, const FloatSize& dprev, int* curDir, int* dirChanges, int* angleSign)
588 {
589     int thisDir = convexCompare(dcur);
590     if (thisDir == -*curDir)
591         ++*dirChanges;
592     *curDir = thisDir;
593     float cross = convexCross(dprev, dcur);
594     if (cross > 0) {
595         if (*angleSign == -1)
596             return false;
597         *angleSign = 1;
598     } else if (cross < 0) {
599         if (*angleSign == 1)
600             return false;
601         *angleSign = -1;
602     }
603     return true;
604 }
605
606 bool isConvex(const FloatPoint* vertices, int nVertices)
607 {
608     int dirChanges = 0, angleSign = 0;
609     FloatPoint second, third;
610     FloatSize dprev, dcur;
611
612     /* Get different point, return if less than 3 diff points. */
613     if (nVertices < 3)
614         return false;
615     int i = 1;
616     while (true) {
617         second = vertices[i++];
618         dprev = second - vertices[0];
619         if (dprev.width() || dprev.height())
620             break;
621         /* Check if out of points. Check here to avoid slowing down cases
622          * without repeated points.
623          */
624         if (i >= nVertices)
625             return false;
626     }
627     FloatPoint saveSecond = second;
628     int curDir = convexCompare(dprev);        /* Find initial direction */
629     while (i < nVertices) {
630         /* Get different point, break if no more points */
631         third = vertices[i++];
632         dcur = third - second;
633         if (!dcur.width() && !dcur.height())
634             continue;
635
636         /* Check current three points */
637         if (!convexCheckTriple(dcur, dprev, &curDir, &dirChanges, &angleSign)) 
638             return false;
639         second = third;     /* Remember ptr to current point. */
640         dprev = dcur;       /* Remember current delta. */
641     }
642
643     /* Must check for direction changes from last vertex back to first */
644     third = vertices[0];                  /* Prepare for 'ConvexCheckTriple' */
645     dcur = third - second;
646     if (convexCompare(dcur)) {
647         if (!convexCheckTriple(dcur, dprev, &curDir, &dirChanges, &angleSign)) 
648             return false;
649         second = third;     /* Remember ptr to current point. */
650         dprev = dcur;       /* Remember current delta. */
651     }
652
653     /* and check for direction changes back to second vertex */
654     dcur = saveSecond - second;
655     if (!convexCheckTriple(dcur, dprev, &curDir, &dirChanges, &angleSign)) 
656         return false;
657
658     /* Decide on polygon type given accumulated status */
659     if (dirChanges > 2)
660         return false;
661
662     if (angleSign > 0 || angleSign < 0)
663         return true;
664     return false;
665 }
666
667 } // namespace LoopBlinnMathUtils
668 } // namespace WebCore
669
670 #endif