LCOV - code coverage report
Current view: directory - gfx/skia/src/core - SkStrokerPriv.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 103 0 0.0 %
Date: 2012-06-02 Functions: 11 0 0.0 %

       1                 : 
       2                 : /*
       3                 :  * Copyright 2006 The Android Open Source Project
       4                 :  *
       5                 :  * Use of this source code is governed by a BSD-style license that can be
       6                 :  * found in the LICENSE file.
       7                 :  */
       8                 : 
       9                 : 
      10                 : #include "SkStrokerPriv.h"
      11                 : #include "SkGeometry.h"
      12                 : #include "SkPath.h"
      13                 : 
      14               0 : static void ButtCapper(SkPath* path, const SkPoint& pivot,
      15                 :                        const SkVector& normal, const SkPoint& stop,
      16                 :                        SkPath*)
      17                 : {
      18               0 :     path->lineTo(stop.fX, stop.fY);
      19               0 : }
      20                 : 
      21               0 : static void RoundCapper(SkPath* path, const SkPoint& pivot,
      22                 :                         const SkVector& normal, const SkPoint& stop,
      23                 :                         SkPath*)
      24                 : {
      25               0 :     SkScalar    px = pivot.fX;
      26               0 :     SkScalar    py = pivot.fY;
      27               0 :     SkScalar    nx = normal.fX;
      28               0 :     SkScalar    ny = normal.fY;
      29               0 :     SkScalar    sx = SkScalarMul(nx, CUBIC_ARC_FACTOR);
      30               0 :     SkScalar    sy = SkScalarMul(ny, CUBIC_ARC_FACTOR);
      31                 : 
      32                 :     path->cubicTo(px + nx + CWX(sx, sy), py + ny + CWY(sx, sy),
      33                 :                   px + CWX(nx, ny) + sx, py + CWY(nx, ny) + sy,
      34               0 :                   px + CWX(nx, ny), py + CWY(nx, ny));
      35                 :     path->cubicTo(px + CWX(nx, ny) - sx, py + CWY(nx, ny) - sy,
      36                 :                   px - nx + CWX(sx, sy), py - ny + CWY(sx, sy),
      37               0 :                   stop.fX, stop.fY);
      38               0 : }
      39                 : 
      40               0 : static void SquareCapper(SkPath* path, const SkPoint& pivot,
      41                 :                          const SkVector& normal, const SkPoint& stop,
      42                 :                          SkPath* otherPath)
      43                 : {
      44                 :     SkVector parallel;
      45               0 :     normal.rotateCW(&parallel);
      46                 : 
      47               0 :     if (otherPath)
      48                 :     {
      49               0 :         path->setLastPt(pivot.fX + normal.fX + parallel.fX, pivot.fY + normal.fY + parallel.fY);
      50               0 :         path->lineTo(pivot.fX - normal.fX + parallel.fX, pivot.fY - normal.fY + parallel.fY);
      51                 :     }
      52                 :     else
      53                 :     {
      54               0 :         path->lineTo(pivot.fX + normal.fX + parallel.fX, pivot.fY + normal.fY + parallel.fY);
      55               0 :         path->lineTo(pivot.fX - normal.fX + parallel.fX, pivot.fY - normal.fY + parallel.fY);
      56               0 :         path->lineTo(stop.fX, stop.fY);
      57                 :     }
      58               0 : }
      59                 : 
      60                 : /////////////////////////////////////////////////////////////////////////////
      61                 : 
      62               0 : static bool is_clockwise(const SkVector& before, const SkVector& after)
      63                 : {
      64               0 :     return SkScalarMul(before.fX, after.fY) - SkScalarMul(before.fY, after.fX) > 0;
      65                 : }
      66                 : 
      67                 : enum AngleType {
      68                 :     kNearly180_AngleType,
      69                 :     kSharp_AngleType,
      70                 :     kShallow_AngleType,
      71                 :     kNearlyLine_AngleType
      72                 : };
      73                 : 
      74               0 : static AngleType Dot2AngleType(SkScalar dot)
      75                 : {
      76                 : // need more precise fixed normalization
      77                 : //  SkASSERT(SkScalarAbs(dot) <= SK_Scalar1 + SK_ScalarNearlyZero);
      78                 : 
      79               0 :     if (dot >= 0)   // shallow or line
      80               0 :         return SkScalarNearlyZero(SK_Scalar1 - dot) ? kNearlyLine_AngleType : kShallow_AngleType;
      81                 :     else            // sharp or 180
      82               0 :         return SkScalarNearlyZero(SK_Scalar1 + dot) ? kNearly180_AngleType : kSharp_AngleType;
      83                 : }
      84                 : 
      85               0 : static void HandleInnerJoin(SkPath* inner, const SkPoint& pivot, const SkVector& after)
      86                 : {
      87                 : #if 1
      88                 :     /*  In the degenerate case that the stroke radius is larger than our segments
      89                 :         just connecting the two inner segments may "show through" as a funny
      90                 :         diagonal. To pseudo-fix this, we go through the pivot point. This adds
      91                 :         an extra point/edge, but I can't see a cheap way to know when this is
      92                 :         not needed :(
      93                 :     */
      94               0 :     inner->lineTo(pivot.fX, pivot.fY);
      95                 : #endif
      96                 : 
      97               0 :     inner->lineTo(pivot.fX - after.fX, pivot.fY - after.fY);
      98               0 : }
      99                 : 
     100               0 : static void BluntJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal,
     101                 :                         const SkPoint& pivot, const SkVector& afterUnitNormal,
     102                 :                         SkScalar radius, SkScalar invMiterLimit, bool, bool)
     103                 : {
     104                 :     SkVector    after;
     105               0 :     afterUnitNormal.scale(radius, &after);
     106                 : 
     107               0 :     if (!is_clockwise(beforeUnitNormal, afterUnitNormal))
     108                 :     {
     109               0 :         SkTSwap<SkPath*>(outer, inner);
     110               0 :         after.negate();
     111                 :     }
     112                 : 
     113               0 :     outer->lineTo(pivot.fX + after.fX, pivot.fY + after.fY);
     114               0 :     HandleInnerJoin(inner, pivot, after);
     115               0 : }
     116                 : 
     117               0 : static void RoundJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal,
     118                 :                         const SkPoint& pivot, const SkVector& afterUnitNormal,
     119                 :                         SkScalar radius, SkScalar invMiterLimit, bool, bool)
     120                 : {
     121               0 :     SkScalar    dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal);
     122               0 :     AngleType   angleType = Dot2AngleType(dotProd);
     123                 : 
     124               0 :     if (angleType == kNearlyLine_AngleType)
     125               0 :         return;
     126                 : 
     127               0 :     SkVector            before = beforeUnitNormal;
     128               0 :     SkVector            after = afterUnitNormal;
     129               0 :     SkRotationDirection dir = kCW_SkRotationDirection;
     130                 : 
     131               0 :     if (!is_clockwise(before, after))
     132                 :     {
     133               0 :         SkTSwap<SkPath*>(outer, inner);
     134               0 :         before.negate();
     135               0 :         after.negate();
     136               0 :         dir = kCCW_SkRotationDirection;
     137                 :     }
     138                 : 
     139                 :     SkPoint     pts[kSkBuildQuadArcStorage];
     140                 :     SkMatrix    matrix;
     141               0 :     matrix.setScale(radius, radius);
     142               0 :     matrix.postTranslate(pivot.fX, pivot.fY);
     143               0 :     int count = SkBuildQuadArc(before, after, dir, &matrix, pts);
     144               0 :     SkASSERT((count & 1) == 1);
     145                 : 
     146               0 :     if (count > 1)
     147                 :     {
     148               0 :         for (int i = 1; i < count; i += 2)
     149               0 :             outer->quadTo(pts[i].fX, pts[i].fY, pts[i+1].fX, pts[i+1].fY);
     150                 : 
     151               0 :         after.scale(radius);
     152               0 :         HandleInnerJoin(inner, pivot, after);
     153                 :     }
     154                 : }
     155                 : 
     156                 : #ifdef SK_SCALAR_IS_FLOAT
     157                 :     #define kOneOverSqrt2   (0.707106781f)
     158                 : #else
     159                 :     #define kOneOverSqrt2   (46341)
     160                 : #endif
     161                 : 
     162               0 : static void MiterJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal,
     163                 :                         const SkPoint& pivot, const SkVector& afterUnitNormal,
     164                 :                         SkScalar radius, SkScalar invMiterLimit,
     165                 :                         bool prevIsLine, bool currIsLine)
     166                 : {
     167                 :     // negate the dot since we're using normals instead of tangents
     168               0 :     SkScalar    dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal);
     169               0 :     AngleType   angleType = Dot2AngleType(dotProd);
     170               0 :     SkVector    before = beforeUnitNormal;
     171               0 :     SkVector    after = afterUnitNormal;
     172                 :     SkVector    mid;
     173                 :     SkScalar    sinHalfAngle;
     174                 :     bool        ccw;
     175                 : 
     176               0 :     if (angleType == kNearlyLine_AngleType)
     177               0 :         return;
     178               0 :     if (angleType == kNearly180_AngleType)
     179                 :     {
     180               0 :         currIsLine = false;
     181               0 :         goto DO_BLUNT;
     182                 :     }
     183                 :     
     184               0 :     ccw = !is_clockwise(before, after);
     185               0 :     if (ccw)
     186                 :     {
     187               0 :         SkTSwap<SkPath*>(outer, inner);
     188               0 :         before.negate();
     189               0 :         after.negate();
     190                 :     }
     191                 :     
     192                 :     /*  Before we enter the world of square-roots and divides,
     193                 :         check if we're trying to join an upright right angle
     194                 :         (common case for stroking rectangles). If so, special case
     195                 :         that (for speed an accuracy).
     196                 :         Note: we only need to check one normal if dot==0
     197                 :     */
     198               0 :     if (0 == dotProd && invMiterLimit <= kOneOverSqrt2)
     199                 :     {
     200                 :         mid.set(SkScalarMul(before.fX + after.fX, radius),
     201               0 :                 SkScalarMul(before.fY + after.fY, radius));
     202               0 :         goto DO_MITER;
     203                 :     }
     204                 : 
     205                 :     /*  midLength = radius / sinHalfAngle
     206                 :         if (midLength > miterLimit * radius) abort
     207                 :         if (radius / sinHalf > miterLimit * radius) abort
     208                 :         if (1 / sinHalf > miterLimit) abort
     209                 :         if (1 / miterLimit > sinHalf) abort
     210                 :         My dotProd is opposite sign, since it is built from normals and not tangents
     211                 :         hence 1 + dot instead of 1 - dot in the formula
     212                 :     */
     213               0 :     sinHalfAngle = SkScalarSqrt(SkScalarHalf(SK_Scalar1 + dotProd));
     214               0 :     if (sinHalfAngle < invMiterLimit)
     215                 :     {
     216               0 :         currIsLine = false;
     217               0 :         goto DO_BLUNT;
     218                 :     }
     219                 : 
     220                 :     // choose the most accurate way to form the initial mid-vector
     221               0 :     if (angleType == kSharp_AngleType)
     222                 :     {
     223               0 :         mid.set(after.fY - before.fY, before.fX - after.fX);
     224               0 :         if (ccw)
     225               0 :             mid.negate();
     226                 :     }
     227                 :     else
     228               0 :         mid.set(before.fX + after.fX, before.fY + after.fY);
     229                 : 
     230               0 :     mid.setLength(SkScalarDiv(radius, sinHalfAngle));
     231                 : DO_MITER:
     232               0 :     if (prevIsLine)
     233               0 :         outer->setLastPt(pivot.fX + mid.fX, pivot.fY + mid.fY);
     234                 :     else
     235               0 :         outer->lineTo(pivot.fX + mid.fX, pivot.fY + mid.fY);
     236                 : 
     237                 : DO_BLUNT:
     238               0 :     after.scale(radius);
     239               0 :     if (!currIsLine)
     240               0 :         outer->lineTo(pivot.fX + after.fX, pivot.fY + after.fY);
     241               0 :     HandleInnerJoin(inner, pivot, after);
     242                 : }
     243                 : 
     244                 : /////////////////////////////////////////////////////////////////////////////
     245                 : 
     246               0 : SkStrokerPriv::CapProc SkStrokerPriv::CapFactory(SkPaint::Cap cap)
     247                 : {
     248                 :     static const SkStrokerPriv::CapProc gCappers[] = {
     249                 :         ButtCapper, RoundCapper, SquareCapper
     250                 :     };
     251                 : 
     252               0 :     SkASSERT((unsigned)cap < SkPaint::kCapCount);
     253               0 :     return gCappers[cap];
     254                 : }
     255                 : 
     256               0 : SkStrokerPriv::JoinProc SkStrokerPriv::JoinFactory(SkPaint::Join join)
     257                 : {
     258                 :     static const SkStrokerPriv::JoinProc gJoiners[] = {
     259                 :         MiterJoiner, RoundJoiner, BluntJoiner
     260                 :     };
     261                 : 
     262               0 :     SkASSERT((unsigned)join < SkPaint::kJoinCount);
     263               0 :     return gJoiners[join];
     264                 : }
     265                 : 
     266                 : 
     267                 : 

Generated by: LCOV version 1.7