Update TextShaper APIs to address API council feedback

This CL contains followings:
- Rename TextShaper to TextRunShaper, StyledTextShaper to TextShaper
- Renamed getTotalAdvance to getAdvance
- Rename getStyle to getGlyphStyle
- Rename getOriginX/Y to getOffsetX/Y
- Rename getPositionX/Y to getGlyphX/Y
- Fixed some documentation errors.
- Remvoed GlyphStyle. Added GlyphConsumer instead.

Bug: 170255480
Test: atest TextShaperRunTest GlyphStyleTest TextShaperTest

Change-Id: I0ffd7a3374e9cd1e04872240c2d0da26bc530244
diff --git a/api/current.txt b/api/current.txt
index a550bf8..1c20e78 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16525,23 +16525,6 @@
 
 package android.graphics.text {
 
-  public class GlyphStyle {
-    ctor public GlyphStyle(@ColorInt int, @FloatRange(from=0) float, @FloatRange(from=0) float, @FloatRange(from=0) float, int);
-    ctor public GlyphStyle(@NonNull android.graphics.Paint);
-    method public void applyToPaint(@NonNull android.graphics.Paint);
-    method @ColorInt public int getColor();
-    method public int getFlags();
-    method @FloatRange(from=0) public float getFontSize();
-    method @FloatRange(from=0) public float getScaleX();
-    method @FloatRange(from=0) public float getSkewX();
-    method public void setColor(@ColorInt int);
-    method public void setFlags(int);
-    method public void setFontSize(@FloatRange(from=0) float);
-    method public void setFromPaint(@NonNull android.graphics.Paint);
-    method public void setScaleX(@FloatRange(from=0) float);
-    method public void setSkewX(@FloatRange(from=0) float);
-  }
-
   public class LineBreaker {
     method @NonNull public android.graphics.text.LineBreaker.Result computeLineBreaks(@NonNull android.graphics.text.MeasuredText, @NonNull android.graphics.text.LineBreaker.ParagraphConstraints, @IntRange(from=0) int);
     field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
@@ -16603,20 +16586,19 @@
   }
 
   public final class PositionedGlyphs {
+    method public float getAdvance();
     method public float getAscent();
     method public float getDescent();
     method @NonNull public android.graphics.fonts.Font getFont(@IntRange(from=0) int);
     method @IntRange(from=0) public int getGlyphId(@IntRange(from=0) int);
-    method public float getOriginX();
-    method public float getOriginY();
-    method public float getPositionX(@IntRange(from=0) int);
-    method public float getPositionY(@IntRange(from=0) int);
-    method @NonNull public android.graphics.text.GlyphStyle getStyle();
-    method public float getTotalAdvance();
+    method public float getGlyphX(@IntRange(from=0) int);
+    method public float getGlyphY(@IntRange(from=0) int);
+    method public float getOffsetX();
+    method public float getOffsetY();
     method @IntRange(from=0) public int glyphCount();
   }
 
-  public class TextShaper {
+  public class TextRunShaper {
     method @NonNull public static android.graphics.text.PositionedGlyphs shapeTextRun(@NonNull char[], int, int, int, int, float, float, boolean, @NonNull android.graphics.Paint);
     method @NonNull public static android.graphics.text.PositionedGlyphs shapeTextRun(@NonNull CharSequence, int, int, int, int, float, float, boolean, @NonNull android.graphics.Paint);
   }
@@ -50059,10 +50041,6 @@
     method @NonNull public android.text.StaticLayout.Builder setUseLineSpacingFromFallbacks(boolean);
   }
 
-  public class StyledTextShaper {
-    method @NonNull public static java.util.List<android.graphics.text.PositionedGlyphs> shapeText(@NonNull CharSequence, int, int, @NonNull android.text.TextDirectionHeuristic, @NonNull android.text.TextPaint);
-  }
-
   public interface TextDirectionHeuristic {
     method public boolean isRtl(char[], int, int);
     method public boolean isRtl(CharSequence, int, int);
@@ -50092,6 +50070,14 @@
     field @Px public float underlineThickness;
   }
 
+  public class TextShaper {
+    method public static void shapeText(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.text.TextDirectionHeuristic, @NonNull android.text.TextPaint, @NonNull android.text.TextShaper.GlyphsConsumer);
+  }
+
+  public static interface TextShaper.GlyphsConsumer {
+    method public void accept(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.text.PositionedGlyphs, @NonNull android.text.TextPaint);
+  }
+
   public class TextUtils {
     method @Deprecated public static CharSequence commaEllipsize(CharSequence, android.text.TextPaint, float, String, String);
     method public static CharSequence concat(java.lang.CharSequence...);
diff --git a/core/java/android/text/StyledTextShaper.java b/core/java/android/text/StyledTextShaper.java
deleted file mode 100644
index bf90614..0000000
--- a/core/java/android/text/StyledTextShaper.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.text;
-
-import android.annotation.NonNull;
-import android.graphics.Paint;
-import android.graphics.text.PositionedGlyphs;
-import android.graphics.text.TextShaper;
-
-import java.util.List;
-
-/**
- * Provides text shaping for multi-styled text.
- *
- * @see TextShaper#shapeTextRun(char[], int, int, int, int, float, float, boolean, Paint)
- * @see TextShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)
- * @see StyledTextShaper#shapeText(CharSequence, int, int, TextDirectionHeuristic, TextPaint)
- */
-public class StyledTextShaper {
-    private StyledTextShaper() {}
-
-
-    /**
-     * Shape multi-styled text.
-     *
-     * @param text a styled text.
-     * @param start a start index of shaping target in the text.
-     * @param count a length of shaping target in the text.
-     * @param dir a text direction.
-     * @param paint a paint
-     * @return a shape result.
-     */
-    public static @NonNull List<PositionedGlyphs> shapeText(
-            @NonNull CharSequence text, int start, int count,
-            @NonNull TextDirectionHeuristic dir, @NonNull TextPaint paint) {
-        MeasuredParagraph mp = MeasuredParagraph.buildForBidi(
-                text, start, start + count, dir, null);
-        TextLine tl = TextLine.obtain();
-        try {
-            tl.set(paint, text, start, start + count,
-                    mp.getParagraphDir(),
-                    mp.getDirections(start, start + count),
-                    false /* tabstop is not supported */,
-                    null,
-                    -1, -1 // ellipsis is not supported.
-            );
-            return tl.shape();
-        } finally {
-            TextLine.recycle(tl);
-        }
-    }
-
-}
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index b826832..4471056 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -24,7 +24,7 @@
 import android.graphics.Paint;
 import android.graphics.Paint.FontMetricsInt;
 import android.graphics.text.PositionedGlyphs;
-import android.graphics.text.TextShaper;
+import android.graphics.text.TextRunShaper;
 import android.os.Build;
 import android.text.Layout.Directions;
 import android.text.Layout.TabStops;
@@ -37,7 +37,6 @@
 import com.android.internal.util.ArrayUtils;
 
 import java.util.ArrayList;
-import java.util.List;
 
 /**
  * Represents a line of styled text, for measuring in visual order and
@@ -312,8 +311,7 @@
     /**
      * Shape the TextLine.
      */
-    List<PositionedGlyphs> shape() {
-        List<PositionedGlyphs> glyphs = new ArrayList<>();
+    void shape(TextShaper.GlyphsConsumer consumer) {
         float horizontal = 0;
         float x = 0;
         final int runCount = mDirections.getRunCount();
@@ -326,7 +324,7 @@
             int segStart = runStart;
             for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
                 if (j == runLimit || charAt(j) == TAB_CHAR) {
-                    horizontal += shapeRun(glyphs, segStart, j, runIsRtl, x + horizontal,
+                    horizontal += shapeRun(consumer, segStart, j, runIsRtl, x + horizontal,
                             runIndex != (runCount - 1) || j != mLen);
 
                     if (j != runLimit) {  // charAt(j) == TAB_CHAR
@@ -336,7 +334,6 @@
                 }
             }
         }
-        return glyphs;
     }
 
     /**
@@ -546,7 +543,7 @@
     /**
      * Shape a unidirectional (but possibly multi-styled) run of text.
      *
-     * @param glyphs the output positioned glyphs list
+     * @param consumer the consumer of the shape result
      * @param start the line-relative start
      * @param limit the line-relative limit
      * @param runIsRtl true if the run is right-to-left
@@ -555,16 +552,17 @@
      * @return the signed width of the run, based on the paragraph direction.
      * Only valid if needWidth is true.
      */
-    private float shapeRun(List<PositionedGlyphs> glyphs, int start,
+    private float shapeRun(TextShaper.GlyphsConsumer consumer, int start,
             int limit, boolean runIsRtl, float x, boolean needWidth) {
 
         if ((mDir == Layout.DIR_LEFT_TO_RIGHT) == runIsRtl) {
             float w = -measureRun(start, limit, limit, runIsRtl, null);
-            handleRun(start, limit, limit, runIsRtl, null, glyphs, x + w, 0, 0, 0, null, false);
+            handleRun(start, limit, limit, runIsRtl, null, consumer, x + w, 0, 0, 0, null, false);
             return w;
         }
 
-        return handleRun(start, limit, limit, runIsRtl, null, glyphs, x, 0, 0, 0, null, needWidth);
+        return handleRun(start, limit, limit, runIsRtl, null, consumer, x, 0, 0, 0, null,
+                needWidth);
     }
 
 
@@ -899,7 +897,7 @@
      * @param end the end of the text
      * @param runIsRtl true if the run is right-to-left
      * @param c the canvas, can be null if rendering is not needed
-     * @param glyphs the output positioned glyph list, can be null if not necessary
+     * @param consumer the output positioned glyph list, can be null if not necessary
      * @param x the edge of the run closest to the leading margin
      * @param top the top of the line
      * @param y the baseline
@@ -913,7 +911,7 @@
      */
     private float handleText(TextPaint wp, int start, int end,
             int contextStart, int contextEnd, boolean runIsRtl,
-            Canvas c, List<PositionedGlyphs> glyphs, float x, int top, int y, int bottom,
+            Canvas c, TextShaper.GlyphsConsumer consumer, float x, int top, int y, int bottom,
             FontMetricsInt fmi, boolean needWidth, int offset,
             @Nullable ArrayList<DecorationInfo> decorations) {
 
@@ -946,8 +944,8 @@
             rightX = x + totalWidth;
         }
 
-        if (glyphs != null) {
-            shapeTextRun(glyphs, wp, start, end, contextStart, contextEnd, runIsRtl, leftX);
+        if (consumer != null) {
+            shapeTextRun(consumer, wp, start, end, contextStart, contextEnd, runIsRtl, leftX);
         }
 
         if (c != null) {
@@ -1135,7 +1133,7 @@
      * @param limit the limit of the run
      * @param runIsRtl true if the run is right-to-left
      * @param c the canvas, can be null
-     * @param glyphs the output positioned glyphs, can be null
+     * @param consumer the output positioned glyphs, can be null
      * @param x the end of the run closest to the leading margin
      * @param top the top of the line
      * @param y the baseline
@@ -1147,7 +1145,7 @@
      */
     private float handleRun(int start, int measureLimit,
             int limit, boolean runIsRtl, Canvas c,
-            List<PositionedGlyphs> glyphs, float x, int top, int y,
+            TextShaper.GlyphsConsumer consumer, float x, int top, int y,
             int bottom, FontMetricsInt fmi, boolean needWidth) {
 
         if (measureLimit < start || measureLimit > limit) {
@@ -1180,7 +1178,7 @@
             wp.set(mPaint);
             wp.setStartHyphenEdit(adjustStartHyphenEdit(start, wp.getStartHyphenEdit()));
             wp.setEndHyphenEdit(adjustEndHyphenEdit(limit, wp.getEndHyphenEdit()));
-            return handleText(wp, start, limit, start, limit, runIsRtl, c, glyphs, x, top,
+            return handleText(wp, start, limit, start, limit, runIsRtl, c, consumer, x, top,
                     y, bottom, fmi, needWidth, measureLimit, null);
         }
 
@@ -1262,7 +1260,7 @@
                     activePaint.setEndHyphenEdit(
                             adjustEndHyphenEdit(activeEnd, mPaint.getEndHyphenEdit()));
                     x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c,
-                            glyphs, x, top, y, bottom, fmi, needWidth || activeEnd < measureLimit,
+                            consumer, x, top, y, bottom, fmi, needWidth || activeEnd < measureLimit,
                             Math.min(activeEnd, mlimit), mDecorations);
 
                     activeStart = j;
@@ -1288,7 +1286,7 @@
                     adjustStartHyphenEdit(activeStart, mPaint.getStartHyphenEdit()));
             activePaint.setEndHyphenEdit(
                     adjustEndHyphenEdit(activeEnd, mPaint.getEndHyphenEdit()));
-            x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, glyphs, x,
+            x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, consumer, x,
                     top, y, bottom, fmi, needWidth || activeEnd < measureLimit,
                     Math.min(activeEnd, mlimit), mDecorations);
         }
@@ -1327,7 +1325,7 @@
     /**
      * Shape a text run with the set-up paint.
      *
-     * @param glyphs the output positioned glyphs list
+     * @param consumer the output positioned glyphs list
      * @param paint the paint used to render the text
      * @param start the start of the run
      * @param end the end of the run
@@ -1336,30 +1334,32 @@
      * @param runIsRtl true if the run is right-to-left
      * @param x the x position of the left edge of the run
      */
-    private void shapeTextRun(List<PositionedGlyphs> glyphs, TextPaint paint,
+    private void shapeTextRun(TextShaper.GlyphsConsumer consumer, TextPaint paint,
             int start, int end, int contextStart, int contextEnd, boolean runIsRtl, float x) {
 
         int count = end - start;
         int contextCount = contextEnd - contextStart;
+        PositionedGlyphs glyphs;
         if (mCharsValid) {
-            glyphs.add(TextShaper.shapeTextRun(
+            glyphs = TextRunShaper.shapeTextRun(
                     mChars,
                     start, count,
                     contextStart, contextCount,
                     x, 0f,
                     runIsRtl,
                     paint
-            ));
+            );
         } else {
-            glyphs.add(TextShaper.shapeTextRun(
+            glyphs = TextRunShaper.shapeTextRun(
                     mText,
                     mStart + start, count,
                     mStart + contextStart, contextCount,
                     x, 0f,
                     runIsRtl,
                     paint
-            ));
+            );
         }
+        consumer.accept(start, count, glyphs, paint);
     }
 
 
diff --git a/core/java/android/text/TextShaper.java b/core/java/android/text/TextShaper.java
new file mode 100644
index 0000000..dd25704
--- /dev/null
+++ b/core/java/android/text/TextShaper.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.graphics.Paint;
+import android.graphics.text.PositionedGlyphs;
+import android.graphics.text.TextRunShaper;
+
+/**
+ * Provides text shaping for multi-styled text.
+ *
+ * Here is an example of animating text size and letter spacing for simple text.
+ * <pre>
+ * <code>
+ * // In this example, shape the text once for start and end state, then animate between two shape
+ * // result without re-shaping in each frame.
+ * class SimpleAnimationView @JvmOverloads constructor(
+ *         context: Context,
+ *         attrs: AttributeSet? = null,
+ *         defStyleAttr: Int = 0
+ * ) : View(context, attrs, defStyleAttr) {
+ *     private val textDir = TextDirectionHeuristics.LOCALE
+ *     private val text = "Hello, World."  // The text to be displayed
+ *
+ *     // Class for keeping drawing parameters.
+ *     data class DrawStyle(val textSize: Float, val alpha: Int)
+ *
+ *     // The start and end text shaping result. This class will animate between these two.
+ *     private val start = mutableListOf&lt;Pair&lt;PositionedGlyphs, DrawStyle&gt;&gt;()
+ *     private val end = mutableListOf&lt;Pair&lt;PositionedGlyphs, DrawStyle&gt;&gt;()
+ *
+ *     init {
+ *         val startPaint = TextPaint().apply {
+ *             alpha = 0 // Alpha only affect text drawing but not text shaping
+ *             textSize = 36f // TextSize affect both text shaping and drawing.
+ *             letterSpacing = 0f // Letter spacing only affect text shaping but not drawing.
+ *         }
+ *
+ *         val endPaint = TextPaint().apply {
+ *             alpha = 255
+ *             textSize =128f
+ *             letterSpacing = 0.1f
+ *         }
+ *
+ *         TextShaper.shapeText(text, 0, text.length, textDir, startPaint) { _, _, glyphs, paint ->
+ *             start.add(Pair(glyphs, DrawStyle(paint.textSize, paint.alpha)))
+ *         }
+ *         TextShaper.shapeText(text, 0, text.length, textDir, endPaint) { _, _, glyphs, paint ->
+ *             end.add(Pair(glyphs, DrawStyle(paint.textSize, paint.alpha)))
+ *         }
+ *     }
+ *
+ *     override fun onDraw(canvas: Canvas) {
+ *         super.onDraw(canvas)
+ *
+ *         // Set the baseline to the vertical center of the view.
+ *         canvas.translate(0f, height / 2f)
+ *
+ *         // Assume the number of PositionedGlyphs are the same. If different, you may want to
+ *         // animate in a different way, e.g. cross fading.
+ *         start.zip(end) { (startGlyphs, startDrawStyle), (endGlyphs, endDrawStyle) ->
+ *             // Tween the style and set to paint.
+ *             paint.textSize = lerp(startDrawStyle.textSize, endDrawStyle.textSize, progress)
+ *             paint.alpha = lerp(startDrawStyle.alpha, endDrawStyle.alpha, progress)
+ *
+ *             // Assume the number of glyphs are the same. If different, you may want to animate in
+ *             // a different way, e.g. cross fading.
+ *             require(startGlyphs.glyphCount() == endGlyphs.glyphCount())
+ *
+ *             if (startGlyphs.glyphCount() == 0) return@zip
+ *
+ *             var curFont = startGlyphs.getFont(0)
+ *             var drawStart = 0
+ *             for (i in 1 until startGlyphs.glyphCount()) {
+ *                 // Assume the pair of Glyph ID and font is the same. If different, you may want
+ *                 // to animate in a different way, e.g. cross fading.
+ *                 require(startGlyphs.getGlyphId(i) == endGlyphs.getGlyphId(i))
+ *                 require(startGlyphs.getFont(i) === endGlyphs.getFont(i))
+ *
+ *                 val font = startGlyphs.getFont(i)
+ *                 if (curFont != font) {
+ *                     drawGlyphs(canvas, startGlyphs, endGlyphs, drawStart, i, curFont, paint)
+ *                     curFont = font
+ *                     drawStart = i
+ *                 }
+ *             }
+ *             if (drawStart != startGlyphs.glyphCount() - 1) {
+ *                 drawGlyphs(canvas, startGlyphs, endGlyphs, drawStart, startGlyphs.glyphCount(),
+ *                         curFont, paint)
+ *             }
+ *         }
+ *     }
+ *
+ *     // Draws Glyphs for the same font run.
+ *     private fun drawGlyphs(canvas: Canvas, startGlyph: PositionedGlyphs,
+ *                            endGlyph: PositionedGlyphs, start: Int, end: Int, font: Font,
+ *                            paint: Paint) {
+ *         var cacheIndex = 0
+ *         for (i in start until end) {
+ *             intArrayCache[cacheIndex] = startGlyph.getGlyphId(i)
+ *             // The glyph positions are different from start to end since they are shaped
+ *             // with different letter spacing. Use linear interpolation for positions
+ *             // during animation.
+ *             floatArrayCache[cacheIndex * 2] =
+ *                     lerp(startGlyph.getGlyphX(i), endGlyph.getGlyphX(i), progress)
+ *             floatArrayCache[cacheIndex * 2 + 1] =
+ *                     lerp(startGlyph.getGlyphY(i), endGlyph.getGlyphY(i), progress)
+ *             if (cacheIndex == CACHE_SIZE) {  // Cached int array is full. Flashing.
+ *                 canvas.drawGlyphs(
+ *                         intArrayCache, 0, // glyphID array and its starting offset
+ *                         floatArrayCache, 0, // position array and its starting offset
+ *                         cacheIndex, // glyph count
+ *                         font,
+ *                         paint
+ *                 )
+ *                 cacheIndex = 0
+ *             }
+ *             cacheIndex++
+ *         }
+ *         if (cacheIndex != 0) {
+ *             canvas.drawGlyphs(
+ *                     intArrayCache, 0, // glyphID array and its starting offset
+ *                     floatArrayCache, 0, // position array and its starting offset
+ *                     cacheIndex, // glyph count
+ *                     font,
+ *                     paint
+ *             )
+ *         }
+ *     }
+ *
+ *     // Linear Interpolator
+ *     private fun lerp(start: Float, end: Float, t: Float) = start * (1f - t) + end * t
+ *     private fun lerp(start: Int, end: Int, t: Float) = (start * (1f - t) + end * t).toInt()
+ *
+ *     // The animation progress.
+ *     var progress: Float = 0f
+ *         set(value) {
+ *             field = value
+ *             invalidate()
+ *         }
+ *
+ *     // working copy of paint.
+ *     private val paint = Paint()
+ *
+ *     // Array cache for reducing allocation during drawing.
+ *     private var intArrayCache = IntArray(CACHE_SIZE)
+ *     private var floatArrayCache = FloatArray(CACHE_SIZE * 2)
+ * }
+ * </code>
+ * </pre>
+ * @see TextRunShaper#shapeTextRun(char[], int, int, int, int, float, float, boolean, Paint)
+ * @see TextRunShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)
+ * @see TextShaper#shapeText(CharSequence, int, int, TextDirectionHeuristic, TextPaint,
+ * GlyphsConsumer)
+ */
+public class TextShaper {
+    private TextShaper() {}
+
+    /**
+     * An consumer interface for accepting text shape result.
+     */
+    public interface GlyphsConsumer {
+        /**
+         * Accept text shape result.
+         *
+         * The implementation must not keep reference of paint since it will be mutated for the
+         * subsequent styles. Also, for saving heap size, keep only necessary members in the
+         * {@link TextPaint} instead of copying {@link TextPaint} object.
+         *
+         * @param start The start index of the shaped text.
+         * @param count The length of the shaped text.
+         * @param glyphs The shape result.
+         * @param paint The paint to be used for drawing.
+         */
+        void accept(
+                @IntRange(from = 0) int start,
+                @IntRange(from = 0) int count,
+                @NonNull PositionedGlyphs glyphs,
+                @NonNull TextPaint paint);
+    }
+
+    /**
+     * Shape multi-styled text.
+     *
+     * @param text a styled text.
+     * @param start a start index of shaping target in the text.
+     * @param count a length of shaping target in the text.
+     * @param dir a text direction.
+     * @param paint a paint
+     * @param consumer a consumer of the shape result.
+     */
+    public static void shapeText(
+            @NonNull CharSequence text, @IntRange(from = 0) int start,
+            @IntRange(from = 0) int count, @NonNull TextDirectionHeuristic dir,
+            @NonNull TextPaint paint, @NonNull GlyphsConsumer consumer) {
+        MeasuredParagraph mp = MeasuredParagraph.buildForBidi(
+                text, start, start + count, dir, null);
+        TextLine tl = TextLine.obtain();
+        try {
+            tl.set(paint, text, start, start + count,
+                    mp.getParagraphDir(),
+                    mp.getDirections(start, start + count),
+                    false /* tabstop is not supported */,
+                    null,
+                    -1, -1 // ellipsis is not supported.
+            );
+            tl.shape(consumer);
+        } finally {
+            TextLine.recycle(tl);
+        }
+    }
+
+}
diff --git a/core/tests/coretests/src/android/text/TextShaperTest.java b/core/tests/coretests/src/android/text/TextShaperTest.java
index f92ea99..8237cb0 100644
--- a/core/tests/coretests/src/android/text/TextShaperTest.java
+++ b/core/tests/coretests/src/android/text/TextShaperTest.java
@@ -18,16 +18,12 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.graphics.text.PositionedGlyphs;
-
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.List;
-
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class TextShaperTest {
@@ -36,11 +32,10 @@
     public void testFontWithPath() {
         TextPaint p = new TextPaint();
         p.setFontFeatureSettings("'wght' 900");
-        List<PositionedGlyphs> glyphs = StyledTextShaper.shapeText("a", 0, 1,
-                TextDirectionHeuristics.LTR, p);
-        assertThat(glyphs.size()).isEqualTo(1);
-        // This test only passes if the font of the Latin font is variable font.
-        assertThat(glyphs.get(0).getFont(0).getFile()).isNotNull();
-
+        TextShaper.shapeText("a", 0, 1, TextDirectionHeuristics.LTR, p,
+                (start, end, glyphs, paint) -> {
+                // This test only passes if the font of the Latin font is variable font.
+                assertThat(glyphs.getFont(0).getFile()).isNotNull();
+            });
     }
 }
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index 05df250..54f9fa8 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -26,11 +26,13 @@
 import android.graphics.Canvas.VertexMode;
 import android.graphics.fonts.Font;
 import android.graphics.text.MeasuredText;
+import android.graphics.text.TextRunShaper;
 import android.text.GraphicsOperations;
 import android.text.MeasuredParagraph;
 import android.text.PrecomputedText;
 import android.text.SpannableString;
 import android.text.SpannedString;
+import android.text.TextShaper;
 import android.text.TextUtils;
 
 import com.android.internal.util.Preconditions;
@@ -471,8 +473,8 @@
      * @param font Font used for drawing.
      * @param paint Paint used for drawing. The typeface set to this paint is ignored.
      *
-     * @see android.graphics.text.TextShaper
-     * @see android.text.StyledTextShaper
+     * @see TextRunShaper
+     * @see TextShaper
      */
     public void drawGlyphs(
             @NonNull int[] glyphIds,
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 5e07d15..829d0f4 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -26,7 +26,9 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.fonts.Font;
 import android.graphics.text.MeasuredText;
+import android.graphics.text.TextRunShaper;
 import android.os.Build;
+import android.text.TextShaper;
 
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
@@ -2053,7 +2055,7 @@
      * Draw array of glyphs with specified font.
      *
      * @param glyphIds Array of glyph IDs. The length of array must be greater than or equal to
-     *                 {@code glyphStart + glyphCount}.
+     *                 {@code glyphIdOffset + glyphCount}.
      * @param glyphIdOffset Number of elements to skip before drawing in <code>glyphIds</code>
      *                     array.
      * @param positions A flattened X and Y position array. The first glyph X position must be
@@ -2071,8 +2073,8 @@
      * @param font Font used for drawing.
      * @param paint Paint used for drawing. The typeface set to this paint is ignored.
      *
-     * @see android.graphics.text.TextShaper
-     * @see android.text.StyledTextShaper
+     * @see TextRunShaper
+     * @see TextShaper
      */
     public void drawGlyphs(
             @NonNull int[] glyphIds,
diff --git a/graphics/java/android/graphics/text/GlyphStyle.java b/graphics/java/android/graphics/text/GlyphStyle.java
deleted file mode 100644
index cc8c4d2..0000000
--- a/graphics/java/android/graphics/text/GlyphStyle.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics.text;
-
-import android.annotation.ColorInt;
-import android.annotation.FloatRange;
-import android.annotation.NonNull;
-import android.graphics.Paint;
-
-import java.util.Objects;
-
-/**
- * Represents subset of Paint parameters such as font size, scaleX that is used to draw a glyph.
- *
- * Glyph is a most primitive unit of text drawing.
- *
- */
-public class GlyphStyle {
-    private @ColorInt int mColor;
-    private float mFontSize;
-    private float mScaleX;
-    private float mSkewX;
-    private int mFlags;
-
-    /**
-     * @param color a color.
-     * @param fontSize a font size in pixels.
-     * @param scaleX a horizontal scale factor.
-     * @param skewX a horizontal skew factor
-     * @param flags paint flags
-     *
-     * @see Paint#getFlags()
-     * @see Paint#setFlags(int)
-     */
-    public GlyphStyle(
-            @ColorInt int color,
-            @FloatRange(from = 0) float fontSize,
-            @FloatRange(from = 0) float scaleX,
-            @FloatRange(from = 0) float skewX,
-            int flags) {
-        mColor = color;
-        mFontSize = fontSize;
-        mScaleX = scaleX;
-        mSkewX = skewX;
-        mFlags = flags;
-    }
-
-    /**
-     * Create glyph style from Paint
-     *
-     * @param paint a paint
-     */
-    public GlyphStyle(@NonNull Paint paint) {
-        setFromPaint(paint);
-    }
-
-    /**
-     * Gets the color.
-     *
-     * @return a color
-     * @see Paint#getColor()
-     * @see Paint#setColor(int)
-     */
-    public @ColorInt int getColor() {
-        return mColor;
-    }
-
-    /**
-     * Sets the color.
-     *
-     * @param color a color
-     * @see Paint#getColor()
-     * @see Paint#setColor(int)
-     */
-    public void setColor(@ColorInt int color) {
-        mColor = color;
-    }
-
-    /**
-     * Gets the font size in pixels.
-     *
-     * @return font size
-     * @see Paint#getTextSize()
-     * @see Paint#setTextSize(float)
-     */
-    public @FloatRange(from = 0) float getFontSize() {
-        return mFontSize;
-    }
-
-    /**
-     * Sets the font size in pixels.
-     *
-     * @param fontSize font size in pixel
-     * @see Paint#getTextSize()
-     * @see Paint#setTextSize(float)
-     */
-    public void setFontSize(@FloatRange(from = 0) float fontSize) {
-        mFontSize = fontSize;
-    }
-
-    /**
-     * Return the horizontal scale factor
-     *
-     * @return a horizontal scale factor
-     * @see Paint#getTextScaleX()
-     * @see Paint#setTextScaleX(float)
-     */
-    public @FloatRange(from = 0) float getScaleX() {
-        return mScaleX;
-    }
-
-    /**
-     * Set the horizontal scale factor
-     *
-     * @param scaleX a horizontal scale factor
-     * @see Paint#getTextScaleX()
-     * @see Paint#setTextScaleX(float)
-     */
-    public void setScaleX(@FloatRange(from = 0) float scaleX) {
-        mScaleX = scaleX;
-    }
-
-    /**
-     * Return the horizontal skew factor
-     *
-     * @return a horizontal skew factor
-     * @see Paint#getTextSkewX()
-     * @see Paint#setTextSkewX(float)
-     */
-    public @FloatRange(from = 0) float getSkewX() {
-        return mSkewX;
-    }
-
-    /**
-     * Set the horizontal skew factor
-     *
-     * @param skewX a horizontal skew factor
-     * @see Paint#getTextSkewX()
-     * @see Paint#setTextSkewX(float)
-     */
-    public void setSkewX(@FloatRange(from = 0) float skewX) {
-        mSkewX = skewX;
-    }
-
-    /**
-     * Returns the Paint flags.
-     *
-     * @return a paint flags
-     * @see Paint#getFlags()
-     * @see Paint#setFlags(int)
-     */
-    public int getFlags() {
-        return mFlags;
-    }
-
-    /**
-     * Set the Paint flags.
-     *
-     * @param flags a paint flags
-     * @see Paint#getFlags()
-     * @see Paint#setFlags(int)
-     */
-    public void setFlags(int flags) {
-        mFlags = flags;
-    }
-
-    /**
-     * Applies glyph style to the paint object.
-     *
-     * @param paint a paint object
-     */
-    public void applyToPaint(@NonNull Paint paint) {
-        paint.setColor(mColor);
-        paint.setTextSize(mFontSize);
-        paint.setTextScaleX(mScaleX);
-        paint.setTextSkewX(mSkewX);
-        paint.setFlags(mFlags);
-    }
-
-    /**
-     * Copy parameters from a Paint object.
-     *
-     * @param paint a paint object
-     */
-    public void setFromPaint(@NonNull Paint paint) {
-        mColor = paint.getColor();
-        mFontSize = paint.getTextSize();
-        mScaleX = paint.getTextScaleX();
-        mSkewX = paint.getTextSkewX();
-        mFlags = paint.getFlags();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (!(o instanceof GlyphStyle)) return false;
-        GlyphStyle that = (GlyphStyle) o;
-        return that.mColor == mColor
-                && Float.compare(that.mFontSize, mFontSize) == 0
-                && Float.compare(that.mScaleX, mScaleX) == 0
-                && Float.compare(that.mSkewX, mSkewX) == 0
-                && mFlags == that.mFlags;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mColor, mFontSize, mScaleX, mSkewX, mFlags);
-    }
-
-    @Override
-    public String toString() {
-        return "GlyphStyle{"
-                + "mColor=" + mColor
-                + ", mFontSize=" + mFontSize
-                + ", mScaleX=" + mScaleX
-                + ", mSkewX=" + mSkewX
-                + ", mFlags=" + mFlags
-                + '}';
-    }
-}
diff --git a/graphics/java/android/graphics/text/PositionedGlyphs.java b/graphics/java/android/graphics/text/PositionedGlyphs.java
index 7364d54..ecbc45c 100644
--- a/graphics/java/android/graphics/text/PositionedGlyphs.java
+++ b/graphics/java/android/graphics/text/PositionedGlyphs.java
@@ -35,11 +35,12 @@
  * Text shaping result object for single style text.
  *
  * You can get text shaping result by
- * {@link TextShaper#shapeTextRun(char[], int, int, int, int, float, float, boolean, Paint)} and
- * {@link TextShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)}.
+ * {@link TextRunShaper#shapeTextRun(char[], int, int, int, int, float, float, boolean, Paint)} and
+ * {@link TextRunShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean,
+ * Paint)}.
  *
- * @see TextShaper#shapeTextRun(char[], int, int, int, int, float, float, boolean, Paint)
- * @see TextShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)
+ * @see TextRunShaper#shapeTextRun(char[], int, int, int, int, float, float, boolean, Paint)
+ * @see TextRunShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)
  */
 public final class PositionedGlyphs {
     private static final NativeAllocationRegistry REGISTRY =
@@ -49,7 +50,6 @@
     private final long mLayoutPtr;
     private final float mXOffset;
     private final float mYOffset;
-    private final GlyphStyle mGlyphStyle;
     private final ArrayList<Font> mFonts;
 
     /**
@@ -62,7 +62,7 @@
      *
      * @return total amount of advance
      */
-    public float getTotalAdvance() {
+    public float getAdvance() {
         return nGetTotalAdvance(mLayoutPtr);
     }
 
@@ -91,21 +91,11 @@
     }
 
     /**
-     * Returns the glyph style used for drawing the glyph at the given index.
-     *
-     * @return A glyph style
-     */
-    @NonNull
-    public GlyphStyle getStyle() {
-        return mGlyphStyle;
-    }
-
-    /**
      * Returns the amount of X offset added to glyph position.
      *
      * @return The X offset added to glyph position.
      */
-    public float getOriginX() {
+    public float getOffsetX() {
         return mXOffset;
     }
 
@@ -114,7 +104,7 @@
      *
      * @return The Y offset added to glyph position.
      */
-    public float getOriginY() {
+    public float getOffsetY() {
         return mYOffset;
     }
 
@@ -144,7 +134,7 @@
      * Returns the glyph ID used for drawing the glyph at the given index.
      *
      * @param index the glyph index
-     * @return A font object
+     * @return An glyph ID of the font.
      */
     @IntRange(from = 0)
     public int getGlyphId(@IntRange(from = 0) int index) {
@@ -158,7 +148,7 @@
      * @param index the glyph index
      * @return A X offset in pixels
      */
-    public float getPositionX(@IntRange(from = 0) int index) {
+    public float getGlyphX(@IntRange(from = 0) int index) {
         Preconditions.checkArgumentInRange(index, 0, glyphCount() - 1, "index");
         return nGetX(mLayoutPtr, index) + mXOffset;
     }
@@ -169,7 +159,7 @@
      * @param index the glyph index
      * @return A Y offset in pixels.
      */
-    public float getPositionY(@IntRange(from = 0) int index) {
+    public float getGlyphY(@IntRange(from = 0) int index) {
         Preconditions.checkArgumentInRange(index, 0, glyphCount() - 1, "index");
         return nGetY(mLayoutPtr, index) + mYOffset;
     }
@@ -184,7 +174,6 @@
      */
     public PositionedGlyphs(long layoutPtr, @NonNull Paint paint, float xOffset, float yOffset) {
         mLayoutPtr = layoutPtr;
-        mGlyphStyle = new GlyphStyle(paint);
         int glyphCount = nGetGlyphCount(layoutPtr);
         mFonts = new ArrayList<>(glyphCount);
         mXOffset = xOffset;
@@ -229,14 +218,13 @@
         if (!(o instanceof PositionedGlyphs)) return false;
         PositionedGlyphs that = (PositionedGlyphs) o;
 
-        if (!mGlyphStyle.equals(that.mGlyphStyle)) return false;
         if (mXOffset != that.mXOffset || mYOffset != that.mYOffset) return false;
         if (glyphCount() != that.glyphCount()) return false;
 
         for (int i = 0; i < glyphCount(); ++i) {
             if (getGlyphId(i) != that.getGlyphId(i)) return false;
-            if (getPositionX(i) != that.getPositionX(i)) return false;
-            if (getPositionY(i) != that.getPositionY(i)) return false;
+            if (getGlyphX(i) != that.getGlyphX(i)) return false;
+            if (getGlyphY(i) != that.getGlyphY(i)) return false;
             // Intentionally using reference equality since font equality is heavy due to buffer
             // compare.
             if (getFont(i) != that.getFont(i)) return false;
@@ -247,10 +235,10 @@
 
     @Override
     public int hashCode() {
-        int hashCode = Objects.hash(mXOffset, mYOffset, mGlyphStyle);
+        int hashCode = Objects.hash(mXOffset, mYOffset);
         for (int i = 0; i < glyphCount(); ++i) {
             hashCode = Objects.hash(hashCode,
-                    getGlyphId(i), getPositionX(i), getPositionY(i), getFont(i));
+                    getGlyphId(i), getGlyphX(i), getGlyphY(i), getFont(i));
         }
         return hashCode;
     }
@@ -263,7 +251,7 @@
                 sb.append(", ");
             }
             sb.append("[ ID = " + getGlyphId(i) + ","
-                    + " pos = (" + getPositionX(i) + "," + getPositionY(i) + ")"
+                    + " pos = (" + getGlyphX(i) + "," + getGlyphY(i) + ")"
                     + " font = " + getFont(i) + " ]");
         }
         sb.append("]");
@@ -271,7 +259,6 @@
                 + "glyphs = " + sb.toString()
                 + ", mXOffset=" + mXOffset
                 + ", mYOffset=" + mYOffset
-                + ", mGlyphStyle=" + mGlyphStyle
                 + '}';
     }
 }
diff --git a/graphics/java/android/graphics/text/TextShaper.java b/graphics/java/android/graphics/text/TextRunShaper.java
similarity index 88%
rename from graphics/java/android/graphics/text/TextShaper.java
rename to graphics/java/android/graphics/text/TextRunShaper.java
index f40ed8f..b73436e 100644
--- a/graphics/java/android/graphics/text/TextShaper.java
+++ b/graphics/java/android/graphics/text/TextRunShaper.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.graphics.Paint;
 import android.text.TextDirectionHeuristic;
+import android.text.TextPaint;
 import android.text.TextUtils;
 
 import com.android.internal.util.Preconditions;
@@ -31,15 +32,18 @@
  * Text shaping is a preprocess for drawing text into canvas with glyphs. The glyph is a most
  * primitive unit of the text drawing, consist of glyph identifier in the font file and its position
  * and style. You can draw the shape result to Canvas by calling Canvas#drawGlyphs.
-
  *
- * @see TextShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)
- * @see TextShaper#shapeTextRun(char[], int, int, int, int, float, float, boolean, Paint)
- * @see android.text.StyledTextShaper#shapeText(CharSequence, int, int, TextDirectionHeuristic,
- * TextPaint)
+ * For most of the use cases, {@link android.text.TextShaper} will provide text shaping
+ * functionalities needed. {@link TextRunShaper} is a lower level API that is used by
+ * {@link android.text.TextShaper}.
+ *
+ * @see TextRunShaper#shapeTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)
+ * @see TextRunShaper#shapeTextRun(char[], int, int, int, int, float, float, boolean, Paint)
+ * @see android.text.TextShaper#shapeText(CharSequence, int, int, TextDirectionHeuristic, TextPaint,
+ * TextShaper.GlyphsConsumer)
  */
-public class TextShaper {
-    private TextShaper() {}  // Do not instantiate
+public class TextRunShaper {
+    private TextRunShaper() {}  // Do not instantiate
 
     /**
      * Shape non-styled text.
diff --git a/libs/hwui/jni/text/TextShaper.cpp b/libs/hwui/jni/text/TextShaper.cpp
index 9d9e91f..9785aa5 100644
--- a/libs/hwui/jni/text/TextShaper.cpp
+++ b/libs/hwui/jni/text/TextShaper.cpp
@@ -196,7 +196,7 @@
 };
 
 int register_android_graphics_text_TextShaper(JNIEnv* env) {
-    return RegisterMethodsOrDie(env, "android/graphics/text/TextShaper", gMethods,
+    return RegisterMethodsOrDie(env, "android/graphics/text/TextRunShaper", gMethods,
                                 NELEM(gMethods))
         + RegisterMethodsOrDie(env, "android/graphics/text/PositionedGlyphs",
             gResultMethods, NELEM(gResultMethods));
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 58e4ccc..fbe3d32 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -16507,23 +16507,6 @@
 
 package android.graphics.text {
 
-  public class GlyphStyle {
-    ctor public GlyphStyle(@ColorInt int, @FloatRange(from=0) float, @FloatRange(from=0) float, @FloatRange(from=0) float, int);
-    ctor public GlyphStyle(@NonNull android.graphics.Paint);
-    method public void applyToPaint(@NonNull android.graphics.Paint);
-    method @ColorInt public int getColor();
-    method public int getFlags();
-    method @FloatRange(from=0) public float getFontSize();
-    method @FloatRange(from=0) public float getScaleX();
-    method @FloatRange(from=0) public float getSkewX();
-    method public void setColor(@ColorInt int);
-    method public void setFlags(int);
-    method public void setFontSize(@FloatRange(from=0) float);
-    method public void setFromPaint(@NonNull android.graphics.Paint);
-    method public void setScaleX(@FloatRange(from=0) float);
-    method public void setSkewX(@FloatRange(from=0) float);
-  }
-
   public class LineBreaker {
     method @NonNull public android.graphics.text.LineBreaker.Result computeLineBreaks(@NonNull android.graphics.text.MeasuredText, @NonNull android.graphics.text.LineBreaker.ParagraphConstraints, @IntRange(from=0) int);
     field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
@@ -16585,20 +16568,19 @@
   }
 
   public final class PositionedGlyphs {
+    method public float getAdvance();
     method public float getAscent();
     method public float getDescent();
     method @NonNull public android.graphics.fonts.Font getFont(@IntRange(from=0) int);
     method @IntRange(from=0) public int getGlyphId(@IntRange(from=0) int);
-    method public float getOriginX();
-    method public float getOriginY();
-    method public float getPositionX(@IntRange(from=0) int);
-    method public float getPositionY(@IntRange(from=0) int);
-    method @NonNull public android.graphics.text.GlyphStyle getStyle();
-    method public float getTotalAdvance();
+    method public float getGlyphX(@IntRange(from=0) int);
+    method public float getGlyphY(@IntRange(from=0) int);
+    method public float getOffsetX();
+    method public float getOffsetY();
     method @IntRange(from=0) public int glyphCount();
   }
 
-  public class TextShaper {
+  public class TextRunShaper {
     method @NonNull public static android.graphics.text.PositionedGlyphs shapeTextRun(@NonNull char[], int, int, int, int, float, float, boolean, @NonNull android.graphics.Paint);
     method @NonNull public static android.graphics.text.PositionedGlyphs shapeTextRun(@NonNull CharSequence, int, int, int, int, float, float, boolean, @NonNull android.graphics.Paint);
   }
@@ -48193,10 +48175,6 @@
     method @NonNull public android.text.StaticLayout.Builder setUseLineSpacingFromFallbacks(boolean);
   }
 
-  public class StyledTextShaper {
-    method @NonNull public static java.util.List<android.graphics.text.PositionedGlyphs> shapeText(@NonNull CharSequence, int, int, @NonNull android.text.TextDirectionHeuristic, @NonNull android.text.TextPaint);
-  }
-
   public interface TextDirectionHeuristic {
     method public boolean isRtl(char[], int, int);
     method public boolean isRtl(CharSequence, int, int);
@@ -48226,6 +48204,14 @@
     field @Px public float underlineThickness;
   }
 
+  public class TextShaper {
+    method public static void shapeText(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.text.TextDirectionHeuristic, @NonNull android.text.TextPaint, @NonNull android.text.TextShaper.GlyphsConsumer);
+  }
+
+  public static interface TextShaper.GlyphsConsumer {
+    method public void accept(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.text.PositionedGlyphs, @NonNull android.text.TextPaint);
+  }
+
   public class TextUtils {
     method @Deprecated public static CharSequence commaEllipsize(CharSequence, android.text.TextPaint, float, String, String);
     method public static CharSequence concat(java.lang.CharSequence...);