Viewport.cpp 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /*
  2. * Copyright (c) 2018-2023, Andreas Kling <andreas@ladybird.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibWeb/DOM/Range.h>
  7. #include <LibWeb/Dump.h>
  8. #include <LibWeb/Layout/TextNode.h>
  9. #include <LibWeb/Layout/Viewport.h>
  10. #include <LibWeb/Painting/PaintableBox.h>
  11. #include <LibWeb/Painting/StackingContext.h>
  12. #include <LibWeb/Painting/ViewportPaintable.h>
  13. namespace Web::Layout {
  14. JS_DEFINE_ALLOCATOR(Viewport);
  15. Viewport::Viewport(DOM::Document& document, CSS::StyleProperties style)
  16. : BlockContainer(document, &document, move(style))
  17. {
  18. }
  19. Viewport::~Viewport() = default;
  20. JS::GCPtr<Painting::Paintable> Viewport::create_paintable() const
  21. {
  22. return Painting::ViewportPaintable::create(*this);
  23. }
  24. void Viewport::visit_edges(Visitor& visitor)
  25. {
  26. Base::visit_edges(visitor);
  27. if (!m_text_blocks.has_value())
  28. return;
  29. for (auto& text_block : *m_text_blocks) {
  30. for (auto& text_position : text_block.positions)
  31. visitor.visit(text_position.dom_node);
  32. }
  33. }
  34. Vector<Viewport::TextBlock> const& Viewport::text_blocks()
  35. {
  36. if (!m_text_blocks.has_value())
  37. update_text_blocks();
  38. return *m_text_blocks;
  39. }
  40. void Viewport::update_text_blocks()
  41. {
  42. StringBuilder builder;
  43. size_t current_start_position = 0;
  44. Vector<TextPosition> text_positions;
  45. Vector<TextBlock> text_blocks;
  46. for_each_in_inclusive_subtree([&](auto const& layout_node) {
  47. if (layout_node.display().is_none() || !layout_node.first_paintable() || !layout_node.first_paintable()->is_visible())
  48. return TraversalDecision::Continue;
  49. if (layout_node.is_box() || layout_node.is_generated()) {
  50. if (!builder.is_empty()) {
  51. text_blocks.append({ builder.to_string_without_validation(), text_positions });
  52. current_start_position = 0;
  53. text_positions.clear_with_capacity();
  54. builder.clear();
  55. }
  56. return TraversalDecision::Continue;
  57. }
  58. if (layout_node.is_text_node()) {
  59. auto const& text_node = verify_cast<Layout::TextNode>(layout_node);
  60. auto& dom_node = const_cast<DOM::Text&>(text_node.dom_node());
  61. if (text_positions.is_empty()) {
  62. text_positions.empend(dom_node);
  63. } else {
  64. text_positions.empend(dom_node, current_start_position);
  65. }
  66. auto const& current_node_text = text_node.text_for_rendering();
  67. current_start_position += current_node_text.bytes_as_string_view().length();
  68. builder.append(move(current_node_text));
  69. }
  70. return TraversalDecision::Continue;
  71. });
  72. if (!builder.is_empty())
  73. text_blocks.append({ builder.to_string_without_validation(), text_positions });
  74. m_text_blocks = move(text_blocks);
  75. }
  76. }