Flutter Engine
main.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <hb-subset.h>
6 #include <cstdlib>
7 #include <fstream>
8 #include <iostream>
9 #include <limits>
10 #include <set>
11 #include <string>
12 
13 #include "hb_wrappers.h"
14 
15 hb_codepoint_t ParseCodepoint(const std::string& arg) {
16  uint64_t value = 0;
17  // Check for \u123, u123, otherwise let strtoul work it out.
18  if (arg[0] == 'u') {
19  value = strtoul(arg.c_str() + 1, nullptr, 16);
20  } else if (arg[0] == '\\' && arg[1] == 'u') {
21  value = strtoul(arg.c_str() + 2, nullptr, 16);
22  } else {
23  value = strtoul(arg.c_str(), nullptr, 0);
24  }
25  if (value == 0 || value > std::numeric_limits<hb_codepoint_t>::max()) {
26  std::cerr << "The value '" << arg << "' (" << value
27  << ") could not be parsed as a valid unicode codepoint; aborting."
28  << std::endl;
29  exit(-1);
30  }
31  return value;
32 }
33 
34 void Usage() {
35  std::cout << "Usage:" << std::endl;
36  std::cout << "font-subset <output.ttf> <input.ttf>" << std::endl;
37  std::cout << std::endl;
38  std::cout << "The output.ttf file will be overwritten if it exists already "
39  "and the subsetting operation succeeds."
40  << std::endl;
41  std::cout << "Codepoints should be specified on stdin, separated by spaces, "
42  "and must be input as decimal numbers (123), hexidecimal "
43  "numbers (0x7B), or unicode hexidecimal characters (\\u7B)."
44  << std::endl;
45  std::cout << "Input terminates with a newline." << std::endl;
46  std::cout
47  << "This program will de-duplicate codepoints if the same codepoint is "
48  "specified multiple times, e.g. '123 123' will be treated as '123'."
49  << std::endl;
50 }
51 
52 int main(int argc, char** argv) {
53  if (argc != 3) {
54  Usage();
55  return -1;
56  }
57  std::string output_file_path(argv[1]);
58  std::string input_file_path(argv[2]);
59  std::cout << "Using output file: " << output_file_path << std::endl;
60  std::cout << "Using source file: " << input_file_path << std::endl;
61 
63  hb_blob_create_from_file(input_file_path.c_str()));
64  if (!hb_blob_get_length(font_blob.get())) {
65  std::cerr << "Failed to load input font " << input_file_path
66  << "; aborting. This error indicates that the font is invalid or "
67  "the current version of Harfbuzz is unable to process it."
68  << std::endl;
69  return -1;
70  }
71 
72  HarfbuzzWrappers::HbFacePtr font_face(hb_face_create(font_blob.get(), 0));
73  if (font_face.get() == hb_face_get_empty()) {
74  std::cerr << "Failed to load input font face " << input_file_path
75  << "; aborting. This error indicates that the font is invalid or "
76  "the current version of Harfbuzz is unable to process it."
77  << std::endl;
78  return -1;
79  }
80 
81  HarfbuzzWrappers::HbSubsetInputPtr input(hb_subset_input_create_or_fail());
82  {
83  hb_set_t* desired_codepoints = hb_subset_input_unicode_set(input.get());
84  HarfbuzzWrappers::HbSetPtr actual_codepoints(hb_set_create());
85  hb_face_collect_unicodes(font_face.get(), actual_codepoints.get());
86  std::string raw_codepoint;
87  while (std::cin >> raw_codepoint) {
88  auto codepoint = ParseCodepoint(raw_codepoint);
89  if (!codepoint) {
90  std::cerr << "Invalid codepoint for " << raw_codepoint << "; exiting."
91  << std::endl;
92  return -1;
93  }
94  if (!hb_set_has(actual_codepoints.get(), codepoint)) {
95  std::cerr << "Codepoint " << raw_codepoint
96  << " not found in font, aborting." << std::endl;
97  return -1;
98  }
99  hb_set_add(desired_codepoints, codepoint);
100  }
101  if (hb_set_is_empty(desired_codepoints)) {
102  std::cerr << "No codepoints specified, exiting." << std::endl;
103  return -1;
104  }
105  }
106 
107  HarfbuzzWrappers::HbFacePtr new_face(hb_subset(font_face.get(), input.get()));
108 
109  if (new_face.get() == hb_face_get_empty()) {
110  std::cerr
111  << "Failed to subset font; aborting. This error normally indicates "
112  "the current version of Harfbuzz is unable to process it."
113  << std::endl;
114  return -1;
115  }
116 
117  HarfbuzzWrappers::HbBlobPtr result(hb_face_reference_blob(new_face.get()));
118  if (!hb_blob_get_length(result.get())) {
119  std::cerr << "Failed get new font bytes; aborting. This error may indicate "
120  "low availability of memory or a bug in Harfbuzz."
121  << std::endl;
122  return -1;
123  }
124 
125  unsigned int data_length;
126  const char* data = hb_blob_get_data(result.get(), &data_length);
127 
128  std::ofstream output_font_file;
129  output_font_file.open(output_file_path,
130  std::ios::out | std::ios::trunc | std::ios::binary);
131  if (!output_font_file.is_open()) {
132  std::cerr << "Failed to open output file '" << output_file_path
133  << "'. The parent directory may not exist, or the user does not "
134  "have permission to create this file."
135  << std::endl;
136  return -1;
137  }
138  output_font_file.write(data, data_length);
139  output_font_file.flush();
140  output_font_file.close();
141 
142  std::cout << "Wrote " << data_length << " bytes to " << output_file_path
143  << std::endl;
144  return 0;
145 }
void Usage()
Definition: main.cc:34
std::unique_ptr< hb_face_t, hb_face_deleter > HbFacePtr
Definition: hb_wrappers.h:30
int main(int argc, const char **argv)
Definition: main.cc:34
uint8_t value
hb_codepoint_t ParseCodepoint(const std::string &arg)
Definition: main.cc:15
std::unique_ptr< hb_blob_t, hb_blob_deleter > HbBlobPtr
Definition: hb_wrappers.h:29
std::unique_ptr< hb_set_t, hb_set_deleter > HbSetPtr
Definition: hb_wrappers.h:33
std::unique_ptr< hb_subset_input_t, hb_subset_input_deleter > HbSubsetInputPtr
Definition: hb_wrappers.h:32