blob: 2f79fc69d07c6b644809a25b1b0fe1b08ccef759 [file] [log] [blame]
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +04301/*
2 * Copyright © 2018 Ebrahim Byagowi
Ebrahim Byagowi6795dcf2018-10-21 09:51:15 +03303 * Copyright © 2018 Khaled Hosny
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +04304 *
5 * This is part of HarfBuzz, a text shaping library.
6 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 */
25
Behdad Esfahbodfd3d0042018-05-24 15:58:26 -070026#include "hb-static.cc"
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +043027#include "hb-ot-color-cbdt-table.hh"
Ebrahim Byagowia62554a2018-04-10 00:53:50 +043028#include "hb-ot-color-colr-table.hh"
29#include "hb-ot-color-cpal-table.hh"
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +043030#include "hb-ot-color-sbix-table.hh"
31#include "hb-ot-color-svg-table.hh"
32
Ebrahim Byagowia62554a2018-04-10 00:53:50 +043033#include "hb-ft.h"
34
35#include <ft2build.h>
36#include FT_FREETYPE_H
37#include FT_GLYPH_H
38
39#include <cairo.h>
40#include <cairo-ft.h>
41#include <cairo-svg.h>
42
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +043043#ifdef HAVE_GLIB
44#include <glib.h>
45#endif
46#include <stdlib.h>
47#include <stdio.h>
48
Ebrahim Byagowi00e94ce2018-10-20 00:31:04 +033049static void
50cbdt_callback (const uint8_t* data, unsigned int length,
51 unsigned int group, unsigned int gid)
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +043052{
Ebrahim Byagowia62554a2018-04-10 00:53:50 +043053 char output_path[255];
54 sprintf (output_path, "out/cbdt-%d-%d.png", group, gid);
55 FILE *f = fopen (output_path, "wb");
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +043056 fwrite (data, 1, length, f);
57 fclose (f);
58}
59
Ebrahim Byagowi00e94ce2018-10-20 00:31:04 +033060static void
61sbix_callback (const uint8_t* data, unsigned int length,
62 unsigned int group, unsigned int gid)
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +043063{
Ebrahim Byagowia62554a2018-04-10 00:53:50 +043064 char output_path[255];
65 sprintf (output_path, "out/sbix-%d-%d.png", group, gid);
66 FILE *f = fopen (output_path, "wb");
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +043067 fwrite (data, 1, length, f);
68 fclose (f);
69}
70
Ebrahim Byagowi00e94ce2018-10-20 00:31:04 +033071static void
72svg_callback (const uint8_t* data, unsigned int length,
73 unsigned int start_glyph, unsigned int end_glyph)
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +043074{
Ebrahim Byagowia62554a2018-04-10 00:53:50 +043075 char output_path[255];
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +043076 if (start_glyph == end_glyph)
Ebrahim Byagowia62554a2018-04-10 00:53:50 +043077 sprintf (output_path, "out/svg-%d.svg", start_glyph);
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +043078 else
Ebrahim Byagowia62554a2018-04-10 00:53:50 +043079 sprintf (output_path, "out/svg-%d-%d.svg", start_glyph, end_glyph);
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +043080
81 // append "z" if the content is gzipped
82 if ((data[0] == 0x1F) && (data[1] == 0x8B))
Ebrahim Byagowia62554a2018-04-10 00:53:50 +043083 strcat (output_path, "z");
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +043084
Ebrahim Byagowia62554a2018-04-10 00:53:50 +043085 FILE *f = fopen (output_path, "wb");
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +043086 fwrite (data, 1, length, f);
87 fclose (f);
88}
89
Ebrahim Byagowi00e94ce2018-10-20 00:31:04 +033090static void
91colr_cpal_rendering (hb_face_t *face, cairo_font_face_t *cairo_face)
Ebrahim Byagowia62554a2018-04-10 00:53:50 +043092{
Khaled Hosnyd4e928b2018-05-01 17:16:46 +020093 unsigned int upem = hb_face_get_upem (face);
94
Ebrahim Byagowid4261b42018-10-21 08:48:07 +033095 unsigned glyph_count = hb_face_get_glyph_count (face);
96 for (hb_codepoint_t gid = 0; gid < glyph_count; ++gid)
Ebrahim Byagowia62554a2018-04-10 00:53:50 +043097 {
Ebrahim Byagowi0babf762018-10-23 01:33:45 +033098 unsigned int num_layers = hb_ot_color_glyph_get_layers (face, gid, 0, nullptr, nullptr);
Khaled Hosnyd4e928b2018-05-01 17:16:46 +020099 if (!num_layers)
100 continue;
101
Ebrahim Byagowi0babf762018-10-23 01:33:45 +0330102 hb_ot_color_layer_t *layers = (hb_ot_color_layer_t*) malloc (num_layers * sizeof (hb_ot_color_layer_t));
Khaled Hosnyd4e928b2018-05-01 17:16:46 +0200103
Ebrahim Byagowi0babf762018-10-23 01:33:45 +0330104 hb_ot_color_glyph_get_layers (face, gid, 0, &num_layers, layers);
Khaled Hosnyd4e928b2018-05-01 17:16:46 +0200105 if (num_layers)
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430106 {
107 // Measure
108 cairo_text_extents_t extents;
109 {
110 cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
111 cairo_t *cr = cairo_create (surface);
112 cairo_set_font_face (cr, cairo_face);
113 cairo_set_font_size (cr, upem);
114
115 cairo_glyph_t *glyphs = (cairo_glyph_t *) calloc (num_layers, sizeof (cairo_glyph_t));
116 for (unsigned int j = 0; j < num_layers; ++j)
Ebrahim Byagowi0babf762018-10-23 01:33:45 +0330117 glyphs[j].index = layers[j].glyph;
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430118 cairo_glyph_extents (cr, glyphs, num_layers, &extents);
119 free (glyphs);
120 cairo_surface_destroy (surface);
121 cairo_destroy (cr);
122 }
123
124 // Add a slight margin
125 extents.width += extents.width / 10;
126 extents.height += extents.height / 10;
127 extents.x_bearing -= extents.width / 20;
128 extents.y_bearing -= extents.height / 20;
129
130 // Render
Ebrahim Byagowi0babf762018-10-23 01:33:45 +0330131 unsigned int palette_count = hb_ot_color_palette_get_count (face);
Ebrahim Byagowi456978d2018-10-21 08:26:40 +0330132 for (unsigned int palette = 0; palette < palette_count; palette++) {
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430133 char output_path[255];
134
Ebrahim Byagowi0babf762018-10-23 01:33:45 +0330135 unsigned int num_colors = hb_ot_color_palette_get_colors (face, palette, 0, nullptr, nullptr);
Ebrahim Byagowi687f6792018-10-20 17:50:39 +0330136 if (!num_colors)
137 continue;
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430138
Ebrahim Byagowi456978d2018-10-21 08:26:40 +0330139 hb_color_t *colors = (hb_color_t*) calloc (num_colors, sizeof (hb_color_t));
Ebrahim Byagowi0babf762018-10-23 01:33:45 +0330140 hb_ot_color_palette_get_colors (face, palette, 0, &num_colors, colors);
Ebrahim Byagowi687f6792018-10-20 17:50:39 +0330141 if (num_colors)
142 {
Ebrahim Byagowi6795dcf2018-10-21 09:51:15 +0330143 // If we have more than one palette, use a simpler naming
Ebrahim Byagowi456978d2018-10-21 08:26:40 +0330144 if (palette_count == 1)
Khaled Hosnyd4e928b2018-05-01 17:16:46 +0200145 sprintf (output_path, "out/colr-%d.svg", gid);
146 else
Ebrahim Byagowi456978d2018-10-21 08:26:40 +0330147 sprintf (output_path, "out/colr-%d-%d.svg", gid, palette);
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430148
Khaled Hosnyd4e928b2018-05-01 17:16:46 +0200149 cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height);
150 cairo_t *cr = cairo_create (surface);
151 cairo_set_font_face (cr, cairo_face);
152 cairo_set_font_size (cr, upem);
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430153
Khaled Hosnyd4e928b2018-05-01 17:16:46 +0200154 for (unsigned int layer = 0; layer < num_layers; ++layer)
155 {
Ebrahim Byagowi456978d2018-10-21 08:26:40 +0330156 hb_color_t color = 0x000000FF;
Ebrahim Byagowi0babf762018-10-23 01:33:45 +0330157 if (layers[layer].color_index != 0xFFFF)
158 color = colors[layers[layer].color_index];
Ebrahim Byagowi687f6792018-10-20 17:50:39 +0330159 cairo_set_source_rgba (cr,
Ebrahim Byagowi456978d2018-10-21 08:26:40 +0330160 hb_color_get_red (color) / 255.,
161 hb_color_get_green (color) / 255.,
162 hb_color_get_blue (color) / 255.,
163 hb_color_get_alpha (color) / 255.);
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430164
Khaled Hosnyd4e928b2018-05-01 17:16:46 +0200165 cairo_glyph_t glyph;
Ebrahim Byagowi0babf762018-10-23 01:33:45 +0330166 glyph.index = layers[layer].glyph;
Khaled Hosnyd4e928b2018-05-01 17:16:46 +0200167 glyph.x = -extents.x_bearing;
168 glyph.y = -extents.y_bearing;
169 cairo_show_glyphs (cr, &glyph, 1);
170 }
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430171
Khaled Hosnyd4e928b2018-05-01 17:16:46 +0200172 cairo_surface_destroy (surface);
173 cairo_destroy (cr);
Ebrahim Byagowi687f6792018-10-20 17:50:39 +0330174 }
175 free (colors);
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430176 }
177 }
Khaled Hosnyd4e928b2018-05-01 17:16:46 +0200178
Ebrahim Byagowi0babf762018-10-23 01:33:45 +0330179 free (layers);
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430180 }
181}
182
Ebrahim Byagowi00e94ce2018-10-20 00:31:04 +0330183static void
184dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem,
185 unsigned int num_glyphs)
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430186{
187 // Dump every glyph available on the font
Ebrahim Byagowi1e1e9082018-04-10 03:26:01 +0430188 return; // disabled for now
Behdad Esfahbodabc12f72018-05-08 02:23:36 -0700189 for (unsigned int i = 0; i < num_glyphs; ++i)
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430190 {
191 cairo_text_extents_t extents;
192 cairo_glyph_t glyph = {0};
193 glyph.index = i;
194
195 // Measure
196 {
197 cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
198 cairo_t *cr = cairo_create (surface);
199 cairo_set_font_face (cr, cairo_face);
200 cairo_set_font_size (cr, upem);
201
202 cairo_glyph_extents (cr, &glyph, 1, &extents);
203 cairo_surface_destroy (surface);
204 cairo_destroy (cr);
205 }
206
207 // Add a slight margin
208 extents.width += extents.width / 10;
209 extents.height += extents.height / 10;
210 extents.x_bearing -= extents.width / 20;
211 extents.y_bearing -= extents.height / 20;
212
213 // Render
214 {
215 char output_path[255];
216 sprintf (output_path, "out/%d.svg", i);
217 cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height);
218 cairo_t *cr = cairo_create (surface);
219 cairo_set_font_face (cr, cairo_face);
220 cairo_set_font_size (cr, upem);
221 glyph.x = -extents.x_bearing;
222 glyph.y = -extents.y_bearing;
223 cairo_show_glyphs (cr, &glyph, 1);
224 cairo_surface_destroy (surface);
225 cairo_destroy (cr);
226 }
227 }
228}
229
Ebrahim Byagowi00e94ce2018-10-20 00:31:04 +0330230int
231main (int argc, char **argv)
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +0430232{
233 if (argc != 2) {
Ebrahim Byagowi27e095a2018-10-15 12:04:14 +0330234 fprintf (stderr, "usage: %s font-file.ttf\n"
Ebrahim Byagowi8f3048a2018-10-15 12:16:47 +0330235 "run it like `rm -rf out && mkdir out && %s font-file.ttf`\n",
236 argv[0], argv[0]);
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +0430237 exit (1);
238 }
239
Ebrahim Byagowi27e095a2018-10-15 12:04:14 +0330240
241 FILE *font_name_file = fopen ("out/_font_name_file.txt", "r");
242 if (font_name_file != nullptr)
243 {
244 fprintf (stderr, "Purge or move ./out folder in order to run a new dump\n");
245 exit (1);
246 }
247
248 font_name_file = fopen ("out/_font_name_file.txt", "w");
249 if (font_name_file == nullptr)
250 {
Khaled Hosnyd4e928b2018-05-01 17:16:46 +0200251 fprintf (stderr, "./out is not accessible as a folder, create it please\n");
Ebrahim Byagowi27e095a2018-10-15 12:04:14 +0330252 exit (1);
253 }
Ebrahim Byagowi8f3048a2018-10-15 12:16:47 +0330254 fwrite (argv[1], 1, strlen (argv[1]), font_name_file);
Ebrahim Byagowi27e095a2018-10-15 12:04:14 +0330255 fclose (font_name_file);
256
Ebrahim Byagowice173402018-04-20 10:29:06 +0430257 hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +0430258 hb_face_t *face = hb_face_create (blob, 0);
259 hb_font_t *font = hb_font_create (face);
260
261 OT::CBDT::accelerator_t cbdt;
262 cbdt.init (face);
263 cbdt.dump (cbdt_callback);
264 cbdt.fini ();
265
266 OT::sbix::accelerator_t sbix;
267 sbix.init (face);
268 sbix.dump (sbix_callback);
269 sbix.fini ();
270
271 OT::SVG::accelerator_t svg;
272 svg.init (face);
273 svg.dump (svg_callback);
274 svg.fini ();
275
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430276 cairo_font_face_t *cairo_face;
277 {
278 FT_Library library;
279 FT_Init_FreeType (&library);
280 FT_Face ftface;
281 FT_New_Face (library, argv[1], 0, &ftface);
282 cairo_face = cairo_ft_font_face_create_for_ft_face (ftface, 0);
283 }
Ebrahim Byagowi687f6792018-10-20 17:50:39 +0330284 colr_cpal_rendering (face, cairo_face);
285
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430286 unsigned int num_glyphs = hb_face_get_glyph_count (face);
287 unsigned int upem = hb_face_get_upem (face);
Ebrahim Byagowia62554a2018-04-10 00:53:50 +0430288 dump_glyphs (cairo_face, upem, num_glyphs);
289
Ebrahim Byagowi8fd55422018-03-27 16:57:09 +0430290 hb_font_destroy (font);
291 hb_face_destroy (face);
292 hb_blob_destroy (blob);
293
294 return 0;
295}