Revert "Make some thread-unsafe functions thread-safe in Layout.cpp"

Reverting since the parent CL had a regression.

This reverts commit ed05ce7cf4a99c0db17a322c56850de90062bfdb.

Bug: 73054061
Change-Id: I227b3148b663d62743d9e373e2d5521d36df9199
(cherry picked from commit ca2f1bb67836d5d12b5bc819518b8a3b7df4e5af)
diff --git a/include/minikin/HbUtils.h b/include/minikin/HbUtils.h
index 68e4ab8..1cf375d 100644
--- a/include/minikin/HbUtils.h
+++ b/include/minikin/HbUtils.h
@@ -33,15 +33,9 @@
 struct HbFontDeleter {
     void operator()(hb_font_t* v) { hb_font_destroy(v); }
 };
-
-struct HbBufferDeleter {
-    void operator()(hb_buffer_t* v) { hb_buffer_destroy(v); }
-};
-
 using HbBlobUniquePtr = std::unique_ptr<hb_blob_t, HbBlobDeleter>;
 using HbFaceUniquePtr = std::unique_ptr<hb_face_t, HbFaceDeleter>;
 using HbFontUniquePtr = std::unique_ptr<hb_font_t, HbFontDeleter>;
-using HbBufferUniquePtr = std::unique_ptr<hb_buffer_t, HbBufferDeleter>;
 
 }  // namespace minikin
 
diff --git a/libs/minikin/Layout.cpp b/libs/minikin/Layout.cpp
index c9ffd0f..1a413f8 100644
--- a/libs/minikin/Layout.cpp
+++ b/libs/minikin/Layout.cpp
@@ -30,6 +30,7 @@
 #include <unicode/utf16.h>
 #include <utils/JenkinsHash.h>
 #include <utils/LruCache.h>
+#include <utils/Singleton.h>
 
 #include "minikin/Emoji.h"
 #include "minikin/HbUtils.h"
@@ -48,70 +49,6 @@
     FontFakery fakery;
 };
 
-static hb_position_t harfbuzzGetGlyphHorizontalAdvance(hb_font_t* /* hbFont */, void* fontData,
-                                                       hb_codepoint_t glyph, void* /* userData */) {
-    SkiaArguments* args = reinterpret_cast<SkiaArguments*>(fontData);
-    float advance = args->font->GetHorizontalAdvance(glyph, *args->paint, args->fakery);
-    return 256 * advance + 0.5;
-}
-
-static hb_bool_t harfbuzzGetGlyphHorizontalOrigin(hb_font_t* /* hbFont */, void* /* fontData */,
-                                                  hb_codepoint_t /* glyph */,
-                                                  hb_position_t* /* x */, hb_position_t* /* y */,
-                                                  void* /* userData */) {
-    // Just return true, following the way that Harfbuzz-FreeType implementation does.
-    return true;
-}
-
-// TODO: Initialize in Zygote if it helps.
-hb_unicode_funcs_t* getUnicodeFunctions() {
-    static hb_unicode_funcs_t* unicodeFunctions = nullptr;
-    static std::once_flag once;
-    std::call_once(once, [&]() {
-        unicodeFunctions = hb_unicode_funcs_create(hb_icu_get_unicode_funcs());
-        /* Disable the function used for compatibility decomposition */
-        hb_unicode_funcs_set_decompose_compatibility_func(
-                unicodeFunctions,
-                [](hb_unicode_funcs_t*, hb_codepoint_t, hb_codepoint_t*, void*) -> unsigned int {
-                    return 0;
-                },
-                nullptr, nullptr);
-    });
-    return unicodeFunctions;
-}
-
-// TODO: Initialize in Zygote if it helps.
-hb_font_funcs_t* getFontFuncs() {
-    static hb_font_funcs_t* fontFuncs = nullptr;
-    static std::once_flag once;
-    std::call_once(once, [&]() {
-        fontFuncs = hb_font_funcs_create();
-        // Override the h_advance function since we can't use HarfBuzz's implemenation. It may
-        // return the wrong value if the font uses hinting aggressively.
-        hb_font_funcs_set_glyph_h_advance_func(fontFuncs, harfbuzzGetGlyphHorizontalAdvance, 0, 0);
-        hb_font_funcs_set_glyph_h_origin_func(fontFuncs, harfbuzzGetGlyphHorizontalOrigin, 0, 0);
-        hb_font_funcs_make_immutable(fontFuncs);
-    });
-    return fontFuncs;
-}
-
-// TODO: Initialize in Zygote if it helps.
-hb_font_funcs_t* getFontFuncsForEmoji() {
-    static hb_font_funcs_t* fontFuncs = nullptr;
-    static std::once_flag once;
-    std::call_once(once, [&]() {
-        fontFuncs = hb_font_funcs_create();
-        // Don't override the h_advance function since we use HarfBuzz's implementation for emoji
-        // for performance reasons.
-        // Note that it is technically possible for a TrueType font to have outline and embedded
-        // bitmap at the same time. We ignore modified advances of hinted outline glyphs in that
-        // case.
-        hb_font_funcs_set_glyph_h_origin_func(fontFuncs, harfbuzzGetGlyphHorizontalOrigin, 0, 0);
-        hb_font_funcs_make_immutable(fontFuncs);
-    });
-    return fontFuncs;
-}
-
 }  // namespace
 
 static inline UBiDiLevel bidiToUBidiLevel(Bidi bidi) {
@@ -236,11 +173,6 @@
         dprintf(fd, "  Hit ratio: %d/%d (%f)\n", mCacheHitCount, mRequestCount, ratio);
     }
 
-    static LayoutCache& getInstance() {
-        static LayoutCache cache;
-        return cache;
-    }
-
 private:
     // callback for OnEntryRemoved
     void operator()(LayoutCacheKey& key, Layout*& value) {
@@ -260,6 +192,27 @@
     static const size_t kMaxEntries = 5000;
 };
 
+static unsigned int disabledDecomposeCompatibility(hb_unicode_funcs_t*, hb_codepoint_t,
+                                                   hb_codepoint_t*, void*) {
+    return 0;
+}
+
+class LayoutEngine : public ::android::Singleton<LayoutEngine> {
+public:
+    LayoutEngine() {
+        unicodeFunctions = hb_unicode_funcs_create(hb_icu_get_unicode_funcs());
+        /* Disable the function used for compatibility decomposition */
+        hb_unicode_funcs_set_decompose_compatibility_func(
+                unicodeFunctions, disabledDecomposeCompatibility, NULL, NULL);
+        hbBuffer = hb_buffer_create();
+        hb_buffer_set_unicode_funcs(hbBuffer, unicodeFunctions);
+    }
+
+    hb_buffer_t* hbBuffer;
+    hb_unicode_funcs_t* unicodeFunctions;
+    LayoutCache layoutCache;
+};
+
 bool LayoutCacheKey::operator==(const LayoutCacheKey& other) const {
     return mId == other.mId && mStart == other.mStart && mCount == other.mCount &&
            mStyle == other.mStyle && mSize == other.mSize && mScaleX == other.mScaleX &&
@@ -314,6 +267,48 @@
     mAdvance = 0;
 }
 
+static hb_position_t harfbuzzGetGlyphHorizontalAdvance(hb_font_t* /* hbFont */, void* fontData,
+                                                       hb_codepoint_t glyph, void* /* userData */) {
+    SkiaArguments* args = reinterpret_cast<SkiaArguments*>(fontData);
+    float advance = args->font->GetHorizontalAdvance(glyph, *args->paint, args->fakery);
+    return 256 * advance + 0.5;
+}
+
+static hb_bool_t harfbuzzGetGlyphHorizontalOrigin(hb_font_t* /* hbFont */, void* /* fontData */,
+                                                  hb_codepoint_t /* glyph */,
+                                                  hb_position_t* /* x */, hb_position_t* /* y */,
+                                                  void* /* userData */) {
+    // Just return true, following the way that Harfbuzz-FreeType
+    // implementation does.
+    return true;
+}
+
+hb_font_funcs_t* getHbFontFuncs(bool forColorBitmapFont) {
+    assertMinikinLocked();
+
+    static hb_font_funcs_t* hbFuncs = nullptr;
+    static hb_font_funcs_t* hbFuncsForColorBitmap = nullptr;
+
+    hb_font_funcs_t** funcs = forColorBitmapFont ? &hbFuncs : &hbFuncsForColorBitmap;
+    if (*funcs == nullptr) {
+        *funcs = hb_font_funcs_create();
+        if (forColorBitmapFont) {
+            // Don't override the h_advance function since we use HarfBuzz's implementation for
+            // emoji for performance reasons.
+            // Note that it is technically possible for a TrueType font to have outline and embedded
+            // bitmap at the same time. We ignore modified advances of hinted outline glyphs in that
+            // case.
+        } else {
+            // Override the h_advance function since we can't use HarfBuzz's implemenation. It may
+            // return the wrong value if the font uses hinting aggressively.
+            hb_font_funcs_set_glyph_h_advance_func(*funcs, harfbuzzGetGlyphHorizontalAdvance, 0, 0);
+        }
+        hb_font_funcs_set_glyph_h_origin_func(*funcs, harfbuzzGetGlyphHorizontalOrigin, 0, 0);
+        hb_font_funcs_make_immutable(*funcs);
+    }
+    return *funcs;
+}
+
 static bool isColorBitmapFont(const HbFontUniquePtr& font) {
     HbBlob cbdt(font, HB_TAG('C', 'B', 'D', 'T'));
     return cbdt;
@@ -350,7 +345,7 @@
         // Create new hb_font_t from base font.
         HbFontUniquePtr font(hb_font_create_sub_font(face.font->baseFont().get()));
         hb_font_set_funcs(
-                font.get(), isColorBitmapFont(font) ? getFontFuncsForEmoji() : getFontFuncs(),
+                font.get(), getHbFontFuncs(isColorBitmapFont(font)),
                 new SkiaArguments({face.font->typeface().get(), &ctx->paint, face.fakery}),
                 [](void* data) { delete reinterpret_cast<SkiaArguments*>(data); });
         ctx->hbFonts.push_back(std::move(font));
@@ -358,6 +353,14 @@
     return ix;
 }
 
+static hb_script_t codePointToScript(hb_codepoint_t codepoint) {
+    static hb_unicode_funcs_t* u = 0;
+    if (!u) {
+        u = LayoutEngine::getInstance().unicodeFunctions;
+    }
+    return hb_unicode_script(u, codepoint);
+}
+
 static hb_codepoint_t decodeUtf16(const uint16_t* chars, size_t len, ssize_t* iter) {
     UChar32 result;
     U16_NEXT(chars, *iter, (ssize_t)len, result);
@@ -372,12 +375,12 @@
         return HB_SCRIPT_UNKNOWN;
     }
     uint32_t cp = decodeUtf16(chars, len, iter);
-    hb_script_t current_script = hb_unicode_script(getUnicodeFunctions(), cp);
+    hb_script_t current_script = codePointToScript(cp);
     for (;;) {
         if (size_t(*iter) == len) break;
         const ssize_t prev_iter = *iter;
         cp = decodeUtf16(chars, len, iter);
-        const hb_script_t script = hb_unicode_script(getUnicodeFunctions(), cp);
+        const hb_script_t script = codePointToScript(cp);
         if (script != current_script) {
             if (current_script == HB_SCRIPT_INHERITED || current_script == HB_SCRIPT_COMMON) {
                 current_script = script;
@@ -678,7 +681,7 @@
                            bool isRtl, LayoutContext* ctx, size_t bufStart,
                            StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, Layout* layout,
                            float* advances, MinikinExtent* extents, LayoutPieces* lpOut) {
-    LayoutCache& cache = LayoutCache::getInstance();
+    LayoutCache& cache = LayoutEngine::getInstance().layoutCache;
     LayoutCacheKey key(ctx->paint, buf, start, count, bufSize, isRtl, startHyphen, endHyphen);
 
     float wordSpacing = count == 1 && isWordSpace(buf[start]) ? ctx->paint.wordSpacing : 0;
@@ -765,23 +768,22 @@
 }
 
 template <typename HyphenEdit>
-static inline void addHyphenToHbBuffer(const HbBufferUniquePtr& buffer, const HbFontUniquePtr& font,
+static inline void addHyphenToHbBuffer(hb_buffer_t* buffer, const HbFontUniquePtr& font,
                                        HyphenEdit hyphen, uint32_t cluster) {
     const uint32_t* chars;
     size_t size;
     std::tie(chars, size) = getHyphenString(hyphen);
     for (size_t i = 0; i < size; i++) {
-        hb_buffer_add(buffer.get(), determineHyphenChar(chars[i], font.get()), cluster);
+        hb_buffer_add(buffer, determineHyphenChar(chars[i], font.get()), cluster);
     }
 }
 
 // Returns the cluster value assigned to the first codepoint added to the buffer, which can be used
 // to translate cluster values returned by HarfBuzz to input indices.
-static inline uint32_t addToHbBuffer(const HbBufferUniquePtr& buffer, const uint16_t* buf,
-                                     size_t start, size_t count, size_t bufSize,
-                                     ssize_t scriptRunStart, ssize_t scriptRunEnd,
-                                     StartHyphenEdit inStartHyphen, EndHyphenEdit inEndHyphen,
-                                     const HbFontUniquePtr& hbFont) {
+static inline uint32_t addToHbBuffer(hb_buffer_t* buffer, const uint16_t* buf, size_t start,
+                                     size_t count, size_t bufSize, ssize_t scriptRunStart,
+                                     ssize_t scriptRunEnd, StartHyphenEdit inStartHyphen,
+                                     EndHyphenEdit inEndHyphen, const HbFontUniquePtr& hbFont) {
     // Only hyphenate the very first script run for starting hyphens.
     const StartHyphenEdit startHyphen =
             (scriptRunStart == 0) ? inStartHyphen : StartHyphenEdit::NO_EDIT;
@@ -842,10 +844,10 @@
         hbTextLength = hbItemOffset + hbItemLength;
     }
 
-    hb_buffer_add_utf16(buffer.get(), hbText, hbTextLength, hbItemOffset, hbItemLength);
+    hb_buffer_add_utf16(buffer, hbText, hbTextLength, hbItemOffset, hbItemLength);
 
     unsigned int numCodepoints;
-    hb_glyph_info_t* cpInfo = hb_buffer_get_glyph_infos(buffer.get(), &numCodepoints);
+    hb_glyph_info_t* cpInfo = hb_buffer_get_glyph_infos(buffer, &numCodepoints);
 
     // Add the hyphen at the end, if there's any.
     if (hasEndInsertion || hasEndReplacement) {
@@ -869,7 +871,7 @@
         addHyphenToHbBuffer(buffer, hbFont, endHyphen, hyphenCluster);
         // Since we have just added to the buffer, cpInfo no longer necessarily points to
         // the right place. Refresh it.
-        cpInfo = hb_buffer_get_glyph_infos(buffer.get(), nullptr /* we don't need the size */);
+        cpInfo = hb_buffer_get_glyph_infos(buffer, nullptr /* we don't need the size */);
     }
     return cpInfo[0].cluster;
 }
@@ -877,8 +879,7 @@
 void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
                          bool isRtl, LayoutContext* ctx, StartHyphenEdit startHyphen,
                          EndHyphenEdit endHyphen) {
-    HbBufferUniquePtr buffer(hb_buffer_create());
-    hb_buffer_set_unicode_funcs(buffer.get(), getUnicodeFunctions());
+    hb_buffer_t* buffer = LayoutEngine::getInstance().hbBuffer;
     std::vector<FontCollection::Run> items;
     ctx->paint.font->itemize(buf + start, count, ctx->paint, &items);
 
@@ -951,9 +952,9 @@
                 letterSpaceHalfRight = letterSpace - letterSpaceHalfLeft;
             }
 
-            hb_buffer_clear_contents(buffer.get());
-            hb_buffer_set_script(buffer.get(), script);
-            hb_buffer_set_direction(buffer.get(), isRtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
+            hb_buffer_clear_contents(buffer);
+            hb_buffer_set_script(buffer, script);
+            hb_buffer_set_direction(buffer, isRtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
             const LocaleList& localeList = LocaleListCache::getById(ctx->paint.localeListId);
             if (localeList.size() != 0) {
                 hb_language_t hbLanguage = localeList.getHbLanguage(0);
@@ -963,18 +964,17 @@
                         break;
                     }
                 }
-                hb_buffer_set_language(buffer.get(), hbLanguage);
+                hb_buffer_set_language(buffer, hbLanguage);
             }
 
             const uint32_t clusterStart =
                     addToHbBuffer(buffer, buf, start, count, bufSize, scriptRunStart, scriptRunEnd,
                                   startHyphen, endHyphen, hbFont);
 
-            hb_shape(hbFont.get(), buffer.get(), features.empty() ? NULL : &features[0],
-                     features.size());
+            hb_shape(hbFont.get(), buffer, features.empty() ? NULL : &features[0], features.size());
             unsigned int numGlyphs;
-            hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer.get(), &numGlyphs);
-            hb_glyph_position_t* positions = hb_buffer_get_glyph_positions(buffer.get(), NULL);
+            hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, &numGlyphs);
+            hb_glyph_position_t* positions = hb_buffer_get_glyph_positions(buffer, NULL);
 
             // At this point in the code, the cluster values in the info buffer correspond to the
             // input characters with some shift. The cluster value clusterStart corresponds to the
@@ -1129,12 +1129,19 @@
 
 void Layout::purgeCaches() {
     android::AutoMutex _l(gMinikinLock);
-    LayoutCache::getInstance().clear();
+    LayoutCache& layoutCache = LayoutEngine::getInstance().layoutCache;
+    layoutCache.clear();
 }
 
 void Layout::dumpMinikinStats(int fd) {
     android::AutoMutex _l(gMinikinLock);
-    LayoutCache::getInstance().dumpStats(fd);
+    LayoutEngine::getInstance().layoutCache.dumpStats(fd);
 }
 
 }  // namespace minikin
+
+// Unable to define the static data member outside of android.
+// TODO: introduce our own Singleton to drop android namespace.
+namespace android {
+ANDROID_SINGLETON_STATIC_INSTANCE(minikin::LayoutEngine);
+}  // namespace android