blob: 018e5dc8367bea5ef21f55114ee0993f50109ae3 [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.Typeface.Builder;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.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;
import java.util.Locale;
@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";
private static final float GLYPH_1EM_WIDTH;
private static final float GLYPH_3EM_WIDTH;
private static float measureText(String text, Typeface typeface) {
final Paint paint = new Paint();
// Fix the locale so that fix the locale based fallback.
paint.setTextLocale(Locale.US);
paint.setTypeface(typeface);
return paint.measureText(text);
}
static {
// 3em.ttf supports "a", "b", "c". The width of "a" is 3em, others are 1em.
final Context ctx = InstrumentationRegistry.getTargetContext();
final Typeface typeface = ctx.getResources().getFont(R.font.a3em);
GLYPH_3EM_WIDTH = measureText("a", typeface);
GLYPH_1EM_WIDTH = measureText("b", typeface);
}
// 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);
final String testString = "abcde";
float widthDefaultTypeface = measureText(testString, Typeface.DEFAULT);
float widthCustomTypeface = measureText(testString, typeface);
assertEquals(widthDefaultTypeface, widthCustomTypeface, 1.0f);
}
@Test
public void testInvalidCmapFont2() {
Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "bombfont2.ttf");
assertNotNull(typeface);
final String testString = "abcde";
float widthDefaultTypeface = measureText(testString, Typeface.DEFAULT);
float widthCustomTypeface = measureText(testString, typeface);
assertEquals(widthDefaultTypeface, widthCustomTypeface, 1.0f);
}
@Test
public void testInvalidCmapFont_tooLargeCodePoints() {
// Following three font doen't have any coverage between U+0000..U+10FFFF. Just make sure
// they don't crash us.
final String[] INVALID_CMAP_FONTS = {
"out_of_unicode_start_cmap12.ttf",
"out_of_unicode_end_cmap12.ttf",
"too_large_start_cmap12.ttf",
"too_large_end_cmap12.ttf",
};
for (final String file : INVALID_CMAP_FONTS) {
final Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), file);
assertNotNull(typeface);
}
}
@Test
public void testInvalidCmapFont_unsortedEntries() {
// Following two font files have glyph for U+0400 and U+0100 but the fonts must not be used
// due to invalid cmap data. For more details, see each ttx source file.
final String[] INVALID_CMAP_FONTS = { "unsorted_cmap4.ttf", "unsorted_cmap12.ttf" };
for (final String file : INVALID_CMAP_FONTS) {
final Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), file);
assertNotNull(typeface);
final String testString = "\u0100\u0400";
final float widthDefaultTypeface = measureText(testString, Typeface.DEFAULT);
final float widthCustomTypeface = measureText(testString, typeface);
assertEquals(widthDefaultTypeface, widthCustomTypeface, 0.0f);
}
// Following two font files have glyph for U+0400 U+FE00 and U+0100 U+FE00 but the fonts
// must not be used due to invalid cmap data. For more details, see each ttx source file.
final String[] INVALID_CMAP_VS_FONTS = {
"unsorted_cmap14_default_uvs.ttf",
"unsorted_cmap14_non_default_uvs.ttf"
};
for (final String file : INVALID_CMAP_VS_FONTS) {
final Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), file);
assertNotNull(typeface);
final String testString = "\u0100\uFE00\u0400\uFE00";
final float widthDefaultTypeface = measureText(testString, Typeface.DEFAULT);
final float widthCustomTypeface = measureText(testString, typeface);
assertEquals(widthDefaultTypeface, widthCustomTypeface, 0.0f);
}
}
@Test
public void testCreateFromAsset_cachesTypeface() {
Typeface typeface1 = Typeface.createFromAsset(mContext.getAssets(), "samplefont.ttf");
assertNotNull(typeface1);
Typeface typeface2 = Typeface.createFromAsset(mContext.getAssets(), "samplefont.ttf");
assertNotNull(typeface2);
assertSame("Same font asset should return same Typeface object", typeface1, typeface2);
Typeface typeface3 = Typeface.createFromAsset(mContext.getAssets(), "samplefont2.ttf");
assertNotNull(typeface3);
assertNotSame("Different font asset should return different Typeface object",
typeface2, typeface3);
Typeface typeface4 = Typeface.createFromAsset(mContext.getAssets(), "samplefont3.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() {
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 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);
final String testString = "a";
float widthDefaultTypeface = measureText(testString, Typeface.DEFAULT);
float widthCustomTypeface = measureText(testString, typeface);
// 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.setTextLocale(Locale.US);
p.setTextSize(128);
p.setTypeface(regularTypeface);
final float widthFromRegular = p.measureText(testString);
p.setTypeface(blackTypeface);
final float widthFromBlack = p.measureText(testString);
assertNotEquals(widthFromRegular, widthFromBlack, 1.0f);
}
@Test
public void testTypefaceCreate_withExactWeight() {
// multiweight_family has following fonts.
// - a3em.ttf with weight = 100, style=normal configuration.
// This font supports "a", "b", "c". The weight "a" is 3em, others are 1em.
// - b3em.ttf with weight = 400, style=normal configuration.
// This font supports "a", "b", "c". The weight "b" is 3em, others are 1em.
// - c3em.ttf with weight = 700, style=normal configuration.
// This font supports "a", "b", "c". The weight "c" is 3em, others are 1em.
final Typeface family = mContext.getResources().getFont(R.font.multiweight_family);
assertNotNull(family);
// By default, the font which weight is 400 is selected.
assertEquals(GLYPH_1EM_WIDTH, measureText("a", family), 0f);
assertEquals(GLYPH_3EM_WIDTH, measureText("b", family), 0f);
assertEquals(GLYPH_1EM_WIDTH, measureText("c", family), 0f);
// Draw with the font which weight is 100.
final Typeface thinFamily = Typeface.create(family, 100 /* weight */, false /* italic */);
assertEquals(GLYPH_3EM_WIDTH, measureText("a", thinFamily), 0f);
assertEquals(GLYPH_1EM_WIDTH, measureText("b", thinFamily), 0f);
assertEquals(GLYPH_1EM_WIDTH, measureText("c", thinFamily), 0f);
// Draw with the font which weight is 700.
final Typeface boldFamily = Typeface.create(family, 700 /* weight */, false /* italic */);
assertEquals(GLYPH_1EM_WIDTH, measureText("a", boldFamily), 0f);
assertEquals(GLYPH_1EM_WIDTH, measureText("b", boldFamily), 0f);
assertEquals(GLYPH_3EM_WIDTH, measureText("c", boldFamily), 0f);
}
@Test
public void testTypefaceCreate_withExactStyle() {
// multiweight_family has following fonts.
// - a3em.ttf with weight = 400, style=normal configuration.
// This font supports "a", "b", "c". The weight "a" is 3em, others are 1em.
// - b3em.ttf with weight = 400, style=italic configuration.
// This font supports "a", "b", "c". The weight "b" is 3em, others are 1em.
// - c3em.ttf with weight = 700, style=italic configuration.
// This font supports "a", "b", "c". The weight "c" is 3em, others are 1em.
final Typeface family = mContext.getResources().getFont(R.font.multistyle_family);
assertNotNull(family);
// By default, the normal style font which weight is 400 is selected.
assertEquals(GLYPH_3EM_WIDTH, measureText("a", family), 0f);
assertEquals(GLYPH_1EM_WIDTH, measureText("b", family), 0f);
assertEquals(GLYPH_1EM_WIDTH, measureText("c", family), 0f);
// Draw with the italic font.
final Typeface italicFamily = Typeface.create(family, 400 /* weight */, true /* italic */);
assertEquals(GLYPH_1EM_WIDTH, measureText("a", italicFamily), 0f);
assertEquals(GLYPH_3EM_WIDTH, measureText("b", italicFamily), 0f);
assertEquals(GLYPH_1EM_WIDTH, measureText("c", italicFamily), 0f);
// Draw with the italic font which weigth is 700.
final Typeface boldItalicFamily =
Typeface.create(family, 700 /* weight */, true /* italic */);
assertEquals(GLYPH_1EM_WIDTH, measureText("a", boldItalicFamily), 0f);
assertEquals(GLYPH_1EM_WIDTH, measureText("b", boldItalicFamily), 0f);
assertEquals(GLYPH_3EM_WIDTH, measureText("c", boldItalicFamily), 0f);
}
@Test
public void testFontVariationSettings() {
// WeightEqualsEmVariableFont is a special font generating the outlines a glyph of 1/1000
// width of the given wght axis. For example, if 300 is given as the wght value to the font,
// the font will generate 0.3em of the glyph for the 'a'..'z' characters.
// The minimum, default, maximum value of 'wght' is 0, 0, 1000.
// No other axes are supported.
final AssetManager am = mContext.getAssets();
final Paint paint = new Paint();
paint.setTextSize(100); // Make 1em = 100px
// By default, WeightEqualsEmVariableFont has 0 'wght' value.
paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf").build());
assertEquals(0.0f, paint.measureText("a"), 0.0f);
paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf")
.setFontVariationSettings("'wght' 100").build());
assertEquals(10.0f, paint.measureText("a"), 0.0f);
paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf")
.setFontVariationSettings("'wght' 300").build());
assertEquals(30.0f, paint.measureText("a"), 0.0f);
paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf")
.setFontVariationSettings("'wght' 800").build());
assertEquals(80.0f, paint.measureText("a"), 0.0f);
paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf")
.setFontVariationSettings("'wght' 550").build());
assertEquals(55.0f, paint.measureText("a"), 0.0f);
}
@Test
public void testFontVariationSettings_UnsupportedAxes() {
// WeightEqualsEmVariableFont is a special font generating the outlines a glyph of 1/1000
// width of the given wght axis. For example, if 300 is given as the wght value to the font,
// the font will generate 0.3em of the glyph for the 'a'..'z' characters.
// The minimum, default, maximum value of 'wght' is 0, 0, 1000.
// No other axes are supported.
final AssetManager am = mContext.getAssets();
final Paint paint = new Paint();
paint.setTextSize(100); // Make 1em = 100px
// Unsupported axes do not affect the result.
paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf")
.setFontVariationSettings("'wght' 300, 'wdth' 10").build());
assertEquals(30.0f, paint.measureText("a"), 0.0f);
paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf")
.setFontVariationSettings("'wdth' 10, 'wght' 300").build());
assertEquals(30.0f, paint.measureText("a"), 0.0f);
}
@Test
public void testFontVariationSettings_OutOfRangeValue() {
// WeightEqualsEmVariableFont is a special font generating the outlines a glyph of 1/1000
// width of the given wght axis. For example, if 300 is given as the wght value to the font,
// the font will generate 0.3em of the glyph for the 'a'..'z' characters.
// The minimum, default, maximum value of 'wght' is 0, 0, 1000.
// No other axes are supported.
final AssetManager am = mContext.getAssets();
final Paint paint = new Paint();
paint.setTextSize(100); // Make 1em = 100px
// Out of range value needs to be clipped at the minimum or maximum values.
paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf")
.setFontVariationSettings("'wght' -100").build());
assertEquals(0.0f, paint.measureText("a"), 0.0f);
paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf")
.setFontVariationSettings("'wght' 1300").build());
assertEquals(100.0f, paint.measureText("a"), 0.0f);
}
@Test
public void testTypefaceCreate_getWeight() {
Typeface typeface = Typeface.DEFAULT;
assertEquals(400, typeface.getWeight());
assertFalse(typeface.isItalic());
typeface = Typeface.create(Typeface.DEFAULT, 100, false /* italic */);
assertEquals(100, typeface.getWeight());
assertFalse(typeface.isItalic());
typeface = Typeface.create(Typeface.DEFAULT, 100, true /* italic */);
assertEquals(100, typeface.getWeight());
assertTrue(typeface.isItalic());
typeface = Typeface.create(Typeface.DEFAULT, 400, false /* italic */);
assertEquals(400, typeface.getWeight());
assertFalse(typeface.isItalic());
typeface = Typeface.create(Typeface.DEFAULT, 400, true /* italic */);
assertEquals(400, typeface.getWeight());
assertTrue(typeface.isItalic());
typeface = Typeface.create(Typeface.DEFAULT, 700, false /* italic */);
assertEquals(700, typeface.getWeight());
assertFalse(typeface.isItalic());
typeface = Typeface.create(Typeface.DEFAULT, 700, true /* italic */);
assertEquals(700, typeface.getWeight());
assertTrue(typeface.isItalic());
// Non-standard weight.
typeface = Typeface.create(Typeface.DEFAULT, 250, false /* italic */);
assertEquals(250, typeface.getWeight());
assertFalse(typeface.isItalic());
typeface = Typeface.create(Typeface.DEFAULT, 250, true /* italic */);
assertEquals(250, typeface.getWeight());
assertTrue(typeface.isItalic());
}
@Test
public void testTypefaceCreate_customFont_getWeight() {
final AssetManager am = mContext.getAssets();
Typeface typeface = new Builder(am, "ascii_a3em_weight100_upright.ttf").build();
assertEquals(100, typeface.getWeight());
assertFalse(typeface.isItalic());
typeface = new Builder(am, "ascii_b3em_weight100_italic.ttf").build();
assertEquals(100, typeface.getWeight());
assertTrue(typeface.isItalic());
}
@Test
public void testTypefaceCreate_customFont_customWeight() {
final AssetManager am = mContext.getAssets();
Typeface typeface = new Builder(am, "ascii_a3em_weight100_upright.ttf")
.setWeight(400).build();
assertEquals(400, typeface.getWeight());
assertFalse(typeface.isItalic());
typeface = new Builder(am, "ascii_b3em_weight100_italic.ttf").setWeight(400).build();
assertEquals(400, typeface.getWeight());
assertTrue(typeface.isItalic());
}
@Test
public void testTypefaceCreate_customFont_customItalic() {
final AssetManager am = mContext.getAssets();
Typeface typeface = new Builder(am, "ascii_a3em_weight100_upright.ttf")
.setItalic(true).build();
assertEquals(100, typeface.getWeight());
assertTrue(typeface.isItalic());
typeface = new Builder(am, "ascii_b3em_weight100_italic.ttf").setItalic(false).build();
assertEquals(100, typeface.getWeight());
assertFalse(typeface.isItalic());
}
}