FontCairoHarfbuzzNG.cpp [plain text]
#include "config.h"
#include "FontCascade.h"
#if USE(CAIRO)
#include "CharacterProperties.h"
#include "FontCache.h"
#include "SurrogatePairAwareTextIterator.h"
namespace WebCore {
bool FontCascade::canReturnFallbackFontsForComplexText()
{
return false;
}
bool FontCascade::canExpandAroundIdeographsInComplexText()
{
return false;
}
static bool characterSequenceIsEmoji(SurrogatePairAwareTextIterator& iterator, UChar32 firstCharacter, unsigned firstClusterLength)
{
UChar32 character = firstCharacter;
unsigned clusterLength = firstClusterLength;
if (!iterator.consume(character, clusterLength))
return false;
if (isEmojiKeycapBase(character)) {
iterator.advance(clusterLength);
UChar32 nextCharacter;
if (!iterator.consume(nextCharacter, clusterLength))
return false;
if (nextCharacter == combiningEnclosingKeycap)
return true;
if (nextCharacter == 0xFE0F) {
iterator.advance(clusterLength);
if (!iterator.consume(nextCharacter, clusterLength))
return false;
if (nextCharacter == combiningEnclosingKeycap)
return true;
}
return false;
}
if (isEmojiRegionalIndicator(character)) {
iterator.advance(clusterLength);
UChar32 nextCharacter;
if (!iterator.consume(nextCharacter, clusterLength))
return false;
if (isEmojiRegionalIndicator(nextCharacter))
return true;
return false;
}
if (character == combiningEnclosingKeycap)
return true;
if (isEmojiWithPresentationByDefault(character)
|| isEmojiModifierBase(character)
|| isEmojiFitzpatrickModifier(character))
return true;
return false;
}
const Font* FontCascade::fontForCombiningCharacterSequence(const UChar* originalCharacters, size_t originalLength) const
{
auto normalizedString = normalizedNFC(StringView { originalCharacters, static_cast<unsigned>(originalLength) });
auto characters = normalizedString.view.characters16();
auto length = normalizedString.view.length();
UChar32 character;
unsigned clusterLength = 0;
SurrogatePairAwareTextIterator iterator(characters, 0, length, length);
if (!iterator.consume(character, clusterLength))
return nullptr;
bool isEmoji = characterSequenceIsEmoji(iterator, character, clusterLength);
bool preferColoredFont = isEmoji;
if (characters[length - 1] == 0xFE0E)
preferColoredFont = false;
else if (characters[length - 1] == 0xFE0F)
preferColoredFont = true;
const Font* baseFont = glyphDataForCharacter(character, false, NormalVariant).font;
if (baseFont
&& (clusterLength == length || baseFont->canRenderCombiningCharacterSequence(characters, length))
&& (!preferColoredFont || baseFont->platformData().isColorBitmapFont()))
return baseFont;
for (unsigned i = 0; !fallbackRangesAt(i).isNull(); ++i) {
const Font* fallbackFont = fallbackRangesAt(i).fontForCharacter(character);
if (!fallbackFont || fallbackFont == baseFont)
continue;
if (fallbackFont->canRenderCombiningCharacterSequence(characters, length) && (!preferColoredFont || fallbackFont->platformData().isColorBitmapFont()))
return fallbackFont;
}
if (auto systemFallback = FontCache::singleton().systemFallbackForCharacters(m_fontDescription, baseFont, IsForPlatformFont::No, preferColoredFont ? FontCache::PreferColoredFont::Yes : FontCache::PreferColoredFont::No, characters, length)) {
if (systemFallback->canRenderCombiningCharacterSequence(characters, length) && (!preferColoredFont || systemFallback->platformData().isColorBitmapFont()))
return systemFallback.get();
if (isEmoji && characters[length - 1] == 0xFE0F && systemFallback->platformData().isColorBitmapFont() && systemFallback->canRenderCombiningCharacterSequence(characters, length - 1))
return systemFallback.get();
}
return baseFont;
}
}
#endif // USE(CAIRO)