blob: 13f8c8ee8e9f2cff27db8afd397abd76562cf6b1 [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>
Robert Phillipscb77eab2020-03-24 14:19:40 +000024#include "modules/canvaskit/WasmAliases.h"
Kevin Lubick369f6a52019-10-03 11:22:08 -040025
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 {
Robert Phillipscb77eab2020-03-24 14:19:40 +000037 SkColor backgroundColor;
38 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;
Robert Phillipscb77eab2020-03-24 14:19:40 +000043 SkColor foregroundColor;
Kevin Lubickd3b1fe62019-10-21 10:50:26 -040044
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;
Robert Phillipscb77eab2020-03-24 14:19:40 +000051 if (s.color != 0) {
52 ts.setColor(s.color);
53 }
Kevin Lubick369f6a52019-10-03 11:22:08 -040054
Robert Phillipscb77eab2020-03-24 14:19:40 +000055 if (s.foregroundColor != 0) {
56 SkPaint p;
57 p.setColor(s.foregroundColor);
58 ts.setForegroundColor(p);
59 }
Kevin Lubick369f6a52019-10-03 11:22:08 -040060
Robert Phillipscb77eab2020-03-24 14:19:40 +000061 if (s.backgroundColor != 0) {
62 SkPaint p;
63 p.setColor(s.backgroundColor);
64 ts.setBackgroundColor(p);
65 }
Kevin Lubick369f6a52019-10-03 11:22:08 -040066
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
Kevin Lubick4a5f4f22019-11-20 08:27:10 -0500126struct SimpleTextBox {
127 SkRect rect;
128 // This isn't the most efficient way to represent this, but it is much easier to keep
129 // everything as floats when unpacking on the JS side.
130 // 0.0 = RTL, 1.0 = LTr
131 SkScalar direction;
132};
133
Kevin Lubick369f6a52019-10-03 11:22:08 -0400134Float32Array GetRectsForRange(para::ParagraphImpl& self, unsigned start, unsigned end,
135 para::RectHeightStyle heightStyle, para::RectWidthStyle widthStyle) {
136 std::vector<para::TextBox> boxes = self.getRectsForRange(start, end, heightStyle, widthStyle);
Kevin Lubick4a5f4f22019-11-20 08:27:10 -0500137 // Pack these text boxes into an array of n groups of 5 SkScalar (floats)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400138 if (!boxes.size()) {
139 return emscripten::val::null();
140 }
Kevin Lubick4a5f4f22019-11-20 08:27:10 -0500141 SimpleTextBox* rects = new SimpleTextBox[boxes.size()];
Kevin Lubick369f6a52019-10-03 11:22:08 -0400142 for (int i = 0; i< boxes.size(); i++) {
Kevin Lubick4a5f4f22019-11-20 08:27:10 -0500143 rects[i].rect = boxes[i].rect;
144 if (boxes[i].direction == para::TextDirection::kRtl) {
145 rects[i].direction = 0;
146 } else {
147 rects[i].direction = 1;
148 }
Kevin Lubick369f6a52019-10-03 11:22:08 -0400149 }
150 float* fPtr = reinterpret_cast<float*>(rects);
151 // Of note: now that we have cast rects to float*, emscripten is smart enough to wrap this
152 // into a Float32Array for us.
Kevin Lubick4a5f4f22019-11-20 08:27:10 -0500153 return Float32Array(typed_memory_view(boxes.size()*5, fPtr));
Kevin Lubick369f6a52019-10-03 11:22:08 -0400154}
155
156EMSCRIPTEN_BINDINGS(Paragraph) {
157
158 class_<para::Paragraph>("Paragraph");
159
160 // This "base<>" tells Emscripten that ParagraphImpl is a Paragraph and can get substituted
161 // in properly in drawParagraph. However, Emscripten will not let us bind pure virtual methods
Kevin Lubick04912672019-11-15 14:48:55 -0500162 // so we have to "expose" the ParagraphImpl in those cases.
Kevin Lubick369f6a52019-10-03 11:22:08 -0400163 class_<para::ParagraphImpl, base<para::Paragraph>>("ParagraphImpl")
Kevin Lubick04912672019-11-15 14:48:55 -0500164 .function("didExceedMaxLines", &para::Paragraph::didExceedMaxLines)
165 .function("getAlphabeticBaseline", &para::Paragraph::getAlphabeticBaseline)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400166 .function("getGlyphPositionAtCoordinate", &para::ParagraphImpl::getGlyphPositionAtCoordinate)
Kevin Lubick04912672019-11-15 14:48:55 -0500167 .function("getHeight", &para::Paragraph::getHeight)
168 .function("getIdeographicBaseline", &para::Paragraph::getIdeographicBaseline)
169 .function("getLongestLine", &para::Paragraph::getLongestLine)
170 .function("getMaxIntrinsicWidth", &para::Paragraph::getMaxIntrinsicWidth)
171 .function("getMaxWidth", &para::Paragraph::getMaxWidth)
172 .function("getMinIntrinsicWidth", &para::Paragraph::getMinIntrinsicWidth)
173 .function("_getRectsForRange", &GetRectsForRange)
174 .function("getWordBoundary", &para::ParagraphImpl::getWordBoundary)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400175 .function("layout", &para::ParagraphImpl::layout);
176
177 class_<para::ParagraphBuilderImpl>("ParagraphBuilder")
178 .class_function("Make", optional_override([](SimpleParagraphStyle style,
179 sk_sp<SkFontMgr> fontMgr)-> para::ParagraphBuilderImpl {
180 auto fc = sk_make_sp<para::FontCollection>();
181 fc->setDefaultFontManager(fontMgr);
182 auto ps = toParagraphStyle(style);
183 para::ParagraphBuilderImpl pbi(ps, fc);
184 return pbi;
185 }), allow_raw_pointers())
186 .function("addText", optional_override([](para::ParagraphBuilderImpl& self, std::string text) {
187 return self.addText(text.c_str(), text.length());
188 }))
189 .function("build", &para::ParagraphBuilderImpl::Build, allow_raw_pointers())
190 .function("pop", &para::ParagraphBuilderImpl::pop)
191 .function("pushStyle", optional_override([](para::ParagraphBuilderImpl& self,
192 SimpleTextStyle textStyle) {
193 auto ts = toTextStyle(textStyle);
194 self.pushStyle(ts);
195 }));
196
197
198 enum_<para::Affinity>("Affinity")
199 .value("Upstream", para::Affinity::kUpstream)
200 .value("Downstream", para::Affinity::kDownstream);
201
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400202 enum_<SkFontStyle::Slant>("FontSlant")
203 .value("Upright", SkFontStyle::Slant::kUpright_Slant)
204 .value("Italic", SkFontStyle::Slant::kItalic_Slant)
205 .value("Oblique", SkFontStyle::Slant::kOblique_Slant);
206
207 enum_<SkFontStyle::Weight>("FontWeight")
208 .value("Invisible", SkFontStyle::Weight::kInvisible_Weight)
209 .value("Thin", SkFontStyle::Weight::kThin_Weight)
210 .value("ExtraLight", SkFontStyle::Weight::kExtraLight_Weight)
211 .value("Light", SkFontStyle::Weight::kLight_Weight)
212 .value("Normal", SkFontStyle::Weight::kNormal_Weight)
213 .value("Medium", SkFontStyle::Weight::kMedium_Weight)
214 .value("SemiBold", SkFontStyle::Weight::kSemiBold_Weight)
215 .value("Bold", SkFontStyle::Weight::kBold_Weight)
216 .value("ExtraBold", SkFontStyle::Weight::kExtraBold_Weight)
217 .value("Black" , SkFontStyle::Weight::kBlack_Weight)
218 .value("ExtraBlack", SkFontStyle::Weight::kExtraBlack_Weight);
219
220 enum_<SkFontStyle::Width>("FontWidth")
221 .value("UltraCondensed", SkFontStyle::Width::kUltraCondensed_Width)
222 .value("ExtraCondensed", SkFontStyle::Width::kExtraCondensed_Width)
223 .value("Condensed", SkFontStyle::Width::kCondensed_Width)
224 .value("SemiCondensed", SkFontStyle::Width::kSemiCondensed_Width)
225 .value("Normal", SkFontStyle::Width::kNormal_Width)
226 .value("SemiExpanded", SkFontStyle::Width::kSemiExpanded_Width)
227 .value("Expanded", SkFontStyle::Width::kExpanded_Width)
228 .value("ExtraExpanded", SkFontStyle::Width::kExtraExpanded_Width)
229 .value("UltraExpanded", SkFontStyle::Width::kUltraExpanded_Width);
230
Kevin Lubick369f6a52019-10-03 11:22:08 -0400231 enum_<para::RectHeightStyle>("RectHeightStyle")
Kevin Lubick4a5f4f22019-11-20 08:27:10 -0500232 .value("Tight", para::RectHeightStyle::kTight)
233 .value("Max", para::RectHeightStyle::kMax)
234 .value("IncludeLineSpacingMiddle", para::RectHeightStyle::kIncludeLineSpacingMiddle)
235 .value("IncludeLineSpacingTop", para::RectHeightStyle::kIncludeLineSpacingTop)
236 .value("IncludeLineSpacingBottom", para::RectHeightStyle::kIncludeLineSpacingBottom);
Kevin Lubick369f6a52019-10-03 11:22:08 -0400237
238 enum_<para::RectWidthStyle>("RectWidthStyle")
239 .value("Tight", para::RectWidthStyle::kTight)
240 .value("Max", para::RectWidthStyle::kMax);
241
242 enum_<para::TextAlign>("TextAlign")
243 .value("Left", para::TextAlign::kLeft)
244 .value("Right", para::TextAlign::kRight)
245 .value("Center", para::TextAlign::kCenter)
246 .value("Justify", para::TextAlign::kJustify)
247 .value("Start", para::TextAlign::kStart)
248 .value("End", para::TextAlign::kEnd);
249
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400250 enum_<para::TextDirection>("TextDirection")
251 .value("LTR", para::TextDirection::kLtr)
252 .value("RTL", para::TextDirection::kRtl);
253
Kevin Lubick369f6a52019-10-03 11:22:08 -0400254
255 value_object<para::PositionWithAffinity>("PositionWithAffinity")
256 .field("pos", &para::PositionWithAffinity::position)
257 .field("affinity", &para::PositionWithAffinity::affinity);
258
Kevin Lubick04912672019-11-15 14:48:55 -0500259 value_object<SimpleFontStyle>("FontStyle")
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400260 .field("slant", &SimpleFontStyle::slant)
261 .field("weight", &SimpleFontStyle::weight)
262 .field("width", &SimpleFontStyle::width);
263
Kevin Lubick369f6a52019-10-03 11:22:08 -0400264 value_object<SimpleParagraphStyle>("ParagraphStyle")
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400265 .field("disableHinting", &SimpleParagraphStyle::disableHinting)
266 .field("_ellipsisPtr", &SimpleParagraphStyle::ellipsisPtr)
267 .field("_ellipsisLen", &SimpleParagraphStyle::ellipsisLen)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400268 .field("heightMultiplier", &SimpleParagraphStyle::heightMultiplier)
269 .field("maxLines", &SimpleParagraphStyle::maxLines)
270 .field("textAlign", &SimpleParagraphStyle::textAlign)
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400271 .field("textDirection", &SimpleParagraphStyle::textDirection)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400272 .field("textStyle", &SimpleParagraphStyle::textStyle);
273
274 value_object<SimpleTextStyle>("TextStyle")
275 .field("backgroundColor", &SimpleTextStyle::backgroundColor)
276 .field("color", &SimpleTextStyle::color)
277 .field("decoration", &SimpleTextStyle::decoration)
278 .field("decorationThickness", &SimpleTextStyle::decorationThickness)
279 .field("_fontFamilies", &SimpleTextStyle::fontFamilies)
280 .field("fontSize", &SimpleTextStyle::fontSize)
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400281 .field("fontStyle", &SimpleTextStyle::fontStyle)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400282 .field("foregroundColor", &SimpleTextStyle::foregroundColor)
283 .field("_numFontFamilies", &SimpleTextStyle::numFontFamilies);
284
Kevin Lubick04912672019-11-15 14:48:55 -0500285 // The U stands for unsigned - we can't bind a generic/template object, so we have to specify it
286 // with the type we are using.
287 value_object<para::SkRange<size_t>>("URange")
288 .field("start", &para::SkRange<size_t>::start)
289 .field("end", &para::SkRange<size_t>::end);
290
Kevin Lubick369f6a52019-10-03 11:22:08 -0400291 // TextDecoration should be a const because they can be combined
292 constant("NoDecoration", int(para::TextDecoration::kNoDecoration));
293 constant("UnderlineDecoration", int(para::TextDecoration::kUnderline));
294 constant("OverlineDecoration", int(para::TextDecoration::kOverline));
295 constant("LineThroughDecoration", int(para::TextDecoration::kLineThrough));
296}