diff options
Diffstat (limited to 'tests')
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 Binary files differindex be6d5fe..2e6835b 100644 --- a/tests/data/Ascii.ttf +++ b/tests/data/Ascii.ttf 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 Binary files differnew file mode 100644 index 0000000..c89c59c --- /dev/null +++ b/tests/data/Bbox.ttf 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 Binary files differnew file mode 100644 index 0000000..659226d --- /dev/null +++ b/tests/data/EmojiBase.ttf 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 Binary files differnew file mode 100644 index 0000000..890796b --- /dev/null +++ b/tests/data/OverrideEmoji.ttf 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 |