Flutter Engine
The Flutter Engine
using_skia_and_harfbuzz.cpp
Go to the documentation of this file.
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// This sample progam demonstrates how to use Skia and HarfBuzz to
9// produce a PDF file from UTF-8 text in stdin.
10
11#include <cassert>
12#include <cstdlib>
13#include <iostream>
14#include <map>
15#include <sstream>
16#include <string>
17#include <vector>
18
28
29namespace {
31#if defined(SK_UNICODE_ICU_IMPLEMENTATION)
33 if (unicode) {
34 return unicode;
35 }
36#endif
37 SkDEBUGFAIL("Only ICU implementation of SkUnicode is supported");
38 return nullptr;
39}
40
41} // namespace
42
43// Options /////////////////////////////////////////////////////////////////////
44
45struct BaseOption {
46 std::string selector;
47 std::string description;
48 virtual void set(const std::string& _value) = 0;
49 virtual std::string valueToString() = 0;
50
51 BaseOption(std::string _selector, std::string _description)
52 : selector(std::move(_selector))
53 , description(std::move(_description)) {}
54
55 virtual ~BaseOption() {}
56
57 static void Init(const std::vector<BaseOption*> &, int argc, char **argv);
58};
59
60template <class T>
63 Option(std::string _selector, std::string _description, T defaultValue)
64 : BaseOption(std::move(_selector), std::move(_description))
65 , value(defaultValue) {}
66};
67
68void BaseOption::Init(const std::vector<BaseOption*> &option_list,
69 int argc, char **argv) {
70 std::map<std::string, BaseOption *> options;
71 for (BaseOption *opt : option_list) {
72 options[opt->selector] = opt;
73 }
74 for (int i = 1; i < argc; i++) {
75 std::string option_selector(argv[i]);
76 auto it = options.find(option_selector);
77 if (it != options.end()) {
78 if (i >= argc) {
79 break;
80 }
81 const char *option_value = argv[i + 1];
82 it->second->set(option_value);
83 i++;
84 } else {
85 printf("Ignoring unrecognized option: %s.\n", argv[i]);
86 printf("Usage: %s {option value}\n", argv[0]);
87 printf("\tTakes text from stdin and produces pdf file.\n");
88 printf("Supported options:\n");
89 for (BaseOption *opt : option_list) {
90 printf("\t%s\t%s (%s)\n", opt->selector.c_str(),
91 opt->description.c_str(), opt->valueToString().c_str());
92 }
93 exit(-1);
94 }
95 }
96}
97
98struct DoubleOption : Option<double> {
99 void set(const std::string& _value) override { value = atof(_value.c_str()); }
100 std::string valueToString() override {
101 std::ostringstream stm;
102 stm << value;
103 return stm.str();
104 }
105 DoubleOption(std::string _selector, std::string _description, double defaultValue)
106 : Option<double>(std::move(_selector),
107 std::move(_description),
108 std::move(defaultValue)) {}
109};
110
111struct StringOption : Option<std::string> {
112 void set(const std::string& _value) override { value = _value; }
113 std::string valueToString() override { return value; }
114 StringOption(std::string _selector, std::string _description, std::string defaultValue)
115 : Option<std::string>(std::move(_selector),
116 std::move(_description),
117 std::move(defaultValue)) {}
118};
119
120// Config //////////////////////////////////////////////////////////////////////
121
122struct Config {
123 DoubleOption page_width = DoubleOption("-w", "Page width", 600.0f);
124 DoubleOption page_height = DoubleOption("-h", "Page height", 800.0f);
125 StringOption title = StringOption("-t", "PDF title", "---");
126 StringOption author = StringOption("-a", "PDF author", "---");
127 StringOption subject = StringOption("-k", "PDF subject", "---");
128 StringOption keywords = StringOption("-c", "PDF keywords", "---");
129 StringOption creator = StringOption("-t", "PDF creator", "---");
130 StringOption font_file = StringOption("-f", ".ttf font file", "");
131 DoubleOption font_size = DoubleOption("-z", "Font size", 8.0f);
132 DoubleOption left_margin = DoubleOption("-m", "Left margin", 20.0f);
134 DoubleOption("-h", "Line spacing ratio", 0.25f);
136 StringOption("-o", ".pdf output file name", "out-skiahf.pdf");
137
138 Config(int argc, char **argv) {
139 BaseOption::Init(std::vector<BaseOption*>{
143 }
144};
145
146// Placement ///////////////////////////////////////////////////////////////////
147
149public:
150 Placement(const Config* conf, SkDocument *doc)
151 : config(conf), document(doc), pageCanvas(nullptr) {
152 white_paint.setColor(SK_ColorWHITE);
153 glyph_paint.setColor(SK_ColorBLACK);
154 glyph_paint.setAntiAlias(true);
156 font.setSubpixel(true);
158 }
159
160 void WriteLine(const SkShaper& shaper, const char* text, size_t textBytes) {
161 SkTextBlobBuilderRunHandler textBlobBuilder(text, {0, 0});
162
163 const SkBidiIterator::Level defaultLevel = SkBidiIterator::kLTR;
164 std::unique_ptr<SkShaper::BiDiRunIterator> bidi =
165 SkShapers::unicode::BidiRunIterator(get_unicode(), text, textBytes, defaultLevel);
166 SkASSERT(bidi);
167
168 std::unique_ptr<SkShaper::LanguageRunIterator> language =
170 SkASSERT(language);
171
172 std::unique_ptr<SkShaper::ScriptRunIterator> script =
175
176 std::unique_ptr<SkShaper::FontRunIterator> fontRuns =
178 SkASSERT(fontRuns);
179
180 const SkScalar width = config->page_width.value - 2 * config->left_margin.value;
181 shaper.shape(text,
182 textBytes,
183 *fontRuns,
184 *bidi,
185 *script,
186 *language,
187 nullptr,
188 0,
189 width,
190 &textBlobBuilder);
191 SkPoint endPoint = textBlobBuilder.endPoint();
192 sk_sp<const SkTextBlob> blob = textBlobBuilder.makeBlob();
193 // If we don't have a page, or if we're not at the start of the page and the blob won't fit
194 if (!pageCanvas ||
195 (current_y > config->line_spacing_ratio.value * config->font_size.value &&
196 current_y + endPoint.y() > config->page_height.value)
197 ) {
198 if (pageCanvas) {
199 document->endPage();
200 }
201 pageCanvas = document->beginPage(
204 pageCanvas->drawPaint(white_paint);
205 current_x = config->left_margin.value;
206 current_y = config->line_spacing_ratio.value * config->font_size.value;
207 }
208 pageCanvas->drawTextBlob(
209 blob.get(), SkDoubleToScalar(current_x),
210 SkDoubleToScalar(current_y), glyph_paint);
211 // Advance to the next line.
212 current_y += endPoint.y() + config->line_spacing_ratio.value * config->font_size.value;
213 }
214
215private:
216 const Config* config;
217 SkDocument *document;
218 SkCanvas *pageCanvas;
219 SkPaint white_paint;
220 SkPaint glyph_paint;
221 SkFont font;
222 double current_x;
223 double current_y;
224};
225
226////////////////////////////////////////////////////////////////////////////////
227
228static sk_sp<SkDocument> MakePDFDocument(const Config &config, SkWStream *wStream) {
229 SkPDF::Metadata pdf_info;
230 pdf_info.fTitle = config.title.value.c_str();
231 pdf_info.fAuthor = config.author.value.c_str();
232 pdf_info.fSubject = config.subject.value.c_str();
233 pdf_info.fKeywords = config.keywords.value.c_str();
234 pdf_info.fCreator = config.creator.value.c_str();
235 #if 0
236 SkPDF::DateTime now;
238 pdf_info.fCreation = now;
239 pdf_info.fModified = now;
240 pdf_info.fPDFA = true;
241 #endif
242 return SkPDF::MakeDocument(wStream, pdf_info);
243}
244
245int main(int argc, char **argv) {
246 Config config(argc, argv);
247 SkFILEWStream wStream(config.output_file_name.value.c_str());
248 sk_sp<SkDocument> doc = MakePDFDocument(config, &wStream);
249 assert(doc);
250 Placement placement(&config, doc.get());
251
252 const std::string &font_file = config.font_file.value;
253 sk_sp<SkTypeface> typeface;
254 if (font_file.size() > 0) {
255 // There are different font managers for different platforms. See include/ports
257 assert(mgr);
258 typeface = mgr->makeFromFile(font_file.c_str(), 0 /* index */);
259 }
260 std::unique_ptr<SkShaper> shaper =
262 assert(shaper);
263 //SkString line("This is هذا هو الخط a line.");
264 //SkString line("⁧This is a line هذا هو الخط.⁩");
265 for (std::string line; std::getline(std::cin, line);) {
266 placement.WriteLine(*shaper, line.c_str(), line.size());
267 }
268
269 doc->close();
270 wStream.flush();
271 return 0;
272}
const char * options
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SkASSERT(cond)
Definition: SkAssert.h:116
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
SK_API sk_sp< SkFontMgr > SkFontMgr_New_Custom_Empty()
#define SkDoubleToScalar(x)
Definition: SkScalar.h:64
sk_sp< SkUnicode > get_unicode()
void WriteLine(const SkShaper &shaper, const char *text, size_t textBytes)
Placement(const Config *conf, SkDocument *doc)
uint8_t Level
Definition: SkUnicode.h:46
void drawPaint(const SkPaint &paint)
Definition: SkCanvas.cpp:1668
void drawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint)
Definition: SkCanvas.cpp:2484
SkCanvas * beginPage(SkScalar width, SkScalar height, const SkRect *content=nullptr)
Definition: SkDocument.cpp:32
void endPage()
Definition: SkDocument.cpp:45
void flush() override
Definition: SkStream.cpp:442
static sk_sp< SkFontMgr > RefEmpty()
Definition: SkFontMgr.cpp:154
sk_sp< SkTypeface > makeFromFile(const char path[], int ttcIndex=0) const
Definition: SkFontMgr.cpp:143
Definition: SkFont.h:35
void setSubpixel(bool subpixel)
Definition: SkFont.cpp:109
void setEdging(Edging edging)
Definition: SkFont.cpp:121
void setSize(SkScalar textSize)
Definition: SkFont.cpp:129
@ kSubpixelAntiAlias
glyph positioned in pixel using transparency
void setColor(SkColor color)
Definition: SkPaint.cpp:119
void setAntiAlias(bool aa)
Definition: SkPaint.h:170
static std::unique_ptr< FontRunIterator > MakeFontMgrRunIterator(const char *utf8, size_t utf8Bytes, const SkFont &font, sk_sp< SkFontMgr > fallback)
Definition: SkShaper.cpp:187
static std::unique_ptr< LanguageRunIterator > MakeStdLanguageRunIterator(const char *utf8, size_t utf8Bytes)
Definition: SkShaper.cpp:204
virtual void shape(const char *utf8, size_t utf8Bytes, const SkFont &srcFont, bool leftToRight, SkScalar width, RunHandler *) const =0
T * get() const
Definition: SkRefCnt.h:303
float SkScalar
Definition: extension.cpp:12
std::u16string text
char ** argv
Definition: library.h:9
void GetDateTime(SkPDF::DateTime *)
Definition: SkPDFUtils.cpp:431
SK_API sk_sp< SkDocument > MakeDocument(SkWStream *stream, const Metadata &metadata)
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: SkSLString.cpp:83
SKSHAPER_API std::unique_ptr< SkShaper > ShaperDrivenWrapper(sk_sp< SkUnicode > unicode, sk_sp< SkFontMgr > fallback)
SKSHAPER_API std::unique_ptr< SkShaper::ScriptRunIterator > ScriptRunIterator(const char *utf8, size_t utf8Bytes)
SKSHAPER_API std::unique_ptr< SkShaper::BiDiRunIterator > BidiRunIterator(sk_sp< SkUnicode > unicode, const char *utf8, size_t utf8Bytes, uint8_t bidiLevel)
SKUNICODE_API sk_sp< SkUnicode > Make()
exit(kErrorExitCode)
Definition: ref_ptr.h:256
#define T
Definition: precompiler.cc:65
int32_t width
virtual std::string valueToString()=0
static void Init(const std::vector< BaseOption * > &, int argc, char **argv)
BaseOption(std::string _selector, std::string _description)
virtual void set(const std::string &_value)=0
Config(int argc, char **argv)
DoubleOption line_spacing_ratio
StringOption author
StringOption keywords
DoubleOption page_width
DoubleOption page_height
StringOption title
DoubleOption left_margin
StringOption creator
StringOption font_file
StringOption output_file_name
DoubleOption font_size
StringOption subject
DoubleOption(std::string _selector, std::string _description, double defaultValue)
std::string valueToString() override
void set(const std::string &_value) override
Option(std::string _selector, std::string _description, T defaultValue)
SkString fSubject
Definition: SkPDFDocument.h:96
SkString fAuthor
Definition: SkPDFDocument.h:92
SkString fKeywords
DateTime fCreation
DateTime fModified
constexpr float y() const
Definition: SkPoint_impl.h:187
void set(const std::string &_value) override
StringOption(std::string _selector, std::string _description, std::string defaultValue)
std::string valueToString() override
int main(int argc, char **argv)
static sk_sp< SkDocument > MakePDFDocument(const Config &config, SkWStream *wStream)