Snap for 10447354 from 418a20ae7450ceab1291bf20d45cfeeaa980f027 to mainline-wifi-release

Change-Id: Id5d3810a7e760e3ff613339437c81cefda6d8638
diff --git a/Android.bp b/Android.bp
index f5aaf31..8988459 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2,6 +2,16 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+cc_defaults {
+    name: "libminikin_defaults",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-Wthread-safety",
+    ],
+}
+
 cc_library_headers {
     name: "libminikin_headers",
     host_supported: true,
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..862b5c7
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+
+file:platform/frameworks/base:/core/java/android/text/OWNERS
diff --git a/app/Android.bp b/app/Android.bp
index 9d6c28a..939d58c 100644
--- a/app/Android.bp
+++ b/app/Android.bp
@@ -33,5 +33,5 @@
 
     srcs: ["HyphTool.cpp"],
 
-    cflags: ["-Wall", "-Werror"],
+    defaults: ["libminikin_defaults"],
 }
diff --git a/fuzz/hyphenator_fuzzer/Android.bp b/fuzz/hyphenator_fuzzer/Android.bp
new file mode 100644
index 0000000..0b69dc3
--- /dev/null
+++ b/fuzz/hyphenator_fuzzer/Android.bp
@@ -0,0 +1,44 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2022 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+    name: "hyphenator_fuzzer",
+    srcs: [
+        "hyphenator_fuzzer.cpp",
+    ],
+    static_libs: [
+        "libminikin",
+        "libminikin-tests-util",
+    ],
+    shared_libs: [
+        "liblog",
+        "libharfbuzz_ng",
+        "libft2",
+        "libicu",
+        "libutils",
+    ],
+    header_libs: [
+        "libminikin_headers",
+        "libminikin-headers-for-tests",
+    ],
+    dictionary: "hyphenator.dict",
+}
diff --git a/fuzz/hyphenator_fuzzer/hyphenator.dict b/fuzz/hyphenator_fuzzer/hyphenator.dict
new file mode 100644
index 0000000..6bcb2b4
--- /dev/null
+++ b/fuzz/hyphenator_fuzzer/hyphenator.dict
@@ -0,0 +1,67 @@
+# Copyright (C) 2022 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.
+#
+################################################################################
+"U+063B"
+"U+FE8x"
+"U+06F7"
+"U+06CB"
+"U+06C7"
+"pl"
+"ca"
+"sl"
+"pl"
+"ca"
+"as"
+"be"
+"bn"
+"bg"
+"cu"
+"cy"
+"da"
+"de"
+"de-1996"
+"de-ch-1901"
+"en-GB"
+"en-gb"
+"en-US"
+"en-us"
+"es"
+"et"
+"eu"
+"Ethi"
+"und-ethi"
+"fr"
+"ga"
+"gu"
+"hi"
+"hr"
+"hu"
+"hy"
+"kn"
+"la"
+"ml"
+"mn"
+"mn-cyrl"
+"mr"
+"nb"
+"nn"
+"or"
+"pa"
+"pt"
+"sl"
+"ta"
+"te"
+"tk"
+"ca"
diff --git a/fuzz/hyphenator_fuzzer/hyphenator_fuzzer.cpp b/fuzz/hyphenator_fuzzer/hyphenator_fuzzer.cpp
new file mode 100644
index 0000000..1fa4d95
--- /dev/null
+++ b/fuzz/hyphenator_fuzzer/hyphenator_fuzzer.cpp
@@ -0,0 +1,137 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2022 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 <fuzzer/FuzzedDataProvider.h>
+#include <minikin/Hyphenator.h>
+
+#include <iostream>
+#include <string>
+
+#include "HyphenatorMap.h"
+#include "Locale.h"
+#include "LocaleListCache.h"
+#include "MinikinInternal.h"
+#include "UnicodeUtils.h"
+#include "minikin/LocaleList.h"
+#include "minikin/U16StringPiece.h"
+
+using namespace minikin;
+
+const EndHyphenEdit EndHyphenEdits[] = {
+        EndHyphenEdit::NO_EDIT,
+        EndHyphenEdit::REPLACE_WITH_HYPHEN,
+        EndHyphenEdit::INSERT_HYPHEN,
+        EndHyphenEdit::INSERT_ARMENIAN_HYPHEN,
+        EndHyphenEdit::INSERT_MAQAF,
+        EndHyphenEdit::INSERT_UCAS_HYPHEN,
+        EndHyphenEdit::INSERT_ZWJ_AND_HYPHEN,
+};
+
+const StartHyphenEdit StartHyphenEdits[] = {
+        StartHyphenEdit::NO_EDIT,
+        StartHyphenEdit::INSERT_HYPHEN,
+        StartHyphenEdit::INSERT_ZWJ,
+};
+
+const HyphenationType HyphenationTypes[] = {
+        HyphenationType::DONT_BREAK,
+        HyphenationType::BREAK_AND_INSERT_HYPHEN,
+        HyphenationType::BREAK_AND_INSERT_ARMENIAN_HYPHEN,
+        HyphenationType::BREAK_AND_INSERT_MAQAF,
+        HyphenationType::BREAK_AND_INSERT_UCAS_HYPHEN,
+        HyphenationType::BREAK_AND_DONT_INSERT_HYPHEN,
+        HyphenationType::BREAK_AND_REPLACE_WITH_HYPHEN,
+        HyphenationType::BREAK_AND_INSERT_HYPHEN_AT_NEXT_LINE,
+        HyphenationType::BREAK_AND_INSERT_HYPHEN_AND_ZWJ,
+};
+
+uint16_t specialChars[] = {
+        0x000A, 0x000D, 0x0009, 0x002D, 0x00A0, 0x00AD,
+        0x00B7, 0x058A, 0x05BE, 0x1400, 0x200D, 0x2010,
+};
+
+const uint16_t MAX_STR_LEN = 256;
+
+// Function to generate StringPiece from a vector by pushing random valued elements using fdp
+U16StringPiece generateStringPiece(FuzzedDataProvider* fdp) {
+    uint16_t size = fdp->ConsumeIntegralInRange<uint16_t>(0, (fdp->remaining_bytes() / 3));
+
+    std::vector<uint16_t> v;
+    for (uint16_t i = 0; i < size; ++i) {
+        // To randomize the insertion of special characters
+        if (fdp->ConsumeBool()) {
+            v.push_back(fdp->PickValueInArray(specialChars));
+        } else {
+            v.push_back(fdp->ConsumeIntegral<uint16_t>());
+        }
+    }
+
+    return U16StringPiece(v);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+
+    uint8_t minPrefix = fdp.ConsumeIntegral<size_t>();
+    uint8_t minSuffix = fdp.ConsumeIntegral<size_t>();
+    std::string locale = fdp.ConsumeRandomLengthString(MAX_STR_LEN);
+    std::vector<uint8_t> patternData(fdp.ConsumeIntegralInRange<uint32_t>(0, 256));
+
+    Hyphenator* hyphenator = Hyphenator::loadBinary(&patternData[0], minPrefix, minSuffix, locale);
+
+    // To randomize the API calls
+    while (fdp.remaining_bytes() > 0) {
+        auto func = fdp.PickValueInArray<const std::function<void()>>({
+                [&]() { addHyphenator(locale, hyphenator); },
+                [&]() {
+                    auto fromLocaleString = fdp.ConsumeRandomLengthString(MAX_STR_LEN);
+                    auto toLocaleString = fdp.ConsumeRandomLengthString(MAX_STR_LEN);
+                    addHyphenatorAlias(fromLocaleString, toLocaleString);
+                },
+                [&]() {
+                    packHyphenEdit(fdp.PickValueInArray(StartHyphenEdits),
+                                   fdp.PickValueInArray(EndHyphenEdits));
+                },
+                [&]() {
+                    auto textBuf = generateStringPiece(&fdp);
+                    std::vector<HyphenationType> result;
+                    result.push_back(fdp.PickValueInArray(HyphenationTypes));
+                    hyphenator->hyphenate(textBuf, &result);
+                },
+                // Get the list of locales and invoke the API for each one of them
+                [&]() {
+                    uint32_t id = registerLocaleList(fdp.ConsumeRandomLengthString(MAX_STR_LEN));
+                    const LocaleList& locales = LocaleListCache::getById(id);
+                    for (size_t i = 0; i < locales.size(); ++i) {
+                        HyphenatorMap::lookup(locales[i]);
+                    }
+                },
+                [&]() { getHyphenString(endHyphenEdit(fdp.ConsumeIntegral<uint8_t>())); },
+                [&]() { getHyphenString(startHyphenEdit(fdp.ConsumeIntegral<uint8_t>())); },
+                [&]() { isInsertion(endHyphenEdit(fdp.ConsumeIntegral<uint8_t>())); },
+                [&]() { isInsertion(startHyphenEdit(fdp.ConsumeIntegral<uint8_t>())); },
+                [&]() { editForThisLine(fdp.PickValueInArray(HyphenationTypes)); },
+                [&]() { editForNextLine(fdp.PickValueInArray(HyphenationTypes)); },
+                [&]() { isReplacement(endHyphenEdit(fdp.ConsumeIntegral<uint8_t>())); },
+        });
+
+        func();
+    }
+
+    return 0;
+}
diff --git a/fuzz/locale_fuzzer/Android.bp b/fuzz/locale_fuzzer/Android.bp
new file mode 100644
index 0000000..5367687
--- /dev/null
+++ b/fuzz/locale_fuzzer/Android.bp
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2022 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+ cc_fuzz {
+    name: "locale_fuzzer",
+    srcs: [
+        "locale_fuzzer.cpp",
+    ],
+    static_libs: [
+        "libminikin",
+        "libminikin-tests-util",
+    ],
+    shared_libs: [
+        "liblog",
+        "libharfbuzz_ng",
+        "libft2",
+        "libicu",
+        "libutils",
+        "libz",
+    ],
+    header_libs: [
+        "libminikin_headers",
+        "libminikin-headers-for-tests",
+    ],
+    dictionary: "locale.dict",
+}
diff --git a/fuzz/locale_fuzzer/locale.dict b/fuzz/locale_fuzzer/locale.dict
new file mode 100644
index 0000000..66654de
--- /dev/null
+++ b/fuzz/locale_fuzzer/locale.dict
@@ -0,0 +1,83 @@
+# Copyright (C) 2022 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.
+#
+################################################################################
+"as"
+"be"
+"bn"
+"bg"
+"cu"
+"cy"
+"da"
+"de"
+"de-1996"
+"de-ch-1901"
+"en-GB"
+"en-gb"
+"en-US"
+"en-us"
+"es"
+"et"
+"eu"
+"Ethi"
+"und-ethi"
+"fr"
+"ga"
+"gu"
+"hi"
+"hr"
+"hu"
+"hy"
+"kn"
+"la"
+"ml"
+"mn"
+"mn-cyrl"
+"mr"
+"nb"
+"nn"
+"or"
+"pa"
+"pt"
+"sl"
+"ta"
+"te"
+"tk"
+"en-Latn"
+"Latn"
+"Jpan"
+"zh-Hant"
+"Hant"
+"ko-Kore"
+"Kore"
+"ko-Hang"
+"zh-Hans"
+"Bopo"
+"Hang"
+"Hant"
+"zh-Hant"
+"Hans"
+"zh-Hans"
+"ja-Hira"
+"ja-Kana"
+"ja-Hrkt"
+"ja-Hani"
+"Hrkt"
+"Hira"
+"Kana"
+"zh-Hani"
+"Hanb"
+"ko-Hani"
+"Hani"
+"zh-Hanb"
diff --git a/fuzz/locale_fuzzer/locale_fuzzer.cpp b/fuzz/locale_fuzzer/locale_fuzzer.cpp
new file mode 100644
index 0000000..8ae5140
--- /dev/null
+++ b/fuzz/locale_fuzzer/locale_fuzzer.cpp
@@ -0,0 +1,53 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2022 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 <fuzzer/FuzzedDataProvider.h>
+
+#include "LocaleListCache.h"
+#include "minikin/LocaleList.h"
+
+using namespace minikin;
+
+const SubtagBits subtangBits[] = {SubtagBits::EMPTY,  SubtagBits::LANGUAGE, SubtagBits::SCRIPT,
+                                  SubtagBits::REGION, SubtagBits::VARIANT,  SubtagBits::EMOJI,
+                                  SubtagBits::ALL};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+
+    uint32_t id = registerLocaleList(fdp.ConsumeRandomLengthString());
+    uint32_t localeListId = fdp.ConsumeIntegralInRange<uint32_t>(0, id);
+    const LocaleList& locales = LocaleListCache::getById(localeListId);
+    std::string langTag = getLocaleString(localeListId);
+
+    for (size_t i = 0; i < locales.size(); i++) {
+        locales[i].getPartialLocale(fdp.PickValueInArray(subtangBits));
+        locales[i].supportsScript(fdp.ConsumeIntegral<uint32_t>());
+        locales[i].calcScoreFor(locales);
+    }
+
+    BufferWriter fakeWriter(nullptr);
+    LocaleListCache::writeTo(&fakeWriter, LocaleListCache::getId(langTag));
+    std::vector<uint8_t> buffer(fakeWriter.size());
+    BufferWriter writer(buffer.data());
+    LocaleListCache::writeTo(&writer, LocaleListCache::getId(langTag));
+    BufferReader reader(buffer.data());
+    LocaleListCache::readFrom(&reader);
+
+    return 0;
+}
diff --git a/fuzz/measurement_fuzzer/Android.bp b/fuzz/measurement_fuzzer/Android.bp
new file mode 100644
index 0000000..133c172
--- /dev/null
+++ b/fuzz/measurement_fuzzer/Android.bp
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2022 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+    name: "measurement_fuzzer",
+    srcs: [
+        "measurement_fuzzer.cpp",
+    ],
+    static_libs: [
+        "libminikin",
+        "libminikin-tests-util",
+        "libxml2",
+    ],
+    shared_libs: [
+        "liblog",
+        "libharfbuzz_ng",
+        "libft2",
+        "libicu",
+        "libutils",
+        "libz",
+    ],
+    header_libs: [
+        "libminikin_headers",
+        "libminikin-headers-for-tests",
+    ],
+}
diff --git a/fuzz/measurement_fuzzer/measurement_fuzzer.cpp b/fuzz/measurement_fuzzer/measurement_fuzzer.cpp
new file mode 100644
index 0000000..872f4c6
--- /dev/null
+++ b/fuzz/measurement_fuzzer/measurement_fuzzer.cpp
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2022 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 <fuzzer/FuzzedDataProvider.h>
+
+#include "minikin/Measurement.h"
+using namespace minikin;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+    float advance = fdp.ConsumeFloatingPoint<float>();
+    int sizeof_size = (int)sizeof(size_t);
+    int sizeof_uint16 = (int)sizeof(uint16_t);
+    int sizeof_float = (int)sizeof(float);
+    int remaining = fdp.remaining_bytes();
+    int limit = (int)((remaining - 3 * sizeof_size) / sizeof_uint16);
+    limit = (limit < 0) ? 0 : limit;
+    int buf_size = fdp.ConsumeIntegralInRange<int>(0, limit);
+    if (buf_size == 0) return 0;
+    uint16_t buf[buf_size];
+    for (int i = 0; i < buf_size; i++) buf[i] = fdp.ConsumeIntegral<uint16_t>();
+    size_t start = fdp.ConsumeIntegralInRange<size_t>(0, buf_size - 1);
+    size_t count = fdp.ConsumeIntegralInRange<size_t>(0, buf_size - 1 - start);
+    size_t offset = fdp.ConsumeIntegralInRange<size_t>(start, start + count);
+    remaining = fdp.remaining_bytes();
+    if (remaining / sizeof_float < count) return 0;
+    if (offset == start + count) return 0;
+    int advances_size = count;
+    float advances[advances_size];
+    for (int i = 0; i < advances_size; i++) advances[i] = fdp.ConsumeFloatingPoint<float>();
+    float advance_run = getRunAdvance(advances, buf, start, count, offset);
+    size_t advance_offset = getOffsetForAdvance(advances, buf, start, count, advance);
+    return 0;
+}
diff --git a/include/minikin/Buffer.h b/include/minikin/Buffer.h
index 87ba3fd..a4d0104 100644
--- a/include/minikin/Buffer.h
+++ b/include/minikin/Buffer.h
@@ -27,55 +27,88 @@
 // This is a helper class to read data from a memory buffer.
 // This class does not copy memory, and may return pointers to parts of the memory buffer.
 // Thus the memory buffer should outlive objects created using this class.
+//
+// Note on alignment:
+// Some CPU archs (e.g. arm32) do not allow misaligned memory access.
+// Therefore, BufferReader and BufferWriter automatically insert paddings
+// to align data records.
+// For the padding to be deterministic, the following conditions must be met:
+// (1) Alignment and size of each data record must be fixed regardless of
+//     CPU arch.
+// (2) Alignment for each data record must be a power of 2 (2^n) and
+//     must be less than or equal to kMaxAlignment.
+// (3) The head address of the buffer must be aligned at kMaxAlignment.
+//
+// The condition (2) and (3) ensures that 'headAddress % align == 0'
+// and the padding is determined only by the current position.
+// I.e. mCurrent % align == (mCurrent - headAddress) % align.
 class BufferReader {
 public:
-    BufferReader(const void* buffer) : BufferReader(buffer, 0) {}
-    BufferReader(const void* buffer, uint32_t pos)
-            : mData(reinterpret_cast<const uint8_t*>(buffer)), mPos(pos) {}
+    static constexpr size_t kMaxAlignment = 8;
 
-    template <typename T>
-    static uint32_t align(uint32_t pos) {
-        // This should be true for all types, unless custom alignment attributes are set.
-        static_assert(sizeof(T) % alignof(T) == 0, "sizeof(T) must be a multiple of alignof(T)");
-        // We align to sizeof(T) instead of alignof(T), because the buffer may be shared between
-        // 32-bit processes and 64-bit processes. alignof(T) may change between the two.
-        // We assume that T is a type whose size is fixed (e.g. uint32_t).
-        return (pos + sizeof(T) - 1) / sizeof(T) * sizeof(T);
+    explicit BufferReader(const void* buffer) : BufferReader(buffer, 0) {}
+    BufferReader(const void* buffer, uint32_t pos)
+            : mCurrent(reinterpret_cast<const uint8_t*>(buffer) + pos) {}
+
+    // align() adds padding if necessary so that the returned pointer is aligned
+    // at 'align' template parameter (i.e. align<T, _align>(p) % _align == 0).
+    //
+    // By default we align to sizeof(T) instead of alignof(T), because the
+    // buffer may be shared between 32-bit processes and 64-bit processes.
+    // The value of alignof(T) may change between the two.
+    //
+    // If T is a large struct or class, you would need to specify 'align'
+    // template parameter manually.
+    template <typename T, size_t align = sizeof(T)>
+    static const uint8_t* align(const uint8_t* p) {
+        static_assert(align <= kMaxAlignment);
+        static_assert(__builtin_popcount(align) == 1, "align must be a power of 2");
+        constexpr size_t mask = align - 1;
+        intptr_t i = reinterpret_cast<intptr_t>(p);
+        intptr_t aligned = (i + mask) & ~mask;
+        return reinterpret_cast<const uint8_t*>(aligned);
     }
 
-    template <typename T>
+    template <typename T, size_t align = sizeof(T)>
     const T& read() {
-        static_assert(std::is_pod<T>::value, "T must be a POD");
-        mPos = BufferReader::align<T>(mPos);
-        const T* data = reinterpret_cast<const T*>(mData + mPos);
-        mPos += sizeof(T);
+        const T* data = map<T, align>(sizeof(T));
         return *data;
     }
 
-    template <typename T>
+    template <typename T, size_t align = sizeof(T)>
+    const T* map(uint32_t size) {
+        static_assert(std::is_pod<T>::value, "T must be a POD");
+        mCurrent = BufferReader::align<T, align>(mCurrent);
+        const T* data = reinterpret_cast<const T*>(mCurrent);
+        mCurrent += size;
+        return data;
+    }
+
+    template <typename T, size_t align = sizeof(T)>
     void skip() {
         static_assert(std::is_pod<T>::value, "T must be a POD");
-        mPos = BufferReader::align<T>(mPos);
-        mPos += sizeof(T);
+        mCurrent = BufferReader::align<T, align>(mCurrent);
+        mCurrent += sizeof(T);
     }
 
     // Return a pointer to an array and its number of elements.
-    template <typename T>
+    template <typename T, size_t align = sizeof(T)>
     std::pair<const T*, uint32_t> readArray() {
         static_assert(std::is_pod<T>::value, "T must be a POD");
+        static_assert(sizeof(T) % align == 0);
         uint32_t size = read<uint32_t>();
-        mPos = BufferReader::align<T>(mPos);
-        const T* data = reinterpret_cast<const T*>(mData + mPos);
-        mPos += size * sizeof(T);
+        mCurrent = BufferReader::align<T, align>(mCurrent);
+        const T* data = reinterpret_cast<const T*>(mCurrent);
+        mCurrent += size * sizeof(T);
         return std::make_pair(data, size);
     }
 
-    template <typename T>
+    template <typename T, size_t align = sizeof(T)>
     void skipArray() {
         static_assert(std::is_pod<T>::value, "T must be a POD");
         uint32_t size = read<uint32_t>();
-        mPos = BufferReader::align<T>(mPos);
-        mPos += size * sizeof(T);
+        mCurrent = BufferReader::align<T, align>(mCurrent);
+        mCurrent += size * sizeof(T);
     }
 
     std::string_view readString() {
@@ -85,20 +118,32 @@
 
     void skipString() { skipArray<char>(); }
 
-    const void* data() const { return mData; }
-    size_t pos() const { return mPos; }
+    const void* current() const { return mCurrent; }
 
 private:
-    const uint8_t* mData;
-    size_t mPos;
+    const uint8_t* mCurrent;
 };
 
 // This is a helper class to write data to a memory buffer.
+//
+// BufferWriter does NOT allocate the memory.
+// The typical usage is to use BufferWriter twice; in the first pass, write
+// data with a fake BufferWriter (BufferWriter(nullptr)) to calculate the buffer
+// size. In the second pass, allocate a memory buffer and use a real
+// BufferWriter to write the data.
+// Pseudo code:
+//     BufferWriter fakeWriter(nullptr);
+//     myData.writeTo(&fakeWriter);
+//     void* buffer = malloc(fakeWriter.size());
+//     BufferWriter realWriter(buffer);
+//     myData.writeTo(&realWriter);
 class BufferWriter {
 public:
     // Create a buffer writer. Passing nullptr creates a fake writer,
     // which can be used to measure the buffer size needed.
-    BufferWriter(void* buffer) : mData(reinterpret_cast<uint8_t*>(buffer)), mPos(0) {}
+    explicit BufferWriter(void* buffer) : BufferWriter(buffer, 0) {}
+    BufferWriter(void* buffer, uint32_t pos)
+            : mData(reinterpret_cast<uint8_t*>(buffer)), mPos(pos) {}
 
     BufferWriter(BufferWriter&&) = default;
     BufferWriter& operator=(BufferWriter&&) = default;
@@ -107,25 +152,35 @@
     // Please always specify T explicitly using <>. std::common_type_t<T> resolves to T, but
     // disables template argument deduction.
     // TODO: use std::type_identity_t when C++20 is available.
-    template <typename T>
+    template <typename T, size_t align = sizeof(T)>
     void write(const std::common_type_t<T>& data) {
-        static_assert(std::is_pod<T>::value, "T must be a POD");
-        mPos = BufferReader::align<T>(mPos);
-        if (mData != nullptr) {
-            memcpy(mData + mPos, &data, sizeof(T));
+        T* buf = reserve<T, align>(sizeof(T));
+        if (buf != nullptr) {
+            memcpy(buf, &data, sizeof(T));
         }
-        mPos += sizeof(T);
+    }
+
+    // Reserve a region and return a pointer to the reserved region.
+    // The reserved region is not initialized.
+    template <typename T, size_t align = sizeof(T)>
+    T* reserve(uint32_t size) {
+        static_assert(std::is_pod<T>::value, "T must be a POD");
+        mPos = BufferWriter::align<T, align>(mPos);
+        uint32_t pos = mPos;
+        mPos += size;
+        return mData == nullptr ? nullptr : reinterpret_cast<T*>(mData + pos);
     }
 
     // Write an array of type T.
     // Please always specify T explicitly using <>. std::common_type_t<T> resolves to T, but
     // disables template argument deduction.
     // TODO: use std::type_identity_t when C++20 is available.
-    template <typename T>
+    template <typename T, size_t align = sizeof(T)>
     void writeArray(const std::common_type_t<T>* data, uint32_t size) {
         static_assert(std::is_pod<T>::value, "T must be a POD");
+        static_assert(sizeof(T) % align == 0);
         write<uint32_t>(size);
-        mPos = BufferReader::align<T>(mPos);
+        mPos = BufferWriter::align<T, align>(mPos);
         if (mData != nullptr) {
             memcpy(mData + mPos, data, size * sizeof(T));
         }
@@ -141,6 +196,11 @@
     uint8_t* mData;
     size_t mPos;
 
+    template <typename T, size_t align>
+    size_t align(size_t pos) const {
+        return BufferReader::align<T, align>(mData + pos) - mData;
+    }
+
     // Forbid copy and assign.
     BufferWriter(const BufferWriter&) = delete;
     void operator=(const BufferWriter&) = delete;
diff --git a/include/minikin/CmapCoverage.h b/include/minikin/CmapCoverage.h
index 583593d..898e63b 100644
--- a/include/minikin/CmapCoverage.h
+++ b/include/minikin/CmapCoverage.h
@@ -27,7 +27,7 @@
 class CmapCoverage {
 public:
     static SparseBitSet getCoverage(const uint8_t* cmap_data, size_t cmap_size,
-                                    std::vector<std::unique_ptr<SparseBitSet>>* out);
+                                    std::vector<SparseBitSet>* out);
 };
 
 }  // namespace minikin
diff --git a/include/minikin/Font.h b/include/minikin/Font.h
index 67feecf..f144bea 100644
--- a/include/minikin/Font.h
+++ b/include/minikin/Font.h
@@ -17,8 +17,10 @@
 #ifndef MINIKIN_FONT_H
 #define MINIKIN_FONT_H
 
+#include <gtest/gtest_prod.h>
+
+#include <atomic>
 #include <memory>
-#include <mutex>
 #include <unordered_set>
 
 #include "minikin/Buffer.h"
@@ -110,29 +112,12 @@
         bool mIsSlantSet = false;
     };
 
-    // Type for functions to load MinikinFont lazily.
-    using TypefaceLoader = std::shared_ptr<MinikinFont>(BufferReader reader);
-    // Type for functions to read MinikinFont metadata and return
-    // TypefaceLoader.
-    using TypefaceReader = TypefaceLoader*(BufferReader* reader);
-    // Type for functions to write MinikinFont metadata.
-    using TypefaceWriter = void(BufferWriter* writer, const MinikinFont* typeface);
+    explicit Font(BufferReader* reader);
+    void writeTo(BufferWriter* writer) const;
 
-    template <TypefaceReader typefaceReader>
-    static std::shared_ptr<Font> readFrom(BufferReader* reader, uint32_t localeListId) {
-        FontStyle style = FontStyle(reader);
-        BufferReader typefaceMetadataReader = *reader;
-        TypefaceLoader* typefaceLoader = typefaceReader(reader);
-        return std::shared_ptr<Font>(
-                new Font(style, typefaceMetadataReader, typefaceLoader, localeListId));
-    }
-
-    template <TypefaceWriter typefaceWriter>
-    void writeTo(BufferWriter* writer) const {
-        mStyle.writeTo(writer);
-        typefaceWriter(writer, typeface().get());
-    }
-
+    Font(Font&& o) noexcept;
+    Font& operator=(Font&& o) noexcept;
+    ~Font();
     // This locale list is just for API compatibility. This is not used in font selection or family
     // fallback.
     uint32_t getLocaleListId() const { return mLocaleListId; }
@@ -144,46 +129,47 @@
     std::unordered_set<AxisTag> getSupportedAxes() const;
 
 private:
+    // ExternalRefs holds references to objects provided by external libraries.
+    // Because creating these external objects is costly,
+    // ExternalRefs is lazily created if Font was created by readFrom().
+    class ExternalRefs {
+    public:
+        ExternalRefs(std::shared_ptr<MinikinFont>&& typeface, HbFontUniquePtr&& baseFont)
+                : mTypeface(std::move(typeface)), mBaseFont(std::move(baseFont)) {}
+
+        std::shared_ptr<MinikinFont> mTypeface;
+        HbFontUniquePtr mBaseFont;
+    };
+
     // Use Builder instead.
     Font(std::shared_ptr<MinikinFont>&& typeface, FontStyle style, HbFontUniquePtr&& baseFont,
          uint32_t localeListId)
-            : mTypeface(std::move(typeface)),
+            : mExternalRefsHolder(new ExternalRefs(std::move(typeface), std::move(baseFont))),
               mStyle(style),
-              mBaseFont(std::move(baseFont)),
-              mTypefaceLoader(nullptr),
-              mTypefaceMetadataReader(nullptr),
-              mLocaleListId(localeListId) {}
-    Font(FontStyle style, BufferReader typefaceMetadataReader, TypefaceLoader* typefaceLoader,
-         uint32_t localeListId)
-            : mStyle(style),
-              mTypefaceLoader(typefaceLoader),
-              mTypefaceMetadataReader(typefaceMetadataReader),
-              mLocaleListId(localeListId) {}
+              mLocaleListId(localeListId),
+              mTypefaceMetadataReader(nullptr) {}
 
-    void initTypefaceLocked() const EXCLUSIVE_LOCKS_REQUIRED(mTypefaceMutex);
+    void resetExternalRefs(ExternalRefs* refs);
+
+    const ExternalRefs* getExternalRefs() const;
 
     static HbFontUniquePtr prepareFont(const std::shared_ptr<MinikinFont>& typeface);
     static FontStyle analyzeStyle(const HbFontUniquePtr& font);
 
     // Lazy-initialized if created by readFrom().
-    mutable std::shared_ptr<MinikinFont> mTypeface GUARDED_BY(mTypefaceMutex);
+    mutable std::atomic<ExternalRefs*> mExternalRefsHolder;
     FontStyle mStyle;
-    // Lazy-initialized if created by readFrom().
-    mutable HbFontUniquePtr mBaseFont GUARDED_BY(mTypefaceMutex);
+    uint32_t mLocaleListId;
 
-    mutable std::mutex mTypefaceMutex;
-    // Non-null if created by readFrom().
-    TypefaceLoader* mTypefaceLoader;
     // Non-null if created by readFrom().
     BufferReader mTypefaceMetadataReader;
 
-    uint32_t mLocaleListId;
-
-    // Stop copying and moving
-    Font(Font&& o) = delete;
-    Font& operator=(Font&& o) = delete;
+    // Stop copying.
     Font(const Font& o) = delete;
     Font& operator=(const Font& o) = delete;
+
+    FRIEND_TEST(FontTest, MoveConstructorTest);
+    FRIEND_TEST(FontTest, MoveAssignmentTest);
 };
 
 }  // namespace minikin
diff --git a/include/minikin/FontCollection.h b/include/minikin/FontCollection.h
index 98df571..1679abc 100644
--- a/include/minikin/FontCollection.h
+++ b/include/minikin/FontCollection.h
@@ -17,13 +17,12 @@
 #ifndef MINIKIN_FONT_COLLECTION_H
 #define MINIKIN_FONT_COLLECTION_H
 
+#include <gtest/gtest_prod.h>
+
 #include <memory>
 #include <unordered_map>
-#include <unordered_set>
 #include <vector>
 
-#include <gtest/gtest_prod.h>
-
 #include "minikin/Buffer.h"
 #include "minikin/Font.h"
 #include "minikin/FontFamily.h"
@@ -37,43 +36,13 @@
 
 class FontCollection {
 public:
-    explicit FontCollection(const std::vector<std::shared_ptr<FontFamily>>& typefaces);
-    explicit FontCollection(std::shared_ptr<FontFamily>&& typeface);
+    static std::shared_ptr<FontCollection> create(
+            const std::vector<std::shared_ptr<FontFamily>>& typefaces);
+    static std::shared_ptr<FontCollection> create(std::shared_ptr<FontFamily>&& typeface);
 
-    template <Font::TypefaceReader typefaceReader>
-    static std::vector<std::shared_ptr<FontCollection>> readVector(BufferReader* reader) {
-        uint32_t allFontFamiliesCount = reader->read<uint32_t>();
-        std::vector<std::shared_ptr<FontFamily>> allFontFamilies;
-        allFontFamilies.reserve(allFontFamiliesCount);
-        for (uint32_t i = 0; i < allFontFamiliesCount; i++) {
-            allFontFamilies.push_back(FontFamily::readFrom<typefaceReader>(reader));
-        }
-        uint32_t fontCollectionsCount = reader->read<uint32_t>();
-        std::vector<std::shared_ptr<FontCollection>> fontCollections;
-        fontCollections.reserve(fontCollectionsCount);
-        for (uint32_t i = 0; i < fontCollectionsCount; i++) {
-            fontCollections.emplace_back(new FontCollection(reader, allFontFamilies));
-        }
-        return fontCollections;
-    }
-
-    template <Font::TypefaceWriter typefaceWriter>
+    static std::vector<std::shared_ptr<FontCollection>> readVector(BufferReader* reader);
     static void writeVector(BufferWriter* writer,
-                            const std::vector<std::shared_ptr<FontCollection>>& fontCollections) {
-        std::vector<std::shared_ptr<FontFamily>> allFontFamilies;
-        // Note: operator== for shared_ptr compares raw pointer values.
-        std::unordered_map<std::shared_ptr<FontFamily>, uint32_t> fontFamilyToIndexMap;
-        collectAllFontFamilies(fontCollections, &allFontFamilies, &fontFamilyToIndexMap);
-
-        writer->write<uint32_t>(allFontFamilies.size());
-        for (const auto& fontFamily : allFontFamilies) {
-            fontFamily->writeTo<typefaceWriter>(writer);
-        }
-        writer->write<uint32_t>(fontCollections.size());
-        for (const auto& fontCollection : fontCollections) {
-            fontCollection->writeTo(writer, fontFamilyToIndexMap);
-        }
-    }
+                            const std::vector<std::shared_ptr<FontCollection>>& fontCollections);
 
     // Helper class for representing font family match result in packed bits.
     struct FamilyMatchResult {
@@ -190,18 +159,32 @@
     // nullptr if none of variations apply to this collection.
     std::shared_ptr<FontCollection> createCollectionWithVariation(
             const std::vector<FontVariation>& variations);
+    // Creates new FontCollection that uses the specified families as top families and
+    // families from this FontCollection as fallback.
+    std::shared_ptr<FontCollection> createCollectionWithFamilies(
+            std::vector<std::shared_ptr<FontFamily>>&& families) const;
 
-    const std::unordered_set<AxisTag>& getSupportedTags() const { return mSupportedAxes; }
+    size_t getSupportedAxesCount() const { return mSupportedAxesCount; }
+    AxisTag getSupportedAxisAt(size_t index) const { return mSupportedAxes[index]; }
 
     uint32_t getId() const;
 
-    const std::vector<std::shared_ptr<FontFamily>>& getFamilies() const { return mFamilies; }
+    size_t getFamilyCount() const { return mFamilyCount; }
+
+    const std::shared_ptr<FontFamily>& getFamilyAt(size_t index) const {
+        if (mFamilyIndices != nullptr) {
+            index = mFamilyIndices[index];
+        }
+        return (*mMaybeSharedFamilies)[index];
+    }
 
 private:
     FRIEND_TEST(FontCollectionTest, bufferTest);
 
-    FontCollection(BufferReader* reader,
-                   const std::vector<std::shared_ptr<FontFamily>>& allFontFamilies);
+    explicit FontCollection(const std::vector<std::shared_ptr<FontFamily>>& typefaces);
+    FontCollection(
+            BufferReader* reader,
+            const std::shared_ptr<std::vector<std::shared_ptr<FontFamily>>>& allFontFamilies);
     // Write fields of the instance, using fontFamilyToIndexMap for finding
     // indices for FontFamily.
     void writeTo(BufferWriter* writer,
@@ -215,8 +198,9 @@
     static const int kLogCharsPerPage = 8;
     static const int kPageMask = (1 << kLogCharsPerPage) - 1;
 
-    // mFamilyVec holds the indices of the mFamilies and mRanges holds the range of indices of
-    // mFamilyVec. The maximum number of pages is 0x10FF (U+10FFFF >> 8). The maximum number of
+    // mFamilyVec holds the indices of the family (as in getFamilyAt()) and
+    // mRanges holds the range of indices of mFamilyVec.
+    // The maximum number of pages is 0x10FF (U+10FFFF >> 8). The maximum number of
     // the fonts is 0xFF. Thus, technically the maximum length of mFamilyVec is 0x10EE01
     // (0x10FF * 0xFF). However, in practice, 16-bit integers are enough since most fonts supports
     // only limited range of code points.
@@ -237,6 +221,8 @@
     uint32_t calcCoverageScore(uint32_t ch, uint32_t vs, uint32_t localeListId,
                                const std::shared_ptr<FontFamily>& fontFamily) const;
 
+    bool isPrimaryFamily(const std::shared_ptr<FontFamily>& fontFamily) const;
+
     static uint32_t calcLocaleMatchingScore(uint32_t userLocaleListId,
                                             const FontFamily& fontFamily);
 
@@ -250,7 +236,18 @@
 
     // This vector has pointers to the all font family instances in this collection.
     // This vector can't be empty.
-    std::vector<std::shared_ptr<FontFamily>> mFamilies;
+    // This vector may be shared with other font collections.
+    // (1) When shared, this vector is a union of all font family instances
+    //     shared by multiple font collections.
+    //     mFamilyIndices will be non-null in this case.
+    //     The i-th family in this collection will be
+    //     mMaybeSharedFamilies[mFamilyIndices[i]].
+    // (2) When not shared, mFamilyIndices will be null and
+    //     the i-th family in this collection will be mMaybeSharedFamilies[i].
+    // Use getFamilyAt(i) to access the i-th font in this family.
+    std::shared_ptr<std::vector<std::shared_ptr<FontFamily>>> mMaybeSharedFamilies;
+    uint32_t mFamilyCount;
+    const uint32_t* mFamilyIndices;
 
     // Following two vectors are pre-calculated tables for resolving coverage faster.
     // For example, to iterate over all fonts which support Unicode code point U+XXYYZZ,
@@ -267,7 +264,9 @@
     std::vector<std::shared_ptr<FontFamily>> mVSFamilyVec;
 
     // Set of supported axes in this collection.
-    std::unordered_set<AxisTag> mSupportedAxes;
+    uint32_t mSupportedAxesCount;
+    // mSupportedAxes is sorted.
+    std::unique_ptr<AxisTag[]> mSupportedAxes;
 
     // Owns allocated memory if this class is created from font families, otherwise these are
     // nullptr.
diff --git a/include/minikin/FontFamily.h b/include/minikin/FontFamily.h
index 6169193..6161f5c 100644
--- a/include/minikin/FontFamily.h
+++ b/include/minikin/FontFamily.h
@@ -19,7 +19,6 @@
 
 #include <memory>
 #include <string>
-#include <unordered_set>
 #include <vector>
 
 #include "minikin/FamilyVariant.h"
@@ -33,32 +32,19 @@
 
 class FontFamily {
 public:
-    explicit FontFamily(std::vector<std::shared_ptr<Font>>&& fonts);
-    FontFamily(FamilyVariant variant, std::vector<std::shared_ptr<Font>>&& fonts);
-    FontFamily(uint32_t localeListId, FamilyVariant variant,
-               std::vector<std::shared_ptr<Font>>&& fonts, bool isCustomFallback);
+    static std::shared_ptr<FontFamily> create(std::vector<std::shared_ptr<Font>>&& fonts);
+    static std::shared_ptr<FontFamily> create(FamilyVariant variant,
+                                              std::vector<std::shared_ptr<Font>>&& fonts);
+    static std::shared_ptr<FontFamily> create(uint32_t localeListId, FamilyVariant variant,
+                                              std::vector<std::shared_ptr<Font>>&& fonts,
+                                              bool isCustomFallback, bool isDefaultFallback);
 
-    template <Font::TypefaceReader typefaceReader>
-    static std::shared_ptr<FontFamily> readFrom(BufferReader* reader) {
-        uint32_t localeListId = readLocaleListInternal(reader);
-        uint32_t fontsCount = reader->read<uint32_t>();
-        std::vector<std::shared_ptr<Font>> fonts;
-        fonts.reserve(fontsCount);
-        for (uint32_t i = 0; i < fontsCount; i++) {
-            fonts.emplace_back(Font::readFrom<typefaceReader>(reader, localeListId));
-        }
-        return readFromInternal(reader, std::move(fonts), localeListId);
-    }
+    FontFamily(FontFamily&&) = default;
+    FontFamily& operator=(FontFamily&&) = default;
 
-    template <Font::TypefaceWriter typefaceWriter>
-    void writeTo(BufferWriter* writer) const {
-        writeLocaleListInternal(writer);
-        writer->write<uint32_t>(mFonts.size());
-        for (const std::shared_ptr<Font>& font : mFonts) {
-            font->writeTo<typefaceWriter>(writer);
-        }
-        writeToInternal(writer);
-    }
+    static std::vector<std::shared_ptr<FontFamily>> readVector(BufferReader* reader);
+    static void writeVector(BufferWriter* writer,
+                            const std::vector<std::shared_ptr<FontFamily>>& families);
 
     FakedFont getClosestMatch(FontStyle style) const;
 
@@ -66,13 +52,15 @@
     FamilyVariant variant() const { return mVariant; }
 
     // API's for enumerating the fonts in a family. These don't guarantee any particular order
-    size_t getNumFonts() const { return mFonts.size(); }
+    size_t getNumFonts() const { return mFontsCount; }
     const Font* getFont(size_t index) const { return mFonts[index].get(); }
     const std::shared_ptr<Font>& getFontRef(size_t index) const { return mFonts[index]; }
     FontStyle getStyle(size_t index) const { return mFonts[index]->style(); }
     bool isColorEmojiFamily() const { return mIsColorEmoji; }
-    const std::unordered_set<AxisTag>& supportedAxes() const { return mSupportedAxes; }
+    size_t getSupportedAxesCount() const { return mSupportedAxesCount; }
+    AxisTag getSupportedAxisAt(size_t index) const { return mSupportedAxes[index]; }
     bool isCustomFallback() const { return mIsCustomFallback; }
+    bool isDefaultFallback() const { return mIsDefaultFallback; }
 
     // Get Unicode coverage.
     const SparseBitSet& getCoverage() const { return mCoverage; }
@@ -82,7 +70,7 @@
     bool hasGlyph(uint32_t codepoint, uint32_t variationSelector) const;
 
     // Returns true if this font family has a variaion sequence table (cmap format 14 subtable).
-    bool hasVSTable() const { return !mCmapFmt14Coverage.empty(); }
+    bool hasVSTable() const { return mCmapFmt14CoverageCount != 0; }
 
     // Creates new FontFamily based on this family while applying font variations. Returns nullptr
     // if none of variations apply to this family.
@@ -91,29 +79,30 @@
 
 private:
     FontFamily(uint32_t localeListId, FamilyVariant variant,
-               std::vector<std::shared_ptr<Font>>&& fonts,
-               std::unordered_set<AxisTag>&& supportedAxes, bool isColorEmoji,
-               bool isCustomFallback, SparseBitSet&& coverage,
-               std::vector<std::unique_ptr<SparseBitSet>>&& cmapFmt14Coverage);
+               std::vector<std::shared_ptr<Font>>&& fonts, bool isCustomFallback,
+               bool isDefaultFallback);
+    explicit FontFamily(BufferReader* reader, const std::shared_ptr<std::vector<Font>>& fonts);
 
-    static uint32_t readLocaleListInternal(BufferReader* reader);
-    static std::shared_ptr<FontFamily> readFromInternal(BufferReader* reader,
-                                                        std::vector<std::shared_ptr<Font>>&& fonts,
-                                                        uint32_t localeListId);
-    void writeLocaleListInternal(BufferWriter* writer) const;
-    void writeToInternal(BufferWriter* writer) const;
+    void writeTo(BufferWriter* writer, uint32_t* fontIndex) const;
 
     void computeCoverage();
 
-    uint32_t mLocaleListId;
-    FamilyVariant mVariant;
-    std::vector<std::shared_ptr<Font>> mFonts;
-    std::unordered_set<AxisTag> mSupportedAxes;
-    bool mIsColorEmoji;
-    bool mIsCustomFallback;
-
+    // Note: to minimize padding, small member fields are grouped at the end.
+    std::unique_ptr<std::shared_ptr<Font>[]> mFonts;
+    // mSupportedAxes is sorted.
+    std::unique_ptr<AxisTag[]> mSupportedAxes;
     SparseBitSet mCoverage;
-    std::vector<std::unique_ptr<SparseBitSet>> mCmapFmt14Coverage;
+    std::unique_ptr<SparseBitSet[]> mCmapFmt14Coverage;
+    uint32_t mLocaleListId;  // 4 bytes
+    uint32_t mFontsCount;    // 4 bytes
+    // OpenType supports up to 2^16-1 (uint16) axes.
+    // https://docs.microsoft.com/en-us/typography/opentype/spec/fvar
+    uint16_t mSupportedAxesCount;      // 2 bytes
+    uint16_t mCmapFmt14CoverageCount;  // 2 bytes
+    FamilyVariant mVariant;            // 1 byte
+    bool mIsColorEmoji;                // 1 byte
+    bool mIsCustomFallback;            // 1 byte
+    bool mIsDefaultFallback;           // 1 byte
 
     MINIKIN_PREVENT_COPY_AND_ASSIGN(FontFamily);
 };
diff --git a/include/minikin/Measurement.h b/include/minikin/Measurement.h
index 76f3701..ef0b6a5 100644
--- a/include/minikin/Measurement.h
+++ b/include/minikin/Measurement.h
@@ -28,6 +28,8 @@
 float getRunAdvance(const float* advances, const uint16_t* buf, size_t start, size_t count,
                     size_t offset);
 
+void distributeAdvances(float* advances, const uint16_t* buf, size_t start, size_t count);
+
 size_t getOffsetForAdvance(const float* advances, const uint16_t* buf, size_t start, size_t count,
                            float advance);
 
diff --git a/include/minikin/MinikinFontFactory.h b/include/minikin/MinikinFontFactory.h
new file mode 100644
index 0000000..b8c3368
--- /dev/null
+++ b/include/minikin/MinikinFontFactory.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#ifndef MINIKIN_MINIKIN_FONT_FACTORY_H
+#define MINIKIN_MINIKIN_FONT_FACTORY_H
+
+#include "minikin/Buffer.h"
+#include "minikin/MinikinFont.h"
+
+namespace minikin {
+
+// A class to serialize / deserialize MinikinFont instance into / from memory buffer.
+class MinikinFontFactory {
+public:
+    MinikinFontFactory() {}
+
+    virtual ~MinikinFontFactory() = 0;
+
+    // Create MinikinFont instance from the buffer.
+    virtual std::shared_ptr<MinikinFont> create(BufferReader reader) const = 0;
+
+    // Skip a MinikinFont region in the buffer and advance the reader to the
+    // next position.
+    virtual void skip(BufferReader* reader) const = 0;
+
+    // Serialize MinikinFont into the buffer.
+    virtual void write(BufferWriter* writer, const MinikinFont* minikinFont) const = 0;
+
+    // Return the singleton MinikinFontFactory instance.
+    // setInstance() must be called before any MinikinFont instance is
+    // serialized or deserialized.
+    static const MinikinFontFactory& getInstance();
+
+    // Set the factory instance.
+    // The factory must be a singleton and cannot be changed during the process lifetime.
+    // It is safe to call this method multiple times with the same instance.
+    // This method itself is not thread safe. The call to this method, as well
+    // as deserialized MinikinFont objects, must be synchronized by the caller.
+    static void setInstance(const MinikinFontFactory* factory);
+};
+
+}  // namespace minikin
+
+#endif  // MINIKIN_MINIKIN_FONT_FACTORY_H
diff --git a/include/minikin/SparseBitSet.h b/include/minikin/SparseBitSet.h
index 3034243..33047e8 100644
--- a/include/minikin/SparseBitSet.h
+++ b/include/minikin/SparseBitSet.h
@@ -19,6 +19,7 @@
 
 #include <minikin/Buffer.h>
 #include <sys/types.h>
+
 #include <cstdint>
 #include <memory>
 
@@ -34,7 +35,7 @@
 class SparseBitSet {
 public:
     // Create an empty bit set.
-    SparseBitSet() : mMaxVal(0) {}
+    SparseBitSet() : mData(nullptr) {}
 
     // Initialize the set to a new value, represented by ranges. For
     // simplicity, these ranges are arranged as pairs of values,
@@ -52,14 +53,16 @@
 
     // Determine whether the value is included in the set
     bool get(uint32_t ch) const {
-        if (ch >= mMaxVal) return false;
-        const uint32_t* bitmap = &mBitmaps[mIndices[ch >> kLogValuesPerPage]];
+        if (ch >= length()) return false;
+        const uint32_t* bitmap = mData->bitmaps() + mData->indices()[ch >> kLogValuesPerPage];
         uint32_t index = ch & kPageMask;
         return (bitmap[index >> kLogBitsPerEl] & (kElFirst >> (index & kElMask))) != 0;
     }
 
     // One more than the maximum value in the set, or zero if empty
-    uint32_t length() const { return mMaxVal; }
+    uint32_t length() const { return mData != nullptr ? mData->mMaxVal : 0; }
+
+    bool empty() const { return mData == nullptr || mData->mMaxVal == 0; }
 
     // The next set bit starting at fromIndex, inclusive, or kNotFound
     // if none exists.
@@ -86,20 +89,53 @@
     static uint32_t calcNumPages(const uint32_t* ranges, size_t nRanges);
     static int CountLeadingZeros(element x);
 
-    uint32_t mMaxVal;
-    uint32_t mIndicesCount;
-    const uint16_t* mIndices;
-    uint32_t mBitmapsCount;
-    const element* mBitmaps;
-    uint16_t mZeroPageIndex;
+    // MappableData represents memory block holding SparseBitSet's fields.
+    // 'packed' is used so that the object layout won't change between
+    // 32-bit and 64-bit processes.
+    // 'aligned(4)' is only for optimization.
+    struct __attribute__((packed, aligned(4))) MappableData {
+        uint32_t mMaxVal;
+        uint32_t mIndicesCount;
+        uint32_t mBitmapsCount;
+        uint16_t mZeroPageIndex;
+        // Whether the memory is mapped (BufferReader::map()) or allocated
+        // (malloc()).
+        uint16_t mIsMapped;
+        // mArray packs two arrays:
+        // element mBitmaps[mBitmapsCount];
+        // uint16_t mIndices[mIndicesCount];
+        __attribute__((aligned(4))) uint32_t mArray[];
+        const element* bitmaps() const { return mArray; }
+        element* bitmaps() { return mArray; }
+        const uint16_t* indices() const {
+            return reinterpret_cast<const uint16_t*>(mArray + mBitmapsCount);
+        }
+        uint16_t* indices() { return reinterpret_cast<uint16_t*>(mArray + mBitmapsCount); }
+        size_t size() const { return calcSize(mIndicesCount, mBitmapsCount); }
+        static size_t calcSize(uint32_t indicesCount, uint32_t bitmapsCount) {
+            static_assert(std::is_same<element, uint32_t>::value);
+            static_assert(sizeof(uint32_t) == 4);
+            static_assert(sizeof(uint16_t) == 2);
+            // Round-up indicesCount / 2
+            size_t arrayCount = bitmapsCount + (indicesCount + 1) / 2;
+            return offsetof(MappableData, mArray) + sizeof(uint32_t) * arrayCount;
+        }
+        static MappableData* allocate(uint32_t indicesCount, uint32_t bitmapsCount);
+    };
 
-    // Owns allocated memory if this class is created from ranges, otherwise these are nullptr.
-    std::unique_ptr<uint16_t[]> mOwnedIndices;
-    std::unique_ptr<element[]> mOwnedBitmaps;
+    // MappableDataDeleter does NOT call free() if the data is on a memory map.
+    class MappableDataDeleter {
+    public:
+        void operator()(const MappableData* data) const {
+            if (data != nullptr && !data->mIsMapped) free((void*)data);
+        }
+    };
+
+    std::unique_ptr<const MappableData, MappableDataDeleter> mData;
 
     // Forbid copy and assign.
     SparseBitSet(const SparseBitSet&) = delete;
-    void operator=(const SparseBitSet&) = delete;
+    SparseBitSet& operator=(const SparseBitSet&) = delete;
 };
 
 }  // namespace minikin
diff --git a/include/minikin/SystemFonts.h b/include/minikin/SystemFonts.h
index cf4ab75..4ef2705 100644
--- a/include/minikin/SystemFonts.h
+++ b/include/minikin/SystemFonts.h
@@ -50,11 +50,6 @@
     }
 
     // This obtains a mutex inside, so do not call this method inside callback.
-    static void getFontMap(
-            std::function<void(const std::vector<std::shared_ptr<FontCollection>>&)> func) {
-        return getInstance().getFontMapInternal(func);
-    }
-
     static void getFontSet(std::function<void(const std::vector<std::shared_ptr<Font>>&)> func) {
         return getInstance().getFontSetInternal(func);
     }
@@ -81,12 +76,6 @@
         mCollections.emplace_back(std::move(collections));
     }
 
-    void getFontMapInternal(
-            std::function<void(const std::vector<std::shared_ptr<FontCollection>>&)> func) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        func(mCollections);
-    }
-
     void getFontSetInternal(std::function<void(const std::vector<std::shared_ptr<Font>>&)> func) {
         std::lock_guard<std::mutex> lock(mMutex);
         if (!mFonts) {
diff --git a/libs/minikin/Android.bp b/libs/minikin/Android.bp
index c0c4035..5c7abf2 100644
--- a/libs/minikin/Android.bp
+++ b/libs/minikin/Android.bp
@@ -50,16 +50,14 @@
         "LocaleListCache.cpp",
         "MeasuredText.cpp",
         "Measurement.cpp",
+        "MinikinFontFactory.cpp",
         "MinikinInternal.cpp",
         "OptimalLineBreaker.cpp",
         "SparseBitSet.cpp",
         "SystemFonts.cpp",
         "WordBreaker.cpp",
     ],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
+    defaults: ["libminikin_defaults"],
     sanitize: {
         misc_undefined: [
             "signed-integer-overflow",
@@ -67,12 +65,6 @@
             "bounds",
         ],
     },
-    cppflags: [
-        "-Werror",
-        "-Wall",
-        "-Wextra",
-        "-Wthread-safety",
-    ],
     product_variables: {
         debuggable: {
             // Enable assertion on eng and userdebug build.
@@ -93,10 +85,10 @@
     target: {
         android: {
             shared_libs: [
-                "libandroidicu",
+                "libicu",
             ],
             export_shared_lib_headers: [
-                "libandroidicu",
+                "libicu",
             ],
         },
         host: {
diff --git a/libs/minikin/CmapCoverage.cpp b/libs/minikin/CmapCoverage.cpp
index 8d04ce8..fd1a7f1 100644
--- a/libs/minikin/CmapCoverage.cpp
+++ b/libs/minikin/CmapCoverage.cpp
@@ -368,8 +368,7 @@
     return true;
 }
 
-static void getCoverageFormat14(std::vector<std::unique_ptr<SparseBitSet>>* out,
-                                const uint8_t* data, size_t size,
+static void getCoverageFormat14(std::vector<SparseBitSet>* out, const uint8_t* data, size_t size,
                                 const SparseBitSet& baseCoverage) {
     constexpr size_t kHeaderSize = 10;
     constexpr size_t kRecordSize = 11;
@@ -417,14 +416,14 @@
         if (out->size() < vsIndex + 1) {
             out->resize(vsIndex + 1);
         }
-        (*out)[vsIndex].reset(new SparseBitSet(ranges.data(), ranges.size() >> 1));
+        (*out)[vsIndex] = SparseBitSet(ranges.data(), ranges.size() >> 1);
     }
 
     out->shrink_to_fit();
 }
 
 SparseBitSet CmapCoverage::getCoverage(const uint8_t* cmap_data, size_t cmap_size,
-                                       std::vector<std::unique_ptr<SparseBitSet>>* out) {
+                                       std::vector<SparseBitSet>* out) {
     constexpr size_t kHeaderSize = 4;
     constexpr size_t kNumTablesOffset = 2;
     constexpr size_t kTableSize = 8;
diff --git a/libs/minikin/Font.cpp b/libs/minikin/Font.cpp
index c2e74b7..bf7450a 100644
--- a/libs/minikin/Font.cpp
+++ b/libs/minikin/Font.cpp
@@ -18,17 +18,18 @@
 
 #include "minikin/Font.h"
 
-#include <vector>
-
 #include <hb-ot.h>
 #include <hb.h>
 #include <log/log.h>
 
-#include "minikin/HbUtils.h"
-#include "minikin/MinikinFont.h"
+#include <vector>
 
 #include "FontUtils.h"
+#include "LocaleListCache.h"
 #include "MinikinInternal.h"
+#include "minikin/HbUtils.h"
+#include "minikin/MinikinFont.h"
+#include "minikin/MinikinFontFactory.h"
 
 namespace minikin {
 
@@ -51,25 +52,80 @@
                                           std::move(font), mLocaleListId));
 }
 
+Font::Font(BufferReader* reader) : mExternalRefsHolder(nullptr), mTypefaceMetadataReader(nullptr) {
+    mStyle = FontStyle(reader);
+    mLocaleListId = LocaleListCache::readFrom(reader);
+    mTypefaceMetadataReader = *reader;
+    MinikinFontFactory::getInstance().skip(reader);
+}
+
+void Font::writeTo(BufferWriter* writer) const {
+    mStyle.writeTo(writer);
+    LocaleListCache::writeTo(writer, mLocaleListId);
+    MinikinFontFactory::getInstance().write(writer, typeface().get());
+}
+
+Font::Font(Font&& o) noexcept
+        : mStyle(o.mStyle),
+          mLocaleListId(o.mLocaleListId),
+          mTypefaceMetadataReader(o.mTypefaceMetadataReader) {
+    mExternalRefsHolder.store(o.mExternalRefsHolder.exchange(nullptr));
+}
+
+Font& Font::operator=(Font&& o) noexcept {
+    resetExternalRefs(o.mExternalRefsHolder.exchange(nullptr));
+    mStyle = o.mStyle;
+    mLocaleListId = o.mLocaleListId;
+    mTypefaceMetadataReader = o.mTypefaceMetadataReader;
+    return *this;
+}
+
+Font::~Font() {
+    resetExternalRefs(nullptr);
+}
+
+void Font::resetExternalRefs(ExternalRefs* refs) {
+    ExternalRefs* oldRefs = mExternalRefsHolder.exchange(refs);
+    if (oldRefs != nullptr) {
+        delete oldRefs;
+    }
+}
+
 const std::shared_ptr<MinikinFont>& Font::typeface() const {
-    std::lock_guard lock(mTypefaceMutex);
-    if (mTypeface) return mTypeface;
-    initTypefaceLocked();
-    return mTypeface;
+    return getExternalRefs()->mTypeface;
 }
 
 const HbFontUniquePtr& Font::baseFont() const {
-    std::lock_guard lock(mTypefaceMutex);
-    if (mBaseFont) return mBaseFont;
-    initTypefaceLocked();
-    mBaseFont = prepareFont(mTypeface);
-    return mBaseFont;
+    return getExternalRefs()->mBaseFont;
 }
 
-void Font::initTypefaceLocked() const {
-    if (mTypeface) return;
-    MINIKIN_ASSERT(mTypefaceLoader, "mTypefaceLoader should not be empty when mTypeface is null");
-    mTypeface = mTypefaceLoader(mTypefaceMetadataReader);
+const Font::ExternalRefs* Font::getExternalRefs() const {
+    // Thread safety note: getExternalRefs() is thread-safe.
+    // getExternalRefs() returns the first ExternalRefs set to mExternalRefsHolder.
+    // When multiple threads called getExternalRefs() at the same time and
+    // mExternalRefsHolder is not set, multiple ExternalRefs may be created,
+    // but only one ExternalRefs will be set to mExternalRefsHolder and
+    // others will be deleted.
+    Font::ExternalRefs* externalRefs = mExternalRefsHolder.load();
+    if (externalRefs) return externalRefs;
+    // mExternalRefsHolder is null. Try creating an ExternalRefs.
+    std::shared_ptr<MinikinFont> typeface =
+            MinikinFontFactory::getInstance().create(mTypefaceMetadataReader);
+    HbFontUniquePtr font = prepareFont(typeface);
+    Font::ExternalRefs* newExternalRefs =
+            new Font::ExternalRefs(std::move(typeface), std::move(font));
+    // Set the new ExternalRefs to mExternalRefsHolder if it is still null.
+    Font::ExternalRefs* expected = nullptr;
+    if (mExternalRefsHolder.compare_exchange_strong(expected, newExternalRefs)) {
+        return newExternalRefs;
+    } else {
+        // Another thread has already created and set an ExternalRefs.
+        // Delete ours and use theirs instead.
+        delete newExternalRefs;
+        // compare_exchange_strong writes the stored value into 'expected'
+        // when comparison fails.
+        return expected;
+    }
 }
 
 // static
diff --git a/libs/minikin/FontCollection.cpp b/libs/minikin/FontCollection.cpp
index 38fc022..0c1a173 100644
--- a/libs/minikin/FontCollection.cpp
+++ b/libs/minikin/FontCollection.cpp
@@ -22,6 +22,7 @@
 #include <unicode/unorm2.h>
 
 #include <algorithm>
+#include <unordered_set>
 
 #include "Locale.h"
 #include "LocaleListCache.h"
@@ -121,13 +122,22 @@
 
 }  // namespace
 
-FontCollection::FontCollection(std::shared_ptr<FontFamily>&& typeface) : mMaxChar(0) {
+// static
+std::shared_ptr<FontCollection> FontCollection::create(std::shared_ptr<FontFamily>&& typeface) {
     std::vector<std::shared_ptr<FontFamily>> typefaces;
     typefaces.push_back(typeface);
-    init(typefaces);
+    return create(typefaces);
 }
 
-FontCollection::FontCollection(const vector<std::shared_ptr<FontFamily>>& typefaces) : mMaxChar(0) {
+// static
+std::shared_ptr<FontCollection> FontCollection::create(
+        const vector<std::shared_ptr<FontFamily>>& typefaces) {
+    // TODO(b/174672300): Revert back to make_shared.
+    return std::shared_ptr<FontCollection>(new FontCollection(typefaces));
+}
+
+FontCollection::FontCollection(const vector<std::shared_ptr<FontFamily>>& typefaces)
+        : mMaxChar(0), mSupportedAxes(nullptr) {
     init(typefaces);
 }
 
@@ -136,26 +146,38 @@
     vector<uint32_t> lastChar;
     size_t nTypefaces = typefaces.size();
     const FontStyle defaultStyle;
+    auto families = std::make_shared<vector<std::shared_ptr<FontFamily>>>();
+    std::unordered_set<AxisTag> supportedAxesSet;
     for (size_t i = 0; i < nTypefaces; i++) {
         const std::shared_ptr<FontFamily>& family = typefaces[i];
         if (family->getClosestMatch(defaultStyle).font == nullptr) {
             continue;
         }
         const SparseBitSet& coverage = family->getCoverage();
-        mFamilies.push_back(family);  // emplace_back would be better
+        families->emplace_back(family);
         if (family->hasVSTable()) {
             mVSFamilyVec.push_back(family);
         }
         mMaxChar = max(mMaxChar, coverage.length());
         lastChar.push_back(coverage.nextSetBit(0));
 
-        const std::unordered_set<AxisTag>& supportedAxes = family->supportedAxes();
-        mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end());
+        for (size_t i = 0; i < family->getSupportedAxesCount(); i++) {
+            supportedAxesSet.insert(family->getSupportedAxisAt(i));
+        }
     }
-    nTypefaces = mFamilies.size();
-    MINIKIN_ASSERT(nTypefaces > 0, "Font collection must have at least one valid typeface");
-    MINIKIN_ASSERT(nTypefaces <= MAX_FAMILY_COUNT,
+    // mMaybeSharedFamilies is not shared.
+    mMaybeSharedFamilies = families;
+    mFamilyCount = families->size();
+    mFamilyIndices = nullptr;
+    MINIKIN_ASSERT(mFamilyCount > 0, "Font collection must have at least one valid typeface");
+    MINIKIN_ASSERT(mFamilyCount <= MAX_FAMILY_COUNT,
                    "Font collection may only have up to %d font families.", MAX_FAMILY_COUNT);
+    // Although OpenType supports up to 2^16-1 axes per font,
+    // mSupportedAxesCount may exceed 2^16-1 as we have multiple fonts.
+    mSupportedAxesCount = static_cast<uint32_t>(supportedAxesSet.size());
+    if (mSupportedAxesCount > 0) {
+        mSupportedAxes = sortedArrayFromSet(supportedAxesSet);
+    }
     size_t nPages = (mMaxChar + kPageMask) >> kLogCharsPerPage;
     // TODO: Use variation selector map for mRanges construction.
     // A font can have a glyph for a base code point and variation selector pair but no glyph for
@@ -167,9 +189,9 @@
     for (size_t i = 0; i < nPages; i++) {
         Range* range = &mOwnedRanges[i];
         range->start = mOwnedFamilyVec.size();
-        for (size_t j = 0; j < nTypefaces; j++) {
+        for (size_t j = 0; j < getFamilyCount(); j++) {
             if (lastChar[j] < (i + 1) << kLogCharsPerPage) {
-                const std::shared_ptr<FontFamily>& family = mFamilies[j];
+                const std::shared_ptr<FontFamily>& family = getFamilyAt(j);
                 mOwnedFamilyVec.push_back(static_cast<uint8_t>(j));
                 uint32_t nextChar = family->getCoverage().nextSetBit((i + 1) << kLogCharsPerPage);
                 lastChar[j] = nextChar;
@@ -184,52 +206,78 @@
     mFamilyVecCount = mOwnedFamilyVec.size();
 }
 
-FontCollection::FontCollection(BufferReader* reader,
-                               const std::vector<std::shared_ptr<FontFamily>>& families) {
+FontCollection::FontCollection(
+        BufferReader* reader,
+        const std::shared_ptr<std::vector<std::shared_ptr<FontFamily>>>& families)
+        : mSupportedAxes(nullptr) {
     mId = gNextCollectionId++;
     mMaxChar = reader->read<uint32_t>();
-    uint32_t familiesCount = reader->read<uint32_t>();
-    mFamilies.reserve(familiesCount);
-    for (uint32_t i = 0; i < familiesCount; i++) {
-        uint32_t index = reader->read<uint32_t>();
-        if (index >= families.size()) {
-            ALOGE("Invalid FontFamily index: %zu", (size_t)index);
-        } else {
-            mFamilies.push_back(families[index]);
-            if (families[index]->hasVSTable()) {
-                mVSFamilyVec.push_back(families[index]);
-            }
-        }
+    mMaybeSharedFamilies = families;
+    std::tie(mFamilyIndices, mFamilyCount) = reader->readArray<uint32_t>();
+    for (size_t i = 0; i < getFamilyCount(); i++) {
+        const auto& family = getFamilyAt(i);
+        if (family->hasVSTable()) mVSFamilyVec.emplace_back(family);
     }
     // Range is two packed uint16_t
     static_assert(sizeof(Range) == 4);
     std::tie(mRanges, mRangesCount) = reader->readArray<Range>();
     std::tie(mFamilyVec, mFamilyVecCount) = reader->readArray<uint8_t>();
     const auto& [axesPtr, axesCount] = reader->readArray<AxisTag>();
-    mSupportedAxes.insert(axesPtr, axesPtr + axesCount);
+    mSupportedAxesCount = axesCount;
+    if (axesCount > 0) {
+        mSupportedAxes = std::unique_ptr<AxisTag[]>(new AxisTag[axesCount]);
+        std::copy(axesPtr, axesPtr + axesCount, mSupportedAxes.get());
+    }
 }
 
 void FontCollection::writeTo(BufferWriter* writer,
                              const std::unordered_map<std::shared_ptr<FontFamily>, uint32_t>&
                                      fontFamilyToIndexMap) const {
     writer->write<uint32_t>(mMaxChar);
-    writer->write<uint32_t>(mFamilies.size());
-    for (const std::shared_ptr<FontFamily>& fontFamily : mFamilies) {
+    std::vector<uint32_t> indices;
+    indices.reserve(getFamilyCount());
+    for (size_t i = 0; i < getFamilyCount(); ++i) {
+        const std::shared_ptr<FontFamily>& fontFamily = getFamilyAt(i);
         auto it = fontFamilyToIndexMap.find(fontFamily);
         if (it == fontFamilyToIndexMap.end()) {
             ALOGE("fontFamily not found in fontFamilyToIndexMap");
-            writer->write<uint32_t>(-1);
         } else {
-            writer->write<uint32_t>(it->second);
+            indices.push_back(it->second);
         }
     }
+    writer->writeArray<uint32_t>(indices.data(), indices.size());
     writer->writeArray<Range>(mRanges, mRangesCount);
     writer->writeArray<uint8_t>(mFamilyVec, mFamilyVecCount);
     // No need to serialize mVSFamilyVec as it can be reconstructed easily from mFamilies.
-    std::vector<AxisTag> axes(mSupportedAxes.begin(), mSupportedAxes.end());
-    // Sort axes to be deterministic.
-    std::sort(axes.begin(), axes.end());
-    writer->writeArray<AxisTag>(axes.data(), axes.size());
+    writer->writeArray<AxisTag>(mSupportedAxes.get(), mSupportedAxesCount);
+}
+
+// static
+std::vector<std::shared_ptr<FontCollection>> FontCollection::readVector(BufferReader* reader) {
+    auto allFontFamilies = std::make_shared<std::vector<std::shared_ptr<FontFamily>>>(
+            FontFamily::readVector(reader));
+    uint32_t count = reader->read<uint32_t>();
+    std::vector<std::shared_ptr<FontCollection>> fontCollections;
+    fontCollections.reserve(count);
+    for (uint32_t i = 0; i < count; i++) {
+        fontCollections.emplace_back(new FontCollection(reader, allFontFamilies));
+    }
+    return fontCollections;
+}
+
+// static
+void FontCollection::writeVector(
+        BufferWriter* writer, const std::vector<std::shared_ptr<FontCollection>>& fontCollections) {
+    std::vector<std::shared_ptr<FontFamily>> allFontFamilies;
+    // Note: operator== for shared_ptr compares raw pointer values.
+    std::unordered_map<std::shared_ptr<FontFamily>, uint32_t> fontFamilyToIndexMap;
+    collectAllFontFamilies(fontCollections, &allFontFamilies, &fontFamilyToIndexMap);
+
+    FontFamily::writeVector(writer, allFontFamilies);
+    writer->write<uint32_t>(fontCollections.size());
+    for (const auto& fontCollection : fontCollections) {
+        fontCollection->writeTo(writer, fontFamilyToIndexMap);
+    }
 }
 
 // static
@@ -238,7 +286,8 @@
         std::vector<std::shared_ptr<FontFamily>>* outAllFontFamilies,
         std::unordered_map<std::shared_ptr<FontFamily>, uint32_t>* outFontFamilyToIndexMap) {
     for (const auto& fontCollection : fontCollections) {
-        for (const std::shared_ptr<FontFamily>& fontFamily : fontCollection->mFamilies) {
+        for (size_t i = 0; i < fontCollection->getFamilyCount(); ++i) {
+            const std::shared_ptr<FontFamily>& fontFamily = fontCollection->getFamilyAt(i);
             bool inserted =
                     outFontFamilyToIndexMap->emplace(fontFamily, outAllFontFamilies->size()).second;
             if (inserted) {
@@ -286,6 +335,22 @@
     return coverageScore << 29 | localeScore << 1 | variantScore;
 }
 
+// Returns true if
+//  - the fontFamily is a developer specified custom fallback.
+//  - no custom fallback is provided and the fontFamily is a default fallback.
+bool FontCollection::isPrimaryFamily(const std::shared_ptr<FontFamily>& fontFamily) const {
+    // If the font family is provided by developers, it is primary.
+    if (fontFamily->isCustomFallback()) {
+        return true;
+    }
+
+    if (getFamilyAt(0)->isCustomFallback()) {
+        return false;
+    } else {
+        return fontFamily->isDefaultFallback();
+    }
+}
+
 // Calculates a font score based on variation sequence coverage.
 // - Returns kUnsupportedFontScore if the font doesn't support the variation sequence or its base
 //   character.
@@ -304,7 +369,7 @@
         return kUnsupportedFontScore;
     }
 
-    if ((vs == 0 || hasVSGlyph) && (mFamilies[0] == fontFamily || fontFamily->isCustomFallback())) {
+    if ((vs == 0 || hasVSGlyph) && isPrimaryFamily(fontFamily)) {
         // If the first font family supports the given character or variation sequence, always use
         // it.
         return kFirstFontScore;
@@ -404,7 +469,7 @@
     Range range = mRanges[ch >> kLogCharsPerPage];
 
     if (vs != 0) {
-        range = {0, static_cast<uint16_t>(mFamilies.size())};
+        range = {0, static_cast<uint16_t>(getFamilyCount())};
     }
 
     uint32_t bestScore = kUnsupportedFontScore;
@@ -412,7 +477,7 @@
 
     for (size_t i = range.start; i < range.end; i++) {
         const uint8_t familyIndex = vs == 0 ? mFamilyVec[i] : i;
-        const std::shared_ptr<FontFamily>& family = mFamilies[familyIndex];
+        const std::shared_ptr<FontFamily>& family = getFamilyAt(familyIndex);
         const uint32_t score = calcFamilyScore(ch, vs, variant, localeListId, family);
         if (score == kFirstFontScore) {
             // If the first font family supports the given character or variation sequence, always
@@ -505,8 +570,9 @@
     // sequences, since Unicode is adding variation sequences more frequently now and may even move
     // towards allowing text and emoji variation selectors on any character.
     if (variationSelector == TEXT_STYLE_VS) {
-        for (size_t i = 0; i < mFamilies.size(); ++i) {
-            if (!mFamilies[i]->isColorEmojiFamily() && mFamilies[i]->hasGlyph(baseCodepoint, 0)) {
+        for (size_t i = 0; i < getFamilyCount(); ++i) {
+            const std::shared_ptr<FontFamily>& family = getFamilyAt(i);
+            if (!family->isColorEmojiFamily() && family->hasGlyph(baseCodepoint, 0)) {
                 return true;
             }
         }
@@ -586,12 +652,12 @@
         } else if (!lastFamilyIndices.empty() && (isStickyAllowlisted(ch) || isCombining(ch))) {
             // Continue using existing font as long as it has coverage and is whitelisted.
 
-            const std::shared_ptr<FontFamily>& lastFamily = mFamilies[lastFamilyIndices[0]];
+            const std::shared_ptr<FontFamily>& lastFamily = getFamilyAt(lastFamilyIndices[0]);
             if (lastFamily->isColorEmojiFamily()) {
                 // If the last family is color emoji font, find the longest family.
                 shouldContinueRun = false;
                 for (uint8_t ix : lastFamilyIndices) {
-                    shouldContinueRun |= mFamilies[ix]->getCoverage().get(ch);
+                    shouldContinueRun |= getFamilyAt(ix)->getCoverage().get(ch);
                 }
             } else {
                 shouldContinueRun = lastFamily->getCoverage().get(ch);
@@ -605,7 +671,7 @@
             if (utf16Pos == 0 || lastFamilyIndices.empty()) {
                 breakRun = true;
             } else {
-                const std::shared_ptr<FontFamily>& lastFamily = mFamilies[lastFamilyIndices[0]];
+                const std::shared_ptr<FontFamily>& lastFamily = getFamilyAt(lastFamilyIndices[0]);
                 if (lastFamily->isColorEmojiFamily()) {
                     FamilyMatchResult intersection =
                             FamilyMatchResult::intersect(familyIndices, lastFamilyIndices);
@@ -637,7 +703,7 @@
                 if (utf16Pos != 0 &&
                     (isCombining(ch) || (isEmojiModifier(ch) && isEmojiBase(prevCh)))) {
                     for (uint8_t ix : familyIndices) {
-                        if (mFamilies[ix]->getCoverage().get(prevCh)) {
+                        if (getFamilyAt(ix)->getCoverage().get(prevCh)) {
                             const size_t prevChLength = U16_LENGTH(prevCh);
                             if (run != nullptr) {
                                 run->end -= prevChLength;
@@ -696,10 +762,10 @@
     uint8_t bestIndex = 0;
     uint32_t bestScore = 0xFFFFFFFF;
 
-    const std::shared_ptr<FontFamily>& family = mFamilies[run.familyMatch[0]];
+    const std::shared_ptr<FontFamily>& family = getFamilyAt(run.familyMatch[0]);
     if (family->isColorEmojiFamily() && run.familyMatch.size() > 1) {
         for (size_t i = 0; i < run.familyMatch.size(); ++i) {
-            const std::shared_ptr<FontFamily>& family = mFamilies[run.familyMatch[i]];
+            const std::shared_ptr<FontFamily>& family = getFamilyAt(run.familyMatch[i]);
             const HbFontUniquePtr& font = family->getFont(0)->baseFont();
             uint32_t score = getGlyphScore(text, run.start, run.end, font);
 
@@ -711,22 +777,23 @@
     } else {
         bestIndex = run.familyMatch[0];
     }
-    return mFamilies[bestIndex]->getClosestMatch(style);
+    return getFamilyAt(bestIndex)->getClosestMatch(style);
 }
 
 FakedFont FontCollection::baseFontFaked(FontStyle style) {
-    return mFamilies[0]->getClosestMatch(style);
+    return getFamilyAt(0)->getClosestMatch(style);
 }
 
 std::shared_ptr<FontCollection> FontCollection::createCollectionWithVariation(
         const std::vector<FontVariation>& variations) {
-    if (variations.empty() || mSupportedAxes.empty()) {
+    if (variations.empty() || mSupportedAxesCount == 0) {
         return nullptr;
     }
 
     bool hasSupportedAxis = false;
     for (const FontVariation& variation : variations) {
-        if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end()) {
+        if (std::binary_search(mSupportedAxes.get(), mSupportedAxes.get() + mSupportedAxesCount,
+                               variation.axisTag)) {
             hasSupportedAxis = true;
             break;
         }
@@ -737,7 +804,8 @@
     }
 
     std::vector<std::shared_ptr<FontFamily>> families;
-    for (const std::shared_ptr<FontFamily>& family : mFamilies) {
+    for (size_t i = 0; i < getFamilyCount(); ++i) {
+        const std::shared_ptr<FontFamily>& family = getFamilyAt(i);
         std::shared_ptr<FontFamily> newFamily = family->createFamilyWithVariation(variations);
         if (newFamily) {
             families.push_back(newFamily);
@@ -749,6 +817,15 @@
     return std::shared_ptr<FontCollection>(new FontCollection(families));
 }
 
+std::shared_ptr<FontCollection> FontCollection::createCollectionWithFamilies(
+        std::vector<std::shared_ptr<FontFamily>>&& families) const {
+    families.reserve(families.size() + getFamilyCount());
+    for (size_t i = 0; i < getFamilyCount(); i++) {
+        families.push_back(getFamilyAt(i));
+    }
+    return FontCollection::create(families);
+}
+
 uint32_t FontCollection::getId() const {
     return mId;
 }
diff --git a/libs/minikin/FontFamily.cpp b/libs/minikin/FontFamily.cpp
index f1fd00a..836674c 100644
--- a/libs/minikin/FontFamily.cpp
+++ b/libs/minikin/FontFamily.cpp
@@ -18,118 +18,190 @@
 
 #include "minikin/FontFamily.h"
 
-#include <algorithm>
-#include <vector>
-
 #include <log/log.h>
 
-#include "minikin/CmapCoverage.h"
-#include "minikin/FamilyVariant.h"
-#include "minikin/HbUtils.h"
-#include "minikin/MinikinFont.h"
+#include <algorithm>
+#include <unordered_set>
+#include <vector>
 
 #include "FontUtils.h"
 #include "Locale.h"
 #include "LocaleListCache.h"
 #include "MinikinInternal.h"
+#include "minikin/CmapCoverage.h"
+#include "minikin/FamilyVariant.h"
+#include "minikin/HbUtils.h"
+#include "minikin/MinikinFont.h"
 
 namespace minikin {
 
-FontFamily::FontFamily(std::vector<std::shared_ptr<Font>>&& fonts)
-        : FontFamily(FamilyVariant::DEFAULT, std::move(fonts)) {}
+// static
+std::shared_ptr<FontFamily> FontFamily::create(std::vector<std::shared_ptr<Font>>&& fonts) {
+    return create(FamilyVariant::DEFAULT, std::move(fonts));
+}
 
-FontFamily::FontFamily(FamilyVariant variant, std::vector<std::shared_ptr<Font>>&& fonts)
-        : FontFamily(kEmptyLocaleListId, variant, std::move(fonts), false /* isCustomFallback */) {}
+// static
+std::shared_ptr<FontFamily> FontFamily::create(FamilyVariant variant,
+                                               std::vector<std::shared_ptr<Font>>&& fonts) {
+    return create(kEmptyLocaleListId, variant, std::move(fonts), false /* isCustomFallback */,
+                  false /* isDefaultFallback */);
+}
+
+// static
+std::shared_ptr<FontFamily> FontFamily::create(uint32_t localeListId, FamilyVariant variant,
+                                               std::vector<std::shared_ptr<Font>>&& fonts,
+                                               bool isCustomFallback, bool isDefaultFallback) {
+    // TODO(b/174672300): Revert back to make_shared.
+    return std::shared_ptr<FontFamily>(new FontFamily(localeListId, variant, std::move(fonts),
+                                                      isCustomFallback, isDefaultFallback));
+}
 
 FontFamily::FontFamily(uint32_t localeListId, FamilyVariant variant,
-                       std::vector<std::shared_ptr<Font>>&& fonts, bool isCustomFallback)
-        : mLocaleListId(localeListId),
+                       std::vector<std::shared_ptr<Font>>&& fonts, bool isCustomFallback,
+                       bool isDefaultFallback)
+        : mFonts(std::make_unique<std::shared_ptr<Font>[]>(fonts.size())),
+          // computeCoverage may update supported axes and coverages later.
+          mSupportedAxes(nullptr),
+          mCoverage(),
+          mCmapFmt14Coverage(nullptr),
+          mLocaleListId(localeListId),
+          mFontsCount(static_cast<uint32_t>(fonts.size())),
+          mSupportedAxesCount(0),
+          mCmapFmt14CoverageCount(0),
           mVariant(variant),
-          mFonts(std::move(fonts)),
           mIsColorEmoji(LocaleListCache::getById(localeListId).getEmojiStyle() ==
                         EmojiStyle::EMOJI),
-          mIsCustomFallback(isCustomFallback) {
-    MINIKIN_ASSERT(!mFonts.empty(), "FontFamily must contain at least one font.");
+          mIsCustomFallback(isCustomFallback),
+          mIsDefaultFallback(isDefaultFallback) {
+    MINIKIN_ASSERT(!fonts.empty(), "FontFamily must contain at least one font.");
+    MINIKIN_ASSERT(fonts.size() <= std::numeric_limits<uint32_t>::max(),
+                   "Number of fonts must be less than 2^32.");
+    for (size_t i = 0; i < mFontsCount; i++) {
+        mFonts[i] = std::move(fonts[i]);
+    }
     computeCoverage();
 }
 
-FontFamily::FontFamily(uint32_t localeListId, FamilyVariant variant,
-                       std::vector<std::shared_ptr<Font>>&& fonts,
-                       std::unordered_set<AxisTag>&& supportedAxes, bool isColorEmoji,
-                       bool isCustomFallback, SparseBitSet&& coverage,
-                       std::vector<std::unique_ptr<SparseBitSet>>&& cmapFmt14Coverage)
-        : mLocaleListId(localeListId),
-          mVariant(variant),
-          mFonts(std::move(fonts)),
-          mSupportedAxes(std::move(supportedAxes)),
-          mIsColorEmoji(isColorEmoji),
-          mIsCustomFallback(isCustomFallback),
-          mCoverage(std::move(coverage)),
-          mCmapFmt14Coverage(std::move(cmapFmt14Coverage)) {}
-
-// Read fields other than mFonts, mLocaleList.
-// static
-std::shared_ptr<FontFamily> FontFamily::readFromInternal(BufferReader* reader,
-                                                         std::vector<std::shared_ptr<Font>>&& fonts,
-                                                         uint32_t localeListId) {
+FontFamily::FontFamily(BufferReader* reader, const std::shared_ptr<std::vector<Font>>& allFonts)
+        : mSupportedAxes(nullptr), mCmapFmt14Coverage(nullptr) {
+    mLocaleListId = LocaleListCache::readFrom(reader);
+    mFontsCount = reader->read<uint32_t>();
+    mFonts = std::make_unique<std::shared_ptr<Font>[]>(mFontsCount);
+    for (size_t i = 0; i < mFontsCount; i++) {
+        uint32_t fontIndex = reader->read<uint32_t>();
+        // Use aliasing constructor to save memory.
+        // See the comments on FontFamily::readVector for details.
+        mFonts[i] = std::shared_ptr<Font>(allFonts, &(*allFonts)[fontIndex]);
+    }
     // FamilyVariant is uint8_t
     static_assert(sizeof(FamilyVariant) == 1);
-    FamilyVariant variant = reader->read<FamilyVariant>();
+    mVariant = reader->read<FamilyVariant>();
     // AxisTag is uint32_t
     static_assert(sizeof(AxisTag) == 4);
     const auto& [axesPtr, axesCount] = reader->readArray<AxisTag>();
-    std::unordered_set<AxisTag> supportedAxes(axesPtr, axesPtr + axesCount);
-    bool isColorEmoji = static_cast<bool>(reader->read<uint8_t>());
-    bool isCustomFallback = static_cast<bool>(reader->read<uint8_t>());
-    SparseBitSet coverage(reader);
+    mSupportedAxesCount = axesCount;
+    if (axesCount > 0) {
+        mSupportedAxes = std::unique_ptr<AxisTag[]>(new AxisTag[axesCount]);
+        std::copy(axesPtr, axesPtr + axesCount, mSupportedAxes.get());
+    }
+    mIsColorEmoji = static_cast<bool>(reader->read<uint8_t>());
+    mIsCustomFallback = static_cast<bool>(reader->read<uint8_t>());
+    mIsDefaultFallback = static_cast<bool>(reader->read<uint8_t>());
+    mCoverage = SparseBitSet(reader);
     // Read mCmapFmt14Coverage. As it can have null entries, it is stored in the buffer as a sparse
     // array (size, non-null entry count, array of (index, entry)).
-    uint32_t cmapFmt14CoverageSize = reader->read<uint32_t>();
-    std::vector<std::unique_ptr<SparseBitSet>> cmapFmt14Coverage(cmapFmt14CoverageSize);
-    uint32_t cmapFmt14CoverageEntryCount = reader->read<uint32_t>();
-    for (uint32_t i = 0; i < cmapFmt14CoverageEntryCount; i++) {
-        uint32_t index = reader->read<uint32_t>();
-        cmapFmt14Coverage[index] = std::make_unique<SparseBitSet>(reader);
-    }
-    return std::shared_ptr<FontFamily>(new FontFamily(
-            localeListId, variant, std::move(fonts), std::move(supportedAxes), isColorEmoji,
-            isCustomFallback, std::move(coverage), std::move(cmapFmt14Coverage)));
-}
-
-// static
-uint32_t FontFamily::readLocaleListInternal(BufferReader* reader) {
-    return LocaleListCache::readFrom(reader);
-}
-
-// Write fields other than mFonts.
-void FontFamily::writeToInternal(BufferWriter* writer) const {
-    writer->write<FamilyVariant>(mVariant);
-    std::vector<AxisTag> axes(mSupportedAxes.begin(), mSupportedAxes.end());
-    // Sort axes to be deterministic.
-    std::sort(axes.begin(), axes.end());
-    writer->writeArray<AxisTag>(axes.data(), axes.size());
-    writer->write<uint8_t>(mIsColorEmoji);
-    writer->write<uint8_t>(mIsCustomFallback);
-    mCoverage.writeTo(writer);
-    // Write mCmapFmt14Coverage as a sparse array (size, non-null entry count,
-    // array of (index, entry))
-    writer->write<uint32_t>(mCmapFmt14Coverage.size());
-    uint32_t cmapFmt14CoverageEntryCount = 0;
-    for (const std::unique_ptr<SparseBitSet>& coverage : mCmapFmt14Coverage) {
-        if (coverage != nullptr) cmapFmt14CoverageEntryCount++;
-    }
-    writer->write<uint32_t>(cmapFmt14CoverageEntryCount);
-    for (size_t i = 0; i < mCmapFmt14Coverage.size(); i++) {
-        if (mCmapFmt14Coverage[i] != nullptr) {
-            writer->write<uint32_t>(i);
-            mCmapFmt14Coverage[i]->writeTo(writer);
+    mCmapFmt14CoverageCount = reader->read<uint32_t>();
+    if (mCmapFmt14CoverageCount > 0) {
+        mCmapFmt14Coverage = std::make_unique<SparseBitSet[]>(mCmapFmt14CoverageCount);
+        uint32_t cmapFmt14CoverageEntryCount = reader->read<uint32_t>();
+        for (uint32_t i = 0; i < cmapFmt14CoverageEntryCount; i++) {
+            uint32_t index = reader->read<uint32_t>();
+            mCmapFmt14Coverage[index] = SparseBitSet(reader);
         }
     }
 }
 
-void FontFamily::writeLocaleListInternal(BufferWriter* writer) const {
+void FontFamily::writeTo(BufferWriter* writer, uint32_t* fontIndex) const {
     LocaleListCache::writeTo(writer, mLocaleListId);
+    writer->write<uint32_t>(mFontsCount);
+    for (size_t i = 0; i < mFontsCount; i++) {
+        writer->write<uint32_t>(*fontIndex);
+        (*fontIndex)++;
+    }
+    writer->write<FamilyVariant>(mVariant);
+    writer->writeArray<AxisTag>(mSupportedAxes.get(), mSupportedAxesCount);
+    writer->write<uint8_t>(mIsColorEmoji);
+    writer->write<uint8_t>(mIsCustomFallback);
+    writer->write<uint8_t>(mIsDefaultFallback);
+    mCoverage.writeTo(writer);
+    // Write mCmapFmt14Coverage as a sparse array (size, non-null entry count,
+    // array of (index, entry))
+    writer->write<uint32_t>(mCmapFmt14CoverageCount);
+    // Skip writing the sparse entries if the size is zero
+    if (mCmapFmt14CoverageCount > 0) {
+        uint32_t cmapFmt14CoverageEntryCount = 0;
+        for (size_t i = 0; i < mCmapFmt14CoverageCount; i++) {
+            if (!mCmapFmt14Coverage[i].empty()) cmapFmt14CoverageEntryCount++;
+        }
+        writer->write<uint32_t>(cmapFmt14CoverageEntryCount);
+        for (size_t i = 0; i < mCmapFmt14CoverageCount; i++) {
+            if (!mCmapFmt14Coverage[i].empty()) {
+                writer->write<uint32_t>(i);
+                mCmapFmt14Coverage[i].writeTo(writer);
+            }
+        }
+    }
 }
+
+// static
+std::vector<std::shared_ptr<FontFamily>> FontFamily::readVector(BufferReader* reader) {
+    // To save memory used for reference counting objects, we store
+    // Font / FontFamily in shared_ptr<vector<Font / FontFamily>>, and use
+    // shared_ptr's aliasing constructor to create shared_ptr<Font / FontFamily>
+    // that share the reference counting objects with
+    // the shared_ptr<vector<Font / FontFamily>>.
+    // We can do this because we know that all Font and FontFamily
+    // instances based on the same BufferReader share the same life span.
+    uint32_t fontsCount = reader->read<uint32_t>();
+    std::shared_ptr<std::vector<Font>> fonts = std::make_shared<std::vector<Font>>();
+    fonts->reserve(fontsCount);
+    for (uint32_t i = 0; i < fontsCount; i++) {
+        fonts->emplace_back(reader);
+    }
+    uint32_t count = reader->read<uint32_t>();
+    std::shared_ptr<std::vector<FontFamily>> families = std::make_shared<std::vector<FontFamily>>();
+    families->reserve(count);
+    std::vector<std::shared_ptr<FontFamily>> pointers;
+    pointers.reserve(count);
+    for (uint32_t i = 0; i < count; i++) {
+        // TODO(b/174672300): Revert back to emplace_back.
+        families->push_back(FontFamily(reader, fonts));
+        // Use aliasing constructor.
+        pointers.emplace_back(families, &families->back());
+    }
+    return pointers;
+}
+
+// static
+void FontFamily::writeVector(BufferWriter* writer,
+                             const std::vector<std::shared_ptr<FontFamily>>& families) {
+    std::vector<std::shared_ptr<Font>> fonts;
+    for (const auto& fontFamily : families) {
+        for (uint32_t i = 0; i < fontFamily->getNumFonts(); i++) {
+            fonts.emplace_back(fontFamily->getFontRef(i));
+        }
+    }
+    writer->write<uint32_t>(fonts.size());
+    for (const auto& font : fonts) {
+        font->writeTo(writer);
+    }
+    uint32_t fontIndex = 0;
+    writer->write<uint32_t>(families.size());
+    for (const auto& fontFamily : families) {
+        fontFamily->writeTo(writer, &fontIndex);
+    }
+}
+
 // Compute a matching metric between two styles - 0 is an exact match
 static int computeMatch(FontStyle style1, FontStyle style2) {
     if (style1 == style2) return 0;
@@ -154,7 +226,7 @@
     int bestIndex = 0;
     Font* bestFont = mFonts[bestIndex].get();
     int bestMatch = computeMatch(bestFont->style(), style);
-    for (size_t i = 1; i < mFonts.size(); i++) {
+    for (size_t i = 1; i < mFontsCount; i++) {
         Font* font = mFonts[i].get();
         int match = computeMatch(font->style(), style);
         if (i == 0 || match < bestMatch) {
@@ -174,11 +246,31 @@
         return;
     }
 
-    mCoverage = CmapCoverage::getCoverage(cmapTable.get(), cmapTable.size(), &mCmapFmt14Coverage);
+    std::vector<SparseBitSet> cmapFmt14Coverage;
+    mCoverage = CmapCoverage::getCoverage(cmapTable.get(), cmapTable.size(), &cmapFmt14Coverage);
+    static_assert(INVALID_VS_INDEX <= std::numeric_limits<uint16_t>::max());
+    // cmapFmt14Coverage maps VS index to coverage.
+    // cmapFmt14Coverage's size cannot exceed INVALID_VS_INDEX.
+    MINIKIN_ASSERT(cmapFmt14Coverage.size() <= INVALID_VS_INDEX,
+                   "cmapFmt14Coverage's size must not exceed INVALID_VS_INDEX.");
+    mCmapFmt14CoverageCount = static_cast<uint16_t>(cmapFmt14Coverage.size());
+    if (mCmapFmt14CoverageCount > 0) {
+        mCmapFmt14Coverage = std::make_unique<SparseBitSet[]>(mCmapFmt14CoverageCount);
+        for (size_t i = 0; i < mCmapFmt14CoverageCount; i++) {
+            mCmapFmt14Coverage[i] = std::move(cmapFmt14Coverage[i]);
+        }
+    }
 
-    for (size_t i = 0; i < mFonts.size(); ++i) {
+    std::unordered_set<AxisTag> supportedAxesSet;
+    for (size_t i = 0; i < mFontsCount; ++i) {
         std::unordered_set<AxisTag> supportedAxes = mFonts[i]->getSupportedAxes();
-        mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end());
+        supportedAxesSet.insert(supportedAxes.begin(), supportedAxes.end());
+    }
+    MINIKIN_ASSERT(supportedAxesSet.size() <= std::numeric_limits<uint32_t>::max(),
+                   "Number of supported axes must be less than 2^16.");
+    mSupportedAxesCount = static_cast<uint16_t>(supportedAxesSet.size());
+    if (mSupportedAxesCount > 0) {
+        mSupportedAxes = sortedArrayFromSet(supportedAxesSet);
     }
 }
 
@@ -187,35 +279,36 @@
         return mCoverage.get(codepoint);
     }
 
-    if (mCmapFmt14Coverage.empty()) {
+    if (mCmapFmt14CoverageCount == 0) {
         return false;
     }
 
     const uint16_t vsIndex = getVsIndex(variationSelector);
 
-    if (vsIndex >= mCmapFmt14Coverage.size()) {
+    if (vsIndex >= mCmapFmt14CoverageCount) {
         // Even if vsIndex is INVALID_VS_INDEX, we reach here since INVALID_VS_INDEX is defined to
         // be at the maximum end of the range.
         return false;
     }
 
-    const std::unique_ptr<SparseBitSet>& bitset = mCmapFmt14Coverage[vsIndex];
-    if (bitset.get() == nullptr) {
+    const SparseBitSet& bitset = mCmapFmt14Coverage[vsIndex];
+    if (bitset.empty()) {
         return false;
     }
 
-    return bitset->get(codepoint);
+    return bitset.get(codepoint);
 }
 
 std::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation(
         const std::vector<FontVariation>& variations) const {
-    if (variations.empty() || mSupportedAxes.empty()) {
+    if (variations.empty() || mSupportedAxesCount == 0) {
         return nullptr;
     }
 
     bool hasSupportedAxis = false;
     for (const FontVariation& variation : variations) {
-        if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end()) {
+        if (std::binary_search(mSupportedAxes.get(), mSupportedAxes.get() + mSupportedAxesCount,
+                               variation.axisTag)) {
             hasSupportedAxis = true;
             break;
         }
@@ -226,7 +319,8 @@
     }
 
     std::vector<std::shared_ptr<Font>> fonts;
-    for (const auto& font : mFonts) {
+    for (size_t i = 0; i < mFontsCount; i++) {
+        const std::shared_ptr<Font>& font = mFonts[i];
         bool supportedVariations = false;
         std::unordered_set<AxisTag> supportedAxes = font->getSupportedAxes();
         if (!supportedAxes.empty()) {
@@ -248,8 +342,7 @@
         }
     }
 
-    return std::shared_ptr<FontFamily>(
-            new FontFamily(mLocaleListId, mVariant, std::move(fonts), mIsCustomFallback));
+    return create(mLocaleListId, mVariant, std::move(fonts), mIsCustomFallback, mIsDefaultFallback);
 }
 
 }  // namespace minikin
diff --git a/libs/minikin/Measurement.cpp b/libs/minikin/Measurement.cpp
index 093dba8..968ab6f 100644
--- a/libs/minikin/Measurement.cpp
+++ b/libs/minikin/Measurement.cpp
@@ -24,11 +24,33 @@
 #include "minikin/BoundsCache.h"
 #include "minikin/GraphemeBreak.h"
 
+namespace {
+bool isAsciiOrBidiControlCharacter(uint16_t c) {
+    return (0x0000 <= c && c <= 0x001F)                  // ASCII control characters
+           || c == 0x061C || c == 0x200E || c == 0x200F  // BiDi control characters
+           || (0x202A <= c && c <= 0x202E) || (0x2066 <= c && c <= 0x2069);
+}
+
+}  // namespace
+
 namespace minikin {
 
 // These could be considered helper methods of layout, but need only be loosely coupled, so
 // are separate.
 
+/**
+ * Return the unsigned advance of the given offset from the run start.
+ *
+ * @param advances the computed advances of the characters in buf. The advance of
+ * the i-th character in buf is stored at index (i - layoutStart) in this array.
+ * @param buf the text stored in utf-16 format.
+ * @param layoutStart the start index of the character that is laid out.
+ * @param start the start index of the run.
+ * @param count the number of the characters in this run.
+ * @param offset the target offset to compute the index. It should be in the
+ * range of [start, start + count).
+ * @return the unsigned advance from the run start to the given offset.
+ */
 static float getRunAdvance(const float* advances, const uint16_t* buf, size_t layoutStart,
                            size_t start, size_t count, size_t offset) {
     float advance = 0.0f;
@@ -42,13 +64,17 @@
             clusterWidth = charAdvance;
         }
     }
-    if (offset < start + count && advances[offset - layoutStart] == 0.0f) {
+    if (offset < start + count && !isAsciiOrBidiControlCharacter(buf[offset]) &&
+        advances[offset - layoutStart] == 0.0f) {
         // In the middle of a cluster, distribute width of cluster so that each grapheme cluster
         // gets an equal share.
         // TODO: get caret information out of font when that's available
         size_t nextCluster;
         for (nextCluster = offset + 1; nextCluster < start + count; nextCluster++) {
-            if (advances[nextCluster - layoutStart] != 0.0f) break;
+            if (advances[nextCluster - layoutStart] != 0.0f ||
+                isAsciiOrBidiControlCharacter(buf[nextCluster])) {
+                break;
+            }
         }
         int numGraphemeClusters = 0;
         int numGraphemeClustersAfter = 0;
@@ -69,6 +95,50 @@
     return advance;
 }
 
+/**
+ * Helper method that distribute the advance to ligature characters.
+ * When ligature is applied, the first character in the ligature is assigned with the entire width.
+ * This method will evenly distribute the advance to each grapheme in the ligature.
+ *
+ * @param advances the computed advances of the characters in buf. The advance of
+ * the i-th character in buf is stored at index (i - start) in this array. This
+ * method will update this array so that advances is distributed evenly for
+ * ligature characters.
+ * @param buf the text stored in utf-16 format.
+ * @param start the start index of the run.
+ * @param count the number of the characters in this run.
+ */
+void distributeAdvances(float* advances, const uint16_t* buf, size_t start, size_t count) {
+    size_t clusterStart = start;
+    while (clusterStart < start + count) {
+        float clusterAdvance = advances[clusterStart - start];
+        size_t clusterEnd;
+        for (clusterEnd = clusterStart + 1; clusterEnd < start + count; clusterEnd++) {
+            if (advances[clusterEnd - start] != 0.0f ||
+                isAsciiOrBidiControlCharacter(buf[clusterEnd])) {
+                break;
+            }
+        }
+        size_t numGraphemeClusters = 0;
+        for (size_t i = clusterStart; i < clusterEnd; i++) {
+            if (GraphemeBreak::isGraphemeBreak(advances, buf, start, count, i)) {
+                numGraphemeClusters++;
+            }
+        }
+        // When there are more than one grapheme in this cluster, ligature is applied.
+        // And we will distribute the width to each grapheme.
+        if (numGraphemeClusters > 1) {
+            for (size_t i = clusterStart; i < clusterEnd; ++i) {
+                if (GraphemeBreak::isGraphemeBreak(advances, buf, start, count, i)) {
+                    // Only distribute the advance to the first character of the cluster.
+                    advances[i - start] = clusterAdvance / numGraphemeClusters;
+                }
+            }
+        }
+        clusterStart = clusterEnd;
+    }
+}
+
 float getRunAdvance(const float* advances, const uint16_t* buf, size_t start, size_t count,
                     size_t offset) {
     return getRunAdvance(advances, buf, start, start, count, offset);
diff --git a/libs/minikin/MinikinFontFactory.cpp b/libs/minikin/MinikinFontFactory.cpp
new file mode 100644
index 0000000..77f13d8
--- /dev/null
+++ b/libs/minikin/MinikinFontFactory.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#define LOG_TAG "Minikin"
+
+#include "minikin/MinikinFontFactory.h"
+
+#include <log/log.h>
+
+#include "MinikinInternal.h"
+
+namespace minikin {
+
+namespace {
+static const MinikinFontFactory* gMinikinFontFactory = nullptr;
+}
+
+MinikinFontFactory::~MinikinFontFactory() {}
+
+// static
+const MinikinFontFactory& MinikinFontFactory::getInstance() {
+    MINIKIN_ASSERT(gMinikinFontFactory != nullptr, "setInstance should have been called.");
+    return *gMinikinFontFactory;
+}
+
+// static
+void MinikinFontFactory::setInstance(const MinikinFontFactory* factory) {
+    MINIKIN_ASSERT(gMinikinFontFactory == nullptr || gMinikinFontFactory == factory,
+                   "MinikinFontFactory cannot be changed after it is set.");
+    gMinikinFontFactory = factory;
+}
+
+}  // namespace minikin
diff --git a/libs/minikin/MinikinInternal.h b/libs/minikin/MinikinInternal.h
index d90f099..22e1b75 100644
--- a/libs/minikin/MinikinInternal.h
+++ b/libs/minikin/MinikinInternal.h
@@ -23,6 +23,11 @@
 #include <utils/Log.h>
 #include <utils/Mutex.h>
 
+#include <algorithm>
+#include <memory>
+#include <unordered_set>
+
+#include "minikin/FontVariation.h"
 #include "minikin/HbUtils.h"
 #include "minikin/MinikinFont.h"
 
@@ -75,6 +80,14 @@
     HbBlobUniquePtr mBlob;
 };
 
+template <typename T>
+std::unique_ptr<T[]> sortedArrayFromSet(const std::unordered_set<T>& set) {
+    std::unique_ptr<T[]> array(new T[set.size()]);
+    std::copy(set.begin(), set.end(), array.get());
+    std::sort(array.get(), array.get() + set.size());
+    return array;
+}
+
 }  // namespace minikin
 
 #endif  // MINIKIN_INTERNAL_H
diff --git a/libs/minikin/SparseBitSet.cpp b/libs/minikin/SparseBitSet.cpp
index 41151f1..a2814f7 100644
--- a/libs/minikin/SparseBitSet.cpp
+++ b/libs/minikin/SparseBitSet.cpp
@@ -54,16 +54,16 @@
     if (maxVal >= kMaximumCapacity) {
         return;
     }
-    mMaxVal = maxVal;
-    mIndicesCount = (mMaxVal + kPageMask) >> kLogValuesPerPage;
-    // Avoid zero-filling mOwnedIndices.
-    mOwnedIndices.reset(new uint16_t[mIndicesCount]);
-    mIndices = mOwnedIndices.get();
+    uint32_t indicesCount = (maxVal + kPageMask) >> kLogValuesPerPage;
     uint32_t nPages = calcNumPages(ranges, nRanges);
-    mBitmapsCount = nPages << (kLogValuesPerPage - kLogBitsPerEl);
-    mOwnedBitmaps = std::make_unique<element[]>(mBitmapsCount);
-    mBitmaps = mOwnedBitmaps.get();
-    mZeroPageIndex = noZeroPage;
+    uint32_t bitmapsCount = nPages << (kLogValuesPerPage - kLogBitsPerEl);
+    MappableData* data = MappableData::allocate(indicesCount, bitmapsCount);
+    mData.reset(data);
+    data->mMaxVal = maxVal;
+    uint16_t* indices = data->indices();
+    element* bitmaps = data->bitmaps();
+    memset(bitmaps, 0, sizeof(uint32_t) * bitmapsCount);
+    data->mZeroPageIndex = noZeroPage;
     uint32_t nonzeroPageEnd = 0;
     uint32_t currentPage = 0;
     for (size_t i = 0; i < nRanges; i++) {
@@ -74,54 +74,56 @@
         uint32_t endPage = (end - 1) >> kLogValuesPerPage;
         if (startPage >= nonzeroPageEnd) {
             if (startPage > nonzeroPageEnd) {
-                if (mZeroPageIndex == noZeroPage) {
-                    mZeroPageIndex = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
+                if (data->mZeroPageIndex == noZeroPage) {
+                    data->mZeroPageIndex = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
                 }
                 for (uint32_t j = nonzeroPageEnd; j < startPage; j++) {
-                    mOwnedIndices[j] = mZeroPageIndex;
+                    indices[j] = data->mZeroPageIndex;
                 }
             }
-            mOwnedIndices[startPage] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
+            indices[startPage] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
         }
 
         size_t index = ((currentPage - 1) << (kLogValuesPerPage - kLogBitsPerEl)) +
                        ((start & kPageMask) >> kLogBitsPerEl);
         size_t nElements = (end - (start & ~kElMask) + kElMask) >> kLogBitsPerEl;
         if (nElements == 1) {
-            mOwnedBitmaps[index] |=
+            bitmaps[index] |=
                     (kElAllOnes >> (start & kElMask)) & (kElAllOnes << ((~end + 1) & kElMask));
         } else {
-            mOwnedBitmaps[index] |= kElAllOnes >> (start & kElMask);
+            bitmaps[index] |= kElAllOnes >> (start & kElMask);
             for (size_t j = 1; j < nElements - 1; j++) {
-                mOwnedBitmaps[index + j] = kElAllOnes;
+                bitmaps[index + j] = kElAllOnes;
             }
-            mOwnedBitmaps[index + nElements - 1] |= kElAllOnes << ((~end + 1) & kElMask);
+            bitmaps[index + nElements - 1] |= kElAllOnes << ((~end + 1) & kElMask);
         }
         for (size_t j = startPage + 1; j < endPage + 1; j++) {
-            mOwnedIndices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
+            indices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
         }
         nonzeroPageEnd = endPage + 1;
     }
 }
 
 void SparseBitSet::initFromBuffer(BufferReader* reader) {
-    mMaxVal = reader->read<uint32_t>();
-    // mIndices and mBitmaps are not initialized when mMaxVal == 0
-    if (mMaxVal == 0) return;
-    std::tie(mIndices, mIndicesCount) = reader->readArray<uint16_t>();
-    // element is uint32_t
-    static_assert(sizeof(element) == 4);
-    std::tie(mBitmaps, mBitmapsCount) = reader->readArray<element>();
-    mZeroPageIndex = reader->read<uint16_t>();
+    uint32_t size = reader->read<uint32_t>();
+    if (size == 0) return;
+    mData.reset(reader->map<MappableData, alignof(MappableData)>(size));
 }
 
 void SparseBitSet::writeTo(BufferWriter* writer) const {
-    writer->write<uint32_t>(mMaxVal);
-    // mIndices and mBitmaps are not initialized when mMaxVal == 0
-    if (mMaxVal == 0) return;
-    writer->writeArray<uint16_t>(mIndices, mIndicesCount);
-    writer->writeArray<element>(mBitmaps, mBitmapsCount);
-    writer->write<uint16_t>(mZeroPageIndex);
+    if (mData == nullptr) {
+        // Write 0 for empty SparseBitSet.
+        writer->write<uint32_t>(0);
+        return;
+    }
+    size_t size = mData->size();
+    writer->write<uint32_t>(size);
+    static_assert(alignof(MappableData) == 4);
+    MappableData* out = writer->reserve<MappableData, alignof(MappableData)>(size);
+    if (out != nullptr) {
+        memcpy(out, mData.get(), size);
+        out->mIsMapped = 1;
+    }
 }
 
 int SparseBitSet::CountLeadingZeros(element x) {
@@ -130,11 +132,11 @@
 }
 
 uint32_t SparseBitSet::nextSetBit(uint32_t fromIndex) const {
-    if (fromIndex >= mMaxVal) {
+    if (mData == nullptr || fromIndex >= mData->mMaxVal) {
         return kNotFound;
     }
     uint32_t fromPage = fromIndex >> kLogValuesPerPage;
-    const element* bitmap = &mBitmaps[mIndices[fromPage]];
+    const element* bitmap = mData->bitmaps() + mData->indices()[fromPage];
     uint32_t offset = (fromIndex & kPageMask) >> kLogBitsPerEl;
     element e = bitmap[offset] & (kElAllOnes >> (fromIndex & kElMask));
     if (e != 0) {
@@ -146,13 +148,13 @@
             return (fromIndex & ~kPageMask) + (j << kLogBitsPerEl) + CountLeadingZeros(e);
         }
     }
-    uint32_t maxPage = (mMaxVal + kPageMask) >> kLogValuesPerPage;
+    uint32_t maxPage = (mData->mMaxVal + kPageMask) >> kLogValuesPerPage;
     for (uint32_t page = fromPage + 1; page < maxPage; page++) {
-        uint16_t index = mIndices[page];
-        if (index == mZeroPageIndex) {
+        uint16_t index = mData->indices()[page];
+        if (index == mData->mZeroPageIndex) {
             continue;
         }
-        bitmap = &mBitmaps[index];
+        bitmap = mData->bitmaps() + index;
         for (uint32_t j = 0; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) {
             e = bitmap[j];
             if (e != 0) {
@@ -163,4 +165,15 @@
     return kNotFound;
 }
 
+// static
+SparseBitSet::MappableData* SparseBitSet::MappableData::allocate(uint32_t indicesCount,
+                                                                 uint32_t bitmapsCount) {
+    MappableData* data = reinterpret_cast<MappableData*>(
+            malloc(MappableData::calcSize(indicesCount, bitmapsCount)));
+    data->mIndicesCount = indicesCount;
+    data->mBitmapsCount = bitmapsCount;
+    data->mIsMapped = 0;
+    return data;
+}
+
 }  // namespace minikin
diff --git a/libs/minikin/SystemFonts.cpp b/libs/minikin/SystemFonts.cpp
index 9c8fa66..b263d66 100644
--- a/libs/minikin/SystemFonts.cpp
+++ b/libs/minikin/SystemFonts.cpp
@@ -40,7 +40,8 @@
     std::unordered_set<FontFamily*> uniqueFamilies;
 
     for (const auto& collection : mCollections) {
-        for (const auto& family : collection->getFamilies()) {
+        for (size_t i = 0; i < collection->getFamilyCount(); ++i) {
+            const auto& family = collection->getFamilyAt(i);
             uniqueFamilies.insert(family.get());
         }
     }
diff --git a/libs/minikin/WordBreaker.cpp b/libs/minikin/WordBreaker.cpp
index fd0dea9..ae79d3c 100644
--- a/libs/minikin/WordBreaker.cpp
+++ b/libs/minikin/WordBreaker.cpp
@@ -75,17 +75,21 @@
     mPool.push_front(std::move(slot));
 }
 
-WordBreaker::WordBreaker() : mPool(&ICULineBreakerPoolImpl::getInstance()) {}
+WordBreaker::WordBreaker()
+        : mPool(&ICULineBreakerPoolImpl::getInstance()), mUText(nullptr, &utext_close) {}
 
-WordBreaker::WordBreaker(ICULineBreakerPool* pool) : mPool(pool) {}
+WordBreaker::WordBreaker(ICULineBreakerPool* pool) : mPool(pool), mUText(nullptr, &utext_close) {}
 
 ssize_t WordBreaker::followingWithLocale(const Locale& locale, LineBreakStyle lbStyle,
                                          LineBreakWordStyle lbWordStyle, size_t from) {
+    if (!mUText) {
+        return mCurrent;
+    }
     mIcuBreaker = mPool->acquire(locale, lbStyle, lbWordStyle);
     UErrorCode status = U_ZERO_ERROR;
     MINIKIN_ASSERT(mText != nullptr, "setText must be called first");
     // TODO: handle failure status
-    ubrk_setUText(mIcuBreaker.breaker.get(), &mUText, &status);
+    ubrk_setUText(mIcuBreaker.breaker.get(), mUText.get(), &status);
     if (mInEmailOrUrl) {
         // Note:
         // Don't reset mCurrent, mLast, or mScanOffset for keeping email/URL context.
@@ -108,7 +112,7 @@
     mScanOffset = 0;
     mInEmailOrUrl = false;
     UErrorCode status = U_ZERO_ERROR;
-    utext_openUChars(&mUText, reinterpret_cast<const UChar*>(data), size, &status);
+    mUText.reset(utext_openUChars(nullptr, reinterpret_cast<const UChar*>(data), size, &status));
 }
 
 ssize_t WordBreaker::current() const {
@@ -317,8 +321,7 @@
 
 void WordBreaker::finish() {
     mText = nullptr;
-    // Note: calling utext_close multiply is safe
-    utext_close(&mUText);
+    mUText.reset();
     mPool->release(std::move(mIcuBreaker));
 }
 
diff --git a/libs/minikin/WordBreaker.h b/libs/minikin/WordBreaker.h
index 45bcd40..c4af635 100644
--- a/libs/minikin/WordBreaker.h
+++ b/libs/minikin/WordBreaker.h
@@ -26,6 +26,7 @@
 #include <unicode/ubrk.h>
 
 #include <list>
+#include <memory>
 #include <mutex>
 
 #include "Locale.h"
@@ -146,7 +147,7 @@
 
     ICULineBreakerPool::Slot mIcuBreaker;
 
-    UText mUText = UTEXT_INITIALIZER;
+    std::unique_ptr<UText, decltype(&utext_close)> mUText;
     const uint16_t* mText = nullptr;
     size_t mTextSize;
     ssize_t mLast;
diff --git a/tests/perftests/Android.bp b/tests/perftests/Android.bp
index 19ed8eb..dcf5b98 100644
--- a/tests/perftests/Android.bp
+++ b/tests/perftests/Android.bp
@@ -21,11 +21,7 @@
 cc_benchmark {
     name: "minikin_perftests",
     test_suites: ["device-tests"],
-    cppflags: [
-        "-Werror",
-        "-Wall",
-        "-Wextra",
-    ],
+    defaults: ["libminikin_defaults"],
     srcs: [
         "FontCollection.cpp",
         "FontLanguage.cpp",
@@ -46,7 +42,7 @@
     shared_libs: [
         "libft2",
         "libharfbuzz_ng",
-        "libandroidicu",
+        "libicu",
         "liblog",
 
     ],
diff --git a/tests/perftests/FontCollection.cpp b/tests/perftests/FontCollection.cpp
index 15d1c5e..b0be292 100644
--- a/tests/perftests/FontCollection.cpp
+++ b/tests/perftests/FontCollection.cpp
@@ -36,15 +36,14 @@
     std::vector<std::shared_ptr<FontFamily>> families =
             getFontFamilies(SYSTEM_FONT_PATH, SYSTEM_FONT_XML);
     while (state.KeepRunning()) {
-        std::make_shared<FontCollection>(families);
+        FontCollection::create(families);
     }
 }
 
 BENCHMARK(BM_FontCollection_construct);
 
 static void BM_FontCollection_hasVariationSelector(benchmark::State& state) {
-    auto collection =
-            std::make_shared<FontCollection>(getFontFamilies(SYSTEM_FONT_PATH, SYSTEM_FONT_XML));
+    auto collection = FontCollection::create(getFontFamilies(SYSTEM_FONT_PATH, SYSTEM_FONT_XML));
 
     uint32_t baseCp = state.range(0);
     uint32_t vsCp = state.range(1);
@@ -80,8 +79,7 @@
 };
 
 static void BM_FontCollection_itemize(benchmark::State& state) {
-    auto collection =
-            std::make_shared<FontCollection>(getFontFamilies(SYSTEM_FONT_PATH, SYSTEM_FONT_XML));
+    auto collection = FontCollection::create(getFontFamilies(SYSTEM_FONT_PATH, SYSTEM_FONT_XML));
 
     size_t testIndex = state.range(0);
     state.SetLabel("Itemize: " + ITEMIZE_TEST_CASES[testIndex].labelText);
diff --git a/tests/stresstest/Android.bp b/tests/stresstest/Android.bp
index 784dc6a..d963a09 100644
--- a/tests/stresstest/Android.bp
+++ b/tests/stresstest/Android.bp
@@ -36,7 +36,7 @@
 
         "libft2",
         "libharfbuzz_ng",
-        "libandroidicu",
+        "libicu",
         "liblog",
         "libutils",
         "libz",
@@ -47,9 +47,5 @@
         "MultithreadTest.cpp",
     ],
 
-    cflags: [
-        "-Werror",
-        "-Wall",
-        "-Wextra",
-    ],
+    defaults: ["libminikin_defaults"],
 }
diff --git a/tests/stresstest/FontFamilyTest.cpp b/tests/stresstest/FontFamilyTest.cpp
index 7a9813e..f5632a2 100644
--- a/tests/stresstest/FontFamilyTest.cpp
+++ b/tests/stresstest/FontFamilyTest.cpp
@@ -38,7 +38,7 @@
     auto font = std::make_shared<FreeTypeMinikinFontForTest>(fontPath);
     std::vector<std::shared_ptr<Font>> fonts;
     fonts.push_back(Font::Builder(font).build());
-    std::shared_ptr<FontFamily> family = std::make_shared<FontFamily>(std::move(fonts));
+    std::shared_ptr<FontFamily> family = FontFamily::create(std::move(fonts));
 
     hb_font_t* hbFont = family->getFont(0)->baseFont().get();
 
diff --git a/tests/stresstest/MultithreadTest.cpp b/tests/stresstest/MultithreadTest.cpp
index 560b517..d32d0b4 100644
--- a/tests/stresstest/MultithreadTest.cpp
+++ b/tests/stresstest/MultithreadTest.cpp
@@ -21,17 +21,19 @@
 #include <random>
 #include <thread>
 
+#include <android-base/thread_annotations.h>
 #include <cutils/log.h>
 #include <gtest/gtest.h>
 
 #include "minikin/FontCollection.h"
 #include "minikin/Macros.h"
 #include "minikin/MinikinPaint.h"
-
 #include "FontTestUtils.h"
 #include "MinikinInternal.h"
 #include "PathUtils.h"
 
+using android::base::ScopedLockAssertion;
+
 namespace minikin {
 
 constexpr int LAYOUT_COUNT_PER_COLLECTION = 500;
@@ -63,7 +65,7 @@
     {
         // Wait until all threads are created.
         std::unique_lock<std::mutex> lock(gMutex);
-        gCv.wait(lock, [] { return gReady; });
+        gCv.wait(lock, []() EXCLUSIVE_LOCKS_REQUIRED(gMutex) { return gReady; });
     }
 
     std::mt19937 mt(tid);
@@ -90,7 +92,7 @@
     std::vector<std::thread> threads;
 
     {
-        std::unique_lock<std::mutex> lock(gMutex);
+        ScopedLockAssertion lock(gMutex);
         threads.reserve(NUM_THREADS);
         for (int i = 0; i < NUM_THREADS; ++i) {
             threads.emplace_back(&thread_main, i);
diff --git a/tests/unittest/Android.bp b/tests/unittest/Android.bp
index d36c52f..9800416 100644
--- a/tests/unittest/Android.bp
+++ b/tests/unittest/Android.bp
@@ -36,7 +36,7 @@
     shared_libs: [
         "libft2",
         "libharfbuzz_ng",
-        "libandroidicu",
+        "libicu",
         "liblog",
         "libutils",
         "libz",
@@ -79,9 +79,5 @@
         "WordBreakerTests.cpp",
     ],
 
-    cflags: [
-        "-Werror",
-        "-Wall",
-        "-Wextra",
-    ],
+    defaults: ["libminikin_defaults"],
 }
diff --git a/tests/unittest/BufferTest.cpp b/tests/unittest/BufferTest.cpp
index 8b1db33..2e589b2 100644
--- a/tests/unittest/BufferTest.cpp
+++ b/tests/unittest/BufferTest.cpp
@@ -33,6 +33,11 @@
         // padding (3), array size (4), uint32_t (4) * 2
         uint32_t uint32Array[] = {0x98765432, 0x98765433};
         writer->writeArray<uint32_t>(uint32Array, 2);
+        uint16_t* uint16Array = writer->reserve<uint16_t>(2 * sizeof(uint16_t));
+        if (uint16Array != nullptr) {
+            uint16Array[0] = 0x1234u;
+            uint16Array[1] = 0x5678u;
+        }
     }
 };
 
@@ -40,7 +45,7 @@
     TestObject testObject;
     BufferWriter fakeWriter(nullptr);
     testObject.writeTo(&fakeWriter);
-    ASSERT_EQ(fakeWriter.size(), 20u);
+    ASSERT_EQ(fakeWriter.size(), 24u);
     std::vector<uint8_t> buffer(fakeWriter.size());
 
     BufferWriter writer(buffer.data());
@@ -48,26 +53,29 @@
     ASSERT_EQ(writer.size(), buffer.size());
 
     BufferReader reader(buffer.data());
-    ASSERT_EQ(reader.data(), buffer.data());
-    ASSERT_EQ(reader.pos(), 0u);
+    ASSERT_EQ(reader.current(), buffer.data());
     ASSERT_EQ(reader.read<uint8_t>(), 0xABu);
-    ASSERT_EQ(reader.pos(), 1u);
+    ASSERT_EQ(reader.current(), buffer.data() + 1u);
     ASSERT_EQ(reader.read<uint16_t>(), 0xCDEFu);
-    ASSERT_EQ(reader.pos(), 4u);
+    ASSERT_EQ(reader.current(), buffer.data() + 4u);
     ASSERT_EQ(reader.read<uint8_t>(), 0x01u);
-    ASSERT_EQ(reader.pos(), 5u);
+    ASSERT_EQ(reader.current(), buffer.data() + 5u);
     auto [uint32Array, size] = reader.readArray<uint32_t>();
     ASSERT_EQ(size, 2u);
     ASSERT_EQ(uint32Array[0], 0x98765432u);
     ASSERT_EQ(uint32Array[1], 0x98765433u);
-    ASSERT_EQ(reader.pos(), 20u);
+    ASSERT_EQ(reader.current(), buffer.data() + 20u);
+    const uint16_t* uint16Array = reader.map<uint16_t>(4);
+    ASSERT_EQ(uint16Array[0], 0x1234u);
+    ASSERT_EQ(uint16Array[1], 0x5678u);
+    ASSERT_EQ(reader.current(), buffer.data() + 24u);
 }
 
 TEST(BufferTest, testSkip) {
     TestObject testObject;
     BufferWriter fakeWriter(nullptr);
     testObject.writeTo(&fakeWriter);
-    ASSERT_EQ(fakeWriter.size(), 20u);
+    ASSERT_EQ(fakeWriter.size(), 24u);
     std::vector<uint8_t> buffer(fakeWriter.size());
 
     BufferWriter writer(buffer.data());
@@ -75,16 +83,18 @@
     ASSERT_EQ(writer.size(), buffer.size());
 
     BufferReader reader(buffer.data());
-    ASSERT_EQ(reader.data(), buffer.data());
-    ASSERT_EQ(reader.pos(), 0u);
+    ASSERT_EQ(reader.current(), buffer.data());
     reader.skip<uint8_t>();
-    ASSERT_EQ(reader.pos(), 1u);
+    ASSERT_EQ(reader.current(), buffer.data() + 1u);
     reader.read<uint16_t>();
-    ASSERT_EQ(reader.pos(), 4u);
+    ASSERT_EQ(reader.current(), buffer.data() + 4u);
     reader.skip<uint8_t>();
-    ASSERT_EQ(reader.pos(), 5u);
+    ASSERT_EQ(reader.current(), buffer.data() + 5u);
     reader.skipArray<uint32_t>();
-    ASSERT_EQ(reader.pos(), 20u);
+    ASSERT_EQ(reader.current(), buffer.data() + 20u);
+    // No skip function for mapped data.
+    reader.map<uint16_t>(4);
+    ASSERT_EQ(reader.current(), buffer.data() + 24u);
 }
 
 }  // namespace minikin
diff --git a/tests/unittest/CmapCoverageTest.cpp b/tests/unittest/CmapCoverageTest.cpp
index 9dba583..f871c19 100644
--- a/tests/unittest/CmapCoverageTest.cpp
+++ b/tests/unittest/CmapCoverageTest.cpp
@@ -285,7 +285,7 @@
 };
 
 TEST(CmapCoverageTest, SingleFormat4_brokenCmap) {
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
     {
         SCOPED_TRACE("Reading beyond buffer size - Too small cmap size");
         std::vector<uint8_t> cmap =
@@ -337,7 +337,7 @@
 }
 
 TEST(CmapCoverageTest, SingleFormat4) {
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
     struct TestCast {
         std::string testTitle;
         uint16_t platformId;
@@ -360,7 +360,7 @@
 }
 
 TEST(CmapCoverageTest, SingleFormat12) {
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
 
     struct TestCast {
         std::string testTitle;
@@ -384,7 +384,7 @@
 }
 
 TEST(CmapCoverageTest, Format12_beyondTheUnicodeLimit) {
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
     {
         SCOPED_TRACE("Starting range is out of Unicode code point. Should be ignored.");
         std::vector<uint8_t> cmap = CmapBuilder::buildSingleFormat12Cmap(
@@ -410,7 +410,7 @@
 }
 
 TEST(CmapCoverageTest, notSupportedEncodings) {
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
 
     struct TestCast {
         std::string testTitle;
@@ -451,7 +451,7 @@
 }
 
 TEST(CmapCoverageTest, brokenFormat4Table) {
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
     {
         SCOPED_TRACE("Too small table cmap size");
         std::vector<uint8_t> table = buildCmapFormat4Table(std::vector<uint16_t>({'a', 'a'}));
@@ -505,7 +505,7 @@
 }
 
 TEST(CmapCoverageTest, duplicatedCmap4EntryTest) {
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
     std::vector<uint8_t> table = buildCmapFormat4Table(std::vector<uint16_t>({'a', 'b', 'b', 'b'}));
     CmapBuilder builder(1);
     builder.appendTable(0, 0, table);
@@ -518,7 +518,7 @@
 }
 
 TEST(CmapCoverageTest, brokenFormat12Table) {
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
     {
         SCOPED_TRACE("Too small cmap size");
         std::vector<uint8_t> table = buildCmapFormat12Table(std::vector<uint32_t>({'a', 'a'}));
@@ -594,7 +594,7 @@
     std::vector<uint8_t> format4 = buildCmapFormat4Table(std::vector<uint16_t>({'b', 'b'}));
     std::vector<uint8_t> format12 = buildCmapFormat12Table(std::vector<uint32_t>({'b', 'b'}));
 
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
     {
         SCOPED_TRACE("(platform, encoding) = (3, 10) is the highest priority.");
 
@@ -646,7 +646,7 @@
 
 TEST(CmapCoverageTest, TableSelection_SkipBrokenFormat4Table) {
     std::vector<uint8_t> validTable = buildCmapFormat4Table(std::vector<uint16_t>({'a', 'a'}));
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
     {
         SCOPED_TRACE("Unsupported format");
         CmapBuilder builder(2);
@@ -692,7 +692,7 @@
 }
 
 TEST(CmapCoverageTest, TableSelection_SkipBrokenFormat12Table) {
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
     std::vector<uint8_t> validTable = buildCmapFormat12Table(std::vector<uint32_t>({'a', 'a'}));
     {
         SCOPED_TRACE("Unsupported format");
@@ -751,28 +751,28 @@
     builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
     std::vector<uint8_t> cmap = builder.build();
 
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
     SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
     EXPECT_TRUE(coverage.get('a'));
     ASSERT_FALSE(vsTables.empty());
 
     const uint16_t vs15Index = getVsIndex(0xFE0E);
     ASSERT_LT(vs15Index, vsTables.size());
-    ASSERT_TRUE(vsTables[vs15Index]);
-    EXPECT_TRUE(vsTables[vs15Index]->get('a'));
-    EXPECT_TRUE(vsTables[vs15Index]->get('b'));
+    ASSERT_FALSE(vsTables[vs15Index].empty());
+    EXPECT_TRUE(vsTables[vs15Index].get('a'));
+    EXPECT_TRUE(vsTables[vs15Index].get('b'));
 
     const uint16_t vs16Index = getVsIndex(0xFE0F);
     ASSERT_LT(vs16Index, vsTables.size());
-    ASSERT_TRUE(vsTables[vs16Index]);
-    EXPECT_TRUE(vsTables[vs16Index]->get('a'));
-    EXPECT_TRUE(vsTables[vs16Index]->get('b'));
+    ASSERT_FALSE(vsTables[vs16Index].empty());
+    EXPECT_TRUE(vsTables[vs16Index].get('a'));
+    EXPECT_TRUE(vsTables[vs16Index].get('b'));
 
     const uint16_t vs17Index = getVsIndex(0xE0100);
     ASSERT_LT(vs17Index, vsTables.size());
-    ASSERT_TRUE(vsTables[vs17Index]);
-    EXPECT_TRUE(vsTables[vs17Index]->get('a'));
-    EXPECT_TRUE(vsTables[vs17Index]->get('b'));
+    ASSERT_FALSE(vsTables[vs17Index].empty());
+    EXPECT_TRUE(vsTables[vs17Index].get('a'));
+    EXPECT_TRUE(vsTables[vs17Index].get('b'));
 }
 
 TEST(CmapCoverageTest, TableSelection_InterSection) {
@@ -799,66 +799,66 @@
     builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
     std::vector<uint8_t> cmap = builder.build();
 
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
     SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
     EXPECT_TRUE(coverage.get('a'));
     ASSERT_FALSE(vsTables.empty());
 
     const uint16_t vs15Index = getVsIndex(0xFE0E);
     ASSERT_LT(vs15Index, vsTables.size());
-    ASSERT_TRUE(vsTables[vs15Index]);
-    EXPECT_TRUE(vsTables[vs15Index]->get('a'));
-    EXPECT_TRUE(vsTables[vs15Index]->get('b'));
-    EXPECT_TRUE(vsTables[vs15Index]->get('c'));
-    EXPECT_TRUE(vsTables[vs15Index]->get('d'));
-    EXPECT_TRUE(vsTables[vs15Index]->get('e'));
+    ASSERT_FALSE(vsTables[vs15Index].empty());
+    EXPECT_TRUE(vsTables[vs15Index].get('a'));
+    EXPECT_TRUE(vsTables[vs15Index].get('b'));
+    EXPECT_TRUE(vsTables[vs15Index].get('c'));
+    EXPECT_TRUE(vsTables[vs15Index].get('d'));
+    EXPECT_TRUE(vsTables[vs15Index].get('e'));
 
     const uint16_t vs16Index = getVsIndex(0xFE0F);
     ASSERT_LT(vs16Index, vsTables.size());
-    ASSERT_TRUE(vsTables[vs16Index]);
-    EXPECT_TRUE(vsTables[vs16Index]->get('a'));
-    EXPECT_TRUE(vsTables[vs16Index]->get('b'));
-    EXPECT_TRUE(vsTables[vs16Index]->get('c'));
-    EXPECT_TRUE(vsTables[vs16Index]->get('d'));
-    EXPECT_TRUE(vsTables[vs16Index]->get('e'));
+    ASSERT_FALSE(vsTables[vs16Index].empty());
+    EXPECT_TRUE(vsTables[vs16Index].get('a'));
+    EXPECT_TRUE(vsTables[vs16Index].get('b'));
+    EXPECT_TRUE(vsTables[vs16Index].get('c'));
+    EXPECT_TRUE(vsTables[vs16Index].get('d'));
+    EXPECT_TRUE(vsTables[vs16Index].get('e'));
 
     const uint16_t vs17Index = getVsIndex(0xE0100);
     ASSERT_LT(vs17Index, vsTables.size());
-    ASSERT_TRUE(vsTables[vs17Index]);
-    EXPECT_TRUE(vsTables[vs17Index]->get('a'));
-    EXPECT_TRUE(vsTables[vs17Index]->get('b'));
-    EXPECT_TRUE(vsTables[vs17Index]->get('c'));
-    EXPECT_TRUE(vsTables[vs17Index]->get('d'));
+    ASSERT_FALSE(vsTables[vs17Index].empty());
+    EXPECT_TRUE(vsTables[vs17Index].get('a'));
+    EXPECT_TRUE(vsTables[vs17Index].get('b'));
+    EXPECT_TRUE(vsTables[vs17Index].get('c'));
+    EXPECT_TRUE(vsTables[vs17Index].get('d'));
 
     const uint16_t vs18Index = getVsIndex(0xE0101);
     ASSERT_LT(vs18Index, vsTables.size());
-    ASSERT_TRUE(vsTables[vs18Index]);
-    EXPECT_TRUE(vsTables[vs18Index]->get('a'));
-    EXPECT_TRUE(vsTables[vs18Index]->get('b'));
-    EXPECT_TRUE(vsTables[vs18Index]->get('c'));
-    EXPECT_TRUE(vsTables[vs18Index]->get('d'));
+    ASSERT_FALSE(vsTables[vs18Index].empty());
+    EXPECT_TRUE(vsTables[vs18Index].get('a'));
+    EXPECT_TRUE(vsTables[vs18Index].get('b'));
+    EXPECT_TRUE(vsTables[vs18Index].get('c'));
+    EXPECT_TRUE(vsTables[vs18Index].get('d'));
 
     const uint16_t vs19Index = getVsIndex(0xE0102);
     ASSERT_LT(vs19Index, vsTables.size());
-    ASSERT_TRUE(vsTables[vs19Index]);
-    EXPECT_TRUE(vsTables[vs19Index]->get('a'));
-    EXPECT_TRUE(vsTables[vs19Index]->get('b'));
-    EXPECT_TRUE(vsTables[vs19Index]->get('c'));
-    EXPECT_TRUE(vsTables[vs19Index]->get('d'));
-    EXPECT_TRUE(vsTables[vs19Index]->get('e'));
-    EXPECT_TRUE(vsTables[vs19Index]->get('f'));
-    EXPECT_TRUE(vsTables[vs19Index]->get('g'));
-    EXPECT_TRUE(vsTables[vs19Index]->get('h'));
+    ASSERT_FALSE(vsTables[vs19Index].empty());
+    EXPECT_TRUE(vsTables[vs19Index].get('a'));
+    EXPECT_TRUE(vsTables[vs19Index].get('b'));
+    EXPECT_TRUE(vsTables[vs19Index].get('c'));
+    EXPECT_TRUE(vsTables[vs19Index].get('d'));
+    EXPECT_TRUE(vsTables[vs19Index].get('e'));
+    EXPECT_TRUE(vsTables[vs19Index].get('f'));
+    EXPECT_TRUE(vsTables[vs19Index].get('g'));
+    EXPECT_TRUE(vsTables[vs19Index].get('h'));
 
     const uint16_t vs20Index = getVsIndex(0xE0103);
     ASSERT_LT(vs20Index, vsTables.size());
-    ASSERT_TRUE(vsTables[vs20Index]);
-    EXPECT_TRUE(vsTables[vs20Index]->get('a'));
-    EXPECT_TRUE(vsTables[vs20Index]->get('b'));
-    EXPECT_TRUE(vsTables[vs20Index]->get('c'));
-    EXPECT_TRUE(vsTables[vs20Index]->get('d'));
-    EXPECT_TRUE(vsTables[vs20Index]->get('e'));
-    EXPECT_TRUE(vsTables[vs20Index]->get('f'));
+    ASSERT_FALSE(vsTables[vs20Index].empty());
+    EXPECT_TRUE(vsTables[vs20Index].get('a'));
+    EXPECT_TRUE(vsTables[vs20Index].get('b'));
+    EXPECT_TRUE(vsTables[vs20Index].get('c'));
+    EXPECT_TRUE(vsTables[vs20Index].get('d'));
+    EXPECT_TRUE(vsTables[vs20Index].get('e'));
+    EXPECT_TRUE(vsTables[vs20Index].get('f'));
 }
 
 TEST(CmapCoverageTest, TableSelection_brokenVSTable) {
@@ -872,7 +872,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage =
                 CmapCoverage::getCoverage(cmap.data(), 3 /* too small size */, &vsTables);
         EXPECT_FALSE(coverage.get('a'));
@@ -888,7 +888,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -902,7 +902,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -916,7 +916,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -931,7 +931,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -946,7 +946,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -959,7 +959,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -972,7 +972,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -985,7 +985,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -998,7 +998,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -1014,7 +1014,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -1030,7 +1030,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -1046,7 +1046,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -1062,7 +1062,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -1078,7 +1078,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -1094,7 +1094,7 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
         ASSERT_TRUE(vsTables.empty());
     }
@@ -1113,17 +1113,17 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
 
         const uint16_t vs16Index = getVsIndex(0xFE0F);
         ASSERT_LT(vs16Index, vsTables.size());
-        ASSERT_TRUE(vsTables[vs16Index]);
-        EXPECT_TRUE(vsTables[vs16Index]->get('a'));
-        EXPECT_TRUE(vsTables[vs16Index]->get('b'));
+        ASSERT_FALSE(vsTables[vs16Index].empty());
+        EXPECT_TRUE(vsTables[vs16Index].get('a'));
+        EXPECT_TRUE(vsTables[vs16Index].get('b'));
 
         const uint16_t vs15Index = getVsIndex(0xFE0E);
-        EXPECT_FALSE(vsTables[vs15Index]);
+        EXPECT_TRUE(vsTables[vs15Index].empty());
     }
     {
         SCOPED_TRACE("Invalid non default UVS offset in variation records");
@@ -1136,17 +1136,17 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
 
         const uint16_t vs16Index = getVsIndex(0xFE0F);
         ASSERT_LT(vs16Index, vsTables.size());
-        ASSERT_TRUE(vsTables[vs16Index]);
-        EXPECT_TRUE(vsTables[vs16Index]->get('a'));
-        EXPECT_TRUE(vsTables[vs16Index]->get('b'));
+        ASSERT_FALSE(vsTables[vs16Index].empty());
+        EXPECT_TRUE(vsTables[vs16Index].get('a'));
+        EXPECT_TRUE(vsTables[vs16Index].get('b'));
 
         const uint16_t vs15Index = getVsIndex(0xFE0E);
-        EXPECT_FALSE(vsTables[vs15Index]);
+        EXPECT_TRUE(vsTables[vs15Index].empty());
     }
     {
         SCOPED_TRACE("Unknown variation selectors.");
@@ -1158,14 +1158,14 @@
         builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
         std::vector<uint8_t> cmap = builder.build();
 
-        std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+        std::vector<SparseBitSet> vsTables;
         SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
 
         const uint16_t vs16Index = getVsIndex(0xFE0F);
         ASSERT_LT(vs16Index, vsTables.size());
-        ASSERT_TRUE(vsTables[vs16Index]);
-        EXPECT_TRUE(vsTables[vs16Index]->get('a'));
-        EXPECT_TRUE(vsTables[vs16Index]->get('b'));
+        ASSERT_FALSE(vsTables[vs16Index].empty());
+        EXPECT_TRUE(vsTables[vs16Index].get('a'));
+        EXPECT_TRUE(vsTables[vs16Index].get('b'));
     }
 }
 
@@ -1183,16 +1183,16 @@
     builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
     std::vector<uint8_t> cmap = builder.build();
 
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
     SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
     const uint16_t vsIndex = getVsIndex(0xFE0F);
     ASSERT_LT(vsIndex, vsTables.size());
-    ASSERT_TRUE(vsTables[vsIndex]);
+    ASSERT_FALSE(vsTables[vsIndex].empty());
 
     for (char c = 'a'; c <= 'z'; ++c) {
         // Default UVS table points the variation sequence to the glyph of the base code point.
         // Thus, if the base code point is not supported, we should exclude them.
-        EXPECT_EQ(coverage.get(c), vsTables[vsIndex]->get(c)) << c;
+        EXPECT_EQ(coverage.get(c), vsTables[vsIndex].get(c)) << c;
     }
 }
 
@@ -1206,11 +1206,11 @@
     builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable);
     std::vector<uint8_t> cmap = builder.build();
 
-    std::vector<std::unique_ptr<SparseBitSet>> vsTables;
+    std::vector<SparseBitSet> vsTables;
     SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables);
     const uint16_t vsIndex = getVsIndex(0xFE0F);
     ASSERT_LT(vsIndex, vsTables.size());
-    ASSERT_TRUE(vsTables[vsIndex]);
-    EXPECT_TRUE(vsTables[vsIndex]->get('a'));
+    ASSERT_FALSE(vsTables[vsIndex].empty());
+    EXPECT_TRUE(vsTables[vsIndex].get('a'));
 }
 }  // namespace minikin
diff --git a/tests/unittest/FontCollectionItemizeTest.cpp b/tests/unittest/FontCollectionItemizeTest.cpp
index e3f8a6b..1723519 100644
--- a/tests/unittest/FontCollectionItemizeTest.cpp
+++ b/tests/unittest/FontCollectionItemizeTest.cpp
@@ -741,7 +741,7 @@
     families.push_back(buildFontFamily(kLatinFont));
     families.push_back(buildFontFamily(kVSTestFont));
 
-    std::shared_ptr<FontCollection> collection(new FontCollection(families));
+    std::shared_ptr<FontCollection> collection(FontCollection::create(families));
 
     auto runs = itemize(collection, "U+717D U+FE02");
     ASSERT_EQ(1U, runs.size());
@@ -937,9 +937,9 @@
                 std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(kNoGlyphFont));
         std::vector<std::shared_ptr<Font>> fonts;
         fonts.push_back(Font::Builder(firstFamilyMinikinFont).build());
-        auto firstFamily =
-                std::make_shared<FontFamily>(registerLocaleList("und"), FamilyVariant::DEFAULT,
-                                             std::move(fonts), false /* isCustomFallback */);
+        auto firstFamily = FontFamily::create(registerLocaleList("und"), FamilyVariant::DEFAULT,
+                                              std::move(fonts), false /* isCustomFallback */,
+                                              false /* isDefaultFallback */);
         families.push_back(firstFamily);
 
         // Prepare font families
@@ -952,13 +952,13 @@
                     std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(kJAFont));
             std::vector<std::shared_ptr<Font>> fonts;
             fonts.push_back(Font::Builder(minikinFont).build());
-            auto family = std::make_shared<FontFamily>(registerLocaleList(testCase.fontLocales[i]),
-                                                       FamilyVariant::DEFAULT, std::move(fonts),
-                                                       false /* isCustomFallback */);
+            auto family = FontFamily::create(
+                    registerLocaleList(testCase.fontLocales[i]), FamilyVariant::DEFAULT,
+                    std::move(fonts), false /* isCustomFallback */, false /* isDefaultFallback */);
             families.push_back(family);
             fontLocaleIdxMap.insert(std::make_pair(minikinFont.get(), i));
         }
-        std::shared_ptr<FontCollection> collection(new FontCollection(families));
+        std::shared_ptr<FontCollection> collection(FontCollection::create(families));
         // Do itemize
         auto runs = itemize(collection, "U+9AA8", testCase.userPreferredLocale);
         ASSERT_EQ(1U, runs.size());
@@ -1525,8 +1525,8 @@
     std::vector<std::shared_ptr<FontFamily>> families = {dummyFamily, familyA, familyB};
     std::vector<std::shared_ptr<FontFamily>> reversedFamilies = {dummyFamily, familyB, familyA};
 
-    std::shared_ptr<FontCollection> collection(new FontCollection(families));
-    std::shared_ptr<FontCollection> reversedCollection(new FontCollection(reversedFamilies));
+    std::shared_ptr<FontCollection> collection(FontCollection::create(families));
+    std::shared_ptr<FontCollection> reversedCollection(FontCollection::create(reversedFamilies));
 
     // Both fontA/fontB support U+35A8 but don't support U+35A8 U+E0100. The first font should be
     // selected.
@@ -1548,8 +1548,8 @@
     std::vector<std::shared_ptr<FontFamily>> reversedFamilies = {dummyFamily, noCmapFormat14Family,
                                                                  hasCmapFormat14Family};
 
-    std::shared_ptr<FontCollection> collection(new FontCollection(families));
-    std::shared_ptr<FontCollection> reversedCollection(new FontCollection(reversedFamilies));
+    std::shared_ptr<FontCollection> collection(FontCollection::create(families));
+    std::shared_ptr<FontCollection> reversedCollection(FontCollection::create(reversedFamilies));
 
     // Both hasCmapFormat14Font/noCmapFormat14Font support U+5380 but don't support U+5380 U+E0100.
     // The first font should be selected.
@@ -1567,7 +1567,7 @@
 
     std::vector<std::shared_ptr<FontFamily>> families = {dummyFamily, textEmojiFamily,
                                                          colorEmojiFamily};
-    auto collection = std::make_shared<FontCollection>(families);
+    auto collection = FontCollection::create(families);
     // Both textEmojiFamily and colorEmojiFamily supports U+203C and U+23E9.
     // U+203C is text default emoji, and U+23E9 is color default emoji.
     auto runs = itemize(collection, "U+203C", "en-US,en-Zsym");
@@ -1619,7 +1619,7 @@
     std::vector<std::shared_ptr<FontFamily>> families = {firstFamily, customFallbackFamily,
                                                          languageFamily};
 
-    auto collection = std::make_shared<FontCollection>(families);
+    auto collection = FontCollection::create(families);
 
     auto runs = itemize(collection, "'a'", "");
     EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font.get());
@@ -1643,7 +1643,7 @@
     std::vector<std::shared_ptr<FontFamily>> families = {firstFamily, OverrideEmojiFamily,
                                                          emojiBaseFamily};
 
-    auto collection = std::make_shared<FontCollection>(families);
+    auto collection = FontCollection::create(families);
     auto runs = itemize(collection, txt.c_str());
 
     std::vector<ItemizeResult> out;
diff --git a/tests/unittest/FontCollectionTest.cpp b/tests/unittest/FontCollectionTest.cpp
index aa9d4a8..b4933ab 100644
--- a/tests/unittest/FontCollectionTest.cpp
+++ b/tests/unittest/FontCollectionTest.cpp
@@ -177,25 +177,40 @@
     }
 }
 
+TEST(FontCollectionTest, createCollectionWithFamilies) {
+    auto fallback = buildFontCollectionFromXml(kEmojiXmlFile);
+    std::shared_ptr<FontFamily> family = buildFontFamily(kVsTestFont);
+    std::shared_ptr<FontCollection> created = fallback->createCollectionWithFamilies({family});
+    ASSERT_EQ(fallback->getFamilyCount() + 1, created->getFamilyCount());
+    EXPECT_EQ(family, created->getFamilyAt(0));
+    for (size_t i = 0; i < fallback->getFamilyCount(); i++) {
+        EXPECT_EQ(fallback->getFamilyAt(i), created->getFamilyAt(i + 1));
+    }
+}
+
 std::vector<uint8_t> writeToBuffer(
         const std::vector<std::shared_ptr<FontCollection>>& collections) {
     BufferWriter fakeWriter(nullptr);
-    FontCollection::writeVector<writeFreeTypeMinikinFontForTest>(&fakeWriter, collections);
+    FontCollection::writeVector(&fakeWriter, collections);
     std::vector<uint8_t> buffer(fakeWriter.size());
     BufferWriter writer(buffer.data());
-    FontCollection::writeVector<writeFreeTypeMinikinFontForTest>(&writer, collections);
+    FontCollection::writeVector(&writer, collections);
     return buffer;
 }
 
 TEST(FontCollectionTest, bufferTest) {
+    FreeTypeMinikinFontForTestFactory::init();
     {
         std::vector<std::shared_ptr<FontCollection>> original({buildFontCollection(kVsTestFont)});
         std::vector<uint8_t> buffer = writeToBuffer(original);
         BufferReader reader(buffer.data());
-        auto copied = FontCollection::readVector<readFreeTypeMinikinFontForTest>(&reader);
+        auto copied = FontCollection::readVector(&reader);
         EXPECT_EQ(1u, copied.size());
         expectVSGlyphsForVsTestFont(copied[0].get());
-        EXPECT_EQ(original[0]->getSupportedTags(), copied[0]->getSupportedTags());
+        ASSERT_EQ(original[0]->getSupportedAxesCount(), copied[0]->getSupportedAxesCount());
+        for (size_t i = 0; i < original[0]->getSupportedAxesCount(); i++) {
+            EXPECT_EQ(original[0]->getSupportedAxisAt(i), copied[0]->getSupportedAxisAt(i));
+        }
         // Id will be different.
         EXPECT_NE(original[0]->getId(), copied[0]->getId());
         std::vector<uint8_t> newBuffer = writeToBuffer(copied);
@@ -204,14 +219,14 @@
     {
         // Test that FontFamily instances are shared.
         std::vector<std::shared_ptr<FontFamily>> families = {buildFontFamily(kVsTestFont)};
-        auto fc1 = std::make_shared<FontCollection>(families);
-        auto fc2 = std::make_shared<FontCollection>(families);
+        auto fc1 = FontCollection::create(families);
+        auto fc2 = FontCollection::create(families);
         std::vector<std::shared_ptr<FontCollection>> original({fc1, fc2});
         std::vector<uint8_t> buffer = writeToBuffer(original);
         BufferReader reader(buffer.data());
-        auto copied = FontCollection::readVector<readFreeTypeMinikinFontForTest>(&reader);
+        auto copied = FontCollection::readVector(&reader);
         EXPECT_EQ(2u, copied.size());
-        EXPECT_EQ(copied[0]->mFamilies[0], copied[1]->mFamilies[0]);
+        EXPECT_EQ(copied[0]->getFamilyAt(0), copied[1]->getFamilyAt(0));
         std::vector<uint8_t> newBuffer = writeToBuffer(copied);
         EXPECT_EQ(buffer, newBuffer);
     }
@@ -223,12 +238,12 @@
                 {buildFontCollection(kMultiAxisFont)});
         std::vector<uint8_t> buffer = writeToBuffer(original);
         BufferReader reader(buffer.data());
-        auto copied = FontCollection::readVector<readFreeTypeMinikinFontForTest>(&reader);
+        auto copied = FontCollection::readVector(&reader);
         EXPECT_EQ(1u, copied.size());
-        EXPECT_EQ(1u,
-                  copied[0]->getSupportedTags().count(MinikinFont::MakeTag('w', 'd', 't', 'h')));
-        EXPECT_EQ(1u,
-                  copied[0]->getSupportedTags().count(MinikinFont::MakeTag('w', 'g', 'h', 't')));
+        ASSERT_EQ(2u, copied[0]->getSupportedAxesCount());
+        // mSupportedAxes must be sorted.
+        EXPECT_EQ(MinikinFont::MakeTag('w', 'd', 't', 'h'), copied[0]->getSupportedAxisAt(0));
+        EXPECT_EQ(MinikinFont::MakeTag('w', 'g', 'h', 't'), copied[0]->getSupportedAxisAt(1));
         std::vector<uint8_t> newBuffer = writeToBuffer(copied);
         EXPECT_EQ(buffer, newBuffer);
     }
diff --git a/tests/unittest/FontFamilyTest.cpp b/tests/unittest/FontFamilyTest.cpp
index ce710f3..3230c27 100644
--- a/tests/unittest/FontFamilyTest.cpp
+++ b/tests/unittest/FontFamilyTest.cpp
@@ -14,17 +14,16 @@
  * limitations under the License.
  */
 
-#include "minikin/FontFamily.h"
-
 #include <gtest/gtest.h>
-
-#include "minikin/LocaleList.h"
+#include <malloc.h>
 
 #include "BufferUtils.h"
 #include "FontTestUtils.h"
 #include "FreeTypeMinikinFontForTest.h"
 #include "LocaleListCache.h"
 #include "MinikinInternal.h"
+#include "minikin/FontFamily.h"
+#include "minikin/LocaleList.h"
 
 namespace minikin {
 
@@ -801,8 +800,8 @@
             fonts.push_back(Font::Builder(dummyFont).setStyle(familyStyle).build());
         }
 
-        FontFamily family(std::move(fonts));
-        FakedFont closest = family.getClosestMatch(testCase.wantedStyle);
+        std::shared_ptr<FontFamily> family = FontFamily::create(std::move(fonts));
+        FakedFont closest = family->getClosestMatch(testCase.wantedStyle);
 
         size_t idx = dummyFonts.size();
         for (size_t i = 0; i < dummyFonts.size(); i++) {
@@ -821,41 +820,57 @@
     }
 }
 
+std::vector<uint8_t> writeToBuffer(const std::vector<std::shared_ptr<FontFamily>>& families) {
+    BufferWriter fakeWriter(nullptr);
+    FontFamily::writeVector(&fakeWriter, families);
+    std::vector<uint8_t> buffer(fakeWriter.size());
+    BufferWriter writer(buffer.data());
+    FontFamily::writeVector(&writer, families);
+    return buffer;
+}
+
+void expectFontFamilyEquals(const std::shared_ptr<FontFamily>& expected,
+                            const std::shared_ptr<FontFamily>& actual) {
+    ASSERT_EQ(expected->localeListId(), actual->localeListId());
+    ASSERT_EQ(expected->variant(), actual->variant());
+    ASSERT_EQ(expected->getNumFonts(), actual->getNumFonts());
+    ASSERT_EQ(expected->getSupportedAxesCount(), actual->getSupportedAxesCount());
+    for (size_t i = 0; i < expected->getSupportedAxesCount(); i++) {
+        ASSERT_EQ(expected->getSupportedAxisAt(i), actual->getSupportedAxisAt(i));
+    }
+    ASSERT_EQ(expected->isColorEmojiFamily(), actual->isColorEmojiFamily());
+    ASSERT_EQ(expected->isCustomFallback(), actual->isCustomFallback());
+    ASSERT_EQ(expected->hasVSTable(), actual->hasVSTable());
+}
+
+size_t getHeapSize() {
+    struct mallinfo info = mallinfo();
+    return info.uordblks;
+}
+
 TEST_F(FontFamilyTest, bufferTest) {
+    FreeTypeMinikinFontForTestFactory::init();
+    size_t baseHeapSize = getHeapSize();
     {
-        // Font with variation selectors
-        std::shared_ptr<FontFamily> original = buildFontFamily(kVsTestFont);
-        std::vector<uint8_t> buffer =
-                writeToBuffer<FontFamily, writeFreeTypeMinikinFontForTest>(*original);
-        BufferReader reader(buffer.data());
-        std::shared_ptr<FontFamily> copied =
-                FontFamily::readFrom<readFreeTypeMinikinFontForTest>(&reader);
-        ASSERT_EQ(original->localeListId(), copied->localeListId());
-        ASSERT_EQ(original->variant(), copied->variant());
-        ASSERT_EQ(original->getNumFonts(), copied->getNumFonts());
-        ASSERT_EQ(original->supportedAxes(), copied->supportedAxes());
-        ASSERT_EQ(original->isColorEmojiFamily(), copied->isColorEmojiFamily());
-        ASSERT_EQ(original->isCustomFallback(), copied->isCustomFallback());
-        ASSERT_EQ(original->hasVSTable(), copied->hasVSTable());
-        expectVSGlyphsForVsTestFont(copied.get());
-        std::vector<uint8_t> newBuffer =
-                writeToBuffer<FontFamily, writeFreeTypeMinikinFontForTest>(*copied);
-        ASSERT_EQ(buffer, newBuffer);
-    }
-    {
-        // Font with axes
         constexpr char kMultiAxisFont[] = "MultiAxis.ttf";
-        std::shared_ptr<FontFamily> original = buildFontFamily(kMultiAxisFont);
-        std::vector<uint8_t> buffer =
-                writeToBuffer<FontFamily, writeFreeTypeMinikinFontForTest>(*original);
+        std::vector<std::shared_ptr<FontFamily>> original = {
+                // Font with variation selectors
+                buildFontFamily(kVsTestFont),
+                // Font with axes
+                buildFontFamily(kMultiAxisFont),
+        };
+        std::vector<uint8_t> buffer = writeToBuffer(original);
         BufferReader reader(buffer.data());
-        std::shared_ptr<FontFamily> copied =
-                FontFamily::readFrom<readFreeTypeMinikinFontForTest>(&reader);
-        ASSERT_EQ(original->supportedAxes(), copied->supportedAxes());
-        std::vector<uint8_t> newBuffer =
-                writeToBuffer<FontFamily, writeFreeTypeMinikinFontForTest>(*copied);
+        std::vector<std::shared_ptr<FontFamily>> copied = FontFamily::readVector(&reader);
+        ASSERT_EQ(2u, copied.size());
+        expectFontFamilyEquals(original[0], copied[0]);
+        expectVSGlyphsForVsTestFont(copied[0].get());
+        expectFontFamilyEquals(original[1], copied[1]);
+        std::vector<uint8_t> newBuffer = writeToBuffer(copied);
         ASSERT_EQ(buffer, newBuffer);
     }
+    // Test that there is no leak after all FontFamily is destructed.
+    EXPECT_EQ(baseHeapSize, getHeapSize());
 }
 
 }  // namespace minikin
diff --git a/tests/unittest/FontTest.cpp b/tests/unittest/FontTest.cpp
index 68f5b51..b50ac90 100644
--- a/tests/unittest/FontTest.cpp
+++ b/tests/unittest/FontTest.cpp
@@ -24,19 +24,121 @@
 
 namespace minikin {
 
+namespace {
+
+size_t getHeapSize() {
+    struct mallinfo info = mallinfo();
+    return info.uordblks;
+}
+
+}  // namespace
+
 TEST(FontTest, BufferTest) {
+    FreeTypeMinikinFontForTestFactory::init();
     auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath("Ascii.ttf"));
     std::shared_ptr<Font> original = Font::Builder(minikinFont).build();
-    std::vector<uint8_t> buffer = writeToBuffer<Font, writeFreeTypeMinikinFontForTest>(*original);
+    std::vector<uint8_t> buffer = writeToBuffer<Font>(*original);
 
     BufferReader reader(buffer.data());
-    std::shared_ptr<Font> font =
-            Font::readFrom<readFreeTypeMinikinFontForTest>(&reader, kEmptyLocaleListId);
-    EXPECT_EQ(minikinFont->GetFontPath(), font->typeface()->GetFontPath());
-    EXPECT_EQ(original->style(), font->style());
-    EXPECT_NE(nullptr, font->baseFont());
-    std::vector<uint8_t> newBuffer = writeToBuffer<Font, writeFreeTypeMinikinFontForTest>(*font);
+    Font font(&reader);
+    EXPECT_EQ(minikinFont->GetFontPath(), font.typeface()->GetFontPath());
+    EXPECT_EQ(original->style(), font.style());
+    EXPECT_EQ(original->getLocaleListId(), font.getLocaleListId());
+    // baseFont() should return the same non-null instance when called twice.
+    const auto& baseFont = font.baseFont();
+    EXPECT_NE(nullptr, baseFont);
+    EXPECT_EQ(baseFont, font.baseFont());
+    // typeface() should return the same non-null instance when called twice.
+    const auto& typeface = font.typeface();
+    EXPECT_NE(nullptr, typeface);
+    EXPECT_EQ(typeface, font.typeface());
+    std::vector<uint8_t> newBuffer = writeToBuffer<Font>(font);
     EXPECT_EQ(buffer, newBuffer);
 }
 
+TEST(FontTest, MoveConstructorTest) {
+    FreeTypeMinikinFontForTestFactory::init();
+    // Note: by definition, only BufferReader-based Font can be moved.
+    auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath("Ascii.ttf"));
+    std::shared_ptr<Font> original = Font::Builder(minikinFont).build();
+    std::vector<uint8_t> buffer = writeToBuffer<Font>(*original);
+
+    size_t baseHeapSize = getHeapSize();
+    {
+        BufferReader reader(buffer.data());
+        Font moveFrom(&reader);
+        Font moveTo(std::move(moveFrom));
+        EXPECT_EQ(nullptr, moveFrom.mExternalRefsHolder.load());
+        EXPECT_EQ(nullptr, moveTo.mExternalRefsHolder.load());
+    }
+    EXPECT_EQ(baseHeapSize, getHeapSize());
+    {
+        BufferReader reader(buffer.data());
+        Font moveFrom(&reader);
+        std::shared_ptr<MinikinFont> typeface = moveFrom.typeface();
+        Font moveTo(std::move(moveFrom));
+        EXPECT_EQ(nullptr, moveFrom.mExternalRefsHolder.load());
+        EXPECT_EQ(typeface, moveTo.typeface());
+    }
+    EXPECT_EQ(baseHeapSize, getHeapSize());
+}
+
+TEST(FontTest, MoveAssignmentTest) {
+    FreeTypeMinikinFontForTestFactory::init();
+    // Note: by definition, only BufferReader-based Font can be moved.
+    auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath("Ascii.ttf"));
+    std::shared_ptr<Font> original = Font::Builder(minikinFont).build();
+    std::vector<uint8_t> buffer = writeToBuffer<Font>(*original);
+
+    size_t baseHeapSize = getHeapSize();
+    {
+        // mExternalRefsHolder: null -> null
+        BufferReader reader(buffer.data());
+        Font moveFrom(&reader);
+        BufferReader reader2(buffer.data());
+        Font moveTo(&reader2);
+        moveTo = std::move(moveFrom);
+        EXPECT_EQ(nullptr, moveFrom.mExternalRefsHolder.load());
+        EXPECT_EQ(nullptr, moveTo.mExternalRefsHolder.load());
+    }
+    EXPECT_EQ(baseHeapSize, getHeapSize());
+    {
+        // mExternalRefsHolder: non-null -> null
+        BufferReader reader(buffer.data());
+        Font moveFrom(&reader);
+        std::shared_ptr<MinikinFont> typeface = moveFrom.typeface();
+        BufferReader reader2(buffer.data());
+        Font moveTo(&reader2);
+        moveTo = std::move(moveFrom);
+        EXPECT_EQ(nullptr, moveFrom.mExternalRefsHolder.load());
+        EXPECT_EQ(typeface, moveTo.typeface());
+    }
+    EXPECT_EQ(baseHeapSize, getHeapSize());
+    {
+        // mExternalRefsHolder: null -> non-null
+        BufferReader reader(buffer.data());
+        Font moveFrom(&reader);
+        BufferReader reader2(buffer.data());
+        Font moveTo(&reader2);
+        moveTo.typeface();
+        moveTo = std::move(moveFrom);
+        EXPECT_EQ(nullptr, moveFrom.mExternalRefsHolder.load());
+        EXPECT_EQ(nullptr, moveTo.mExternalRefsHolder.load());
+    }
+    EXPECT_EQ(baseHeapSize, getHeapSize());
+    {
+        // mExternalRefsHolder: non-null -> non-null
+        BufferReader reader(buffer.data());
+        Font moveFrom(&reader);
+        std::shared_ptr<MinikinFont> typeface = moveFrom.typeface();
+        BufferReader reader2(buffer.data());
+        Font moveTo(&reader2);
+        moveTo.typeface();
+        moveTo = std::move(moveFrom);
+        EXPECT_EQ(nullptr, moveFrom.mExternalRefsHolder.load());
+        EXPECT_EQ(typeface, moveTo.typeface());
+    }
+    EXPECT_EQ(baseHeapSize, getHeapSize());
+}
+
 }  // namespace minikin
diff --git a/tests/unittest/GreedyLineBreakerTest.cpp b/tests/unittest/GreedyLineBreakerTest.cpp
index 3c395f4..e51ff83 100644
--- a/tests/unittest/GreedyLineBreakerTest.cpp
+++ b/tests/unittest/GreedyLineBreakerTest.cpp
@@ -75,7 +75,7 @@
         auto family1 = buildFontFamily("Ascii.ttf");
         auto family2 = buildFontFamily("CustomExtent.ttf");
         std::vector<std::shared_ptr<FontFamily>> families = {family1, family2};
-        auto fc = std::make_shared<FontCollection>(families);
+        auto fc = FontCollection::create(families);
         MinikinPaint paint(fc);
         paint.size = 10.0f;  // Make 1em=10px
         paint.localeListId = LocaleListCache::getId(lang);
@@ -98,7 +98,7 @@
     MeasuredTextBuilder builder;
     auto family1 = buildFontFamily("Ascii.ttf");
     std::vector<std::shared_ptr<FontFamily>> families = {family1};
-    auto fc = std::make_shared<FontCollection>(families);
+    auto fc = FontCollection::create(families);
     MinikinPaint paint(fc);
     paint.size = 56.0f;  // Make 1em=56px
     paint.scaleX = 1;
diff --git a/tests/unittest/LayoutCoreTest.cpp b/tests/unittest/LayoutCoreTest.cpp
index 2ab7543..4edc556 100644
--- a/tests/unittest/LayoutCoreTest.cpp
+++ b/tests/unittest/LayoutCoreTest.cpp
@@ -33,30 +33,29 @@
                        StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
 }
 
-static LayoutPiece buildLayout(const std::string& text, const std::vector<std::string>& fonts) {
-    std::vector<std::shared_ptr<FontFamily>> families;
-    for (const auto& fontPath : fonts) {
-        families.push_back(buildFontFamily(fontPath));
-    }
-    auto fc = std::make_shared<FontCollection>(families);
+static LayoutPiece buildLayout(const std::string& text, std::shared_ptr<FontCollection> fc) {
     MinikinPaint paint(fc);
     paint.size = 10.0f;  // make 1em = 10px
     return buildLayout(text, paint);
 }
 
-static LayoutPiece buildLayout(const std::string& text, const std::vector<std::string>& fonts,
+static LayoutPiece buildLayout(const std::string& text, std::shared_ptr<FontCollection> fc,
                                const std::string fontFeaturesSettings) {
-    std::vector<std::shared_ptr<FontFamily>> families;
-    for (const auto& fontPath : fonts) {
-        families.push_back(buildFontFamily(fontPath));
-    }
-    auto fc = std::make_shared<FontCollection>(families);
     MinikinPaint paint(fc);
     paint.size = 10.0f;  // make 1em = 10px
     paint.fontFeatureSettings = fontFeaturesSettings;
     return buildLayout(text, paint);
 }
 
+static std::shared_ptr<FontCollection> makeFontCollection(
+        std::initializer_list<std::string> fonts) {
+    std::vector<std::shared_ptr<FontFamily>> families;
+    for (const auto& fontPath : fonts) {
+        families.push_back(buildFontFamily(fontPath));
+    }
+    return FontCollection::create(families);
+}
+
 TEST(LayoutPieceTest, doLayoutTest) {
     // The LayoutTestFont.ttf has following coverage, extent, width and bbox.
     // Ascender: 10em, Descender: -2em
@@ -71,7 +70,8 @@
     // U+FFFD (invalid surrogate will be replaced to this): 7em, (0, 0) - (7, 7)
     // U+10331 (\uD800\uDF31): 10em, (0, 0) - (10, 10)
     {
-        auto layout = buildLayout("I", {"LayoutTestFont.ttf"});
+        auto fc = makeFontCollection({"LayoutTestFont.ttf"});
+        auto layout = buildLayout("I", fc);
         EXPECT_EQ(1u, layout.glyphCount());
         EXPECT_EQ(Point(0, 0), layout.pointAt(0));
         EXPECT_EQ(MinikinExtent(-100.0f, 20.0f), layout.extent());
@@ -82,7 +82,8 @@
         EXPECT_EQ(10.0f, layout.advance());
     }
     {
-        auto layout = buildLayout("II", {"LayoutTestFont.ttf"});
+        auto fc = makeFontCollection({"LayoutTestFont.ttf"});
+        auto layout = buildLayout("II", fc);
         EXPECT_EQ(2u, layout.glyphCount());
         EXPECT_EQ(Point(0, 0), layout.pointAt(0));
         EXPECT_EQ(Point(10.0f, 0), layout.pointAt(1));
@@ -97,7 +98,8 @@
         EXPECT_EQ(20.0f, layout.advance());
     }
     {
-        auto layout = buildLayout("IV", {"LayoutTestFont.ttf"});
+        auto fc = makeFontCollection({"LayoutTestFont.ttf"});
+        auto layout = buildLayout("IV", fc);
         EXPECT_EQ(2u, layout.glyphCount());
         EXPECT_EQ(Point(0, 0), layout.pointAt(0));
         EXPECT_EQ(Point(10.0f, 0), layout.pointAt(1));
@@ -123,7 +125,8 @@
     // U+3048: 2em, (0, 0) - (2, 2)
     // U+304A: 2em, (0, 0) - (2, 2)
     {
-        auto layout = buildLayout("I\u3042", {"LayoutTestFont.ttf", "Hiragana.ttf"});
+        auto fc = makeFontCollection({"LayoutTestFont.ttf", "Hiragana.ttf"});
+        auto layout = buildLayout("I\u3042", fc);
         EXPECT_EQ(2u, layout.glyphCount());
         EXPECT_EQ(Point(0, 0), layout.pointAt(0));
         EXPECT_EQ(Point(10.0f, 0), layout.pointAt(1));
@@ -138,7 +141,8 @@
         EXPECT_EQ(30.0f, layout.advance());
     }
     {
-        auto layout = buildLayout("\u3042I", {"LayoutTestFont.ttf", "Hiragana.ttf"});
+        auto fc = makeFontCollection({"LayoutTestFont.ttf", "Hiragana.ttf"});
+        auto layout = buildLayout("\u3042I", fc);
         EXPECT_EQ(2u, layout.glyphCount());
         EXPECT_EQ(Point(0, 0), layout.pointAt(0));
         EXPECT_EQ(Point(20.0f, 0), layout.pointAt(1));
@@ -160,7 +164,8 @@
     // U+0020..U+007E: 1em, (0, 0) - (1, 1)
     // Also this has ligature entry for fi as "ccmp" feature, ff as "liga" feature.
     {
-        auto layout = buildLayout("fi", {"Ligature.ttf"});
+        auto fc = makeFontCollection({"Ligature.ttf"});
+        auto layout = buildLayout("fi", fc);
         EXPECT_EQ(1u, layout.glyphCount());
         EXPECT_EQ(Point(0, 0), layout.pointAt(0));
         EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
@@ -172,7 +177,8 @@
         EXPECT_EQ(10.0f, layout.advance());
     }
     {
-        auto layout = buildLayout("ff", {"Ligature.ttf"});
+        auto fc = makeFontCollection({"Ligature.ttf"});
+        auto layout = buildLayout("ff", fc);
         EXPECT_EQ(1u, layout.glyphCount());
         EXPECT_EQ(Point(0, 0), layout.pointAt(0));
         EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
@@ -184,7 +190,8 @@
         EXPECT_EQ(10.0f, layout.advance());
     }
     {
-        auto layout = buildLayout("fi", {"Ligature.ttf"}, "'liga' off");
+        auto fc = makeFontCollection({"Ligature.ttf"});
+        auto layout = buildLayout("fi", fc, "'liga' off");
         EXPECT_EQ(1u, layout.glyphCount());
         EXPECT_EQ(Point(0, 0), layout.pointAt(0));
         EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
@@ -196,7 +203,8 @@
         EXPECT_EQ(10.0f, layout.advance());
     }
     {
-        auto layout = buildLayout("ff", {"Ligature.ttf"}, "'liga' off");
+        auto fc = makeFontCollection({"Ligature.ttf"});
+        auto layout = buildLayout("ff", fc, "'liga' off");
         EXPECT_EQ(2u, layout.glyphCount());
         EXPECT_EQ(Point(0, 0), layout.pointAt(0));
         EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
@@ -210,7 +218,8 @@
         EXPECT_EQ(20.0f, layout.advance());
     }
     {
-        auto layout = buildLayout("fii", {"Ligature.ttf"});
+        auto fc = makeFontCollection({"Ligature.ttf"});
+        auto layout = buildLayout("fii", fc);
         EXPECT_EQ(2u, layout.glyphCount());
         EXPECT_EQ(Point(0, 0), layout.pointAt(0));
         EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
@@ -225,7 +234,8 @@
         EXPECT_EQ(20.0f, layout.advance());
     }
     {
-        auto layout = buildLayout("if", {"Ligature.ttf"});
+        auto fc = makeFontCollection({"Ligature.ttf"});
+        auto layout = buildLayout("if", fc);
         EXPECT_EQ(2u, layout.glyphCount());
         EXPECT_EQ(Point(0, 0), layout.pointAt(0));
         EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
diff --git a/tests/unittest/MeasurementTests.cpp b/tests/unittest/MeasurementTests.cpp
index b5a85c7..ff36f67 100644
--- a/tests/unittest/MeasurementTests.cpp
+++ b/tests/unittest/MeasurementTests.cpp
@@ -31,6 +31,15 @@
     return getRunAdvance(advances, buf, 0, size, offset);
 }
 
+void distributeAdvances(float* advances, const char* src, int count) {
+    const size_t BUF_SIZE = 256;
+    uint16_t buf[BUF_SIZE];
+    size_t offset;
+    size_t size;
+    ParseUnicode(buf, BUF_SIZE, src, &size, &offset);
+    distributeAdvances(advances, buf, offset, count);
+}
+
 // Latin fi
 TEST(Measurement, getRunAdvance_fi) {
     const float unligated[] = {30.0, 20.0};
@@ -44,6 +53,22 @@
     EXPECT_EQ(40.0, getAdvance(ligated, "'f' 'i' |"));
 }
 
+TEST(Measurement, getRunAdvance_control_characters) {
+    const float unligated[] = {30.0, 20.0, 0.0, 0.0};
+    EXPECT_EQ(0.0, getAdvance(unligated, "| 'f' 'i' U+2066 U+202C"));
+    EXPECT_EQ(30.0, getAdvance(unligated, "'f' | 'i' U+2066 U+202C"));
+    EXPECT_EQ(50.0, getAdvance(unligated, "'f' 'i' | U+2066 U+202C"));
+    EXPECT_EQ(50.0, getAdvance(unligated, "'f' 'i' U+2066 | U+202C"));
+    EXPECT_EQ(50.0, getAdvance(unligated, "'f' 'i' U+2066 U+202C |"));
+
+    const float liagated[] = {40.0, 0.0, 0.0, 0.0};
+    EXPECT_EQ(0.0, getAdvance(liagated, "| 'f' 'i' U+2066 U+202C"));
+    EXPECT_EQ(20.0, getAdvance(liagated, "'f' | 'i' U+2066 U+202C"));
+    EXPECT_EQ(40.0, getAdvance(liagated, "'f' 'i' | U+2066 U+202C"));
+    EXPECT_EQ(40.0, getAdvance(liagated, "'f' 'i' U+2066 | U+202C"));
+    EXPECT_EQ(40.0, getAdvance(liagated, "'f' 'i' U+2066 U+202C |"));
+}
+
 // Devanagari ka+virama+ka
 TEST(Measurement, getRunAdvance_kka) {
     const float unligated[] = {30.0, 0.0, 30.0};
@@ -59,4 +84,69 @@
     EXPECT_EQ(30.0, getAdvance(ligated, "U+0915 U+094D U+0915 |"));
 }
 
+TEST(Measurement, distributeAdvances_fi) {
+    float ligated[] = {20.0, 0.0};
+    distributeAdvances(ligated, "| 'f' 'i' ", 2);
+    EXPECT_EQ(ligated[0], 10.0);
+    EXPECT_EQ(ligated[1], 10.0);
+}
+
+TEST(Measurement, distributeAdvances_non_zero_start) {
+    // Note that advance[i] corresponding to (i + start)-th character.
+    float ligated[] = {20.0, 0.0};
+    distributeAdvances(ligated, "'a' 'b' | 'f' 'i' ", 2);
+    EXPECT_EQ(ligated[0], 10.0);
+    EXPECT_EQ(ligated[1], 10.0);
+}
+
+TEST(Measurement, distributeAdvances_non_zero_start_with_control_characters) {
+    // Note that advance[i] corresponding to (i + start)-th character.
+    float ligated[] = {20.0, 0.0, 0.0, 0.0};
+    distributeAdvances(ligated, "'a' U+2066 | 'f' 'i' U+2066 U+202C", 4);
+    EXPECT_EQ(ligated[0], 10.0);
+    EXPECT_EQ(ligated[1], 10.0);
+    EXPECT_EQ(ligated[2], 0.0);
+    EXPECT_EQ(ligated[3], 0.0);
+}
+
+TEST(Measurement, distributeAdvances_with_count) {
+    // Note that advance[i] corresponding to (i + start)-th character.
+    float ligated[] = {20.0, 0.0, 30.0, 0.0};
+    distributeAdvances(ligated, "'a' 'b' | 'f' 'i' 'f' 'i' ", 2);
+    EXPECT_EQ(ligated[0], 10.0);
+    EXPECT_EQ(ligated[1], 10.0);
+    // Count is 2, so it won't change the rest of the array.
+    EXPECT_EQ(ligated[2], 30.0);
+    EXPECT_EQ(ligated[3], 0.0);
+}
+
+TEST(Measurement, distributeAdvances_control_characters) {
+    float ligated[] = {20.0, 0.0, 0.0, 0.0};
+    distributeAdvances(ligated, "| 'f' 'i' U+2066 U+202C", 4);
+    EXPECT_EQ(ligated[0], 10.0);
+    EXPECT_EQ(ligated[1], 10.0);
+    EXPECT_EQ(ligated[2], 0.0);
+    EXPECT_EQ(ligated[3], 0.0);
+}
+
+TEST(Measurement, distributeAdvances_surrogate) {
+    float advances[] = {20.0, 0.0, 0.0, 0.0};
+    distributeAdvances(advances, "| U+D83D U+DE00 U+2066 U+202C", 4);
+    EXPECT_EQ(advances[0], 20.0);
+    EXPECT_EQ(advances[1], 0.0);
+    EXPECT_EQ(advances[2], 0.0);
+    EXPECT_EQ(advances[3], 0.0);
+}
+
+TEST(Measurement, distributeAdvances_surrogate_in_ligature) {
+    // If a ligature contains surrogates, advances is assigned to the first
+    // character in surrogate.
+    float ligated[] = {40.0, 0.0, 0.0, 0.0};
+    distributeAdvances(ligated, "| U+D83D U+DE00 U+D83D U+DE01", 4);
+    EXPECT_EQ(ligated[0], 20.0);
+    EXPECT_EQ(ligated[1], 0.0);
+    EXPECT_EQ(ligated[2], 20.0);
+    EXPECT_EQ(ligated[3], 0.0);
+}
+
 }  // namespace minikin
diff --git a/tests/unittest/OptimalLineBreakerTest.cpp b/tests/unittest/OptimalLineBreakerTest.cpp
index a5f8625..18619e3 100644
--- a/tests/unittest/OptimalLineBreakerTest.cpp
+++ b/tests/unittest/OptimalLineBreakerTest.cpp
@@ -71,7 +71,7 @@
         auto family1 = buildFontFamily("Ascii.ttf");
         auto family2 = buildFontFamily("CustomExtent.ttf");
         std::vector<std::shared_ptr<FontFamily>> families = {family1, family2};
-        auto fc = std::make_shared<FontCollection>(families);
+        auto fc = FontCollection::create(families);
         MinikinPaint paint(fc);
         paint.size = 10.0f;  // Make 1em=10px
         paint.localeListId = LocaleListCache::getId(lang);
@@ -1847,7 +1847,7 @@
     MeasuredTextBuilder builder;
     auto family1 = buildFontFamily("Ascii.ttf");
     std::vector<std::shared_ptr<FontFamily>> families = {family1};
-    auto fc = std::make_shared<FontCollection>(families);
+    auto fc = FontCollection::create(families);
     MinikinPaint paint(fc);
     paint.size = 56.0f;  // Make 1em=56px
     paint.scaleX = 1;
diff --git a/tests/unittest/SparseBitSetTest.cpp b/tests/unittest/SparseBitSetTest.cpp
index 8c67964..d79ebac 100644
--- a/tests/unittest/SparseBitSetTest.cpp
+++ b/tests/unittest/SparseBitSetTest.cpp
@@ -79,4 +79,8 @@
     ASSERT_EQ(buffer, newBuffer);
 }
 
+TEST(SparseBitSetTest, sizeTest) {
+    ASSERT_EQ(sizeof(void*), sizeof(SparseBitSet));
+}
+
 }  // namespace minikin
diff --git a/tests/unittest/SystemFontsTest.cpp b/tests/unittest/SystemFontsTest.cpp
index f1b0109..1bff31f 100644
--- a/tests/unittest/SystemFontsTest.cpp
+++ b/tests/unittest/SystemFontsTest.cpp
@@ -95,8 +95,8 @@
 
     auto fc1Families = std::vector<std::shared_ptr<FontFamily>>{asciiFamily, boldItalicFamily};
     auto fc2Families = std::vector<std::shared_ptr<FontFamily>>{boldFamily, boldItalicFamily};
-    auto fc1 = std::make_shared<FontCollection>(std::move(fc1Families));
-    auto fc2 = std::make_shared<FontCollection>(std::move(fc2Families));
+    auto fc1 = FontCollection::create(std::move(fc1Families));
+    auto fc2 = FontCollection::create(std::move(fc2Families));
 
     systemFonts.addFontMap(std::move(fc1));
     systemFonts.addFontMap(std::move(fc2));
diff --git a/tests/unittest/WordBreakerTests.cpp b/tests/unittest/WordBreakerTests.cpp
index 4b5fc35..0c20a80 100644
--- a/tests/unittest/WordBreakerTests.cpp
+++ b/tests/unittest/WordBreakerTests.cpp
@@ -19,8 +19,6 @@
 #include <cstdio>
 
 #include <gtest/gtest.h>
-#include <unicode/uclean.h>
-#include <unicode/udata.h>
 
 #include "UnicodeUtils.h"
 
diff --git a/tests/util/Android.bp b/tests/util/Android.bp
index 1d3d8cf..d8c153d 100644
--- a/tests/util/Android.bp
+++ b/tests/util/Android.bp
@@ -11,7 +11,7 @@
         "PathUtils.cpp",
         "UnicodeUtils.cpp",
     ],
-    cflags: ["-Wall", "-Werror"],
+    defaults: ["libminikin_defaults"],
     export_include_dirs: ["."],
     shared_libs: ["libxml2", "libft2"],
     static_libs: ["libminikin"],
diff --git a/tests/util/BufferUtils.h b/tests/util/BufferUtils.h
index 355e74e..015a939 100644
--- a/tests/util/BufferUtils.h
+++ b/tests/util/BufferUtils.h
@@ -46,14 +46,6 @@
     return buffer;
 }
 
-template <class T, auto arg>
-std::vector<uint8_t> writeToBuffer(const T& t) {
-    std::vector<uint8_t> buffer = allocateBuffer<T, arg>(t);
-    BufferWriter writer(buffer.data());
-    t.template writeTo<arg>(&writer);
-    return buffer;
-}
-
 }  // namespace minikin
 
 #endif  // MINIKIN_TEST_BUFFER_UTILS_H
diff --git a/tests/util/FontTestUtils.cpp b/tests/util/FontTestUtils.cpp
index 5370ab6..a1025fe 100644
--- a/tests/util/FontTestUtils.cpp
+++ b/tests/util/FontTestUtils.cpp
@@ -106,11 +106,12 @@
         xmlChar* lang = xmlGetProp(familyNode, (const xmlChar*)"lang");
         std::shared_ptr<FontFamily> family;
         if (lang == nullptr) {
-            family = std::make_shared<FontFamily>(variant, std::move(fonts));
+            family = FontFamily::create(variant, std::move(fonts));
         } else {
             uint32_t langId = registerLocaleList(std::string((const char*)lang, xmlStrlen(lang)));
-            family = std::make_shared<FontFamily>(langId, variant, std::move(fonts),
-                                                  false /* isCustomFallback */);
+            family =
+                    FontFamily::create(langId, variant, std::move(fonts),
+                                       false /* isCustomFallback */, false /* isdefaultFallback */);
         }
         families.push_back(family);
     }
@@ -119,14 +120,14 @@
 }
 
 std::shared_ptr<FontCollection> buildFontCollection(const std::string& filePath) {
-    return std::make_shared<FontCollection>(buildFontFamily(filePath));
+    return FontCollection::create(buildFontFamily(filePath));
 }
 
 std::shared_ptr<FontFamily> buildFontFamily(const std::string& filePath) {
     auto font = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(filePath));
     std::vector<std::shared_ptr<Font>> fonts;
     fonts.push_back(Font::Builder(font).build());
-    return std::make_shared<FontFamily>(std::move(fonts));
+    return FontFamily::create(std::move(fonts));
 }
 
 std::shared_ptr<FontFamily> buildFontFamily(const std::string& filePath, const std::string& lang,
@@ -134,8 +135,8 @@
     auto font = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(filePath));
     std::vector<std::shared_ptr<Font>> fonts;
     fonts.push_back(Font::Builder(font).build());
-    return std::make_shared<FontFamily>(LocaleListCache::getId(lang), FamilyVariant::DEFAULT,
-                                        std::move(fonts), isCustomFallback);
+    return FontFamily::create(LocaleListCache::getId(lang), FamilyVariant::DEFAULT,
+                              std::move(fonts), isCustomFallback, false /* isDefaultFallback */);
 }
 
 }  // namespace minikin
diff --git a/tests/util/FontTestUtils.h b/tests/util/FontTestUtils.h
index 660438b..63748e4 100644
--- a/tests/util/FontTestUtils.h
+++ b/tests/util/FontTestUtils.h
@@ -19,9 +19,8 @@
 
 #include <memory>
 
-#include "minikin/FontCollection.h"
-
 #include "PathUtils.h"
+#include "minikin/FontCollection.h"
 
 namespace minikin {
 
@@ -40,8 +39,7 @@
  * The XML path and font files are needed to be in the test data directory.
  */
 inline std::shared_ptr<FontCollection> buildFontCollectionFromXml(const std::string& xmlPath) {
-    return std::make_shared<FontCollection>(
-            getFontFamilies(getTestDataDir(), getTestDataDir() + xmlPath));
+    return FontCollection::create(getFontFamilies(getTestDataDir(), getTestDataDir() + xmlPath));
 }
 
 /**
diff --git a/tests/util/FreeTypeMinikinFontForTest.cpp b/tests/util/FreeTypeMinikinFontForTest.cpp
index 1be466a..ce36ec0 100644
--- a/tests/util/FreeTypeMinikinFontForTest.cpp
+++ b/tests/util/FreeTypeMinikinFontForTest.cpp
@@ -112,18 +112,27 @@
     extent->descent = -static_cast<float>(mFtFace->descender) * paint.size / upem;
 }
 
-void writeFreeTypeMinikinFontForTest(BufferWriter* writer, const MinikinFont* typeface) {
+FreeTypeMinikinFontForTestFactory::FreeTypeMinikinFontForTestFactory() : MinikinFontFactory() {
+    MinikinFontFactory::setInstance(this);
+}
+
+// static
+void FreeTypeMinikinFontForTestFactory::init() {
+    static FreeTypeMinikinFontForTestFactory factory;
+}
+
+void FreeTypeMinikinFontForTestFactory::write(BufferWriter* writer,
+                                              const MinikinFont* typeface) const {
     writer->writeString(typeface->GetFontPath());
 }
 
-std::shared_ptr<MinikinFont> loadFreeTypeMinikinFontForTest(BufferReader reader) {
+std::shared_ptr<MinikinFont> FreeTypeMinikinFontForTestFactory::create(BufferReader reader) const {
     std::string fontPath(reader.readString());
     return std::make_shared<FreeTypeMinikinFontForTest>(fontPath);
 }
 
-Font::TypefaceLoader* readFreeTypeMinikinFontForTest(BufferReader* reader) {
+void FreeTypeMinikinFontForTestFactory::skip(BufferReader* reader) const {
     reader->skipString();  // fontPath
-    return &loadFreeTypeMinikinFontForTest;
 }
 
 }  // namespace minikin
diff --git a/tests/util/FreeTypeMinikinFontForTest.h b/tests/util/FreeTypeMinikinFontForTest.h
index 4cdb6d8..6903deb 100644
--- a/tests/util/FreeTypeMinikinFontForTest.h
+++ b/tests/util/FreeTypeMinikinFontForTest.h
@@ -17,13 +17,14 @@
 #ifndef MINIKIN_TEST_FREE_TYPE_MINIKIN_FONT_FOR_TEST_H
 #define MINIKIN_TEST_FREE_TYPE_MINIKIN_FONT_FOR_TEST_H
 
+#include <ft2build.h>
+
 #include <string>
 
 #include "minikin/Buffer.h"
 #include "minikin/Font.h"
 #include "minikin/MinikinFont.h"
-
-#include <ft2build.h>
+#include "minikin/MinikinFontFactory.h"
 #include FT_FREETYPE_H
 
 #include "minikin/Macros.h"
@@ -64,9 +65,19 @@
     MINIKIN_PREVENT_COPY_AND_ASSIGN(FreeTypeMinikinFontForTest);
 };
 
-void writeFreeTypeMinikinFontForTest(BufferWriter* writer, const MinikinFont* typeface);
+class FreeTypeMinikinFontForTestFactory : MinikinFontFactory {
+private:
+    FreeTypeMinikinFontForTestFactory();
 
-Font::TypefaceLoader* readFreeTypeMinikinFontForTest(BufferReader* reader);
+public:
+    static void init();
+
+    void write(BufferWriter* writer, const MinikinFont* typeface) const override;
+
+    std::shared_ptr<MinikinFont> create(BufferReader reader) const override;
+
+    void skip(BufferReader* reader) const override;
+};
 
 }  // namespace minikin
 
diff --git a/tools/mk_hyb_file.py b/tools/mk_hyb_file.py
index 89949f9..d213bc9 100755
--- a/tools/mk_hyb_file.py
+++ b/tools/mk_hyb_file.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 # Copyright (C) 2015 The Android Open Source Project
 #
@@ -563,6 +563,14 @@
       reconstructed_chr.remove(u'\u03B0')
       reconstructed_chr.append(u'\u03B0\u03B0')
 
+    if u'\u1c86' in reconstructed_chr:
+      reconstructed_chr.remove(u'\u1c86')
+      reconstructed_chr.append(u'\u1c86\u1c86')
+
+    if u'\u1c82' in reconstructed_chr:
+      reconstructed_chr.remove(u'\u1c82')
+      reconstructed_chr.append(u'\u1c82\u1c82')
+
     assert verify_file_sorted(reconstructed_chr, chr_fn), 'alphabet table not verified'
 
     # reconstruct trie