xref: /aosp_15_r20/external/angle/src/libANGLE/gen_overlay_fonts.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1#!/usr/bin/env vpython3
2#
3# [VPYTHON:BEGIN]
4# wheel: <
5#   name: "infra/python/wheels/freetype-py/${vpython_platform}"
6#   version: "version:2.2.0.chromium.4"
7# >
8# [VPYTHON:END]
9
10# Copyright 2019 The ANGLE Project Authors. All rights reserved.
11# Use of this source code is governed by a BSD-style license that can be
12# found in the LICENSE file.
13#
14# gen_vk_overlay_fonts.py:
15#  Code generation for overlay fonts.  Should be run if the font file under overlay/ is changed,
16#  or the font sizes declared in this file are modified.  The font is assumed to be monospace.
17#  The output will contain ASCII characters in order from ' ' to '~'.  The output will be images
18#  with 95 layers, with each smaller font size having half the size of the previous to form a mip
19#  chain.
20#  NOTE: don't run this script directly. Run scripts/run_code_generation.py.
21
22import sys
23
24# Conditional import enables getting inputs/outputs with python3 instead of vpython3
25if len(sys.argv) < 2:
26    from freetype import *
27
28out_file_cpp = 'Overlay_font_autogen.cpp'
29out_file_h = 'Overlay_font_autogen.h'
30font_file = 'overlay/RobotoMono-Bold.ttf'
31font_license = u"""// Font copyright Google:
32//
33//     Licensed under the Apache License, Version 2.0 (the "License");
34//     you may not use this file except in compliance with the License.
35//     You may obtain a copy of the License at
36//
37//         http://www.apache.org/licenses/LICENSE-2.0
38//
39//     Unless required by applicable law or agreed to in writing, software
40//     distributed under the License is distributed on an "AS IS" BASIS,
41//     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
42//     See the License for the specific language governing permissions and
43//     limitations under the License."""
44
45template_out_file_h = u"""// GENERATED FILE - DO NOT EDIT.
46// Generated by {script_name} using {font_file}.
47//
48// Copyright 2022 The ANGLE Project Authors. All rights reserved.
49// Use of this source code is governed by a BSD-style license that can be
50// found in the LICENSE file.
51//
52// {out_file_name}:
53//   Autogenerated overlay font data.
54
55#include "libANGLE/Overlay.h"
56
57namespace gl
58{{
59namespace overlay
60{{
61constexpr uint32_t kFontMipCount = {font_count};
62constexpr uint32_t kFontCharacters = {char_count};
63constexpr uint32_t kFontGlyphWidth = {max_font_width};
64constexpr uint32_t kFontGlyphHeight = {max_font_height};
65constexpr uint32_t kFontMipDataSize[kFontMipCount] = {{{font_mip_data_sizes}}};
66constexpr uint32_t kFontMipDataOffset[kFontMipCount] = {{{font_mip_data_offsets}}};
67constexpr uint32_t kFontTotalDataSize = {total_font_data_size};
68{font_mips}
69}}  // namespace overlay
70}}  // namespace gl
71
72"""
73
74template_out_file_cpp = u"""// GENERATED FILE - DO NOT EDIT.
75// Generated by {script_name} using images from {font_file}.
76//
77// Copyright 2022 The ANGLE Project Authors. All rights reserved.
78// Use of this source code is governed by a BSD-style license that can be
79// found in the LICENSE file.
80//
81{font_license}
82//
83// {out_file_name}:
84//   Autogenerated overlay font data.
85
86#include "libANGLE/Overlay.h"
87#include "libANGLE/Overlay_font_autogen.h"
88
89#include <numeric>
90
91namespace gl
92{{
93using namespace overlay;
94
95// Save binary size if the font images are never to be used.
96#if ANGLE_ENABLE_OVERLAY
97namespace
98{{
99constexpr uint8_t kFontData[{total_font_data_size}] = {{
100// clang-format off
101{all_font_data}
102// clang-format on
103}};
104}}  // anonymous namespace
105
106const uint8_t *OverlayState::getFontData() const
107{{
108    return kFontData;
109}}
110#else
111const uint8_t *OverlayState::getFontData() const
112{{
113    return nullptr;
114}}
115#endif
116}}  // namespace gl
117"""
118
119
120def main():
121    if len(sys.argv) == 2 and sys.argv[1] == 'inputs':
122        # disabled because of issues on Windows. http://anglebug.com/42262538
123        # print(font_file)
124        return
125    if len(sys.argv) == 2 and sys.argv[1] == 'outputs':
126        print(','.join([out_file_cpp, out_file_h]))
127        return
128
129    # Font sizes are chosen such that the sizes form a mip chain.
130    font_defs = [('large', 29), ('small', 14)]
131    chars = ' !"#$%&\'()*+,-./0123456789:;<=>?' + \
132            '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_' + \
133            '`abcdefghijklmnopqrstuvwxyz{|}~'
134    char_count = len(chars)
135
136    font_glyph_widths = []
137    font_glyph_heights = []
138    font_data = ""
139    font_mips = []
140    current_font_mip = 0
141    font_data_sizes = []
142    font_data_offsets = []
143    total_font_data_size = 0
144
145    # Load the font file.
146    face = Face(font_file)
147    assert (face.is_fixed_width)
148
149    for font_name, font_size in font_defs:
150
151        # Since the font is fixed width, we can retrieve its size right away.
152        face.set_char_size(font_size << 6)
153        glyph_width = face.size.max_advance >> 6
154        glyph_ascender = face.size.ascender >> 6
155        glyph_descender = face.size.descender >> 6
156        glyph_height = glyph_ascender - glyph_descender
157        font_glyph_widths.append(glyph_width)
158        font_glyph_heights.append(glyph_height)
159
160        # Make sure the fonts form a mipchain
161        if current_font_mip > 0:
162            assert (glyph_width == font_glyph_widths[current_font_mip - 1] // 2)
163            assert (glyph_height == font_glyph_heights[current_font_mip - 1] // 2)
164
165        font_tag = font_name.capitalize()
166        font_mip = str(current_font_mip)
167        font_mip_symbol = 'kFontMip' + font_tag
168
169        font_data += '// ' + font_tag + '\n'
170
171        # Font pixels are packed in 32-bit values.
172        font_data_size = char_count * glyph_width * glyph_height
173        font_data_sizes.append(font_data_size)
174        font_data_offsets.append(total_font_data_size)
175        total_font_data_size += font_data_size
176
177        for charIndex in range(char_count):
178            char = chars[charIndex]
179            font_data += "// '" + char + "'\n"
180
181            # Render the character.
182            face.load_char(char)
183            bitmap = face.glyph.bitmap
184            left = face.glyph.bitmap_left
185            top = face.glyph.bitmap_top
186            width = bitmap.width
187            rows = bitmap.rows
188            pitch = bitmap.pitch
189
190            offset_x = left
191            offset_y = glyph_height - (top - glyph_descender)
192
193            # Some glyphs like '#', '&' etc generate a larger glyph than the "fixed" font width.
194            if offset_x + width > glyph_width:
195                offset_x = glyph_width - width
196                if offset_x < 0:
197                    width += offset_x
198                    offset_x = 0
199
200            assert (offset_x + width <= glyph_width)
201            assert (offset_y + rows <= glyph_height)
202
203            # Write the character bitmap in the font image.
204            for y in range(glyph_height):
205                for x in range(glyph_width):
206                    if y < offset_y or y >= offset_y + rows or x < offset_x or x >= offset_x + width:
207                        font_data += '   0,'
208                    else:
209                        pixel_value = bitmap.buffer[(y - offset_y) * pitch + (x - offset_x)]
210                        if pixel_value == 0:
211                            font_data += '   0,'
212                        else:
213                            font_data += '0x{:02X},'.format(pixel_value)
214                font_data += '\n'
215
216        font_mips.append('constexpr uint32_t ' + font_mip_symbol + ' = ' + font_mip + ';')
217        current_font_mip += 1
218
219    with open(out_file_h, 'w') as outfile:
220        outfile.write(
221            template_out_file_h.format(
222                script_name=os.path.basename(__file__),
223                font_file=font_file,
224                out_file_name=out_file_h,
225                font_count=len(font_defs),
226                char_count=char_count,
227                max_font_width=font_glyph_widths[0],
228                max_font_height=font_glyph_heights[0],
229                font_mip_data_sizes=','.join([str(s) for s in font_data_sizes]),
230                font_mip_data_offsets=','.join([str(s) for s in font_data_offsets]),
231                total_font_data_size=total_font_data_size,
232                font_mips='\n'.join(font_mips)))
233        outfile.close()
234
235    with open(out_file_cpp, 'w') as outfile:
236        outfile.write(
237            template_out_file_cpp.format(
238                script_name=os.path.basename(__file__),
239                font_file=font_file,
240                font_license=font_license,
241                out_file_name=out_file_cpp,
242                total_font_data_size=total_font_data_size,
243                all_font_data=font_data))
244        outfile.close()
245
246
247if __name__ == '__main__':
248    sys.exit(main())
249