summaryrefslogtreecommitdiff
path: root/libs/minikin/FontFamily.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/minikin/FontFamily.cpp')
-rw-r--r--libs/minikin/FontFamily.cpp267
1 files changed, 180 insertions, 87 deletions
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);
+ 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);
+ }
+ }
}
-// Write fields other than mFonts.
-void FontFamily::writeToInternal(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);
- 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);
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>(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);
+ 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);
+ }
}
}
}
-void FontFamily::writeLocaleListInternal(BufferWriter* writer) const {
- LocaleListCache::writeTo(writer, mLocaleListId);
+// 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 @@ FakedFont FontFamily::getClosestMatch(FontStyle style) const {
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 @@ void FontFamily::computeCoverage() {
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 @@ bool FontFamily::hasGlyph(uint32_t codepoint, uint32_t variationSelector) const
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::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation(
}
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 @@ std::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation(
}
}
- return std::shared_ptr<FontFamily>(
- new FontFamily(mLocaleListId, mVariant, std::move(fonts), mIsCustomFallback));
+ return create(mLocaleListId, mVariant, std::move(fonts), mIsCustomFallback, mIsDefaultFallback);
}
} // namespace minikin