OSDN Git Service

Remove FontVariationAxis.InvalidFormatException.
[android-x86/frameworks-base.git] / graphics / java / android / graphics / fonts / FontVariationAxis.java
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package android.graphics.fonts;
18
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.text.TextUtils;
22
23 import java.util.ArrayList;
24 import java.util.regex.Pattern;
25
26 /**
27  * Class that holds information about single font variation axis.
28  */
29 public final class FontVariationAxis {
30     private final int mTag;
31     private final String mTagString;
32     private final float mStyleValue;
33
34     /**
35      * Construct FontVariationAxis.
36      *
37      * The axis tag must contain four ASCII characters. Tag string that are longer or shorter than
38      * four characters, or contains characters outside of U+0020..U+007E are invalid.
39      *
40      * @throws IllegalArgumentException If given tag string is invalid.
41      */
42     public FontVariationAxis(@NonNull String tagString, float styleValue) {
43         if (!isValidTag(tagString)) {
44             throw new IllegalArgumentException("Illegal tag pattern: " + tagString);
45         }
46         mTag = makeTag(tagString);
47         mTagString = tagString;
48         mStyleValue = styleValue;
49     }
50
51     /**
52      * Returns the OpenType style tag value.
53      * @hide
54      */
55     public int getOpenTypeTagValue() {
56         return mTag;
57     }
58
59     /**
60      * Returns the variable font axis tag associated to this axis.
61      */
62     public String getTag() {
63         return mTagString;
64     }
65
66     /**
67      * Returns the style value associated to the given axis for this font.
68      */
69     public float getStyleValue() {
70         return mStyleValue;
71     }
72
73     /**
74      * Returns a valid font variation setting string for this object.
75      */
76     @Override
77     public @NonNull String toString() {
78         return "'" + mTagString + "' " + Float.toString(mStyleValue);
79     }
80
81     /**
82      * The 'tag' attribute value is read as four character values between U+0020 and U+007E
83      * inclusive.
84      */
85     private static final Pattern TAG_PATTERN = Pattern.compile("[\u0020-\u007E]{4}");
86
87     /**
88      * Returns true if 'tagString' is valid for font variation axis tag.
89      */
90     private static boolean isValidTag(String tagString) {
91         return tagString != null && TAG_PATTERN.matcher(tagString).matches();
92     }
93
94     /**
95      * The 'styleValue' attribute has an optional leading '-', followed by '<digits>',
96      * '<digits>.<digits>', or '.<digits>' where '<digits>' is one or more of [0-9].
97      */
98     private static final Pattern STYLE_VALUE_PATTERN =
99             Pattern.compile("-?(([0-9]+(\\.[0-9]+)?)|(\\.[0-9]+))");
100
101     private static boolean isValidValueFormat(String valueString) {
102         return valueString != null && STYLE_VALUE_PATTERN.matcher(valueString).matches();
103     }
104
105     /** @hide */
106     public static int makeTag(String tagString) {
107         final char c1 = tagString.charAt(0);
108         final char c2 = tagString.charAt(1);
109         final char c3 = tagString.charAt(2);
110         final char c4 = tagString.charAt(3);
111         return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
112     }
113
114     /**
115      * Construct FontVariationAxis array from font variation settings.
116      *
117      * The settings string is constructed from multiple pairs of axis tag and style values. The axis
118      * tag must contain four ASCII characters and must be wrapped with single quotes (U+0027) or
119      * double quotes (U+0022). Axis strings that are longer or shorter than four characters, or
120      * contain characters outside of U+0020..U+007E are invalid. If a specified axis name is not
121      * defined in the font, the settings will be ignored.
122      *
123      * <pre>
124      *   FontVariationAxis.fromFontVariationSettings("'wdth' 1.0");
125      *   FontVariationAxis.fromFontVariationSettings("'AX  ' 1.0, 'FB  ' 2.0");
126      * </pre>
127      *
128      * @param settings font variation settings.
129      * @return FontVariationAxis[] the array of parsed font variation axis. {@code null} if settings
130      *                             has no font variation settings.
131      * @throws IllegalArgumentException If given string is not a valid font variation settings
132      *                                  format.
133      */
134     public static @Nullable FontVariationAxis[] fromFontVariationSettings(
135             @Nullable String settings) {
136         if (settings == null || settings.isEmpty()) {
137             return null;
138         }
139         final ArrayList<FontVariationAxis> axisList = new ArrayList<>();
140         final int length = settings.length();
141         for (int i = 0; i < length; i++) {
142             final char c = settings.charAt(i);
143             if (Character.isWhitespace(c)) {
144                 continue;
145             }
146             if (!(c == '\'' || c == '"') || length < i + 6 || settings.charAt(i + 5) != c) {
147                 throw new IllegalArgumentException(
148                         "Tag should be wrapped with double or single quote: " + settings);
149             }
150             final String tagString = settings.substring(i + 1, i + 5);
151
152             i += 6;  // Move to end of tag.
153             int endOfValueString = settings.indexOf(',', i);
154             if (endOfValueString == -1) {
155                 endOfValueString = length;
156             }
157             final float value;
158             try {
159                 // Float.parseFloat ignores leading/trailing whitespaces.
160                 value = Float.parseFloat(settings.substring(i, endOfValueString));
161             } catch (NumberFormatException e) {
162                 throw new IllegalArgumentException(
163                         "Failed to parse float string: " + e.getMessage());
164             }
165             axisList.add(new FontVariationAxis(tagString, value));
166             i = endOfValueString;
167         }
168         if (axisList.isEmpty()) {
169             return null;
170         }
171         return axisList.toArray(new FontVariationAxis[0]);
172     }
173
174     /**
175      * Stringify the array of FontVariationAxis.
176      *
177      * @param axes an array of FontVariationAxis.
178      * @return String a valid font variation settings string.
179      */
180     public static @NonNull String toFontVariationSettings(@Nullable FontVariationAxis[] axes) {
181         if (axes == null || axes.length == 0) {
182             return "";
183         }
184         return TextUtils.join(",", axes);
185     }
186 }
187