summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2020-10-06 18:58:54 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-10-06 18:58:54 +0000
commitaade3bc06807a4f01ac15cd0332cc16aa6b10579 (patch)
tree5752483ea5a6a2e966a823d1fcae943f3d4927de
parentefc301a8443024b5c1f2f77bacb6429611c0e75e (diff)
parent39c482f21fbfff39654c6f49e40105574be58377 (diff)
Merge "Add Canvas#drawGlyphs"
-rw-r--r--api/current.txt1
-rw-r--r--graphics/java/android/graphics/BaseCanvas.java61
-rw-r--r--graphics/java/android/graphics/BaseRecordingCanvas.java38
-rw-r--r--graphics/java/android/graphics/Canvas.java39
-rw-r--r--libs/hwui/hwui/Canvas.cpp20
-rw-r--r--libs/hwui/hwui/Canvas.h4
-rw-r--r--libs/hwui/jni/android_graphics_Canvas.cpp17
-rw-r--r--non-updatable-api/current.txt1
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);