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     struct Entry {
    124         uint32_t fTag;
    125         uint32_t fLen;
    126     };
    127 
    128 #ifdef SK_DEBUG
    129     uint32_t getChecksum() const { return fChecksum; }
    130     uint32_t getCount() const { return fCount; }
    131 #endif
    132 
    133 private:
    134     uint32_t fChecksum;  // must be first
    135     uint32_t fLength;    // must be second
    136     uint32_t fCount;
    137 
    138     static uint32_t ComputeChecksum(const SkDescriptor* desc)
    139     {
    140         const uint32_t*  ptr = (const uint32_t*)desc + 1; // skip the checksum field
    141         const uint32_t*  stop = (const uint32_t*)((const char*)desc + desc->fLength);
    142         uint32_t         sum = 0;
    143 
    144         SkASSERT(ptr < stop);
    145         do {
    146             sum = (sum << 1) | (sum >> 31);
    147             sum ^= *ptr++;
    148         } while (ptr < stop);
    149 
    150         return sum;
    151     }
    152 
    153     // private so no one can create one except our factories
    154     SkDescriptor() {}
    155 };
    156 
    157 #include "SkScalerContext.h"
    158 
    159 class SkAutoDescriptor : SkNoncopyable {
    160 public:
    161     SkAutoDescriptor(size_t size)
    162     {
    163         if (size <= sizeof(fStorage))
    164             fDesc = (SkDescriptor*)(void*)fStorage;
    165         else
    166             fDesc = SkDescriptor::Alloc(size);
    167     }
    168     ~SkAutoDescriptor()
    169     {
    170         if (fDesc != (SkDescriptor*)(void*)fStorage)
    171             SkDescriptor::Free(fDesc);
    172     }
    173     SkDescriptor* getDesc() const { return fDesc; }
    174 private:
    175     enum {
    176         kStorageSize =  sizeof(SkDescriptor)
    177                         + sizeof(SkDescriptor::Entry) + sizeof(SkScalerContext::Rec)    // for rec
    178                         + sizeof(SkDescriptor::Entry) + sizeof(void*)                   // for typeface
    179                         + 32   // slop for occational small extras
    180     };
    181     SkDescriptor*   fDesc;
    182     uint32_t        fStorage[(kStorageSize + 3) >> 2];
    183 };
    184 
    185 
    186 #endif
    187 
    188