LibWeb: Store correct text offsets in PaintableFragment
Some checks are pending
CI / macOS, arm64, Sanitizer, Clang (push) Waiting to run
CI / Linux, x86_64, Fuzzers, Clang (push) Waiting to run
CI / Linux, x86_64, Sanitizer, GNU (push) Waiting to run
CI / Linux, x86_64, Sanitizer, Clang (push) Waiting to run
Package the js repl as a binary artifact / Linux, arm64 (push) Waiting to run
Package the js repl as a binary artifact / macOS, arm64 (push) Waiting to run
Package the js repl as a binary artifact / Linux, x86_64 (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run

Previously, we were collapsing whitespace in Layout::TextNode and then
passed the resulting string for further processing through ChunkIterator
-> InlineLevelIterator -> InlineFormattingContext -> LineBuilder ->
LineBoxFragment -> PaintableFragment. Our painting tree is where we deal
with things like range offsets into the underlying text nodes, but since
we modified the original string, the offsets were wrong.

This changes the way we generate fragments:

  * Layout::TextNode no longer collapses whitespace as part of its
    stored "text for rendering", but moves this logic to ChunkIterator
    which splits up this text into separate views whenever whitespace
    needs to be collapsed.

  * Layout::LineBox now only extends the last fragment if its end offset
    is equal to the new fragment's start offset. Otherwise, there's a
    gap caused by collapsing whitespace and we need to generate a
    separate fragment for that in order to have a correct start offset.

Some tests need new baselines because of the fixed start offsets.

Fixes #566.
This commit is contained in:
Jelle Raaijmakers 2025-09-12 10:06:27 +02:00 committed by Tim Flynn
commit 9e9db9a9dd
Notes: github-actions[bot] 2025-09-12 19:35:11 +00:00
50 changed files with 386 additions and 298 deletions

View file

@ -389,20 +389,17 @@ void dump_tree(StringBuilder& builder, Layout::Node const& layout_node, bool sho
fragment.length_in_code_units(),
fragment.absolute_rect(),
fragment.baseline());
if (is<Layout::TextNode>(fragment.layout_node())) {
if (fragment.length_in_code_units() > 0) {
builder.append_repeated(" "sv, indent);
auto const& layout_text = static_cast<Layout::TextNode const&>(fragment.layout_node());
auto fragment_text = layout_text.text_for_rendering().substring_view(fragment.start_offset(), fragment.length_in_code_units());
builder.appendff(" \"{}\"\n", fragment_text);
builder.appendff(" \"{}\"\n", fragment.text());
}
};
if (is<Layout::BlockContainer>(layout_node) && static_cast<Layout::BlockContainer const&>(layout_node).children_are_inline()) {
auto& block = static_cast<Layout::BlockContainer const&>(layout_node);
for (size_t fragment_index = 0; block.paintable_with_lines() && fragment_index < block.paintable_with_lines()->fragments().size(); ++fragment_index) {
auto const& fragment = block.paintable_with_lines()->fragments()[fragment_index];
dump_fragment(fragment, fragment_index);
}
if (auto const* block_container = as_if<Layout::BlockContainer>(layout_node);
block_container && block_container->children_are_inline() && block_container->paintable_with_lines()) {
size_t fragment_index = 0;
for (auto const& fragment : block_container->paintable_with_lines()->fragments())
dump_fragment(fragment, fragment_index++);
}
if (is<Layout::InlineNode>(layout_node) && layout_node.first_paintable()) {

View file

@ -318,7 +318,8 @@ struct RequiredLineBreakCount {
// https://html.spec.whatwg.org/multipage/dom.html#rendered-text-collection-steps
static Vector<Variant<Utf16String, RequiredLineBreakCount>> rendered_text_collection_steps(DOM::Node const& node)
{
// 1. Let items be the result of running the rendered text collection steps with each child node of node in tree order, and then concatenating the results to a single list.
// 1. Let items be the result of running the rendered text collection steps with each child node of node in tree
// order, and then concatenating the results to a single list.
Vector<Variant<Utf16String, RequiredLineBreakCount>> items;
node.for_each_child([&](auto const& child) {
auto child_items = rendered_text_collection_steps(child);
@ -348,18 +349,22 @@ static Vector<Variant<Utf16String, RequiredLineBreakCount>> rendered_text_collec
if (computed_values.content_visibility() == CSS::ContentVisibility::Hidden)
return items;
// 4. If node is a Text node, then for each CSS text box produced by node, in content order,
// compute the text of the box after application of the CSS 'white-space' processing rules
// and 'text-transform' rules, set items to the list of the resulting strings, and return items.
// 4. If node is a Text node, then for each CSS text box produced by node, in content order, compute the text of the
// box after application of the CSS 'white-space' processing rules and 'text-transform' rules, set items to the
// list of the resulting strings, and return items.
// FIXME: The CSS 'white-space' processing rules are slightly modified:
// collapsible spaces at the end of lines are always collapsed,
// but they are only removed if the line is the last line of the block,
// or it ends with a br element. Soft hyphens should be preserved. [CSSTEXT]
// FIXME: The CSS 'white-space' processing rules are slightly modified: collapsible spaces at the end of lines are
// always collapsed, but they are only removed if the line is the last line of the block, or it ends with a br
// element. Soft hyphens should be preserved. [CSSTEXT]
if (is<DOM::Text>(node)) {
auto const* layout_text_node = as<Layout::TextNode>(layout_node);
items.append(layout_text_node->text_for_rendering());
if (auto const* layout_text_node = as_if<Layout::TextNode>(layout_node)) {
Layout::TextNode::ChunkIterator iterator { *layout_text_node, false, false };
while (true) {
auto chunk = iterator.next();
if (!chunk.has_value())
break;
items.append(Utf16String::from_utf16(chunk.release_value().view));
}
return items;
}
@ -430,9 +435,8 @@ Utf16String HTMLElement::get_the_text_steps()
while (!results.is_empty() && results.last().has<RequiredLineBreakCount>())
results.take_last();
// 6. Replace each remaining run of consecutive required line break count items
// with a string consisting of as many U+000A LF code points as the maximum of the values
// in the required line break count items.
// 6. Replace each remaining run of consecutive required line break count items with a string consisting of as many
// U+000A LF code points as the maximum of the values in the required line break count items.
StringBuilder builder(StringBuilder::Mode::UTF16);
for (size_t i = 0; i < results.size(); ++i) {
results[i].visit(

View file

@ -341,8 +341,7 @@ void InlineFormattingContext::generate_line_boxes()
next_width = iterator.next_non_whitespace_sequence_width();
}
// If whitespace caused us to break, we swallow the whitespace instead of
// putting it on the next line.
// If whitespace caused us to break, we swallow the whitespace instead of putting it on the next line.
if (is_whitespace && next_width > 0 && line_builder.break_if_needed(item.border_box_width() + next_width))
break;
} else if (text_node.computed_values().text_overflow() == CSS::TextOverflow::Ellipsis

View file

@ -490,11 +490,9 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead(
if (!m_current_node)
return {};
if (is<Layout::TextNode>(*m_current_node)) {
auto& text_node = static_cast<Layout::TextNode const&>(*m_current_node);
if (auto* text_node = as_if<Layout::TextNode>(*m_current_node)) {
if (!m_text_node_context.has_value())
enter_text_node(text_node);
enter_text_node(*text_node);
auto chunk_opt = m_text_node_context->chunk_iterator.next();
if (!chunk_opt.has_value()) {
@ -511,7 +509,8 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead(
if (text_type == Gfx::GlyphRun::TextType::Ltr || text_type == Gfx::GlyphRun::TextType::Rtl)
m_text_node_context->last_known_direction = text_type;
if (m_text_node_context->do_respect_linebreaks && chunk.has_breaking_newline) {
auto do_respect_linebreak = m_text_node_context->chunk_iterator.should_respect_linebreaks();
if (do_respect_linebreak && chunk.has_breaking_newline) {
m_text_node_context->is_last_chunk = true;
if (chunk.is_all_whitespace)
text_type = Gfx::GlyphRun::TextType::EndPadding;
@ -520,15 +519,12 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead(
if (text_type == Gfx::GlyphRun::TextType::ContextDependent)
text_type = resolve_text_direction_from_context();
if (m_text_node_context->do_respect_linebreaks && chunk.has_breaking_newline) {
return Item {
.type = Item::Type::ForcedBreak,
};
}
if (do_respect_linebreak && chunk.has_breaking_newline)
return Item { .type = Item::Type::ForcedBreak };
auto letter_spacing = text_node.computed_values().letter_spacing();
auto letter_spacing = text_node->computed_values().letter_spacing();
// FIXME: We should apply word spacing to all word-separator characters not just breaking tabs
auto word_spacing = text_node.computed_values().word_spacing();
auto word_spacing = text_node->computed_values().word_spacing();
auto x = 0.0f;
if (chunk.has_breaking_tab) {
@ -541,13 +537,13 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead(
}
// https://drafts.csswg.org/css-text/#tab-size-property
CSS::CalculationResolutionContext calculation_context { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(text_node) };
auto tab_size = text_node.computed_values().tab_size();
CSS::CalculationResolutionContext calculation_context { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*text_node) };
auto tab_size = text_node->computed_values().tab_size();
CSSPixels tab_width;
tab_width = tab_size.visit(
[&](CSS::LengthOrCalculated const& t) -> CSSPixels {
return t.resolved(calculation_context)
.map([&](auto& it) { return it.to_px(text_node); })
.map([&](auto& it) { return it.to_px(*text_node); })
.value_or(0);
},
[&](CSS::NumberOrCalculated const& n) -> CSSPixels {
@ -585,16 +581,17 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead(
CSSPixels chunk_width = CSSPixels::nearest_value_for(glyph_run->width() + x);
// NOTE: We never consider `content: ""` to be collapsible whitespace.
bool is_generated_empty_string = text_node.is_generated() && chunk.length == 0;
bool is_generated_empty_string = text_node->is_generated() && chunk.length == 0;
auto collapse_whitespace = m_text_node_context->chunk_iterator.should_collapse_whitespace();
Item item {
.type = Item::Type::Text,
.node = &text_node,
.node = text_node,
.glyph_run = move(glyph_run),
.offset_in_node = chunk.start,
.length_in_node = chunk.length,
.width = chunk_width,
.is_collapsible_whitespace = m_text_node_context->do_collapse && chunk.is_all_whitespace && !is_generated_empty_string,
.is_collapsible_whitespace = collapse_whitespace && chunk.is_all_whitespace && !is_generated_empty_string,
};
add_extra_box_model_metrics_to_item(item, m_text_node_context->is_first_chunk, m_text_node_context->is_last_chunk);
@ -671,17 +668,11 @@ void InlineLevelIterator::enter_text_node(Layout::TextNode const& text_node)
auto white_space_collapse = text_node.computed_values().white_space_collapse();
auto text_wrap_mode = text_node.computed_values().text_wrap_mode();
bool do_collapse = white_space_collapse == CSS::WhiteSpaceCollapse::Collapse || white_space_collapse == CSS::WhiteSpaceCollapse::PreserveBreaks;
// https://drafts.csswg.org/css-text-4/#collapse
bool do_wrap_lines = text_wrap_mode == CSS::TextWrapMode::Wrap;
bool do_respect_linebreaks = white_space_collapse == CSS::WhiteSpaceCollapse::Preserve || white_space_collapse == CSS::WhiteSpaceCollapse::PreserveBreaks || white_space_collapse == CSS::WhiteSpaceCollapse::BreakSpaces;
if (text_node.dom_node().is_editable() && !text_node.dom_node().is_uninteresting_whitespace_node())
do_collapse = false;
bool do_respect_linebreaks = first_is_one_of(white_space_collapse, CSS::WhiteSpaceCollapse::Preserve, CSS::WhiteSpaceCollapse::PreserveBreaks, CSS::WhiteSpaceCollapse::BreakSpaces);
m_text_node_context = TextNodeContext {
.do_collapse = do_collapse,
.do_wrap_lines = do_wrap_lines,
.do_respect_linebreaks = do_respect_linebreaks,
.is_first_chunk = true,
.is_last_chunk = false,
.chunk_iterator = TextNode::ChunkIterator { text_node, do_wrap_lines, do_respect_linebreaks },

View file

@ -81,9 +81,6 @@ private:
LayoutMode const m_layout_mode;
struct TextNodeContext {
bool do_collapse {};
bool do_wrap_lines {};
bool do_respect_linebreaks {};
bool is_first_chunk {};
bool is_last_chunk {};
TextNode::ChunkIterator chunk_iterator;

View file

@ -289,7 +289,7 @@ void LayoutState::commit(Box& root)
if (auto* paintable_with_lines = as_if<Painting::PaintableWithLines>(*paintable_box)) {
for (size_t line_index = 0; line_index < used_values.line_boxes.size(); ++line_index) {
auto& line_box = used_values.line_boxes[line_index];
for (auto& fragment : line_box.fragments()) {
for (auto const& fragment : line_box.fragments()) {
if (auto const* text_node = as_if<TextNode>(fragment.layout_node()))
text_nodes.set(const_cast<TextNode*>(text_node));
auto did_relocate_fragment = try_to_relocate_fragment_in_inline_node(fragment, line_index);

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2025, Jelle Raaijmakers <jelle@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -35,18 +36,24 @@ CSSPixels LineBox::bottom() const
return m_bottom;
}
void LineBox::add_fragment(Node const& layout_node, size_t start, size_t length, CSSPixels leading_size, CSSPixels trailing_size, CSSPixels leading_margin, CSSPixels trailing_margin, CSSPixels content_width, CSSPixels content_height, CSSPixels border_box_top, CSSPixels border_box_bottom, RefPtr<Gfx::GlyphRun> glyph_run)
void LineBox::add_fragment(Node const& layout_node, size_t start, size_t length, CSSPixels leading_size,
CSSPixels trailing_size, CSSPixels leading_margin, CSSPixels trailing_margin, CSSPixels content_width,
CSSPixels content_height, CSSPixels border_box_top, CSSPixels border_box_bottom, RefPtr<Gfx::GlyphRun> glyph_run)
{
bool text_align_is_justify = layout_node.computed_values().text_align() == CSS::TextAlign::Justify;
if (glyph_run && !text_align_is_justify && !m_fragments.is_empty() && &m_fragments.last().layout_node() == &layout_node && &m_fragments.last().m_glyph_run->font() == &glyph_run->font()) {
if (glyph_run && !text_align_is_justify && !m_fragments.is_empty()
&& &m_fragments.last().layout_node() == &layout_node
&& &m_fragments.last().m_glyph_run->font() == &glyph_run->font()
&& m_fragments.last().start() + m_fragments.last().length_in_code_units() == start) {
// The fragment we're adding is from the last Layout::Node on the line.
// Expand the last fragment instead of adding a new one with the same Layout::Node.
m_fragments.last().m_length = (start - m_fragments.last().m_start) + length;
m_fragments.last().m_length_in_code_units += length;
m_fragments.last().append_glyph_run(glyph_run, content_width);
} else {
CSSPixels inline_offset = leading_margin + leading_size + m_inline_length;
CSSPixels block_offset = 0;
m_fragments.append(LineBoxFragment { layout_node, start, length, inline_offset, block_offset, content_width, content_height, border_box_top, m_direction, m_writing_mode, move(glyph_run) });
m_fragments.append(LineBoxFragment { layout_node, start, length, inline_offset, block_offset, content_width,
content_height, border_box_top, m_direction, m_writing_mode, move(glyph_run) });
}
m_inline_length += leading_margin + leading_size + content_width + trailing_size + trailing_margin;
m_block_length = max(m_block_length, content_height + border_box_top + border_box_bottom);
@ -68,8 +75,7 @@ CSSPixels LineBox::calculate_or_trim_trailing_whitespace(RemoveTrailingWhitespac
return whitespace_width;
last_fragment = &m_fragments[--fragment_index];
auto const* dom_node = last_fragment->layout_node().dom_node();
if (dom_node) {
if (auto const* dom_node = last_fragment->layout_node().dom_node()) {
auto cursor_position = dom_node->document().cursor_position();
if (cursor_position && cursor_position->node() == dom_node)
return whitespace_width;
@ -90,9 +96,9 @@ CSSPixels LineBox::calculate_or_trim_trailing_whitespace(RemoveTrailingWhitespac
if (last_text.is_null())
return whitespace_width;
size_t last_fragment_length = last_fragment->length();
while (last_fragment_length) {
auto last_character = last_text.code_unit_at(--last_fragment_length);
size_t last_text_length = last_text.length_in_code_units();
while (last_text_length) {
auto last_character = last_text.code_unit_at(--last_text_length);
if (!is_ascii_space(last_character))
break;
@ -100,7 +106,7 @@ CSSPixels LineBox::calculate_or_trim_trailing_whitespace(RemoveTrailingWhitespac
int last_character_width = font.glyph_width(last_character);
whitespace_width += last_character_width;
if (should_remove == RemoveTrailingWhitespace::Yes) {
last_fragment->m_length -= 1;
--last_fragment->m_length_in_code_units;
last_fragment->set_inline_length(last_fragment->inline_length() - last_character_width);
m_inline_length -= last_character_width;
}

View file

@ -12,10 +12,12 @@
namespace Web::Layout {
LineBoxFragment::LineBoxFragment(Node const& layout_node, size_t start, size_t length, CSSPixels inline_offset, CSSPixels block_offset, CSSPixels inline_length, CSSPixels block_length, CSSPixels border_box_top, CSS::Direction direction, CSS::WritingMode writing_mode, RefPtr<Gfx::GlyphRun> glyph_run)
LineBoxFragment::LineBoxFragment(Node const& layout_node, size_t start, size_t length_in_code_units,
CSSPixels inline_offset, CSSPixels block_offset, CSSPixels inline_length, CSSPixels block_length,
CSSPixels border_box_top, CSS::Direction direction, CSS::WritingMode writing_mode, RefPtr<Gfx::GlyphRun> glyph_run)
: m_layout_node(layout_node)
, m_start(start)
, m_length(length)
, m_length_in_code_units(length_in_code_units)
, m_inline_offset(inline_offset)
, m_block_offset(block_offset)
, m_inline_length(inline_length)
@ -48,10 +50,9 @@ CSSPixelSize LineBoxFragment::size() const
bool LineBoxFragment::ends_in_whitespace() const
{
auto text = this->text();
if (text.is_empty())
if (m_length_in_code_units == 0)
return false;
return is_ascii_space(text.code_unit_at(text.length_in_code_units() - 1));
return is_ascii_space(text().code_unit_at(m_length_in_code_units - 1));
}
bool LineBoxFragment::is_justifiable_whitespace() const
@ -62,7 +63,7 @@ bool LineBoxFragment::is_justifiable_whitespace() const
Utf16View LineBoxFragment::text() const
{
if (auto* text_node = as_if<TextNode>(layout_node()))
return text_node->text_for_rendering().substring_view(m_start, m_length);
return text_node->text_for_rendering().substring_view(m_start, m_length_in_code_units);
return {};
}

View file

@ -22,7 +22,7 @@ public:
Node const& layout_node() const { return m_layout_node; }
size_t start() const { return m_start; }
size_t length() const { return m_length; }
size_t length_in_code_units() const { return m_length_in_code_units; }
CSSPixelPoint offset() const;
CSSPixels inline_offset() const { return m_inline_offset; }
@ -61,7 +61,7 @@ private:
GC::Ref<Node const> m_layout_node;
size_t m_start { 0 };
size_t m_length { 0 };
size_t m_length_in_code_units { 0 };
CSSPixels m_inline_offset;
CSSPixels m_block_offset;
CSSPixels m_inline_length;

View file

@ -86,7 +86,8 @@ void LineBuilder::append_box(Box const& box, CSSPixels leading_size, CSSPixels t
{
auto& box_state = m_layout_state.get_mutable(box);
auto& line_box = ensure_last_line_box();
line_box.add_fragment(box, 0, 0, leading_size, trailing_size, leading_margin, trailing_margin, box_state.content_width(), box_state.content_height(), box_state.border_box_top(), box_state.border_box_bottom());
line_box.add_fragment(box, 0, 0, leading_size, trailing_size, leading_margin, trailing_margin,
box_state.content_width(), box_state.content_height(), box_state.border_box_top(), box_state.border_box_bottom());
m_max_height_on_current_line = max(m_max_height_on_current_line, box_state.margin_box_height());
box_state.containing_line_box_fragment = LineBoxFragmentCoordinate {
@ -98,7 +99,8 @@ void LineBuilder::append_box(Box const& box, CSSPixels leading_size, CSSPixels t
void LineBuilder::append_text_chunk(TextNode const& text_node, size_t offset_in_node, size_t length_in_node, CSSPixels leading_size, CSSPixels trailing_size, CSSPixels leading_margin, CSSPixels trailing_margin, CSSPixels content_width, CSSPixels content_height, RefPtr<Gfx::GlyphRun> glyph_run)
{
auto& line_box = ensure_last_line_box();
line_box.add_fragment(text_node, offset_in_node, length_in_node, leading_size, trailing_size, leading_margin, trailing_margin, content_width, content_height, 0, 0, move(glyph_run));
line_box.add_fragment(text_node, offset_in_node, length_in_node, leading_size, trailing_size, leading_margin,
trailing_margin, content_width, content_height, 0, 0, move(glyph_run));
m_max_height_on_current_line = max(m_max_height_on_current_line, line_box.block_length());
}
@ -300,9 +302,7 @@ void LineBuilder::update_last_line()
CSSPixels uppermost_box_top = strut_top;
CSSPixels lowermost_box_bottom = strut_bottom;
for (size_t i = 0; i < line_box.fragments().size(); ++i) {
auto& fragment = line_box.fragments()[i];
for (auto& fragment : line_box.fragments()) {
CSSPixels new_fragment_inline_offset = inline_offset + fragment.inline_offset();
CSSPixels new_fragment_block_offset = 0;

View file

@ -282,10 +282,9 @@ static Utf16String apply_text_transform(Utf16String const& string, CSS::TextTran
return apply_math_auto_text_transform(string);
case CSS::TextTransform::Capitalize:
return string.to_titlecase(locale, TrailingCodePointTransformation::PreserveExisting);
case CSS::TextTransform::FullSizeKana: {
case CSS::TextTransform::FullSizeKana:
dbgln("FIXME: Implement text-transform full-size-kana");
return string;
}
case CSS::TextTransform::FullWidth:
return string.to_fullwidth();
}
@ -306,7 +305,6 @@ Utf16String const& TextNode::text_for_rendering() const
return *m_text_for_rendering;
}
// NOTE: This collapses whitespace into a single ASCII space if the CSS white-space property tells us to.
void TextNode::compute_text_for_rendering()
{
if (dom_node().is_password_input()) {
@ -314,53 +312,85 @@ void TextNode::compute_text_for_rendering()
return;
}
bool collapse = first_is_one_of(computed_values().white_space_collapse(), CSS::WhiteSpaceCollapse::Collapse, CSS::WhiteSpaceCollapse::PreserveBreaks);
// Apply text-transform
// FIXME: This can generate more code points than there were before; we need to find a better way to map the
// resulting paintable fragments' offsets into the original text node data.
// See: https://github.com/LadybirdBrowser/ladybird/issues/6177
auto parent_element = dom_node().parent_element();
auto const maybe_lang = parent_element ? parent_element->lang() : Optional<String> {};
auto const lang = maybe_lang.has_value() ? maybe_lang.value() : Optional<StringView> {};
auto text = apply_text_transform(dom_node().data(), computed_values().text_transform(), lang);
auto data = apply_text_transform(dom_node().data(), computed_values().text_transform(), lang);
// NOTE: A couple fast returns to avoid unnecessarily allocating a StringBuilder.
if (!collapse || data.is_empty()) {
m_text_for_rendering = move(data);
// The logic below deals with converting whitespace characters. If we don't have them, return early.
if (text.is_empty() || !any_of(text, is_ascii_space)) {
m_text_for_rendering = move(text);
return;
}
if (data.length_in_code_units() == 1) {
if (data.is_ascii_whitespace())
// https://drafts.csswg.org/css-text-4/#white-space-phase-1
bool convert_newlines = false;
bool convert_tabs = false;
// If white-space-collapse is set to collapse or preserve-breaks, white space characters are considered collapsible
// and are processed by performing the following steps:
auto white_space_collapse = computed_values().white_space_collapse();
if (first_is_one_of(white_space_collapse, CSS::WhiteSpaceCollapse::Collapse, CSS::WhiteSpaceCollapse::PreserveBreaks)) {
// 1. FIXME: Any sequence of collapsible spaces and tabs immediately preceding or following a segment break is removed.
// 2. Collapsible segment breaks are transformed for rendering according to the segment break transformation
// rules.
{
// https://drafts.csswg.org/css-text-4/#line-break-transform
// FIXME: When white-space-collapse is not collapse, segment breaks are not collapsible. For values other than
// collapse or preserve-spaces (which transforms them into spaces), segment breaks are instead transformed
// into a preserved line feed (U+000A).
// When white-space-collapse is collapse, segment breaks are collapsible, and are collapsed as follows:
if (white_space_collapse == CSS::WhiteSpaceCollapse::Collapse) {
// 1. FIXME: First, any collapsible segment break immediately following another collapsible segment break is
// removed.
// 2. FIXME: Then any remaining segment break is either transformed into a space (U+0020) or removed depending
// on the context before and after the break. The rules for this operation are UA-defined in this
// level.
convert_newlines = true;
}
}
// 3. Every collapsible tab is converted to a collapsible space (U+0020).
convert_tabs = true;
// 4. Any collapsible space immediately following another collapsible space—even one outside the boundary of the
// inline containing that space, provided both spaces are within the same inline formatting context—is
// collapsed to have zero advance width. (It is invisible, but retains its soft wrap opportunity, if any.)
// AD-HOC: This is handled by TextNode::ChunkIterator by removing the space.
}
// If white-space-collapse is set to preserve-spaces, each tab and segment break is converted to a space.
if (white_space_collapse == CSS::WhiteSpaceCollapse::PreserveSpaces) {
convert_tabs = true;
convert_newlines = true;
}
// AD-HOC: Prevent allocating a StringBuilder for a single space/newline/tab.
if (text == " "sv || (convert_tabs && text == "\t"sv) || (convert_newlines && text == "\n"sv)) {
m_text_for_rendering = " "_utf16;
else
m_text_for_rendering = move(data);
return;
}
if (!any_of(data, is_ascii_space)) {
m_text_for_rendering = move(data);
return;
// AD-HOC: It's important to not change the amount of code units in the resulting transformed text, so ChunkIterator
// can pass views to this string with associated code unit offsets that still match the original text.
if (convert_newlines || convert_tabs) {
StringBuilder text_builder { StringBuilder::Mode::UTF16, text.length_in_code_units() };
for (auto code_point : text) {
if ((convert_newlines && code_point == '\n') || (convert_tabs && code_point == '\t'))
code_point = ' ';
text_builder.append_code_point(code_point);
}
text = text_builder.to_utf16_string();
}
StringBuilder builder { StringBuilder::Mode::UTF16, data.length_in_code_units() };
size_t index = 0;
auto skip_over_whitespace = [&] {
while (index < data.length_in_code_units() && is_ascii_space(data.code_unit_at(index)))
++index;
};
while (index < data.length_in_code_units()) {
if (is_ascii_space(data.code_unit_at(index))) {
builder.append(' ');
++index;
skip_over_whitespace();
} else {
builder.append_code_unit(data.code_unit_at(index));
++index;
}
}
m_text_for_rendering = builder.to_utf16_string();
m_text_for_rendering = move(text);
}
Unicode::Segmenter& TextNode::grapheme_segmenter() const
@ -373,22 +403,20 @@ Unicode::Segmenter& TextNode::grapheme_segmenter() const
return *m_grapheme_segmenter;
}
TextNode::ChunkIterator::ChunkIterator(TextNode const& text_node, bool wrap_lines, bool respect_linebreaks)
: m_wrap_lines(wrap_lines)
, m_respect_linebreaks(respect_linebreaks)
, m_view(text_node.text_for_rendering())
, m_font_cascade_list(text_node.computed_values().font_list())
, m_grapheme_segmenter(text_node.grapheme_segmenter())
TextNode::ChunkIterator::ChunkIterator(TextNode const& text_node, bool should_wrap_lines, bool should_respect_linebreaks)
: ChunkIterator(text_node, text_node.text_for_rendering(), text_node.grapheme_segmenter(), should_wrap_lines, should_respect_linebreaks)
{
}
TextNode::ChunkIterator::ChunkIterator(TextNode const& text_node, Utf16View const& text, Unicode::Segmenter& grapheme_segmenter, bool wrap_lines, bool respect_linebreaks)
: m_wrap_lines(wrap_lines)
, m_respect_linebreaks(respect_linebreaks)
TextNode::ChunkIterator::ChunkIterator(TextNode const& text_node, Utf16View const& text,
Unicode::Segmenter& grapheme_segmenter, bool should_wrap_lines, bool should_respect_linebreaks)
: m_should_wrap_lines(should_wrap_lines)
, m_should_respect_linebreaks(should_respect_linebreaks)
, m_view(text)
, m_font_cascade_list(text_node.computed_values().font_list())
, m_grapheme_segmenter(grapheme_segmenter)
{
m_should_collapse_whitespace = first_is_one_of(text_node.computed_values().white_space_collapse(), CSS::WhiteSpaceCollapse::Collapse, CSS::WhiteSpaceCollapse::PreserveBreaks);
}
static Gfx::GlyphRun::TextType text_type_for_code_point(u32 code_point)
@ -456,13 +484,18 @@ Optional<TextNode::Chunk> TextNode::ChunkIterator::next_without_peek()
if (m_current_index >= m_view.length_in_code_units())
return {};
auto current_code_point = [this]() {
auto current_code_point = [this] {
return m_view.code_point_at(m_current_index);
};
auto next_grapheme_boundary = [this]() {
auto next_grapheme_boundary = [this] {
return m_grapheme_segmenter.next_boundary(m_current_index).value_or(m_view.length_in_code_units());
};
// https://drafts.csswg.org/css-text-4/#collapsible-white-space
auto is_collapsible = [this](u32 code_point) {
return m_should_collapse_whitespace && is_ascii_space(code_point);
};
auto code_point = current_code_point();
auto start_of_chunk = m_current_index;
@ -489,7 +522,7 @@ Optional<TextNode::Chunk> TextNode::ChunkIterator::next_without_peek()
return result.release_value();
}
if (m_respect_linebreaks && code_point == '\n') {
if (m_should_respect_linebreaks && code_point == '\n') {
// Newline encountered, and we're supposed to preserve them.
// If we have accumulated some code points in the current chunk, commit them now and continue with the newline next time.
if (auto result = try_commit_chunk(start_of_chunk, m_current_index, false, broken_on_tab, font, text_type); result.has_value())
@ -502,7 +535,19 @@ Optional<TextNode::Chunk> TextNode::ChunkIterator::next_without_peek()
return result.release_value();
}
if (m_wrap_lines) {
// If both this code point and the previous code point are collapsible, skip code points until we're at a non-
// collapsible code point.
if (is_collapsible(code_point) && m_current_index > 0 && is_collapsible(m_view.code_point_at(m_current_index - 1))) {
auto result = try_commit_chunk(start_of_chunk, m_current_index, false, broken_on_tab, font, text_type);
while (m_current_index < m_view.length_in_code_units() && is_collapsible(current_code_point()))
m_current_index = next_grapheme_boundary();
if (result.has_value())
return result.release_value();
}
if (m_should_wrap_lines) {
if (text_type != text_type_for_code_point(code_point)) {
if (auto result = try_commit_chunk(start_of_chunk, m_current_index, false, broken_on_tab, font, text_type); result.has_value())
return result.release_value();

View file

@ -42,8 +42,12 @@ public:
class ChunkIterator {
public:
ChunkIterator(TextNode const&, bool wrap_lines, bool respect_linebreaks);
ChunkIterator(TextNode const&, Utf16View const&, Unicode::Segmenter&, bool wrap_lines, bool respect_linebreaks);
ChunkIterator(TextNode const&, bool should_wrap_lines, bool should_respect_linebreaks);
ChunkIterator(TextNode const&, Utf16View const&, Unicode::Segmenter&, bool should_wrap_lines, bool should_respect_linebreaks);
bool should_wrap_lines() const { return m_should_wrap_lines; }
bool should_respect_linebreaks() const { return m_should_respect_linebreaks; }
bool should_collapse_whitespace() const { return m_should_collapse_whitespace; }
Optional<Chunk> next();
Optional<Chunk> peek(size_t);
@ -52,8 +56,9 @@ public:
Optional<Chunk> next_without_peek();
Optional<Chunk> try_commit_chunk(size_t start, size_t end, bool has_breaking_newline, bool has_breaking_tab, Gfx::Font const&, Gfx::GlyphRun::TextType) const;
bool const m_wrap_lines;
bool const m_respect_linebreaks;
bool const m_should_wrap_lines;
bool const m_should_respect_linebreaks;
bool m_should_collapse_whitespace;
Utf16View m_view;
Gfx::FontCascadeList const& m_font_cascade_list;

View file

@ -490,10 +490,10 @@ void TreeBuilder::restructure_block_node_in_inline_parent(NodeWithStyleAndBoxMod
static bool is_ignorable_whitespace(Layout::Node const& node)
{
if (node.is_text_node() && static_cast<TextNode const&>(node).text_for_rendering().is_ascii_whitespace())
if (auto* text_node = as_if<TextNode>(node); text_node && text_node->text_for_rendering().is_ascii_whitespace())
return true;
if (node.is_anonymous() && node.is_block_container() && static_cast<BlockContainer const&>(node).children_are_inline()) {
if (node.is_anonymous() && node.is_block_container() && node.children_are_inline()) {
bool contains_only_white_space = true;
node.for_each_in_inclusive_subtree([&contains_only_white_space](auto& descendant) {
if (auto* text_node = as_if<TextNode>(descendant)) {

View file

@ -369,8 +369,6 @@ public:
m_fragments.append(PaintableFragment { fragment });
}
void set_fragments(Vector<PaintableFragment>&& fragments) { m_fragments = move(fragments); }
template<typename Callback>
void for_each_fragment(Callback callback) const
{

View file

@ -21,7 +21,7 @@ PaintableFragment::PaintableFragment(Layout::LineBoxFragment const& fragment)
, m_size(fragment.size())
, m_baseline(fragment.baseline())
, m_start_offset(fragment.start())
, m_length_in_code_units(fragment.length())
, m_length_in_code_units(fragment.length_in_code_units())
, m_glyph_run(fragment.glyph_run())
, m_writing_mode(fragment.writing_mode())
{

View file

@ -35,7 +35,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
TextNode <#text> (not painted)
BlockContainer <(anonymous)> at [235,65] [0+0+0 139.96875 0+0+0] [0+0+0 19 0+0+0] children: not-inline continuation
BlockContainer <p> at [235,65] [0+0+0 139.96875 0+0+0] [0+0+0 19 0+0+0] children: inline
frag 0 from TextNode start: 1, length: 5, rect: [235,65 27.5x19] baseline: 12.5
frag 0 from TextNode start: 33, length: 5, rect: [235,65 27.5x19] baseline: 12.5
"bang "
frag 1 from RadioButton start: 0, length: 0, rect: [262.5,65 12x12] baseline: 12
TextNode <#text> (not painted)
@ -46,7 +46,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
TextNode <#text> (not painted)
BlockContainer <(anonymous)> at [235,84] [0+0+0 139.96875 0+0+0] [0+0+0 19 0+0+0] children: not-inline continuation
BlockContainer <p> at [235,84] [0+0+0 139.96875 0+0+0] [0+0+0 19 0+0+0] children: inline
frag 0 from TextNode start: 1, length: 8, rect: [235,84 45.171875x19] baseline: 12.5
frag 0 from TextNode start: 33, length: 8, rect: [235,84 45.171875x19] baseline: 12.5
"whimper "
frag 1 from RadioButton start: 0, length: 0, rect: [280.171875,84 12x12] baseline: 12
TextNode <#text> (not painted)
@ -94,19 +94,27 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> at [20,30] [0+0+0 480 0+0+0] [0+0+0 0 0+0+0] children: inline
TextNode <#text> (not painted)
BlockContainer <p> at [20,335] [0+0+0 480 0+0+0] [0+0+0 65 0+0+0] children: inline
frag 0 from TextNode start: 1, length: 90, rect: [20,335 473.6875x13] baseline: 9.5
"This is a nonsensical document, but syntactically valid HTML 4.0. All 100%-conformant CSS1"
frag 1 from TextNode start: 92, length: 74, rect: [20,348 396.96875x13] baseline: 9.5
frag 0 from TextNode start: 13, length: 86, rect: [20,335 448.296875x13] baseline: 9.5
"This is a nonsensical document, but syntactically valid HTML 4.0. All 100%-conformant "
frag 1 from TextNode start: 111, length: 4, rect: [468.296875,335 25.390625x13] baseline: 9.5
"CSS1"
frag 2 from TextNode start: 116, length: 74, rect: [20,348 396.96875x13] baseline: 9.5
"agents should be able to render the document elements above this paragraph"
frag 2 from TextNode start: 167, length: 43, rect: [20,361 207.9375x13] baseline: 9.5
frag 3 from TextNode start: 203, length: 43, rect: [20,361 207.9375x13] baseline: 9.5
"indistinguishably (to the pixel) from this "
frag 3 from TextNode start: 0, length: 31, rect: [330.96875,361 159.671875x13] baseline: 9.5
frag 4 from TextNode start: 0, length: 1, rect: [330.96875,361 5x13] baseline: 9.5
" "
frag 5 from TextNode start: 13, length: 30, rect: [335.96875,361 154.671875x13] baseline: 9.5
"(except font rasterization and"
frag 4 from TextNode start: 32, length: 89, rect: [20,374 465.09375x13] baseline: 9.5
"form widgets). All discrepancies should be traceable to CSS1 implementation shortcomings."
frag 5 from TextNode start: 122, length: 67, rect: [20,387 345.59375x13] baseline: 9.5
"Once you have finished evaluating this test, you can return to the "
frag 6 from TextNode start: 0, length: 1, rect: [425.5,387 2.71875x13] baseline: 9.5
frag 6 from TextNode start: 44, length: 56, rect: [20,374 286.6875x13] baseline: 9.5
"form widgets). All discrepancies should be traceable to "
frag 7 from TextNode start: 112, length: 33, rect: [306.6875,374 178.40625x13] baseline: 9.5
"CSS1 implementation shortcomings."
frag 8 from TextNode start: 146, length: 53, rect: [20,387 271.421875x13] baseline: 9.5
"Once you have finished evaluating this test, you can "
frag 9 from TextNode start: 211, length: 14, rect: [291.421875,387 74.171875x13] baseline: 9.5
"return to the "
frag 10 from TextNode start: 0, length: 1, rect: [425.5,387 2.71875x13] baseline: 9.5
"."
TextNode <#text> (not painted)
InlineNode <a> at [227.9375,361] [0+0+0 103.03125 0+0+0] [0+0+0 13 0+0+0]

View file

@ -2,23 +2,23 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <html> at [0,0] [0+0+0 800 0+0+0] [0+0+0 304 0+0+0] [BFC] children: not-inline
BlockContainer <body> at [8,8] [8+0+0 784 0+0+8] [8+0+0 288 0+0+8] children: not-inline
BlockContainer <div.margin-left> at [243.1875,8] [235.1875+0+0 548.8125 0+0+0] [0+0+0 162 0+0+0] children: inline
frag 0 from TextNode start: 1, length: 62, rect: [243.1875,8 515.390625x18] baseline: 13.796875
frag 0 from TextNode start: 2, length: 62, rect: [243.1875,8 515.390625x18] baseline: 13.796875
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce"
frag 1 from TextNode start: 64, length: 68, rect: [243.1875,26 543.484375x18] baseline: 13.796875
frag 1 from TextNode start: 65, length: 68, rect: [243.1875,26 543.484375x18] baseline: 13.796875
"cursus est eget nisl porta, id vulputate velit imperdiet. Vestibulum"
frag 2 from TextNode start: 133, length: 69, rect: [243.1875,44 533.765625x18] baseline: 13.796875
frag 2 from TextNode start: 134, length: 69, rect: [243.1875,44 533.765625x18] baseline: 13.796875
"mollis ligula sit amet ligula aliquam, vitae vulputate magna iaculis."
frag 3 from TextNode start: 203, length: 68, rect: [243.1875,62 533.015625x18] baseline: 13.796875
frag 3 from TextNode start: 204, length: 68, rect: [243.1875,62 533.015625x18] baseline: 13.796875
"Nulla et augue fringilla, molestie nulla blandit, condimentum risus."
frag 4 from TextNode start: 272, length: 58, rect: [243.1875,80 488.140625x18] baseline: 13.796875
frag 4 from TextNode start: 273, length: 58, rect: [243.1875,80 488.140625x18] baseline: 13.796875
"Suspendisse lectus augue, sodales vitae metus ac, interdum"
frag 5 from TextNode start: 331, length: 63, rect: [243.1875,98 526.546875x18] baseline: 13.796875
frag 5 from TextNode start: 332, length: 63, rect: [243.1875,98 526.546875x18] baseline: 13.796875
"volutpat arcu. Aenean eu placerat risus, at dictum lectus. Nunc"
frag 6 from TextNode start: 395, length: 64, rect: [243.1875,116 524.5x18] baseline: 13.796875
frag 6 from TextNode start: 396, length: 64, rect: [243.1875,116 524.5x18] baseline: 13.796875
"maximus est eu risus porta tincidunt. Cras nec felis tellus. Sed"
frag 7 from TextNode start: 460, length: 66, rect: [243.1875,134 523.078125x18] baseline: 13.796875
frag 7 from TextNode start: 461, length: 66, rect: [243.1875,134 523.078125x18] baseline: 13.796875
"euismod ultricies ipsum, eget ultricies nisl dignissim nec. Mauris"
frag 8 from TextNode start: 527, length: 21, rect: [243.1875,152 178.53125x18] baseline: 13.796875
frag 8 from TextNode start: 528, length: 21, rect: [243.1875,152 178.53125x18] baseline: 13.796875
"aliquet rhoncus urna."
TextNode <#text> (not painted)
BlockContainer <(anonymous)> at [8,170] [0+0+0 784 0+0+0] [0+0+0 0 0+0+0] children: inline

View file

@ -4,7 +4,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
TextNode <#text> (not painted)
BlockContainer <body> at [8,8] [8+0+0 784 0+0+8] [8+0+0 36 0+0+8] children: not-inline
BlockContainer <(anonymous)> at [8,8] [0+0+0 784 0+0+0] [0+0+0 18 0+0+0] children: inline
frag 0 from TextNode start: 1, length: 3, rect: [137.109375,8 27.640625x18] baseline: 13.796875
frag 0 from TextNode start: 3, length: 3, rect: [137.109375,8 27.640625x18] baseline: 13.796875
"bar"
BlockContainer <div.big-float> at [8,8] floating [0+0+0 100 0+0+0] [0+0+0 100 0+0+0] [BFC] children: not-inline
TextNode <#text> (not painted)
@ -14,7 +14,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
TextNode <#text> (not painted)
TextNode <#text> (not painted)
BlockContainer <div> at [8,26] [0+0+0 784 0+0+0] [0+0+0 18 0+0+0] children: inline
frag 0 from TextNode start: 1, length: 3, rect: [129.515625,26 27.203125x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 3, rect: [129.515625,26 27.203125x18] baseline: 13.796875
"baz"
TextNode <#text> (not painted)
BlockContainer <div.yyy> at [108,26] floating [0+0+0 21.515625 0+0+0] [0+0+0 18 0+0+0] [BFC] children: inline

View file

@ -9,13 +9,13 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> at [22,29] [0+0+0 48.6875 0+0+0] [0+0+0 0 0+0+0] children: inline
TextNode <#text> (not painted)
BlockContainer <div.border-black> at [32,39] [0+10+0 28.6875 0+10+0] [0+10+0 18 0+10+0] children: inline
frag 0 from TextNode start: 1, length: 3, rect: [32,39 28.6875x18] baseline: 13.796875
frag 0 from TextNode start: 13, length: 3, rect: [32,39 28.6875x18] baseline: 13.796875
"one"
TextNode <#text> (not painted)
BlockContainer <(anonymous)> at [22,67] [0+0+0 48.6875 0+0+0] [0+0+0 0 0+0+0] children: inline
TextNode <#text> (not painted)
BlockContainer <div.border-black> at [32,77] [0+10+0 28.6875 0+10+0] [0+10+0 100 0+10+0] children: inline
frag 0 from TextNode start: 1, length: 3, rect: [32.125,77 28.4375x18] baseline: 13.796875
frag 0 from TextNode start: 13, length: 3, rect: [32.125,77 28.4375x18] baseline: 13.796875
"two"
TextNode <#text> (not painted)
BlockContainer <(anonymous)> at [22,187] [0+0+0 48.6875 0+0+0] [0+0+0 0 0+0+0] children: inline

View file

@ -46,43 +46,51 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> at [8,8] [0+0+0 784 0+0+0] [0+0+0 0 0+0+0] children: inline
TextNode <#text> (not painted)
BlockContainer <div> at [8,8] [0+0+0 784 0+0+0] [0+0+0 342 0+0+0] children: inline
frag 0 from TextNode start: 1, length: 47, rect: [228,8 414.5625x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 47, rect: [228,8 414.5625x18] baseline: 13.796875
"lorem ipsum lorem ipsum lorem ipsum lorem ipsum"
frag 1 from TextNode start: 49, length: 47, rect: [228,26 414.5625x18] baseline: 13.796875
frag 1 from TextNode start: 53, length: 47, rect: [228,26 414.5625x18] baseline: 13.796875
"lorem ipsum lorem ipsum lorem ipsum lorem ipsum"
frag 2 from TextNode start: 97, length: 53, rect: [228,44 466.90625x18] baseline: 13.796875
frag 2 from TextNode start: 101, length: 53, rect: [228,44 466.90625x18] baseline: 13.796875
"lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 3 from TextNode start: 151, length: 65, rect: [188,62 573.5x18] baseline: 13.796875
frag 3 from TextNode start: 155, length: 65, rect: [188,62 573.5x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum"
frag 4 from TextNode start: 217, length: 65, rect: [188,80 572.546875x18] baseline: 13.796875
"lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 5 from TextNode start: 283, length: 77, rect: [108,98 679.140625x18] baseline: 13.796875
frag 4 from TextNode start: 221, length: 60, rect: [188,80 528.203125x18] baseline: 13.796875
"lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum "
frag 5 from TextNode start: 285, length: 5, rect: [716.203125,80 44.34375x18] baseline: 13.796875
"lorem"
frag 6 from TextNode start: 291, length: 77, rect: [108,98 679.140625x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum"
frag 6 from TextNode start: 361, length: 89, rect: [8,116 783.828125x18] baseline: 13.796875
frag 7 from TextNode start: 369, length: 89, rect: [8,116 783.828125x18] baseline: 13.796875
"lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 7 from TextNode start: 451, length: 83, rect: [8,134 731.484375x18] baseline: 13.796875
frag 8 from TextNode start: 459, length: 83, rect: [8,134 731.484375x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 8 from TextNode start: 535, length: 83, rect: [8,152 731.484375x18] baseline: 13.796875
frag 9 from TextNode start: 543, length: 18, rect: [8,152 158.9375x18] baseline: 13.796875
"ipsum lorem ipsum "
frag 10 from TextNode start: 565, length: 65, rect: [166.9375,152 572.546875x18] baseline: 13.796875
"lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 11 from TextNode start: 631, length: 83, rect: [8,170 731.484375x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 9 from TextNode start: 619, length: 83, rect: [8,170 731.484375x18] baseline: 13.796875
frag 12 from TextNode start: 715, length: 83, rect: [8,188 731.484375x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 10 from TextNode start: 703, length: 83, rect: [8,188 731.484375x18] baseline: 13.796875
frag 13 from TextNode start: 799, length: 42, rect: [8,206 370.21875x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum "
frag 14 from TextNode start: 845, length: 41, rect: [378.21875,206 361.265625x18] baseline: 13.796875
"lorem ipsum lorem ipsum lorem ipsum lorem"
frag 15 from TextNode start: 887, length: 83, rect: [8,224 731.484375x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 11 from TextNode start: 787, length: 83, rect: [8,206 731.484375x18] baseline: 13.796875
frag 16 from TextNode start: 971, length: 83, rect: [8,242 731.484375x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 12 from TextNode start: 871, length: 83, rect: [8,224 731.484375x18] baseline: 13.796875
frag 17 from TextNode start: 1055, length: 66, rect: [8,260 581.5x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum "
frag 18 from TextNode start: 1125, length: 17, rect: [589.5,260 149.984375x18] baseline: 13.796875
"lorem ipsum lorem"
frag 19 from TextNode start: 1143, length: 83, rect: [8,278 731.484375x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 13 from TextNode start: 955, length: 83, rect: [8,242 731.484375x18] baseline: 13.796875
frag 20 from TextNode start: 1227, length: 83, rect: [8,296 731.484375x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 14 from TextNode start: 1039, length: 83, rect: [8,260 731.484375x18] baseline: 13.796875
frag 21 from TextNode start: 1311, length: 83, rect: [8,314 731.484375x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 15 from TextNode start: 1123, length: 83, rect: [8,278 731.484375x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 16 from TextNode start: 1207, length: 83, rect: [8,296 731.484375x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 17 from TextNode start: 1291, length: 83, rect: [8,314 731.484375x18] baseline: 13.796875
"ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
frag 18 from TextNode start: 1375, length: 5, rect: [8,332 45.296875x18] baseline: 13.796875
frag 22 from TextNode start: 1395, length: 5, rect: [8,332 45.296875x18] baseline: 13.796875
"ipsum"
TextNode <#text> (not painted)
BlockContainer <(anonymous)> at [8,350] [0+0+0 784 0+0+0] [0+0+0 0 0+0+0] children: inline

View file

@ -2,7 +2,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <html> at [0,0] [0+0+0 800 0+0+0] [0+0+0 416 0+0+0] [BFC] children: not-inline
BlockContainer <body> at [8,8] [8+0+0 784 0+0+8] [8+0+0 400 0+0+8] children: not-inline
BlockContainer <div.a> at [8,8] [0+0+0 784 0+0+0] [0+0+0 200 0+0+0] children: inline
frag 0 from TextNode start: 1, length: 3, rect: [8,8 27.15625x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 3, rect: [8,8 27.15625x18] baseline: 13.796875
"foo"
TextNode <#text> (not painted)
BlockContainer <div.b> at [292,8] floating [0+0+0 500 0+0+0] [0+0+0 200 0+0+0] [BFC] children: not-inline

View file

@ -2,7 +2,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <html> at [0,0] [0+0+0 800 0+0+0] [0+0+0 414 0+0+0] [BFC] children: not-inline
BlockContainer <body> at [8,8] [8+0+0 784 0+0+8] [8+0+0 6 0+0+8] children: not-inline
BlockContainer <div.a> at [8,8] [0+0+0 100 0+0+684] [0+0+0 6 0+0+0] children: inline
frag 0 from TextNode start: 1, length: 1, rect: [8,8 4.328125x6] baseline: 4.5
frag 0 from TextNode start: 5, length: 1, rect: [8,8 4.328125x6] baseline: 4.5
"H"
TextNode <#text> (not painted)
BlockContainer <div.b.l> at [8,14] floating [0+0+0 100 0+0+0] [0+0+0 100 0+0+0] [BFC] children: not-inline

View file

@ -4,40 +4,54 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> at [8,8] [0+0+0 784 0+0+0] [0+0+0 0 0+0+0] children: inline
TextNode <#text> (not painted)
BlockContainer <div.outer> at [9,9] [0+1+0 300 0+1+482] [0+1+0 250 0+1+0] children: inline
frag 0 from TextNode start: 1, length: 24, rect: [61,9 212x16] baseline: 12.796875
frag 0 from TextNode start: 9, length: 24, rect: [61,9 212x16] baseline: 12.796875
"foo bar baz foo bar baz "
frag 1 from TextNode start: 1, length: 3, rect: [273,9 27.15625x16] baseline: 12.796875
frag 1 from TextNode start: 9, length: 3, rect: [273,9 27.15625x16] baseline: 12.796875
"foo"
frag 2 from TextNode start: 5, length: 3, rect: [263,25 27.640625x16] baseline: 12.796875
frag 2 from TextNode start: 13, length: 3, rect: [263,25 27.640625x16] baseline: 12.796875
"bar"
frag 3 from TextNode start: 9, length: 3, rect: [263,41 27.203125x16] baseline: 12.796875
frag 3 from TextNode start: 17, length: 3, rect: [263,41 27.203125x16] baseline: 12.796875
"baz"
frag 4 from TextNode start: 13, length: 3, rect: [263,57 27.15625x16] baseline: 12.796875
frag 4 from TextNode start: 21, length: 3, rect: [263,57 27.15625x16] baseline: 12.796875
"foo"
frag 5 from TextNode start: 17, length: 11, rect: [9,77 98x16] baseline: 12.796875
"bar baz foo"
frag 6 from TextNode start: 29, length: 11, rect: [9,93 98x16] baseline: 12.796875
"bar baz foo"
frag 7 from TextNode start: 41, length: 7, rect: [9,109 62.84375x16] baseline: 12.796875
frag 5 from TextNode start: 25, length: 8, rect: [9,77 70.84375x16] baseline: 12.796875
"bar baz "
frag 8 from TextNode start: 1, length: 7, rect: [9,125 62.796875x16] baseline: 12.796875
frag 6 from TextNode start: 41, length: 3, rect: [79.84375,77 27.15625x16] baseline: 12.796875
"foo"
frag 7 from TextNode start: 45, length: 11, rect: [9,93 98x16] baseline: 12.796875
"bar baz foo"
frag 8 from TextNode start: 57, length: 7, rect: [9,109 62.84375x16] baseline: 12.796875
"bar baz"
frag 9 from TextNode start: 9, length: 7, rect: [9,125 62.796875x16] baseline: 12.796875
"foo bar"
frag 9 from TextNode start: 9, length: 31, rect: [9,141 274.359375x16] baseline: 12.796875
"baz foo bar baz foo bar baz foo"
frag 10 from TextNode start: 41, length: 31, rect: [9,157 274.84375x16] baseline: 12.796875
"bar baz foo bar baz foo bar baz"
frag 11 from TextNode start: 1, length: 23, rect: [61,173 204x16] baseline: 12.796875
frag 10 from TextNode start: 17, length: 16, rect: [9,141 141.203125x16] baseline: 12.796875
"baz foo bar baz "
frag 11 from TextNode start: 41, length: 15, rect: [150.203125,141 133.15625x16] baseline: 12.796875
"foo bar baz foo"
frag 12 from TextNode start: 57, length: 8, rect: [9,157 70.84375x16] baseline: 12.796875
"bar baz "
frag 13 from TextNode start: 73, length: 23, rect: [79.84375,157 204x16] baseline: 12.796875
"foo bar baz foo bar baz"
frag 12 from TextNode start: 1, length: 23, rect: [61,189 204x16] baseline: 12.796875
frag 14 from TextNode start: 9, length: 23, rect: [61,173 204x16] baseline: 12.796875
"foo bar baz foo bar baz"
frag 15 from TextNode start: 9, length: 23, rect: [61,189 204x16] baseline: 12.796875
"foo bar baz foo bar baz"
frag 16 from TextNode start: 41, length: 24, rect: [61,205 212x16] baseline: 12.796875
"foo bar baz foo bar baz "
frag 17 from TextNode start: 73, length: 3, rect: [273,205 27.15625x16] baseline: 12.796875
"foo"
frag 18 from TextNode start: 77, length: 20, rect: [61,221 176.84375x16] baseline: 12.796875
"bar baz foo bar baz "
frag 19 from TextNode start: 105, length: 7, rect: [237.84375,221 62.796875x16] baseline: 12.796875
"foo bar"
frag 20 from TextNode start: 113, length: 16, rect: [9,237 141.203125x16] baseline: 12.796875
"baz foo bar baz "
frag 21 from TextNode start: 137, length: 15, rect: [150.203125,237 133.15625x16] baseline: 12.796875
"foo bar baz foo"
frag 22 from TextNode start: 153, length: 8, rect: [9,253 70.84375x16] baseline: 12.796875
"bar baz "
frag 23 from TextNode start: 169, length: 23, rect: [79.84375,253 204x16] baseline: 12.796875
"foo bar baz foo bar baz"
frag 13 from TextNode start: 25, length: 27, rect: [61,205 239.15625x16] baseline: 12.796875
"foo bar baz foo bar baz foo"
frag 14 from TextNode start: 53, length: 27, rect: [61,221 239.640625x16] baseline: 12.796875
"bar baz foo bar baz foo bar"
frag 15 from TextNode start: 81, length: 31, rect: [9,237 274.359375x16] baseline: 12.796875
"baz foo bar baz foo bar baz foo"
frag 16 from TextNode start: 113, length: 31, rect: [9,253 274.84375x16] baseline: 12.796875
"bar baz foo bar baz foo bar baz"
TextNode <#text> (not painted)
BlockContainer <div.lefty> at [10,10] floating [0+1+0 50 0+1+0] [0+1+0 50 0+1+0] [BFC] children: not-inline
TextNode <#text> (not painted)

View file

@ -4,7 +4,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> at [8,8] [0+0+0 784 0+0+0] [0+0+0 0 0+0+0] children: inline
TextNode <#text> (not painted)
BlockContainer <div.outer> at [9,9] [0+1+0 300 0+1+482] [0+1+0 250 0+1+0] children: inline
frag 0 from TextNode start: 1, length: 23, rect: [61,9 204x16] baseline: 12.796875
frag 0 from TextNode start: 9, length: 23, rect: [61,9 204x16] baseline: 12.796875
"foo bar baz foo bar baz"
TextNode <#text> (not painted)
BlockContainer <div.lefty> at [10,10] floating [0+1+0 50 0+1+0] [0+1+0 50 0+1+0] [BFC] children: not-inline

View file

@ -6,9 +6,9 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> at [8,8] [0+0+0 784 0+0+0] [0+0+0 0 0+0+0] children: inline
TextNode <#text> (not painted)
BlockContainer <div.container> at [9,9] [0+1+0 100 0+1+682] [0+1+0 150 0+1+0] children: inline
frag 0 from TextNode start: 1, length: 11, rect: [9,9 99.109375x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 11, rect: [9,9 99.109375x18] baseline: 13.796875
"abc abc abc"
frag 1 from TextNode start: 13, length: 11, rect: [9,27 99.109375x18] baseline: 13.796875
frag 1 from TextNode start: 21, length: 11, rect: [9,27 99.109375x18] baseline: 13.796875
"abc abc abc"
TextNode <#text> (not painted)
BlockContainer <div.left.w80.red> at [9,45] floating [0+0+0 80 0+0+0] [0+0+0 50 0+0+0] [BFC] children: not-inline

View file

@ -2,9 +2,9 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <html> at [0,0] [0+0+0 800 0+0+0] [0+0+0 102 0+0+0] [BFC] children: not-inline
BlockContainer <body> at [8,8] [8+0+0 784 0+0+8] [8+0+0 86 0+0+8] children: not-inline
BlockContainer <div.a> at [8,8] [0+0+0 50 0+0+734] [0+0+0 86 0+0+0] children: inline
frag 0 from TextNode start: 1, length: 3, rect: [8,58 27.15625x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 3, rect: [8,58 27.15625x18] baseline: 13.796875
"foo"
frag 1 from TextNode start: 1, length: 3, rect: [8,76 27.640625x18] baseline: 13.796875
frag 1 from TextNode start: 5, length: 3, rect: [8,76 27.640625x18] baseline: 13.796875
"bar"
TextNode <#text> (not painted)
BlockContainer <div.b> at [8,8] floating [0+0+0 50 0+0+0] [0+0+0 50 0+0+0] [BFC] children: not-inline

View file

@ -3,12 +3,12 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <body> at [100,8] [100+0+0 200 0+0+500] [8+0+0 200 0+0+8] children: not-inline
BlockContainer <div.row> at [50,8] [-50+0+0 250 0+0+0] [0+0+0 200 0+0+0] children: inline
BlockContainer <div.item> at [50,8] floating [0+0+0 125 0+0+0] [0+0+0 18 0+0+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 1, rect: [50,8 9.34375x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 1, rect: [50,8 9.34375x18] baseline: 13.796875
"a"
TextNode <#text> (not painted)
TextNode <#text> (not painted)
BlockContainer <div.item> at [175,8] floating [0+0+0 125 0+0+0] [0+0+0 18 0+0+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 1, rect: [175,8 9.46875x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 1, rect: [175,8 9.46875x18] baseline: 13.796875
"b"
TextNode <#text> (not painted)
TextNode <#text> (not painted)

View file

@ -6,14 +6,22 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <div.bfc> at [18,18] [0+10+0 564 0+10+0] [0+10+0 90 0+10+0] [BFC] children: inline
frag 0 from TextNode start: 0, length: 56, rect: [18,18 458.125x18] baseline: 13.796875
"Lorem ipsum dolor sit amet, consectetur adipiscing elit."
frag 1 from TextNode start: 57, length: 60, rect: [18,36 511.796875x18] baseline: 13.796875
"Pellentesque vitae neque nunc. Nam fermentum libero a lectus"
frag 2 from TextNode start: 118, length: 67, rect: [18,54 537.078125x18] baseline: 13.796875
"vulputate eleifend. Nam sagittis tristique augue, id sodales mauris"
frag 3 from TextNode start: 186, length: 65, rect: [18,72 537.34375x18] baseline: 13.796875
"suscipit at. Vivamus eget placerat ex. Suspendisse potenti. Morbi"
frag 4 from TextNode start: 252, length: 57, rect: [18,90 455.375x18] baseline: 13.796875
"pulvinar ipsum eget nulla dapibus, ac varius mi eleifend."
frag 1 from TextNode start: 57, length: 19, rect: [18,36 155.203125x18] baseline: 13.796875
"Pellentesque vitae "
frag 2 from TextNode start: 80, length: 41, rect: [173.203125,36 356.59375x18] baseline: 13.796875
"neque nunc. Nam fermentum libero a lectus"
frag 3 from TextNode start: 122, length: 33, rect: [18,54 258.640625x18] baseline: 13.796875
"vulputate eleifend. Nam sagittis "
frag 4 from TextNode start: 159, length: 34, rect: [276.640625,54 278.4375x18] baseline: 13.796875
"tristique augue, id sodales mauris"
frag 5 from TextNode start: 194, length: 39, rect: [18,72 316.96875x18] baseline: 13.796875
"suscipit at. Vivamus eget placerat ex. "
frag 6 from TextNode start: 237, length: 26, rect: [334.96875,72 220.375x18] baseline: 13.796875
"Suspendisse potenti. Morbi"
frag 7 from TextNode start: 264, length: 48, rect: [18,90 392.171875x18] baseline: 13.796875
"pulvinar ipsum eget nulla dapibus, ac varius mi "
frag 8 from TextNode start: 316, length: 9, rect: [410.171875,90 63.203125x18] baseline: 13.796875
"eleifend."
TextNode <#text> (not painted)
ViewportPaintable (Viewport<#document>) [0,0 800x600] overflow: [0,0 800x1008]

View file

@ -3,14 +3,14 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <body> at [8,8] [8+0+0 784 0+0+8] [8+0+0 28 0+0+8] children: not-inline
Box <div.flex> at [8,8] flex-container(row) [0+0+0 784 0+0+0] [0+0+0 28 0+0+0] [FFC] children: not-inline
BlockContainer <(anonymous)> at [8,8] flex-item [0+0+0 24.171875 0+0+0] [0+0+0 28 0+0+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 3, rect: [8,8 24.171875x18] baseline: 13.796875
frag 0 from TextNode start: 3, length: 3, rect: [8,8 24.171875x18] baseline: 13.796875
"163"
TextNode <#text> (not painted)
TextNode <#text> (not painted)
BlockContainer <foo-a> at [32.171875,8] flex-item [0+0+0 58.15625 0+0+0] [0+0+0 28 0+0+0] [BFC] children: not-inline
Box <foo-b> at [37.171875,13] flex-container(row) [0+5+0 48.15625 0+5+0] [0+5+0 18 0+5+0] [FFC] children: not-inline
BlockContainer <(anonymous)> at [37.171875,13] flex-item [0+0+0 48.15625 0+0+0] [0+0+0 18 0+0+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 5, rect: [37.171875,13 48.15625x18] baseline: 13.796875
frag 0 from TextNode start: 9, length: 5, rect: [37.171875,13 48.15625x18] baseline: 13.796875
"Share"
TextNode <#text> (not painted)
TextNode <#text> (not painted)

View file

@ -11,9 +11,9 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
TextNode <#text> (not painted)
BlockContainer <div> at [8,126] [0+0+0 784 0+0+0] [0+0+0 136 0+0+0] children: not-inline
BlockContainer <(anonymous)> at [8,126] [0+0+0 784 0+0+0] [0+0+0 36 0+0+0] children: inline
frag 0 from TextNode start: 1, length: 87, rect: [8,126 711.4375x18] baseline: 13.796875
frag 0 from TextNode start: 9, length: 87, rect: [8,126 711.4375x18] baseline: 13.796875
"This text and the green square are both left aligned despite being nested in a div with"
frag 1 from TextNode start: 89, length: 14, rect: [8,144 94.296875x18] baseline: 13.796875
frag 1 from TextNode start: 97, length: 14, rect: [8,144 94.296875x18] baseline: 13.796875
"align="right":"
TextNode <#text> (not painted)
BlockContainer <div.square> at [8,162] [0+0+0 100 0+0+684] [0+0+0 100 0+0+0] children: inline

View file

@ -7,7 +7,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <button> at [13,10] inline-block [0+1+4 275.546875 4+1+0] [0+1+1 18 1+1+0] [BFC] children: not-inline
BlockContainer <(anonymous)> at [13,10] flex-container(column) [0+0+0 275.546875 0+0+0] [0+0+0 18 0+0+0] [FFC] children: not-inline
BlockContainer <(anonymous)> at [13,10] flex-item [0+0+0 275.546875 0+0+0] [0+0+0 18 0+0+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 24, rect: [13,10 275.546875x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 24, rect: [13,10 275.546875x18] baseline: 13.796875
"LOOOOOOOOOOOOOOOOOOOOONG"
TextNode <#text> (not painted)
TextNode <#text> (not painted)

View file

@ -13,7 +13,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> (not painted) [BFC] children: inline
TextNode <#text> (not painted)
BlockContainer <div> at [8,128] flex-item [0+0+0 784 0+0+0] [0+0+0 18 0+0+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 14, rect: [8,128 112.421875x18] baseline: 13.796875
frag 0 from TextNode start: 9, length: 14, rect: [8,128 112.421875x18] baseline: 13.796875
"text text text"
TextNode <#text> (not painted)
BlockContainer <(anonymous)> (not painted) [BFC] children: inline

View file

@ -5,7 +5,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> (not painted) [BFC] children: inline
TextNode <#text> (not painted)
BlockContainer <div> at [18,117] [0+0+0 200 0+0+0] [0+0+0 150 0+0+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 1, rect: [18,117 11.5625x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 1, rect: [18,117 11.5625x18] baseline: 13.796875
"X"
frag 1 from TextNode start: 0, length: 2, rect: [18,135 23.125x18] baseline: 13.796875
"XX"

View file

@ -3,12 +3,16 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
Box <body> at [8,8] flex-container(column) [8+0+0 784 0+0+8] [8+0+0 50 0+0+8] [FFC] children: not-inline
Box <div.content> at [8,8] flex-item [0+0+0 784 0+0+0] [0+0+0 54 0+0+0] [GFC] children: not-inline
BlockContainer <(anonymous)> at [8,8] [0+0+0 784 0+0+0] [0+0+0 54 0+0+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 87, rect: [8,8 705.625x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 87, rect: [8,8 705.625x18] baseline: 13.796875
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam dignissim elit eget arcu"
frag 1 from TextNode start: 89, length: 92, rect: [8,26 758x18] baseline: 13.796875
"accumsan imperdiet vulputate a justo. Phasellus tincidunt sem non tellus tristique hendrerit"
frag 2 from TextNode start: 182, length: 82, rect: [8,44 683.125x18] baseline: 13.796875
"quis eu eros. Morbi dolor erat, posuere ut feugiat rhoncus, vestibulum vel tortor."
frag 1 from TextNode start: 93, length: 29, rect: [8,26 246.296875x18] baseline: 13.796875
"accumsan imperdiet vulputate "
frag 2 from TextNode start: 126, length: 63, rect: [254.296875,26 511.703125x18] baseline: 13.796875
"a justo. Phasellus tincidunt sem non tellus tristique hendrerit"
frag 3 from TextNode start: 190, length: 51, rect: [8,44 427.265625x18] baseline: 13.796875
"quis eu eros. Morbi dolor erat, posuere ut feugiat "
frag 4 from TextNode start: 245, length: 31, rect: [435.265625,44 255.859375x18] baseline: 13.796875
"rhoncus, vestibulum vel tortor."
TextNode <#text> (not painted)
BlockContainer <(anonymous)> (not painted) [BFC] children: inline
TextNode <#text> (not painted)

View file

@ -2,7 +2,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <html> at [0,0] [0+0+0 800 0+0+0] [0+0+0 34 0+0+0] [BFC] children: not-inline
BlockContainer <body> at [8,8] [8+0+0 784 0+0+8] [8+0+0 18 0+0+8] children: inline
InlineNode <object> at [8,8] [0+0+0 181.5 0+0+0] [0+0+0 18 0+0+0]
frag 0 from TextNode start: 1, length: 23, rect: [8,8 181.5x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 23, rect: [8,8 181.5x18] baseline: 13.796875
"This should be visible!"
TextNode <#text> (not painted)
TextNode <#text> (not painted)

View file

@ -11,7 +11,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> (not painted)
BlockContainer <caption> at [8,10] [0+0+0 82.734375 0+0+0] [0+0+0 18 0+0+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 9, rect: [16.21875,10 82.734375x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 9, rect: [16.21875,10 82.734375x18] baseline: 13.796875
"A Caption"
TextNode <#text> (not painted)
BlockContainer <(anonymous)> (not painted) children: inline

View file

@ -28,7 +28,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
TextNode <#text> (not painted)
TextNode <#text> (not painted)
BlockContainer <div.right> at [603.828125,8] floating [0+0+0 188.15625 0+0+0] [0+0+0 18 0+0+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 1, rect: [603.828125,8 10.3125x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 1, rect: [603.828125,8 10.3125x18] baseline: 13.796875
"C"
TextNode <#text> (not painted)

View file

@ -8,7 +8,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> (not painted)
BlockContainer <caption> at [8,76] [0+0+0 82.734375 0+0+0] [0+0+0 18 0+0+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 9, rect: [16.21875,76 82.734375x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 9, rect: [16.21875,76 82.734375x18] baseline: 13.796875
"A Caption"
TextNode <#text> (not painted)
BlockContainer <(anonymous)> (not painted) children: inline

View file

@ -12,13 +12,15 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
"hello hello hello hello hello hello"
frag 1 from TextNode start: 37, length: 35, rect: [11,29 261.0625x18] baseline: 13.796875
"hello hello hello hello hello hello"
frag 2 from TextNode start: 73, length: 35, rect: [11,47 261.0625x18] baseline: 13.796875
frag 2 from TextNode start: 73, length: 24, rect: [11,47 179.375x18] baseline: 13.796875
"hello hello hello hello "
frag 3 from TextNode start: 109, length: 11, rect: [190.375,47 81.6875x18] baseline: 13.796875
"hello hello"
frag 4 from TextNode start: 121, length: 35, rect: [11,65 261.0625x18] baseline: 13.796875
"hello hello hello hello hello hello"
frag 3 from TextNode start: 109, length: 35, rect: [11,65 261.0625x18] baseline: 13.796875
frag 5 from TextNode start: 157, length: 35, rect: [11,83 261.0625x18] baseline: 13.796875
"hello hello hello hello hello hello"
frag 4 from TextNode start: 145, length: 35, rect: [11,83 261.0625x18] baseline: 13.796875
"hello hello hello hello hello hello"
frag 5 from TextNode start: 181, length: 11, rect: [11,101 81.6875x18] baseline: 13.796875
frag 6 from TextNode start: 193, length: 11, rect: [11,101 81.6875x18] baseline: 13.796875
"hello hello"
TextNode <#text> (not painted)
BlockContainer <div> at [11,119] [0+0+0 270 0+0+0] [0+0+0 0 0+0+0] children: not-inline

View file

@ -18,7 +18,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> (not painted)
BlockContainer <td> at [28.296875,10] table-cell [0+1+1 20.40625 1+1+0] [0+1+1 36 1+1+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 1, rect: [28.296875,10 9.34375x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 1, rect: [28.296875,10 9.34375x18] baseline: 13.796875
"B"
frag 1 from TextNode start: 0, length: 1, rect: [28.296875,28 10.3125x18] baseline: 13.796875
"C"
@ -28,7 +28,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> (not painted)
BlockContainer <td> at [52.703125,19] table-cell [0+1+1 14.296875 1+1+0] [0+1+10 18 10+1+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 1, rect: [52.703125,19 11.140625x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 1, rect: [52.703125,19 11.140625x18] baseline: 13.796875
"D"
TextNode <#text> (not painted)
BlockContainer <(anonymous)> (not painted) children: inline

View file

@ -8,9 +8,9 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> (not painted)
BlockContainer <caption> at [8,8] [0+0+0 59.046875 0+0+0] [0+0+0 36 0+0+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 6, rect: [10.5,8 54.03125x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 6, rect: [10.5,8 54.03125x18] baseline: 13.796875
"A long"
frag 1 from TextNode start: 8, length: 7, rect: [8,26 59.046875x18] baseline: 13.796875
frag 1 from TextNode start: 12, length: 7, rect: [8,26 59.046875x18] baseline: 13.796875
"caption"
TextNode <#text> (not painted)
BlockContainer <(anonymous)> (not painted) children: inline

View file

@ -6,7 +6,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> (not painted)
BlockContainer <caption> at [8,8] [0+0+0 60.46875 0+0+0] [0+0+10 18 10+0+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 7, rect: [8,8 60.46875x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 7, rect: [8,8 60.46875x18] baseline: 13.796875
"Caption"
TextNode <#text> (not painted)
BlockContainer <(anonymous)> (not painted) children: inline

View file

@ -12,19 +12,19 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> (not painted)
BlockContainer <td> at [10,10] table-cell [0+1+1 216.09375 1+1+0] [0+1+1 18 1+1+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 1, rect: [10,10 14.265625x18] baseline: 13.796875
frag 0 from TextNode start: 17, length: 1, rect: [10,10 14.265625x18] baseline: 13.796875
"A"
TextNode <#text> (not painted)
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> (not painted)
BlockContainer <td> at [230.09375,10] table-cell [0+1+1 156.796875 1+1+0] [0+1+1 18 1+1+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 1, rect: [230.09375,10 9.34375x18] baseline: 13.796875
frag 0 from TextNode start: 17, length: 1, rect: [230.09375,10 9.34375x18] baseline: 13.796875
"B"
TextNode <#text> (not painted)
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> (not painted)
BlockContainer <td> at [390.890625,10] table-cell [0+1+1 399.109375 1+1+0] [0+1+1 18 1+1+0] [BFC] children: inline
frag 0 from TextNode start: 1, length: 3, rect: [390.890625,10 29.453125x18] baseline: 13.796875
frag 0 from TextNode start: 17, length: 3, rect: [390.890625,10 29.453125x18] baseline: 13.796875
"C D"
TextNode <#text> (not painted)
BlockContainer <(anonymous)> (not painted) children: inline

View file

@ -2,65 +2,65 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <html> at [0,0] [0+0+0 800 0+0+0] [0+0+0 118 0+0+0] [BFC] children: not-inline
BlockContainer <body> at [8,8] [8+0+0 784 0+0+8] [8+0+0 102 0+0+8] children: not-inline
BlockContainer <div> at [9,9] [0+1+0 100 0+1+682] [0+1+0 100 0+1+0] children: inline
frag 0 from TextNode start: 1, length: 3, rect: [9,9 27.15625x18] baseline: 13.796875
frag 0 from TextNode start: 5, length: 3, rect: [9,9 27.15625x18] baseline: 13.796875
"foo"
frag 1 from TextNode start: 4, length: 1, rect: [36.15625,9 9x18] baseline: 13.796875
frag 1 from TextNode start: 8, length: 1, rect: [36.15625,9 9x18] baseline: 13.796875
" "
frag 2 from TextNode start: 5, length: 3, rect: [45.15625,9 27.640625x18] baseline: 13.796875
frag 2 from TextNode start: 9, length: 3, rect: [45.15625,9 27.640625x18] baseline: 13.796875
"bar"
frag 3 from TextNode start: 8, length: 1, rect: [72.796875,9 9x18] baseline: 13.796875
frag 3 from TextNode start: 12, length: 1, rect: [72.796875,9 9x18] baseline: 13.796875
" "
frag 4 from TextNode start: 9, length: 3, rect: [81.796875,9 27.203125x18] baseline: 13.796875
frag 4 from TextNode start: 13, length: 3, rect: [81.796875,9 27.203125x18] baseline: 13.796875
"baz"
frag 5 from TextNode start: 13, length: 3, rect: [9,27 27.15625x18] baseline: 13.796875
frag 5 from TextNode start: 21, length: 3, rect: [9,27 27.15625x18] baseline: 13.796875
"foo"
frag 6 from TextNode start: 16, length: 1, rect: [36.15625,27 8x18] baseline: 13.796875
frag 6 from TextNode start: 24, length: 1, rect: [36.15625,27 8x18] baseline: 13.796875
" "
frag 7 from TextNode start: 17, length: 3, rect: [44.15625,27 27.640625x18] baseline: 13.796875
frag 7 from TextNode start: 25, length: 3, rect: [44.15625,27 27.640625x18] baseline: 13.796875
"bar"
frag 8 from TextNode start: 20, length: 1, rect: [71.796875,27 8x18] baseline: 13.796875
frag 8 from TextNode start: 28, length: 1, rect: [71.796875,27 8x18] baseline: 13.796875
" "
frag 9 from TextNode start: 21, length: 3, rect: [79.796875,27 27.203125x18] baseline: 13.796875
frag 9 from TextNode start: 29, length: 3, rect: [79.796875,27 27.203125x18] baseline: 13.796875
"baz"
frag 10 from TextNode start: 1, length: 3, rect: [9,45 27.15625x18] baseline: 13.796875
frag 10 from TextNode start: 5, length: 3, rect: [9,45 27.15625x18] baseline: 13.796875
"foo"
frag 11 from TextNode start: 4, length: 1, rect: [36.15625,45 9x18] baseline: 13.796875
frag 11 from TextNode start: 8, length: 1, rect: [36.15625,45 9x18] baseline: 13.796875
" "
frag 12 from TextNode start: 5, length: 3, rect: [45.15625,45 27.640625x18] baseline: 13.796875
frag 12 from TextNode start: 9, length: 3, rect: [45.15625,45 27.640625x18] baseline: 13.796875
"bar"
frag 13 from TextNode start: 8, length: 1, rect: [72.796875,45 9x18] baseline: 13.796875
frag 13 from TextNode start: 12, length: 1, rect: [72.796875,45 9x18] baseline: 13.796875
" "
frag 14 from TextNode start: 9, length: 3, rect: [81.796875,45 27.203125x18] baseline: 13.796875
frag 14 from TextNode start: 13, length: 3, rect: [81.796875,45 27.203125x18] baseline: 13.796875
"baz"
frag 15 from TextNode start: 13, length: 3, rect: [9,63 27.15625x18] baseline: 13.796875
frag 15 from TextNode start: 21, length: 3, rect: [9,63 27.15625x18] baseline: 13.796875
"foo"
frag 16 from TextNode start: 16, length: 1, rect: [36.15625,63 9x18] baseline: 13.796875
frag 16 from TextNode start: 24, length: 1, rect: [36.15625,63 9x18] baseline: 13.796875
" "
frag 17 from TextNode start: 17, length: 3, rect: [45.15625,63 27.640625x18] baseline: 13.796875
frag 17 from TextNode start: 25, length: 3, rect: [45.15625,63 27.640625x18] baseline: 13.796875
"bar"
frag 18 from TextNode start: 20, length: 1, rect: [72.796875,63 9x18] baseline: 13.796875
frag 18 from TextNode start: 28, length: 1, rect: [72.796875,63 9x18] baseline: 13.796875
" "
frag 19 from TextNode start: 21, length: 3, rect: [81.796875,63 27.203125x18] baseline: 13.796875
frag 19 from TextNode start: 29, length: 3, rect: [81.796875,63 27.203125x18] baseline: 13.796875
"baz"
frag 20 from TextNode start: 25, length: 3, rect: [9,81 27.15625x18] baseline: 13.796875
frag 20 from TextNode start: 37, length: 3, rect: [9,81 27.15625x18] baseline: 13.796875
"foo"
frag 21 from TextNode start: 28, length: 1, rect: [36.15625,81 8x18] baseline: 13.796875
frag 21 from TextNode start: 40, length: 1, rect: [36.15625,81 8x18] baseline: 13.796875
" "
frag 22 from TextNode start: 29, length: 3, rect: [44.15625,81 27.640625x18] baseline: 13.796875
frag 22 from TextNode start: 41, length: 3, rect: [44.15625,81 27.640625x18] baseline: 13.796875
"bar"
frag 23 from TextNode start: 32, length: 1, rect: [71.796875,81 8x18] baseline: 13.796875
frag 23 from TextNode start: 44, length: 1, rect: [71.796875,81 8x18] baseline: 13.796875
" "
frag 24 from TextNode start: 33, length: 3, rect: [79.796875,81 27.203125x18] baseline: 13.796875
frag 24 from TextNode start: 45, length: 3, rect: [79.796875,81 27.203125x18] baseline: 13.796875
"baz"
frag 25 from TextNode start: 1, length: 3, rect: [9,99 27.15625x18] baseline: 13.796875
frag 25 from TextNode start: 5, length: 3, rect: [9,99 27.15625x18] baseline: 13.796875
"foo"
frag 26 from TextNode start: 4, length: 1, rect: [36.15625,99 8x18] baseline: 13.796875
frag 26 from TextNode start: 8, length: 1, rect: [36.15625,99 8x18] baseline: 13.796875
" "
frag 27 from TextNode start: 5, length: 3, rect: [44.15625,99 27.640625x18] baseline: 13.796875
frag 27 from TextNode start: 9, length: 3, rect: [44.15625,99 27.640625x18] baseline: 13.796875
"bar"
frag 28 from TextNode start: 8, length: 1, rect: [71.796875,99 8x18] baseline: 13.796875
frag 28 from TextNode start: 12, length: 1, rect: [71.796875,99 8x18] baseline: 13.796875
" "
frag 29 from TextNode start: 9, length: 3, rect: [79.796875,99 27.203125x18] baseline: 13.796875
frag 29 from TextNode start: 13, length: 3, rect: [79.796875,99 27.203125x18] baseline: 13.796875
"baz"
TextNode <#text> (not painted)
BreakNode <br> (not painted)

View file

@ -4,7 +4,7 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
BlockContainer <(anonymous)> at [8,16] [0+0+0 784 0+0+0] [0+0+0 0 0+0+0] children: inline
TextNode <#text> (not painted)
BlockContainer <p> at [8,16] [0+0+0 784 0+0+0] [16+0+0 18 0+0+16] children: inline
frag 0 from TextNode start: 1, length: 5, rect: [8,16 29.21875x18] baseline: 13.796875
frag 0 from TextNode start: 3, length: 5, rect: [8,16 29.21875x18] baseline: 13.796875
"好啦朋友們"
TextNode <#text> (not painted)
BlockContainer <(anonymous)> at [8,50] [0+0+0 784 0+0+0] [0+0+0 0 0+0+0] children: inline

View file

@ -1 +1 @@
Selected range: 6 - 11
Selected range: 10 - 15

View file

@ -1,4 +1,4 @@
Events:
selectionchange anchorNode=<#text > anchorOffset=1 type=Caret focusNode=<#text > focusOffset=1 isCollapsed=true
selectionchange anchorNode=<#text > anchorOffset=1 type=Caret focusNode=<#text > focusOffset=1 isCollapsed=true
selectionchange anchorNode=<#text > anchorOffset=2 type=Caret focusNode=<#text > focusOffset=2 isCollapsed=true
selectionchange anchorNode=<#text > anchorOffset=6 type=Caret focusNode=<#text > focusOffset=6 isCollapsed=true
selectionchange anchorNode=<#text > anchorOffset=6 type=Caret focusNode=<#text > focusOffset=6 isCollapsed=true
selectionchange anchorNode=<#text > anchorOffset=7 type=Caret focusNode=<#text > focusOffset=7 isCollapsed=true

View file

@ -2,8 +2,8 @@ Harness status: OK
Found 272 tests
210 Pass
62 Fail
212 Pass
60 Fail
Pass Simplest possible test ("<div>abc")
Fail Leading whitespace removed ("<div> abc")
Fail Trailing whitespace removed ("<div>abc ")
@ -35,8 +35,8 @@ Pass \t preserved ("<span style='white-space:pre'>abc\tdef")
Fail Leading whitespace removed ("<div style='white-space:pre-line'> abc")
Fail Trailing whitespace removed ("<div style='white-space:pre-line'>abc ")
Pass Internal whitespace collapsed ("<div style='white-space:pre-line'>abc def")
Fail \n preserved ("<div style='white-space:pre-line'>abc\ndef")
Fail \r converted to newline ("<div style='white-space:pre-line'>abc\rdef")
Pass \n preserved ("<div style='white-space:pre-line'>abc\ndef")
Pass \r converted to newline ("<div style='white-space:pre-line'>abc\rdef")
Pass \t converted to space ("<div style='white-space:pre-line'>abc\tdef")
Fail Whitespace collapses across element boundaries ("<div><span>abc </span> def")
Fail Whitespace collapses across element boundaries ("<div><span>abc </span><span></span> def")

View file

@ -2,6 +2,6 @@ Harness status: OK
Found 2 tests
2 Fail
Fail innerText should be the same for the pre-line and pre examples
Fail innerText has collapsed whitespace but preserved newlines with pre-line
2 Pass
Pass innerText should be the same for the pre-line and pre examples
Pass innerText has collapsed whitespace but preserved newlines with pre-line

View file

@ -6,6 +6,7 @@
internals.doubleclick(85, 20);
const selection = document.getSelection().getRangeAt(0);
// FIXME: This should output 6-15 instead of 10-15
println(`Selected range: ${selection.startOffset} - ${selection.endOffset}`);
});
</script>