| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  * modification, are permitted provided that the following conditions are met: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 1. Redistributions of source code must retain the above copyright notice, this | 
					
						
							|  |  |  |  *    list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | 
					
						
							|  |  |  |  *    this list of conditions and the following disclaimer in the documentation | 
					
						
							|  |  |  |  *    and/or other materials provided with the distribution. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 
					
						
							|  |  |  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
					
						
							|  |  |  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
					
						
							|  |  |  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | 
					
						
							|  |  |  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
					
						
							|  |  |  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 
					
						
							|  |  |  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | 
					
						
							|  |  |  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
					
						
							|  |  |  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
					
						
							|  |  |  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-06 20:33:02 +01:00
										 |  |  | #include <LibGUI/Painter.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-07 10:32:51 +01:00
										 |  |  | #include <LibWeb/DOM/Document.h>
 | 
					
						
							|  |  |  | #include <LibWeb/DOM/Element.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-07 10:06:22 +02:00
										 |  |  | #include <LibWeb/Frame/Frame.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-07 10:32:51 +01:00
										 |  |  | #include <LibWeb/Layout/LayoutBlock.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-05 16:54:28 +02:00
										 |  |  | #include <LibWeb/Layout/LayoutDocument.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-07 10:32:51 +01:00
										 |  |  | #include <LibWeb/Layout/LayoutNode.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-05 16:54:28 +02:00
										 |  |  | #include <LibWeb/Layout/LayoutReplaced.h>
 | 
					
						
							| 
									
										
										
										
											2019-06-15 22:49:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 10:27:02 +01:00
										 |  |  | namespace Web { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 19:41:12 +02:00
										 |  |  | LayoutNode::LayoutNode(Document& document, const Node* node) | 
					
						
							|  |  |  |     : m_document(document) | 
					
						
							|  |  |  |     , m_node(node) | 
					
						
							| 
									
										
										
										
											2019-06-15 22:49:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-04 21:05:52 +02:00
										 |  |  |     if (m_node) | 
					
						
							|  |  |  |         m_node->set_layout_node({}, this); | 
					
						
							| 
									
										
										
										
											2019-06-15 22:49:44 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | LayoutNode::~LayoutNode() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-13 12:34:25 +02:00
										 |  |  |     if (m_node && m_node->layout_node() == this) | 
					
						
							| 
									
										
										
										
											2019-10-04 21:05:52 +02:00
										 |  |  |         m_node->set_layout_node({}, nullptr); | 
					
						
							| 
									
										
										
										
											2019-06-15 22:49:44 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-27 19:20:49 +02:00
										 |  |  | void LayoutNode::layout(LayoutMode layout_mode) | 
					
						
							| 
									
										
										
										
											2019-06-16 21:35:03 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-05-26 21:53:10 +02:00
										 |  |  |     for_each_child([&](auto& child) { | 
					
						
							| 
									
										
										
										
											2020-05-27 19:20:49 +02:00
										 |  |  |         child.layout(layout_mode); | 
					
						
							| 
									
										
										
										
											2019-06-16 21:35:03 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-07-01 07:28:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-05 16:54:28 +02:00
										 |  |  | bool LayoutNode::can_contain_boxes_with_position_absolute() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-24 14:34:40 +02:00
										 |  |  |     return style().position() != CSS::Position::Static || is_root(); | 
					
						
							| 
									
										
										
										
											2020-06-05 16:54:28 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-01 07:28:37 +02:00
										 |  |  | const LayoutBlock* LayoutNode::containing_block() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-05 19:13:27 +02:00
										 |  |  |     auto nearest_block_ancestor = [this] { | 
					
						
							| 
									
										
										
										
											2020-06-05 16:54:28 +02:00
										 |  |  |         auto* ancestor = parent(); | 
					
						
							| 
									
										
										
										
											2020-06-05 19:13:27 +02:00
										 |  |  |         while (ancestor && !is<LayoutBlock>(*ancestor)) | 
					
						
							| 
									
										
										
										
											2020-06-05 16:54:28 +02:00
										 |  |  |             ancestor = ancestor->parent(); | 
					
						
							|  |  |  |         return to<LayoutBlock>(ancestor); | 
					
						
							| 
									
										
										
										
											2020-06-05 19:13:27 +02:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (is_text()) | 
					
						
							|  |  |  |         return nearest_block_ancestor(); | 
					
						
							| 
									
										
										
										
											2020-06-05 16:54:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 14:34:40 +02:00
										 |  |  |     auto position = style().position(); | 
					
						
							| 
									
										
										
										
											2020-06-12 14:19:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (position == CSS::Position::Absolute) { | 
					
						
							| 
									
										
										
										
											2020-06-05 16:54:28 +02:00
										 |  |  |         auto* ancestor = parent(); | 
					
						
							|  |  |  |         while (ancestor && !ancestor->can_contain_boxes_with_position_absolute()) | 
					
						
							|  |  |  |             ancestor = ancestor->parent(); | 
					
						
							|  |  |  |         while (ancestor && (!is<LayoutBlock>(ancestor) || ancestor->is_anonymous())) | 
					
						
							|  |  |  |             ancestor = ancestor->containing_block(); | 
					
						
							|  |  |  |         return to<LayoutBlock>(ancestor); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-12 14:19:03 +02:00
										 |  |  |     if (position == CSS::Position::Fixed) | 
					
						
							| 
									
										
										
										
											2020-06-05 16:54:28 +02:00
										 |  |  |         return &root(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-05 19:13:27 +02:00
										 |  |  |     return nearest_block_ancestor(); | 
					
						
							| 
									
										
										
										
											2019-07-01 07:28:37 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-09-25 12:40:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-18 21:35:44 +02:00
										 |  |  | void LayoutNode::paint(PaintContext& context, PaintPhase phase) | 
					
						
							| 
									
										
										
										
											2019-09-25 12:40:37 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-09 21:25:29 +02:00
										 |  |  |     if (!is_visible()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-25 12:40:37 +03:00
										 |  |  |     for_each_child([&](auto& child) { | 
					
						
							| 
									
										
										
										
											2020-06-15 17:29:35 +02:00
										 |  |  |         if (child.is_box() && to<LayoutBox>(child).stacking_context()) | 
					
						
							|  |  |  |             return; | 
					
						
							| 
									
										
										
										
											2020-06-18 21:35:44 +02:00
										 |  |  |         child.paint(context, phase); | 
					
						
							| 
									
										
										
										
											2019-09-25 12:40:37 +03:00
										 |  |  |     }); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-09-28 23:02:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 10:57:59 +02:00
										 |  |  | HitTestResult LayoutNode::hit_test(const Gfx::IntPoint& position) const | 
					
						
							| 
									
										
										
										
											2019-09-28 23:02:22 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-15 16:48:38 +02:00
										 |  |  |     HitTestResult result; | 
					
						
							| 
									
										
										
										
											2019-09-28 23:02:22 +02:00
										 |  |  |     for_each_child([&](auto& child) { | 
					
						
							|  |  |  |         auto child_result = child.hit_test(position); | 
					
						
							|  |  |  |         if (child_result.layout_node) | 
					
						
							|  |  |  |             result = child_result; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-09-29 11:43:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-14 16:45:45 +02:00
										 |  |  | const Frame& LayoutNode::frame() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ASSERT(document().frame()); | 
					
						
							|  |  |  |     return *document().frame(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Frame& LayoutNode::frame() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ASSERT(document().frame()); | 
					
						
							|  |  |  |     return *document().frame(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-04 19:37:52 +01:00
										 |  |  | const LayoutDocument& LayoutNode::root() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ASSERT(document().layout_node()); | 
					
						
							|  |  |  |     return *document().layout_node(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | LayoutDocument& LayoutNode::root() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ASSERT(document().layout_node()); | 
					
						
							|  |  |  |     return *document().layout_node(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-27 19:20:49 +02:00
										 |  |  | void LayoutNode::split_into_lines(LayoutBlock& container, LayoutMode layout_mode) | 
					
						
							| 
									
										
										
										
											2019-10-05 23:20:35 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     for_each_child([&](auto& child) { | 
					
						
							| 
									
										
										
										
											2020-06-15 17:38:44 +02:00
										 |  |  |         child.split_into_lines(container, layout_mode); | 
					
						
							| 
									
										
										
										
											2019-10-05 23:20:35 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-10-09 21:25:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | void LayoutNode::set_needs_display() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-20 09:14:12 +02:00
										 |  |  |     if (auto* block = containing_block()) { | 
					
						
							|  |  |  |         block->for_each_fragment([&](auto& fragment) { | 
					
						
							|  |  |  |             if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) { | 
					
						
							| 
									
										
										
										
											2020-06-14 16:45:45 +02:00
										 |  |  |                 frame().set_needs_display(enclosing_int_rect(fragment.absolute_rect())); | 
					
						
							| 
									
										
										
										
											2019-10-20 09:14:12 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |             return IterationDecision::Continue; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-07 17:55:46 +02:00
										 |  |  | float LayoutNode::font_size() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // FIXME: This doesn't work right for relative font-sizes
 | 
					
						
							| 
									
										
										
										
											2020-06-24 13:51:14 +02:00
										 |  |  |     auto length = specified_style().length_or_fallback(CSS::PropertyID::FontSize, Length(10, Length::Type::Px)); | 
					
						
							| 
									
										
										
										
											2020-06-07 17:55:46 +02:00
										 |  |  |     return length.raw_value(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-06 14:35:54 +01:00
										 |  |  | Gfx::FloatPoint LayoutNode::box_type_agnostic_position() const | 
					
						
							| 
									
										
										
										
											2019-10-20 09:14:12 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (is_box()) | 
					
						
							| 
									
										
										
										
											2020-06-10 10:42:29 +02:00
										 |  |  |         return to<LayoutBox>(*this).absolute_position(); | 
					
						
							| 
									
										
										
										
											2019-10-20 09:14:12 +02:00
										 |  |  |     ASSERT(is_inline()); | 
					
						
							| 
									
										
										
										
											2020-02-06 14:35:54 +01:00
										 |  |  |     Gfx::FloatPoint position; | 
					
						
							| 
									
										
										
										
											2019-10-20 09:14:12 +02:00
										 |  |  |     if (auto* block = containing_block()) { | 
					
						
							|  |  |  |         block->for_each_fragment([&](auto& fragment) { | 
					
						
							|  |  |  |             if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) { | 
					
						
							| 
									
										
										
										
											2020-06-10 10:42:29 +02:00
										 |  |  |                 position = fragment.absolute_rect().location(); | 
					
						
							| 
									
										
										
										
											2019-10-20 09:14:12 +02:00
										 |  |  |                 return IterationDecision::Break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return IterationDecision::Continue; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return position; | 
					
						
							| 
									
										
										
										
											2019-10-09 21:25:29 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-03-07 10:27:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-05 16:54:28 +02:00
										 |  |  | bool LayoutNode::is_absolutely_positioned() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-15 12:57:43 +02:00
										 |  |  |     if (!has_style()) | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2020-06-24 14:34:40 +02:00
										 |  |  |     auto position = style().position(); | 
					
						
							| 
									
										
										
										
											2020-06-12 14:19:03 +02:00
										 |  |  |     return position == CSS::Position::Absolute || position == CSS::Position::Fixed; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool LayoutNode::is_fixed_position() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-15 12:57:43 +02:00
										 |  |  |     if (!has_style()) | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2020-06-24 14:34:40 +02:00
										 |  |  |     auto position = style().position(); | 
					
						
							| 
									
										
										
										
											2020-06-23 23:15:23 +02:00
										 |  |  |     return position == CSS::Position::Fixed; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 19:41:12 +02:00
										 |  |  | LayoutNodeWithStyle::LayoutNodeWithStyle(Document& document, const Node* node, NonnullRefPtr<StyleProperties> specified_style) | 
					
						
							|  |  |  |     : LayoutNode(document, node) | 
					
						
							|  |  |  |     , m_specified_style(move(specified_style)) | 
					
						
							| 
									
										
										
										
											2020-06-23 23:15:23 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     m_has_style = true; | 
					
						
							| 
									
										
										
										
											2020-06-24 19:41:12 +02:00
										 |  |  |     apply_style(*m_specified_style); | 
					
						
							| 
									
										
										
										
											2020-06-24 14:17:05 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void LayoutNodeWithStyle::apply_style(const StyleProperties& specified_style) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto& style = static_cast<MutableLayoutStyle&>(m_style); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 14:34:40 +02:00
										 |  |  |     style.set_position(specified_style.position()); | 
					
						
							|  |  |  |     style.set_text_align(specified_style.text_align()); | 
					
						
							| 
									
										
										
										
											2020-06-24 16:37:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     auto white_space = specified_style.white_space(); | 
					
						
							|  |  |  |     if (white_space.has_value()) | 
					
						
							|  |  |  |         style.set_white_space(white_space.value()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 14:17:05 +02:00
										 |  |  |     style.set_z_index(specified_style.z_index()); | 
					
						
							| 
									
										
										
										
											2020-06-24 15:38:21 +02:00
										 |  |  |     style.set_width(specified_style.length_or_fallback(CSS::PropertyID::Width, {})); | 
					
						
							| 
									
										
										
										
											2020-06-24 16:03:25 +02:00
										 |  |  |     style.set_min_width(specified_style.length_or_fallback(CSS::PropertyID::MinWidth, {})); | 
					
						
							|  |  |  |     style.set_max_width(specified_style.length_or_fallback(CSS::PropertyID::MaxWidth, {})); | 
					
						
							| 
									
										
										
										
											2020-06-24 16:11:15 +02:00
										 |  |  |     style.set_height(specified_style.length_or_fallback(CSS::PropertyID::Height, {})); | 
					
						
							|  |  |  |     style.set_min_height(specified_style.length_or_fallback(CSS::PropertyID::MinHeight, {})); | 
					
						
							|  |  |  |     style.set_max_height(specified_style.length_or_fallback(CSS::PropertyID::MaxHeight, {})); | 
					
						
							| 
									
										
										
										
											2020-06-24 17:45:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     style.set_offset(specified_style.length_box(CSS::PropertyID::Left, CSS::PropertyID::Top, CSS::PropertyID::Right, CSS::PropertyID::Bottom)); | 
					
						
							|  |  |  |     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)); | 
					
						
							| 
									
										
										
										
											2020-06-24 19:41:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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); | 
					
						
							| 
									
										
										
										
											2020-06-05 16:54:28 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 10:27:02 +01:00
										 |  |  | } |