提交 62ad5653 编写于 作者: S Seigo Nonaka

Use std::mutex instead of android::Mutex

This CL includes:
- Stop using utils/Mutex and use std::mutex instead.
- Stop using utils/Singleton.

Test: minikin_tests passed
Change-Id: Ib3f75b83397a546472bb5f91e066e44506e78263
上级 c436e925
......@@ -26,6 +26,8 @@
namespace minikin {
class FontLanguages;
class FontCollection {
public:
explicit FontCollection(const std::vector<std::shared_ptr<FontFamily>>& typefaces);
......@@ -73,15 +75,16 @@ private:
void init(const std::vector<std::shared_ptr<FontFamily>>& typefaces);
const std::shared_ptr<FontFamily>& getFamilyForChar(uint32_t ch, uint32_t vs,
uint32_t langListId, int variant) const;
const FontLanguages& styleLanguages, int variant) const;
uint32_t calcFamilyScore(uint32_t ch, uint32_t vs, int variant, uint32_t langListId,
uint32_t calcFamilyScore(uint32_t ch, uint32_t vs, int variant,
const FontLanguages& styleLanguages,
const std::shared_ptr<FontFamily>& fontFamily) const;
uint32_t calcCoverageScore(uint32_t ch, uint32_t vs,
const std::shared_ptr<FontFamily>& fontFamily) const;
static uint32_t calcLanguageMatchingScore(uint32_t userLangListId,
static uint32_t calcLanguageMatchingScore(const FontLanguages& styleLanguages,
const FontFamily& fontFamily);
static uint32_t calcVariantMatchingScore(int variant, const FontFamily& fontFamily);
......
......@@ -31,6 +31,7 @@
namespace minikin {
class MinikinFont;
class FontLanguages;
// FontStyle represents all style information needed to select an actual font
// from a collection. The implementation is packed into two 32-bit words
......@@ -168,6 +169,7 @@ private:
int mVariant;
std::vector<Font> mFonts;
std::unordered_set<AxisTag> mSupportedAxes;
std::unique_ptr<FontLanguages> mLanguages;
SparseBitSet mCoverage;
bool mHasVSTable;
......
......@@ -91,7 +91,7 @@ FontCollection::FontCollection(const vector<std::shared_ptr<FontFamily>>& typefa
}
void FontCollection::init(const vector<std::shared_ptr<FontFamily>>& typefaces) {
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
mId = sNextId++;
vector<uint32_t> lastChar;
size_t nTypefaces = typefaces.size();
......@@ -171,7 +171,8 @@ const uint32_t kFirstFontScore = UINT32_MAX;
// base character.
// - kFirstFontScore: When the font is the first font family in the collection and it supports the
// given character or variation sequence.
uint32_t FontCollection::calcFamilyScore(uint32_t ch, uint32_t vs, int variant, uint32_t langListId,
uint32_t FontCollection::calcFamilyScore(uint32_t ch, uint32_t vs, int variant,
const FontLanguages& styleLanguages,
const std::shared_ptr<FontFamily>& fontFamily) const {
const uint32_t coverageScore = calcCoverageScore(ch, vs, fontFamily);
......@@ -180,7 +181,7 @@ uint32_t FontCollection::calcFamilyScore(uint32_t ch, uint32_t vs, int variant,
return coverageScore;
}
const uint32_t languageScore = calcLanguageMatchingScore(langListId, *fontFamily);
const uint32_t languageScore = calcLanguageMatchingScore(styleLanguages, *fontFamily);
const uint32_t variantScore = calcVariantMatchingScore(variant, *fontFamily);
// Subscores are encoded into 31 bits representation to meet the subscore priority.
......@@ -222,7 +223,7 @@ uint32_t FontCollection::calcCoverageScore(uint32_t ch, uint32_t vs,
}
if (vs == EMOJI_STYLE_VS || vs == TEXT_STYLE_VS) {
const FontLanguages& langs = FontLanguageListCache::getById(fontFamily->langId());
const FontLanguages& langs = getFontLanguagesFromCacheLocked(fontFamily->langId());
bool hasEmojiFlag = false;
for (size_t i = 0; i < langs.size(); ++i) {
if (langs[i].getEmojiStyle() == FontLanguage::EMSTYLE_EMOJI) {
......@@ -259,14 +260,13 @@ uint32_t FontCollection::calcCoverageScore(uint32_t ch, uint32_t vs,
// Here, m is the maximum number of languages to be compared, and s(i) is the i-th language's
// matching score. The possible values of s(i) are 0, 1, 2, 3 and 4.
uint32_t FontCollection::calcLanguageMatchingScore(
uint32_t userLangListId, const FontFamily& fontFamily) {
const FontLanguages& langList = FontLanguageListCache::getById(userLangListId);
const FontLanguages& fontLanguages = FontLanguageListCache::getById(fontFamily.langId());
const FontLanguages& styleLanguages, const FontFamily& fontFamily) {
const FontLanguages& fontLanguages = getFontLanguagesFromCacheLocked(fontFamily.langId());
const size_t maxCompareNum = std::min(langList.size(), FONT_LANGUAGES_LIMIT);
const size_t maxCompareNum = std::min(styleLanguages.size(), FONT_LANGUAGES_LIMIT);
uint32_t score = 0;
for (size_t i = 0; i < maxCompareNum; ++i) {
score = score * 5u + langList[i].calcScoreFor(fontLanguages);
score = score * 5u + styleLanguages[i].calcScoreFor(fontLanguages);
}
return score;
}
......@@ -284,7 +284,7 @@ uint32_t FontCollection::calcVariantMatchingScore(int variant, const FontFamily&
// 3. Highest score wins, with ties resolved to the first font.
// This method never returns nullptr.
const std::shared_ptr<FontFamily>& FontCollection::getFamilyForChar(uint32_t ch, uint32_t vs,
uint32_t langListId, int variant) const {
const FontLanguages& styleLanguages, int variant) const {
if (ch >= mMaxChar) {
return mFamilies[0];
}
......@@ -303,7 +303,7 @@ const std::shared_ptr<FontFamily>& FontCollection::getFamilyForChar(uint32_t ch,
for (size_t i = range.start; i < range.end; i++) {
const std::shared_ptr<FontFamily>& family =
vs == 0 ? mFamilies[mFamilyVec[i]] : mFamilies[i];
const uint32_t score = calcFamilyScore(ch, vs, variant, langListId, family);
const uint32_t score = calcFamilyScore(ch, vs, variant, styleLanguages, family);
if (score == kFirstFontScore) {
// If the first font family supports the given character or variation sequence, always
// use it.
......@@ -323,7 +323,7 @@ const std::shared_ptr<FontFamily>& FontCollection::getFamilyForChar(uint32_t ch,
if (U_SUCCESS(errorCode) && len > 0) {
int off = 0;
U16_NEXT_UNSAFE(decomposed, off, ch);
return getFamilyForChar(ch, vs, langListId, variant);
return getFamilyForChar(ch, vs, styleLanguages, variant);
}
}
return mFamilies[0];
......@@ -368,7 +368,7 @@ bool FontCollection::hasVariationSelector(uint32_t baseCodepoint,
return false;
}
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
// Currently mRanges can not be used here since it isn't aware of the variation sequence.
for (size_t i = 0; i < mVSFamilyVec.size(); i++) {
......@@ -381,8 +381,7 @@ bool FontCollection::hasVariationSelector(uint32_t baseCodepoint,
// for emoji + U+FE0E case since we have special fallback rule for the sequence.
if (isEmojiStyleVSBase(baseCodepoint) && variationSelector == TEXT_STYLE_VS) {
for (size_t i = 0; i < mFamilies.size(); ++i) {
if (!mFamilies[i]->isColorEmojiFamily() && variationSelector == TEXT_STYLE_VS &&
mFamilies[i]->hasGlyph(baseCodepoint, 0)) {
if (!mFamilies[i]->isColorEmojiFamily() && mFamilies[i]->hasGlyph(baseCodepoint, 0)) {
return true;
}
}
......@@ -393,7 +392,8 @@ bool FontCollection::hasVariationSelector(uint32_t baseCodepoint,
void FontCollection::itemize(const uint16_t *string, size_t string_size, FontStyle style,
vector<Run>* result) const {
const uint32_t langListId = style.getLanguageListId();
const FontLanguages& styleLanguages =
getFontLanguagesFromCacheLocked(style.getLanguageListId());
int variant = style.getVariant();
const FontFamily* lastFamily = nullptr;
Run* run = NULL;
......@@ -433,7 +433,7 @@ void FontCollection::itemize(const uint16_t *string, size_t string_size, FontSty
if (!shouldContinueRun) {
const std::shared_ptr<FontFamily>& family = getFamilyForChar(
ch, isVariationSelector(nextCh) ? nextCh : 0, langListId, variant);
ch, isVariationSelector(nextCh) ? nextCh : 0, styleLanguages, variant);
if (utf16Pos == 0 || family.get() != lastFamily) {
size_t start = utf16Pos;
// Workaround for combining marks and emoji modifiers until we implement
......
......@@ -41,7 +41,7 @@ using std::vector;
namespace minikin {
FontStyle::FontStyle(int variant, int weight, bool italic)
: FontStyle(FontLanguageListCache::kEmptyListId, variant, weight, italic) {
: FontStyle(kEmptyLanguageListId, variant, weight, italic) {
}
FontStyle::FontStyle(uint32_t languageListId, int variant, int weight, bool italic)
......@@ -56,8 +56,8 @@ android::hash_t FontStyle::hash() const {
// static
uint32_t FontStyle::registerLanguageList(const std::string& languages) {
android::AutoMutex _l(gMinikinLock);
return FontLanguageListCache::getId(languages);
ScopedLock _l(gLock);
return putLanguageListToCacheLocked(languages);
}
// static
......@@ -76,7 +76,7 @@ Font::Font(std::shared_ptr<MinikinFont>&& typeface, FontStyle style)
}
void Font::loadAxes() {
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
const uint32_t fvarTag = MinikinFont::MakeTag('f', 'v', 'a', 'r');
HbBlob fvarTable(getFontTable(typeface.get(), fvarTag));
if (fvarTable.size() == 0) {
......@@ -104,7 +104,7 @@ FontFamily::FontFamily(std::vector<Font>&& fonts) : FontFamily(0 /* variant */,
}
FontFamily::FontFamily(int variant, std::vector<Font>&& fonts)
: FontFamily(FontLanguageListCache::kEmptyListId, variant, std::move(fonts)) {
: FontFamily(kEmptyLanguageListId, variant, std::move(fonts)) {
}
FontFamily::FontFamily(uint32_t langId, int variant, std::vector<Font>&& fonts)
......@@ -117,7 +117,7 @@ FontFamily::~FontFamily() {
bool FontFamily::analyzeStyle(const std::shared_ptr<MinikinFont>& typeface, int* weight,
bool* italic) {
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
const uint32_t os2Tag = MinikinFont::MakeTag('O', 'S', '/', '2');
HbBlob os2Table(getFontTable(typeface.get(), os2Tag));
if (os2Table.get() == nullptr) return false;
......@@ -162,7 +162,7 @@ FakedFont FontFamily::getClosestMatch(FontStyle style) const {
}
bool FontFamily::isColorEmojiFamily() const {
const FontLanguages& languageList = FontLanguageListCache::getById(mLangId);
const FontLanguages& languageList = getFontLanguagesFromCacheLocked(mLangId);
for (size_t i = 0; i < languageList.size(); ++i) {
if (languageList[i].getEmojiStyle() == FontLanguage::EMSTYLE_EMOJI) {
return true;
......@@ -172,7 +172,7 @@ bool FontFamily::isColorEmojiFamily() const {
}
void FontFamily::computeCoverage() {
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
const FontStyle defaultStyle;
const MinikinFont* typeface = getClosestMatch(defaultStyle).font;
const uint32_t cmapTag = MinikinFont::MakeTag('c', 'm', 'a', 'p');
......@@ -190,7 +190,7 @@ void FontFamily::computeCoverage() {
}
bool FontFamily::hasGlyph(uint32_t codepoint, uint32_t variationSelector) const {
assertMinikinLocked();
assertLocked(gLock);
if (variationSelector != 0 && !mHasVSTable) {
// Early exit if the variation selector is specified but the font doesn't have a cmap format
// 14 subtable.
......
......@@ -20,6 +20,8 @@
#include <unicode/uloc.h>
#include <unordered_set>
#include <unordered_map>
#include <minikin/FontFamily.h>
#include <log/log.h>
......@@ -28,8 +30,6 @@
namespace minikin {
const uint32_t FontLanguageListCache::kEmptyListId;
// Returns the text length of output.
static size_t toLanguageTag(char* output, size_t outSize, const std::string& locale) {
output[0] = '\0';
......@@ -111,46 +111,61 @@ static std::vector<FontLanguage> parseLanguageList(const std::string& input) {
return result;
}
// static
uint32_t FontLanguageListCache::getId(const std::string& languages) {
FontLanguageListCache* inst = FontLanguageListCache::getInstance();
std::unordered_map<std::string, uint32_t>::const_iterator it =
inst->mLanguageListLookupTable.find(languages);
if (it != inst->mLanguageListLookupTable.end()) {
return it->second;
class FontLanguageListCache {
public:
FontLanguageListCache() {
// Insert an empty language list for mapping default language list to kEmptyListId.
// The default language list has only one FontLanguage and it is the unsupported language.
mLanguageLists.emplace(kEmptyLanguageListId, FontLanguages());
mLanguageListLookupTable.emplace("", kEmptyLanguageListId);
}
uint32_t put(const std::string& languages) {
assertLocked(gLock);
const auto& it = mLanguageListLookupTable.find(languages);
if (it != mLanguageListLookupTable.end()) {
return it->second;
}
// Given language list is not in cache. Insert it and return newly assigned ID.
const uint32_t nextId = mLanguageLists.size();
FontLanguages fontLanguages(parseLanguageList(languages));
if (fontLanguages.empty()) {
mLanguageListLookupTable.emplace(languages, kEmptyLanguageListId);
return kEmptyLanguageListId;
}
mLanguageLists.emplace(nextId, std::move(fontLanguages));
mLanguageListLookupTable.emplace(languages, nextId);
return nextId;
}
// Given language list is not in cache. Insert it and return newly assigned ID.
const uint32_t nextId = inst->mLanguageLists.size();
FontLanguages fontLanguages(parseLanguageList(languages));
if (fontLanguages.empty()) {
return kEmptyListId;
const FontLanguages& get(uint32_t id) {
assertLocked(gLock);
return mLanguageLists[id];
}
inst->mLanguageLists.push_back(std::move(fontLanguages));
inst->mLanguageListLookupTable.insert(std::make_pair(languages, nextId));
return nextId;
private:
std::unordered_map<uint32_t, FontLanguages> mLanguageLists;
// A map from string representation of the font language list to the ID.
std::unordered_map<std::string, uint32_t> mLanguageListLookupTable;
};
static FontLanguageListCache& getInstance() {
static FontLanguageListCache instance;
return instance;
}
// static
const FontLanguages& FontLanguageListCache::getById(uint32_t id) {
FontLanguageListCache* inst = FontLanguageListCache::getInstance();
LOG_ALWAYS_FATAL_IF(id >= inst->mLanguageLists.size(), "Lookup by unknown language list ID.");
return inst->mLanguageLists[id];
uint32_t putLanguageListToCacheLocked(const std::string& languages) {
return getInstance().put(languages);
}
// static
FontLanguageListCache* FontLanguageListCache::getInstance() {
assertMinikinLocked();
static FontLanguageListCache* instance = nullptr;
if (instance == nullptr) {
instance = new FontLanguageListCache();
// Insert an empty language list for mapping default language list to kEmptyListId.
// The default language list has only one FontLanguage and it is the unsupported language.
instance->mLanguageLists.push_back(FontLanguages());
instance->mLanguageListLookupTable.insert(std::make_pair("", kEmptyListId));
}
return instance;
const FontLanguages& getFontLanguagesFromCacheLocked(uint32_t id) {
return getInstance().get(id);
}
} // namespace minikin
......@@ -17,39 +17,21 @@
#ifndef MINIKIN_FONT_LANGUAGE_LIST_CACHE_H
#define MINIKIN_FONT_LANGUAGE_LIST_CACHE_H
#include <unordered_map>
#include <minikin/FontFamily.h>
#include "FontLanguage.h"
namespace minikin {
class FontLanguageListCache {
public:
// A special ID for the empty language list.
// This value must be 0 since the empty language list is inserted into mLanguageLists by
// default.
const static uint32_t kEmptyListId = 0;
// Returns language list ID for the given string representation of FontLanguages.
// Caller should acquire a lock before calling the method.
static uint32_t getId(const std::string& languages);
// Caller should acquire a lock before calling the method.
static const FontLanguages& getById(uint32_t id);
private:
FontLanguageListCache() {} // Singleton
~FontLanguageListCache() {}
// Caller should acquire a lock before calling the method.
static FontLanguageListCache* getInstance();
// A special ID for the empty language list.
// This value must be 0 since the empty language list is inserted into mLanguageLists by default.
const uint32_t kEmptyLanguageListId = 0;
std::vector<FontLanguages> mLanguageLists;
// Looks up from internal cache and returns associated ID if FontLanguages constructed from given
// string is already registered. If it is new to internal cache, put it to internal cache and
// returns newly assigned ID.
uint32_t putLanguageListToCacheLocked(const std::string& languages);
// A map from string representation of the font language list to the ID.
std::unordered_map<std::string, uint32_t> mLanguageListLookupTable;
};
// Returns FontLanguages associated with given ID.
const FontLanguages& getFontLanguagesFromCacheLocked(uint32_t id);
} // namespace minikin
......
......@@ -62,70 +62,80 @@ private:
android::LruCache<int32_t, hb_font_t*> mCache;
};
HbFontCache* getFontCacheLocked() {
assertMinikinLocked();
static HbFontCache* cache = nullptr;
if (cache == nullptr) {
cache = new HbFontCache();
class HbFontCacheHolder {
public:
HbFontCacheHolder() {}
hb_font_t* getCachedFont(const MinikinFont* minikinFont) {
assertLocked(gLock);
// 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);
}
const int32_t fontId = minikinFont->GetUniqueId();
hb_font_t* font = mFontCache.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);
hb_font_destroy(parent_font);
hb_face_destroy(face);
mFontCache.put(fontId, font);
return hb_font_reference(font);
}
void clearFontCache() {
assertLocked(gLock);
mFontCache.clear();
}
return cache;
void removeFont(const MinikinFont* minikinFont) {
assertLocked(gLock);
mFontCache.remove(minikinFont->GetUniqueId());
}
private:
HbFontCache mFontCache;
};
static HbFontCacheHolder& getInstance() {
static HbFontCacheHolder instance;
return instance;
}
void purgeHbFontCacheLocked() {
assertMinikinLocked();
getFontCacheLocked()->clear();
getInstance().clearFontCache();
}
void purgeHbFontLocked(const MinikinFont* minikinFont) {
assertMinikinLocked();
const int32_t fontId = minikinFont->GetUniqueId();
getFontCacheLocked()->remove(fontId);
getInstance().removeFont(minikinFont);
}
// 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);
return getInstance().getCachedFont(minikinFont);
}
} // namespace minikin
......@@ -28,7 +28,6 @@
#include <log/log.h>
#include <utils/JenkinsHash.h>
#include <utils/LruCache.h>
#include <utils/Singleton.h>
#include <utils/String16.h>
#include <hb-icu.h>
......@@ -201,7 +200,7 @@ static unsigned int disabledDecomposeCompatibility(hb_unicode_funcs_t*, hb_codep
return 0;
}
class LayoutEngine : public ::android::Singleton<LayoutEngine> {
class LayoutEngine {
public:
LayoutEngine() {
unicodeFunctions = hb_unicode_funcs_create(hb_icu_get_unicode_funcs());
......@@ -212,8 +211,26 @@ public:
hb_buffer_set_unicode_funcs(hbBuffer, unicodeFunctions);
}
Layout* getCachedLayout(LayoutCacheKey& key, LayoutContext* ctx,
const std::shared_ptr<FontCollection>& collection) {
assertLocked(gLock);
return layoutCache.get(key, ctx, collection);
}
void clearLayoutCache() {
assertLocked(gLock);
layoutCache.clear();
}
hb_buffer_t* hbBuffer;
hb_unicode_funcs_t* unicodeFunctions;
static LayoutEngine& getInstance() {
static LayoutEngine instance;
return instance;
}
private:
LayoutCache layoutCache;
};
......@@ -288,8 +305,7 @@ static hb_bool_t harfbuzzGetGlyphHorizontalOrigin(hb_font_t* /* hbFont */, void*
}
hb_font_funcs_t* getHbFontFuncs(bool forColorBitmapFont) {
assertMinikinLocked();
assertLocked(gLock);
static hb_font_funcs_t* hbFuncs = nullptr;
static hb_font_funcs_t* hbFuncsForColorBitmap = nullptr;
......@@ -585,8 +601,7 @@ BidiText::BidiText(const uint16_t* buf, size_t start, size_t count, size_t bufSi
void Layout::doLayout(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
int bidiFlags, const FontStyle &style, const MinikinPaint &paint) {
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
LayoutContext ctx;
ctx.style = style;
ctx.paint = paint;
......@@ -604,8 +619,7 @@ void Layout::doLayout(const uint16_t* buf, size_t start, size_t count, size_t bu
float Layout::measureText(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
int bidiFlags, const FontStyle &style, const MinikinPaint &paint,
const std::shared_ptr<FontCollection>& collection, float* advances) {
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
LayoutContext ctx;
ctx.style = style;
ctx.paint = paint;
......@@ -677,7 +691,6 @@ float Layout::doLayoutRunCached(const uint16_t* buf, size_t start, size_t count,
float Layout::doLayoutWord(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
bool isRtl, LayoutContext* ctx, size_t bufStart,
const std::shared_ptr<FontCollection>& collection, Layout* layout, float* advances) {
LayoutCache& cache = LayoutEngine::getInstance().layoutCache;
LayoutCacheKey key(collection, ctx->paint, ctx->style, buf, start, count, bufSize, isRtl);
float wordSpacing = count == 1 && isWordSpace(buf[start]) ? ctx->paint.wordSpacing : 0;
......@@ -694,7 +707,7 @@ float Layout::doLayoutWord(const uint16_t* buf, size_t start, size_t count, size
}
advance = layoutForWord.getAdvance();
} else {
Layout* layoutForWord = cache.get(key, ctx, collection);
Layout* layoutForWord = LayoutEngine::getInstance().getCachedLayout(key, ctx, collection);
if (layout) {
layout->appendLayout(layoutForWord, bufStart, wordSpacing);
}
......@@ -947,7 +960,7 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
hb_buffer_set_script(buffer, script);
hb_buffer_set_direction(buffer, isRtl? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
const FontLanguages& langList =
FontLanguageListCache::getById(ctx->style.getLanguageListId());
getFontLanguagesFromCacheLocked(ctx->style.getLanguageListId());
if (langList.size() != 0) {
const FontLanguage* hbLanguage = &langList[0];
for (size_t i = 0; i < langList.size(); ++i) {
......@@ -1149,17 +1162,9 @@ void Layout::getBounds(MinikinRect* bounds) const {
}
void Layout::purgeCaches() {
android::AutoMutex _l(gMinikinLock);
LayoutCache& layoutCache = LayoutEngine::getInstance().layoutCache;
layoutCache.clear();
ScopedLock _l(gLock);
LayoutEngine::getInstance().clearLayoutCache();
purgeHbFontCacheLocked();
}
} // 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
......@@ -21,7 +21,7 @@
namespace minikin {
MinikinFont::~MinikinFont() {
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
purgeHbFontLocked(this);
}
......
......@@ -25,13 +25,8 @@
namespace minikin {
android::Mutex gMinikinLock;
void assertMinikinLocked() {
#ifdef ENABLE_RACE_DETECTION
LOG_ALWAYS_FATAL_IF(gMinikinLock.tryLock() == 0);
#endif
}
std::mutex gMutex;
std::unique_lock<std::mutex> gLock(gMutex, std::defer_lock);
bool isEmoji(uint32_t c) {
// U+2695 U+2640 U+2642 are not in emoji category in Unicode 9 but they are now emoji category.
......@@ -86,7 +81,7 @@ bool isEmojiBase(uint32_t c) {
}
hb_blob_t* getFontTable(const MinikinFont* minikinFont, uint32_t tag) {
assertMinikinLocked();
assertLocked(gLock);
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);
......
......@@ -21,20 +21,27 @@
#include <hb.h>
#include <utils/Mutex.h>
#include <minikin/MinikinFont.h>
#include <log/log.h>
#include <mutex>
namespace minikin {
// All external Minikin interfaces are designed to be thread-safe.
// Presently, that's implemented by through a global lock, and having
// all external interfaces take that lock.
extern android::Mutex gMinikinLock;
// Presently, that's implemented by a global lock, and having all external interfaces take that
// lock.
extern std::unique_lock<std::mutex> gLock;
typedef std::unique_lock<std::unique_lock<std::mutex>> ScopedLock;
#ifdef ENABLE_RACE_DETECTION
inline void assertLocked(const std::unique_lock<std::mutex>& lock) {
LOG_ALWAYS_FATAL_IF(!lock.owns_lock());
}
#else
inline void assertLocked(const std::unique_lock<std::mutex>&) {}
#endif
// Aborts if gMinikinLock is not acquired. Do nothing on the release build.
void assertMinikinLocked();
// Returns true if c is emoji.
bool isEmoji(uint32_t c);
......
......@@ -77,7 +77,7 @@ static void BM_FontCollection_itemize(benchmark::State& state) {
std::vector<FontCollection::Run> result;
FontStyle style(FontStyle::registerLanguageList(ITEMIZE_TEST_CASES[testIndex].languageTag));
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
while (state.KeepRunning()) {
result.clear();
collection->itemize(buffer, utf16_length, style, &result);
......
......@@ -60,7 +60,7 @@ void itemize(const std::shared_ptr<FontCollection>& collection, const char* str,
result->clear();
ParseUnicode(buf, BUF_SIZE, str, &len, NULL);
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
collection->itemize(buf, len, style, result);
}
......@@ -72,8 +72,8 @@ const std::string& getFontPath(const FontCollection::Run& run) {
// Utility function to obtain FontLanguages from string.
const FontLanguages& registerAndGetFontLanguages(const std::string& lang_string) {
android::AutoMutex _l(gMinikinLock);
return FontLanguageListCache::getById(FontLanguageListCache::getId(lang_string));
ScopedLock _l(gLock);
return getFontLanguagesFromCacheLocked(putLanguageListToCacheLocked(lang_string));
}
TEST_F(FontCollectionItemizeTest, itemize_latin) {
......
......@@ -30,15 +30,15 @@ typedef ICUTestBase FontLanguagesTest;
typedef ICUTestBase FontLanguageTest;
static const FontLanguages& createFontLanguages(const std::string& input) {
android::AutoMutex _l(gMinikinLock);
uint32_t langId = FontLanguageListCache::getId(input);
return FontLanguageListCache::getById(langId);
ScopedLock _l(gLock);
uint32_t langId = putLanguageListToCacheLocked(input);
return getFontLanguagesFromCacheLocked(langId);
}
static FontLanguage createFontLanguage(const std::string& input) {
android::AutoMutex _l(gMinikinLock);
uint32_t langId = FontLanguageListCache::getId(input);
return FontLanguageListCache::getById(langId)[0];
ScopedLock _l(gLock);
uint32_t langId = putLanguageListToCacheLocked(input);
return getFontLanguagesFromCacheLocked(langId)[0];
}
static FontLanguage createFontLanguageWithoutICUSanitization(const std::string& input) {
......@@ -533,7 +533,7 @@ TEST_F(FontFamilyTest, hasVariationSelectorTest) {
std::shared_ptr<FontFamily> family(
new FontFamily(std::vector<Font>{ Font(minikinFont, FontStyle()) }));
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
const uint32_t kVS1 = 0xFE00;
const uint32_t kVS2 = 0xFE01;
......@@ -586,7 +586,7 @@ TEST_F(FontFamilyTest, hasVSTableTest) {
new MinikinFontForTest(testCase.fontPath));
std::shared_ptr<FontFamily> family(new FontFamily(
std::vector<Font>{ Font(minikinFont, FontStyle()) }));
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
EXPECT_EQ(testCase.hasVSTable, family->hasVSTable());
}
}
......
......@@ -31,40 +31,43 @@ TEST_F(FontLanguageListCacheTest, getId) {
EXPECT_NE(0UL, FontStyle::registerLanguageList("jp"));
EXPECT_NE(0UL, FontStyle::registerLanguageList("en,zh-Hans"));
android::AutoMutex _l(gMinikinLock);
EXPECT_EQ(0UL, FontLanguageListCache::getId(""));
EXPECT_EQ(FontLanguageListCache::getId("en"), FontLanguageListCache::getId("en"));
EXPECT_NE(FontLanguageListCache::getId("en"), FontLanguageListCache::getId("jp"));
EXPECT_EQ(FontLanguageListCache::getId("en,zh-Hans"),
FontLanguageListCache::getId("en,zh-Hans"));
EXPECT_NE(FontLanguageListCache::getId("en,zh-Hans"),
FontLanguageListCache::getId("zh-Hans,en"));
EXPECT_NE(FontLanguageListCache::getId("en,zh-Hans"),
FontLanguageListCache::getId("jp"));
EXPECT_NE(FontLanguageListCache::getId("en,zh-Hans"),
FontLanguageListCache::getId("en"));
EXPECT_NE(FontLanguageListCache::getId("en,zh-Hans"),
FontLanguageListCache::getId("en,zh-Hant"));
ScopedLock _l(gLock);
EXPECT_EQ(0UL, putLanguageListToCacheLocked(""));
EXPECT_EQ(putLanguageListToCacheLocked("en"), putLanguageListToCacheLocked("en"));
EXPECT_NE(putLanguageListToCacheLocked("en"), putLanguageListToCacheLocked("jp"));
EXPECT_EQ(putLanguageListToCacheLocked("en,zh-Hans"),
putLanguageListToCacheLocked("en,zh-Hans"));
EXPECT_NE(putLanguageListToCacheLocked("en,zh-Hans"),
putLanguageListToCacheLocked("zh-Hans,en"));
EXPECT_NE(putLanguageListToCacheLocked("en,zh-Hans"),
putLanguageListToCacheLocked("jp"));
EXPECT_NE(putLanguageListToCacheLocked("en,zh-Hans"),
putLanguageListToCacheLocked("en"));
EXPECT_NE(putLanguageListToCacheLocked("en,zh-Hans"),
putLanguageListToCacheLocked("en,zh-Hant"));
}
TEST_F(FontLanguageListCacheTest, getById) {
android::AutoMutex _l(gMinikinLock);
uint32_t enLangId = FontLanguageListCache::getId("en");
uint32_t jpLangId = FontLanguageListCache::getId("jp");
FontLanguage english = FontLanguageListCache::getById(enLangId)[0];
FontLanguage japanese = FontLanguageListCache::getById(jpLangId)[0];
ScopedLock _l(gLock);
uint32_t enLangId = putLanguageListToCacheLocked("en");
uint32_t jpLangId = putLanguageListToCacheLocked("jp");
FontLanguage english = getFontLanguagesFromCacheLocked(enLangId)[0];
FontLanguage japanese = getFontLanguagesFromCacheLocked(jpLangId)[0];
const FontLanguages& defLangs = FontLanguageListCache::getById(0);
const FontLanguages& defLangs = getFontLanguagesFromCacheLocked(0);
EXPECT_TRUE(defLangs.empty());
const FontLanguages& langs = FontLanguageListCache::getById(FontLanguageListCache::getId("en"));
const FontLanguages& langs = getFontLanguagesFromCacheLocked(
putLanguageListToCacheLocked("en"));
ASSERT_EQ(1UL, langs.size());
EXPECT_EQ(english, langs[0]);
const FontLanguages& langs2 =
FontLanguageListCache::getById(FontLanguageListCache::getId("en,jp"));
const FontLanguages& langs2 = getFontLanguagesFromCacheLocked(
putLanguageListToCacheLocked("en,jp"));
ASSERT_EQ(2UL, langs2.size());
EXPECT_EQ(english, langs2[0]);
EXPECT_EQ(japanese, langs2[1]);
......
......@@ -18,7 +18,6 @@
#include <android/log.h>
#include <gtest/gtest.h>
#include <utils/Mutex.h>
#include <memory>
......@@ -33,7 +32,7 @@ namespace minikin {
class HbFontCacheTest : public testing::Test {
public:
virtual void TearDown() {
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
purgeHbFontCacheLocked();
}
};
......@@ -48,7 +47,8 @@ TEST_F(HbFontCacheTest, getHbFontLockedTest) {
std::shared_ptr<MinikinFontForTest> fontC(
new MinikinFontForTest(kTestFontDir "BoldItalic.ttf"));
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
// Never return NULL.
EXPECT_NE(nullptr, getHbFontLocked(fontA.get()));
EXPECT_NE(nullptr, getHbFontLocked(fontB.get()));
......@@ -70,7 +70,8 @@ TEST_F(HbFontCacheTest, purgeCacheTest) {
std::shared_ptr<MinikinFontForTest> minikinFont(
new MinikinFontForTest(kTestFontDir "Regular.ttf"));
android::AutoMutex _l(gMinikinLock);
ScopedLock _l(gLock);
hb_font_t* font = getHbFontLocked(minikinFont.get());
ASSERT_NE(nullptr, font);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册