| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 // This sample progam demonstrates how to use Skia and HarfBuzz to | 8 // This sample progam demonstrates how to use Skia and HarfBuzz to |
| 9 // produce a PDF file from UTF-8 text in stdin. | 9 // produce a PDF file from UTF-8 text in stdin. |
| 10 | 10 |
| 11 #include <cassert> | 11 #include <cassert> |
| 12 #include <cstdlib> | 12 #include <cstdlib> |
| 13 #include <iostream> | 13 #include <iostream> |
| 14 #include <map> | 14 #include <map> |
| 15 #include <string> | 15 #include <string> |
| 16 #include <sstream> | 16 #include <sstream> |
| 17 | 17 |
| 18 #include <hb-ot.h> | 18 #include <hb-ot.h> |
| 19 | 19 |
| 20 #include "SkCanvas.h" | 20 #include "SkCanvas.h" |
| 21 #include "SkDocument.h" | 21 #include "SkDocument.h" |
| 22 #include "SkFontMgr.h" |
| 22 #include "SkStream.h" | 23 #include "SkStream.h" |
| 23 #include "SkTextBlob.h" | 24 #include "SkTextBlob.h" |
| 24 #include "SkTypeface.h" | 25 #include "SkTypeface.h" |
| 25 | 26 |
| 26 struct BaseOption { | 27 struct BaseOption { |
| 27 std::string selector; | 28 std::string selector; |
| 28 std::string description; | 29 std::string description; |
| 29 virtual void set(std::string _value) = 0; | 30 virtual void set(std::string _value) = 0; |
| 30 virtual std::string valueToString() = 0; | 31 virtual std::string valueToString() = 0; |
| 31 | 32 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 }; | 80 }; |
| 80 | 81 |
| 81 struct Config { | 82 struct Config { |
| 82 DoubleOption *page_width = new DoubleOption("-w", "Page width", 600.0f); | 83 DoubleOption *page_width = new DoubleOption("-w", "Page width", 600.0f); |
| 83 DoubleOption *page_height = new DoubleOption("-h", "Page height", 800.0f); | 84 DoubleOption *page_height = new DoubleOption("-h", "Page height", 800.0f); |
| 84 SkStringOption *title = new SkStringOption("-t", "PDF title", SkString("---"))
; | 85 SkStringOption *title = new SkStringOption("-t", "PDF title", SkString("---"))
; |
| 85 SkStringOption *author = new SkStringOption("-a", "PDF author", SkString("---"
)); | 86 SkStringOption *author = new SkStringOption("-a", "PDF author", SkString("---"
)); |
| 86 SkStringOption *subject = new SkStringOption("-k", "PDF subject", SkString("--
-")); | 87 SkStringOption *subject = new SkStringOption("-k", "PDF subject", SkString("--
-")); |
| 87 SkStringOption *keywords = new SkStringOption("-c", "PDF keywords", SkString("
---")); | 88 SkStringOption *keywords = new SkStringOption("-c", "PDF keywords", SkString("
---")); |
| 88 SkStringOption *creator = new SkStringOption("-t", "PDF creator", SkString("--
-")); | 89 SkStringOption *creator = new SkStringOption("-t", "PDF creator", SkString("--
-")); |
| 89 StdStringOption *font_file = new StdStringOption("-f", ".ttf font file", "font
s/DejaVuSans.ttf"); | 90 StdStringOption *font_file = new StdStringOption("-f", ".ttf font file", ""); |
| 90 DoubleOption *font_size = new DoubleOption("-z", "Font size", 8.0f); | 91 DoubleOption *font_size = new DoubleOption("-z", "Font size", 8.0f); |
| 91 DoubleOption *left_margin = new DoubleOption("-m", "Left margin", 20.0f); | 92 DoubleOption *left_margin = new DoubleOption("-m", "Left margin", 20.0f); |
| 92 DoubleOption *line_spacing_ratio = new DoubleOption("-h", "Line spacing ratio"
, 1.5f); | 93 DoubleOption *line_spacing_ratio = new DoubleOption("-h", "Line spacing ratio"
, 1.5f); |
| 93 StdStringOption *output_file_name = new StdStringOption("-o", ".pdf output fil
e name", "out-skiahf.pdf"); | 94 StdStringOption *output_file_name = new StdStringOption("-o", ".pdf output fil
e name", "out-skiahf.pdf"); |
| 94 | 95 |
| 95 std::map<std::string, BaseOption*> options = { | 96 std::map<std::string, BaseOption*> options = { |
| 96 { page_width->selector, page_width }, | 97 { page_width->selector, page_width }, |
| 97 { page_height->selector, page_height }, | 98 { page_height->selector, page_height }, |
| 98 { title->selector, title }, | 99 { title->selector, title }, |
| 99 { author->selector, author }, | 100 { author->selector, author }, |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 hb_blob_destroy(blob); | 164 hb_blob_destroy(blob); |
| 164 assert(face); | 165 assert(face); |
| 165 if (!face) { | 166 if (!face) { |
| 166 fSkiaTypeface.reset(); | 167 fSkiaTypeface.reset(); |
| 167 return; | 168 return; |
| 168 } | 169 } |
| 169 hb_face_set_index(face, (unsigned)index); | 170 hb_face_set_index(face, (unsigned)index); |
| 170 hb_face_set_upem(face, fSkiaTypeface->getUnitsPerEm()); | 171 hb_face_set_upem(face, fSkiaTypeface->getUnitsPerEm()); |
| 171 fHarfBuzzFace.reset(face); | 172 fHarfBuzzFace.reset(face); |
| 172 } | 173 } |
| 174 Face(sk_sp<SkTypeface> typeface) { |
| 175 fSkiaTypeface = std::move(typeface); |
| 176 int ttcIndex = 0; |
| 177 std::unique_ptr<SkStreamAsset> asset(fSkiaTypeface->openStream(&ttcIndex)); |
| 178 size_t length = asset->getLength(); |
| 179 void* data = sk_malloc_throw(length); |
| 180 asset->read(data, length); |
| 181 asset = nullptr; |
| 182 hb_blob_t* blob = hb_blob_create( |
| 183 static_cast<const char*>(data), SkToUInt(length), |
| 184 HB_MEMORY_MODE_WRITABLE, data, sk_free); |
| 185 assert(blob); |
| 186 hb_blob_make_immutable(blob); |
| 187 hb_face_t* face = hb_face_create(blob, (unsigned)ttcIndex); |
| 188 hb_blob_destroy(blob); |
| 189 assert(face); |
| 190 if (!face) { |
| 191 fSkiaTypeface.reset(); |
| 192 return; |
| 193 } |
| 194 hb_face_set_index(face, (unsigned)ttcIndex); |
| 195 hb_face_set_upem(face, fSkiaTypeface->getUnitsPerEm()); |
| 196 fHarfBuzzFace.reset(face); |
| 197 } |
| 173 }; | 198 }; |
| 174 | 199 |
| 175 class Placement { | 200 class Placement { |
| 176 public: | 201 public: |
| 177 Placement(Config &_config, SkWStream* outputStream) : config(_config) { | 202 Placement(Config &_config, SkWStream* outputStream) : config(_config) { |
| 178 face = new Face(config.font_file->value.c_str(), 0 /* index */); | 203 const char* font_file = config.font_file->value.c_str(); |
| 204 if (font_file && strlen(font_file)) { |
| 205 face = new Face(config.font_file->value.c_str(), 0 /* index */); |
| 206 } else { |
| 207 sk_sp<SkFontMgr> mgr(SkFontMgr::RefDefault()); |
| 208 sk_sp<SkTypeface> typeface(mgr->matchFamilyStyle(nullptr, SkFontStyle())); |
| 209 face = new Face(std::move(typeface)); |
| 210 } |
| 179 hb_font = hb_font_create(face->fHarfBuzzFace.get()); | 211 hb_font = hb_font_create(face->fHarfBuzzFace.get()); |
| 180 | |
| 181 hb_font_set_scale(hb_font, | 212 hb_font_set_scale(hb_font, |
| 182 FONT_SIZE_SCALE * config.font_size->value, | 213 FONT_SIZE_SCALE * config.font_size->value, |
| 183 FONT_SIZE_SCALE * config.font_size->value); | 214 FONT_SIZE_SCALE * config.font_size->value); |
| 184 hb_ot_font_set_funcs(hb_font); | 215 hb_ot_font_set_funcs(hb_font); |
| 185 | 216 |
| 186 SkDocument::PDFMetadata pdf_info; | 217 SkDocument::PDFMetadata pdf_info; |
| 187 pdf_info.fTitle = config.title->value; | 218 pdf_info.fTitle = config.title->value; |
| 188 pdf_info.fAuthor = config.author->value; | 219 pdf_info.fAuthor = config.author->value; |
| 189 pdf_info.fSubject = config.subject->value; | 220 pdf_info.fSubject = config.subject->value; |
| 190 pdf_info.fKeywords = config.keywords->value; | 221 pdf_info.fKeywords = config.keywords->value; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 219 | 250 |
| 220 void WriteLine(const char *text) { | 251 void WriteLine(const char *text) { |
| 221 /* Create hb-buffer and populate. */ | 252 /* Create hb-buffer and populate. */ |
| 222 hb_buffer_t *hb_buffer = hb_buffer_create (); | 253 hb_buffer_t *hb_buffer = hb_buffer_create (); |
| 223 hb_buffer_add_utf8 (hb_buffer, text, -1, 0, -1); | 254 hb_buffer_add_utf8 (hb_buffer, text, -1, 0, -1); |
| 224 hb_buffer_guess_segment_properties (hb_buffer); | 255 hb_buffer_guess_segment_properties (hb_buffer); |
| 225 | 256 |
| 226 /* Shape it! */ | 257 /* Shape it! */ |
| 227 hb_shape (hb_font, hb_buffer, NULL, 0); | 258 hb_shape (hb_font, hb_buffer, NULL, 0); |
| 228 | 259 |
| 229 DrawGlyphs(hb_buffer); | 260 DrawGlyphs(text, hb_buffer); |
| 230 | 261 |
| 231 hb_buffer_destroy (hb_buffer); | 262 hb_buffer_destroy (hb_buffer); |
| 232 | 263 |
| 233 // Advance to the next line. | 264 // Advance to the next line. |
| 234 current_y += config.line_spacing_ratio->value * config.font_size->value; | 265 current_y += config.line_spacing_ratio->value * config.font_size->value; |
| 235 if (current_y > config.page_height->value) { | 266 if (current_y > config.page_height->value) { |
| 236 pdfDocument->endPage(); | 267 pdfDocument->endPage(); |
| 237 NewPage(); | 268 NewPage(); |
| 238 } | 269 } |
| 239 } | 270 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 261 | 292 |
| 262 void NewPage() { | 293 void NewPage() { |
| 263 pageCanvas = pdfDocument->beginPage(config.page_width->value, config.page_he
ight->value); | 294 pageCanvas = pdfDocument->beginPage(config.page_width->value, config.page_he
ight->value); |
| 264 | 295 |
| 265 pageCanvas->drawPaint(white_paint); | 296 pageCanvas->drawPaint(white_paint); |
| 266 | 297 |
| 267 current_x = config.left_margin->value; | 298 current_x = config.left_margin->value; |
| 268 current_y = config.line_spacing_ratio->value * config.font_size->value; | 299 current_y = config.line_spacing_ratio->value * config.font_size->value; |
| 269 } | 300 } |
| 270 | 301 |
| 271 bool DrawGlyphs(hb_buffer_t *hb_buffer) { | 302 bool DrawGlyphs(const char *text, hb_buffer_t *hb_buffer) { |
| 272 SkTextBlobBuilder textBlobBuilder; | 303 SkTextBlobBuilder textBlobBuilder; |
| 273 unsigned len = hb_buffer_get_length (hb_buffer); | 304 unsigned len = hb_buffer_get_length (hb_buffer); |
| 274 if (len == 0) { | 305 if (len == 0) { |
| 275 return true; | 306 return true; |
| 276 } | 307 } |
| 277 hb_glyph_info_t *info = hb_buffer_get_glyph_infos (hb_buffer, NULL); | 308 hb_glyph_info_t *info = hb_buffer_get_glyph_infos (hb_buffer, NULL); |
| 278 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (hb_buffer, NULL); | 309 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (hb_buffer, NULL); |
| 279 auto runBuffer = textBlobBuilder.allocRunPos(glyph_paint, len); | 310 size_t text_len = strlen(text); |
| 311 auto runBuffer = textBlobBuilder.allocRunTextPos( |
| 312 glyph_paint, len, text_len, SkString()); |
| 313 memcpy(runBuffer.utf8text, text, text_len); |
| 280 | 314 |
| 281 double x = 0; | 315 double x = 0; |
| 282 double y = 0; | 316 double y = 0; |
| 283 for (unsigned int i = 0; i < len; i++) | 317 for (unsigned int i = 0; i < len; i++) |
| 284 { | 318 { |
| 285 runBuffer.glyphs[i] = info[i].codepoint; | 319 runBuffer.glyphs[i] = info[i].codepoint; |
| 320 runBuffer.clusters[i] = info[i].cluster; |
| 286 reinterpret_cast<SkPoint*>(runBuffer.pos)[i] = SkPoint::Make( | 321 reinterpret_cast<SkPoint*>(runBuffer.pos)[i] = SkPoint::Make( |
| 287 x + pos[i].x_offset / FONT_SIZE_SCALE, | 322 x + pos[i].x_offset / FONT_SIZE_SCALE, |
| 288 y - pos[i].y_offset / FONT_SIZE_SCALE); | 323 y - pos[i].y_offset / FONT_SIZE_SCALE); |
| 289 x += pos[i].x_advance / FONT_SIZE_SCALE; | 324 x += pos[i].x_advance / FONT_SIZE_SCALE; |
| 290 y += pos[i].y_advance / FONT_SIZE_SCALE; | 325 y += pos[i].y_advance / FONT_SIZE_SCALE; |
| 291 } | 326 } |
| 292 | 327 |
| 293 pageCanvas->drawTextBlob(textBlobBuilder.build(), current_x, current_y, glyp
h_paint); | 328 pageCanvas->drawTextBlob(textBlobBuilder.build(), current_x, current_y, glyp
h_paint); |
| 294 return true; | 329 return true; |
| 295 } // end of DrawGlyphs | 330 } // end of DrawGlyphs |
| 296 }; // end of Placement class | 331 }; // end of Placement class |
| 297 | 332 |
| 298 int main(int argc, char** argv) { | 333 int main(int argc, char** argv) { |
| 299 Config config(argc, argv); | 334 Config config(argc, argv); |
| 300 | 335 |
| 301 Placement placement(config, new SkFILEWStream(config.output_file_name->value
.c_str())); | 336 Placement placement(config, new SkFILEWStream(config.output_file_name->value
.c_str())); |
| 302 for (std::string line; std::getline(std::cin, line);) { | 337 for (std::string line; std::getline(std::cin, line);) { |
| 303 placement.WriteLine(line.c_str()); | 338 placement.WriteLine(line.c_str()); |
| 304 } | 339 } |
| 305 placement.Close(); | 340 placement.Close(); |
| 306 | 341 |
| 307 return 0; | 342 return 0; |
| 308 } | 343 } |
| OLD | NEW |