7#include "otype_utilities.hpp"
10namespace hi {
inline namespace v1 {
12[[nodiscard]]
inline std::span<std::byte const>
13otype_cmap_find(std::span<std::byte const> bytes, uint16_t platform_id, uint16_t platform_specific_id)
16 big_uint16_buf_t version;
17 big_uint16_buf_t num_tables;
21 big_uint16_buf_t platform_id;
22 big_uint16_buf_t platform_specific_id;
23 big_uint32_buf_t offset;
28 hilet& header = implicit_cast<header_type>(offset, bytes);
29 hi_check(*header.version == 0,
"CMAP version is not 0");
31 hilet entries = implicit_cast<entry_type>(offset, bytes, *header.num_tables);
33 auto key = (truncate<uint32_t>(platform_id) << 16) | truncate<uint32_t>(platform_specific_id);
34 if (
hilet entry = fast_binary_search_eq<std::endian::big>(entries, key)) {
41[[nodiscard]]
inline font_char_map otype_cmap_parse_map_4(std::span<std::byte const> over_sized_bytes)
44 big_uint16_buf_t format;
45 big_uint16_buf_t length;
46 big_uint16_buf_t language;
47 big_uint16_buf_t seg_count_x2;
48 big_uint16_buf_t search_range;
49 big_uint16_buf_t entry_selector;
50 big_uint16_buf_t range_shift;
54 hilet& header = implicit_cast<header_type>(offset, over_sized_bytes);
56 hilet length = *header.length;
59 hilet seg_count = *header.seg_count_x2 / 2;
61 hilet end_codes = implicit_cast<big_uint16_buf_t>(offset, bytes, seg_count);
62 offset +=
sizeof(uint16_t);
63 hilet start_codes = implicit_cast<big_uint16_buf_t>(offset, bytes, seg_count);
65 hilet id_deltas = implicit_cast<big_uint16_buf_t>(offset, bytes, seg_count);
67 hilet id_range_offsets = implicit_cast<big_uint16_buf_t>(offset, bytes, seg_count);
69 hilet glyph_id_array_count = (bytes.size() - offset) /
sizeof(big_uint16_buf_t);
70 hilet glyph_id_array = implicit_cast<big_uint16_buf_t>(offset, bytes, glyph_id_array_count);
72 auto r = font_char_map{};
74 auto prev_end_code_point =
char32_t{0};
75 for (
auto i = 0_uz; i != seg_count; ++i) {
76 hilet end_code_point = char_cast<char32_t>(*end_codes[i]);
77 hilet start_code_point = char_cast<char32_t>(*start_codes[i]);
79 hi_check(start_code_point <= end_code_point,
"'cmap' subtable 4, start code-point must come before end code-point.");
81 i == 0 or prev_end_code_point < start_code_point,
82 "'cmap' subtable 4, all entries must be non-overlapping and ordered.");
84 if (start_code_point == 0xffff and end_code_point == 0xffff) {
89 auto id_range_offset = wide_cast<size_t>(*id_range_offsets[i]);
90 if (id_range_offset == 0) {
92 auto start_glyph_id = *id_deltas[i];
93 start_glyph_id += char_cast<uint16_t>(start_code_point);
96 start_glyph_id + (end_code_point - start_code_point) + 1_uz < 0xffff,
97 "'cmap' subtable 4, glyph_id must be in range 0 to 0xfffe.");
98 r.add(start_code_point, end_code_point, start_glyph_id);
105 id_range_offset /=
sizeof(big_uint16_buf_t);
107 id_range_offset -= seg_count - i;
110 hilet code_point_count = end_code_point - start_code_point + 1;
111 for (
auto j = 0_uz; j != code_point_count; ++j) {
112 hilet code_point = char_cast<char32_t>(start_code_point + j);
115 hi_check(glyph_id < 0xfffe,
"'cmap' subtable 4, glyph_id must be in range 0 to 0xfffe.");
116 r.add(code_point, code_point, glyph_id);
120 prev_end_code_point = end_code_point;
127[[nodiscard]]
inline font_char_map otype_cmap_parse_map_6(std::span<std::byte const> over_sized_bytes)
130 big_uint16_buf_t format;
131 big_uint16_buf_t length;
132 big_uint16_buf_t language;
133 big_uint16_buf_t first_code;
134 big_uint16_buf_t entry_count;
138 hilet& header = implicit_cast<header_type>(offset, over_sized_bytes);
142 hilet entry_count = *header.entry_count;
143 hilet entries = implicit_cast<big_uint16_buf_t>(offset, bytes, entry_count);
145 auto r = font_char_map{};
146 r.reserve(entry_count);
147 auto code_point = char_cast<char32_t>(*header.first_code);
148 for (
auto i = 0_uz; i != entry_count; ++i, ++code_point) {
149 hilet glyph_id = *entries[i];
150 hi_check(glyph_id < 0xfffe,
"'cmap' subtable 6, glyph_id must be in range 0 to 0xfffe.");
151 r.add(code_point, code_point, glyph_id);
159[[nodiscard]]
inline font_char_map otype_cmap_parse_map_12(std::span<std::byte const> over_sized_bytes)
162 big_uint16_buf_t format;
163 big_uint16_buf_t reserved;
164 big_uint32_buf_t length;
165 big_uint32_buf_t language;
166 big_uint32_buf_t num_groups;
170 big_uint32_buf_t start_char_code;
171 big_uint32_buf_t end_char_code;
172 big_uint32_buf_t start_glyph_id;
176 hilet& header = implicit_cast<header_type>(offset, over_sized_bytes);
180 hilet entries = implicit_cast<entry_type>(offset, bytes, *header.num_groups);
182 auto r = font_char_map{};
183 r.reserve(*header.num_groups);
184 for (
hilet& entry : entries) {
185 hilet start_code_point = char_cast<char32_t>(*entry.start_char_code);
186 hilet end_code_point = char_cast<char32_t>(*entry.end_char_code);
187 hi_check(start_code_point <= end_code_point,
"'cmap' subtable 12, has invalid code-point range.");
189 hilet start_glyph_id = *entry.start_glyph_id;
191 start_glyph_id + (end_code_point - start_code_point) + 1_uz < 0xffff,
192 "'cmap' subtable 12, glyph_id must be in range 0 to 0xfffe.");
193 r.add(start_code_point, end_code_point, narrow_cast<uint16_t>(start_glyph_id));
201[[nodiscard]]
inline font_char_map otype_cmap_parse_map(std::span<std::byte const> bytes)
204 hilet format = *implicit_cast<big_uint16_buf_t>(bytes);
208 return otype_cmap_parse_map_4(bytes);
210 return otype_cmap_parse_map_6(bytes);
212 return otype_cmap_parse_map_12(bytes);
219[[nodiscard]]
inline font_char_map otype_cmap_parse(std::span<std::byte const> bytes)
231 for (
hilet[platform_id, platform_specific_id] : search_order) {
232 if (
hilet map_bytes = otype_cmap_find(bytes, platform_id, platform_specific_id); not map_bytes.empty()) {
233 if (
auto r = otype_cmap_parse_map(map_bytes); not r.empty()) {
239 throw parse_error(
"'cmap' no compatible character map found.");
Defined font_char_map type.
#define hi_check(expression, message,...)
Check if the expression is valid, or throw a parse_error.
Definition assert.hpp:110
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hi_check_at(span, index)
Get an element from a span, or throw a parse_error.
Definition assert.hpp:176
#define hi_check_subspan(span, offset,...)
Get a subspan, or throw a parse_error.
Definition assert.hpp:151
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11