Add Canvas#drawGlyphs
Bug: 168048923 Test: atest CanvasDrawGlyphsTest Change-Id: I013335fa82883146044ea03fbbe67e1e26a35f6d
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -408,6 +414,34 @@ public class BaseRecordingCanvas extends Canvas {
|
||||
paint.getNativeInstance());
|
||||
}
|
||||
|
||||
@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) {
|
||||
@@ -673,6 +707,10 @@ public class BaseRecordingCanvas extends Canvas {
|
||||
int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset,
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -2047,6 +2049,43 @@ public class Canvas extends BaseCanvas {
|
||||
super.drawDoubleRoundRect(outer, outerRadii, inner, innerRadii, paint);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user