LayoutBox.cpp 4.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #include <LibGUI/GPainter.h>
  2. #include <LibHTML/DOM/Document.h>
  3. #include <LibHTML/Frame.h>
  4. #include <LibHTML/Layout/LayoutBlock.h>
  5. #include <LibHTML/Layout/LayoutBox.h>
  6. //#define DRAW_BOXES_AROUND_LAYOUT_NODES
  7. //#define DRAW_BOXES_AROUND_HOVERED_NODES
  8. void LayoutBox::render(RenderingContext& context)
  9. {
  10. if (!is_visible())
  11. return;
  12. #ifdef DRAW_BOXES_AROUND_LAYOUT_NODES
  13. context.painter().draw_rect(m_rect, Color::Blue);
  14. #endif
  15. #ifdef DRAW_BOXES_AROUND_HOVERED_NODES
  16. if (!is_anonymous() && node() == document().hovered_node())
  17. context.painter().draw_rect(m_rect, Color::Red);
  18. #endif
  19. Rect padded_rect;
  20. padded_rect.set_x(x() - box_model().padding().left.to_px());
  21. padded_rect.set_width(width() + box_model().padding().left.to_px() + box_model().padding().right.to_px());
  22. padded_rect.set_y(y() - box_model().padding().top.to_px());
  23. padded_rect.set_height(height() + box_model().padding().top.to_px() + box_model().padding().bottom.to_px());
  24. auto bgcolor = style().property(CSS::PropertyID::BackgroundColor);
  25. if (bgcolor.has_value() && bgcolor.value()->is_color()) {
  26. context.painter().fill_rect(padded_rect, bgcolor.value()->to_color(document()));
  27. }
  28. // FIXME: Respect all individual border sides
  29. auto border_width_value = style().property(CSS::PropertyID::BorderTopWidth);
  30. auto border_color_value = style().property(CSS::PropertyID::BorderTopColor);
  31. auto border_style_value = style().property(CSS::PropertyID::BorderTopStyle);
  32. if (border_width_value.has_value() && border_color_value.has_value()) {
  33. int border_width = border_width_value.value()->to_length().to_px();
  34. Color border_color = border_color_value.value()->to_color(document());
  35. if (border_style_value.has_value() && border_style_value.value()->to_string() == "inset") {
  36. // border-style: inset
  37. auto shadow_color = Color::from_rgb(0x888888);
  38. auto highlight_color = Color::from_rgb(0x5a5a5a);
  39. context.painter().draw_line(padded_rect.top_left(), padded_rect.top_right(), highlight_color, border_width);
  40. context.painter().draw_line(padded_rect.top_right(), padded_rect.bottom_right(), shadow_color, border_width);
  41. context.painter().draw_line(padded_rect.bottom_right(), padded_rect.bottom_left(), shadow_color, border_width);
  42. context.painter().draw_line(padded_rect.bottom_left(), padded_rect.top_left(), highlight_color, border_width);
  43. } else if (border_style_value.has_value() && border_style_value.value()->to_string() == "outset") {
  44. // border-style: outset
  45. auto highlight_color = Color::from_rgb(0x888888);
  46. auto shadow_color = Color::from_rgb(0x5a5a5a);
  47. context.painter().draw_line(padded_rect.top_left(), padded_rect.top_right(), highlight_color, border_width);
  48. context.painter().draw_line(padded_rect.top_right(), padded_rect.bottom_right(), shadow_color, border_width);
  49. context.painter().draw_line(padded_rect.bottom_right(), padded_rect.bottom_left(), shadow_color, border_width);
  50. context.painter().draw_line(padded_rect.bottom_left(), padded_rect.top_left(), highlight_color, border_width);
  51. } else {
  52. // border-style: solid
  53. context.painter().draw_line(padded_rect.top_left(), padded_rect.top_right(), border_color, border_width);
  54. context.painter().draw_line(padded_rect.top_right(), padded_rect.bottom_right(), border_color, border_width);
  55. context.painter().draw_line(padded_rect.bottom_right(), padded_rect.bottom_left(), border_color, border_width);
  56. context.painter().draw_line(padded_rect.bottom_left(), padded_rect.top_left(), border_color, border_width);
  57. }
  58. }
  59. LayoutNodeWithStyleAndBoxModelMetrics::render(context);
  60. }
  61. HitTestResult LayoutBox::hit_test(const Point& position) const
  62. {
  63. // FIXME: It would be nice if we could confidently skip over hit testing
  64. // parts of the layout tree, but currently we can't just check
  65. // m_rect.contains() since inline text rects can't be trusted..
  66. HitTestResult result { m_rect.contains(position) ? this : nullptr };
  67. for_each_child([&](auto& child) {
  68. auto child_result = child.hit_test(position);
  69. if (child_result.layout_node)
  70. result = child_result;
  71. });
  72. return result;
  73. }
  74. void LayoutBox::set_needs_display()
  75. {
  76. auto* frame = document().frame();
  77. ASSERT(frame);
  78. if (!is_inline()) {
  79. const_cast<Frame*>(frame)->set_needs_display(rect());
  80. return;
  81. }
  82. LayoutNode::set_needs_display();
  83. }