HtmlView.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #include <LibGUI/GApplication.h>
  2. #include <LibGUI/GPainter.h>
  3. #include <LibGUI/GScrollBar.h>
  4. #include <LibHTML/DOM/Element.h>
  5. #include <LibHTML/DOM/HTMLAnchorElement.h>
  6. #include <LibHTML/Dump.h>
  7. #include <LibHTML/Frame.h>
  8. #include <LibHTML/HtmlView.h>
  9. #include <LibHTML/Layout/LayoutNode.h>
  10. #include <LibHTML/RenderingContext.h>
  11. #include <stdio.h>
  12. HtmlView::HtmlView(GWidget* parent)
  13. : GScrollableWidget(parent)
  14. , m_main_frame(Frame::create())
  15. {
  16. set_frame_shape(FrameShape::Container);
  17. set_frame_shadow(FrameShadow::Sunken);
  18. set_frame_thickness(2);
  19. set_should_hide_unnecessary_scrollbars(true);
  20. set_background_color(Color::White);
  21. }
  22. HtmlView::~HtmlView()
  23. {
  24. }
  25. void HtmlView::set_document(Document* document)
  26. {
  27. if (document == m_document)
  28. return;
  29. m_document = document;
  30. main_frame().set_document(document);
  31. if (document == nullptr)
  32. m_layout_root = nullptr;
  33. else
  34. m_layout_root = document->create_layout_tree(document->style_resolver(), nullptr);
  35. #ifdef HTML_DEBUG
  36. if (document != nullptr) {
  37. dbgprintf("\033[33;1mLayout tree before layout:\033[0m\n");
  38. ::dump_tree(*m_layout_root);
  39. }
  40. #endif
  41. layout_and_sync_size();
  42. update();
  43. }
  44. void HtmlView::layout_and_sync_size()
  45. {
  46. if (!m_layout_root)
  47. return;
  48. main_frame().set_size(available_size());
  49. m_layout_root->layout();
  50. set_content_size(m_layout_root->rect().size());
  51. #ifdef HTML_DEBUG
  52. dbgprintf("\033[33;1mLayout tree after layout:\033[0m\n");
  53. ::dump_tree(*m_layout_root);
  54. #endif
  55. }
  56. void HtmlView::resize_event(GResizeEvent& event)
  57. {
  58. GScrollableWidget::resize_event(event);
  59. layout_and_sync_size();
  60. }
  61. void HtmlView::paint_event(GPaintEvent& event)
  62. {
  63. GFrame::paint_event(event);
  64. GPainter painter(*this);
  65. painter.add_clip_rect(widget_inner_rect());
  66. painter.add_clip_rect(event.rect());
  67. if (!m_layout_root) {
  68. painter.fill_rect(event.rect(), background_color());
  69. return;
  70. }
  71. painter.translate(frame_thickness(), frame_thickness());
  72. painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value());
  73. painter.fill_rect(rect(), m_document->background_color());
  74. RenderingContext context { painter };
  75. m_layout_root->render(context);
  76. }
  77. void HtmlView::mousemove_event(GMouseEvent& event)
  78. {
  79. if (!m_layout_root)
  80. return GScrollableWidget::mousemove_event(event);
  81. bool hovered_node_changed = false;
  82. auto result = m_layout_root->hit_test(to_content_position(event.position()));
  83. if (result.layout_node) {
  84. auto* node = result.layout_node->node();
  85. hovered_node_changed = node != m_document->hovered_node();
  86. m_document->set_hovered_node(const_cast<Node*>(node));
  87. #ifdef HTML_DEBUG
  88. if (node) {
  89. if (auto* link = node->enclosing_link_element()) {
  90. dbg() << "HtmlView: hovering over a link to " << link->href();
  91. }
  92. }
  93. #endif
  94. }
  95. if (hovered_node_changed) {
  96. update();
  97. auto* hovered_html_element = m_document->hovered_node() ? m_document->hovered_node()->enclosing_html_element() : nullptr;
  98. if (hovered_html_element && !hovered_html_element->title().is_null()) {
  99. auto screen_position = screen_relative_rect().location().translated(event.position());
  100. GApplication::the().show_tooltip(hovered_html_element->title(), screen_position.translated(4, 4));
  101. } else {
  102. GApplication::the().hide_tooltip();
  103. }
  104. }
  105. event.accept();
  106. }
  107. void HtmlView::mousedown_event(GMouseEvent& event)
  108. {
  109. if (!m_layout_root)
  110. return GScrollableWidget::mousemove_event(event);
  111. bool hovered_node_changed = false;
  112. auto result = m_layout_root->hit_test(to_content_position(event.position()));
  113. if (result.layout_node) {
  114. auto* node = result.layout_node->node();
  115. hovered_node_changed = node != m_document->hovered_node();
  116. m_document->set_hovered_node(const_cast<Node*>(node));
  117. if (node) {
  118. if (auto* link = node->enclosing_link_element()) {
  119. dbg() << "HtmlView: clicking on a link to " << link->href();
  120. if (on_link_click)
  121. on_link_click(link->href());
  122. }
  123. }
  124. }
  125. if (hovered_node_changed)
  126. update();
  127. event.accept();
  128. }