blob: c4313889ecc55372a020f55d2850c722b0ff74d1 [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>
Nathaniel Nifong4e79b672020-03-24 09:08:37 -040024#include "modules/canvaskit/WasmCommon.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 {
Nathaniel Nifong4e79b672020-03-24 09:08:37 -040037 SimpleColor4f backgroundColor;
38 SimpleColor4f 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;
Nathaniel Nifong4e79b672020-03-24 09:08:37 -040043 SimpleColor4f 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;
Kevin Lubick369f6a52019-10-03 11:22:08 -040051
Nathaniel Nifong4e79b672020-03-24 09:08:37 -040052 // textstype doesn't support a 4f color
53 //SkColor4f({s.color.r, s.color.g, s.color.b, s.color.a}
54 ts.setColor(s.color.toSkColor());
Kevin Lubick369f6a52019-10-03 11:22:08 -040055
Nathaniel Nifong4e79b672020-03-24 09:08:37 -040056 // TODO(nifong): when color was a uint, these were left unset if the color was white, was that
57 // important?
58 SkPaint p1;
59 p1.setColor4f(s.foregroundColor.toSkColor4f());
60 ts.setForegroundColor(p1);
61
62 SkPaint p2;
63 p2.setColor4f(s.backgroundColor.toSkColor4f());
64 ts.setBackgroundColor(p2);
Kevin Lubick369f6a52019-10-03 11:22:08 -040065
66 if (s.fontSize != 0) {
67 ts.setFontSize(s.fontSize);
68 }
69
70 ts.setDecoration(para::TextDecoration(s.decoration));
71 if (s.decorationThickness != 0) {
72 ts.setDecorationThicknessMultiplier(s.decorationThickness);
73 }
74
75 const char** fontFamilies = reinterpret_cast<const char**>(s.fontFamilies);
76 if (s.numFontFamilies > 0 && fontFamilies != nullptr) {
77 std::vector<SkString> ff;
78 for (int i = 0; i< s.numFontFamilies; i++) {
79 ff.emplace_back(fontFamilies[i]);
80 }
81 ts.setFontFamilies(ff);
82 }
83
Kevin Lubickd3b1fe62019-10-21 10:50:26 -040084 SkFontStyle fs(s.fontStyle.weight, s.fontStyle.width, s.fontStyle.slant);
85 ts.setFontStyle(fs);
86
Kevin Lubick369f6a52019-10-03 11:22:08 -040087 return ts;
88}
89
90struct SimpleParagraphStyle {
Kevin Lubickd3b1fe62019-10-21 10:50:26 -040091 bool disableHinting;
92 uintptr_t /* const char* */ ellipsisPtr;
93 size_t ellipsisLen;
Kevin Lubick369f6a52019-10-03 11:22:08 -040094 SkScalar heightMultiplier;
Kevin Lubick369f6a52019-10-03 11:22:08 -040095 size_t maxLines;
Kevin Lubickd3b1fe62019-10-21 10:50:26 -040096 para::TextAlign textAlign;
97 para::TextDirection textDirection;
98 SimpleTextStyle textStyle;
Kevin Lubick369f6a52019-10-03 11:22:08 -040099};
100
101para::ParagraphStyle toParagraphStyle(const SimpleParagraphStyle& s) {
102 para::ParagraphStyle ps;
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400103 if (s.disableHinting) {
104 ps.turnHintingOff();
105 }
106
107 if (s.ellipsisLen > 0) {
108 const char* ellipsisPtr = reinterpret_cast<const char*>(s.ellipsisPtr);
109 SkString eStr(ellipsisPtr, s.ellipsisLen);
110 ps.setEllipsis(eStr);
111 }
112 ps.setTextAlign(s.textAlign);
113 ps.setTextDirection(s.textDirection);
Kevin Lubick369f6a52019-10-03 11:22:08 -0400114 auto ts = toTextStyle(s.textStyle);
115 ps.setTextStyle(ts);
116 if (s.heightMultiplier != 0) {
117 ps.setHeight(s.heightMultiplier);
118 }
Kevin Lubick369f6a52019-10-03 11:22:08 -0400119 if (s.maxLines != 0) {
120 ps.setMaxLines(s.maxLines);
121 }
122 return ps;
123}
124
Kevin Lubick4a5f4f22019-11-20 08:27:10 -0500125struct SimpleTextBox {
126 SkRect rect;
127 // This isn't the most efficient way to represent this, but it is much easier to keep
128 // everything as floats when unpacking on the JS side.
129 // 0.0 = RTL, 1.0 = LTr
130 SkScalar direction;
131};
132
Kevin Lubick369f6a52019-10-03 11:22:08 -0400133Float32Array GetRectsForRange(para::ParagraphImpl& self, unsigned start, unsigned end,
134 para::RectHeightStyle heightStyle, para::RectWidthStyle widthStyle) {
135 std::vector<para::TextBox> boxes = self.getRectsForRange(start, end, heightStyle, widthStyle);
Kevin Lubick4a5f4f22019-11-20 08:27:10 -0500136 // Pack these text boxes into an array of n groups of 5 SkScalar (floats)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400137 if (!boxes.size()) {
138 return emscripten::val::null();
139 }
Kevin Lubick4a5f4f22019-11-20 08:27:10 -0500140 SimpleTextBox* rects = new SimpleTextBox[boxes.size()];
Kevin Lubick369f6a52019-10-03 11:22:08 -0400141 for (int i = 0; i< boxes.size(); i++) {
Kevin Lubick4a5f4f22019-11-20 08:27:10 -0500142 rects[i].rect = boxes[i].rect;
143 if (boxes[i].direction == para::TextDirection::kRtl) {
144 rects[i].direction = 0;
145 } else {
146 rects[i].direction = 1;
147 }
Kevin Lubick369f6a52019-10-03 11:22:08 -0400148 }
149 float* fPtr = reinterpret_cast<float*>(rects);
150 // Of note: now that we have cast rects to float*, emscripten is smart enough to wrap this
151 // into a Float32Array for us.
Kevin Lubick4a5f4f22019-11-20 08:27:10 -0500152 return Float32Array(typed_memory_view(boxes.size()*5, fPtr));
Kevin Lubick369f6a52019-10-03 11:22:08 -0400153}
154
155EMSCRIPTEN_BINDINGS(Paragraph) {
156
157 class_<para::Paragraph>("Paragraph");
158
159 // This "base<>" tells Emscripten that ParagraphImpl is a Paragraph and can get substituted
160 // in properly in drawParagraph. However, Emscripten will not let us bind pure virtual methods
Kevin Lubick04912672019-11-15 14:48:55 -0500161 // so we have to "expose" the ParagraphImpl in those cases.
Kevin Lubick369f6a52019-10-03 11:22:08 -0400162 class_<para::ParagraphImpl, base<para::Paragraph>>("ParagraphImpl")
Kevin Lubick04912672019-11-15 14:48:55 -0500163 .function("didExceedMaxLines", &para::Paragraph::didExceedMaxLines)
164 .function("getAlphabeticBaseline", &para::Paragraph::getAlphabeticBaseline)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400165 .function("getGlyphPositionAtCoordinate", &para::ParagraphImpl::getGlyphPositionAtCoordinate)
Kevin Lubick04912672019-11-15 14:48:55 -0500166 .function("getHeight", &para::Paragraph::getHeight)
167 .function("getIdeographicBaseline", &para::Paragraph::getIdeographicBaseline)
168 .function("getLongestLine", &para::Paragraph::getLongestLine)
169 .function("getMaxIntrinsicWidth", &para::Paragraph::getMaxIntrinsicWidth)
170 .function("getMaxWidth", &para::Paragraph::getMaxWidth)
171 .function("getMinIntrinsicWidth", &para::Paragraph::getMinIntrinsicWidth)
172 .function("_getRectsForRange", &GetRectsForRange)
173 .function("getWordBoundary", &para::ParagraphImpl::getWordBoundary)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400174 .function("layout", &para::ParagraphImpl::layout);
175
176 class_<para::ParagraphBuilderImpl>("ParagraphBuilder")
177 .class_function("Make", optional_override([](SimpleParagraphStyle style,
178 sk_sp<SkFontMgr> fontMgr)-> para::ParagraphBuilderImpl {
179 auto fc = sk_make_sp<para::FontCollection>();
180 fc->setDefaultFontManager(fontMgr);
181 auto ps = toParagraphStyle(style);
182 para::ParagraphBuilderImpl pbi(ps, fc);
183 return pbi;
184 }), allow_raw_pointers())
185 .function("addText", optional_override([](para::ParagraphBuilderImpl& self, std::string text) {
186 return self.addText(text.c_str(), text.length());
187 }))
188 .function("build", &para::ParagraphBuilderImpl::Build, allow_raw_pointers())
189 .function("pop", &para::ParagraphBuilderImpl::pop)
190 .function("pushStyle", optional_override([](para::ParagraphBuilderImpl& self,
191 SimpleTextStyle textStyle) {
192 auto ts = toTextStyle(textStyle);
193 self.pushStyle(ts);
194 }));
195
196
197 enum_<para::Affinity>("Affinity")
198 .value("Upstream", para::Affinity::kUpstream)
199 .value("Downstream", para::Affinity::kDownstream);
200
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400201 enum_<SkFontStyle::Slant>("FontSlant")
202 .value("Upright", SkFontStyle::Slant::kUpright_Slant)
203 .value("Italic", SkFontStyle::Slant::kItalic_Slant)
204 .value("Oblique", SkFontStyle::Slant::kOblique_Slant);
205
206 enum_<SkFontStyle::Weight>("FontWeight")
207 .value("Invisible", SkFontStyle::Weight::kInvisible_Weight)
208 .value("Thin", SkFontStyle::Weight::kThin_Weight)
209 .value("ExtraLight", SkFontStyle::Weight::kExtraLight_Weight)
210 .value("Light", SkFontStyle::Weight::kLight_Weight)
211 .value("Normal", SkFontStyle::Weight::kNormal_Weight)
212 .value("Medium", SkFontStyle::Weight::kMedium_Weight)
213 .value("SemiBold", SkFontStyle::Weight::kSemiBold_Weight)
214 .value("Bold", SkFontStyle::Weight::kBold_Weight)
215 .value("ExtraBold", SkFontStyle::Weight::kExtraBold_Weight)
216 .value("Black" , SkFontStyle::Weight::kBlack_Weight)
217 .value("ExtraBlack", SkFontStyle::Weight::kExtraBlack_Weight);
218
219 enum_<SkFontStyle::Width>("FontWidth")
220 .value("UltraCondensed", SkFontStyle::Width::kUltraCondensed_Width)
221 .value("ExtraCondensed", SkFontStyle::Width::kExtraCondensed_Width)
222 .value("Condensed", SkFontStyle::Width::kCondensed_Width)
223 .value("SemiCondensed", SkFontStyle::Width::kSemiCondensed_Width)
224 .value("Normal", SkFontStyle::Width::kNormal_Width)
225 .value("SemiExpanded", SkFontStyle::Width::kSemiExpanded_Width)
226 .value("Expanded", SkFontStyle::Width::kExpanded_Width)
227 .value("ExtraExpanded", SkFontStyle::Width::kExtraExpanded_Width)
228 .value("UltraExpanded", SkFontStyle::Width::kUltraExpanded_Width);
229
Kevin Lubick369f6a52019-10-03 11:22:08 -0400230 enum_<para::RectHeightStyle>("RectHeightStyle")
Kevin Lubick4a5f4f22019-11-20 08:27:10 -0500231 .value("Tight", para::RectHeightStyle::kTight)
232 .value("Max", para::RectHeightStyle::kMax)
233 .value("IncludeLineSpacingMiddle", para::RectHeightStyle::kIncludeLineSpacingMiddle)
234 .value("IncludeLineSpacingTop", para::RectHeightStyle::kIncludeLineSpacingTop)
235 .value("IncludeLineSpacingBottom", para::RectHeightStyle::kIncludeLineSpacingBottom);
Kevin Lubick369f6a52019-10-03 11:22:08 -0400236
237 enum_<para::RectWidthStyle>("RectWidthStyle")
238 .value("Tight", para::RectWidthStyle::kTight)
239 .value("Max", para::RectWidthStyle::kMax);
240
241 enum_<para::TextAlign>("TextAlign")
242 .value("Left", para::TextAlign::kLeft)
243 .value("Right", para::TextAlign::kRight)
244 .value("Center", para::TextAlign::kCenter)
245 .value("Justify", para::TextAlign::kJustify)
246 .value("Start", para::TextAlign::kStart)
247 .value("End", para::TextAlign::kEnd);
248
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400249 enum_<para::TextDirection>("TextDirection")
250 .value("LTR", para::TextDirection::kLtr)
251 .value("RTL", para::TextDirection::kRtl);
252
Kevin Lubick369f6a52019-10-03 11:22:08 -0400253
254 value_object<para::PositionWithAffinity>("PositionWithAffinity")
255 .field("pos", &para::PositionWithAffinity::position)
256 .field("affinity", &para::PositionWithAffinity::affinity);
257
Kevin Lubick04912672019-11-15 14:48:55 -0500258 value_object<SimpleFontStyle>("FontStyle")
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400259 .field("slant", &SimpleFontStyle::slant)
260 .field("weight", &SimpleFontStyle::weight)
261 .field("width", &SimpleFontStyle::width);
262
Kevin Lubick369f6a52019-10-03 11:22:08 -0400263 value_object<SimpleParagraphStyle>("ParagraphStyle")
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400264 .field("disableHinting", &SimpleParagraphStyle::disableHinting)
265 .field("_ellipsisPtr", &SimpleParagraphStyle::ellipsisPtr)
266 .field("_ellipsisLen", &SimpleParagraphStyle::ellipsisLen)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400267 .field("heightMultiplier", &SimpleParagraphStyle::heightMultiplier)
268 .field("maxLines", &SimpleParagraphStyle::maxLines)
269 .field("textAlign", &SimpleParagraphStyle::textAlign)
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400270 .field("textDirection", &SimpleParagraphStyle::textDirection)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400271 .field("textStyle", &SimpleParagraphStyle::textStyle);
272
273 value_object<SimpleTextStyle>("TextStyle")
274 .field("backgroundColor", &SimpleTextStyle::backgroundColor)
275 .field("color", &SimpleTextStyle::color)
276 .field("decoration", &SimpleTextStyle::decoration)
277 .field("decorationThickness", &SimpleTextStyle::decorationThickness)
278 .field("_fontFamilies", &SimpleTextStyle::fontFamilies)
279 .field("fontSize", &SimpleTextStyle::fontSize)
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400280 .field("fontStyle", &SimpleTextStyle::fontStyle)
Kevin Lubick369f6a52019-10-03 11:22:08 -0400281 .field("foregroundColor", &SimpleTextStyle::foregroundColor)
282 .field("_numFontFamilies", &SimpleTextStyle::numFontFamilies);
283
Kevin Lubick04912672019-11-15 14:48:55 -0500284 // The U stands for unsigned - we can't bind a generic/template object, so we have to specify it
285 // with the type we are using.
286 value_object<para::SkRange<size_t>>("URange")
287 .field("start", &para::SkRange<size_t>::start)
288 .field("end", &para::SkRange<size_t>::end);
289
Kevin Lubick369f6a52019-10-03 11:22:08 -0400290 // TextDecoration should be a const because they can be combined
291 constant("NoDecoration", int(para::TextDecoration::kNoDecoration));
292 constant("UnderlineDecoration", int(para::TextDecoration::kUnderline));
293 constant("OverlineDecoration", int(para::TextDecoration::kOverline));
294 constant("LineThroughDecoration", int(para::TextDecoration::kLineThrough));
295}