summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Android.bp8
-rw-r--r--tests/data/Ascii.ttfbin1848 -> 1944 bytes
-rw-r--r--tests/data/Ascii.ttx17
-rw-r--r--tests/data/Bbox.ttfbin0 -> 2016 bytes
-rw-r--r--tests/data/Bbox.ttx265
-rw-r--r--tests/data/EmojiBase.ttfbin0 -> 1428 bytes
-rw-r--r--tests/data/EmojiBase.ttx537
-rw-r--r--tests/data/OverrideEmoji.ttfbin0 -> 1200 bytes
-rw-r--r--tests/data/OverrideEmoji.ttx521
-rw-r--r--tests/data/emoji_itemization.xml28
-rw-r--r--tests/perftests/Android.bp4
-rw-r--r--tests/perftests/main.cpp20
-rw-r--r--tests/stresstest/Android.bp4
-rw-r--r--tests/stresstest/FontFamilyTest.cpp2
-rw-r--r--tests/unittest/Android.bp7
-rw-r--r--tests/unittest/BoundsCacheTest.cpp172
-rw-r--r--tests/unittest/BufferTest.cpp90
-rw-r--r--tests/unittest/FontCollectionItemizeTest.cpp153
-rw-r--r--tests/unittest/FontCollectionTest.cpp160
-rw-r--r--tests/unittest/FontFamilyTest.cpp93
-rw-r--r--tests/unittest/FontFileParserTest.cpp132
-rw-r--r--tests/unittest/FontLanguageListCacheTest.cpp21
-rw-r--r--tests/unittest/FontTest.cpp29
-rw-r--r--tests/unittest/GreedyLineBreakerTest.cpp27
-rw-r--r--tests/unittest/HasherTest.cpp5
-rw-r--r--tests/unittest/ICUEnvironment.h66
-rw-r--r--tests/unittest/LayoutCoreTest.cpp11
-rw-r--r--tests/unittest/LayoutTest.cpp43
-rw-r--r--tests/unittest/MeasuredTextTest.cpp105
-rw-r--r--tests/unittest/OptimalLineBreakerTest.cpp28
-rw-r--r--tests/unittest/SparseBitSetTest.cpp27
-rw-r--r--tests/unittest/SystemFontsTest.cpp50
-rw-r--r--tests/unittest/TestMain.cpp3
-rw-r--r--tests/util/Android.bp4
-rw-r--r--tests/util/BufferUtils.h59
-rw-r--r--tests/util/FontTestUtils.cpp6
-rw-r--r--tests/util/FreeTypeMinikinFontForTest.cpp18
-rw-r--r--tests/util/FreeTypeMinikinFontForTest.h9
38 files changed, 2503 insertions, 221 deletions
diff --git a/tests/Android.bp b/tests/Android.bp
index 1d8c019..3088ca4 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -1,8 +1,13 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
filegroup {
name: "minikin-test-data",
srcs: [
"data/Arabic.ttf",
"data/Ascii.ttf",
+ "data/Bbox.ttf",
"data/Bold.ttf",
"data/BoldItalic.ttf",
"data/Cherokee.ttf",
@@ -10,6 +15,7 @@ filegroup {
"data/ColorTextMixedEmojiFont.ttf",
"data/CustomExtent.ttf",
"data/Emoji.ttf",
+ "data/EmojiBase.ttf",
"data/Hiragana.ttf",
"data/Italic.ttf",
"data/Ja.ttf",
@@ -19,6 +25,7 @@ filegroup {
"data/MultiAxis.ttf",
"data/NoCmapFormat14.ttf",
"data/NoGlyphFont.ttf",
+ "data/OverrideEmoji.ttf",
"data/Regular.ttf",
"data/TextEmojiFont.ttf",
"data/UnicodeBMPOnly.ttf",
@@ -28,6 +35,7 @@ filegroup {
"data/ZhHans.ttf",
"data/ZhHant.ttf",
"data/emoji.xml",
+ "data/emoji_itemization.xml",
"data/itemize.xml",
],
}
diff --git a/tests/data/Ascii.ttf b/tests/data/Ascii.ttf
index be6d5fe..2e6835b 100644
--- a/tests/data/Ascii.ttf
+++ b/tests/data/Ascii.ttf
Binary files differ
diff --git a/tests/data/Ascii.ttx b/tests/data/Ascii.ttx
index 74eba96..c0a2ef6 100644
--- a/tests/data/Ascii.ttx
+++ b/tests/data/Ascii.ttx
@@ -18,6 +18,7 @@
<GlyphOrder>
<GlyphID id="0" name=".notdef"/>
<GlyphID id="1" name="1em"/>
+ <GlyphID id="2" name="2em"/>
</GlyphOrder>
<head>
@@ -117,6 +118,7 @@
<hmtx>
<mtx name=".notdef" width="50" lsb="0"/>
<mtx name="1em" width="100" lsb="0"/>
+ <mtx name="2em" width="200" lsb="0"/>
</hmtx>
<cmap>
@@ -217,6 +219,12 @@
<map code="0x007C" name="1em" /> <!-- '|' -->
<map code="0x007D" name="1em" /> <!-- '}' -->
<map code="0x007E" name="1em" /> <!-- '~' -->
+ <map code="0x02B1" name="2em" /> <!-- 'α' -->
+ <map code="0x02B2" name="2em" /> <!-- 'β' -->
+ <map code="0x02B3" name="2em" /> <!-- 'γ' -->
+ <map code="0x02B4" name="2em" /> <!-- 'δ' -->
+ <map code="0x02B5" name="2em" /> <!-- 'ε' -->
+ <map code="0x02B6" name="2em" /> <!-- 'ζ' -->
</cmap_format_12>
</cmap>
@@ -235,6 +243,15 @@
</contour>
<instructions><assembly></assembly></instructions>
</TTGlyph>
+ <TTGlyph name="2em" xMin="0" yMin="0" xMax="200" yMax="200">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="200" y="0" on="1" />
+ <pt x="200" y="200" on="1" />
+ <pt x="0" y="200" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
</glyf>
<name>
diff --git a/tests/data/Bbox.ttf b/tests/data/Bbox.ttf
new file mode 100644
index 0000000..c89c59c
--- /dev/null
+++ b/tests/data/Bbox.ttf
Binary files differ
diff --git a/tests/data/Bbox.ttx b/tests/data/Bbox.ttx
new file mode 100644
index 0000000..e7d34bd
--- /dev/null
+++ b/tests/data/Bbox.ttx
@@ -0,0 +1,265 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2020 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>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="1emx1em"/>
+ <GlyphID id="2" name="2emx2em"/>
+ <GlyphID id="3" name="3emx3em"/>
+ <GlyphID id="4" name="2emx2em_lsb_1em"/>
+ <GlyphID id="5" name="1emx1em_y1em_origin"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements 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="1emx1em" width="1000" lsb="0"/>
+ <mtx name="2emx2em" width="2000" lsb="0"/>
+ <mtx name="3emx3em" width="3000" lsb="0"/>
+ <mtx name="2emx2em_lsb_1em" width="2000" lsb="1000"/>
+ <mtx name="1emx1em_y1em_origin" width="1000" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_12 format="12" reserved="0" length="3" nGroups="6" platformID="3" platEncID="1" language="0">
+ <map code="0x0028" name="1emx1em" />
+ <map code="0x0061" name="1emx1em" />
+ <map code="0x0062" name="2emx2em" />
+ <map code="0x0063" name="3emx3em" />
+ <map code="0x0064" name="2emx2em_lsb_1em" />
+ <map code="0x0065" name="1emx1em_y1em_origin" />
+ </cmap_format_12>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="1emx1em" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="500" y="1000" on="1" />
+ <pt x="1000" y="0" on="1" />
+ </contour>
+ <instructions />
+ </TTGlyph>
+ <TTGlyph name="2emx2em" xMin="0" yMin="0" xMax="2000" yMax="2000">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="1000" y="2000" on="1" />
+ <pt x="2000" y="0" on="1" />
+ </contour>
+ <instructions />
+ </TTGlyph>
+ <TTGlyph name="3emx3em" xMin="0" yMin="0" xMax="3000" yMax="3000">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="1500" y="3000" on="1" />
+ <pt x="3000" y="0" on="1" />
+ </contour>
+ <instructions />
+ </TTGlyph>
+ <TTGlyph name="2emx2em_lsb_1em" xMin="0" yMin="0" xMax="2000" yMax="2000">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="1000" y="2000" on="1" />
+ <pt x="2000" y="0" on="1" />
+ </contour>
+ <instructions />
+ </TTGlyph>
+ <TTGlyph name="1emx1em_y1em_origin" xMin="0" yMin="1000" xMax="1000" yMax="2000">
+ <contour>
+ <pt x="0" y="1000" on="1" />
+ <pt x="500" y="2000" on="1" />
+ <pt x="1000" y="1000" on="1" />
+ </contour>
+ <instructions />
+ </TTGlyph>
+ </glyf>
+
+ <GSUB>
+ <Version value="0x00010000"/>
+ <ScriptList>
+ <ScriptRecord index="0">
+ <ScriptTag value="latn"/>
+ <Script>
+ <DefaultLangSys>
+ <ReqFeatureIndex value="65535"/>
+ <FeatureIndex index="0" value="0"/>
+ </DefaultLangSys>
+ </Script>
+ </ScriptRecord>
+ </ScriptList>
+ <FeatureList>
+ <FeatureRecord index="0">
+ <FeatureTag value="rtlm"/>
+ <Feature>
+ <LookupListIndex index="0" value="0"/>
+ </Feature>
+ </FeatureRecord>
+ </FeatureList>
+ <LookupList>
+ <Lookup index="0">
+ <LookupType value="1"/>
+ <LookupFlag value="0"/>
+ <SingleSubst index="0" Format="2">
+ <Substitution in="1emx1em" out="3emx3em" />
+ </SingleSubst>
+ </Lookup>
+ </LookupList>
+
+ </GSUB>
+
+ <name>
+ <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+ Copyright (C) 2017 The Android Open Source Project
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+ </namerecord>
+ <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
+ http://www.apache.org/licenses/LICENSE-2.0
+ </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>
diff --git a/tests/data/EmojiBase.ttf b/tests/data/EmojiBase.ttf
new file mode 100644
index 0000000..659226d
--- /dev/null
+++ b/tests/data/EmojiBase.ttf
Binary files differ
diff --git a/tests/data/EmojiBase.ttx b/tests/data/EmojiBase.ttx
new file mode 100644
index 0000000..e6e3da8
--- /dev/null
+++ b/tests/data/EmojiBase.ttx
@@ -0,0 +1,537 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 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.9">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+
+ <!-- Compbining characters for Emoji -->
+ <GlyphID id="1" name="U+200D"/>
+ <GlyphID id="2" name="U+1F3FB"/>
+ <GlyphID id="3" name="U+1F3FC"/>
+
+ <!-- Random Emoji -->
+ <GlyphID id="4" name="U+1F9B0"/>
+ <GlyphID id="5" name="U+1F9B1"/>
+ <GlyphID id="6" name="U+1F9B2"/>
+ <GlyphID id="7" name="U+1F9B3"/>
+ <GlyphID id="8" name="U+1F9B4"/>
+ <GlyphID id="9" name="U+1F9B5"/>
+ <GlyphID id="10" name="U+1F9B6"/>
+ <GlyphID id="11" name="U+1F9B7"/>
+ <GlyphID id="12" name="U+1F9B8"/>
+ <GlyphID id="13" name="U+1F9B9"/>
+
+ <!-- Unassigned Code Points -->
+ <GlyphID id="14" name="U+E0000"/>
+ <GlyphID id="15" name="U+E0001"/>
+
+ <!-- Ligature Form. Not in cmap -->
+ <GlyphID id="16" name="LigaForm1"/>
+ <GlyphID id="17" name="LigaForm2"/>
+ <GlyphID id="18" name="LigaForm3"/>
+ <GlyphID id="19" name="LigaForm4"/>
+ <GlyphID id="20" name="LigaForm5"/>
+ <GlyphID id="21" name="LigaForm6"/>
+ <GlyphID id="22" name="LigaForm7"/>
+
+ <!-- Regional Indicators -->
+ <GlyphID id="23" name="U+1F1E6"/>
+ <GlyphID id="24" name="U+1F1E7"/>
+
+ </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="0"/>
+ <yMin value="0"/>
+ <xMax value="0"/>
+ <yMax value="0"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <advanceWidthMax value="500"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="0"/>
+ <xMaxExtent value="0"/>
+ <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="1"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="8"/>
+ <maxPoints value="0"/>
+ <maxContours value="0"/>
+ <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="48"/>
+ <usLastCharIndex value="65535"/>
+ <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="U+200D" width="500" lsb="93"/>
+ <mtx name="U+1F1E6" width="500" lsb="93"/>
+ <mtx name="U+1F1E7" width="500" lsb="93"/>
+ <mtx name="U+1F3FB" width="500" lsb="93"/>
+ <mtx name="U+1F3FC" width="500" lsb="93"/>
+ <mtx name="U+1F9B0" width="500" lsb="93"/>
+ <mtx name="U+1F9B1" width="500" lsb="93"/>
+ <mtx name="U+1F9B2" width="500" lsb="93"/>
+ <mtx name="U+1F9B3" width="500" lsb="93"/>
+ <mtx name="U+1F9B4" width="500" lsb="93"/>
+ <mtx name="U+1F9B5" width="500" lsb="93"/>
+ <mtx name="U+1F9B6" width="500" lsb="93"/>
+ <mtx name="U+1F9B7" width="500" lsb="93"/>
+ <mtx name="U+1F9B8" width="500" lsb="93"/>
+ <mtx name="U+1F9B9" width="500" lsb="93"/>
+ <mtx name="U+E0000" width="500" lsb="93"/>
+ <mtx name="U+E0001" width="500" lsb="93"/>
+ <mtx name="LigaForm1" width="500" lsb="93"/>
+ <mtx name="LigaForm2" width="500" lsb="93"/>
+ <mtx name="LigaForm3" width="500" lsb="93"/>
+ <mtx name="LigaForm4" width="500" lsb="93"/>
+ <mtx name="LigaForm5" width="500" lsb="93"/>
+ <mtx name="LigaForm6" width="500" lsb="93"/>
+ <mtx name="LigaForm7" width="500" lsb="93"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_12 format="12" reserved="0" length="3" nGroups="6" platformID="3" platEncID="1" language="0">
+ <map code="0x200D" name="U+200D" />
+ <map code="0x1F1E6" name="U+1F1E6" />
+ <map code="0x1F1E7" name="U+1F1E7" />
+ <map code="0x1F3FB" name="U+1F3FB" />
+ <map code="0x1F3FC" name="U+1F3FC" />
+ <map code="0x1F9B0" name="U+1F9B0" />
+ <map code="0x1F9B1" name="U+1F9B1" />
+ <map code="0x1F9B2" name="U+1F9B2" />
+ <map code="0x1F9B3" name="U+1F9B3" />
+ <map code="0x1F9B4" name="U+1F9B4" />
+ <map code="0x1F9B5" name="U+1F9B5" />
+ <map code="0x1F9B6" name="U+1F9B6" />
+ <map code="0x1F9B7" name="U+1F9B7" />
+ <map code="0x1F9B8" name="U+1F9B8" />
+ <map code="0x1F9B9" name="U+1F9B9" />
+ <map code="0xE0000" name="U+E0000" />
+ <map code="0xE0001" name="U+E0001" />
+ </cmap_format_12>
+ </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="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+200D" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F1E6" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F1E7" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F3FB" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F3FC" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B0" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B1" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B2" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B3" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B4" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B5" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B6" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B7" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B8" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B9" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+E0000" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+E0001" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="LigaForm1" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="LigaForm2" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="LigaForm3" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="LigaForm4" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="LigaForm5" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="LigaForm6" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="LigaForm7" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ EmojiBaseFont
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ EmojiBaseFont
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ EmojiBaseFont
+ </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>
+
+ <GSUB>
+ <Version value="0x00010000"/>
+ <ScriptList>
+ <ScriptRecord index="0">
+ <ScriptTag value="DFLT"/>
+ <Script>
+ <DefaultLangSys>
+ <ReqFeatureIndex value="65535"/>
+ <FeatureIndex index="0" value="0"/>
+ </DefaultLangSys>
+ </Script>
+ </ScriptRecord>
+ </ScriptList>
+ <FeatureList>
+ <FeatureRecord index="0">
+ <FeatureTag value="ccmp"/>
+ <Feature>
+ <LookupListIndex index="0" value="0"/>
+ </Feature>
+ </FeatureRecord>
+ </FeatureList>
+ <LookupList>
+ <Lookup index="0">
+ <LookupType value="4"/>
+ <LookupFlag value="0"/>
+ <LigatureSubst index="0" Format="1">
+ <LigatureSet glyph="U+1F9B0">
+ <!-- U+1F9B0 U+1F3FB -> LigaForm1 -->
+ <Ligature components="U+1F3FB" glyph="LigaForm1"/>
+
+ <!-- U+1F9B0 U+1F3FC -> LigaForm2 -->
+ <Ligature components="U+1F3FC" glyph="LigaForm2"/>
+ </LigatureSet>
+ <LigatureSet glyph="U+1F9B1">
+ <!-- U+1F9B1 U+1F3FB -> LigaForm3 -->
+ <Ligature components="U+1F3FB" glyph="LigaForm3"/>
+ </LigatureSet>
+ <LigatureSet glyph="U+1F9B2">
+ <Ligature components="U+200D,U+1F9B3,U+200D,U+1F9B4" glyph="LigaForm4"/>
+ </LigatureSet>
+ <LigatureSet glyph="U+1F9B6">
+ <!-- U+1F9B6 U+1F3FB -> LigaForm3 -->
+ <Ligature components="U+1F3FB" glyph="LigaForm3"/>
+ </LigatureSet>
+ <LigatureSet glyph="U+1F1E6">
+ <Ligature components="U+1F1E6" glyph="LigaForm6"/>
+ <Ligature components="U+1F1E7" glyph="LigaForm7"/>
+ </LigatureSet>
+ </LigatureSubst>
+ </Lookup>
+ </LookupList>
+ </GSUB>
+</ttFont>
diff --git a/tests/data/OverrideEmoji.ttf b/tests/data/OverrideEmoji.ttf
new file mode 100644
index 0000000..890796b
--- /dev/null
+++ b/tests/data/OverrideEmoji.ttf
Binary files differ
diff --git a/tests/data/OverrideEmoji.ttx b/tests/data/OverrideEmoji.ttx
new file mode 100644
index 0000000..d5d4091
--- /dev/null
+++ b/tests/data/OverrideEmoji.ttx
@@ -0,0 +1,521 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 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.9">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+
+ <!-- Compbining characters for Emoji -->
+ <GlyphID id="1" name="U+200D"/>
+ <GlyphID id="2" name="U+1F3FB"/>
+ <GlyphID id="3" name="U+1F3FC"/>
+
+ <!-- Random Emoji -->
+ <GlyphID id="4" name="U+1F9B0"/>
+ <GlyphID id="5" name="U+1F9B1"/>
+ <GlyphID id="6" name="U+1F9B2"/>
+ <GlyphID id="7" name="U+1F9B3"/>
+ <GlyphID id="8" name="U+1F9B4"/>
+ <GlyphID id="9" name="U+1F9B5"/>
+ <!--
+ Following four glyphs are removed from EmojiBase.ttf for verifying fallback.
+ <GlyphID id="10" name="U+1F9B6"/>
+ <GlyphID id="11" name="U+1F9B7"/>
+ <GlyphID id="12" name="U+1F9B8"/>
+ <GlyphID id="13" name="U+1F9B9"/>
+ -->
+
+ <!-- Unassigned Code Points -->
+ <GlyphID id="14" name="U+E0000"/>
+ <!--
+ Following glyph is removed from EmojiBase.ttf for verifying fallback.
+ <GlyphID id="15" name="U+E0001"/>
+ -->
+
+ <!-- Ligature Form. Not in cmap -->
+ <GlyphID id="16" name="LigaForm1"/>
+ <GlyphID id="17" name="LigaForm2"/>
+ <GlyphID id="18" name="LigaForm3"/>
+ <!--
+ Following glyphs are removed from EmojiBase.ttf for verifying fallback.
+ <GlyphID id="19" name="LigaForm4"/>
+ <GlyphID id="20" name="LigaForm5"/>
+ -->
+ <GlyphID id="21" name="LigaForm6"/>
+ <!--
+ Following glyph is removed from EmojiBase.ttf for verifying fallback.
+ <GlyphID id="22" name="LigaForm7"/>
+ -->
+
+ <GlyphID id="23" name="U+1F1E6"/>
+ <GlyphID id="24" name="U+1F1E7"/>
+ </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="0"/>
+ <yMin value="0"/>
+ <xMax value="0"/>
+ <yMax value="0"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <advanceWidthMax value="500"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="0"/>
+ <xMaxExtent value="0"/>
+ <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="1"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="8"/>
+ <maxPoints value="0"/>
+ <maxContours value="0"/>
+ <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="48"/>
+ <usLastCharIndex value="65535"/>
+ <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="U+200D" width="500" lsb="93"/>
+ <mtx name="U+1F1E6" width="500" lsb="93"/>
+ <mtx name="U+1F1E7" width="500" lsb="93"/>
+ <mtx name="U+1F3FB" width="500" lsb="93"/>
+ <mtx name="U+1F3FC" width="500" lsb="93"/>
+ <mtx name="U+1F9B0" width="500" lsb="93"/>
+ <mtx name="U+1F9B1" width="500" lsb="93"/>
+ <mtx name="U+1F9B2" width="500" lsb="93"/>
+ <mtx name="U+1F9B3" width="500" lsb="93"/>
+ <mtx name="U+1F9B4" width="500" lsb="93"/>
+ <mtx name="U+1F9B5" width="500" lsb="93"/>
+ <!--
+ Following four glyphs are removed from EmojiBase.ttf for verifying fallback.
+ <mtx name="U+1F9B6" width="500" lsb="93"/>
+ <mtx name="U+1F9B7" width="500" lsb="93"/>
+ <mtx name="U+1F9B8" width="500" lsb="93"/>
+ <mtx name="U+1F9B9" width="500" lsb="93"/>
+ -->
+ <mtx name="U+E0000" width="500" lsb="93"/>
+ <!--
+ Following glyph is removed from EmojiBase.ttf for verifying fallback.
+ <mtx name="U+1F9B6" width="500" lsb="93"/>
+ -->
+ <mtx name="U+E0001" width="500" lsb="93"/>
+ <mtx name="LigaForm1" width="500" lsb="93"/>
+ <mtx name="LigaForm2" width="500" lsb="93"/>
+ <mtx name="LigaForm3" width="500" lsb="93"/>
+ <!--
+ Following two glyphs are removed from EmojiBase.ttf for verifying fallback.
+ <mtx name="LigaForm4" width="500" lsb="93"/>
+ <mtx name="LigaForm5" width="500" lsb="93"/>
+ -->
+ <mtx name="LigaForm6" width="500" lsb="93"/>
+ <!--
+ Following glyph is removed from EmojiBase.ttf for verifying fallback.
+ <mtx name="LigaForm7" width="500" lsb="93"/>
+ -->
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_12 format="12" reserved="0" length="3" nGroups="6" platformID="3" platEncID="1" language="0">
+ <map code="0x200D" name="U+200D" />
+ <map code="0x1F1E6" name="U+1F1E6" />
+ <map code="0x1F1E7" name="U+1F1E7" />
+ <map code="0x1F3FB" name="U+1F3FB" />
+ <map code="0x1F3FC" name="U+1F3FC" />
+ <map code="0x1F9B0" name="U+1F9B0" />
+ <map code="0x1F9B1" name="U+1F9B1" />
+ <map code="0x1F9B2" name="U+1F9B2" />
+ <map code="0x1F9B3" name="U+1F9B3" />
+ <map code="0x1F9B4" name="U+1F9B4" />
+ <map code="0x1F9B5" name="U+1F9B5" />
+ <!--
+ Following four glyphs are removed from EmojiBase.ttf for verifying fallback.
+ <map code="0x1F9B6" name="U+1F9B6" />
+ <map code="0x1F9B7" name="U+1F9B7" />
+ <map code="0x1F9B8" name="U+1F9B8" />
+ <map code="0x1F9B9" name="U+1F9B9" />
+ -->
+ <map code="0xE0000" name="U+E0000" />
+ <!--
+ Following glyph is removed from EmojiBase.ttf for verifying fallback.
+ <map code="0xE0001" name="U+E0001" />
+ -->
+ </cmap_format_12>
+ </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="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+200D" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F1E6" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F1E7" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F3FB" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F3FC" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B0" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B1" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B2" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B3" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B4" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="U+1F9B5" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <!--
+ Following four glyphs are removed from EmojiBase.ttf for verifying fallback.
+ <TTGlyph name="U+1F9B6">
+ <TTGlyph name="U+1F9B7">
+ <TTGlyph name="U+1F9B8">
+ <TTGlyph name="U+1F9B9">
+ -->
+ <TTGlyph name="U+E0000" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <!--
+ Following glyph is removed from EmojiBase.ttf for verifying fallback.
+ <TTGlyph name="U+E0001"/>
+ -->
+ <TTGlyph name="LigaForm1" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="LigaForm2" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="LigaForm3" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <!--
+ Following two glyphs are removed from EmojiBase.ttf for verifying fallback.
+ <TTGlyph name="LigaForm4">
+ <TTGlyph name="LigaForm5">
+ -->
+ <TTGlyph name="LigaForm6" xMin="0" yMin="0" xMax="100" yMax="100">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="100" y="0" on="1" />
+ <pt x="100" y="100" on="1" />
+ <pt x="0" y="100" on="1" />
+ </contour>
+ <instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <!--
+ Following glyph is removed from EmojiBase.ttf for verifying fallback.
+ <TTGlyph name="LigaForm7">
+ -->
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ OverrideEmojiFont
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ OverrideEmojiFont
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ OverrideEmojiFont
+ </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>
+
+ <GSUB>
+ <Version value="0x00010000"/>
+ <ScriptList>
+ <ScriptRecord index="0">
+ <ScriptTag value="DFLT"/>
+ <Script>
+ <DefaultLangSys>
+ <ReqFeatureIndex value="65535"/>
+ <FeatureIndex index="0" value="0"/>
+ </DefaultLangSys>
+ </Script>
+ </ScriptRecord>
+ </ScriptList>
+ <FeatureList>
+ <FeatureRecord index="0">
+ <FeatureTag value="ccmp"/>
+ <Feature>
+ <LookupListIndex index="0" value="0"/>
+ </Feature>
+ </FeatureRecord>
+ </FeatureList>
+ <LookupList>
+ <Lookup index="0">
+ <LookupType value="4"/>
+ <LookupFlag value="0"/>
+ <LigatureSubst index="0" Format="1">
+ <LigatureSet glyph="U+1F9B0">
+ <!-- U+1F9B0 U+1F3FB -> LigaForm0 -->
+ <Ligature components="U+1F3FB" glyph="LigaForm1"/>
+
+ <!-- U+1F9B0 U+1F3FC -> LigaForm1 -->
+ <!--
+ Following ligature is removed from the EmojiBase.ttf for verifying fallback
+ <Ligature components="U+1F3FC" glyph="LigaForm2"/>
+ -->
+ </LigatureSet>
+ <!--
+ Following ligature is removed from the EmojiBase.ttf for verifying fallback
+ <LigatureSet glyph="U+1F9B1">
+ <Ligature components="U+1F3FB" glyph="LigaForm3"/>
+ </LigatureSet>
+ -->
+ <LigatureSet glyph="U+1F9B2">
+ <Ligature components="U+200D,U+1F9B3" glyph="LigaForm3"/>
+ </LigatureSet>
+ <!--
+ Following ligature is removed from the EmojIBase.ttf for verifying fallback.
+ <LigatureSet glyph="U+1F9B6">
+ <Ligature components="U+1F3FB" glyph="LigaForm3"/>
+ </LigatureSet>
+ -->
+ <LigatureSet glyph="U+1F1E6">
+ <Ligature components="U+1F1E6" glyph="LigaForm6"/>
+ <Ligature components="U+1F1E7" glyph=".notdef"/>
+ </LigatureSet>
+ </LigatureSubst>
+ </Lookup>
+ </LookupList>
+ </GSUB>
+</ttFont>
diff --git a/tests/data/emoji_itemization.xml b/tests/data/emoji_itemization.xml
new file mode 100644
index 0000000..d4213f9
--- /dev/null
+++ b/tests/data/emoji_itemization.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<familyset version="22">
+ <!-- Place NoGlyphFont here since the first font can be chosen if no font is
+ available for the code point. -->
+ <family>
+ <font weight="400" style="normal">Ascii.ttf</font>
+ </family>
+ <family lang="und-Zsye">
+ <font weight="400" style="normal">EmojiSubset.ttf</font>
+ </family>
+ <family lang="und-Zsye">
+ <font weight="400" style="normal">EmojiBase.ttf</font>
+ </family>
+</familyset>
diff --git a/tests/perftests/Android.bp b/tests/perftests/Android.bp
index 83db1c5..19ed8eb 100644
--- a/tests/perftests/Android.bp
+++ b/tests/perftests/Android.bp
@@ -14,6 +14,10 @@
// limitations under the License.
//
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
cc_benchmark {
name: "minikin_perftests",
test_suites: ["device-tests"],
diff --git a/tests/perftests/main.cpp b/tests/perftests/main.cpp
index 11904e9..88e1900 100644
--- a/tests/perftests/main.cpp
+++ b/tests/perftests/main.cpp
@@ -13,32 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
#include <benchmark/benchmark.h>
-#include <cutils/log.h>
-#include <unicode/uclean.h>
-#include <unicode/udata.h>
int main(int argc, char** argv) {
- const char* fn = "/apex/com.android.i18n/etc/icu/" U_ICUDATA_NAME ".dat";
- int fd = open(fn, O_RDONLY);
- LOG_ALWAYS_FATAL_IF(fd == -1);
- struct stat st;
- LOG_ALWAYS_FATAL_IF(fstat(fd, &st) != 0);
- void* data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
-
- UErrorCode errorCode = U_ZERO_ERROR;
- udata_setCommonData(data, &errorCode);
- LOG_ALWAYS_FATAL_IF(U_FAILURE(errorCode));
- u_init(&errorCode);
- LOG_ALWAYS_FATAL_IF(U_FAILURE(errorCode));
-
benchmark::Initialize(&argc, argv);
benchmark::RunSpecifiedBenchmarks();
- u_cleanup();
return 0;
}
diff --git a/tests/stresstest/Android.bp b/tests/stresstest/Android.bp
index fb73e09..784dc6a 100644
--- a/tests/stresstest/Android.bp
+++ b/tests/stresstest/Android.bp
@@ -14,6 +14,10 @@
// see how_to_run.txt for instructions on running these tests
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
cc_test {
name: "minikin_stress_tests",
diff --git a/tests/stresstest/FontFamilyTest.cpp b/tests/stresstest/FontFamilyTest.cpp
index 7554314..7a9813e 100644
--- a/tests/stresstest/FontFamilyTest.cpp
+++ b/tests/stresstest/FontFamilyTest.cpp
@@ -36,7 +36,7 @@ TEST_P(FontFamilyHarfBuzzCompatibilityTest, CoverageTest) {
int ttcIndex = GetParam().second;
auto font = std::make_shared<FreeTypeMinikinFontForTest>(fontPath);
- std::vector<Font> fonts;
+ std::vector<std::shared_ptr<Font>> fonts;
fonts.push_back(Font::Builder(font).build());
std::shared_ptr<FontFamily> family = std::make_shared<FontFamily>(std::move(fonts));
diff --git a/tests/unittest/Android.bp b/tests/unittest/Android.bp
index 0971a06..cae9003 100644
--- a/tests/unittest/Android.bp
+++ b/tests/unittest/Android.bp
@@ -14,6 +14,10 @@
// see how_to_run.txt for instructions on running these tests
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
cc_test {
name: "minikin_tests",
test_suites: ["device-tests"],
@@ -41,12 +45,15 @@ cc_test {
srcs: [
"AndroidLineBreakerHelperTest.cpp",
"BidiUtilsTest.cpp",
+ "BufferTest.cpp",
+ "BoundsCacheTest.cpp",
"CmapCoverageTest.cpp",
"EmojiTest.cpp",
"FontTest.cpp",
"FontCollectionTest.cpp",
"FontCollectionItemizeTest.cpp",
"FontFamilyTest.cpp",
+ "FontFileParserTest.cpp",
"FontLanguageListCacheTest.cpp",
"FontUtilsTest.cpp",
"HasherTest.cpp",
diff --git a/tests/unittest/BoundsCacheTest.cpp b/tests/unittest/BoundsCacheTest.cpp
new file mode 100644
index 0000000..8c727f9
--- /dev/null
+++ b/tests/unittest/BoundsCacheTest.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2018 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 <gtest/gtest.h>
+
+#include "minikin/BoundsCache.h"
+
+#include "FontTestUtils.h"
+#include "LocaleListCache.h"
+#include "UnicodeUtils.h"
+
+namespace minikin {
+
+class TestableBoundsCache : public BoundsCache {
+public:
+ TestableBoundsCache(uint32_t maxEntries) : BoundsCache(maxEntries) {}
+};
+
+class BoundsCapture {
+public:
+ BoundsCapture() {}
+
+ void operator()(const MinikinRect& rect, float advance) {
+ mRect = rect;
+ mAdvance = advance;
+ }
+
+ const MinikinRect& rect() const { return mRect; }
+ float advance() const { return mAdvance; }
+
+private:
+ MinikinRect mRect;
+ float mAdvance;
+};
+
+TEST(BoundsCacheTest, cacheHitTest) {
+ auto text = utf8ToUtf16("android");
+ Range range(0, text.size());
+ MinikinPaint paint(buildFontCollection("Ascii.ttf"));
+
+ TestableBoundsCache boundsCache(10);
+
+ BoundsCapture bounds1;
+ boundsCache.getOrCreate(text, range, paint, false /* LTR */, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, bounds1);
+
+ BoundsCapture bounds2;
+ boundsCache.getOrCreate(text, range, paint, false /* LTR */, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, bounds2);
+
+ EXPECT_EQ(bounds1.rect(), bounds2.rect());
+ EXPECT_EQ(bounds1.advance(), bounds2.advance());
+}
+
+TEST(BoundsCacheTest, cacheMissTest) {
+ auto text1 = utf8ToUtf16("android");
+ auto text2 = utf8ToUtf16("αβγδζ");
+ MinikinPaint paint(buildFontCollection("Ascii.ttf"));
+
+ TestableBoundsCache boundsCache(10);
+
+ BoundsCapture bounds1;
+ BoundsCapture bounds2;
+
+ {
+ SCOPED_TRACE("Different text");
+ boundsCache.getOrCreate(text1, Range(0, text1.size()), paint, false /* LTR */,
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1);
+ boundsCache.getOrCreate(text2, Range(0, text2.size()), paint, false /* LTR */,
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2);
+ EXPECT_NE(bounds1.rect(), bounds2.rect());
+ EXPECT_NE(bounds1.advance(), bounds2.advance());
+ }
+ {
+ SCOPED_TRACE("Different range");
+ boundsCache.getOrCreate(text1, Range(0, text1.size()), paint, false /* LTR */,
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1);
+ boundsCache.getOrCreate(text1, Range(1, text1.size()), paint, false /* LTR */,
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2);
+ EXPECT_NE(bounds1.rect(), bounds2.rect());
+ EXPECT_NE(bounds1.advance(), bounds2.advance());
+ }
+ {
+ SCOPED_TRACE("Different collection");
+ MinikinPaint paint1(buildFontCollection("Ascii.ttf"));
+ paint1.size = 10.0f;
+ paint1.scaleX = 1.0f;
+ boundsCache.getOrCreate(text1, Range(0, text1.size()), paint1, false /* LTR */,
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1);
+ MinikinPaint paint2(buildFontCollection("Emoji.ttf"));
+ paint2.size = 10.0f;
+ paint2.scaleX = 1.0f;
+ boundsCache.getOrCreate(text1, Range(0, text1.size()), paint2, false /* LTR */,
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2);
+ EXPECT_NE(bounds1.rect(), bounds2.rect());
+ EXPECT_NE(bounds1.advance(), bounds2.advance());
+ }
+ {
+ SCOPED_TRACE("Different size");
+ auto collection = buildFontCollection("Ascii.ttf");
+ MinikinPaint paint1(collection);
+ paint1.size = 10.0f;
+ paint1.scaleX = 1.0f;
+ boundsCache.getOrCreate(text1, Range(0, text1.size()), paint1, false /* LTR */,
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1);
+ MinikinPaint paint2(collection);
+ paint2.size = 20.0f;
+ paint2.scaleX = 1.0f;
+ boundsCache.getOrCreate(text1, Range(0, text1.size()), paint2, false /* LTR */,
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2);
+ EXPECT_NE(bounds1.rect(), bounds2.rect());
+ EXPECT_NE(bounds1.advance(), bounds2.advance());
+ }
+ {
+ SCOPED_TRACE("Different letter spacing");
+ auto collection = buildFontCollection("Ascii.ttf");
+ MinikinPaint paint1(collection);
+ paint1.letterSpacing = 0.0f;
+ paint1.size = 10.0f;
+ paint1.scaleX = 1.0f;
+ boundsCache.getOrCreate(text1, Range(0, text1.size()), paint1, false /* LTR */,
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1);
+ MinikinPaint paint2(collection);
+ paint2.letterSpacing = 1.0f;
+ paint2.size = 10.0f;
+ paint2.scaleX = 1.0f;
+ boundsCache.getOrCreate(text1, Range(0, text1.size()), paint2, false /* LTR */,
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2);
+ EXPECT_NE(bounds1.rect(), bounds2.rect());
+ EXPECT_NE(bounds1.advance(), bounds2.advance());
+ }
+}
+
+TEST(BoundsCacheTest, cacheOverflowTest) {
+ auto text = utf8ToUtf16("android");
+ Range range(0, text.size());
+ MinikinPaint paint(buildFontCollection("Ascii.ttf"));
+
+ TestableBoundsCache boundsCache(5);
+
+ BoundsCapture bounds1;
+ boundsCache.getOrCreate(text, range, paint, false /* LTR */, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, bounds1);
+
+ for (char c = 'a'; c <= 'z'; c++) {
+ auto text1 = utf8ToUtf16(std::string(10, c));
+ BoundsCapture bounds2;
+ boundsCache.getOrCreate(text1, Range(0, text1.size()), paint, false /* LTR */,
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2);
+ }
+
+ BoundsCapture bounds3;
+ boundsCache.getOrCreate(text, range, paint, false /* LTR */, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, bounds3);
+ EXPECT_EQ(bounds1.rect(), bounds3.rect());
+ EXPECT_EQ(bounds1.advance(), bounds3.advance());
+}
+
+} // namespace minikin
diff --git a/tests/unittest/BufferTest.cpp b/tests/unittest/BufferTest.cpp
new file mode 100644
index 0000000..8b1db33
--- /dev/null
+++ b/tests/unittest/BufferTest.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 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 "minikin/Buffer.h"
+
+#include <gtest/gtest.h>
+
+namespace minikin {
+
+class TestObject {
+public:
+ void writeTo(BufferWriter* writer) const {
+ // Total size = 20
+ // uint8_t (1)
+ writer->write<uint8_t>(0xAB);
+ // padding (1), uint16_t (2)
+ writer->write<uint16_t>(0xCDEF);
+ // uint8_t(1)
+ writer->write<uint8_t>(0x01);
+ // padding (3), array size (4), uint32_t (4) * 2
+ uint32_t uint32Array[] = {0x98765432, 0x98765433};
+ writer->writeArray<uint32_t>(uint32Array, 2);
+ }
+};
+
+TEST(BufferTest, testMeasureWriteRead) {
+ TestObject testObject;
+ BufferWriter fakeWriter(nullptr);
+ testObject.writeTo(&fakeWriter);
+ ASSERT_EQ(fakeWriter.size(), 20u);
+ std::vector<uint8_t> buffer(fakeWriter.size());
+
+ BufferWriter writer(buffer.data());
+ testObject.writeTo(&writer);
+ ASSERT_EQ(writer.size(), buffer.size());
+
+ BufferReader reader(buffer.data());
+ ASSERT_EQ(reader.data(), buffer.data());
+ ASSERT_EQ(reader.pos(), 0u);
+ ASSERT_EQ(reader.read<uint8_t>(), 0xABu);
+ ASSERT_EQ(reader.pos(), 1u);
+ ASSERT_EQ(reader.read<uint16_t>(), 0xCDEFu);
+ ASSERT_EQ(reader.pos(), 4u);
+ ASSERT_EQ(reader.read<uint8_t>(), 0x01u);
+ ASSERT_EQ(reader.pos(), 5u);
+ auto [uint32Array, size] = reader.readArray<uint32_t>();
+ ASSERT_EQ(size, 2u);
+ ASSERT_EQ(uint32Array[0], 0x98765432u);
+ ASSERT_EQ(uint32Array[1], 0x98765433u);
+ ASSERT_EQ(reader.pos(), 20u);
+}
+
+TEST(BufferTest, testSkip) {
+ TestObject testObject;
+ BufferWriter fakeWriter(nullptr);
+ testObject.writeTo(&fakeWriter);
+ ASSERT_EQ(fakeWriter.size(), 20u);
+ std::vector<uint8_t> buffer(fakeWriter.size());
+
+ BufferWriter writer(buffer.data());
+ testObject.writeTo(&writer);
+ ASSERT_EQ(writer.size(), buffer.size());
+
+ BufferReader reader(buffer.data());
+ ASSERT_EQ(reader.data(), buffer.data());
+ ASSERT_EQ(reader.pos(), 0u);
+ reader.skip<uint8_t>();
+ ASSERT_EQ(reader.pos(), 1u);
+ reader.read<uint16_t>();
+ ASSERT_EQ(reader.pos(), 4u);
+ reader.skip<uint8_t>();
+ ASSERT_EQ(reader.pos(), 5u);
+ reader.skipArray<uint32_t>();
+ ASSERT_EQ(reader.pos(), 20u);
+}
+
+} // namespace minikin
diff --git a/tests/unittest/FontCollectionItemizeTest.cpp b/tests/unittest/FontCollectionItemizeTest.cpp
index 8cd95aa..6f1e194 100644
--- a/tests/unittest/FontCollectionItemizeTest.cpp
+++ b/tests/unittest/FontCollectionItemizeTest.cpp
@@ -21,6 +21,7 @@
#include <gtest/gtest.h>
#include "minikin/FontFamily.h"
+#include "minikin/FontFileParser.h"
#include "minikin/LocaleList.h"
#include "minikin/MinikinPaint.h"
@@ -55,10 +56,15 @@ const char kMixedEmojiFont[] = "ColorTextMixedEmojiFont.ttf";
const char kHasCmapFormat14Font[] = "NoCmapFormat14.ttf";
const char kNoCmapFormat14Font[] = "VariationSelectorTest-Regular.ttf";
+struct Run {
+ FakedFont fakedFont;
+ int start;
+ int end;
+};
+
// Utility functions for calling itemize function.
-std::vector<FontCollection::Run> itemize(const std::shared_ptr<FontCollection>& collection,
- const char* str, FontStyle style,
- const std::string& localeList) {
+std::vector<Run> itemize(const std::shared_ptr<FontCollection>& collection, const char* str,
+ FontStyle style, const std::string& localeList) {
const size_t BUF_SIZE = 256;
uint16_t buf[BUF_SIZE];
size_t len;
@@ -76,35 +82,38 @@ std::vector<FontCollection::Run> itemize(const std::shared_ptr<FontCollection>&
for (uint32_t i = 0; i < runMax; ++i) {
EXPECT_EQ(result[i].start, resultWithRunMax[i].start);
EXPECT_EQ(result[i].end, resultWithRunMax[i].end);
- EXPECT_EQ(result[i].fakedFont, resultWithRunMax[i].fakedFont);
+ EXPECT_EQ(result[i].familyMatch, resultWithRunMax[i].familyMatch);
}
}
- return result;
+ std::vector<Run> runs;
+ for (const auto& r : result) {
+ runs.push_back(
+ {collection->getBestFont(U16StringPiece(buf, len), r, style), r.start, r.end});
+ }
+ return runs;
}
// Overloaded version for default font style.
-std::vector<FontCollection::Run> itemize(const std::shared_ptr<FontCollection>& collection,
- const char* str, const std::string& localeList) {
+std::vector<Run> itemize(const std::shared_ptr<FontCollection>& collection, const char* str,
+ const std::string& localeList) {
return itemize(collection, str, FontStyle(), localeList);
}
// Overloaded version for empty locale list id.
-std::vector<FontCollection::Run> itemize(const std::shared_ptr<FontCollection>& collection,
- const char* str, FontStyle style) {
+std::vector<Run> itemize(const std::shared_ptr<FontCollection>& collection, const char* str,
+ FontStyle style) {
return itemize(collection, str, style, "");
}
// Overloaded version for default font style and empty locale list id.
-std::vector<FontCollection::Run> itemize(const std::shared_ptr<FontCollection>& collection,
- const char* str) {
+std::vector<Run> itemize(const std::shared_ptr<FontCollection>& collection, const char* str) {
return itemize(collection, str, FontStyle(), "");
}
// Utility function to obtain font path associated with run.
-std::string getFontName(const FontCollection::Run& run) {
- EXPECT_NE(nullptr, run.fakedFont.font);
- return getBasename(
- ((FreeTypeMinikinFontForTest*)run.fakedFont.font->typeface().get())->fontPath());
+std::string getFontName(const Run& run) {
+ EXPECT_NE(nullptr, run.fakedFont.font.get());
+ return getBasename(run.fakedFont.font.get()->typeface()->GetFontPath());
}
// Utility function to obtain LocaleList from string.
@@ -515,13 +524,13 @@ TEST(FontCollectionItemizeTest, itemize_variationSelector) {
ASSERT_EQ(1U, runs.size());
EXPECT_EQ(0, runs[0].start);
EXPECT_EQ(1, runs[0].end);
- EXPECT_TRUE(runs[0].fakedFont.font == nullptr || kLatinFont == getFontName(runs[0]));
+ EXPECT_TRUE(runs[0].fakedFont.font.get() == nullptr || kLatinFont == getFontName(runs[0]));
runs = itemize(collection, "U+FE00", "zh-Hant");
ASSERT_EQ(1U, runs.size());
EXPECT_EQ(0, runs[0].start);
EXPECT_EQ(1, runs[0].end);
- EXPECT_TRUE(runs[0].fakedFont.font == nullptr || kLatinFont == getFontName(runs[0]));
+ EXPECT_TRUE(runs[0].fakedFont.font.get() == nullptr || kLatinFont == getFontName(runs[0]));
// First font family (Regular.ttf) supports U+203C but doesn't support U+203C U+FE0F.
// Emoji.ttf font supports U+203C U+FE0F. Emoji.ttf should be selected.
@@ -652,13 +661,13 @@ TEST(FontCollectionItemizeTest, itemize_variationSelectorSupplement) {
ASSERT_EQ(1U, runs.size());
EXPECT_EQ(0, runs[0].start);
EXPECT_EQ(2, runs[0].end);
- EXPECT_TRUE(runs[0].fakedFont.font == nullptr || kLatinFont == getFontName(runs[0]));
+ EXPECT_TRUE(runs[0].fakedFont.font.get() == nullptr || kLatinFont == getFontName(runs[0]));
runs = itemize(collection, "U+E0100", "zh-Hant");
ASSERT_EQ(1U, runs.size());
EXPECT_EQ(0, runs[0].start);
EXPECT_EQ(2, runs[0].end);
- EXPECT_TRUE(runs[0].fakedFont.font == nullptr || kLatinFont == getFontName(runs[0]));
+ EXPECT_TRUE(runs[0].fakedFont.font.get() == nullptr || kLatinFont == getFontName(runs[0]));
}
TEST(FontCollectionItemizeTest, itemize_no_crash) {
@@ -926,7 +935,7 @@ TEST(FontCollectionItemizeTest, itemize_LocaleScore) {
// Prepare first font which doesn't supports U+9AA8
auto firstFamilyMinikinFont =
std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(kNoGlyphFont));
- std::vector<Font> fonts;
+ std::vector<std::shared_ptr<Font>> fonts;
fonts.push_back(Font::Builder(firstFamilyMinikinFont).build());
auto firstFamily =
std::make_shared<FontFamily>(registerLocaleList("und"), FamilyVariant::DEFAULT,
@@ -941,7 +950,7 @@ TEST(FontCollectionItemizeTest, itemize_LocaleScore) {
for (size_t i = 0; i < testCase.fontLocales.size(); ++i) {
auto minikinFont =
std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(kJAFont));
- std::vector<Font> fonts;
+ std::vector<std::shared_ptr<Font>> fonts;
fonts.push_back(Font::Builder(minikinFont).build());
auto family = std::make_shared<FontFamily>(registerLocaleList(testCase.fontLocales[i]),
FamilyVariant::DEFAULT, std::move(fonts),
@@ -953,14 +962,15 @@ TEST(FontCollectionItemizeTest, itemize_LocaleScore) {
// Do itemize
auto runs = itemize(collection, "U+9AA8", testCase.userPreferredLocale);
ASSERT_EQ(1U, runs.size());
- ASSERT_NE(nullptr, runs[0].fakedFont.font);
+ ASSERT_NE(nullptr, runs[0].fakedFont.font.get());
// First family doesn't support U+9AA8 and others support it, so the first font should not
// be selected.
- EXPECT_NE(firstFamilyMinikinFont.get(), runs[0].fakedFont.font->typeface().get());
+ EXPECT_NE(firstFamilyMinikinFont.get(), runs[0].fakedFont.font.get()->typeface().get());
// Lookup used font family by MinikinFont*.
- const int usedLocaleIndex = fontLocaleIdxMap[runs[0].fakedFont.font->typeface().get()];
+ const int usedLocaleIndex =
+ fontLocaleIdxMap[runs[0].fakedFont.font.get()->typeface().get()];
EXPECT_EQ(testCase.selectedFontIndex, usedLocaleIndex);
}
}
@@ -1521,10 +1531,10 @@ TEST(FontCollectionItemizeTest, itemizeShouldKeepOrderForVS) {
// Both fontA/fontB support U+35A8 but don't support U+35A8 U+E0100. The first font should be
// selected.
auto runs = itemize(collection, "U+35A8 U+E0100");
- EXPECT_EQ(familyA->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(familyA->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(reversedCollection, "U+35A8 U+E0100");
- EXPECT_EQ(familyB->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(familyB->getFont(0), runs[0].fakedFont.font.get());
}
// For b/29585939
@@ -1544,10 +1554,10 @@ TEST(FontCollectionItemizeTest, itemizeShouldKeepOrderForVS2) {
// Both hasCmapFormat14Font/noCmapFormat14Font support U+5380 but don't support U+5380 U+E0100.
// The first font should be selected.
auto runs = itemize(collection, "U+5380 U+E0100");
- EXPECT_EQ(hasCmapFormat14Family->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(hasCmapFormat14Family->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(reversedCollection, "U+5380 U+E0100");
- EXPECT_EQ(noCmapFormat14Family->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(noCmapFormat14Family->getFont(0), runs[0].fakedFont.font.get());
}
TEST(FontCollectionItemizeTest, colorEmojiSelectionTest) {
@@ -1561,44 +1571,44 @@ TEST(FontCollectionItemizeTest, colorEmojiSelectionTest) {
// Both textEmojiFamily and colorEmojiFamily supports U+203C and U+23E9.
// U+203C is text default emoji, and U+23E9 is color default emoji.
auto runs = itemize(collection, "U+203C", "en-US,en-Zsym");
- EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+23E9", "en-US,en-Zsym");
- EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+203C", "en-US,en-Zsye");
- EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+23E9", "en-US,en-Zsye");
- EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+203C", "ja-Zsym-JP");
- EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+23E9", "ja-Zsym-JP");
- EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+203C", "ja-Zsye-JP");
- EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+23E9", "ja-Zsye-JP");
- EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+203C", "ja-JP-u-em-text");
- EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+23E9", "ja-JP-u-em-text");
- EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+203C", "ja-JP-u-em-emoji");
- EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+23E9", "ja-JP-u-em-emoji");
- EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+203C", "ja-JP,und-Zsym");
- EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+23E9", "ja-JP,und-Zsym");
- EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+203C", "ja-JP,und-Zsye");
- EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "U+23E9", "ja-JP,und-Zsye");
- EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
}
TEST(FontCollectionItemizeTest, customFallbackTest) {
@@ -1612,11 +1622,60 @@ TEST(FontCollectionItemizeTest, customFallbackTest) {
auto collection = std::make_shared<FontCollection>(families);
auto runs = itemize(collection, "'a'", "");
- EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "'a'", "en-US");
- EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font.get());
runs = itemize(collection, "'a'", "ja-JP");
- EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font);
+ EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font.get());
+}
+
+std::string itemizeEmojiAndFontPostScriptName(const std::string& txt) {
+ auto firstFamily = buildFontFamily(kAsciiFont);
+ auto OverrideEmojiFamily = buildFontFamily("OverrideEmoji.ttf", "und-Zsye");
+ auto emojiBaseFamily = buildFontFamily("EmojiBase.ttf", "und-Zsye");
+
+ std::vector<std::shared_ptr<FontFamily>> families = {firstFamily, OverrideEmojiFamily,
+ emojiBaseFamily};
+
+ auto collection = std::make_shared<FontCollection>(families);
+ auto runs = itemize(collection, txt.c_str());
+
+ EXPECT_EQ(1u, runs.size());
+ return FontFileParser(runs[0].fakedFont.font->baseFont()).getPostScriptName().value();
+}
+
+TEST(FontCollectionItemizeTest, emojiFallback) {
+ // OverrideEmojiFont supports U+1F9B0, U+E0000, U+1F3FB and U+1F9B0 U+1F3FB sequence.
+ // Use Override font.
+ EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B0"));
+ EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+E0000"));
+ EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B0 U+1F3FB"));
+ EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B0 U+FE0F U+1F3FB"));
+
+ // OverrideEmojiFont doesn't suppot U+1F9B6 U+E0001 and U+1F3FC.
+ EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B6"));
+ EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+E0001"));
+ EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B6 U+1F3FC"));
+ EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B6 U+FE0F U+1F3FC"));
+
+ // OverrideEmojiFont support U+1F9B1, U+1F3FB but doesn't support the sequence U+1F9B1 U+1F3FB.
+ EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B1"));
+ EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F3FB"));
+ EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B1 U+1F3FB"));
+ EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B1 U+FE0F U+1F3FB"));
+
+ // Find the longest sequence if two sequences are supported.
+ EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B2 U+200D U+1F9B3"));
+ EXPECT_EQ("EmojiBaseFont",
+ itemizeEmojiAndFontPostScriptName("U+1F9B2 U+200D U+1F9B3 U+200D U+1F9B4"));
+}
+
+TEST(FontCollectionItemizeTest, emojiFlagFallback) {
+ // If the OverrideEmojiFont supports U+1F1E6 U+1F1E6, use that font.
+ EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F1E6 U+1F1E6"));
+
+ // Even if the OverrideEmojiFont directs to .notdef (i.e. Tofu glyph) for the sequence, use it.
+ EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F1E6 U+1F1E7"));
}
} // namespace minikin
diff --git a/tests/unittest/FontCollectionTest.cpp b/tests/unittest/FontCollectionTest.cpp
index 6b39508..aa9d4a8 100644
--- a/tests/unittest/FontCollectionTest.cpp
+++ b/tests/unittest/FontCollectionTest.cpp
@@ -19,6 +19,7 @@
#include <gtest/gtest.h>
#include "FontTestUtils.h"
+#include "FreeTypeMinikinFontForTest.h"
#include "MinikinInternal.h"
namespace minikin {
@@ -56,22 +57,23 @@ void expectVSGlyphs(const FontCollection* fc, uint32_t codepoint, const std::set
}
}
-TEST(FontCollectionTest, hasVariationSelectorTest) {
- auto fc = buildFontCollection(kVsTestFont);
-
+void expectVSGlyphsForVsTestFont(const FontCollection* fc) {
EXPECT_FALSE(fc->hasVariationSelector(0x82A6, 0));
- expectVSGlyphs(fc.get(), 0x82A6,
- std::set<uint32_t>({0xFE00, 0xFE0E, 0xE0100, 0xE0101, 0xE0102}));
+ expectVSGlyphs(fc, 0x82A6, std::set<uint32_t>({0xFE00, 0xFE0E, 0xE0100, 0xE0101, 0xE0102}));
EXPECT_FALSE(fc->hasVariationSelector(0x845B, 0));
- expectVSGlyphs(fc.get(), 0x845B,
- std::set<uint32_t>({0xFE01, 0xFE0E, 0xE0101, 0xE0102, 0xE0103}));
+ expectVSGlyphs(fc, 0x845B, std::set<uint32_t>({0xFE01, 0xFE0E, 0xE0101, 0xE0102, 0xE0103}));
EXPECT_FALSE(fc->hasVariationSelector(0x537F, 0));
- expectVSGlyphs(fc.get(), 0x537F, std::set<uint32_t>({0xFE0E}));
+ expectVSGlyphs(fc, 0x537F, std::set<uint32_t>({0xFE0E}));
EXPECT_FALSE(fc->hasVariationSelector(0x717D, 0));
- expectVSGlyphs(fc.get(), 0x717D, std::set<uint32_t>({0xFE02, 0xE0102, 0xE0103}));
+ expectVSGlyphs(fc, 0x717D, std::set<uint32_t>({0xFE02, 0xE0102, 0xE0103}));
+}
+
+TEST(FontCollectionTest, hasVariationSelectorTest) {
+ auto fc = buildFontCollection(kVsTestFont);
+ expectVSGlyphsForVsTestFont(fc.get());
}
const char kEmojiXmlFile[] = "emoji.xml";
@@ -175,4 +177,144 @@ TEST(FontCollectionTest, createWithVariations) {
}
}
+std::vector<uint8_t> writeToBuffer(
+ const std::vector<std::shared_ptr<FontCollection>>& collections) {
+ BufferWriter fakeWriter(nullptr);
+ FontCollection::writeVector<writeFreeTypeMinikinFontForTest>(&fakeWriter, collections);
+ std::vector<uint8_t> buffer(fakeWriter.size());
+ BufferWriter writer(buffer.data());
+ FontCollection::writeVector<writeFreeTypeMinikinFontForTest>(&writer, collections);
+ return buffer;
+}
+
+TEST(FontCollectionTest, bufferTest) {
+ {
+ std::vector<std::shared_ptr<FontCollection>> original({buildFontCollection(kVsTestFont)});
+ std::vector<uint8_t> buffer = writeToBuffer(original);
+ BufferReader reader(buffer.data());
+ auto copied = FontCollection::readVector<readFreeTypeMinikinFontForTest>(&reader);
+ EXPECT_EQ(1u, copied.size());
+ expectVSGlyphsForVsTestFont(copied[0].get());
+ EXPECT_EQ(original[0]->getSupportedTags(), copied[0]->getSupportedTags());
+ // Id will be different.
+ EXPECT_NE(original[0]->getId(), copied[0]->getId());
+ std::vector<uint8_t> newBuffer = writeToBuffer(copied);
+ EXPECT_EQ(buffer, newBuffer);
+ }
+ {
+ // Test that FontFamily instances are shared.
+ std::vector<std::shared_ptr<FontFamily>> families = {buildFontFamily(kVsTestFont)};
+ auto fc1 = std::make_shared<FontCollection>(families);
+ auto fc2 = std::make_shared<FontCollection>(families);
+ std::vector<std::shared_ptr<FontCollection>> original({fc1, fc2});
+ std::vector<uint8_t> buffer = writeToBuffer(original);
+ BufferReader reader(buffer.data());
+ auto copied = FontCollection::readVector<readFreeTypeMinikinFontForTest>(&reader);
+ EXPECT_EQ(2u, copied.size());
+ EXPECT_EQ(copied[0]->mFamilies[0], copied[1]->mFamilies[0]);
+ std::vector<uint8_t> newBuffer = writeToBuffer(copied);
+ EXPECT_EQ(buffer, newBuffer);
+ }
+ {
+ // Test axes.
+ // This font has 'wdth' and 'wght' axes.
+ const char kMultiAxisFont[] = "MultiAxis.ttf";
+ std::vector<std::shared_ptr<FontCollection>> original(
+ {buildFontCollection(kMultiAxisFont)});
+ std::vector<uint8_t> buffer = writeToBuffer(original);
+ BufferReader reader(buffer.data());
+ auto copied = FontCollection::readVector<readFreeTypeMinikinFontForTest>(&reader);
+ EXPECT_EQ(1u, copied.size());
+ EXPECT_EQ(1u,
+ copied[0]->getSupportedTags().count(MinikinFont::MakeTag('w', 'd', 't', 'h')));
+ EXPECT_EQ(1u,
+ copied[0]->getSupportedTags().count(MinikinFont::MakeTag('w', 'g', 'h', 't')));
+ std::vector<uint8_t> newBuffer = writeToBuffer(copied);
+ EXPECT_EQ(buffer, newBuffer);
+ }
+}
+
+TEST(FontCollectionTest, FamilyMatchResultBuilderTest) {
+ using Builder = FontCollection::FamilyMatchResult::Builder;
+ EXPECT_TRUE(Builder().empty());
+ EXPECT_EQ(0u, Builder().size());
+ EXPECT_EQ(1u, Builder().add(5).size());
+ EXPECT_EQ(2u, Builder().add(5).add(4).size());
+
+ // Reset
+ EXPECT_TRUE(Builder().add(5).reset().empty());
+ EXPECT_EQ(0u, Builder().add(5).reset().size());
+}
+
+TEST(FontCollectionTest, FamilyMatchResultTest) {
+ using Builder = FontCollection::FamilyMatchResult::Builder;
+
+ auto r = Builder().build();
+ EXPECT_EQ(0u, r.size());
+ EXPECT_TRUE(r.empty());
+
+ r = Builder().add(1).build();
+ EXPECT_EQ(1u, r.size());
+ EXPECT_FALSE(r.empty());
+ EXPECT_EQ(1u, r[0]);
+
+ r = Builder().add(1).add(2).build();
+ EXPECT_EQ(2u, r.size());
+ EXPECT_FALSE(r.empty());
+ EXPECT_EQ(1u, r[0]);
+ EXPECT_EQ(2u, r[1]);
+}
+
+TEST(FontCollectionTest, FamilyMatchResultTest_BuilderHoldeFirst7) {
+ auto b = FontCollection::FamilyMatchResult::Builder();
+ for (uint8_t i = 0; i < 128; ++i) {
+ b.add(i);
+ }
+ auto r = b.build();
+ EXPECT_EQ(7u, r.size());
+ EXPECT_FALSE(r.empty());
+ EXPECT_EQ(0u, r[0]);
+ EXPECT_EQ(1u, r[1]);
+ EXPECT_EQ(2u, r[2]);
+ EXPECT_EQ(3u, r[3]);
+ EXPECT_EQ(4u, r[4]);
+ EXPECT_EQ(5u, r[5]);
+ EXPECT_EQ(6u, r[6]);
+}
+
+TEST(FontCollectionTest, FamilyMatchResultTest_iterator) {
+ auto b = FontCollection::FamilyMatchResult::Builder();
+ for (uint8_t i = 0; i < 7; ++i) {
+ b.add(i);
+ }
+ auto r = b.build();
+ EXPECT_EQ(7u, r.size());
+ EXPECT_FALSE(r.empty());
+ int i = 0;
+ for (auto v : r) {
+ EXPECT_EQ(i, v);
+ i++;
+ }
+}
+
+TEST(FontCollectionTest, FamilyMatchResultTest_intersect) {
+ using Builder = FontCollection::FamilyMatchResult::Builder;
+
+ EXPECT_EQ(Builder().add(1).add(2).add(3).build(),
+ FontCollection::FamilyMatchResult::intersect(Builder().add(1).add(2).add(3).build(),
+ Builder().add(1).add(2).add(3).build()));
+
+ EXPECT_EQ(Builder().build(),
+ FontCollection::FamilyMatchResult::intersect(Builder().add(1).add(2).add(3).build(),
+ Builder().build()));
+
+ EXPECT_EQ(Builder().build(),
+ FontCollection::FamilyMatchResult::intersect(Builder().add(2).add(4).add(6).build(),
+ Builder().add(1).add(3).add(5).build()));
+
+ EXPECT_EQ(Builder().add(1).add(3).build(),
+ FontCollection::FamilyMatchResult::intersect(Builder().add(1).add(2).add(3).build(),
+ Builder().add(1).add(3).add(5).build()));
+}
+
} // namespace minikin
diff --git a/tests/unittest/FontFamilyTest.cpp b/tests/unittest/FontFamilyTest.cpp
index 2b70faf..fd2fc9a 100644
--- a/tests/unittest/FontFamilyTest.cpp
+++ b/tests/unittest/FontFamilyTest.cpp
@@ -20,6 +20,7 @@
#include "minikin/LocaleList.h"
+#include "BufferUtils.h"
#include "FontTestUtils.h"
#include "FreeTypeMinikinFontForTest.h"
#include "LocaleListCache.h"
@@ -156,6 +157,40 @@ TEST(LocaleTest, testReconstruction) {
EXPECT_EQ("zzz-Zzzz-999", createLocaleWithoutICUSanitization("zzz-Zzzz-999").getString());
}
+TEST(LocaleTest, ReconstructFromIdentifierTest) {
+ std::string locales[] = {
+ // Language
+ "en",
+ "fil",
+ "und",
+ // Script
+ "en-Latn",
+ "fil-Taga",
+ "und-Zsye",
+ // Region
+ "en-US",
+ "fil-PH",
+ "es-419",
+ // Variant
+ "de-Latn-DE",
+ "de-Latn-DE-1901",
+ "de-Latn-DE-1996",
+ // Line break style
+ "ja-JP-u-lb-loose",
+ "ja-JP-u-lb-normal",
+ "ja-JP-u-lb-strict",
+ // Emoji subtag
+ "es-Latn-419-u-em-emoji",
+ // Everything
+ "de-Latn-DE-1996-u-lb-loose-u-em-emoji",
+ };
+ for (const std::string& locale : locales) {
+ EXPECT_EQ(createLocaleWithoutICUSanitization(locale),
+ Locale(createLocaleWithoutICUSanitization(locale).getIdentifier()))
+ << "locale = " << locale;
+ }
+}
+
TEST(LocaleTest, ScriptEqualTest) {
EXPECT_TRUE(createLocale("en").isEqualScript(createLocale("en")));
EXPECT_TRUE(createLocale("en-Latn").isEqualScript(createLocale("en")));
@@ -515,9 +550,7 @@ void expectVSGlyphs(FontFamily* family, uint32_t codepoint, const std::set<uint3
}
}
-TEST_F(FontFamilyTest, hasVariationSelectorTest) {
- std::shared_ptr<FontFamily> family = buildFontFamily(kVsTestFont);
-
+void expectVSGlyphsForVsTestFont(FontFamily* family) {
const uint32_t kVS1 = 0xFE00;
const uint32_t kVS2 = 0xFE01;
const uint32_t kVS3 = 0xFE02;
@@ -528,23 +561,28 @@ TEST_F(FontFamilyTest, hasVariationSelectorTest) {
const uint32_t kSupportedChar1 = 0x82A6;
EXPECT_TRUE(family->getCoverage().get(kSupportedChar1));
- expectVSGlyphs(family.get(), kSupportedChar1, std::set<uint32_t>({kVS1, kVS17, kVS18, kVS19}));
+ expectVSGlyphs(family, kSupportedChar1, std::set<uint32_t>({kVS1, kVS17, kVS18, kVS19}));
const uint32_t kSupportedChar2 = 0x845B;
EXPECT_TRUE(family->getCoverage().get(kSupportedChar2));
- expectVSGlyphs(family.get(), kSupportedChar2, std::set<uint32_t>({kVS2, kVS18, kVS19, kVS20}));
+ expectVSGlyphs(family, kSupportedChar2, std::set<uint32_t>({kVS2, kVS18, kVS19, kVS20}));
const uint32_t kNoVsSupportedChar = 0x537F;
EXPECT_TRUE(family->getCoverage().get(kNoVsSupportedChar));
- expectVSGlyphs(family.get(), kNoVsSupportedChar, std::set<uint32_t>());
+ expectVSGlyphs(family, kNoVsSupportedChar, std::set<uint32_t>());
const uint32_t kVsOnlySupportedChar = 0x717D;
EXPECT_FALSE(family->getCoverage().get(kVsOnlySupportedChar));
- expectVSGlyphs(family.get(), kVsOnlySupportedChar, std::set<uint32_t>({kVS3, kVS19, kVS20}));
+ expectVSGlyphs(family, kVsOnlySupportedChar, std::set<uint32_t>({kVS3, kVS19, kVS20}));
const uint32_t kNotSupportedChar = 0x845C;
EXPECT_FALSE(family->getCoverage().get(kNotSupportedChar));
- expectVSGlyphs(family.get(), kNotSupportedChar, std::set<uint32_t>());
+ expectVSGlyphs(family, kNotSupportedChar, std::set<uint32_t>());
+}
+
+TEST_F(FontFamilyTest, hasVariationSelectorTest) {
+ std::shared_ptr<FontFamily> family = buildFontFamily(kVsTestFont);
+ expectVSGlyphsForVsTestFont(family.get());
}
TEST_F(FontFamilyTest, hasVSTableTest) {
@@ -728,7 +766,7 @@ TEST_F(FontFamilyTest, closestMatch) {
for (const TestCase& testCase : testCases) {
std::vector<std::shared_ptr<MinikinFont>> dummyFonts;
- std::vector<Font> fonts;
+ std::vector<std::shared_ptr<Font>> fonts;
for (auto familyStyle : testCase.familyStyles) {
std::shared_ptr<MinikinFont> dummyFont(
new FreeTypeMinikinFontForTest(getTestFontPath(kTestFont)));
@@ -756,4 +794,41 @@ TEST_F(FontFamilyTest, closestMatch) {
}
}
+TEST_F(FontFamilyTest, bufferTest) {
+ {
+ // Font with variation selectors
+ std::shared_ptr<FontFamily> original = buildFontFamily(kVsTestFont);
+ std::vector<uint8_t> buffer =
+ writeToBuffer<FontFamily, writeFreeTypeMinikinFontForTest>(*original);
+ BufferReader reader(buffer.data());
+ std::shared_ptr<FontFamily> copied =
+ FontFamily::readFrom<readFreeTypeMinikinFontForTest>(&reader);
+ ASSERT_EQ(original->localeListId(), copied->localeListId());
+ ASSERT_EQ(original->variant(), copied->variant());
+ ASSERT_EQ(original->getNumFonts(), copied->getNumFonts());
+ ASSERT_EQ(original->supportedAxes(), copied->supportedAxes());
+ ASSERT_EQ(original->isColorEmojiFamily(), copied->isColorEmojiFamily());
+ ASSERT_EQ(original->isCustomFallback(), copied->isCustomFallback());
+ ASSERT_EQ(original->hasVSTable(), copied->hasVSTable());
+ expectVSGlyphsForVsTestFont(copied.get());
+ std::vector<uint8_t> newBuffer =
+ writeToBuffer<FontFamily, writeFreeTypeMinikinFontForTest>(*copied);
+ ASSERT_EQ(buffer, newBuffer);
+ }
+ {
+ // Font with axes
+ constexpr char kMultiAxisFont[] = "MultiAxis.ttf";
+ std::shared_ptr<FontFamily> original = buildFontFamily(kMultiAxisFont);
+ std::vector<uint8_t> buffer =
+ writeToBuffer<FontFamily, writeFreeTypeMinikinFontForTest>(*original);
+ BufferReader reader(buffer.data());
+ std::shared_ptr<FontFamily> copied =
+ FontFamily::readFrom<readFreeTypeMinikinFontForTest>(&reader);
+ ASSERT_EQ(original->supportedAxes(), copied->supportedAxes());
+ std::vector<uint8_t> newBuffer =
+ writeToBuffer<FontFamily, writeFreeTypeMinikinFontForTest>(*copied);
+ ASSERT_EQ(buffer, newBuffer);
+ }
+}
+
} // namespace minikin
diff --git a/tests/unittest/FontFileParserTest.cpp b/tests/unittest/FontFileParserTest.cpp
new file mode 100644
index 0000000..d960217
--- /dev/null
+++ b/tests/unittest/FontFileParserTest.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2021 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 "minikin/FontFileParser.h"
+
+#include <gtest/gtest.h>
+
+#include "FontTestUtils.h"
+#include "FreeTypeMinikinFontForTest.h"
+#include "PathUtils.h"
+
+namespace minikin {
+namespace {
+
+static size_t writeU16(uint16_t x, uint8_t* out, size_t offset) {
+ out[offset] = x >> 8;
+ out[offset + 1] = x;
+ return offset + 2;
+}
+
+static size_t writeU32(uint32_t x, uint8_t* out, size_t offset) {
+ out[offset] = x >> 24;
+ out[offset + 1] = x >> 16;
+ out[offset + 2] = x >> 8;
+ out[offset + 3] = x;
+ return offset + 4;
+}
+
+class TestableFontFileParser : public FontFileParser {
+public:
+ using FontFileParser::analyzeFontRevision;
+ using FontFileParser::checkPSName;
+};
+
+// Returns valid head table contents.
+static std::vector<uint8_t> buildHeadTable(uint32_t fontRevision) {
+ std::vector<uint8_t> out(46);
+ size_t head = writeU16(1, out.data(), 0); // major version
+ head = writeU16(0, out.data(), head); // minor version
+ head = writeU32(fontRevision, out.data(), head); // fontRevision
+ head = writeU32(0xB1B0AFBA, out.data(), head); // checksum. (random value)
+ head = writeU32(0x5F0F3CF5, out.data(), head); // magicNumber
+ head = writeU16(0, out.data(), head); // flasgs
+ head = writeU16(1024, out.data(), head); // unitsPerEm
+ head = writeU32(123457890, out.data(), head); // created (random value)
+ head = writeU32(123457890, out.data(), head); // modified (random value)
+ head = writeU16(0, out.data(), head); // xMin
+ head = writeU16(100, out.data(), head); // yMin
+ head = writeU16(1024, out.data(), head); // xMax
+ head = writeU16(2048, out.data(), head); // yMax
+ head = writeU16(0, out.data(), head); // macStyle
+ head = writeU16(10, out.data(), head); // lowestRecPPEM
+ head = writeU16(1, out.data(), head); // fontDirectionHint
+ head = writeU16(1, out.data(), head); // indexToLocFormat
+ head = writeU16(0, out.data(), head); // glyphDataFormat;
+
+ return out;
+}
+
+TEST(FontFileParserTest, analyzeFontRevision) {
+ uint32_t rev = 0x12345678;
+ std::vector<uint8_t> head = buildHeadTable(rev);
+
+ uint32_t out = 0;
+ EXPECT_TRUE(TestableFontFileParser::analyzeFontRevision(head.data(), head.size(), &out));
+ EXPECT_EQ(rev, out);
+}
+
+TEST(FontFileParserTest, headInvalidLength) {
+ uint32_t rev = 0x12345678;
+ std::vector<uint8_t> head = buildHeadTable(rev);
+
+ uint32_t out = 0;
+ EXPECT_FALSE(TestableFontFileParser::analyzeFontRevision(head.data(), 6, &out));
+}
+
+TEST(FontFileParserTest, parseFontForRev) {
+ auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath("Ascii.ttf"));
+ auto parser = FontFileParser(minikinFont->GetFontData(), minikinFont->GetFontSize(), 0);
+
+ auto revision = parser.getFontRevision();
+ EXPECT_TRUE(revision.has_value());
+ EXPECT_EQ(0x00010000u, revision.value());
+}
+
+TEST(FontFileParser, checkPSName) {
+ EXPECT_TRUE(TestableFontFileParser::checkPSName("Roboto-Regular"));
+ EXPECT_TRUE(TestableFontFileParser::checkPSName("NotoColorEmoji"));
+
+ // Space character is not allowed.
+ EXPECT_FALSE(TestableFontFileParser::checkPSName("Roboto Regular"));
+ EXPECT_FALSE(TestableFontFileParser::checkPSName("Noto Color Emoji"));
+
+ // parens are not not allowed.
+ EXPECT_FALSE(TestableFontFileParser::checkPSName("Roboto (Regular)"));
+ EXPECT_FALSE(TestableFontFileParser::checkPSName("Noto <Color> {Emoji}"));
+
+ // control characters are not allowed
+ EXPECT_FALSE(TestableFontFileParser::checkPSName("Roboto-Regular\b"));
+ EXPECT_FALSE(TestableFontFileParser::checkPSName("NotoColorEmoji\t"));
+
+ // Up to 63 character is allowed.
+ EXPECT_FALSE(TestableFontFileParser::checkPSName(std::string(64, 'a')));
+
+ // Only printable ASCII is allowed.
+ EXPECT_FALSE(TestableFontFileParser::checkPSName("ろぼとふぉんと"));
+}
+
+TEST(FontFileParserTest, parseFontForPSName) {
+ auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath("Ascii.ttf"));
+ auto parser = FontFileParser(minikinFont->GetFontData(), minikinFont->GetFontSize(), 0);
+
+ auto psName = parser.getPostScriptName();
+ EXPECT_TRUE(psName.has_value());
+ EXPECT_EQ("SampleFont-Regular", psName.value());
+}
+
+} // namespace
+} // namespace minikin
diff --git a/tests/unittest/FontLanguageListCacheTest.cpp b/tests/unittest/FontLanguageListCacheTest.cpp
index e957cfc..e68922d 100644
--- a/tests/unittest/FontLanguageListCacheTest.cpp
+++ b/tests/unittest/FontLanguageListCacheTest.cpp
@@ -61,4 +61,25 @@ TEST(LocaleListCacheTest, getById) {
EXPECT_EQ(japanese, locales2[1]);
}
+TEST(LocaleListCacheTest, buffer) {
+ std::string locales[] = {"en", "jp", "en,zh-Hans"};
+ // Measure
+ BufferWriter fakeWriter(nullptr);
+ for (const std::string& locale : locales) {
+ LocaleListCache::writeTo(&fakeWriter, LocaleListCache::getId(locale));
+ }
+ // Write
+ std::vector<uint8_t> buffer(fakeWriter.size());
+ BufferWriter writer(buffer.data());
+ for (const std::string& locale : locales) {
+ LocaleListCache::writeTo(&writer, LocaleListCache::getId(locale));
+ }
+ // Read
+ BufferReader reader(buffer.data());
+ for (const std::string& locale : locales) {
+ EXPECT_EQ(LocaleListCache::getId(locale), LocaleListCache::readFrom(&reader))
+ << "locale = " << locale;
+ }
+}
+
} // namespace minikin
diff --git a/tests/unittest/FontTest.cpp b/tests/unittest/FontTest.cpp
index ff2f9bc..68f5b51 100644
--- a/tests/unittest/FontTest.cpp
+++ b/tests/unittest/FontTest.cpp
@@ -18,28 +18,25 @@
#include <gtest/gtest.h>
+#include "BufferUtils.h"
#include "FontTestUtils.h"
#include "FreeTypeMinikinFontForTest.h"
namespace minikin {
-TEST(FontTest, CopyTest) {
+TEST(FontTest, BufferTest) {
auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath("Ascii.ttf"));
- {
- Font font = Font::Builder(minikinFont).build();
- {
- Font copied(font);
- EXPECT_EQ(font.typeface(), copied.typeface());
- EXPECT_EQ(font.style(), copied.style());
- EXPECT_EQ(font.baseFont(), copied.baseFont());
- }
- {
- Font copied = font;
- EXPECT_EQ(font.typeface(), copied.typeface());
- EXPECT_EQ(font.style(), copied.style());
- EXPECT_EQ(font.baseFont(), copied.baseFont());
- }
- }
+ std::shared_ptr<Font> original = Font::Builder(minikinFont).build();
+ std::vector<uint8_t> buffer = writeToBuffer<Font, writeFreeTypeMinikinFontForTest>(*original);
+
+ BufferReader reader(buffer.data());
+ std::shared_ptr<Font> font =
+ Font::readFrom<readFreeTypeMinikinFontForTest>(&reader, kEmptyLocaleListId);
+ EXPECT_EQ(minikinFont->GetFontPath(), font->typeface()->GetFontPath());
+ EXPECT_EQ(original->style(), font->style());
+ EXPECT_NE(nullptr, font->baseFont());
+ std::vector<uint8_t> newBuffer = writeToBuffer<Font, writeFreeTypeMinikinFontForTest>(*font);
+ EXPECT_EQ(buffer, newBuffer);
}
} // namespace minikin
diff --git a/tests/unittest/GreedyLineBreakerTest.cpp b/tests/unittest/GreedyLineBreakerTest.cpp
index 13cc03c..e9da1a1 100644
--- a/tests/unittest/GreedyLineBreakerTest.cpp
+++ b/tests/unittest/GreedyLineBreakerTest.cpp
@@ -93,6 +93,33 @@ private:
std::vector<uint8_t> mHyphenationPattern;
};
+TEST_F(GreedyLineBreakerTest, roundingError) {
+ MeasuredTextBuilder builder;
+ auto family1 = buildFontFamily("Ascii.ttf");
+ std::vector<std::shared_ptr<FontFamily>> families = {family1};
+ auto fc = std::make_shared<FontCollection>(families);
+ MinikinPaint paint(fc);
+ paint.size = 56.0f; // Make 1em=56px
+ paint.scaleX = 1;
+ paint.letterSpacing = -0.093f;
+ paint.localeListId = LocaleListCache::getId("en-US");
+ const std::vector<uint16_t> textBuffer = utf8ToUtf16("8888888888888888888");
+
+ float measured = Layout::measureText(textBuffer, Range(0, textBuffer.size()), Bidi::LTR, paint,
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, nullptr);
+
+ builder.addStyleRun(0, textBuffer.size(), std::move(paint), false);
+ std::unique_ptr<MeasuredText> measuredText =
+ builder.build(textBuffer, false /* compute hyphenation */,
+ false /* compute full layout */, nullptr /* no hint */);
+ RectangleLineWidth rectangleLineWidth(measured);
+ TabStops tabStops(nullptr, 0, 10);
+ LineBreakResult r = breakLineGreedy(textBuffer, *measuredText, rectangleLineWidth, tabStops,
+ false /* do hyphenation */);
+
+ EXPECT_EQ(1u, r.breakPoints.size());
+}
+
TEST_F(GreedyLineBreakerTest, testBreakWithoutHyphenation) {
constexpr bool NO_HYPHEN = false; // No hyphenation in this test case.
const std::vector<uint16_t> textBuf = utf8ToUtf16("This is an example text.");
diff --git a/tests/unittest/HasherTest.cpp b/tests/unittest/HasherTest.cpp
index 8e11cc6..02cbda8 100644
--- a/tests/unittest/HasherTest.cpp
+++ b/tests/unittest/HasherTest.cpp
@@ -35,4 +35,9 @@ TEST(HasherTest, hasherTest) {
EXPECT_EQ(hasher.hash(), hasher.hash());
}
+TEST(HasherTest, hasherTestFloat) {
+ float x = 1.1f;
+ EXPECT_NE(Hasher().update(x).hash(), Hasher().update(1).hash());
+}
+
} // namespace minikin
diff --git a/tests/unittest/ICUEnvironment.h b/tests/unittest/ICUEnvironment.h
deleted file mode 100644
index 8fd285f..0000000
--- a/tests/unittest/ICUEnvironment.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef MINIKIN_TEST_ICU_ENVIRONMENT_H
-#define MINIKIN_TEST_ICU_ENVIRONMENT_H
-
-// low level file access for mapping ICU data
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-#include <cutils/log.h>
-#include <gtest/gtest.h>
-#include <unicode/uclean.h>
-#include <unicode/udata.h>
-
-namespace minikin {
-
-class ICUEnvironment : public testing::Environment {
-public:
- ICUEnvironment() : testing::Environment(), mData(nullptr), mSize(0) {}
-
- void* mData;
- size_t mSize;
-
- virtual void SetUp() override {
- const char* fn = "/apex/com.android.i18n/etc/icu/" U_ICUDATA_NAME ".dat";
- int fd = open(fn, O_RDONLY);
- LOG_ALWAYS_FATAL_IF(fd == -1);
- struct stat sb;
- LOG_ALWAYS_FATAL_IF(fstat(fd, &sb) != 0);
-
- mSize = sb.st_size;
- void* mData = mmap(nullptr, mSize, PROT_READ, MAP_SHARED, fd, 0);
- close(fd);
-
- UErrorCode errorCode = U_ZERO_ERROR;
- udata_setCommonData(mData, &errorCode);
- LOG_ALWAYS_FATAL_IF(U_FAILURE(errorCode));
-
- errorCode = U_ZERO_ERROR;
- u_init(&errorCode);
- LOG_ALWAYS_FATAL_IF(U_FAILURE(errorCode));
- }
-
- virtual void TearDown() override {
- u_cleanup();
- munmap(mData, mSize);
- }
-};
-
-} // namespace minikin
-#endif // MINIKIN_TEST_ICU_ENVIRONMENT_H
diff --git a/tests/unittest/LayoutCoreTest.cpp b/tests/unittest/LayoutCoreTest.cpp
index ef972a0..2ab7543 100644
--- a/tests/unittest/LayoutCoreTest.cpp
+++ b/tests/unittest/LayoutCoreTest.cpp
@@ -74,7 +74,6 @@ TEST(LayoutPieceTest, doLayoutTest) {
auto layout = buildLayout("I", {"LayoutTestFont.ttf"});
EXPECT_EQ(1u, layout.glyphCount());
EXPECT_EQ(Point(0, 0), layout.pointAt(0));
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.bounds());
EXPECT_EQ(MinikinExtent(-100.0f, 20.0f), layout.extent());
EXPECT_EQ(1u, layout.fonts().size());
EXPECT_TRUE(layout.fontAt(0).font);
@@ -87,7 +86,6 @@ TEST(LayoutPieceTest, doLayoutTest) {
EXPECT_EQ(2u, layout.glyphCount());
EXPECT_EQ(Point(0, 0), layout.pointAt(0));
EXPECT_EQ(Point(10.0f, 0), layout.pointAt(1));
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.bounds());
EXPECT_EQ(MinikinExtent(-100.0f, 20.0f), layout.extent());
EXPECT_EQ(1u, layout.fonts().size());
EXPECT_TRUE(layout.fontAt(0).font);
@@ -103,7 +101,6 @@ TEST(LayoutPieceTest, doLayoutTest) {
EXPECT_EQ(2u, layout.glyphCount());
EXPECT_EQ(Point(0, 0), layout.pointAt(0));
EXPECT_EQ(Point(10.0f, 0), layout.pointAt(1));
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 60.0f, 0.0f), layout.bounds());
EXPECT_EQ(MinikinExtent(-100.0f, 20.0f), layout.extent());
EXPECT_EQ(1u, layout.fonts().size());
EXPECT_TRUE(layout.fontAt(0).font);
@@ -130,7 +127,6 @@ TEST(LayoutPieceTest, doLayoutTest_MultiFont) {
EXPECT_EQ(2u, layout.glyphCount());
EXPECT_EQ(Point(0, 0), layout.pointAt(0));
EXPECT_EQ(Point(10.0f, 0), layout.pointAt(1));
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 30.0f, 0.0f), layout.bounds());
EXPECT_EQ(MinikinExtent(-160.0f, 40.0f), layout.extent());
EXPECT_EQ(2u, layout.fonts().size());
EXPECT_TRUE(layout.fontAt(0).font);
@@ -146,7 +142,6 @@ TEST(LayoutPieceTest, doLayoutTest_MultiFont) {
EXPECT_EQ(2u, layout.glyphCount());
EXPECT_EQ(Point(0, 0), layout.pointAt(0));
EXPECT_EQ(Point(20.0f, 0), layout.pointAt(1));
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 30.0f, 0.0f), layout.bounds());
EXPECT_EQ(MinikinExtent(-160.0f, 40.0f), layout.extent());
EXPECT_EQ(2u, layout.fonts().size());
EXPECT_TRUE(layout.fontAt(0).font);
@@ -168,7 +163,6 @@ TEST(LayoutPieceTest, doLayoutTest_Ligature) {
auto layout = buildLayout("fi", {"Ligature.ttf"});
EXPECT_EQ(1u, layout.glyphCount());
EXPECT_EQ(Point(0, 0), layout.pointAt(0));
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.bounds());
EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
EXPECT_EQ(1u, layout.fonts().size());
EXPECT_TRUE(layout.fontAt(0).font);
@@ -181,7 +175,6 @@ TEST(LayoutPieceTest, doLayoutTest_Ligature) {
auto layout = buildLayout("ff", {"Ligature.ttf"});
EXPECT_EQ(1u, layout.glyphCount());
EXPECT_EQ(Point(0, 0), layout.pointAt(0));
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.bounds());
EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
EXPECT_EQ(1u, layout.fonts().size());
EXPECT_TRUE(layout.fontAt(0).font);
@@ -194,7 +187,6 @@ TEST(LayoutPieceTest, doLayoutTest_Ligature) {
auto layout = buildLayout("fi", {"Ligature.ttf"}, "'liga' off");
EXPECT_EQ(1u, layout.glyphCount());
EXPECT_EQ(Point(0, 0), layout.pointAt(0));
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.bounds());
EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
EXPECT_EQ(1u, layout.fonts().size());
EXPECT_TRUE(layout.fontAt(0).font);
@@ -207,7 +199,6 @@ TEST(LayoutPieceTest, doLayoutTest_Ligature) {
auto layout = buildLayout("ff", {"Ligature.ttf"}, "'liga' off");
EXPECT_EQ(2u, layout.glyphCount());
EXPECT_EQ(Point(0, 0), layout.pointAt(0));
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.bounds());
EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
EXPECT_EQ(1u, layout.fonts().size());
EXPECT_TRUE(layout.fontAt(0).font);
@@ -222,7 +213,6 @@ TEST(LayoutPieceTest, doLayoutTest_Ligature) {
auto layout = buildLayout("fii", {"Ligature.ttf"});
EXPECT_EQ(2u, layout.glyphCount());
EXPECT_EQ(Point(0, 0), layout.pointAt(0));
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.bounds());
EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
EXPECT_EQ(1u, layout.fonts().size());
EXPECT_TRUE(layout.fontAt(0).font);
@@ -238,7 +228,6 @@ TEST(LayoutPieceTest, doLayoutTest_Ligature) {
auto layout = buildLayout("if", {"Ligature.ttf"});
EXPECT_EQ(2u, layout.glyphCount());
EXPECT_EQ(Point(0, 0), layout.pointAt(0));
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.bounds());
EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent());
EXPECT_EQ(1u, layout.fonts().size());
EXPECT_TRUE(layout.fontAt(0).font);
diff --git a/tests/unittest/LayoutTest.cpp b/tests/unittest/LayoutTest.cpp
index 4b97cee..7771051 100644
--- a/tests/unittest/LayoutTest.cpp
+++ b/tests/unittest/LayoutTest.cpp
@@ -20,6 +20,7 @@
#include "minikin/FontCollection.h"
#include "minikin/LayoutPieces.h"
+#include "minikin/Measurement.h"
#include "FontTestUtils.h"
#include "UnicodeUtils.h"
@@ -35,6 +36,12 @@ static void expectAdvances(const std::vector<float>& expected, const std::vector
}
}
+static void getBounds(const U16StringPiece& text, Bidi bidiFlags, const MinikinPaint& paint,
+ MinikinRect* out) {
+ getBounds(text, Range(0, text.size()), bidiFlags, paint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, out);
+}
+
class LayoutTest : public testing::Test {
protected:
LayoutTest() : mCollection(nullptr) {}
@@ -64,7 +71,8 @@ TEST_F(LayoutTest, doLayoutTest) {
Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
EXPECT_EQ(70.0f, layout.getAdvance());
- layout.getBounds(&rect);
+
+ getBounds(text, Bidi::LTR, paint, &rect);
EXPECT_EQ(0.0f, rect.mLeft);
EXPECT_EQ(10.0f, rect.mTop);
EXPECT_EQ(70.0f, rect.mRight);
@@ -82,7 +90,8 @@ TEST_F(LayoutTest, doLayoutTest) {
Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
EXPECT_EQ(90.0f, layout.getAdvance());
- layout.getBounds(&rect);
+
+ getBounds(text, Bidi::LTR, paint, &rect);
EXPECT_EQ(0.0f, rect.mLeft);
EXPECT_EQ(10.0f, rect.mTop);
EXPECT_EQ(90.0f, rect.mRight);
@@ -100,7 +109,8 @@ TEST_F(LayoutTest, doLayoutTest) {
Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
EXPECT_EQ(160.0f, layout.getAdvance());
- layout.getBounds(&rect);
+
+ getBounds(text, Bidi::LTR, paint, &rect);
EXPECT_EQ(0.0f, rect.mLeft);
EXPECT_EQ(10.0f, rect.mTop);
EXPECT_EQ(160.0f, rect.mRight);
@@ -118,7 +128,8 @@ TEST_F(LayoutTest, doLayoutTest) {
Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
EXPECT_EQ(110.0f, layout.getAdvance());
- layout.getBounds(&rect);
+
+ getBounds(text, Bidi::LTR, paint, &rect);
EXPECT_EQ(0.0f, rect.mLeft);
EXPECT_EQ(10.0f, rect.mTop);
EXPECT_EQ(110.0f, rect.mRight);
@@ -148,7 +159,8 @@ TEST_F(LayoutTest, doLayoutTest_wordSpacing) {
Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
EXPECT_EQ(70.0f, layout.getAdvance());
- layout.getBounds(&rect);
+
+ getBounds(text, Bidi::LTR, paint, &rect);
EXPECT_EQ(0.0f, rect.mLeft);
EXPECT_EQ(10.0f, rect.mTop);
EXPECT_EQ(70.0f, rect.mRight);
@@ -166,7 +178,8 @@ TEST_F(LayoutTest, doLayoutTest_wordSpacing) {
Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
EXPECT_EQ(95.0f, layout.getAdvance());
- layout.getBounds(&rect);
+
+ getBounds(text, Bidi::LTR, paint, &rect);
EXPECT_EQ(0.0f, rect.mLeft);
EXPECT_EQ(10.0f, rect.mTop);
EXPECT_EQ(95.0f, rect.mRight);
@@ -185,7 +198,8 @@ TEST_F(LayoutTest, doLayoutTest_wordSpacing) {
Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
EXPECT_EQ(170.0f, layout.getAdvance());
- layout.getBounds(&rect);
+
+ getBounds(text, Bidi::LTR, paint, &rect);
EXPECT_EQ(0.0f, rect.mLeft);
EXPECT_EQ(10.0f, rect.mTop);
EXPECT_EQ(170.0f, rect.mRight);
@@ -205,7 +219,8 @@ TEST_F(LayoutTest, doLayoutTest_wordSpacing) {
Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
EXPECT_EQ(120.0f, layout.getAdvance());
- layout.getBounds(&rect);
+
+ getBounds(text, Bidi::LTR, paint, &rect);
EXPECT_EQ(0.0f, rect.mLeft);
EXPECT_EQ(10.0f, rect.mTop);
EXPECT_EQ(120.0f, rect.mRight);
@@ -238,7 +253,8 @@ TEST_F(LayoutTest, doLayoutTest_negativeWordSpacing) {
Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
EXPECT_EQ(70.0f, layout.getAdvance());
- layout.getBounds(&rect);
+
+ getBounds(text, Bidi::LTR, paint, &rect);
EXPECT_EQ(0.0f, rect.mLeft);
EXPECT_EQ(10.0f, rect.mTop);
EXPECT_EQ(70.0f, rect.mRight);
@@ -256,7 +272,8 @@ TEST_F(LayoutTest, doLayoutTest_negativeWordSpacing) {
Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
EXPECT_EQ(85.0f, layout.getAdvance());
- layout.getBounds(&rect);
+
+ getBounds(text, Bidi::LTR, paint, &rect);
EXPECT_EQ(0.0f, rect.mLeft);
EXPECT_EQ(10.0f, rect.mTop);
EXPECT_EQ(85.0f, rect.mRight);
@@ -275,7 +292,8 @@ TEST_F(LayoutTest, doLayoutTest_negativeWordSpacing) {
Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
EXPECT_EQ(140.0f, layout.getAdvance());
- layout.getBounds(&rect);
+
+ getBounds(text, Bidi::LTR, paint, &rect);
EXPECT_EQ(0.0f, rect.mLeft);
EXPECT_EQ(10.0f, rect.mTop);
EXPECT_EQ(140.0f, rect.mRight);
@@ -295,7 +313,8 @@ TEST_F(LayoutTest, doLayoutTest_negativeWordSpacing) {
Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
EXPECT_EQ(100.0f, layout.getAdvance());
- layout.getBounds(&rect);
+
+ getBounds(text, Bidi::LTR, paint, &rect);
EXPECT_EQ(0.0f, rect.mLeft);
EXPECT_EQ(10.0f, rect.mTop);
EXPECT_EQ(100.0f, rect.mRight);
diff --git a/tests/unittest/MeasuredTextTest.cpp b/tests/unittest/MeasuredTextTest.cpp
index 1934ed8..e5766a1 100644
--- a/tests/unittest/MeasuredTextTest.cpp
+++ b/tests/unittest/MeasuredTextTest.cpp
@@ -19,6 +19,7 @@
#include <gtest/gtest.h>
#include "minikin/LineBreaker.h"
+#include "minikin/Measurement.h"
#include "FontTestUtils.h"
#include "UnicodeUtils.h"
@@ -75,6 +76,34 @@ TEST(MeasuredTextTest, getBoundsTest) {
EXPECT_EQ(MinikinRect(0.0f, 10.0f, 130.0f, 0.0f), mt->getBounds(text, Range(0, text.size())));
}
+TEST(MeasuredTextTest, getBoundsTest_LTR) {
+ auto text = utf8ToUtf16("\u0028"); // U+0028 has 1em in LTR, 3em in RTL.
+ auto font = buildFontCollection("Bbox.ttf");
+
+ MeasuredTextBuilder builder;
+ MinikinPaint paint(font);
+ paint.size = 10.0f;
+ builder.addStyleRun(0, text.size(), std::move(paint), false /* is RTL */);
+ auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
+ nullptr /* no hint */);
+
+ EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), mt->getBounds(text, Range(0, 1)));
+}
+
+TEST(MeasuredTextTest, getBoundsTest_RTL) {
+ auto text = utf8ToUtf16("\u0028"); // U+0028 has 1em in LTR, 3em in RTL.
+ auto font = buildFontCollection("Bbox.ttf");
+
+ MeasuredTextBuilder builder;
+ MinikinPaint paint(font);
+ paint.size = 10.0f;
+ builder.addStyleRun(0, text.size(), std::move(paint), true /* is RTL */);
+ auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
+ nullptr /* no hint */);
+
+ EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), mt->getBounds(text, Range(0, 2)));
+}
+
TEST(MeasuredTextTest, getBoundsTest_multiStyle) {
auto text = utf8ToUtf16("Hello, World!");
auto font = buildFontCollection("Ascii.ttf");
@@ -155,6 +184,7 @@ TEST(MeasuredTextTest, buildLayoutTest) {
auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
nullptr /* no hint */);
+ MinikinRect rect;
MinikinPaint samePaint(font);
samePaint.size = 10.0f;
@@ -171,7 +201,9 @@ TEST(MeasuredTextTest, buildLayoutTest) {
EXPECT_EQ(10.0f, layout.getAdvance());
EXPECT_EQ(10.0f, layout.getCharAdvance(0));
EXPECT_EQ(1u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(0, 1), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect);
layout = mt->buildLayout(text, Range(0, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
@@ -185,7 +217,9 @@ TEST(MeasuredTextTest, buildLayoutTest) {
EXPECT_EQ(10.0f, layout.getCharAdvance(0));
EXPECT_EQ(10.0f, layout.getCharAdvance(1));
EXPECT_EQ(2u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(0, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), rect);
layout = mt->buildLayout(text, Range(1, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
@@ -196,7 +230,9 @@ TEST(MeasuredTextTest, buildLayoutTest) {
EXPECT_EQ(10.0f, layout.getAdvance());
EXPECT_EQ(10.0f, layout.getCharAdvance(0));
EXPECT_EQ(1u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(1, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect);
layout = mt->buildLayout(text, Range(0, text.size()), fullContext, samePaint,
StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
@@ -210,7 +246,9 @@ TEST(MeasuredTextTest, buildLayoutTest) {
}
EXPECT_EQ(130.0f, layout.getAdvance());
EXPECT_EQ(text.size(), layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 130.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(0, text.size()), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 10.0f, 130.0f, 0.0f), rect);
}
TEST(MeasuredTextTest, buildLayoutTest_multiStyle) {
@@ -229,6 +267,7 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle) {
auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
nullptr /* no hint */);
+ MinikinRect rect;
MinikinPaint samePaint(font);
samePaint.size = 10.0f;
@@ -245,7 +284,9 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle) {
EXPECT_EQ(10.0f, layout.getAdvance());
EXPECT_EQ(10.0f, layout.getCharAdvance(0));
EXPECT_EQ(1u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(0, 1), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect);
layout = mt->buildLayout(text, Range(0, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
@@ -259,7 +300,9 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle) {
EXPECT_EQ(10.0f, layout.getCharAdvance(0));
EXPECT_EQ(10.0f, layout.getCharAdvance(1));
EXPECT_EQ(2u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(0, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), rect);
layout = mt->buildLayout(text, Range(1, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
@@ -270,7 +313,9 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle) {
EXPECT_EQ(10.0f, layout.getAdvance());
EXPECT_EQ(10.0f, layout.getCharAdvance(0));
EXPECT_EQ(1u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(1, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect);
layout = mt->buildLayout(text, Range(7, 7), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
EndHyphenEdit::NO_EDIT);
@@ -287,7 +332,9 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle) {
EXPECT_EQ(20.0f, layout.getAdvance());
EXPECT_EQ(20.0f, layout.getCharAdvance(0));
EXPECT_EQ(1u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(7, 8), Bidi::LTR, samePaint2, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), rect);
}
TEST(MeasuredTextTest, buildLayoutTest_differentPaint) {
@@ -302,6 +349,7 @@ TEST(MeasuredTextTest, buildLayoutTest_differentPaint) {
auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
nullptr /* no hint */);
+ MinikinRect rect;
MinikinPaint differentPaint(font);
differentPaint.size = 20.0f;
@@ -318,7 +366,9 @@ TEST(MeasuredTextTest, buildLayoutTest_differentPaint) {
EXPECT_EQ(20.0f, layout.getAdvance());
EXPECT_EQ(20.0f, layout.getCharAdvance(0));
EXPECT_EQ(1u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(0, 1), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), rect);
layout = mt->buildLayout(text, Range(0, 2), fullContext, differentPaint,
StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
@@ -332,7 +382,9 @@ TEST(MeasuredTextTest, buildLayoutTest_differentPaint) {
EXPECT_EQ(20.0f, layout.getCharAdvance(0));
EXPECT_EQ(20.0f, layout.getCharAdvance(1));
EXPECT_EQ(2u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 20.0f, 40.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(0, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 20.0f, 40.0f, 0.0f), rect);
layout = mt->buildLayout(text, Range(1, 2), fullContext, differentPaint,
StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
@@ -343,7 +395,9 @@ TEST(MeasuredTextTest, buildLayoutTest_differentPaint) {
EXPECT_EQ(20.0f, layout.getAdvance());
EXPECT_EQ(20.0f, layout.getCharAdvance(0));
EXPECT_EQ(1u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(1, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), rect);
layout = mt->buildLayout(text, Range(0, text.size()), fullContext, differentPaint,
StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
@@ -357,7 +411,9 @@ TEST(MeasuredTextTest, buildLayoutTest_differentPaint) {
}
EXPECT_EQ(260.0f, layout.getAdvance());
EXPECT_EQ(text.size(), layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 20.0f, 260.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(0, text.size()), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 20.0f, 260.0f, 0.0f), rect);
}
TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) {
@@ -376,6 +432,7 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) {
auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
nullptr /* no hint */);
+ MinikinRect rect;
MinikinPaint differentPaint(font);
differentPaint.size = 30.0f;
@@ -392,7 +449,9 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) {
EXPECT_EQ(30.0f, layout.getAdvance());
EXPECT_EQ(30.0f, layout.getCharAdvance(0));
EXPECT_EQ(1u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(0, 1), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), rect);
layout = mt->buildLayout(text, Range(0, 2), fullContext, differentPaint,
StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
@@ -406,7 +465,9 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) {
EXPECT_EQ(30.0f, layout.getCharAdvance(0));
EXPECT_EQ(30.0f, layout.getCharAdvance(1));
EXPECT_EQ(2u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 30.0f, 60.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(0, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 30.0f, 60.0f, 0.0f), rect);
layout = mt->buildLayout(text, Range(1, 2), fullContext, differentPaint,
StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
@@ -417,7 +478,9 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) {
EXPECT_EQ(30.0f, layout.getAdvance());
EXPECT_EQ(30.0f, layout.getCharAdvance(0));
EXPECT_EQ(1u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(1, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), rect);
layout = mt->buildLayout(text, Range(7, 7), fullContext, differentPaint,
StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
@@ -432,7 +495,9 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) {
EXPECT_EQ(30.0f, layout.getAdvance());
EXPECT_EQ(30.0f, layout.getCharAdvance(0));
EXPECT_EQ(1u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(7, 8), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), rect);
layout = mt->buildLayout(text, Range(6, 8), fullContext, differentPaint,
StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
@@ -446,7 +511,9 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) {
EXPECT_EQ(30.0f, layout.getCharAdvance(0));
EXPECT_EQ(30.0f, layout.getCharAdvance(1));
EXPECT_EQ(2u, layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 30.0f, 60.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(6, 8), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 30.0f, 60.0f, 0.0f), rect);
layout = mt->buildLayout(text, Range(0, text.size()), fullContext, differentPaint,
StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
@@ -460,7 +527,9 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) {
}
EXPECT_EQ(390.0f, layout.getAdvance());
EXPECT_EQ(text.size(), layout.getAdvances().size());
- EXPECT_EQ(MinikinRect(0.0f, 30.0f, 390.0f, 0.0f), layout.getBounds());
+ getBounds(text, Range(0, text.size()), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
+ EndHyphenEdit::NO_EDIT, &rect);
+ EXPECT_EQ(MinikinRect(0.0f, 30.0f, 390.0f, 0.0f), rect);
}
} // namespace minikin
diff --git a/tests/unittest/OptimalLineBreakerTest.cpp b/tests/unittest/OptimalLineBreakerTest.cpp
index 51aab60..d6801cc 100644
--- a/tests/unittest/OptimalLineBreakerTest.cpp
+++ b/tests/unittest/OptimalLineBreakerTest.cpp
@@ -2080,5 +2080,33 @@ TEST_F(OptimalLineBreakerTest, testControllCharAfterSpace) {
<< toString(textBuf, actual);
}
}
+
+TEST_F(OptimalLineBreakerTest, roundingError) {
+ MeasuredTextBuilder builder;
+ auto family1 = buildFontFamily("Ascii.ttf");
+ std::vector<std::shared_ptr<FontFamily>> families = {family1};
+ auto fc = std::make_shared<FontCollection>(families);
+ MinikinPaint paint(fc);
+ paint.size = 56.0f; // Make 1em=56px
+ paint.scaleX = 1;
+ paint.letterSpacing = -0.093f;
+ paint.localeListId = LocaleListCache::getId("en-US");
+ const std::vector<uint16_t> textBuffer = utf8ToUtf16("8888888888888888888");
+
+ float measured = Layout::measureText(textBuffer, Range(0, textBuffer.size()), Bidi::LTR, paint,
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, nullptr);
+
+ builder.addStyleRun(0, textBuffer.size(), std::move(paint), false);
+ std::unique_ptr<MeasuredText> measuredText =
+ builder.build(textBuffer, false /* compute hyphenation */,
+ false /* compute full layout */, nullptr /* no hint */);
+ RectangleLineWidth rectangleLineWidth(measured);
+ TabStops tabStops(nullptr, 0, 10);
+ LineBreakResult r = doLineBreak(textBuffer, *measuredText, BreakStrategy::Balanced,
+ HyphenationFrequency::None, measured);
+
+ EXPECT_EQ(1u, r.breakPoints.size());
+}
+
} // namespace
} // namespace minikin
diff --git a/tests/unittest/SparseBitSetTest.cpp b/tests/unittest/SparseBitSetTest.cpp
index 03a14d9..8c67964 100644
--- a/tests/unittest/SparseBitSetTest.cpp
+++ b/tests/unittest/SparseBitSetTest.cpp
@@ -20,6 +20,8 @@
#include <gtest/gtest.h>
+#include "BufferUtils.h"
+
namespace minikin {
TEST(SparseBitSetTest, randomTest) {
@@ -52,4 +54,29 @@ TEST(SparseBitSetTest, randomTest) {
}
}
+TEST(SparseBitSetTest, bufferTest) {
+ std::vector<uint32_t> range({10, 20});
+ SparseBitSet originalBitset(range.data(), range.size() / 2);
+ std::vector<uint8_t> buffer = writeToBuffer(originalBitset);
+ BufferReader reader(buffer.data());
+ SparseBitSet bitset(&reader);
+
+ for (size_t i = 0; i < 10; ++i) ASSERT_FALSE(bitset.get(i)) << i;
+ for (size_t i = 10; i < 20; ++i) ASSERT_TRUE(bitset.get(i)) << i;
+ for (size_t i = 20; i < 30; ++i) ASSERT_FALSE(bitset.get(i)) << i;
+ std::vector<uint8_t> newBuffer = writeToBuffer(bitset);
+ ASSERT_EQ(buffer, newBuffer);
+}
+
+TEST(SparseBitSetTest, emptyBitSetBufferTest) {
+ SparseBitSet empty;
+ std::vector<uint8_t> buffer = writeToBuffer(empty);
+ BufferReader reader(buffer.data());
+ SparseBitSet bitset(&reader);
+
+ ASSERT_FALSE(bitset.get(0));
+ std::vector<uint8_t> newBuffer = writeToBuffer(bitset);
+ ASSERT_EQ(buffer, newBuffer);
+}
+
} // namespace minikin
diff --git a/tests/unittest/SystemFontsTest.cpp b/tests/unittest/SystemFontsTest.cpp
index fe603a9..f1b0109 100644
--- a/tests/unittest/SystemFontsTest.cpp
+++ b/tests/unittest/SystemFontsTest.cpp
@@ -21,6 +21,7 @@
#include "minikin/FontCollection.h"
#include "FontTestUtils.h"
+#include "PathUtils.h"
namespace minikin {
namespace {
@@ -30,10 +31,18 @@ public:
TestableSystemFonts() : SystemFonts() {}
virtual ~TestableSystemFonts() {}
- std::shared_ptr<FontCollection> findFontCollection(const std::string& familyName) const {
+ std::shared_ptr<FontCollection> findFontCollection(const std::string& familyName) {
return findFontCollectionInternal(familyName);
}
+ void addFontMap(std::shared_ptr<FontCollection>&& collections) {
+ addFontMapInternal(std::move(collections));
+ }
+
+ void getFontSet(std::function<void(const std::vector<std::shared_ptr<Font>>&)> func) {
+ getFontSetInternal(func);
+ }
+
void registerFallback(const std::string& familyName,
const std::shared_ptr<FontCollection>& fc) {
registerFallbackInternal(familyName, fc);
@@ -66,5 +75,44 @@ TEST(SystemFontsTest, registerDefaultAndFallback) {
EXPECT_EQ(fc2, systemFonts.findFontCollection("sans"));
}
+TEST(SystemFontsTest, updateDefaultAndFallback) {
+ TestableSystemFonts systemFonts;
+ auto fc1 = buildFontCollection("Ascii.ttf");
+ auto fc2 = buildFontCollection("Bold.ttf");
+ systemFonts.registerDefault(fc1);
+ systemFonts.registerFallback("sans", fc2);
+ systemFonts.registerDefault(fc2);
+ systemFonts.registerFallback("sans", fc1);
+ EXPECT_EQ(fc2, systemFonts.findFontCollection("unknown-name"));
+ EXPECT_EQ(fc1, systemFonts.findFontCollection("sans"));
+}
+
+TEST(SystemFontTest, getAvailableFont_dedupFonts) {
+ TestableSystemFonts systemFonts;
+ auto asciiFamily = buildFontFamily("Ascii.ttf");
+ auto boldFamily = buildFontFamily("Bold.ttf");
+ auto boldItalicFamily = buildFontFamily("BoldItalic.ttf");
+
+ auto fc1Families = std::vector<std::shared_ptr<FontFamily>>{asciiFamily, boldItalicFamily};
+ auto fc2Families = std::vector<std::shared_ptr<FontFamily>>{boldFamily, boldItalicFamily};
+ auto fc1 = std::make_shared<FontCollection>(std::move(fc1Families));
+ auto fc2 = std::make_shared<FontCollection>(std::move(fc2Families));
+
+ systemFonts.addFontMap(std::move(fc1));
+ systemFonts.addFontMap(std::move(fc2));
+
+ systemFonts.getFontSet([](const std::vector<std::shared_ptr<Font>>& fonts) {
+ EXPECT_EQ(3u, fonts.size()); // Ascii, Bold and BoldItalic
+ std::unordered_set<std::string> fontPaths;
+ for (const auto& font : fonts) {
+ fontPaths.insert(getBasename(font->typeface()->GetFontPath()));
+ }
+
+ EXPECT_TRUE(fontPaths.find("Ascii.ttf") != fontPaths.end());
+ EXPECT_TRUE(fontPaths.find("Bold.ttf") != fontPaths.end());
+ EXPECT_TRUE(fontPaths.find("BoldItalic.ttf") != fontPaths.end());
+ });
+}
+
} // namespace
} // namespace minikin
diff --git a/tests/unittest/TestMain.cpp b/tests/unittest/TestMain.cpp
index 6680fbd..05e3da4 100644
--- a/tests/unittest/TestMain.cpp
+++ b/tests/unittest/TestMain.cpp
@@ -14,12 +14,9 @@
* limitations under the License.
*/
-#include "ICUEnvironment.h"
-
#include <gtest/gtest.h>
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
- ::testing::AddGlobalTestEnvironment(new minikin::ICUEnvironment);
return RUN_ALL_TESTS();
}
diff --git a/tests/util/Android.bp b/tests/util/Android.bp
index 8bf125b..1d3d8cf 100644
--- a/tests/util/Android.bp
+++ b/tests/util/Android.bp
@@ -1,3 +1,7 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
cc_library_static {
name: "libminikin-tests-util",
srcs: [
diff --git a/tests/util/BufferUtils.h b/tests/util/BufferUtils.h
new file mode 100644
index 0000000..355e74e
--- /dev/null
+++ b/tests/util/BufferUtils.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef MINIKIN_TEST_BUFFER_UTILS_H
+#define MINIKIN_TEST_BUFFER_UTILS_H
+
+#include <minikin/Buffer.h>
+#include <vector>
+
+namespace minikin {
+
+template <class T>
+std::vector<uint8_t> allocateBuffer(const T& t) {
+ BufferWriter writer(nullptr);
+ t.writeTo(&writer);
+ // Fill with 0xFF for debugging.
+ return std::vector<uint8_t>(writer.size(), 0xFFu);
+}
+
+template <class T, auto arg>
+std::vector<uint8_t> allocateBuffer(const T& t) {
+ BufferWriter writer(nullptr);
+ t.template writeTo<arg>(&writer);
+ // Fill with 0xFF for debugging.
+ return std::vector<uint8_t>(writer.size(), 0xFFu);
+}
+
+template <class T>
+std::vector<uint8_t> writeToBuffer(const T& t) {
+ std::vector<uint8_t> buffer = allocateBuffer(t);
+ BufferWriter writer(buffer.data());
+ t.writeTo(&writer);
+ return buffer;
+}
+
+template <class T, auto arg>
+std::vector<uint8_t> writeToBuffer(const T& t) {
+ std::vector<uint8_t> buffer = allocateBuffer<T, arg>(t);
+ BufferWriter writer(buffer.data());
+ t.template writeTo<arg>(&writer);
+ return buffer;
+}
+
+} // namespace minikin
+
+#endif // MINIKIN_TEST_BUFFER_UTILS_H
diff --git a/tests/util/FontTestUtils.cpp b/tests/util/FontTestUtils.cpp
index 4143c04..5370ab6 100644
--- a/tests/util/FontTestUtils.cpp
+++ b/tests/util/FontTestUtils.cpp
@@ -67,7 +67,7 @@ std::vector<std::shared_ptr<FontFamily>> getFontFamilies(const std::string& font
}
}
- std::vector<Font> fonts;
+ std::vector<std::shared_ptr<Font>> fonts;
for (xmlNode* fontNode = familyNode->children; fontNode; fontNode = fontNode->next) {
if (xmlStrcmp(fontNode->name, (const xmlChar*)"font") != 0) {
continue;
@@ -124,7 +124,7 @@ std::shared_ptr<FontCollection> buildFontCollection(const std::string& filePath)
std::shared_ptr<FontFamily> buildFontFamily(const std::string& filePath) {
auto font = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(filePath));
- std::vector<Font> fonts;
+ std::vector<std::shared_ptr<Font>> fonts;
fonts.push_back(Font::Builder(font).build());
return std::make_shared<FontFamily>(std::move(fonts));
}
@@ -132,7 +132,7 @@ std::shared_ptr<FontFamily> buildFontFamily(const std::string& filePath) {
std::shared_ptr<FontFamily> buildFontFamily(const std::string& filePath, const std::string& lang,
bool isCustomFallback) {
auto font = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(filePath));
- std::vector<Font> fonts;
+ std::vector<std::shared_ptr<Font>> fonts;
fonts.push_back(Font::Builder(font).build());
return std::make_shared<FontFamily>(LocaleListCache::getId(lang), FamilyVariant::DEFAULT,
std::move(fonts), isCustomFallback);
diff --git a/tests/util/FreeTypeMinikinFontForTest.cpp b/tests/util/FreeTypeMinikinFontForTest.cpp
index 1ea0631..1be466a 100644
--- a/tests/util/FreeTypeMinikinFontForTest.cpp
+++ b/tests/util/FreeTypeMinikinFontForTest.cpp
@@ -37,8 +37,6 @@
namespace minikin {
namespace {
-static int uniqueId = 0;
-
constexpr FT_Int32 LOAD_FLAG =
FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
@@ -62,7 +60,7 @@ void loadGlyphOrDie(uint32_t glyphId, float size, FT_Face face) {
} // namespace
FreeTypeMinikinFontForTest::FreeTypeMinikinFontForTest(const std::string& font_path, int index)
- : MinikinFont(uniqueId++), mFontPath(font_path), mFontIndex(index) {
+ : mFontPath(font_path), mFontIndex(index) {
int fd = open(font_path.c_str(), O_RDONLY);
LOG_ALWAYS_FATAL_IF(fd == -1, "Open failed: %s", font_path.c_str());
struct stat st = {};
@@ -114,4 +112,18 @@ void FreeTypeMinikinFontForTest::GetFontExtent(MinikinExtent* extent, const Mini
extent->descent = -static_cast<float>(mFtFace->descender) * paint.size / upem;
}
+void writeFreeTypeMinikinFontForTest(BufferWriter* writer, const MinikinFont* typeface) {
+ writer->writeString(typeface->GetFontPath());
+}
+
+std::shared_ptr<MinikinFont> loadFreeTypeMinikinFontForTest(BufferReader reader) {
+ std::string fontPath(reader.readString());
+ return std::make_shared<FreeTypeMinikinFontForTest>(fontPath);
+}
+
+Font::TypefaceLoader* readFreeTypeMinikinFontForTest(BufferReader* reader) {
+ reader->skipString(); // fontPath
+ return &loadFreeTypeMinikinFontForTest;
+}
+
} // namespace minikin
diff --git a/tests/util/FreeTypeMinikinFontForTest.h b/tests/util/FreeTypeMinikinFontForTest.h
index 4b6ea05..4cdb6d8 100644
--- a/tests/util/FreeTypeMinikinFontForTest.h
+++ b/tests/util/FreeTypeMinikinFontForTest.h
@@ -19,6 +19,8 @@
#include <string>
+#include "minikin/Buffer.h"
+#include "minikin/Font.h"
#include "minikin/MinikinFont.h"
#include <ft2build.h>
@@ -43,8 +45,7 @@ public:
void GetFontExtent(MinikinExtent* extent, const MinikinPaint& paint,
const FontFakery& fakery) const override;
- const std::string& fontPath() const { return mFontPath; }
-
+ const std::string& GetFontPath() const override { return mFontPath; }
const void* GetFontData() const { return mFontData; }
size_t GetFontSize() const { return mFontSize; }
int GetFontIndex() const { return mFontIndex; }
@@ -63,6 +64,10 @@ private:
MINIKIN_PREVENT_COPY_AND_ASSIGN(FreeTypeMinikinFontForTest);
};
+void writeFreeTypeMinikinFontForTest(BufferWriter* writer, const MinikinFont* typeface);
+
+Font::TypefaceLoader* readFreeTypeMinikinFontForTest(BufferReader* reader);
+
} // namespace minikin
#endif // MINIKIN_TEST_FREE_TYPE_MINIKIN_FONT_FOR_TEST_H