Sat, 03 Jan 2015 20:18:00 +0100
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 }