OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/paint/SVGFilterPainter.h" | 5 #include "core/paint/SVGFilterPainter.h" |
6 | 6 |
7 #include "core/layout/svg/LayoutSVGResourceFilter.h" | 7 #include "core/layout/svg/LayoutSVGResourceFilter.h" |
8 #include "core/paint/FilterEffectBuilder.h" | 8 #include "core/paint/FilterEffectBuilder.h" |
9 #include "core/paint/LayoutObjectDrawingRecorder.h" | 9 #include "core/paint/LayoutObjectDrawingRecorder.h" |
10 #include "core/svg/SVGFilterElement.h" | 10 #include "core/svg/SVGFilterElement.h" |
11 #include "core/svg/graphics/filters/SVGFilterBuilder.h" | 11 #include "core/svg/graphics/filters/SVGFilterBuilder.h" |
12 #include "platform/graphics/filters/Filter.h" | 12 #include "platform/graphics/filters/Filter.h" |
13 #include "platform/graphics/filters/SkiaImageFilterBuilder.h" | 13 #include "platform/graphics/filters/SkiaImageFilterBuilder.h" |
14 #include "platform/graphics/filters/SourceGraphic.h" | 14 #include "platform/graphics/filters/SourceGraphic.h" |
15 #include "platform/wtf/PtrUtil.h" | 15 #include "platform/wtf/PtrUtil.h" |
16 | 16 |
17 namespace blink { | 17 namespace blink { |
18 | 18 |
19 GraphicsContext* SVGFilterRecordingContext::BeginContent( | 19 GraphicsContext* SVGFilterRecordingContext::BeginContent() { |
20 FilterData* filter_data) { | |
21 DCHECK_EQ(filter_data->state_, FilterData::kInitial); | |
22 | |
23 // Create a new context so the contents of the filter can be drawn and cached. | 20 // Create a new context so the contents of the filter can be drawn and cached. |
24 paint_controller_ = PaintController::Create(); | 21 paint_controller_ = PaintController::Create(); |
25 context_ = WTF::WrapUnique(new GraphicsContext(*paint_controller_)); | 22 context_ = WTF::WrapUnique(new GraphicsContext(*paint_controller_)); |
26 | 23 |
27 // Content painted into a new PaintRecord in SPv2 will have an | 24 // Content painted into a new PaintRecord in SPv2 will have an |
28 // independent property tree set. | 25 // independent property tree set. |
29 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { | 26 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
30 paint_controller_->UpdateCurrentPaintChunkProperties( | 27 paint_controller_->UpdateCurrentPaintChunkProperties( |
31 nullptr, PropertyTreeState::Root()); | 28 nullptr, PropertyTreeState::Root()); |
32 } | 29 } |
33 | |
34 filter_data->state_ = FilterData::kRecordingContent; | |
35 return context_.get(); | 30 return context_.get(); |
36 } | 31 } |
37 | 32 |
38 void SVGFilterRecordingContext::EndContent(FilterData* filter_data) { | 33 sk_sp<PaintRecord> SVGFilterRecordingContext::EndContent( |
39 DCHECK_EQ(filter_data->state_, FilterData::kRecordingContent); | 34 const FloatRect& bounds) { |
40 | |
41 Filter* filter = filter_data->last_effect->GetFilter(); | |
42 SourceGraphic* source_graphic = filter->GetSourceGraphic(); | |
43 DCHECK(source_graphic); | |
44 | |
45 // Use the context that contains the filtered content. | 35 // Use the context that contains the filtered content. |
46 DCHECK(paint_controller_); | 36 DCHECK(paint_controller_); |
47 DCHECK(context_); | 37 DCHECK(context_); |
48 context_->BeginRecording(filter->FilterRegion()); | 38 context_->BeginRecording(bounds); |
49 paint_controller_->CommitNewDisplayItems(); | 39 paint_controller_->CommitNewDisplayItems(); |
50 | 40 |
51 paint_controller_->GetPaintArtifact().Replay(filter->FilterRegion(), | 41 paint_controller_->GetPaintArtifact().Replay(bounds, *context_); |
52 *context_); | |
53 | 42 |
54 SkiaImageFilterBuilder::BuildSourceGraphic(source_graphic, | 43 sk_sp<PaintRecord> content = context_->EndRecording(); |
55 context_->EndRecording()); | |
56 | |
57 // Content is cached by the source graphic so temporaries can be freed. | 44 // Content is cached by the source graphic so temporaries can be freed. |
58 paint_controller_ = nullptr; | 45 paint_controller_ = nullptr; |
59 context_ = nullptr; | 46 context_ = nullptr; |
60 | 47 return content; |
61 filter_data->state_ = FilterData::kReadyToPaint; | |
62 } | 48 } |
63 | 49 |
64 static void PaintFilteredContent(GraphicsContext& context, | 50 static void PaintFilteredContent(GraphicsContext& context, |
65 const LayoutObject& object, | 51 const LayoutObject& object, |
66 FilterData* filter_data) { | 52 const FloatRect& bounds, |
53 FilterEffect* effect) { | |
67 if (LayoutObjectDrawingRecorder::UseCachedDrawingIfPossible( | 54 if (LayoutObjectDrawingRecorder::UseCachedDrawingIfPossible( |
68 context, object, DisplayItem::kSVGFilter)) | 55 context, object, DisplayItem::kSVGFilter)) |
69 return; | 56 return; |
70 | 57 |
71 FloatRect filter_bounds = | |
72 filter_data ? filter_data->last_effect->GetFilter()->FilterRegion() | |
73 : FloatRect(); | |
74 LayoutObjectDrawingRecorder recorder(context, object, DisplayItem::kSVGFilter, | 58 LayoutObjectDrawingRecorder recorder(context, object, DisplayItem::kSVGFilter, |
75 filter_bounds); | 59 bounds); |
76 if (!filter_data || filter_data->state_ != FilterData::kReadyToPaint) | |
77 return; | |
78 DCHECK(filter_data->last_effect->GetFilter()->GetSourceGraphic()); | |
79 | |
80 filter_data->state_ = FilterData::kPaintingFilter; | |
81 | |
82 FilterEffect* last_effect = filter_data->last_effect; | |
83 sk_sp<SkImageFilter> image_filter = | 60 sk_sp<SkImageFilter> image_filter = |
84 SkiaImageFilterBuilder::Build(last_effect, kColorSpaceDeviceRGB); | 61 SkiaImageFilterBuilder::Build(effect, kColorSpaceDeviceRGB); |
85 context.Save(); | 62 context.Save(); |
86 | 63 |
87 // Clip drawing of filtered image to the minimum required paint rect. | 64 // Clip drawing of filtered image to the minimum required paint rect. |
88 context.ClipRect(last_effect->MapRect(object.StrokeBoundingBox())); | 65 context.ClipRect(effect->MapRect(object.StrokeBoundingBox())); |
89 | 66 |
90 context.BeginLayer(1, SkBlendMode::kSrcOver, &filter_bounds, kColorFilterNone, | 67 context.BeginLayer(1, SkBlendMode::kSrcOver, &bounds, kColorFilterNone, |
91 std::move(image_filter)); | 68 std::move(image_filter)); |
92 context.EndLayer(); | 69 context.EndLayer(); |
93 context.Restore(); | 70 context.Restore(); |
94 | |
95 filter_data->state_ = FilterData::kReadyToPaint; | |
96 } | 71 } |
97 | 72 |
98 GraphicsContext* SVGFilterPainter::PrepareEffect( | 73 GraphicsContext* SVGFilterPainter::PrepareEffect( |
99 const LayoutObject& object, | 74 const LayoutObject& object, |
100 SVGFilterRecordingContext& recording_context) { | 75 SVGFilterRecordingContext& recording_context) { |
101 filter_.ClearInvalidationMask(); | 76 filter_.ClearInvalidationMask(); |
102 | 77 |
103 if (FilterData* filter_data = filter_.GetFilterDataForLayoutObject(&object)) { | 78 if (FilterData* filter_data = filter_.GetFilterDataForLayoutObject(&object)) { |
104 // If the filterData already exists we do not need to record the content | 79 // If the filterData already exists we do not need to record the content |
105 // to be filtered. This can occur if the content was previously recorded | 80 // to be filtered. This can occur if the content was previously recorded |
(...skipping 14 matching lines...) Expand all Loading... | |
120 if (!filter || !filter->LastEffect()) | 95 if (!filter || !filter->LastEffect()) |
121 return nullptr; | 96 return nullptr; |
122 | 97 |
123 IntRect source_region = EnclosingIntRect( | 98 IntRect source_region = EnclosingIntRect( |
124 Intersection(filter->FilterRegion(), object.StrokeBoundingBox())); | 99 Intersection(filter->FilterRegion(), object.StrokeBoundingBox())); |
125 filter->GetSourceGraphic()->SetSourceRect(source_region); | 100 filter->GetSourceGraphic()->SetSourceRect(source_region); |
126 | 101 |
127 FilterData* filter_data = FilterData::Create(); | 102 FilterData* filter_data = FilterData::Create(); |
128 filter_data->last_effect = filter->LastEffect(); | 103 filter_data->last_effect = filter->LastEffect(); |
129 filter_data->node_map = node_map; | 104 filter_data->node_map = node_map; |
105 DCHECK_EQ(filter_data->state_, FilterData::kInitial); | |
130 | 106 |
131 // TODO(pdr): Can this be moved out of painter? | 107 // TODO(pdr): Can this be moved out of painter? |
132 filter_.SetFilterDataForLayoutObject(const_cast<LayoutObject*>(&object), | 108 filter_.SetFilterDataForLayoutObject(const_cast<LayoutObject*>(&object), |
133 filter_data); | 109 filter_data); |
134 return recording_context.BeginContent(filter_data); | 110 filter_data->state_ = FilterData::kRecordingContent; |
111 return recording_context.BeginContent(); | |
135 } | 112 } |
136 | 113 |
137 void SVGFilterPainter::FinishEffect( | 114 void SVGFilterPainter::FinishEffect( |
138 const LayoutObject& object, | 115 const LayoutObject& object, |
139 SVGFilterRecordingContext& recording_context) { | 116 SVGFilterRecordingContext& recording_context) { |
140 FilterData* filter_data = filter_.GetFilterDataForLayoutObject(&object); | 117 FilterData* filter_data = filter_.GetFilterDataForLayoutObject(&object); |
141 if (filter_data) { | 118 if (!filter_data) |
142 // A painting cycle can occur when an FeImage references a source that | 119 return; |
143 // makes use of the FeImage itself. This is the first place we would hit | |
144 // the cycle so we reset the state and continue. | |
145 if (filter_data->state_ == FilterData::kPaintingFilterCycleDetected) | |
146 filter_data->state_ = FilterData::kPaintingFilter; | |
147 | 120 |
148 // Check for RecordingContent here because we may can be re-painting | 121 // A painting cycle can occur when an FeImage references a source that |
149 // without re-recording the contents to be filtered. | 122 // makes use of the FeImage itself. This is the first place we would hit |
150 if (filter_data->state_ == FilterData::kRecordingContent) | 123 // the cycle so we reset the state and continue. |
151 recording_context.EndContent(filter_data); | 124 if (filter_data->state_ == FilterData::kPaintingFilterCycleDetected) { |
125 filter_data->state_ = FilterData::kPaintingFilter; | |
126 return; | |
127 } | |
128 if (filter_data->state_ == FilterData::kRecordingContentCycleDetected) { | |
129 filter_data->state_ = FilterData::kRecordingContent; | |
130 return; | |
131 } | |
152 | 132 |
153 if (filter_data->state_ == FilterData::kRecordingContentCycleDetected) | 133 // Check for RecordingContent here because we may can be re-painting |
154 filter_data->state_ = FilterData::kRecordingContent; | 134 // without re-recording the contents to be filtered. |
135 Filter* filter = filter_data->last_effect->GetFilter(); | |
136 FloatRect bounds = filter->FilterRegion(); | |
137 if (filter_data->state_ == FilterData::kRecordingContent) { | |
138 DCHECK(filter->GetSourceGraphic()); | |
139 sk_sp<PaintRecord> content = recording_context.EndContent(bounds); | |
140 SkiaImageFilterBuilder::BuildSourceGraphic(filter->GetSourceGraphic(), | |
141 std::move(content)); | |
142 filter_data->state_ = FilterData::kReadyToPaint; | |
155 } | 143 } |
156 PaintFilteredContent(recording_context.PaintingContext(), object, | 144 |
chrishtr
2017/04/28 18:20:56
The old code would have executed this line in the
fs
2017/04/28 18:40:52
Previously it would've early-outed in PaintFiltere
chrishtr
2017/04/28 18:45:49
Ok great.
| |
157 filter_data); | 145 DCHECK_EQ(filter_data->state_, FilterData::kReadyToPaint); |
146 filter_data->state_ = FilterData::kPaintingFilter; | |
147 PaintFilteredContent(recording_context.PaintingContext(), object, bounds, | |
148 filter_data->last_effect); | |
149 filter_data->state_ = FilterData::kReadyToPaint; | |
158 } | 150 } |
159 | 151 |
160 } // namespace blink | 152 } // namespace blink |
OLD | NEW |