Fix double bolding

resolveStyle increases minikinStyle's weight value based on Skia's style
value. Since we compute Skia's style based on given weight value, we
should not add extra bold weight to minikinStyle.

This CL also fixes misunderstanding of base weight.
The base weight is only used for computing weight relative to the
weighted alias. Thus, base weight should not be updated except for
createWeightAlias method.

To be clear, this CL changes the function names but keeps the same
semantics as before.

Test: adb shell /data/nativetest/hwui_unit_tests/hwui_unit_tests
Test: am instrument -w -e class android.graphics.cts.TypefaceTest\
      android.graphics.cts/android.support.test.runner.AndroidJUnitRunner
Bug: 37880319
Merged-In: Ied73189b11792fb062da46f45afd2db664e6ecb4

Change-Id: I82350a1bfb99ce198b955f127949e21bccccb1cb
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index fc90fb3..9ad57b1 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -41,9 +41,6 @@
 
 namespace android {
 
-// Must be same with Java constant in Typeface.Builder. See Typeface.java
-constexpr jint RESOLVE_BY_FONT_TABLE = -1;
-
 struct NativeFamilyBuilder {
     NativeFamilyBuilder(uint32_t langId, int variant)
         : langId(langId), variant(variant), allowUnsupportedFont(false) {}
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 86c97a1..eb2ca5d 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -30,14 +30,14 @@
 
 static jlong Typeface_createFromTypeface(JNIEnv* env, jobject, jlong familyHandle, jint style) {
     Typeface* family = reinterpret_cast<Typeface*>(familyHandle);
-    Typeface* face = Typeface::createFromTypeface(family, (SkTypeface::Style)style);
+    Typeface* face = Typeface::createRelative(family, (SkTypeface::Style)style);
     // TODO: the following logic shouldn't be necessary, the above should always succeed.
     // Try to find the closest matching font, using the standard heuristic
     if (NULL == face) {
-        face = Typeface::createFromTypeface(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic));
+        face = Typeface::createRelative(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic));
     }
     for (int i = 0; NULL == face && i < 4; i++) {
-        face = Typeface::createFromTypeface(family, (SkTypeface::Style)i);
+        face = Typeface::createRelative(family, (SkTypeface::Style)i);
     }
     return reinterpret_cast<jlong>(face);
 }
@@ -45,8 +45,7 @@
 static jlong Typeface_createFromTypefaceWithExactStyle(JNIEnv* env, jobject, jlong nativeInstance,
         jint weight, jboolean italic) {
     Typeface* baseTypeface = reinterpret_cast<Typeface*>(nativeInstance);
-    return reinterpret_cast<jlong>(
-            Typeface::createFromTypefaceWithStyle(baseTypeface, weight, italic));
+    return reinterpret_cast<jlong>(Typeface::createAbsolute(baseTypeface, weight, italic));
 }
 
 static jlong Typeface_createFromTypefaceWithVariation(JNIEnv* env, jobject, jlong familyHandle,
@@ -68,7 +67,7 @@
 
 static jlong Typeface_createWeightAlias(JNIEnv* env, jobject, jlong familyHandle, jint weight) {
     Typeface* family = reinterpret_cast<Typeface*>(familyHandle);
-    Typeface* face = Typeface::createWeightAlias(family, weight);
+    Typeface* face = Typeface::createWithDifferentBaseWeight(family, weight);
     return reinterpret_cast<jlong>(face);
 }
 
@@ -82,9 +81,9 @@
     return face->fSkiaStyle;
 }
 
-static jint Typeface_getBaseWeight(JNIEnv* env, jobject obj, jlong faceHandle) {
+static jint Typeface_getWeight(JNIEnv* env, jobject obj, jlong faceHandle) {
     Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
-    return face->fBaseWeight;
+    return face->fStyle.getWeight() * 100;
 }
 
 static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray,
@@ -134,7 +133,7 @@
     { "nativeCreateWeightAlias",  "(JI)J", (void*)Typeface_createWeightAlias },
     { "nativeUnref",              "(J)V",  (void*)Typeface_unref },
     { "nativeGetStyle",           "(J)I",  (void*)Typeface_getStyle },
-    { "nativeGetBaseWeight",      "(J)I",  (void*)Typeface_getBaseWeight },
+    { "nativeGetWeight",      "(J)I",  (void*)Typeface_getWeight },
     { "nativeCreateFromArray",    "([JII)J",
                                            (void*)Typeface_createFromArray },
     { "nativeSetDefault",         "(J)V",   (void*)Typeface_setDefault },
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 79898bc..5a56f53 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -123,7 +123,7 @@
     public static final int BOLD_ITALIC = 3;
 
     private int mStyle = 0;
-    private int mBaseWeight = 0;
+    private int mWeight = 0;
 
     // Value for weight and italic. Indicates the value is resolved by font metadata.
     // Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp
@@ -544,7 +544,7 @@
                 return base;
             }
 
-            final int weight = (mWeight == RESOLVE_BY_FONT_TABLE) ? base.mBaseWeight : mWeight;
+            final int weight = (mWeight == RESOLVE_BY_FONT_TABLE) ? base.mWeight : mWeight;
             final boolean italic =
                     (mItalic == RESOLVE_BY_FONT_TABLE) ? (base.mStyle & ITALIC) != 0 : mItalic == 1;
             final int key = weight << 1 | (italic ? 1 : 0);
@@ -882,7 +882,7 @@
 
         native_instance = ni;
         mStyle = nativeGetStyle(ni);
-        mBaseWeight = nativeGetBaseWeight(ni);
+        mWeight = nativeGetWeight(ni);
     }
 
     private static FontFamily makeFamilyFromParsed(FontConfig.Family family,
@@ -1068,7 +1068,7 @@
     private static native long nativeCreateWeightAlias(long native_instance, int weight);
     private static native void nativeUnref(long native_instance);
     private static native int  nativeGetStyle(long native_instance);
-    private static native int  nativeGetBaseWeight(long native_instance);
+    private static native int  nativeGetWeight(long native_instance);
     private static native long nativeCreateFromArray(long[] familyArray, int weight, int italic);
     private static native void nativeSetDefault(long native_instance);
     private static native int[] nativeGetSupportedAxes(long native_instance);
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 5ef49dc..030e845 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -319,6 +319,7 @@
     tests/unit/TestUtilsTests.cpp \
     tests/unit/TextDropShadowCacheTests.cpp \
     tests/unit/TextureCacheTests.cpp \
+    tests/unit/TypefaceTests.cpp \
     tests/unit/VectorDrawableTests.cpp \
 
 include $(LOCAL_PATH)/hwui_static_deps.mk
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index 4fb4b533..f66bb04 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -36,28 +36,33 @@
 #include <minikin/FontFamily.h>
 #include <minikin/Layout.h>
 #include <utils/Log.h>
+#include <utils/MathUtils.h>
 
 namespace android {
 
-// This indicates that the passed information should be resolved by OS/2 table.
-// This value must be the same as the android.graphics.Typeface$Builder.RESOLVE_BY_FONT_TABLE.
-constexpr int RESOLVE_BY_FONT_TABLE = -1;
+static SkTypeface::Style computeSkiaStyle(int weight, bool italic) {
+    // This bold detection comes from SkTypeface.h
+    if (weight >= SkFontStyle::kSemiBold_Weight) {
+        return italic ? SkTypeface::kBoldItalic : SkTypeface::kBold;
+    } else {
+        return italic ? SkTypeface::kItalic : SkTypeface::kNormal;
+    }
+}
 
-// Resolve the 1..10 weight based on base weight and bold flag
-static void resolveStyle(Typeface* typeface) {
+static minikin::FontStyle computeMinikinStyle(int weight, bool italic) {
     // TODO: Better to use raw base weight value for font selection instead of dividing by 100.
-    int weight = (typeface->fBaseWeight + 50) / 100;
-    if (typeface->fSkiaStyle & SkTypeface::kBold) {
-        weight += 3;
+    const int minikinWeight = uirenderer::MathUtils::clamp((weight + 50) / 100, 1, 10);
+    return minikin::FontStyle(minikinWeight, italic);
+}
+
+// Resolve the relative weight from the baseWeight and target style.
+static minikin::FontStyle computeRelativeStyle(int baseWeight, SkTypeface::Style relativeStyle) {
+    int weight = baseWeight;
+    if ((relativeStyle & SkTypeface::kBold) != 0) {
+        weight += 300;
     }
-    if (weight > 10) {
-        weight = 10;
-    }
-    if (weight < 1) {
-        weight = 1;
-    }
-    bool italic = (typeface->fSkiaStyle & SkTypeface::kItalic) != 0;
-    typeface->fStyle = minikin::FontStyle(weight, italic);
+    bool italic = (relativeStyle & SkTypeface::kItalic) != 0;
+    return computeMinikinStyle(weight, italic);
 }
 
 Typeface* gDefaultTypeface = NULL;
@@ -67,26 +72,26 @@
     return src == nullptr ? gDefaultTypeface : src;
 }
 
-Typeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) {
+Typeface* Typeface::createRelative(Typeface* src, SkTypeface::Style style) {
     Typeface* resolvedFace = Typeface::resolveDefault(src);
     Typeface* result = new Typeface;
     if (result != nullptr) {
         result->fFontCollection = resolvedFace->fFontCollection;
-        result->fSkiaStyle = style;
         result->fBaseWeight = resolvedFace->fBaseWeight;
-        resolveStyle(result);
+        result->fSkiaStyle = style;
+        result->fStyle = computeRelativeStyle(result->fBaseWeight, style);
     }
     return result;
 }
 
-Typeface* Typeface::createFromTypefaceWithStyle(Typeface* base, int weight, bool italic) {
+Typeface* Typeface::createAbsolute(Typeface* base, int weight, bool italic) {
     Typeface* resolvedFace = Typeface::resolveDefault(base);
     Typeface* result = new Typeface();
     if (result != nullptr) {
         result->fFontCollection = resolvedFace->fFontCollection;
-        result->fBaseWeight = weight;
-        result->fStyle = minikin::FontStyle(weight / 100, italic);
-        result->fSkiaStyle = resolvedFace->fSkiaStyle;
+        result->fBaseWeight = resolvedFace->fBaseWeight;
+        result->fSkiaStyle = computeSkiaStyle(weight, italic);
+        result->fStyle = computeMinikinStyle(weight, italic);
     }
     return result;
 }
@@ -103,21 +108,23 @@
             // So we will reuse the same collection with incrementing reference count.
             result->fFontCollection = resolvedFace->fFontCollection;
         }
-        result->fSkiaStyle = resolvedFace->fSkiaStyle;
+        // Do not update styles.
+        // TODO: We may want to update base weight if the 'wght' is specified.
         result->fBaseWeight = resolvedFace->fBaseWeight;
-        resolveStyle(result);
+        result->fSkiaStyle = resolvedFace->fSkiaStyle;
+        result->fStyle = resolvedFace->fStyle;
     }
     return result;
 }
 
-Typeface* Typeface::createWeightAlias(Typeface* src, int weight) {
+Typeface* Typeface::createWithDifferentBaseWeight(Typeface* src, int weight) {
     Typeface* resolvedFace = Typeface::resolveDefault(src);
     Typeface* result = new Typeface;
     if (result != nullptr) {
         result->fFontCollection = resolvedFace->fFontCollection;
-        result->fSkiaStyle = resolvedFace->fSkiaStyle;
         result->fBaseWeight = weight;
-        resolveStyle(result);
+        result->fSkiaStyle = resolvedFace->fSkiaStyle;
+        result->fStyle = computeRelativeStyle(weight, result->fSkiaStyle);
     }
     return result;
 }
@@ -160,14 +167,8 @@
     }
 
     result->fBaseWeight = weight;
-    // This bold detection comes from SkTypefae.h
-    const bool isBold = weight >= SkFontStyle::kSemiBold_Weight;
-    const bool isItalic = italic == 1;
-    // TODO: remove fSkiaStyle
-    result->fSkiaStyle = isBold ?
-            (isItalic ? SkTypeface::kBoldItalic : SkTypeface::kBold) :
-            (isItalic ? SkTypeface::kItalic : SkTypeface::kNormal);
-    resolveStyle(result);
+    result->fSkiaStyle = computeSkiaStyle(weight, italic);
+    result->fStyle = computeMinikinStyle(weight, italic);
     return result;
 }
 
@@ -197,7 +198,7 @@
     Typeface* hwTypeface = new Typeface();
     hwTypeface->fFontCollection = collection;
     hwTypeface->fSkiaStyle = SkTypeface::kNormal;
-    hwTypeface->fBaseWeight = SkFontStyle::kSemiBold_Weight;
+    hwTypeface->fBaseWeight = SkFontStyle::kNormal_Weight;
     hwTypeface->fStyle = minikin::FontStyle(4 /* weight */, false /* italic */);
 
     Typeface::setDefault(hwTypeface);
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index e35a7b4..db0b2cd 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -27,28 +27,53 @@
 
 namespace android {
 
-struct ANDROID_API Typeface {
-    std::shared_ptr<minikin::FontCollection> fFontCollection;
+// This indicates that the weight or italic information should be resolved by OS/2 table.
+// This value must be the same as the android.graphics.Typeface$Builder.RESOLVE_BY_FONT_TABLE.
+constexpr int RESOLVE_BY_FONT_TABLE = -1;
 
-    // style used for constructing and querying Typeface objects
-    SkTypeface::Style fSkiaStyle;
-    // base weight in CSS-style units, 100..900
-    int fBaseWeight;
+struct ANDROID_API Typeface {
+ public:
+    std::shared_ptr<minikin::FontCollection> fFontCollection;
 
     // resolved style actually used for rendering
     minikin::FontStyle fStyle;
 
+    // style used for constructing and querying Typeface objects
+    SkTypeface::Style fSkiaStyle;
+
     static Typeface* resolveDefault(Typeface* src);
 
-    static Typeface* createFromTypeface(Typeface* src, SkTypeface::Style style);
-
-    static Typeface* createFromTypefaceWithStyle(Typeface* base, int weight, bool italic);
+    // The following three functions create new Typeface from an existing Typeface with a different
+    // style. There is a base weight concept which is used for calculating relative style from an
+    // existing Typeface.
+    // The createRelative method creates a new Typeface with a style relative to the base Typeface.
+    // For example, if the base Typeface has a base weight of 400 and the desired style is bold, the
+    // resulting Typeface renders the text with a weight of 700. This function doesn't change the
+    // base weight, so even if you create a new Typeface from the bold Typeface specifying bold on
+    // it again, the text is still rendered with a weight of 700.
+    // You can create another base weight Typeface from an existing Typeface with
+    // createWithDifferentBaseWeight. The Typeface created with this function renders the text with
+    // a specified base weight.
+    // The createAbsolute method creates a new Typeface ignoring the base weight.
+    // Here is an example:
+    //   Typeface* base = resolveDefault(nullptr);  // Usually this has a weight of 400.
+    //   Typeface* bold = createRelative(base, Bold);  // Rendered with a weight of 700.
+    //   Typeface* bold2 = createRelative(bold, Bold); // Rendered with a weight of 700.
+    //
+    //   Typeface* boldBase = createWithDifferentBaseWeight(base, 700);  // With a weight of 700.
+    //   Typeface* boldBold = createRelative(boldBase, Bold);  // Rendered with a weight of 1000.
+    //
+    //   Typeface* lightBase = createWithDifferentBaseWeight(base, 300);  // With a weight of 300.
+    //   Typeface* lightBold = createRelative(lightBase, Bold);  // Rendered with a weight of 600.
+    //
+    //   Typeface* black = createAbsolute(base, 900, false);  // Rendered with a weight of 900.
+    static Typeface* createWithDifferentBaseWeight(Typeface* src, int baseweight);
+    static Typeface* createRelative(Typeface* src, SkTypeface::Style desiredStyle);
+    static Typeface* createAbsolute(Typeface* base, int weight, bool italic);
 
     static Typeface* createFromTypefaceWithVariation(Typeface* src,
             const std::vector<minikin::FontVariation>& variations);
 
-    static Typeface* createWeightAlias(Typeface* src, int baseweight);
-
     static Typeface* createFromFamilies(
             std::vector<std::shared_ptr<minikin::FontFamily>>&& families,
             int weight, int italic);
@@ -57,6 +82,10 @@
 
     // Sets roboto font as the default typeface for testing purpose.
     static void setRobotoTypefaceForTest();
+ private:
+    // base weight in CSS-style units, 1..1000
+    int fBaseWeight;
+
 };
 
 }
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
new file mode 100644
index 0000000..c90b6f0
--- /dev/null
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <utils/Log.h>
+
+#include "SkFontMgr.h"
+#include "SkStream.h"
+
+#include "hwui/MinikinSkia.h"
+#include "hwui/Typeface.h"
+
+using namespace android;
+
+namespace {
+
+constexpr char kRobotoRegular[] = "/system/fonts/Roboto-Regular.ttf";
+constexpr char kRobotoBold[] = "/system/fonts/Roboto-Bold.ttf";
+constexpr char kRobotoItalic[] = "/system/fonts/Roboto-Italic.ttf";
+constexpr char kRobotoBoldItalic[] = "/system/fonts/Roboto-BoldItalic.ttf";
+
+void unmap(const void* ptr, void* context) {
+    void* p = const_cast<void*>(ptr);
+    size_t len = reinterpret_cast<size_t>(context);
+    munmap(p, len);
+}
+
+std::shared_ptr<minikin::FontFamily> buildFamily(const char* fileName) {
+    int fd = open(fileName, O_RDONLY);
+    LOG_ALWAYS_FATAL_IF(fd == -1, "Failed to open file %s", fileName);
+    struct stat st = {};
+    LOG_ALWAYS_FATAL_IF(fstat(fd, &st) == -1, "Failed to stat file %s", fileName);
+    void* data = mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+    sk_sp<SkData> skData =
+            SkData::MakeWithProc(data, st.st_size, unmap, reinterpret_cast<void*>(st.st_size));
+    std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(skData));
+    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
+    sk_sp<SkTypeface> typeface(fm->createFromStream(fontData.release()));
+    LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", fileName);
+    std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
+            std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
+    return std::make_shared<minikin::FontFamily>(
+            std::vector<minikin::Font>({ minikin::Font(std::move(font), minikin::FontStyle()) }));
+}
+
+std::vector<std::shared_ptr<minikin::FontFamily>> makeSingleFamlyVector(const char* fileName) {
+    return std::vector<std::shared_ptr<minikin::FontFamily>>({ buildFamily(fileName) });
+}
+
+TEST(TypefaceTest, resolveDefault_and_setDefaultTest) {
+    std::unique_ptr<Typeface> regular(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(regular.get(), Typeface::resolveDefault(regular.get()));
+
+    Typeface* old = Typeface::resolveDefault(nullptr);  // Keep the original to restore it later.
+    ASSERT_NE(nullptr, old);
+
+    Typeface::setDefault(regular.get());
+    EXPECT_EQ(regular.get(), Typeface::resolveDefault(nullptr));
+
+    Typeface::setDefault(old);  // Restore to the original.
+}
+
+TEST(TypefaceTest, createWithDifferentBaseWeight) {
+    std::unique_ptr<Typeface> bold(Typeface::createWithDifferentBaseWeight(nullptr, 700));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, bold->fSkiaStyle);
+
+    std::unique_ptr<Typeface> light(Typeface::createWithDifferentBaseWeight(nullptr, 300));
+    EXPECT_EQ(3, light->fStyle.getWeight());
+    EXPECT_FALSE(light->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, light->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_fromRegular) {
+    // In Java, Typeface.create(Typeface.DEFAULT, Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(nullptr, SkTypeface::kNormal));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.DEFAULT, Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(nullptr, SkTypeface::kBold));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.DEFAULT, Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(nullptr, SkTypeface::kItalic));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.DEFAULT, Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface> boldItalic(
+            Typeface::createRelative(nullptr, SkTypeface::kBoldItalic));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_BoldBase) {
+    std::unique_ptr<Typeface> base(Typeface::createWithDifferentBaseWeight(nullptr, 700));
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(7, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(10, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(7, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(10, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_LightBase) {
+    std::unique_ptr<Typeface> base(Typeface::createWithDifferentBaseWeight(nullptr, 300));
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(3, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(6, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.ITLIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(3, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(6, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_fromBoldStyled) {
+    std::unique_ptr<Typeface> base(Typeface::createRelative(nullptr, SkTypeface::kBold));
+
+    // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_fromItalicStyled) {
+    std::unique_ptr<Typeface> base(Typeface::createRelative(nullptr, SkTypeface::kItalic));
+
+    // In Java,
+    // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java,
+    // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_fromSpecifiedStyled) {
+    std::unique_ptr<Typeface> base(Typeface::createAbsolute(nullptr, 400, false));
+
+    // In Java,
+    // Typeface typeface = new Typeface.Builder(invalid).setFallback("sans-serif")
+    //     .setWeight(700).setItalic(false).build();
+    // Typeface.create(typeface, Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java,
+    // Typeface typeface = new Typeface.Builder(invalid).setFallback("sans-serif")
+    //     .setWeight(700).setItalic(false).build();
+    // Typeface.create(typeface, Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java,
+    // Typeface typeface = new Typeface.Builder(invalid).setFallback("sans-serif")
+    //     .setWeight(700).setItalic(false).build();
+    // Typeface.create(typeface, Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // Typeface typeface = new Typeface.Builder(invalid).setFallback("sans-serif")
+    //     .setWeight(700).setItalic(false).build();
+    // Typeface.create(typeface, Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createAbsolute) {
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(400).setItalic(false)
+    //     .build();
+    std::unique_ptr<Typeface> regular(Typeface::createAbsolute(nullptr, 400, false));
+    EXPECT_EQ(4, regular->fStyle.getWeight());
+    EXPECT_FALSE(regular->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, regular->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(700).setItalic(false)
+    //     .build();
+    std::unique_ptr<Typeface> bold(Typeface::createAbsolute(nullptr, 700, false));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(400).setItalic(true)
+    //     .build();
+    std::unique_ptr<Typeface> italic(Typeface::createAbsolute(nullptr, 400, true));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(700).setItalic(true)
+    //     .build();
+    std::unique_ptr<Typeface> boldItalic(Typeface::createAbsolute(nullptr, 700, true));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(1100).setItalic(true)
+    //     .build();
+    std::unique_ptr<Typeface> over1000(Typeface::createAbsolute(nullptr, 1100, false));
+    EXPECT_EQ(10, over1000->fStyle.getWeight());
+    EXPECT_FALSE(over1000->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, over1000->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createFromFamilies_Single) {
+    // In Java, new Typeface.Builder("Roboto-Regular.ttf").setWeight(400).setItalic(false).build();
+    std::unique_ptr<Typeface> regular(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular), 400, false));
+    EXPECT_EQ(4, regular->fStyle.getWeight());
+    EXPECT_FALSE(regular->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, regular->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-Bold.ttf").setWeight(700).setItalic(false).build();
+    std::unique_ptr<Typeface> bold(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold), 700, false));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-Italic.ttf").setWeight(400).setItalic(true).build();
+    std::unique_ptr<Typeface> italic(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoItalic), 400, true));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(700).setItalic(true).build();
+    std::unique_ptr<Typeface> boldItalic(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBoldItalic), 700, true));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(1100).setItalic(false).build();
+    std::unique_ptr<Typeface> over1000(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold), 1100, false));
+    EXPECT_EQ(10, over1000->fStyle.getWeight());
+    EXPECT_FALSE(over1000->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, over1000->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createFromFamilies_Single_resolveByTable) {
+    // In Java, new Typeface.Builder("Roboto-Regular.ttf").build();
+    std::unique_ptr<Typeface> regular(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(4, regular->fStyle.getWeight());
+    EXPECT_FALSE(regular->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, regular->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-Bold.ttf").build();
+    std::unique_ptr<Typeface> bold(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-Italic.ttf").build();
+    std::unique_ptr<Typeface> italic(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoItalic),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-BoldItalic.ttf").build();
+    std::unique_ptr<Typeface> boldItalic(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBoldItalic),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createFromFamilies_Family) {
+    std::vector<std::shared_ptr<minikin::FontFamily>> families = {
+            buildFamily(kRobotoRegular), buildFamily(kRobotoBold), buildFamily(kRobotoItalic),
+            buildFamily(kRobotoBoldItalic)
+    };
+    std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies(std::move(families),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(4, typeface->fStyle.getWeight());
+    EXPECT_FALSE(typeface->fStyle.getItalic());
+}
+
+TEST(TypefaceTest, createFromFamilies_Family_withoutRegular) {
+    std::vector<std::shared_ptr<minikin::FontFamily>> families = {
+            buildFamily(kRobotoBold), buildFamily(kRobotoItalic), buildFamily(kRobotoBoldItalic)
+    };
+    std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies(std::move(families),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(7, typeface->fStyle.getWeight());
+    EXPECT_FALSE(typeface->fStyle.getItalic());
+}
+
+}  // namespace