mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 10:47:35 +00:00
LibWeb: Rename directory LibHTML => LibWeb
Let's rename this to LibWeb since it aims to provide more parts of the web platform than just HTML. :^)
This commit is contained in:
parent
7a6c4a72d5
commit
830a57c6b2
158 changed files with 360 additions and 360 deletions
49
Libraries/LibWeb/Layout/BoxModelMetrics.cpp
Normal file
49
Libraries/LibWeb/Layout/BoxModelMetrics.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/Layout/BoxModelMetrics.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
BoxModelMetrics::BoxModelMetrics()
|
||||
{
|
||||
}
|
||||
|
||||
BoxModelMetrics::~BoxModelMetrics()
|
||||
{
|
||||
}
|
||||
|
||||
BoxModelMetrics::PixelBox BoxModelMetrics::full_margin() const
|
||||
{
|
||||
return {
|
||||
m_margin.top.to_px() + m_border.top.to_px() + m_padding.top.to_px(),
|
||||
m_margin.right.to_px() + m_border.right.to_px() + m_padding.right.to_px(),
|
||||
m_margin.bottom.to_px() + m_border.bottom.to_px() + m_padding.bottom.to_px(),
|
||||
m_margin.left.to_px() + m_border.left.to_px() + m_padding.left.to_px(),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
62
Libraries/LibWeb/Layout/BoxModelMetrics.h
Normal file
62
Libraries/LibWeb/Layout/BoxModelMetrics.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibGfx/Size.h>
|
||||
#include <LibWeb/CSS/LengthBox.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class BoxModelMetrics {
|
||||
public:
|
||||
BoxModelMetrics();
|
||||
~BoxModelMetrics();
|
||||
|
||||
LengthBox& margin() { return m_margin; }
|
||||
LengthBox& padding() { return m_padding; }
|
||||
LengthBox& border() { return m_border; }
|
||||
|
||||
const LengthBox& margin() const { return m_margin; }
|
||||
const LengthBox& padding() const { return m_padding; }
|
||||
const LengthBox& border() const { return m_border; }
|
||||
|
||||
struct PixelBox {
|
||||
float top;
|
||||
float right;
|
||||
float bottom;
|
||||
float left;
|
||||
};
|
||||
|
||||
PixelBox full_margin() const;
|
||||
|
||||
private:
|
||||
LengthBox m_margin;
|
||||
LengthBox m_padding;
|
||||
LengthBox m_border;
|
||||
};
|
||||
|
||||
}
|
390
Libraries/LibWeb/Layout/LayoutBlock.cpp
Normal file
390
Libraries/LibWeb/Layout/LayoutBlock.cpp
Normal file
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibWeb/CSS/StyleResolver.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/Layout/LayoutBlock.h>
|
||||
#include <LibWeb/Layout/LayoutInline.h>
|
||||
#include <LibWeb/Layout/LayoutReplaced.h>
|
||||
#include <LibWeb/Layout/LayoutText.h>
|
||||
#include <math.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutBlock::LayoutBlock(const Node* node, NonnullRefPtr<StyleProperties> style)
|
||||
: LayoutBox(node, move(style))
|
||||
{
|
||||
}
|
||||
|
||||
LayoutBlock::~LayoutBlock()
|
||||
{
|
||||
}
|
||||
|
||||
LayoutNode& LayoutBlock::inline_wrapper()
|
||||
{
|
||||
if (!last_child() || !last_child()->is_block() || last_child()->node() != nullptr) {
|
||||
append_child(adopt(*new LayoutBlock(nullptr, style_for_anonymous_block())));
|
||||
last_child()->set_children_are_inline(true);
|
||||
}
|
||||
return *last_child();
|
||||
}
|
||||
|
||||
void LayoutBlock::layout()
|
||||
{
|
||||
compute_width();
|
||||
compute_position();
|
||||
|
||||
if (children_are_inline())
|
||||
layout_inline_children();
|
||||
else
|
||||
layout_block_children();
|
||||
|
||||
compute_height();
|
||||
}
|
||||
|
||||
void LayoutBlock::layout_block_children()
|
||||
{
|
||||
ASSERT(!children_are_inline());
|
||||
float content_height = 0;
|
||||
for_each_child([&](auto& child) {
|
||||
// FIXME: What should we do here? Something like a <table> might have a bunch of useless text children..
|
||||
if (child.is_inline())
|
||||
return;
|
||||
auto& child_block = static_cast<LayoutBlock&>(child);
|
||||
child_block.layout();
|
||||
content_height = child_block.rect().bottom() + child_block.box_model().full_margin().bottom - rect().top();
|
||||
});
|
||||
rect().set_height(content_height);
|
||||
}
|
||||
|
||||
void LayoutBlock::layout_inline_children()
|
||||
{
|
||||
ASSERT(children_are_inline());
|
||||
m_line_boxes.clear();
|
||||
for_each_child([&](auto& child) {
|
||||
ASSERT(child.is_inline());
|
||||
child.split_into_lines(*this);
|
||||
});
|
||||
|
||||
for (auto& line_box : m_line_boxes) {
|
||||
line_box.trim_trailing_whitespace();
|
||||
}
|
||||
|
||||
float min_line_height = style().line_height();
|
||||
float line_spacing = min_line_height - style().font().glyph_height();
|
||||
float content_height = 0;
|
||||
|
||||
// FIXME: This should be done by the CSS parser!
|
||||
CSS::ValueID text_align = CSS::ValueID::Left;
|
||||
auto text_align_string = style().string_or_fallback(CSS::PropertyID::TextAlign, "left");
|
||||
if (text_align_string == "center")
|
||||
text_align = CSS::ValueID::Center;
|
||||
else if (text_align_string == "left")
|
||||
text_align = CSS::ValueID::Left;
|
||||
else if (text_align_string == "right")
|
||||
text_align = CSS::ValueID::Right;
|
||||
else if (text_align_string == "justify")
|
||||
text_align = CSS::ValueID::Justify;
|
||||
|
||||
for (auto& line_box : m_line_boxes) {
|
||||
float max_height = min_line_height;
|
||||
for (auto& fragment : line_box.fragments()) {
|
||||
max_height = max(max_height, fragment.rect().height());
|
||||
}
|
||||
|
||||
float x_offset = x();
|
||||
float excess_horizontal_space = (float)width() - line_box.width();
|
||||
|
||||
switch (text_align) {
|
||||
case CSS::ValueID::Center:
|
||||
x_offset += excess_horizontal_space / 2;
|
||||
break;
|
||||
case CSS::ValueID::Right:
|
||||
x_offset += excess_horizontal_space;
|
||||
break;
|
||||
case CSS::ValueID::Left:
|
||||
case CSS::ValueID::Justify:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
float excess_horizontal_space_including_whitespace = excess_horizontal_space;
|
||||
int whitespace_count = 0;
|
||||
if (text_align == CSS::ValueID::Justify) {
|
||||
for (auto& fragment : line_box.fragments()) {
|
||||
if (fragment.is_justifiable_whitespace()) {
|
||||
++whitespace_count;
|
||||
excess_horizontal_space_including_whitespace += fragment.rect().width();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float justified_space_width = whitespace_count ? (excess_horizontal_space_including_whitespace / (float)whitespace_count) : 0;
|
||||
|
||||
for (size_t i = 0; i < line_box.fragments().size(); ++i) {
|
||||
auto& fragment = line_box.fragments()[i];
|
||||
// Vertically align everyone's bottom to the line.
|
||||
// FIXME: Support other kinds of vertical alignment.
|
||||
fragment.rect().set_x(roundf(x_offset + fragment.rect().x()));
|
||||
fragment.rect().set_y(y() + content_height + (max_height - fragment.rect().height()) - (line_spacing / 2));
|
||||
|
||||
if (text_align == CSS::ValueID::Justify) {
|
||||
if (fragment.is_justifiable_whitespace()) {
|
||||
if (fragment.rect().width() != justified_space_width) {
|
||||
float diff = justified_space_width - fragment.rect().width();
|
||||
fragment.rect().set_width(justified_space_width);
|
||||
// Shift subsequent sibling fragments to the right to adjust for change in width.
|
||||
for (size_t j = i + 1; j < line_box.fragments().size(); ++j) {
|
||||
line_box.fragments()[j].rect().move_by(diff, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is<LayoutReplaced>(fragment.layout_node()))
|
||||
const_cast<LayoutReplaced&>(to<LayoutReplaced>(fragment.layout_node())).set_rect(fragment.rect());
|
||||
|
||||
float final_line_box_width = 0;
|
||||
for (auto& fragment : line_box.fragments())
|
||||
final_line_box_width += fragment.rect().width();
|
||||
line_box.m_width = final_line_box_width;
|
||||
}
|
||||
|
||||
content_height += max_height;
|
||||
}
|
||||
|
||||
rect().set_height(content_height);
|
||||
}
|
||||
|
||||
void LayoutBlock::compute_width()
|
||||
{
|
||||
auto& style = this->style();
|
||||
|
||||
auto auto_value = Length();
|
||||
auto zero_value = Length(0, Length::Type::Absolute);
|
||||
|
||||
Length margin_left;
|
||||
Length margin_right;
|
||||
Length border_left;
|
||||
Length border_right;
|
||||
Length padding_left;
|
||||
Length padding_right;
|
||||
|
||||
auto try_compute_width = [&](const auto& a_width) {
|
||||
Length width = a_width;
|
||||
#ifdef HTML_DEBUG
|
||||
dbg() << " Left: " << margin_left << "+" << border_left << "+" << padding_left;
|
||||
dbg() << "Right: " << margin_right << "+" << border_right << "+" << padding_right;
|
||||
#endif
|
||||
margin_left = style.length_or_fallback(CSS::PropertyID::MarginLeft, zero_value);
|
||||
margin_right = style.length_or_fallback(CSS::PropertyID::MarginRight, zero_value);
|
||||
border_left = style.length_or_fallback(CSS::PropertyID::BorderLeftWidth, zero_value);
|
||||
border_right = style.length_or_fallback(CSS::PropertyID::BorderRightWidth, zero_value);
|
||||
padding_left = style.length_or_fallback(CSS::PropertyID::PaddingLeft, zero_value);
|
||||
padding_right = style.length_or_fallback(CSS::PropertyID::PaddingRight, zero_value);
|
||||
|
||||
float total_px = 0;
|
||||
for (auto& value : { margin_left, border_left, padding_left, width, padding_right, border_right, margin_right }) {
|
||||
total_px += value.to_px();
|
||||
}
|
||||
|
||||
#ifdef HTML_DEBUG
|
||||
dbg() << "Total: " << total_px;
|
||||
#endif
|
||||
|
||||
// 10.3.3 Block-level, non-replaced elements in normal flow
|
||||
// If 'width' is not 'auto' and 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' (plus any of 'margin-left' or 'margin-right' that are not 'auto') is larger than the width of the containing block, then any 'auto' values for 'margin-left' or 'margin-right' are, for the following rules, treated as zero.
|
||||
if (width.is_auto() && total_px > containing_block()->width()) {
|
||||
if (margin_left.is_auto())
|
||||
margin_left = zero_value;
|
||||
if (margin_right.is_auto())
|
||||
margin_right = zero_value;
|
||||
}
|
||||
|
||||
// 10.3.3 cont'd.
|
||||
auto underflow_px = containing_block()->width() - total_px;
|
||||
|
||||
if (width.is_auto()) {
|
||||
if (margin_left.is_auto())
|
||||
margin_left = zero_value;
|
||||
if (margin_right.is_auto())
|
||||
margin_right = zero_value;
|
||||
if (underflow_px >= 0) {
|
||||
width = Length(underflow_px, Length::Type::Absolute);
|
||||
} else {
|
||||
width = zero_value;
|
||||
margin_right = Length(margin_right.to_px() + underflow_px, Length::Type::Absolute);
|
||||
}
|
||||
} else {
|
||||
if (!margin_left.is_auto() && !margin_right.is_auto()) {
|
||||
margin_right = Length(margin_right.to_px() + underflow_px, Length::Type::Absolute);
|
||||
} else if (!margin_left.is_auto() && margin_right.is_auto()) {
|
||||
margin_right = Length(underflow_px, Length::Type::Absolute);
|
||||
} else if (margin_left.is_auto() && !margin_right.is_auto()) {
|
||||
margin_left = Length(underflow_px, Length::Type::Absolute);
|
||||
} else { // margin_left.is_auto() && margin_right.is_auto()
|
||||
auto half_of_the_underflow = Length(underflow_px / 2, Length::Type::Absolute);
|
||||
margin_left = half_of_the_underflow;
|
||||
margin_right = half_of_the_underflow;
|
||||
}
|
||||
}
|
||||
return width;
|
||||
};
|
||||
|
||||
auto specified_width = style.length_or_fallback(CSS::PropertyID::Width, auto_value);
|
||||
|
||||
// 1. The tentative used width is calculated (without 'min-width' and 'max-width')
|
||||
auto used_width = try_compute_width(specified_width);
|
||||
|
||||
// 2. The tentative used width is greater than 'max-width', the rules above are applied again,
|
||||
// but this time using the computed value of 'max-width' as the computed value for 'width'.
|
||||
auto specified_max_width = style.length_or_fallback(CSS::PropertyID::MaxWidth, auto_value);
|
||||
if (!specified_max_width.is_auto()) {
|
||||
if (used_width.to_px() > specified_max_width.to_px()) {
|
||||
used_width = try_compute_width(specified_max_width);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. If the resulting width is smaller than 'min-width', the rules above are applied again,
|
||||
// but this time using the value of 'min-width' as the computed value for 'width'.
|
||||
auto specified_min_width = style.length_or_fallback(CSS::PropertyID::MinWidth, auto_value);
|
||||
if (!specified_min_width.is_auto()) {
|
||||
if (used_width.to_px() < specified_min_width.to_px()) {
|
||||
used_width = try_compute_width(specified_min_width);
|
||||
}
|
||||
}
|
||||
|
||||
rect().set_width(used_width.to_px());
|
||||
box_model().margin().left = margin_left;
|
||||
box_model().margin().right = margin_right;
|
||||
box_model().border().left = border_left;
|
||||
box_model().border().right = border_right;
|
||||
box_model().padding().left = padding_left;
|
||||
box_model().padding().right = padding_right;
|
||||
}
|
||||
|
||||
void LayoutBlock::compute_position()
|
||||
{
|
||||
auto& style = this->style();
|
||||
|
||||
auto auto_value = Length();
|
||||
auto zero_value = Length(0, Length::Type::Absolute);
|
||||
|
||||
auto width = style.length_or_fallback(CSS::PropertyID::Width, auto_value);
|
||||
|
||||
box_model().margin().top = style.length_or_fallback(CSS::PropertyID::MarginTop, zero_value);
|
||||
box_model().margin().bottom = style.length_or_fallback(CSS::PropertyID::MarginBottom, zero_value);
|
||||
box_model().border().top = style.length_or_fallback(CSS::PropertyID::BorderTopWidth, zero_value);
|
||||
box_model().border().bottom = style.length_or_fallback(CSS::PropertyID::BorderBottomWidth, zero_value);
|
||||
box_model().padding().top = style.length_or_fallback(CSS::PropertyID::PaddingTop, zero_value);
|
||||
box_model().padding().bottom = style.length_or_fallback(CSS::PropertyID::PaddingBottom, zero_value);
|
||||
rect().set_x(containing_block()->x() + box_model().margin().left.to_px() + box_model().border().left.to_px() + box_model().padding().left.to_px());
|
||||
|
||||
float top_border = -1;
|
||||
if (previous_sibling() != nullptr) {
|
||||
auto& previous_sibling_rect = previous_sibling()->rect();
|
||||
auto& previous_sibling_style = previous_sibling()->box_model();
|
||||
top_border = previous_sibling_rect.y() + previous_sibling_rect.height();
|
||||
top_border += previous_sibling_style.full_margin().bottom;
|
||||
} else {
|
||||
top_border = containing_block()->y();
|
||||
}
|
||||
rect().set_y(top_border + box_model().full_margin().top);
|
||||
}
|
||||
|
||||
void LayoutBlock::compute_height()
|
||||
{
|
||||
auto& style = this->style();
|
||||
|
||||
auto height_property = style.property(CSS::PropertyID::Height);
|
||||
if (!height_property.has_value())
|
||||
return;
|
||||
auto height_length = height_property.value()->to_length();
|
||||
if (height_length.is_absolute())
|
||||
rect().set_height(height_length.to_px());
|
||||
}
|
||||
|
||||
void LayoutBlock::render(RenderingContext& context)
|
||||
{
|
||||
if (!is_visible())
|
||||
return;
|
||||
|
||||
LayoutBox::render(context);
|
||||
|
||||
if (children_are_inline()) {
|
||||
for (auto& line_box : m_line_boxes) {
|
||||
for (auto& fragment : line_box.fragments()) {
|
||||
if (context.should_show_line_box_borders())
|
||||
context.painter().draw_rect(enclosing_int_rect(fragment.rect()), Color::Green);
|
||||
fragment.render(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HitTestResult LayoutBlock::hit_test(const Gfx::Point& position) const
|
||||
{
|
||||
if (!children_are_inline())
|
||||
return LayoutBox::hit_test(position);
|
||||
|
||||
HitTestResult result;
|
||||
for (auto& line_box : m_line_boxes) {
|
||||
for (auto& fragment : line_box.fragments()) {
|
||||
if (enclosing_int_rect(fragment.rect()).contains(position)) {
|
||||
return { fragment.layout_node(), fragment.text_index_at(position.x()) };
|
||||
}
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
NonnullRefPtr<StyleProperties> LayoutBlock::style_for_anonymous_block() const
|
||||
{
|
||||
auto new_style = StyleProperties::create();
|
||||
|
||||
style().for_each_property([&](auto property_id, auto& value) {
|
||||
if (StyleResolver::is_inherited_property(property_id))
|
||||
new_style->set_property(property_id, value);
|
||||
});
|
||||
|
||||
return new_style;
|
||||
}
|
||||
|
||||
LineBox& LayoutBlock::ensure_last_line_box()
|
||||
{
|
||||
if (m_line_boxes.is_empty())
|
||||
m_line_boxes.append(LineBox());
|
||||
return m_line_boxes.last();
|
||||
}
|
||||
|
||||
LineBox& LayoutBlock::add_line_box()
|
||||
{
|
||||
m_line_boxes.append(LineBox());
|
||||
return m_line_boxes.last();
|
||||
}
|
||||
|
||||
}
|
109
Libraries/LibWeb/Layout/LayoutBlock.h
Normal file
109
Libraries/LibWeb/Layout/LayoutBlock.h
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Layout/LayoutBox.h>
|
||||
#include <LibWeb/Layout/LineBox.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class Element;
|
||||
|
||||
class LayoutBlock : public LayoutBox {
|
||||
public:
|
||||
LayoutBlock(const Node*, NonnullRefPtr<StyleProperties>);
|
||||
virtual ~LayoutBlock() override;
|
||||
|
||||
virtual const char* class_name() const override { return "LayoutBlock"; }
|
||||
|
||||
virtual void layout() override;
|
||||
virtual void render(RenderingContext&) override;
|
||||
|
||||
virtual LayoutNode& inline_wrapper() override;
|
||||
|
||||
Vector<LineBox>& line_boxes() { return m_line_boxes; }
|
||||
const Vector<LineBox>& line_boxes() const { return m_line_boxes; }
|
||||
|
||||
LineBox& ensure_last_line_box();
|
||||
LineBox& add_line_box();
|
||||
|
||||
virtual HitTestResult hit_test(const Gfx::Point&) const override;
|
||||
|
||||
LayoutBlock* previous_sibling() { return to<LayoutBlock>(LayoutNode::previous_sibling()); }
|
||||
const LayoutBlock* previous_sibling() const { return to<LayoutBlock>(LayoutNode::previous_sibling()); }
|
||||
LayoutBlock* next_sibling() { return to<LayoutBlock>(LayoutNode::next_sibling()); }
|
||||
const LayoutBlock* next_sibling() const { return to<LayoutBlock>(LayoutNode::next_sibling()); }
|
||||
|
||||
template<typename Callback>
|
||||
void for_each_fragment(Callback);
|
||||
template<typename Callback>
|
||||
void for_each_fragment(Callback) const;
|
||||
|
||||
private:
|
||||
virtual bool is_block() const override { return true; }
|
||||
|
||||
NonnullRefPtr<StyleProperties> style_for_anonymous_block() const;
|
||||
|
||||
void layout_inline_children();
|
||||
void layout_block_children();
|
||||
|
||||
void compute_width();
|
||||
void compute_position();
|
||||
void compute_height();
|
||||
|
||||
Vector<LineBox> m_line_boxes;
|
||||
};
|
||||
|
||||
template<typename Callback>
|
||||
void LayoutBlock::for_each_fragment(Callback callback)
|
||||
{
|
||||
for (auto& line_box : line_boxes()) {
|
||||
for (auto& fragment : line_box.fragments()) {
|
||||
if (callback(fragment) == IterationDecision::Break)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Callback>
|
||||
void LayoutBlock::for_each_fragment(Callback callback) const
|
||||
{
|
||||
for (auto& line_box : line_boxes()) {
|
||||
for (auto& fragment : line_box.fragments()) {
|
||||
if (callback(fragment) == IterationDecision::Break)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool is<LayoutBlock>(const LayoutNode& node)
|
||||
{
|
||||
return node.is_block();
|
||||
}
|
||||
|
||||
}
|
244
Libraries/LibWeb/Layout/LayoutBox.cpp
Normal file
244
Libraries/LibWeb/Layout/LayoutBox.cpp
Normal file
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/HTMLBodyElement.h>
|
||||
#include <LibWeb/Frame.h>
|
||||
#include <LibWeb/Layout/LayoutBlock.h>
|
||||
#include <LibWeb/Layout/LayoutBox.h>
|
||||
|
||||
//#define DRAW_BOXES_AROUND_LAYOUT_NODES
|
||||
//#define DRAW_BOXES_AROUND_HOVERED_NODES
|
||||
|
||||
namespace Web {
|
||||
|
||||
void LayoutBox::paint_border(RenderingContext& context, Edge edge, const Gfx::FloatRect& rect, CSS::PropertyID style_property_id, CSS::PropertyID color_property_id, CSS::PropertyID width_property_id)
|
||||
{
|
||||
auto border_width = style().property(width_property_id);
|
||||
if (!border_width.has_value())
|
||||
return;
|
||||
|
||||
auto border_style = style().property(style_property_id);
|
||||
float width = border_width.value()->to_length().to_px();
|
||||
|
||||
int int_width = max((int)width, 1);
|
||||
|
||||
Color color;
|
||||
auto border_color = style().property(color_property_id);
|
||||
if (border_color.has_value()) {
|
||||
color = border_color.value()->to_color(document());
|
||||
} else {
|
||||
// FIXME: This is basically CSS "currentColor" which should be handled elsewhere
|
||||
// in a much more reusable way.
|
||||
auto current_color = style().property(CSS::PropertyID::Color);
|
||||
if (current_color.has_value())
|
||||
color = current_color.value()->to_color(document());
|
||||
else
|
||||
color = Color::Black;
|
||||
}
|
||||
|
||||
auto first_point_for_edge = [](Edge edge, const Gfx::FloatRect& rect) {
|
||||
switch (edge) {
|
||||
case Edge::Top:
|
||||
return rect.top_left();
|
||||
case Edge::Right:
|
||||
return rect.top_right();
|
||||
case Edge::Bottom:
|
||||
return rect.bottom_left();
|
||||
case Edge::Left:
|
||||
default:
|
||||
return rect.top_left();
|
||||
}
|
||||
};
|
||||
|
||||
auto second_point_for_edge = [](Edge edge, const Gfx::FloatRect& rect) {
|
||||
switch (edge) {
|
||||
case Edge::Top:
|
||||
return rect.top_right();
|
||||
case Edge::Right:
|
||||
return rect.bottom_right();
|
||||
case Edge::Bottom:
|
||||
return rect.bottom_right();
|
||||
case Edge::Left:
|
||||
default:
|
||||
return rect.bottom_left();
|
||||
}
|
||||
};
|
||||
|
||||
auto p1 = first_point_for_edge(edge, rect);
|
||||
auto p2 = second_point_for_edge(edge, rect);
|
||||
|
||||
if (border_style.has_value() && border_style.value()->to_string() == "inset") {
|
||||
auto top_left_color = Color::from_rgb(0x5a5a5a);
|
||||
auto bottom_right_color = Color::from_rgb(0x888888);
|
||||
color = (edge == Edge::Left || edge == Edge::Top) ? top_left_color : bottom_right_color;
|
||||
} else if (border_style.has_value() && border_style.value()->to_string() == "outset") {
|
||||
auto top_left_color = Color::from_rgb(0x888888);
|
||||
auto bottom_right_color = Color::from_rgb(0x5a5a5a);
|
||||
color = (edge == Edge::Left || edge == Edge::Top) ? top_left_color : bottom_right_color;
|
||||
}
|
||||
|
||||
bool dotted = border_style.has_value() && border_style.value()->to_string() == "dotted";
|
||||
|
||||
auto draw_line = [&](auto& p1, auto& p2) {
|
||||
context.painter().draw_line({ (int)p1.x(), (int)p1.y() }, { (int)p2.x(), (int)p2.y() }, color, 1, dotted);
|
||||
};
|
||||
|
||||
auto width_for = [&](CSS::PropertyID property_id) -> float {
|
||||
auto width = style().property(property_id);
|
||||
if (!width.has_value())
|
||||
return 0;
|
||||
return width.value()->to_length().to_px();
|
||||
};
|
||||
|
||||
float p1_step = 0;
|
||||
float p2_step = 0;
|
||||
|
||||
switch (edge) {
|
||||
case Edge::Top:
|
||||
p1_step = width_for(CSS::PropertyID::BorderLeftWidth) / (float)int_width;
|
||||
p2_step = width_for(CSS::PropertyID::BorderRightWidth) / (float)int_width;
|
||||
for (int i = 0; i < int_width; ++i) {
|
||||
draw_line(p1, p2);
|
||||
p1.move_by(p1_step, 1);
|
||||
p2.move_by(-p2_step, 1);
|
||||
}
|
||||
break;
|
||||
case Edge::Right:
|
||||
p1_step = width_for(CSS::PropertyID::BorderTopWidth) / (float)int_width;
|
||||
p2_step = width_for(CSS::PropertyID::BorderBottomWidth) / (float)int_width;
|
||||
for (int i = int_width - 1; i >= 0; --i) {
|
||||
draw_line(p1, p2);
|
||||
p1.move_by(-1, p1_step);
|
||||
p2.move_by(-1, -p2_step);
|
||||
}
|
||||
break;
|
||||
case Edge::Bottom:
|
||||
p1_step = width_for(CSS::PropertyID::BorderLeftWidth) / (float)int_width;
|
||||
p2_step = width_for(CSS::PropertyID::BorderRightWidth) / (float)int_width;
|
||||
for (int i = int_width - 1; i >= 0; --i) {
|
||||
draw_line(p1, p2);
|
||||
p1.move_by(p1_step, -1);
|
||||
p2.move_by(-p2_step, -1);
|
||||
}
|
||||
break;
|
||||
case Edge::Left:
|
||||
p1_step = width_for(CSS::PropertyID::BorderTopWidth) / (float)int_width;
|
||||
p2_step = width_for(CSS::PropertyID::BorderBottomWidth) / (float)int_width;
|
||||
for (int i = 0; i < int_width; ++i) {
|
||||
draw_line(p1, p2);
|
||||
p1.move_by(1, p1_step);
|
||||
p2.move_by(1, -p2_step);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutBox::render(RenderingContext& context)
|
||||
{
|
||||
if (!is_visible())
|
||||
return;
|
||||
|
||||
#ifdef DRAW_BOXES_AROUND_LAYOUT_NODES
|
||||
context.painter().draw_rect(m_rect, Color::Blue);
|
||||
#endif
|
||||
#ifdef DRAW_BOXES_AROUND_HOVERED_NODES
|
||||
if (!is_anonymous() && node() == document().hovered_node())
|
||||
context.painter().draw_rect(m_rect, Color::Red);
|
||||
#endif
|
||||
|
||||
if (node() && document().inspected_node() == node())
|
||||
context.painter().draw_rect(enclosing_int_rect(m_rect), Color::Magenta);
|
||||
|
||||
Gfx::FloatRect padded_rect;
|
||||
padded_rect.set_x(x() - box_model().padding().left.to_px());
|
||||
padded_rect.set_width(width() + box_model().padding().left.to_px() + box_model().padding().right.to_px());
|
||||
padded_rect.set_y(y() - box_model().padding().top.to_px());
|
||||
padded_rect.set_height(height() + box_model().padding().top.to_px() + box_model().padding().bottom.to_px());
|
||||
|
||||
if (!is_body()) {
|
||||
auto bgcolor = style().property(CSS::PropertyID::BackgroundColor);
|
||||
if (bgcolor.has_value() && bgcolor.value()->is_color()) {
|
||||
context.painter().fill_rect(enclosing_int_rect(padded_rect), bgcolor.value()->to_color(document()));
|
||||
}
|
||||
|
||||
auto bgimage = style().property(CSS::PropertyID::BackgroundImage);
|
||||
if (bgimage.has_value() && bgimage.value()->is_image()) {
|
||||
auto& image_value = static_cast<const ImageStyleValue&>(*bgimage.value());
|
||||
if (image_value.bitmap()) {
|
||||
context.painter().draw_tiled_bitmap(enclosing_int_rect(padded_rect), *image_value.bitmap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Gfx::FloatRect bordered_rect;
|
||||
bordered_rect.set_x(padded_rect.x() - box_model().border().left.to_px());
|
||||
bordered_rect.set_width(padded_rect.width() + box_model().border().left.to_px() + box_model().border().right.to_px());
|
||||
bordered_rect.set_y(padded_rect.y() - box_model().border().top.to_px());
|
||||
bordered_rect.set_height(padded_rect.height() + box_model().border().top.to_px() + box_model().border().bottom.to_px());
|
||||
|
||||
paint_border(context, Edge::Left, bordered_rect, CSS::PropertyID::BorderLeftStyle, CSS::PropertyID::BorderLeftColor, CSS::PropertyID::BorderLeftWidth);
|
||||
paint_border(context, Edge::Right, bordered_rect, CSS::PropertyID::BorderRightStyle, CSS::PropertyID::BorderRightColor, CSS::PropertyID::BorderRightWidth);
|
||||
paint_border(context, Edge::Top, bordered_rect, CSS::PropertyID::BorderTopStyle, CSS::PropertyID::BorderTopColor, CSS::PropertyID::BorderTopWidth);
|
||||
paint_border(context, Edge::Bottom, bordered_rect, CSS::PropertyID::BorderBottomStyle, CSS::PropertyID::BorderBottomColor, CSS::PropertyID::BorderBottomWidth);
|
||||
|
||||
LayoutNodeWithStyleAndBoxModelMetrics::render(context);
|
||||
}
|
||||
|
||||
HitTestResult LayoutBox::hit_test(const Gfx::Point& position) const
|
||||
{
|
||||
// FIXME: It would be nice if we could confidently skip over hit testing
|
||||
// parts of the layout tree, but currently we can't just check
|
||||
// m_rect.contains() since inline text rects can't be trusted..
|
||||
HitTestResult result { m_rect.contains(position.x(), position.y()) ? this : nullptr };
|
||||
for_each_child([&](auto& child) {
|
||||
auto child_result = child.hit_test(position);
|
||||
if (child_result.layout_node)
|
||||
result = child_result;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void LayoutBox::set_needs_display()
|
||||
{
|
||||
auto* frame = document().frame();
|
||||
ASSERT(frame);
|
||||
|
||||
if (!is_inline()) {
|
||||
const_cast<Frame*>(frame)->set_needs_display(enclosing_int_rect(rect()));
|
||||
return;
|
||||
}
|
||||
|
||||
LayoutNode::set_needs_display();
|
||||
}
|
||||
|
||||
bool LayoutBox::is_body() const
|
||||
{
|
||||
return node() && node() == document().body();
|
||||
}
|
||||
|
||||
}
|
80
Libraries/LibWeb/Layout/LayoutBox.h
Normal file
80
Libraries/LibWeb/Layout/LayoutBox.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibGfx/FloatRect.h>
|
||||
#include <LibWeb/Layout/LayoutNode.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LayoutBox : public LayoutNodeWithStyleAndBoxModelMetrics {
|
||||
public:
|
||||
const Gfx::FloatRect& rect() const { return m_rect; }
|
||||
Gfx::FloatRect& rect() { return m_rect; }
|
||||
void set_rect(const Gfx::FloatRect& rect) { m_rect = rect; }
|
||||
|
||||
float x() const { return rect().x(); }
|
||||
float y() const { return rect().y(); }
|
||||
float width() const { return rect().width(); }
|
||||
float height() const { return rect().height(); }
|
||||
Gfx::FloatSize size() const { return rect().size(); }
|
||||
Gfx::FloatPoint position() const { return rect().location(); }
|
||||
|
||||
virtual HitTestResult hit_test(const Gfx::Point& position) const override;
|
||||
virtual void set_needs_display() override;
|
||||
|
||||
bool is_body() const;
|
||||
|
||||
protected:
|
||||
LayoutBox(const Node* node, NonnullRefPtr<StyleProperties> style)
|
||||
: LayoutNodeWithStyleAndBoxModelMetrics(node, move(style))
|
||||
{
|
||||
}
|
||||
|
||||
virtual void render(RenderingContext&) override;
|
||||
|
||||
private:
|
||||
virtual bool is_box() const override { return true; }
|
||||
|
||||
enum class Edge {
|
||||
Top,
|
||||
Right,
|
||||
Bottom,
|
||||
Left,
|
||||
};
|
||||
void paint_border(RenderingContext&, Edge, const Gfx::FloatRect&, CSS::PropertyID style_property_id, CSS::PropertyID color_property_id, CSS::PropertyID width_property_id);
|
||||
|
||||
Gfx::FloatRect m_rect;
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool is<LayoutBox>(const LayoutNode& node)
|
||||
{
|
||||
return node.is_box();
|
||||
}
|
||||
|
||||
}
|
47
Libraries/LibWeb/Layout/LayoutBreak.cpp
Normal file
47
Libraries/LibWeb/Layout/LayoutBreak.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/Layout/LayoutBlock.h>
|
||||
#include <LibWeb/Layout/LayoutBreak.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutBreak::LayoutBreak(const HTMLBRElement& element)
|
||||
: LayoutNodeWithStyleAndBoxModelMetrics(&element, StyleProperties::create())
|
||||
{
|
||||
set_inline(true);
|
||||
}
|
||||
|
||||
LayoutBreak::~LayoutBreak()
|
||||
{
|
||||
}
|
||||
|
||||
void LayoutBreak::split_into_lines(LayoutBlock& block)
|
||||
{
|
||||
block.add_line_box();
|
||||
}
|
||||
|
||||
}
|
46
Libraries/LibWeb/Layout/LayoutBreak.h
Normal file
46
Libraries/LibWeb/Layout/LayoutBreak.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/DOM/HTMLBRElement.h>
|
||||
#include <LibWeb/Layout/LayoutNode.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LayoutBreak final : public LayoutNodeWithStyleAndBoxModelMetrics {
|
||||
public:
|
||||
explicit LayoutBreak(const HTMLBRElement&);
|
||||
virtual ~LayoutBreak() override;
|
||||
|
||||
const HTMLBRElement& node() const { return to<HTMLBRElement>(*LayoutNode::node()); }
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "LayoutBreak"; }
|
||||
virtual void split_into_lines(LayoutBlock&) override;
|
||||
};
|
||||
|
||||
}
|
71
Libraries/LibWeb/Layout/LayoutDocument.cpp
Normal file
71
Libraries/LibWeb/Layout/LayoutDocument.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/Dump.h>
|
||||
#include <LibWeb/Frame.h>
|
||||
#include <LibWeb/Layout/LayoutDocument.h>
|
||||
#include <LibWeb/Layout/LayoutImage.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutDocument::LayoutDocument(const Document& document, NonnullRefPtr<StyleProperties> style)
|
||||
: LayoutBlock(&document, move(style))
|
||||
{
|
||||
}
|
||||
|
||||
LayoutDocument::~LayoutDocument()
|
||||
{
|
||||
}
|
||||
|
||||
void LayoutDocument::layout()
|
||||
{
|
||||
ASSERT(document().frame());
|
||||
rect().set_width(document().frame()->size().width());
|
||||
|
||||
LayoutNode::layout();
|
||||
|
||||
ASSERT(!children_are_inline());
|
||||
|
||||
int lowest_bottom = 0;
|
||||
for_each_child([&](auto& child) {
|
||||
ASSERT(is<LayoutBlock>(child));
|
||||
auto& child_block = to<LayoutBlock>(child);
|
||||
if (child_block.rect().bottom() > lowest_bottom)
|
||||
lowest_bottom = child_block.rect().bottom();
|
||||
});
|
||||
rect().set_bottom(lowest_bottom);
|
||||
}
|
||||
|
||||
void LayoutDocument::did_set_viewport_rect(Badge<Frame>, const Gfx::Rect& a_viewport_rect)
|
||||
{
|
||||
Gfx::FloatRect viewport_rect(a_viewport_rect.x(), a_viewport_rect.y(), a_viewport_rect.width(), a_viewport_rect.height());
|
||||
for_each_in_subtree_of_type<LayoutImage>([&](auto& layout_image) {
|
||||
const_cast<HTMLImageElement&>(layout_image.node()).set_volatile({}, !viewport_rect.intersects(layout_image.rect()));
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
52
Libraries/LibWeb/Layout/LayoutDocument.h
Normal file
52
Libraries/LibWeb/Layout/LayoutDocument.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/Layout/LayoutBlock.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LayoutDocument final : public LayoutBlock {
|
||||
public:
|
||||
explicit LayoutDocument(const Document&, NonnullRefPtr<StyleProperties>);
|
||||
virtual ~LayoutDocument() override;
|
||||
|
||||
const Document& node() const { return static_cast<const Document&>(*LayoutNode::node()); }
|
||||
virtual const char* class_name() const override { return "LayoutDocument"; }
|
||||
virtual void layout() override;
|
||||
|
||||
const LayoutRange& selection() const { return m_selection; }
|
||||
LayoutRange& selection() { return m_selection; }
|
||||
|
||||
void did_set_viewport_rect(Badge<Frame>, const Gfx::Rect&);
|
||||
|
||||
private:
|
||||
LayoutRange m_selection;
|
||||
};
|
||||
|
||||
}
|
89
Libraries/LibWeb/Layout/LayoutImage.cpp
Normal file
89
Libraries/LibWeb/Layout/LayoutImage.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibGfx/Font.h>
|
||||
#include <LibGfx/StylePainter.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibWeb/Layout/LayoutImage.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutImage::LayoutImage(const HTMLImageElement& element, NonnullRefPtr<StyleProperties> style)
|
||||
: LayoutReplaced(element, move(style))
|
||||
{
|
||||
}
|
||||
|
||||
LayoutImage::~LayoutImage()
|
||||
{
|
||||
}
|
||||
|
||||
void LayoutImage::layout()
|
||||
{
|
||||
if (node().preferred_width() && node().preferred_height()) {
|
||||
rect().set_width(node().preferred_width());
|
||||
rect().set_height(node().preferred_height());
|
||||
} else if (renders_as_alt_text()) {
|
||||
auto& font = Gfx::Font::default_font();
|
||||
auto alt = node().alt();
|
||||
if (alt.is_empty())
|
||||
alt = node().src();
|
||||
rect().set_width(font.width(alt) + 16);
|
||||
rect().set_height(font.glyph_height() + 16);
|
||||
} else {
|
||||
rect().set_width(16);
|
||||
rect().set_height(16);
|
||||
}
|
||||
|
||||
LayoutReplaced::layout();
|
||||
}
|
||||
|
||||
void LayoutImage::render(RenderingContext& context)
|
||||
{
|
||||
if (!is_visible())
|
||||
return;
|
||||
|
||||
// FIXME: This should be done at a different level. Also rect() does not include padding etc!
|
||||
if (!context.viewport_rect().intersects(enclosing_int_rect(rect())))
|
||||
return;
|
||||
|
||||
if (renders_as_alt_text()) {
|
||||
context.painter().set_font(Gfx::Font::default_font());
|
||||
Gfx::StylePainter::paint_frame(context.painter(), enclosing_int_rect(rect()), context.palette(), Gfx::FrameShape::Container, Gfx::FrameShadow::Sunken, 2);
|
||||
auto alt = node().alt();
|
||||
if (alt.is_empty())
|
||||
alt = node().src();
|
||||
context.painter().draw_text(enclosing_int_rect(rect()), alt, Gfx::TextAlignment::Center, style().color_or_fallback(CSS::PropertyID::Color, document(), Color::Black), Gfx::TextElision::Right);
|
||||
} else if (node().bitmap())
|
||||
context.painter().draw_scaled_bitmap(enclosing_int_rect(rect()), *node().bitmap(), node().bitmap()->rect());
|
||||
LayoutReplaced::render(context);
|
||||
}
|
||||
|
||||
bool LayoutImage::renders_as_alt_text() const
|
||||
{
|
||||
return !node().image_decoder();
|
||||
}
|
||||
|
||||
}
|
59
Libraries/LibWeb/Layout/LayoutImage.h
Normal file
59
Libraries/LibWeb/Layout/LayoutImage.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/DOM/HTMLImageElement.h>
|
||||
#include <LibWeb/Layout/LayoutReplaced.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class HTMLImageElement;
|
||||
|
||||
class LayoutImage : public LayoutReplaced {
|
||||
public:
|
||||
LayoutImage(const HTMLImageElement&, NonnullRefPtr<StyleProperties>);
|
||||
virtual ~LayoutImage() override;
|
||||
|
||||
virtual void layout() override;
|
||||
virtual void render(RenderingContext&) override;
|
||||
|
||||
const HTMLImageElement& node() const { return static_cast<const HTMLImageElement&>(LayoutReplaced::node()); }
|
||||
|
||||
bool renders_as_alt_text() const;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "LayoutImage"; }
|
||||
virtual bool is_image() const override { return true; }
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool is<LayoutImage>(const LayoutNode& node)
|
||||
{
|
||||
return node.is_image();
|
||||
}
|
||||
|
||||
}
|
43
Libraries/LibWeb/Layout/LayoutInline.cpp
Normal file
43
Libraries/LibWeb/Layout/LayoutInline.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/Layout/LayoutBlock.h>
|
||||
#include <LibWeb/Layout/LayoutInline.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutInline::LayoutInline(const Element& element, NonnullRefPtr<StyleProperties> style)
|
||||
: LayoutNodeWithStyleAndBoxModelMetrics(&element, move(style))
|
||||
{
|
||||
set_inline(true);
|
||||
}
|
||||
|
||||
LayoutInline::~LayoutInline()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
42
Libraries/LibWeb/Layout/LayoutInline.h
Normal file
42
Libraries/LibWeb/Layout/LayoutInline.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Layout/LayoutBox.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LayoutBlock;
|
||||
|
||||
class LayoutInline : public LayoutNodeWithStyleAndBoxModelMetrics {
|
||||
public:
|
||||
LayoutInline(const Element&, NonnullRefPtr<StyleProperties>);
|
||||
virtual ~LayoutInline() override;
|
||||
virtual const char* class_name() const override { return "LayoutInline"; }
|
||||
};
|
||||
|
||||
}
|
56
Libraries/LibWeb/Layout/LayoutListItem.cpp
Normal file
56
Libraries/LibWeb/Layout/LayoutListItem.cpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/Layout/LayoutListItem.h>
|
||||
#include <LibWeb/Layout/LayoutListItemMarker.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutListItem::LayoutListItem(const Element& element, NonnullRefPtr<StyleProperties> style)
|
||||
: LayoutBlock(&element, move(style))
|
||||
{
|
||||
}
|
||||
|
||||
LayoutListItem::~LayoutListItem()
|
||||
{
|
||||
}
|
||||
|
||||
void LayoutListItem::layout()
|
||||
{
|
||||
LayoutBlock::layout();
|
||||
|
||||
if (!m_marker) {
|
||||
m_marker = adopt(*new LayoutListItemMarker);
|
||||
if (first_child())
|
||||
m_marker->set_inline(first_child()->is_inline());
|
||||
append_child(*m_marker);
|
||||
}
|
||||
|
||||
Gfx::FloatRect marker_rect { x() - 8, y(), 4, height() };
|
||||
m_marker->set_rect(marker_rect);
|
||||
}
|
||||
|
||||
}
|
49
Libraries/LibWeb/Layout/LayoutListItem.h
Normal file
49
Libraries/LibWeb/Layout/LayoutListItem.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/Layout/LayoutBlock.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LayoutListItemMarker;
|
||||
|
||||
class LayoutListItem final : public LayoutBlock {
|
||||
public:
|
||||
LayoutListItem(const Element&, NonnullRefPtr<StyleProperties>);
|
||||
virtual ~LayoutListItem() override;
|
||||
|
||||
virtual void layout() override;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "LayoutListItem"; }
|
||||
|
||||
RefPtr<LayoutListItemMarker> m_marker;
|
||||
};
|
||||
|
||||
}
|
50
Libraries/LibWeb/Layout/LayoutListItemMarker.cpp
Normal file
50
Libraries/LibWeb/Layout/LayoutListItemMarker.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibWeb/Layout/LayoutListItemMarker.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutListItemMarker::LayoutListItemMarker()
|
||||
: LayoutBox(nullptr, StyleProperties::create())
|
||||
{
|
||||
}
|
||||
|
||||
LayoutListItemMarker::~LayoutListItemMarker()
|
||||
{
|
||||
}
|
||||
|
||||
void LayoutListItemMarker::render(RenderingContext& context)
|
||||
{
|
||||
Gfx::Rect bullet_rect { 0, 0, 4, 4 };
|
||||
bullet_rect.center_within(enclosing_int_rect(rect()));
|
||||
// FIXME: It would be nicer to not have to go via the parent here to get our inherited style.
|
||||
auto color = parent()->style().color_or_fallback(CSS::PropertyID::Color, document(), context.palette().base_text());
|
||||
context.painter().fill_rect(bullet_rect, color);
|
||||
}
|
||||
|
||||
}
|
44
Libraries/LibWeb/Layout/LayoutListItemMarker.h
Normal file
44
Libraries/LibWeb/Layout/LayoutListItemMarker.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Layout/LayoutBox.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LayoutListItemMarker final : public LayoutBox {
|
||||
public:
|
||||
LayoutListItemMarker();
|
||||
virtual ~LayoutListItemMarker() override;
|
||||
|
||||
virtual void render(RenderingContext&) override;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "LayoutListItemMarker"; }
|
||||
};
|
||||
|
||||
}
|
158
Libraries/LibWeb/Layout/LayoutNode.cpp
Normal file
158
Libraries/LibWeb/Layout/LayoutNode.cpp
Normal file
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/Frame.h>
|
||||
#include <LibWeb/Layout/LayoutBlock.h>
|
||||
#include <LibWeb/Layout/LayoutNode.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutNode::LayoutNode(const Node* node)
|
||||
: m_node(node)
|
||||
{
|
||||
if (m_node)
|
||||
m_node->set_layout_node({}, this);
|
||||
}
|
||||
|
||||
LayoutNode::~LayoutNode()
|
||||
{
|
||||
if (m_node && m_node->layout_node() == this)
|
||||
m_node->set_layout_node({}, nullptr);
|
||||
}
|
||||
|
||||
void LayoutNode::layout()
|
||||
{
|
||||
for_each_child([](auto& child) {
|
||||
child.layout();
|
||||
});
|
||||
}
|
||||
|
||||
const LayoutBlock* LayoutNode::containing_block() const
|
||||
{
|
||||
for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
|
||||
if (is<LayoutBlock>(*ancestor))
|
||||
return to<LayoutBlock>(ancestor);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void LayoutNode::render(RenderingContext& context)
|
||||
{
|
||||
if (!is_visible())
|
||||
return;
|
||||
|
||||
// TODO: render our border
|
||||
for_each_child([&](auto& child) {
|
||||
child.render(context);
|
||||
});
|
||||
}
|
||||
|
||||
HitTestResult LayoutNode::hit_test(const Gfx::Point& position) const
|
||||
{
|
||||
HitTestResult result;
|
||||
for_each_child([&](auto& child) {
|
||||
auto child_result = child.hit_test(position);
|
||||
if (child_result.layout_node)
|
||||
result = child_result;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
const Document& LayoutNode::document() const
|
||||
{
|
||||
if (is_anonymous())
|
||||
return parent()->document();
|
||||
return node()->document();
|
||||
}
|
||||
|
||||
Document& LayoutNode::document()
|
||||
{
|
||||
if (is_anonymous())
|
||||
return parent()->document();
|
||||
// FIXME: Remove this const_cast once we give up on the idea of a const link from layout tree to DOM tree.
|
||||
return const_cast<Node*>(node())->document();
|
||||
}
|
||||
|
||||
const LayoutDocument& LayoutNode::root() const
|
||||
{
|
||||
ASSERT(document().layout_node());
|
||||
return *document().layout_node();
|
||||
}
|
||||
|
||||
LayoutDocument& LayoutNode::root()
|
||||
{
|
||||
ASSERT(document().layout_node());
|
||||
return *document().layout_node();
|
||||
}
|
||||
|
||||
void LayoutNode::split_into_lines(LayoutBlock& container)
|
||||
{
|
||||
for_each_child([&](auto& child) {
|
||||
if (child.is_inline()) {
|
||||
child.split_into_lines(container);
|
||||
} else {
|
||||
// FIXME: Support block children of inlines.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void LayoutNode::set_needs_display()
|
||||
{
|
||||
auto* frame = document().frame();
|
||||
ASSERT(frame);
|
||||
|
||||
if (auto* block = containing_block()) {
|
||||
block->for_each_fragment([&](auto& fragment) {
|
||||
if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
|
||||
const_cast<Frame*>(frame)->set_needs_display(enclosing_int_rect(fragment.rect()));
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Gfx::FloatPoint LayoutNode::box_type_agnostic_position() const
|
||||
{
|
||||
if (is_box())
|
||||
return to<LayoutBox>(*this).position();
|
||||
ASSERT(is_inline());
|
||||
Gfx::FloatPoint position;
|
||||
if (auto* block = containing_block()) {
|
||||
block->for_each_fragment([&](auto& fragment) {
|
||||
if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
|
||||
position = fragment.rect().location();
|
||||
return IterationDecision::Break;
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
}
|
321
Libraries/LibWeb/Layout/LayoutNode.h
Normal file
321
Libraries/LibWeb/Layout/LayoutNode.h
Normal file
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibGfx/FloatRect.h>
|
||||
#include <LibGfx/Rect.h>
|
||||
#include <LibWeb/CSS/StyleProperties.h>
|
||||
#include <LibWeb/Layout/BoxModelMetrics.h>
|
||||
#include <LibWeb/Layout/LayoutPosition.h>
|
||||
#include <LibWeb/RenderingContext.h>
|
||||
#include <LibWeb/TreeNode.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class Document;
|
||||
class Element;
|
||||
class LayoutBlock;
|
||||
class LayoutDocument;
|
||||
class LayoutNode;
|
||||
class LayoutNodeWithStyle;
|
||||
class LineBoxFragment;
|
||||
class Node;
|
||||
|
||||
struct HitTestResult {
|
||||
RefPtr<LayoutNode> layout_node;
|
||||
int index_in_node { 0 };
|
||||
};
|
||||
|
||||
class LayoutNode : public TreeNode<LayoutNode> {
|
||||
public:
|
||||
virtual ~LayoutNode();
|
||||
|
||||
virtual HitTestResult hit_test(const Gfx::Point&) const;
|
||||
|
||||
bool is_anonymous() const { return !m_node; }
|
||||
const Node* node() const { return m_node; }
|
||||
|
||||
Document& document();
|
||||
const Document& document() const;
|
||||
|
||||
const LayoutDocument& root() const;
|
||||
LayoutDocument& root();
|
||||
|
||||
template<typename Callback>
|
||||
inline void for_each_child(Callback callback) const
|
||||
{
|
||||
for (auto* node = first_child(); node; node = node->next_sibling())
|
||||
callback(*node);
|
||||
}
|
||||
|
||||
template<typename Callback>
|
||||
inline void for_each_child(Callback callback)
|
||||
{
|
||||
for (auto* node = first_child(); node; node = node->next_sibling())
|
||||
callback(*node);
|
||||
}
|
||||
|
||||
virtual const char* class_name() const { return "LayoutNode"; }
|
||||
virtual bool is_text() const { return false; }
|
||||
virtual bool is_block() const { return false; }
|
||||
virtual bool is_replaced() const { return false; }
|
||||
virtual bool is_widget() const { return false; }
|
||||
virtual bool is_image() const { return false; }
|
||||
virtual bool is_box() const { return false; }
|
||||
virtual bool is_table() const { return false; }
|
||||
virtual bool is_table_row() const { return false; }
|
||||
virtual bool is_table_cell() const { return false; }
|
||||
bool has_style() const { return m_has_style; }
|
||||
|
||||
bool is_inline() const { return m_inline; }
|
||||
void set_inline(bool b) { m_inline = b; }
|
||||
|
||||
virtual void layout();
|
||||
virtual void render(RenderingContext&);
|
||||
|
||||
const LayoutBlock* containing_block() const;
|
||||
|
||||
virtual LayoutNode& inline_wrapper() { return *this; }
|
||||
|
||||
const StyleProperties& style() const;
|
||||
|
||||
LayoutNodeWithStyle* parent();
|
||||
const LayoutNodeWithStyle* parent() const;
|
||||
|
||||
void inserted_into(LayoutNode&) {}
|
||||
void removed_from(LayoutNode&) {}
|
||||
|
||||
virtual void split_into_lines(LayoutBlock& container);
|
||||
|
||||
bool is_visible() const { return m_visible; }
|
||||
void set_visible(bool visible) { m_visible = visible; }
|
||||
|
||||
virtual void set_needs_display();
|
||||
|
||||
bool children_are_inline() const { return m_children_are_inline; }
|
||||
void set_children_are_inline(bool value) { m_children_are_inline = value; }
|
||||
|
||||
template<typename U>
|
||||
const U* next_sibling_of_type() const;
|
||||
|
||||
template<typename U>
|
||||
U* next_sibling_of_type();
|
||||
|
||||
template<typename T>
|
||||
const T* first_child_of_type() const;
|
||||
|
||||
template<typename T>
|
||||
T* first_child_of_type();
|
||||
|
||||
template<typename T>
|
||||
const T* first_ancestor_of_type() const;
|
||||
|
||||
template<typename T>
|
||||
T* first_ancestor_of_type();
|
||||
|
||||
Gfx::FloatPoint box_type_agnostic_position() const;
|
||||
|
||||
protected:
|
||||
explicit LayoutNode(const Node*);
|
||||
|
||||
private:
|
||||
friend class LayoutNodeWithStyle;
|
||||
|
||||
const Node* m_node { nullptr };
|
||||
|
||||
bool m_inline { false };
|
||||
bool m_has_style { false };
|
||||
bool m_visible { true };
|
||||
bool m_children_are_inline { false };
|
||||
};
|
||||
|
||||
class LayoutNodeWithStyle : public LayoutNode {
|
||||
public:
|
||||
virtual ~LayoutNodeWithStyle() override {}
|
||||
|
||||
const StyleProperties& style() const { return m_style; }
|
||||
void set_style(const StyleProperties& style) { m_style = style; }
|
||||
|
||||
protected:
|
||||
explicit LayoutNodeWithStyle(const Node* node, NonnullRefPtr<StyleProperties> style)
|
||||
: LayoutNode(node)
|
||||
, m_style(move(style))
|
||||
{
|
||||
m_has_style = true;
|
||||
}
|
||||
|
||||
private:
|
||||
NonnullRefPtr<StyleProperties> m_style;
|
||||
};
|
||||
|
||||
class LayoutNodeWithStyleAndBoxModelMetrics : public LayoutNodeWithStyle {
|
||||
public:
|
||||
BoxModelMetrics& box_model() { return m_box_model; }
|
||||
const BoxModelMetrics& box_model() const { return m_box_model; }
|
||||
|
||||
protected:
|
||||
LayoutNodeWithStyleAndBoxModelMetrics(const Node* node, NonnullRefPtr<StyleProperties> style)
|
||||
: LayoutNodeWithStyle(node, move(style))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
BoxModelMetrics m_box_model;
|
||||
};
|
||||
|
||||
inline const StyleProperties& LayoutNode::style() const
|
||||
{
|
||||
if (m_has_style)
|
||||
return static_cast<const LayoutNodeWithStyle*>(this)->style();
|
||||
return parent()->style();
|
||||
}
|
||||
|
||||
inline const LayoutNodeWithStyle* LayoutNode::parent() const
|
||||
{
|
||||
return static_cast<const LayoutNodeWithStyle*>(TreeNode<LayoutNode>::parent());
|
||||
}
|
||||
|
||||
inline LayoutNodeWithStyle* LayoutNode::parent()
|
||||
{
|
||||
return static_cast<LayoutNodeWithStyle*>(TreeNode<LayoutNode>::parent());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool is(const LayoutNode&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool is(const LayoutNode* node)
|
||||
{
|
||||
return !node || is<T>(*node);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool is<LayoutNode>(const LayoutNode&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool is<LayoutNodeWithStyle>(const LayoutNode& node)
|
||||
{
|
||||
return node.has_style();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const T& to(const LayoutNode& node)
|
||||
{
|
||||
ASSERT(is<T>(node));
|
||||
return static_cast<const T&>(node);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T* to(LayoutNode* node)
|
||||
{
|
||||
ASSERT(is<T>(node));
|
||||
return static_cast<T*>(node);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const T* to(const LayoutNode* node)
|
||||
{
|
||||
ASSERT(is<T>(node));
|
||||
return static_cast<const T*>(node);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T& to(LayoutNode& node)
|
||||
{
|
||||
ASSERT(is<T>(node));
|
||||
return static_cast<T&>(node);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const T* LayoutNode::next_sibling_of_type() const
|
||||
{
|
||||
for (auto* sibling = next_sibling(); sibling; sibling = sibling->next_sibling()) {
|
||||
if (is<T>(*sibling))
|
||||
return &to<T>(*sibling);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T* LayoutNode::next_sibling_of_type()
|
||||
{
|
||||
for (auto* sibling = next_sibling(); sibling; sibling = sibling->next_sibling()) {
|
||||
if (is<T>(*sibling))
|
||||
return &to<T>(*sibling);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const T* LayoutNode::first_child_of_type() const
|
||||
{
|
||||
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
||||
if (is<T>(*child))
|
||||
return &to<T>(*child);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T* LayoutNode::first_child_of_type()
|
||||
{
|
||||
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
||||
if (is<T>(*child))
|
||||
return &to<T>(*child);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const T* LayoutNode::first_ancestor_of_type() const
|
||||
{
|
||||
for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
|
||||
if (is<T>(*ancestor))
|
||||
return &to<T>(*ancestor);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T* LayoutNode::first_ancestor_of_type()
|
||||
{
|
||||
for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
|
||||
if (is<T>(*ancestor))
|
||||
return &to<T>(*ancestor);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
86
Libraries/LibWeb/Layout/LayoutPosition.h
Normal file
86
Libraries/LibWeb/Layout/LayoutPosition.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/RefPtr.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LayoutNode;
|
||||
|
||||
struct LayoutPosition {
|
||||
bool operator>=(const LayoutPosition& other) const
|
||||
{
|
||||
if (layout_node == other.layout_node)
|
||||
return index_in_node >= other.index_in_node;
|
||||
|
||||
// FIXME: Implement.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator<=(const LayoutPosition& other) const
|
||||
{
|
||||
if (layout_node == other.layout_node)
|
||||
return index_in_node <= other.index_in_node;
|
||||
|
||||
// FIXME: Implement.
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<LayoutNode> layout_node;
|
||||
int index_in_node { 0 };
|
||||
};
|
||||
|
||||
class LayoutRange {
|
||||
public:
|
||||
LayoutRange() {}
|
||||
LayoutRange(const LayoutPosition& start, const LayoutPosition& end)
|
||||
: m_start(start)
|
||||
, m_end(end)
|
||||
{
|
||||
}
|
||||
|
||||
bool is_valid() const { return m_start.layout_node && m_end.layout_node; }
|
||||
|
||||
void set(const LayoutPosition& start, const LayoutPosition& end)
|
||||
{
|
||||
m_start = start;
|
||||
m_end = end;
|
||||
}
|
||||
|
||||
void set_start(const LayoutPosition& start) { m_start = start; }
|
||||
void set_end(const LayoutPosition& end) { m_end = end; }
|
||||
|
||||
const LayoutPosition& start() const { return m_start; }
|
||||
const LayoutPosition& end() const { return m_end; }
|
||||
|
||||
private:
|
||||
LayoutPosition m_start;
|
||||
LayoutPosition m_end;
|
||||
};
|
||||
|
||||
}
|
54
Libraries/LibWeb/Layout/LayoutReplaced.cpp
Normal file
54
Libraries/LibWeb/Layout/LayoutReplaced.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/Layout/LayoutBlock.h>
|
||||
#include <LibWeb/Layout/LayoutReplaced.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutReplaced::LayoutReplaced(const Element& element, NonnullRefPtr<StyleProperties> style)
|
||||
: LayoutBox(&element, move(style))
|
||||
{
|
||||
// FIXME: Allow non-inline replaced elements.
|
||||
set_inline(true);
|
||||
}
|
||||
|
||||
LayoutReplaced::~LayoutReplaced()
|
||||
{
|
||||
}
|
||||
|
||||
void LayoutReplaced::split_into_lines(LayoutBlock& container)
|
||||
{
|
||||
layout();
|
||||
|
||||
auto* line_box = &container.ensure_last_line_box();
|
||||
if (line_box->width() > 0 && line_box->width() + width() > container.width())
|
||||
line_box = &container.add_line_box();
|
||||
line_box->add_fragment(*this, 0, 0, width(), height());
|
||||
}
|
||||
|
||||
}
|
53
Libraries/LibWeb/Layout/LayoutReplaced.h
Normal file
53
Libraries/LibWeb/Layout/LayoutReplaced.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/Layout/LayoutBox.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LayoutReplaced : public LayoutBox {
|
||||
public:
|
||||
LayoutReplaced(const Element&, NonnullRefPtr<StyleProperties>);
|
||||
virtual ~LayoutReplaced() override;
|
||||
|
||||
const Element& node() const { return to<Element>(*LayoutNode::node()); }
|
||||
|
||||
virtual bool is_replaced() const final { return true; }
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "LayoutReplaced"; }
|
||||
|
||||
virtual void split_into_lines(LayoutBlock& container) override;
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool is<LayoutReplaced>(const LayoutNode& node)
|
||||
{
|
||||
return node.is_replaced();
|
||||
}
|
||||
|
||||
}
|
58
Libraries/LibWeb/Layout/LayoutTable.cpp
Normal file
58
Libraries/LibWeb/Layout/LayoutTable.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/Layout/LayoutTable.h>
|
||||
#include <LibWeb/Layout/LayoutTableRow.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutTable::LayoutTable(const Element& element, NonnullRefPtr<StyleProperties> style)
|
||||
: LayoutBlock(&element, move(style))
|
||||
{
|
||||
}
|
||||
|
||||
LayoutTable::~LayoutTable()
|
||||
{
|
||||
}
|
||||
|
||||
void LayoutTable::layout()
|
||||
{
|
||||
|
||||
LayoutBlock::layout();
|
||||
}
|
||||
|
||||
LayoutTableRow* LayoutTable::first_row()
|
||||
{
|
||||
return first_child_of_type<LayoutTableRow>();
|
||||
}
|
||||
|
||||
const LayoutTableRow* LayoutTable::first_row() const
|
||||
{
|
||||
return first_child_of_type<LayoutTableRow>();
|
||||
}
|
||||
|
||||
}
|
56
Libraries/LibWeb/Layout/LayoutTable.h
Normal file
56
Libraries/LibWeb/Layout/LayoutTable.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Layout/LayoutBlock.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LayoutTableRow;
|
||||
|
||||
class LayoutTable final : public LayoutBlock {
|
||||
public:
|
||||
LayoutTable(const Element&, NonnullRefPtr<StyleProperties>);
|
||||
virtual ~LayoutTable() override;
|
||||
|
||||
virtual void layout() override;
|
||||
|
||||
LayoutTableRow* first_row();
|
||||
const LayoutTableRow* first_row() const;
|
||||
|
||||
private:
|
||||
virtual bool is_table() const override { return true; }
|
||||
virtual const char* class_name() const override { return "LayoutTable"; }
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool is<LayoutTable>(const LayoutNode& node)
|
||||
{
|
||||
return node.is_table();
|
||||
}
|
||||
|
||||
}
|
41
Libraries/LibWeb/Layout/LayoutTableCell.cpp
Normal file
41
Libraries/LibWeb/Layout/LayoutTableCell.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/Layout/LayoutTableCell.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutTableCell::LayoutTableCell(const Element& element, NonnullRefPtr<StyleProperties> style)
|
||||
: LayoutBlock(&element, move(style))
|
||||
{
|
||||
}
|
||||
|
||||
LayoutTableCell::~LayoutTableCell()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
52
Libraries/LibWeb/Layout/LayoutTableCell.h
Normal file
52
Libraries/LibWeb/Layout/LayoutTableCell.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Layout/LayoutBlock.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LayoutTableCell final : public LayoutBlock {
|
||||
public:
|
||||
LayoutTableCell(const Element&, NonnullRefPtr<StyleProperties>);
|
||||
virtual ~LayoutTableCell() override;
|
||||
|
||||
LayoutTableCell* next_cell() { return next_sibling_of_type<LayoutTableCell>(); }
|
||||
const LayoutTableCell* next_cell() const { return next_sibling_of_type<LayoutTableCell>(); }
|
||||
|
||||
private:
|
||||
virtual bool is_table_cell() const override { return true; }
|
||||
virtual const char* class_name() const override { return "LayoutTableCell"; }
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool is<LayoutTableCell>(const LayoutNode& node)
|
||||
{
|
||||
return node.is_table_cell();
|
||||
}
|
||||
|
||||
}
|
67
Libraries/LibWeb/Layout/LayoutTableRow.cpp
Normal file
67
Libraries/LibWeb/Layout/LayoutTableRow.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/Layout/LayoutTableCell.h>
|
||||
#include <LibWeb/Layout/LayoutTableRow.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutTableRow::LayoutTableRow(const Element& element, NonnullRefPtr<StyleProperties> style)
|
||||
: LayoutBox(&element, move(style))
|
||||
{
|
||||
}
|
||||
|
||||
LayoutTableRow::~LayoutTableRow()
|
||||
{
|
||||
}
|
||||
|
||||
void LayoutTableRow::layout()
|
||||
{
|
||||
LayoutBox::layout();
|
||||
}
|
||||
|
||||
LayoutTableCell* LayoutTableRow::first_cell()
|
||||
{
|
||||
return first_child_of_type<LayoutTableCell>();
|
||||
}
|
||||
|
||||
const LayoutTableCell* LayoutTableRow::first_cell() const
|
||||
{
|
||||
return first_child_of_type<LayoutTableCell>();
|
||||
}
|
||||
|
||||
LayoutTableRow* LayoutTableRow::next_row()
|
||||
{
|
||||
return next_sibling_of_type<LayoutTableRow>();
|
||||
}
|
||||
|
||||
const LayoutTableRow* LayoutTableRow::next_row() const
|
||||
{
|
||||
return next_sibling_of_type<LayoutTableRow>();
|
||||
}
|
||||
|
||||
}
|
59
Libraries/LibWeb/Layout/LayoutTableRow.h
Normal file
59
Libraries/LibWeb/Layout/LayoutTableRow.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Layout/LayoutBox.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LayoutTableCell;
|
||||
|
||||
class LayoutTableRow final : public LayoutBox {
|
||||
public:
|
||||
LayoutTableRow(const Element&, NonnullRefPtr<StyleProperties>);
|
||||
virtual ~LayoutTableRow() override;
|
||||
|
||||
virtual void layout() override;
|
||||
|
||||
LayoutTableCell* first_cell();
|
||||
const LayoutTableCell* first_cell() const;
|
||||
|
||||
LayoutTableRow* next_row();
|
||||
const LayoutTableRow* next_row() const;
|
||||
|
||||
private:
|
||||
virtual bool is_table_row() const override { return true; }
|
||||
virtual const char* class_name() const override { return "LayoutTableRow"; }
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool is<LayoutTableRow>(const LayoutNode& node)
|
||||
{
|
||||
return node.is_table_row();
|
||||
}
|
||||
|
||||
}
|
237
Libraries/LibWeb/Layout/LayoutText.cpp
Normal file
237
Libraries/LibWeb/Layout/LayoutText.cpp
Normal file
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Utf8View.h>
|
||||
#include <LibCore/DirIterator.h>
|
||||
#include <LibGfx/Font.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/Layout/LayoutBlock.h>
|
||||
#include <LibWeb/Layout/LayoutText.h>
|
||||
#include <ctype.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutText::LayoutText(const Text& text)
|
||||
: LayoutNode(&text)
|
||||
{
|
||||
set_inline(true);
|
||||
}
|
||||
|
||||
LayoutText::~LayoutText()
|
||||
{
|
||||
}
|
||||
|
||||
static bool is_all_whitespace(const String& string)
|
||||
{
|
||||
for (size_t i = 0; i < string.length(); ++i) {
|
||||
if (!isspace(string[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const String& LayoutText::text_for_style(const StyleProperties& style) const
|
||||
{
|
||||
static String one_space = " ";
|
||||
if (is_all_whitespace(node().data())) {
|
||||
if (style.string_or_fallback(CSS::PropertyID::WhiteSpace, "normal") == "normal")
|
||||
return one_space;
|
||||
}
|
||||
return node().data();
|
||||
}
|
||||
|
||||
void LayoutText::render_fragment(RenderingContext& context, const LineBoxFragment& fragment) const
|
||||
{
|
||||
auto& painter = context.painter();
|
||||
painter.set_font(style().font());
|
||||
|
||||
auto background_color = style().property(CSS::PropertyID::BackgroundColor);
|
||||
if (background_color.has_value() && background_color.value()->is_color())
|
||||
painter.fill_rect(enclosing_int_rect(fragment.rect()), background_color.value()->to_color(document()));
|
||||
|
||||
auto color = style().color_or_fallback(CSS::PropertyID::Color, document(), context.palette().base_text());
|
||||
auto text_decoration = style().string_or_fallback(CSS::PropertyID::TextDecoration, "none");
|
||||
|
||||
if (document().inspected_node() == &node())
|
||||
context.painter().draw_rect(enclosing_int_rect(fragment.rect()), Color::Magenta);
|
||||
|
||||
bool is_underline = text_decoration == "underline";
|
||||
if (is_underline)
|
||||
painter.draw_line(enclosing_int_rect(fragment.rect()).bottom_left().translated(0, 1), enclosing_int_rect(fragment.rect()).bottom_right().translated(0, 1), color);
|
||||
|
||||
painter.draw_text(enclosing_int_rect(fragment.rect()), m_text_for_rendering.substring_view(fragment.start(), fragment.length()), Gfx::TextAlignment::TopLeft, color);
|
||||
}
|
||||
|
||||
template<typename Callback>
|
||||
void LayoutText::for_each_word(Callback callback) const
|
||||
{
|
||||
Utf8View view(m_text_for_rendering);
|
||||
if (view.is_empty())
|
||||
return;
|
||||
|
||||
auto start_of_word = view.begin();
|
||||
|
||||
auto commit_word = [&](auto it) {
|
||||
int start = view.byte_offset_of(start_of_word);
|
||||
int length = view.byte_offset_of(it) - view.byte_offset_of(start_of_word);
|
||||
|
||||
if (length > 0) {
|
||||
callback(view.substring_view(start, length), start, length);
|
||||
}
|
||||
|
||||
start_of_word = it;
|
||||
};
|
||||
|
||||
bool last_was_space = isspace(*view.begin());
|
||||
|
||||
for (auto it = view.begin(); it != view.end();) {
|
||||
bool is_space = isspace(*it);
|
||||
if (is_space == last_was_space) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
last_was_space = is_space;
|
||||
commit_word(it);
|
||||
++it;
|
||||
}
|
||||
if (start_of_word != view.end())
|
||||
commit_word(view.end());
|
||||
}
|
||||
|
||||
void LayoutText::split_preformatted_into_lines(LayoutBlock& container)
|
||||
{
|
||||
auto& font = style().font();
|
||||
auto& line_boxes = container.line_boxes();
|
||||
m_text_for_rendering = node().data();
|
||||
|
||||
Utf8View view(m_text_for_rendering);
|
||||
if (view.is_empty())
|
||||
return;
|
||||
|
||||
auto start_of_line = view.begin();
|
||||
|
||||
auto commit_line = [&](auto it) {
|
||||
int start = view.byte_offset_of(start_of_line);
|
||||
int length = view.byte_offset_of(it) - view.byte_offset_of(start_of_line);
|
||||
if (length > 0)
|
||||
line_boxes.last().add_fragment(*this, start, length, font.width(view), font.glyph_height());
|
||||
};
|
||||
|
||||
bool last_was_newline = false;
|
||||
for (auto it = view.begin(); it != view.end();) {
|
||||
bool did_commit = false;
|
||||
if (*it == '\n') {
|
||||
commit_line(it);
|
||||
line_boxes.append(LineBox());
|
||||
did_commit = true;
|
||||
last_was_newline = true;
|
||||
} else {
|
||||
last_was_newline = false;
|
||||
}
|
||||
++it;
|
||||
if (did_commit)
|
||||
start_of_line = it;
|
||||
}
|
||||
if (start_of_line != view.end() || last_was_newline)
|
||||
commit_line(view.end());
|
||||
}
|
||||
|
||||
void LayoutText::split_into_lines(LayoutBlock& container)
|
||||
{
|
||||
auto& font = style().font();
|
||||
float space_width = font.glyph_width(' ') + font.glyph_spacing();
|
||||
|
||||
auto& line_boxes = container.line_boxes();
|
||||
if (line_boxes.is_empty())
|
||||
line_boxes.append(LineBox());
|
||||
float available_width = container.width() - line_boxes.last().width();
|
||||
|
||||
if (style().string_or_fallback(CSS::PropertyID::WhiteSpace, "normal") == "pre") {
|
||||
split_preformatted_into_lines(container);
|
||||
return;
|
||||
}
|
||||
|
||||
// Collapse whitespace into single spaces
|
||||
auto utf8_view = Utf8View(node().data());
|
||||
StringBuilder builder(node().data().length());
|
||||
for (auto it = utf8_view.begin(); it != utf8_view.end(); ++it) {
|
||||
if (!isspace(*it)) {
|
||||
builder.append(utf8_view.as_string().characters_without_null_termination() + utf8_view.byte_offset_of(it), it.codepoint_length_in_bytes());
|
||||
} else {
|
||||
builder.append(' ');
|
||||
auto prev = it;
|
||||
while (it != utf8_view.end() && isspace(*it)) {
|
||||
prev = it;
|
||||
++it;
|
||||
}
|
||||
it = prev;
|
||||
}
|
||||
}
|
||||
m_text_for_rendering = builder.to_string();
|
||||
|
||||
struct Word {
|
||||
Utf8View view;
|
||||
int start;
|
||||
int length;
|
||||
};
|
||||
Vector<Word> words;
|
||||
|
||||
for_each_word([&](const Utf8View& view, int start, int length) {
|
||||
words.append({ Utf8View(view), start, length });
|
||||
});
|
||||
|
||||
for (size_t i = 0; i < words.size(); ++i) {
|
||||
auto& word = words[i];
|
||||
|
||||
float word_width;
|
||||
bool is_whitespace = isspace(*word.view.begin());
|
||||
|
||||
if (is_whitespace)
|
||||
word_width = space_width;
|
||||
else
|
||||
word_width = font.width(word.view) + font.glyph_spacing();
|
||||
|
||||
if (line_boxes.last().width() > 0 && word_width > available_width) {
|
||||
line_boxes.append(LineBox());
|
||||
available_width = container.width();
|
||||
}
|
||||
|
||||
if (is_whitespace && line_boxes.last().fragments().is_empty())
|
||||
continue;
|
||||
|
||||
line_boxes.last().add_fragment(*this, word.start, is_whitespace ? 1 : word.length, word_width, font.glyph_height());
|
||||
available_width -= word_width;
|
||||
|
||||
if (available_width < 0) {
|
||||
line_boxes.append(LineBox());
|
||||
available_width = container.width();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
70
Libraries/LibWeb/Layout/LayoutText.h
Normal file
70
Libraries/LibWeb/Layout/LayoutText.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/DOM/Text.h>
|
||||
#include <LibWeb/Layout/LayoutNode.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LineBoxFragment;
|
||||
|
||||
class LayoutText : public LayoutNode {
|
||||
public:
|
||||
explicit LayoutText(const Text&);
|
||||
virtual ~LayoutText() override;
|
||||
|
||||
const Text& node() const { return static_cast<const Text&>(*LayoutNode::node()); }
|
||||
|
||||
const String& text_for_style(const StyleProperties&) const;
|
||||
const String& text_for_rendering() const { return m_text_for_rendering; }
|
||||
|
||||
virtual const char* class_name() const override { return "LayoutText"; }
|
||||
virtual bool is_text() const final { return true; }
|
||||
|
||||
void render_fragment(RenderingContext&, const LineBoxFragment&) const;
|
||||
|
||||
virtual void split_into_lines(LayoutBlock& container) override;
|
||||
|
||||
const StyleProperties& style() const { return parent()->style(); }
|
||||
|
||||
private:
|
||||
void split_preformatted_into_lines(LayoutBlock& container);
|
||||
|
||||
template<typename Callback>
|
||||
void for_each_word(Callback) const;
|
||||
|
||||
String m_text_for_rendering;
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool is<LayoutText>(const LayoutNode& node)
|
||||
{
|
||||
return node.is_text();
|
||||
}
|
||||
|
||||
}
|
91
Libraries/LibWeb/Layout/LayoutTreeBuilder.cpp
Normal file
91
Libraries/LibWeb/Layout/LayoutTreeBuilder.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/ParentNode.h>
|
||||
#include <LibWeb/Layout/LayoutNode.h>
|
||||
#include <LibWeb/Layout/LayoutTable.h>
|
||||
#include <LibWeb/Layout/LayoutText.h>
|
||||
#include <LibWeb/Layout/LayoutTreeBuilder.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutTreeBuilder::LayoutTreeBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
static RefPtr<LayoutNode> create_layout_tree(Node& node, const StyleProperties* parent_style)
|
||||
{
|
||||
auto layout_node = node.create_layout_node(parent_style);
|
||||
if (!layout_node)
|
||||
return nullptr;
|
||||
|
||||
if (!node.has_children())
|
||||
return layout_node;
|
||||
|
||||
NonnullRefPtrVector<LayoutNode> layout_children;
|
||||
bool have_inline_children = false;
|
||||
bool have_block_children = false;
|
||||
|
||||
to<ParentNode>(node).for_each_child([&](Node& child) {
|
||||
auto layout_child = create_layout_tree(child, &layout_node->style());
|
||||
if (!layout_child)
|
||||
return;
|
||||
if (layout_child->is_inline())
|
||||
have_inline_children = true;
|
||||
if (layout_child->is_block())
|
||||
have_block_children = true;
|
||||
layout_children.append(layout_child.release_nonnull());
|
||||
});
|
||||
|
||||
for (auto& layout_child : layout_children) {
|
||||
if (have_block_children && have_inline_children && layout_child.is_inline()) {
|
||||
if (is<LayoutText>(layout_child) && to<LayoutText>(layout_child).text_for_style(*parent_style) == " ")
|
||||
continue;
|
||||
layout_node->inline_wrapper().append_child(layout_child);
|
||||
} else {
|
||||
layout_node->append_child(layout_child);
|
||||
}
|
||||
}
|
||||
|
||||
if (have_inline_children && !have_block_children)
|
||||
layout_node->set_children_are_inline(true);
|
||||
|
||||
// FIXME: This is really hackish. Some layout nodes don't care about inline children.
|
||||
if (is<LayoutTable>(layout_node))
|
||||
layout_node->set_children_are_inline(false);
|
||||
|
||||
return layout_node;
|
||||
}
|
||||
|
||||
RefPtr<LayoutNode> LayoutTreeBuilder::build(Node& node)
|
||||
{
|
||||
// FIXME: Support building partial trees.
|
||||
ASSERT(is<Document>(node));
|
||||
return create_layout_tree(node, nullptr);
|
||||
}
|
||||
|
||||
}
|
43
Libraries/LibWeb/Layout/LayoutTreeBuilder.h
Normal file
43
Libraries/LibWeb/Layout/LayoutTreeBuilder.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/RefPtr.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class Node;
|
||||
class LayoutNode;
|
||||
|
||||
class LayoutTreeBuilder {
|
||||
public:
|
||||
LayoutTreeBuilder();
|
||||
|
||||
RefPtr<LayoutNode> build(Node&);
|
||||
};
|
||||
|
||||
}
|
58
Libraries/LibWeb/Layout/LayoutWidget.cpp
Normal file
58
Libraries/LibWeb/Layout/LayoutWidget.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibGfx/Font.h>
|
||||
#include <LibGfx/StylePainter.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibGUI/Widget.h>
|
||||
#include <LibWeb/Layout/LayoutWidget.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
LayoutWidget::LayoutWidget(const Element& element, GUI::Widget& widget)
|
||||
: LayoutReplaced(element, StyleProperties::create())
|
||||
, m_widget(widget)
|
||||
{
|
||||
}
|
||||
|
||||
LayoutWidget::~LayoutWidget()
|
||||
{
|
||||
widget().remove_from_parent();
|
||||
}
|
||||
|
||||
void LayoutWidget::layout()
|
||||
{
|
||||
rect().set_size(widget().width(), widget().height());
|
||||
LayoutReplaced::layout();
|
||||
widget().move_to(rect().x(), rect().y());
|
||||
}
|
||||
|
||||
void LayoutWidget::render(RenderingContext& context)
|
||||
{
|
||||
LayoutReplaced::render(context);
|
||||
}
|
||||
|
||||
}
|
58
Libraries/LibWeb/Layout/LayoutWidget.h
Normal file
58
Libraries/LibWeb/Layout/LayoutWidget.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Layout/LayoutReplaced.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LayoutWidget : public LayoutReplaced {
|
||||
public:
|
||||
LayoutWidget(const Element&, GUI::Widget&);
|
||||
virtual ~LayoutWidget() override;
|
||||
|
||||
virtual void layout() override;
|
||||
virtual void render(RenderingContext&) override;
|
||||
|
||||
GUI::Widget& widget() { return m_widget; }
|
||||
const GUI::Widget& widget() const { return m_widget; }
|
||||
|
||||
virtual bool is_widget() const final { return true; }
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "LayoutWidget"; }
|
||||
|
||||
NonnullRefPtr<GUI::Widget> m_widget;
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool is<LayoutWidget>(const LayoutNode& node)
|
||||
{
|
||||
return node.is_widget();
|
||||
}
|
||||
|
||||
}
|
72
Libraries/LibWeb/Layout/LineBox.cpp
Normal file
72
Libraries/LibWeb/Layout/LineBox.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/Utf8View.h>
|
||||
#include <LibWeb/Layout/LayoutNode.h>
|
||||
#include <LibWeb/Layout/LayoutText.h>
|
||||
#include <LibWeb/Layout/LineBox.h>
|
||||
#include <ctype.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
void LineBox::add_fragment(const LayoutNode& layout_node, int start, int length, int width, int height)
|
||||
{
|
||||
bool text_align_is_justify = layout_node.style().string_or_fallback(CSS::PropertyID::TextAlign, "left") == "justify";
|
||||
if (!text_align_is_justify && !m_fragments.is_empty() && &m_fragments.last().layout_node() == &layout_node) {
|
||||
// The fragment we're adding is from the last LayoutNode on the line.
|
||||
// Expand the last fragment instead of adding a new one with the same LayoutNode.
|
||||
m_fragments.last().m_length = (start - m_fragments.last().m_start) + length;
|
||||
m_fragments.last().m_rect.set_width(m_fragments.last().m_rect.width() + width);
|
||||
} else {
|
||||
m_fragments.empend(layout_node, start, length, Gfx::FloatRect(m_width, 0, width, height));
|
||||
}
|
||||
m_width += width;
|
||||
}
|
||||
|
||||
void LineBox::trim_trailing_whitespace()
|
||||
{
|
||||
while (!m_fragments.is_empty() && m_fragments.last().is_justifiable_whitespace()) {
|
||||
auto fragment = m_fragments.take_last();
|
||||
m_width -= fragment.width();
|
||||
}
|
||||
|
||||
if (m_fragments.is_empty())
|
||||
return;
|
||||
|
||||
auto last_text = m_fragments.last().text();
|
||||
if (last_text.is_null())
|
||||
return;
|
||||
auto& last_fragment = m_fragments.last();
|
||||
|
||||
int space_width = last_fragment.layout_node().style().font().glyph_width(' ');
|
||||
while (last_fragment.length() && isspace(last_text[last_fragment.length() - 1])) {
|
||||
last_fragment.m_length -= 1;
|
||||
last_fragment.m_rect.set_width(last_fragment.m_rect.width() - space_width);
|
||||
m_width -= space_width;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
52
Libraries/LibWeb/Layout/LineBox.h
Normal file
52
Libraries/LibWeb/Layout/LineBox.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Vector.h>
|
||||
#include <LibWeb/Layout/LineBoxFragment.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LineBox {
|
||||
public:
|
||||
LineBox() {}
|
||||
|
||||
float width() const { return m_width; }
|
||||
|
||||
void add_fragment(const LayoutNode& layout_node, int start, int length, int width, int height);
|
||||
|
||||
const Vector<LineBoxFragment>& fragments() const { return m_fragments; }
|
||||
Vector<LineBoxFragment>& fragments() { return m_fragments; }
|
||||
|
||||
void trim_trailing_whitespace();
|
||||
private:
|
||||
friend class LayoutBlock;
|
||||
Vector<LineBoxFragment> m_fragments;
|
||||
float m_width { 0 };
|
||||
};
|
||||
|
||||
}
|
81
Libraries/LibWeb/Layout/LineBoxFragment.cpp
Normal file
81
Libraries/LibWeb/Layout/LineBoxFragment.cpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/Utf8View.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibWeb/Layout/LayoutDocument.h>
|
||||
#include <LibWeb/Layout/LayoutText.h>
|
||||
#include <LibWeb/Layout/LineBoxFragment.h>
|
||||
#include <LibWeb/RenderingContext.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
void LineBoxFragment::render(RenderingContext& context)
|
||||
{
|
||||
for (auto* ancestor = layout_node().parent(); ancestor; ancestor = ancestor->parent()) {
|
||||
if (!ancestor->is_visible())
|
||||
return;
|
||||
}
|
||||
|
||||
if (is<LayoutText>(layout_node())) {
|
||||
to<LayoutText>(layout_node()).render_fragment(context, *this);
|
||||
}
|
||||
}
|
||||
|
||||
bool LineBoxFragment::is_justifiable_whitespace() const
|
||||
{
|
||||
return text() == " ";
|
||||
}
|
||||
|
||||
StringView LineBoxFragment::text() const
|
||||
{
|
||||
if (!is<LayoutText>(layout_node()))
|
||||
return {};
|
||||
return to<LayoutText>(layout_node()).text_for_rendering().substring_view(m_start, m_length);
|
||||
}
|
||||
|
||||
int LineBoxFragment::text_index_at(float x) const
|
||||
{
|
||||
if (!layout_node().is_text())
|
||||
return 0;
|
||||
auto& layout_text = to<LayoutText>(layout_node());
|
||||
auto& font = layout_text.style().font();
|
||||
Utf8View view(text());
|
||||
|
||||
float relative_x = x - m_rect.location().x();
|
||||
float glyph_spacing = font.glyph_spacing();
|
||||
|
||||
float width_so_far = 0;
|
||||
for (auto it = view.begin(); it != view.end(); ++it) {
|
||||
float glyph_width = font.glyph_or_emoji_width(*it);
|
||||
if ((width_so_far + glyph_width + glyph_spacing) > relative_x)
|
||||
return m_start + view.byte_offset_of(it);
|
||||
width_so_far += glyph_width + glyph_spacing;
|
||||
}
|
||||
return m_start + m_length - 1;
|
||||
}
|
||||
|
||||
}
|
69
Libraries/LibWeb/Layout/LineBoxFragment.h
Normal file
69
Libraries/LibWeb/Layout/LineBoxFragment.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibGfx/FloatRect.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class LayoutNode;
|
||||
class RenderingContext;
|
||||
|
||||
class LineBoxFragment {
|
||||
friend class LineBox;
|
||||
public:
|
||||
LineBoxFragment(const LayoutNode& layout_node, int start, int length, const Gfx::FloatRect& rect)
|
||||
: m_layout_node(layout_node)
|
||||
, m_start(start)
|
||||
, m_length(length)
|
||||
, m_rect(rect)
|
||||
{
|
||||
}
|
||||
|
||||
const LayoutNode& layout_node() const { return m_layout_node; }
|
||||
int start() const { return m_start; }
|
||||
int length() const { return m_length; }
|
||||
const Gfx::FloatRect& rect() const { return m_rect; }
|
||||
Gfx::FloatRect& rect() { return m_rect; }
|
||||
|
||||
float width() const { return m_rect.width(); }
|
||||
|
||||
void render(RenderingContext&);
|
||||
|
||||
bool is_justifiable_whitespace() const;
|
||||
StringView text() const;
|
||||
|
||||
int text_index_at(float x) const;
|
||||
|
||||
private:
|
||||
const LayoutNode& m_layout_node;
|
||||
int m_start { 0 };
|
||||
int m_length { 0 };
|
||||
Gfx::FloatRect m_rect;
|
||||
};
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue