| 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..4375944176753e12ecd1f5c6fdc1d7f5c4057baa
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/platform/fonts/SymbolsIterator.cpp
|
| @@ -0,0 +1,156 @@
|
| +// 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 == combiningEnclosingKeycapCharacter
|
| + || codepoint == combiningEnclosingCircleBackslashCharacter)
|
| + 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();
|
| +
|
| + // Except at the beginning, ZWJ just carries over the emoji or neutral
|
| + // text type, VS15 & VS16 we just carry over as well, since we already
|
| + // resolved those through lookahead. Also, the text presentation emoji
|
| + // are upgraded to emoji presentation when combined through ZWJ in the
|
| + // case of example U+1F441 U+200D U+1F5E8, eye + ZWJ + left speech
|
| + // bubble, see below.
|
| + if ((!(m_nextChar == zeroWidthJoinerCharacter
|
| + && m_previousFontFallbackPriority == FontFallbackPriority::EmojiEmoji)
|
| + && m_nextChar != variationSelector15Character
|
| + && m_nextChar != variationSelector16Character
|
| + && !Character::isRegionalIndicator(m_nextChar)
|
| + && !(m_nextChar == leftSpeechBubbleCharacter
|
| + && 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 == combiningEnclosingKeycapCharacter) {
|
| + m_currentFontFallbackPriority = FontFallbackPriority::EmojiEmoji;
|
| + };
|
| +
|
| + // ...and Combining Enclosing Circle Backslash.
|
| + if (m_currentFontFallbackPriority == FontFallbackPriority::EmojiText
|
| + && peekChar == combiningEnclosingCircleBackslashCharacter) {
|
| + 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 == eyeCharacter && 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;
|
| +}
|
| +
|
| +}
|
|
|