gfx/skia/trunk/src/core/SkPictureFlat.h

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 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

mercurial