michael@0: /* GRAPHITE2 LICENSING michael@0: michael@0: Copyright 2010, SIL International michael@0: All rights reserved. michael@0: michael@0: This library is free software; you can redistribute it and/or modify michael@0: it under the terms of the GNU Lesser General Public License as published michael@0: by the Free Software Foundation; either version 2.1 of License, or michael@0: (at your option) any later version. michael@0: michael@0: This program is distributed in the hope that it will be useful, michael@0: but WITHOUT ANY WARRANTY; without even the implied warranty of michael@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU michael@0: Lesser General Public License for more details. michael@0: michael@0: You should also have received a copy of the GNU Lesser General Public michael@0: License along with this library in the file named "LICENSE". michael@0: If not, write to the Free Software Foundation, 51 Franklin Street, michael@0: Suite 500, Boston, MA 02110-1335, USA or visit their web page on the michael@0: internet at http://www.fsf.org/licenses/lgpl.html. michael@0: michael@0: Alternatively, the contents of this file may be used under the terms of the michael@0: Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public michael@0: License, as published by the Free Software Foundation, either version 2 michael@0: of the License or (at your option) any later version. michael@0: */ michael@0: michael@0: #include "inc/Main.h" michael@0: #include "inc/CmapCache.h" michael@0: #include "inc/Face.h" michael@0: #include "inc/TtfTypes.h" michael@0: #include "inc/TtfUtil.h" michael@0: michael@0: michael@0: using namespace graphite2; michael@0: michael@0: const void * bmp_subtable(const Face::Table & cmap) michael@0: { michael@0: const void * stbl; michael@0: if (!cmap.size()) return 0; michael@0: if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size())) michael@0: || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size())) michael@0: || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size())) michael@0: || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size())) michael@0: || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()))) michael@0: return stbl; michael@0: return 0; michael@0: } michael@0: michael@0: const void * smp_subtable(const Face::Table & cmap) michael@0: { michael@0: const void * stbl; michael@0: if (!cmap.size()) return 0; michael@0: if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size())) michael@0: || TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()))) michael@0: return stbl; michael@0: return 0; michael@0: } michael@0: michael@0: template michael@0: bool cache_subtable(uint16 * blocks[], const void * cst, const unsigned int limit) michael@0: { michael@0: int rangeKey = 0; michael@0: uint32 codePoint = NextCodePoint(cst, 0, &rangeKey), michael@0: prevCodePoint = 0; michael@0: while (codePoint != limit) michael@0: { michael@0: unsigned int block = codePoint >> 8; michael@0: if (!blocks[block]) michael@0: { michael@0: blocks[block] = grzeroalloc(0x100); michael@0: if (!blocks[block]) michael@0: return false; michael@0: } michael@0: blocks[block][codePoint & 0xFF] = LookupCodePoint(cst, codePoint, rangeKey); michael@0: // prevent infinite loop michael@0: if (codePoint <= prevCodePoint) michael@0: codePoint = prevCodePoint + 1; michael@0: prevCodePoint = codePoint; michael@0: codePoint = NextCodePoint(cst, codePoint, &rangeKey); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: michael@0: CachedCmap::CachedCmap(const Face & face) michael@0: : m_isBmpOnly(true), michael@0: m_blocks(0) michael@0: { michael@0: const Face::Table cmap(face, Tag::cmap); michael@0: if (!cmap) return; michael@0: michael@0: const void * bmp_cmap = bmp_subtable(cmap); michael@0: const void * smp_cmap = smp_subtable(cmap); michael@0: m_isBmpOnly = !smp_cmap; michael@0: michael@0: m_blocks = grzeroalloc(m_isBmpOnly ? 0x100 : 0x1100); michael@0: if (m_blocks && smp_cmap) michael@0: { michael@0: if (!cache_subtable(m_blocks, smp_cmap, 0x10FFFF)) michael@0: return; michael@0: } michael@0: michael@0: if (m_blocks && bmp_cmap) michael@0: { michael@0: if (!cache_subtable(m_blocks, bmp_cmap, 0xFFFF)) michael@0: return; michael@0: } michael@0: } michael@0: michael@0: CachedCmap::~CachedCmap() throw() michael@0: { michael@0: if (!m_blocks) return; michael@0: unsigned int numBlocks = (m_isBmpOnly)? 0x100 : 0x1100; michael@0: for (unsigned int i = 0; i < numBlocks; i++) michael@0: free(m_blocks[i]); michael@0: free(m_blocks); michael@0: } michael@0: michael@0: uint16 CachedCmap::operator [] (const uint32 usv) const throw() michael@0: { michael@0: if ((m_isBmpOnly && usv > 0xFFFF) || (usv > 0x10FFFF)) michael@0: return 0; michael@0: const uint32 block = 0xFFFF & (usv >> 8); michael@0: if (m_blocks[block]) michael@0: return m_blocks[block][usv & 0xFF]; michael@0: return 0; michael@0: }; michael@0: michael@0: CachedCmap::operator bool() const throw() michael@0: { michael@0: return m_blocks != 0; michael@0: } michael@0: michael@0: michael@0: DirectCmap::DirectCmap(const Face & face) michael@0: : _cmap(face, Tag::cmap), michael@0: _smp(smp_subtable(_cmap)), michael@0: _bmp(bmp_subtable(_cmap)) michael@0: { michael@0: } michael@0: michael@0: uint16 DirectCmap::operator [] (const uint32 usv) const throw() michael@0: { michael@0: return usv > 0xFFFF michael@0: ? (_smp ? TtfUtil::CmapSubtable12Lookup(_smp, usv, 0) : 0) michael@0: : TtfUtil::CmapSubtable4Lookup(_bmp, usv, 0); michael@0: } michael@0: michael@0: DirectCmap::operator bool () const throw() michael@0: { michael@0: return _cmap && _bmp; michael@0: } michael@0: