LibWeb: Add support for CSS image-rendering property

Currently only "auto" and "pixelated" values are supported.
This commit is contained in:
Maciej 2022-02-18 12:21:27 +01:00 committed by Andreas Kling
parent 246b42b635
commit 3e1c1c0b16
11 changed files with 73 additions and 1 deletions

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>image-rendering property</title>
</head>
<body>
<h1>image-rendering property</h1>
<p>This image should be blurred:</p>
<img style="width: 256px" src="file:///res/graphics/buggie.png">
<p>This image should be blurred:</p>
<img style="image-rendering: auto; width: 256px" src="file:///res/graphics/buggie.png">
<p>This image should be pixelated:</p>
<img style="image-rendering: pixelated; width: 256px" src="file:///res/graphics/buggie.png">
</body>
</html>

View file

@ -117,6 +117,7 @@
<li><a href="float-3.html">Floating boxes with overflow=hidden</a></li>
<li><a href="clear-1.html">Float clearing</a></li>
<li><a href="overflow.html">Overflow</a></li>
<li><a href="image-rendering.html">image-rendering property</a></li>
<li><h3>Features</h3></li>
<li><a href="css.html">Basic functionality</a></li>
<li><a href="colors.html">css colors</a></li>

View file

@ -29,6 +29,7 @@ public:
static CSS::ListStyleType list_style_type() { return CSS::ListStyleType::Disc; }
static CSS::FlexDirection flex_direction() { return CSS::FlexDirection::Row; }
static CSS::FlexWrap flex_wrap() { return CSS::FlexWrap::Nowrap; }
static CSS::ImageRendering image_rendering() { return CSS::ImageRendering::Auto; }
static CSS::JustifyContent justify_content() { return CSS::JustifyContent::FlexStart; }
static CSS::AlignItems align_items() { return CSS::AlignItems::Stretch; }
static CSS::Overflow overflow() { return CSS::Overflow::Visible; }
@ -105,6 +106,7 @@ public:
float flex_shrink() const { return m_noninherited.flex_shrink; }
CSS::AlignItems align_items() const { return m_noninherited.align_items; }
float opacity() const { return m_noninherited.opacity; }
CSS::ImageRendering image_rendering() const { return m_inherited.image_rendering; }
CSS::JustifyContent justify_content() const { return m_noninherited.justify_content; }
Vector<BoxShadowData> const& box_shadow() const { return m_noninherited.box_shadow; }
CSS::BoxSizing box_sizing() const { return m_noninherited.box_sizing; }
@ -155,6 +157,7 @@ protected:
struct {
Color color { InitialValues::color() };
CSS::Cursor cursor { InitialValues::cursor() };
CSS::ImageRendering image_rendering { InitialValues::image_rendering() };
CSS::PointerEvents pointer_events { InitialValues::pointer_events() };
CSS::TextAlign text_align { InitialValues::text_align() };
CSS::TextTransform text_transform { InitialValues::text_transform() };
@ -216,6 +219,7 @@ class MutableComputedValues final : public ComputedValues {
public:
void set_color(const Color& color) { m_inherited.color = color; }
void set_cursor(CSS::Cursor cursor) { m_inherited.cursor = cursor; }
void set_image_rendering(CSS::ImageRendering value) { m_inherited.image_rendering = value; }
void set_pointer_events(CSS::PointerEvents value) { m_inherited.pointer_events = value; }
void set_background_color(const Color& color) { m_noninherited.background_color = color; }
void set_background_layers(Vector<BackgroundLayerData>&& layers) { m_noninherited.background_layers = move(layers); }

View file

@ -156,6 +156,7 @@
"outside",
"overline",
"padding-box",
"pixelated",
"pointer",
"pre",
"pre-line",

View file

@ -748,6 +748,14 @@
"unitless-length"
]
},
"image-rendering": {
"inherited": true,
"initial": "auto",
"valid-identifiers": [
"auto",
"pixelated"
]
},
"justify-content": {
"inherited": false,
"initial": "flex-start",

View file

@ -358,6 +358,17 @@ static CSS::ValueID to_css_value_id(CSS::FlexWrap value)
VERIFY_NOT_REACHED();
}
static CSS::ValueID to_css_value_id(CSS::ImageRendering value)
{
switch (value) {
case ImageRendering::Auto:
return CSS::ValueID::Auto;
case ImageRendering::Pixelated:
return CSS::ValueID::Pixelated;
}
VERIFY_NOT_REACHED();
}
static CSS::ValueID to_css_value_id(CSS::JustifyContent value)
{
switch (value) {
@ -515,6 +526,8 @@ RefPtr<StyleValue> ResolvedCSSStyleDeclaration::style_value_for_property(Layout:
return NumericStyleValue::create_float(layout_node.computed_values().flex_shrink());
case CSS::PropertyID::Opacity:
return NumericStyleValue::create_float(layout_node.computed_values().opacity());
case CSS::PropertyID::ImageRendering:
return IdentifierStyleValue::create(to_css_value_id(layout_node.computed_values().image_rendering()));
case CSS::PropertyID::JustifyContent:
return IdentifierStyleValue::create(to_css_value_id(layout_node.computed_values().justify_content()));
case CSS::PropertyID::BoxShadow: {

View file

@ -269,6 +269,21 @@ float StyleProperties::flex_shrink() const
return value.value()->to_number();
}
Optional<CSS::ImageRendering> StyleProperties::image_rendering() const
{
auto value = property(CSS::PropertyID::ImageRendering);
if (!value.has_value())
return {};
switch (value.value()->to_identifier()) {
case CSS::ValueID::Auto:
return CSS::ImageRendering::Auto;
case CSS::ValueID::Pixelated:
return CSS::ImageRendering::Pixelated;
default:
return {};
}
}
Optional<CSS::JustifyContent> StyleProperties::justify_content() const
{
auto value = property(CSS::PropertyID::JustifyContent);

View file

@ -62,6 +62,7 @@ public:
float flex_shrink() const;
Optional<CSS::AlignItems> align_items() const;
float opacity() const;
Optional<CSS::ImageRendering> image_rendering() const;
Optional<CSS::JustifyContent> justify_content() const;
Optional<CSS::Overflow> overflow_x() const;
Optional<CSS::Overflow> overflow_y() const;

View file

@ -140,6 +140,11 @@ enum class Float {
Right,
};
enum class ImageRendering {
Auto,
Pixelated
};
enum class JustifyContent {
FlexStart,
FlexEnd,

View file

@ -7,6 +7,8 @@
#include <LibGfx/FontDatabase.h>
#include <LibGfx/Painter.h>
#include <LibGfx/StylePainter.h>
#include <LibWeb/CSS/StyleValue.h>
#include <LibWeb/CSS/ValueID.h>
#include <LibWeb/HTML/BrowsingContext.h>
#include <LibWeb/Layout/ImageBox.h>
@ -91,7 +93,9 @@ void ImageBox::paint(PaintContext& context, PaintPhase phase)
alt = image_element.src();
context.painter().draw_text(enclosing_int_rect(absolute_rect()), alt, Gfx::TextAlignment::Center, computed_values().color(), Gfx::TextElision::Right);
} else if (auto bitmap = m_image_loader.bitmap(m_image_loader.current_frame_index())) {
context.painter().draw_scaled_bitmap(rounded_int_rect(absolute_rect()), *bitmap, bitmap->rect(), 1.0f, Gfx::Painter::ScalingMode::BilinearBlend);
// FIXME: Support 'crisp-edges', 'smooth' and 'high-quality'
auto scaling_mode = computed_values().image_rendering() == CSS::ImageRendering::Pixelated ? Gfx::Painter::ScalingMode::NearestNeighbor : Gfx::Painter::ScalingMode::BilinearBlend;
context.painter().draw_scaled_bitmap(rounded_int_rect(absolute_rect()), *bitmap, bitmap->rect(), 1.0f, scaling_mode);
}
}
}

View file

@ -396,6 +396,10 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style)
if (cursor.has_value())
computed_values.set_cursor(cursor.value());
auto image_rendering = specified_style.image_rendering();
if (image_rendering.has_value())
computed_values.set_image_rendering(image_rendering.value());
auto pointer_events = specified_style.pointer_events();
if (pointer_events.has_value())
computed_values.set_pointer_events(pointer_events.value());