gfx/skia/trunk/src/core/SkRegion_path.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 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  */
    10 #include "SkRegionPriv.h"
    11 #include "SkBlitter.h"
    12 #include "SkScan.h"
    13 #include "SkTDArray.h"
    14 #include "SkPath.h"
    16 class SkRgnBuilder : public SkBlitter {
    17 public:
    18     SkRgnBuilder();
    19     virtual ~SkRgnBuilder();
    21     // returns true if it could allocate the working storage needed
    22     bool init(int maxHeight, int maxTransitions, bool pathIsInverse);
    24     void done() {
    25         if (fCurrScanline != NULL) {
    26             fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX()));
    27             if (!this->collapsWithPrev()) { // flush the last line
    28                 fCurrScanline = fCurrScanline->nextScanline();
    29             }
    30         }
    31     }
    33     int     computeRunCount() const;
    34     void    copyToRect(SkIRect*) const;
    35     void    copyToRgn(SkRegion::RunType runs[]) const;
    37     virtual void blitH(int x, int y, int width);
    39 #ifdef SK_DEBUG
    40     void dump() const {
    41         SkDebugf("SkRgnBuilder: Top = %d\n", fTop);
    42         const Scanline* line = (Scanline*)fStorage;
    43         while (line < fCurrScanline) {
    44             SkDebugf("SkRgnBuilder::Scanline: LastY=%d, fXCount=%d", line->fLastY, line->fXCount);
    45             for (int i = 0; i < line->fXCount; i++) {
    46                 SkDebugf(" %d", line->firstX()[i]);
    47             }
    48             SkDebugf("\n");
    50             line = line->nextScanline();
    51         }
    52     }
    53 #endif
    54 private:
    55     /*
    56      *  Scanline mimics a row in the region, nearly. A row in a region is:
    57      *      [Bottom IntervalCount [L R]... Sentinel]
    58      *  while a Scanline is
    59      *      [LastY XCount [L R]... uninitialized]
    60      *  The two are the same length (which is good), but we have to transmute
    61      *  the scanline a little when we convert it to a region-row.
    62      *
    63      *  Potentially we could recode this to exactly match the row format, in
    64      *  which case copyToRgn() could be a single memcpy. Not sure that is worth
    65      *  the effort.
    66      */
    67     struct Scanline {
    68         SkRegion::RunType fLastY;
    69         SkRegion::RunType fXCount;
    71         SkRegion::RunType* firstX() const { return (SkRegion::RunType*)(this + 1); }
    72         Scanline* nextScanline() const {
    73             // add final +1 for the x-sentinel
    74             return (Scanline*)((SkRegion::RunType*)(this + 1) + fXCount + 1);
    75         }
    76     };
    77     SkRegion::RunType*  fStorage;
    78     Scanline*           fCurrScanline;
    79     Scanline*           fPrevScanline;
    80     //  points at next avialable x[] in fCurrScanline
    81     SkRegion::RunType*  fCurrXPtr;
    82     SkRegion::RunType   fTop;           // first Y value
    84     int fStorageCount;
    86     bool collapsWithPrev() {
    87         if (fPrevScanline != NULL &&
    88             fPrevScanline->fLastY + 1 == fCurrScanline->fLastY &&
    89             fPrevScanline->fXCount == fCurrScanline->fXCount &&
    90             !memcmp(fPrevScanline->firstX(),
    91                     fCurrScanline->firstX(),
    92                     fCurrScanline->fXCount * sizeof(SkRegion::RunType)))
    93         {
    94             // update the height of fPrevScanline
    95             fPrevScanline->fLastY = fCurrScanline->fLastY;
    96             return true;
    97         }
    98         return false;
    99     }
   100 };
   102 SkRgnBuilder::SkRgnBuilder()
   103     : fStorage(NULL) {
   104 }
   106 SkRgnBuilder::~SkRgnBuilder() {
   107     sk_free(fStorage);
   108 }
   110 bool SkRgnBuilder::init(int maxHeight, int maxTransitions, bool pathIsInverse) {
   111     if ((maxHeight | maxTransitions) < 0) {
   112         return false;
   113     }
   115     if (pathIsInverse) {
   116         // allow for additional X transitions to "invert" each scanline
   117         // [ L' ... normal transitions ... R' ]
   118         //
   119         maxTransitions += 2;
   120     }
   122     // compute the count with +1 and +3 slop for the working buffer
   123     int64_t count = sk_64_mul(maxHeight + 1, 3 + maxTransitions);
   125     if (pathIsInverse) {
   126         // allow for two "empty" rows for the top and bottom
   127         //      [ Y, 1, L, R, S] == 5 (*2 for top and bottom)
   128         count += 10;
   129     }
   131     if (count < 0 || !sk_64_isS32(count)) {
   132         return false;
   133     }
   134     fStorageCount = sk_64_asS32(count);
   136     int64_t size = sk_64_mul(fStorageCount, sizeof(SkRegion::RunType));
   137     if (size < 0 || !sk_64_isS32(size)) {
   138         return false;
   139     }
   141     fStorage = (SkRegion::RunType*)sk_malloc_flags(sk_64_asS32(size), 0);
   142     if (NULL == fStorage) {
   143         return false;
   144     }
   146     fCurrScanline = NULL;    // signal empty collection
   147     fPrevScanline = NULL;    // signal first scanline
   148     return true;
   149 }
   151 void SkRgnBuilder::blitH(int x, int y, int width) {
   152     if (fCurrScanline == NULL) {  // first time
   153         fTop = (SkRegion::RunType)(y);
   154         fCurrScanline = (Scanline*)fStorage;
   155         fCurrScanline->fLastY = (SkRegion::RunType)(y);
   156         fCurrXPtr = fCurrScanline->firstX();
   157     } else {
   158         SkASSERT(y >= fCurrScanline->fLastY);
   160         if (y > fCurrScanline->fLastY) {
   161             // if we get here, we're done with fCurrScanline
   162             fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX()));
   164             int prevLastY = fCurrScanline->fLastY;
   165             if (!this->collapsWithPrev()) {
   166                 fPrevScanline = fCurrScanline;
   167                 fCurrScanline = fCurrScanline->nextScanline();
   169             }
   170             if (y - 1 > prevLastY) {  // insert empty run
   171                 fCurrScanline->fLastY = (SkRegion::RunType)(y - 1);
   172                 fCurrScanline->fXCount = 0;
   173                 fCurrScanline = fCurrScanline->nextScanline();
   174             }
   175             // setup for the new curr line
   176             fCurrScanline->fLastY = (SkRegion::RunType)(y);
   177             fCurrXPtr = fCurrScanline->firstX();
   178         }
   179     }
   180     //  check if we should extend the current run, or add a new one
   181     if (fCurrXPtr > fCurrScanline->firstX() && fCurrXPtr[-1] == x) {
   182         fCurrXPtr[-1] = (SkRegion::RunType)(x + width);
   183     } else {
   184         fCurrXPtr[0] = (SkRegion::RunType)(x);
   185         fCurrXPtr[1] = (SkRegion::RunType)(x + width);
   186         fCurrXPtr += 2;
   187     }
   188     SkASSERT(fCurrXPtr - fStorage < fStorageCount);
   189 }
   191 int SkRgnBuilder::computeRunCount() const {
   192     if (fCurrScanline == NULL) {
   193         return 0;
   194     }
   196     const SkRegion::RunType*  line = fStorage;
   197     const SkRegion::RunType*  stop = (const SkRegion::RunType*)fCurrScanline;
   199     return 2 + (int)(stop - line);
   200 }
   202 void SkRgnBuilder::copyToRect(SkIRect* r) const {
   203     SkASSERT(fCurrScanline != NULL);
   204     // A rect's scanline is [bottom intervals left right sentinel] == 5
   205     SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage == 5);
   207     const Scanline* line = (const Scanline*)fStorage;
   208     SkASSERT(line->fXCount == 2);
   210     r->set(line->firstX()[0], fTop, line->firstX()[1], line->fLastY + 1);
   211 }
   213 void SkRgnBuilder::copyToRgn(SkRegion::RunType runs[]) const {
   214     SkASSERT(fCurrScanline != NULL);
   215     SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage > 4);
   217     const Scanline* line = (const Scanline*)fStorage;
   218     const Scanline* stop = fCurrScanline;
   220     *runs++ = fTop;
   221     do {
   222         *runs++ = (SkRegion::RunType)(line->fLastY + 1);
   223         int count = line->fXCount;
   224         *runs++ = count >> 1;   // intervalCount
   225         if (count) {
   226             memcpy(runs, line->firstX(), count * sizeof(SkRegion::RunType));
   227             runs += count;
   228         }
   229         *runs++ = SkRegion::kRunTypeSentinel;
   230         line = line->nextScanline();
   231     } while (line < stop);
   232     SkASSERT(line == stop);
   233     *runs = SkRegion::kRunTypeSentinel;
   234 }
   236 static unsigned verb_to_initial_last_index(unsigned verb) {
   237     static const uint8_t gPathVerbToInitialLastIndex[] = {
   238         0,  //  kMove_Verb
   239         1,  //  kLine_Verb
   240         2,  //  kQuad_Verb
   241         2,  //  kConic_Verb
   242         3,  //  kCubic_Verb
   243         0,  //  kClose_Verb
   244         0   //  kDone_Verb
   245     };
   246     SkASSERT((unsigned)verb < SK_ARRAY_COUNT(gPathVerbToInitialLastIndex));
   247     return gPathVerbToInitialLastIndex[verb];
   248 }
   250 static unsigned verb_to_max_edges(unsigned verb) {
   251     static const uint8_t gPathVerbToMaxEdges[] = {
   252         0,  //  kMove_Verb
   253         1,  //  kLine_Verb
   254         2,  //  kQuad_VerbB
   255         2,  //  kConic_VerbB
   256         3,  //  kCubic_Verb
   257         0,  //  kClose_Verb
   258         0   //  kDone_Verb
   259     };
   260     SkASSERT((unsigned)verb < SK_ARRAY_COUNT(gPathVerbToMaxEdges));
   261     return gPathVerbToMaxEdges[verb];
   262 }
   265 static int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) {
   266     SkPath::Iter    iter(path, true);
   267     SkPoint         pts[4];
   268     SkPath::Verb    verb;
   270     int maxEdges = 0;
   271     SkScalar    top = SkIntToScalar(SK_MaxS16);
   272     SkScalar    bot = SkIntToScalar(SK_MinS16);
   274     while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
   275         maxEdges += verb_to_max_edges(verb);
   277         int lastIndex = verb_to_initial_last_index(verb);
   278         if (lastIndex > 0) {
   279             for (int i = 1; i <= lastIndex; i++) {
   280                 if (top > pts[i].fY) {
   281                     top = pts[i].fY;
   282                 } else if (bot < pts[i].fY) {
   283                     bot = pts[i].fY;
   284                 }
   285             }
   286         } else if (SkPath::kMove_Verb == verb) {
   287             if (top > pts[0].fY) {
   288                 top = pts[0].fY;
   289             } else if (bot < pts[0].fY) {
   290                 bot = pts[0].fY;
   291             }
   292         }
   293     }
   294     SkASSERT(top <= bot);
   296     *itop = SkScalarRoundToInt(top);
   297     *ibot = SkScalarRoundToInt(bot);
   298     return maxEdges;
   299 }
   301 bool SkRegion::setPath(const SkPath& path, const SkRegion& clip) {
   302     SkDEBUGCODE(this->validate();)
   304     if (clip.isEmpty()) {
   305         return this->setEmpty();
   306     }
   308     if (path.isEmpty()) {
   309         if (path.isInverseFillType()) {
   310             return this->set(clip);
   311         } else {
   312             return this->setEmpty();
   313         }
   314     }
   316     //  compute worst-case rgn-size for the path
   317     int pathTop, pathBot;
   318     int pathTransitions = count_path_runtype_values(path, &pathTop, &pathBot);
   319     int clipTop, clipBot;
   320     int clipTransitions;
   322     clipTransitions = clip.count_runtype_values(&clipTop, &clipBot);
   324     int top = SkMax32(pathTop, clipTop);
   325     int bot = SkMin32(pathBot, clipBot);
   327     if (top >= bot)
   328         return this->setEmpty();
   330     SkRgnBuilder builder;
   332     if (!builder.init(bot - top,
   333                       SkMax32(pathTransitions, clipTransitions),
   334                       path.isInverseFillType())) {
   335         // can't allocate working space, so return false
   336         return this->setEmpty();
   337     }
   339     SkScan::FillPath(path, clip, &builder);
   340     builder.done();
   342     int count = builder.computeRunCount();
   343     if (count == 0) {
   344         return this->setEmpty();
   345     } else if (count == kRectRegionRuns) {
   346         builder.copyToRect(&fBounds);
   347         this->setRect(fBounds);
   348     } else {
   349         SkRegion tmp;
   351         tmp.fRunHead = RunHead::Alloc(count);
   352         builder.copyToRgn(tmp.fRunHead->writable_runs());
   353         tmp.fRunHead->computeRunBounds(&tmp.fBounds);
   354         this->swap(tmp);
   355     }
   356     SkDEBUGCODE(this->validate();)
   357     return true;
   358 }
   360 /////////////////////////////////////////////////////////////////////////////////////////////////
   361 /////////////////////////////////////////////////////////////////////////////////////////////////
   363 struct Edge {
   364     enum {
   365         kY0Link = 0x01,
   366         kY1Link = 0x02,
   368         kCompleteLink = (kY0Link | kY1Link)
   369     };
   371     SkRegion::RunType fX;
   372     SkRegion::RunType fY0, fY1;
   373     uint8_t fFlags;
   374     Edge*   fNext;
   376     void set(int x, int y0, int y1) {
   377         SkASSERT(y0 != y1);
   379         fX = (SkRegion::RunType)(x);
   380         fY0 = (SkRegion::RunType)(y0);
   381         fY1 = (SkRegion::RunType)(y1);
   382         fFlags = 0;
   383         SkDEBUGCODE(fNext = NULL;)
   384     }
   386     int top() const {
   387         return SkFastMin32(fY0, fY1);
   388     }
   389 };
   391 static void find_link(Edge* base, Edge* stop) {
   392     SkASSERT(base < stop);
   394     if (base->fFlags == Edge::kCompleteLink) {
   395         SkASSERT(base->fNext);
   396         return;
   397     }
   399     SkASSERT(base + 1 < stop);
   401     int y0 = base->fY0;
   402     int y1 = base->fY1;
   404     Edge* e = base;
   405     if ((base->fFlags & Edge::kY0Link) == 0) {
   406         for (;;) {
   407             e += 1;
   408             if ((e->fFlags & Edge::kY1Link) == 0 && y0 == e->fY1) {
   409                 SkASSERT(NULL == e->fNext);
   410                 e->fNext = base;
   411                 e->fFlags = SkToU8(e->fFlags | Edge::kY1Link);
   412                 break;
   413             }
   414         }
   415     }
   417     e = base;
   418     if ((base->fFlags & Edge::kY1Link) == 0) {
   419         for (;;) {
   420             e += 1;
   421             if ((e->fFlags & Edge::kY0Link) == 0 && y1 == e->fY0) {
   422                 SkASSERT(NULL == base->fNext);
   423                 base->fNext = e;
   424                 e->fFlags = SkToU8(e->fFlags | Edge::kY0Link);
   425                 break;
   426             }
   427         }
   428     }
   430     base->fFlags = Edge::kCompleteLink;
   431 }
   433 static int extract_path(Edge* edge, Edge* stop, SkPath* path) {
   434     while (0 == edge->fFlags) {
   435         edge++; // skip over "used" edges
   436     }
   438     SkASSERT(edge < stop);
   440     Edge* base = edge;
   441     Edge* prev = edge;
   442     edge = edge->fNext;
   443     SkASSERT(edge != base);
   445     int count = 1;
   446     path->moveTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY0));
   447     prev->fFlags = 0;
   448     do {
   449         if (prev->fX != edge->fX || prev->fY1 != edge->fY0) { // skip collinear
   450             path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1));    // V
   451             path->lineTo(SkIntToScalar(edge->fX), SkIntToScalar(edge->fY0));    // H
   452         }
   453         prev = edge;
   454         edge = edge->fNext;
   455         count += 1;
   456         prev->fFlags = 0;
   457     } while (edge != base);
   458     path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1));    // V
   459     path->close();
   460     return count;
   461 }
   463 #include "SkTSearch.h"
   465 static int EdgeProc(const Edge* a, const Edge* b) {
   466     return (a->fX == b->fX) ? a->top() - b->top() : a->fX - b->fX;
   467 }
   469 bool SkRegion::getBoundaryPath(SkPath* path) const {
   470     // path could safely be NULL if we're empty, but the caller shouldn't
   471     // *know* that
   472     SkASSERT(path);
   474     if (this->isEmpty()) {
   475         return false;
   476     }
   478     const SkIRect& bounds = this->getBounds();
   480     if (this->isRect()) {
   481         SkRect  r;
   482         r.set(bounds);      // this converts the ints to scalars
   483         path->addRect(r);
   484         return true;
   485     }
   487     SkRegion::Iterator  iter(*this);
   488     SkTDArray<Edge>     edges;
   490     for (const SkIRect& r = iter.rect(); !iter.done(); iter.next()) {
   491         Edge* edge = edges.append(2);
   492         edge[0].set(r.fLeft, r.fBottom, r.fTop);
   493         edge[1].set(r.fRight, r.fTop, r.fBottom);
   494     }
   495     qsort(edges.begin(), edges.count(), sizeof(Edge), SkCastForQSort(EdgeProc));
   497     int count = edges.count();
   498     Edge* start = edges.begin();
   499     Edge* stop = start + count;
   500     Edge* e;
   502     for (e = start; e != stop; e++) {
   503         find_link(e, stop);
   504     }
   506 #ifdef SK_DEBUG
   507     for (e = start; e != stop; e++) {
   508         SkASSERT(e->fNext != NULL);
   509         SkASSERT(e->fFlags == Edge::kCompleteLink);
   510     }
   511 #endif
   513     path->incReserve(count << 1);
   514     do {
   515         SkASSERT(count > 1);
   516         count -= extract_path(start, stop, path);
   517     } while (count > 0);
   519     return true;
   520 }

mercurial