Home | History | Annotate | Download | only in core
      1 
      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  */
      8 
      9 
     10 #ifndef SkDescriptor_DEFINED
     11 #define SkDescriptor_DEFINED
     12 
     13 #include "SkTypes.h"
     14 
     15 class SkDescriptor : SkNoncopyable {
     16 public:
     17     static size_t ComputeOverhead(int entryCount)
     18     {
     19         SkASSERT(entryCount >= 0);
     20         return sizeof(SkDescriptor) + entryCount * sizeof(Entry);
     21     }
     22 
     23     static SkDescriptor* Alloc(size_t length)
     24     {
     25         SkASSERT(SkAlign4(length) == length);
     26         SkDescriptor* desc = (SkDescriptor*)sk_malloc_throw(length);
     27         return desc;
     28     }
     29 
     30     static void Free(SkDescriptor* desc)
     31     {
     32         sk_free(desc);
     33     }
     34 
     35     void init()
     36     {
     37         fLength = sizeof(SkDescriptor);
     38         fCount  = 0;
     39     }
     40 
     41     uint32_t getLength() const { return fLength; }
     42 
     43     void* addEntry(uint32_t tag, uint32_t length, const void* data = NULL)
     44     {
     45         SkASSERT(tag);
     46         SkASSERT(SkAlign4(length) == length);
     47         SkASSERT(this->findEntry(tag, NULL) == NULL);
     48 
     49         Entry*  entry = (Entry*)((char*)this + fLength);
     50         entry->fTag = tag;
     51         entry->fLen = length;
     52         if (data)
     53             memcpy(entry + 1, data, length);
     54 
     55         fCount += 1;
     56         fLength += sizeof(Entry) + length;
     57         return (entry + 1); // return its data
     58     }
     59 
     60     void computeChecksum()
     61     {
     62         fChecksum = SkDescriptor::ComputeChecksum(this);
     63     }
     64 
     65 #ifdef SK_DEBUG
     66     void assertChecksum() const
     67     {
     68         SkASSERT(fChecksum == SkDescriptor::ComputeChecksum(this));
     69     }
     70 #endif
     71 
     72     const void* findEntry(uint32_t tag, uint32_t* length) const
     73     {
     74         const Entry* entry = (const Entry*)(this + 1);
     75         int          count = fCount;
     76 
     77         while (--count >= 0)
     78         {
     79             if (entry->fTag == tag)
     80             {
     81                 if (length)
     82                     *length = entry->fLen;
     83                 return entry + 1;
     84             }
     85             entry = (const Entry*)((const char*)(entry + 1) + entry->fLen);
     86         }
     87         return NULL;
     88     }
     89 
     90     SkDescriptor* copy() const
     91     {
     92         SkDescriptor* desc = SkDescriptor::Alloc(fLength);
     93         memcpy(desc, this, fLength);
     94         return desc;
     95     }
     96 
     97     bool equals(const SkDescriptor& other) const
     98     {
     99         // probe to see if we have a good checksum algo
    100 //        SkASSERT(a.fChecksum != b.fChecksum || memcmp(&a, &b, a.fLength) == 0);
    101 
    102         // the first value we should look at is the checksum, so this loop
    103         // should terminate early if they descriptors are different.
    104         // NOTE: if we wrote a sentinel value at the end of each, we chould
    105         //       remove the aa < stop test in the loop...
    106         const uint32_t* aa = (const uint32_t*)this;
    107         const uint32_t* bb = (const uint32_t*)&other;
    108         const uint32_t* stop = (const uint32_t*)((const char*)aa + fLength);
    109         do {
    110             if (*aa++ != *bb++)
    111                 return false;
    112         } while (aa < stop);
    113         return true;
    114     }
    115 
    116     uint32_t getChecksum() const { return fChecksum; }
    117 
    118     struct Entry {
    119         uint32_t fTag;
    120         uint32_t fLen;
    121     };
    122 
    123 #ifdef SK_DEBUG
    124     uint32_t getCount() const { return fCount; }
    125 #endif
    126 
    127 private:
    128     uint32_t fChecksum;  // must be first
    129     uint32_t fLength;    // must be second
    130     uint32_t fCount;
    131 
    132     static uint32_t ComputeChecksum(const SkDescriptor* desc)
    133     {
    134         const uint32_t*  ptr = (const uint32_t*)desc + 1; // skip the checksum field
    135         const uint32_t*  stop = (const uint32_t*)((const char*)desc + desc->fLength);
    136         uint32_t         sum = 0;
    137 
    138         SkASSERT(ptr < stop);
    139         do {
    140             sum = (sum << 1) | (sum >> 31);
    141             sum ^= *ptr++;
    142         } while (ptr < stop);
    143 
    144         return sum;
    145     }
    146 
    147     // private so no one can create one except our factories
    148     SkDescriptor() {}
    149 };
    150 
    151 #include "SkScalerContext.h"
    152 
    153 class SkAutoDescriptor : SkNoncopyable {
    154 public:
    155     SkAutoDescriptor(size_t size)
    156     {
    157         if (size <= sizeof(fStorage))
    158             fDesc = (SkDescriptor*)(void*)fStorage;
    159         else
    160             fDesc = SkDescriptor::Alloc(size);
    161     }
    162     ~SkAutoDescriptor()
    163     {
    164         if (fDesc != (SkDescriptor*)(void*)fStorage)
    165             SkDescriptor::Free(fDesc);
    166     }
    167     SkDescriptor* getDesc() const { return fDesc; }
    168 private:
    169     enum {
    170         kStorageSize =  sizeof(SkDescriptor)
    171                         + sizeof(SkDescriptor::Entry) + sizeof(SkScalerContext::Rec)    // for rec
    172                         + sizeof(SkDescriptor::Entry) + sizeof(void*)                   // for typeface
    173                         + 32   // slop for occational small extras
    174     };
    175     SkDescriptor*   fDesc;
    176     uint32_t        fStorage[(kStorageSize + 3) >> 2];
    177 };
    178 
    179 
    180 #endif
    181 
    182