mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 13:28:11 +00:00
LibHTML: Use floating point numbers throughout the layout tree
This commit is contained in:
parent
da23864c8d
commit
c628ebda0f
15 changed files with 59 additions and 52 deletions
|
@ -15,21 +15,26 @@ public:
|
||||||
, m_value(value)
|
, m_value(value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
Length(float value, Type type)
|
||||||
|
: m_type(type)
|
||||||
|
, m_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
~Length() {}
|
~Length() {}
|
||||||
|
|
||||||
bool is_auto() const { return m_type == Type::Auto; }
|
bool is_auto() const { return m_type == Type::Auto; }
|
||||||
bool is_absolute() const { return m_type == Type::Absolute; }
|
bool is_absolute() const { return m_type == Type::Absolute; }
|
||||||
|
|
||||||
int value() const { return m_value; }
|
float value() const { return m_value; }
|
||||||
|
|
||||||
String to_string() const
|
String to_string() const
|
||||||
{
|
{
|
||||||
if (is_auto())
|
if (is_auto())
|
||||||
return "[Length/auto]";
|
return "[Length/auto]";
|
||||||
return String::format("%d [Length/px]", m_value);
|
return String::format("%g [Length/px]", m_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
int to_px() const
|
float to_px() const
|
||||||
{
|
{
|
||||||
if (is_auto())
|
if (is_auto())
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -38,7 +43,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type m_type { Type::Auto };
|
Type m_type { Type::Auto };
|
||||||
int m_value { 0 };
|
float m_value { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const LogStream& operator<<(const LogStream& stream, const Length& value)
|
inline const LogStream& operator<<(const LogStream& stream, const Length& value)
|
||||||
|
|
|
@ -101,10 +101,9 @@ void StyleProperties::load_font() const
|
||||||
FontCache::the().set({ font_family, font_weight }, *m_font);
|
FontCache::the().set({ font_family, font_weight }, *m_font);
|
||||||
}
|
}
|
||||||
|
|
||||||
int StyleProperties::line_height() const
|
float StyleProperties::line_height() const
|
||||||
{
|
{
|
||||||
// FIXME: Allow overriding the line-height. We currently default to 140% which seems to look nice.
|
return (float)font().glyph_height() * 1.4f;
|
||||||
return (int)(font().glyph_height() * 1.4f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StyleProperties::operator==(const StyleProperties& other) const
|
bool StyleProperties::operator==(const StyleProperties& other) const
|
||||||
|
|
|
@ -32,7 +32,7 @@ public:
|
||||||
return *m_font;
|
return *m_font;
|
||||||
}
|
}
|
||||||
|
|
||||||
int line_height() const;
|
float line_height() const;
|
||||||
|
|
||||||
bool operator==(const StyleProperties&) const;
|
bool operator==(const StyleProperties&) const;
|
||||||
bool operator!=(const StyleProperties& other) const { return !(*this == other); }
|
bool operator!=(const StyleProperties& other) const { return !(*this == other); }
|
||||||
|
|
|
@ -85,14 +85,14 @@ void HtmlView::layout_and_sync_size()
|
||||||
|
|
||||||
main_frame().set_size(available_size());
|
main_frame().set_size(available_size());
|
||||||
document()->layout();
|
document()->layout();
|
||||||
set_content_size(layout_root()->size());
|
set_content_size(enclosing_int_rect(layout_root()->rect()).size());
|
||||||
|
|
||||||
// NOTE: If layout caused us to gain or lose scrollbars, we have to lay out again
|
// NOTE: If layout caused us to gain or lose scrollbars, we have to lay out again
|
||||||
// since the scrollbars now take up some of the available space.
|
// since the scrollbars now take up some of the available space.
|
||||||
if (had_vertical_scrollbar != vertical_scrollbar().is_visible() || had_horizontal_scrollbar != horizontal_scrollbar().is_visible()) {
|
if (had_vertical_scrollbar != vertical_scrollbar().is_visible() || had_horizontal_scrollbar != horizontal_scrollbar().is_visible()) {
|
||||||
main_frame().set_size(available_size());
|
main_frame().set_size(available_size());
|
||||||
document()->layout();
|
document()->layout();
|
||||||
set_content_size(layout_root()->size());
|
set_content_size(enclosing_int_rect(layout_root()->rect()).size());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HTML_DEBUG
|
#ifdef HTML_DEBUG
|
||||||
|
@ -360,7 +360,8 @@ void HtmlView::scroll_to_anchor(const StringView& name)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto& layout_node = *element->layout_node();
|
auto& layout_node = *element->layout_node();
|
||||||
scroll_into_view({ layout_node.box_type_agnostic_position(), visible_content_rect().size() }, true, true);
|
FloatRect float_rect { layout_node.box_type_agnostic_position(), { (float)visible_content_rect().width(), (float)visible_content_rect().height() } };
|
||||||
|
scroll_into_view(enclosing_int_rect(float_rect), true, true);
|
||||||
window()->set_override_cursor(GStandardCursor::None);
|
window()->set_override_cursor(GStandardCursor::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,10 @@ public:
|
||||||
const LengthBox& border() const { return m_border; }
|
const LengthBox& border() const { return m_border; }
|
||||||
|
|
||||||
struct PixelBox {
|
struct PixelBox {
|
||||||
int top;
|
float top;
|
||||||
int right;
|
float right;
|
||||||
int bottom;
|
float bottom;
|
||||||
int left;
|
float left;
|
||||||
};
|
};
|
||||||
|
|
||||||
PixelBox full_margin() const;
|
PixelBox full_margin() const;
|
||||||
|
|
|
@ -41,7 +41,7 @@ void LayoutBlock::layout()
|
||||||
void LayoutBlock::layout_block_children()
|
void LayoutBlock::layout_block_children()
|
||||||
{
|
{
|
||||||
ASSERT(!children_are_inline());
|
ASSERT(!children_are_inline());
|
||||||
int content_height = 0;
|
float content_height = 0;
|
||||||
for_each_child([&](auto& child) {
|
for_each_child([&](auto& child) {
|
||||||
// FIXME: What should we do here? Something like a <table> might have a bunch of useless text children..
|
// FIXME: What should we do here? Something like a <table> might have a bunch of useless text children..
|
||||||
if (child.is_inline())
|
if (child.is_inline())
|
||||||
|
@ -66,8 +66,8 @@ void LayoutBlock::layout_inline_children()
|
||||||
line_box.trim_trailing_whitespace();
|
line_box.trim_trailing_whitespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
int min_line_height = style().line_height();
|
float min_line_height = style().line_height();
|
||||||
int content_height = 0;
|
float content_height = 0;
|
||||||
|
|
||||||
// FIXME: This should be done by the CSS parser!
|
// FIXME: This should be done by the CSS parser!
|
||||||
CSS::ValueID text_align = CSS::ValueID::Left;
|
CSS::ValueID text_align = CSS::ValueID::Left;
|
||||||
|
@ -82,9 +82,9 @@ void LayoutBlock::layout_inline_children()
|
||||||
text_align = CSS::ValueID::Justify;
|
text_align = CSS::ValueID::Justify;
|
||||||
|
|
||||||
for (auto& line_box : m_line_boxes) {
|
for (auto& line_box : m_line_boxes) {
|
||||||
int max_height = min_line_height;
|
float max_height = min_line_height;
|
||||||
for (auto& fragment : line_box.fragments()) {
|
for (auto& fragment : line_box.fragments()) {
|
||||||
max_height = max(max_height, enclosing_int_rect(fragment.rect()).height());
|
max_height = max(max_height, fragment.rect().height());
|
||||||
}
|
}
|
||||||
|
|
||||||
float x_offset = x();
|
float x_offset = x();
|
||||||
|
@ -137,7 +137,7 @@ void LayoutBlock::layout_inline_children()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is<LayoutReplaced>(fragment.layout_node()))
|
if (is<LayoutReplaced>(fragment.layout_node()))
|
||||||
const_cast<LayoutReplaced&>(to<LayoutReplaced>(fragment.layout_node())).set_rect(enclosing_int_rect(fragment.rect()));
|
const_cast<LayoutReplaced&>(to<LayoutReplaced>(fragment.layout_node())).set_rect(fragment.rect());
|
||||||
|
|
||||||
float final_line_box_width = 0;
|
float final_line_box_width = 0;
|
||||||
for (auto& fragment : line_box.fragments())
|
for (auto& fragment : line_box.fragments())
|
||||||
|
@ -178,7 +178,7 @@ void LayoutBlock::compute_width()
|
||||||
padding_left = style.length_or_fallback(CSS::PropertyID::PaddingLeft, zero_value);
|
padding_left = style.length_or_fallback(CSS::PropertyID::PaddingLeft, zero_value);
|
||||||
padding_right = style.length_or_fallback(CSS::PropertyID::PaddingRight, zero_value);
|
padding_right = style.length_or_fallback(CSS::PropertyID::PaddingRight, zero_value);
|
||||||
|
|
||||||
int total_px = 0;
|
float total_px = 0;
|
||||||
for (auto& value : { margin_left, border_left, padding_left, width, padding_right, border_right, margin_right }) {
|
for (auto& value : { margin_left, border_left, padding_left, width, padding_right, border_right, margin_right }) {
|
||||||
total_px += value.to_px();
|
total_px += value.to_px();
|
||||||
}
|
}
|
||||||
|
@ -275,7 +275,7 @@ void LayoutBlock::compute_position()
|
||||||
box_model().padding().bottom = style.length_or_fallback(CSS::PropertyID::PaddingBottom, 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());
|
rect().set_x(containing_block()->x() + box_model().margin().left.to_px() + box_model().border().left.to_px() + box_model().padding().left.to_px());
|
||||||
|
|
||||||
int top_border = -1;
|
float top_border = -1;
|
||||||
if (previous_sibling() != nullptr) {
|
if (previous_sibling() != nullptr) {
|
||||||
auto& previous_sibling_rect = previous_sibling()->rect();
|
auto& previous_sibling_rect = previous_sibling()->rect();
|
||||||
auto& previous_sibling_style = previous_sibling()->box_model();
|
auto& previous_sibling_style = previous_sibling()->box_model();
|
||||||
|
|
|
@ -22,7 +22,7 @@ void LayoutBox::render(RenderingContext& context)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (node() && document().inspected_node() == node())
|
if (node() && document().inspected_node() == node())
|
||||||
context.painter().draw_rect(m_rect, Color::Magenta);
|
context.painter().draw_rect(enclosing_int_rect(m_rect), Color::Magenta);
|
||||||
|
|
||||||
Rect padded_rect;
|
Rect padded_rect;
|
||||||
padded_rect.set_x(x() - box_model().padding().left.to_px());
|
padded_rect.set_x(x() - box_model().padding().left.to_px());
|
||||||
|
@ -51,7 +51,7 @@ void LayoutBox::render(RenderingContext& context)
|
||||||
auto border_style_value = style().property(CSS::PropertyID::BorderTopStyle);
|
auto border_style_value = style().property(CSS::PropertyID::BorderTopStyle);
|
||||||
|
|
||||||
if (border_width_value.has_value()) {
|
if (border_width_value.has_value()) {
|
||||||
int border_width = border_width_value.value()->to_length().to_px();
|
float border_width = border_width_value.value()->to_length().to_px();
|
||||||
|
|
||||||
Color border_color;
|
Color border_color;
|
||||||
if (border_color_value.has_value())
|
if (border_color_value.has_value())
|
||||||
|
@ -99,7 +99,7 @@ HitTestResult LayoutBox::hit_test(const Point& position) const
|
||||||
// FIXME: It would be nice if we could confidently skip over hit testing
|
// 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
|
// parts of the layout tree, but currently we can't just check
|
||||||
// m_rect.contains() since inline text rects can't be trusted..
|
// m_rect.contains() since inline text rects can't be trusted..
|
||||||
HitTestResult result { m_rect.contains(position) ? this : nullptr };
|
HitTestResult result { m_rect.contains(FloatPoint(position.x(), position.y())) ? this : nullptr };
|
||||||
for_each_child([&](auto& child) {
|
for_each_child([&](auto& child) {
|
||||||
auto child_result = child.hit_test(position);
|
auto child_result = child.hit_test(position);
|
||||||
if (child_result.layout_node)
|
if (child_result.layout_node)
|
||||||
|
@ -114,7 +114,7 @@ void LayoutBox::set_needs_display()
|
||||||
ASSERT(frame);
|
ASSERT(frame);
|
||||||
|
|
||||||
if (!is_inline()) {
|
if (!is_inline()) {
|
||||||
const_cast<Frame*>(frame)->set_needs_display(rect());
|
const_cast<Frame*>(frame)->set_needs_display(enclosing_int_rect(rect()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibDraw/FloatRect.h>
|
||||||
#include <LibHTML/Layout/LayoutNode.h>
|
#include <LibHTML/Layout/LayoutNode.h>
|
||||||
|
|
||||||
class LayoutBox : public LayoutNodeWithStyleAndBoxModelMetrics {
|
class LayoutBox : public LayoutNodeWithStyleAndBoxModelMetrics {
|
||||||
public:
|
public:
|
||||||
const Rect& rect() const { return m_rect; }
|
const FloatRect& rect() const { return m_rect; }
|
||||||
Rect& rect() { return m_rect; }
|
FloatRect& rect() { return m_rect; }
|
||||||
void set_rect(const Rect& rect) { m_rect = rect; }
|
void set_rect(const FloatRect& rect) { m_rect = rect; }
|
||||||
|
|
||||||
int x() const { return rect().x(); }
|
float x() const { return rect().x(); }
|
||||||
int y() const { return rect().y(); }
|
float y() const { return rect().y(); }
|
||||||
int width() const { return rect().width(); }
|
float width() const { return rect().width(); }
|
||||||
int height() const { return rect().height(); }
|
float height() const { return rect().height(); }
|
||||||
Size size() const { return rect().size(); }
|
FloatSize size() const { return rect().size(); }
|
||||||
Point position() const { return rect().location(); }
|
FloatPoint position() const { return rect().location(); }
|
||||||
|
|
||||||
virtual HitTestResult hit_test(const Point& position) const override;
|
virtual HitTestResult hit_test(const Point& position) const override;
|
||||||
virtual void set_needs_display() override;
|
virtual void set_needs_display() override;
|
||||||
|
@ -31,7 +32,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
virtual bool is_box() const override { return true; }
|
virtual bool is_box() const override { return true; }
|
||||||
|
|
||||||
Rect m_rect;
|
FloatRect m_rect;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
|
@ -38,18 +38,18 @@ void LayoutImage::render(RenderingContext& context)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// FIXME: This should be done at a different level. Also rect() does not include padding etc!
|
// FIXME: This should be done at a different level. Also rect() does not include padding etc!
|
||||||
if (!context.viewport_rect().intersects(rect()))
|
if (!context.viewport_rect().intersects(enclosing_int_rect(rect())))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (renders_as_alt_text()) {
|
if (renders_as_alt_text()) {
|
||||||
context.painter().set_font(Font::default_font());
|
context.painter().set_font(Font::default_font());
|
||||||
StylePainter::paint_frame(context.painter(), rect(), FrameShape::Container, FrameShadow::Sunken, 2);
|
StylePainter::paint_frame(context.painter(), enclosing_int_rect(rect()), FrameShape::Container, FrameShadow::Sunken, 2);
|
||||||
auto alt = node().alt();
|
auto alt = node().alt();
|
||||||
if (alt.is_empty())
|
if (alt.is_empty())
|
||||||
alt = node().src();
|
alt = node().src();
|
||||||
context.painter().draw_text(rect(), alt, TextAlignment::Center, style().color_or_fallback(CSS::PropertyID::Color, document(), Color::Black), TextElision::Right);
|
context.painter().draw_text(enclosing_int_rect(rect()), alt, TextAlignment::Center, style().color_or_fallback(CSS::PropertyID::Color, document(), Color::Black), TextElision::Right);
|
||||||
} else {
|
} else {
|
||||||
context.painter().draw_scaled_bitmap(rect(), *node().bitmap(), node().bitmap()->rect());
|
context.painter().draw_scaled_bitmap(enclosing_int_rect(rect()), *node().bitmap(), node().bitmap()->rect());
|
||||||
}
|
}
|
||||||
LayoutReplaced::render(context);
|
LayoutReplaced::render(context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,6 @@ void LayoutListItem::layout()
|
||||||
append_child(*m_marker);
|
append_child(*m_marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect marker_rect { x() - 8, y(), 4, height() };
|
FloatRect marker_rect { x() - 8, y(), 4, height() };
|
||||||
m_marker->set_rect(marker_rect);
|
m_marker->set_rect(marker_rect);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ LayoutListItemMarker::~LayoutListItemMarker()
|
||||||
void LayoutListItemMarker::render(RenderingContext& context)
|
void LayoutListItemMarker::render(RenderingContext& context)
|
||||||
{
|
{
|
||||||
Rect bullet_rect { 0, 0, 4, 4 };
|
Rect bullet_rect { 0, 0, 4, 4 };
|
||||||
bullet_rect.center_within(rect());
|
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.
|
// FIXME: It would be nicer to not have to go via the parent here to get our inherited style.
|
||||||
context.painter().fill_rect(bullet_rect, parent()->style().color_or_fallback(CSS::PropertyID::Color, document(), Color::Black));
|
context.painter().fill_rect(bullet_rect, parent()->style().color_or_fallback(CSS::PropertyID::Color, document(), Color::Black));
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,16 +109,16 @@ void LayoutNode::set_needs_display()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Point LayoutNode::box_type_agnostic_position() const
|
FloatPoint LayoutNode::box_type_agnostic_position() const
|
||||||
{
|
{
|
||||||
if (is_box())
|
if (is_box())
|
||||||
return to<LayoutBox>(*this).position();
|
return to<LayoutBox>(*this).position();
|
||||||
ASSERT(is_inline());
|
ASSERT(is_inline());
|
||||||
Point position;
|
FloatPoint position;
|
||||||
if (auto* block = containing_block()) {
|
if (auto* block = containing_block()) {
|
||||||
block->for_each_fragment([&](auto& fragment) {
|
block->for_each_fragment([&](auto& fragment) {
|
||||||
if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
|
if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
|
||||||
position = enclosing_int_rect(fragment.rect()).location();
|
position = fragment.rect().location();
|
||||||
return IterationDecision::Break;
|
return IterationDecision::Break;
|
||||||
}
|
}
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <AK/NonnullRefPtr.h>
|
#include <AK/NonnullRefPtr.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
|
#include <LibDraw/FloatRect.h>
|
||||||
#include <LibDraw/Rect.h>
|
#include <LibDraw/Rect.h>
|
||||||
#include <LibHTML/CSS/StyleProperties.h>
|
#include <LibHTML/CSS/StyleProperties.h>
|
||||||
#include <LibHTML/Layout/BoxModelMetrics.h>
|
#include <LibHTML/Layout/BoxModelMetrics.h>
|
||||||
|
@ -108,7 +109,7 @@ public:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T* first_ancestor_of_type();
|
T* first_ancestor_of_type();
|
||||||
|
|
||||||
Point box_type_agnostic_position() const;
|
FloatPoint box_type_agnostic_position() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit LayoutNode(const Node*);
|
explicit LayoutNode(const Node*);
|
||||||
|
|
|
@ -126,13 +126,13 @@ void LayoutText::for_each_source_line(Callback callback) const
|
||||||
void LayoutText::split_into_lines(LayoutBlock& container)
|
void LayoutText::split_into_lines(LayoutBlock& container)
|
||||||
{
|
{
|
||||||
auto& font = style().font();
|
auto& font = style().font();
|
||||||
int space_width = font.glyph_width(' ') + font.glyph_spacing();
|
float space_width = font.glyph_width(' ') + font.glyph_spacing();
|
||||||
int line_height = style().line_height();
|
float line_height = style().line_height();
|
||||||
|
|
||||||
auto& line_boxes = container.line_boxes();
|
auto& line_boxes = container.line_boxes();
|
||||||
if (line_boxes.is_empty())
|
if (line_boxes.is_empty())
|
||||||
line_boxes.append(LineBox());
|
line_boxes.append(LineBox());
|
||||||
int available_width = container.width() - line_boxes.last().width();
|
float available_width = container.width() - line_boxes.last().width();
|
||||||
|
|
||||||
bool is_preformatted = style().string_or_fallback(CSS::PropertyID::WhiteSpace, "normal") == "pre";
|
bool is_preformatted = style().string_or_fallback(CSS::PropertyID::WhiteSpace, "normal") == "pre";
|
||||||
if (is_preformatted) {
|
if (is_preformatted) {
|
||||||
|
@ -176,7 +176,7 @@ void LayoutText::split_into_lines(LayoutBlock& container)
|
||||||
for (int i = 0; i < words.size(); ++i) {
|
for (int i = 0; i < words.size(); ++i) {
|
||||||
auto& word = words[i];
|
auto& word = words[i];
|
||||||
|
|
||||||
int word_width;
|
float word_width;
|
||||||
bool is_whitespace = isspace(*word.view.begin());
|
bool is_whitespace = isspace(*word.view.begin());
|
||||||
|
|
||||||
if (is_whitespace)
|
if (is_whitespace)
|
||||||
|
|
|
@ -28,7 +28,7 @@ NonnullRefPtr<StyleValue> parse_css_value(const StringView& view)
|
||||||
char* endptr = nullptr;
|
char* endptr = nullptr;
|
||||||
long value = strtol(String(view).characters(), &endptr, 10);
|
long value = strtol(String(view).characters(), &endptr, 10);
|
||||||
if (endptr && ((!*endptr) || (endptr[0] == 'p' && endptr[1] == 'x' && endptr[2] == '\0')))
|
if (endptr && ((!*endptr) || (endptr[0] == 'p' && endptr[1] == 'x' && endptr[2] == '\0')))
|
||||||
return LengthStyleValue::create(Length(value, Length::Type::Absolute));
|
return LengthStyleValue::create(Length((float)value, Length::Type::Absolute));
|
||||||
if (string == "inherit")
|
if (string == "inherit")
|
||||||
return InheritStyleValue::create();
|
return InheritStyleValue::create();
|
||||||
if (string == "initial")
|
if (string == "initial")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue