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