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

Commit 4b4024b5 authored by Seigo Nonaka's avatar Seigo Nonaka
Browse files

Use variable definition for variable font family

Bug: 281769620
Test: Manually done
Test: atest FontListParserTest TypefaceSystemFallbackTest
Test: atest CtsGraphicsTestCases CtsTextTestCases
Change-Id: Ice5a51024c7fbba2af7c5886c751e2508c3670d7
parent cea6bf39
Loading
Loading
Loading
Loading
+22 −2
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.fonts.FontFamily.Builder.VariableFontFamilyType;
import android.graphics.fonts.FontStyle;
import android.graphics.fonts.FontVariationAxis;
import android.os.Build;
@@ -528,6 +529,7 @@ public final class FontConfig implements Parcelable {
        private final @NonNull List<Font> mFonts;
        private final @NonNull LocaleList mLocaleList;
        private final @Variant int mVariant;
        private final int mVariableFontFamilyType;

        /** @hide */
        @Retention(SOURCE)
@@ -567,10 +569,11 @@ public final class FontConfig implements Parcelable {
         * @hide Only system server can create this instance and passed via IPC.
         */
        public FontFamily(@NonNull List<Font> fonts, @NonNull LocaleList localeList,
                @Variant int variant) {
                @Variant int variant, int variableFontFamilyType) {
            mFonts = fonts;
            mLocaleList = localeList;
            mVariant = variant;
            mVariableFontFamilyType = variableFontFamilyType;
        }

        /**
@@ -621,6 +624,20 @@ public final class FontConfig implements Parcelable {
            return mVariant;
        }

        /**
         * Returns the font family type.
         *
         * @see Builder#VARIABLE_FONT_FAMILY_TYPE_NONE
         * @see Builder#VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ITAL
         * @see Builder#VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ONLY
         * @see Builder#VARIABLE_FONT_FAMILY_TYPE_TWO_FONTS_WGHT
         * @hide
         * @return variable font family type.
         */
        public @VariableFontFamilyType int getVariableFontFamilyType() {
            return mVariableFontFamilyType;
        }

        @Override
        public int describeContents() {
            return 0;
@@ -631,6 +648,7 @@ public final class FontConfig implements Parcelable {
            dest.writeTypedList(mFonts, flags);
            dest.writeString8(mLocaleList.toLanguageTags());
            dest.writeInt(mVariant);
            dest.writeInt(mVariableFontFamilyType);
        }

        public static final @NonNull Creator<FontFamily> CREATOR = new Creator<FontFamily>() {
@@ -641,8 +659,10 @@ public final class FontConfig implements Parcelable {
                source.readTypedList(fonts, Font.CREATOR);
                String langTags = source.readString8();
                int variant = source.readInt();
                int varFamilyType = source.readInt();

                return new FontFamily(fonts, LocaleList.forLanguageTags(langTags), variant);
                return new FontFamily(fonts, LocaleList.forLanguageTags(langTags), variant,
                        varFamilyType);
            }

            @Override
+31 −8
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.fail;

import android.graphics.fonts.FontCustomizationParser;
import android.graphics.fonts.FontFamily;
import android.graphics.fonts.FontStyle;
import android.os.LocaleList;
import android.text.FontConfig;
@@ -64,7 +65,8 @@ public final class FontListParserTest {
                Collections.singletonList(new FontConfig.FontFamily(
                    Arrays.asList(new FontConfig.Font(new File("test.ttf"), null, "test",
                        new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT), 0, "", null)),
                    LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif");
                    LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT,
                        FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_NONE)), "sans-serif");
        FontConfig.NamedFamilyList family = readNamedFamily(xml);
        assertThat(family).isEqualTo(expected);
    }
@@ -84,7 +86,8 @@ public final class FontListParserTest {
                        new FontConfig.Font(new File("test.ttf"), null, "test",
                                new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
                                0, "", "serif")),
                LocaleList.forLanguageTags("en"), VARIANT_DEFAULT);
                LocaleList.forLanguageTags("en"), VARIANT_DEFAULT,
                FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_NONE);

        FontConfig.FontFamily family = readFamily(xml);
        assertThat(family).isEqualTo(expected);
@@ -101,7 +104,8 @@ public final class FontListParserTest {
                        new FontConfig.Font(new File("test.ttf"), null, "test",
                                new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
                                0, "", null)),
                LocaleList.forLanguageTags("en"), VARIANT_COMPACT);
                LocaleList.forLanguageTags("en"), VARIANT_COMPACT,
                FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_NONE);

        FontConfig.FontFamily family = readFamily(xml);
        assertThat(family).isEqualTo(expected);
@@ -118,7 +122,8 @@ public final class FontListParserTest {
                        new FontConfig.Font(new File("test.ttf"), null, "test",
                                new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
                                0, "", null)),
                LocaleList.forLanguageTags("en"), VARIANT_ELEGANT);
                LocaleList.forLanguageTags("en"), VARIANT_ELEGANT,
                FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_NONE);

        FontConfig.FontFamily family = readFamily(xml);
        assertThat(family).isEqualTo(expected);
@@ -140,7 +145,8 @@ public final class FontListParserTest {
                        new FontStyle(100, FONT_SLANT_UPRIGHT), 0, "", null),
                      new FontConfig.Font(new File("italic.ttf"), null, "test",
                        new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_ITALIC), 0, "", null)),
                    LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif");
                    LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT,
                        FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_NONE)), "sans-serif");
        FontConfig.NamedFamilyList family = readNamedFamily(xml);
        assertThat(family).isEqualTo(expected);
    }
@@ -166,7 +172,8 @@ public final class FontListParserTest {
                        new FontConfig.Font(new File("test-VF.ttf"), null, "test",
                                new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
                                0, "'wdth' 400.0,'wght' 700.0", null)),
                        LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)),
                        LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT,
                        FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_NONE)),
                "sans-serif");
        FontConfig.NamedFamilyList family = readNamedFamily(xml);
        assertThat(family).isEqualTo(expected);
@@ -187,7 +194,8 @@ public final class FontListParserTest {
                        new FontConfig.Font(new File("test.ttc"), null, "test",
                                new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
                                1, "", null)),
                                LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)),
                                LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT,
                        FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_NONE)),
                "sans-serif");
        FontConfig.NamedFamilyList family = readNamedFamily(xml);
        assertThat(family).isEqualTo(expected);
@@ -206,7 +214,8 @@ public final class FontListParserTest {
                        new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT), 0, "", null),
                      new FontConfig.Font(new File("test.ttc"), null, "test",
                        new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT), 1, "", null)),
                    LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif");
                    LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT,
                        FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_NONE)), "sans-serif");
        FontConfig.NamedFamilyList family = readNamedFamily(xml);
        assertThat(family).isEqualTo(expected);
    }
@@ -372,6 +381,20 @@ public final class FontListParserTest {
                .isEqualTo("emoji.ttf");
    }

    @Test
    public void varFamilyType() throws Exception {
        String xml = "<?xml version='1.0' encoding='UTF-8'?>"
                + "<familyset>"
                + "  <family name='sans-serif' varFamilyType='1'>"
                + "    <font>test.ttf</font>"
                + "  </family>"
                + "</familyset>";
        FontConfig config = readFamilies(xml, true /* include non-existing font files */);
        List<FontConfig.FontFamily> families = config.getFontFamilies();
        assertThat(families.size()).isEqualTo(1);  // legacy one should be ignored.
        assertThat(families.get(0).getVariableFontFamilyType()).isEqualTo(1);
    }

    private FontConfig readFamilies(String xml, boolean allowNonExisting)
            throws IOException, XmlPullParserException {
        ByteArrayInputStream buffer = new ByteArrayInputStream(
+82 −829

File changed.

Preview size limit exceeded, changes collapsed.

+40 −1
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package android.graphics;

import static android.graphics.fonts.FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_NONE;
import static android.graphics.fonts.FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ITAL;
import static android.graphics.fonts.FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ONLY;
import static android.graphics.fonts.FontFamily.Builder.VARIABLE_FONT_FAMILY_TYPE_TWO_FONTS_WGHT;
import static android.text.FontConfig.NamedFamilyList;

import android.annotation.NonNull;
@@ -28,6 +32,7 @@ import android.os.Build;
import android.os.LocaleList;
import android.text.FontConfig;
import android.util.ArraySet;
import android.util.Log;
import android.util.Xml;

import org.xmlpull.v1.XmlPullParser;
@@ -256,6 +261,7 @@ public class FontListParser {
        final String lang = parser.getAttributeValue("", "lang");
        final String variant = parser.getAttributeValue(null, "variant");
        final String ignore = parser.getAttributeValue(null, "ignore");
        final String varFamilyTypeStr = parser.getAttributeValue(null, "varFamilyType");
        final List<FontConfig.Font> fonts = new ArrayList<>();
        while (keepReading(parser)) {
            if (parser.getEventType() != XmlPullParser.START_TAG) continue;
@@ -278,12 +284,45 @@ public class FontListParser {
                intVariant = FontConfig.FontFamily.VARIANT_ELEGANT;
            }
        }
        int varFamilyType = VARIABLE_FONT_FAMILY_TYPE_NONE;
        if (varFamilyTypeStr != null) {
            varFamilyType = Integer.parseInt(varFamilyTypeStr);
            if (varFamilyType <= -1 || varFamilyType > 3) {
                Log.e(TAG, "Error: unexpected varFamilyType value: " + varFamilyTypeStr);
                varFamilyType = VARIABLE_FONT_FAMILY_TYPE_NONE;
            }

            // validation but don't read font content for performance reasons.
            switch (varFamilyType) {
                case VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ONLY:
                    if (fonts.size() != 1) {
                        Log.e(TAG, "Error: Single font support wght axis, but two or more fonts are"
                                + " included in the font family.");
                        varFamilyType = VARIABLE_FONT_FAMILY_TYPE_NONE;
                    }
                    break;
                case VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ITAL:
                    if (fonts.size() != 1) {
                        Log.e(TAG, "Error: Single font support both ital and wght axes, but two or"
                                + " more fonts are included in the font family.");
                        varFamilyType = VARIABLE_FONT_FAMILY_TYPE_NONE;
                    }
                    break;
                case VARIABLE_FONT_FAMILY_TYPE_TWO_FONTS_WGHT:
                    if (fonts.size() != 2) {
                        Log.e(TAG, "Error: two fonts that support wght axis, but one or three or"
                                + " more fonts are included in the font family.");
                        varFamilyType = VARIABLE_FONT_FAMILY_TYPE_NONE;
                    }
            }
        }

        boolean skip = (ignore != null && (ignore.equals("true") || ignore.equals("1")));
        if (skip || fonts.isEmpty()) {
            return null;
        }
        return new FontConfig.FontFamily(fonts, LocaleList.forLanguageTags(lang), intVariant);
        return new FontConfig.FontFamily(fonts, LocaleList.forLanguageTags(lang), intVariant,
                varFamilyType);
    }

    private static void throwIfAttributeExists(String attrName, XmlPullParser parser) {
+34 −1
Original line number Diff line number Diff line
@@ -18,7 +18,10 @@ package android.graphics.fonts;

import static com.android.text.flags.Flags.FLAG_DEPRECATE_FONTS_XML;

import static java.lang.annotation.RetentionPolicy.SOURCE;

import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -32,6 +35,7 @@ import dalvik.annotation.optimization.FastNative;

import libcore.util.NativeAllocationRegistry;

import java.lang.annotation.Retention;
import java.util.ArrayList;
import java.util.Set;

@@ -184,32 +188,59 @@ public final class FontFamily {
        }

        /**
         * A special variable font family type that indicates `analyzeAndResolveVariableType` could
         * not be identified the variable font family type.
         *
         * @see #buildVariableFamily()
         * @hide
         */
        public static final int VARIABLE_FONT_FAMILY_TYPE_UNKNOWN = -1;

        /**
         * A variable font family type that indicates no variable font family can be used.
         *
         * The font family is used as bundle of static fonts.
         * @see #buildVariableFamily()
         * @hide
         */
        public static final int VARIABLE_FONT_FAMILY_TYPE_NONE = 0;
        /**
         * A variable font family type that indicates single font file can be used for multiple
         * weight. For the italic style, fake italic may be applied.
         *
         * @see #buildVariableFamily()
         * @hide
         */
        public static final int VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ONLY = 1;
        /**
         * A variable font family type that indicates single font file can be used for multiple
         * weight and italic.
         *
         * @see #buildVariableFamily()
         * @hide
         */
        public static final int VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ITAL = 2;
        /**
         * A variable font family type that indicates two font files are included in the family:
         * one can be used for upright with various weights, the other one can be used for italic
         * with various weights.
         *
         * @see #buildVariableFamily()
         * @hide
         */
        public static final int VARIABLE_FONT_FAMILY_TYPE_TWO_FONTS_WGHT = 3;

        /** @hide */
        @Retention(SOURCE)
        @IntDef(prefix = { "VARIABLE_FONT_FAMILY_TYPE_" }, value = {
                VARIABLE_FONT_FAMILY_TYPE_UNKNOWN,
                VARIABLE_FONT_FAMILY_TYPE_NONE,
                VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ONLY,
                VARIABLE_FONT_FAMILY_TYPE_SINGLE_FONT_WGHT_ITAL,
                VARIABLE_FONT_FAMILY_TYPE_TWO_FONTS_WGHT
        })
        public @interface VariableFontFamilyType {}

        /**
         * The registered italic axis used for adjusting requested style.
         * https://learn.microsoft.com/en-us/typography/opentype/spec/dvaraxistag_ital
@@ -222,7 +253,9 @@ public final class FontFamily {
         */
        private static final int TAG_wght = 0x77676874;  // w(0x77), g(0x67), h(0x68), t(0x74)

        private static int analyzeAndResolveVariableType(ArrayList<Font> fonts) {
        /** @hide */
        public static @VariableFontFamilyType int analyzeAndResolveVariableType(
                ArrayList<Font> fonts) {
            if (fonts.size() > 2) {
                return VARIABLE_FONT_FAMILY_TYPE_UNKNOWN;
            }
Loading