LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkStrokerPriv.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 21 101 20.8 %
Date: 2017-07-14 16:53:18 Functions: 5 11 45.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13