SVGGraphicsPaintable.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /*
  2. * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibWeb/Layout/ImageBox.h>
  7. #include <LibWeb/Painting/CommandExecutorCPU.h>
  8. #include <LibWeb/Painting/SVGGraphicsPaintable.h>
  9. #include <LibWeb/Painting/StackingContext.h>
  10. #include <LibWeb/SVG/SVGMaskElement.h>
  11. #include <LibWeb/SVG/SVGSVGElement.h>
  12. namespace Web::Painting {
  13. JS::NonnullGCPtr<SVGGraphicsPaintable> SVGGraphicsPaintable::create(Layout::SVGGraphicsBox const& layout_box)
  14. {
  15. return layout_box.heap().allocate_without_realm<SVGGraphicsPaintable>(layout_box);
  16. }
  17. SVGGraphicsPaintable::SVGGraphicsPaintable(Layout::SVGGraphicsBox const& layout_box)
  18. : SVGPaintable(layout_box)
  19. {
  20. }
  21. bool SVGGraphicsPaintable::forms_unconnected_subtree() const
  22. {
  23. // Masks should not be painted (i.e. reachable) unless referenced by another element.
  24. return is<SVG::SVGMaskElement>(dom_node());
  25. }
  26. Layout::SVGGraphicsBox const& SVGGraphicsPaintable::layout_box() const
  27. {
  28. return static_cast<Layout::SVGGraphicsBox const&>(layout_node());
  29. }
  30. Optional<CSSPixelRect> SVGGraphicsPaintable::get_masking_area() const
  31. {
  32. auto const& graphics_element = verify_cast<SVG::SVGGraphicsElement const>(*dom_node());
  33. auto mask = graphics_element.mask();
  34. if (!mask)
  35. return {};
  36. auto target_area = [&] {
  37. auto mask_units = mask->mask_units();
  38. if (mask_units == SVG::MaskUnits::UserSpaceOnUse) {
  39. auto const* svg_element = graphics_element.shadow_including_first_ancestor_of_type<SVG::SVGSVGElement>();
  40. return svg_element->paintable_box()->absolute_border_box_rect();
  41. } else {
  42. VERIFY(mask_units == SVG::MaskUnits::ObjectBoundingBox);
  43. return absolute_border_box_rect();
  44. }
  45. }();
  46. return mask->resolve_masking_area(target_area);
  47. }
  48. static Gfx::Bitmap::MaskKind mask_type_to_gfx_mask_kind(CSS::MaskType mask_type)
  49. {
  50. switch (mask_type) {
  51. case CSS::MaskType::Alpha:
  52. return Gfx::Bitmap::MaskKind::Alpha;
  53. case CSS::MaskType::Luminance:
  54. return Gfx::Bitmap::MaskKind::Luminance;
  55. default:
  56. VERIFY_NOT_REACHED();
  57. }
  58. }
  59. Optional<Gfx::Bitmap::MaskKind> SVGGraphicsPaintable::get_mask_type() const
  60. {
  61. auto const& graphics_element = verify_cast<SVG::SVGGraphicsElement const>(*dom_node());
  62. auto mask = graphics_element.mask();
  63. if (!mask)
  64. return {};
  65. return mask_type_to_gfx_mask_kind(mask->layout_node()->computed_values().mask_type());
  66. }
  67. RefPtr<Gfx::Bitmap> SVGGraphicsPaintable::calculate_mask(PaintContext& context, CSSPixelRect const& masking_area) const
  68. {
  69. auto const& graphics_element = verify_cast<SVG::SVGGraphicsElement const>(*dom_node());
  70. auto mask = graphics_element.mask();
  71. VERIFY(mask);
  72. if (mask->mask_content_units() != SVG::MaskContentUnits::UserSpaceOnUse) {
  73. dbgln("SVG: maskContentUnits=objectBoundingBox is not supported");
  74. return {};
  75. }
  76. auto mask_rect = context.enclosing_device_rect(masking_area);
  77. RefPtr<Gfx::Bitmap> mask_bitmap = {};
  78. if (mask && mask->layout_node() && is<PaintableBox>(mask->layout_node()->paintable())) {
  79. auto& mask_paintable = static_cast<PaintableBox const&>(*mask->layout_node()->paintable());
  80. auto mask_bitmap_or_error = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, mask_rect.size().to_type<int>());
  81. if (mask_bitmap_or_error.is_error())
  82. return {};
  83. mask_bitmap = mask_bitmap_or_error.release_value();
  84. {
  85. CommandList painting_commands;
  86. RecordingPainter recording_painter(painting_commands);
  87. recording_painter.translate(-mask_rect.location().to_type<int>());
  88. auto paint_context = context.clone(recording_painter);
  89. paint_context.set_svg_transform(graphics_element.get_transform());
  90. StackingContext::paint_node_as_stacking_context(mask_paintable, paint_context);
  91. CommandExecutorCPU executor { *mask_bitmap };
  92. painting_commands.execute(executor);
  93. }
  94. }
  95. return mask_bitmap;
  96. }
  97. }