HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
otype_name.hpp
1// Copyright Take Vos 2023.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "otype_utilities.hpp"
8#include "../utility/module.hpp"
9#include "../i18n/module.hpp"
10#include <span>
11#include <cstddef>
12
13namespace hi { inline namespace v1 {
14namespace detail {
15
17 big_uint16_buf_t length;
18 big_uint16_buf_t offset;
19};
20
21[[nodiscard]] inline language_tag otype_name_get_language_tag(
22 std::span<std::byte const> storage_bytes,
23 std::span<otype_name_language_entry_type const> language_tag_table,
24 uint16_t language_id)
25{
26 hi_axiom(language_id >= 0x8000);
27 hilet& entry = hi_check_at(language_tag_table, language_id - 0x8000);
28 hilet tag_bytes = hi_check_subspan(storage_bytes, *entry.offset, *entry.length);
29 return language_tag{std::string_view{reinterpret_cast<char const *>(tag_bytes.data()), tag_bytes.size()}};
30}
31
32[[nodiscard]] inline language_tag otype_name_get_language_unicode(
33 std::span<std::byte const> storage_bytes,
34 std::span<otype_name_language_entry_type const> language_tag_table,
35 uint16_t language_id)
36{
37 if (language_id == 0 or language_id == 0xffff) {
38 // In Unicode mode only language_id zero is defined, and defined as "no particular language".
39 return {"en"};
40
41 } else if (language_id >= 0x8000) {
42 // Use the optional language tag table.
43 return otype_name_get_language_tag(storage_bytes, language_tag_table, language_id);
44
45 } else {
46 // This language id is invalid.
47 return {};
48 }
49}
50
51[[nodiscard]] inline language_tag
52otype_name_get_language_quickdraw(std::span<std::byte const> storage_bytes, uint16_t platform_specific_id, uint16_t language_id)
53{
54 if (platform_specific_id == 0 and language_id == 0) {
55 // Roman, English.
56 return language_tag{"en"};
57 } else {
58 return language_tag{};
59 }
60}
61
62[[nodiscard]] inline language_tag otype_name_get_language_microsoft(
63 std::span<std::byte const> storage_bytes,
64 std::span<otype_name_language_entry_type const> language_tag_table,
65 uint16_t language_id)
66{
67 if (language_id == 0x409) {
68 return language_tag{"en-US"};
69 } else if (language_id >= 0x8000) {
70 return otype_name_get_language_tag(storage_bytes, language_tag_table, language_id);
71 } else {
72 return language_tag{};
73 }
74}
75
76[[nodiscard]] inline language_tag otype_name_get_language(
77 std::span<std::byte const> storage_bytes,
78 std::span<otype_name_language_entry_type const> language_tag_table,
79 uint16_t platform_id,
80 uint16_t platform_specific_id,
81 uint16_t language_id)
82{
83 switch (platform_id) {
84 case 0:
85 return otype_name_get_language_unicode(storage_bytes, language_tag_table, language_id);
86 case 1:
87 return otype_name_get_language_quickdraw(storage_bytes, platform_specific_id, language_id);
88 case 3:
89 return otype_name_get_language_microsoft(storage_bytes, language_tag_table, language_id);
90 default:
91 return {};
92 }
93}
94
95} // namespace detail
96
104[[nodiscard]] inline std::optional<std::string>
105otype_name_search(std::span<std::byte const> bytes, uint16_t name_id, language_tag language = language_tag{"en"})
106{
107 struct header_type_0 {
108 big_uint16_buf_t format;
109 big_uint16_buf_t count;
110 big_uint16_buf_t storage_offset;
111 };
112
113 struct header_type_1 : header_type_0 {
114 big_uint16_buf_t language_tag_count;
115 };
116
117 struct entry_type {
118 big_uint16_buf_t platform_id;
119 big_uint16_buf_t platform_specific_id;
120 big_uint16_buf_t language_id;
121 big_uint16_buf_t name_id;
122 big_uint16_buf_t length;
123 big_uint16_buf_t offset;
124 };
125
126 auto offset = 0_uz;
127 hilet& header = implicit_cast<header_type_0>(offset, bytes);
128
129 hilet format = *header.format;
130 hi_check(format == 0 or format == 1, "'name' table must be format 0 or format 1.");
131
132 hilet storage_bytes = hi_check_subspan(bytes, *header.storage_offset);
133
134 auto language_tag_count = 0_uz;
135 if (format == 1) {
136 offset = 0_uz;
137 hilet header1 = implicit_cast<header_type_1>(offset, bytes);
138 language_tag_count = *header1.language_tag_count;
139 }
140
141 hilet language_tag_table = implicit_cast<detail::otype_name_language_entry_type>(offset, bytes, language_tag_count);
142
143 hilet entries = implicit_cast<entry_type>(offset, bytes, *header.count);
144 for (hilet& entry : entries) {
145 if (*entry.name_id != name_id) {
146 continue;
147 }
148
149 hilet platform_id = *entry.platform_id;
150 hilet platform_specific_id = *entry.platform_specific_id;
151
152 hilet name_language = detail::otype_name_get_language(
153 storage_bytes, language_tag_table, platform_id, platform_specific_id, *entry.language_id);
154
155 if (not matches(name_language, language)) {
156 continue;
157 }
158
159 hilet name_bytes = hi_check_subspan(storage_bytes, *entry.offset, *entry.length);
160
161 if (auto s = otype_get_string(name_bytes, platform_id, platform_specific_id)) {
162 return s;
163 }
164 }
165
166 return std::nullopt;
167}
168
169[[nodiscard]] inline auto otype_name_get_family(std::span<std::byte const> bytes)
170{
171 struct return_type {
172 std::string family_name;
173 std::string sub_family_name;
174 };
175
176 auto r = return_type{};
177
178 if (auto typographic_family_name = otype_name_search(bytes, 16)) {
179 r.family_name = std::move(*typographic_family_name);
180 } else if (auto common_family_name = otype_name_search(bytes, 1)) {
181 r.family_name = std::move(*common_family_name);
182 }
183
184 if (auto typographic_sub_family_name = otype_name_search(bytes, 17)) {
185 r.sub_family_name = std::move(*typographic_sub_family_name);
186 } else if (auto common_sub_family_name = otype_name_search(bytes, 2)) {
187 r.sub_family_name = std::move(*common_sub_family_name);
188 }
189
190 return r;
191}
192
193}} // namespace hi::v1
#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
constexpr bool matches(text_phrasing_mask const &lhs, text_phrasing const &rhs) noexcept
Check if the text-phrasing is included in the text-phrasing-mask.
Definition text_phrasing.hpp:216
geometry/margins.hpp
Definition cache.hpp:11
std::optional< std::string > otype_name_search(std::span< std::byte const > bytes, uint16_t name_id, language_tag language=language_tag{"en"})
Get a name from the name table.
Definition otype_name.hpp:105
T move(T... args)