Home | History | Annotate | Download | only in fonts
      1 /*
      2  * Copyright 2018 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 static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertNotEquals;
     21 
     22 import android.graphics.Typeface;
     23 import android.graphics.cts.R;
     24 import android.text.TextPaint;
     25 import android.util.Pair;
     26 
     27 import java.util.ArrayList;
     28 import java.util.Collections;
     29 import java.util.HashMap;
     30 import java.util.List;
     31 import java.util.Locale;
     32 import java.util.Map;
     33 
     34 /**
     35  * Provides a utility for testing fonts
     36  *
     37  * For the purpose of testing font selection of families or fallbacks, this class provies following
     38  * regular font files.
     39  *
     40  * - ascii_a3em_weight100_upright.ttf
     41  *   'a' has 3em width and others have 1em width. The metadata has weight=100, non-italic value.
     42  * - ascii_b3em_weight100_italic.ttf
     43  *   'b' has 3em width and others have 1em width. The metadata has weight=100, italic value.
     44  * - ascii_c3em_weight200_upright.ttf
     45  *   'c' has 3em width and others have 1em width. The metadata has weight=200, non-italic value.
     46  * - ascii_d3em_weight200_italic.ttf
     47  *   'd' has 3em width and others have 1em width. The metadata has weight=200, italic value.
     48  * - ascii_e3em_weight300_upright.ttf
     49  *   'e' has 3em width and others have 1em width. The metadata has weight=300, non-italic value.
     50  * - ascii_f3em_weight300_italic.ttf
     51  *   'f' has 3em width and others have 1em width. The metadata has weight=300, italic value.
     52  * - ascii_g3em_weight400_upright.ttf
     53  *   'g' has 3em width and others have 1em width. The metadata has weight=400, non-italic value.
     54  * - ascii_h3em_weight400_italic.ttf
     55  *   'h' has 3em width and others have 1em width. The metadata has weight=400, italic value.
     56  * - ascii_i3em_weight500_upright.ttf
     57  *   'i' has 3em width and others have 1em width. The metadata has weight=500, non-italic value.
     58  * - ascii_j3em_weight500_italic.ttf
     59  *   'j' has 3em width and others have 1em width. The metadata has weight=500, italic value.
     60  * - ascii_k3em_weight600_upright.ttf
     61  *   'k' has 3em width and others have 1em width. The metadata has weight=600, non-italic value.
     62  * - ascii_l3em_weight600_italic.ttf
     63  *   'l' has 3em width and others have 1em width. The metadata has weight=600, italic value.
     64  * - ascii_m3em_weight700_upright.ttf
     65  *   'm' has 3em width and others have 1em width. The metadata has weight=700, non-italic value.
     66  * - ascii_n3em_weight700_italic.ttf
     67  *   'n' has 3em width and others have 1em width. The metadata has weight=700, italic value.
     68  * - ascii_o3em_weight800_upright.ttf
     69  *   'o' has 3em width and others have 1em width. The metadata has weight=800, non-italic value.
     70  * - ascii_p3em_weight800_italic.ttf
     71  *   'p' has 3em width and others have 1em width. The metadata has weight=800, italic value.
     72  * - ascii_q3em_weight900_upright.ttf
     73  *   'q' has 3em width and others have 1em width. The metadata has weight=900, non-italic value.
     74  * - ascii_r3em_weight900_italic.ttf
     75  *   'r' has 3em width and others have 1em width. The metadata has weight=900, italic value.
     76  *
     77  * In addition to above font files, this class provides a font collection file and a variable font
     78  * file.
     79  * - ascii.ttc
     80  *   The collection of above 18 fonts with above order.
     81  * - ascii_vf.ttf
     82  *   This font supports a-z characters and all characters has 1em width. This font supports 'wght',
     83  *   'ital' axes but no effect for the glyph width. This font also supports 'Asc[a-z]' 26 axes which
     84  *   makes glyph width 3em. For example, 'Asca 1.0' makes a glyph width of 'a' 3em, 'Ascb 1.0' makes
     85  *   a glyph width of 'b' 3em. With these axes, above font can be replicated like
     86  *   - 'Asca' 1.0, 'wght' 100.0' is equivalent with ascii_a3em_width100_upright.ttf
     87  *   - 'Ascb' 1.0, 'wght' 100.0, 'ital' 1.0' is equivalent with ascii_b3em_width100_italic.ttf
     88  */
     89 public class FontTestUtil {
     90     private static final String FAMILY_SELECTION_FONT_PATH_IN_ASSET = "fonts/family_selection";
     91     private static final List<Pair<Integer, Boolean>> sStyleList;
     92     private static final Map<Pair<Integer, Boolean>, String> sFontMap;
     93     private static final Map<Pair<Integer, Boolean>, Integer> sTtcMap;
     94     private static final Map<Pair<Integer, Boolean>, String> sVariationSettingsMap;
     95     private static final Map<Pair<Integer, Boolean>, Integer> sResourceMap;
     96     private static final String[] sFontList = {  // Same order of ascii.ttc
     97             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_a3em_weight100_upright.ttf",
     98             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_b3em_weight100_italic.ttf",
     99             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_c3em_weight200_upright.ttf",
    100             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_d3em_weight200_italic.ttf",
    101             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_e3em_weight300_upright.ttf",
    102             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_f3em_weight300_italic.ttf",
    103             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_g3em_weight400_upright.ttf",
    104             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_h3em_weight400_italic.ttf",
    105             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_i3em_weight500_upright.ttf",
    106             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_j3em_weight500_italic.ttf",
    107             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_k3em_weight600_upright.ttf",
    108             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_l3em_weight600_italic.ttf",
    109             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_m3em_weight700_upright.ttf",
    110             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_n3em_weight700_italic.ttf",
    111             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_o3em_weight800_upright.ttf",
    112             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_p3em_weight800_italic.ttf",
    113             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_q3em_weight900_upright.ttf",
    114             FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_r3em_weight900_italic.ttf",
    115     };
    116 
    117     private static final String[] FONT_VARIATION_SETTING_LIST = {
    118             "'Asca' 1.0, 'wght' 100.0",
    119             "'Ascb' 1.0, 'wght' 100.0, 'ital' 1.0",
    120             "'Ascc' 1.0, 'wght' 200.0",
    121             "'Ascd' 1.0, 'wght' 200.0, 'ital' 1.0",
    122             "'Asce' 1.0, 'wght' 300.0",
    123             "'Ascf' 1.0, 'wght' 300.0, 'ital' 1.0",
    124             "'Ascg' 1.0, 'wght' 400.0",
    125             "'Asch' 1.0, 'wght' 400.0, 'ital' 1.0",
    126             "'Asci' 1.0, 'wght' 500.0",
    127             "'Ascj' 1.0, 'wght' 500.0, 'ital' 1.0",
    128             "'Asck' 1.0, 'wght' 600.0",
    129             "'Ascl' 1.0, 'wght' 600.0, 'ital' 1.0",
    130             "'Ascm' 1.0, 'wght' 700.0",
    131             "'Ascn' 1.0, 'wght' 700.0, 'ital' 1.0",
    132             "'Asco' 1.0, 'wght' 800.0",
    133             "'Ascp' 1.0, 'wght' 800.0, 'ital' 1.0",
    134             "'Ascq' 1.0, 'wght' 900.0",
    135             "'Ascr' 1.0, 'wght' 900.0, 'ital' 1.0",
    136     };
    137 
    138     private static final int[] FONT_RESOURCE_ID_LIST = {
    139             R.font.ascii_a3em_weight100_upright,
    140             R.font.ascii_b3em_weight100_italic,
    141             R.font.ascii_c3em_weight200_upright,
    142             R.font.ascii_d3em_weight200_italic,
    143             R.font.ascii_e3em_weight300_upright,
    144             R.font.ascii_f3em_weight300_italic,
    145             R.font.ascii_g3em_weight400_upright,
    146             R.font.ascii_h3em_weight400_italic,
    147             R.font.ascii_i3em_weight500_upright,
    148             R.font.ascii_j3em_weight500_italic,
    149             R.font.ascii_k3em_weight600_upright,
    150             R.font.ascii_l3em_weight600_italic,
    151             R.font.ascii_m3em_weight700_upright,
    152             R.font.ascii_n3em_weight700_italic,
    153             R.font.ascii_o3em_weight800_upright,
    154             R.font.ascii_p3em_weight800_italic,
    155             R.font.ascii_q3em_weight900_upright,
    156             R.font.ascii_r3em_weight900_italic,
    157     };
    158 
    159     private static final char[] CHAR_3EM_WIDTH = {
    160             'a',
    161             'b',
    162             'c',
    163             'd',
    164             'e',
    165             'f',
    166             'g',
    167             'h',
    168             'i',
    169             'j',
    170             'k',
    171             'l',
    172             'm',
    173             'n',
    174             'o',
    175             'p',
    176             'q',
    177             'r',
    178     };
    179 
    180     static {
    181         // Style list with the same order of sFontList.
    182         ArrayList<Pair<Integer, Boolean>> styles = new ArrayList<>();
    183         styles.add(new Pair<>(100, false));
    184         styles.add(new Pair<>(100, true));
    185         styles.add(new Pair<>(200, false));
    186         styles.add(new Pair<>(200, true));
    187         styles.add(new Pair<>(300, false));
    188         styles.add(new Pair<>(300, true));
    189         styles.add(new Pair<>(400, false));
    190         styles.add(new Pair<>(400, true));
    191         styles.add(new Pair<>(500, false));
    192         styles.add(new Pair<>(500, true));
    193         styles.add(new Pair<>(600, false));
    194         styles.add(new Pair<>(600, true));
    195         styles.add(new Pair<>(700, false));
    196         styles.add(new Pair<>(700, true));
    197         styles.add(new Pair<>(800, false));
    198         styles.add(new Pair<>(800, true));
    199         styles.add(new Pair<>(900, false));
    200         styles.add(new Pair<>(900, true));
    201         sStyleList = Collections.unmodifiableList(styles);
    202 
    203         HashMap<Pair<Integer, Boolean>, String> map = new HashMap<>();
    204         HashMap<Pair<Integer, Boolean>, Integer> ttcMap = new HashMap<>();
    205         HashMap<Pair<Integer, Boolean>, String> variationMap = new HashMap<>();
    206         HashMap<Pair<Integer, Boolean>, Integer> resourceMap = new HashMap<>();
    207         HashMap<Character, Pair<Integer, Boolean>> reverseMap = new HashMap<>();
    208         for (int i = 0; i < sFontList.length; ++i) {
    209             map.put(sStyleList.get(i), sFontList[i]);
    210             ttcMap.put(sStyleList.get(i), i);
    211             variationMap.put(sStyleList.get(i), FONT_VARIATION_SETTING_LIST[i]);
    212             resourceMap.put(sStyleList.get(i), FONT_RESOURCE_ID_LIST[i]);
    213         }
    214         sFontMap = Collections.unmodifiableMap(map);
    215         sTtcMap = Collections.unmodifiableMap(ttcMap);
    216         sVariationSettingsMap = Collections.unmodifiableMap(variationMap);
    217         sResourceMap = Collections.unmodifiableMap(resourceMap);
    218     }
    219 
    220     /**
    221      * Measure a character with 100px text size
    222      */
    223     private static float measureChar(Typeface typeface, char c) {
    224         final TextPaint tp = new TextPaint();
    225         tp.setTextSize(100);
    226         tp.setTypeface(typeface);
    227         tp.setTextLocale(Locale.US);
    228         return tp.measureText(new char[] { c }, 0, 1);
    229     }
    230 
    231     /**
    232      * Returns a path to the font collection file in asset directory.
    233      */
    234     public static String getTtcFontFileInAsset() {
    235         return FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ascii.ttc";
    236     }
    237 
    238     /**
    239      * Returns a resource id for the font collection file.
    240      */
    241     public static int getTtcFontFileResourceId() {
    242         return R.font.ascii;
    243     }
    244 
    245     /**
    246      * Returns a path to the variable font file in asset directory.
    247      */
    248     public static String getVFFontInAsset() {
    249         return FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ascii_vf.ttf";
    250     }
    251 
    252     /**
    253      * Returns a resource id for the variable font.
    254      */
    255     public static int getVFFontResourceId() {
    256         return R.font.ascii_vf;
    257     }
    258 
    259     /**
    260      * Returns a ttc index of the specified style.
    261      */
    262     public static int getTtcIndexFromStyle(int weight, boolean italic) {
    263         return sTtcMap.get(new Pair<>(weight, italic)).intValue();
    264     }
    265 
    266     /**
    267      * Returns a variation settings string of the specified style.
    268      */
    269     public static String getVarSettingsFromStyle(int weight, boolean italic) {
    270         return sVariationSettingsMap.get(new Pair<>(weight, italic));
    271     }
    272 
    273     /**
    274      * Returns a font resource ID of the specific style.
    275      */
    276     public static int getFontResourceIdFromStyle(int weight, boolean italic) {
    277         return sResourceMap.get(new Pair<>(weight, italic));
    278     }
    279 
    280     /**
    281      * Returns a font path from the specified style.
    282      */
    283     public static String getFontPathFromStyle(int weight, boolean italic) {
    284         return sFontMap.get(new Pair<>(weight, italic));
    285     }
    286 
    287     /**
    288      * Returns all supported styles.
    289      *
    290      * @return a pair of weight and style(uplight/italic)
    291      */
    292     public static List<Pair<Integer, Boolean>> getAllStyles() {
    293         return sStyleList;
    294     }
    295 
    296     /**
    297      * Returns selected font index in the sStyleList array.
    298      */
    299     private static int getSelectedFontStyle(Typeface typeface) {
    300         int indexOf3Em = -1;
    301         for (int i = 0; i < CHAR_3EM_WIDTH.length; ++i) {
    302             if (measureChar(typeface, CHAR_3EM_WIDTH[i]) == 300.0f) {
    303                 assertEquals("A font has two 3em width character. Likely the wrong test setup.",
    304                         -1, indexOf3Em);
    305                 indexOf3Em = i;
    306             }
    307         }
    308         assertNotEquals("No font has 3em width character. Likely the wrong test setup.",
    309                 -1, indexOf3Em);
    310         return indexOf3Em;
    311     }
    312 
    313     /**
    314      * Returns selected font's style.
    315      */
    316     public static Pair<Integer, Boolean> getSelectedStyle(Typeface typeface) {
    317         return sStyleList.get(getSelectedFontStyle(typeface));
    318     }
    319 
    320     /**
    321      * Returns selected font's file path.
    322      *
    323      * Note that this is valid only if the all Font objects in the FontFamily is created with
    324      * AssetManager.
    325      */
    326     public static String getSelectedFontPathInAsset(Typeface typeface) {
    327         return sFontList[getSelectedFontStyle(typeface)];
    328     }
    329 
    330     /**
    331      * Returns selected font's ttc index.
    332      *
    333      * Note that this is valid only if the all Font objects in the FontFamily is created with
    334      * TTC font with ttcIndex.
    335      */
    336     public static int getSelectedTtcIndex(Typeface typeface) {
    337         return getSelectedFontStyle(typeface);
    338     }
    339 
    340     /**
    341      * Returns selected font's variation settings.
    342      *
    343      * Note that this is valid only if the all Font objects in the FontFamily is created with
    344      * variable fonts with font variation settings.
    345      */
    346     public static String getSelectedVariationSettings(Typeface typeface) {
    347         return FONT_VARIATION_SETTING_LIST[getSelectedFontStyle(typeface)];
    348     }
    349 }
    350