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

Commit e4b016ec authored by Yirui Huang's avatar Yirui Huang Committed by Android (Google) Code Review
Browse files

Merge "Introduce font variation settings parser"

parents 5ab97721 3002ab67
Loading
Loading
Loading
Loading
+64 −4
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import com.android.internal.annotations.VisibleForTesting;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -99,6 +101,67 @@ public class FontListParser {
        }
    }

    // Note that a well-formed variation contains a four-character tag and a float as styleValue,
    // with spacers in between. The tag is enclosd either by double quotes or single quotes.
    @VisibleForTesting
    public static Axis[] parseFontVariationSettings(String settings) {
        String[] settingList = settings.split(",");
        ArrayList<Axis> axisList = new ArrayList<>();
        settingLoop:
        for (String setting : settingList) {
            int pos = 0;
            while (pos < setting.length()) {
                char c = setting.charAt(pos);
                if (c == '\'' || c == '"') {
                    break;
                } else if (!isSpacer(c)) {
                    continue settingLoop;  // Only spacers are allowed before tag appeared.
                }
                pos++;
            }
            if (pos + 7 > setting.length()) {
                continue;  // 7 is the minimum length of tag-style value pair text.
            }
            if (setting.charAt(pos) != setting.charAt(pos + 5)) {
                continue;  // Tag should be wrapped with double or single quote.
            }
            String tagString = setting.substring(pos + 1, pos + 5);
            if (!TAG_PATTERN.matcher(tagString).matches()) {
                continue;  // Skip incorrect format tag.
            }
            pos += 6;
            while (pos < setting.length()) {
                if (!isSpacer(setting.charAt(pos++))) {
                    break;  // Skip spacers between the tag and the styleValue.
                }
            }
            // Skip invalid styleValue
            float styleValue;
            String valueString = setting.substring(pos - 1);
            if (!STYLE_VALUE_PATTERN.matcher(valueString).matches()) {
                continue;  // Skip incorrect format styleValue.
            }
            try {
                styleValue = Float.parseFloat(valueString);
            } catch (NumberFormatException e) {
                continue;  // ignoreing invalid number format
            }
            int tag = makeTag(tagString.charAt(0), tagString.charAt(1), tagString.charAt(2),
                    tagString.charAt(3));
            axisList.add(new Axis(tag, styleValue));
        }
        return axisList.toArray(new Axis[axisList.size()]);
    }

    @VisibleForTesting
    public static int makeTag(char c1, char c2, char c3, char c4) {
        return (c1 << 24) + (c2 << 16) + (c3 << 8) + c4;
    }

    private static boolean isSpacer(char c) {
        return c == ' ' || c == '\r' || c == '\t' || c == '\n';
    }

    private static Config readFamilies(XmlPullParser parser)
            throws XmlPullParserException, IOException {
        Config config = new Config();
@@ -179,10 +242,7 @@ public class FontListParser {
        int tag = 0;
        String tagStr = parser.getAttributeValue(null, "tag");
        if (tagStr != null && TAG_PATTERN.matcher(tagStr).matches()) {
            tag = (tagStr.charAt(0) << 24) +
                  (tagStr.charAt(1) << 16) +
                  (tagStr.charAt(2) <<  8) +
                  (tagStr.charAt(3)      );
            tag = makeTag(tagStr.charAt(0), tagStr.charAt(1), tagStr.charAt(2), tagStr.charAt(3));
        } else {
            throw new XmlPullParserException("Invalid tag attribute value.", parser, null);
        }
+113 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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;

import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.TestCase;


public class VariationParserTest extends TestCase {

    @SmallTest
    public void testParseFontVariationSetting() {
        int tag = FontListParser.makeTag('w', 'd', 't', 'h');
        FontListParser.Axis[] axis = FontListParser.parseFontVariationSettings("'wdth' 1");
        assertEquals(tag, axis[0].tag);
        assertEquals(1.0f, axis[0].styleValue);

        axis = FontListParser.parseFontVariationSettings("\"wdth\" 100");
        assertEquals(tag, axis[0].tag);
        assertEquals(100.0f, axis[0].styleValue);

        axis = FontListParser.parseFontVariationSettings("   'wdth' 100");
        assertEquals(tag, axis[0].tag);
        assertEquals(100.0f, axis[0].styleValue);

        axis = FontListParser.parseFontVariationSettings("\t'wdth' 0.5");
        assertEquals(tag, axis[0].tag);
        assertEquals(0.5f, axis[0].styleValue);

        tag = FontListParser.makeTag('A', 'X', ' ', ' ');
        axis = FontListParser.parseFontVariationSettings("'AX  ' 1");
        assertEquals(tag, axis[0].tag);
        assertEquals(1.0f, axis[0].styleValue);

        axis = FontListParser.parseFontVariationSettings("'AX  '\t1");
        assertEquals(tag, axis[0].tag);
        assertEquals(1.0f, axis[0].styleValue);

        axis = FontListParser.parseFontVariationSettings("'AX  '\n1");
        assertEquals(tag, axis[0].tag);
        assertEquals(1.0f, axis[0].styleValue);

        axis = FontListParser.parseFontVariationSettings("'AX  '\r1");
        assertEquals(tag, axis[0].tag);
        assertEquals(1.0f, axis[0].styleValue);

        axis = FontListParser.parseFontVariationSettings("'AX  '\r\t\n 1");
        assertEquals(tag, axis[0].tag);
        assertEquals(1.0f, axis[0].styleValue);

        // Test for invalid input
        axis = FontListParser.parseFontVariationSettings("");
        assertEquals(0, axis.length);
        axis = FontListParser.parseFontVariationSettings("invalid_form");
        assertEquals(0, axis.length);

        // Test with invalid tag
        axis = FontListParser.parseFontVariationSettings("'' 1");
        assertEquals(0, axis.length);
        axis = FontListParser.parseFontVariationSettings("'invalid' 1");
        assertEquals(0, axis.length);

        // Test with invalid styleValue
        axis = FontListParser.parseFontVariationSettings("'wdth' ");
        assertEquals(0, axis.length);
        axis = FontListParser.parseFontVariationSettings("'wdth' x");
        assertEquals(0, axis.length);
        axis = FontListParser.parseFontVariationSettings("'wdth' \t");
        assertEquals(0, axis.length);
        axis = FontListParser.parseFontVariationSettings("'wdth' \n\r");
        assertEquals(0, axis.length);
    }

    @SmallTest
    public void testParseFontVariationStyleSettings() {
        FontListParser.Axis[] axis =
                FontListParser.parseFontVariationSettings("'wdth' 10,'AX  '\r1");
        int tag1 = FontListParser.makeTag('w', 'd', 't', 'h');
        int tag2 = FontListParser.makeTag('A', 'X', ' ', ' ');
        assertEquals(tag1, axis[0].tag);
        assertEquals(10.0f, axis[0].styleValue);
        assertEquals(tag2, axis[1].tag);
        assertEquals(1.0f, axis[1].styleValue);

        // Test only spacers are allowed before tag
        axis = FontListParser.parseFontVariationSettings("     'wdth' 10,ab'wdth' 1");
        tag1 = FontListParser.makeTag('w', 'd', 't', 'h');
        assertEquals(tag1, axis[0].tag);
        assertEquals(10.0f, axis[0].styleValue);
        assertEquals(1, axis.length);
    }

    @SmallTest
    public void testMakeTag() {
      assertEquals(0x77647468, FontListParser.makeTag('w', 'd', 't', 'h'));
      assertEquals(0x41582020, FontListParser.makeTag('A', 'X', ' ', ' '));
      assertEquals(0x20202020, FontListParser.makeTag(' ', ' ', ' ', ' '));
    }
}
 No newline at end of file