Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ed4f644 authored by Seigo Nonaka's avatar Seigo Nonaka
Browse files

Add necessary APIs for supporting glyph level drawing

This CL adds following APIs

Font#cloneWithSettings
  This API provides a faster Font instance creation for different
  variation settings.

Font#getBounds
  This API provides glyph advance and bounding box information.

Font#getMetrics
  This API provides font metrics that will be used for deciding line
  height and/or baseline.

Bug: 168136332
Test: atest FontTest
Test: TreeHugger

Change-Id: I335557ce47ea0ca8e012c2a48b804c00bb348392
parent 3c99024f
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -16390,7 +16390,9 @@ package android.graphics.fonts {
    method @Nullable public android.graphics.fonts.FontVariationAxis[] getAxes();
    method @NonNull public java.nio.ByteBuffer getBuffer();
    method @Nullable public java.io.File getFile();
    method public float getGlyphBounds(@IntRange(from=0) int, @NonNull android.graphics.Paint, @Nullable android.graphics.RectF);
    method @NonNull public android.os.LocaleList getLocaleList();
    method public void getMetrics(@NonNull android.graphics.Paint, @Nullable android.graphics.Paint.FontMetrics);
    method @NonNull public android.graphics.fonts.FontStyle getStyle();
    method @IntRange(from=0) public int getTtcIndex();
  }
@@ -16402,6 +16404,7 @@ package android.graphics.fonts {
    ctor public Font.Builder(@NonNull android.os.ParcelFileDescriptor, @IntRange(from=0) long, @IntRange(from=0xffffffff) long);
    ctor public Font.Builder(@NonNull android.content.res.AssetManager, @NonNull String);
    ctor public Font.Builder(@NonNull android.content.res.Resources, int);
    ctor public Font.Builder(@NonNull android.graphics.fonts.Font);
    method @NonNull public android.graphics.fonts.Font build() throws java.io.IOException;
    method @NonNull public android.graphics.fonts.Font.Builder setFontVariationSettings(@Nullable String);
    method @NonNull public android.graphics.fonts.Font.Builder setFontVariationSettings(@Nullable android.graphics.fonts.FontVariationAxis[]);
+71 −2
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import android.annotation.Nullable;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.LocaleList;
import android.os.ParcelFileDescriptor;
import android.util.TypedValue;
@@ -29,6 +31,7 @@ import android.util.TypedValue;
import com.android.internal.util.Preconditions;

import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;

import libcore.util.NativeAllocationRegistry;

@@ -63,6 +66,7 @@ public final class Font {

        private @Nullable ByteBuffer mBuffer;
        private @Nullable File mFile;
        private @Nullable Font mFont;
        private @NonNull String mLocaleList = "";
        private @IntRange(from = -1, to = 1000) int mWeight = NOT_SPECIFIED;
        private @IntRange(from = -1, to = 1) int mItalic = NOT_SPECIFIED;
@@ -203,6 +207,22 @@ public final class Font {
            }
        }

        /**
         * Constructs a builder from existing Font instance.
         *
         * @param font the font instance.
         */
        public Builder(@NonNull Font font) {
            mFont = font;
            // Copies all parameters as a default value.
            mBuffer = font.getBuffer();
            mWeight = font.getStyle().getWeight();
            mItalic = font.getStyle().getSlant();
            mAxes = font.getAxes();
            mFile = font.getFile();
            mTtcIndex = font.getTtcIndex();
        }

        /**
         * Creates a buffer containing font data using the assetManager and other
         * provided inputs.
@@ -430,8 +450,13 @@ public final class Font {
            }
            final ByteBuffer readonlyBuffer = mBuffer.asReadOnlyBuffer();
            final String filePath = mFile == null ? "" : mFile.getAbsolutePath();
            final long ptr = nBuild(builderPtr, readonlyBuffer, filePath, mWeight, italic,
                    mTtcIndex);

            long ptr;
            if (mFont == null) {
                ptr = nBuild(builderPtr, readonlyBuffer, filePath, mWeight, italic, mTtcIndex);
            } else {
                ptr = nClone(mFont.getNativePtr(), builderPtr, mWeight, italic, mTtcIndex);
            }
            final Font font = new Font(ptr, readonlyBuffer, mFile,
                    new FontStyle(mWeight, slant), mTtcIndex, mAxes, mLocaleList);
            sFontRegistry.registerNativeAllocation(font, ptr);
@@ -449,6 +474,10 @@ public final class Font {
                boolean italic, int ttcIndex);
        @CriticalNative
        private static native long nGetReleaseNativeFont();

        @FastNative
        private static native long nClone(long fontPtr, long builderPtr, int weight,
                boolean italic, int ttcIndex);
    }

    private final long mNativePtr;  // address of the shared ptr of minikin::Font
@@ -538,6 +567,40 @@ public final class Font {
        return LocaleList.forLanguageTags(mLocaleList);
    }

    /**
     * Retrieve the glyph horizontal advance and bounding box.
     *
     * Note that {@link android.graphics.Typeface} in {@link android.graphics.Paint} is ignored.
     *
     * @param glyphId a glyph ID
     * @param paint a paint object used for resolving glyph style
     * @param rect a nullable destination object. If null is passed, this function just return the
     *             horizontal advance. If non-null is passed, this function fills bounding box
     *             information to this object.
     * @return the amount of horizontal advance in pixels
     */
    public float getGlyphBounds(@IntRange(from = 0) int glyphId, @NonNull Paint paint,
            @Nullable RectF rect) {
        return nGetGlyphBounds(mNativePtr, glyphId, paint.getNativeInstance(), rect);
    }

    /**
     * Retrieve the font metrics information.
     *
     * Note that {@link android.graphics.Typeface} in {@link android.graphics.Paint} is ignored.
     *
     * @param paint a paint object used for retrieving font metrics.
     * @param metrics a nullable destination object. If null is passed, this function only retrieve
     *                recommended interline spacing. If non-null is passed, this function fills to
     *                font metrics to it.
     *
     * @see Paint#getFontMetrics()
     * @see Paint#getFontMetricsInt()
     */
    public void getMetrics(@NonNull Paint paint, @Nullable Paint.FontMetrics metrics) {
        nGetFontMetrics(mNativePtr, paint.getNativeInstance(), metrics);
    }

    /** @hide */
    public long getNativePtr() {
        return mNativePtr;
@@ -573,4 +636,10 @@ public final class Font {
            + ", buffer=" + mBuffer
            + "}";
    }

    @FastNative
    private static native float nGetGlyphBounds(long font, int glyphId, long paint, RectF rect);

    @FastNative
    private static native float nGetFontMetrics(long font, long paint, Paint.FontMetrics metrics);
}
+59 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include "GraphicsJNI.h"

#include "SkCanvas.h"
#include "SkFontMetrics.h"
#include "SkMath.h"
#include "SkRegion.h"
#include <cutils/ashmem.h>
@@ -228,6 +229,20 @@ static jfieldID gColorSpace_Named_LinearExtendedSRGBFieldID;
static jclass gTransferParameters_class;
static jmethodID gTransferParameters_constructorMethodID;

static jclass   gFontMetrics_class;
static jfieldID gFontMetrics_top;
static jfieldID gFontMetrics_ascent;
static jfieldID gFontMetrics_descent;
static jfieldID gFontMetrics_bottom;
static jfieldID gFontMetrics_leading;

static jclass   gFontMetricsInt_class;
static jfieldID gFontMetricsInt_top;
static jfieldID gFontMetricsInt_ascent;
static jfieldID gFontMetricsInt_descent;
static jfieldID gFontMetricsInt_bottom;
static jfieldID gFontMetricsInt_leading;

///////////////////////////////////////////////////////////////////////////////

void GraphicsJNI::get_jrect(JNIEnv* env, jobject obj, int* L, int* T, int* R, int* B)
@@ -468,6 +483,32 @@ SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region)
    return r;
}

void GraphicsJNI::set_metrics(JNIEnv* env, jobject metrics, const SkFontMetrics& skmetrics) {
    if (metrics == nullptr) return;
    SkASSERT(env->IsInstanceOf(metrics, gFontMetrics_class));
    env->SetFloatField(metrics, gFontMetrics_top, SkScalarToFloat(skmetrics.fTop));
    env->SetFloatField(metrics, gFontMetrics_ascent, SkScalarToFloat(skmetrics.fAscent));
    env->SetFloatField(metrics, gFontMetrics_descent, SkScalarToFloat(skmetrics.fDescent));
    env->SetFloatField(metrics, gFontMetrics_bottom, SkScalarToFloat(skmetrics.fBottom));
    env->SetFloatField(metrics, gFontMetrics_leading, SkScalarToFloat(skmetrics.fLeading));
}

int GraphicsJNI::set_metrics_int(JNIEnv* env, jobject metrics, const SkFontMetrics& skmetrics) {
    int ascent = SkScalarRoundToInt(skmetrics.fAscent);
    int descent = SkScalarRoundToInt(skmetrics.fDescent);
    int leading = SkScalarRoundToInt(skmetrics.fLeading);

    if (metrics) {
        SkASSERT(env->IsInstanceOf(metrics, gFontMetricsInt_class));
        env->SetIntField(metrics, gFontMetricsInt_top, SkScalarFloorToInt(skmetrics.fTop));
        env->SetIntField(metrics, gFontMetricsInt_ascent, ascent);
        env->SetIntField(metrics, gFontMetricsInt_descent, descent);
        env->SetIntField(metrics, gFontMetricsInt_bottom, SkScalarCeilToInt(skmetrics.fBottom));
        env->SetIntField(metrics, gFontMetricsInt_leading, leading);
    }
    return descent - ascent + leading;
}

///////////////////////////////////////////////////////////////////////////////////////////

jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, skia::BitmapRegionDecoder* bitmap)
@@ -764,5 +805,23 @@ int register_android_graphics_Graphics(JNIEnv* env)
    gTransferParameters_constructorMethodID = GetMethodIDOrDie(env, gTransferParameters_class,
            "<init>", "(DDDDDDD)V");

    gFontMetrics_class = FindClassOrDie(env, "android/graphics/Paint$FontMetrics");
    gFontMetrics_class = MakeGlobalRefOrDie(env, gFontMetrics_class);

    gFontMetrics_top = GetFieldIDOrDie(env, gFontMetrics_class, "top", "F");
    gFontMetrics_ascent = GetFieldIDOrDie(env, gFontMetrics_class, "ascent", "F");
    gFontMetrics_descent = GetFieldIDOrDie(env, gFontMetrics_class, "descent", "F");
    gFontMetrics_bottom = GetFieldIDOrDie(env, gFontMetrics_class, "bottom", "F");
    gFontMetrics_leading = GetFieldIDOrDie(env, gFontMetrics_class, "leading", "F");

    gFontMetricsInt_class = FindClassOrDie(env, "android/graphics/Paint$FontMetricsInt");
    gFontMetricsInt_class = MakeGlobalRefOrDie(env, gFontMetricsInt_class);

    gFontMetricsInt_top = GetFieldIDOrDie(env, gFontMetricsInt_class, "top", "I");
    gFontMetricsInt_ascent = GetFieldIDOrDie(env, gFontMetricsInt_class, "ascent", "I");
    gFontMetricsInt_descent = GetFieldIDOrDie(env, gFontMetricsInt_class, "descent", "I");
    gFontMetricsInt_bottom = GetFieldIDOrDie(env, gFontMetricsInt_class, "bottom", "I");
    gFontMetricsInt_leading = GetFieldIDOrDie(env, gFontMetricsInt_class, "leading", "I");

    return 0;
}
+12 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include "graphics_jni_helpers.h"

class SkCanvas;
struct SkFontMetrics;

namespace android {
namespace skia {
@@ -85,6 +86,17 @@ public:
                                     bool* isHardware);
    static SkRegion* getNativeRegion(JNIEnv*, jobject region);

    /**
     * Set SkFontMetrics to Java Paint.FontMetrics.
     * Do nothing if metrics is nullptr.
     */
    static void set_metrics(JNIEnv*, jobject metrics, const SkFontMetrics& skmetrics);
    /**
     * Set SkFontMetrics to Java Paint.FontMetricsInt and return recommended interline space.
     * Do nothing if metrics is nullptr.
     */
    static int set_metrics_int(JNIEnv*, jobject metrics, const SkFontMetrics& skmetrics);

    /*
     *  LegacyBitmapConfig is the old enum in Skia that matched the enum int values
     *  in Bitmap.Config. Skia no longer supports this config, but has replaced it
+2 −55
Original line number Diff line number Diff line
@@ -59,20 +59,6 @@ using namespace android::uirenderer;

namespace android {

struct JMetricsID {
    jfieldID    top;
    jfieldID    ascent;
    jfieldID    descent;
    jfieldID    bottom;
    jfieldID    leading;
};

static jclass   gFontMetrics_class;
static JMetricsID gFontMetrics_fieldID;

static jclass   gFontMetricsInt_class;
static JMetricsID gFontMetricsInt_fieldID;

static void getPosTextPath(const SkFont& font, const uint16_t glyphs[], int count,
                           const SkPoint pos[], SkPath* dst) {
    dst->reset();
@@ -618,35 +604,14 @@ namespace PaintGlue {
    static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj) {
        SkFontMetrics metrics;
        SkScalar spacing = getMetricsInternal(paintHandle, &metrics);

        if (metricsObj) {
            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
            env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
            env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
            env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
            env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
            env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
        }
        GraphicsJNI::set_metrics(env, metricsObj, metrics);
        return SkScalarToFloat(spacing);
    }

    static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj) {
        SkFontMetrics metrics;

        getMetricsInternal(paintHandle, &metrics);
        int ascent = SkScalarRoundToInt(metrics.fAscent);
        int descent = SkScalarRoundToInt(metrics.fDescent);
        int leading = SkScalarRoundToInt(metrics.fLeading);

        if (metricsObj) {
            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
        }
        return descent - ascent + leading;
        return GraphicsJNI::set_metrics_int(env, metricsObj, metrics);
    }


@@ -1137,24 +1102,6 @@ static const JNINativeMethod methods[] = {
};

int register_android_graphics_Paint(JNIEnv* env) {
    gFontMetrics_class = FindClassOrDie(env, "android/graphics/Paint$FontMetrics");
    gFontMetrics_class = MakeGlobalRefOrDie(env, gFontMetrics_class);

    gFontMetrics_fieldID.top = GetFieldIDOrDie(env, gFontMetrics_class, "top", "F");
    gFontMetrics_fieldID.ascent = GetFieldIDOrDie(env, gFontMetrics_class, "ascent", "F");
    gFontMetrics_fieldID.descent = GetFieldIDOrDie(env, gFontMetrics_class, "descent", "F");
    gFontMetrics_fieldID.bottom = GetFieldIDOrDie(env, gFontMetrics_class, "bottom", "F");
    gFontMetrics_fieldID.leading = GetFieldIDOrDie(env, gFontMetrics_class, "leading", "F");

    gFontMetricsInt_class = FindClassOrDie(env, "android/graphics/Paint$FontMetricsInt");
    gFontMetricsInt_class = MakeGlobalRefOrDie(env, gFontMetricsInt_class);

    gFontMetricsInt_fieldID.top = GetFieldIDOrDie(env, gFontMetricsInt_class, "top", "I");
    gFontMetricsInt_fieldID.ascent = GetFieldIDOrDie(env, gFontMetricsInt_class, "ascent", "I");
    gFontMetricsInt_fieldID.descent = GetFieldIDOrDie(env, gFontMetricsInt_class, "descent", "I");
    gFontMetricsInt_fieldID.bottom = GetFieldIDOrDie(env, gFontMetricsInt_class, "bottom", "I");
    gFontMetricsInt_fieldID.leading = GetFieldIDOrDie(env, gFontMetricsInt_class, "leading", "I");

    return RegisterMethodsOrDie(env, "android/graphics/Paint", methods, NELEM(methods));
}

Loading