From 90e6b1885d44c33b1da9477a85dc7dd066acd33f Mon Sep 17 00:00:00 2001 From: Seigo Nonaka Date: Tue, 22 Nov 2016 18:10:57 +0900 Subject: [PATCH] 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 --- include/minikin/FontCollection.h | 8 + include/minikin/FontFamily.h | 17 +- include/minikin/MinikinFont.h | 4 + libs/minikin/AnalyzeStyle.cpp | 43 ---- libs/minikin/Android.mk | 2 +- libs/minikin/FontCollection.cpp | 39 +++ libs/minikin/FontFamily.cpp | 67 +++++- libs/minikin/FontUtils.cpp | 77 ++++++ .../minikin/FontUtils.h | 9 +- tests/data/MultiAxis.ttf | Bin 0 -> 844 bytes tests/data/MultiAxis.ttx | 223 ++++++++++++++++++ tests/unittest/Android.mk | 1 + tests/unittest/FontCollectionTest.cpp | 72 ++++++ tests/unittest/FontFamilyTest.cpp | 63 +++++ tests/util/MinikinFontForTest.cpp | 9 +- tests/util/MinikinFontForTest.h | 9 +- 16 files changed, 588 insertions(+), 55 deletions(-) delete mode 100644 libs/minikin/AnalyzeStyle.cpp create mode 100644 libs/minikin/FontUtils.cpp rename include/minikin/AnalyzeStyle.h => libs/minikin/FontUtils.h (75%) create mode 100644 tests/data/MultiAxis.ttf create mode 100644 tests/data/MultiAxis.ttx diff --git a/include/minikin/FontCollection.h b/include/minikin/FontCollection.h index f6312dcea5..eaebcbcf93 100644 --- a/include/minikin/FontCollection.h +++ b/include/minikin/FontCollection.h @@ -18,6 +18,7 @@ #define MINIKIN_FONT_COLLECTION_H #include +#include #include #include @@ -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& variations); + uint32_t getId() const; private: @@ -96,6 +101,9 @@ private: // These are offsets into mFamilyVec, one range per page std::vector mRanges; + + // Set of supported axes in this collection. + std::unordered_set mSupportedAxes; }; } // namespace minikin diff --git a/include/minikin/FontFamily.h b/include/minikin/FontFamily.h index bdf00e9f7c..b848a04630 100644 --- a/include/minikin/FontFamily.h +++ b/include/minikin/FontFamily.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -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 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& 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& variations) const; + private: void computeCoverage(); - uint32_t mLangId; int mVariant; std::vector mFonts; + std::unordered_set mSupportedAxes; SparseBitSet mCoverage; bool mHasVSTable; diff --git a/include/minikin/MinikinFont.h b/include/minikin/MinikinFont.h index 353edd6566..57b939788a 100644 --- a/include/minikin/MinikinFont.h +++ b/include/minikin/MinikinFont.h @@ -126,6 +126,10 @@ public: return 0; } + virtual MinikinFont* createFontWithVariation(const std::vector&) 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; diff --git a/libs/minikin/AnalyzeStyle.cpp b/libs/minikin/AnalyzeStyle.cpp deleted file mode 100644 index 333f008f7f..0000000000 --- a/libs/minikin/AnalyzeStyle.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 -#include - -#include - -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 diff --git a/libs/minikin/Android.mk b/libs/minikin/Android.mk index d6c3df7f62..44abb88532 100644 --- a/libs/minikin/Android.mk +++ b/libs/minikin/Android.mk @@ -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 \ diff --git a/libs/minikin/FontCollection.cpp b/libs/minikin/FontCollection.cpp index 9e9223fd2e..ac6f8f336d 100644 --- a/libs/minikin/FontCollection.cpp +++ b/libs/minikin/FontCollection.cpp @@ -103,6 +103,9 @@ FontCollection::FontCollection(const vector& typefaces) : } mMaxChar = max(mMaxChar, coverage.length()); lastChar.push_back(coverage.nextSetBit(0)); + + const std::unordered_set& 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& 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 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; } diff --git a/libs/minikin/FontFamily.cpp b/libs/minikin/FontFamily.cpp index 164cc7d8ad..5a277f7810 100644 --- a/libs/minikin/FontFamily.cpp +++ b/libs/minikin/FontFamily.cpp @@ -28,10 +28,11 @@ #include "FontLanguage.h" #include "FontLanguageListCache.h" +#include "FontUtils.h" #include "HbFontCache.h" #include "MinikinInternal.h" -#include #include +#include #include #include @@ -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& 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 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 diff --git a/libs/minikin/FontUtils.cpp b/libs/minikin/FontUtils.cpp new file mode 100644 index 0000000000..56be16d696 --- /dev/null +++ b/libs/minikin/FontUtils.cpp @@ -0,0 +1,77 @@ +/* + * 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 +#include + +#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* 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 diff --git a/include/minikin/AnalyzeStyle.h b/libs/minikin/FontUtils.h similarity index 75% rename from include/minikin/AnalyzeStyle.h rename to libs/minikin/FontUtils.h index b4cd915108..fa2051b409 100644 --- a/include/minikin/AnalyzeStyle.h +++ b/libs/minikin/FontUtils.h @@ -1,5 +1,5 @@ /* - * 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 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* axes); } // namespace minikin diff --git a/tests/data/MultiAxis.ttf b/tests/data/MultiAxis.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1d687cb367d740ad61bf6e3c633ac76732d05c91 GIT binary patch literal 844 zcmZ`%Jxmlq6#iy*?+&<&8l#CuiY@4bXf8%6G?9jefbqb91?c2hcF*kn)x)YQ-zi?en8W_G!t!AWM``@Z+RnKy3+0ze+?aB%m@{GDRB z5^MotlI+WJRW(q6!P~^+Yp+%F$MNxRz_~^|8ANZ^VDcf3xQvFrTFtzByGehS^L|Le z{V2cD?{kiYRo#_Ou}u92aW<-#6)qu1{N3QH>NfB-ze9Y3*sH0k@0YW;iGOm+M!luu zFDL@i?C06DdH(0U^#?C5Kl}yZoRG)i_1=N8N6$Z<8k>$BWa=@;If;2k(Z{mru_Akm zGa;?8jL|0%$v%vtL;NV;vpPqX#0O+BB;U&=GBb%4D=3O_qsUm9UH;nr+05b`9z#Jn z9&6ZV&HGeYjp$3$IWMWqbc#dpZANGda7~1(Yt<@_iMYnwNj6cA{Y>|wg;fkrw+I+Q z`fAL&I#5dt6D3;r9G}Ha++qd79cFY4_flU{vy}SoIX=txc{SUPbY-erX-(H_+FS5j zdcX`E6EcyBk{`4q)x<2?h@ery6uMknm_{8nG9DJ-6YC2!|Ia$hnLvrzf!$r9$s0SS jH|)-i`AZiJ(}gSiEfVIR7doptOnaC1R-hAv`d{u3H>`$T literal 0 HcmV?d00001 diff --git a/tests/data/MultiAxis.ttx b/tests/data/MultiAxis.ttx new file mode 100644 index 0000000000..d8df7281f5 --- /dev/null +++ b/tests/data/MultiAxis.ttx @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + wdth + -1.0 + 0.0 + 1.0 + 256 + + + wght + -1.0 + 0.0 + 1.0 + 256 + + + + + + MultiAxisFont Test + + + MultiAxis + + + MultiAxisFont Test + + + MultiAxisFontTest-Regular + + + MultiAxisFont Test + + + MultiAxis + + + MultiAxisFont Test + + + MultiAxisFontTest-Regular + + + + + + + + + + + + + + + + diff --git a/tests/unittest/Android.mk b/tests/unittest/Android.mk index cced545737..7b3f60f8f9 100644 --- a/tests/unittest/Android.mk +++ b/tests/unittest/Android.mk @@ -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 \ diff --git a/tests/unittest/FontCollectionTest.cpp b/tests/unittest/FontCollectionTest.cpp index c0b6b526b7..02e861c903 100644 --- a/tests/unittest/FontCollectionTest.cpp +++ b/tests/unittest/FontCollectionTest.cpp @@ -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 multiAxisFont(new MinikinFontForTest(kMultiAxisFont)); + MinikinAutoUnref multiAxisFamily(new FontFamily( + std::vector({ Font(multiAxisFont.get(), FontStyle()) }))); + std::vector multiAxisFamilies({multiAxisFamily.get()}); + MinikinAutoUnref multiAxisFc(new FontCollection(multiAxisFamilies)); + + MinikinAutoUnref noAxisFont(new MinikinFontForTest(kNoAxisFont)); + MinikinAutoUnref noAxisFamily(new FontFamily( + std::vector({ Font(noAxisFont.get(), FontStyle()) }))); + std::vector noAxisFamilies({noAxisFamily.get()}); + MinikinAutoUnref noAxisFc(new FontCollection(noAxisFamilies)); + + { + // Do not ceate new instance if none of variations are specified. + EXPECT_EQ(nullptr, + multiAxisFc->createCollectionWithVariation(std::vector())); + EXPECT_EQ(nullptr, + noAxisFc->createCollectionWithVariation(std::vector())); + } + { + // New instance should be used for supported variation. + std::vector variations = { + { MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f } + }; + MinikinAutoUnref 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 variations = { + { MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f }, + { MinikinFont::MakeTag('w', 'g', 'h', 't'), 1.0f } + }; + MinikinAutoUnref 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 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 variations = { + { MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f }, + { MinikinFont::MakeTag('Z', 'Z', 'Z', 'Z'), 1.0f } + }; + MinikinAutoUnref newFc( + multiAxisFc->createCollectionWithVariation(variations)); + EXPECT_NE(nullptr, newFc.get()); + EXPECT_NE(multiAxisFc.get(), newFc.get()); + + EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation(variations)); + } +} + } // namespace minikin diff --git a/tests/unittest/FontFamilyTest.cpp b/tests/unittest/FontFamilyTest.cpp index ddc36e4570..35f387304b 100644 --- a/tests/unittest/FontFamilyTest.cpp +++ b/tests/unittest/FontFamilyTest.cpp @@ -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 multiAxisFont(new MinikinFontForTest(kMultiAxisFont)); + MinikinAutoUnref multiAxisFamily(new FontFamily( + std::vector({Font(multiAxisFont.get(), FontStyle())}))); + + MinikinAutoUnref noAxisFont(new MinikinFontForTest(kNoAxisFont)); + MinikinAutoUnref noAxisFamily(new FontFamily( + std::vector({Font(noAxisFont.get(), FontStyle())}))); + + { + // Do not ceate new instance if none of variations are specified. + EXPECT_EQ(nullptr, + multiAxisFamily->createFamilyWithVariation(std::vector())); + EXPECT_EQ(nullptr, + noAxisFamily->createFamilyWithVariation(std::vector())); + } + { + // New instance should be used for supported variation. + std::vector variations = {{MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f}}; + MinikinAutoUnref 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 variations = { + { MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f }, + { MinikinFont::MakeTag('w', 'g', 'h', 't'), 1.0f } + }; + MinikinAutoUnref 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 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 variations = { + { MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f }, + { MinikinFont::MakeTag('Z', 'Z', 'Z', 'Z'), 1.0f } + }; + MinikinAutoUnref newFamily( + multiAxisFamily->createFamilyWithVariation(variations)); + EXPECT_NE(nullptr, newFamily.get()); + EXPECT_NE(multiAxisFamily.get(), newFamily.get()); + EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation(variations)); + } +} + } // namespace minikin diff --git a/tests/util/MinikinFontForTest.cpp b/tests/util/MinikinFontForTest.cpp index a4132e5178..f191f07d6e 100644 --- a/tests/util/MinikinFontForTest.cpp +++ b/tests/util/MinikinFontForTest.cpp @@ -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& 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& variations) const { + return new MinikinFontForTest(mFontPath, mFontIndex, variations); +} + } // namespace minikin diff --git a/tests/util/MinikinFontForTest.h b/tests/util/MinikinFontForTest.h index ee0eadbe0c..2a107036ed 100644 --- a/tests/util/MinikinFontForTest.h +++ b/tests/util/MinikinFontForTest.h @@ -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& variations); + MinikinFontForTest(const std::string& font_path, int index) + : MinikinFontForTest(font_path, index, std::vector()) {} 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& 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& variations) const; private: MinikinFontForTest() = delete; MinikinFontForTest(const MinikinFontForTest&) = delete; MinikinFontForTest& operator=(MinikinFontForTest&) = delete; const std::string mFontPath; + const std::vector mVariations; const int mFontIndex; void* mFontData; size_t mFontSize; -- GitLab