Revert "Remove HbFontCache"
This causes a regression for some characters.
This reverts commit 6c6954b40f7a6bd6dcf8a3d01c78600437c2e011.
Bug: 73054061
Change-Id: I010754474eebd55e43666893c4f7af9de12b22f3
(cherry picked from commit 4de86391218f9fa2d1ba15d78cd80514fb5ce43d)
diff --git a/include/minikin/FontFamily.h b/include/minikin/FontFamily.h
index 7605dd9..6cc672c 100644
--- a/include/minikin/FontFamily.h
+++ b/include/minikin/FontFamily.h
@@ -23,13 +23,10 @@
#include <vector>
#include "minikin/FontStyle.h"
-#include "minikin/HbUtils.h"
-#include "minikin/Macros.h"
#include "minikin/SparseBitSet.h"
namespace minikin {
-class Font;
class MinikinFont;
// attributes representing transforms (fake bold, fake italic) to match styles
@@ -48,73 +45,25 @@
struct FakedFont {
// ownership is the enclosing FontCollection
- const Font* font;
+ MinikinFont* font;
FontFakery fakery;
};
typedef uint32_t AxisTag;
-// Represents a single font file.
-class Font {
-public:
- class Builder {
- public:
- Builder(const std::shared_ptr<MinikinFont>& typeface) : mTypeface(typeface) {}
-
- // Override the font style. If not called, info from OS/2 table is used.
- Builder& setStyle(FontStyle style) {
- mWeight = style.weight();
- mSlant = style.slant();
- mIsWeightSet = mIsSlantSet = true;
- return *this;
- }
-
- // Override the font weight. If not called, info from OS/2 table is used.
- Builder& setWeight(uint16_t weight) {
- mWeight = weight;
- mIsWeightSet = true;
- return *this;
- }
-
- // Override the font slant. If not called, info from OS/2 table is used.
- Builder& setSlant(FontStyle::Slant slant) {
- mSlant = slant;
- mIsSlantSet = true;
- return *this;
- }
-
- Font build();
-
- private:
- std::shared_ptr<MinikinFont> mTypeface;
- uint16_t mWeight = static_cast<uint16_t>(FontStyle::Weight::NORMAL);
- FontStyle::Slant mSlant = FontStyle::Slant::UPRIGHT;
- bool mIsWeightSet = false;
- bool mIsSlantSet = false;
- };
+struct Font {
+ Font(const std::shared_ptr<MinikinFont>& typeface, FontStyle style);
Font(Font&& o) = default;
Font& operator=(Font&& o) = default;
+ // prevent copy constructor and assign operator.
+ Font(const Font& o) = delete;
+ Font& operator=(const Font& o) = delete;
- inline const std::shared_ptr<MinikinFont>& typeface() const { return mTypeface; }
- inline FontStyle style() const { return mStyle; }
- inline const HbFontUniquePtr& baseFont() const { return mBaseFont; }
+ std::shared_ptr<MinikinFont> typeface;
+ FontStyle style;
- std::unordered_set<AxisTag> getSupportedAxes() const;
-
-private:
- // Use Builder instead.
- Font(std::shared_ptr<MinikinFont>&& typeface, FontStyle style, HbFontUniquePtr&& baseFont)
- : mTypeface(std::move(typeface)), mStyle(style), mBaseFont(std::move(baseFont)) {}
-
- static HbFontUniquePtr prepareFont(const std::shared_ptr<MinikinFont>& typeface);
- static FontStyle analyzeStyle(const HbFontUniquePtr& font);
-
- std::shared_ptr<MinikinFont> mTypeface;
- FontStyle mStyle;
- HbFontUniquePtr mBaseFont;
-
- MINIKIN_PREVENT_COPY_AND_ASSIGN(Font);
+ std::unordered_set<AxisTag> getSupportedAxesLocked() const;
};
struct FontVariation {
@@ -136,6 +85,9 @@
FontFamily(Variant variant, std::vector<Font>&& fonts);
FontFamily(uint32_t localeListId, Variant variant, std::vector<Font>&& fonts);
+ // TODO: Good to expose FontUtil.h.
+ static bool analyzeStyle(const std::shared_ptr<MinikinFont>& typeface, int* weight,
+ bool* italic);
FakedFont getClosestMatch(FontStyle style) const;
uint32_t localeListId() const { return mLocaleListId; }
@@ -143,8 +95,10 @@
// API's for enumerating the fonts in a family. These don't guarantee any particular order
size_t getNumFonts() const { return mFonts.size(); }
- const Font* getFont(size_t index) const { return &mFonts[index]; }
- FontStyle getStyle(size_t index) const { return mFonts[index].style(); }
+ const std::shared_ptr<MinikinFont>& getFont(size_t index) const {
+ return mFonts[index].typeface;
+ }
+ FontStyle getStyle(size_t index) const { return mFonts[index].style; }
bool isColorEmojiFamily() const;
const std::unordered_set<AxisTag>& supportedAxes() const { return mSupportedAxes; }
@@ -174,7 +128,9 @@
SparseBitSet mCoverage;
std::vector<std::unique_ptr<SparseBitSet>> mCmapFmt14Coverage;
- MINIKIN_PREVENT_COPY_AND_ASSIGN(FontFamily);
+ // Forbid copying and assignment.
+ FontFamily(const FontFamily&) = delete;
+ void operator=(const FontFamily&) = delete;
};
} // namespace minikin
diff --git a/include/minikin/HbUtils.h b/include/minikin/HbUtils.h
deleted file mode 100644
index 1cf375d..0000000
--- a/include/minikin/HbUtils.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2018 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_HB_UTILS_H
-#define MINIKIN_HB_UTILS_H
-
-#include <hb.h>
-#include <memory>
-
-namespace minikin {
-
-struct HbBlobDeleter {
- void operator()(hb_blob_t* v) { hb_blob_destroy(v); }
-};
-
-struct HbFaceDeleter {
- void operator()(hb_face_t* v) { hb_face_destroy(v); }
-};
-
-struct HbFontDeleter {
- void operator()(hb_font_t* v) { hb_font_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>;
-
-} // namespace minikin
-
-#endif // MINIKIN_HB_UTILS_H
diff --git a/include/minikin/LineBreaker.h b/include/minikin/LineBreaker.h
index 7d59c63..d97965a 100644
--- a/include/minikin/LineBreaker.h
+++ b/include/minikin/LineBreaker.h
@@ -115,7 +115,7 @@
}
private:
- MINIKIN_PREVENT_COPY_AND_ASSIGN(LineBreakResult);
+ PREVENT_COPY_AND_ASSIGN(LineBreakResult);
};
LineBreakResult breakIntoLines(const U16StringPiece& textBuffer, BreakStrategy strategy,
diff --git a/include/minikin/Macros.h b/include/minikin/Macros.h
index 6791ce0..1eeaa8c 100644
--- a/include/minikin/Macros.h
+++ b/include/minikin/Macros.h
@@ -16,13 +16,13 @@
#ifndef MINIKIN_MACROS_H
#define MINIKIN_MACROS_H
-#define MINIKIN_PREVENT_COPY_AND_ASSIGN(Type) \
- Type(const Type&) = delete; \
+#define PREVENT_COPY_AND_ASSIGN(Type) \
+ Type(const Type&) = delete; \
Type& operator=(const Type&) = delete
-#define MINIKIN_PREVENT_COPY_ASSIGN_AND_MOVE(Type) \
- Type(const Type&) = delete; \
- Type& operator=(const Type&) = delete; \
- Type(Type&&) = delete; \
+#define PREVENT_COPY_ASSIGN_AND_MOVE(Type) \
+ Type(const Type&) = delete; \
+ Type& operator=(const Type&) = delete; \
+ Type(Type&&) = delete; \
Type& operator=(Type&&) = delete
#endif // MINIKIN_MACROS_H
diff --git a/include/minikin/MeasuredText.h b/include/minikin/MeasuredText.h
index 83b774f..5da37eb 100644
--- a/include/minikin/MeasuredText.h
+++ b/include/minikin/MeasuredText.h
@@ -175,7 +175,7 @@
MeasuredText(MeasuredText&&) = default;
MeasuredText& operator=(MeasuredText&&) = default;
- MINIKIN_PREVENT_COPY_AND_ASSIGN(MeasuredText);
+ PREVENT_COPY_AND_ASSIGN(MeasuredText);
private:
friend class MeasuredTextBuilder;
@@ -215,7 +215,7 @@
new MeasuredText(textBuf, std::move(mRuns), computeHyphenation, computeLayout));
}
- MINIKIN_PREVENT_COPY_ASSIGN_AND_MOVE(MeasuredTextBuilder);
+ PREVENT_COPY_ASSIGN_AND_MOVE(MeasuredTextBuilder);
private:
std::vector<std::unique_ptr<Run>> mRuns;
diff --git a/include/minikin/MinikinFont.h b/include/minikin/MinikinFont.h
index 6c53583..74a3811 100644
--- a/include/minikin/MinikinFont.h
+++ b/include/minikin/MinikinFont.h
@@ -117,7 +117,7 @@
public:
explicit MinikinFont(int32_t uniqueId) : mUniqueId(uniqueId) {}
- virtual ~MinikinFont() {}
+ virtual ~MinikinFont();
virtual float GetHorizontalAdvance(uint32_t glyph_id, const MinikinPaint& paint,
const FontFakery& fakery) const = 0;
diff --git a/libs/minikin/Android.bp b/libs/minikin/Android.bp
index 0f9d003..b1c8fa5 100644
--- a/libs/minikin/Android.bp
+++ b/libs/minikin/Android.bp
@@ -36,6 +36,7 @@
"FontUtils.cpp",
"GraphemeBreak.cpp",
"GreedyLineBreaker.cpp",
+ "HbFontCache.cpp",
"HyphenatorMap.cpp",
"Layout.cpp",
"LayoutUtils.cpp",
@@ -45,6 +46,7 @@
"LocaleListCache.cpp",
"MeasuredText.cpp",
"Measurement.cpp",
+ "MinikinFont.cpp",
"MinikinInternal.cpp",
"OptimalLineBreaker.cpp",
"SparseBitSet.cpp",
diff --git a/libs/minikin/FontFamily.cpp b/libs/minikin/FontFamily.cpp
index 1c89960..5291540 100644
--- a/libs/minikin/FontFamily.cpp
+++ b/libs/minikin/FontFamily.cpp
@@ -21,13 +21,10 @@
#include <cstdint>
#include <vector>
-#include <hb-ot.h>
-#include <hb.h>
#include <log/log.h>
#include <utils/JenkinsHash.h>
#include "minikin/CmapCoverage.h"
-#include "minikin/HbUtils.h"
#include "minikin/MinikinFont.h"
#include "FontUtils.h"
@@ -37,73 +34,22 @@
namespace minikin {
-Font Font::Builder::build() {
- if (mIsWeightSet && mIsSlantSet) {
- // No need to read OS/2 header of the font file.
- return Font(std::move(mTypeface), FontStyle(mWeight, mSlant), prepareFont(mTypeface));
- }
+Font::Font(const std::shared_ptr<MinikinFont>& typeface, FontStyle style)
+ : typeface(typeface), style(style) {}
- HbFontUniquePtr font = prepareFont(mTypeface);
- FontStyle styleFromFont = analyzeStyle(font);
- if (!mIsWeightSet) {
- mWeight = styleFromFont.weight();
- }
- if (!mIsSlantSet) {
- mSlant = styleFromFont.slant();
- }
- return Font(std::move(mTypeface), FontStyle(mWeight, mSlant), std::move(font));
-}
-
-// static
-HbFontUniquePtr Font::prepareFont(const std::shared_ptr<MinikinFont>& typeface) {
- const char* buf = reinterpret_cast<const char*>(typeface->GetFontData());
- size_t size = typeface->GetFontSize();
- uint32_t ttcIndex = typeface->GetFontIndex();
-
- HbBlobUniquePtr blob(hb_blob_create(buf, size, HB_MEMORY_MODE_READONLY, nullptr, nullptr));
- HbFaceUniquePtr face(hb_face_create(blob.get(), ttcIndex));
- HbFontUniquePtr parent(hb_font_create(face.get()));
- hb_ot_font_set_funcs(parent.get());
-
- uint32_t upem = hb_face_get_upem(face.get());
- hb_font_set_scale(parent.get(), upem, upem);
-
- HbFontUniquePtr font(hb_font_create_sub_font(parent.get()));
- std::vector<hb_variation_t> variations;
- variations.reserve(typeface->GetAxes().size());
- for (const FontVariation& variation : typeface->GetAxes()) {
- variations.push_back({variation.axisTag, variation.value});
- }
- hb_font_set_variations(font.get(), variations.data(), variations.size());
- return font;
-}
-
-// static
-FontStyle Font::analyzeStyle(const HbFontUniquePtr& font) {
- HbBlob os2Table(font, MinikinFont::MakeTag('O', 'S', '/', '2'));
- if (!os2Table) {
- return FontStyle();
- }
-
- int weight;
- bool italic;
- if (!::minikin::analyzeStyle(os2Table.get(), os2Table.size(), &weight, &italic)) {
- return FontStyle();
- }
- // TODO: Update weight/italic based on fvar value.
- return FontStyle(static_cast<uint16_t>(weight), static_cast<FontStyle::Slant>(italic));
-}
-
-std::unordered_set<AxisTag> Font::getSupportedAxes() const {
- HbBlob fvarTable(mBaseFont, MinikinFont::MakeTag('f', 'v', 'a', 'r'));
- if (!fvarTable) {
+std::unordered_set<AxisTag> Font::getSupportedAxesLocked() const {
+ const uint32_t fvarTag = MinikinFont::MakeTag('f', 'v', 'a', 'r');
+ HbBlob fvarTable(getFontTable(typeface.get(), fvarTag));
+ if (fvarTable.size() == 0) {
return std::unordered_set<AxisTag>();
}
+
std::unordered_set<AxisTag> supportedAxes;
analyzeAxes(fvarTable.get(), fvarTable.size(), &supportedAxes);
return supportedAxes;
}
+// static
FontFamily::FontFamily(std::vector<Font>&& fonts)
: FontFamily(Variant::DEFAULT, std::move(fonts)) {}
@@ -116,6 +62,15 @@
computeCoverage();
}
+bool FontFamily::analyzeStyle(const std::shared_ptr<MinikinFont>& typeface, int* weight,
+ bool* italic) {
+ android::AutoMutex _l(gMinikinLock);
+ const uint32_t os2Tag = MinikinFont::MakeTag('O', 'S', '/', '2');
+ HbBlob os2Table(getFontTable(typeface.get(), os2Tag));
+ if (os2Table.get() == nullptr) return false;
+ return ::minikin::analyzeStyle(os2Table.get(), os2Table.size(), weight, italic);
+}
+
// Compute a matching metric between two styles - 0 is an exact match
static int computeMatch(FontStyle style1, FontStyle style2) {
if (style1 == style2) return 0;
@@ -138,16 +93,16 @@
FakedFont FontFamily::getClosestMatch(FontStyle style) const {
const Font* bestFont = &mFonts[0];
- int bestMatch = computeMatch(bestFont->style(), style);
+ int bestMatch = computeMatch(bestFont->style, style);
for (size_t i = 1; i < mFonts.size(); i++) {
const Font& font = mFonts[i];
- int match = computeMatch(font.style(), style);
+ int match = computeMatch(font.style, style);
if (i == 0 || match < bestMatch) {
bestFont = &font;
bestMatch = match;
}
}
- return FakedFont{bestFont, computeFakery(style, bestFont->style())};
+ return FakedFont{bestFont->typeface.get(), computeFakery(style, bestFont->style)};
}
bool FontFamily::isColorEmojiFamily() const {
@@ -161,17 +116,19 @@
}
void FontFamily::computeCoverage() {
- const Font* font = getClosestMatch(FontStyle()).font;
- HbBlob cmapTable(font->baseFont(), MinikinFont::MakeTag('c', 'm', 'a', 'p'));
+ android::AutoMutex _l(gMinikinLock);
+ const FontStyle defaultStyle;
+ const MinikinFont* typeface = getClosestMatch(defaultStyle).font;
+ const uint32_t cmapTag = MinikinFont::MakeTag('c', 'm', 'a', 'p');
+ HbBlob cmapTable(getFontTable(typeface, cmapTag));
if (cmapTable.get() == nullptr) {
ALOGE("Could not get cmap table size!\n");
return;
}
-
mCoverage = CmapCoverage::getCoverage(cmapTable.get(), cmapTable.size(), &mCmapFmt14Coverage);
for (size_t i = 0; i < mFonts.size(); ++i) {
- std::unordered_set<AxisTag> supportedAxes = mFonts[i].getSupportedAxes();
+ std::unordered_set<AxisTag> supportedAxes = mFonts[i].getSupportedAxesLocked();
mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end());
}
}
@@ -222,7 +179,8 @@
std::vector<Font> fonts;
for (const Font& font : mFonts) {
bool supportedVariations = false;
- std::unordered_set<AxisTag> supportedAxes = font.getSupportedAxes();
+ android::AutoMutex _l(gMinikinLock);
+ std::unordered_set<AxisTag> supportedAxes = font.getSupportedAxesLocked();
if (!supportedAxes.empty()) {
for (const FontVariation& variation : variations) {
if (supportedAxes.find(variation.axisTag) != supportedAxes.end()) {
@@ -233,12 +191,12 @@
}
std::shared_ptr<MinikinFont> minikinFont;
if (supportedVariations) {
- minikinFont = font.typeface()->createFontWithVariation(variations);
+ minikinFont = font.typeface->createFontWithVariation(variations);
}
if (minikinFont == nullptr) {
- minikinFont = font.typeface();
+ minikinFont = font.typeface;
}
- fonts.push_back(Font::Builder(minikinFont).setStyle(font.style()).build());
+ fonts.push_back(Font(std::move(minikinFont), font.style));
}
return std::shared_ptr<FontFamily>(new FontFamily(mLocaleListId, mVariant, std::move(fonts)));
diff --git a/libs/minikin/GreedyLineBreaker.cpp b/libs/minikin/GreedyLineBreaker.cpp
index 6d82373..9336f28 100644
--- a/libs/minikin/GreedyLineBreaker.cpp
+++ b/libs/minikin/GreedyLineBreaker.cpp
@@ -124,7 +124,7 @@
// The result of line breaking.
std::vector<BreakPoint> mBreakPoints;
- MINIKIN_PREVENT_COPY_ASSIGN_AND_MOVE(GreedyLineBreaker);
+ PREVENT_COPY_ASSIGN_AND_MOVE(GreedyLineBreaker);
};
void GreedyLineBreaker::breakLineAt(uint32_t offset, float lineWidth, float remainingNextLineWidth,
diff --git a/libs/minikin/HbFontCache.cpp b/libs/minikin/HbFontCache.cpp
new file mode 100644
index 0000000..4f80c37
--- /dev/null
+++ b/libs/minikin/HbFontCache.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2015 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 "HbFontCache.h"
+
+#include <hb-ot.h>
+#include <hb.h>
+#include <utils/LruCache.h>
+
+#include "minikin/MinikinFont.h"
+
+#include "MinikinInternal.h"
+
+namespace minikin {
+
+class HbFontCache : private android::OnEntryRemoved<int32_t, hb_font_t*> {
+public:
+ HbFontCache() : mCache(kMaxEntries) { mCache.setOnEntryRemovedListener(this); }
+
+ // callback for OnEntryRemoved
+ void operator()(int32_t& /* key */, hb_font_t*& value) { hb_font_destroy(value); }
+
+ hb_font_t* get(int32_t fontId) { return mCache.get(fontId); }
+
+ void put(int32_t fontId, hb_font_t* font) { mCache.put(fontId, font); }
+
+ void clear() { mCache.clear(); }
+
+ void remove(int32_t fontId) { mCache.remove(fontId); }
+
+private:
+ static const size_t kMaxEntries = 100;
+
+ android::LruCache<int32_t, hb_font_t*> mCache;
+};
+
+HbFontCache* getFontCacheLocked() {
+ assertMinikinLocked();
+ static HbFontCache* cache = nullptr;
+ if (cache == nullptr) {
+ cache = new HbFontCache();
+ }
+ return cache;
+}
+
+void purgeHbFontLocked(const MinikinFont* minikinFont) {
+ assertMinikinLocked();
+ const int32_t fontId = minikinFont->GetUniqueId();
+ getFontCacheLocked()->remove(fontId);
+}
+
+// Returns a new reference to a hb_font_t object, caller is
+// responsible for calling hb_font_destroy() on it.
+hb_font_t* getHbFontLocked(const MinikinFont* minikinFont) {
+ assertMinikinLocked();
+ // TODO: get rid of nullFaceFont
+ static hb_font_t* nullFaceFont = nullptr;
+ if (minikinFont == nullptr) {
+ if (nullFaceFont == nullptr) {
+ nullFaceFont = hb_font_create(nullptr);
+ }
+ return hb_font_reference(nullFaceFont);
+ }
+
+ HbFontCache* fontCache = getFontCacheLocked();
+ const int32_t fontId = minikinFont->GetUniqueId();
+ hb_font_t* font = fontCache->get(fontId);
+ if (font != nullptr) {
+ return hb_font_reference(font);
+ }
+
+ hb_face_t* face;
+ const void* buf = minikinFont->GetFontData();
+ size_t size = minikinFont->GetFontSize();
+ hb_blob_t* blob = hb_blob_create(reinterpret_cast<const char*>(buf), size,
+ HB_MEMORY_MODE_READONLY, nullptr, nullptr);
+ face = hb_face_create(blob, minikinFont->GetFontIndex());
+ hb_blob_destroy(blob);
+
+ hb_font_t* parent_font = hb_font_create(face);
+ hb_ot_font_set_funcs(parent_font);
+
+ unsigned int upem = hb_face_get_upem(face);
+ hb_font_set_scale(parent_font, upem, upem);
+
+ font = hb_font_create_sub_font(parent_font);
+ std::vector<hb_variation_t> variations;
+ for (const FontVariation& variation : minikinFont->GetAxes()) {
+ variations.push_back({variation.axisTag, variation.value});
+ }
+ hb_font_set_variations(font, variations.data(), variations.size());
+ hb_font_destroy(parent_font);
+ hb_face_destroy(face);
+ fontCache->put(fontId, font);
+ return hb_font_reference(font);
+}
+
+} // namespace minikin
diff --git a/libs/minikin/Layout.cpp b/libs/minikin/Layout.cpp
index 1a413f8..ba6ca83 100644
--- a/libs/minikin/Layout.cpp
+++ b/libs/minikin/Layout.cpp
@@ -33,8 +33,8 @@
#include <utils/Singleton.h>
#include "minikin/Emoji.h"
-#include "minikin/HbUtils.h"
+#include "HbFontCache.h"
#include "LayoutUtils.h"
#include "LocaleListCache.h"
#include "MinikinInternal.h"
@@ -73,8 +73,18 @@
struct LayoutContext {
LayoutContext(const MinikinPaint& paint) : paint(paint) {}
+
const MinikinPaint& paint;
- std::vector<HbFontUniquePtr> hbFonts; // parallel to mFaces
+
+ std::vector<hb_font_t*> hbFonts; // parallel to mFaces
+
+ void clearHbFonts() {
+ for (size_t i = 0; i < hbFonts.size(); i++) {
+ hb_font_set_funcs(hbFonts[i], nullptr, nullptr, nullptr);
+ hb_font_destroy(hbFonts[i]);
+ }
+ hbFonts.clear();
+ }
};
// Layout cache datatypes
@@ -117,6 +127,7 @@
void doLayout(Layout* layout, LayoutContext* ctx) const {
layout->mAdvances.resize(mCount, 0);
layout->mExtents.resize(mCount);
+ ctx->clearHbFonts();
layout->doLayoutRun(mChars, mStart, mCount, mNchars, mIsRtl, ctx, mStartHyphen, mEndHyphen);
}
@@ -309,9 +320,10 @@
return *funcs;
}
-static bool isColorBitmapFont(const HbFontUniquePtr& font) {
- HbBlob cbdt(font, HB_TAG('C', 'B', 'D', 'T'));
- return cbdt;
+static bool isColorBitmapFont(hb_font_t* font) {
+ hb_face_t* face = hb_font_get_face(font);
+ HbBlob cbdt(hb_face_reference_table(face, HB_TAG('C', 'B', 'D', 'T')));
+ return cbdt.size() > 0;
}
static float HBFixedToFloat(hb_position_t v) {
@@ -341,14 +353,11 @@
// Note: ctx == nullptr means we're copying from the cache, no need to create corresponding
// hb_font object.
if (ctx != nullptr) {
- // We override some functions which are not thread safe.
- // 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(), 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));
+ hb_font_t* font = getHbFontLocked(face.font);
+ hb_font_set_funcs(font, getHbFontFuncs(isColorBitmapFont(font)),
+ new SkiaArguments({face.font, &ctx->paint, face.fakery}),
+ [](void* data) { delete reinterpret_cast<SkiaArguments*>(data); });
+ ctx->hbFonts.push_back(font);
}
return ix;
}
@@ -588,6 +597,7 @@
runInfo.mIsRtl, &ctx, range.getStart(), startHyphen, endHyphen, this,
nullptr, nullptr, nullptr);
}
+ ctx.clearHbFonts();
}
// static
@@ -609,6 +619,8 @@
nullptr, // extents. Not used.
out);
}
+
+ ctx.clearHbFonts();
}
float Layout::measureText(const U16StringPiece& textBuf, const Range& range, Bidi bidiFlags,
@@ -627,6 +639,8 @@
textBuf.size(), runInfo.mIsRtl, &ctx, 0, startHyphen,
endHyphen, NULL, advancesForRun, extentsForRun, nullptr);
}
+
+ ctx.clearHbFonts();
return advance;
}
@@ -768,13 +782,13 @@
}
template <typename HyphenEdit>
-static inline void addHyphenToHbBuffer(hb_buffer_t* buffer, const HbFontUniquePtr& font,
- HyphenEdit hyphen, uint32_t cluster) {
+static inline void addHyphenToHbBuffer(hb_buffer_t* buffer, hb_font_t* 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, determineHyphenChar(chars[i], font.get()), cluster);
+ hb_buffer_add(buffer, determineHyphenChar(chars[i], font), cluster);
}
}
@@ -783,7 +797,7 @@
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) {
+ EndHyphenEdit inEndHyphen, hb_font_t* hbFont) {
// Only hyphenate the very first script run for starting hyphens.
const StartHyphenEdit startHyphen =
(scriptRunStart == 0) ? inStartHyphen : StartHyphenEdit::NO_EDIT;
@@ -907,15 +921,19 @@
isRtl ? --run_ix : ++run_ix) {
FontCollection::Run& run = items[run_ix];
const FakedFont& fakedFont = run.fakedFont;
+ if (fakedFont.font == NULL) {
+ ALOGE("no font for run starting u+%04x length %d", buf[run.start], run.end - run.start);
+ continue;
+ }
const int font_ix = findOrPushBackFace(fakedFont, ctx);
- const HbFontUniquePtr& hbFont = ctx->hbFonts[font_ix];
+ hb_font_t* hbFont = ctx->hbFonts[font_ix];
MinikinExtent verticalExtent;
- fakedFont.font->typeface()->GetFontExtent(&verticalExtent, ctx->paint, fakedFont.fakery);
+ fakedFont.font->GetFontExtent(&verticalExtent, ctx->paint, fakedFont.fakery);
std::fill(&mExtents[run.start], &mExtents[run.end], verticalExtent);
- hb_font_set_ppem(hbFont.get(), size * scaleX, size);
- hb_font_set_scale(hbFont.get(), HBFloatToFixed(size * scaleX), HBFloatToFixed(size));
+ hb_font_set_ppem(hbFont, size * scaleX, size);
+ hb_font_set_scale(hbFont, HBFloatToFixed(size * scaleX), HBFloatToFixed(size));
const bool is_color_bitmap_font = isColorBitmapFont(hbFont);
@@ -971,7 +989,7 @@
addToHbBuffer(buffer, buf, start, count, bufSize, scriptRunStart, scriptRunEnd,
startHyphen, endHyphen, hbFont);
- hb_shape(hbFont.get(), buffer, features.empty() ? NULL : &features[0], features.size());
+ hb_shape(hbFont, buffer, features.empty() ? NULL : &features[0], features.size());
unsigned int numGlyphs;
hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, &numGlyphs);
hb_glyph_position_t* positions = hb_buffer_get_glyph_positions(buffer, NULL);
@@ -1008,8 +1026,7 @@
}
MinikinRect glyphBounds;
hb_glyph_extents_t extents = {};
- if (is_color_bitmap_font &&
- hb_font_get_glyph_extents(hbFont.get(), glyph_ix, &extents)) {
+ if (is_color_bitmap_font && hb_font_get_glyph_extents(hbFont, glyph_ix, &extents)) {
// Note that it is technically possible for a TrueType font to have outline and
// embedded bitmap at the same time. We ignore modified bbox of hinted outline
// glyphs in that case.
@@ -1019,8 +1036,7 @@
glyphBounds.mBottom =
roundf(HBFixedToFloat(-extents.y_bearing - extents.height));
} else {
- fakedFont.font->typeface()->GetBounds(&glyphBounds, glyph_ix, ctx->paint,
- fakedFont.fakery);
+ fakedFont.font->GetBounds(&glyphBounds, glyph_ix, ctx->paint, fakedFont.fakery);
}
glyphBounds.offset(xoff, yoff);
@@ -1088,7 +1104,7 @@
const MinikinFont* Layout::getFont(int i) const {
const LayoutGlyph& glyph = mGlyphs[i];
- return mFaces[glyph.font_ix].font->typeface().get();
+ return mFaces[glyph.font_ix].font;
}
FontFakery Layout::getFakery(int i) const {
diff --git a/libs/minikin/MinikinInternal.cpp b/libs/minikin/MinikinInternal.cpp
index 0ed667d..a5702e5 100644
--- a/libs/minikin/MinikinInternal.cpp
+++ b/libs/minikin/MinikinInternal.cpp
@@ -19,6 +19,7 @@
#include <log/log.h>
+#include "HbFontCache.h"
#include "MinikinInternal.h"
namespace minikin {
@@ -31,6 +32,15 @@
#endif
}
+hb_blob_t* getFontTable(const MinikinFont* minikinFont, uint32_t tag) {
+ assertMinikinLocked();
+ hb_font_t* font = getHbFontLocked(minikinFont);
+ hb_face_t* face = hb_font_get_face(font);
+ hb_blob_t* blob = hb_face_reference_table(face, tag);
+ hb_font_destroy(font);
+ return blob;
+}
+
inline static bool isBMPVariationSelector(uint32_t codePoint) {
return VS1 <= codePoint && codePoint <= VS16;
}
diff --git a/libs/minikin/MinikinInternal.h b/libs/minikin/MinikinInternal.h
index 05dcb9c..bffda70 100644
--- a/libs/minikin/MinikinInternal.h
+++ b/libs/minikin/MinikinInternal.h
@@ -23,7 +23,6 @@
#include <utils/Log.h>
#include <utils/Mutex.h>
-#include "minikin/HbUtils.h"
#include "minikin/MinikinFont.h"
namespace minikin {
@@ -37,6 +36,8 @@
// Aborts if gMinikinLock is not acquired. Do nothing on the release build.
void assertMinikinLocked();
+hb_blob_t* getFontTable(const MinikinFont* minikinFont, uint32_t tag);
+
#ifdef ENABLE_ASSERTION
#define MINIKIN_ASSERT(cond, ...) LOG_ALWAYS_FATAL_IF(!(cond), __VA_ARGS__)
#else
@@ -64,24 +65,24 @@
// Note that this function returns false for Mongolian free variation selectors.
bool isVariationSelector(uint32_t codePoint);
-// An RAII accessor for hb_blob_t
+// An RAII wrapper for hb_blob_t
class HbBlob {
public:
- HbBlob(const HbFaceUniquePtr& face, uint32_t tag)
- : mBlob(hb_face_reference_table(face.get(), tag)) {}
- HbBlob(const HbFontUniquePtr& font, uint32_t tag)
- : mBlob(hb_face_reference_table(hb_font_get_face(font.get()), tag)) {}
+ // Takes ownership of hb_blob_t object, caller is no longer
+ // responsible for calling hb_blob_destroy().
+ explicit HbBlob(hb_blob_t* blob) : mBlob(blob) {}
- inline const uint8_t* get() const {
- return reinterpret_cast<const uint8_t*>(hb_blob_get_data(mBlob.get(), nullptr));
+ ~HbBlob() { hb_blob_destroy(mBlob); }
+
+ const uint8_t* get() const {
+ const char* data = hb_blob_get_data(mBlob, nullptr);
+ return reinterpret_cast<const uint8_t*>(data);
}
- inline size_t size() const { return (size_t)hb_blob_get_length(mBlob.get()); }
-
- inline operator bool() const { return size() > 0; }
+ size_t size() const { return (size_t)hb_blob_get_length(mBlob); }
private:
- HbBlobUniquePtr mBlob;
+ hb_blob_t* mBlob;
};
} // namespace minikin
diff --git a/tests/stresstest/FontFamilyTest.cpp b/tests/stresstest/FontFamilyTest.cpp
index f7d8b8e..a7eb07b 100644
--- a/tests/stresstest/FontFamilyTest.cpp
+++ b/tests/stresstest/FontFamilyTest.cpp
@@ -17,11 +17,11 @@
#include "minikin/FontFamily.h"
#include <gtest/gtest.h>
-#include <hb.h>
#include "minikin/FontCollection.h"
#include "FontTestUtils.h"
+#include "HbFontCache.h"
#include "MinikinInternal.h"
namespace minikin {
@@ -37,7 +37,7 @@
std::shared_ptr<FontFamily> family = buildFontFamily(fontPath);
android::AutoMutex _l(gMinikinLock);
- hb_font_t* hbFont = family->getFont(0)->baseFont().get();
+ hb_font_t* hbFont = getHbFontLocked(family->getFont(0).get());
for (uint32_t codePoint = 0; codePoint < MAX_UNICODE_CODE_POINT; ++codePoint) {
uint32_t unusedGlyph;
diff --git a/tests/unittest/Android.bp b/tests/unittest/Android.bp
index 9ded52e..34f789e 100644
--- a/tests/unittest/Android.bp
+++ b/tests/unittest/Android.bp
@@ -45,6 +45,7 @@
"FontCollectionItemizeTest.cpp",
"FontFamilyTest.cpp",
"FontLanguageListCacheTest.cpp",
+ "HbFontCacheTest.cpp",
"HyphenatorMapTest.cpp",
"HyphenatorTest.cpp",
"GraphemeBreakTests.cpp",
diff --git a/tests/unittest/FontCollectionItemizeTest.cpp b/tests/unittest/FontCollectionItemizeTest.cpp
index c130f6d..2ab33f6 100644
--- a/tests/unittest/FontCollectionItemizeTest.cpp
+++ b/tests/unittest/FontCollectionItemizeTest.cpp
@@ -91,7 +91,7 @@
// Utility function to obtain font path associated with run.
const std::string& getFontPath(const FontCollection::Run& run) {
EXPECT_NE(nullptr, run.fakedFont.font);
- return ((FreeTypeMinikinFontForTest*)run.fakedFont.font->typeface().get())->fontPath();
+ return ((FreeTypeMinikinFontForTest*)run.fakedFont.font)->fontPath();
}
// Utility function to obtain LocaleList from string.
@@ -945,7 +945,7 @@
// Prepare first font which doesn't supports U+9AA8
auto firstFamilyMinikinFont = std::make_shared<FreeTypeMinikinFontForTest>(kNoGlyphFont);
std::vector<Font> fonts;
- fonts.push_back(Font::Builder(firstFamilyMinikinFont).build());
+ fonts.push_back(Font(firstFamilyMinikinFont, FontStyle()));
auto firstFamily = std::make_shared<FontFamily>(
registerLocaleList("und"), FontFamily::Variant::DEFAULT, std::move(fonts));
families.push_back(firstFamily);
@@ -958,7 +958,7 @@
for (size_t i = 0; i < testCase.fontLocales.size(); ++i) {
auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(kJAFont);
std::vector<Font> fonts;
- fonts.push_back(Font::Builder(minikinFont).build());
+ fonts.push_back(Font(minikinFont, FontStyle()));
auto family =
std::make_shared<FontFamily>(registerLocaleList(testCase.fontLocales[i]),
FontFamily::Variant::DEFAULT, std::move(fonts));
@@ -974,10 +974,10 @@
// First family doesn't support U+9AA8 and others support it, so the first font should not
// be selected.
- EXPECT_NE(firstFamilyMinikinFont.get(), runs[0].fakedFont.font->typeface().get());
+ EXPECT_NE(firstFamilyMinikinFont.get(), runs[0].fakedFont.font);
// Lookup used font family by MinikinFont*.
- const int usedLocaleIndex = fontLocaleIdxMap[runs[0].fakedFont.font->typeface().get()];
+ const int usedLocaleIndex = fontLocaleIdxMap[runs[0].fakedFont.font];
EXPECT_EQ(testCase.selectedFontIndex, usedLocaleIndex);
}
}
@@ -1545,10 +1545,10 @@
// selected.
std::vector<FontCollection::Run> runs;
itemize(collection, "U+35A8 U+E0100", &runs);
- EXPECT_EQ(familyA->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(familyA->getFont(0).get(), runs[0].fakedFont.font);
itemize(reversedCollection, "U+35A8 U+E0100", &runs);
- EXPECT_EQ(familyB->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(familyB->getFont(0).get(), runs[0].fakedFont.font);
}
// For b/29585939
@@ -1569,10 +1569,10 @@
// The first font should be selected.
std::vector<FontCollection::Run> runs;
itemize(collection, "U+5380 U+E0100", &runs);
- EXPECT_EQ(hasCmapFormat14Family->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(hasCmapFormat14Family->getFont(0).get(), runs[0].fakedFont.font);
itemize(reversedCollection, "U+5380 U+E0100", &runs);
- EXPECT_EQ(noCmapFormat14Family->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(noCmapFormat14Family->getFont(0).get(), runs[0].fakedFont.font);
}
} // namespace minikin
diff --git a/tests/unittest/FontFamilyTest.cpp b/tests/unittest/FontFamilyTest.cpp
index 402f26b..a0ed9be 100644
--- a/tests/unittest/FontFamilyTest.cpp
+++ b/tests/unittest/FontFamilyTest.cpp
@@ -725,7 +725,7 @@
for (auto familyStyle : testCase.familyStyles) {
std::shared_ptr<MinikinFont> dummyFont(new FreeTypeMinikinFontForTest(ROBOTO));
dummyFonts.push_back(dummyFont);
- fonts.push_back(Font::Builder(dummyFont).setStyle(familyStyle).build());
+ fonts.push_back(Font(dummyFont, familyStyle));
}
FontFamily family(std::move(fonts));
@@ -733,7 +733,7 @@
size_t idx = dummyFonts.size();
for (size_t i = 0; i < dummyFonts.size(); i++) {
- if (dummyFonts[i].get() == closest.font->typeface().get()) {
+ if (dummyFonts[i].get() == closest.font) {
idx = i;
break;
}
diff --git a/tests/unittest/HbFontCacheTest.cpp b/tests/unittest/HbFontCacheTest.cpp
new file mode 100644
index 0000000..2c88077
--- /dev/null
+++ b/tests/unittest/HbFontCacheTest.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 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 "HbFontCache.h"
+
+#include <memory>
+
+#include <gtest/gtest.h>
+#include <hb.h>
+
+#include "minikin/MinikinFont.h"
+
+#include "FreeTypeMinikinFontForTest.h"
+#include "MinikinInternal.h"
+
+namespace minikin {
+
+class HbFontCacheTest : public testing::Test {
+public:
+ virtual void TearDown() {
+ android::AutoMutex _l(gMinikinLock);
+ }
+};
+
+TEST_F(HbFontCacheTest, getHbFontLockedTest) {
+ auto fontA = std::make_shared<FreeTypeMinikinFontForTest>(kTestFontDir "Regular.ttf");
+ auto fontB = std::make_shared<FreeTypeMinikinFontForTest>(kTestFontDir "Bold.ttf");
+ auto fontC = std::make_shared<FreeTypeMinikinFontForTest>(kTestFontDir "BoldItalic.ttf");
+
+ android::AutoMutex _l(gMinikinLock);
+ // Never return NULL.
+ EXPECT_NE(nullptr, getHbFontLocked(fontA.get()));
+ EXPECT_NE(nullptr, getHbFontLocked(fontB.get()));
+ EXPECT_NE(nullptr, getHbFontLocked(fontC.get()));
+
+ EXPECT_NE(nullptr, getHbFontLocked(nullptr));
+
+ // Must return same object if same font object is passed.
+ EXPECT_EQ(getHbFontLocked(fontA.get()), getHbFontLocked(fontA.get()));
+ EXPECT_EQ(getHbFontLocked(fontB.get()), getHbFontLocked(fontB.get()));
+ EXPECT_EQ(getHbFontLocked(fontC.get()), getHbFontLocked(fontC.get()));
+
+ // Different object must be returned if the passed minikinFont has different ID.
+ EXPECT_NE(getHbFontLocked(fontA.get()), getHbFontLocked(fontB.get()));
+ EXPECT_NE(getHbFontLocked(fontA.get()), getHbFontLocked(fontC.get()));
+}
+
+} // namespace minikin
diff --git a/tests/util/FontTestUtils.cpp b/tests/util/FontTestUtils.cpp
index 699d53b..77199ac 100644
--- a/tests/util/FontTestUtils.cpp
+++ b/tests/util/FontTestUtils.cpp
@@ -88,16 +88,15 @@
continue;
}
- FontStyle style(weight, italic);
if (index == nullptr) {
std::shared_ptr<MinikinFont> minikinFont =
std::make_shared<FreeTypeMinikinFontForTest>(fontPath);
- fonts.push_back(Font::Builder(minikinFont).setStyle(style).build());
+ fonts.push_back(Font(minikinFont, FontStyle(weight, italic)));
} else {
std::shared_ptr<MinikinFont> minikinFont =
std::make_shared<FreeTypeMinikinFontForTest>(fontPath,
atoi((const char*)index));
- fonts.push_back(Font::Builder(minikinFont).setStyle(style).build());
+ fonts.push_back(Font(minikinFont, FontStyle(weight, italic)));
}
}
@@ -126,7 +125,7 @@
std::shared_ptr<FontFamily> buildFontFamily(const std::string& filePath) {
auto font = std::make_shared<FreeTypeMinikinFontForTest>(filePath);
std::vector<Font> fonts;
- fonts.push_back(Font::Builder(font).build());
+ fonts.push_back(Font(font, FontStyle()));
return std::make_shared<FontFamily>(std::move(fonts));
}
diff --git a/tests/util/FreeTypeMinikinFontForTest.h b/tests/util/FreeTypeMinikinFontForTest.h
index d63b2bf..f9e0e9f 100644
--- a/tests/util/FreeTypeMinikinFontForTest.h
+++ b/tests/util/FreeTypeMinikinFontForTest.h
@@ -58,7 +58,7 @@
FT_Library mFtLibrary;
FT_Face mFtFace;
- MINIKIN_PREVENT_COPY_AND_ASSIGN(FreeTypeMinikinFontForTest);
+ PREVENT_COPY_AND_ASSIGN(FreeTypeMinikinFontForTest);
};
} // namespace minikin