1 | // SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later |
2 | // Copyright 2010, SIL International, All rights reserved. |
3 | |
4 | |
5 | #include "inc/Main.h" |
6 | #include "inc/CmapCache.h" |
7 | #include "inc/Face.h" |
8 | #include "inc/TtfTypes.h" |
9 | #include "inc/TtfUtil.h" |
10 | |
11 | |
12 | using namespace graphite2; |
13 | |
14 | const void * bmp_subtable(const Face::Table & cmap) |
15 | { |
16 | const void * stbl; |
17 | if (!cmap.size()) return 0; |
18 | if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()), cmap + cmap.size()) |
19 | || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()), cmap + cmap.size()) |
20 | || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()), cmap + cmap.size()) |
21 | || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()), cmap + cmap.size()) |
22 | || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()), cmap + cmap.size())) |
23 | return stbl; |
24 | return 0; |
25 | } |
26 | |
27 | const void * smp_subtable(const Face::Table & cmap) |
28 | { |
29 | const void * stbl; |
30 | if (!cmap.size()) return 0; |
31 | if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()), cmap + cmap.size()) |
32 | || TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()), cmap + cmap.size())) |
33 | return stbl; |
34 | return 0; |
35 | } |
36 | |
37 | template <unsigned int (*NextCodePoint)(const void *, unsigned int, int *), |
38 | uint16 (*LookupCodePoint)(const void *, unsigned int, int)> |
39 | bool cache_subtable(uint16 * blocks[], const void * cst, const unsigned int limit) |
40 | { |
41 | int rangeKey = 0; |
42 | uint32 codePoint = NextCodePoint(cst, 0, &rangeKey), |
43 | prevCodePoint = 0; |
44 | while (codePoint < limit) |
45 | { |
46 | unsigned int block = codePoint >> 8; |
47 | if (!blocks[block]) |
48 | { |
49 | blocks[block] = grzeroalloc<uint16>(0x100); |
50 | if (!blocks[block]) |
51 | return false; |
52 | } |
53 | blocks[block][codePoint & 0xFF] = LookupCodePoint(cst, codePoint, rangeKey); |
54 | // prevent infinite loop |
55 | if (codePoint <= prevCodePoint) |
56 | codePoint = prevCodePoint + 1; |
57 | prevCodePoint = codePoint; |
58 | codePoint = NextCodePoint(cst, codePoint, &rangeKey); |
59 | } |
60 | return true; |
61 | } |
62 | |
63 | |
64 | CachedCmap::CachedCmap(const Face & face) |
65 | : m_isBmpOnly(true), |
66 | m_blocks(0) |
67 | { |
68 | const Face::Table cmap(face, Tag::cmap); |
69 | if (!cmap) return; |
70 | |
71 | const void * bmp_cmap = bmp_subtable(cmap); |
72 | const void * smp_cmap = smp_subtable(cmap); |
73 | m_isBmpOnly = !smp_cmap; |
74 | |
75 | m_blocks = grzeroalloc<uint16 *>(m_isBmpOnly ? 0x100 : 0x1100); |
76 | if (m_blocks && smp_cmap) |
77 | { |
78 | if (!cache_subtable<TtfUtil::CmapSubtable12NextCodepoint, TtfUtil::CmapSubtable12Lookup>(m_blocks, smp_cmap, 0x10FFFF)) |
79 | return; |
80 | } |
81 | |
82 | if (m_blocks && bmp_cmap) |
83 | { |
84 | if (!cache_subtable<TtfUtil::CmapSubtable4NextCodepoint, TtfUtil::CmapSubtable4Lookup>(m_blocks, bmp_cmap, 0xFFFF)) |
85 | return; |
86 | } |
87 | } |
88 | |
89 | CachedCmap::~CachedCmap() throw() |
90 | { |
91 | if (!m_blocks) return; |
92 | unsigned int numBlocks = (m_isBmpOnly)? 0x100 : 0x1100; |
93 | for (unsigned int i = 0; i < numBlocks; i++) |
94 | free(m_blocks[i]); |
95 | free(m_blocks); |
96 | } |
97 | |
98 | uint16 CachedCmap::operator [] (const uint32 usv) const throw() |
99 | { |
100 | if ((m_isBmpOnly && usv > 0xFFFF) || (usv > 0x10FFFF)) |
101 | return 0; |
102 | const uint32 block = 0xFFFF & (usv >> 8); |
103 | if (m_blocks[block]) |
104 | return m_blocks[block][usv & 0xFF]; |
105 | return 0; |
106 | }; |
107 | |
108 | CachedCmap::operator bool() const throw() |
109 | { |
110 | return m_blocks != 0; |
111 | } |
112 | |
113 | |
114 | DirectCmap::DirectCmap(const Face & face) |
115 | : _cmap(face, Tag::cmap), |
116 | _smp(smp_subtable(_cmap)), |
117 | _bmp(bmp_subtable(_cmap)) |
118 | { |
119 | } |
120 | |
121 | uint16 DirectCmap::operator [] (const uint32 usv) const throw() |
122 | { |
123 | return usv > 0xFFFF |
124 | ? (_smp ? TtfUtil::CmapSubtable12Lookup(_smp, usv, 0) : 0) |
125 | : TtfUtil::CmapSubtable4Lookup(_bmp, usv, 0); |
126 | } |
127 | |
128 | DirectCmap::operator bool () const throw() |
129 | { |
130 | return _cmap && _bmp; |
131 | } |
132 | |
133 | |