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