提交 90e6b188 编写于 作者: S Seigo Nonaka

Introduce createCollectionWithVariation.

This lays the groundwork for variation settings support.
Since we should regard different variations of a font as different fonts, we
need to create new typefaces. To reuse the same instance of MinikinFont, as
much as possible, FontFamily::createFamilyWithVariation now reuses an
existence instance, while incrementing the reference count.

Test: minikin_tests
Bug: 33062398
Change-Id: I08e9b74192f8af1d045f1276498fa4e60d73863e
上级 dfab450f
......@@ -18,6 +18,7 @@
#define MINIKIN_FONT_COLLECTION_H
#include <vector>
#include <unordered_set>
#include <minikin/MinikinRefCounted.h>
#include <minikin/MinikinFont.h>
......@@ -51,6 +52,10 @@ 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:
......@@ -96,6 +101,9 @@ private:
// These are offsets into mFamilyVec, one range per page
std::vector<Range> mRanges;
// Set of supported axes in this collection.
std::unordered_set<AxisTag> mSupportedAxes;
};
} // namespace minikin
......
......@@ -19,6 +19,7 @@
#include <vector>
#include <string>
#include <unordered_set>
#include <hb.h>
#include <utils/TypeHelpers.h>
......@@ -98,6 +99,8 @@ struct FakedFont {
FontFakery fakery;
};
typedef uint32_t AxisTag;
struct Font {
Font(MinikinFont* typeface, FontStyle style);
Font(Font&& o);
......@@ -106,6 +109,13 @@ 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 {
......@@ -129,6 +139,7 @@ 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; }
......@@ -140,12 +151,16 @@ 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;
......
......@@ -126,6 +126,10 @@ 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;
......
......@@ -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 \
......
......@@ -103,6 +103,9 @@ 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,
......@@ -462,6 +465,42 @@ 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;
}
......
......@@ -28,10 +28,11 @@
#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>
......@@ -66,19 +67,30 @@ uint32_t FontStyle::pack(int variant, int weight, bool italic) {
Font::Font(MinikinFont* typeface, FontStyle style)
: typeface(typeface), style(style) {
typeface->Ref();
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);
}
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() {
......@@ -174,9 +186,10 @@ void FontFamily::computeCoverage() {
}
// TODO: Error check?
CmapCoverage::getCoverage(mCoverage, cmapTable.get(), cmapTable.size(), &mHasVSTable);
#ifdef VERBOSE_DEBUG
ALOGD("font coverage length=%d, first ch=%x\n", mCoverage.length(), mCoverage.nextSetBit(0));
#endif
for (size_t i = 0; i < mFonts.size(); ++i) {
mSupportedAxes.insert(mFonts[i].supportedAxes.begin(), mFonts[i].supportedAxes.end());
}
}
bool FontFamily::hasGlyph(uint32_t codepoint, uint32_t variationSelector) const {
......@@ -196,4 +209,48 @@ 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
/*
* Copyright (C) 2013 The Android Open Source Project
* 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.
......@@ -17,15 +17,19 @@
#include <stdlib.h>
#include <stdint.h>
#include <minikin/AnalyzeStyle.h>
#include "FontUtils.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) {
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;
......@@ -40,4 +44,34 @@ bool analyzeStyle(const uint8_t* os2_data, size_t os2_size, int* weight, bool* i
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
/*
* Copyright (C) 2013 The Android Open Source Project
* 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.
......@@ -14,12 +14,15 @@
* limitations under the License.
*/
#ifndef MINIKIN_ANALYZE_STYLE_H
#define MINIKIN_ANALYZE_STYLE_H
#ifndef MINIKIN_FONT_UTILS_H
#define MINIKIN_FONT_UTILS_H
#include <unordered_set>
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
......
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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.
-->
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
<GlyphOrder>
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
<GlyphID id="0" name=".notdef"/>
<GlyphID id="1" name="default"/>
</GlyphOrder>
<head>
<!-- Most of this table will be recalculated by the compiler -->
<tableVersion value="1.0"/>
<fontRevision value="1.0"/>
<checkSumAdjustment value="0x640cdb2f"/>
<magicNumber value="0x5f0f3cf5"/>
<flags value="00000000 00000011"/>
<unitsPerEm value="1000"/>
<created value="Wed Sep 9 08:01:17 2015"/>
<modified value="Wed Sep 9 08:48:07 2015"/>
<xMin value="30"/>
<yMin value="-200"/>
<xMax value="629"/>
<yMax value="800"/>
<macStyle value="00000000 00000000"/>
<lowestRecPPEM value="7"/>
<fontDirectionHint value="2"/>
<indexToLocFormat value="0"/>
<glyphDataFormat value="0"/>
</head>
<hhea>
<tableVersion value="1.0"/>
<ascent value="1000"/>
<descent value="-200"/>
<lineGap value="0"/>
<advanceWidthMax value="659"/>
<minLeftSideBearing value="0"/>
<minRightSideBearing value="30"/>
<xMaxExtent value="629"/>
<caretSlopeRise value="1"/>
<caretSlopeRun value="0"/>
<caretOffset value="0"/>
<reserved0 value="0"/>
<reserved1 value="0"/>
<reserved2 value="0"/>
<reserved3 value="0"/>
<metricDataFormat value="0"/>
<numberOfHMetrics value="18"/>
</hhea>
<maxp>
<!-- Most of this table will be recalculated by the compiler -->
<tableVersion value="0x10000"/>
<numGlyphs value="54"/>
<maxPoints value="73"/>
<maxContours value="10"/>
<maxCompositePoints value="0"/>
<maxCompositeContours value="0"/>
<maxZones value="2"/>
<maxTwilightPoints value="12"/>
<maxStorage value="28"/>
<maxFunctionDefs value="119"/>
<maxInstructionDefs value="0"/>
<maxStackElements value="61"/>
<maxSizeOfInstructions value="2967"/>
<maxComponentElements value="0"/>
<maxComponentDepth value="0"/>
</maxp>
<OS_2>
<!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
will be recalculated by the compiler -->
<version value="3"/>
<xAvgCharWidth value="594"/>
<usWeightClass value="400"/>
<usWidthClass value="5"/>
<fsType value="00000000 00001000"/>
<ySubscriptXSize value="650"/>
<ySubscriptYSize value="600"/>
<ySubscriptXOffset value="0"/>
<ySubscriptYOffset value="75"/>
<ySuperscriptXSize value="650"/>
<ySuperscriptYSize value="600"/>
<ySuperscriptXOffset value="0"/>
<ySuperscriptYOffset value="350"/>
<yStrikeoutSize value="50"/>
<yStrikeoutPosition value="300"/>
<sFamilyClass value="0"/>
<panose>
<bFamilyType value="0"/>
<bSerifStyle value="0"/>
<bWeight value="5"/>
<bProportion value="0"/>
<bContrast value="0"/>
<bStrokeVariation value="0"/>
<bArmStyle value="0"/>
<bLetterForm value="0"/>
<bMidline value="0"/>
<bXHeight value="0"/>
</panose>
<ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
<ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
<ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
<ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
<achVendID value="UKWN"/>
<fsSelection value="00000000 01000000"/>
<usFirstCharIndex value="32"/>
<usLastCharIndex value="122"/>
<sTypoAscender value="800"/>
<sTypoDescender value="-200"/>
<sTypoLineGap value="200"/>
<usWinAscent value="1000"/>
<usWinDescent value="200"/>
<ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
<ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
<sxHeight value="500"/>
<sCapHeight value="700"/>
<usDefaultChar value="0"/>
<usBreakChar value="32"/>
<usMaxContext value="0"/>
</OS_2>
<hmtx>
<mtx name=".notdef" width="500" lsb="93"/>
<mtx name="default" width="500" lsb="93"/>
</hmtx>
<cmap>
<tableVersion version="0"/>
<cmap_format_4 platformID="3" platEncID="10" language="0">
<map code="0x0061" name="default" />
</cmap_format_4>
</cmap>
<loca>
<!-- The 'loca' table will be calculated by the compiler -->
</loca>
<glyf>
<!-- The xMin, yMin, xMax and yMax values
will be recalculated by the compiler. -->
<TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0">
<contour></contour><instructions><assembly></assembly></instructions>
</TTGlyph>
<TTGlyph name="default" xMin="0" yMin="0" xMax="0" yMax="0">
<contour></contour><instructions><assembly></assembly></instructions>
</TTGlyph>
</glyf>
<fvar>
<Axis>
<AxisTag>wdth</AxisTag>
<MinValue>-1.0</MinValue>
<DefaultValue>0.0</DefaultValue>
<MaxValue>1.0</MaxValue>
<NameID>256</NameID>
</Axis>
<Axis>
<AxisTag>wght</AxisTag>
<MinValue>-1.0</MinValue>
<DefaultValue>0.0</DefaultValue>
<MaxValue>1.0</MaxValue>
<NameID>256</NameID>
</Axis>
</fvar>
<name>
<namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
MultiAxisFont Test
</namerecord>
<namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
MultiAxis
</namerecord>
<namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
MultiAxisFont Test
</namerecord>
<namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
MultiAxisFontTest-Regular
</namerecord>
<namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
MultiAxisFont Test
</namerecord>
<namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
MultiAxis
</namerecord>
<namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
MultiAxisFont Test
</namerecord>
<namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
MultiAxisFontTest-Regular
</namerecord>
</name>
<post>
<formatType value="3.0"/>
<italicAngle value="0.0"/>
<underlinePosition value="-75"/>
<underlineThickness value="50"/>
<isFixedPitch value="0"/>
<minMemType42 value="0"/>
<maxMemType42 value="0"/>
<minMemType1 value="0"/>
<maxMemType1 value="0"/>
</post>
</ttFont>
......@@ -27,6 +27,7 @@ LOCAL_TEST_DATA := \
data/Italic.ttf \
data/Ja.ttf \
data/Ko.ttf \
data/MultiAxis.ttf \
data/NoCmapFormat14.ttf \
data/NoGlyphFont.ttf \
data/Regular.ttf \
......
......@@ -121,4 +121,76 @@ 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
......@@ -527,4 +527,67 @@ 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
......@@ -34,9 +34,11 @@ namespace minikin {
static int uniqueId = 0; // TODO: make thread safe if necessary.
MinikinFontForTest::MinikinFontForTest(const std::string& font_path, int index) :
MinikinFontForTest::MinikinFontForTest(const std::string& font_path, int index,
const std::vector<FontVariation>& variations) :
MinikinFont(uniqueId++),
mFontPath(font_path),
mVariations(variations),
mFontIndex(index) {
int fd = open(font_path.c_str(), O_RDONLY);
LOG_ALWAYS_FATAL_IF(fd == -1);
......@@ -67,4 +69,9 @@ 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
......@@ -25,7 +25,10 @@ namespace minikin {
class MinikinFontForTest : public MinikinFont {
public:
MinikinFontForTest(const std::string& font_path, int index);
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) : MinikinFontForTest(font_path, 0) {}
virtual ~MinikinFontForTest();
......@@ -35,15 +38,19 @@ 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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册