mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 19:52:45 +00:00 
			
		
		
		
	LibWeb: Compute the final border-style property before painting
Instead of doing a CSS property lookup for the line style of each border edge during paint, we now cache the final CSS::LineStyle to use in the Layout::BorderData.
This commit is contained in:
		
							parent
							
								
									88ca932fac
								
							
						
					
					
						commit
						2cbbab8f73
					
				
					 7 changed files with 82 additions and 50 deletions
				
			
		|  | @ -259,6 +259,35 @@ Optional<CSS::WhiteSpace> StyleProperties::white_space() const | |||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| Optional<CSS::LineStyle> StyleProperties::line_style(CSS::PropertyID property_id) const | ||||
| { | ||||
|     auto value = property(property_id); | ||||
|     if (!value.has_value() || !value.value()->is_string()) | ||||
|         return {}; | ||||
|     auto string = value.value()->to_string(); | ||||
|     if (string == "none") | ||||
|         return CSS::LineStyle::None; | ||||
|     if (string == "hidden") | ||||
|         return CSS::LineStyle::Hidden; | ||||
|     if (string == "dotted") | ||||
|         return CSS::LineStyle::Dotted; | ||||
|     if (string == "dashed") | ||||
|         return CSS::LineStyle::Dashed; | ||||
|     if (string == "solid") | ||||
|         return CSS::LineStyle::Solid; | ||||
|     if (string == "double") | ||||
|         return CSS::LineStyle::Double; | ||||
|     if (string == "groove") | ||||
|         return CSS::LineStyle::Groove; | ||||
|     if (string == "ridge") | ||||
|         return CSS::LineStyle::Ridge; | ||||
|     if (string == "inset") | ||||
|         return CSS::LineStyle::Inset; | ||||
|     if (string == "outset") | ||||
|         return CSS::LineStyle::Outset; | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| Optional<CSS::Float> StyleProperties::float_() const | ||||
| { | ||||
|     auto value = property(CSS::PropertyID::Float); | ||||
|  |  | |||
|  | @ -64,6 +64,7 @@ public: | |||
|     CSS::Display display() const; | ||||
|     Optional<CSS::Float> float_() const; | ||||
|     Optional<CSS::WhiteSpace> white_space() const; | ||||
|     Optional<CSS::LineStyle> line_style(CSS::PropertyID) const; | ||||
| 
 | ||||
|     const Gfx::Font& font() const | ||||
|     { | ||||
|  |  | |||
|  | @ -149,6 +149,19 @@ enum class Float { | |||
|     Right, | ||||
| }; | ||||
| 
 | ||||
| enum class LineStyle { | ||||
|     None, | ||||
|     Hidden, | ||||
|     Dotted, | ||||
|     Dashed, | ||||
|     Solid, | ||||
|     Double, | ||||
|     Groove, | ||||
|     Ridge, | ||||
|     Inset, | ||||
|     Outset, | ||||
| }; | ||||
| 
 | ||||
| class StyleValue : public RefCounted<StyleValue> { | ||||
| public: | ||||
|     virtual ~StyleValue(); | ||||
|  |  | |||
|  | @ -33,66 +33,53 @@ | |||
| 
 | ||||
| namespace Web::Layout { | ||||
| 
 | ||||
| void Box::paint_border(PaintContext& context, Edge edge, const Gfx::FloatRect& rect, CSS::PropertyID style_property_id, const BorderData& border_data) | ||||
| void Box::paint_border(PaintContext& context, Edge edge, const Gfx::FloatRect& rect, const BorderData& border_data) | ||||
| { | ||||
|     float width = border_data.width; | ||||
|     if (width <= 0) | ||||
|         return; | ||||
| 
 | ||||
|     auto color = border_data.color; | ||||
|     auto border_style = specified_style().property(style_property_id); | ||||
|     auto border_style = border_data.line_style; | ||||
|     int int_width = max((int)width, 1); | ||||
| 
 | ||||
|     auto first_point_for_edge = [](Edge edge, const Gfx::FloatRect& rect) { | ||||
|     struct Points { | ||||
|         Gfx::FloatPoint p1; | ||||
|         Gfx::FloatPoint p2; | ||||
|     }; | ||||
| 
 | ||||
|     auto points_for_edge = [](Edge edge, const Gfx::FloatRect& rect) -> Points { | ||||
|         switch (edge) { | ||||
|         case Edge::Top: | ||||
|             return rect.top_left(); | ||||
|             return { rect.top_left(), rect.top_right() }; | ||||
|         case Edge::Right: | ||||
|             return rect.top_right(); | ||||
|             return { rect.top_right(), rect.bottom_right() }; | ||||
|         case Edge::Bottom: | ||||
|             return rect.bottom_left(); | ||||
|         case Edge::Left: | ||||
|         default: | ||||
|             return rect.top_left(); | ||||
|             return { rect.bottom_left(), rect.bottom_right() }; | ||||
|         default: // Edge::Left
 | ||||
|             return { rect.top_left(), rect.bottom_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, p2] = points_for_edge(edge, rect); | ||||
| 
 | ||||
|     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") { | ||||
|     if (border_style == CSS::LineStyle::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") { | ||||
|     } else if (border_style == CSS::LineStyle::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; | ||||
|     } | ||||
| 
 | ||||
|     auto line_style = Gfx::Painter::LineStyle::Solid; | ||||
|     if (border_style.has_value()) { | ||||
|         if (border_style.value()->to_string() == "dotted") | ||||
|             line_style = Gfx::Painter::LineStyle::Dotted; | ||||
|         if (border_style.value()->to_string() == "dashed") | ||||
|             line_style = Gfx::Painter::LineStyle::Dashed; | ||||
|     } | ||||
|     auto gfx_line_style = Gfx::Painter::LineStyle::Solid; | ||||
|     if (border_style == CSS::LineStyle::Dotted) | ||||
|         gfx_line_style = Gfx::Painter::LineStyle::Dotted; | ||||
|     if (border_style == CSS::LineStyle::Dashed) | ||||
|         gfx_line_style = Gfx::Painter::LineStyle::Dashed; | ||||
| 
 | ||||
|     if (line_style != Gfx::Painter::LineStyle::Solid) { | ||||
|     if (gfx_line_style != Gfx::Painter::LineStyle::Solid) { | ||||
|         switch (edge) { | ||||
|         case Edge::Top: | ||||
|             p1.move_by(int_width / 2, int_width / 2); | ||||
|  | @ -111,12 +98,12 @@ void Box::paint_border(PaintContext& context, Edge edge, const Gfx::FloatRect& r | |||
|             p2.move_by(int_width / 2, -int_width / 2); | ||||
|             break; | ||||
|         } | ||||
|         context.painter().draw_line({ (int)p1.x(), (int)p1.y() }, { (int)p2.x(), (int)p2.y() }, color, int_width, line_style); | ||||
|         context.painter().draw_line({ (int)p1.x(), (int)p1.y() }, { (int)p2.x(), (int)p2.y() }, color, int_width, gfx_line_style); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     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, line_style); | ||||
|         context.painter().draw_line({ (int)p1.x(), (int)p1.y() }, { (int)p2.x(), (int)p2.y() }, color, 1, gfx_line_style); | ||||
|     }; | ||||
| 
 | ||||
|     float p1_step = 0; | ||||
|  | @ -200,10 +187,10 @@ void Box::paint(PaintContext& context, PaintPhase phase) | |||
|         bordered_rect.set_y(padded_rect.y() - box_model().border.top.to_px(*this)); | ||||
|         bordered_rect.set_height(padded_rect.height() + box_model().border.top.to_px(*this) + box_model().border.bottom.to_px(*this)); | ||||
| 
 | ||||
|         paint_border(context, Edge::Left, bordered_rect, CSS::PropertyID::BorderLeftStyle, style().border_left()); | ||||
|         paint_border(context, Edge::Right, bordered_rect, CSS::PropertyID::BorderRightStyle, style().border_right()); | ||||
|         paint_border(context, Edge::Top, bordered_rect, CSS::PropertyID::BorderTopStyle, style().border_top()); | ||||
|         paint_border(context, Edge::Bottom, bordered_rect, CSS::PropertyID::BorderBottomStyle, style().border_bottom()); | ||||
|         paint_border(context, Edge::Left, bordered_rect, style().border_left()); | ||||
|         paint_border(context, Edge::Right, bordered_rect, style().border_right()); | ||||
|         paint_border(context, Edge::Top, bordered_rect, style().border_top()); | ||||
|         paint_border(context, Edge::Bottom, bordered_rect, style().border_bottom()); | ||||
|     } | ||||
| 
 | ||||
|     Layout::NodeWithStyleAndBoxModelMetrics::paint(context, phase); | ||||
|  |  | |||
|  | @ -98,7 +98,7 @@ private: | |||
|         Bottom, | ||||
|         Left, | ||||
|     }; | ||||
|     void paint_border(PaintContext&, Edge, const Gfx::FloatRect&, CSS::PropertyID style_property_id, const BorderData&); | ||||
|     void paint_border(PaintContext&, Edge, const Gfx::FloatRect&, const BorderData&); | ||||
| 
 | ||||
|     Gfx::FloatPoint m_offset; | ||||
|     Gfx::FloatSize m_size; | ||||
|  |  | |||
|  | @ -41,6 +41,7 @@ public: | |||
| struct BorderData { | ||||
| public: | ||||
|     Color color { Color::Transparent }; | ||||
|     CSS::LineStyle line_style { CSS::LineStyle::None }; | ||||
|     float width { 0 }; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -241,15 +241,16 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style) | |||
|     style.set_margin(specified_style.length_box(CSS::PropertyID::MarginLeft, CSS::PropertyID::MarginTop, CSS::PropertyID::MarginRight, CSS::PropertyID::MarginBottom)); | ||||
|     style.set_padding(specified_style.length_box(CSS::PropertyID::PaddingLeft, CSS::PropertyID::PaddingTop, CSS::PropertyID::PaddingRight, CSS::PropertyID::PaddingBottom)); | ||||
| 
 | ||||
|     style.border_left().width = specified_style.length_or_fallback(CSS::PropertyID::BorderLeftWidth, {}).resolved_or_zero(*this, 0).to_px(*this); | ||||
|     style.border_top().width = specified_style.length_or_fallback(CSS::PropertyID::BorderTopWidth, {}).resolved_or_zero(*this, 0).to_px(*this); | ||||
|     style.border_right().width = specified_style.length_or_fallback(CSS::PropertyID::BorderRightWidth, {}).resolved_or_zero(*this, 0).to_px(*this); | ||||
|     style.border_bottom().width = specified_style.length_or_fallback(CSS::PropertyID::BorderBottomWidth, {}).resolved_or_zero(*this, 0).to_px(*this); | ||||
|     auto do_border_style = [&](BorderData& border, CSS::PropertyID width_property, CSS::PropertyID color_property, CSS::PropertyID style_property) { | ||||
|         border.width = specified_style.length_or_fallback(width_property, {}).resolved_or_zero(*this, 0).to_px(*this); | ||||
|         border.color = specified_style.color_or_fallback(color_property, document(), Color::Transparent); | ||||
|         border.line_style = specified_style.line_style(style_property).value_or(CSS::LineStyle::None); | ||||
|     }; | ||||
| 
 | ||||
|     style.border_left().color = specified_style.color_or_fallback(CSS::PropertyID::BorderLeftColor, document(), Color::Transparent); | ||||
|     style.border_top().color = specified_style.color_or_fallback(CSS::PropertyID::BorderTopColor, document(), Color::Transparent); | ||||
|     style.border_right().color = specified_style.color_or_fallback(CSS::PropertyID::BorderRightColor, document(), Color::Transparent); | ||||
|     style.border_bottom().color = specified_style.color_or_fallback(CSS::PropertyID::BorderBottomColor, document(), Color::Transparent); | ||||
|     do_border_style(style.border_left(), CSS::PropertyID::BorderLeftWidth, CSS::PropertyID::BorderLeftColor, CSS::PropertyID::BorderLeftStyle); | ||||
|     do_border_style(style.border_top(), CSS::PropertyID::BorderTopWidth, CSS::PropertyID::BorderTopColor, CSS::PropertyID::BorderTopStyle); | ||||
|     do_border_style(style.border_right(), CSS::PropertyID::BorderRightWidth, CSS::PropertyID::BorderRightColor, CSS::PropertyID::BorderRightStyle); | ||||
|     do_border_style(style.border_bottom(), CSS::PropertyID::BorderBottomWidth, CSS::PropertyID::BorderBottomColor, CSS::PropertyID::BorderBottomStyle); | ||||
| } | ||||
| 
 | ||||
| void Node::handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint&, unsigned, unsigned) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling