Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(158)

Side by Side Diff: tools/using_skia_and_harfbuzz.cpp

Issue 1940393002: Start building Harfbuzz+Skia example (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2016-05-03 (Tuesday) 17:58:47 EDT Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/harfbuzz/hb-version.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkCanvas.h"
9 #include "SkDocument.h"
10 #include "SkFontMgr.h"
11 #include "SkGradientShader.h"
12 #include "SkPaint.h"
13 #include "SkStream.h"
14 #include "SkString.h"
15 #include "SkTextBlob.h"
16 #include "SkTypeface.h"
17
18 #include <hb.h>
19 #include <hb-ot.h>
20
21 #include <cassert>
22 #include <iostream>
23 #include <map>
24 #include <string>
25
26
27 struct BaseOption {
28 std::string selector;
29 std::string description;
30 virtual void set(std::string _value) = 0;
31 virtual std::string valueToString() = 0;
32
33 BaseOption(std::string _selector, std::string _description) :
34 selector(_selector),
35 description(_description) {}
36
37 virtual ~BaseOption() {}
38 };
39
40 template <class T> struct Option : BaseOption {
41 T value;
42 Option(std::string selector, std::string description, T defaultValue) :
43 BaseOption(selector, description),
44 value(defaultValue) {}
45 };
46
47 struct DoubleOption : Option<double> {
48 virtual void set(std::string _value) {
49 value = atof(_value.c_str());
50 }
51 virtual std::string valueToString() {
52 return std::to_string(value);
53 }
54 DoubleOption(std::string selector, std::string description, double defaultValu e) :
55 Option<double>(selector, description, defaultValue) {}
56 };
57
58 struct SkStringOption : Option<SkString> {
59 virtual void set(std::string _value) {
60 value = _value.c_str();
61 }
62 virtual std::string valueToString() {
63 return value.c_str();
64 }
65 SkStringOption(std::string selector, std::string description, SkString default Value) :
66 Option<SkString>(selector, description, defaultValue) {}
67 };
68
69 struct StdStringOption : Option<std::string> {
70 virtual void set(std::string _value) {
71 value = _value;
72 }
73 virtual std::string valueToString() {
74 return value;
75 }
76 StdStringOption(std::string selector, std::string description, std::string def aultValue) :
77 Option<std::string>(selector, description, defaultValue) {}
78 };
79
80 struct Config {
81 DoubleOption *page_width = new DoubleOption("-w", "Page width", 600.0f);
82 DoubleOption *page_height = new DoubleOption("-h", "Page height", 800.0f);
83 SkStringOption *title = new SkStringOption("-t", "PDF title", SkString("---")) ;
84 SkStringOption *author = new SkStringOption("-a", "PDF author", SkString("---" ));
85 SkStringOption *subject = new SkStringOption("-k", "PDF subject", SkString("-- -"));
86 SkStringOption *keywords = new SkStringOption("-c", "PDF keywords", SkString(" ---"));
87 SkStringOption *creator = new SkStringOption("-t", "PDF creator", SkString("-- -"));
88 StdStringOption *font_file = new StdStringOption("-f", ".ttf font file", "font s/DejaVuSans.ttf");
89 DoubleOption *font_size = new DoubleOption("-z", "Font size", 8.0f);
90 DoubleOption *left_margin = new DoubleOption("-m", "Left margin", 20.0f);
91 DoubleOption *line_spacing_ratio = new DoubleOption("-h", "Line spacing ratio" , 1.5f);
92 StdStringOption *output_file_name = new StdStringOption("-o", ".pdf output fil e name", "out-skiahf.pdf");
93
94 std::map<std::string, BaseOption*> options = {
95 { page_width->selector, page_width },
96 { page_height->selector, page_height },
97 { title->selector, title },
98 { author->selector, author },
99 { subject->selector, subject },
100 { keywords->selector, keywords },
101 { creator->selector, creator },
102 { font_file->selector, font_file },
103 { font_size->selector, font_size },
104 { left_margin->selector, left_margin },
105 { line_spacing_ratio->selector, line_spacing_ratio },
106 { output_file_name->selector, output_file_name },
107 };
108
109 Config(int argc, char **argv) {
110 for (int i = 1; i < argc; i++) {
111 std::string option_selector(argv[i]);
112 auto it = options.find(option_selector);
113 if (it != options.end()) {
114 if (i >= argc) {
115 break;
116 }
117 const char *option_value = argv[i + 1];
118 it->second->set(option_value);
119 i++;
120 } else {
121 printf("Ignoring unrecognized option: %s.\n", argv[i]);
122 printf("Usage: %s {option value}\n", argv[0]);
123 printf("\tTakes text from stdin and produces pdf file.\n");
124 printf("Supported options:\n");
125 for (auto it = options.begin(); it != options.end(); ++it) {
126 printf("\t%s\t%s (%s)\n", it->first.c_str(),
127 it->second->description.c_str(),
128 it->second->valueToString().c_str());
129 }
130 exit(-1);
131 }
132 }
133 } // end of Config::Config
134 };
135
136 const double FONT_SIZE_SCALE = 64.0f;
137
138 struct Face {
139 struct HBFDel { void operator()(hb_face_t* f) { hb_face_destroy(f); } };
140 std::unique_ptr<hb_face_t, HBFDel> fHarfBuzzFace;
141 sk_sp<SkTypeface> fSkiaTypeface;
142
143 Face(const char* path, int index) {
144 // fairly portable mmap impl
145 auto data = SkData::MakeFromFileName(path);
146 assert(data);
147 if (!data) { return; }
148 fSkiaTypeface.reset(
149 SkTypeface::CreateFromStream(
150 new SkMemoryStream(data), index));
151 assert(fSkiaTypeface);
152 if (!fSkiaTypeface) { return; }
153 auto destroy = [](void *d) { static_cast<SkData*>(d)->unref(); };
154 const char* bytes = (const char*)data->data();
155 unsigned int size = (unsigned int)data->size();
156 hb_blob_t* blob = hb_blob_create(bytes,
157 size,
158 HB_MEMORY_MODE_READONLY,
159 data.release(),
160 destroy);
161 assert(blob);
162 hb_blob_make_immutable(blob);
163 hb_face_t* face = hb_face_create(blob, (unsigned)index);
164 hb_blob_destroy(blob);
165 assert(face);
166 if (!face) {
167 fSkiaTypeface.reset();
168 return;
169 }
170 hb_face_set_index(face, (unsigned)index);
171 hb_face_set_upem(face, fSkiaTypeface->getUnitsPerEm());
172 fHarfBuzzFace.reset(face);
173 }
174 };
175
176 class Placement {
177 public:
178 Placement(Config &_config, SkWStream* outputStream) : config(_config) {
179 face = new Face(config.font_file->value.c_str(), 0 /* index */);
180 hb_font = hb_font_create(face->fHarfBuzzFace.get());
181
182 hb_font_set_scale(hb_font,
183 FONT_SIZE_SCALE * config.font_size->value,
184 FONT_SIZE_SCALE * config.font_size->value);
185 hb_ot_font_set_funcs(hb_font);
186
187 SkDocument::PDFMetadata pdf_info;
188 pdf_info.fTitle = config.title->value;
189 pdf_info.fAuthor = config.author->value;
190 pdf_info.fSubject = config.subject->value;
191 pdf_info.fKeywords = config.keywords->value;
192 pdf_info.fCreator = config.creator->value;
193 SkTime::DateTime now;
194 SkTime::GetDateTime(&now);
195 pdf_info.fCreation.fEnabled = true;
196 pdf_info.fCreation.fDateTime = now;
197 pdf_info.fModified.fEnabled = true;
198 pdf_info.fModified.fDateTime = now;
199 pdfDocument = SkDocument::MakePDF(outputStream, SK_ScalarDefaultRasterDPI,
200 pdf_info, nullptr, true);
201 assert(pdfDocument);
202
203 white_paint.setColor(SK_ColorWHITE);
204
205 glyph_paint.setFlags(
206 SkPaint::kAntiAlias_Flag |
207 SkPaint::kSubpixelText_Flag); // ... avoid waggly text when rotating.
208 glyph_paint.setColor(SK_ColorBLACK);
209 glyph_paint.setTextSize(config.font_size->value);
210 SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
211 glyph_paint.setTypeface(face->fSkiaTypeface);
212 glyph_paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
213
214 NewPage();
215 } // end of Placement
216
217 ~Placement() {
218 delete face;
219 hb_font_destroy (hb_font);
220 }
221
222 void WriteLine(const char *text) {
223 /* Create hb-buffer and populate. */
224 hb_buffer_t *hb_buffer = hb_buffer_create ();
225 hb_buffer_add_utf8 (hb_buffer, text, -1, 0, -1);
226 hb_buffer_guess_segment_properties (hb_buffer);
227
228 /* Shape it! */
229 hb_shape (hb_font, hb_buffer, NULL, 0);
230
231 DrawGlyphs(hb_buffer);
232
233 hb_buffer_destroy (hb_buffer);
234
235 // Advance to the next line.
236 current_y += config.line_spacing_ratio->value * config.font_size->value;
237 if (current_y > config.page_height->value) {
238 pdfDocument->endPage();
239 NewPage();
240 }
241 }
242
243 bool Close() {
244 return pdfDocument->close();
245 }
246
247 private:
248 Config config;
249
250 Face *face;
251
252 hb_font_t *hb_font;
253
254 sk_sp<SkDocument> pdfDocument;
255
256 SkCanvas* pageCanvas;
257
258 SkPaint white_paint;
259 SkPaint glyph_paint;
260
261 double current_x;
262 double current_y;
263
264 void NewPage() {
265 pageCanvas = pdfDocument->beginPage(config.page_width->value, config.page_he ight->value);
266
267 pageCanvas->drawPaint(white_paint);
268
269 current_x = config.left_margin->value;
270 current_y = config.line_spacing_ratio->value * config.font_size->value;
271 }
272
273 bool DrawGlyphs(hb_buffer_t *hb_buffer) {
274 SkTextBlobBuilder textBlobBuilder;
275 unsigned len = hb_buffer_get_length (hb_buffer);
276 if (len == 0) {
277 return true;
278 }
279 hb_glyph_info_t *info = hb_buffer_get_glyph_infos (hb_buffer, NULL);
280 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (hb_buffer, NULL);
281 auto runBuffer = textBlobBuilder.allocRunPos(glyph_paint, len);
282
283 double x = 0;
284 double y = 0;
285 for (unsigned int i = 0; i < len; i++)
286 {
287 runBuffer.glyphs[i] = info[i].codepoint;
288 reinterpret_cast<SkPoint*>(runBuffer.pos)[i] = SkPoint::Make(
289 x + pos[i].x_offset / FONT_SIZE_SCALE,
290 y - pos[i].y_offset / FONT_SIZE_SCALE);
291 x += pos[i].x_advance / FONT_SIZE_SCALE;
292 y += pos[i].y_advance / FONT_SIZE_SCALE;
293 }
294
295 pageCanvas->drawTextBlob(textBlobBuilder.build(), current_x, current_y, glyp h_paint);
296 return true;
297 } // end of DrawGlyphs
298 }; // end of Placement class
299
300 int main(int argc, char** argv) {
301 Config config(argc, argv);
302
303 Placement placement(config, new SkFILEWStream(config.output_file_name->value .c_str()));
304 for (std::string line; std::getline(std::cin, line);) {
305 placement.WriteLine(line.c_str());
306 }
307 placement.Close();
308
309 return 0;
310 }
OLDNEW
« no previous file with comments | « third_party/harfbuzz/hb-version.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698