| /* |
| * Copyright (C) 2017 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.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.annotation.UnsupportedAppUsage; |
| import android.os.Build; |
| import android.text.TextUtils; |
| |
| import java.util.ArrayList; |
| import java.util.regex.Pattern; |
| |
| /** |
| * Class that holds information about single font variation axis. |
| */ |
| public final class FontVariationAxis { |
| @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) |
| private final int mTag; |
| private final String mTagString; |
| @UnsupportedAppUsage |
| private final float mStyleValue; |
| |
| /** |
| * Construct FontVariationAxis. |
| * |
| * The axis tag must contain four ASCII characters. Tag string that are longer or shorter than |
| * four characters, or contains characters outside of U+0020..U+007E are invalid. |
| * |
| * @throws IllegalArgumentException If given tag string is invalid. |
| */ |
| public FontVariationAxis(@NonNull String tagString, float styleValue) { |
| if (!isValidTag(tagString)) { |
| throw new IllegalArgumentException("Illegal tag pattern: " + tagString); |
| } |
| mTag = makeTag(tagString); |
| mTagString = tagString; |
| mStyleValue = styleValue; |
| } |
| |
| /** |
| * Returns the OpenType style tag value. |
| * @hide |
| */ |
| public int getOpenTypeTagValue() { |
| return mTag; |
| } |
| |
| /** |
| * Returns the variable font axis tag associated to this axis. |
| */ |
| public String getTag() { |
| return mTagString; |
| } |
| |
| /** |
| * Returns the style value associated to the given axis for this font. |
| */ |
| public float getStyleValue() { |
| return mStyleValue; |
| } |
| |
| /** |
| * Returns a valid font variation setting string for this object. |
| */ |
| @Override |
| public @NonNull String toString() { |
| return "'" + mTagString + "' " + Float.toString(mStyleValue); |
| } |
| |
| /** |
| * The 'tag' attribute value is read as four character values between U+0020 and U+007E |
| * inclusive. |
| */ |
| private static final Pattern TAG_PATTERN = Pattern.compile("[\u0020-\u007E]{4}"); |
| |
| /** |
| * Returns true if 'tagString' is valid for font variation axis tag. |
| */ |
| private static boolean isValidTag(String tagString) { |
| return tagString != null && TAG_PATTERN.matcher(tagString).matches(); |
| } |
| |
| /** |
| * The 'styleValue' attribute has an optional leading '-', followed by '<digits>', |
| * '<digits>.<digits>', or '.<digits>' where '<digits>' is one or more of [0-9]. |
| */ |
| private static final Pattern STYLE_VALUE_PATTERN = |
| Pattern.compile("-?(([0-9]+(\\.[0-9]+)?)|(\\.[0-9]+))"); |
| |
| private static boolean isValidValueFormat(String valueString) { |
| return valueString != null && STYLE_VALUE_PATTERN.matcher(valueString).matches(); |
| } |
| |
| /** @hide */ |
| public static int makeTag(String tagString) { |
| final char c1 = tagString.charAt(0); |
| final char c2 = tagString.charAt(1); |
| final char c3 = tagString.charAt(2); |
| final char c4 = tagString.charAt(3); |
| return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4; |
| } |
| |
| /** |
| * Construct FontVariationAxis array from font variation settings. |
| * |
| * The settings string is constructed from multiple pairs of axis tag and style values. The axis |
| * tag must contain four ASCII characters and must be wrapped with single quotes (U+0027) or |
| * double quotes (U+0022). Axis strings that are longer or shorter than four characters, or |
| * contain characters outside of U+0020..U+007E are invalid. If a specified axis name is not |
| * defined in the font, the settings will be ignored. |
| * |
| * <pre> |
| * FontVariationAxis.fromFontVariationSettings("'wdth' 1.0"); |
| * FontVariationAxis.fromFontVariationSettings("'AX ' 1.0, 'FB ' 2.0"); |
| * </pre> |
| * |
| * @param settings font variation settings. |
| * @return FontVariationAxis[] the array of parsed font variation axis. {@code null} if settings |
| * has no font variation settings. |
| * @throws IllegalArgumentException If given string is not a valid font variation settings |
| * format. |
| */ |
| public static @Nullable FontVariationAxis[] fromFontVariationSettings( |
| @Nullable String settings) { |
| if (settings == null || settings.isEmpty()) { |
| return null; |
| } |
| final ArrayList<FontVariationAxis> axisList = new ArrayList<>(); |
| final int length = settings.length(); |
| for (int i = 0; i < length; i++) { |
| final char c = settings.charAt(i); |
| if (Character.isWhitespace(c)) { |
| continue; |
| } |
| if (!(c == '\'' || c == '"') || length < i + 6 || settings.charAt(i + 5) != c) { |
| throw new IllegalArgumentException( |
| "Tag should be wrapped with double or single quote: " + settings); |
| } |
| final String tagString = settings.substring(i + 1, i + 5); |
| |
| i += 6; // Move to end of tag. |
| int endOfValueString = settings.indexOf(',', i); |
| if (endOfValueString == -1) { |
| endOfValueString = length; |
| } |
| final float value; |
| try { |
| // Float.parseFloat ignores leading/trailing whitespaces. |
| value = Float.parseFloat(settings.substring(i, endOfValueString)); |
| } catch (NumberFormatException e) { |
| throw new IllegalArgumentException( |
| "Failed to parse float string: " + e.getMessage()); |
| } |
| axisList.add(new FontVariationAxis(tagString, value)); |
| i = endOfValueString; |
| } |
| if (axisList.isEmpty()) { |
| return null; |
| } |
| return axisList.toArray(new FontVariationAxis[0]); |
| } |
| |
| /** |
| * Stringify the array of FontVariationAxis. |
| * |
| * @param axes an array of FontVariationAxis. |
| * @return String a valid font variation settings string. |
| */ |
| public static @NonNull String toFontVariationSettings(@Nullable FontVariationAxis[] axes) { |
| if (axes == null) { |
| return ""; |
| } |
| return TextUtils.join(",", axes); |
| } |
| } |
| |