Expose Paragraph.unresolvedCodepoints

Change-Id: I64afafc054503d1deb36e111681f275b85ac1e1d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/702336
Reviewed-by: Julia Lavrova <jlavrova@google.com>
diff --git a/modules/canvaskit/CHANGELOG.md b/modules/canvaskit/CHANGELOG.md
index 8d6fba1..c26d83b 100644
--- a/modules/canvaskit/CHANGELOG.md
+++ b/modules/canvaskit/CHANGELOG.md
@@ -6,6 +6,10 @@
 
 ## [Unreleased]
 
+### Added
+ - `Paragraph.unresolvedCodepoints` which allows clients to identify gaps in font coverage
+    more easily.
+
 ## [0.38.1] - 2023-05-02
 
 ### Removed
diff --git a/modules/canvaskit/npm_build/types/canvaskit-wasm-tests.ts b/modules/canvaskit/npm_build/types/canvaskit-wasm-tests.ts
index a7c3143..93aeeb5 100644
--- a/modules/canvaskit/npm_build/types/canvaskit-wasm-tests.ts
+++ b/modules/canvaskit/npm_build/types/canvaskit-wasm-tests.ts
@@ -557,6 +557,7 @@
     p.layout(300);
     const m = p.getLineMetrics(); // $ExpectType LineMetrics[]
     const n = CK.GlyphRunFlags.IsWhiteSpace === 1;
+    const o = p.unresolvedCodepoints(); // $ExpectType number[]
 }
 
 function paragraphBuilderTests(CK: CanvasKit, fontMgr?: FontMgr, paint?: Paint) {
diff --git a/modules/canvaskit/npm_build/types/index.d.ts b/modules/canvaskit/npm_build/types/index.d.ts
index 1fa34a6..f70e68c 100644
--- a/modules/canvaskit/npm_build/types/index.d.ts
+++ b/modules/canvaskit/npm_build/types/index.d.ts
@@ -998,6 +998,12 @@
      * @param width
      */
     layout(width: number): void;
+
+    /**
+     * When called after shaping, returns the glyph IDs which were not matched
+     * by any of the provided fonts.
+     */
+    unresolvedCodepoints(): number[];
 }
 
 export interface ParagraphBuilder extends EmbindObject<ParagraphBuilder> {
diff --git a/modules/canvaskit/paragraph_bindings.cpp b/modules/canvaskit/paragraph_bindings.cpp
index 2727171..51f6761 100644
--- a/modules/canvaskit/paragraph_bindings.cpp
+++ b/modules/canvaskit/paragraph_bindings.cpp
@@ -447,6 +447,14 @@
     return vec;
 }
 
+JSArray UnresolvedCodepoints(para::Paragraph& self) {
+    JSArray result = emscripten::val::array();
+    for (auto cp : self.unresolvedCodepoints()) {
+        result.call<void>("push", cp);
+    }
+    return result;
+}
+
 EMSCRIPTEN_BINDINGS(Paragraph) {
 
     class_<para::Paragraph>("Paragraph")
@@ -464,7 +472,8 @@
         .function("_getRectsForRange", &GetRectsForRange)
         .function("getShapedLines", &GetShapedLines)
         .function("getWordBoundary", &para::Paragraph::getWordBoundary)
-        .function("layout", &para::Paragraph::layout);
+        .function("layout", &para::Paragraph::layout)
+        .function("unresolvedCodepoints", &UnresolvedCodepoints);
 
     class_<para::ParagraphBuilderImpl>("ParagraphBuilder")
             .class_function(
diff --git a/modules/canvaskit/tests/paragraph_test.js b/modules/canvaskit/tests/paragraph_test.js
index 4bb22c2..73cfe46 100644
--- a/modules/canvaskit/tests/paragraph_test.js
+++ b/modules/canvaskit/tests/paragraph_test.js
@@ -129,6 +129,9 @@
         expect(flm.left).toBeCloseTo(13.818, 3);
         expect(flm.baseline).toBeCloseTo(21.141, 3);
 
+        const unresolvedGlyphs = paragraph.unresolvedCodepoints();
+        expect(unresolvedGlyphs.length).toEqual(0, unresolvedGlyphs);
+
         canvas.drawRect(CanvasKit.LTRBRect(10, 10, wrapTo+10, 230), paint);
         canvas.drawParagraph(paragraph, 10, 10);