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:
Seigo Nonaka
2016-02-26 03:22:09 +00:00
committed by android-build-merger
5 changed files with 93 additions and 118 deletions

View File

@@ -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) {

View File

@@ -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

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -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]));
}