Use color font if skin tone is specified.
am: b7d66e3db0
* commit 'b7d66e3db0473ace4ddfd3b553c4e9796e49c410':
Use color font if skin tone is specified.
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user