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

Commit a1c21c0a authored by Seigo Nonaka's avatar Seigo Nonaka
Browse files

Introduce Font and its builder class

This CL is a ground work of the new Typeface construction API and
nobody uses this class except for CTS.
I'll add FontFamily class to be able to bundle these Font clases
and register to the Typeface.

Bug: 72665240
Test: atest FontTest
Test: atest CtsWidgetTestCases:EditTextTest
    CtsWidgetTestCases:TextViewFadingEdgeTest
    FrameworksCoreTests:TextViewFallbackLineSpacingTest
    FrameworksCoreTests:TextViewTest FrameworksCoreTests:TypefaceTest
    CtsGraphicsTestCases:TypefaceTest CtsWidgetTestCases:TextViewTest
    CtsTextTestCases FrameworksCoreTests:android.text
    CtsWidgetTestCases:TextViewPrecomputedTextTest

Change-Id: I68555a8b4bd6dd770ba7baae72d9a3777b2087a5
parent a71bee87
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -15171,6 +15171,37 @@ package android.graphics.drawable.shapes {
package android.graphics.fonts {
  public class Font {
    method public android.graphics.fonts.FontVariationAxis[] getAxes();
    method public int getTtcIndex();
    method public int getWeight();
    method public boolean isItalic();
    field public static final int FONT_WEIGHT_BLACK = 900; // 0x384
    field public static final int FONT_WEIGHT_BOLD = 700; // 0x2bc
    field public static final int FONT_WEIGHT_EXTRA_BOLD = 800; // 0x320
    field public static final int FONT_WEIGHT_EXTRA_LIGHT = 200; // 0xc8
    field public static final int FONT_WEIGHT_LIGHT = 300; // 0x12c
    field public static final int FONT_WEIGHT_MEDIUM = 500; // 0x1f4
    field public static final int FONT_WEIGHT_NORMAL = 400; // 0x190
    field public static final int FONT_WEIGHT_SEMI_BOLD = 600; // 0x258
    field public static final int FONT_WEIGHT_THIN = 100; // 0x64
  }
  public static class Font.Builder {
    ctor public Font.Builder(java.nio.ByteBuffer);
    ctor public Font.Builder(java.io.File) throws java.io.IOException;
    ctor public Font.Builder(java.io.FileDescriptor) throws java.io.IOException;
    ctor public Font.Builder(java.io.FileDescriptor, long, long) throws java.io.IOException;
    ctor public Font.Builder(android.content.res.AssetManager, java.lang.String) throws java.io.IOException;
    ctor public Font.Builder(android.content.res.Resources, int) throws java.io.IOException;
    method public android.graphics.fonts.Font build();
    method public android.graphics.fonts.Font.Builder setFontVariationSettings(java.lang.String);
    method public android.graphics.fonts.Font.Builder setFontVariationSettings(android.graphics.fonts.FontVariationAxis[]);
    method public android.graphics.fonts.Font.Builder setItalic(boolean);
    method public android.graphics.fonts.Font.Builder setTtcIndex(int);
    method public android.graphics.fonts.Font.Builder setWeight(int);
  }
  public final class FontVariationAxis {
    ctor public FontVariationAxis(java.lang.String, float);
    method public static android.graphics.fonts.FontVariationAxis[] fromFontVariationSettings(java.lang.String);
+1 −0
Original line number Diff line number Diff line
@@ -154,6 +154,7 @@ cc_library_shared {
        "android/graphics/Typeface.cpp",
        "android/graphics/Utils.cpp",
        "android/graphics/YuvToJpegEncoder.cpp",
        "android/graphics/fonts/Font.cpp",
        "android/graphics/pdf/PdfDocument.cpp",
        "android/graphics/pdf/PdfEditor.cpp",
        "android/graphics/pdf/PdfRenderer.cpp",
+2 −0
Original line number Diff line number Diff line
@@ -140,6 +140,7 @@ extern int register_android_graphics_Region(JNIEnv* env);
extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env);
extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
extern int register_android_graphics_fonts_Font(JNIEnv* env);
extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
@@ -1406,6 +1407,7 @@ static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_android_graphics_YuvImage),
    REG_JNI(register_android_graphics_drawable_AnimatedVectorDrawable),
    REG_JNI(register_android_graphics_drawable_VectorDrawable),
    REG_JNI(register_android_graphics_fonts_Font),
    REG_JNI(register_android_graphics_pdf_PdfDocument),
    REG_JNI(register_android_graphics_pdf_PdfEditor),
    REG_JNI(register_android_graphics_pdf_PdfRenderer),
+7 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include <jni.h>
#include <memory>

#include <minikin/Font.h>

namespace minikin {
class FontFamily;
}  // namespace minikin
@@ -31,6 +33,11 @@ struct FontFamilyWrapper {
  std::shared_ptr<minikin::FontFamily> family;
};

struct FontWrapper {
  FontWrapper(minikin::Font&& font) : font(std::move(font)) {}
  minikin::Font font;
};

// Utility wrapper for java.util.List
class ListHelper {
public:
+205 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.
 */

#define LOG_TAG "Minikin"

#include <nativehelper/JNIHelp.h>
#include <core_jni_helpers.h>

#include "SkData.h"
#include "SkFontMgr.h"
#include "SkRefCnt.h"
#include "SkTypeface.h"
#include "GraphicsJNI.h"
#include <nativehelper/ScopedUtfChars.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_util_AssetManager.h>
#include <androidfw/AssetManager2.h>
#include "Utils.h"
#include "FontUtils.h"

#include <hwui/MinikinSkia.h>
#include <hwui/Typeface.h>
#include <utils/FatVector.h>
#include <minikin/FontFamily.h>

#include <memory>

namespace android {

struct NativeFontBuilder {
    std::vector<minikin::FontVariation> axes;
};

static inline NativeFontBuilder* toBuilder(jlong ptr) {
    return reinterpret_cast<NativeFontBuilder*>(ptr);
}

static inline Asset* toAsset(jlong ptr) {
    return reinterpret_cast<Asset*>(ptr);
}

static void releaseAsset(jlong asset) {
    delete toAsset(asset);
}

static void releaseFont(jlong font) {
    delete reinterpret_cast<FontWrapper*>(font);
}

static void release_global_ref(const void* /*data*/, void* context) {
    JNIEnv* env = AndroidRuntime::getJNIEnv();
    if (env == nullptr) {
        JavaVMAttachArgs args;
        args.version = JNI_VERSION_1_4;
        args.name = "release_font_data";
        args.group = nullptr;
        jint result = AndroidRuntime::getJavaVM()->AttachCurrentThread(&env, &args);
        if (result != JNI_OK) {
            ALOGE("failed to attach to thread to release global ref.");
            return;
        }
    }

    jobject obj = reinterpret_cast<jobject>(context);
    env->DeleteGlobalRef(obj);
}

// Regular JNI
static jlong Font_Builder_getNativeAsset(
    JNIEnv* env, jobject clazz, jobject assetMgr, jstring path, jboolean isAsset, jint cookie) {
    NPE_CHECK_RETURN_ZERO(env, assetMgr);
    NPE_CHECK_RETURN_ZERO(env, path);

    Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(env, assetMgr);
    if (mgr == nullptr) {
        return 0;
    }

    ScopedUtfChars str(env, path);
    if (str.c_str() == nullptr) {
        return 0;
    }

    std::unique_ptr<Asset> asset;
    {
      ScopedLock<AssetManager2> locked_mgr(*mgr);
      if (isAsset) {
          asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
      } else if (cookie > 0) {
          // Valid java cookies are 1-based, but AssetManager cookies are 0-based.
          asset = locked_mgr->OpenNonAsset(str.c_str(), static_cast<ApkAssetsCookie>(cookie - 1),
                  Asset::ACCESS_BUFFER);
      } else {
          asset = locked_mgr->OpenNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
      }
    }

    return reinterpret_cast<jlong>(asset.release());
}

// Regular JNI
static jobject Font_Builder_getAssetBuffer(JNIEnv* env, jobject clazz, jlong nativeAsset) {
    Asset* asset = toAsset(nativeAsset);
    return env->NewDirectByteBuffer(const_cast<void*>(asset->getBuffer(false)), asset->getLength());
}

// CriticalNative
static jlong Font_Builder_getReleaseNativeAssetFunc() {
    return reinterpret_cast<jlong>(&releaseAsset);
}

// Regular JNI
static jlong Font_Builder_initBuilder(JNIEnv*, jobject) {
    return reinterpret_cast<jlong>(new NativeFontBuilder());
}

// Critical Native
static void Font_Builder_addAxis(jlong builderPtr, jint tag, jfloat value) {
    toBuilder(builderPtr)->axes.emplace_back(static_cast<minikin::AxisTag>(tag), value);
}

// Regular JNI
static jlong Font_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr, jobject buffer,
        jint weight, jboolean italic, jint ttcIndex) {
    NPE_CHECK_RETURN_ZERO(env, buffer);
    std::unique_ptr<NativeFontBuilder> builder(toBuilder(builderPtr));
    const void* fontPtr = env->GetDirectBufferAddress(buffer);
    if (fontPtr == nullptr) {
        jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
        return 0;
    }
    jlong fontSize = env->GetDirectBufferCapacity(buffer);
    if (fontSize <= 0) {
        jniThrowException(env, "java/lang/IllegalArgumentException",
                          "buffer size must not be zero or negative");
        return 0;
    }
    jobject fontRef = MakeGlobalRefOrDie(env, buffer);
    sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
            release_global_ref, reinterpret_cast<void*>(fontRef)));

    uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes;
    for (const auto& axis : builder->axes) {
        skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
    }

    std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));

    SkFontArguments params;
    params.setCollectionIndex(ttcIndex);
    params.setAxes(skiaAxes.data(), skiaAxes.size());

    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
    sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), params));
    if (face == nullptr) {
        jniThrowException(env, "java/lang/IllegalArgumentException",
                          "Failed to create internal object. maybe invalid font data.");
        return 0;
    }
    std::shared_ptr<minikin::MinikinFont> minikinFont =
            std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize, ttcIndex,
                    builder->axes);
    minikin::Font font = minikin::Font::Builder(minikinFont).setWeight(weight)
                    .setSlant(static_cast<minikin::FontStyle::Slant>(italic)).build();
    return reinterpret_cast<jlong>(new FontWrapper(std::move(font)));
}

// Critical Native
static jlong Font_Builder_getReleaseNativeFont() {
    return reinterpret_cast<jlong>(releaseFont);
}

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

static const JNINativeMethod gFontBuilderMethods[] = {
    { "nInitBuilder", "()J", (void*) Font_Builder_initBuilder },
    { "nAddAxis", "(JIF)V", (void*) Font_Builder_addAxis },
    { "nBuild", "(JLjava/nio/ByteBuffer;IZI)J", (void*) Font_Builder_build },
    { "nGetReleaseNativeFont", "()J", (void*) Font_Builder_getReleaseNativeFont },

    { "nGetNativeAsset", "(Landroid/content/res/AssetManager;Ljava/lang/String;ZI)J",
      (void*) Font_Builder_getNativeAsset },
    { "nGetAssetBuffer", "(J)Ljava/nio/ByteBuffer;", (void*) Font_Builder_getAssetBuffer },
    { "nGetReleaseNativeAssetFunc", "()J", (void*) Font_Builder_getReleaseNativeAssetFunc },
};

int register_android_graphics_fonts_Font(JNIEnv* env) {
    return RegisterMethodsOrDie(env, "android/graphics/fonts/Font$Builder", gFontBuilderMethods,
            NELEM(gFontBuilderMethods));
}

}
Loading