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
This commit is contained in:
@@ -16525,23 +16525,6 @@ package android.graphics.pdf {
|
||||
|
||||
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 @@ package android.graphics.text {
|
||||
}
|
||||
|
||||
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 @@ package android.text {
|
||||
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 @@ package android.text {
|
||||
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...);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import android.graphics.Canvas;
|
||||
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.annotations.VisibleForTesting;
|
||||
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 @@ public class TextLine {
|
||||
/**
|
||||
* 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 @@ public class TextLine {
|
||||
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 @@ public class TextLine {
|
||||
}
|
||||
}
|
||||
}
|
||||
return glyphs;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -546,7 +543,7 @@ public class TextLine {
|
||||
/**
|
||||
* 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 @@ public class TextLine {
|
||||
* @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 @@ public class TextLine {
|
||||
* @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 @@ public class TextLine {
|
||||
*/
|
||||
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 @@ public class TextLine {
|
||||
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 @@ public class TextLine {
|
||||
* @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 @@ public class TextLine {
|
||||
*/
|
||||
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 @@ public class TextLine {
|
||||
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 @@ public class TextLine {
|
||||
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 @@ public class TextLine {
|
||||
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 @@ public class TextLine {
|
||||
/**
|
||||
* 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 @@ public class TextLine {
|
||||
* @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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
229
core/java/android/text/TextShaper.java
Normal file
229
core/java/android/text/TextShaper.java
Normal file
@@ -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<Pair<PositionedGlyphs, DrawStyle>>()
|
||||
* private val end = mutableListOf<Pair<PositionedGlyphs, DrawStyle>>()
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,16 +18,12 @@ package android.text;
|
||||
|
||||
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 class TextShaperTest {
|
||||
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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,11 +26,13 @@ import android.compat.annotation.UnsupportedAppUsage;
|
||||
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 @@ public abstract class BaseCanvas {
|
||||
* @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,
|
||||
|
||||
@@ -26,7 +26,9 @@ import android.annotation.Size;
|
||||
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 @@ public class Canvas extends BaseCanvas {
|
||||
* 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 @@ public class Canvas extends BaseCanvas {
|
||||
* @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,
|
||||
|
||||
@@ -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
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
@@ -35,11 +35,12 @@ import java.util.Objects;
|
||||
* 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 @@ public final class PositionedGlyphs {
|
||||
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 @@ public final class PositionedGlyphs {
|
||||
*
|
||||
* @return total amount of advance
|
||||
*/
|
||||
public float getTotalAdvance() {
|
||||
public float getAdvance() {
|
||||
return nGetTotalAdvance(mLayoutPtr);
|
||||
}
|
||||
|
||||
@@ -90,22 +90,12 @@ public final class PositionedGlyphs {
|
||||
return nGetDescent(mLayoutPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public final class PositionedGlyphs {
|
||||
*
|
||||
* @return The Y offset added to glyph position.
|
||||
*/
|
||||
public float getOriginY() {
|
||||
public float getOffsetY() {
|
||||
return mYOffset;
|
||||
}
|
||||
|
||||
@@ -144,7 +134,7 @@ public final class PositionedGlyphs {
|
||||
* 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 @@ public final class PositionedGlyphs {
|
||||
* @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 @@ public final class PositionedGlyphs {
|
||||
* @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 final class PositionedGlyphs {
|
||||
*/
|
||||
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 @@ public final class PositionedGlyphs {
|
||||
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 @@ public final class PositionedGlyphs {
|
||||
|
||||
@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 @@ public final class PositionedGlyphs {
|
||||
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 @@ public final class PositionedGlyphs {
|
||||
+ "glyphs = " + sb.toString()
|
||||
+ ", mXOffset=" + mXOffset
|
||||
+ ", mYOffset=" + mYOffset
|
||||
+ ", mGlyphStyle=" + mGlyphStyle
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.graphics.text;
|
||||
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 @@ import dalvik.annotation.optimization.FastNative;
|
||||
* 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.
|
||||
@@ -196,7 +196,7 @@ static const JNINativeMethod gResultMethods[] = {
|
||||
};
|
||||
|
||||
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));
|
||||
|
||||
@@ -16507,23 +16507,6 @@ package android.graphics.pdf {
|
||||
|
||||
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 @@ package android.graphics.text {
|
||||
}
|
||||
|
||||
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 @@ package android.text {
|
||||
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 @@ package android.text {
|
||||
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...);
|
||||
|
||||
Reference in New Issue
Block a user