summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc
blob: 62d1617857a804f10f1229db1709a55447b39599 (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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
 * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.h"

#include <memory>

namespace blink {

LayoutSVGResourceGradient::LayoutSVGResourceGradient(SVGGradientElement* node)
    : LayoutSVGResourcePaintServer(node),
      should_collect_gradient_attributes_(true),
      gradient_map_(MakeGarbageCollected<GradientMap>()) {}

void LayoutSVGResourceGradient::RemoveAllClientsFromCache(
    bool mark_for_invalidation) {
  gradient_map_->clear();
  should_collect_gradient_attributes_ = true;
  To<SVGGradientElement>(*GetElement()).InvalidateDependentGradients();
  MarkAllClientsForInvalidation(
      mark_for_invalidation ? SVGResourceClient::kPaintInvalidation
                            : SVGResourceClient::kParentOnlyInvalidation);
}

bool LayoutSVGResourceGradient::RemoveClientFromCache(
    SVGResourceClient& client) {
  auto entry = gradient_map_->find(&client);
  if (entry == gradient_map_->end())
    return false;
  gradient_map_->erase(entry);
  return true;
}

SVGPaintServer LayoutSVGResourceGradient::PreparePaintServer(
    const SVGResourceClient& client,
    const FloatRect& object_bounding_box) {
  ClearInvalidationMask();

  // Validate gradient DOM state before building the actual
  // gradient. This should avoid tearing down the gradient we're
  // currently working on. Preferably the state validation should have
  // no side-effects though.
  if (should_collect_gradient_attributes_) {
    if (!CollectGradientAttributes())
      return SVGPaintServer::Invalid();
    should_collect_gradient_attributes_ = false;
  }

  // Spec: When the geometry of the applicable element has no width or height
  // and objectBoundingBox is specified, then the given effect (e.g. a gradient
  // or a filter) will be ignored.
  if (GradientUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox &&
      object_bounding_box.IsEmpty())
    return SVGPaintServer::Invalid();

  std::unique_ptr<GradientData>& gradient_data =
      gradient_map_->insert(&client, nullptr).stored_value->value;
  if (!gradient_data)
    gradient_data = std::make_unique<GradientData>();

  // Create gradient object
  if (!gradient_data->gradient) {
    gradient_data->gradient = BuildGradient();

    // We want the text bounding box applied to the gradient space transform
    // now, so the gradient shader can use it.
    if (GradientUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox &&
        !object_bounding_box.IsEmpty()) {
      gradient_data->userspace_transform.Translate(object_bounding_box.X(),
                                                   object_bounding_box.Y());
      gradient_data->userspace_transform.ScaleNonUniform(
          object_bounding_box.Width(), object_bounding_box.Height());
    }

    AffineTransform gradient_transform = CalculateGradientTransform();
    gradient_data->userspace_transform *= gradient_transform;
  }

  if (!gradient_data->gradient)
    return SVGPaintServer::Invalid();

  return SVGPaintServer(gradient_data->gradient,
                        gradient_data->userspace_transform);
}

bool LayoutSVGResourceGradient::IsChildAllowed(LayoutObject* child,
                                               const ComputedStyle&) const {
  if (!child->IsSVGResourceContainer())
    return false;

  return ToLayoutSVGResourceContainer(child)->IsSVGPaintServer();
}

GradientSpreadMethod LayoutSVGResourceGradient::PlatformSpreadMethodFromSVGType(
    SVGSpreadMethodType method) {
  switch (method) {
    case kSVGSpreadMethodUnknown:
    case kSVGSpreadMethodPad:
      return kSpreadMethodPad;
    case kSVGSpreadMethodReflect:
      return kSpreadMethodReflect;
    case kSVGSpreadMethodRepeat:
      return kSpreadMethodRepeat;
  }

  NOTREACHED();
  return kSpreadMethodPad;
}

}  // namespace blink