Merge "Revert "Introduce createCollectionWithVariation.""

This commit is contained in:
Siyamed Sinir
2017-01-20 01:59:47 +00:00
committed by Android (Google) Code Review
14 changed files with 55 additions and 365 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2013 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.
@@ -14,15 +14,12 @@
* limitations under the License.
*/
#ifndef MINIKIN_FONT_UTILS_H
#define MINIKIN_FONT_UTILS_H
#include <unordered_set>
#ifndef MINIKIN_ANALYZE_STYLE_H
#define MINIKIN_ANALYZE_STYLE_H
namespace minikin {
bool analyzeStyle(const uint8_t* os2_data, size_t os2_size, int* weight, bool* italic);
void analyzeAxes(const uint8_t* fvar_data, size_t fvar_size, std::unordered_set<uint32_t>* axes);
} // namespace minikin

View File

@@ -18,7 +18,6 @@
#define MINIKIN_FONT_COLLECTION_H
#include <vector>
#include <unordered_set>
#include <minikin/MinikinRefCounted.h>
#include <minikin/MinikinFont.h>
@@ -52,10 +51,6 @@ public:
// Get base font with fakery information (fake bold could affect metrics)
FakedFont baseFontFaked(FontStyle style);
// Creates new FontCollection based on this collection while applying font variations. Returns
// nullptr if none of variations apply to this collection.
FontCollection* createCollectionWithVariation(const std::vector<FontVariation>& variations);
uint32_t getId() const;
private:
@@ -101,9 +96,6 @@ private:
// These are offsets into mInstanceVec, one range per page
std::vector<Range> mRanges;
// Set of supported axes in this collection.
std::unordered_set<AxisTag> mSupportedAxes;
};
} // namespace minikin

View File

@@ -19,7 +19,6 @@
#include <vector>
#include <string>
#include <unordered_set>
#include <hb.h>
#include <utils/TypeHelpers.h>
@@ -99,8 +98,6 @@ struct FakedFont {
FontFakery fakery;
};
typedef uint32_t AxisTag;
struct Font {
Font(MinikinFont* typeface, FontStyle style);
Font(Font&& o);
@@ -109,13 +106,6 @@ struct Font {
MinikinFont* typeface;
FontStyle style;
std::unordered_set<AxisTag> supportedAxes;
};
struct FontVariation {
FontVariation(AxisTag axisTag, float value) : axisTag(axisTag), value(value) {}
AxisTag axisTag;
float value;
};
class FontFamily : public MinikinRefCounted {
@@ -139,7 +129,6 @@ public:
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; }
// Get Unicode coverage.
const SparseBitSet& getCoverage() const { return mCoverage; }
@@ -151,16 +140,12 @@ public:
// Returns true if this font family has a variaion sequence table (cmap format 14 subtable).
bool hasVSTable() const { return mHasVSTable; }
// Creates new FontFamily based on this family while applying font variations. Returns nullptr
// if none of variations apply to this family.
FontFamily* createFamilyWithVariation(const std::vector<FontVariation>& variations) const;
private:
void computeCoverage();
uint32_t mLangId;
int mVariant;
std::vector<Font> mFonts;
std::unordered_set<AxisTag> mSupportedAxes;
SparseBitSet mCoverage;
bool mHasVSTable;

View File

@@ -126,10 +126,6 @@ public:
return 0;
}
virtual MinikinFont* createFontWithVariation(const std::vector<FontVariation>&) const {
return nullptr;
}
static uint32_t MakeTag(char c1, char c2, char c3, char c4) {
return ((uint32_t)c1 << 24) | ((uint32_t)c2 << 16) |
((uint32_t)c3 << 8) | (uint32_t)c4;

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2013 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 <stdlib.h>
#include <stdint.h>
#include <minikin/AnalyzeStyle.h>
namespace minikin {
// should we have a single FontAnalyzer class this stuff lives in, to avoid dup?
static int32_t readU16(const uint8_t* data, size_t offset) {
return data[offset] << 8 | data[offset + 1];
}
bool analyzeStyle(const uint8_t* os2_data, size_t os2_size, int* weight, bool* italic) {
const size_t kUsWeightClassOffset = 4;
const size_t kFsSelectionOffset = 62;
const uint16_t kItalicFlag = (1 << 0);
if (os2_size < kFsSelectionOffset + 2) {
return false;
}
uint16_t weightClass = readU16(os2_data, kUsWeightClassOffset);
*weight = weightClass / 100;
uint16_t fsSelection = readU16(os2_data, kFsSelectionOffset);
*italic = (fsSelection & kItalicFlag) != 0;
return true;
}
} // namespace minikin

View File

@@ -30,12 +30,12 @@ $(UNICODE_EMOJI_H):
include $(CLEAR_VARS)
minikin_src_files := \
AnalyzeStyle.cpp \
CmapCoverage.cpp \
FontCollection.cpp \
FontFamily.cpp \
FontLanguage.cpp \
FontLanguageListCache.cpp \
FontUtils.cpp \
GraphemeBreak.cpp \
HbFontCache.cpp \
Hyphenator.cpp \

View File

@@ -103,9 +103,6 @@ FontCollection::FontCollection(const vector<FontFamily*>& typefaces) :
}
mMaxChar = max(mMaxChar, coverage.length());
lastChar.push_back(coverage.nextSetBit(0));
const std::unordered_set<AxisTag>& supportedAxes = family->supportedAxes();
mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end());
}
nTypefaces = mFamilies.size();
LOG_ALWAYS_FATAL_IF(nTypefaces == 0,
@@ -464,42 +461,6 @@ FakedFont FontCollection::baseFontFaked(FontStyle style) {
return mFamilies[0]->getClosestMatch(style);
}
FontCollection* FontCollection::createCollectionWithVariation(
const std::vector<FontVariation>& variations) {
if (variations.empty() || mSupportedAxes.empty()) {
return nullptr;
}
bool hasSupportedAxis = false;
for (const FontVariation& variation : variations) {
if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end()) {
hasSupportedAxis = true;
break;
}
}
if (!hasSupportedAxis) {
// None of variation axes are supported by this font collection.
return nullptr;
}
std::vector<FontFamily*> families;
for (FontFamily* family : mFamilies) {
FontFamily* newFamily = family->createFamilyWithVariation(variations);
if (newFamily) {
families.push_back(newFamily);
} else {
family->Ref();
families.push_back(family);
}
}
FontCollection* result = new FontCollection(families);
for (FontFamily* family : families) {
family->Unref();
}
return result;
}
uint32_t FontCollection::getId() const {
return mId;
}

View File

@@ -28,11 +28,10 @@
#include "FontLanguage.h"
#include "FontLanguageListCache.h"
#include "FontUtils.h"
#include "HbFontCache.h"
#include "MinikinInternal.h"
#include <minikin/AnalyzeStyle.h>
#include <minikin/CmapCoverage.h>
#include <minikin/MinikinFont.h>
#include <minikin/FontFamily.h>
#include <minikin/MinikinFont.h>
@@ -67,30 +66,19 @@ uint32_t FontStyle::pack(int variant, int weight, bool italic) {
Font::Font(MinikinFont* typeface, FontStyle style)
: typeface(typeface), style(style) {
android::AutoMutex _l(gMinikinLock);
typeface->RefLocked();
const uint32_t fvarTag = MinikinFont::MakeTag('f', 'v', 'a', 'r');
HbBlob fvarTable(getFontTable(typeface, fvarTag));
if (fvarTable.size() == 0) {
return;
}
analyzeAxes(fvarTable.get(), fvarTable.size(), &supportedAxes);
typeface->Ref();
}
Font::Font(Font&& o) {
typeface = o.typeface;
style = o.style;
o.typeface = nullptr;
supportedAxes = std::move(o.supportedAxes);
}
Font::Font(const Font& o) {
typeface = o.typeface;
typeface->Ref();
style = o.style;
supportedAxes = o.supportedAxes;
}
Font::~Font() {
@@ -186,10 +174,9 @@ void FontFamily::computeCoverage() {
}
// TODO: Error check?
CmapCoverage::getCoverage(mCoverage, cmapTable.get(), cmapTable.size(), &mHasVSTable);
for (size_t i = 0; i < mFonts.size(); ++i) {
mSupportedAxes.insert(mFonts[i].supportedAxes.begin(), mFonts[i].supportedAxes.end());
}
#ifdef VERBOSE_DEBUG
ALOGD("font coverage length=%d, first ch=%x\n", mCoverage.length(), mCoverage.nextSetBit(0));
#endif
}
bool FontFamily::hasGlyph(uint32_t codepoint, uint32_t variationSelector) const {
@@ -209,48 +196,4 @@ bool FontFamily::hasGlyph(uint32_t codepoint, uint32_t variationSelector) const
return result;
}
FontFamily* FontFamily::createFamilyWithVariation(
const std::vector<FontVariation>& variations) const {
if (variations.empty() || mSupportedAxes.empty()) {
return nullptr;
}
bool hasSupportedAxis = false;
for (const FontVariation& variation : variations) {
if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end()) {
hasSupportedAxis = true;
break;
}
}
if (!hasSupportedAxis) {
// None of variation axes are suppored by this family.
return nullptr;
}
std::vector<Font> fonts;
for (const Font& font : mFonts) {
bool supportedVariations = false;
if (!font.supportedAxes.empty()) {
for (const FontVariation& variation : variations) {
if (font.supportedAxes.find(variation.axisTag) != font.supportedAxes.end()) {
supportedVariations = true;
break;
}
}
}
MinikinFont* minikinFont = nullptr;
if (supportedVariations) {
minikinFont = font.typeface->createFontWithVariation(variations);
}
if (minikinFont == nullptr) {
minikinFont = font.typeface;
minikinFont->Ref();
}
fonts.push_back(Font(minikinFont, font.style));
minikinFont->Unref();
}
return new FontFamily(mLangId, mVariant, std::move(fonts));
}
} // namespace minikin

View File

@@ -1,77 +0,0 @@
/*
* 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 <stdlib.h>
#include <stdint.h>
#include "FontUtils.h"
namespace minikin {
static uint16_t readU16(const uint8_t* data, size_t offset) {
return data[offset] << 8 | data[offset + 1];
}
static uint32_t readU32(const uint8_t* data, size_t offset) {
return ((uint32_t)data[offset]) << 24 | ((uint32_t)data[offset + 1]) << 16 |
((uint32_t)data[offset + 2]) << 8 | ((uint32_t)data[offset + 3]);
}
bool analyzeStyle(const uint8_t* os2_data, size_t os2_size, int* weight, bool* italic) {
const size_t kUsWeightClassOffset = 4;
const size_t kFsSelectionOffset = 62;
const uint16_t kItalicFlag = (1 << 0);
if (os2_size < kFsSelectionOffset + 2) {
return false;
}
uint16_t weightClass = readU16(os2_data, kUsWeightClassOffset);
*weight = weightClass / 100;
uint16_t fsSelection = readU16(os2_data, kFsSelectionOffset);
*italic = (fsSelection & kItalicFlag) != 0;
return true;
}
void analyzeAxes(const uint8_t* fvar_data, size_t fvar_size, std::unordered_set<uint32_t>* axes) {
const size_t kMajorVersionOffset = 0;
const size_t kMinorVersionOffset = 2;
const size_t kOffsetToAxesArrayOffset = 4;
const size_t kAxisCountOffset = 8;
const size_t kAxisSizeOffset = 10;
axes->clear();
if (fvar_size < kAxisSizeOffset + 2) {
return;
}
const uint16_t majorVersion = readU16(fvar_data, kMajorVersionOffset);
const uint16_t minorVersion = readU16(fvar_data, kMinorVersionOffset);
const uint32_t axisOffset = readU16(fvar_data, kOffsetToAxesArrayOffset);
const uint32_t axisCount = readU16(fvar_data, kAxisCountOffset);
const uint32_t axisSize = readU16(fvar_data, kAxisSizeOffset);
if (majorVersion != 1 || minorVersion != 0 || axisOffset != 0x10 || axisSize != 0x14) {
return; // Unsupported version.
}
if (fvar_size < axisOffset + axisOffset * axisCount) {
return; // Invalid table size.
}
for (uint32_t i = 0; i < axisCount; ++i) {
size_t axisRecordOffset = axisOffset + i * axisSize;
uint32_t tag = readU32(fvar_data, axisRecordOffset);
axes->insert(tag);
}
}
} // namespace minikin

View File

@@ -27,7 +27,6 @@ LOCAL_TEST_DATA := \
data/Italic.ttf \
data/Ja.ttf \
data/Ko.ttf \
data/MultiAxis.ttf \
data/NoCmapFormat14.ttf \
data/NoGlyphFont.ttf \
data/Regular.ttf \

View File

@@ -121,76 +121,4 @@ TEST(FontCollectionTest, newEmojiTest) {
EXPECT_FALSE(collection->hasVariationSelector(0x2642, 0xFE0F));
}
TEST(FontCollectionTest, createWithVariations) {
// This font has 'wdth' and 'wght' axes.
const char kMultiAxisFont[] = kTestFontDir "/MultiAxis.ttf";
const char kNoAxisFont[] = kTestFontDir "/Regular.ttf";
MinikinAutoUnref<MinikinFont> multiAxisFont(new MinikinFontForTest(kMultiAxisFont));
MinikinAutoUnref<FontFamily> multiAxisFamily(new FontFamily(
std::vector<Font>({ Font(multiAxisFont.get(), FontStyle()) })));
std::vector<FontFamily*> multiAxisFamilies({multiAxisFamily.get()});
MinikinAutoUnref<FontCollection> multiAxisFc(new FontCollection(multiAxisFamilies));
MinikinAutoUnref<MinikinFont> noAxisFont(new MinikinFontForTest(kNoAxisFont));
MinikinAutoUnref<FontFamily> noAxisFamily(new FontFamily(
std::vector<Font>({ Font(noAxisFont.get(), FontStyle()) })));
std::vector<FontFamily*> noAxisFamilies({noAxisFamily.get()});
MinikinAutoUnref<FontCollection> noAxisFc(new FontCollection(noAxisFamilies));
{
// Do not ceate new instance if none of variations are specified.
EXPECT_EQ(nullptr,
multiAxisFc->createCollectionWithVariation(std::vector<FontVariation>()));
EXPECT_EQ(nullptr,
noAxisFc->createCollectionWithVariation(std::vector<FontVariation>()));
}
{
// New instance should be used for supported variation.
std::vector<FontVariation> variations = {
{ MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f }
};
MinikinAutoUnref<FontCollection> newFc(
multiAxisFc->createCollectionWithVariation(variations));
EXPECT_NE(nullptr, newFc.get());
EXPECT_NE(multiAxisFc.get(), newFc.get());
EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation(variations));
}
{
// New instance should be used for supported variation (multiple variations case).
std::vector<FontVariation> variations = {
{ MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f },
{ MinikinFont::MakeTag('w', 'g', 'h', 't'), 1.0f }
};
MinikinAutoUnref<FontCollection> newFc(
multiAxisFc->createCollectionWithVariation(variations));
EXPECT_NE(nullptr, newFc.get());
EXPECT_NE(multiAxisFc.get(), newFc.get());
EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation(variations));
}
{
// Do not ceate new instance if none of variations are supported.
std::vector<FontVariation> variations = {
{ MinikinFont::MakeTag('Z', 'Z', 'Z', 'Z'), 1.0f }
};
EXPECT_EQ(nullptr, multiAxisFc->createCollectionWithVariation(variations));
EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation(variations));
}
{
// At least one axis is supported, should create new instance.
std::vector<FontVariation> variations = {
{ MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f },
{ MinikinFont::MakeTag('Z', 'Z', 'Z', 'Z'), 1.0f }
};
MinikinAutoUnref<FontCollection> newFc(
multiAxisFc->createCollectionWithVariation(variations));
EXPECT_NE(nullptr, newFc.get());
EXPECT_NE(multiAxisFc.get(), newFc.get());
EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation(variations));
}
}
} // namespace minikin

View File

@@ -527,67 +527,4 @@ TEST_F(FontFamilyTest, hasVSTableTest) {
}
}
TEST_F(FontFamilyTest, createFamilyWithVariationTest) {
// This font has 'wdth' and 'wght' axes.
const char kMultiAxisFont[] = kTestFontDir "/MultiAxis.ttf";
const char kNoAxisFont[] = kTestFontDir "/Regular.ttf";
MinikinAutoUnref<MinikinFont> multiAxisFont(new MinikinFontForTest(kMultiAxisFont));
MinikinAutoUnref<FontFamily> multiAxisFamily(new FontFamily(
std::vector<Font>({Font(multiAxisFont.get(), FontStyle())})));
MinikinAutoUnref<MinikinFont> noAxisFont(new MinikinFontForTest(kNoAxisFont));
MinikinAutoUnref<FontFamily> noAxisFamily(new FontFamily(
std::vector<Font>({Font(noAxisFont.get(), FontStyle())})));
{
// Do not ceate new instance if none of variations are specified.
EXPECT_EQ(nullptr,
multiAxisFamily->createFamilyWithVariation(std::vector<FontVariation>()));
EXPECT_EQ(nullptr,
noAxisFamily->createFamilyWithVariation(std::vector<FontVariation>()));
}
{
// New instance should be used for supported variation.
std::vector<FontVariation> variations = {{MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f}};
MinikinAutoUnref<FontFamily> newFamily(
multiAxisFamily->createFamilyWithVariation(variations));
EXPECT_NE(nullptr, newFamily.get());
EXPECT_NE(multiAxisFamily.get(), newFamily.get());
EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation(variations));
}
{
// New instance should be used for supported variation. (multiple variations case)
std::vector<FontVariation> variations = {
{ MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f },
{ MinikinFont::MakeTag('w', 'g', 'h', 't'), 1.0f }
};
MinikinAutoUnref<FontFamily> newFamily(
multiAxisFamily->createFamilyWithVariation(variations));
EXPECT_NE(nullptr, newFamily.get());
EXPECT_NE(multiAxisFamily.get(), newFamily.get());
EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation(variations));
}
{
// Do not ceate new instance if none of variations are supported.
std::vector<FontVariation> variations = {
{ MinikinFont::MakeTag('Z', 'Z', 'Z', 'Z'), 1.0f }
};
EXPECT_EQ(nullptr, multiAxisFamily->createFamilyWithVariation(variations));
EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation(variations));
}
{
// At least one axis is supported, should create new instance.
std::vector<FontVariation> variations = {
{ MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f },
{ MinikinFont::MakeTag('Z', 'Z', 'Z', 'Z'), 1.0f }
};
MinikinAutoUnref<FontFamily> newFamily(
multiAxisFamily->createFamilyWithVariation(variations));
EXPECT_NE(nullptr, newFamily.get());
EXPECT_NE(multiAxisFamily.get(), newFamily.get());
EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation(variations));
}
}
} // namespace minikin

View File

@@ -34,11 +34,9 @@ namespace minikin {
static int uniqueId = 0; // TODO: make thread safe if necessary.
MinikinFontForTest::MinikinFontForTest(const std::string& font_path, int index,
const std::vector<FontVariation>& variations) :
MinikinFontForTest::MinikinFontForTest(const std::string& font_path, int index) :
MinikinFont(uniqueId++),
mFontPath(font_path),
mVariations(variations),
mFontIndex(index) {
int fd = open(font_path.c_str(), O_RDONLY);
LOG_ALWAYS_FATAL_IF(fd == -1);
@@ -69,9 +67,4 @@ void MinikinFontForTest::GetBounds(MinikinRect* bounds, uint32_t /* glyph_id */,
bounds->mBottom = 10.0f;
}
MinikinFont* MinikinFontForTest::createFontWithVariation(
const std::vector<FontVariation>& variations) const {
return new MinikinFontForTest(mFontPath, mFontIndex, variations);
}
} // namespace minikin

View File

@@ -25,10 +25,7 @@ namespace minikin {
class MinikinFontForTest : public MinikinFont {
public:
MinikinFontForTest(const std::string& font_path, int index,
const std::vector<FontVariation>& variations);
MinikinFontForTest(const std::string& font_path, int index)
: MinikinFontForTest(font_path, index, std::vector<FontVariation>()) {}
MinikinFontForTest(const std::string& font_path, int index);
MinikinFontForTest(const std::string& font_path) : MinikinFontForTest(font_path, 0) {}
virtual ~MinikinFontForTest();
@@ -38,19 +35,15 @@ public:
const MinikinPaint& paint) const;
const std::string& fontPath() const { return mFontPath; }
const std::vector<FontVariation>& variations() const { return mVariations; }
const void* GetFontData() const { return mFontData; }
size_t GetFontSize() const { return mFontSize; }
int GetFontIndex() const { return mFontIndex; }
MinikinFont* createFontWithVariation(const std::vector<FontVariation>& variations) const;
private:
MinikinFontForTest() = delete;
MinikinFontForTest(const MinikinFontForTest&) = delete;
MinikinFontForTest& operator=(MinikinFontForTest&) = delete;
const std::string mFontPath;
const std::vector<FontVariation> mVariations;
const int mFontIndex;
void* mFontData;
size_t mFontSize;