Chromium Code Reviews| Index: third_party/WebKit/Source/platform/fonts/SymbolsIterator.cpp |
| diff --git a/third_party/WebKit/Source/platform/fonts/SymbolsIterator.cpp b/third_party/WebKit/Source/platform/fonts/SymbolsIterator.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..475841095274c92d61f8f71c49f706f14ce26bd1 |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/platform/fonts/SymbolsIterator.cpp |
| @@ -0,0 +1,145 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "SymbolsIterator.h" |
| + |
| +#include <unicode/uchar.h> |
| +#include <unicode/uniset.h> |
| + |
| +namespace blink { |
| + |
| +using namespace WTF::Unicode; |
| + |
| +SymbolsIterator::SymbolsIterator(const UChar* buffer, unsigned bufferSize) |
| + : m_utf16Iterator(adoptPtr(new UTF16TextIterator(buffer, bufferSize))) |
| + , m_bufferSize(bufferSize) |
| + , m_nextChar(0) |
| + , m_atEnd(bufferSize == 0) |
| + , m_currentFontFallbackPriority(FontFallbackPriority::Invalid) |
| +{ |
| +} |
| + |
| +FontFallbackPriority SymbolsIterator::fontFallbackPriorityForCharacter(UChar32 codepoint) |
| +{ |
| + |
| + // Those should only be Emoji presentation as combinations of two. |
| + if (Character::isEmojiKeycapBase(codepoint) || Character::isRegionalIndicator(codepoint)) |
| + return FontFallbackPriority::Text; |
| + |
| + if (codepoint == 0x20E3 || codepoint == 0x20E0) |
|
eae
2016/01/22 00:38:32
Could you please add these codepoints to Character
|
| + return FontFallbackPriority::EmojiEmoji; |
| + |
| + // There are overlaps between isEmojiTextpresentation and isEmojiEmojiPresentation. |
| + // We want to prioritize emoji presentation if the character has such a property. |
| + if (Character::isEmojiEmojiPresentation(codepoint) |
| + || Character::isEmojiModifierBase(codepoint) |
| + || Character::isModifier(codepoint)) |
| + return FontFallbackPriority::EmojiEmoji; |
| + |
| + if (Character::isEmojiTextPresentation(codepoint)) |
| + return FontFallbackPriority::EmojiText; |
| + |
| + UBlockCode block = ublock_getCode(codepoint); |
| + |
| + switch (block) { |
| + case UBLOCK_PLAYING_CARDS: |
| + case UBLOCK_MISCELLANEOUS_SYMBOLS: |
| + case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_ARROWS: |
| + case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS: |
| + case UBLOCK_TRANSPORT_AND_MAP_SYMBOLS: |
| + case UBLOCK_ALCHEMICAL_SYMBOLS: |
| + case UBLOCK_RUNIC: |
| + case UBLOCK_DINGBATS: |
| + case UBLOCK_GOTHIC: |
| + return FontFallbackPriority::Symbols; |
| + case UBLOCK_ARROWS: |
| + case UBLOCK_MATHEMATICAL_OPERATORS: |
| + case UBLOCK_MISCELLANEOUS_TECHNICAL: |
| + case UBLOCK_GEOMETRIC_SHAPES: |
| + case UBLOCK_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A: |
| + case UBLOCK_SUPPLEMENTAL_ARROWS_A: |
| + case UBLOCK_SUPPLEMENTAL_ARROWS_B: |
| + case UBLOCK_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B: |
| + case UBLOCK_SUPPLEMENTAL_MATHEMATICAL_OPERATORS: |
| + case UBLOCK_MATHEMATICAL_ALPHANUMERIC_SYMBOLS: |
| + case UBLOCK_ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS: |
| + case UBLOCK_GEOMETRIC_SHAPES_EXTENDED: |
| + return FontFallbackPriority::Math; |
| + default: |
| + return FontFallbackPriority::Text; |
| + } |
| +} |
| + |
| +bool SymbolsIterator::consume(unsigned *symbolsLimit, FontFallbackPriority* fontFallbackPriority) |
| +{ |
| + if (m_atEnd) |
| + return false; |
| + |
| + while (m_utf16Iterator->consume(m_nextChar)) { |
| + m_previousFontFallbackPriority = m_currentFontFallbackPriority; |
| + unsigned iteratorOffset = m_utf16Iterator->offset(); |
| + m_utf16Iterator->advance(); |
| + |
| + // ZWJ just carries over the emoji or neutral text type, VS15 & VS16 we just carry over as well, since we |
| + // are resolved those through lookahead - except at the beginning. |
| + // Also, the text presentation Keep ZWJ joiner pairs in Emoji presentation. See below. |
| + // Example U+1F441 U+200D U+1F5E8, eye + ZWJ + left speech bubble |
| + if ((!(m_nextChar == zeroWidthJoinerCharacter && m_previousFontFallbackPriority == FontFallbackPriority::EmojiEmoji) |
| + && m_nextChar != variationSelector15Character |
| + && m_nextChar != variationSelector16Character |
| + && !Character::isRegionalIndicator(m_nextChar) |
| + && !(m_nextChar == 0x1F5E8 && m_previousFontFallbackPriority == FontFallbackPriority::EmojiEmoji)) |
| + || m_currentFontFallbackPriority == FontFallbackPriority::Invalid) { |
| + m_currentFontFallbackPriority = fontFallbackPriorityForCharacter(m_nextChar); |
| + } |
| + |
| + UChar32 peekChar = 0; |
| + if (m_utf16Iterator->consume(peekChar) |
| + && peekChar != 0) { |
| + |
| + // Variation Selectors |
| + if (m_currentFontFallbackPriority == FontFallbackPriority::EmojiEmoji && peekChar == variationSelector15Character) { |
| + m_currentFontFallbackPriority = FontFallbackPriority::EmojiText; |
| + } |
| + |
| + if (m_currentFontFallbackPriority == FontFallbackPriority::EmojiText && peekChar == variationSelector16Character) { |
| + m_currentFontFallbackPriority = FontFallbackPriority::EmojiEmoji; |
| + } |
| + |
| + // Combining characters Keycap... |
| + if (Character::isEmojiKeycapBase(m_nextChar) && peekChar == 0x20E3) { |
| + m_currentFontFallbackPriority = FontFallbackPriority::EmojiEmoji; |
| + }; |
| + |
| + // ...and Combining Enclosing Circle Backslash. |
| + if (m_currentFontFallbackPriority == FontFallbackPriority::EmojiText && peekChar == 0x20E0) { |
| + m_currentFontFallbackPriority = FontFallbackPriority::EmojiEmoji; |
| + } |
| + |
| + // Regional indicators |
| + if (Character::isRegionalIndicator(m_nextChar) && Character::isRegionalIndicator(peekChar)) { |
| + m_currentFontFallbackPriority = FontFallbackPriority::EmojiEmoji; |
| + } |
| + |
| + // Upgrade text presentation emoji to emoji presentation when followed by ZWJ, |
| + // Example U+1F441 U+200D U+1F5E8, eye + ZWJ + left speech bubble |
| + if (m_nextChar == 0x1F441 && peekChar == zeroWidthJoinerCharacter) { |
| + m_currentFontFallbackPriority = FontFallbackPriority::EmojiEmoji; |
| + } |
| + } |
| + |
| + if (m_previousFontFallbackPriority != m_currentFontFallbackPriority |
| + && (m_previousFontFallbackPriority != FontFallbackPriority::Invalid)) { |
| + *symbolsLimit = iteratorOffset; |
| + *fontFallbackPriority = m_previousFontFallbackPriority; |
| + return true; |
| + } |
| + } |
| + *symbolsLimit = m_bufferSize; |
| + *fontFallbackPriority = m_currentFontFallbackPriority; |
| + m_atEnd = true; |
| + return true; |
| +} |
| + |
| +} |