blob: dbb5639328d919a9f9b2712b405786514b2ef50c [file] [log] [blame]
Kevin Lubick369f6a52019-10-03 11:22:08 -04001/*
2 * Copyright 2019 Google LLC
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 "include/core/SkColor.h"
Kevin Lubickd3b1fe62019-10-21 10:50:26 -04009#include "include/core/SkFontStyle.h"
Kevin Lubick369f6a52019-10-03 11:22:08 -040010#include "include/core/SkString.h"
11
12#include "modules/skparagraph/include/DartTypes.h"
13#include "modules/skparagraph/include/Paragraph.h"
14#include "modules/skparagraph/include/ParagraphBuilder.h"
15#include "modules/skparagraph/include/TextStyle.h"
16#include "modules/skparagraph/src/ParagraphBuilderImpl.h"
17#include "modules/skparagraph/src/ParagraphImpl.h"
18
19#include <string>
20#include <vector>
21
22#include <emscripten.h>
23#include <emscripten/bind.h>
24#include "modules/canvaskit/WasmAliases.h"
25
26using namespace emscripten;
27
28namespace para = skia::textlayout;
29
Kevin Lubickd3b1fe62019-10-21 10:50:26 -040030struct SimpleFontStyle {
31 SkFontStyle::Slant slant;
32 SkFontStyle::Weight weight;
33 SkFontStyle::Width width;
34};
35
Kevin Lubick369f6a52019-10-03 11:22:08 -040036struct SimpleTextStyle {
Kevin Lubick369f6a52019-10-03 11:22:08 -040037 SkColor backgroundColor;
Kevin Lubickd3b1fe62019-10-21 10:50:26 -040038 SkColor color;
Kevin Lubick369f6a52019-10-03 11:22:08 -040039 uint8_t decoration;
Kevin Lubick369f6a52019-10-03 11:22:08 -040040 SkScalar decorationThickness;
Kevin Lubickd3b1fe62019-10-21 10:50:26 -040041 SkScalar fontSize;
42 SimpleFontStyle fontStyle;
43 SkColor foregroundColor;
44
Kevin Lubick369f6a52019-10-03 11:22:08 -040045 uintptr_t /* const char** */ fontFamilies;
46 int numFontFamilies;
47};
48
49para::TextStyle toTextStyle(const SimpleTextStyle& s) {
50 para::TextStyle ts;
51 if (s.color != 0) {
52 ts.setColor(s.color);
53 }
54
55 if (s.foregroundColor != 0) {
56 SkPaint p;
57 p.setColor(s.foregroundColor);
58 ts.setForegroundColor(p);
59 }
60
61 if (s.backgroundColor != 0) {
62 SkPaint p;
63 p.setColor(s.backgroundColor);
64 ts.setBackgroundColor(p);
65 }
66
67 if (s.fontSize != 0) {
68 ts.setFontSize(s.fontSize);
69 }
70
71 ts.setDecoration(para::TextDecoration(s.decoration));
72 if (s.decorationThickness != 0) {
73 ts.setDecorationThicknessMultiplier(s.decorationThickness);
74 }
75
76 const char** fontFamilies = reinterpret_cast<const char**>(s.fontFamilies);
77 if (s.numFontFamilies > 0 && fontFamilies != nullptr) {
78 std::vector<SkString> ff;
79 for (int i = 0; i< s.numFontFamilies; i++) {
80 ff.emplace_back(fontFamilies[i]);
81 }
82 ts.setFontFamilies(ff);
83 }
84
Kevin Lubickd3b1fe62019-10-21 10:50:26 -040085 SkFontStyle fs(s.fontStyle.weight, s.fontStyle.width, s.fontStyle.slant);
86 ts.setFontStyle(fs);
87
Kevin Lubick369f6a52019-10-03 11:22:08 -040088 return ts;
89}
90
91struct SimpleParagraphStyle {
Kevin Lubickd3b1fe62019-10-21 10:50:26 -040092 bool disableHinting;
93 uintptr_t /* const char* */ ellipsisPtr;
94 size_t ellipsisLen;
Kevin Lubick369f6a52019-10-03 11:22:08 -040095 SkScalar heightMultiplier;
Kevin Lubick369f6a52019-10-03 11:22:08 -040096 size_t maxLines;
Kevin Lubickd3b1fe62019-10-21 10:50:26 -040097 para::TextAlign textAlign;
98 para::TextDirection textDirection;
99 SimpleTextStyle textStyle;
Kevin Lubick369f6a52019-10-03 11:22:08 -0400100};
101
102para::ParagraphStyle toParagraphStyle(const SimpleParagraphStyle& s) {
103 para::ParagraphStyle ps;
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400104 if (s.disableHinting) {
105 ps.turnHintingOff();
106 }
107
108 if (s.ellipsisLen > 0) {
109 const char* ellipsisPtr = reinterpret_cast<const char*>(s.ellipsisPtr);
110 SkString eStr(ellipsisPtr, s.ellipsisLen);
111 ps.setEllipsis(eStr);
112 }
113 ps.setTextAlign(s.textAlign);
114 ps.setTextDirection(s.textDirection);
Kevin Lubick369f6a52019-10-03 11:22:08 -0400115 auto ts = toTextStyle(s.textStyle);
116 ps.setTextStyle(ts);
117 if (s.heightMultiplier != 0) {
118 ps.setHeight(s.heightMultiplier);
119 }
Kevin Lubick369f6a52019-10-03 11:22:08 -0400120 if (s.maxLines != 0) {
121 ps.setMaxLines(s.maxLines);
122 }
123 return ps;
124}
125
126Float32Array GetRectsForRange(para::ParagraphImpl& self, unsigned start, unsigned end,
127 para::RectHeightStyle heightStyle, para::RectWidthStyle widthStyle) {
128 std::vector<para::TextBox> boxes = self.getRectsForRange(start, end, heightStyle, widthStyle);
129 // Pack these text boxes into an array of n groups of 4 SkScalar (floats)
130 if (!boxes.size()) {
131 return emscripten::val::null();
132 }
133 SkRect* rects = new SkRect[boxes.size()];
134 for (int i = 0; i< boxes.size(); i++) {
135 rects[i] = boxes[i].rect;
136 }
137 float* fPtr = reinterpret_cast<float*>(rects);
138 // Of note: now that we have cast rects to float*, emscripten is smart enough to wrap this
139 // into a Float32Array for us.
140 return Float32Array(typed_memory_view(boxes.size()*4, fPtr));
141}
142
143EMSCRIPTEN_BINDINGS(Paragraph) {
144
145 class_<para::Paragraph>("Paragraph");
146
147 // This "base<>" tells Emscripten that ParagraphImpl is a Paragraph and can get substituted
148 // in properly in drawParagraph. However, Emscripten will not let us bind pure virtual methods
149 // so we have to "expose" the ParagraphImpl and its methods.
150 class_<para::ParagraphImpl, base<para::Paragraph>>("ParagraphImpl")
151 .function("_getRectsForRange", &GetRectsForRange)
152 .function("getGlyphPositionAtCoordinate", &para::ParagraphImpl::getGlyphPositionAtCoordinate)
153 .function("layout", &para::ParagraphImpl::layout);
154
155 class_<para::ParagraphBuilderImpl>("ParagraphBuilder")
156 .class_function("Make", optional_override([](SimpleParagraphStyle style,
157 sk_sp<SkFontMgr> fontMgr)-> para::ParagraphBuilderImpl {
158 auto fc = sk_make_sp<para::FontCollection>();
159 fc->setDefaultFontManager(fontMgr);
160 auto ps = toParagraphStyle(style);
161 para::ParagraphBuilderImpl pbi(ps, fc);
162 return pbi;
163 }), allow_raw_pointers())
164 .function("addText", optional_override([](para::ParagraphBuilderImpl& self, std::string text) {
165 return self.addText(text.c_str(), text.length());
166 }))
167 .function("build", &para::ParagraphBuilderImpl::Build, allow_raw_pointers())
168 .function("pop", &para::ParagraphBuilderImpl::pop)
169 .function("pushStyle", optional_override([](para::ParagraphBuilderImpl& self,
170 SimpleTextStyle textStyle) {
171 auto ts = toTextStyle(textStyle);
172 self.pushStyle(ts);
173 }));
174
175
176 enum_<para::Affinity>("Affinity")
177 .value("Upstream", para::Affinity::kUpstream)
178 .value("Downstream", para::Affinity::kDownstream);
179
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400180 enum_<SkFontStyle::Slant>("FontSlant")
181 .value("Upright", SkFontStyle::Slant::kUpright_Slant)
182 .value("Italic", SkFontStyle::Slant::kItalic_Slant)
183 .value("Oblique", SkFontStyle::Slant::kOblique_Slant);
184
185 enum_<SkFontStyle::Weight>("FontWeight")
186 .value("Invisible", SkFontStyle::Weight::kInvisible_Weight)
187 .value("Thin", SkFontStyle::Weight::kThin_Weight)
188 .value("ExtraLight", SkFontStyle::Weight::kExtraLight_Weight)
189 .value("Light", SkFontStyle::Weight::kLight_Weight)
190 .value("Normal", SkFontStyle::Weight::kNormal_Weight)
191 .value("Medium", SkFontStyle::Weight::kMedium_Weight)
192 .value("SemiBold", SkFontStyle::Weight::kSemiBold_Weight)
193 .value("Bold", SkFontStyle::Weight::kBold_Weight)
194 .value("ExtraBold", SkFontStyle::Weight::kExtraBold_Weight)
195 .value("Black" , SkFontStyle::Weight::kBlack_Weight)
196 .value("ExtraBlack", SkFontStyle::Weight::kExtraBlack_Weight);
197
198 enum_<SkFontStyle::Width>("FontWidth")
199 .value("UltraCondensed", SkFontStyle::Width::kUltraCondensed_Width)
200 .value("ExtraCondensed", SkFontStyle::Width::kExtraCondensed_Width)
201 .value("Condensed", SkFontStyle::Width::kCondensed_Width)
202 .value("SemiCondensed", SkFontStyle::Width::kSemiCondensed_Width)
203 .value("Normal", SkFontStyle::Width::kNormal_Width)
204 .value("SemiExpanded", SkFontStyle::Width::kSemiExpanded_Width)
205 .value("Expanded", SkFontStyle::Width::kExpanded_Width)
206 .value("ExtraExpanded", SkFontStyle::Width::kExtraExpanded_Width)
207 .value("UltraExpanded", SkFontStyle::Width::kUltraExpanded_Width);
208
Kevin Lubick369f6a52019-10-03 11:22:08 -0400209 enum_<para::RectHeightStyle>("RectHeightStyle")
210 .value("Tight", para::RectHeightStyle::kTight)
211 .value("Max", para::RectHeightStyle::kMax);
212
213 enum_<para::RectWidthStyle>("RectWidthStyle")
214 .value("Tight", para::RectWidthStyle::kTight)
215 .value("Max", para::RectWidthStyle::kMax);
216
217 enum_<para::TextAlign>("TextAlign")
218 .value("Left", para::TextAlign::kLeft)
219 .value("Right", para::TextAlign::kRight)
220 .value("Center", para::TextAlign::kCenter)
221 .value("Justify", para::TextAlign::kJustify)
222 .value("Start", para::TextAlign::kStart)
223 .value("End", para::TextAlign::kEnd);
224
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400225 enum_<para::TextDirection>("TextDirection")
226 .value("LTR", para::TextDirection::kLtr)
227 .value("RTL", para::TextDirection::kRtl);
228
Kevin Lubick369f6a52019-10-03 11:22:08 -0400229
230 value_object<para::PositionWithAffinity>("PositionWithAffinity")
231 .field("pos", &para::PositionWithAffinity::position)
232 .field("affinity", &para::PositionWithAffinity::affinity);
233
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400234 value_object<SimpleFontStyle>("FontStyle")
235 .field("slant", &SimpleFontStyle::slant)
236 .field("weight", &SimpleFontStyle::weight)
237 .field("width", &SimpleFontStyle::width);
238
Kevin Lubick369f6a52019-10-03 11:22:08 -0400239 value_object<SimpleParagraphStyle>("ParagraphStyle")
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400240 .field("disableHinting", &SimpleParagraphStyle::disableHinting)
241 .field("_ellipsisPtr", &SimpleParagraphStyle::ellipsisPtr)
242 .field("_ellipsisLen", &SimpleParagraphStyle::ellipsisLen)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400243 .field("heightMultiplier", &SimpleParagraphStyle::heightMultiplier)
244 .field("maxLines", &SimpleParagraphStyle::maxLines)
245 .field("textAlign", &SimpleParagraphStyle::textAlign)
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400246 .field("textDirection", &SimpleParagraphStyle::textDirection)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400247 .field("textStyle", &SimpleParagraphStyle::textStyle);
248
249 value_object<SimpleTextStyle>("TextStyle")
250 .field("backgroundColor", &SimpleTextStyle::backgroundColor)
251 .field("color", &SimpleTextStyle::color)
252 .field("decoration", &SimpleTextStyle::decoration)
253 .field("decorationThickness", &SimpleTextStyle::decorationThickness)
254 .field("_fontFamilies", &SimpleTextStyle::fontFamilies)
255 .field("fontSize", &SimpleTextStyle::fontSize)
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400256 .field("fontStyle", &SimpleTextStyle::fontStyle)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400257 .field("foregroundColor", &SimpleTextStyle::foregroundColor)
258 .field("_numFontFamilies", &SimpleTextStyle::numFontFamilies);
259
260 // TextDecoration should be a const because they can be combined
261 constant("NoDecoration", int(para::TextDecoration::kNoDecoration));
262 constant("UnderlineDecoration", int(para::TextDecoration::kUnderline));
263 constant("OverlineDecoration", int(para::TextDecoration::kOverline));
264 constant("LineThroughDecoration", int(para::TextDecoration::kLineThrough));
265}