1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2019 Google LLC 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkColor.h" 9cb93a386Sopenharmony_ci#include "include/core/SkFontStyle.h" 10cb93a386Sopenharmony_ci#include "include/core/SkPictureRecorder.h" 11cb93a386Sopenharmony_ci#include "include/core/SkString.h" 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_ci#include "modules/skparagraph/include/DartTypes.h" 14cb93a386Sopenharmony_ci#include "modules/skparagraph/include/Paragraph.h" 15cb93a386Sopenharmony_ci#include "modules/skparagraph/include/TextStyle.h" 16cb93a386Sopenharmony_ci#include "modules/skparagraph/include/TypefaceFontProvider.h" 17cb93a386Sopenharmony_ci#include "modules/skparagraph/src/ParagraphBuilderImpl.h" 18cb93a386Sopenharmony_ci#include "modules/skparagraph/src/ParagraphImpl.h" 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_ci#include <string> 21cb93a386Sopenharmony_ci#include <vector> 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci#include <emscripten.h> 24cb93a386Sopenharmony_ci#include <emscripten/bind.h> 25cb93a386Sopenharmony_ci#include "modules/canvaskit/WasmCommon.h" 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ciusing namespace emscripten; 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_cinamespace para = skia::textlayout; 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ciSkColor4f toSkColor4f(WASMPointerF32 cPtr) { 32cb93a386Sopenharmony_ci float* fourFloats = reinterpret_cast<float*>(cPtr); 33cb93a386Sopenharmony_ci SkColor4f color = {fourFloats[0], fourFloats[1], fourFloats[2], fourFloats[3]}; 34cb93a386Sopenharmony_ci return color; 35cb93a386Sopenharmony_ci} 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_cistruct SimpleFontStyle { 38cb93a386Sopenharmony_ci SkFontStyle::Slant slant; 39cb93a386Sopenharmony_ci SkFontStyle::Weight weight; 40cb93a386Sopenharmony_ci SkFontStyle::Width width; 41cb93a386Sopenharmony_ci}; 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_cistruct SimpleTextStyle { 44cb93a386Sopenharmony_ci WASMPointerF32 colorPtr; 45cb93a386Sopenharmony_ci WASMPointerF32 foregroundColorPtr; 46cb93a386Sopenharmony_ci WASMPointerF32 backgroundColorPtr; 47cb93a386Sopenharmony_ci uint8_t decoration; 48cb93a386Sopenharmony_ci SkScalar decorationThickness; 49cb93a386Sopenharmony_ci WASMPointerF32 decorationColorPtr; 50cb93a386Sopenharmony_ci para::TextDecorationStyle decorationStyle; 51cb93a386Sopenharmony_ci para::TextBaseline textBaseline; 52cb93a386Sopenharmony_ci SkScalar fontSize; 53cb93a386Sopenharmony_ci SkScalar letterSpacing; 54cb93a386Sopenharmony_ci SkScalar wordSpacing; 55cb93a386Sopenharmony_ci SkScalar heightMultiplier; 56cb93a386Sopenharmony_ci bool halfLeading; 57cb93a386Sopenharmony_ci WASMPointerU8 localePtr; 58cb93a386Sopenharmony_ci int localeLen; 59cb93a386Sopenharmony_ci SimpleFontStyle fontStyle; 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci WASMPointerU8 fontFamiliesPtr; 62cb93a386Sopenharmony_ci int fontFamiliesLen; 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ci int shadowLen; 65cb93a386Sopenharmony_ci WASMPointerF32 shadowColorsPtr; 66cb93a386Sopenharmony_ci WASMPointerF32 shadowOffsetsPtr; 67cb93a386Sopenharmony_ci WASMPointerF32 shadowBlurRadiiPtr; 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_ci int fontFeatureLen; 70cb93a386Sopenharmony_ci WASMPointerF32 fontFeatureNamesPtr; 71cb93a386Sopenharmony_ci WASMPointerF32 fontFeatureValuesPtr; 72cb93a386Sopenharmony_ci}; 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_cistruct SimpleStrutStyle { 75cb93a386Sopenharmony_ci WASMPointerU32 fontFamiliesPtr; 76cb93a386Sopenharmony_ci int fontFamiliesLen; 77cb93a386Sopenharmony_ci SimpleFontStyle fontStyle; 78cb93a386Sopenharmony_ci SkScalar fontSize; 79cb93a386Sopenharmony_ci SkScalar heightMultiplier; 80cb93a386Sopenharmony_ci bool halfLeading; 81cb93a386Sopenharmony_ci SkScalar leading; 82cb93a386Sopenharmony_ci bool strutEnabled; 83cb93a386Sopenharmony_ci bool forceStrutHeight; 84cb93a386Sopenharmony_ci}; 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_cipara::StrutStyle toStrutStyle(const SimpleStrutStyle& s) { 87cb93a386Sopenharmony_ci para::StrutStyle ss; 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci const char** fontFamilies = reinterpret_cast<const char**>(s.fontFamiliesPtr); 90cb93a386Sopenharmony_ci if (fontFamilies != nullptr) { 91cb93a386Sopenharmony_ci std::vector<SkString> ff; 92cb93a386Sopenharmony_ci for (int i = 0; i < s.fontFamiliesLen; i++) { 93cb93a386Sopenharmony_ci ff.emplace_back(fontFamilies[i]); 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci ss.setFontFamilies(ff); 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ci SkFontStyle fs(s.fontStyle.weight, s.fontStyle.width, s.fontStyle.slant); 99cb93a386Sopenharmony_ci ss.setFontStyle(fs); 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci if (s.fontSize != 0) { 102cb93a386Sopenharmony_ci ss.setFontSize(s.fontSize); 103cb93a386Sopenharmony_ci } 104cb93a386Sopenharmony_ci if (s.heightMultiplier != 0) { 105cb93a386Sopenharmony_ci ss.setHeight(s.heightMultiplier); 106cb93a386Sopenharmony_ci ss.setHeightOverride(true); 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci ss.setHalfLeading(s.halfLeading); 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci if (s.leading != 0) { 111cb93a386Sopenharmony_ci ss.setLeading(s.leading); 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci ss.setStrutEnabled(s.strutEnabled); 115cb93a386Sopenharmony_ci ss.setForceStrutHeight(s.forceStrutHeight); 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ci return ss; 118cb93a386Sopenharmony_ci} 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_cipara::TextStyle toTextStyle(const SimpleTextStyle& s) { 121cb93a386Sopenharmony_ci para::TextStyle ts; 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci // textstyle.color doesn't support a 4f color, however the foreground and background fields 124cb93a386Sopenharmony_ci // below do. 125cb93a386Sopenharmony_ci ts.setColor(toSkColor4f(s.colorPtr).toSkColor()); 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_ci // It is functionally important that these paints be unset when no value was provided. 128cb93a386Sopenharmony_ci if (s.foregroundColorPtr) { 129cb93a386Sopenharmony_ci SkPaint p1; 130cb93a386Sopenharmony_ci p1.setColor4f(toSkColor4f(s.foregroundColorPtr)); 131cb93a386Sopenharmony_ci ts.setForegroundColor(p1); 132cb93a386Sopenharmony_ci } 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci if (s.backgroundColorPtr) { 135cb93a386Sopenharmony_ci SkPaint p2; 136cb93a386Sopenharmony_ci p2.setColor4f(toSkColor4f(s.backgroundColorPtr)); 137cb93a386Sopenharmony_ci ts.setBackgroundColor(p2); 138cb93a386Sopenharmony_ci } 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ci if (s.fontSize != 0) { 141cb93a386Sopenharmony_ci ts.setFontSize(s.fontSize); 142cb93a386Sopenharmony_ci } 143cb93a386Sopenharmony_ci if (s.letterSpacing != 0) { 144cb93a386Sopenharmony_ci ts.setLetterSpacing(s.letterSpacing); 145cb93a386Sopenharmony_ci } 146cb93a386Sopenharmony_ci if (s.wordSpacing != 0) { 147cb93a386Sopenharmony_ci ts.setWordSpacing(s.wordSpacing); 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ci if (s.heightMultiplier != 0) { 151cb93a386Sopenharmony_ci ts.setHeight(s.heightMultiplier); 152cb93a386Sopenharmony_ci ts.setHeightOverride(true); 153cb93a386Sopenharmony_ci } 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci ts.setHalfLeading(s.halfLeading); 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci ts.setDecoration(para::TextDecoration(s.decoration)); 158cb93a386Sopenharmony_ci ts.setDecorationStyle(s.decorationStyle); 159cb93a386Sopenharmony_ci if (s.decorationThickness != 0) { 160cb93a386Sopenharmony_ci ts.setDecorationThicknessMultiplier(s.decorationThickness); 161cb93a386Sopenharmony_ci } 162cb93a386Sopenharmony_ci if (s.decorationColorPtr) { 163cb93a386Sopenharmony_ci ts.setDecorationColor(toSkColor4f(s.decorationColorPtr).toSkColor()); 164cb93a386Sopenharmony_ci } 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ci if (s.localeLen > 0) { 167cb93a386Sopenharmony_ci const char* localePtr = reinterpret_cast<const char*>(s.localePtr); 168cb93a386Sopenharmony_ci SkString lStr(localePtr, s.localeLen); 169cb93a386Sopenharmony_ci ts.setLocale(lStr); 170cb93a386Sopenharmony_ci } 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_ci const char** fontFamilies = reinterpret_cast<const char**>(s.fontFamiliesPtr); 173cb93a386Sopenharmony_ci if (fontFamilies != nullptr) { 174cb93a386Sopenharmony_ci std::vector<SkString> ff; 175cb93a386Sopenharmony_ci for (int i = 0; i < s.fontFamiliesLen; i++) { 176cb93a386Sopenharmony_ci ff.emplace_back(fontFamilies[i]); 177cb93a386Sopenharmony_ci } 178cb93a386Sopenharmony_ci ts.setFontFamilies(ff); 179cb93a386Sopenharmony_ci } 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci ts.setTextBaseline(s.textBaseline); 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ci SkFontStyle fs(s.fontStyle.weight, s.fontStyle.width, s.fontStyle.slant); 184cb93a386Sopenharmony_ci ts.setFontStyle(fs); 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_ci if (s.shadowLen > 0) { 187cb93a386Sopenharmony_ci const SkColor4f* colors = reinterpret_cast<const SkColor4f*>(s.shadowColorsPtr); 188cb93a386Sopenharmony_ci const SkPoint* offsets = reinterpret_cast<const SkPoint*>(s.shadowOffsetsPtr); 189cb93a386Sopenharmony_ci const float* blurRadii = reinterpret_cast<const float*>(s.shadowBlurRadiiPtr); 190cb93a386Sopenharmony_ci for (int i = 0; i < s.shadowLen; i++) { 191cb93a386Sopenharmony_ci para::TextShadow shadow(colors[i].toSkColor(), offsets[i], blurRadii[i]); 192cb93a386Sopenharmony_ci ts.addShadow(shadow); 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci } 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_ci if (s.fontFeatureLen > 0) { 198cb93a386Sopenharmony_ci const char** fontFeatureNames = reinterpret_cast<const char**>(s.fontFeatureNamesPtr); 199cb93a386Sopenharmony_ci const int* fontFeatureValues = reinterpret_cast<const int*>(s.fontFeatureValuesPtr); 200cb93a386Sopenharmony_ci for (int i = 0; i < s.fontFeatureLen; i++) { 201cb93a386Sopenharmony_ci // Font features names are 4-character simple strings. 202cb93a386Sopenharmony_ci SkString name(fontFeatureNames[i], 4); 203cb93a386Sopenharmony_ci ts.addFontFeature(name, fontFeatureValues[i]); 204cb93a386Sopenharmony_ci } 205cb93a386Sopenharmony_ci } 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_ci return ts; 208cb93a386Sopenharmony_ci} 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_cistruct SimpleParagraphStyle { 211cb93a386Sopenharmony_ci bool disableHinting; 212cb93a386Sopenharmony_ci WASMPointerU8 ellipsisPtr; 213cb93a386Sopenharmony_ci size_t ellipsisLen; 214cb93a386Sopenharmony_ci SkScalar heightMultiplier; 215cb93a386Sopenharmony_ci size_t maxLines; 216cb93a386Sopenharmony_ci para::TextAlign textAlign; 217cb93a386Sopenharmony_ci para::TextDirection textDirection; 218cb93a386Sopenharmony_ci para::TextHeightBehavior textHeightBehavior; 219cb93a386Sopenharmony_ci SimpleTextStyle textStyle; 220cb93a386Sopenharmony_ci SimpleStrutStyle strutStyle; 221cb93a386Sopenharmony_ci}; 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_cipara::ParagraphStyle toParagraphStyle(const SimpleParagraphStyle& s) { 224cb93a386Sopenharmony_ci para::ParagraphStyle ps; 225cb93a386Sopenharmony_ci if (s.disableHinting) { 226cb93a386Sopenharmony_ci ps.turnHintingOff(); 227cb93a386Sopenharmony_ci } 228cb93a386Sopenharmony_ci 229cb93a386Sopenharmony_ci if (s.ellipsisLen > 0) { 230cb93a386Sopenharmony_ci const char* ellipsisPtr = reinterpret_cast<const char*>(s.ellipsisPtr); 231cb93a386Sopenharmony_ci SkString eStr(ellipsisPtr, s.ellipsisLen); 232cb93a386Sopenharmony_ci ps.setEllipsis(eStr); 233cb93a386Sopenharmony_ci } 234cb93a386Sopenharmony_ci ps.setTextAlign(s.textAlign); 235cb93a386Sopenharmony_ci ps.setTextDirection(s.textDirection); 236cb93a386Sopenharmony_ci auto ts = toTextStyle(s.textStyle); 237cb93a386Sopenharmony_ci ps.setTextStyle(ts); 238cb93a386Sopenharmony_ci auto ss = toStrutStyle(s.strutStyle); 239cb93a386Sopenharmony_ci ps.setStrutStyle(ss); 240cb93a386Sopenharmony_ci if (s.heightMultiplier != 0) { 241cb93a386Sopenharmony_ci ps.setHeight(s.heightMultiplier); 242cb93a386Sopenharmony_ci } 243cb93a386Sopenharmony_ci if (s.maxLines != 0) { 244cb93a386Sopenharmony_ci ps.setMaxLines(s.maxLines); 245cb93a386Sopenharmony_ci } 246cb93a386Sopenharmony_ci ps.setTextHeightBehavior(s.textHeightBehavior); 247cb93a386Sopenharmony_ci return ps; 248cb93a386Sopenharmony_ci} 249cb93a386Sopenharmony_ci 250cb93a386Sopenharmony_cistruct SimpleTextBox { 251cb93a386Sopenharmony_ci SkRect rect; 252cb93a386Sopenharmony_ci // This isn't the most efficient way to represent this, but it is much easier to keep 253cb93a386Sopenharmony_ci // everything as floats when unpacking on the JS side. 254cb93a386Sopenharmony_ci // 0.0 = RTL, 1.0 = LTr 255cb93a386Sopenharmony_ci SkScalar direction; 256cb93a386Sopenharmony_ci}; 257cb93a386Sopenharmony_ci 258cb93a386Sopenharmony_ciFloat32Array TextBoxesToFloat32Array(std::vector<para::TextBox> boxes) { 259cb93a386Sopenharmony_ci // Pack these text boxes into an array of n groups of 5 SkScalar (floats) 260cb93a386Sopenharmony_ci if (!boxes.size()) { 261cb93a386Sopenharmony_ci return emscripten::val::null(); 262cb93a386Sopenharmony_ci } 263cb93a386Sopenharmony_ci SimpleTextBox* rects = new SimpleTextBox[boxes.size()]; 264cb93a386Sopenharmony_ci for (int i = 0; i < boxes.size(); i++) { 265cb93a386Sopenharmony_ci rects[i].rect = boxes[i].rect; 266cb93a386Sopenharmony_ci if (boxes[i].direction == para::TextDirection::kRtl) { 267cb93a386Sopenharmony_ci rects[i].direction = 0; 268cb93a386Sopenharmony_ci } else { 269cb93a386Sopenharmony_ci rects[i].direction = 1; 270cb93a386Sopenharmony_ci } 271cb93a386Sopenharmony_ci } 272cb93a386Sopenharmony_ci float* fPtr = reinterpret_cast<float*>(rects); 273cb93a386Sopenharmony_ci // Of note: now that we have cast rects to float*, emscripten is smart enough to wrap this 274cb93a386Sopenharmony_ci // into a Float32Array for us. 275cb93a386Sopenharmony_ci return Float32Array(typed_memory_view(boxes.size() * 5, fPtr)); 276cb93a386Sopenharmony_ci} 277cb93a386Sopenharmony_ci 278cb93a386Sopenharmony_ciFloat32Array GetRectsForRange(para::Paragraph& self, 279cb93a386Sopenharmony_ci unsigned start, 280cb93a386Sopenharmony_ci unsigned end, 281cb93a386Sopenharmony_ci para::RectHeightStyle heightStyle, 282cb93a386Sopenharmony_ci para::RectWidthStyle widthStyle) { 283cb93a386Sopenharmony_ci std::vector<para::TextBox> boxes = self.getRectsForRange(start, end, heightStyle, widthStyle); 284cb93a386Sopenharmony_ci return TextBoxesToFloat32Array(boxes); 285cb93a386Sopenharmony_ci} 286cb93a386Sopenharmony_ci 287cb93a386Sopenharmony_ciFloat32Array GetRectsForPlaceholders(para::Paragraph& self) { 288cb93a386Sopenharmony_ci std::vector<para::TextBox> boxes = self.getRectsForPlaceholders(); 289cb93a386Sopenharmony_ci return TextBoxesToFloat32Array(boxes); 290cb93a386Sopenharmony_ci} 291cb93a386Sopenharmony_ci 292cb93a386Sopenharmony_ciJSArray GetLineMetrics(para::Paragraph& self) { 293cb93a386Sopenharmony_ci std::vector<skia::textlayout::LineMetrics> metrics; 294cb93a386Sopenharmony_ci self.getLineMetrics(metrics); 295cb93a386Sopenharmony_ci JSArray result = emscripten::val::array(); 296cb93a386Sopenharmony_ci for (auto metric : metrics) { 297cb93a386Sopenharmony_ci JSObject m = emscripten::val::object(); 298cb93a386Sopenharmony_ci m.set("startIndex", metric.fStartIndex); 299cb93a386Sopenharmony_ci m.set("endIndex", metric.fEndIndex); 300cb93a386Sopenharmony_ci m.set("endExcludingWhitespaces", metric.fEndExcludingWhitespaces); 301cb93a386Sopenharmony_ci m.set("endIncludingNewline", metric.fEndIncludingNewline); 302cb93a386Sopenharmony_ci m.set("isHardBreak", metric.fHardBreak); 303cb93a386Sopenharmony_ci m.set("ascent", metric.fAscent); 304cb93a386Sopenharmony_ci m.set("descent", metric.fDescent); 305cb93a386Sopenharmony_ci m.set("height", metric.fHeight); 306cb93a386Sopenharmony_ci m.set("width", metric.fWidth); 307cb93a386Sopenharmony_ci m.set("left", metric.fLeft); 308cb93a386Sopenharmony_ci m.set("baseline", metric.fBaseline); 309cb93a386Sopenharmony_ci m.set("lineNumber", metric.fLineNumber); 310cb93a386Sopenharmony_ci result.call<void>("push", m); 311cb93a386Sopenharmony_ci } 312cb93a386Sopenharmony_ci return result; 313cb93a386Sopenharmony_ci} 314cb93a386Sopenharmony_ci 315cb93a386Sopenharmony_ci/* 316cb93a386Sopenharmony_ci * Returns Lines[] 317cb93a386Sopenharmony_ci */ 318cb93a386Sopenharmony_ciJSArray GetShapedLines(para::Paragraph& self) { 319cb93a386Sopenharmony_ci struct LineAccumulate { 320cb93a386Sopenharmony_ci int lineNumber = -1; // deliberately -1 from starting value 321cb93a386Sopenharmony_ci uint32_t minOffset = 0xFFFFFFFF; 322cb93a386Sopenharmony_ci uint32_t maxOffset = 0; 323cb93a386Sopenharmony_ci float minAscent = 0; 324cb93a386Sopenharmony_ci float maxDescent = 0; 325cb93a386Sopenharmony_ci // not really accumulated, but definitely set 326cb93a386Sopenharmony_ci float baseline = 0; 327cb93a386Sopenharmony_ci 328cb93a386Sopenharmony_ci void reset(int lineNumber) { 329cb93a386Sopenharmony_ci new (this) LineAccumulate; 330cb93a386Sopenharmony_ci this->lineNumber = lineNumber; 331cb93a386Sopenharmony_ci } 332cb93a386Sopenharmony_ci }; 333cb93a386Sopenharmony_ci 334cb93a386Sopenharmony_ci // where we accumulate our js output 335cb93a386Sopenharmony_ci JSArray jlines = emscripten::val::array(); 336cb93a386Sopenharmony_ci JSObject jline = emscripten::val::null(); 337cb93a386Sopenharmony_ci JSArray jruns = emscripten::val::null(); 338cb93a386Sopenharmony_ci LineAccumulate accum; 339cb93a386Sopenharmony_ci 340cb93a386Sopenharmony_ci self.visit([&](int lineNumber, const para::Paragraph::VisitorInfo* info) { 341cb93a386Sopenharmony_ci if (!info) { 342cb93a386Sopenharmony_ci if (!jline) return; // how??? 343cb93a386Sopenharmony_ci // end of current line 344cb93a386Sopenharmony_ci JSObject range = emscripten::val::object(); 345cb93a386Sopenharmony_ci range.set("first", accum.minOffset); 346cb93a386Sopenharmony_ci range.set("last", accum.maxOffset); 347cb93a386Sopenharmony_ci jline.set("textRange", range); 348cb93a386Sopenharmony_ci 349cb93a386Sopenharmony_ci jline.set("top", accum.baseline + accum.minAscent); 350cb93a386Sopenharmony_ci jline.set("bottom", accum.baseline + accum.maxDescent); 351cb93a386Sopenharmony_ci jline.set("baseline", accum.baseline); 352cb93a386Sopenharmony_ci return; 353cb93a386Sopenharmony_ci } 354cb93a386Sopenharmony_ci 355cb93a386Sopenharmony_ci if (lineNumber != accum.lineNumber) { 356cb93a386Sopenharmony_ci SkASSERT(lineNumber == accum.lineNumber + 1); // assume monotonic 357cb93a386Sopenharmony_ci 358cb93a386Sopenharmony_ci accum.reset(lineNumber); 359cb93a386Sopenharmony_ci jruns = emscripten::val::array(); 360cb93a386Sopenharmony_ci 361cb93a386Sopenharmony_ci jline = emscripten::val::object(); 362cb93a386Sopenharmony_ci jline.set("runs", jruns); 363cb93a386Sopenharmony_ci // will assign textRange and metrics on end-of-line signal 364cb93a386Sopenharmony_ci 365cb93a386Sopenharmony_ci jlines.call<void>("push", jline); 366cb93a386Sopenharmony_ci } 367cb93a386Sopenharmony_ci 368cb93a386Sopenharmony_ci // append the run 369cb93a386Sopenharmony_ci const int N = info->count; // glyphs 370cb93a386Sopenharmony_ci const int N1 = N + 1; // positions, offsets have 1 extra (trailing) slot 371cb93a386Sopenharmony_ci 372cb93a386Sopenharmony_ci JSObject jrun = emscripten::val::object(); 373cb93a386Sopenharmony_ci 374cb93a386Sopenharmony_ci jrun.set("flags", info->flags); 375cb93a386Sopenharmony_ci 376cb93a386Sopenharmony_ci// TODO: figure out how to set a wrapped sk_sp<SkTypeface> 377cb93a386Sopenharmony_ci// jrun.set("typeface", info->font.getTypeface()); 378cb93a386Sopenharmony_ci jrun.set("typeface", emscripten::val::null()); 379cb93a386Sopenharmony_ci jrun.set("size", info->font.getSize()); 380cb93a386Sopenharmony_ci if (info->font.getScaleX()) { 381cb93a386Sopenharmony_ci jrun.set("scaleX", info->font.getScaleX()); 382cb93a386Sopenharmony_ci } 383cb93a386Sopenharmony_ci 384cb93a386Sopenharmony_ci jrun.set("glyphs", MakeTypedArray(N, info->glyphs)); 385cb93a386Sopenharmony_ci jrun.set("offsets", MakeTypedArray(N1, info->utf8Starts)); 386cb93a386Sopenharmony_ci 387cb93a386Sopenharmony_ci // we need to modify the positions, so make a temp copy 388cb93a386Sopenharmony_ci SkAutoSTMalloc<32, SkPoint> positions(N1); 389cb93a386Sopenharmony_ci for (int i = 0; i < N; ++i) { 390cb93a386Sopenharmony_ci positions.get()[i] = info->positions[i] + info->origin; 391cb93a386Sopenharmony_ci } 392cb93a386Sopenharmony_ci positions.get()[N] = { info->advanceX, positions.get()[N - 1].fY }; 393cb93a386Sopenharmony_ci jrun.set("positions", MakeTypedArray(N1*2, (const float*)positions.get())); 394cb93a386Sopenharmony_ci 395cb93a386Sopenharmony_ci jruns.call<void>("push", jrun); 396cb93a386Sopenharmony_ci 397cb93a386Sopenharmony_ci // update accum 398cb93a386Sopenharmony_ci { SkFontMetrics fm; 399cb93a386Sopenharmony_ci info->font.getMetrics(&fm); 400cb93a386Sopenharmony_ci 401cb93a386Sopenharmony_ci accum.minAscent = std::min(accum.minAscent, fm.fAscent); 402cb93a386Sopenharmony_ci accum.maxDescent = std::max(accum.maxDescent, fm.fDescent); 403cb93a386Sopenharmony_ci accum.baseline = info->origin.fY; 404cb93a386Sopenharmony_ci 405cb93a386Sopenharmony_ci accum.minOffset = std::min(accum.minOffset, info->utf8Starts[0]); 406cb93a386Sopenharmony_ci accum.maxOffset = std::max(accum.maxOffset, info->utf8Starts[N]); 407cb93a386Sopenharmony_ci } 408cb93a386Sopenharmony_ci 409cb93a386Sopenharmony_ci }); 410cb93a386Sopenharmony_ci return jlines; 411cb93a386Sopenharmony_ci} 412cb93a386Sopenharmony_ci 413cb93a386Sopenharmony_ciEMSCRIPTEN_BINDINGS(Paragraph) { 414cb93a386Sopenharmony_ci 415cb93a386Sopenharmony_ci class_<para::Paragraph>("Paragraph") 416cb93a386Sopenharmony_ci .function("didExceedMaxLines", ¶::Paragraph::didExceedMaxLines) 417cb93a386Sopenharmony_ci .function("getAlphabeticBaseline", ¶::Paragraph::getAlphabeticBaseline) 418cb93a386Sopenharmony_ci .function("getGlyphPositionAtCoordinate", ¶::Paragraph::getGlyphPositionAtCoordinate) 419cb93a386Sopenharmony_ci .function("getHeight", ¶::Paragraph::getHeight) 420cb93a386Sopenharmony_ci .function("getIdeographicBaseline", ¶::Paragraph::getIdeographicBaseline) 421cb93a386Sopenharmony_ci .function("getLineMetrics", &GetLineMetrics) 422cb93a386Sopenharmony_ci .function("getLongestLine", ¶::Paragraph::getLongestLine) 423cb93a386Sopenharmony_ci .function("getMaxIntrinsicWidth", ¶::Paragraph::getMaxIntrinsicWidth) 424cb93a386Sopenharmony_ci .function("getMaxWidth", ¶::Paragraph::getMaxWidth) 425cb93a386Sopenharmony_ci .function("getMinIntrinsicWidth", ¶::Paragraph::getMinIntrinsicWidth) 426cb93a386Sopenharmony_ci .function("_getRectsForPlaceholders", &GetRectsForPlaceholders) 427cb93a386Sopenharmony_ci .function("_getRectsForRange", &GetRectsForRange) 428cb93a386Sopenharmony_ci .function("getShapedLines", &GetShapedLines) 429cb93a386Sopenharmony_ci .function("getWordBoundary", ¶::Paragraph::getWordBoundary) 430cb93a386Sopenharmony_ci .function("layout", ¶::Paragraph::layout); 431cb93a386Sopenharmony_ci 432cb93a386Sopenharmony_ci class_<para::ParagraphBuilderImpl>("ParagraphBuilder") 433cb93a386Sopenharmony_ci .class_function( 434cb93a386Sopenharmony_ci "_Make", 435cb93a386Sopenharmony_ci optional_override([](SimpleParagraphStyle style, sk_sp<SkFontMgr> fontMgr) 436cb93a386Sopenharmony_ci -> std::unique_ptr<para::ParagraphBuilderImpl> { 437cb93a386Sopenharmony_ci auto fc = sk_make_sp<para::FontCollection>(); 438cb93a386Sopenharmony_ci fc->setDefaultFontManager(fontMgr); 439cb93a386Sopenharmony_ci fc->enableFontFallback(); 440cb93a386Sopenharmony_ci auto ps = toParagraphStyle(style); 441cb93a386Sopenharmony_ci auto pb = para::ParagraphBuilderImpl::make(ps, fc); 442cb93a386Sopenharmony_ci return std::unique_ptr<para::ParagraphBuilderImpl>( 443cb93a386Sopenharmony_ci static_cast<para::ParagraphBuilderImpl*>(pb.release())); 444cb93a386Sopenharmony_ci }), 445cb93a386Sopenharmony_ci allow_raw_pointers()) 446cb93a386Sopenharmony_ci .class_function( 447cb93a386Sopenharmony_ci "_MakeFromFontProvider", 448cb93a386Sopenharmony_ci optional_override([](SimpleParagraphStyle style, 449cb93a386Sopenharmony_ci sk_sp<para::TypefaceFontProvider> fontProvider) 450cb93a386Sopenharmony_ci -> std::unique_ptr<para::ParagraphBuilderImpl> { 451cb93a386Sopenharmony_ci auto fc = sk_make_sp<para::FontCollection>(); 452cb93a386Sopenharmony_ci fc->setDefaultFontManager(fontProvider); 453cb93a386Sopenharmony_ci fc->enableFontFallback(); 454cb93a386Sopenharmony_ci auto ps = toParagraphStyle(style); 455cb93a386Sopenharmony_ci auto pb = para::ParagraphBuilderImpl::make(ps, fc); 456cb93a386Sopenharmony_ci return std::unique_ptr<para::ParagraphBuilderImpl>( 457cb93a386Sopenharmony_ci static_cast<para::ParagraphBuilderImpl*>(pb.release())); 458cb93a386Sopenharmony_ci }), 459cb93a386Sopenharmony_ci allow_raw_pointers()) 460cb93a386Sopenharmony_ci .class_function( 461cb93a386Sopenharmony_ci "_ShapeText", 462cb93a386Sopenharmony_ci optional_override([](JSString jtext, JSArray jruns, float width) -> JSArray { 463cb93a386Sopenharmony_ci std::string textStorage = jtext.as<std::string>(); 464cb93a386Sopenharmony_ci const char* text = textStorage.data(); 465cb93a386Sopenharmony_ci size_t textCount = textStorage.size(); 466cb93a386Sopenharmony_ci 467cb93a386Sopenharmony_ci auto fc = sk_make_sp<para::FontCollection>(); 468cb93a386Sopenharmony_ci fc->setDefaultFontManager(SkFontMgr::RefDefault()); 469cb93a386Sopenharmony_ci fc->enableFontFallback(); 470cb93a386Sopenharmony_ci 471cb93a386Sopenharmony_ci para::ParagraphStyle pstyle; 472cb93a386Sopenharmony_ci { 473cb93a386Sopenharmony_ci // For the most part this is ignored, since we set an explicit TextStyle 474cb93a386Sopenharmony_ci // for all of our text runs, but it is required by SkParagraph. 475cb93a386Sopenharmony_ci para::TextStyle style; 476cb93a386Sopenharmony_ci style.setFontFamilies({SkString("sans-serif")}); 477cb93a386Sopenharmony_ci style.setFontSize(32); 478cb93a386Sopenharmony_ci pstyle.setTextStyle(style); 479cb93a386Sopenharmony_ci } 480cb93a386Sopenharmony_ci 481cb93a386Sopenharmony_ci auto pb = para::ParagraphBuilder::make(pstyle, fc); 482cb93a386Sopenharmony_ci 483cb93a386Sopenharmony_ci // tease apart the FontBlock runs 484cb93a386Sopenharmony_ci size_t runCount = jruns["length"].as<size_t>(); 485cb93a386Sopenharmony_ci for (size_t i = 0; i < runCount; ++i) { 486cb93a386Sopenharmony_ci emscripten::val r = jruns[i]; 487cb93a386Sopenharmony_ci 488cb93a386Sopenharmony_ci para::TextStyle style; 489cb93a386Sopenharmony_ci style.setTypeface(r["typeface"].as< sk_sp<SkTypeface> >()); 490cb93a386Sopenharmony_ci style.setFontSize(r["size"].as<float>()); 491cb93a386Sopenharmony_ci 492cb93a386Sopenharmony_ci const size_t subTextCount = r["length"].as<size_t>(); 493cb93a386Sopenharmony_ci if (subTextCount > textCount) { 494cb93a386Sopenharmony_ci return emscripten::val("block runs exceed text length!"); 495cb93a386Sopenharmony_ci } 496cb93a386Sopenharmony_ci 497cb93a386Sopenharmony_ci pb->pushStyle(style); 498cb93a386Sopenharmony_ci pb->addText(text, subTextCount); 499cb93a386Sopenharmony_ci pb->pop(); 500cb93a386Sopenharmony_ci 501cb93a386Sopenharmony_ci text += subTextCount; 502cb93a386Sopenharmony_ci textCount -= subTextCount; 503cb93a386Sopenharmony_ci } 504cb93a386Sopenharmony_ci if (textCount != 0) { 505cb93a386Sopenharmony_ci return emscripten::val("Didn't have enough block runs to cover text"); 506cb93a386Sopenharmony_ci } 507cb93a386Sopenharmony_ci 508cb93a386Sopenharmony_ci auto pa = pb->Build(); 509cb93a386Sopenharmony_ci pa->layout(width); 510cb93a386Sopenharmony_ci 511cb93a386Sopenharmony_ci // workaround until this is fixed in SkParagraph 512cb93a386Sopenharmony_ci { 513cb93a386Sopenharmony_ci SkPictureRecorder rec; 514cb93a386Sopenharmony_ci pa->paint(rec.beginRecording({0,0,9999,9999}), 0, 0); 515cb93a386Sopenharmony_ci } 516cb93a386Sopenharmony_ci return GetShapedLines(*pa); 517cb93a386Sopenharmony_ci }), 518cb93a386Sopenharmony_ci allow_raw_pointers()) 519cb93a386Sopenharmony_ci .function("addText", 520cb93a386Sopenharmony_ci optional_override([](para::ParagraphBuilderImpl& self, std::string text) { 521cb93a386Sopenharmony_ci return self.addText(text.c_str(), text.length()); 522cb93a386Sopenharmony_ci })) 523cb93a386Sopenharmony_ci .function("build", ¶::ParagraphBuilderImpl::Build, allow_raw_pointers()) 524cb93a386Sopenharmony_ci .function("pop", ¶::ParagraphBuilderImpl::pop) 525cb93a386Sopenharmony_ci .function("_pushStyle", optional_override([](para::ParagraphBuilderImpl& self, 526cb93a386Sopenharmony_ci SimpleTextStyle textStyle) { 527cb93a386Sopenharmony_ci auto ts = toTextStyle(textStyle); 528cb93a386Sopenharmony_ci self.pushStyle(ts); 529cb93a386Sopenharmony_ci })) 530cb93a386Sopenharmony_ci // A method of pushing a textStyle with paints instead of colors for foreground and 531cb93a386Sopenharmony_ci // background. Since SimpleTextStyle is a value object, it cannot contain paints, which 532cb93a386Sopenharmony_ci // are not primitives. This binding is here to accept them. Any color that is specified 533cb93a386Sopenharmony_ci // in the textStyle is overridden. 534cb93a386Sopenharmony_ci .function("_pushPaintStyle", 535cb93a386Sopenharmony_ci optional_override([](para::ParagraphBuilderImpl& self, 536cb93a386Sopenharmony_ci SimpleTextStyle textStyle, SkPaint foreground, 537cb93a386Sopenharmony_ci SkPaint background) { 538cb93a386Sopenharmony_ci auto ts = toTextStyle(textStyle); 539cb93a386Sopenharmony_ci ts.setForegroundColor(foreground); 540cb93a386Sopenharmony_ci ts.setBackgroundColor(background); 541cb93a386Sopenharmony_ci self.pushStyle(ts); 542cb93a386Sopenharmony_ci })) 543cb93a386Sopenharmony_ci .function("_addPlaceholder", optional_override([](para::ParagraphBuilderImpl& self, 544cb93a386Sopenharmony_ci SkScalar width, 545cb93a386Sopenharmony_ci SkScalar height, 546cb93a386Sopenharmony_ci para::PlaceholderAlignment alignment, 547cb93a386Sopenharmony_ci para::TextBaseline baseline, 548cb93a386Sopenharmony_ci SkScalar offset) { 549cb93a386Sopenharmony_ci para::PlaceholderStyle ps(width, height, alignment, baseline, offset); 550cb93a386Sopenharmony_ci self.addPlaceholder(ps); 551cb93a386Sopenharmony_ci })); 552cb93a386Sopenharmony_ci 553cb93a386Sopenharmony_ci class_<para::TypefaceFontProvider, base<SkFontMgr>>("TypefaceFontProvider") 554cb93a386Sopenharmony_ci .smart_ptr<sk_sp<para::TypefaceFontProvider>>("sk_sp<TypefaceFontProvider>") 555cb93a386Sopenharmony_ci .class_function("Make", optional_override([]()-> sk_sp<para::TypefaceFontProvider> { 556cb93a386Sopenharmony_ci return sk_make_sp<para::TypefaceFontProvider>(); 557cb93a386Sopenharmony_ci })) 558cb93a386Sopenharmony_ci .function("_registerFont", optional_override([](para::TypefaceFontProvider& self, 559cb93a386Sopenharmony_ci sk_sp<SkTypeface> typeface, 560cb93a386Sopenharmony_ci WASMPointerU8 familyPtr) { 561cb93a386Sopenharmony_ci const char* fPtr = reinterpret_cast<const char*>(familyPtr); 562cb93a386Sopenharmony_ci SkString fStr(fPtr); 563cb93a386Sopenharmony_ci self.registerTypeface(typeface, fStr); 564cb93a386Sopenharmony_ci }), allow_raw_pointers()); 565cb93a386Sopenharmony_ci 566cb93a386Sopenharmony_ci 567cb93a386Sopenharmony_ci // These value objects make it easier to send data across the wire. 568cb93a386Sopenharmony_ci value_object<para::PositionWithAffinity>("PositionWithAffinity") 569cb93a386Sopenharmony_ci .field("pos", ¶::PositionWithAffinity::position) 570cb93a386Sopenharmony_ci .field("affinity", ¶::PositionWithAffinity::affinity); 571cb93a386Sopenharmony_ci 572cb93a386Sopenharmony_ci value_object<SimpleFontStyle>("FontStyle") 573cb93a386Sopenharmony_ci .field("slant", &SimpleFontStyle::slant) 574cb93a386Sopenharmony_ci .field("weight", &SimpleFontStyle::weight) 575cb93a386Sopenharmony_ci .field("width", &SimpleFontStyle::width); 576cb93a386Sopenharmony_ci 577cb93a386Sopenharmony_ci value_object<SimpleParagraphStyle>("ParagraphStyle") 578cb93a386Sopenharmony_ci .field("disableHinting", &SimpleParagraphStyle::disableHinting) 579cb93a386Sopenharmony_ci .field("_ellipsisPtr", &SimpleParagraphStyle::ellipsisPtr) 580cb93a386Sopenharmony_ci .field("_ellipsisLen", &SimpleParagraphStyle::ellipsisLen) 581cb93a386Sopenharmony_ci .field("heightMultiplier", &SimpleParagraphStyle::heightMultiplier) 582cb93a386Sopenharmony_ci .field("maxLines", &SimpleParagraphStyle::maxLines) 583cb93a386Sopenharmony_ci .field("textAlign", &SimpleParagraphStyle::textAlign) 584cb93a386Sopenharmony_ci .field("textDirection", &SimpleParagraphStyle::textDirection) 585cb93a386Sopenharmony_ci .field("textHeightBehavior", &SimpleParagraphStyle::textHeightBehavior) 586cb93a386Sopenharmony_ci .field("textStyle", &SimpleParagraphStyle::textStyle) 587cb93a386Sopenharmony_ci .field("strutStyle", &SimpleParagraphStyle::strutStyle); 588cb93a386Sopenharmony_ci 589cb93a386Sopenharmony_ci value_object<SimpleStrutStyle>("StrutStyle") 590cb93a386Sopenharmony_ci .field("_fontFamiliesPtr", &SimpleStrutStyle::fontFamiliesPtr) 591cb93a386Sopenharmony_ci .field("_fontFamiliesLen", &SimpleStrutStyle::fontFamiliesLen) 592cb93a386Sopenharmony_ci .field("strutEnabled", &SimpleStrutStyle::strutEnabled) 593cb93a386Sopenharmony_ci .field("fontSize", &SimpleStrutStyle::fontSize) 594cb93a386Sopenharmony_ci .field("fontStyle", &SimpleStrutStyle::fontStyle) 595cb93a386Sopenharmony_ci .field("heightMultiplier", &SimpleStrutStyle::heightMultiplier) 596cb93a386Sopenharmony_ci .field("halfLeading", &SimpleStrutStyle::halfLeading) 597cb93a386Sopenharmony_ci .field("leading", &SimpleStrutStyle::leading) 598cb93a386Sopenharmony_ci .field("forceStrutHeight", &SimpleStrutStyle::forceStrutHeight); 599cb93a386Sopenharmony_ci 600cb93a386Sopenharmony_ci value_object<SimpleTextStyle>("TextStyle") 601cb93a386Sopenharmony_ci .field("_colorPtr", &SimpleTextStyle::colorPtr) 602cb93a386Sopenharmony_ci .field("_foregroundColorPtr", &SimpleTextStyle::foregroundColorPtr) 603cb93a386Sopenharmony_ci .field("_backgroundColorPtr", &SimpleTextStyle::backgroundColorPtr) 604cb93a386Sopenharmony_ci .field("decoration", &SimpleTextStyle::decoration) 605cb93a386Sopenharmony_ci .field("decorationThickness", &SimpleTextStyle::decorationThickness) 606cb93a386Sopenharmony_ci .field("_decorationColorPtr", &SimpleTextStyle::decorationColorPtr) 607cb93a386Sopenharmony_ci .field("decorationStyle", &SimpleTextStyle::decorationStyle) 608cb93a386Sopenharmony_ci .field("_fontFamiliesPtr", &SimpleTextStyle::fontFamiliesPtr) 609cb93a386Sopenharmony_ci .field("_fontFamiliesLen", &SimpleTextStyle::fontFamiliesLen) 610cb93a386Sopenharmony_ci .field("fontSize", &SimpleTextStyle::fontSize) 611cb93a386Sopenharmony_ci .field("letterSpacing", &SimpleTextStyle::letterSpacing) 612cb93a386Sopenharmony_ci .field("wordSpacing", &SimpleTextStyle::wordSpacing) 613cb93a386Sopenharmony_ci .field("heightMultiplier", &SimpleTextStyle::heightMultiplier) 614cb93a386Sopenharmony_ci .field("halfLeading", &SimpleTextStyle::halfLeading) 615cb93a386Sopenharmony_ci .field("_localePtr", &SimpleTextStyle::localePtr) 616cb93a386Sopenharmony_ci .field("_localeLen", &SimpleTextStyle::localeLen) 617cb93a386Sopenharmony_ci .field("fontStyle", &SimpleTextStyle::fontStyle) 618cb93a386Sopenharmony_ci .field("_shadowLen", &SimpleTextStyle::shadowLen) 619cb93a386Sopenharmony_ci .field("_shadowColorsPtr", &SimpleTextStyle::shadowColorsPtr) 620cb93a386Sopenharmony_ci .field("_shadowOffsetsPtr", &SimpleTextStyle::shadowOffsetsPtr) 621cb93a386Sopenharmony_ci .field("_shadowBlurRadiiPtr", &SimpleTextStyle::shadowBlurRadiiPtr) 622cb93a386Sopenharmony_ci .field("_fontFeatureLen", &SimpleTextStyle::fontFeatureLen) 623cb93a386Sopenharmony_ci .field("_fontFeatureNamesPtr", &SimpleTextStyle::fontFeatureNamesPtr) 624cb93a386Sopenharmony_ci .field("_fontFeatureValuesPtr", &SimpleTextStyle::fontFeatureValuesPtr); 625cb93a386Sopenharmony_ci 626cb93a386Sopenharmony_ci // The U stands for unsigned - we can't bind a generic/template object, so we have to specify it 627cb93a386Sopenharmony_ci // with the type we are using. 628cb93a386Sopenharmony_ci // TODO(kjlubick) make this a typedarray. 629cb93a386Sopenharmony_ci value_object<para::SkRange<size_t>>("URange") 630cb93a386Sopenharmony_ci .field("start", ¶::SkRange<size_t>::start) 631cb93a386Sopenharmony_ci .field("end", ¶::SkRange<size_t>::end); 632cb93a386Sopenharmony_ci 633cb93a386Sopenharmony_ci // TextDecoration should be a const because they can be combined 634cb93a386Sopenharmony_ci constant("NoDecoration", int(para::TextDecoration::kNoDecoration)); 635cb93a386Sopenharmony_ci constant("UnderlineDecoration", int(para::TextDecoration::kUnderline)); 636cb93a386Sopenharmony_ci constant("OverlineDecoration", int(para::TextDecoration::kOverline)); 637cb93a386Sopenharmony_ci constant("LineThroughDecoration", int(para::TextDecoration::kLineThrough)); 638cb93a386Sopenharmony_ci} 639