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

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

mercurial