summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libs/minikin/FontCollection.cpp10
-rw-r--r--libs/minikin/GraphemeBreak.cpp43
-rw-r--r--libs/minikin/MinikinInternal.cpp42
-rw-r--r--libs/minikin/MinikinInternal.h6
-rw-r--r--tests/FontCollectionItemizeTest.cpp110
-rw-r--r--tests/data/ColorEmojiFont.ttfbin948 -> 1020 bytes
-rw-r--r--tests/data/ColorEmojiFont.ttx16
-rw-r--r--tests/data/TextEmojiFont.ttfbin940 -> 964 bytes
-rw-r--r--tests/data/TextEmojiFont.ttx6
-rw-r--r--tests/data/emoji.xml6
10 files changed, 116 insertions, 123 deletions
diff --git a/libs/minikin/FontCollection.cpp b/libs/minikin/FontCollection.cpp
index dd905a3..4541af8 100644
--- a/libs/minikin/FontCollection.cpp
+++ b/libs/minikin/FontCollection.cpp
@@ -379,11 +379,13 @@ void FontCollection::itemize(const uint16_t *string, size_t string_size, FontSty
langListId, variant);
if (utf16Pos == 0 || family != lastFamily) {
size_t start = utf16Pos;
- // Workaround for Emoji keycap until we implement per-cluster font
- // selection: if keycap is found in a different font that also
- // supports previous char, attach previous char to the new run.
+ // Workaround for Emoji keycap and emoji modifier until we implement per-cluster
+ // font selection: if a keycap or an emoji modifier is found in a different font
+ // that also supports previous char, attach previous char to the new run.
// Bug 7557244.
- if (ch == KEYCAP && utf16Pos != 0 && family && family->getCoverage()->get(prevCh)) {
+ if (utf16Pos != 0 &&
+ (ch == KEYCAP || (isEmojiModifier(ch) && isEmojiBase(prevCh))) &&
+ family && family->getCoverage()->get(prevCh)) {
const size_t prevChLength = U16_LENGTH(prevCh);
run->end -= prevChLength;
if (run->start == run->end) {
diff --git a/libs/minikin/GraphemeBreak.cpp b/libs/minikin/GraphemeBreak.cpp
index 4141091..ef323d5 100644
--- a/libs/minikin/GraphemeBreak.cpp
+++ b/libs/minikin/GraphemeBreak.cpp
@@ -19,6 +19,7 @@
#include <unicode/utf16.h>
#include <minikin/GraphemeBreak.h>
+#include "MinikinInternal.h"
namespace android {
@@ -77,48 +78,6 @@ bool isZwjEmoji(uint32_t c) {
|| c == 0x1F5E8); // LEFT SPEECH BUBBLE
}
-// Based on Modifiers from http://www.unicode.org/L2/L2016/16011-data-file.txt
-bool isEmojiModifier(uint32_t c) {
- return (0x1F3FB <= c && c <= 0x1F3FF);
-}
-
-// Based on Emoji_Modifier_Base from
-// http://www.unicode.org/Public/emoji/3.0/emoji-data.txt
-bool isEmojiBase(uint32_t c) {
- if (0x261D <= c && c <= 0x270D) {
- return (c == 0x261D || c == 0x26F9 || (0x270A <= c && c <= 0x270D));
- } else if (0x1F385 <= c && c <= 0x1F93E) {
- return (c == 0x1F385
- || (0x1F3C3 <= c || c <= 0x1F3C4)
- || (0x1F3CA <= c || c <= 0x1F3CB)
- || (0x1F442 <= c || c <= 0x1F443)
- || (0x1F446 <= c || c <= 0x1F450)
- || (0x1F466 <= c || c <= 0x1F469)
- || c == 0x1F46E
- || (0x1F470 <= c || c <= 0x1F478)
- || c == 0x1F47C
- || (0x1F481 <= c || c <= 0x1F483)
- || (0x1F485 <= c || c <= 0x1F487)
- || c == 0x1F4AA
- || c == 0x1F575
- || c == 0x1F57A
- || c == 0x1F590
- || (0x1F595 <= c || c <= 0x1F596)
- || (0x1F645 <= c || c <= 0x1F647)
- || (0x1F64B <= c || c <= 0x1F64F)
- || c == 0x1F6A3
- || (0x1F6B4 <= c || c <= 0x1F6B6)
- || c == 0x1F6C0
- || (0x1F918 <= c || c <= 0x1F91E)
- || c == 0x1F926
- || c == 0x1F930
- || (0x1F933 <= c || c <= 0x1F939)
- || (0x1F93B <= c || c <= 0x1F93E));
- } else {
- return false;
- }
-}
-
bool GraphemeBreak::isGraphemeBreak(const uint16_t* buf, size_t start, size_t count,
size_t offset) {
// This implementation closely follows Unicode Standard Annex #29 on
diff --git a/libs/minikin/MinikinInternal.cpp b/libs/minikin/MinikinInternal.cpp
index c2aa01a..7fa7ce9 100644
--- a/libs/minikin/MinikinInternal.cpp
+++ b/libs/minikin/MinikinInternal.cpp
@@ -30,4 +30,46 @@ void assertMinikinLocked() {
#endif
}
+// Based on Modifiers from http://www.unicode.org/L2/L2016/16011-data-file.txt
+bool isEmojiModifier(uint32_t c) {
+ return (0x1F3FB <= c && c <= 0x1F3FF);
+}
+
+// Based on Emoji_Modifier_Base from
+// http://www.unicode.org/Public/emoji/3.0/emoji-data.txt
+bool isEmojiBase(uint32_t c) {
+ if (0x261D <= c && c <= 0x270D) {
+ return (c == 0x261D || c == 0x26F9 || (0x270A <= c && c <= 0x270D));
+ } else if (0x1F385 <= c && c <= 0x1F93E) {
+ return (c == 0x1F385
+ || (0x1F3C3 <= c || c <= 0x1F3C4)
+ || (0x1F3CA <= c || c <= 0x1F3CB)
+ || (0x1F442 <= c || c <= 0x1F443)
+ || (0x1F446 <= c || c <= 0x1F450)
+ || (0x1F466 <= c || c <= 0x1F469)
+ || c == 0x1F46E
+ || (0x1F470 <= c || c <= 0x1F478)
+ || c == 0x1F47C
+ || (0x1F481 <= c || c <= 0x1F483)
+ || (0x1F485 <= c || c <= 0x1F487)
+ || c == 0x1F4AA
+ || c == 0x1F575
+ || c == 0x1F57A
+ || c == 0x1F590
+ || (0x1F595 <= c || c <= 0x1F596)
+ || (0x1F645 <= c || c <= 0x1F647)
+ || (0x1F64B <= c || c <= 0x1F64F)
+ || c == 0x1F6A3
+ || (0x1F6B4 <= c || c <= 0x1F6B6)
+ || c == 0x1F6C0
+ || (0x1F918 <= c || c <= 0x1F91E)
+ || c == 0x1F926
+ || c == 0x1F930
+ || (0x1F933 <= c || c <= 0x1F939)
+ || (0x1F93B <= c || c <= 0x1F93E));
+ } else {
+ return false;
+ }
+}
+
}
diff --git a/libs/minikin/MinikinInternal.h b/libs/minikin/MinikinInternal.h
index 34a95bb..3d68691 100644
--- a/libs/minikin/MinikinInternal.h
+++ b/libs/minikin/MinikinInternal.h
@@ -32,6 +32,12 @@ extern Mutex gMinikinLock;
// Aborts if gMinikinLock is not acquired. Do nothing on the release build.
void assertMinikinLocked();
+// Returns true if c is emoji modifier base.
+bool isEmojiBase(uint32_t c);
+
+// Returns true if c is emoji modifier.
+bool isEmojiModifier(uint32_t c);
+
}
#endif // MINIKIN_INTERNAL_H
diff --git a/tests/FontCollectionItemizeTest.cpp b/tests/FontCollectionItemizeTest.cpp
index 446efc6..031f3f9 100644
--- a/tests/FontCollectionItemizeTest.cpp
+++ b/tests/FontCollectionItemizeTest.cpp
@@ -1119,78 +1119,6 @@ TEST_F(FontCollectionItemizeTest, itemize_LanguageAndCoverage) {
}
}
-TEST_F(FontCollectionItemizeTest, itemize_emojiSelection) {
- std::unique_ptr<FontCollection> collection = getFontCollection(kTestFontDir, kEmojiXmlFile);
- std::vector<FontCollection::Run> runs;
-
- const FontStyle kDefaultFontStyle;
-
- // U+00A9 is a text default emoji which is only available in TextEmojiFont.ttf.
- // TextEmojiFont.ttf should be selected.
- itemize(collection.get(), "U+00A9", kDefaultFontStyle, &runs);
- ASSERT_EQ(1U, runs.size());
- EXPECT_EQ(0, runs[0].start);
- EXPECT_EQ(1, runs[0].end);
- EXPECT_EQ(kTextEmojiFont, getFontPath(runs[0]));
-
- // U+00AE is a text default emoji which is only available in ColorEmojiFont.ttf.
- // ColorEmojiFont.ttf should be selected.
- itemize(collection.get(), "U+00AE", kDefaultFontStyle, &runs);
- ASSERT_EQ(1U, runs.size());
- EXPECT_EQ(0, runs[0].start);
- EXPECT_EQ(1, runs[0].end);
- EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0]));
-
- // U+203C is a text default emoji which is available in both TextEmojiFont.ttf and
- // ColorEmojiFont.ttf. TextEmojiFont.ttf should be selected.
- itemize(collection.get(), "U+203C", kDefaultFontStyle, &runs);
- ASSERT_EQ(1U, runs.size());
- EXPECT_EQ(0, runs[0].start);
- EXPECT_EQ(1, runs[0].end);
- // TODO: use text font for text default emoji.
- // EXPECT_EQ(kTextEmojiFont, getFontPath(runs[0]));
-
- // U+2049 is a text default emoji which is not available in either TextEmojiFont.ttf or
- // ColorEmojiFont.ttf. No font should be selected.
- itemize(collection.get(), "U+2049", kDefaultFontStyle, &runs);
- ASSERT_EQ(1U, runs.size());
- EXPECT_EQ(0, runs[0].start);
- EXPECT_EQ(1, runs[0].end);
- EXPECT_TRUE(runs[0].fakedFont.font == NULL || kNoGlyphFont == getFontPath(runs[0]));
-
- // U+231A is a emoji default emoji which is available only in TextEmojiFont.ttf.
- // TextEmojiFont.ttf should be selected.
- itemize(collection.get(), "U+231A", kDefaultFontStyle, &runs);
- ASSERT_EQ(1U, runs.size());
- EXPECT_EQ(0, runs[0].start);
- EXPECT_EQ(1, runs[0].end);
- EXPECT_EQ(kTextEmojiFont, getFontPath(runs[0]));
-
- // U+231B is a emoji default emoji which is available only in ColorEmojiFont.ttf.
- // ColorEmojiFont.ttf should be selected.
- itemize(collection.get(), "U+231B", kDefaultFontStyle, &runs);
- ASSERT_EQ(1U, runs.size());
- EXPECT_EQ(0, runs[0].start);
- EXPECT_EQ(1, runs[0].end);
- EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0]));
-
- // U+23E9 is a emoji default emoji which is available in both TextEmojiFont.ttf and
- // ColorEmojiFont.ttf. ColorEmojiFont should be selected.
- itemize(collection.get(), "U+23E9", kDefaultFontStyle, &runs);
- ASSERT_EQ(1U, runs.size());
- EXPECT_EQ(0, runs[0].start);
- EXPECT_EQ(1, runs[0].end);
- EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0]));
-
- // U+23EA is a emoji default emoji which is not avaialble in either TextEmojiFont.ttf and
- // ColorEmojiFont.ttf. No font should b e selected.
- itemize(collection.get(), "U+23EA", kDefaultFontStyle, &runs);
- ASSERT_EQ(1U, runs.size());
- EXPECT_EQ(0, runs[0].start);
- EXPECT_EQ(1, runs[0].end);
- EXPECT_TRUE(runs[0].fakedFont.font == NULL || kNoGlyphFont == getFontPath(runs[0]));
-}
-
TEST_F(FontCollectionItemizeTest, itemize_emojiSelection_withFE0E) {
std::unique_ptr<FontCollection> collection = getFontCollection(kTestFontDir, kEmojiXmlFile);
std::vector<FontCollection::Run> runs;
@@ -1355,3 +1283,41 @@ TEST_F(FontCollectionItemizeTest, itemize_emojiSelection_withFE0F) {
EXPECT_EQ(kMixedEmojiFont, getFontPath(runs[0]));
}
+TEST_F(FontCollectionItemizeTest, itemize_emojiSelection_with_skinTone) {
+ std::unique_ptr<FontCollection> collection = getFontCollection(kTestFontDir, kEmojiXmlFile);
+ std::vector<FontCollection::Run> runs;
+
+ const FontStyle kDefaultFontStyle;
+
+ // TextEmoji font is selected since it is listed before ColorEmoji font.
+ itemize(collection.get(), "U+261D", kDefaultFontStyle, &runs);
+ ASSERT_EQ(1U, runs.size());
+ EXPECT_EQ(0, runs[0].start);
+ EXPECT_EQ(1, runs[0].end);
+ EXPECT_EQ(kTextEmojiFont, getFontPath(runs[0]));
+
+ // If skin tone is specified, it should be colored.
+ itemize(collection.get(), "U+261D U+1F3FD", kDefaultFontStyle, &runs);
+ ASSERT_EQ(1U, runs.size());
+ EXPECT_EQ(0, runs[0].start);
+ EXPECT_EQ(3, runs[0].end);
+ EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0]));
+
+ // Still color font is selected if an emoji variation selector is specified.
+ itemize(collection.get(), "U+261D U+FE0F U+1F3FD", kDefaultFontStyle, &runs);
+ ASSERT_EQ(1U, runs.size());
+ EXPECT_EQ(0, runs[0].start);
+ EXPECT_EQ(4, runs[0].end);
+ EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0]));
+
+ // Text font should be selected if a text variation selector is specified and skin tone is
+ // rendered by itself.
+ itemize(collection.get(), "U+261D U+FE0E U+1F3FD", kDefaultFontStyle, &runs);
+ ASSERT_EQ(2U, runs.size());
+ EXPECT_EQ(0, runs[0].start);
+ EXPECT_EQ(2, runs[0].end);
+ EXPECT_EQ(kTextEmojiFont, getFontPath(runs[0]));
+ EXPECT_EQ(2, runs[1].start);
+ EXPECT_EQ(4, runs[1].end);
+ EXPECT_EQ(kColorEmojiFont, getFontPath(runs[1]));
+}
diff --git a/tests/data/ColorEmojiFont.ttf b/tests/data/ColorEmojiFont.ttf
index dd72eea..e0b34a1 100644
--- a/tests/data/ColorEmojiFont.ttf
+++ b/tests/data/ColorEmojiFont.ttf
Binary files differ
diff --git a/tests/data/ColorEmojiFont.ttx b/tests/data/ColorEmojiFont.ttx
index b077339..58b3d83 100644
--- a/tests/data/ColorEmojiFont.ttx
+++ b/tests/data/ColorEmojiFont.ttx
@@ -27,6 +27,8 @@
<GlyphID id="7" name="Emoji7"/>
<GlyphID id="8" name="Emoji8"/>
<GlyphID id="9" name="Emoji9"/>
+ <GlyphID id="10" name="WHITE_UP_POINTING_INDEX" />
+ <GlyphID id="11" name="EMOJI_MODIFIER_FITZPATRICK_TYPE_4" />
</GlyphOrder>
<head>
@@ -153,17 +155,21 @@
<mtx name="Emoji7" width="500" lsb="93"/>
<mtx name="Emoji8" width="500" lsb="93"/>
<mtx name="Emoji9" width="500" lsb="93"/>
+ <mtx name="WHITE_UP_POINTING_INDEX" width="500" lsb="93" />
+ <mtx name="EMOJI_MODIFIER_FITZPATRICK_TYPE_4" width="500" lsb="93" />
</hmtx>
<cmap>
<tableVersion version="0"/>
- <cmap_format_4 platformID="3" platEncID="10" language="0">
+ <cmap_format_12 format="12" reserved="0" length="7" nGroups="1" platformID="3" platEncID="10" language="0">
<map code="0x00AE" name="Emoji2" /> <!-- Text Default -->
<map code="0x203C" name="Emoji3" /> <!-- Text Default -->
<map code="0x231B" name="Emoji6" /> <!-- Emoji Default -->
<map code="0x23E9" name="Emoji7" /> <!-- Emoji Default -->
<map code="0x26F9" name="Emoji9" /> <!-- U+26F9 U+FE0F is in ColorTextMixedEmojiFont.ttf -->
- </cmap_format_4>
+ <map code="0x261D" name="WHITE_UP_POINTING_INDEX" />
+ <map code="0x1F3FD" name="EMOJI_MODIFIER_FITZPATRICK_TYPE_4" />
+ </cmap_format_12>
</cmap>
<loca>
@@ -206,6 +212,12 @@
<TTGlyph name="Emoji9" xMin="0" yMin="0" xMax="0" yMax="0">
<contour></contour><instructions><assembly></assembly></instructions>
</TTGlyph>
+ <TTGlyph name="WHITE_UP_POINTING_INDEX" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
+ <TTGlyph name="EMOJI_MODIFIER_FITZPATRICK_TYPE_4" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
</glyf>
<name>
diff --git a/tests/data/TextEmojiFont.ttf b/tests/data/TextEmojiFont.ttf
index 21013a0..21b6801 100644
--- a/tests/data/TextEmojiFont.ttf
+++ b/tests/data/TextEmojiFont.ttf
Binary files differ
diff --git a/tests/data/TextEmojiFont.ttx b/tests/data/TextEmojiFont.ttx
index 35e7d98..83cc9bc 100644
--- a/tests/data/TextEmojiFont.ttx
+++ b/tests/data/TextEmojiFont.ttx
@@ -27,6 +27,7 @@
<GlyphID id="7" name="Emoji7"/>
<GlyphID id="8" name="Emoji8"/>
<GlyphID id="9" name="Emoji9"/>
+ <GlyphID id="10" name="WHITE_UP_POINTING_INDEX" />
</GlyphOrder>
<head>
@@ -153,6 +154,7 @@
<mtx name="Emoji7" width="500" lsb="93"/>
<mtx name="Emoji8" width="500" lsb="93"/>
<mtx name="Emoji9" width="500" lsb="93"/>
+ <mtx name="WHITE_UP_POINTING_INDEX" width="500" lsb="93"/>
</hmtx>
<cmap>
@@ -163,6 +165,7 @@
<map code="0x231A" name="Emoji5" /> <!-- Emoji Default -->
<map code="0x23E9" name="Emoji7" /> <!-- Emoji Default -->
<map code="0x26FA" name="Emoji9" /> <!-- U+26FA U+FE0E is in ColorTextMixedEmojiFont.ttf -->
+ <map code="0x261D" name="WHITE_UP_POINTING_INDEX" />
</cmap_format_4>
</cmap>
@@ -206,6 +209,9 @@
<TTGlyph name="Emoji9" xMin="0" yMin="0" xMax="0" yMax="0">
<contour></contour><instructions><assembly></assembly></instructions>
</TTGlyph>
+ <TTGlyph name="WHITE_UP_POINTING_INDEX" xMin="0" yMin="0" xMax="0" yMax="0">
+ <contour></contour><instructions><assembly></assembly></instructions>
+ </TTGlyph>
</glyf>
<name>
diff --git a/tests/data/emoji.xml b/tests/data/emoji.xml
index a908b46..796a0f1 100644
--- a/tests/data/emoji.xml
+++ b/tests/data/emoji.xml
@@ -19,12 +19,12 @@
<family>
<font weight="400" style="normal">NoGlyphFont.ttf</font>
</family>
- <family lang="und-Zsye">
- <font weight="400" style="normal">ColorEmojiFont.ttf</font>
- </family>
<family>
<font weight="400" style="normal">TextEmojiFont.ttf</font>
</family>
+ <family lang="und-Zsye">
+ <font weight="400" style="normal">ColorEmojiFont.ttf</font>
+ </family>
<family>
<font weight="400" style="normal">ColorTextMixedEmojiFont.ttf</font>
</family>