LibWeb: Apply the font-variant-emoji property to font selection
This commit is contained in:
parent
57103da08d
commit
360bfd66f6
8 changed files with 58 additions and 1 deletions
|
|
@ -182,6 +182,7 @@ public:
|
|||
static CursorData cursor() { return { CursorPredefined::Auto }; }
|
||||
static WhiteSpaceCollapse white_space_collapse() { return WhiteSpaceCollapse::Collapse; }
|
||||
static WordBreak word_break() { return WordBreak::Normal; }
|
||||
static FontVariantEmoji font_variant_emoji() { return FontVariantEmoji::Normal; }
|
||||
static CSSPixels word_spacing() { return 0; }
|
||||
static CSSPixels letter_spacing() { return 0; }
|
||||
static Variant<Length, double> tab_size() { return 8; }
|
||||
|
|
@ -574,6 +575,7 @@ public:
|
|||
WhiteSpaceCollapse white_space_collapse() const { return m_inherited.white_space_collapse; }
|
||||
WhiteSpaceTrimData white_space_trim() const { return m_noninherited.white_space_trim; }
|
||||
WordBreak word_break() const { return m_inherited.word_break; }
|
||||
FontVariantEmoji font_variant_emoji() const { return m_inherited.font_variant_emoji; }
|
||||
CSSPixels const& word_spacing() const { return m_inherited.word_spacing; }
|
||||
CSSPixels letter_spacing() const { return m_inherited.letter_spacing; }
|
||||
FlexDirection flex_direction() const { return m_noninherited.flex_direction; }
|
||||
|
|
@ -805,6 +807,7 @@ protected:
|
|||
CSSPixels text_underline_offset { InitialValues::text_underline_offset() };
|
||||
WhiteSpaceCollapse white_space_collapse { InitialValues::white_space_collapse() };
|
||||
WordBreak word_break { InitialValues::word_break() };
|
||||
FontVariantEmoji font_variant_emoji { InitialValues::font_variant_emoji() };
|
||||
ListStylePosition list_style_position { InitialValues::list_style_position() };
|
||||
Visibility visibility { InitialValues::visibility() };
|
||||
CSSPixels word_spacing { InitialValues::word_spacing() };
|
||||
|
|
@ -1027,6 +1030,7 @@ public:
|
|||
void set_white_space_trim(WhiteSpaceTrimData value) { m_noninherited.white_space_trim = value; }
|
||||
void set_word_spacing(CSSPixels value) { m_inherited.word_spacing = value; }
|
||||
void set_word_break(WordBreak value) { m_inherited.word_break = value; }
|
||||
void set_font_variant_emoji(FontVariantEmoji value) { m_inherited.font_variant_emoji = value; }
|
||||
void set_letter_spacing(CSSPixels value) { m_inherited.letter_spacing = value; }
|
||||
void set_width(Size const& width) { m_noninherited.width = width; }
|
||||
void set_min_width(Size const& width) { m_noninherited.min_width = width; }
|
||||
|
|
|
|||
|
|
@ -709,6 +709,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
|
|||
computed_values.set_font_size(computed_style.font_size());
|
||||
computed_values.set_font_weight(computed_style.font_weight());
|
||||
computed_values.set_line_height(computed_style.line_height());
|
||||
computed_values.set_font_variant_emoji(computed_style.font_variant_emoji());
|
||||
|
||||
// NOTE: color must be set after color-scheme to ensure currentColor can be resolved in other properties (e.g. background-color).
|
||||
// NOTE: color must be set after font_size as `CalculatedStyleValue`s can rely on it being set for resolving lengths.
|
||||
|
|
|
|||
|
|
@ -513,6 +513,7 @@ TextNode::ChunkList const& TextNode::chunks_for_layout(bool should_wrap_lines, b
|
|||
.should_respect_linebreaks = should_respect_linebreaks,
|
||||
.white_space_collapse = computed_values.white_space_collapse(),
|
||||
.word_break = computed_values.word_break(),
|
||||
.font_variant_emoji = computed_values.font_variant_emoji(),
|
||||
.font_cascade_list = computed_values.font_list(),
|
||||
};
|
||||
|
||||
|
|
@ -558,6 +559,7 @@ TextNode::ChunkIterator::ChunkIterator(TextNode const& text_node, Utf16View cons
|
|||
, m_grapheme_segmenter(grapheme_segmenter)
|
||||
, m_line_segmenter(line_segmenter)
|
||||
, m_word_break(word_break)
|
||||
, m_font_variant_emoji(text_node.computed_values().font_variant_emoji())
|
||||
{
|
||||
m_should_collapse_whitespace = first_is_one_of(text_node.computed_values().white_space_collapse(), CSS::WhiteSpaceCollapse::Collapse, CSS::WhiteSpaceCollapse::PreserveBreaks);
|
||||
}
|
||||
|
|
@ -778,7 +780,22 @@ Gfx::EmojiPresentationResult TextNode::ChunkIterator::emoji_presentation_at(size
|
|||
if (next_offset < m_view.length_in_code_units())
|
||||
next_code_point = m_view.code_point_at(next_offset);
|
||||
|
||||
return Gfx::emoji_presentation_for_code_point(code_point, next_code_point);
|
||||
auto default_presentation = Gfx::emoji_presentation_for_code_point(code_point, next_code_point);
|
||||
|
||||
if (default_presentation.forced == Gfx::ForcedPresentation::Yes || !Unicode::code_point_has_emoji_property(code_point))
|
||||
return default_presentation;
|
||||
|
||||
switch (m_font_variant_emoji) {
|
||||
case CSS::FontVariantEmoji::Text:
|
||||
return { Gfx::EmojiPresentation::Text, Gfx::ForcedPresentation::Yes };
|
||||
case CSS::FontVariantEmoji::Emoji:
|
||||
return { Gfx::EmojiPresentation::Emoji, Gfx::ForcedPresentation::Yes };
|
||||
case CSS::FontVariantEmoji::Unicode:
|
||||
return { default_presentation.presentation, Gfx::ForcedPresentation::Yes };
|
||||
case CSS::FontVariantEmoji::Normal:
|
||||
return default_presentation;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
Optional<TextNode::Chunk> TextNode::ChunkIterator::next_without_peek()
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ public:
|
|||
Unicode::Segmenter& m_grapheme_segmenter;
|
||||
Unicode::Segmenter& m_line_segmenter;
|
||||
CSS::WordBreak m_word_break;
|
||||
CSS::FontVariantEmoji m_font_variant_emoji;
|
||||
size_t m_current_index { 0 };
|
||||
|
||||
Vector<Chunk> m_peek_queue;
|
||||
|
|
@ -130,6 +131,7 @@ private:
|
|||
bool should_respect_linebreaks { false };
|
||||
CSS::WhiteSpaceCollapse white_space_collapse { CSS::WhiteSpaceCollapse::Collapse };
|
||||
CSS::WordBreak word_break { CSS::WordBreak::Normal };
|
||||
CSS::FontVariantEmoji font_variant_emoji { CSS::FontVariantEmoji::Normal };
|
||||
RefPtr<Gfx::FontCascadeList const> font_cascade_list;
|
||||
|
||||
bool operator==(ChunkCacheKey const&) const = default;
|
||||
|
|
|
|||
BIN
Tests/LibWeb/Ref/data/fonts/NotoColorEmoji-Regular_subset.ttf
Normal file
BIN
Tests/LibWeb/Ref/data/fonts/NotoColorEmoji-Regular_subset.ttf
Normal file
Binary file not shown.
BIN
Tests/LibWeb/Ref/data/fonts/NotoEmoji-Regular_subset.ttf
Normal file
BIN
Tests/LibWeb/Ref/data/fonts/NotoEmoji-Regular_subset.ttf
Normal file
Binary file not shown.
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: ColorEmojiFont;
|
||||
src: url("../data/fonts/NotoColorEmoji-Regular_subset.ttf");
|
||||
}
|
||||
@font-face {
|
||||
font-family: MonoEmojiFont;
|
||||
src: url("../data/fonts/NotoEmoji-Regular_subset.ttf");
|
||||
}
|
||||
div { font: 48px serif; }
|
||||
</style>
|
||||
<div style="font-family: MonoEmojiFont; font-variant-emoji: text">ℹ</div>
|
||||
<div style="font-family: ColorEmojiFont; font-variant-emoji: emoji">ℹ</div>
|
||||
<div style="font-family: ColorEmojiFont; font-variant-emoji: emoji">🫨</div>
|
||||
<div style="font-family: MonoEmojiFont; font-variant-emoji: text">🫨</div>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="match" href="../expected/css-font-variant-emoji-presentation-ref.html">
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: ColorEmojiFont;
|
||||
src: url("../data/fonts/NotoColorEmoji-Regular_subset.ttf");
|
||||
}
|
||||
@font-face {
|
||||
font-family: MonoEmojiFont;
|
||||
src: url("../data/fonts/NotoEmoji-Regular_subset.ttf");
|
||||
}
|
||||
div { font: 48px ColorEmojiFont, MonoEmojiFont; }
|
||||
</style>
|
||||
<div style="font-variant-emoji: unicode">ℹ</div>
|
||||
<div style="font-variant-emoji: emoji">ℹ</div>
|
||||
<div style="font-variant-emoji: unicode">🫨</div>
|
||||
<div style="font-variant-emoji: text">🫨</div>
|
||||
Loading…
Reference in a new issue