| /* |
| * Copyright (C) 2009 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.cts; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNotSame; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertSame; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import android.content.Context; |
| import android.content.res.AssetManager; |
| import android.graphics.Paint; |
| import android.graphics.Typeface; |
| import android.graphics.fonts.FontVariationAxis; |
| import android.provider.FontsContract; |
| import android.support.test.InstrumentationRegistry; |
| import android.support.test.filters.SmallTest; |
| import android.support.test.runner.AndroidJUnit4; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| |
| @SmallTest |
| @RunWith(AndroidJUnit4.class) |
| public class TypefaceTest { |
| // generic family name for monospaced fonts |
| private static final String MONO = "monospace"; |
| private static final String DEFAULT = (String)null; |
| private static final String INVALID = "invalid-family-name"; |
| |
| // list of family names to try when attempting to find a typeface with a given style |
| private static final String[] FAMILIES = |
| { (String) null, "monospace", "serif", "sans-serif", "cursive", "arial", "times" }; |
| |
| private Context mContext; |
| |
| /** |
| * Create a typeface of the given style. If the default font does not support the style, |
| * a number of generic families are tried. |
| * @return The typeface or null, if no typeface with the given style can be found. |
| */ |
| private static Typeface createTypeface(int style) { |
| for (String family : FAMILIES) { |
| Typeface tf = Typeface.create(family, style); |
| if (tf.getStyle() == style) { |
| return tf; |
| } |
| } |
| return null; |
| } |
| |
| @Before |
| public void setup() { |
| mContext = InstrumentationRegistry.getTargetContext(); |
| } |
| |
| @Test |
| public void testIsBold() { |
| Typeface typeface = createTypeface(Typeface.BOLD); |
| if (typeface != null) { |
| assertEquals(Typeface.BOLD, typeface.getStyle()); |
| assertTrue(typeface.isBold()); |
| assertFalse(typeface.isItalic()); |
| } |
| |
| typeface = createTypeface(Typeface.ITALIC); |
| if (typeface != null) { |
| assertEquals(Typeface.ITALIC, typeface.getStyle()); |
| assertFalse(typeface.isBold()); |
| assertTrue(typeface.isItalic()); |
| } |
| |
| typeface = createTypeface(Typeface.BOLD_ITALIC); |
| if (typeface != null) { |
| assertEquals(Typeface.BOLD_ITALIC, typeface.getStyle()); |
| assertTrue(typeface.isBold()); |
| assertTrue(typeface.isItalic()); |
| } |
| |
| typeface = createTypeface(Typeface.NORMAL); |
| if (typeface != null) { |
| assertEquals(Typeface.NORMAL, typeface.getStyle()); |
| assertFalse(typeface.isBold()); |
| assertFalse(typeface.isItalic()); |
| } |
| } |
| |
| @Test |
| public void testCreate() { |
| Typeface typeface = Typeface.create(DEFAULT, Typeface.NORMAL); |
| assertNotNull(typeface); |
| typeface = Typeface.create(MONO, Typeface.BOLD); |
| assertNotNull(typeface); |
| typeface = Typeface.create(INVALID, Typeface.ITALIC); |
| assertNotNull(typeface); |
| |
| typeface = Typeface.create(typeface, Typeface.NORMAL); |
| assertNotNull(typeface); |
| typeface = Typeface.create(typeface, Typeface.BOLD); |
| assertNotNull(typeface); |
| } |
| |
| @Test |
| public void testDefaultFromStyle() { |
| Typeface typeface = Typeface.defaultFromStyle(Typeface.NORMAL); |
| assertNotNull(typeface); |
| typeface = Typeface.defaultFromStyle(Typeface.BOLD); |
| assertNotNull(typeface); |
| typeface = Typeface.defaultFromStyle(Typeface.ITALIC); |
| assertNotNull(typeface); |
| typeface = Typeface.defaultFromStyle(Typeface.BOLD_ITALIC); |
| assertNotNull(typeface); |
| } |
| |
| @Test |
| public void testConstants() { |
| assertNotNull(Typeface.DEFAULT); |
| assertNotNull(Typeface.DEFAULT_BOLD); |
| assertNotNull(Typeface.MONOSPACE); |
| assertNotNull(Typeface.SANS_SERIF); |
| assertNotNull(Typeface.SERIF); |
| } |
| |
| @Test(expected=NullPointerException.class) |
| public void testCreateFromAssetNull() { |
| // input abnormal params. |
| Typeface.createFromAsset(null, null); |
| } |
| |
| @Test(expected=NullPointerException.class) |
| public void testCreateFromAssetNullPath() { |
| // input abnormal params. |
| Typeface.createFromAsset(mContext.getAssets(), null); |
| } |
| |
| @Test(expected=RuntimeException.class) |
| public void testCreateFromAssetInvalidPath() { |
| // input abnormal params. |
| Typeface.createFromAsset(mContext.getAssets(), "invalid path"); |
| } |
| |
| @Test |
| public void testCreateFromAsset() { |
| Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "samplefont.ttf"); |
| assertNotNull(typeface); |
| } |
| |
| @Test(expected=NullPointerException.class) |
| public void testCreateFromFileByFileReferenceNull() { |
| // input abnormal params. |
| Typeface.createFromFile((File) null); |
| } |
| |
| @Test |
| public void testCreateFromFileByFileReference() throws IOException { |
| File file = new File(obtainPath()); |
| Typeface typeface = Typeface.createFromFile(file); |
| assertNotNull(typeface); |
| } |
| |
| @Test(expected=RuntimeException.class) |
| public void testCreateFromFileWithInvalidPath() throws IOException { |
| File file = new File("/invalid/path"); |
| Typeface.createFromFile(file); |
| } |
| |
| @Test(expected=NullPointerException.class) |
| public void testCreateFromFileByFileNameNull() throws IOException { |
| // input abnormal params. |
| Typeface.createFromFile((String) null); |
| } |
| |
| @Test(expected=RuntimeException.class) |
| public void testCreateFromFileByInvalidFileName() throws IOException { |
| // input abnormal params. |
| Typeface.createFromFile("/invalid/path"); |
| } |
| |
| @Test |
| public void testCreateFromFileByFileName() throws IOException { |
| Typeface typeface = Typeface.createFromFile(obtainPath()); |
| assertNotNull(typeface); |
| } |
| |
| private String obtainPath() throws IOException { |
| File dir = mContext.getFilesDir(); |
| dir.mkdirs(); |
| File file = new File(dir, "test.jpg"); |
| if (!file.createNewFile()) { |
| if (!file.exists()) { |
| fail("Failed to create new File!"); |
| } |
| } |
| InputStream is = mContext.getAssets().open("samplefont.ttf"); |
| FileOutputStream fOutput = new FileOutputStream(file); |
| byte[] dataBuffer = new byte[1024]; |
| int readLength = 0; |
| while ((readLength = is.read(dataBuffer)) != -1) { |
| fOutput.write(dataBuffer, 0, readLength); |
| } |
| is.close(); |
| fOutput.close(); |
| return (file.getPath()); |
| } |
| |
| @Test |
| public void testInvalidCmapFont() { |
| Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "bombfont.ttf"); |
| assertNotNull(typeface); |
| Paint p = new Paint(); |
| final String testString = "abcde"; |
| float widthDefaultTypeface = p.measureText(testString); |
| p.setTypeface(typeface); |
| float widthCustomTypeface = p.measureText(testString); |
| assertEquals(widthDefaultTypeface, widthCustomTypeface, 1.0f); |
| } |
| |
| @Test |
| public void testInvalidCmapFont2() { |
| Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "bombfont2.ttf"); |
| assertNotNull(typeface); |
| Paint p = new Paint(); |
| final String testString = "abcde"; |
| float widthDefaultTypeface = p.measureText(testString); |
| p.setTypeface(typeface); |
| float widthCustomTypeface = p.measureText(testString); |
| assertEquals(widthDefaultTypeface, widthCustomTypeface, 1.0f); |
| } |
| |
| @Test |
| public void testCreateFromAsset_cachesTypeface() { |
| Typeface typeface1 = Typeface.createFromAsset(mContext.getAssets(), "bombfont2.ttf"); |
| assertNotNull(typeface1); |
| |
| Typeface typeface2 = Typeface.createFromAsset(mContext.getAssets(), "bombfont2.ttf"); |
| assertNotNull(typeface2); |
| assertSame("Same font asset should return same Typeface object", typeface1, typeface2); |
| |
| Typeface typeface3 = Typeface.createFromAsset(mContext.getAssets(), "bombfont.ttf"); |
| assertNotNull(typeface3); |
| assertNotSame("Different font asset should return different Typeface object", |
| typeface2, typeface3); |
| |
| Typeface typeface4 = Typeface.createFromAsset(mContext.getAssets(), "samplefont.ttf"); |
| assertNotNull(typeface4); |
| assertNotSame("Different font asset should return different Typeface object", |
| typeface2, typeface4); |
| assertNotSame("Different font asset should return different Typeface object", |
| typeface3, typeface4); |
| } |
| |
| @Test |
| public void testBadFont() { |
| Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "ft45987.ttf"); |
| assertNotNull(typeface); |
| } |
| |
| @Test |
| public void testTypefaceBuilder_AssetSource() throws FontVariationAxis.InvalidFormatException { |
| Typeface typeface1 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf").build(); |
| assertNotNull(typeface1); |
| |
| Typeface typeface2 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf").build(); |
| assertNotNull(typeface2); |
| assertSame("Same font asset should return same Typeface object", typeface1, typeface2); |
| |
| Typeface typeface3 = new Typeface.Builder(mContext.getAssets(), "samplefont2.ttf").build(); |
| assertNotNull(typeface3); |
| assertNotSame("Different font asset should return different Typeface object", |
| typeface2, typeface3); |
| |
| Typeface typeface4 = new Typeface.Builder(mContext.getAssets(), "samplefont3.ttf").build(); |
| assertNotNull(typeface4); |
| assertNotSame("Different font asset should return different Typeface object", |
| typeface2, typeface4); |
| assertNotSame("Different font asset should return different Typeface object", |
| typeface3, typeface4); |
| |
| Typeface typeface5 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf") |
| .setFontVariationSettings("'wdth' 1.0").build(); |
| assertNotNull(typeface5); |
| assertNotSame("Different font font variation should return different Typeface object", |
| typeface2, typeface5); |
| |
| Typeface typeface6 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf") |
| .setFontVariationSettings("'wdth' 2.0").build(); |
| assertNotNull(typeface6); |
| assertNotSame("Different font font variation should return different Typeface object", |
| typeface2, typeface6); |
| assertNotSame("Different font font variation should return different Typeface object", |
| typeface5, typeface6); |
| |
| // TODO: Add ttc index case. Need TTC file for CTS. (b/36731640) |
| } |
| |
| @Test |
| public void testTypefaceBuilder_FileSource() { |
| try { |
| File file = new File(obtainPath()); |
| Typeface typeface1 = new Typeface.Builder(obtainPath()).build(); |
| assertNotNull(typeface1); |
| |
| Typeface typeface2 = new Typeface.Builder(file).build(); |
| assertNotNull(typeface2); |
| |
| Typeface typeface3 = new Typeface.Builder(file) |
| .setFontVariationSettings("'wdth' 1.0") |
| .build(); |
| assertNotNull(typeface3); |
| assertNotSame(typeface1, typeface3); |
| assertNotSame(typeface2, typeface3); |
| |
| // TODO: Add ttc index case. Need TTC file for CTS. |
| } catch (IOException | FontVariationAxis.InvalidFormatException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| @Test |
| public void testTypefaceBuilder_fallback() throws IOException { |
| final File validFile = new File(obtainPath()); |
| final File invalidFile = new File("/some/invalid/path/to/font/file"); |
| final AssetManager assets = mContext.getAssets(); |
| // By default, returns null if no fallback font is specified. |
| assertNull(new Typeface.Builder(invalidFile).build()); |
| |
| assertNull(new Typeface.Builder(validFile) |
| .setTtcIndex(100 /* non-existing ttc index */).build()); |
| |
| assertNull(new Typeface.Builder(assets, "invalid path").build()); |
| |
| assertNull(new Typeface.Builder(assets, "samplefont.ttf") |
| .setTtcIndex(100 /* non-existing ttc index */).build()); |
| |
| // If fallback is set, the builder never returns null. |
| assertNotNull(new Typeface.Builder(invalidFile).setFallback("").build()); |
| |
| assertNotNull(new Typeface.Builder(invalidFile).setFallback("invalid name").build()); |
| |
| Typeface sansSerifTypeface = new Typeface.Builder(invalidFile) |
| .setFallback("sans-serif").build(); |
| assertNotNull(sansSerifTypeface); |
| |
| Typeface serifTypeface = new Typeface.Builder(invalidFile).setFallback("serif").build(); |
| assertNotNull(serifTypeface); |
| |
| Typeface boldSansSerifTypeface = new Typeface.Builder(invalidFile) |
| .setFallback("sans-serif").setWeight(700).build(); |
| assertNotNull(boldSansSerifTypeface); |
| |
| Typeface boldSerifTypeface = new Typeface.Builder(invalidFile) |
| .setFallback("serif").setWeight(700).build(); |
| assertNotNull(boldSerifTypeface); |
| |
| Typeface italicSansSerifTypeface = new Typeface.Builder(invalidFile) |
| .setFallback("sans-serif").setItalic(true).build(); |
| assertNotNull(italicSansSerifTypeface); |
| |
| Typeface italicSerifTypeface = new Typeface.Builder(invalidFile) |
| .setFallback("serif").setItalic(true).build(); |
| assertNotNull(italicSerifTypeface); |
| |
| // All fallbacks should be different each other. |
| assertNotSame(sansSerifTypeface, serifTypeface); |
| assertNotSame(sansSerifTypeface, boldSansSerifTypeface); |
| assertNotSame(sansSerifTypeface, boldSerifTypeface); |
| assertNotSame(sansSerifTypeface, italicSansSerifTypeface); |
| assertNotSame(sansSerifTypeface, italicSerifTypeface); |
| assertNotSame(serifTypeface, boldSansSerifTypeface); |
| assertNotSame(serifTypeface, boldSerifTypeface); |
| assertNotSame(serifTypeface, italicSansSerifTypeface); |
| assertNotSame(serifTypeface, italicSerifTypeface); |
| assertNotSame(boldSansSerifTypeface, boldSerifTypeface); |
| assertNotSame(boldSansSerifTypeface, italicSansSerifTypeface); |
| assertNotSame(boldSansSerifTypeface, italicSerifTypeface); |
| assertNotSame(boldSerifTypeface, italicSansSerifTypeface); |
| assertNotSame(boldSerifTypeface, italicSerifTypeface); |
| assertNotSame(italicSansSerifTypeface, italicSerifTypeface); |
| |
| // Cache should work for the same fallback. |
| assertSame(sansSerifTypeface, |
| new Typeface.Builder(assets, "samplefont.ttf").setFallback("sans-serif") |
| .setTtcIndex(100 /* non-existing ttc index */).build()); |
| assertSame(serifTypeface, |
| new Typeface.Builder(assets, "samplefont.ttf").setFallback("serif") |
| .setTtcIndex(100 /* non-existing ttc index */).build()); |
| assertSame(boldSansSerifTypeface, |
| new Typeface.Builder(assets, "samplefont.ttf").setFallback("sans-serif") |
| .setTtcIndex(100 /* non-existing ttc index */).setWeight(700).build()); |
| assertSame(boldSerifTypeface, |
| new Typeface.Builder(assets, "samplefont.ttf").setFallback("serif") |
| .setTtcIndex(100 /* non-existing ttc index */).setWeight(700).build()); |
| assertSame(italicSansSerifTypeface, |
| new Typeface.Builder(assets, "samplefont.ttf").setFallback("sans-serif") |
| .setTtcIndex(100 /* non-existing ttc index */).setItalic(true).build()); |
| assertSame(italicSerifTypeface, |
| new Typeface.Builder(assets, "samplefont.ttf").setFallback("serif") |
| .setTtcIndex(100 /* non-existing ttc index */).setItalic(true).build()); |
| } |
| |
| @Test |
| public void testTypefaceBuilder_FileSourceFD() { |
| try (FileInputStream fis = new FileInputStream(obtainPath())) { |
| assertNotNull(new Typeface.Builder(fis.getFD()).build()); |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| @Test |
| public void testTypeface_SupportedCmapEncodingTest() { |
| // We support the following combinations of cmap platfrom/endcoding pairs. |
| String[] fontPaths = { |
| "CmapPlatform0Encoding0.ttf", // Platform ID == 0, Encoding ID == 0 |
| "CmapPlatform0Encoding1.ttf", // Platform ID == 0, Encoding ID == 1 |
| "CmapPlatform0Encoding2.ttf", // Platform ID == 0, Encoding ID == 2 |
| "CmapPlatform0Encoding3.ttf", // Platform ID == 0, Encoding ID == 3 |
| "CmapPlatform0Encoding4.ttf", // Platform ID == 0, Encoding ID == 4 |
| "CmapPlatform0Encoding6.ttf", // Platform ID == 0, Encoding ID == 6 |
| "CmapPlatform3Encoding1.ttf", // Platform ID == 3, Encoding ID == 1 |
| "CmapPlatform3Encoding10.ttf", // Platform ID == 3, Encoding ID == 10 |
| }; |
| |
| for (String fontPath : fontPaths) { |
| Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), fontPath); |
| assertNotNull(typeface); |
| Paint p = new Paint(); |
| final String testString = "a"; |
| float widthDefaultTypeface = p.measureText(testString); |
| p.setTypeface(typeface); |
| float widthCustomTypeface = p.measureText(testString); |
| // The width of the glyph "a" from above fonts are 2em. |
| // So the width should be different from the default one. |
| assertNotEquals(widthDefaultTypeface, widthCustomTypeface, 1.0f); |
| } |
| } |
| |
| @Test |
| public void testTypefaceBuilder_customFallback() { |
| final String fontPath = "samplefont2.ttf"; |
| final Typeface regularTypeface = new Typeface.Builder(mContext.getAssets(), fontPath) |
| .setWeight(400).build(); |
| final Typeface blackTypeface = new Typeface.Builder(mContext.getAssets(), fontPath) |
| .setWeight(900).build(); |
| |
| // W is not supported by samplefont2.ttf |
| final String testString = "WWWWWWWWWWWWWWWWWWWWW"; |
| |
| final Paint p = new Paint(); |
| p.setTextSize(128); |
| |
| p.setTypeface(regularTypeface); |
| final float widthFromRegular = p.measureText(testString); |
| |
| p.setTypeface(blackTypeface); |
| final float widthFromBlack = p.measureText(testString); |
| |
| assertTrue(Math.abs(widthFromRegular - widthFromBlack) > 1.0f); |
| } |
| } |