Merge "Make Paint.hasGlyph variation selector aware."
diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp
index 7fd288a..9b774b3 100644
--- a/core/jni/android/graphics/MinikinUtils.cpp
+++ b/core/jni/android/graphics/MinikinUtils.cpp
@@ -63,6 +63,11 @@
layout->doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint);
}
+bool MinikinUtils::hasVariationSelector(TypefaceImpl* typeface, uint32_t codepoint, uint32_t vs) {
+ const TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
+ return resolvedFace->fFontCollection->hasVariationSelector(codepoint, vs);
+}
+
float MinikinUtils::xOffsetForTextAlign(Paint* paint, const Layout& layout) {
switch (paint->getTextAlign()) {
case Paint::kCenter_Align:
diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h
index 1ee6245..5bf1eec 100644
--- a/core/jni/android/graphics/MinikinUtils.h
+++ b/core/jni/android/graphics/MinikinUtils.h
@@ -40,6 +40,8 @@
TypefaceImpl* typeface, const uint16_t* buf, size_t start, size_t count,
size_t bufSize);
+ static bool hasVariationSelector(TypefaceImpl* typeface, uint32_t codepoint, uint32_t vs);
+
static float xOffsetForTextAlign(Paint* paint, const Layout& layout);
static float hOffsetForTextAlign(Paint* paint, const Layout& layout, const SkPath& path);
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index b50046f..9c11dd1 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -39,6 +39,7 @@
#include <minikin/GraphemeBreak.h>
#include <minikin/Measurement.h>
+#include <unicode/utf16.h>
#include "MinikinSkia.h"
#include "MinikinUtils.h"
#include "Paint.h"
@@ -852,45 +853,44 @@
return false;
}
- static jboolean hasGlyphVariation(const Paint* paint, TypefaceImpl* typeface, jint bidiFlags,
- const jchar* chars, size_t size) {
- // TODO: query font for whether character has variation selector; requires a corresponding
- // function in Minikin.
- return false;
- }
-
static jboolean hasGlyph(JNIEnv *env, jclass, jlong paintHandle, jlong typefaceHandle,
jint bidiFlags, jstring string) {
const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
ScopedStringChars str(env, string);
- /* start by rejecting variation selectors (not supported yet) */
+ /* Start by rejecting unsupported base code point and variation selector pairs. */
size_t nChars = 0;
+ const uint32_t kStartOfString = 0xFFFFFFFF;
+ uint32_t prevCp = kStartOfString;
for (size_t i = 0; i < str.size(); i++) {
- jchar c = str[i];
- if (0xDC00 <= c && c <= 0xDFFF) {
+ jchar cu = str[i];
+ uint32_t cp = cu;
+ if (U16_IS_TRAIL(cu)) {
// invalid UTF-16, unpaired trailing surrogate
return false;
- } else if (0xD800 <= c && c <= 0xDBFF) {
+ } else if (U16_IS_LEAD(cu)) {
if (i + 1 == str.size()) {
// invalid UTF-16, unpaired leading surrogate at end of string
return false;
}
i++;
- jchar c2 = str[i];
- if (!(0xDC00 <= c2 && c2 <= 0xDFFF)) {
+ jchar cu2 = str[i];
+ if (!U16_IS_TRAIL(cu2)) {
// invalid UTF-16, unpaired leading surrogate
return false;
}
- // UTF-16 encoding of range U+E0100..U+E01EF is DB40 DD00 .. DB40 DDEF
- if (c == 0xDB40 && 0xDD00 <= c2 && c2 <= 0xDDEF) {
- return hasGlyphVariation(paint, typeface, bidiFlags, str.get(), str.size());
- }
- } else if (0xFE00 <= c && c <= 0xFE0F) {
- return hasGlyphVariation(paint, typeface, bidiFlags, str.get(), str.size());
+ cp = U16_GET_SUPPLEMENTARY(cu, cu2);
+ }
+
+ if (prevCp != kStartOfString &&
+ ((0xFE00 <= cp && cp <= 0xFE0F) || (0xE0100 <= cp && cp <= 0xE01EF)) &&
+ !MinikinUtils::hasVariationSelector(typeface, prevCp, cp)) {
+ // No font has a glyph for the code point and variation selector pair.
+ return false;
}
nChars++;
+ prevCp = cp;
}
Layout layout;
MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, str.get(), 0, str.size(),
diff --git a/core/tests/coretests/assets/fonts/hasGlyphTestFont.ttf b/core/tests/coretests/assets/fonts/hasGlyphTestFont.ttf
new file mode 100644
index 0000000..add3f40
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/hasGlyphTestFont.ttf
Binary files differ
diff --git a/core/tests/coretests/assets/fonts/hasGlyphTestFont.ttx b/core/tests/coretests/assets/fonts/hasGlyphTestFont.ttx
new file mode 100644
index 0000000..7038f46
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/hasGlyphTestFont.ttx
@@ -0,0 +1,365 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="BaseChar1"/>
+ <GlyphID id="2" name="BaseChar1_VS1"/>
+ <GlyphID id="3" name="BaseChar1_VS17"/>
+ <GlyphID id="4" name="BaseChar1_VS18"/>
+ <GlyphID id="5" name="BaseChar2"/>
+ <GlyphID id="6" name="BaseChar2_VS2"/>
+ <GlyphID id="7" name="BaseChar2_VS18"/>
+ <GlyphID id="8" name="BaseChar2_VS19"/>
+ <GlyphID id="9" name="BaseChar3"/>
+ <GlyphID id="10" name="BaseChar4_VS3"/>
+ <GlyphID id="11" name="BaseChar4_VS19"/>
+ <GlyphID id="12" name="BaseChar4_VS20"/>
+ <GlyphID id="13" name="BaseChar5"/>
+ <GlyphID id="14" name="BaseChar5_VS1"/>
+ <GlyphID id="15" name="BaseChar5_VS17"/>
+ <GlyphID id="16" name="BaseChar5_VS18"/>
+ <GlyphID id="17" name="BaseChar6"/>
+ <GlyphID id="18" name="BaseChar6_VS2"/>
+ <GlyphID id="19" name="BaseChar6_VS18"/>
+ <GlyphID id="20" name="BaseChar6_VS19"/>
+ <GlyphID id="21" name="BaseChar7"/>
+ <GlyphID id="22" name="BaseChar8_VS3"/>
+ <GlyphID id="23" name="BaseChar8_VS19"/>
+ <GlyphID id="24" name="BaseChar8_VS20"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Wed Sep 9 08:01:17 2015"/>
+ <modified value="Wed Sep 9 08:48:07 2015"/>
+ <xMin value="30"/>
+ <yMin value="-200"/>
+ <xMax value="629"/>
+ <yMax value="800"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <advanceWidthMax value="659"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="30"/>
+ <xMaxExtent value="629"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="18"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="54"/>
+ <maxPoints value="73"/>
+ <maxContours value="10"/>
+ <maxCompositePoints value="0"/>
+ <maxCompositeContours value="0"/>
+ <maxZones value="2"/>
+ <maxTwilightPoints value="12"/>
+ <maxStorage value="28"/>
+ <maxFunctionDefs value="119"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="61"/>
+ <maxSizeOfInstructions value="2967"/>
+ <maxComponentElements value="0"/>
+ <maxComponentDepth value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="BaseChar1" width="500" lsb="93"/>
+ <mtx name="BaseChar1_VS1" width="500" lsb="93"/>
+ <mtx name="BaseChar1_VS17" width="500" lsb="93"/>
+ <mtx name="BaseChar1_VS18" width="500" lsb="93"/>
+ <mtx name="BaseChar2" width="500" lsb="93"/>
+ <mtx name="BaseChar2_VS2" width="500" lsb="93"/>
+ <mtx name="BaseChar2_VS18" width="500" lsb="93"/>
+ <mtx name="BaseChar2_VS19" width="500" lsb="93"/>
+ <mtx name="BaseChar3" width="500" lsb="93"/>
+ <mtx name="BaseChar4_VS3" width="500" lsb="93"/>
+ <mtx name="BaseChar4_VS19" width="500" lsb="93"/>
+ <mtx name="BaseChar4_VS20" width="500" lsb="93"/>
+ <mtx name="BaseChar5" width="500" lsb="93"/>
+ <mtx name="BaseChar5_VS1" width="500" lsb="93"/>
+ <mtx name="BaseChar5_VS17" width="500" lsb="93"/>
+ <mtx name="BaseChar5_VS18" width="500" lsb="93"/>
+ <mtx name="BaseChar6" width="500" lsb="93"/>
+ <mtx name="BaseChar6_VS2" width="500" lsb="93"/>
+ <mtx name="BaseChar6_VS18" width="500" lsb="93"/>
+ <mtx name="BaseChar6_VS19" width="500" lsb="93"/>
+ <mtx name="BaseChar7" width="500" lsb="93"/>
+ <mtx name="BaseChar8_VS3" width="500" lsb="93"/>
+ <mtx name="BaseChar8_VS19" width="500" lsb="93"/>
+ <mtx name="BaseChar8_VS20" width="500" lsb="93"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_12 format="12" reserved="0" length="6" nGroups="1" platformID="3" platEncID="10" language="0">
+ <map code="0x0061" name="BaseChar1" />
+ <map code="0x0062" name="BaseChar2" />
+ <map code="0x0063" name="BaseChar3" />
+ <!-- No cmap4 entry for BaseChar4 -->
+ <map code="0x1F000" name="BaseChar5" />
+ <map code="0x1F001" name="BaseChar6" />
+ <map code="0x1F002" name="BaseChar7" />
+ <!-- No cmap4 entry for BaseChar8 -->
+ </cmap_format_12>
+ <cmap_format_14 format="14" platformID="0" platEncID="5" length="24" numVarSelectorRecords="3">
+ <map uvs="0xFE00" uv="0x0061" name="BaseChar1_VS1" />
+ <map uvs="0xE0100" uv="0x0061" name="BaseChar1_VS17" />
+ <map uvs="0xE0101" uv="0x0061" name="BaseChar1_VS18" />
+ <map uvs="0xE0102" uv="0x0061" name="None" />
+
+ <map uvs="0xFE01" uv="0x0062" name="BaseChar2_VS2" />
+ <map uvs="0xE0101" uv="0x0062" name="BaseChar2_VS18" />
+ <map uvs="0xE0102" uv="0x0062" name="BaseChar2_VS19" />
+ <map uvs="0xE0103" uv="0x0062" name="None" />
+
+ <map uvs="0xFE02" uv="0x0064" name="BaseChar4_VS3" />
+ <map uvs="0xE0102" uv="0x0064" name="BaseChar4_VS19" />
+ <map uvs="0xE0103" uv="0x0064" name="BaseChar4_VS20" />
+ <!-- There is no default glyph for U+0064 U+E0104 but there is a entry for
+ default UVS entry. hasGlyph should return false in this
+ case. -->
+ <map uvs="0xE0104" uv="0x0064" name="None" />
+
+ <map uvs="0xFE00" uv="0x1F000" name="BaseChar5_VS1" />
+ <map uvs="0xE0100" uv="0x1F000" name="BaseChar5_VS17" />
+ <map uvs="0xE0101" uv="0x1F000" name="BaseChar5_VS18" />
+ <map uvs="0xE0102" uv="0x1F000" name="None" />
+
+ <map uvs="0xFE01" uv="0x1F001" name="BaseChar6_VS2" />
+ <map uvs="0xE0101" uv="0x1F001" name="BaseChar6_VS18" />
+ <map uvs="0xE0102" uv="0x1F001" name="BaseChar6_VS19" />
+ <map uvs="0xE0103" uv="0x1F001" name="None" />
+
+ <map uvs="0xFE02" uv="0x1F003" name="BaseChar8_VS3" />
+ <map uvs="0xE0102" uv="0x1F003" name="BaseChar8_VS19" />
+ <map uvs="0xE0103" uv="0x1F003" name="BaseChar8_VS20" />
+ <!-- There is no default glyph for U+1F003 U+E0104 but there is a entry for
+ default UVS entry. hasGlyph should return false in this
+ case. -->
+ <map uvs="0xE0104" uv="0x1F003" name="None" />
+ </cmap_format_14>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="BaseChar1" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar1_VS1" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar1_VS17" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar1_VS18" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar2" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar2_VS2" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar2_VS18" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar2_VS19" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar3" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar4_VS3" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar4_VS19" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar4_VS20" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar5" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar5_VS1" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar5_VS17" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar5_VS18" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar6" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar6_VS2" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar6_VS18" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar6_VS19" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar7" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar8_VS3" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar8_VS19" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="BaseChar8_VS20" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Paint.hasGlyph Test
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Paint.hasGlyph Test
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ hasGlyphTestFont-Regular
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Paint.hasGlyph Test
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ hasGlyphTestFont Test
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ hasGlyphTestFont-Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/core/tests/coretests/src/android/graphics/PaintTest.java b/core/tests/coretests/src/android/graphics/PaintTest.java
index e97bb33..2a3d463 100644
--- a/core/tests/coretests/src/android/graphics/PaintTest.java
+++ b/core/tests/coretests/src/android/graphics/PaintTest.java
@@ -20,6 +20,9 @@
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import java.util.Arrays;
+import java.util.HashSet;
+
/**
* PaintTest tests {@link Paint}.
*/
@@ -94,4 +97,63 @@
testCase.mWidthWithHinting, widths);
}
}
+
+ private static class HasGlyphTestCase {
+ public final int mBaseCodepoint;
+ public final HashSet<Integer> mVariationSelectors;
+
+ public HasGlyphTestCase(int baseCodepoint, Integer[] variationSelectors) {
+ mBaseCodepoint = baseCodepoint;
+ mVariationSelectors = new HashSet<>(Arrays.asList(variationSelectors));
+ }
+ }
+
+ private static String codePointsToString(int[] codepoints) {
+ StringBuilder sb = new StringBuilder();
+ for (int codepoint : codepoints) {
+ sb.append(Character.toChars(codepoint));
+ }
+ return sb.toString();
+ }
+
+ public void testHasGlyph_variationSelectors() {
+ final Typeface fontTypeface = Typeface.createFromAsset(
+ getInstrumentation().getContext().getAssets(), "fonts/hasGlyphTestFont.ttf");
+ Paint p = new Paint();
+ p.setTypeface(fontTypeface);
+
+ // Usually latin letters U+0061..U+0064 and Mahjong Tiles U+1F000..U+1F003 don't have
+ // variation selectors. This test may fail if system pre-installed fonts have a variation
+ // selector support for U+0061..U+0064 and U+1F000..U+1F003.
+ HasGlyphTestCase[] HAS_GLYPH_TEST_CASES = {
+ new HasGlyphTestCase(0x0061, new Integer[] {0xFE00, 0xE0100, 0xE0101, 0xE0102}),
+ new HasGlyphTestCase(0x0062, new Integer[] {0xFE01, 0xE0101, 0xE0102, 0xE0103}),
+ new HasGlyphTestCase(0x0063, new Integer[] {}),
+ new HasGlyphTestCase(0x0064, new Integer[] {0xFE02, 0xE0102, 0xE0103}),
+
+ new HasGlyphTestCase(0x1F000, new Integer[] {0xFE00, 0xE0100, 0xE0101, 0xE0102}),
+ new HasGlyphTestCase(0x1F001, new Integer[] {0xFE01, 0xE0101, 0xE0102, 0xE0103}),
+ new HasGlyphTestCase(0x1F002, new Integer[] {}),
+ new HasGlyphTestCase(0x1F003, new Integer[] {0xFE02, 0xE0102, 0xE0103}),
+ };
+
+ for (HasGlyphTestCase testCase : HAS_GLYPH_TEST_CASES) {
+ for (int vs = 0xFE00; vs <= 0xE01EF; ++vs) {
+ // Move to variation selector supplements after variation selectors.
+ if (vs == 0xFF00) {
+ vs = 0xE0100;
+ }
+ final String signature =
+ "hasGlyph(U+" + Integer.toHexString(testCase.mBaseCodepoint) +
+ " U+" + Integer.toHexString(vs) + ")";
+ final String testString =
+ codePointsToString(new int[] {testCase.mBaseCodepoint, vs});
+ if (testCase.mVariationSelectors.contains(vs)) {
+ assertTrue(signature + " is expected to be true", p.hasGlyph(testString));
+ } else {
+ assertFalse(signature + " is expected to be false", p.hasGlyph(testString));
+ }
+ }
+ }
+ }
}