diff options
| author | 2020-10-06 18:58:54 +0000 | |
|---|---|---|
| committer | 2020-10-06 18:58:54 +0000 | |
| commit | aade3bc06807a4f01ac15cd0332cc16aa6b10579 (patch) | |
| tree | 5752483ea5a6a2e966a823d1fcae943f3d4927de | |
| parent | efc301a8443024b5c1f2f77bacb6429611c0e75e (diff) | |
| parent | 39c482f21fbfff39654c6f49e40105574be58377 (diff) | |
Merge "Add Canvas#drawGlyphs"
| -rw-r--r-- | api/current.txt | 1 | ||||
| -rw-r--r-- | graphics/java/android/graphics/BaseCanvas.java | 61 | ||||
| -rw-r--r-- | graphics/java/android/graphics/BaseRecordingCanvas.java | 38 | ||||
| -rw-r--r-- | graphics/java/android/graphics/Canvas.java | 39 | ||||
| -rw-r--r-- | libs/hwui/hwui/Canvas.cpp | 20 | ||||
| -rw-r--r-- | libs/hwui/hwui/Canvas.h | 4 | ||||
| -rw-r--r-- | libs/hwui/jni/android_graphics_Canvas.cpp | 17 | ||||
| -rw-r--r-- | non-updatable-api/current.txt | 1 |
8 files changed, 181 insertions, 0 deletions
diff --git a/api/current.txt b/api/current.txt index 31989fe60509..b22e84c2c6c0 100644 --- a/api/current.txt +++ b/api/current.txt @@ -14356,6 +14356,7 @@ package android.graphics { method public void drawColor(@ColorLong long, @NonNull android.graphics.BlendMode); method public void drawDoubleRoundRect(@NonNull android.graphics.RectF, float, float, @NonNull android.graphics.RectF, float, float, @NonNull android.graphics.Paint); method public void drawDoubleRoundRect(@NonNull android.graphics.RectF, @NonNull float[], @NonNull android.graphics.RectF, @NonNull float[], @NonNull android.graphics.Paint); + method public void drawGlyphs(@NonNull int[], @IntRange(from=0) int, @NonNull float[], @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.fonts.Font, @NonNull android.graphics.Paint); method public void drawLine(float, float, float, float, @NonNull android.graphics.Paint); method public void drawLines(@NonNull @Size(multiple=4) float[], int, int, @NonNull android.graphics.Paint); method public void drawLines(@NonNull @Size(multiple=4) float[], @NonNull android.graphics.Paint); diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java index bee8d5efc933..05df250fa6b9 100644 --- a/graphics/java/android/graphics/BaseCanvas.java +++ b/graphics/java/android/graphics/BaseCanvas.java @@ -18,11 +18,13 @@ package android.graphics; import android.annotation.ColorInt; import android.annotation.ColorLong; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Canvas.VertexMode; +import android.graphics.fonts.Font; import android.graphics.text.MeasuredText; import android.text.GraphicsOperations; import android.text.MeasuredParagraph; @@ -31,6 +33,10 @@ import android.text.SpannableString; import android.text.SpannedString; import android.text.TextUtils; +import com.android.internal.util.Preconditions; + +import java.util.Objects; + /** * This class is a base class for Canvas's drawing operations. Any modifications here * should be accompanied by a similar modification to {@link BaseRecordingCanvas}. @@ -443,6 +449,58 @@ public abstract class BaseCanvas { paint.getNativeInstance()); } + /** + * 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}. + * @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 + * stored at {@code positionOffset}. The first glyph Y position must be stored + * at {@code positionOffset + 1}, then the second glyph X position must be + * stored at {@code positionOffset + 2}. + * The length of array must be greater than or equal to + * {@code positionOffset + glyphCount * 2}. + * @param positionOffset Number of elements to skip before drawing in {@code positions}. + * The first glyph X position must be stored at {@code positionOffset}. + * The first glyph Y position must be stored at + * {@code positionOffset + 1}, then the second glyph X position must be + * stored at {@code positionOffset + 2}. + * @param glyphCount Number of glyphs to be drawn. + * @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 + */ + public void drawGlyphs( + @NonNull int[] glyphIds, + @IntRange(from = 0) int glyphIdOffset, + @NonNull float[] positions, + @IntRange(from = 0) int positionOffset, + @IntRange(from = 0) int glyphCount, + @NonNull Font font, + @NonNull Paint paint) { + Objects.requireNonNull(glyphIds, "glyphIds must not be null."); + Objects.requireNonNull(positions, "positions must not be null."); + Objects.requireNonNull(font, "font must not be null."); + Objects.requireNonNull(paint, "paint must not be null."); + Preconditions.checkArgumentNonnegative(glyphCount); + + if (glyphIdOffset < 0 || glyphIdOffset + glyphCount > glyphIds.length) { + throw new IndexOutOfBoundsException( + "glyphIds must have at least " + (glyphIdOffset + glyphCount) + " of elements"); + } + if (positionOffset < 0 || positionOffset + glyphCount * 2 > positions.length) { + throw new IndexOutOfBoundsException( + "positions must have at least " + (positionOffset + glyphCount * 2) + + " of elements"); + } + nDrawGlyphs(mNativeCanvasWrapper, glyphIds, positions, glyphIdOffset, positionOffset, + glyphCount, font.getNativePtr(), paint.getNativeInstance()); + } + public void drawText(@NonNull char[] text, int index, int count, float x, float y, @NonNull Paint paint) { if ((index | count | (index + count) | @@ -734,6 +792,9 @@ public abstract class BaseCanvas { int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, int indexOffset, int indexCount, long nativePaint); + private static native void nDrawGlyphs(long nativeCanvas, int[] glyphIds, float[] positions, + int glyphIdStart, int positionStart, int glyphCount, long nativeFont, long nativePaint); + private static native void nDrawText(long nativeCanvas, char[] text, int index, int count, float x, float y, int flags, long nativePaint); diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java index 2f5214cb1df5..a8922e84514a 100644 --- a/graphics/java/android/graphics/BaseRecordingCanvas.java +++ b/graphics/java/android/graphics/BaseRecordingCanvas.java @@ -18,9 +18,11 @@ package android.graphics; import android.annotation.ColorInt; import android.annotation.ColorLong; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; +import android.graphics.fonts.Font; import android.graphics.text.MeasuredText; import android.text.GraphicsOperations; import android.text.MeasuredParagraph; @@ -29,8 +31,12 @@ import android.text.SpannableString; import android.text.SpannedString; import android.text.TextUtils; +import com.android.internal.util.Preconditions; + import dalvik.annotation.optimization.FastNative; +import java.util.Objects; + /** * This class is a base class for canvases that defer drawing operations, so all * the draw operations can be marked @FastNative. It contains a re-implementation of @@ -409,6 +415,34 @@ public class BaseRecordingCanvas extends Canvas { } @Override + public void drawGlyphs( + @NonNull int[] glyphIds, + @IntRange(from = 0) int glyphIdOffset, + @NonNull float[] positions, + @IntRange(from = 0) int positionOffset, + @IntRange(from = 0) int glyphCount, + @NonNull Font font, + @NonNull Paint paint) { + Objects.requireNonNull(glyphIds, "glyphIds must not be null."); + Objects.requireNonNull(positions, "positions must not be null."); + Objects.requireNonNull(font, "font must not be null."); + Objects.requireNonNull(paint, "paint must not be null."); + Preconditions.checkArgumentNonnegative(glyphCount); + + if (glyphIdOffset < 0 || glyphIdOffset + glyphCount > glyphIds.length) { + throw new IndexOutOfBoundsException( + "glyphIds must have at least " + (glyphIdOffset + glyphCount) + " of elements"); + } + if (positionOffset < 0 || positionOffset + glyphCount * 2 > positions.length) { + throw new IndexOutOfBoundsException( + "positions must have at least " + (positionOffset + glyphCount * 2) + + " of elements"); + } + nDrawGlyphs(mNativeCanvasWrapper, glyphIds, positions, glyphIdOffset, positionOffset, + glyphCount, font.getNativePtr(), paint.getNativeInstance()); + } + + @Override public final void drawText(@NonNull char[] text, int index, int count, float x, float y, @NonNull Paint paint) { if ((index | count | (index + count) @@ -674,6 +708,10 @@ public class BaseRecordingCanvas extends Canvas { short[] indices, int indexOffset, int indexCount, long nativePaint); @FastNative + private static native void nDrawGlyphs(long nativeCanvas, int[] glyphIds, float[] positions, + int glyphIdStart, int positionStart, int glyphCount, long nativeFont, long nativePaint); + + @FastNative private static native void nDrawText(long nativeCanvas, char[] text, int index, int count, float x, float y, int flags, long nativePaint); diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 559571cb0271..5e07d156a06a 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -19,10 +19,12 @@ package android.graphics; import android.annotation.ColorInt; import android.annotation.ColorLong; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; import android.compat.annotation.UnsupportedAppUsage; +import android.graphics.fonts.Font; import android.graphics.text.MeasuredText; import android.os.Build; @@ -2048,6 +2050,43 @@ 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}. + * @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 + * stored at {@code positionOffset}. The first glyph Y position must be stored + * at {@code positionOffset + 1}, then the second glyph X position must be + * stored at {@code positionOffset + 2}. + * The length of array must be greater than or equal to + * {@code positionOffset + glyphCount * 2}. + * @param positionOffset Number of elements to skip before drawing in {@code positions}. + * The first glyph X position must be stored at {@code positionOffset}. + * The first glyph Y position must be stored at + * {@code positionOffset + 1}, then the second glyph X position must be + * stored at {@code positionOffset + 2}. + * @param glyphCount Number of glyphs to be drawn. + * @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 + */ + public void drawGlyphs( + @NonNull int[] glyphIds, + @IntRange(from = 0) int glyphIdOffset, + @NonNull float[] positions, + @IntRange(from = 0) int positionOffset, + @IntRange(from = 0) int glyphCount, + @NonNull Font font, + @NonNull Paint paint) { + super.drawGlyphs(glyphIds, glyphIdOffset, positions, positionOffset, glyphCount, font, + paint); + } + + /** * Draw the text, with origin at (x,y), using the specified paint. The origin is interpreted * based on the Align setting in the paint. * diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index 8df2770b0157..146bf283c58a 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -135,6 +135,26 @@ private: float totalAdvance; }; +void Canvas::drawGlyphs(const minikin::Font& font, const int* glyphIds, const float* positions, + int glyphCount, const Paint& paint) { + // Minikin modify skFont for auto-fakebold/auto-fakeitalic. + Paint copied(paint); + + auto glyphFunc = [&](uint16_t* outGlyphIds, float* outPositions) { + for (uint32_t i = 0; i < glyphCount; ++i) { + outGlyphIds[i] = static_cast<uint16_t>(glyphIds[i]); + } + memcpy(outPositions, positions, sizeof(float) * 2 * glyphCount); + }; + + const minikin::MinikinFont* minikinFont = font.typeface().get(); + SkFont* skfont = &copied.getSkFont(); + MinikinFontSkia::populateSkFont(skfont, minikinFont, minikin::FontFakery()); + + // total advance is used for drawing underline. We do not support underlyine by glyph drawing. + drawGlyphs(glyphFunc, glyphCount, copied, 0 /* x */, 0 /* y */, 0 /* total Advance */); +} + void Canvas::drawText(const uint16_t* text, int textSize, int start, int count, int contextStart, int contextCount, float x, float y, minikin::Bidi bidiFlags, const Paint& origPaint, const Typeface* typeface, minikin::MeasuredText* mt) { diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index 817c7ee9077f..772b7a28ef04 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -32,6 +32,7 @@ class SkCanvasState; class SkVertices; namespace minikin { +class Font; class Layout; class MeasuredText; enum class Bidi : uint8_t; @@ -255,6 +256,9 @@ public: */ virtual void drawVectorDrawable(VectorDrawableRoot* tree) = 0; + void drawGlyphs(const minikin::Font& font, const int* glyphIds, const float* positions, + int glyphCount, const Paint& paint); + /** * Converts utf16 text to glyphs, calculating position and boundary, * and delegating the final draw to virtual drawGlyphs method. diff --git a/libs/hwui/jni/android_graphics_Canvas.cpp b/libs/hwui/jni/android_graphics_Canvas.cpp index b6c6cd0b5c1c..c04340c36511 100644 --- a/libs/hwui/jni/android_graphics_Canvas.cpp +++ b/libs/hwui/jni/android_graphics_Canvas.cpp @@ -30,6 +30,7 @@ #include <nativehelper/ScopedPrimitiveArray.h> #include <nativehelper/ScopedStringChars.h> +#include "FontUtils.h" #include "Bitmap.h" #include "SkGraphics.h" #include "SkRegion.h" @@ -540,6 +541,21 @@ static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jlong bitma colorA.ptr() + colorIndex, paint); } +static void drawGlyphs(JNIEnv* env, jobject, jlong canvasHandle, jintArray glyphIds, + jfloatArray positions, jint glyphOffset, jint positionOffset, + jint glyphCount, jlong fontHandle, jlong paintHandle) { + Paint* paint = reinterpret_cast<Paint*>(paintHandle); + FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle); + AutoJavaIntArray glyphIdArray(env, glyphIds); + AutoJavaFloatArray positionArray(env, positions); + get_canvas(canvasHandle)->drawGlyphs( + *font->font.get(), + glyphIdArray.ptr() + glyphOffset, + positionArray.ptr() + positionOffset, + glyphCount, + *paint); +} + static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray charArray, jint index, jint count, jfloat x, jfloat y, jint bidiFlags, jlong paintHandle) { @@ -719,6 +735,7 @@ static const JNINativeMethod gDrawMethods[] = { {"nDrawBitmap","(JJFFJIII)V", (void*) CanvasJNI::drawBitmap}, {"nDrawBitmap","(JJFFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect}, {"nDrawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray}, + {"nDrawGlyphs", "(J[I[FIIIJJ)V", (void*)CanvasJNI::drawGlyphs}, {"nDrawText","(J[CIIFFIJ)V", (void*) CanvasJNI::drawTextChars}, {"nDrawText","(JLjava/lang/String;IIFFIJ)V", (void*) CanvasJNI::drawTextString}, {"nDrawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars}, diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt index 0af29b5e77de..d4278fa74600 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -14356,6 +14356,7 @@ package android.graphics { method public void drawColor(@ColorLong long, @NonNull android.graphics.BlendMode); method public void drawDoubleRoundRect(@NonNull android.graphics.RectF, float, float, @NonNull android.graphics.RectF, float, float, @NonNull android.graphics.Paint); method public void drawDoubleRoundRect(@NonNull android.graphics.RectF, @NonNull float[], @NonNull android.graphics.RectF, @NonNull float[], @NonNull android.graphics.Paint); + method public void drawGlyphs(@NonNull int[], @IntRange(from=0) int, @NonNull float[], @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.fonts.Font, @NonNull android.graphics.Paint); method public void drawLine(float, float, float, float, @NonNull android.graphics.Paint); method public void drawLines(@NonNull @Size(multiple=4) float[], int, int, @NonNull android.graphics.Paint); method public void drawLines(@NonNull @Size(multiple=4) float[], @NonNull android.graphics.Paint); |