7#include "otype_utilities.hpp"
9#include "../macros.hpp"
11hi_export_module(hikogui.font.otype_cmap);
13hi_export
namespace hi {
inline namespace v1 {
15[[nodiscard]]
inline std::span<std::byte const>
16otype_cmap_find(std::span<std::byte const> bytes, uint16_t platform_id, uint16_t platform_specific_id)
19 big_uint16_buf_t version;
20 big_uint16_buf_t num_tables;
24 big_uint16_buf_t platform_id;
25 big_uint16_buf_t platform_specific_id;
26 big_uint32_buf_t offset;
29 std::size_t offset = 0;
31 auto const& header = implicit_cast<header_type>(offset, bytes);
32 hi_check(*header.version == 0,
"CMAP version is not 0");
34 auto const entries = implicit_cast<entry_type>(offset, bytes, *header.num_tables);
37 if (
auto const entry = fast_binary_search_eq<std::endian::big>(entries, key)) {
38 return hi_check_subspan(bytes, *entry->offset);
44[[nodiscard]]
inline font_char_map otype_cmap_parse_map_4(std::span<std::byte const> over_sized_bytes)
47 big_uint16_buf_t format;
48 big_uint16_buf_t length;
49 big_uint16_buf_t language;
50 big_uint16_buf_t seg_count_x2;
51 big_uint16_buf_t search_range;
52 big_uint16_buf_t entry_selector;
53 big_uint16_buf_t range_shift;
57 auto const& header = implicit_cast<header_type>(offset, over_sized_bytes);
58 hi_axiom(*header.format == 4);
59 auto const length = *header.length;
60 auto const bytes = hi_check_subspan(over_sized_bytes, 0, length);
62 auto const seg_count = *header.seg_count_x2 / 2;
64 auto const end_codes = implicit_cast<big_uint16_buf_t>(offset, bytes, seg_count);
65 offset +=
sizeof(uint16_t);
66 auto const start_codes = implicit_cast<big_uint16_buf_t>(offset, bytes, seg_count);
68 auto const id_deltas = implicit_cast<big_uint16_buf_t>(offset, bytes, seg_count);
70 auto const id_range_offsets = implicit_cast<big_uint16_buf_t>(offset, bytes, seg_count);
72 auto const glyph_id_array_count = (bytes.size() - offset) /
sizeof(big_uint16_buf_t);
73 auto const glyph_id_array = implicit_cast<big_uint16_buf_t>(offset, bytes, glyph_id_array_count);
77 auto prev_end_code_point =
char32_t{0};
78 for (
auto i = 0_uz; i != seg_count; ++i) {
82 hi_check(start_code_point <= end_code_point,
"'cmap' subtable 4, start code-point must come before end code-point.");
84 i == 0 or prev_end_code_point < start_code_point,
85 "'cmap' subtable 4, all entries must be non-overlapping and ordered.");
87 if (start_code_point == 0xffff and end_code_point == 0xffff) {
93 if (id_range_offset == 0) {
95 auto start_glyph_id = *id_deltas[i];
99 start_glyph_id + (end_code_point - start_code_point) + 1_uz < 0xffff,
100 "'cmap' subtable 4, glyph_id must be in range 0 to 0xfffe.");
101 r.add(start_code_point, end_code_point, start_glyph_id);
108 id_range_offset /=
sizeof(big_uint16_buf_t);
110 id_range_offset -= seg_count - i;
113 auto const code_point_count = end_code_point - start_code_point + 1;
114 for (
auto j = 0_uz; j != code_point_count; ++j) {
117 auto const glyph_id = *hi_check_at(glyph_id_array, id_range_offset + j);
118 hi_check(
glyph_id < 0xfffe,
"'cmap' subtable 4, glyph_id must be in range 0 to 0xfffe.");
119 r.add(code_point, code_point,
glyph_id);
123 prev_end_code_point = end_code_point;
130[[nodiscard]]
inline font_char_map otype_cmap_parse_map_6(std::span<std::byte const> over_sized_bytes)
133 big_uint16_buf_t format;
134 big_uint16_buf_t length;
135 big_uint16_buf_t language;
136 big_uint16_buf_t first_code;
137 big_uint16_buf_t entry_count;
141 auto const& header = implicit_cast<header_type>(offset, over_sized_bytes);
142 hi_axiom(*header.format == 6);
143 auto const bytes = hi_check_subspan(over_sized_bytes, 0, *header.length);
145 auto const entry_count = *header.entry_count;
146 auto const entries = implicit_cast<big_uint16_buf_t>(offset, bytes, entry_count);
151 for (
auto i = 0_uz; i != entry_count; ++i, ++code_point) {
153 hi_check(
glyph_id < 0xfffe,
"'cmap' subtable 6, glyph_id must be in range 0 to 0xfffe.");
154 r.add(code_point, code_point,
glyph_id);
162[[nodiscard]]
inline font_char_map otype_cmap_parse_map_12(std::span<std::byte const> over_sized_bytes)
165 big_uint16_buf_t format;
166 big_uint16_buf_t reserved;
167 big_uint32_buf_t length;
168 big_uint32_buf_t language;
169 big_uint32_buf_t num_groups;
173 big_uint32_buf_t start_char_code;
174 big_uint32_buf_t end_char_code;
175 big_uint32_buf_t start_glyph_id;
179 auto const& header = implicit_cast<header_type>(offset, over_sized_bytes);
180 hi_axiom(*header.format == 12);
181 auto const bytes = hi_check_subspan(over_sized_bytes, 0, *header.length);
183 auto const entries = implicit_cast<entry_type>(offset, bytes, *header.num_groups);
187 for (
auto const& entry : entries) {
190 hi_check(start_code_point <= end_code_point,
"'cmap' subtable 12, has invalid code-point range.");
192 auto const start_glyph_id = *entry.start_glyph_id;
194 start_glyph_id + (end_code_point - start_code_point) + 1_uz < 0xffff,
195 "'cmap' subtable 12, glyph_id must be in range 0 to 0xfffe.");
204[[nodiscard]]
inline font_char_map otype_cmap_parse_map(std::span<std::byte const> bytes)
207 auto const format = *implicit_cast<big_uint16_buf_t>(bytes);
211 return otype_cmap_parse_map_4(bytes);
213 return otype_cmap_parse_map_6(bytes);
215 return otype_cmap_parse_map_12(bytes);
222[[nodiscard]]
inline font_char_map otype_cmap_parse(std::span<std::byte const> bytes)
224 constexpr auto search_order = std::array{
225 std::pair{uint16_t{0}, uint16_t{4}},
226 std::pair{uint16_t{0}, uint16_t{3}},
227 std::pair{uint16_t{0}, uint16_t{2}},
228 std::pair{uint16_t{0}, uint16_t{1}},
229 std::pair{uint16_t{3}, uint16_t{10}},
230 std::pair{uint16_t{3}, uint16_t{1}},
231 std::pair{uint16_t{3}, uint16_t{0}}
234 for (
auto const[platform_id, platform_specific_id] : search_order) {
235 if (
auto const map_bytes = otype_cmap_find(bytes, platform_id, platform_specific_id); not map_bytes.empty()) {
236 if (
auto r = otype_cmap_parse_map(map_bytes); not r.empty()) {
242 throw parse_error(
"'cmap' no compatible character map found.");
Defined font_char_map type.
The HikoGUI namespace.
Definition array_generic.hpp:21
The HikoGUI API version 1.
Definition array_generic.hpp:22
constexpr Out char_cast(In rhs) noexcept
Cast a character.
Definition cast.hpp:560
constexpr Out truncate(In rhs) noexcept
Cast between integral types truncating or zero-extending the result.
Definition cast.hpp:544
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:378
constexpr Out wide_cast(In const &rhs) noexcept
Cast to a type which can hold all values from the input type.
Definition cast.hpp:176
Character map of a font.
Definition font_char_map.hpp:34
constexpr void reserve(size_t n)
Reserve space for a set of ranges to be added.
Definition font_char_map.hpp:50
The identifier of a glyph in a font-file.
Definition glyph_id.hpp:22
Exception thrown during parsing on an error.
Definition exception_intf.hpp:48