gfx/graphite2/src/SegCache.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /*  GRAPHITE2 LICENSING
     3     Copyright 2010, SIL International
     4     All rights reserved.
     6     This library is free software; you can redistribute it and/or modify
     7     it under the terms of the GNU Lesser General Public License as published
     8     by the Free Software Foundation; either version 2.1 of License, or
     9     (at your option) any later version.
    11     This program is distributed in the hope that it will be useful,
    12     but WITHOUT ANY WARRANTY; without even the implied warranty of
    13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    14     Lesser General Public License for more details.
    16     You should also have received a copy of the GNU Lesser General Public
    17     License along with this library in the file named "LICENSE".
    18     If not, write to the Free Software Foundation, 51 Franklin Street,
    19     Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    20     internet at http://www.fsf.org/licenses/lgpl.html.
    22 Alternatively, the contents of this file may be used under the terms of the
    23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
    24 License, as published by the Free Software Foundation, either version 2
    25 of the License or (at your option) any later version.
    26 */
    28 #include "inc/Main.h"
    29 #include "inc/TtfTypes.h"
    30 #include "inc/TtfUtil.h"
    31 #include "inc/SegCache.h"
    32 #include "inc/SegCacheEntry.h"
    33 #include "inc/SegCacheStore.h"
    34 #include "inc/CmapCache.h"
    37 using namespace graphite2;
    39 #ifndef GRAPHITE2_NSEGCACHE
    41 SegCache::SegCache(const SegCacheStore * store, const Features & feats)
    42 : m_prefixLength(ePrefixLength),
    43   m_maxCachedSegLength(eMaxSpliceSize),
    44   m_segmentCount(0),
    45   m_features(feats),
    46   m_totalAccessCount(0l), m_totalMisses(0l),
    47   m_purgeFactor(1.0f / (ePurgeFactor * store->maxSegmentCount()))
    48 {
    49     m_prefixes.raw = grzeroalloc<void*>(store->maxCmapGid() + 2);
    50     m_prefixes.range[SEG_CACHE_MIN_INDEX] = SEG_CACHE_UNSET_INDEX;
    51     m_prefixes.range[SEG_CACHE_MAX_INDEX] = SEG_CACHE_UNSET_INDEX;
    52 }
    54 void SegCache::freeLevel(SegCacheStore * store, SegCachePrefixArray prefixes, size_t level)
    55 {
    56     for (size_t i = 0; i < store->maxCmapGid(); i++)
    57     {
    58         if (prefixes.array[i].raw)
    59         {
    60             if (level + 1 < ePrefixLength)
    61                 freeLevel(store, prefixes.array[i], level + 1);
    62             else
    63             {
    64                 SegCachePrefixEntry * prefixEntry = prefixes.prefixEntries[i];
    65                 delete prefixEntry;
    66             }
    67         }
    68     }
    69     free(prefixes.raw);
    70 }
    72 void SegCache::clear(SegCacheStore * store)
    73 {
    74     freeLevel(store, m_prefixes, 0);
    75     m_prefixes.raw = NULL;
    76 }
    78 SegCache::~SegCache()
    79 {
    80     assert(m_prefixes.raw == NULL);
    81 }
    83 SegCacheEntry* SegCache::cache(SegCacheStore * store, const uint16* cmapGlyphs, size_t length, Segment * seg, size_t charOffset)
    84 {
    85     uint16 pos = 0;
    86     if (!length) return NULL;
    87     assert(length < m_maxCachedSegLength);
    88     SegCachePrefixArray pArray = m_prefixes;
    89     while (pos + 1 < m_prefixLength)
    90     {
    91         uint16 gid = (pos < length)? cmapGlyphs[pos] : 0;
    92         if (!pArray.array[gid].raw)
    93         {
    94             pArray.array[gid].raw = grzeroalloc<void*>(store->maxCmapGid() + 2);
    95             if (!pArray.array[gid].raw)
    96                 return NULL; // malloc failed
    97             if (pArray.range[SEG_CACHE_MIN_INDEX] == SEG_CACHE_UNSET_INDEX)
    98             {
    99                 pArray.range[SEG_CACHE_MIN_INDEX] = gid;
   100                 pArray.range[SEG_CACHE_MAX_INDEX] = gid;
   101             }
   102             else
   103             {
   104                 if (gid < pArray.range[SEG_CACHE_MIN_INDEX])
   105                     pArray.range[SEG_CACHE_MIN_INDEX] = gid;
   106                 else if (gid > pArray.range[SEG_CACHE_MAX_INDEX])
   107                     pArray.range[SEG_CACHE_MAX_INDEX] = gid;
   108             }
   109         }
   110         pArray = pArray.array[gid];
   111         ++pos;
   112     }
   113     uint16 gid = (pos < length)? cmapGlyphs[pos] : 0;
   114     SegCachePrefixEntry * prefixEntry = pArray.prefixEntries[gid];
   115     if (!prefixEntry)
   116     {
   117         prefixEntry = new SegCachePrefixEntry();
   118         pArray.prefixEntries[gid] = prefixEntry;
   119         if (pArray.range[SEG_CACHE_MIN_INDEX] == SEG_CACHE_UNSET_INDEX)
   120         {
   121             pArray.range[SEG_CACHE_MIN_INDEX] = gid;
   122             pArray.range[SEG_CACHE_MAX_INDEX] = gid;
   123         }
   124         else
   125         {
   126             if (gid < pArray.range[SEG_CACHE_MIN_INDEX])
   127                 pArray.range[SEG_CACHE_MIN_INDEX] = gid;
   128             else if (gid > pArray.range[SEG_CACHE_MAX_INDEX])
   129                 pArray.range[SEG_CACHE_MAX_INDEX] = gid;
   130         }
   131     }
   132     if (!prefixEntry) return NULL;
   133     // if the cache is full run a purge - this is slow, since it walks the tree
   134     if (m_segmentCount + 1 > store->maxSegmentCount())
   135     {
   136         purge(store);
   137         assert(m_segmentCount < store->maxSegmentCount());
   138     }
   139     SegCacheEntry * pEntry = prefixEntry->cache(cmapGlyphs, length, seg, charOffset, m_totalAccessCount);
   140     if (pEntry) ++m_segmentCount;
   141     return pEntry;
   142 }
   144 void SegCache::purge(SegCacheStore * store)
   145 {
   146     unsigned long long minAccessCount = static_cast<unsigned long long>(m_totalAccessCount * m_purgeFactor + 1);
   147     if (minAccessCount < 2) minAccessCount = 2;
   148     unsigned long long oldAccessTime = m_totalAccessCount - store->maxSegmentCount() / eAgeFactor;
   149     purgeLevel(store, m_prefixes, 0, minAccessCount, oldAccessTime);
   150 }
   152 void SegCache::purgeLevel(SegCacheStore * store, SegCachePrefixArray prefixes, size_t level,
   153                           unsigned long long minAccessCount, unsigned long long oldAccessTime)
   154 {
   155     if (prefixes.range[SEG_CACHE_MIN_INDEX] == SEG_CACHE_UNSET_INDEX) return;
   156     size_t maxGlyphCached = prefixes.range[SEG_CACHE_MAX_INDEX];
   157     for (size_t i = prefixes.range[SEG_CACHE_MIN_INDEX]; i <= maxGlyphCached; i++)
   158     {
   159         if (prefixes.array[i].raw)
   160         {
   161             if (level + 1 < ePrefixLength)
   162                 purgeLevel(store, prefixes.array[i], level + 1, minAccessCount, oldAccessTime);
   163             else
   164             {
   165                 SegCachePrefixEntry * prefixEntry = prefixes.prefixEntries[i];
   166                 m_segmentCount -= prefixEntry->purge(minAccessCount,
   167                     oldAccessTime, m_totalAccessCount);
   168             }
   169         }
   170     }
   171 }
   173 uint32 SegCachePrefixEntry::purge(unsigned long long minAccessCount,
   174                                               unsigned long long oldAccessTime,
   175                                               unsigned long long currentTime)
   176 {
   177     // ignore the purge request if another has been done recently
   178     //if (m_lastPurge > oldAccessTime)
   179     //    return 0;
   181     uint32 totalPurged = 0;
   182     // real length is length + 1 in this loop
   183     for (uint16 length = 0; length < eMaxSpliceSize; length++)
   184     {
   185         if (m_entryCounts[length] == 0)
   186             continue;
   187         uint16 purgeCount = 0;
   188         uint16 newIndex = 0;
   189         for (uint16 j = 0; j < m_entryCounts[length]; j++)
   190         {
   191             SegCacheEntry & tempEntry = m_entries[length][j];
   192             // purge entries with a low access count which haven't been
   193             // accessed recently
   194             if (tempEntry.accessCount() <= minAccessCount &&
   195                 tempEntry.lastAccess() <= oldAccessTime)
   196             {
   197                 tempEntry.clear();
   198                 ++purgeCount;
   199             }
   200             else
   201             {
   202                 memcpy(m_entries[length] + newIndex++, m_entries[length] + j, sizeof(SegCacheEntry));
   203             }
   204         }
   205         if (purgeCount == m_entryCounts[length])
   206         {
   207             assert(newIndex == 0);
   208             m_entryCounts[length] = 0;
   209             m_entryBSIndex[length] = 0;
   210             free(m_entries[length]);
   211             m_entries[length] = NULL;
   212         }
   213         else if (purgeCount > 0)
   214         {
   215             assert(m_entryCounts[length] == newIndex + purgeCount);
   216             m_entryCounts[length] = newIndex;
   217         }
   218         totalPurged += purgeCount;
   219     }
   220     m_lastPurge = currentTime;
   221     return totalPurged;
   222 }
   224 #endif

mercurial