summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/paint/svg_container_painter.cc
blob: 77847cb1415df263c8168cf863ce4ca52dacf422 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/core/paint/svg_container_painter.h"

#include "base/optional.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_container.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/paint/object_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/scoped_svg_paint_state.h"
#include "third_party/blink/renderer/core/paint/svg_foreign_object_painter.h"
#include "third_party/blink/renderer/core/paint/svg_model_object_painter.h"
#include "third_party/blink/renderer/core/svg/svg_svg_element.h"

namespace blink {

void SVGContainerPainter::Paint(const PaintInfo& paint_info) {
  // Spec: groups w/o children still may render filter content.
  if (!layout_svg_container_.FirstChild() &&
      !layout_svg_container_.SelfWillPaint())
    return;

  // Spec: An empty viewBox on the <svg> element disables rendering.
  DCHECK(layout_svg_container_.GetElement());
  auto* svg_svg_element =
      DynamicTo<SVGSVGElement>(*layout_svg_container_.GetElement());
  if (svg_svg_element && svg_svg_element->HasEmptyViewBox())
    return;

  PaintInfo paint_info_before_filtering(paint_info);

  if (SVGModelObjectPainter(layout_svg_container_)
          .CullRectSkipsPainting(paint_info_before_filtering)) {
    return;
  }

  // We do not apply cull rect optimizations across transforms for two reasons:
  //   1) Performance: We can optimize transform changes by not repainting.
  //   2) Complexity: Difficulty updating clips when ancestor transforms change.
  // This is why we use an infinite cull rect if there is a transform. Non-svg
  // content, does this in PaintLayerPainter::PaintSingleFragment.
  if (layout_svg_container_.StyleRef().HasTransform()) {
    paint_info_before_filtering.ApplyInfiniteCullRect();
  } else if (const auto* properties =
                 layout_svg_container_.FirstFragment().PaintProperties()) {
    if (const auto* transform = properties->Transform())
      paint_info_before_filtering.TransformCullRect(*transform);
  }

  ScopedSVGTransformState transform_state(
      paint_info_before_filtering, layout_svg_container_,
      layout_svg_container_.LocalToSVGParentTransform());
  {
    base::Optional<ScopedPaintChunkProperties> scoped_paint_chunk_properties;
    if (layout_svg_container_.IsSVGViewportContainer() &&
        SVGLayoutSupport::IsOverflowHidden(layout_svg_container_)) {
      const auto* fragment = paint_info.FragmentToPaint(layout_svg_container_);
      if (!fragment)
        return;
      const auto* properties = fragment->PaintProperties();
      // TODO(crbug.com/814815): The condition should be a DCHECK, but for now
      // we may paint the object for filters during PrePaint before the
      // properties are ready.
      if (properties && properties->OverflowClip()) {
        scoped_paint_chunk_properties.emplace(
            paint_info.context.GetPaintController(),
            *properties->OverflowClip(), layout_svg_container_,
            paint_info.DisplayItemTypeForClipping());
      }
    }

    ScopedSVGPaintState paint_state(layout_svg_container_,
                                    paint_info_before_filtering);
    bool continue_rendering = true;
    if (paint_state.GetPaintInfo().phase == PaintPhase::kForeground)
      continue_rendering = paint_state.ApplyClipMaskAndFilterIfNecessary();

    if (continue_rendering) {
      for (LayoutObject* child = layout_svg_container_.FirstChild(); child;
           child = child->NextSibling()) {
        if (child->IsSVGForeignObject()) {
          SVGForeignObjectPainter(ToLayoutSVGForeignObject(*child))
              .PaintLayer(paint_state.GetPaintInfo());
        } else {
          child->Paint(paint_state.GetPaintInfo());
        }
      }
    }
  }

  SVGModelObjectPainter(layout_svg_container_)
      .PaintOutline(paint_info_before_filtering);

  if (paint_info_before_filtering.ShouldAddUrlMetadata() &&
      paint_info_before_filtering.phase == PaintPhase::kForeground) {
    ObjectPainter(layout_svg_container_)
        .AddURLRectIfNeeded(paint_info_before_filtering, PhysicalOffset());
  }
}

}  // namespace blink