
In general it is not safe to convert any arbitrary floating-point value to CSSPixels. CSSPixels has a resolution of 0.015625, which for small values (e.g. scale factors between 0 and 1), can produce bad results if converted to CSSPixels then scaled back up. In the worst case values can underflow to zero and produce incorrect results.
81 lines
3.1 KiB
C++
81 lines
3.1 KiB
C++
/*
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/CharacterTypes.h>
|
|
#include <AK/TypeCasts.h>
|
|
#include <AK/Utf8View.h>
|
|
#include <LibWeb/Layout/Box.h>
|
|
#include <LibWeb/Layout/BreakNode.h>
|
|
#include <LibWeb/Layout/LineBox.h>
|
|
#include <LibWeb/Layout/Node.h>
|
|
#include <LibWeb/Layout/TextNode.h>
|
|
|
|
namespace Web::Layout {
|
|
|
|
void LineBox::add_fragment(Node const& layout_node, int start, int length, CSSPixels leading_size, CSSPixels trailing_size, CSSPixels leading_margin, CSSPixels trailing_margin, CSSPixels content_width, CSSPixels content_height, CSSPixels border_box_top, CSSPixels border_box_bottom)
|
|
{
|
|
bool text_align_is_justify = layout_node.computed_values().text_align() == CSS::TextAlign::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 Layout::Node on the line.
|
|
// Expand the last fragment instead of adding a new one with the same Layout::Node.
|
|
m_fragments.last().m_length = (start - m_fragments.last().m_start) + length;
|
|
m_fragments.last().set_width(m_fragments.last().width() + content_width);
|
|
} else {
|
|
CSSPixels x_offset = leading_margin + leading_size + m_width;
|
|
CSSPixels y_offset = 0;
|
|
m_fragments.append(LineBoxFragment { layout_node, start, length, CSSPixelPoint(x_offset, y_offset), CSSPixelSize(content_width, content_height), border_box_top, border_box_bottom });
|
|
}
|
|
m_width += leading_margin + leading_size + content_width + trailing_size + trailing_margin;
|
|
}
|
|
|
|
void LineBox::trim_trailing_whitespace()
|
|
{
|
|
auto should_trim = [](LineBoxFragment* fragment) {
|
|
auto ws = fragment->layout_node().computed_values().white_space();
|
|
return ws == CSS::WhiteSpace::Normal || ws == CSS::WhiteSpace::Nowrap || ws == CSS::WhiteSpace::PreLine;
|
|
};
|
|
|
|
LineBoxFragment* last_fragment = nullptr;
|
|
for (;;) {
|
|
if (m_fragments.is_empty())
|
|
return;
|
|
// last_fragment cannot be null from here on down, as m_fragments is not empty.
|
|
last_fragment = &m_fragments.last();
|
|
if (!should_trim(last_fragment))
|
|
return;
|
|
if (last_fragment->is_justifiable_whitespace()) {
|
|
m_width -= last_fragment->width();
|
|
m_fragments.remove(m_fragments.size() - 1);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
auto last_text = last_fragment->text();
|
|
if (last_text.is_null())
|
|
return;
|
|
|
|
while (last_fragment->length()) {
|
|
auto last_character = last_text[last_fragment->length() - 1];
|
|
if (!is_ascii_space(last_character))
|
|
break;
|
|
|
|
int last_character_width = last_fragment->layout_node().font().glyph_width(last_character);
|
|
last_fragment->m_length -= 1;
|
|
last_fragment->set_width(last_fragment->width() - last_character_width);
|
|
m_width -= last_character_width;
|
|
}
|
|
}
|
|
|
|
bool LineBox::is_empty_or_ends_in_whitespace() const
|
|
{
|
|
if (m_fragments.is_empty())
|
|
return true;
|
|
|
|
return m_fragments.last().ends_in_whitespace();
|
|
}
|
|
|
|
}
|