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

Commit c678bdd6 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Create Font sets from native fonts"

parents 73665572 3a282056
Loading
Loading
Loading
Loading
+20 −32
Original line number Diff line number Diff line
@@ -123,6 +123,19 @@ public final class Font {
            mLocaleList = localeList;
        }

        /**
         * Construct a builder with a byte buffer and file path.
         *
         * This method is intended to be called only from SystemFonts.
         * @param path font file path
         * @param localeList comma concatenated BCP47 compliant language tag.
         * @hide
         */
        public Builder(@NonNull File path, @NonNull String localeList) {
            this(path);
            mLocaleList = localeList;
        }

        /**
         * Constructs a builder with a file path.
         *
@@ -809,29 +822,13 @@ public final class Font {

            // If not found, create Font object from native object for Java API users.
            ByteBuffer buffer = NativeFontBufferHelper.refByteBuffer(ptr);
            long packed = nGetFontInfo(ptr);
            int weight = (int) (packed & 0x0000_0000_0000_FFFFL);
            boolean italic = (packed & 0x0000_0000_0001_0000L) != 0;
            int ttcIndex = (int) ((packed & 0x0000_FFFF_0000_0000L) >> 32);
            int axisCount = (int) ((packed & 0xFFFF_0000_0000_0000L) >> 48);
            FontVariationAxis[] axes = new FontVariationAxis[axisCount];
            char[] charBuffer = new char[4];
            for (int i = 0; i < axisCount; ++i) {
                long packedAxis = nGetAxisInfo(ptr, i);
                float value = Float.intBitsToFloat((int) (packedAxis & 0x0000_0000_FFFF_FFFFL));
                charBuffer[0] = (char) ((packedAxis & 0xFF00_0000_0000_0000L) >> 56);
                charBuffer[1] = (char) ((packedAxis & 0x00FF_0000_0000_0000L) >> 48);
                charBuffer[2] = (char) ((packedAxis & 0x0000_FF00_0000_0000L) >> 40);
                charBuffer[3] = (char) ((packedAxis & 0x0000_00FF_0000_0000L) >> 32);
                axes[i] = new FontVariationAxis(new String(charBuffer), value);
            }
            String path = nGetFontPath(ptr);
            File file = (path == null) ? null : new File(path);
            Font.Builder builder = new Font.Builder(buffer, file, "")
                    .setWeight(weight)
                    .setSlant(italic ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT)
                    .setTtcIndex(ttcIndex)
                    .setFontVariationSettings(axes);
            NativeFont.Font font = NativeFont.readNativeFont(ptr);

            Font.Builder builder = new Font.Builder(buffer, font.getFile(), "")
                    .setWeight(font.getStyle().getWeight())
                    .setSlant(font.getStyle().getSlant())
                    .setTtcIndex(font.getIndex())
                    .setFontVariationSettings(font.getAxes());

            Font newFont = null;
            try {
@@ -845,15 +842,6 @@ public final class Font {
        }
    }

    @CriticalNative
    private static native long nGetFontInfo(long ptr);

    @CriticalNative
    private static native long nGetAxisInfo(long ptr, int i);

    @FastNative
    private static native String nGetFontPath(long ptr);

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

+205 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.
 */

package android.graphics.fonts;

import android.graphics.Typeface;

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

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * Read native font objects.
 *
 * @hide
 */
public class NativeFont {

    /**
     * Represents native font object.
     */
    public static final class Font {
        private final File mFile;
        private final int mIndex;
        private final FontVariationAxis[] mAxes;
        private final FontStyle mStyle;

        public Font(File file, int index, FontVariationAxis[] axes, FontStyle style) {
            mFile = file;
            mIndex = index;
            mAxes = axes;
            mStyle = style;
        }

        public File getFile() {
            return mFile;
        }

        public FontVariationAxis[] getAxes() {
            return mAxes;
        }

        public FontStyle getStyle() {
            return mStyle;
        }

        public int getIndex() {
            return mIndex;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Font font = (Font) o;
            return mIndex == font.mIndex && mFile.equals(font.mFile)
                    && Arrays.equals(mAxes, font.mAxes) && mStyle.equals(font.mStyle);
        }

        @Override
        public int hashCode() {
            int result = Objects.hash(mFile, mIndex, mStyle);
            result = 31 * result + Arrays.hashCode(mAxes);
            return result;
        }
    }

    /**
     * Represents native font family object.
     */
    public static final class Family {
        private final List<Font> mFonts;
        private final String mLocale;

        public Family(List<Font> fonts, String locale) {
            mFonts = fonts;
            mLocale = locale;
        }

        public List<Font> getFonts() {
            return mFonts;
        }

        public String getLocale() {
            return mLocale;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Family family = (Family) o;
            return mFonts.equals(family.mFonts) && mLocale.equals(family.mLocale);
        }

        @Override
        public int hashCode() {
            return Objects.hash(mFonts, mLocale);
        }
    }

    /**
     * Get underlying font families from Typeface
     *
     * @param typeface a typeface
     * @return list of family
     */
    public static List<Family> readTypeface(Typeface typeface) {
        int familyCount = nGetFamilyCount(typeface.native_instance);
        List<Family> result = new ArrayList<>(familyCount);
        for (int i = 0; i < familyCount; ++i) {
            result.add(readNativeFamily(nGetFamily(typeface.native_instance, i)));
        }
        return result;
    }

    /**
     * Read family object from native pointer
     *
     * @param familyPtr a font family pointer
     * @return a family
     */
    public static Family readNativeFamily(long familyPtr) {
        int fontCount = nGetFontCount(familyPtr);
        List<Font> result = new ArrayList<>(fontCount);
        for (int i = 0; i < fontCount; ++i) {
            result.add(readNativeFont(nGetFont(familyPtr, i)));
        }
        String localeList = nGetLocaleList(familyPtr);
        return new Family(result, localeList);
    }

    /**
     * Read font object from native pointer.
     *
     * @param ptr a font pointer
     * @return a font
     */
    public static Font readNativeFont(long ptr) {
        long packed = nGetFontInfo(ptr);
        int weight = (int) (packed & 0x0000_0000_0000_FFFFL);
        boolean italic = (packed & 0x0000_0000_0001_0000L) != 0;
        int ttcIndex = (int) ((packed & 0x0000_FFFF_0000_0000L) >> 32);
        int axisCount = (int) ((packed & 0xFFFF_0000_0000_0000L) >> 48);
        FontVariationAxis[] axes = new FontVariationAxis[axisCount];
        char[] charBuffer = new char[4];
        for (int i = 0; i < axisCount; ++i) {
            long packedAxis = nGetAxisInfo(ptr, i);
            float value = Float.intBitsToFloat((int) (packedAxis & 0x0000_0000_FFFF_FFFFL));
            charBuffer[0] = (char) ((packedAxis & 0xFF00_0000_0000_0000L) >> 56);
            charBuffer[1] = (char) ((packedAxis & 0x00FF_0000_0000_0000L) >> 48);
            charBuffer[2] = (char) ((packedAxis & 0x0000_FF00_0000_0000L) >> 40);
            charBuffer[3] = (char) ((packedAxis & 0x0000_00FF_0000_0000L) >> 32);
            axes[i] = new FontVariationAxis(new String(charBuffer), value);
        }
        String path = nGetFontPath(ptr);
        File file = (path == null) ? null : new File(path);
        FontStyle style = new FontStyle(weight,
                italic ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT);

        return new Font(file, ttcIndex, axes, style);
    }

    @CriticalNative
    private static native int nGetFamilyCount(long ptr);

    @CriticalNative
    private static native long nGetFamily(long ptr, int index);

    @FastNative
    private static native String nGetLocaleList(long familyPtr);

    @CriticalNative
    private static native long nGetFont(long familyPtr, int fontIndex);

    @CriticalNative
    private static native int nGetFontCount(long familyPtr);

    @CriticalNative
    private static native long nGetFontInfo(long fontPtr);

    @CriticalNative
    private static native long nGetAxisInfo(long fontPtr, int i);

    @FastNative
    private static native String nGetFontPath(long fontPtr);
}
+40 −8
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.graphics.fonts;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.FontListParser;
import android.graphics.Typeface;
import android.text.FontConfig;
import android.util.ArrayMap;
import android.util.Log;
@@ -68,8 +69,10 @@ public final class SystemFonts {
                return sAvailableFonts;
            }

            if (Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
                sAvailableFonts = collectAllFonts();
            } else {
                Set<Font> set = new HashSet<>();

                for (FontFamily[] items : sFamilyMap.values()) {
                    for (FontFamily family : items) {
                        for (int i = 0; i < family.getSize(); ++i) {
@@ -79,10 +82,39 @@ public final class SystemFonts {
                }

                sAvailableFonts = Collections.unmodifiableSet(set);
            }
            return sAvailableFonts;
        }
    }

    private static @NonNull Set<Font> collectAllFonts() {
        Map<String, Typeface> map = Typeface.getSystemFontMap();
        HashSet<NativeFont.Font> seenFonts = new HashSet<>();
        HashSet<Font> result = new HashSet<>();
        for (Typeface typeface : map.values()) {
            List<NativeFont.Family> families = NativeFont.readTypeface(typeface);
            for (NativeFont.Family family : families) {
                for (NativeFont.Font font : family.getFonts()) {
                    if (seenFonts.contains(font)) {
                        continue;
                    }
                    seenFonts.add(font);
                    try {
                        result.add(new Font.Builder(font.getFile(), family.getLocale())
                                .setFontVariationSettings(font.getAxes())
                                .setTtcIndex(font.getIndex())
                                .setWeight(font.getStyle().getWeight())
                                .setSlant(font.getStyle().getSlant())
                                .build());
                    } catch (IOException e) {
                        Log.w(TAG, "Failed to load " + font.getFile(), e);
                    }
                }
            }
        }
        return result;
    }

    private static @Nullable ByteBuffer mmap(@NonNull String fullPath) {
        try (FileInputStream file = new FileInputStream(fullPath)) {
            final FileChannel fileChannel = file.getChannel();
+1 −0
Original line number Diff line number Diff line
@@ -333,6 +333,7 @@ cc_defaults {
        "jni/YuvToJpegEncoder.cpp",
        "jni/fonts/Font.cpp",
        "jni/fonts/FontFamily.cpp",
        "jni/fonts/NativeFont.cpp",
        "jni/text/LineBreaker.cpp",
        "jni/text/MeasuredText.cpp",
        "jni/text/TextShaper.cpp",
+2 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ 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_fonts_FontFamily(JNIEnv* env);
extern int register_android_graphics_fonts_NativeFont(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);
@@ -135,6 +136,7 @@ static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_android_graphics_drawable_VectorDrawable),
    REG_JNI(register_android_graphics_fonts_Font),
    REG_JNI(register_android_graphics_fonts_FontFamily),
    REG_JNI(register_android_graphics_fonts_NativeFont),
    REG_JNI(register_android_graphics_pdf_PdfDocument),
    REG_JNI(register_android_graphics_pdf_PdfEditor),
    REG_JNI(register_android_graphics_pdf_PdfRenderer),
Loading