1 /*
2 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h"
21
22 #include "third_party/blink/renderer/core/dom/element_traversal.h"
23 #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
24 #include "third_party/blink/renderer/core/paint/svg_object_painter.h"
25 #include "third_party/blink/renderer/core/svg/svg_element.h"
26 #include "third_party/blink/renderer/core/svg/svg_mask_element.h"
27 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
28 #include "third_party/blink/renderer/platform/graphics/paint/paint_record.h"
29 #include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
30 #include "third_party/blink/renderer/platform/transforms/affine_transform.h"
31
32 namespace blink {
33
LayoutSVGResourceMasker(SVGMaskElement * node)34 LayoutSVGResourceMasker::LayoutSVGResourceMasker(SVGMaskElement* node)
35 : LayoutSVGResourceContainer(node) {}
36
37 LayoutSVGResourceMasker::~LayoutSVGResourceMasker() = default;
38
RemoveAllClientsFromCache()39 void LayoutSVGResourceMasker::RemoveAllClientsFromCache() {
40 cached_paint_record_.reset();
41 mask_content_boundaries_ = FloatRect();
42 MarkAllClientsForInvalidation(SVGResourceClient::kLayoutInvalidation |
43 SVGResourceClient::kBoundariesInvalidation);
44 }
45
CreatePaintRecord(AffineTransform & content_transformation,const FloatRect & target_bounding_box,GraphicsContext & context)46 sk_sp<const PaintRecord> LayoutSVGResourceMasker::CreatePaintRecord(
47 AffineTransform& content_transformation,
48 const FloatRect& target_bounding_box,
49 GraphicsContext& context) {
50 if (MaskContentUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
51 content_transformation.Translate(target_bounding_box.X(),
52 target_bounding_box.Y());
53 content_transformation.ScaleNonUniform(target_bounding_box.Width(),
54 target_bounding_box.Height());
55 }
56
57 if (cached_paint_record_)
58 return cached_paint_record_;
59
60 SubtreeContentTransformScope content_transform_scope(content_transformation);
61 PaintRecordBuilder builder(nullptr, &context);
62
63 ColorFilter mask_content_filter =
64 StyleRef().SvgStyle().ColorInterpolation() == CI_LINEARRGB
65 ? kColorFilterSRGBToLinearRGB
66 : kColorFilterNone;
67 builder.Context().SetColorFilter(mask_content_filter);
68
69 for (const SVGElement& child_element :
70 Traversal<SVGElement>::ChildrenOf(*GetElement())) {
71 const LayoutObject* layout_object = child_element.GetLayoutObject();
72 if (!layout_object ||
73 layout_object->StyleRef().Display() == EDisplay::kNone)
74 continue;
75 SVGObjectPainter(*layout_object).PaintResourceSubtree(builder.Context());
76 }
77
78 cached_paint_record_ = builder.EndRecording();
79 return cached_paint_record_;
80 }
81
CalculateMaskContentVisualRect()82 void LayoutSVGResourceMasker::CalculateMaskContentVisualRect() {
83 for (const SVGElement& child_element :
84 Traversal<SVGElement>::ChildrenOf(*GetElement())) {
85 const LayoutObject* layout_object = child_element.GetLayoutObject();
86 if (!layout_object ||
87 layout_object->StyleRef().Display() == EDisplay::kNone)
88 continue;
89 mask_content_boundaries_.Unite(
90 layout_object->LocalToSVGParentTransform().MapRect(
91 layout_object->VisualRectInLocalSVGCoordinates()));
92 }
93 }
94
MaskUnits() const95 SVGUnitTypes::SVGUnitType LayoutSVGResourceMasker::MaskUnits() const {
96 return To<SVGMaskElement>(GetElement())
97 ->maskUnits()
98 ->CurrentValue()
99 ->EnumValue();
100 }
101
MaskContentUnits() const102 SVGUnitTypes::SVGUnitType LayoutSVGResourceMasker::MaskContentUnits() const {
103 return To<SVGMaskElement>(GetElement())
104 ->maskContentUnits()
105 ->CurrentValue()
106 ->EnumValue();
107 }
108
ResourceBoundingBox(const FloatRect & reference_box)109 FloatRect LayoutSVGResourceMasker::ResourceBoundingBox(
110 const FloatRect& reference_box) {
111 auto* mask_element = To<SVGMaskElement>(GetElement());
112 DCHECK(mask_element);
113
114 FloatRect mask_boundaries = SVGLengthContext::ResolveRectangle(
115 mask_element, MaskUnits(), reference_box);
116
117 // Resource was not layouted yet. Give back clipping rect of the mask.
118 if (SelfNeedsLayout())
119 return mask_boundaries;
120
121 if (mask_content_boundaries_.IsEmpty())
122 CalculateMaskContentVisualRect();
123
124 FloatRect mask_rect = mask_content_boundaries_;
125 if (MaskContentUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
126 AffineTransform transform;
127 transform.Translate(reference_box.X(), reference_box.Y());
128 transform.ScaleNonUniform(reference_box.Width(), reference_box.Height());
129 mask_rect = transform.MapRect(mask_rect);
130 }
131
132 mask_rect.Intersect(mask_boundaries);
133 return mask_rect;
134 }
135
136 } // namespace blink
137