Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 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.cts;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertNotNull;
     21 import static org.junit.Assert.assertTrue;
     22 
     23 import android.content.res.AssetManager;
     24 import android.graphics.Typeface;
     25 import android.graphics.fonts.Font;
     26 import android.graphics.fonts.FontFamily;
     27 import android.graphics.fonts.FontStyle;
     28 import android.graphics.fonts.FontTestUtil;
     29 import android.text.TextPaint;
     30 import android.util.Pair;
     31 
     32 import androidx.test.InstrumentationRegistry;
     33 import androidx.test.filters.SmallTest;
     34 import androidx.test.runner.AndroidJUnit4;
     35 
     36 import org.junit.Test;
     37 import org.junit.runner.RunWith;
     38 
     39 import java.io.IOException;
     40 import java.util.Locale;
     41 
     42 @SmallTest
     43 @RunWith(AndroidJUnit4.class)
     44 public class TypefaceCustomFallbackBuilderTest {
     45 
     46     /**
     47      * Returns Typeface with a font family which has 100-900 weight and upright/italic style fonts.
     48      */
     49     private Typeface createFullFamilyTypeface() throws IOException {
     50         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
     51         FontFamily.Builder b = null;
     52         for (Pair<Integer, Boolean> style : FontTestUtil.getAllStyles()) {
     53             final int weight = style.first.intValue();
     54             final boolean italic = style.second.booleanValue();
     55 
     56             if (b == null) {
     57                 b = new FontFamily.Builder(new Font.Builder(am,
     58                           FontTestUtil.getFontPathFromStyle(weight, italic)).build());
     59             } else {
     60                 b.addFont(new Font.Builder(am,
     61                           FontTestUtil.getFontPathFromStyle(weight, italic)).build());
     62             }
     63         }
     64         return new Typeface.CustomFallbackBuilder(b.build()).build();
     65     }
     66 
     67     @Test
     68     public void testSingleFont_path() throws IOException {
     69         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
     70         for (Pair<Integer, Boolean> style : FontTestUtil.getAllStyles()) {
     71             final int weight = style.first.intValue();
     72             final boolean italic = style.second.booleanValue();
     73 
     74             final String path = FontTestUtil.getFontPathFromStyle(weight, italic);
     75             assertEquals(path, FontTestUtil.getSelectedFontPathInAsset(
     76                     new Typeface.CustomFallbackBuilder(
     77                             new FontFamily.Builder(
     78                                     new Font.Builder(am, path).build()).build()).build()));
     79         }
     80     }
     81 
     82     @Test
     83     public void testSingleFont_ttc() throws IOException {
     84         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
     85         for (Pair<Integer, Boolean> style : FontTestUtil.getAllStyles()) {
     86             final int weight = style.first.intValue();
     87             final boolean italic = style.second.booleanValue();
     88 
     89             final int ttcIndex = FontTestUtil.getTtcIndexFromStyle(weight, italic);
     90             assertEquals(ttcIndex, FontTestUtil.getSelectedTtcIndex(
     91                     new Typeface.CustomFallbackBuilder(
     92                             new FontFamily.Builder(
     93                                     new Font.Builder(am, FontTestUtil.getTtcFontFileInAsset())
     94                                     .setTtcIndex(ttcIndex).build()).build()).build()));
     95         }
     96     }
     97 
     98     @Test
     99     public void testSingleFont_vf() throws IOException {
    100         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
    101         for (Pair<Integer, Boolean> style : FontTestUtil.getAllStyles()) {
    102             final int weight = style.first.intValue();
    103             final boolean italic = style.second.booleanValue();
    104 
    105             final String varSettings = FontTestUtil.getVarSettingsFromStyle(weight, italic);
    106             assertEquals(varSettings, FontTestUtil.getSelectedVariationSettings(
    107                     new Typeface.CustomFallbackBuilder(new FontFamily.Builder(
    108                             new Font.Builder(am, FontTestUtil.getVFFontInAsset())
    109                                 .setFontVariationSettings(varSettings).build()).build()).build()));
    110         }
    111     }
    112 
    113     @Test
    114     public void testFamily_defaultStyle() throws IOException {
    115         final Typeface typeface = createFullFamilyTypeface();
    116         // If none of setWeight/setItalic is called, the default style(400, upright) is selected.
    117         assertEquals(new Pair<Integer, Boolean>(400, false),
    118                 FontTestUtil.getSelectedStyle(typeface));
    119     }
    120 
    121     @Test
    122     public void testFamily_selectStyle() throws IOException {
    123         final Typeface typeface = createFullFamilyTypeface();
    124         for (Pair<Integer, Boolean> style : FontTestUtil.getAllStyles()) {
    125             final int weight = style.first.intValue();
    126             final boolean italic = style.second.booleanValue();
    127             assertEquals(style,
    128                     FontTestUtil.getSelectedStyle(Typeface.create(typeface, weight, italic)));
    129         }
    130     }
    131 
    132     @Test
    133     public void testFamily_selectStyleByBuilder() throws IOException {
    134         for (Pair<Integer, Boolean> testStyle : FontTestUtil.getAllStyles()) {
    135             final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
    136             FontFamily.Builder b = null;
    137             for (Pair<Integer, Boolean> familyStyle : FontTestUtil.getAllStyles()) {
    138                 final int weight = familyStyle.first.intValue();
    139                 final boolean italic = familyStyle.second.booleanValue();
    140 
    141                 if (b == null) {
    142                     b = new FontFamily.Builder(new Font.Builder(am,
    143                               FontTestUtil.getFontPathFromStyle(weight, italic)).build());
    144                 } else {
    145                     b.addFont(new Font.Builder(am,
    146                               FontTestUtil.getFontPathFromStyle(weight, italic)).build());
    147                 }
    148             }
    149             final Typeface typeface = new Typeface.CustomFallbackBuilder(b.build())
    150                     .setStyle(new FontStyle(testStyle.first.intValue(),
    151                               testStyle.second.booleanValue()
    152                             ?  FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT)).build();
    153 
    154             assertEquals(testStyle, FontTestUtil.getSelectedStyle(typeface));
    155         }
    156     }
    157 
    158     @Test
    159     public void testFamily_closestDefault() throws IOException {
    160         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
    161         final FontFamily.Builder b = new FontFamily.Builder(
    162                 new Font.Builder(am, FontTestUtil.getFontPathFromStyle(300, false)).build())
    163                     .addFont(new Font.Builder(am,
    164                               FontTestUtil.getFontPathFromStyle(700, false)).build());
    165 
    166         final Typeface typeface = new Typeface.CustomFallbackBuilder(b.build()).build();
    167         // If font family doesn't have 400/upright style, the default style should be closest font
    168         // instead.
    169         assertEquals(new Pair<Integer, Boolean>(300, false),
    170                   FontTestUtil.getSelectedStyle(typeface));
    171 
    172         // If 600 is specified, 700 is selected since it is closer than 300.
    173         assertEquals(new Pair<Integer, Boolean>(700, false),
    174                   FontTestUtil.getSelectedStyle(Typeface.create(typeface, 600, false)));
    175     }
    176 
    177     @Test
    178     public void testUserFallback() throws IOException {
    179         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
    180         final FontFamily baseFamily = new FontFamily.Builder(
    181                 new Font.Builder(am, "fonts/user_fallback/ascii.ttf").build()).build();
    182         final FontFamily fallbackFamily = new FontFamily.Builder(
    183                 new Font.Builder(am, "fonts/user_fallback/hebrew.ttf").build()).build();
    184 
    185         // baseFamily supports all ASCII alphabet characters but not supports Hebrew characters.
    186         // FallbackFamily suppors all Hebrew alphabet characters and its width is 2em.
    187         final Typeface typeface = new Typeface.CustomFallbackBuilder(baseFamily)
    188                 .addCustomFallback(fallbackFamily)
    189                 .build();
    190 
    191         TextPaint paint = new TextPaint();
    192         paint.setTextSize(10.0f);  // Make 1em = 10px.
    193         paint.setTypeface(typeface);
    194 
    195         assertEquals(10.0f, paint.measureText("a", 0, 1), 0.0f);
    196         assertEquals(20.0f, paint.measureText("\u05D0", 0, 1), 0.0f);  // Hebrew letter
    197     }
    198 
    199     @Test
    200     public void testMaxCustomFallback() throws IOException {
    201         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
    202         final Font font = new Font.Builder(am, "fonts/user_fallback/ascii.ttf").build();
    203         final Typeface.CustomFallbackBuilder b = new Typeface.CustomFallbackBuilder(
    204                 new FontFamily.Builder(font).build());
    205         // Start from 1 since the first font family is already passed to the constructor.
    206         for (int i = 1; i < Typeface.CustomFallbackBuilder.getMaxCustomFallbackCount(); ++i) {
    207             b.addCustomFallback(new FontFamily.Builder(font).build());
    208         }
    209         assertNotNull(b.build());
    210     }
    211 
    212     @Test(expected = IllegalArgumentException.class)
    213     public void testMaxCustomFallback_exceed_limits() throws IOException {
    214         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
    215         final Font font = new Font.Builder(am, "fonts/user_fallback/ascii.ttf").build();
    216         final Typeface.CustomFallbackBuilder b = new Typeface.CustomFallbackBuilder(
    217                 new FontFamily.Builder(font).build());
    218         // Start from 1 since the first font family is already passed to the constructor.
    219         for (int i = 1; i < Typeface.CustomFallbackBuilder.getMaxCustomFallbackCount() + 1; ++i) {
    220             b.addCustomFallback(new FontFamily.Builder(font).build());
    221         }
    222     }
    223 
    224     @Test
    225     public void testMaxCustomFallbackAtLeast64() throws IOException {
    226         assertTrue(Typeface.CustomFallbackBuilder.getMaxCustomFallbackCount() >= 64);
    227     }
    228 
    229     @Test
    230     public void testMaxCustomFallback_must_be_positive() {
    231         assertTrue(Typeface.CustomFallbackBuilder.getMaxCustomFallbackCount() > 0);
    232     }
    233 
    234     @Test
    235     public void testUserFallbackOverLocaleFallback() throws IOException {
    236         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
    237         final FontFamily baseFamily = new FontFamily.Builder(
    238                 new Font.Builder(am, "fonts/user_fallback/ascii.ttf").build()).build();
    239         final FontFamily fallbackFamily = new FontFamily.Builder(
    240                 new Font.Builder(am, "fonts/user_fallback/ideograms.ttf").build()).build();
    241 
    242         // baseFamily supports all ASCII alphabet characters but not supports Hebrew characters.
    243         // FallbackFamily suppors all Hebrew alphabet characters and its width is 2em.
    244         final Typeface typeface = new Typeface.CustomFallbackBuilder(baseFamily)
    245                 .addCustomFallback(fallbackFamily)
    246                 .build();
    247 
    248         TextPaint paint = new TextPaint();
    249         paint.setTextSize(10.0f);  // Make 1em = 10px.
    250         paint.setTypeface(typeface);
    251         paint.setTextLocale(Locale.JAPANESE);
    252 
    253         assertEquals(10.0f, paint.measureText("a", 0, 1), 0.0f);
    254         assertEquals(20.0f, paint.measureText("\u4E0D", 0, 1), 0.0f);  // Hebrew letter
    255     }
    256 
    257     @Test
    258     public void testSystemFallback_SansSerif() throws IOException {
    259         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
    260         final Font font = new Font.Builder(am, "fonts/user_fallback/ascii.ttf").build();
    261         {
    262             final Typeface.CustomFallbackBuilder b = new Typeface.CustomFallbackBuilder(
    263                     new FontFamily.Builder(font).build());
    264             assertNotNull(b.setSystemFallback("sans-serif").build());
    265         }
    266     }
    267 
    268     @Test
    269     public void testSystemFallback_Serif() throws IOException {
    270         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
    271         final Font font = new Font.Builder(am, "fonts/user_fallback/ascii.ttf").build();
    272         {
    273             final Typeface.CustomFallbackBuilder b = new Typeface.CustomFallbackBuilder(
    274                     new FontFamily.Builder(font).build());
    275             assertNotNull(b.setSystemFallback("serif").build());
    276         }
    277     }
    278 
    279     @Test
    280     public void testSystemFallback_anyString() throws IOException {
    281         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
    282         final Font font = new Font.Builder(am, "fonts/user_fallback/ascii.ttf").build();
    283         {
    284             final Typeface.CustomFallbackBuilder b = new Typeface.CustomFallbackBuilder(
    285                     new FontFamily.Builder(font).build());
    286             assertNotNull(b.setSystemFallback("any-string-is-fine").build());
    287         }
    288     }
    289 
    290     @Test
    291     public void testSystemFallback_emptyString() throws IOException {
    292         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
    293         final Font font = new Font.Builder(am, "fonts/user_fallback/ascii.ttf").build();
    294         {
    295             final Typeface.CustomFallbackBuilder b = new Typeface.CustomFallbackBuilder(
    296                     new FontFamily.Builder(font).build());
    297             assertNotNull(b.setSystemFallback("").build());
    298         }
    299     }
    300 
    301     @Test(expected = NullPointerException.class)
    302     public void testSystemFallback_null() throws IOException {
    303         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
    304         final Font font = new Font.Builder(am, "fonts/user_fallback/ascii.ttf").build();
    305         final Typeface.CustomFallbackBuilder b = new Typeface.CustomFallbackBuilder(
    306                 new FontFamily.Builder(font).build());
    307         b.setSystemFallback(null);
    308     }
    309 }
    310