Merge "Implement family fallback."
This commit is contained in:
@@ -64,17 +64,19 @@ public final class FontConfig {
|
||||
private final int mWeight;
|
||||
private final boolean mIsItalic;
|
||||
private Uri mUri;
|
||||
private final String mFallbackFor;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public Font(@NonNull String fontName, int ttcIndex, @NonNull FontVariationAxis[] axes,
|
||||
int weight, boolean isItalic) {
|
||||
int weight, boolean isItalic, String fallbackFor) {
|
||||
mFontName = fontName;
|
||||
mTtcIndex = ttcIndex;
|
||||
mAxes = axes;
|
||||
mWeight = weight;
|
||||
mIsItalic = isItalic;
|
||||
mFallbackFor = fallbackFor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,6 +127,10 @@ public final class FontConfig {
|
||||
public void setUri(@NonNull Uri uri) {
|
||||
mUri = uri;
|
||||
}
|
||||
|
||||
public String getFallbackFor() {
|
||||
return mFallbackFor;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
BIN
core/tests/coretests/assets/fonts/a3em.ttf
Normal file
BIN
core/tests/coretests/assets/fonts/a3em.ttf
Normal file
Binary file not shown.
187
core/tests/coretests/assets/fonts/a3em.ttx
Normal file
187
core/tests/coretests/assets/fonts/a3em.ttx
Normal file
@@ -0,0 +1,187 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright (C) 2017 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="1em"/>
|
||||
<GlyphID id="2" name="3em"/>
|
||||
</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="1em" width="1000" lsb="93"/>
|
||||
<mtx name="3em" width="3000" lsb="93"/>
|
||||
</hmtx>
|
||||
|
||||
<cmap>
|
||||
<tableVersion version="0"/>
|
||||
<cmap_format_4 platformID="3" platEncID="10" language="0">
|
||||
<map code="0x0061" name="3em" />
|
||||
<map code="0x0062" name="1em" />
|
||||
<map code="0x0063" name="1em" />
|
||||
<map code="0x0064" name="1em" />
|
||||
<map code="0x0065" name="1em" />
|
||||
</cmap_format_4>
|
||||
</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="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
|
||||
<TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
|
||||
</glyf>
|
||||
|
||||
<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>
|
||||
BIN
core/tests/coretests/assets/fonts/all2em.ttf
Normal file
BIN
core/tests/coretests/assets/fonts/all2em.ttf
Normal file
Binary file not shown.
184
core/tests/coretests/assets/fonts/all2em.ttx
Normal file
184
core/tests/coretests/assets/fonts/all2em.ttx
Normal file
@@ -0,0 +1,184 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright (C) 2017 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="2em"/>
|
||||
</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="2em" width="1000" lsb="93"/>
|
||||
</hmtx>
|
||||
|
||||
<cmap>
|
||||
<tableVersion version="0"/>
|
||||
<cmap_format_4 platformID="3" platEncID="10" language="0">
|
||||
<map code="0x0061" name="2em" />
|
||||
<map code="0x0062" name="2em" />
|
||||
<map code="0x0063" name="2em" />
|
||||
<map code="0x0064" name="2em" />
|
||||
<map code="0x0065" name="2em" />
|
||||
</cmap_format_4>
|
||||
</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="2em" xMin="0" yMin="0" xMax="0" yMax="0" />
|
||||
</glyf>
|
||||
|
||||
<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>
|
||||
BIN
core/tests/coretests/assets/fonts/b3em.ttf
Normal file
BIN
core/tests/coretests/assets/fonts/b3em.ttf
Normal file
Binary file not shown.
187
core/tests/coretests/assets/fonts/b3em.ttx
Normal file
187
core/tests/coretests/assets/fonts/b3em.ttx
Normal file
@@ -0,0 +1,187 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright (C) 2017 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="1em"/>
|
||||
<GlyphID id="2" name="3em"/>
|
||||
</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="1em" width="1000" lsb="93"/>
|
||||
<mtx name="3em" width="3000" lsb="93"/>
|
||||
</hmtx>
|
||||
|
||||
<cmap>
|
||||
<tableVersion version="0"/>
|
||||
<cmap_format_4 platformID="3" platEncID="10" language="0">
|
||||
<map code="0x0061" name="1em" />
|
||||
<map code="0x0062" name="3em" />
|
||||
<map code="0x0063" name="1em" />
|
||||
<map code="0x0064" name="1em" />
|
||||
<map code="0x0065" name="1em" />
|
||||
</cmap_format_4>
|
||||
</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="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
|
||||
<TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
|
||||
</glyf>
|
||||
|
||||
<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>
|
||||
BIN
core/tests/coretests/assets/fonts/c3em.ttf
Normal file
BIN
core/tests/coretests/assets/fonts/c3em.ttf
Normal file
Binary file not shown.
187
core/tests/coretests/assets/fonts/c3em.ttx
Normal file
187
core/tests/coretests/assets/fonts/c3em.ttx
Normal file
@@ -0,0 +1,187 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright (C) 2017 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="1em"/>
|
||||
<GlyphID id="2" name="3em"/>
|
||||
</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="1em" width="1000" lsb="93"/>
|
||||
<mtx name="3em" width="3000" lsb="93"/>
|
||||
</hmtx>
|
||||
|
||||
<cmap>
|
||||
<tableVersion version="0"/>
|
||||
<cmap_format_4 platformID="3" platEncID="10" language="0">
|
||||
<map code="0x0061" name="1em" />
|
||||
<map code="0x0062" name="1em" />
|
||||
<map code="0x0063" name="3em" />
|
||||
<map code="0x0064" name="1em" />
|
||||
<map code="0x0065" name="1em" />
|
||||
</cmap_format_4>
|
||||
</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="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
|
||||
<TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
|
||||
</glyf>
|
||||
|
||||
<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>
|
||||
BIN
core/tests/coretests/assets/fonts/no_coverage.ttf
Normal file
BIN
core/tests/coretests/assets/fonts/no_coverage.ttf
Normal file
Binary file not shown.
180
core/tests/coretests/assets/fonts/no_coverage.ttx
Normal file
180
core/tests/coretests/assets/fonts/no_coverage.ttx
Normal file
@@ -0,0 +1,180 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright (C) 2017 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="dummy"/>
|
||||
</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="dummy" width="500" lsb="93"/>
|
||||
</hmtx>
|
||||
|
||||
<cmap>
|
||||
<tableVersion version="0"/>
|
||||
<cmap_format_4 platformID="3" platEncID="10" language="0">
|
||||
<map code="0xFFFD" name="dummy" /> <!-- dummy entry -->
|
||||
</cmap_format_4>
|
||||
</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="dummy" xMin="0" yMin="0" xMax="0" yMax="0" />
|
||||
</glyf>
|
||||
|
||||
<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>
|
||||
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.
|
||||
*/
|
||||
|
||||
package android.graphics;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TypefaceSystemFallbackTest {
|
||||
private static final String SYSTEM_FONT_DIR = "/system/fonts/";
|
||||
private static final String SYSTEM_FONTS_XML = "/system/etc/fonts.xml";
|
||||
|
||||
private static final String[] TEST_FONT_FILES = {
|
||||
"a3em.ttf", // Supports "a","b","c". The width of "a" is 3em, others are 1em.
|
||||
"b3em.ttf", // Supports "a","b","c". The width of "b" is 3em, others are 1em.
|
||||
"c3em.ttf", // Supports "a","b","c". The width of "c" is 3em, others are 1em.
|
||||
"all2em.ttf", // Supports "a,","b","c". All of them have the same width of 2em.
|
||||
"no_coverage.ttf", // This font doesn't support any characters.
|
||||
};
|
||||
private static final String TEST_FONTS_XML;
|
||||
private static final String TEST_FONT_DIR;
|
||||
|
||||
private static final float GLYPH_1EM_WIDTH;
|
||||
private static final float GLYPH_2EM_WIDTH;
|
||||
private static final float GLYPH_3EM_WIDTH;
|
||||
|
||||
static {
|
||||
final Context targetCtx = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
final File cacheDir = new File(targetCtx.getCacheDir(), "TypefaceSystemFallbackTest");
|
||||
if (!cacheDir.isDirectory()) {
|
||||
cacheDir.mkdirs();
|
||||
}
|
||||
TEST_FONT_DIR = cacheDir.getAbsolutePath() + "/";
|
||||
TEST_FONTS_XML = new File(cacheDir, "fonts.xml").getAbsolutePath();
|
||||
|
||||
final AssetManager am =
|
||||
InstrumentationRegistry.getInstrumentation().getContext().getAssets();
|
||||
final Paint paint = new Paint();
|
||||
paint.setTypeface(new Typeface.Builder(am, "fonts/a3em.ttf").build());
|
||||
GLYPH_3EM_WIDTH = paint.measureText("a");
|
||||
GLYPH_1EM_WIDTH = paint.measureText("b");
|
||||
|
||||
paint.setTypeface(new Typeface.Builder(am, "fonts/all2em.ttf").build());
|
||||
GLYPH_2EM_WIDTH = paint.measureText("a");
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
final AssetManager am =
|
||||
InstrumentationRegistry.getInstrumentation().getContext().getAssets();
|
||||
for (final String fontFile : TEST_FONT_FILES) {
|
||||
final String sourceInAsset = "fonts/" + fontFile;
|
||||
final File outInCache = new File(TEST_FONT_DIR, fontFile);
|
||||
try (InputStream is = am.open(sourceInAsset)) {
|
||||
Files.copy(is, outInCache.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
for (final String fontFile : TEST_FONT_FILES) {
|
||||
final File outInCache = new File(TEST_FONT_DIR, fontFile);
|
||||
outInCache.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static void buildSystemFallback(String xml,
|
||||
ArrayMap<String, Typeface> fontMap, ArrayMap<String, FontFamily[]> fallbackMap) {
|
||||
try (FileOutputStream fos = new FileOutputStream(TEST_FONTS_XML)) {
|
||||
fos.write(xml.getBytes(Charset.forName("UTF-8")));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Typeface.buildSystemFallback(TEST_FONTS_XML, TEST_FONT_DIR, fontMap, fallbackMap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildSystemFallback() {
|
||||
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
|
||||
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
|
||||
|
||||
Typeface.buildSystemFallback(SYSTEM_FONTS_XML, SYSTEM_FONT_DIR, fontMap, fallbackMap);
|
||||
|
||||
assertFalse(fontMap.isEmpty());
|
||||
assertFalse(fallbackMap.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildSystemFallback_NonExistentFontShouldBeIgnored() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>a3em.ttf</font>"
|
||||
+ " <font weight='400' style='normal'>NoSuchFont.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family name='NoSuchFont'>"
|
||||
+ " <font weight='400' style='normal'>NoSuchFont.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family>"
|
||||
+ " <font weight='400' style='normal'>NoSuchFont.ttf</font>"
|
||||
+ " </family>"
|
||||
+ "</familyset>";
|
||||
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
|
||||
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
|
||||
|
||||
buildSystemFallback(xml, fontMap, fallbackMap);
|
||||
|
||||
assertEquals(1, fontMap.size());
|
||||
assertTrue(fontMap.containsKey("sans-serif"));
|
||||
assertEquals(1, fallbackMap.size());
|
||||
assertTrue(fallbackMap.containsKey("sans-serif"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildSystemFallback_NamedFamily() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>a3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family name='test'>"
|
||||
+ " <font weight='400' style='normal'>b3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family name='test2'>"
|
||||
+ " <font weight='400' style='normal'>c3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family>"
|
||||
+ " <font weight='400' style='normal'>all2em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ "</familyset>";
|
||||
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
|
||||
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
|
||||
|
||||
buildSystemFallback(xml, fontMap, fallbackMap);
|
||||
|
||||
final Paint paint = new Paint();
|
||||
|
||||
final Typeface sansSerifTypeface = fontMap.get("sans-serif");
|
||||
assertNotNull(sansSerifTypeface);
|
||||
paint.setTypeface(sansSerifTypeface);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
|
||||
final Typeface testTypeface = fontMap.get("test");
|
||||
assertNotNull(testTypeface);
|
||||
paint.setTypeface(testTypeface);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
|
||||
final Typeface test2Typeface = fontMap.get("test2");
|
||||
assertNotNull(test2Typeface);
|
||||
paint.setTypeface(test2Typeface);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildSystemFallback_defaultFallback() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family name='test'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family>"
|
||||
+ " <font weight='400' style='normal'>a3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family>"
|
||||
+ " <font weight='400' style='normal'>all2em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ "</familyset>";
|
||||
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
|
||||
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
|
||||
|
||||
buildSystemFallback(xml, fontMap, fallbackMap);
|
||||
|
||||
final Paint paint = new Paint();
|
||||
|
||||
final Typeface sansSerifTypeface = fontMap.get("sans-serif");
|
||||
assertNotNull(sansSerifTypeface);
|
||||
paint.setTypeface(sansSerifTypeface);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
|
||||
final Typeface testTypeface = fontMap.get("test");
|
||||
assertNotNull(testTypeface);
|
||||
paint.setTypeface(testTypeface);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildSystemFallback_namedFallbackFamily() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family name='test'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family name='test2'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family>"
|
||||
+ " <font weight='400' style='normal' fallbackFor='test'>a3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family>"
|
||||
+ " <font weight='400' style='normal' fallbackFor='test2'>b3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family>"
|
||||
+ " <font weight='400' style='normal'>all2em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ "</familyset>";
|
||||
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
|
||||
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
|
||||
|
||||
buildSystemFallback(xml, fontMap, fallbackMap);
|
||||
|
||||
final Paint paint = new Paint();
|
||||
|
||||
final Typeface sansSerifTypeface = fontMap.get("sans-serif");
|
||||
assertNotNull(sansSerifTypeface);
|
||||
paint.setTypeface(sansSerifTypeface);
|
||||
assertEquals(GLYPH_2EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_2EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_2EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
|
||||
final Typeface testTypeface = fontMap.get("test");
|
||||
assertNotNull(testTypeface);
|
||||
paint.setTypeface(testTypeface);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
|
||||
final Typeface test2Typeface = fontMap.get("test2");
|
||||
assertNotNull(test2Typeface);
|
||||
paint.setTypeface(test2Typeface);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildSystemFallback_namedFallbackFamily2() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family name='test'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family name='test2'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family>"
|
||||
+ " <font weight='400' style='normal' fallbackFor='test'>a3em.ttf</font>"
|
||||
+ " <font weight='400' style='normal'>b3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family>"
|
||||
+ " <font weight='400' style='normal'>all2em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ "</familyset>";
|
||||
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
|
||||
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
|
||||
|
||||
buildSystemFallback(xml, fontMap, fallbackMap);
|
||||
|
||||
final Paint paint = new Paint();
|
||||
|
||||
final Typeface sansSerifTypeface = fontMap.get("sans-serif");
|
||||
assertNotNull(sansSerifTypeface);
|
||||
paint.setTypeface(sansSerifTypeface);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
|
||||
final Typeface testTypeface = fontMap.get("test");
|
||||
assertNotNull(testTypeface);
|
||||
paint.setTypeface(testTypeface);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
|
||||
final Typeface test2Typeface = fontMap.get("test2");
|
||||
assertNotNull(test2Typeface);
|
||||
paint.setTypeface(test2Typeface);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildSystemFallback_ImplicitSansSerifFallback() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>a3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family name='test'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family name='test2'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family>"
|
||||
+ " <font weight='400' style='normal'>all2em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ "</familyset>";
|
||||
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
|
||||
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
|
||||
|
||||
buildSystemFallback(xml, fontMap, fallbackMap);
|
||||
|
||||
final Paint paint = new Paint();
|
||||
|
||||
final Typeface testTypeface = fontMap.get("test");
|
||||
assertNotNull(testTypeface);
|
||||
paint.setTypeface(testTypeface);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
|
||||
final Typeface test2Typeface = fontMap.get("test2");
|
||||
assertNotNull(test2Typeface);
|
||||
paint.setTypeface(test2Typeface);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildSystemFallback_ElegantFallback() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family name='serif'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family variant='elegant'>"
|
||||
+ " <font weight='400' style='normal'>a3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family variant='compact'>"
|
||||
+ " <font weight='400' style='normal'>b3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ "</familyset>";
|
||||
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
|
||||
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
|
||||
|
||||
buildSystemFallback(xml, fontMap, fallbackMap);
|
||||
|
||||
final Paint paint = new Paint();
|
||||
|
||||
final Typeface testTypeface = fontMap.get("serif");
|
||||
assertNotNull(testTypeface);
|
||||
paint.setTypeface(testTypeface);
|
||||
paint.setElegantTextHeight(true);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
|
||||
paint.setElegantTextHeight(false);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildSystemFallback_ElegantFallback_customFallback() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family name='serif'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family variant='elegant'>"
|
||||
+ " <font weight='400' style='normal'>a3em.ttf</font>"
|
||||
+ " <font weight='400' style='normal' fallbackFor='serif'>b3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family variant='compact'>"
|
||||
+ " <font weight='400' style='normal'>c3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ "</familyset>";
|
||||
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
|
||||
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
|
||||
|
||||
buildSystemFallback(xml, fontMap, fallbackMap);
|
||||
|
||||
final Paint paint = new Paint();
|
||||
|
||||
Typeface testTypeface = fontMap.get("serif");
|
||||
assertNotNull(testTypeface);
|
||||
paint.setTypeface(testTypeface);
|
||||
paint.setElegantTextHeight(true);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
|
||||
paint.setElegantTextHeight(false);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
|
||||
testTypeface = fontMap.get("sans-serif");
|
||||
assertNotNull(testTypeface);
|
||||
paint.setTypeface(testTypeface);
|
||||
paint.setElegantTextHeight(true);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
|
||||
paint.setElegantTextHeight(false);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,7 @@ public class FontListParser {
|
||||
String weightStr = parser.getAttributeValue(null, "weight");
|
||||
int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
|
||||
boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
|
||||
String fallbackFor = parser.getAttributeValue(null, "fallbackFor");
|
||||
StringBuilder filename = new StringBuilder();
|
||||
while (parser.next() != XmlPullParser.END_TAG) {
|
||||
if (parser.getEventType() == XmlPullParser.TEXT) {
|
||||
@@ -126,7 +127,7 @@ public class FontListParser {
|
||||
}
|
||||
String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
|
||||
return new FontConfig.Font(sanitizedName, index,
|
||||
axes.toArray(new FontVariationAxis[axes.size()]), weight, isItalic);
|
||||
axes.toArray(new FontVariationAxis[axes.size()]), weight, isItalic, fallbackFor);
|
||||
}
|
||||
|
||||
private static FontVariationAxis readAxis(XmlPullParser parser)
|
||||
|
||||
@@ -38,6 +38,7 @@ import android.os.ResultReceiver;
|
||||
import android.provider.FontRequest;
|
||||
import android.provider.FontsContract;
|
||||
import android.text.FontConfig;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.util.LongSparseArray;
|
||||
@@ -45,6 +46,7 @@ import android.util.LruCache;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
@@ -105,12 +107,10 @@ public class Typeface {
|
||||
private static final LruCache<String, Typeface> sDynamicTypefaceCache = new LruCache<>(16);
|
||||
|
||||
static Typeface sDefaultTypeface;
|
||||
static Map<String, Typeface> sSystemFontMap;
|
||||
static FontFamily[] sFallbackFonts;
|
||||
static final Map<String, Typeface> sSystemFontMap;
|
||||
static final Map<String, FontFamily[]> sSystemFallbackMap;
|
||||
private static final Object sLock = new Object();
|
||||
|
||||
static final String FONTS_CONFIG = "fonts.xml";
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -129,6 +129,7 @@ public class Typeface {
|
||||
// Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp
|
||||
/** @hide */
|
||||
public static final int RESOLVE_BY_FONT_TABLE = -1;
|
||||
private static final String DEFAULT_FAMILY = "sans-serif";
|
||||
|
||||
// Style value for building typeface.
|
||||
private static final int STYLE_NORMAL = 0;
|
||||
@@ -163,28 +164,27 @@ public class Typeface {
|
||||
*/
|
||||
@Nullable
|
||||
public static Typeface createFromResources(AssetManager mgr, String path, int cookie) {
|
||||
if (sFallbackFonts != null) {
|
||||
synchronized (sDynamicTypefaceCache) {
|
||||
final String key = Builder.createAssetUid(
|
||||
mgr, path, 0 /* ttcIndex */, null /* axes */,
|
||||
RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */);
|
||||
Typeface typeface = sDynamicTypefaceCache.get(key);
|
||||
if (typeface != null) return typeface;
|
||||
synchronized (sDynamicTypefaceCache) {
|
||||
final String key = Builder.createAssetUid(
|
||||
mgr, path, 0 /* ttcIndex */, null /* axes */,
|
||||
RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */,
|
||||
DEFAULT_FAMILY);
|
||||
Typeface typeface = sDynamicTypefaceCache.get(key);
|
||||
if (typeface != null) return typeface;
|
||||
|
||||
FontFamily fontFamily = new FontFamily();
|
||||
// TODO: introduce ttc index and variation settings to resource type font.
|
||||
if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */,
|
||||
0 /* ttcIndex */, RESOLVE_BY_FONT_TABLE /* weight */,
|
||||
RESOLVE_BY_FONT_TABLE /* italic */, null /* axes */)) {
|
||||
if (!fontFamily.freeze()) {
|
||||
return null;
|
||||
}
|
||||
FontFamily[] families = {fontFamily};
|
||||
typeface = createFromFamiliesWithDefault(families,
|
||||
RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
|
||||
sDynamicTypefaceCache.put(key, typeface);
|
||||
return typeface;
|
||||
FontFamily fontFamily = new FontFamily();
|
||||
// TODO: introduce ttc index and variation settings to resource type font.
|
||||
if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */,
|
||||
0 /* ttcIndex */, RESOLVE_BY_FONT_TABLE /* weight */,
|
||||
RESOLVE_BY_FONT_TABLE /* italic */, null /* axes */)) {
|
||||
if (!fontFamily.freeze()) {
|
||||
return null;
|
||||
}
|
||||
FontFamily[] families = {fontFamily};
|
||||
typeface = createFromFamiliesWithDefault(families, DEFAULT_FAMILY,
|
||||
RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
|
||||
sDynamicTypefaceCache.put(key, typeface);
|
||||
return typeface;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -197,61 +197,57 @@ public class Typeface {
|
||||
@Nullable
|
||||
public static Typeface createFromResources(
|
||||
FamilyResourceEntry entry, AssetManager mgr, String path) {
|
||||
if (sFallbackFonts != null) {
|
||||
if (entry instanceof ProviderResourceEntry) {
|
||||
final ProviderResourceEntry providerEntry = (ProviderResourceEntry) entry;
|
||||
// Downloadable font
|
||||
List<List<String>> givenCerts = providerEntry.getCerts();
|
||||
List<List<byte[]>> certs = new ArrayList<>();
|
||||
if (givenCerts != null) {
|
||||
for (int i = 0; i < givenCerts.size(); i++) {
|
||||
List<String> certSet = givenCerts.get(i);
|
||||
List<byte[]> byteArraySet = new ArrayList<>();
|
||||
for (int j = 0; j < certSet.size(); j++) {
|
||||
byteArraySet.add(Base64.decode(certSet.get(j), Base64.DEFAULT));
|
||||
}
|
||||
certs.add(byteArraySet);
|
||||
if (entry instanceof ProviderResourceEntry) {
|
||||
final ProviderResourceEntry providerEntry = (ProviderResourceEntry) entry;
|
||||
// Downloadable font
|
||||
List<List<String>> givenCerts = providerEntry.getCerts();
|
||||
List<List<byte[]>> certs = new ArrayList<>();
|
||||
if (givenCerts != null) {
|
||||
for (int i = 0; i < givenCerts.size(); i++) {
|
||||
List<String> certSet = givenCerts.get(i);
|
||||
List<byte[]> byteArraySet = new ArrayList<>();
|
||||
for (int j = 0; j < certSet.size(); j++) {
|
||||
byteArraySet.add(Base64.decode(certSet.get(j), Base64.DEFAULT));
|
||||
}
|
||||
}
|
||||
// Downloaded font and it wasn't cached, request it again and return a
|
||||
// default font instead (nothing we can do now).
|
||||
FontRequest request = new FontRequest(providerEntry.getAuthority(),
|
||||
providerEntry.getPackage(), providerEntry.getQuery(), certs);
|
||||
Typeface typeface = FontsContract.getFontSync(request);
|
||||
return typeface == null ? DEFAULT : typeface;
|
||||
}
|
||||
|
||||
Typeface typeface = findFromCache(mgr, path);
|
||||
if (typeface != null) return typeface;
|
||||
|
||||
// family is FontFamilyFilesResourceEntry
|
||||
final FontFamilyFilesResourceEntry filesEntry =
|
||||
(FontFamilyFilesResourceEntry) entry;
|
||||
|
||||
FontFamily fontFamily = new FontFamily();
|
||||
for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) {
|
||||
// TODO: Add ttc and variation font support. (b/37853920)
|
||||
if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(),
|
||||
0 /* resourceCookie */, false /* isAsset */, 0 /* ttcIndex */,
|
||||
fontFile.getWeight(), fontFile.getItalic(), null /* axes */)) {
|
||||
return null;
|
||||
certs.add(byteArraySet);
|
||||
}
|
||||
}
|
||||
if (!fontFamily.freeze()) {
|
||||
// Downloaded font and it wasn't cached, request it again and return a
|
||||
// default font instead (nothing we can do now).
|
||||
FontRequest request = new FontRequest(providerEntry.getAuthority(),
|
||||
providerEntry.getPackage(), providerEntry.getQuery(), certs);
|
||||
Typeface typeface = FontsContract.getFontSync(request);
|
||||
return typeface == null ? DEFAULT : typeface;
|
||||
}
|
||||
|
||||
Typeface typeface = findFromCache(mgr, path);
|
||||
if (typeface != null) return typeface;
|
||||
|
||||
// family is FontFamilyFilesResourceEntry
|
||||
final FontFamilyFilesResourceEntry filesEntry = (FontFamilyFilesResourceEntry) entry;
|
||||
|
||||
FontFamily fontFamily = new FontFamily();
|
||||
for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) {
|
||||
// TODO: Add ttc and variation font support. (b/37853920)
|
||||
if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(),
|
||||
0 /* resourceCookie */, false /* isAsset */, 0 /* ttcIndex */,
|
||||
fontFile.getWeight(), fontFile.getItalic(), null /* axes */)) {
|
||||
return null;
|
||||
}
|
||||
FontFamily[] familyChain = { fontFamily };
|
||||
typeface = createFromFamiliesWithDefault(familyChain,
|
||||
RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
|
||||
synchronized (sDynamicTypefaceCache) {
|
||||
final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */,
|
||||
null /* axes */, RESOLVE_BY_FONT_TABLE /* weight */,
|
||||
RESOLVE_BY_FONT_TABLE /* italic */);
|
||||
sDynamicTypefaceCache.put(key, typeface);
|
||||
}
|
||||
return typeface;
|
||||
}
|
||||
return null;
|
||||
if (!fontFamily.freeze()) {
|
||||
return null;
|
||||
}
|
||||
FontFamily[] familyChain = { fontFamily };
|
||||
typeface = createFromFamiliesWithDefault(familyChain, DEFAULT_FAMILY,
|
||||
RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
|
||||
synchronized (sDynamicTypefaceCache) {
|
||||
final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */,
|
||||
null /* axes */, RESOLVE_BY_FONT_TABLE /* weight */,
|
||||
RESOLVE_BY_FONT_TABLE /* italic */, DEFAULT_FAMILY);
|
||||
sDynamicTypefaceCache.put(key, typeface);
|
||||
}
|
||||
return typeface;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,7 +257,8 @@ public class Typeface {
|
||||
public static Typeface findFromCache(AssetManager mgr, String path) {
|
||||
synchronized (sDynamicTypefaceCache) {
|
||||
final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, null /* axes */,
|
||||
RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */);
|
||||
RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */,
|
||||
DEFAULT_FAMILY);
|
||||
Typeface typeface = sDynamicTypefaceCache.get(key);
|
||||
if (typeface != null) {
|
||||
return typeface;
|
||||
@@ -498,7 +495,7 @@ public class Typeface {
|
||||
* @return Unique id for a given AssetManager and asset path.
|
||||
*/
|
||||
private static String createAssetUid(final AssetManager mgr, String path, int ttcIndex,
|
||||
@Nullable FontVariationAxis[] axes, int weight, int italic) {
|
||||
@Nullable FontVariationAxis[] axes, int weight, int italic, String fallback) {
|
||||
final SparseArray<String> pkgs = mgr.getAssignedPackageIdentifiers();
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final int size = pkgs.size();
|
||||
@@ -513,7 +510,11 @@ public class Typeface {
|
||||
builder.append(Integer.toString(weight));
|
||||
builder.append("-");
|
||||
builder.append(Integer.toString(italic));
|
||||
builder.append("-");
|
||||
// Family name may contain hyphen. Use double hyphen for avoiding key conflicts before
|
||||
// and after appending falblack name.
|
||||
builder.append("--");
|
||||
builder.append(fallback);
|
||||
builder.append("--");
|
||||
if (axes != null) {
|
||||
for (FontVariationAxis axis : axes) {
|
||||
builder.append(axis.getTag());
|
||||
@@ -593,13 +594,15 @@ public class Typeface {
|
||||
return resolveFallbackTypeface();
|
||||
}
|
||||
FontFamily[] families = { fontFamily };
|
||||
return createFromFamiliesWithDefault(families, mWeight, mItalic);
|
||||
return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight,
|
||||
mItalic);
|
||||
} catch (IOException e) {
|
||||
return resolveFallbackTypeface();
|
||||
}
|
||||
} else if (mAssetManager != null) { // Builder is created with asset manager.
|
||||
final String key = createAssetUid(
|
||||
mAssetManager, mPath, mTtcIndex, mAxes, mWeight, mItalic);
|
||||
mAssetManager, mPath, mTtcIndex, mAxes, mWeight, mItalic,
|
||||
mFallbackFamilyName);
|
||||
synchronized (sLock) {
|
||||
Typeface typeface = sDynamicTypefaceCache.get(key);
|
||||
if (typeface != null) return typeface;
|
||||
@@ -613,7 +616,8 @@ public class Typeface {
|
||||
return resolveFallbackTypeface();
|
||||
}
|
||||
FontFamily[] families = { fontFamily };
|
||||
typeface = createFromFamiliesWithDefault(families, mWeight, mItalic);
|
||||
typeface = createFromFamiliesWithDefault(families, mFallbackFamilyName,
|
||||
mWeight, mItalic);
|
||||
sDynamicTypefaceCache.put(key, typeface);
|
||||
return typeface;
|
||||
}
|
||||
@@ -627,7 +631,8 @@ public class Typeface {
|
||||
return resolveFallbackTypeface();
|
||||
}
|
||||
FontFamily[] families = { fontFamily };
|
||||
return createFromFamiliesWithDefault(families, mWeight, mItalic);
|
||||
return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight,
|
||||
mItalic);
|
||||
} else if (mFonts != null) {
|
||||
final FontFamily fontFamily = new FontFamily();
|
||||
boolean atLeastOneFont = false;
|
||||
@@ -653,7 +658,8 @@ public class Typeface {
|
||||
}
|
||||
fontFamily.freeze();
|
||||
FontFamily[] families = { fontFamily };
|
||||
return createFromFamiliesWithDefault(families, mWeight, mItalic);
|
||||
return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight,
|
||||
mItalic);
|
||||
}
|
||||
|
||||
// Must not reach here.
|
||||
@@ -673,10 +679,7 @@ public class Typeface {
|
||||
* @return The best matching typeface.
|
||||
*/
|
||||
public static Typeface create(String familyName, int style) {
|
||||
if (sSystemFontMap != null) {
|
||||
return create(sSystemFontMap.get(familyName), style);
|
||||
}
|
||||
return null;
|
||||
return create(sSystemFontMap.get(familyName), style);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -751,34 +754,33 @@ public class Typeface {
|
||||
if (path == null) {
|
||||
throw new NullPointerException(); // for backward compatibility
|
||||
}
|
||||
if (sFallbackFonts != null) {
|
||||
synchronized (sLock) {
|
||||
Typeface typeface = new Builder(mgr, path).build();
|
||||
if (typeface != null) return typeface;
|
||||
synchronized (sLock) {
|
||||
Typeface typeface = new Builder(mgr, path).build();
|
||||
if (typeface != null) return typeface;
|
||||
|
||||
final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */,
|
||||
null /* axes */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
|
||||
typeface = sDynamicTypefaceCache.get(key);
|
||||
if (typeface != null) return typeface;
|
||||
final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */,
|
||||
null /* axes */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE,
|
||||
DEFAULT_FAMILY);
|
||||
typeface = sDynamicTypefaceCache.get(key);
|
||||
if (typeface != null) return typeface;
|
||||
|
||||
final FontFamily fontFamily = new FontFamily();
|
||||
if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */,
|
||||
0 /* ttc index */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE,
|
||||
null /* axes */)) {
|
||||
// Due to backward compatibility, even if the font is not supported by our font
|
||||
// stack, we need to place the empty font at the first place. The typeface with
|
||||
// empty font behaves different from default typeface especially in fallback
|
||||
// font selection.
|
||||
fontFamily.allowUnsupportedFont();
|
||||
fontFamily.freeze();
|
||||
final FontFamily[] families = { fontFamily };
|
||||
typeface = createFromFamiliesWithDefault(families, RESOLVE_BY_FONT_TABLE,
|
||||
RESOLVE_BY_FONT_TABLE);
|
||||
sDynamicTypefaceCache.put(key, typeface);
|
||||
return typeface;
|
||||
} else {
|
||||
fontFamily.abortCreation();
|
||||
}
|
||||
final FontFamily fontFamily = new FontFamily();
|
||||
if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */,
|
||||
0 /* ttc index */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE,
|
||||
null /* axes */)) {
|
||||
// Due to backward compatibility, even if the font is not supported by our font
|
||||
// stack, we need to place the empty font at the first place. The typeface with
|
||||
// empty font behaves different from default typeface especially in fallback
|
||||
// font selection.
|
||||
fontFamily.allowUnsupportedFont();
|
||||
fontFamily.freeze();
|
||||
final FontFamily[] families = { fontFamily };
|
||||
typeface = createFromFamiliesWithDefault(families, DEFAULT_FAMILY,
|
||||
RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
|
||||
sDynamicTypefaceCache.put(key, typeface);
|
||||
return typeface;
|
||||
} else {
|
||||
fontFamily.abortCreation();
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Font asset not found " + path);
|
||||
@@ -815,22 +817,20 @@ public class Typeface {
|
||||
* @return The new typeface.
|
||||
*/
|
||||
public static Typeface createFromFile(@Nullable String path) {
|
||||
if (sFallbackFonts != null) {
|
||||
final FontFamily fontFamily = new FontFamily();
|
||||
if (fontFamily.addFont(path, 0 /* ttcIndex */, null /* axes */,
|
||||
RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)) {
|
||||
// Due to backward compatibility, even if the font is not supported by our font
|
||||
// stack, we need to place the empty font at the first place. The typeface with
|
||||
// empty font behaves different from default typeface especially in fallback font
|
||||
// selection.
|
||||
fontFamily.allowUnsupportedFont();
|
||||
fontFamily.freeze();
|
||||
FontFamily[] families = { fontFamily };
|
||||
return createFromFamiliesWithDefault(families, RESOLVE_BY_FONT_TABLE,
|
||||
RESOLVE_BY_FONT_TABLE);
|
||||
} else {
|
||||
fontFamily.abortCreation();
|
||||
}
|
||||
final FontFamily fontFamily = new FontFamily();
|
||||
if (fontFamily.addFont(path, 0 /* ttcIndex */, null /* axes */,
|
||||
RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)) {
|
||||
// Due to backward compatibility, even if the font is not supported by our font
|
||||
// stack, we need to place the empty font at the first place. The typeface with
|
||||
// empty font behaves different from default typeface especially in fallback font
|
||||
// selection.
|
||||
fontFamily.allowUnsupportedFont();
|
||||
fontFamily.freeze();
|
||||
FontFamily[] families = { fontFamily };
|
||||
return createFromFamiliesWithDefault(families, DEFAULT_FAMILY,
|
||||
RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
|
||||
} else {
|
||||
fontFamily.abortCreation();
|
||||
}
|
||||
throw new RuntimeException("Font not found " + path);
|
||||
}
|
||||
@@ -852,6 +852,8 @@ public class Typeface {
|
||||
/**
|
||||
* Create a new typeface from an array of font families, including
|
||||
* also the font families in the fallback list.
|
||||
* @param fallbackName the family name. If given families don't support characters, the
|
||||
* characters will be rendered with this family.
|
||||
* @param weight the weight for this family. {@link RESOLVE_BY_FONT_TABLE} can be used. In that
|
||||
* case, the table information in the first family's font is used. If the first
|
||||
* family has multiple fonts, the closest to the regular weight and upright font
|
||||
@@ -863,13 +865,17 @@ public class Typeface {
|
||||
* @param families array of font families
|
||||
*/
|
||||
private static Typeface createFromFamiliesWithDefault(FontFamily[] families,
|
||||
int weight, int italic) {
|
||||
long[] ptrArray = new long[families.length + sFallbackFonts.length];
|
||||
String fallbackName, int weight, int italic) {
|
||||
FontFamily[] fallback = sSystemFallbackMap.get(fallbackName);
|
||||
if (fallback == null) {
|
||||
fallback = sSystemFallbackMap.get(DEFAULT_FAMILY);
|
||||
}
|
||||
long[] ptrArray = new long[families.length + fallback.length];
|
||||
for (int i = 0; i < families.length; i++) {
|
||||
ptrArray[i] = families[i].mNativePtr;
|
||||
}
|
||||
for (int i = 0; i < sFallbackFonts.length; i++) {
|
||||
ptrArray[i + families.length] = sFallbackFonts[i].mNativePtr;
|
||||
for (int i = 0; i < fallback.length; i++) {
|
||||
ptrArray[i + families.length] = fallback[i].mNativePtr;
|
||||
}
|
||||
return new Typeface(nativeCreateFromArray(ptrArray, weight, italic));
|
||||
}
|
||||
@@ -885,113 +891,189 @@ public class Typeface {
|
||||
mWeight = nativeGetWeight(ni);
|
||||
}
|
||||
|
||||
private static FontFamily makeFamilyFromParsed(FontConfig.Family family,
|
||||
Map<String, ByteBuffer> bufferForPath) {
|
||||
FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant());
|
||||
for (FontConfig.Font font : family.getFonts()) {
|
||||
String fullPathName = "/system/fonts/" + font.getFontName();
|
||||
ByteBuffer fontBuffer = bufferForPath.get(fullPathName);
|
||||
if (fontBuffer == null) {
|
||||
try (FileInputStream file = new FileInputStream(fullPathName)) {
|
||||
FileChannel fileChannel = file.getChannel();
|
||||
long fontSize = fileChannel.size();
|
||||
fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
|
||||
bufferForPath.put(fullPathName, fontBuffer);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error mapping font file " + fullPathName);
|
||||
private static @Nullable ByteBuffer mmap(String fullPath) {
|
||||
try (FileInputStream file = new FileInputStream(fullPath)) {
|
||||
final FileChannel fileChannel = file.getChannel();
|
||||
final long fontSize = fileChannel.size();
|
||||
return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error mapping font file " + fullPath);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable FontFamily createFontFamily(
|
||||
String familyName, List<FontConfig.Font> fonts, String languageTag, int variant,
|
||||
Map<String, ByteBuffer> cache, String fontDir) {
|
||||
final FontFamily family = new FontFamily(languageTag, variant);
|
||||
for (int i = 0; i < fonts.size(); i++) {
|
||||
final FontConfig.Font font = fonts.get(i);
|
||||
final String fullPath = fontDir + font.getFontName();
|
||||
ByteBuffer buffer = cache.get(fullPath);
|
||||
if (buffer == null) {
|
||||
if (cache.containsKey(fullPath)) {
|
||||
continue; // Already failed to mmap. Skip it.
|
||||
}
|
||||
buffer = mmap(fullPath);
|
||||
cache.put(fullPath, buffer);
|
||||
if (buffer == null) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!fontFamily.addFontFromBuffer(fontBuffer, font.getTtcIndex(), font.getAxes(),
|
||||
if (!family.addFontFromBuffer(buffer, font.getTtcIndex(), font.getAxes(),
|
||||
font.getWeight(), font.isItalic() ? STYLE_ITALIC : STYLE_NORMAL)) {
|
||||
Log.e(TAG, "Error creating font " + fullPathName + "#" + font.getTtcIndex());
|
||||
Log.e(TAG, "Error creating font " + fullPath + "#" + font.getTtcIndex());
|
||||
}
|
||||
}
|
||||
if (!fontFamily.freeze()) {
|
||||
// Treat as system error since reaching here means that a system pre-installed font
|
||||
// can't be used by our font stack.
|
||||
Log.e(TAG, "Unable to load Family: " + family.getName() + ":" + family.getLanguage());
|
||||
if (!family.freeze()) {
|
||||
Log.e(TAG, "Unable to load Family: " + familyName + " : " + languageTag);
|
||||
return null;
|
||||
}
|
||||
return fontFamily;
|
||||
return family;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
private static void pushFamilyToFallback(FontConfig.Family xmlFamily,
|
||||
ArrayMap<String, ArrayList<FontFamily>> fallbackMap,
|
||||
Map<String, ByteBuffer> cache,
|
||||
String fontDir) {
|
||||
|
||||
final String languageTag = xmlFamily.getLanguage();
|
||||
final int variant = xmlFamily.getVariant();
|
||||
|
||||
final ArrayList<FontConfig.Font> defaultFonts = new ArrayList<>();
|
||||
final ArrayMap<String, ArrayList<FontConfig.Font>> specificFallbackFonts = new ArrayMap<>();
|
||||
|
||||
// Collect default fallback and specific fallback fonts.
|
||||
for (final FontConfig.Font font : xmlFamily.getFonts()) {
|
||||
final String fallbackName = font.getFallbackFor();
|
||||
if (fallbackName == null) {
|
||||
defaultFonts.add(font);
|
||||
} else {
|
||||
ArrayList<FontConfig.Font> fallback = specificFallbackFonts.get(fallbackName);
|
||||
if (fallback == null) {
|
||||
fallback = new ArrayList<>();
|
||||
specificFallbackFonts.put(fallbackName, fallback);
|
||||
}
|
||||
fallback.add(font);
|
||||
}
|
||||
}
|
||||
|
||||
final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily(
|
||||
xmlFamily.getName(), defaultFonts, languageTag, variant, cache, fontDir);
|
||||
|
||||
// Insert family into fallback map.
|
||||
for (int i = 0; i < fallbackMap.size(); i++) {
|
||||
final ArrayList<FontConfig.Font> fallback =
|
||||
specificFallbackFonts.get(fallbackMap.keyAt(i));
|
||||
if (fallback == null) {
|
||||
if (defaultFamily != null) {
|
||||
fallbackMap.valueAt(i).add(defaultFamily);
|
||||
}
|
||||
} else {
|
||||
final FontFamily family = createFontFamily(
|
||||
xmlFamily.getName(), fallback, languageTag, variant, cache, fontDir);
|
||||
if (family != null) {
|
||||
fallbackMap.valueAt(i).add(family);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the system fallback from xml file.
|
||||
*
|
||||
* This should only be called once, from the static class initializer block.
|
||||
* @param xmlPath A full path string to the fonts.xml file.
|
||||
* @param fontDir A full path string to the system font directory. This must end with
|
||||
* slash('/').
|
||||
* @param fontMap An output system font map. Caller must pass empty map.
|
||||
* @param fallbackMap An output system fallback map. Caller must pass empty map.
|
||||
* @hide
|
||||
*/
|
||||
private static void init() {
|
||||
// Load font config and initialize Minikin state
|
||||
File systemFontConfigLocation = getSystemFontConfigLocation();
|
||||
File configFilename = new File(systemFontConfigLocation, FONTS_CONFIG);
|
||||
@VisibleForTesting
|
||||
public static void buildSystemFallback(String xmlPath, String fontDir,
|
||||
ArrayMap<String, Typeface> fontMap, ArrayMap<String, FontFamily[]> fallbackMap) {
|
||||
try {
|
||||
FileInputStream fontsIn = new FileInputStream(configFilename);
|
||||
FontConfig fontConfig = FontListParser.parse(fontsIn);
|
||||
final FileInputStream fontsIn = new FileInputStream(xmlPath);
|
||||
final FontConfig fontConfig = FontListParser.parse(fontsIn);
|
||||
|
||||
Map<String, ByteBuffer> bufferForPath = new HashMap<String, ByteBuffer>();
|
||||
final HashMap<String, ByteBuffer> bufferCache = new HashMap<String, ByteBuffer>();
|
||||
final FontConfig.Family[] xmlFamilies = fontConfig.getFamilies();
|
||||
|
||||
List<FontFamily> familyList = new ArrayList<FontFamily>();
|
||||
// Note that the default typeface is always present in the fallback list;
|
||||
// this is an enhancement from pre-Minikin behavior.
|
||||
for (int i = 0; i < fontConfig.getFamilies().length; i++) {
|
||||
FontConfig.Family f = fontConfig.getFamilies()[i];
|
||||
if (i == 0 || f.getName() == null) {
|
||||
FontFamily family = makeFamilyFromParsed(f, bufferForPath);
|
||||
if (family != null) {
|
||||
familyList.add(family);
|
||||
}
|
||||
final ArrayMap<String, ArrayList<FontFamily>> fallbackListMap = new ArrayMap<>();
|
||||
// First traverse families which have a 'name' attribute to create fallback map.
|
||||
for (final FontConfig.Family xmlFamily : xmlFamilies) {
|
||||
final String familyName = xmlFamily.getName();
|
||||
if (familyName == null) {
|
||||
continue;
|
||||
}
|
||||
final FontFamily family = createFontFamily(
|
||||
xmlFamily.getName(), Arrays.asList(xmlFamily.getFonts()),
|
||||
xmlFamily.getLanguage(), xmlFamily.getVariant(), bufferCache, fontDir);
|
||||
if (family == null) {
|
||||
continue;
|
||||
}
|
||||
final ArrayList<FontFamily> fallback = new ArrayList<>();
|
||||
fallback.add(family);
|
||||
fallbackListMap.put(familyName, fallback);
|
||||
}
|
||||
|
||||
// Then, add fallback fonts to the each fallback map.
|
||||
for (int i = 0; i < xmlFamilies.length; i++) {
|
||||
final FontConfig.Family xmlFamily = xmlFamilies[i];
|
||||
// The first family (usually the sans-serif family) is always placed immediately
|
||||
// after the primary family in the fallback.
|
||||
if (i == 0 || xmlFamily.getName() == null) {
|
||||
pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache, fontDir);
|
||||
}
|
||||
}
|
||||
sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]);
|
||||
setDefault(Typeface.createFromFamilies(sFallbackFonts));
|
||||
|
||||
Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
|
||||
for (int i = 0; i < fontConfig.getFamilies().length; i++) {
|
||||
Typeface typeface;
|
||||
FontConfig.Family f = fontConfig.getFamilies()[i];
|
||||
if (f.getName() != null) {
|
||||
if (i == 0) {
|
||||
// The first entry is the default typeface; no sense in
|
||||
// duplicating the corresponding FontFamily.
|
||||
typeface = sDefaultTypeface;
|
||||
} else {
|
||||
FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath);
|
||||
if (fontFamily == null) {
|
||||
continue;
|
||||
}
|
||||
FontFamily[] families = { fontFamily };
|
||||
typeface = Typeface.createFromFamiliesWithDefault(families,
|
||||
RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
|
||||
}
|
||||
systemFonts.put(f.getName(), typeface);
|
||||
// Build the font map and fallback map.
|
||||
for (int i = 0; i < fallbackListMap.size(); i++) {
|
||||
final String fallbackName = fallbackListMap.keyAt(i);
|
||||
final List<FontFamily> familyList = fallbackListMap.valueAt(i);
|
||||
final FontFamily[] families = familyList.toArray(new FontFamily[familyList.size()]);
|
||||
|
||||
fallbackMap.put(fallbackName, families);
|
||||
final long[] ptrArray = new long[families.length];
|
||||
for (int j = 0; j < families.length; j++) {
|
||||
ptrArray[j] = families[j].mNativePtr;
|
||||
}
|
||||
fontMap.put(fallbackName, new Typeface(nativeCreateFromArray(
|
||||
ptrArray, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)));
|
||||
}
|
||||
for (FontConfig.Alias alias : fontConfig.getAliases()) {
|
||||
Typeface base = systemFonts.get(alias.getToName());
|
||||
|
||||
// Insert alias to font maps.
|
||||
for (final FontConfig.Alias alias : fontConfig.getAliases()) {
|
||||
Typeface base = fontMap.get(alias.getToName());
|
||||
Typeface newFace = base;
|
||||
int weight = alias.getWeight();
|
||||
if (weight != 400) {
|
||||
newFace = new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
|
||||
}
|
||||
systemFonts.put(alias.getName(), newFace);
|
||||
fontMap.put(alias.getName(), newFace);
|
||||
}
|
||||
sSystemFontMap = systemFonts;
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e);
|
||||
// TODO: normal in non-Minikin case, remove or make error when Minikin-only
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "Error opening " + configFilename, e);
|
||||
Log.e(TAG, "Error opening " + xmlPath, e);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error reading " + configFilename, e);
|
||||
Log.e(TAG, "Error reading " + xmlPath, e);
|
||||
} catch (XmlPullParserException e) {
|
||||
Log.e(TAG, "XML parse exception for " + configFilename, e);
|
||||
Log.e(TAG, "XML parse exception for " + xmlPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
init();
|
||||
final ArrayMap<String, Typeface> systemFontMap = new ArrayMap<>();
|
||||
final ArrayMap<String, FontFamily[]> systemFallbackMap = new ArrayMap<>();
|
||||
buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", systemFontMap,
|
||||
systemFallbackMap);
|
||||
sSystemFontMap = Collections.unmodifiableMap(systemFontMap);
|
||||
sSystemFallbackMap = Collections.unmodifiableMap(systemFallbackMap);
|
||||
|
||||
setDefault(sSystemFontMap.get(DEFAULT_FAMILY));
|
||||
|
||||
// Set up defaults and typefaces exposed in public API
|
||||
DEFAULT = create((String) null, 0);
|
||||
DEFAULT_BOLD = create((String) null, Typeface.BOLD);
|
||||
@@ -1008,10 +1090,6 @@ public class Typeface {
|
||||
|
||||
}
|
||||
|
||||
private static File getSystemFontConfigLocation() {
|
||||
return new File("/system/etc/");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
|
||||
@@ -68,7 +68,7 @@ static minikin::FontStyle computeRelativeStyle(int baseWeight, SkTypeface::Style
|
||||
Typeface* gDefaultTypeface = NULL;
|
||||
|
||||
Typeface* Typeface::resolveDefault(Typeface* src) {
|
||||
LOG_ALWAYS_FATAL_IF(gDefaultTypeface == nullptr);
|
||||
LOG_ALWAYS_FATAL_IF(src == nullptr && gDefaultTypeface == nullptr);
|
||||
return src == nullptr ? gDefaultTypeface : src;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user