xref: /aosp_15_r20/external/skia/modules/canvaskit/paragraph_bindings.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2019 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontStyle.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPictureRecorder.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
11*c8dee2aaSAndroid Build Coastguard Worker 
12*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skparagraph/include/DartTypes.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skparagraph/include/Paragraph.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skparagraph/include/TextStyle.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skparagraph/include/TypefaceFontProvider.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skparagraph/src/ParagraphBuilderImpl.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skparagraph/src/ParagraphImpl.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skunicode/include/SkUnicode.h"
19*c8dee2aaSAndroid Build Coastguard Worker 
20*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_ICU_IMPLEMENTATION)
21*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skunicode/include/SkUnicode_icu.h"
22*c8dee2aaSAndroid Build Coastguard Worker #endif
23*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_CLIENT_IMPLEMENTATION)
24*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skunicode/include/SkUnicode_client.h"
25*c8dee2aaSAndroid Build Coastguard Worker #endif
26*c8dee2aaSAndroid Build Coastguard Worker 
27*c8dee2aaSAndroid Build Coastguard Worker #include <string>
28*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
29*c8dee2aaSAndroid Build Coastguard Worker 
30*c8dee2aaSAndroid Build Coastguard Worker #include <emscripten.h>
31*c8dee2aaSAndroid Build Coastguard Worker #include <emscripten/bind.h>
32*c8dee2aaSAndroid Build Coastguard Worker #include "modules/canvaskit/WasmCommon.h"
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker using namespace emscripten;
35*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
36*c8dee2aaSAndroid Build Coastguard Worker 
37*c8dee2aaSAndroid Build Coastguard Worker namespace para = skia::textlayout;
38*c8dee2aaSAndroid Build Coastguard Worker 
39*c8dee2aaSAndroid Build Coastguard Worker // switch to ptrToSkColor4f (canvaskit_bindings.cpp)
toSkColor4f(WASMPointerF32 cPtr)40*c8dee2aaSAndroid Build Coastguard Worker SkColor4f toSkColor4f(WASMPointerF32 cPtr) {
41*c8dee2aaSAndroid Build Coastguard Worker     float* fourFloats = reinterpret_cast<float*>(cPtr);
42*c8dee2aaSAndroid Build Coastguard Worker     SkColor4f color = {fourFloats[0], fourFloats[1], fourFloats[2], fourFloats[3]};
43*c8dee2aaSAndroid Build Coastguard Worker     return color;
44*c8dee2aaSAndroid Build Coastguard Worker }
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker struct SimpleFontStyle {
47*c8dee2aaSAndroid Build Coastguard Worker     SkFontStyle::Slant slant;
48*c8dee2aaSAndroid Build Coastguard Worker     SkFontStyle::Weight weight;
49*c8dee2aaSAndroid Build Coastguard Worker     SkFontStyle::Width width;
50*c8dee2aaSAndroid Build Coastguard Worker };
51*c8dee2aaSAndroid Build Coastguard Worker 
52*c8dee2aaSAndroid Build Coastguard Worker // TODO(jlavrova, kjlubick) This should probably be created explicitly by the client
53*c8dee2aaSAndroid Build Coastguard Worker // (either one based on ICU data or a client explicitly made) and passed in to build().
get_unicode()54*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkUnicode> get_unicode() {
55*c8dee2aaSAndroid Build Coastguard Worker     // For code size reasons, we prefer to use the unicode implementation first
56*c8dee2aaSAndroid Build Coastguard Worker     // over the full ICU version.
57*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_ICU_IMPLEMENTATION)
58*c8dee2aaSAndroid Build Coastguard Worker     return SkUnicodes::ICU::Make();
59*c8dee2aaSAndroid Build Coastguard Worker #else
60*c8dee2aaSAndroid Build Coastguard Worker     return nullptr;
61*c8dee2aaSAndroid Build Coastguard Worker #endif
62*c8dee2aaSAndroid Build Coastguard Worker }
63*c8dee2aaSAndroid Build Coastguard Worker 
64*c8dee2aaSAndroid Build Coastguard Worker struct SimpleTextStyle {
65*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerF32 colorPtr;
66*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerF32 foregroundColorPtr;
67*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerF32 backgroundColorPtr;
68*c8dee2aaSAndroid Build Coastguard Worker     uint8_t decoration;
69*c8dee2aaSAndroid Build Coastguard Worker     SkScalar decorationThickness;
70*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerF32 decorationColorPtr;
71*c8dee2aaSAndroid Build Coastguard Worker     para::TextDecorationStyle decorationStyle;
72*c8dee2aaSAndroid Build Coastguard Worker     para::TextBaseline textBaseline;
73*c8dee2aaSAndroid Build Coastguard Worker     SkScalar fontSize;
74*c8dee2aaSAndroid Build Coastguard Worker     SkScalar letterSpacing;
75*c8dee2aaSAndroid Build Coastguard Worker     SkScalar wordSpacing;
76*c8dee2aaSAndroid Build Coastguard Worker     SkScalar heightMultiplier;
77*c8dee2aaSAndroid Build Coastguard Worker     bool halfLeading;
78*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerU8 localePtr;
79*c8dee2aaSAndroid Build Coastguard Worker     int localeLen;
80*c8dee2aaSAndroid Build Coastguard Worker     SimpleFontStyle fontStyle;
81*c8dee2aaSAndroid Build Coastguard Worker 
82*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerU8 fontFamiliesPtr;
83*c8dee2aaSAndroid Build Coastguard Worker     int fontFamiliesLen;
84*c8dee2aaSAndroid Build Coastguard Worker 
85*c8dee2aaSAndroid Build Coastguard Worker     int shadowLen;
86*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerF32 shadowColorsPtr;
87*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerF32 shadowOffsetsPtr;
88*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerF32 shadowBlurRadiiPtr;
89*c8dee2aaSAndroid Build Coastguard Worker 
90*c8dee2aaSAndroid Build Coastguard Worker     int fontFeatureLen;
91*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerF32 fontFeatureNamesPtr;
92*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerF32 fontFeatureValuesPtr;
93*c8dee2aaSAndroid Build Coastguard Worker 
94*c8dee2aaSAndroid Build Coastguard Worker     int fontVariationLen;
95*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerF32 fontVariationAxesPtr;
96*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerF32 fontVariationValuesPtr;
97*c8dee2aaSAndroid Build Coastguard Worker };
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker struct SimpleStrutStyle {
100*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerU32 fontFamiliesPtr;
101*c8dee2aaSAndroid Build Coastguard Worker     int fontFamiliesLen;
102*c8dee2aaSAndroid Build Coastguard Worker     SimpleFontStyle fontStyle;
103*c8dee2aaSAndroid Build Coastguard Worker     SkScalar fontSize;
104*c8dee2aaSAndroid Build Coastguard Worker     SkScalar heightMultiplier;
105*c8dee2aaSAndroid Build Coastguard Worker     bool halfLeading;
106*c8dee2aaSAndroid Build Coastguard Worker     SkScalar leading;
107*c8dee2aaSAndroid Build Coastguard Worker     bool strutEnabled;
108*c8dee2aaSAndroid Build Coastguard Worker     bool forceStrutHeight;
109*c8dee2aaSAndroid Build Coastguard Worker };
110*c8dee2aaSAndroid Build Coastguard Worker 
toStrutStyle(const SimpleStrutStyle & s)111*c8dee2aaSAndroid Build Coastguard Worker para::StrutStyle toStrutStyle(const SimpleStrutStyle& s) {
112*c8dee2aaSAndroid Build Coastguard Worker     para::StrutStyle ss;
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker     const char** fontFamilies = reinterpret_cast<const char**>(s.fontFamiliesPtr);
115*c8dee2aaSAndroid Build Coastguard Worker     if (fontFamilies != nullptr) {
116*c8dee2aaSAndroid Build Coastguard Worker         std::vector<SkString> ff;
117*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < s.fontFamiliesLen; i++) {
118*c8dee2aaSAndroid Build Coastguard Worker             ff.emplace_back(fontFamilies[i]);
119*c8dee2aaSAndroid Build Coastguard Worker         }
120*c8dee2aaSAndroid Build Coastguard Worker         ss.setFontFamilies(ff);
121*c8dee2aaSAndroid Build Coastguard Worker     }
122*c8dee2aaSAndroid Build Coastguard Worker 
123*c8dee2aaSAndroid Build Coastguard Worker     SkFontStyle fs(s.fontStyle.weight, s.fontStyle.width, s.fontStyle.slant);
124*c8dee2aaSAndroid Build Coastguard Worker     ss.setFontStyle(fs);
125*c8dee2aaSAndroid Build Coastguard Worker 
126*c8dee2aaSAndroid Build Coastguard Worker     if (s.fontSize != -1) {
127*c8dee2aaSAndroid Build Coastguard Worker         ss.setFontSize(s.fontSize);
128*c8dee2aaSAndroid Build Coastguard Worker     }
129*c8dee2aaSAndroid Build Coastguard Worker     if (s.heightMultiplier != -1) {
130*c8dee2aaSAndroid Build Coastguard Worker         ss.setHeight(s.heightMultiplier);
131*c8dee2aaSAndroid Build Coastguard Worker         ss.setHeightOverride(true);
132*c8dee2aaSAndroid Build Coastguard Worker     }
133*c8dee2aaSAndroid Build Coastguard Worker     ss.setHalfLeading(s.halfLeading);
134*c8dee2aaSAndroid Build Coastguard Worker 
135*c8dee2aaSAndroid Build Coastguard Worker     if (s.leading != 0) {
136*c8dee2aaSAndroid Build Coastguard Worker         ss.setLeading(s.leading);
137*c8dee2aaSAndroid Build Coastguard Worker     }
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker     ss.setStrutEnabled(s.strutEnabled);
140*c8dee2aaSAndroid Build Coastguard Worker     ss.setForceStrutHeight(s.forceStrutHeight);
141*c8dee2aaSAndroid Build Coastguard Worker 
142*c8dee2aaSAndroid Build Coastguard Worker     return ss;
143*c8dee2aaSAndroid Build Coastguard Worker }
144*c8dee2aaSAndroid Build Coastguard Worker 
toTextStyle(const SimpleTextStyle & s)145*c8dee2aaSAndroid Build Coastguard Worker para::TextStyle toTextStyle(const SimpleTextStyle& s) {
146*c8dee2aaSAndroid Build Coastguard Worker     para::TextStyle ts;
147*c8dee2aaSAndroid Build Coastguard Worker 
148*c8dee2aaSAndroid Build Coastguard Worker     // textstyle.color doesn't support a 4f color, however the foreground and background fields
149*c8dee2aaSAndroid Build Coastguard Worker     // below do.
150*c8dee2aaSAndroid Build Coastguard Worker     ts.setColor(toSkColor4f(s.colorPtr).toSkColor());
151*c8dee2aaSAndroid Build Coastguard Worker 
152*c8dee2aaSAndroid Build Coastguard Worker     // It is functionally important that these paints be unset when no value was provided.
153*c8dee2aaSAndroid Build Coastguard Worker     if (s.foregroundColorPtr) {
154*c8dee2aaSAndroid Build Coastguard Worker         SkPaint p1;
155*c8dee2aaSAndroid Build Coastguard Worker         p1.setColor4f(toSkColor4f(s.foregroundColorPtr));
156*c8dee2aaSAndroid Build Coastguard Worker         ts.setForegroundColor(p1);
157*c8dee2aaSAndroid Build Coastguard Worker     }
158*c8dee2aaSAndroid Build Coastguard Worker 
159*c8dee2aaSAndroid Build Coastguard Worker     if (s.backgroundColorPtr) {
160*c8dee2aaSAndroid Build Coastguard Worker         SkPaint p2;
161*c8dee2aaSAndroid Build Coastguard Worker         p2.setColor4f(toSkColor4f(s.backgroundColorPtr));
162*c8dee2aaSAndroid Build Coastguard Worker         ts.setBackgroundColor(p2);
163*c8dee2aaSAndroid Build Coastguard Worker     }
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker     if (s.fontSize != -1) {
166*c8dee2aaSAndroid Build Coastguard Worker         ts.setFontSize(s.fontSize);
167*c8dee2aaSAndroid Build Coastguard Worker     }
168*c8dee2aaSAndroid Build Coastguard Worker     if (s.letterSpacing != 0) {
169*c8dee2aaSAndroid Build Coastguard Worker         ts.setLetterSpacing(s.letterSpacing);
170*c8dee2aaSAndroid Build Coastguard Worker     }
171*c8dee2aaSAndroid Build Coastguard Worker     if (s.wordSpacing != 0) {
172*c8dee2aaSAndroid Build Coastguard Worker         ts.setWordSpacing(s.wordSpacing);
173*c8dee2aaSAndroid Build Coastguard Worker     }
174*c8dee2aaSAndroid Build Coastguard Worker 
175*c8dee2aaSAndroid Build Coastguard Worker     if (s.heightMultiplier != -1) {
176*c8dee2aaSAndroid Build Coastguard Worker         ts.setHeight(s.heightMultiplier);
177*c8dee2aaSAndroid Build Coastguard Worker         ts.setHeightOverride(true);
178*c8dee2aaSAndroid Build Coastguard Worker     }
179*c8dee2aaSAndroid Build Coastguard Worker 
180*c8dee2aaSAndroid Build Coastguard Worker     ts.setHalfLeading(s.halfLeading);
181*c8dee2aaSAndroid Build Coastguard Worker 
182*c8dee2aaSAndroid Build Coastguard Worker     ts.setDecoration(para::TextDecoration(s.decoration));
183*c8dee2aaSAndroid Build Coastguard Worker     ts.setDecorationStyle(s.decorationStyle);
184*c8dee2aaSAndroid Build Coastguard Worker     if (s.decorationThickness != 0) {
185*c8dee2aaSAndroid Build Coastguard Worker         ts.setDecorationThicknessMultiplier(s.decorationThickness);
186*c8dee2aaSAndroid Build Coastguard Worker     }
187*c8dee2aaSAndroid Build Coastguard Worker     if (s.decorationColorPtr) {
188*c8dee2aaSAndroid Build Coastguard Worker         ts.setDecorationColor(toSkColor4f(s.decorationColorPtr).toSkColor());
189*c8dee2aaSAndroid Build Coastguard Worker     }
190*c8dee2aaSAndroid Build Coastguard Worker 
191*c8dee2aaSAndroid Build Coastguard Worker     if (s.localeLen > 0) {
192*c8dee2aaSAndroid Build Coastguard Worker         const char* localePtr = reinterpret_cast<const char*>(s.localePtr);
193*c8dee2aaSAndroid Build Coastguard Worker         SkString lStr(localePtr, s.localeLen);
194*c8dee2aaSAndroid Build Coastguard Worker         ts.setLocale(lStr);
195*c8dee2aaSAndroid Build Coastguard Worker     }
196*c8dee2aaSAndroid Build Coastguard Worker 
197*c8dee2aaSAndroid Build Coastguard Worker     const char** fontFamilies = reinterpret_cast<const char**>(s.fontFamiliesPtr);
198*c8dee2aaSAndroid Build Coastguard Worker     if (fontFamilies != nullptr) {
199*c8dee2aaSAndroid Build Coastguard Worker         std::vector<SkString> ff;
200*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < s.fontFamiliesLen; i++) {
201*c8dee2aaSAndroid Build Coastguard Worker             ff.emplace_back(fontFamilies[i]);
202*c8dee2aaSAndroid Build Coastguard Worker         }
203*c8dee2aaSAndroid Build Coastguard Worker         ts.setFontFamilies(ff);
204*c8dee2aaSAndroid Build Coastguard Worker     }
205*c8dee2aaSAndroid Build Coastguard Worker 
206*c8dee2aaSAndroid Build Coastguard Worker     ts.setTextBaseline(s.textBaseline);
207*c8dee2aaSAndroid Build Coastguard Worker 
208*c8dee2aaSAndroid Build Coastguard Worker     SkFontStyle fs(s.fontStyle.weight, s.fontStyle.width, s.fontStyle.slant);
209*c8dee2aaSAndroid Build Coastguard Worker     ts.setFontStyle(fs);
210*c8dee2aaSAndroid Build Coastguard Worker 
211*c8dee2aaSAndroid Build Coastguard Worker     if (s.shadowLen > 0) {
212*c8dee2aaSAndroid Build Coastguard Worker         const SkColor4f* colors = reinterpret_cast<const SkColor4f*>(s.shadowColorsPtr);
213*c8dee2aaSAndroid Build Coastguard Worker         const SkPoint* offsets = reinterpret_cast<const SkPoint*>(s.shadowOffsetsPtr);
214*c8dee2aaSAndroid Build Coastguard Worker         const float* blurRadii = reinterpret_cast<const float*>(s.shadowBlurRadiiPtr);
215*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < s.shadowLen; i++) {
216*c8dee2aaSAndroid Build Coastguard Worker             para::TextShadow shadow(colors[i].toSkColor(), offsets[i], blurRadii[i]);
217*c8dee2aaSAndroid Build Coastguard Worker             ts.addShadow(shadow);
218*c8dee2aaSAndroid Build Coastguard Worker         }
219*c8dee2aaSAndroid Build Coastguard Worker     }
220*c8dee2aaSAndroid Build Coastguard Worker 
221*c8dee2aaSAndroid Build Coastguard Worker 
222*c8dee2aaSAndroid Build Coastguard Worker     if (s.fontFeatureLen > 0) {
223*c8dee2aaSAndroid Build Coastguard Worker         const char** fontFeatureNames = reinterpret_cast<const char**>(s.fontFeatureNamesPtr);
224*c8dee2aaSAndroid Build Coastguard Worker         const int* fontFeatureValues = reinterpret_cast<const int*>(s.fontFeatureValuesPtr);
225*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < s.fontFeatureLen; i++) {
226*c8dee2aaSAndroid Build Coastguard Worker             // Font features names are 4-character simple strings.
227*c8dee2aaSAndroid Build Coastguard Worker             SkString name(fontFeatureNames[i], 4);
228*c8dee2aaSAndroid Build Coastguard Worker             ts.addFontFeature(name, fontFeatureValues[i]);
229*c8dee2aaSAndroid Build Coastguard Worker         }
230*c8dee2aaSAndroid Build Coastguard Worker     }
231*c8dee2aaSAndroid Build Coastguard Worker 
232*c8dee2aaSAndroid Build Coastguard Worker     if (s.fontVariationLen > 0) {
233*c8dee2aaSAndroid Build Coastguard Worker         const char** fontVariationAxes = reinterpret_cast<const char**>(s.fontVariationAxesPtr);
234*c8dee2aaSAndroid Build Coastguard Worker         const float* fontVariationValues = reinterpret_cast<const float*>(s.fontVariationValuesPtr);
235*c8dee2aaSAndroid Build Coastguard Worker         std::vector<SkFontArguments::VariationPosition::Coordinate> coordinates;
236*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < s.fontVariationLen; i++) {
237*c8dee2aaSAndroid Build Coastguard Worker             // Font variation axis tags are 4-character simple strings.
238*c8dee2aaSAndroid Build Coastguard Worker             SkString axis(fontVariationAxes[i]);
239*c8dee2aaSAndroid Build Coastguard Worker             if (axis.size() != 4) {
240*c8dee2aaSAndroid Build Coastguard Worker                 continue;
241*c8dee2aaSAndroid Build Coastguard Worker             }
242*c8dee2aaSAndroid Build Coastguard Worker             coordinates.push_back({
243*c8dee2aaSAndroid Build Coastguard Worker                 SkSetFourByteTag(axis[0], axis[1], axis[2], axis[3]),
244*c8dee2aaSAndroid Build Coastguard Worker                 fontVariationValues[i]
245*c8dee2aaSAndroid Build Coastguard Worker             });
246*c8dee2aaSAndroid Build Coastguard Worker         }
247*c8dee2aaSAndroid Build Coastguard Worker         SkFontArguments::VariationPosition position = {
248*c8dee2aaSAndroid Build Coastguard Worker             coordinates.data(),
249*c8dee2aaSAndroid Build Coastguard Worker             static_cast<int>(coordinates.size())
250*c8dee2aaSAndroid Build Coastguard Worker         };
251*c8dee2aaSAndroid Build Coastguard Worker         ts.setFontArguments(SkFontArguments().setVariationDesignPosition(position));
252*c8dee2aaSAndroid Build Coastguard Worker     }
253*c8dee2aaSAndroid Build Coastguard Worker 
254*c8dee2aaSAndroid Build Coastguard Worker     return ts;
255*c8dee2aaSAndroid Build Coastguard Worker }
256*c8dee2aaSAndroid Build Coastguard Worker 
257*c8dee2aaSAndroid Build Coastguard Worker struct SimpleParagraphStyle {
258*c8dee2aaSAndroid Build Coastguard Worker     bool disableHinting;
259*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerU8 ellipsisPtr;
260*c8dee2aaSAndroid Build Coastguard Worker     size_t ellipsisLen;
261*c8dee2aaSAndroid Build Coastguard Worker     SkScalar heightMultiplier;
262*c8dee2aaSAndroid Build Coastguard Worker     size_t maxLines;
263*c8dee2aaSAndroid Build Coastguard Worker     bool replaceTabCharacters;
264*c8dee2aaSAndroid Build Coastguard Worker     para::TextAlign textAlign;
265*c8dee2aaSAndroid Build Coastguard Worker     para::TextDirection textDirection;
266*c8dee2aaSAndroid Build Coastguard Worker     para::TextHeightBehavior textHeightBehavior;
267*c8dee2aaSAndroid Build Coastguard Worker     SimpleTextStyle textStyle;
268*c8dee2aaSAndroid Build Coastguard Worker     SimpleStrutStyle strutStyle;
269*c8dee2aaSAndroid Build Coastguard Worker     bool applyRoundingHack;
270*c8dee2aaSAndroid Build Coastguard Worker };
271*c8dee2aaSAndroid Build Coastguard Worker 
toParagraphStyle(const SimpleParagraphStyle & s)272*c8dee2aaSAndroid Build Coastguard Worker para::ParagraphStyle toParagraphStyle(const SimpleParagraphStyle& s) {
273*c8dee2aaSAndroid Build Coastguard Worker     para::ParagraphStyle ps;
274*c8dee2aaSAndroid Build Coastguard Worker     if (s.disableHinting) {
275*c8dee2aaSAndroid Build Coastguard Worker         ps.turnHintingOff();
276*c8dee2aaSAndroid Build Coastguard Worker     }
277*c8dee2aaSAndroid Build Coastguard Worker 
278*c8dee2aaSAndroid Build Coastguard Worker     if (s.ellipsisLen > 0) {
279*c8dee2aaSAndroid Build Coastguard Worker         const char* ellipsisPtr = reinterpret_cast<const char*>(s.ellipsisPtr);
280*c8dee2aaSAndroid Build Coastguard Worker         SkString eStr(ellipsisPtr, s.ellipsisLen);
281*c8dee2aaSAndroid Build Coastguard Worker         ps.setEllipsis(eStr);
282*c8dee2aaSAndroid Build Coastguard Worker     }
283*c8dee2aaSAndroid Build Coastguard Worker     ps.setTextAlign(s.textAlign);
284*c8dee2aaSAndroid Build Coastguard Worker     ps.setTextDirection(s.textDirection);
285*c8dee2aaSAndroid Build Coastguard Worker     auto ts = toTextStyle(s.textStyle);
286*c8dee2aaSAndroid Build Coastguard Worker     ps.setTextStyle(ts);
287*c8dee2aaSAndroid Build Coastguard Worker     auto ss = toStrutStyle(s.strutStyle);
288*c8dee2aaSAndroid Build Coastguard Worker     ps.setStrutStyle(ss);
289*c8dee2aaSAndroid Build Coastguard Worker     if (s.heightMultiplier != -1) {
290*c8dee2aaSAndroid Build Coastguard Worker         ps.setHeight(s.heightMultiplier);
291*c8dee2aaSAndroid Build Coastguard Worker     }
292*c8dee2aaSAndroid Build Coastguard Worker     if (s.maxLines != 0) {
293*c8dee2aaSAndroid Build Coastguard Worker         ps.setMaxLines(s.maxLines);
294*c8dee2aaSAndroid Build Coastguard Worker     }
295*c8dee2aaSAndroid Build Coastguard Worker     ps.setApplyRoundingHack(s.applyRoundingHack);
296*c8dee2aaSAndroid Build Coastguard Worker     ps.setTextHeightBehavior(s.textHeightBehavior);
297*c8dee2aaSAndroid Build Coastguard Worker     ps.setReplaceTabCharacters(s.replaceTabCharacters);
298*c8dee2aaSAndroid Build Coastguard Worker     return ps;
299*c8dee2aaSAndroid Build Coastguard Worker }
300*c8dee2aaSAndroid Build Coastguard Worker 
301*c8dee2aaSAndroid Build Coastguard Worker struct SimpleTextBox {
302*c8dee2aaSAndroid Build Coastguard Worker     SkRect rect;
303*c8dee2aaSAndroid Build Coastguard Worker     // This isn't the most efficient way to represent this, but it is much easier to keep
304*c8dee2aaSAndroid Build Coastguard Worker     // everything as floats when unpacking on the JS side.
305*c8dee2aaSAndroid Build Coastguard Worker     // 0.0 = RTL, 1.0 = LTr
306*c8dee2aaSAndroid Build Coastguard Worker     SkScalar direction;
307*c8dee2aaSAndroid Build Coastguard Worker };
308*c8dee2aaSAndroid Build Coastguard Worker 
TextBoxesToFloat32Array(std::vector<para::TextBox> boxes)309*c8dee2aaSAndroid Build Coastguard Worker Float32Array TextBoxesToFloat32Array(std::vector<para::TextBox> boxes) {
310*c8dee2aaSAndroid Build Coastguard Worker     // Pack these text boxes into an array of n groups of 5 SkScalar (floats)
311*c8dee2aaSAndroid Build Coastguard Worker     if (!boxes.size()) {
312*c8dee2aaSAndroid Build Coastguard Worker         return emscripten::val::null();
313*c8dee2aaSAndroid Build Coastguard Worker     }
314*c8dee2aaSAndroid Build Coastguard Worker     SimpleTextBox* rects = new SimpleTextBox[boxes.size()];
315*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < boxes.size(); i++) {
316*c8dee2aaSAndroid Build Coastguard Worker         rects[i].rect = boxes[i].rect;
317*c8dee2aaSAndroid Build Coastguard Worker         if (boxes[i].direction == para::TextDirection::kRtl) {
318*c8dee2aaSAndroid Build Coastguard Worker             rects[i].direction = 0;
319*c8dee2aaSAndroid Build Coastguard Worker         } else {
320*c8dee2aaSAndroid Build Coastguard Worker             rects[i].direction = 1;
321*c8dee2aaSAndroid Build Coastguard Worker         }
322*c8dee2aaSAndroid Build Coastguard Worker     }
323*c8dee2aaSAndroid Build Coastguard Worker     float* fPtr = reinterpret_cast<float*>(rects);
324*c8dee2aaSAndroid Build Coastguard Worker     // Of note: now that we have cast rects to float*, emscripten is smart enough to wrap this
325*c8dee2aaSAndroid Build Coastguard Worker     // into a Float32Array for us.
326*c8dee2aaSAndroid Build Coastguard Worker     return Float32Array(typed_memory_view(boxes.size() * 5, fPtr));
327*c8dee2aaSAndroid Build Coastguard Worker }
328*c8dee2aaSAndroid Build Coastguard Worker 
GetRectsForRange(para::Paragraph & self,unsigned start,unsigned end,para::RectHeightStyle heightStyle,para::RectWidthStyle widthStyle)329*c8dee2aaSAndroid Build Coastguard Worker Float32Array GetRectsForRange(para::Paragraph& self,
330*c8dee2aaSAndroid Build Coastguard Worker                               unsigned start,
331*c8dee2aaSAndroid Build Coastguard Worker                               unsigned end,
332*c8dee2aaSAndroid Build Coastguard Worker                               para::RectHeightStyle heightStyle,
333*c8dee2aaSAndroid Build Coastguard Worker                               para::RectWidthStyle widthStyle) {
334*c8dee2aaSAndroid Build Coastguard Worker     std::vector<para::TextBox> boxes = self.getRectsForRange(start, end, heightStyle, widthStyle);
335*c8dee2aaSAndroid Build Coastguard Worker     return TextBoxesToFloat32Array(boxes);
336*c8dee2aaSAndroid Build Coastguard Worker }
337*c8dee2aaSAndroid Build Coastguard Worker 
GetRectsForPlaceholders(para::Paragraph & self)338*c8dee2aaSAndroid Build Coastguard Worker Float32Array GetRectsForPlaceholders(para::Paragraph& self) {
339*c8dee2aaSAndroid Build Coastguard Worker     std::vector<para::TextBox> boxes = self.getRectsForPlaceholders();
340*c8dee2aaSAndroid Build Coastguard Worker     return TextBoxesToFloat32Array(boxes);
341*c8dee2aaSAndroid Build Coastguard Worker }
342*c8dee2aaSAndroid Build Coastguard Worker 
JSObjectFromLineMetrics(skia::textlayout::LineMetrics & metrics)343*c8dee2aaSAndroid Build Coastguard Worker JSObject JSObjectFromLineMetrics(skia::textlayout::LineMetrics& metrics) {
344*c8dee2aaSAndroid Build Coastguard Worker     JSObject m = emscripten::val::object();
345*c8dee2aaSAndroid Build Coastguard Worker     m.set("startIndex", metrics.fStartIndex);
346*c8dee2aaSAndroid Build Coastguard Worker     m.set("endIndex", metrics.fEndIndex);
347*c8dee2aaSAndroid Build Coastguard Worker     m.set("endExcludingWhitespaces", metrics.fEndExcludingWhitespaces);
348*c8dee2aaSAndroid Build Coastguard Worker     m.set("endIncludingNewline", metrics.fEndIncludingNewline);
349*c8dee2aaSAndroid Build Coastguard Worker     m.set("isHardBreak", metrics.fHardBreak);
350*c8dee2aaSAndroid Build Coastguard Worker     m.set("ascent", metrics.fAscent);
351*c8dee2aaSAndroid Build Coastguard Worker     m.set("descent", metrics.fDescent);
352*c8dee2aaSAndroid Build Coastguard Worker     m.set("height", metrics.fHeight);
353*c8dee2aaSAndroid Build Coastguard Worker     m.set("width", metrics.fWidth);
354*c8dee2aaSAndroid Build Coastguard Worker     m.set("left", metrics.fLeft);
355*c8dee2aaSAndroid Build Coastguard Worker     m.set("baseline", metrics.fBaseline);
356*c8dee2aaSAndroid Build Coastguard Worker     m.set("lineNumber", metrics.fLineNumber);
357*c8dee2aaSAndroid Build Coastguard Worker     return m;
358*c8dee2aaSAndroid Build Coastguard Worker }
359*c8dee2aaSAndroid Build Coastguard Worker 
JSObjectFromGlyphInfo(skia::textlayout::Paragraph::GlyphInfo & glyphInfo)360*c8dee2aaSAndroid Build Coastguard Worker JSObject JSObjectFromGlyphInfo(skia::textlayout::Paragraph::GlyphInfo& glyphInfo) {
361*c8dee2aaSAndroid Build Coastguard Worker     JSObject object = emscripten::val::object();
362*c8dee2aaSAndroid Build Coastguard Worker 
363*c8dee2aaSAndroid Build Coastguard Worker     JSObject range = emscripten::val::object();
364*c8dee2aaSAndroid Build Coastguard Worker     range.set("start", glyphInfo.fGraphemeClusterTextRange.start);
365*c8dee2aaSAndroid Build Coastguard Worker     range.set("end",  glyphInfo.fGraphemeClusterTextRange.end);
366*c8dee2aaSAndroid Build Coastguard Worker     object.set("graphemeClusterTextRange", range);
367*c8dee2aaSAndroid Build Coastguard Worker 
368*c8dee2aaSAndroid Build Coastguard Worker     JSArray rect = emscripten::val::array();
369*c8dee2aaSAndroid Build Coastguard Worker     rect.call<void>("push", glyphInfo.fGraphemeLayoutBounds.left());
370*c8dee2aaSAndroid Build Coastguard Worker     rect.call<void>("push", glyphInfo.fGraphemeLayoutBounds.top());
371*c8dee2aaSAndroid Build Coastguard Worker     rect.call<void>("push", glyphInfo.fGraphemeLayoutBounds.right());
372*c8dee2aaSAndroid Build Coastguard Worker     rect.call<void>("push", glyphInfo.fGraphemeLayoutBounds.bottom());
373*c8dee2aaSAndroid Build Coastguard Worker     object.set("graphemeLayoutBounds", rect);
374*c8dee2aaSAndroid Build Coastguard Worker 
375*c8dee2aaSAndroid Build Coastguard Worker     object.set("dir", glyphInfo.fDirection == skia::textlayout::TextDirection::kRtl ? 0 : 1);
376*c8dee2aaSAndroid Build Coastguard Worker     object.set("isEllipsis", glyphInfo.fIsEllipsis);
377*c8dee2aaSAndroid Build Coastguard Worker     return object;
378*c8dee2aaSAndroid Build Coastguard Worker }
379*c8dee2aaSAndroid Build Coastguard Worker 
GetLineMetrics(para::Paragraph & self)380*c8dee2aaSAndroid Build Coastguard Worker JSArray GetLineMetrics(para::Paragraph& self) {
381*c8dee2aaSAndroid Build Coastguard Worker     std::vector<skia::textlayout::LineMetrics> metrics;
382*c8dee2aaSAndroid Build Coastguard Worker     self.getLineMetrics(metrics);
383*c8dee2aaSAndroid Build Coastguard Worker     JSArray result = emscripten::val::array();
384*c8dee2aaSAndroid Build Coastguard Worker     for (auto metric : metrics) {
385*c8dee2aaSAndroid Build Coastguard Worker         result.call<void>("push", JSObjectFromLineMetrics(metric));
386*c8dee2aaSAndroid Build Coastguard Worker     }
387*c8dee2aaSAndroid Build Coastguard Worker     return result;
388*c8dee2aaSAndroid Build Coastguard Worker }
389*c8dee2aaSAndroid Build Coastguard Worker 
GetLineMetricsAt(para::Paragraph & self,size_t lineNumber)390*c8dee2aaSAndroid Build Coastguard Worker JSObject GetLineMetricsAt(para::Paragraph& self, size_t lineNumber) {
391*c8dee2aaSAndroid Build Coastguard Worker     skia::textlayout::LineMetrics metrics;
392*c8dee2aaSAndroid Build Coastguard Worker     return self.getLineMetricsAt(lineNumber, &metrics)
393*c8dee2aaSAndroid Build Coastguard Worker         ? JSObjectFromLineMetrics(metrics)
394*c8dee2aaSAndroid Build Coastguard Worker         : emscripten::val::null();
395*c8dee2aaSAndroid Build Coastguard Worker }
396*c8dee2aaSAndroid Build Coastguard Worker 
GetGlyphInfoAt(para::Paragraph & self,size_t index)397*c8dee2aaSAndroid Build Coastguard Worker JSObject GetGlyphInfoAt(para::Paragraph& self, size_t index) {
398*c8dee2aaSAndroid Build Coastguard Worker     skia::textlayout::Paragraph::GlyphInfo glyphInfo;
399*c8dee2aaSAndroid Build Coastguard Worker     return self.getGlyphInfoAtUTF16Offset(index, &glyphInfo)
400*c8dee2aaSAndroid Build Coastguard Worker         ? JSObjectFromGlyphInfo(glyphInfo)
401*c8dee2aaSAndroid Build Coastguard Worker         : emscripten::val::null();
402*c8dee2aaSAndroid Build Coastguard Worker }
403*c8dee2aaSAndroid Build Coastguard Worker 
GetClosestGlyphInfoAtCoordinate(para::Paragraph & self,SkScalar dx,SkScalar dy)404*c8dee2aaSAndroid Build Coastguard Worker JSObject GetClosestGlyphInfoAtCoordinate(para::Paragraph& self, SkScalar dx, SkScalar dy) {
405*c8dee2aaSAndroid Build Coastguard Worker     skia::textlayout::Paragraph::GlyphInfo glyphInfo;
406*c8dee2aaSAndroid Build Coastguard Worker     return self.getClosestUTF16GlyphInfoAt(dx, dy, &glyphInfo)
407*c8dee2aaSAndroid Build Coastguard Worker         ? JSObjectFromGlyphInfo(glyphInfo)
408*c8dee2aaSAndroid Build Coastguard Worker         : emscripten::val::null();
409*c8dee2aaSAndroid Build Coastguard Worker }
410*c8dee2aaSAndroid Build Coastguard Worker 
411*c8dee2aaSAndroid Build Coastguard Worker /*
412*c8dee2aaSAndroid Build Coastguard Worker  *  Returns Lines[]
413*c8dee2aaSAndroid Build Coastguard Worker  */
GetShapedLines(para::Paragraph & self)414*c8dee2aaSAndroid Build Coastguard Worker JSArray GetShapedLines(para::Paragraph& self) {
415*c8dee2aaSAndroid Build Coastguard Worker     struct LineAccumulate {
416*c8dee2aaSAndroid Build Coastguard Worker         int         lineNumber  = -1;   // deliberately -1 from starting value
417*c8dee2aaSAndroid Build Coastguard Worker         uint32_t    minOffset   = 0xFFFFFFFF;
418*c8dee2aaSAndroid Build Coastguard Worker         uint32_t    maxOffset   = 0;
419*c8dee2aaSAndroid Build Coastguard Worker         float       minAscent   = 0;
420*c8dee2aaSAndroid Build Coastguard Worker         float       maxDescent  = 0;
421*c8dee2aaSAndroid Build Coastguard Worker         // not really accumulated, but definitely set
422*c8dee2aaSAndroid Build Coastguard Worker         float       baseline    = 0;
423*c8dee2aaSAndroid Build Coastguard Worker 
424*c8dee2aaSAndroid Build Coastguard Worker         void reset(int newLineNum) {
425*c8dee2aaSAndroid Build Coastguard Worker             new (this) LineAccumulate;
426*c8dee2aaSAndroid Build Coastguard Worker             this->lineNumber = newLineNum;
427*c8dee2aaSAndroid Build Coastguard Worker         }
428*c8dee2aaSAndroid Build Coastguard Worker     };
429*c8dee2aaSAndroid Build Coastguard Worker 
430*c8dee2aaSAndroid Build Coastguard Worker     // where we accumulate our js output
431*c8dee2aaSAndroid Build Coastguard Worker     JSArray  jlines = emscripten::val::array();
432*c8dee2aaSAndroid Build Coastguard Worker     JSObject jline = emscripten::val::null();
433*c8dee2aaSAndroid Build Coastguard Worker     JSArray  jruns = emscripten::val::null();
434*c8dee2aaSAndroid Build Coastguard Worker     LineAccumulate accum;
435*c8dee2aaSAndroid Build Coastguard Worker 
436*c8dee2aaSAndroid Build Coastguard Worker     self.visit([&](int lineNumber, const para::Paragraph::VisitorInfo* info) {
437*c8dee2aaSAndroid Build Coastguard Worker         if (!info) {
438*c8dee2aaSAndroid Build Coastguard Worker             if (!jline) return; // how???
439*c8dee2aaSAndroid Build Coastguard Worker             // end of current line
440*c8dee2aaSAndroid Build Coastguard Worker             JSObject range = emscripten::val::object();
441*c8dee2aaSAndroid Build Coastguard Worker             range.set("first", accum.minOffset);
442*c8dee2aaSAndroid Build Coastguard Worker             range.set("last",  accum.maxOffset);
443*c8dee2aaSAndroid Build Coastguard Worker             jline.set("textRange", range);
444*c8dee2aaSAndroid Build Coastguard Worker 
445*c8dee2aaSAndroid Build Coastguard Worker             jline.set("top", accum.baseline + accum.minAscent);
446*c8dee2aaSAndroid Build Coastguard Worker             jline.set("bottom", accum.baseline + accum.maxDescent);
447*c8dee2aaSAndroid Build Coastguard Worker             jline.set("baseline", accum.baseline);
448*c8dee2aaSAndroid Build Coastguard Worker             return;
449*c8dee2aaSAndroid Build Coastguard Worker         }
450*c8dee2aaSAndroid Build Coastguard Worker 
451*c8dee2aaSAndroid Build Coastguard Worker         if (lineNumber != accum.lineNumber) {
452*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(lineNumber == accum.lineNumber + 1);   // assume monotonic
453*c8dee2aaSAndroid Build Coastguard Worker 
454*c8dee2aaSAndroid Build Coastguard Worker             accum.reset(lineNumber);
455*c8dee2aaSAndroid Build Coastguard Worker             jruns = emscripten::val::array();
456*c8dee2aaSAndroid Build Coastguard Worker 
457*c8dee2aaSAndroid Build Coastguard Worker             jline = emscripten::val::object();
458*c8dee2aaSAndroid Build Coastguard Worker             jline.set("runs", jruns);
459*c8dee2aaSAndroid Build Coastguard Worker             // will assign textRange and metrics on end-of-line signal
460*c8dee2aaSAndroid Build Coastguard Worker 
461*c8dee2aaSAndroid Build Coastguard Worker             jlines.call<void>("push", jline);
462*c8dee2aaSAndroid Build Coastguard Worker         }
463*c8dee2aaSAndroid Build Coastguard Worker 
464*c8dee2aaSAndroid Build Coastguard Worker         // append the run
465*c8dee2aaSAndroid Build Coastguard Worker         const int N = info->count;   // glyphs
466*c8dee2aaSAndroid Build Coastguard Worker         const int N1 = N + 1;       // positions, offsets have 1 extra (trailing) slot
467*c8dee2aaSAndroid Build Coastguard Worker 
468*c8dee2aaSAndroid Build Coastguard Worker         JSObject jrun = emscripten::val::object();
469*c8dee2aaSAndroid Build Coastguard Worker 
470*c8dee2aaSAndroid Build Coastguard Worker         jrun.set("flags",    info->flags);
471*c8dee2aaSAndroid Build Coastguard Worker 
472*c8dee2aaSAndroid Build Coastguard Worker // TODO: figure out how to set a wrapped sk_sp<SkTypeface>
473*c8dee2aaSAndroid Build Coastguard Worker //        jrun.set("typeface", info->font.getTypeface());
474*c8dee2aaSAndroid Build Coastguard Worker         jrun.set("typeface",    emscripten::val::null());
475*c8dee2aaSAndroid Build Coastguard Worker         jrun.set("size",        info->font.getSize());
476*c8dee2aaSAndroid Build Coastguard Worker         if (info->font.getScaleX()) {
477*c8dee2aaSAndroid Build Coastguard Worker             jrun.set("scaleX",  info->font.getScaleX());
478*c8dee2aaSAndroid Build Coastguard Worker         }
479*c8dee2aaSAndroid Build Coastguard Worker 
480*c8dee2aaSAndroid Build Coastguard Worker         jrun.set("glyphs",   MakeTypedArray(N,  info->glyphs));
481*c8dee2aaSAndroid Build Coastguard Worker         jrun.set("offsets",  MakeTypedArray(N1, info->utf8Starts));
482*c8dee2aaSAndroid Build Coastguard Worker 
483*c8dee2aaSAndroid Build Coastguard Worker         // we need to modify the positions, so make a temp copy
484*c8dee2aaSAndroid Build Coastguard Worker         AutoSTMalloc<32, SkPoint> positions(N1);
485*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < N; ++i) {
486*c8dee2aaSAndroid Build Coastguard Worker             positions.get()[i] = info->positions[i] + info->origin;
487*c8dee2aaSAndroid Build Coastguard Worker         }
488*c8dee2aaSAndroid Build Coastguard Worker         positions.get()[N] = { info->advanceX, positions.get()[N - 1].fY };
489*c8dee2aaSAndroid Build Coastguard Worker         jrun.set("positions", MakeTypedArray(N1*2, (const float*)positions.get()));
490*c8dee2aaSAndroid Build Coastguard Worker 
491*c8dee2aaSAndroid Build Coastguard Worker         jruns.call<void>("push", jrun);
492*c8dee2aaSAndroid Build Coastguard Worker 
493*c8dee2aaSAndroid Build Coastguard Worker         // update accum
494*c8dee2aaSAndroid Build Coastguard Worker         {   SkFontMetrics fm;
495*c8dee2aaSAndroid Build Coastguard Worker             info->font.getMetrics(&fm);
496*c8dee2aaSAndroid Build Coastguard Worker 
497*c8dee2aaSAndroid Build Coastguard Worker             accum.minAscent  = std::min(accum.minAscent,  fm.fAscent);
498*c8dee2aaSAndroid Build Coastguard Worker             accum.maxDescent = std::max(accum.maxDescent, fm.fDescent);
499*c8dee2aaSAndroid Build Coastguard Worker             accum.baseline   = info->origin.fY;
500*c8dee2aaSAndroid Build Coastguard Worker 
501*c8dee2aaSAndroid Build Coastguard Worker             accum.minOffset  = std::min(accum.minOffset,  info->utf8Starts[0]);
502*c8dee2aaSAndroid Build Coastguard Worker             accum.maxOffset  = std::max(accum.maxOffset,  info->utf8Starts[N]);
503*c8dee2aaSAndroid Build Coastguard Worker         }
504*c8dee2aaSAndroid Build Coastguard Worker 
505*c8dee2aaSAndroid Build Coastguard Worker     });
506*c8dee2aaSAndroid Build Coastguard Worker     return jlines;
507*c8dee2aaSAndroid Build Coastguard Worker }
508*c8dee2aaSAndroid Build Coastguard Worker 
convertArrayU32(WASMPointerU32 array,size_t count)509*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkUnicode::Position> convertArrayU32(WASMPointerU32 array, size_t count) {
510*c8dee2aaSAndroid Build Coastguard Worker     std::vector<size_t> vec;
511*c8dee2aaSAndroid Build Coastguard Worker     vec.resize(count);
512*c8dee2aaSAndroid Build Coastguard Worker     SkUnicode::Position* data = reinterpret_cast<SkUnicode::Position*>(array);
513*c8dee2aaSAndroid Build Coastguard Worker     std::memcpy(vec.data(), data, count * sizeof(size_t));
514*c8dee2aaSAndroid Build Coastguard Worker     return vec;
515*c8dee2aaSAndroid Build Coastguard Worker }
516*c8dee2aaSAndroid Build Coastguard Worker 
UnresolvedCodepoints(para::Paragraph & self)517*c8dee2aaSAndroid Build Coastguard Worker JSArray UnresolvedCodepoints(para::Paragraph& self) {
518*c8dee2aaSAndroid Build Coastguard Worker     JSArray result = emscripten::val::array();
519*c8dee2aaSAndroid Build Coastguard Worker     for (auto cp : self.unresolvedCodepoints()) {
520*c8dee2aaSAndroid Build Coastguard Worker         result.call<void>("push", cp);
521*c8dee2aaSAndroid Build Coastguard Worker     }
522*c8dee2aaSAndroid Build Coastguard Worker     return result;
523*c8dee2aaSAndroid Build Coastguard Worker }
524*c8dee2aaSAndroid Build Coastguard Worker 
EMSCRIPTEN_BINDINGS(Paragraph)525*c8dee2aaSAndroid Build Coastguard Worker EMSCRIPTEN_BINDINGS(Paragraph) {
526*c8dee2aaSAndroid Build Coastguard Worker 
527*c8dee2aaSAndroid Build Coastguard Worker     class_<para::Paragraph>("Paragraph")
528*c8dee2aaSAndroid Build Coastguard Worker         .function("didExceedMaxLines", &para::Paragraph::didExceedMaxLines)
529*c8dee2aaSAndroid Build Coastguard Worker         .function("getAlphabeticBaseline", &para::Paragraph::getAlphabeticBaseline)
530*c8dee2aaSAndroid Build Coastguard Worker         .function("getGlyphPositionAtCoordinate", &para::Paragraph::getGlyphPositionAtCoordinate)
531*c8dee2aaSAndroid Build Coastguard Worker         .function("getHeight", &para::Paragraph::getHeight)
532*c8dee2aaSAndroid Build Coastguard Worker         .function("getIdeographicBaseline", &para::Paragraph::getIdeographicBaseline)
533*c8dee2aaSAndroid Build Coastguard Worker         .function("getLineMetrics", &GetLineMetrics)
534*c8dee2aaSAndroid Build Coastguard Worker         .function("getLineMetricsAt", &GetLineMetricsAt)
535*c8dee2aaSAndroid Build Coastguard Worker         .function("getLineNumberAt", &para::Paragraph::getLineNumberAt)
536*c8dee2aaSAndroid Build Coastguard Worker         .function("getLongestLine", &para::Paragraph::getLongestLine)
537*c8dee2aaSAndroid Build Coastguard Worker         .function("getMaxIntrinsicWidth", &para::Paragraph::getMaxIntrinsicWidth)
538*c8dee2aaSAndroid Build Coastguard Worker         .function("getMaxWidth", &para::Paragraph::getMaxWidth)
539*c8dee2aaSAndroid Build Coastguard Worker         .function("getMinIntrinsicWidth", &para::Paragraph::getMinIntrinsicWidth)
540*c8dee2aaSAndroid Build Coastguard Worker         .function("getNumberOfLines", &para::Paragraph::lineNumber)
541*c8dee2aaSAndroid Build Coastguard Worker         .function("_getClosestGlyphInfoAtCoordinate", &GetClosestGlyphInfoAtCoordinate)
542*c8dee2aaSAndroid Build Coastguard Worker         .function("_getGlyphInfoAt", &GetGlyphInfoAt)
543*c8dee2aaSAndroid Build Coastguard Worker         .function("_getRectsForPlaceholders", &GetRectsForPlaceholders)
544*c8dee2aaSAndroid Build Coastguard Worker         .function("_getRectsForRange", &GetRectsForRange)
545*c8dee2aaSAndroid Build Coastguard Worker         .function("getShapedLines", &GetShapedLines)
546*c8dee2aaSAndroid Build Coastguard Worker         .function("getWordBoundary", &para::Paragraph::getWordBoundary)
547*c8dee2aaSAndroid Build Coastguard Worker         .function("layout", &para::Paragraph::layout)
548*c8dee2aaSAndroid Build Coastguard Worker         .function("unresolvedCodepoints", &UnresolvedCodepoints);
549*c8dee2aaSAndroid Build Coastguard Worker 
550*c8dee2aaSAndroid Build Coastguard Worker     class_<para::ParagraphBuilderImpl>("ParagraphBuilder")
551*c8dee2aaSAndroid Build Coastguard Worker             .class_function(
552*c8dee2aaSAndroid Build Coastguard Worker                     "_Make",
553*c8dee2aaSAndroid Build Coastguard Worker                     optional_override([](SimpleParagraphStyle style, sk_sp<SkFontMgr> fontMgr)
554*c8dee2aaSAndroid Build Coastguard Worker                                               -> std::unique_ptr<para::ParagraphBuilderImpl> {
555*c8dee2aaSAndroid Build Coastguard Worker                         auto fc = sk_make_sp<para::FontCollection>();
556*c8dee2aaSAndroid Build Coastguard Worker                         fc->setDefaultFontManager(fontMgr);
557*c8dee2aaSAndroid Build Coastguard Worker                         fc->enableFontFallback();
558*c8dee2aaSAndroid Build Coastguard Worker                         auto ps = toParagraphStyle(style);
559*c8dee2aaSAndroid Build Coastguard Worker                         auto pb = para::ParagraphBuilderImpl::make(ps, fc, get_unicode());
560*c8dee2aaSAndroid Build Coastguard Worker                         return std::unique_ptr<para::ParagraphBuilderImpl>(
561*c8dee2aaSAndroid Build Coastguard Worker                                 static_cast<para::ParagraphBuilderImpl*>(pb.release()));
562*c8dee2aaSAndroid Build Coastguard Worker                     }),
563*c8dee2aaSAndroid Build Coastguard Worker                     allow_raw_pointers())
564*c8dee2aaSAndroid Build Coastguard Worker             .class_function(
565*c8dee2aaSAndroid Build Coastguard Worker                     "_MakeFromFontProvider",
566*c8dee2aaSAndroid Build Coastguard Worker                     optional_override([](SimpleParagraphStyle style,
567*c8dee2aaSAndroid Build Coastguard Worker                                          sk_sp<para::TypefaceFontProvider> fontProvider)
568*c8dee2aaSAndroid Build Coastguard Worker                                               -> std::unique_ptr<para::ParagraphBuilderImpl> {
569*c8dee2aaSAndroid Build Coastguard Worker                         auto fc = sk_make_sp<para::FontCollection>();
570*c8dee2aaSAndroid Build Coastguard Worker                         fc->setDefaultFontManager(fontProvider);
571*c8dee2aaSAndroid Build Coastguard Worker                         fc->enableFontFallback();
572*c8dee2aaSAndroid Build Coastguard Worker                         auto ps = toParagraphStyle(style);
573*c8dee2aaSAndroid Build Coastguard Worker                         auto pb = para::ParagraphBuilderImpl::make(ps, fc, get_unicode());
574*c8dee2aaSAndroid Build Coastguard Worker                         return std::unique_ptr<para::ParagraphBuilderImpl>(
575*c8dee2aaSAndroid Build Coastguard Worker                                 static_cast<para::ParagraphBuilderImpl*>(pb.release()));
576*c8dee2aaSAndroid Build Coastguard Worker                     }),
577*c8dee2aaSAndroid Build Coastguard Worker                     allow_raw_pointers())
578*c8dee2aaSAndroid Build Coastguard Worker             .class_function(
579*c8dee2aaSAndroid Build Coastguard Worker                     "_MakeFromFontCollection",
580*c8dee2aaSAndroid Build Coastguard Worker                     optional_override([](SimpleParagraphStyle style,
581*c8dee2aaSAndroid Build Coastguard Worker                                          sk_sp<para::FontCollection> fontCollection)
582*c8dee2aaSAndroid Build Coastguard Worker                                               -> std::unique_ptr<para::ParagraphBuilderImpl> {
583*c8dee2aaSAndroid Build Coastguard Worker                         auto ps = toParagraphStyle(style);
584*c8dee2aaSAndroid Build Coastguard Worker                         auto pb = para::ParagraphBuilderImpl::make(ps, fontCollection, get_unicode());
585*c8dee2aaSAndroid Build Coastguard Worker                         return std::unique_ptr<para::ParagraphBuilderImpl>(
586*c8dee2aaSAndroid Build Coastguard Worker                                 static_cast<para::ParagraphBuilderImpl*>(pb.release()));
587*c8dee2aaSAndroid Build Coastguard Worker                     }),
588*c8dee2aaSAndroid Build Coastguard Worker                     allow_raw_pointers())
589*c8dee2aaSAndroid Build Coastguard Worker             .class_function(
590*c8dee2aaSAndroid Build Coastguard Worker                     "_ShapeText",
591*c8dee2aaSAndroid Build Coastguard Worker                     optional_override([](JSString jtext, JSArray jruns, float width) -> JSArray {
592*c8dee2aaSAndroid Build Coastguard Worker                 std::string textStorage = jtext.as<std::string>();
593*c8dee2aaSAndroid Build Coastguard Worker                 const char* text = textStorage.data();
594*c8dee2aaSAndroid Build Coastguard Worker                 size_t      textCount = textStorage.size();
595*c8dee2aaSAndroid Build Coastguard Worker 
596*c8dee2aaSAndroid Build Coastguard Worker                 auto fc = sk_make_sp<para::FontCollection>();
597*c8dee2aaSAndroid Build Coastguard Worker                 fc->setDefaultFontManager(SkFontMgr::RefEmpty());
598*c8dee2aaSAndroid Build Coastguard Worker                 fc->enableFontFallback();
599*c8dee2aaSAndroid Build Coastguard Worker 
600*c8dee2aaSAndroid Build Coastguard Worker                 para::ParagraphStyle pstyle;
601*c8dee2aaSAndroid Build Coastguard Worker                 {
602*c8dee2aaSAndroid Build Coastguard Worker                     // For the most part this is ignored, since we set an explicit TextStyle
603*c8dee2aaSAndroid Build Coastguard Worker                     // for all of our text runs, but it is required by SkParagraph.
604*c8dee2aaSAndroid Build Coastguard Worker                     para::TextStyle style;
605*c8dee2aaSAndroid Build Coastguard Worker                     style.setFontFamilies({SkString("sans-serif")});
606*c8dee2aaSAndroid Build Coastguard Worker                     style.setFontSize(32);
607*c8dee2aaSAndroid Build Coastguard Worker                     pstyle.setTextStyle(style);
608*c8dee2aaSAndroid Build Coastguard Worker                 }
609*c8dee2aaSAndroid Build Coastguard Worker 
610*c8dee2aaSAndroid Build Coastguard Worker                 auto pb = para::ParagraphBuilder::make(pstyle, fc, get_unicode());
611*c8dee2aaSAndroid Build Coastguard Worker 
612*c8dee2aaSAndroid Build Coastguard Worker                 // tease apart the FontBlock runs
613*c8dee2aaSAndroid Build Coastguard Worker                 size_t runCount = jruns["length"].as<size_t>();
614*c8dee2aaSAndroid Build Coastguard Worker                 for (size_t i = 0; i < runCount; ++i) {
615*c8dee2aaSAndroid Build Coastguard Worker                     emscripten::val r = jruns[i];
616*c8dee2aaSAndroid Build Coastguard Worker 
617*c8dee2aaSAndroid Build Coastguard Worker                     para::TextStyle style;
618*c8dee2aaSAndroid Build Coastguard Worker                     style.setTypeface(r["typeface"].as< sk_sp<SkTypeface> >());
619*c8dee2aaSAndroid Build Coastguard Worker                     style.setFontSize(r["size"].as<float>());
620*c8dee2aaSAndroid Build Coastguard Worker 
621*c8dee2aaSAndroid Build Coastguard Worker                     const size_t subTextCount = r["length"].as<size_t>();
622*c8dee2aaSAndroid Build Coastguard Worker                     if (subTextCount > textCount) {
623*c8dee2aaSAndroid Build Coastguard Worker                         return emscripten::val("block runs exceed text length!");
624*c8dee2aaSAndroid Build Coastguard Worker                     }
625*c8dee2aaSAndroid Build Coastguard Worker 
626*c8dee2aaSAndroid Build Coastguard Worker                     pb->pushStyle(style);
627*c8dee2aaSAndroid Build Coastguard Worker                     pb->addText(text, subTextCount);
628*c8dee2aaSAndroid Build Coastguard Worker                     pb->pop();
629*c8dee2aaSAndroid Build Coastguard Worker 
630*c8dee2aaSAndroid Build Coastguard Worker                     text += subTextCount;
631*c8dee2aaSAndroid Build Coastguard Worker                     textCount -= subTextCount;
632*c8dee2aaSAndroid Build Coastguard Worker                 }
633*c8dee2aaSAndroid Build Coastguard Worker                 if (textCount != 0) {
634*c8dee2aaSAndroid Build Coastguard Worker                     return emscripten::val("Didn't have enough block runs to cover text");
635*c8dee2aaSAndroid Build Coastguard Worker                 }
636*c8dee2aaSAndroid Build Coastguard Worker 
637*c8dee2aaSAndroid Build Coastguard Worker                 auto pa = pb->Build();
638*c8dee2aaSAndroid Build Coastguard Worker                 pa->layout(width);
639*c8dee2aaSAndroid Build Coastguard Worker 
640*c8dee2aaSAndroid Build Coastguard Worker                 // workaround until this is fixed in SkParagraph
641*c8dee2aaSAndroid Build Coastguard Worker                 {
642*c8dee2aaSAndroid Build Coastguard Worker                     SkPictureRecorder rec;
643*c8dee2aaSAndroid Build Coastguard Worker                     pa->paint(rec.beginRecording({0,0,9999,9999}), 0, 0);
644*c8dee2aaSAndroid Build Coastguard Worker                 }
645*c8dee2aaSAndroid Build Coastguard Worker                 return GetShapedLines(*pa);
646*c8dee2aaSAndroid Build Coastguard Worker             }),
647*c8dee2aaSAndroid Build Coastguard Worker             allow_raw_pointers())
648*c8dee2aaSAndroid Build Coastguard Worker             .class_function("RequiresClientICU", &para::ParagraphBuilderImpl::RequiresClientICU)
649*c8dee2aaSAndroid Build Coastguard Worker             .function("addText",
650*c8dee2aaSAndroid Build Coastguard Worker                       optional_override([](para::ParagraphBuilderImpl& self, std::string text) {
651*c8dee2aaSAndroid Build Coastguard Worker                           return self.addText(text.c_str(), text.length());
652*c8dee2aaSAndroid Build Coastguard Worker                       }))
653*c8dee2aaSAndroid Build Coastguard Worker             .function("build", &para::ParagraphBuilderImpl::Build, allow_raw_pointers())
654*c8dee2aaSAndroid Build Coastguard Worker             .function("build", optional_override([](para::ParagraphBuilderImpl& self) {
655*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_CLIENT_IMPLEMENTATION)
656*c8dee2aaSAndroid Build Coastguard Worker                           auto [words, graphemeBreaks, lineBreaks] = self.getClientICUData();
657*c8dee2aaSAndroid Build Coastguard Worker                           auto text = self.getText();
658*c8dee2aaSAndroid Build Coastguard Worker                           sk_sp<SkUnicode> clientICU = SkUnicodes::Client::Make(text, words, graphemeBreaks, lineBreaks);
659*c8dee2aaSAndroid Build Coastguard Worker                           self.SetUnicode(clientICU);
660*c8dee2aaSAndroid Build Coastguard Worker #endif
661*c8dee2aaSAndroid Build Coastguard Worker                           return self.Build();
662*c8dee2aaSAndroid Build Coastguard Worker                       }), allow_raw_pointers())
663*c8dee2aaSAndroid Build Coastguard Worker             .function("pop", &para::ParagraphBuilderImpl::pop)
664*c8dee2aaSAndroid Build Coastguard Worker             .function("reset", &para::ParagraphBuilderImpl::Reset, allow_raw_pointers())
665*c8dee2aaSAndroid Build Coastguard Worker             .function("_pushStyle", optional_override([](para::ParagraphBuilderImpl& self,
666*c8dee2aaSAndroid Build Coastguard Worker                                                          SimpleTextStyle textStyle) {
667*c8dee2aaSAndroid Build Coastguard Worker                           auto ts = toTextStyle(textStyle);
668*c8dee2aaSAndroid Build Coastguard Worker                           self.pushStyle(ts);
669*c8dee2aaSAndroid Build Coastguard Worker                       }))
670*c8dee2aaSAndroid Build Coastguard Worker             // A method of pushing a textStyle with paints instead of colors for foreground and
671*c8dee2aaSAndroid Build Coastguard Worker             // background. Since SimpleTextStyle is a value object, it cannot contain paints, which
672*c8dee2aaSAndroid Build Coastguard Worker             // are not primitives. This binding is here to accept them. Any color that is specified
673*c8dee2aaSAndroid Build Coastguard Worker             // in the textStyle is overridden.
674*c8dee2aaSAndroid Build Coastguard Worker             .function("_pushPaintStyle",
675*c8dee2aaSAndroid Build Coastguard Worker                       optional_override([](para::ParagraphBuilderImpl& self,
676*c8dee2aaSAndroid Build Coastguard Worker                                            SimpleTextStyle textStyle, SkPaint foreground,
677*c8dee2aaSAndroid Build Coastguard Worker                                            SkPaint background) {
678*c8dee2aaSAndroid Build Coastguard Worker                           auto ts = toTextStyle(textStyle);
679*c8dee2aaSAndroid Build Coastguard Worker                           ts.setForegroundColor(foreground);
680*c8dee2aaSAndroid Build Coastguard Worker                           ts.setBackgroundColor(background);
681*c8dee2aaSAndroid Build Coastguard Worker                           self.pushStyle(ts);
682*c8dee2aaSAndroid Build Coastguard Worker                       }))
683*c8dee2aaSAndroid Build Coastguard Worker             .function("_addPlaceholder", optional_override([](para::ParagraphBuilderImpl& self,
684*c8dee2aaSAndroid Build Coastguard Worker                                                               SkScalar width,
685*c8dee2aaSAndroid Build Coastguard Worker                                                               SkScalar height,
686*c8dee2aaSAndroid Build Coastguard Worker                                                               para::PlaceholderAlignment alignment,
687*c8dee2aaSAndroid Build Coastguard Worker                                                               para::TextBaseline baseline,
688*c8dee2aaSAndroid Build Coastguard Worker                                                               SkScalar offset) {
689*c8dee2aaSAndroid Build Coastguard Worker                           para::PlaceholderStyle ps(width, height, alignment, baseline, offset);
690*c8dee2aaSAndroid Build Coastguard Worker                           self.addPlaceholder(ps);
691*c8dee2aaSAndroid Build Coastguard Worker                       }))
692*c8dee2aaSAndroid Build Coastguard Worker             .function("getText",
693*c8dee2aaSAndroid Build Coastguard Worker                       optional_override([](para::ParagraphBuilderImpl& self) -> JSString {
694*c8dee2aaSAndroid Build Coastguard Worker                           auto text = self.getText();
695*c8dee2aaSAndroid Build Coastguard Worker                           return emscripten::val(std::string(text.data(), text.size()).c_str());
696*c8dee2aaSAndroid Build Coastguard Worker                       }))
697*c8dee2aaSAndroid Build Coastguard Worker             .function("_setWordsUtf8",
698*c8dee2aaSAndroid Build Coastguard Worker                       optional_override([](para::ParagraphBuilderImpl& self,
699*c8dee2aaSAndroid Build Coastguard Worker                                            WASMPointerU32 clientWords, size_t wordsNum) {
700*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_CLIENT_IMPLEMENTATION)
701*c8dee2aaSAndroid Build Coastguard Worker                       self.setWordsUtf8(convertArrayU32(clientWords, wordsNum));
702*c8dee2aaSAndroid Build Coastguard Worker #endif
703*c8dee2aaSAndroid Build Coastguard Worker                   }))
704*c8dee2aaSAndroid Build Coastguard Worker             .function("_setWordsUtf16",
705*c8dee2aaSAndroid Build Coastguard Worker                       optional_override([](para::ParagraphBuilderImpl& self,
706*c8dee2aaSAndroid Build Coastguard Worker                                            WASMPointerU32 clientWords, size_t wordsNum) {
707*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_CLIENT_IMPLEMENTATION)
708*c8dee2aaSAndroid Build Coastguard Worker                       self.setWordsUtf16(convertArrayU32(clientWords, wordsNum));
709*c8dee2aaSAndroid Build Coastguard Worker #endif
710*c8dee2aaSAndroid Build Coastguard Worker                   }))
711*c8dee2aaSAndroid Build Coastguard Worker             .function("_setGraphemeBreaksUtf8",
712*c8dee2aaSAndroid Build Coastguard Worker                       optional_override([](para::ParagraphBuilderImpl& self,
713*c8dee2aaSAndroid Build Coastguard Worker                                            WASMPointerU32 clientGraphemes, size_t graphemesNum) {
714*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_CLIENT_IMPLEMENTATION)
715*c8dee2aaSAndroid Build Coastguard Worker                       self.setGraphemeBreaksUtf8(convertArrayU32(clientGraphemes, graphemesNum));
716*c8dee2aaSAndroid Build Coastguard Worker #endif
717*c8dee2aaSAndroid Build Coastguard Worker                   }))
718*c8dee2aaSAndroid Build Coastguard Worker             .function("_setGraphemeBreaksUtf16",
719*c8dee2aaSAndroid Build Coastguard Worker                       optional_override([](para::ParagraphBuilderImpl& self,
720*c8dee2aaSAndroid Build Coastguard Worker                                            WASMPointerU32 clientGraphemes, size_t graphemesNum) {
721*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_CLIENT_IMPLEMENTATION)
722*c8dee2aaSAndroid Build Coastguard Worker                       self.setGraphemeBreaksUtf16(convertArrayU32(clientGraphemes, graphemesNum));
723*c8dee2aaSAndroid Build Coastguard Worker #endif
724*c8dee2aaSAndroid Build Coastguard Worker                   }))
725*c8dee2aaSAndroid Build Coastguard Worker             .function("_setLineBreaksUtf8",
726*c8dee2aaSAndroid Build Coastguard Worker                       optional_override([](para::ParagraphBuilderImpl& self,
727*c8dee2aaSAndroid Build Coastguard Worker                                            WASMPointerU32 clientLineBreaks, size_t lineBreaksNum) {
728*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_CLIENT_IMPLEMENTATION)
729*c8dee2aaSAndroid Build Coastguard Worker                       SkUnicode::Position* lineBreakData = reinterpret_cast<SkUnicode::Position*>(clientLineBreaks);
730*c8dee2aaSAndroid Build Coastguard Worker                       std::vector<SkUnicode::LineBreakBefore> lineBreaks;
731*c8dee2aaSAndroid Build Coastguard Worker                       for (size_t i = 0; i < lineBreaksNum; i += 2) {
732*c8dee2aaSAndroid Build Coastguard Worker                           auto pos = lineBreakData[i];
733*c8dee2aaSAndroid Build Coastguard Worker                           auto breakType = lineBreakData[i+1];
734*c8dee2aaSAndroid Build Coastguard Worker                           if (breakType == 0) {
735*c8dee2aaSAndroid Build Coastguard Worker                               lineBreaks.emplace_back(pos, SkUnicode::LineBreakType::kSoftLineBreak);
736*c8dee2aaSAndroid Build Coastguard Worker                           } else {
737*c8dee2aaSAndroid Build Coastguard Worker                               lineBreaks.emplace_back(pos, SkUnicode::LineBreakType::kHardLineBreak);
738*c8dee2aaSAndroid Build Coastguard Worker                           }
739*c8dee2aaSAndroid Build Coastguard Worker                       }
740*c8dee2aaSAndroid Build Coastguard Worker                       self.setLineBreaksUtf8(std::move(lineBreaks));
741*c8dee2aaSAndroid Build Coastguard Worker #endif
742*c8dee2aaSAndroid Build Coastguard Worker                   }))
743*c8dee2aaSAndroid Build Coastguard Worker             .function("_setLineBreaksUtf16",
744*c8dee2aaSAndroid Build Coastguard Worker                       optional_override([](para::ParagraphBuilderImpl& self,
745*c8dee2aaSAndroid Build Coastguard Worker                                            WASMPointerU32 clientLineBreaks, size_t lineBreaksNum) {
746*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_CLIENT_IMPLEMENTATION)
747*c8dee2aaSAndroid Build Coastguard Worker                       SkUnicode::Position* lineBreakData = reinterpret_cast<SkUnicode::Position*>(clientLineBreaks);
748*c8dee2aaSAndroid Build Coastguard Worker                       std::vector<SkUnicode::LineBreakBefore> lineBreaks;
749*c8dee2aaSAndroid Build Coastguard Worker                       for (size_t i = 0; i < lineBreaksNum; i += 2) {
750*c8dee2aaSAndroid Build Coastguard Worker                           auto pos = lineBreakData[i];
751*c8dee2aaSAndroid Build Coastguard Worker                           auto breakType = lineBreakData[i+1];
752*c8dee2aaSAndroid Build Coastguard Worker                           if (breakType == 0) {
753*c8dee2aaSAndroid Build Coastguard Worker                               lineBreaks.emplace_back(pos, SkUnicode::LineBreakType::kSoftLineBreak);
754*c8dee2aaSAndroid Build Coastguard Worker                           } else {
755*c8dee2aaSAndroid Build Coastguard Worker                               lineBreaks.emplace_back(pos, SkUnicode::LineBreakType::kHardLineBreak);
756*c8dee2aaSAndroid Build Coastguard Worker                           }
757*c8dee2aaSAndroid Build Coastguard Worker                       }
758*c8dee2aaSAndroid Build Coastguard Worker                       self.setLineBreaksUtf16(std::move(lineBreaks));
759*c8dee2aaSAndroid Build Coastguard Worker #endif
760*c8dee2aaSAndroid Build Coastguard Worker                   }));
761*c8dee2aaSAndroid Build Coastguard Worker 
762*c8dee2aaSAndroid Build Coastguard Worker     class_<para::TypefaceFontProvider, base<SkFontMgr>>("TypefaceFontProvider")
763*c8dee2aaSAndroid Build Coastguard Worker       .smart_ptr<sk_sp<para::TypefaceFontProvider>>("sk_sp<TypefaceFontProvider>")
764*c8dee2aaSAndroid Build Coastguard Worker       .class_function("Make", optional_override([]()-> sk_sp<para::TypefaceFontProvider> {
765*c8dee2aaSAndroid Build Coastguard Worker           return sk_make_sp<para::TypefaceFontProvider>();
766*c8dee2aaSAndroid Build Coastguard Worker       }))
767*c8dee2aaSAndroid Build Coastguard Worker       .function("_registerFont", optional_override([](para::TypefaceFontProvider& self,
768*c8dee2aaSAndroid Build Coastguard Worker                                                       sk_sp<SkTypeface> typeface,
769*c8dee2aaSAndroid Build Coastguard Worker                                                       WASMPointerU8 familyPtr) {
770*c8dee2aaSAndroid Build Coastguard Worker           const char* fPtr = reinterpret_cast<const char*>(familyPtr);
771*c8dee2aaSAndroid Build Coastguard Worker           SkString fStr(fPtr);
772*c8dee2aaSAndroid Build Coastguard Worker           self.registerTypeface(typeface, fStr);
773*c8dee2aaSAndroid Build Coastguard Worker       }), allow_raw_pointers());
774*c8dee2aaSAndroid Build Coastguard Worker 
775*c8dee2aaSAndroid Build Coastguard Worker     class_<para::FontCollection>("FontCollection")
776*c8dee2aaSAndroid Build Coastguard Worker       .smart_ptr<sk_sp<para::FontCollection>>("sk_sp<FontCollection>")
777*c8dee2aaSAndroid Build Coastguard Worker       .class_function("Make", optional_override([]()-> sk_sp<para::FontCollection> {
778*c8dee2aaSAndroid Build Coastguard Worker           return sk_make_sp<para::FontCollection>();
779*c8dee2aaSAndroid Build Coastguard Worker       }))
780*c8dee2aaSAndroid Build Coastguard Worker       .function("setDefaultFontManager", optional_override([](para::FontCollection& self,
781*c8dee2aaSAndroid Build Coastguard Worker                                                               const sk_sp<para::TypefaceFontProvider>& fontManager) {
782*c8dee2aaSAndroid Build Coastguard Worker         self.setDefaultFontManager(fontManager);
783*c8dee2aaSAndroid Build Coastguard Worker       }), allow_raw_pointers())
784*c8dee2aaSAndroid Build Coastguard Worker       .function("enableFontFallback", &para::FontCollection::enableFontFallback);
785*c8dee2aaSAndroid Build Coastguard Worker 
786*c8dee2aaSAndroid Build Coastguard Worker     // These value objects make it easier to send data across the wire.
787*c8dee2aaSAndroid Build Coastguard Worker     value_object<para::PositionWithAffinity>("PositionWithAffinity")
788*c8dee2aaSAndroid Build Coastguard Worker         .field("pos",      &para::PositionWithAffinity::position)
789*c8dee2aaSAndroid Build Coastguard Worker         .field("affinity", &para::PositionWithAffinity::affinity);
790*c8dee2aaSAndroid Build Coastguard Worker 
791*c8dee2aaSAndroid Build Coastguard Worker     value_object<SimpleFontStyle>("FontStyle")
792*c8dee2aaSAndroid Build Coastguard Worker         .field("slant",     &SimpleFontStyle::slant)
793*c8dee2aaSAndroid Build Coastguard Worker         .field("weight",    &SimpleFontStyle::weight)
794*c8dee2aaSAndroid Build Coastguard Worker         .field("width",     &SimpleFontStyle::width);
795*c8dee2aaSAndroid Build Coastguard Worker 
796*c8dee2aaSAndroid Build Coastguard Worker     value_object<SimpleParagraphStyle>("ParagraphStyle")
797*c8dee2aaSAndroid Build Coastguard Worker         .field("disableHinting",       &SimpleParagraphStyle::disableHinting)
798*c8dee2aaSAndroid Build Coastguard Worker         .field("_ellipsisPtr",         &SimpleParagraphStyle::ellipsisPtr)
799*c8dee2aaSAndroid Build Coastguard Worker         .field("_ellipsisLen",         &SimpleParagraphStyle::ellipsisLen)
800*c8dee2aaSAndroid Build Coastguard Worker         .field("heightMultiplier",     &SimpleParagraphStyle::heightMultiplier)
801*c8dee2aaSAndroid Build Coastguard Worker         .field("maxLines",             &SimpleParagraphStyle::maxLines)
802*c8dee2aaSAndroid Build Coastguard Worker         .field("replaceTabCharacters", &SimpleParagraphStyle::replaceTabCharacters)
803*c8dee2aaSAndroid Build Coastguard Worker         .field("textAlign",            &SimpleParagraphStyle::textAlign)
804*c8dee2aaSAndroid Build Coastguard Worker         .field("textDirection",        &SimpleParagraphStyle::textDirection)
805*c8dee2aaSAndroid Build Coastguard Worker         .field("textHeightBehavior",   &SimpleParagraphStyle::textHeightBehavior)
806*c8dee2aaSAndroid Build Coastguard Worker         .field("textStyle",            &SimpleParagraphStyle::textStyle)
807*c8dee2aaSAndroid Build Coastguard Worker         .field("strutStyle",           &SimpleParagraphStyle::strutStyle)
808*c8dee2aaSAndroid Build Coastguard Worker         .field("applyRoundingHack",    &SimpleParagraphStyle::applyRoundingHack);
809*c8dee2aaSAndroid Build Coastguard Worker 
810*c8dee2aaSAndroid Build Coastguard Worker     value_object<SimpleStrutStyle>("StrutStyle")
811*c8dee2aaSAndroid Build Coastguard Worker         .field("_fontFamiliesPtr", &SimpleStrutStyle::fontFamiliesPtr)
812*c8dee2aaSAndroid Build Coastguard Worker         .field("_fontFamiliesLen", &SimpleStrutStyle::fontFamiliesLen)
813*c8dee2aaSAndroid Build Coastguard Worker         .field("strutEnabled",     &SimpleStrutStyle::strutEnabled)
814*c8dee2aaSAndroid Build Coastguard Worker         .field("fontSize",         &SimpleStrutStyle::fontSize)
815*c8dee2aaSAndroid Build Coastguard Worker         .field("fontStyle",        &SimpleStrutStyle::fontStyle)
816*c8dee2aaSAndroid Build Coastguard Worker         .field("heightMultiplier", &SimpleStrutStyle::heightMultiplier)
817*c8dee2aaSAndroid Build Coastguard Worker         .field("halfLeading",      &SimpleStrutStyle::halfLeading)
818*c8dee2aaSAndroid Build Coastguard Worker         .field("leading",          &SimpleStrutStyle::leading)
819*c8dee2aaSAndroid Build Coastguard Worker         .field("forceStrutHeight", &SimpleStrutStyle::forceStrutHeight);
820*c8dee2aaSAndroid Build Coastguard Worker 
821*c8dee2aaSAndroid Build Coastguard Worker     value_object<SimpleTextStyle>("TextStyle")
822*c8dee2aaSAndroid Build Coastguard Worker         .field("_colorPtr",             &SimpleTextStyle::colorPtr)
823*c8dee2aaSAndroid Build Coastguard Worker         .field("_foregroundColorPtr",   &SimpleTextStyle::foregroundColorPtr)
824*c8dee2aaSAndroid Build Coastguard Worker         .field("_backgroundColorPtr",   &SimpleTextStyle::backgroundColorPtr)
825*c8dee2aaSAndroid Build Coastguard Worker         .field("decoration",            &SimpleTextStyle::decoration)
826*c8dee2aaSAndroid Build Coastguard Worker         .field("decorationThickness",   &SimpleTextStyle::decorationThickness)
827*c8dee2aaSAndroid Build Coastguard Worker         .field("_decorationColorPtr",   &SimpleTextStyle::decorationColorPtr)
828*c8dee2aaSAndroid Build Coastguard Worker         .field("decorationStyle",       &SimpleTextStyle::decorationStyle)
829*c8dee2aaSAndroid Build Coastguard Worker         .field("_fontFamiliesPtr",      &SimpleTextStyle::fontFamiliesPtr)
830*c8dee2aaSAndroid Build Coastguard Worker         .field("_fontFamiliesLen",      &SimpleTextStyle::fontFamiliesLen)
831*c8dee2aaSAndroid Build Coastguard Worker         .field("fontSize",              &SimpleTextStyle::fontSize)
832*c8dee2aaSAndroid Build Coastguard Worker         .field("letterSpacing",         &SimpleTextStyle::letterSpacing)
833*c8dee2aaSAndroid Build Coastguard Worker         .field("wordSpacing",           &SimpleTextStyle::wordSpacing)
834*c8dee2aaSAndroid Build Coastguard Worker         .field("heightMultiplier",      &SimpleTextStyle::heightMultiplier)
835*c8dee2aaSAndroid Build Coastguard Worker         .field("halfLeading",           &SimpleTextStyle::halfLeading)
836*c8dee2aaSAndroid Build Coastguard Worker         .field("_localePtr",            &SimpleTextStyle::localePtr)
837*c8dee2aaSAndroid Build Coastguard Worker         .field("_localeLen",            &SimpleTextStyle::localeLen)
838*c8dee2aaSAndroid Build Coastguard Worker         .field("fontStyle",             &SimpleTextStyle::fontStyle)
839*c8dee2aaSAndroid Build Coastguard Worker         .field("_shadowLen",            &SimpleTextStyle::shadowLen)
840*c8dee2aaSAndroid Build Coastguard Worker         .field("_shadowColorsPtr",      &SimpleTextStyle::shadowColorsPtr)
841*c8dee2aaSAndroid Build Coastguard Worker         .field("_shadowOffsetsPtr",     &SimpleTextStyle::shadowOffsetsPtr)
842*c8dee2aaSAndroid Build Coastguard Worker         .field("_shadowBlurRadiiPtr",   &SimpleTextStyle::shadowBlurRadiiPtr)
843*c8dee2aaSAndroid Build Coastguard Worker         .field("_fontFeatureLen",       &SimpleTextStyle::fontFeatureLen)
844*c8dee2aaSAndroid Build Coastguard Worker         .field("_fontFeatureNamesPtr",  &SimpleTextStyle::fontFeatureNamesPtr)
845*c8dee2aaSAndroid Build Coastguard Worker         .field("_fontFeatureValuesPtr", &SimpleTextStyle::fontFeatureValuesPtr)
846*c8dee2aaSAndroid Build Coastguard Worker         .field("_fontVariationLen",     &SimpleTextStyle::fontVariationLen)
847*c8dee2aaSAndroid Build Coastguard Worker         .field("_fontVariationAxesPtr", &SimpleTextStyle::fontVariationAxesPtr)
848*c8dee2aaSAndroid Build Coastguard Worker         .field("_fontVariationValuesPtr", &SimpleTextStyle::fontVariationValuesPtr);
849*c8dee2aaSAndroid Build Coastguard Worker 
850*c8dee2aaSAndroid Build Coastguard Worker     // The U stands for unsigned - we can't bind a generic/template object, so we have to specify it
851*c8dee2aaSAndroid Build Coastguard Worker     // with the type we are using.
852*c8dee2aaSAndroid Build Coastguard Worker     // TODO(kjlubick) make this a typedarray.
853*c8dee2aaSAndroid Build Coastguard Worker     value_object<para::SkRange<size_t>>("URange")
854*c8dee2aaSAndroid Build Coastguard Worker         .field("start",    &para::SkRange<size_t>::start)
855*c8dee2aaSAndroid Build Coastguard Worker         .field("end",      &para::SkRange<size_t>::end);
856*c8dee2aaSAndroid Build Coastguard Worker 
857*c8dee2aaSAndroid Build Coastguard Worker     // TextDecoration should be a const because they can be combined
858*c8dee2aaSAndroid Build Coastguard Worker     constant("NoDecoration", int(para::TextDecoration::kNoDecoration));
859*c8dee2aaSAndroid Build Coastguard Worker     constant("UnderlineDecoration", int(para::TextDecoration::kUnderline));
860*c8dee2aaSAndroid Build Coastguard Worker     constant("OverlineDecoration", int(para::TextDecoration::kOverline));
861*c8dee2aaSAndroid Build Coastguard Worker     constant("LineThroughDecoration", int(para::TextDecoration::kLineThrough));
862*c8dee2aaSAndroid Build Coastguard Worker }
863