HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
otype_os2.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 "font_weight.hpp"
9#include "../utility/utility.hpp"
10#include <span>
11#include <cstddef>
12
13hi_export_module(hikogui.font.otype_os2);
14
15hi_export namespace hi { inline namespace v1 {
16
17[[nodiscard]] inline auto otype_parse_os2(std::span<std::byte const> bytes, float em_scale)
18{
19 struct panose_table {
20 uint8_t family_type;
21 uint8_t serif_style;
22 uint8_t weight;
23 uint8_t proportion;
24 uint8_t contrast;
25 uint8_t stroke_variation;
26 uint8_t arm_style;
27 uint8_t letterform;
28 uint8_t midline;
29 uint8_t x_height;
30 };
31
32 struct header_type_0 {
33 big_uint16_buf_t version;
34 big_int16_buf_t avg_char_width;
35 big_uint16_buf_t weight_class;
36 big_uint16_buf_t width_class;
37 big_uint16_buf_t type;
38 big_int16_buf_t subscript_x_size;
39 big_int16_buf_t subscript_y_size;
40 big_int16_buf_t subscript_x_offset;
41 big_int16_buf_t subscript_y_offset;
42 big_int16_buf_t superscript_x_size;
43 big_int16_buf_t superscript_y_size;
44 big_int16_buf_t superscript_x_offset;
45 big_int16_buf_t superscript_y_offset;
46 big_int16_buf_t strikeout_size;
47 big_int16_buf_t strikeout_position;
48 big_int16_buf_t family_class;
49 panose_table panose;
50 big_uint32_buf_t unicode_range_1;
51 big_uint32_buf_t unicode_range_2;
52 big_uint32_buf_t unicode_range_3;
53 big_uint32_buf_t unicode_range_4;
54 big_uint32_buf_t ach_vend_id;
55 big_uint16_buf_t selection;
56 big_uint16_buf_t first_char_index;
57 big_uint16_buf_t last_char_index;
58 };
59
60 struct header_type_2 : header_type_0 {
61 big_int16_buf_t typo_ascender;
62 big_int16_buf_t typo_descender;
63 big_int16_buf_t typo_line_gap;
64 big_uint16_buf_t win_ascent;
65 big_uint16_buf_t win_descent;
66 big_uint32_buf_t code_page_range_1;
67 big_uint32_buf_t code_page_range_2;
68 otype_fword_buf_t x_height;
69 otype_fword_buf_t cap_height;
70 big_uint16_buf_t default_char;
71 big_uint16_buf_t break_char;
72 big_uint16_buf_t max_context;
73 };
74
75 struct return_type {
76 font_weight weight = font_weight::medium;
77 bool condensed = false;
78 bool serif = false;
79 bool monospace = false;
80 bool italic = false;
81 float x_height = 0.0f;
82 float cap_height = 0.0f;
83 };
84
85 auto const& header = implicit_cast<header_type_0>(bytes);
86 hi_check(*header.version <= 5, "'OS/2' version must be between 0 and 5");
87
88 auto r = return_type{};
89
90 auto const weight_value = *header.weight_class;
91 if (weight_value >= 1 && weight_value <= 1000) {
92 r.weight = font_weight_from_int(weight_value);
93 }
94
95 auto const width_value = *header.width_class;
96 if (width_value >= 1 && width_value <= 4) {
97 r.condensed = true;
98 } else if (width_value >= 5 && width_value <= 9) {
99 r.condensed = false;
100 }
101
102 auto const serif_value = header.panose.serif_style;
103 if ((serif_value >= 2 && serif_value <= 10) || (serif_value >= 14 && serif_value <= 15)) {
104 r.serif = true;
105 } else if (serif_value >= 11 && serif_value <= 13) {
106 r.serif = false;
107 }
108
109 // The Panose weight table is odd, assuming the integer values are
110 // increasing with boldness, Thin is bolder then Light.
111 // The table below uses the integer value as an indication of boldness.
112 switch (header.panose.weight) {
113 case 2:
114 r.weight = font_weight::thin;
115 break;
116 case 3:
117 r.weight = font_weight::extra_light;
118 break;
119 case 4:
120 r.weight = font_weight::light;
121 break;
122 case 5:
123 r.weight = font_weight::regular;
124 break;
125 case 6:
126 r.weight = font_weight::medium;
127 break;
128 case 7:
129 r.weight = font_weight::semi_bold;
130 break;
131 case 8:
132 r.weight = font_weight::bold;
133 break;
134 case 9:
135 r.weight = font_weight::extra_bold;
136 break;
137 case 10:
138 r.weight = font_weight::black;
139 break;
140 case 11:
141 r.weight = font_weight::extra_black;
142 break;
143 default:
144 break;
145 }
146
147 switch (header.panose.proportion) {
148 case 2:
149 case 3:
150 case 4:
151 case 5:
152 case 7:
153 r.monospace = false;
154 r.condensed = false;
155 break;
156 case 6:
157 case 8:
158 r.monospace = false;
159 r.condensed = true;
160 break;
161 case 9:
162 r.monospace = true;
163 r.condensed = false;
164 break;
165 }
166
167 auto const letterform_value = header.panose.letterform;
168 if (letterform_value >= 2 && letterform_value <= 8) {
169 r.italic = false;
170 } else if (letterform_value >= 9 && letterform_value <= 15) {
171 r.italic = true;
172 }
173
174 if (*header.version >= 2) {
175 auto const &header_v2 = implicit_cast<header_type_2>(bytes);
176
177 r.x_height = header_v2.x_height * em_scale;
178 r.cap_height = header_v2.cap_height * em_scale;
179 }
180
181 return r;
182}
183
184}} // namespace hi::v1
The HikoGUI namespace.
Definition array_generic.hpp:20
@ italic
A font that is italic.
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
constexpr font_weight font_weight_from_int(numeric_integral auto rhs)
Convert a font weight value between 50 and 1000 to a font weight.
Definition font_weight.hpp:63
font_weight
Definition font_weight.hpp:21