Chromium Code Reviews| 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 |