blob: d3bdee671dc40557f36be21025408dcab86bb8d9 [file] [log] [blame]
/*
* 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);
}
}