Snap for 7428328 from 0a24da587de26c95a1a926a4b9d7a07dc93ee76a to sc-release

Change-Id: I2d188e09ce612fdc11a324d2aac71bb69dfcfeef
diff --git a/include/minikin/SystemFonts.h b/include/minikin/SystemFonts.h
index 616997d..cf4ab75 100644
--- a/include/minikin/SystemFonts.h
+++ b/include/minikin/SystemFonts.h
@@ -55,6 +55,10 @@
         return getInstance().getFontMapInternal(func);
     }
 
+    static void getFontSet(std::function<void(const std::vector<std::shared_ptr<Font>>&)> func) {
+        return getInstance().getFontSetInternal(func);
+    }
+
 protected:
     // Visible for testing purposes.
     SystemFonts() {}
@@ -83,12 +87,23 @@
         func(mCollections);
     }
 
+    void getFontSetInternal(std::function<void(const std::vector<std::shared_ptr<Font>>&)> func) {
+        std::lock_guard<std::mutex> lock(mMutex);
+        if (!mFonts) {
+            buildFontSetLocked();
+        }
+        func(mFonts.value());
+    }
+
 private:
     static SystemFonts& getInstance();
 
+    void buildFontSetLocked() EXCLUSIVE_LOCKS_REQUIRED(mMutex);
+
     std::map<std::string, std::shared_ptr<FontCollection>> mSystemFallbacks GUARDED_BY(mMutex);
     std::shared_ptr<FontCollection> mDefaultFallback GUARDED_BY(mMutex);
     std::vector<std::shared_ptr<FontCollection>> mCollections GUARDED_BY(mMutex);
+    std::optional<std::vector<std::shared_ptr<Font>>> mFonts GUARDED_BY(mMutex);
 
     std::mutex mMutex;
 };
diff --git a/libs/minikin/SystemFonts.cpp b/libs/minikin/SystemFonts.cpp
index b53c8de..9c8fa66 100644
--- a/libs/minikin/SystemFonts.cpp
+++ b/libs/minikin/SystemFonts.cpp
@@ -36,4 +36,22 @@
     return mDefaultFallback;
 }
 
+void SystemFonts::buildFontSetLocked() {
+    std::unordered_set<FontFamily*> uniqueFamilies;
+
+    for (const auto& collection : mCollections) {
+        for (const auto& family : collection->getFamilies()) {
+            uniqueFamilies.insert(family.get());
+        }
+    }
+
+    std::vector<std::shared_ptr<Font>> result;
+    for (const auto family : uniqueFamilies) {
+        for (size_t i = 0; i < family->getNumFonts(); ++i) {
+            result.push_back(family->getFontRef(i));
+        }
+    }
+    mFonts = std::move(result);
+}
+
 }  // namespace minikin
diff --git a/tests/unittest/SystemFontsTest.cpp b/tests/unittest/SystemFontsTest.cpp
index 511081a..f1b0109 100644
--- a/tests/unittest/SystemFontsTest.cpp
+++ b/tests/unittest/SystemFontsTest.cpp
@@ -21,6 +21,7 @@
 #include "minikin/FontCollection.h"
 
 #include "FontTestUtils.h"
+#include "PathUtils.h"
 
 namespace minikin {
 namespace {
@@ -34,6 +35,14 @@
         return findFontCollectionInternal(familyName);
     }
 
+    void addFontMap(std::shared_ptr<FontCollection>&& collections) {
+        addFontMapInternal(std::move(collections));
+    }
+
+    void getFontSet(std::function<void(const std::vector<std::shared_ptr<Font>>&)> func) {
+        getFontSetInternal(func);
+    }
+
     void registerFallback(const std::string& familyName,
                           const std::shared_ptr<FontCollection>& fc) {
         registerFallbackInternal(familyName, fc);
@@ -78,5 +87,32 @@
     EXPECT_EQ(fc1, systemFonts.findFontCollection("sans"));
 }
 
+TEST(SystemFontTest, getAvailableFont_dedupFonts) {
+    TestableSystemFonts systemFonts;
+    auto asciiFamily = buildFontFamily("Ascii.ttf");
+    auto boldFamily = buildFontFamily("Bold.ttf");
+    auto boldItalicFamily = buildFontFamily("BoldItalic.ttf");
+
+    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));
+
+    systemFonts.addFontMap(std::move(fc1));
+    systemFonts.addFontMap(std::move(fc2));
+
+    systemFonts.getFontSet([](const std::vector<std::shared_ptr<Font>>& fonts) {
+        EXPECT_EQ(3u, fonts.size());  // Ascii, Bold and BoldItalic
+        std::unordered_set<std::string> fontPaths;
+        for (const auto& font : fonts) {
+            fontPaths.insert(getBasename(font->typeface()->GetFontPath()));
+        }
+
+        EXPECT_TRUE(fontPaths.find("Ascii.ttf") != fontPaths.end());
+        EXPECT_TRUE(fontPaths.find("Bold.ttf") != fontPaths.end());
+        EXPECT_TRUE(fontPaths.find("BoldItalic.ttf") != fontPaths.end());
+    });
+}
+
 }  // namespace
 }  // namespace minikin