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 2011 Google Inc.
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 #ifndef SkPictureFlat_DEFINED
9 #define SkPictureFlat_DEFINED
11 //#define SK_DEBUG_SIZE
13 #include "SkBitmapHeap.h"
14 #include "SkChecksum.h"
15 #include "SkChunkAlloc.h"
16 #include "SkReadBuffer.h"
17 #include "SkWriteBuffer.h"
18 #include "SkPaint.h"
19 #include "SkPicture.h"
20 #include "SkPtrRecorder.h"
21 #include "SkTDynamicHash.h"
22 #include "SkTRefArray.h"
24 enum DrawType {
25 UNUSED,
26 CLIP_PATH,
27 CLIP_REGION,
28 CLIP_RECT,
29 CLIP_RRECT,
30 CONCAT,
31 DRAW_BITMAP,
32 DRAW_BITMAP_MATRIX,
33 DRAW_BITMAP_NINE,
34 DRAW_BITMAP_RECT_TO_RECT,
35 DRAW_CLEAR,
36 DRAW_DATA,
37 DRAW_OVAL,
38 DRAW_PAINT,
39 DRAW_PATH,
40 DRAW_PICTURE,
41 DRAW_POINTS,
42 DRAW_POS_TEXT,
43 DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
44 DRAW_POS_TEXT_H,
45 DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
46 DRAW_RECT,
47 DRAW_RRECT,
48 DRAW_SPRITE,
49 DRAW_TEXT,
50 DRAW_TEXT_ON_PATH,
51 DRAW_TEXT_TOP_BOTTOM, // fast variant of DRAW_TEXT
52 DRAW_VERTICES,
53 RESTORE,
54 ROTATE,
55 SAVE,
56 SAVE_LAYER,
57 SCALE,
58 SET_MATRIX,
59 SKEW,
60 TRANSLATE,
61 NOOP,
62 BEGIN_COMMENT_GROUP,
63 COMMENT,
64 END_COMMENT_GROUP,
66 // new ops -- feel free to re-alphabetize on next version bump
67 DRAW_DRRECT,
68 PUSH_CULL,
69 POP_CULL,
71 LAST_DRAWTYPE_ENUM = POP_CULL
72 };
74 // In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
75 static const int kDRAW_BITMAP_FLAVOR = LAST_DRAWTYPE_ENUM+1;
77 enum DrawVertexFlags {
78 DRAW_VERTICES_HAS_TEXS = 0x01,
79 DRAW_VERTICES_HAS_COLORS = 0x02,
80 DRAW_VERTICES_HAS_INDICES = 0x04,
81 DRAW_VERTICES_HAS_XFER = 0x08,
82 };
84 ///////////////////////////////////////////////////////////////////////////////
85 // clipparams are packed in 5 bits
86 // doAA:1 | regionOp:4
88 static inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) {
89 unsigned doAABit = doAA ? 1 : 0;
90 return (doAABit << 4) | op;
91 }
93 static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) {
94 return (SkRegion::Op)(packed & 0xF);
95 }
97 static inline bool ClipParams_unpackDoAA(uint32_t packed) {
98 return SkToBool((packed >> 4) & 1);
99 }
101 ///////////////////////////////////////////////////////////////////////////////
103 class SkTypefacePlayback {
104 public:
105 SkTypefacePlayback();
106 virtual ~SkTypefacePlayback();
108 int count() const { return fCount; }
110 void reset(const SkRefCntSet*);
112 void setCount(int count);
113 SkRefCnt* set(int index, SkRefCnt*);
115 void setupBuffer(SkReadBuffer& buffer) const {
116 buffer.setTypefaceArray((SkTypeface**)fArray, fCount);
117 }
119 protected:
120 int fCount;
121 SkRefCnt** fArray;
122 };
124 class SkFactoryPlayback {
125 public:
126 SkFactoryPlayback(int count) : fCount(count) {
127 fArray = SkNEW_ARRAY(SkFlattenable::Factory, count);
128 }
130 ~SkFactoryPlayback() {
131 SkDELETE_ARRAY(fArray);
132 }
134 SkFlattenable::Factory* base() const { return fArray; }
136 void setupBuffer(SkReadBuffer& buffer) const {
137 buffer.setFactoryPlayback(fArray, fCount);
138 }
140 private:
141 int fCount;
142 SkFlattenable::Factory* fArray;
143 };
145 ///////////////////////////////////////////////////////////////////////////////
146 //
147 //
148 // The following templated classes provide an efficient way to store and compare
149 // objects that have been flattened (i.e. serialized in an ordered binary
150 // format).
151 //
152 // SkFlatData: is a simple indexable container for the flattened data
153 // which is agnostic to the type of data is is indexing. It is
154 // also responsible for flattening/unflattening objects but
155 // details of that operation are hidden in the provided traits
156 // SkFlatDictionary: is an abstract templated dictionary that maintains a
157 // searchable set of SkFlatData objects of type T.
158 // SkFlatController: is an interface provided to SkFlatDictionary which handles
159 // allocation (and unallocation in some cases). It also holds
160 // ref count recorders and the like.
161 //
162 // NOTE: any class that wishes to be used in conjunction with SkFlatDictionary must subclass the
163 // dictionary and provide the necessary flattening traits. SkFlatController must also be
164 // implemented, or SkChunkFlatController can be used to use an SkChunkAllocator and never do
165 // replacements.
166 //
167 //
168 ///////////////////////////////////////////////////////////////////////////////
170 class SkFlatData;
172 class SkFlatController : public SkRefCnt {
173 public:
174 SK_DECLARE_INST_COUNT(SkFlatController)
176 SkFlatController(uint32_t writeBufferFlags = 0);
177 virtual ~SkFlatController();
178 /**
179 * Return a new block of memory for the SkFlatDictionary to use.
180 * This memory is owned by the controller and has the same lifetime unless you
181 * call unalloc(), in which case it may be freed early.
182 */
183 virtual void* allocThrow(size_t bytes) = 0;
185 /**
186 * Hint that this block, which was allocated with allocThrow, is no longer needed.
187 * The implementation may choose to free this memory any time beteween now and destruction.
188 */
189 virtual void unalloc(void* ptr) = 0;
191 /**
192 * Used during creation and unflattening of SkFlatData objects. If the
193 * objects being flattened contain bitmaps they are stored in this heap
194 * and the flattenable stores the index to the bitmap on the heap.
195 * This should be set by the protected setBitmapHeap.
196 */
197 SkBitmapHeap* getBitmapHeap() { return fBitmapHeap; }
199 /**
200 * Used during creation of SkFlatData objects. If a typeface recorder is
201 * required to flatten the objects being flattened (i.e. for SkPaints), this
202 * should be set by the protected setTypefaceSet.
203 */
204 SkRefCntSet* getTypefaceSet() { return fTypefaceSet; }
206 /**
207 * Used during unflattening of the SkFlatData objects in the
208 * SkFlatDictionary. Needs to be set by the protected setTypefacePlayback
209 * and needs to be reset to the SkRefCntSet passed to setTypefaceSet.
210 */
211 SkTypefacePlayback* getTypefacePlayback() { return fTypefacePlayback; }
213 /**
214 * Optional factory recorder used during creation of SkFlatData objects. Set
215 * using the protected method setNamedFactorySet.
216 */
217 SkNamedFactorySet* getNamedFactorySet() { return fFactorySet; }
219 /**
220 * Flags to use during creation of SkFlatData objects. Defaults to zero.
221 */
222 uint32_t getWriteBufferFlags() { return fWriteBufferFlags; }
224 protected:
225 /**
226 * Set an SkBitmapHeap to be used to store/read SkBitmaps. Ref counted.
227 */
228 void setBitmapHeap(SkBitmapHeap*);
230 /**
231 * Set an SkRefCntSet to be used to store SkTypefaces during flattening. Ref
232 * counted.
233 */
234 void setTypefaceSet(SkRefCntSet*);
236 /**
237 * Set an SkTypefacePlayback to be used to find references to SkTypefaces
238 * during unflattening. Should be reset to the set provided to
239 * setTypefaceSet.
240 */
241 void setTypefacePlayback(SkTypefacePlayback*);
243 /**
244 * Set an SkNamedFactorySet to be used to store Factorys and their
245 * corresponding names during flattening. Ref counted. Returns the same
246 * set as a convenience.
247 */
248 SkNamedFactorySet* setNamedFactorySet(SkNamedFactorySet*);
250 private:
251 SkBitmapHeap* fBitmapHeap;
252 SkRefCntSet* fTypefaceSet;
253 SkTypefacePlayback* fTypefacePlayback;
254 SkNamedFactorySet* fFactorySet;
255 const uint32_t fWriteBufferFlags;
257 typedef SkRefCnt INHERITED;
258 };
260 class SkFlatData {
261 public:
262 // Flatten obj into an SkFlatData with this index. controller owns the SkFlatData*.
263 template <typename Traits, typename T>
264 static SkFlatData* Create(SkFlatController* controller, const T& obj, int index) {
265 // A buffer of 256 bytes should fit most paints, regions, and matrices.
266 uint32_t storage[64];
267 SkWriteBuffer buffer(storage, sizeof(storage), controller->getWriteBufferFlags());
269 buffer.setBitmapHeap(controller->getBitmapHeap());
270 buffer.setTypefaceRecorder(controller->getTypefaceSet());
271 buffer.setNamedFactoryRecorder(controller->getNamedFactorySet());
273 Traits::Flatten(buffer, obj);
274 size_t size = buffer.bytesWritten();
275 SkASSERT(SkIsAlign4(size));
277 // Allocate enough memory to hold SkFlatData struct and the flat data itself.
278 size_t allocSize = sizeof(SkFlatData) + size;
279 SkFlatData* result = (SkFlatData*) controller->allocThrow(allocSize);
281 // Put the serialized contents into the data section of the new allocation.
282 buffer.writeToMemory(result->data());
283 // Stamp the index, size and checksum in the header.
284 result->stampHeader(index, SkToS32(size));
285 return result;
286 }
288 // Unflatten this into result, using bitmapHeap and facePlayback for bitmaps and fonts if given
289 template <typename Traits, typename T>
290 void unflatten(T* result,
291 SkBitmapHeap* bitmapHeap = NULL,
292 SkTypefacePlayback* facePlayback = NULL) const {
293 SkReadBuffer buffer(this->data(), fFlatSize);
295 if (bitmapHeap) {
296 buffer.setBitmapStorage(bitmapHeap);
297 }
298 if (facePlayback) {
299 facePlayback->setupBuffer(buffer);
300 }
302 Traits::Unflatten(buffer, result);
303 SkASSERT(fFlatSize == (int32_t)buffer.offset());
304 }
306 // Do these contain the same data? Ignores index() and topBot().
307 bool operator==(const SkFlatData& that) const {
308 if (this->checksum() != that.checksum() || this->flatSize() != that.flatSize()) {
309 return false;
310 }
311 return memcmp(this->data(), that.data(), this->flatSize()) == 0;
312 }
314 int index() const { return fIndex; }
315 const uint8_t* data() const { return (const uint8_t*)this + sizeof(*this); }
316 size_t flatSize() const { return fFlatSize; }
317 uint32_t checksum() const { return fChecksum; }
319 // Returns true if fTopBot[] has been recorded.
320 bool isTopBotWritten() const {
321 return !SkScalarIsNaN(fTopBot[0]);
322 }
324 // Returns fTopBot array, so it can be passed to a routine to compute them.
325 // For efficiency, we assert that fTopBot have not been recorded yet.
326 SkScalar* writableTopBot() const {
327 SkASSERT(!this->isTopBotWritten());
328 return fTopBot;
329 }
331 // Return the topbot[] after it has been recorded.
332 const SkScalar* topBot() const {
333 SkASSERT(this->isTopBotWritten());
334 return fTopBot;
335 }
337 private:
338 // For SkTDynamicHash.
339 static const SkFlatData& Identity(const SkFlatData& flat) { return flat; }
340 static uint32_t Hash(const SkFlatData& flat) { return flat.checksum(); }
341 static bool Equal(const SkFlatData& a, const SkFlatData& b) { return a == b; }
343 void setIndex(int index) { fIndex = index; }
344 uint8_t* data() { return (uint8_t*)this + sizeof(*this); }
346 // This assumes the payload flat data has already been written and does not modify it.
347 void stampHeader(int index, int32_t size) {
348 SkASSERT(SkIsAlign4(size));
349 fIndex = index;
350 fFlatSize = size;
351 fTopBot[0] = SK_ScalarNaN; // Mark as unwritten.
352 fChecksum = SkChecksum::Compute((uint32_t*)this->data(), size);
353 }
355 int fIndex;
356 int32_t fFlatSize;
357 uint32_t fChecksum;
358 mutable SkScalar fTopBot[2]; // Cache of FontMetrics fTop, fBottom. Starts as [NaN,?].
359 // uint32_t flattenedData[] implicitly hangs off the end.
361 template <typename T, typename Traits> friend class SkFlatDictionary;
362 };
364 template <typename T, typename Traits>
365 class SkFlatDictionary {
366 public:
367 explicit SkFlatDictionary(SkFlatController* controller)
368 : fController(SkRef(controller))
369 , fScratch(controller->getWriteBufferFlags())
370 , fReady(false) {
371 this->reset();
372 }
374 /**
375 * Clears the dictionary of all entries. However, it does NOT free the
376 * memory that was allocated for each entry (that's owned by controller).
377 */
378 void reset() {
379 fIndexedData.rewind();
380 }
382 int count() const {
383 SkASSERT(fHash.count() == fIndexedData.count());
384 return fHash.count();
385 }
387 // For testing only. Index is zero-based.
388 const SkFlatData* operator[](int index) {
389 return fIndexedData[index];
390 }
392 /**
393 * Given an element of type T return its 1-based index in the dictionary. If
394 * the element wasn't previously in the dictionary it is automatically
395 * added.
396 *
397 */
398 int find(const T& element) {
399 return this->findAndReturnFlat(element)->index();
400 }
402 /**
403 * Similar to find. Allows the caller to specify an SkFlatData to replace in
404 * the case of an add. Also tells the caller whether a new SkFlatData was
405 * added and whether the old one was replaced. The parameters added and
406 * replaced are required to be non-NULL. Rather than returning the index of
407 * the entry in the dictionary, it returns the actual SkFlatData.
408 */
409 const SkFlatData* findAndReplace(const T& element,
410 const SkFlatData* toReplace,
411 bool* added,
412 bool* replaced) {
413 SkASSERT(added != NULL && replaced != NULL);
415 const int oldCount = this->count();
416 SkFlatData* flat = this->findAndReturnMutableFlat(element);
417 *added = this->count() > oldCount;
419 // If we don't want to replace anything, we're done.
420 if (!*added || toReplace == NULL) {
421 *replaced = false;
422 return flat;
423 }
425 // If we don't have the thing to replace, we're done.
426 const SkFlatData* found = fHash.find(*toReplace);
427 if (found == NULL) {
428 *replaced = false;
429 return flat;
430 }
432 // findAndReturnMutableFlat put flat at the back. Swap it into found->index() instead.
433 // indices in SkFlatData are 1-based, while fIndexedData is 0-based. Watch out!
434 SkASSERT(flat->index() == this->count());
435 flat->setIndex(found->index());
436 fIndexedData.removeShuffle(found->index()-1);
437 SkASSERT(flat == fIndexedData[found->index()-1]);
439 // findAndReturnMutableFlat already called fHash.add(), so we just clean up the old entry.
440 fHash.remove(*found);
441 fController->unalloc((void*)found);
442 SkASSERT(this->count() == oldCount);
444 *replaced = true;
445 return flat;
446 }
448 /**
449 * Unflatten the objects and return them in SkTRefArray, or return NULL
450 * if there no objects. Caller takes ownership of result.
451 */
452 SkTRefArray<T>* unflattenToArray() const {
453 const int count = this->count();
454 if (count == 0) {
455 return NULL;
456 }
457 SkTRefArray<T>* array = SkTRefArray<T>::Create(count);
458 for (int i = 0; i < count; i++) {
459 this->unflatten(&array->writableAt(i), fIndexedData[i]);
460 }
461 return array;
462 }
464 /**
465 * Unflatten the specific object at the given index.
466 * Caller takes ownership of the result.
467 */
468 T* unflatten(int index) const {
469 // index is 1-based, while fIndexedData is 0-based.
470 const SkFlatData* element = fIndexedData[index-1];
471 SkASSERT(index == element->index());
473 T* dst = new T;
474 this->unflatten(dst, element);
475 return dst;
476 }
478 /**
479 * Find or insert a flattened version of element into the dictionary.
480 * Caller does not take ownership of the result. This will not return NULL.
481 */
482 const SkFlatData* findAndReturnFlat(const T& element) {
483 return this->findAndReturnMutableFlat(element);
484 }
486 private:
487 // We have to delay fScratch's initialization until its first use; fController might not
488 // be fully set up by the time we get it in the constructor.
489 void lazyInit() {
490 if (fReady) {
491 return;
492 }
494 // Without a bitmap heap, we'll flatten bitmaps into paints. That's never what you want.
495 SkASSERT(fController->getBitmapHeap() != NULL);
496 fScratch.setBitmapHeap(fController->getBitmapHeap());
497 fScratch.setTypefaceRecorder(fController->getTypefaceSet());
498 fScratch.setNamedFactoryRecorder(fController->getNamedFactorySet());
499 fReady = true;
500 }
502 // As findAndReturnFlat, but returns a mutable pointer for internal use.
503 SkFlatData* findAndReturnMutableFlat(const T& element) {
504 // Only valid until the next call to resetScratch().
505 const SkFlatData& scratch = this->resetScratch(element, this->count()+1);
507 SkFlatData* candidate = fHash.find(scratch);
508 if (candidate != NULL) {
509 return candidate;
510 }
512 SkFlatData* detached = this->detachScratch();
513 fHash.add(detached);
514 *fIndexedData.append() = detached;
515 SkASSERT(fIndexedData.top()->index() == this->count());
516 return detached;
517 }
519 // This reference is valid only until the next call to resetScratch() or detachScratch().
520 const SkFlatData& resetScratch(const T& element, int index) {
521 this->lazyInit();
523 // Layout of fScratch: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ]
524 fScratch.reset();
525 fScratch.reserve(sizeof(SkFlatData));
526 Traits::Flatten(fScratch, element);
527 const size_t dataSize = fScratch.bytesWritten() - sizeof(SkFlatData);
529 // Reinterpret data in fScratch as an SkFlatData.
530 SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray();
531 SkASSERT(scratch != NULL);
532 scratch->stampHeader(index, dataSize);
533 return *scratch;
534 }
536 // This result is owned by fController and lives as long as it does (unless unalloc'd).
537 SkFlatData* detachScratch() {
538 // Allocate a new SkFlatData exactly big enough to hold our current scratch.
539 // We use the controller for this allocation to extend the allocation's lifetime and allow
540 // the controller to do whatever memory management it wants.
541 SkFlatData* detached = (SkFlatData*)fController->allocThrow(fScratch.bytesWritten());
543 // Copy scratch into the new SkFlatData.
544 SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray();
545 SkASSERT(scratch != NULL);
546 memcpy(detached, scratch, fScratch.bytesWritten());
548 // We can now reuse fScratch, and detached will live until fController dies.
549 return detached;
550 }
552 void unflatten(T* dst, const SkFlatData* element) const {
553 element->unflatten<Traits>(dst,
554 fController->getBitmapHeap(),
555 fController->getTypefacePlayback());
556 }
558 // All SkFlatData* stored in fIndexedData and fHash are owned by the controller.
559 SkAutoTUnref<SkFlatController> fController;
560 SkWriteBuffer fScratch;
561 bool fReady;
563 // For index -> SkFlatData. 0-based, while all indices in the API are 1-based. Careful!
564 SkTDArray<const SkFlatData*> fIndexedData;
566 // For SkFlatData -> cached SkFlatData, which has index().
567 SkTDynamicHash<SkFlatData, SkFlatData,
568 SkFlatData::Identity, SkFlatData::Hash, SkFlatData::Equal> fHash;
569 };
571 typedef SkFlatDictionary<SkPaint, SkPaint::FlatteningTraits> SkPaintDictionary;
573 class SkChunkFlatController : public SkFlatController {
574 public:
575 SkChunkFlatController(size_t minSize)
576 : fHeap(minSize)
577 , fTypefaceSet(SkNEW(SkRefCntSet))
578 , fLastAllocated(NULL) {
579 this->setTypefaceSet(fTypefaceSet);
580 this->setTypefacePlayback(&fTypefacePlayback);
581 }
583 virtual void* allocThrow(size_t bytes) SK_OVERRIDE {
584 fLastAllocated = fHeap.allocThrow(bytes);
585 return fLastAllocated;
586 }
588 virtual void unalloc(void* ptr) SK_OVERRIDE {
589 // fHeap can only free a pointer if it was the last one allocated. Otherwise, we'll just
590 // have to wait until fHeap is destroyed.
591 if (ptr == fLastAllocated) (void)fHeap.unalloc(ptr);
592 }
594 void setupPlaybacks() const {
595 fTypefacePlayback.reset(fTypefaceSet.get());
596 }
598 void setBitmapStorage(SkBitmapHeap* heap) {
599 this->setBitmapHeap(heap);
600 }
602 private:
603 SkChunkAlloc fHeap;
604 SkAutoTUnref<SkRefCntSet> fTypefaceSet;
605 void* fLastAllocated;
606 mutable SkTypefacePlayback fTypefacePlayback;
607 };
609 #endif