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