ladybird/Libraries/LibHTML/CSS/StyleProperties.cpp
Andreas Kling 735f02900b LibHTML: Implement basic partial style invalidation
This patch makes it possible to call Node::invalidate_style() and have
that node and all of its ancestors recompute their style.

We then figure out if the new style is visually different from the old
style, and if so do a paint invalidation with set_needs_display().
Note that the "are they visually different" code is very incomplete!

Use this to make hover effects a lot more efficient. They no longer
cause a full relayout+repaint, but only a style invalidation.
Style invalidations are still quite heavy though, and there's a lot of
room for improvement there. :^)
2019-10-14 18:33:23 +02:00

119 lines
3.7 KiB
C++

#include <LibCore/CDirIterator.h>
#include <LibHTML/CSS/StyleProperties.h>
#include <ctype.h>
void StyleProperties::set_property(CSS::PropertyID id, NonnullRefPtr<StyleValue> value)
{
m_property_values.set((unsigned)id, move(value));
}
Optional<NonnullRefPtr<StyleValue>> StyleProperties::property(CSS::PropertyID id) const
{
auto it = m_property_values.find((unsigned)id);
if (it == m_property_values.end())
return {};
return it->value;
}
Length StyleProperties::length_or_fallback(CSS::PropertyID id, const Length& fallback) const
{
auto value = property(id);
if (!value.has_value())
return fallback;
return value.value()->to_length();
}
String StyleProperties::string_or_fallback(CSS::PropertyID id, const StringView& fallback) const
{
auto value = property(id);
if (!value.has_value())
return fallback;
return value.value()->to_string();
}
Color StyleProperties::color_or_fallback(CSS::PropertyID id, const Document& document, Color fallback) const
{
auto value = property(id);
if (!value.has_value())
return fallback;
return value.value()->to_color(document);
}
void StyleProperties::load_font() const
{
auto font_family = string_or_fallback(CSS::PropertyID::FontFamily, "Katica");
auto font_weight = string_or_fallback(CSS::PropertyID::FontWeight, "normal");
String weight;
if (font_weight == "lighter")
weight = "Thin";
else if (font_weight == "normal")
weight = "";
else if (font_weight == "bold")
weight = "Bold";
else
ASSERT_NOT_REACHED();
auto look_for_file = [](const StringView& expected_name) -> String {
// TODO: handle font sizes properly?
CDirIterator it { "/res/fonts/", CDirIterator::Flags::SkipDots };
while (it.has_next()) {
String name = it.next_path();
ASSERT(name.ends_with(".font"));
if (!name.starts_with(expected_name))
continue;
// Check that a numeric size immediately
// follows the font name. This prevents,
// for example, matching KaticaBold when
// the regular Katica is requested.
if (!isdigit(name[expected_name.length()]))
continue;
return name;
}
return {};
};
String file_name = look_for_file(String::format("%s%s", font_family.characters(), weight.characters()));
if (file_name.is_null() && weight == "")
file_name = look_for_file(String::format("%sRegular", font_family.characters()));
if (file_name.is_null()) {
dbg() << "Failed to find a font for family " << font_family << " weight " << font_weight;
m_font = Font::default_font();
return;
}
#ifdef HTML_DEBUG
dbg() << "Found font " << file_name << " for family " << font_family << " weight " << font_weight;
#endif
m_font = Font::load_from_file(String::format("/res/fonts/%s", file_name.characters()));
}
int StyleProperties::line_height() const
{
// FIXME: Allow overriding the line-height. We currently default to 140% which seems to look nice.
return (int)(font().glyph_height() * 1.4f);
}
bool StyleProperties::operator==(const StyleProperties& other) const
{
if (m_property_values.size() != other.m_property_values.size())
return false;
for (auto& it : m_property_values) {
auto jt = other.m_property_values.find(it.key);
if (jt == other.m_property_values.end())
return false;
auto& my_value = *it.value;
auto& other_value = *jt->value;
if (my_value.type() != other_value.type())
return false;
if (my_value.to_string() != other_value.to_string())
return false;
}
return true;
}