gfx/skia/trunk/src/core/SkPathMeasure.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     2 /*
     3  * Copyright 2008 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  */
    10 #include "SkPathMeasure.h"
    11 #include "SkGeometry.h"
    12 #include "SkPath.h"
    13 #include "SkTSearch.h"
    15 // these must be 0,1,2 since they are in our 2-bit field
    16 enum {
    17     kLine_SegType,
    18     kQuad_SegType,
    19     kCubic_SegType
    20 };
    22 #define kMaxTValue  32767
    24 static inline SkScalar tValue2Scalar(int t) {
    25     SkASSERT((unsigned)t <= kMaxTValue);
    26     return t * 3.05185e-5f; // t / 32767
    27 }
    29 SkScalar SkPathMeasure::Segment::getScalarT() const {
    30     return tValue2Scalar(fTValue);
    31 }
    33 const SkPathMeasure::Segment* SkPathMeasure::NextSegment(const Segment* seg) {
    34     unsigned ptIndex = seg->fPtIndex;
    36     do {
    37         ++seg;
    38     } while (seg->fPtIndex == ptIndex);
    39     return seg;
    40 }
    42 ///////////////////////////////////////////////////////////////////////////////
    44 static inline int tspan_big_enough(int tspan) {
    45     SkASSERT((unsigned)tspan <= kMaxTValue);
    46     return tspan >> 10;
    47 }
    49 // can't use tangents, since we need [0..1..................2] to be seen
    50 // as definitely not a line (it is when drawn, but not parametrically)
    51 // so we compare midpoints
    52 #define CHEAP_DIST_LIMIT    (SK_Scalar1/2)  // just made this value up
    54 static bool quad_too_curvy(const SkPoint pts[3]) {
    55     // diff = (a/4 + b/2 + c/4) - (a/2 + c/2)
    56     // diff = -a/4 + b/2 - c/4
    57     SkScalar dx = SkScalarHalf(pts[1].fX) -
    58                         SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX));
    59     SkScalar dy = SkScalarHalf(pts[1].fY) -
    60                         SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY));
    62     SkScalar dist = SkMaxScalar(SkScalarAbs(dx), SkScalarAbs(dy));
    63     return dist > CHEAP_DIST_LIMIT;
    64 }
    66 static bool cheap_dist_exceeds_limit(const SkPoint& pt,
    67                                      SkScalar x, SkScalar y) {
    68     SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY));
    69     // just made up the 1/2
    70     return dist > CHEAP_DIST_LIMIT;
    71 }
    73 static bool cubic_too_curvy(const SkPoint pts[4]) {
    74     return  cheap_dist_exceeds_limit(pts[1],
    75                          SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3),
    76                          SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3))
    77                          ||
    78             cheap_dist_exceeds_limit(pts[2],
    79                          SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3),
    80                          SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3));
    81 }
    83 SkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3],
    84                           SkScalar distance, int mint, int maxt, int ptIndex) {
    85     if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) {
    86         SkPoint tmp[5];
    87         int     halft = (mint + maxt) >> 1;
    89         SkChopQuadAtHalf(pts, tmp);
    90         distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex);
    91         distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptIndex);
    92     } else {
    93         SkScalar d = SkPoint::Distance(pts[0], pts[2]);
    94         SkScalar prevD = distance;
    95         distance += d;
    96         if (distance > prevD) {
    97             Segment* seg = fSegments.append();
    98             seg->fDistance = distance;
    99             seg->fPtIndex = ptIndex;
   100             seg->fType = kQuad_SegType;
   101             seg->fTValue = maxt;
   102         }
   103     }
   104     return distance;
   105 }
   107 SkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4],
   108                            SkScalar distance, int mint, int maxt, int ptIndex) {
   109     if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) {
   110         SkPoint tmp[7];
   111         int     halft = (mint + maxt) >> 1;
   113         SkChopCubicAtHalf(pts, tmp);
   114         distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex);
   115         distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIndex);
   116     } else {
   117         SkScalar d = SkPoint::Distance(pts[0], pts[3]);
   118         SkScalar prevD = distance;
   119         distance += d;
   120         if (distance > prevD) {
   121             Segment* seg = fSegments.append();
   122             seg->fDistance = distance;
   123             seg->fPtIndex = ptIndex;
   124             seg->fType = kCubic_SegType;
   125             seg->fTValue = maxt;
   126         }
   127     }
   128     return distance;
   129 }
   131 void SkPathMeasure::buildSegments() {
   132     SkPoint         pts[4];
   133     int             ptIndex = fFirstPtIndex;
   134     SkScalar        distance = 0;
   135     bool            isClosed = fForceClosed;
   136     bool            firstMoveTo = ptIndex < 0;
   137     Segment*        seg;
   139     /*  Note:
   140      *  as we accumulate distance, we have to check that the result of +=
   141      *  actually made it larger, since a very small delta might be > 0, but
   142      *  still have no effect on distance (if distance >>> delta).
   143      *
   144      *  We do this check below, and in compute_quad_segs and compute_cubic_segs
   145      */
   146     fSegments.reset();
   147     bool done = false;
   148     do {
   149         switch (fIter.next(pts)) {
   150             case SkPath::kConic_Verb:
   151                 SkASSERT(0);
   152                 break;
   153             case SkPath::kMove_Verb:
   154                 ptIndex += 1;
   155                 fPts.append(1, pts);
   156                 if (!firstMoveTo) {
   157                     done = true;
   158                     break;
   159                 }
   160                 firstMoveTo = false;
   161                 break;
   163             case SkPath::kLine_Verb: {
   164                 SkScalar d = SkPoint::Distance(pts[0], pts[1]);
   165                 SkASSERT(d >= 0);
   166                 SkScalar prevD = distance;
   167                 distance += d;
   168                 if (distance > prevD) {
   169                     seg = fSegments.append();
   170                     seg->fDistance = distance;
   171                     seg->fPtIndex = ptIndex;
   172                     seg->fType = kLine_SegType;
   173                     seg->fTValue = kMaxTValue;
   174                     fPts.append(1, pts + 1);
   175                     ptIndex++;
   176                 }
   177             } break;
   179             case SkPath::kQuad_Verb: {
   180                 SkScalar prevD = distance;
   181                 distance = this->compute_quad_segs(pts, distance, 0,
   182                                                    kMaxTValue, ptIndex);
   183                 if (distance > prevD) {
   184                     fPts.append(2, pts + 1);
   185                     ptIndex += 2;
   186                 }
   187             } break;
   189             case SkPath::kCubic_Verb: {
   190                 SkScalar prevD = distance;
   191                 distance = this->compute_cubic_segs(pts, distance, 0,
   192                                                     kMaxTValue, ptIndex);
   193                 if (distance > prevD) {
   194                     fPts.append(3, pts + 1);
   195                     ptIndex += 3;
   196                 }
   197             } break;
   199             case SkPath::kClose_Verb:
   200                 isClosed = true;
   201                 break;
   203             case SkPath::kDone_Verb:
   204                 done = true;
   205                 break;
   206         }
   207     } while (!done);
   209     fLength = distance;
   210     fIsClosed = isClosed;
   211     fFirstPtIndex = ptIndex;
   213 #ifdef SK_DEBUG
   214     {
   215         const Segment* seg = fSegments.begin();
   216         const Segment* stop = fSegments.end();
   217         unsigned        ptIndex = 0;
   218         SkScalar        distance = 0;
   220         while (seg < stop) {
   221             SkASSERT(seg->fDistance > distance);
   222             SkASSERT(seg->fPtIndex >= ptIndex);
   223             SkASSERT(seg->fTValue > 0);
   225             const Segment* s = seg;
   226             while (s < stop - 1 && s[0].fPtIndex == s[1].fPtIndex) {
   227                 SkASSERT(s[0].fType == s[1].fType);
   228                 SkASSERT(s[0].fTValue < s[1].fTValue);
   229                 s += 1;
   230             }
   232             distance = seg->fDistance;
   233             ptIndex = seg->fPtIndex;
   234             seg += 1;
   235         }
   236     //  SkDebugf("\n");
   237     }
   238 #endif
   239 }
   241 static void compute_pos_tan(const SkPoint pts[], int segType,
   242                             SkScalar t, SkPoint* pos, SkVector* tangent) {
   243     switch (segType) {
   244         case kLine_SegType:
   245             if (pos) {
   246                 pos->set(SkScalarInterp(pts[0].fX, pts[1].fX, t),
   247                          SkScalarInterp(pts[0].fY, pts[1].fY, t));
   248             }
   249             if (tangent) {
   250                 tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY);
   251             }
   252             break;
   253         case kQuad_SegType:
   254             SkEvalQuadAt(pts, t, pos, tangent);
   255             if (tangent) {
   256                 tangent->normalize();
   257             }
   258             break;
   259         case kCubic_SegType:
   260             SkEvalCubicAt(pts, t, pos, tangent, NULL);
   261             if (tangent) {
   262                 tangent->normalize();
   263             }
   264             break;
   265         default:
   266             SkDEBUGFAIL("unknown segType");
   267     }
   268 }
   270 static void seg_to(const SkPoint pts[], int segType,
   271                    SkScalar startT, SkScalar stopT, SkPath* dst) {
   272     SkASSERT(startT >= 0 && startT <= SK_Scalar1);
   273     SkASSERT(stopT >= 0 && stopT <= SK_Scalar1);
   274     SkASSERT(startT <= stopT);
   276     if (startT == stopT) {
   277         return; // should we report this, to undo a moveTo?
   278     }
   280     SkPoint         tmp0[7], tmp1[7];
   282     switch (segType) {
   283         case kLine_SegType:
   284             if (SK_Scalar1 == stopT) {
   285                 dst->lineTo(pts[1]);
   286             } else {
   287                 dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT),
   288                             SkScalarInterp(pts[0].fY, pts[1].fY, stopT));
   289             }
   290             break;
   291         case kQuad_SegType:
   292             if (0 == startT) {
   293                 if (SK_Scalar1 == stopT) {
   294                     dst->quadTo(pts[1], pts[2]);
   295                 } else {
   296                     SkChopQuadAt(pts, tmp0, stopT);
   297                     dst->quadTo(tmp0[1], tmp0[2]);
   298                 }
   299             } else {
   300                 SkChopQuadAt(pts, tmp0, startT);
   301                 if (SK_Scalar1 == stopT) {
   302                     dst->quadTo(tmp0[3], tmp0[4]);
   303                 } else {
   304                     SkChopQuadAt(&tmp0[2], tmp1, SkScalarDiv(stopT - startT,
   305                                                          SK_Scalar1 - startT));
   306                     dst->quadTo(tmp1[1], tmp1[2]);
   307                 }
   308             }
   309             break;
   310         case kCubic_SegType:
   311             if (0 == startT) {
   312                 if (SK_Scalar1 == stopT) {
   313                     dst->cubicTo(pts[1], pts[2], pts[3]);
   314                 } else {
   315                     SkChopCubicAt(pts, tmp0, stopT);
   316                     dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]);
   317                 }
   318             } else {
   319                 SkChopCubicAt(pts, tmp0, startT);
   320                 if (SK_Scalar1 == stopT) {
   321                     dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]);
   322                 } else {
   323                     SkChopCubicAt(&tmp0[3], tmp1, SkScalarDiv(stopT - startT,
   324                                                         SK_Scalar1 - startT));
   325                     dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]);
   326                 }
   327             }
   328             break;
   329         default:
   330             SkDEBUGFAIL("unknown segType");
   331             sk_throw();
   332     }
   333 }
   335 ////////////////////////////////////////////////////////////////////////////////
   336 ////////////////////////////////////////////////////////////////////////////////
   338 SkPathMeasure::SkPathMeasure() {
   339     fPath = NULL;
   340     fLength = -1;   // signal we need to compute it
   341     fForceClosed = false;
   342     fFirstPtIndex = -1;
   343 }
   345 SkPathMeasure::SkPathMeasure(const SkPath& path, bool forceClosed) {
   346     fPath = &path;
   347     fLength = -1;   // signal we need to compute it
   348     fForceClosed = forceClosed;
   349     fFirstPtIndex = -1;
   351     fIter.setPath(path, forceClosed);
   352 }
   354 SkPathMeasure::~SkPathMeasure() {}
   356 /** Assign a new path, or null to have none.
   357 */
   358 void SkPathMeasure::setPath(const SkPath* path, bool forceClosed) {
   359     fPath = path;
   360     fLength = -1;   // signal we need to compute it
   361     fForceClosed = forceClosed;
   362     fFirstPtIndex = -1;
   364     if (path) {
   365         fIter.setPath(*path, forceClosed);
   366     }
   367     fSegments.reset();
   368     fPts.reset();
   369 }
   371 SkScalar SkPathMeasure::getLength() {
   372     if (fPath == NULL) {
   373         return 0;
   374     }
   375     if (fLength < 0) {
   376         this->buildSegments();
   377     }
   378     SkASSERT(fLength >= 0);
   379     return fLength;
   380 }
   382 const SkPathMeasure::Segment* SkPathMeasure::distanceToSegment(
   383                                             SkScalar distance, SkScalar* t) {
   384     SkDEBUGCODE(SkScalar length = ) this->getLength();
   385     SkASSERT(distance >= 0 && distance <= length);
   387     const Segment*  seg = fSegments.begin();
   388     int             count = fSegments.count();
   390     int index = SkTSearch<SkScalar>(&seg->fDistance, count, distance, sizeof(Segment));
   391     // don't care if we hit an exact match or not, so we xor index if it is negative
   392     index ^= (index >> 31);
   393     seg = &seg[index];
   395     // now interpolate t-values with the prev segment (if possible)
   396     SkScalar    startT = 0, startD = 0;
   397     // check if the prev segment is legal, and references the same set of points
   398     if (index > 0) {
   399         startD = seg[-1].fDistance;
   400         if (seg[-1].fPtIndex == seg->fPtIndex) {
   401             SkASSERT(seg[-1].fType == seg->fType);
   402             startT = seg[-1].getScalarT();
   403         }
   404     }
   406     SkASSERT(seg->getScalarT() > startT);
   407     SkASSERT(distance >= startD);
   408     SkASSERT(seg->fDistance > startD);
   410     *t = startT + SkScalarMulDiv(seg->getScalarT() - startT,
   411                                  distance - startD,
   412                                  seg->fDistance - startD);
   413     return seg;
   414 }
   416 bool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos,
   417                               SkVector* tangent) {
   418     if (NULL == fPath) {
   419         return false;
   420     }
   422     SkScalar    length = this->getLength(); // call this to force computing it
   423     int         count = fSegments.count();
   425     if (count == 0 || length == 0) {
   426         return false;
   427     }
   429     // pin the distance to a legal range
   430     if (distance < 0) {
   431         distance = 0;
   432     } else if (distance > length) {
   433         distance = length;
   434     }
   436     SkScalar        t;
   437     const Segment*  seg = this->distanceToSegment(distance, &t);
   439     compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, t, pos, tangent);
   440     return true;
   441 }
   443 bool SkPathMeasure::getMatrix(SkScalar distance, SkMatrix* matrix,
   444                               MatrixFlags flags) {
   445     if (NULL == fPath) {
   446         return false;
   447     }
   449     SkPoint     position;
   450     SkVector    tangent;
   452     if (this->getPosTan(distance, &position, &tangent)) {
   453         if (matrix) {
   454             if (flags & kGetTangent_MatrixFlag) {
   455                 matrix->setSinCos(tangent.fY, tangent.fX, 0, 0);
   456             } else {
   457                 matrix->reset();
   458             }
   459             if (flags & kGetPosition_MatrixFlag) {
   460                 matrix->postTranslate(position.fX, position.fY);
   461             }
   462         }
   463         return true;
   464     }
   465     return false;
   466 }
   468 bool SkPathMeasure::getSegment(SkScalar startD, SkScalar stopD, SkPath* dst,
   469                                bool startWithMoveTo) {
   470     SkASSERT(dst);
   472     SkScalar length = this->getLength();    // ensure we have built our segments
   474     if (startD < 0) {
   475         startD = 0;
   476     }
   477     if (stopD > length) {
   478         stopD = length;
   479     }
   480     if (startD >= stopD) {
   481         return false;
   482     }
   484     SkPoint  p;
   485     SkScalar startT, stopT;
   486     const Segment* seg = this->distanceToSegment(startD, &startT);
   487     const Segment* stopSeg = this->distanceToSegment(stopD, &stopT);
   488     SkASSERT(seg <= stopSeg);
   490     if (startWithMoveTo) {
   491         compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, startT, &p, NULL);
   492         dst->moveTo(p);
   493     }
   495     if (seg->fPtIndex == stopSeg->fPtIndex) {
   496         seg_to(&fPts[seg->fPtIndex], seg->fType, startT, stopT, dst);
   497     } else {
   498         do {
   499             seg_to(&fPts[seg->fPtIndex], seg->fType, startT, SK_Scalar1, dst);
   500             seg = SkPathMeasure::NextSegment(seg);
   501             startT = 0;
   502         } while (seg->fPtIndex < stopSeg->fPtIndex);
   503         seg_to(&fPts[seg->fPtIndex], seg->fType, 0, stopT, dst);
   504     }
   505     return true;
   506 }
   508 bool SkPathMeasure::isClosed() {
   509     (void)this->getLength();
   510     return fIsClosed;
   511 }
   513 /** Move to the next contour in the path. Return true if one exists, or false if
   514     we're done with the path.
   515 */
   516 bool SkPathMeasure::nextContour() {
   517     fLength = -1;
   518     return this->getLength() > 0;
   519 }
   521 ///////////////////////////////////////////////////////////////////////////////
   522 ///////////////////////////////////////////////////////////////////////////////
   524 #ifdef SK_DEBUG
   526 void SkPathMeasure::dump() {
   527     SkDebugf("pathmeas: length=%g, segs=%d\n", fLength, fSegments.count());
   529     for (int i = 0; i < fSegments.count(); i++) {
   530         const Segment* seg = &fSegments[i];
   531         SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n",
   532                 i, seg->fDistance, seg->fPtIndex, seg->getScalarT(),
   533                  seg->fType);
   534     }
   535 }
   537 #endif

mercurial