Commit 446da8a7 authored by xlai's avatar xlai Committed by Commit Bot

Detach imagebuffer references from CSSPaint

This CL removes RecordingImageBufferSurface.

Bug: 776806
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2
Change-Id: I01e3d77702d92beef2fe73d7ecf7ad51df7ac86d
Reviewed-on: https://chromium-review.googlesource.com/809189
Commit-Queue: Olivia Lai <xlai@chromium.org>
Reviewed-by: default avatarJustin Novosad <junov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#521823}
parent 1ed4b967
...@@ -608,19 +608,6 @@ bool BaseRenderingContext2D::IsFullCanvasCompositeMode(SkBlendMode op) { ...@@ -608,19 +608,6 @@ bool BaseRenderingContext2D::IsFullCanvasCompositeMode(SkBlendMode op) {
op == SkBlendMode::kDstIn || op == SkBlendMode::kDstATop; op == SkBlendMode::kDstIn || op == SkBlendMode::kDstATop;
} }
static bool IsPathExpensive(const Path& path) {
const SkPath& sk_path = path.GetSkPath();
if (CanvasHeuristicParameters::kConcavePathsAreExpensive &&
!sk_path.isConvex())
return true;
if (sk_path.countPoints() >
CanvasHeuristicParameters::kExpensivePathPointCount)
return true;
return false;
}
void BaseRenderingContext2D::DrawPathInternal( void BaseRenderingContext2D::DrawPathInternal(
const Path& path, const Path& path,
CanvasRenderingContext2DState::PaintType paint_type, CanvasRenderingContext2DState::PaintType paint_type,
...@@ -638,17 +625,11 @@ void BaseRenderingContext2D::DrawPathInternal( ...@@ -638,17 +625,11 @@ void BaseRenderingContext2D::DrawPathInternal(
if (!DrawingCanvas()) if (!DrawingCanvas())
return; return;
if (Draw([&sk_path](PaintCanvas* c, const PaintFlags* flags) // draw lambda Draw([&sk_path](PaintCanvas* c, const PaintFlags* flags) // draw lambda
{ c->drawPath(sk_path, *flags); }, { c->drawPath(sk_path, *flags); },
[](const SkIRect& rect) // overdraw test lambda [](const SkIRect& rect) // overdraw test lambda
{ return false; }, { return false; },
bounds, paint_type)) { bounds, paint_type);
if (IsPathExpensive(path)) {
ImageBuffer* buffer = GetImageBuffer();
if (buffer)
buffer->SetHasExpensiveOp();
}
}
} }
static SkPath::FillType ParseWinding(const String& winding_rule_string) { static SkPath::FillType ParseWinding(const String& winding_rule_string) {
...@@ -751,10 +732,6 @@ void BaseRenderingContext2D::ClipInternal(const Path& path, ...@@ -751,10 +732,6 @@ void BaseRenderingContext2D::ClipInternal(const Path& path,
ModifiableState().ClipPath(sk_path, clip_antialiasing_); ModifiableState().ClipPath(sk_path, clip_antialiasing_);
c->clipPath(sk_path, SkClipOp::kIntersect, c->clipPath(sk_path, SkClipOp::kIntersect,
clip_antialiasing_ == kAntiAliased); clip_antialiasing_ == kAntiAliased);
if (CanvasHeuristicParameters::kComplexClipsAreExpensive &&
!sk_path.isRect(nullptr) && HasImageBuffer()) {
GetImageBuffer()->SetHasExpensiveOp();
}
} }
void BaseRenderingContext2D::clip(const String& winding_rule_string) { void BaseRenderingContext2D::clip(const String& winding_rule_string) {
...@@ -1143,12 +1120,6 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state, ...@@ -1143,12 +1120,6 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state,
double start_time = 0; double start_time = 0;
Optional<CustomCountHistogram> timer; Optional<CustomCountHistogram> timer;
if (!IsPaint2D()) { if (!IsPaint2D()) {
if (HasImageBuffer()) {
// TODO(xlai): There should be no more RecordingImageBufferSurface used
// by canvas. crbug.com/776806.
DCHECK(!GetImageBuffer()->IsRecording());
}
start_time = WTF::MonotonicallyIncreasingTime(); start_time = WTF::MonotonicallyIncreasingTime();
if (GetImageBuffer() && GetImageBuffer()->IsAccelerated()) { if (GetImageBuffer() && GetImageBuffer()->IsAccelerated()) {
if (image_source->IsVideoElement()) { if (image_source->IsVideoElement()) {
...@@ -1222,7 +1193,7 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state, ...@@ -1222,7 +1193,7 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state,
SourceImageStatus source_image_status = kInvalidSourceImageStatus; SourceImageStatus source_image_status = kInvalidSourceImageStatus;
if (!image_source->IsVideoElement()) { if (!image_source->IsVideoElement()) {
AccelerationHint hint = AccelerationHint hint =
(GetImageBuffer() && GetImageBuffer()->IsAccelerated()) (HasImageBuffer() && GetImageBuffer()->IsAccelerated())
? kPreferAcceleration ? kPreferAcceleration
: kPreferNoAcceleration; : kPreferNoAcceleration;
image = image_source->GetSourceImageForCanvas(&source_image_status, hint, image = image_source->GetSourceImageForCanvas(&source_image_status, hint,
...@@ -1310,22 +1281,6 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state, ...@@ -1310,22 +1281,6 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state,
ValidateStateStack(); ValidateStateStack();
bool is_expensive = false;
if (CanvasHeuristicParameters::kSVGImageSourcesAreExpensive &&
image_source->IsSVGSource())
is_expensive = true;
if (image_size.Width() * image_size.Height() >
Width() * Height() * CanvasHeuristicParameters::kExpensiveImageSizeRatio)
is_expensive = true;
if (is_expensive) {
ImageBuffer* buffer = GetImageBuffer();
if (buffer)
buffer->SetHasExpensiveOp();
}
if (OriginClean() && if (OriginClean() &&
WouldTaintOrigin(image_source, ExecutionContext::From(script_state))) WouldTaintOrigin(image_source, ExecutionContext::From(script_state)))
SetOriginTainted(); SetOriginTainted();
...@@ -1601,12 +1556,6 @@ ImageData* BaseRenderingContext2D::getImageData( ...@@ -1601,12 +1556,6 @@ ImageData* BaseRenderingContext2D::getImageData(
Optional<ScopedUsHistogramTimer> timer; Optional<ScopedUsHistogramTimer> timer;
if (!IsPaint2D()) { if (!IsPaint2D()) {
if (HasImageBuffer()) {
// TODO(xlai): There should be no more RecordingImageBufferSurface used
// by canvas. crbug.com/776806.
DCHECK(!GetImageBuffer()->IsRecording());
}
if (GetImageBuffer() && GetImageBuffer()->IsAccelerated()) { if (GetImageBuffer() && GetImageBuffer()->IsAccelerated()) {
DEFINE_THREAD_SAFE_STATIC_LOCAL( DEFINE_THREAD_SAFE_STATIC_LOCAL(
CustomCountHistogram, scoped_us_counter_gpu, CustomCountHistogram, scoped_us_counter_gpu,
...@@ -1717,12 +1666,6 @@ void BaseRenderingContext2D::putImageData(ImageData* data, ...@@ -1717,12 +1666,6 @@ void BaseRenderingContext2D::putImageData(ImageData* data,
Optional<ScopedUsHistogramTimer> timer; Optional<ScopedUsHistogramTimer> timer;
if (!IsPaint2D()) { if (!IsPaint2D()) {
if (HasImageBuffer()) {
// TODO(xlai): There should be no more RecordingImageBufferSurface used
// by canvas. crbug.com/776806.
DCHECK(!GetImageBuffer()->IsRecording());
}
if (GetImageBuffer() && GetImageBuffer()->IsAccelerated()) { if (GetImageBuffer() && GetImageBuffer()->IsAccelerated()) {
DEFINE_THREAD_SAFE_STATIC_LOCAL( DEFINE_THREAD_SAFE_STATIC_LOCAL(
CustomCountHistogram, scoped_us_counter_gpu, CustomCountHistogram, scoped_us_counter_gpu,
...@@ -1853,7 +1796,7 @@ void BaseRenderingContext2D::CheckOverdraw( ...@@ -1853,7 +1796,7 @@ void BaseRenderingContext2D::CheckOverdraw(
image_type == CanvasRenderingContext2DState::kNoImage) { image_type == CanvasRenderingContext2DState::kNoImage) {
if (flags->HasShader()) { if (flags->HasShader()) {
if (flags->ShaderIsOpaque() && alpha == 0xFF) if (flags->ShaderIsOpaque() && alpha == 0xFF)
GetImageBuffer()->WillOverwriteCanvas(); this->WillOverwriteCanvas();
return; return;
} }
} }
...@@ -1867,7 +1810,7 @@ void BaseRenderingContext2D::CheckOverdraw( ...@@ -1867,7 +1810,7 @@ void BaseRenderingContext2D::CheckOverdraw(
return; return;
} }
GetImageBuffer()->WillOverwriteCanvas(); this->WillOverwriteCanvas();
} }
float BaseRenderingContext2D::GetFontBaseline( float BaseRenderingContext2D::GetFontBaseline(
......
...@@ -224,8 +224,11 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin, ...@@ -224,8 +224,11 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
virtual int Width() const = 0; virtual int Width() const = 0;
virtual int Height() const = 0; virtual int Height() const = 0;
virtual bool HasImageBuffer() const = 0; virtual bool HasImageBuffer() const { return false; }
virtual ImageBuffer* GetImageBuffer() const = 0; virtual ImageBuffer* GetImageBuffer() const {
NOTREACHED();
return nullptr;
};
virtual bool ParseColorOrCurrentColor(Color&, virtual bool ParseColorOrCurrentColor(Color&,
const String& color_string) const = 0; const String& color_string) const = 0;
...@@ -369,6 +372,11 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin, ...@@ -369,6 +372,11 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
virtual void DidInvokeGPUReadbackInCurrentFrame() {} virtual void DidInvokeGPUReadbackInCurrentFrame() {}
virtual bool IsPaint2D() const { return false; } virtual bool IsPaint2D() const { return false; }
virtual void WillOverwriteCanvas() {
if (HasImageBuffer()) {
GetImageBuffer()->WillOverwriteCanvas();
}
}
private: private:
void RealizeSaves(); void RealizeSaves();
......
...@@ -371,13 +371,6 @@ void CanvasRenderingContext2D::DidDraw(const SkIRect& dirty_rect) { ...@@ -371,13 +371,6 @@ void CanvasRenderingContext2D::DidDraw(const SkIRect& dirty_rect) {
if (dirty_rect.isEmpty()) if (dirty_rect.isEmpty())
return; return;
if (CanvasHeuristicParameters::kBlurredShadowsAreExpensive &&
GetState().ShouldDrawShadows() && GetState().ShadowBlur() > 0) {
ImageBuffer* buffer = GetImageBuffer();
if (buffer)
buffer->SetHasExpensiveOp();
}
CanvasRenderingContext::DidDraw(dirty_rect); CanvasRenderingContext::DidDraw(dirty_rect);
} }
......
...@@ -14,9 +14,7 @@ ...@@ -14,9 +14,7 @@
#include "platform/bindings/ScriptState.h" #include "platform/bindings/ScriptState.h"
#include "platform/bindings/V8BindingMacros.h" #include "platform/bindings/V8BindingMacros.h"
#include "platform/bindings/V8ObjectConstructor.h" #include "platform/bindings/V8ObjectConstructor.h"
#include "platform/graphics/ImageBuffer.h"
#include "platform/graphics/PaintGeneratedImage.h" #include "platform/graphics/PaintGeneratedImage.h"
#include "platform/graphics/RecordingImageBufferSurface.h"
#include "platform/wtf/PtrUtil.h" #include "platform/wtf/PtrUtil.h"
namespace blink { namespace blink {
...@@ -99,10 +97,7 @@ scoped_refptr<Image> CSSPaintDefinition::Paint( ...@@ -99,10 +97,7 @@ scoped_refptr<Image> CSSPaintDefinition::Paint(
} }
PaintRenderingContext2D* rendering_context = PaintRenderingContext2D::Create( PaintRenderingContext2D* rendering_context = PaintRenderingContext2D::Create(
ImageBuffer::Create(WTF::WrapUnique(new RecordingImageBufferSurface( container_size, color_params, context_settings_, zoom);
container_size, RecordingImageBufferSurface::kDisallowFallback,
color_params))),
context_settings_, zoom);
PaintSize* paint_size = PaintSize::Create(specified_size); PaintSize* paint_size = PaintSize::Create(specified_size);
StylePropertyMapReadonly* style_map = StylePropertyMapReadonly* style_map =
FilteredComputedStylePropertyMap::Create(layout_object.GetNode(), FilteredComputedStylePropertyMap::Create(layout_object.GetNode(),
...@@ -130,8 +125,8 @@ scoped_refptr<Image> CSSPaintDefinition::Paint( ...@@ -130,8 +125,8 @@ scoped_refptr<Image> CSSPaintDefinition::Paint(
return nullptr; return nullptr;
} }
return PaintGeneratedImage::Create( return PaintGeneratedImage::Create(rendering_context->GetRecord(),
rendering_context->GetImageBuffer()->GetRecord(), container_size); container_size);
} }
void CSSPaintDefinition::MaybeCreatePaintInstance() { void CSSPaintDefinition::MaybeCreatePaintInstance() {
......
...@@ -4,39 +4,58 @@ ...@@ -4,39 +4,58 @@
#include "modules/csspaint/PaintRenderingContext2D.h" #include "modules/csspaint/PaintRenderingContext2D.h"
#include "platform/graphics/ImageBuffer.h"
#include "platform/graphics/paint/PaintCanvas.h" #include "platform/graphics/paint/PaintCanvas.h"
#include <memory> #include <memory>
namespace blink { namespace blink {
PaintRenderingContext2D::PaintRenderingContext2D( PaintRenderingContext2D::PaintRenderingContext2D(
std::unique_ptr<ImageBuffer> image_buffer, const IntSize& container_size,
const CanvasColorParams& color_params,
const PaintRenderingContext2DSettings& context_settings, const PaintRenderingContext2DSettings& context_settings,
float zoom) float zoom)
: image_buffer_(std::move(image_buffer)), : container_size_(container_size),
color_params_(color_params),
context_settings_(context_settings) { context_settings_(context_settings) {
InitializePaintRecorder();
clip_antialiasing_ = kAntiAliased; clip_antialiasing_ = kAntiAliased;
ModifiableState().SetShouldAntialias(true); ModifiableState().SetShouldAntialias(true);
// RecordingImageBufferSurface doesn't call ImageBufferSurface::clear Canvas()->clear(context_settings.alpha() ? SK_ColorTRANSPARENT
// explicitly. : SK_ColorBLACK);
DCHECK(image_buffer_); did_record_draw_commands_in_paint_recorder_ = true;
image_buffer_->Canvas()->clear(context_settings.alpha() ? SK_ColorTRANSPARENT Canvas()->scale(zoom, zoom);
: SK_ColorBLACK); }
image_buffer_->DidDraw(FloatRect(0, 0, Width(), Height()));
void PaintRenderingContext2D::InitializePaintRecorder() {
paint_recorder_ = WTF::WrapUnique(new PaintRecorder);
PaintCanvas* canvas = paint_recorder_->beginRecording(
container_size_.Width(), container_size_.Height());
image_buffer_->Canvas()->scale(zoom, zoom); // Always save an initial frame, to support resetting the top level matrix
// and clip.
canvas->save();
did_record_draw_commands_in_paint_recorder_ = false;
}
PaintCanvas* PaintRenderingContext2D::Canvas() const {
DCHECK(paint_recorder_);
DCHECK(paint_recorder_->getRecordingCanvas());
return paint_recorder_->getRecordingCanvas();
}
void PaintRenderingContext2D::DidDraw(const SkIRect&) {
did_record_draw_commands_in_paint_recorder_ = true;
} }
int PaintRenderingContext2D::Width() const { int PaintRenderingContext2D::Width() const {
DCHECK(image_buffer_); return container_size_.Width();
return image_buffer_->Size().Width();
} }
int PaintRenderingContext2D::Height() const { int PaintRenderingContext2D::Height() const {
DCHECK(image_buffer_); return container_size_.Height();
return image_buffer_->Size().Height();
} }
bool PaintRenderingContext2D::ParseColorOrCurrentColor( bool PaintRenderingContext2D::ParseColorOrCurrentColor(
...@@ -50,17 +69,11 @@ bool PaintRenderingContext2D::ParseColorOrCurrentColor( ...@@ -50,17 +69,11 @@ bool PaintRenderingContext2D::ParseColorOrCurrentColor(
} }
PaintCanvas* PaintRenderingContext2D::DrawingCanvas() const { PaintCanvas* PaintRenderingContext2D::DrawingCanvas() const {
return image_buffer_->Canvas(); return Canvas();
} }
PaintCanvas* PaintRenderingContext2D::ExistingDrawingCanvas() const { PaintCanvas* PaintRenderingContext2D::ExistingDrawingCanvas() const {
DCHECK(image_buffer_); return Canvas();
return image_buffer_->Canvas();
}
void PaintRenderingContext2D::DidDraw(const SkIRect& dirty_rect) {
DCHECK(image_buffer_);
return image_buffer_->DidDraw(SkRect::Make(dirty_rect));
} }
void PaintRenderingContext2D::ValidateStateStack() const { void PaintRenderingContext2D::ValidateStateStack() const {
...@@ -80,4 +93,25 @@ sk_sp<PaintFilter> PaintRenderingContext2D::StateGetFilter() { ...@@ -80,4 +93,25 @@ sk_sp<PaintFilter> PaintRenderingContext2D::StateGetFilter() {
return GetState().GetFilterForOffscreenCanvas(IntSize(Width(), Height())); return GetState().GetFilterForOffscreenCanvas(IntSize(Width(), Height()));
} }
void PaintRenderingContext2D::WillOverwriteCanvas() {
previous_frame_.reset();
if (did_record_draw_commands_in_paint_recorder_) {
// Discard previous draw commands
paint_recorder_->finishRecordingAsPicture();
InitializePaintRecorder();
}
}
sk_sp<PaintRecord> PaintRenderingContext2D::GetRecord() {
if (!did_record_draw_commands_in_paint_recorder_ && !!previous_frame_) {
return previous_frame_; // Reuse the previous frame
}
CHECK(paint_recorder_);
DCHECK(paint_recorder_->getRecordingCanvas());
previous_frame_ = paint_recorder_->finishRecordingAsPicture();
InitializePaintRecorder();
return previous_frame_;
}
} // namespace blink } // namespace blink
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include "modules/canvas/canvas2d/BaseRenderingContext2D.h" #include "modules/canvas/canvas2d/BaseRenderingContext2D.h"
#include "modules/csspaint/PaintRenderingContext2DSettings.h" #include "modules/csspaint/PaintRenderingContext2DSettings.h"
#include "platform/bindings/ScriptWrappable.h" #include "platform/bindings/ScriptWrappable.h"
#include "platform/graphics/ImageBuffer.h"
namespace blink { namespace blink {
...@@ -25,10 +24,11 @@ class MODULES_EXPORT PaintRenderingContext2D : public ScriptWrappable, ...@@ -25,10 +24,11 @@ class MODULES_EXPORT PaintRenderingContext2D : public ScriptWrappable,
public: public:
static PaintRenderingContext2D* Create( static PaintRenderingContext2D* Create(
std::unique_ptr<ImageBuffer> image_buffer, const IntSize& container_size,
const CanvasColorParams& color_params,
const PaintRenderingContext2DSettings& context_settings, const PaintRenderingContext2DSettings& context_settings,
float zoom) { float zoom) {
return new PaintRenderingContext2D(std::move(image_buffer), return new PaintRenderingContext2D(container_size, color_params,
context_settings, zoom); context_settings, zoom);
} }
...@@ -37,8 +37,6 @@ class MODULES_EXPORT PaintRenderingContext2D : public ScriptWrappable, ...@@ -37,8 +37,6 @@ class MODULES_EXPORT PaintRenderingContext2D : public ScriptWrappable,
BaseRenderingContext2D::Trace(visitor); BaseRenderingContext2D::Trace(visitor);
} }
// BaseRenderingContext2D
// PaintRenderingContext2D doesn't have any pixel readback so the origin // PaintRenderingContext2D doesn't have any pixel readback so the origin
// is always clean, and unable to taint it. // is always clean, and unable to taint it.
bool OriginClean() const final { return true; } bool OriginClean() const final { return true; }
...@@ -50,16 +48,13 @@ class MODULES_EXPORT PaintRenderingContext2D : public ScriptWrappable, ...@@ -50,16 +48,13 @@ class MODULES_EXPORT PaintRenderingContext2D : public ScriptWrappable,
int Width() const final; int Width() const final;
int Height() const final; int Height() const final;
bool HasImageBuffer() const final { return image_buffer_.get(); }
ImageBuffer* GetImageBuffer() const final { return image_buffer_.get(); }
bool ParseColorOrCurrentColor(Color&, const String& color_string) const final; bool ParseColorOrCurrentColor(Color&, const String& color_string) const final;
PaintCanvas* DrawingCanvas() const final; PaintCanvas* DrawingCanvas() const final;
PaintCanvas* ExistingDrawingCanvas() const final; PaintCanvas* ExistingDrawingCanvas() const final;
void DisableDeferral(DisableDeferralReason) final {} void DisableDeferral(DisableDeferralReason) final {}
void DidDraw(const SkIRect& dirty_rect) final; void DidDraw(const SkIRect&) final;
bool StateHasFilter() final; bool StateHasFilter() final;
sk_sp<PaintFilter> StateGetFilter() final; sk_sp<PaintFilter> StateGetFilter() final;
...@@ -72,16 +67,27 @@ class MODULES_EXPORT PaintRenderingContext2D : public ScriptWrappable, ...@@ -72,16 +67,27 @@ class MODULES_EXPORT PaintRenderingContext2D : public ScriptWrappable,
// PaintRenderingContext2D cannot lose it's context. // PaintRenderingContext2D cannot lose it's context.
bool isContextLost() const final { return false; } bool isContextLost() const final { return false; }
sk_sp<PaintRecord> GetRecord();
protected: protected:
bool IsPaint2D() const override { return true; } bool IsPaint2D() const override { return true; }
void WillOverwriteCanvas() override;
private: private:
PaintRenderingContext2D(std::unique_ptr<ImageBuffer>, PaintRenderingContext2D(const IntSize& container_size,
const CanvasColorParams&,
const PaintRenderingContext2DSettings&, const PaintRenderingContext2DSettings&,
float zoom); float zoom);
std::unique_ptr<ImageBuffer> image_buffer_; void InitializePaintRecorder();
PaintCanvas* Canvas() const;
std::unique_ptr<PaintRecorder> paint_recorder_;
sk_sp<PaintRecord> previous_frame_;
IntSize container_size_;
const CanvasColorParams& color_params_;
PaintRenderingContext2DSettings context_settings_; PaintRenderingContext2DSettings context_settings_;
bool did_record_draw_commands_in_paint_recorder_;
}; };
} // namespace blink } // namespace blink
......
...@@ -25,7 +25,7 @@ void PaintRenderingContext2DTest::SetUp() { ...@@ -25,7 +25,7 @@ void PaintRenderingContext2DTest::SetUp() {
PaintRenderingContext2DSettings context_settings; PaintRenderingContext2DSettings context_settings;
context_settings.setAlpha(false); context_settings.setAlpha(false);
ctx_ = PaintRenderingContext2D::Create( ctx_ = PaintRenderingContext2D::Create(
ImageBuffer::Create(IntSize(kWidth, kHeight)), context_settings, kZoom); IntSize(kWidth, kHeight), CanvasColorParams(), context_settings, kZoom);
} }
void TrySettingStrokeStyle(PaintRenderingContext2D* ctx, void TrySettingStrokeStyle(PaintRenderingContext2D* ctx,
......
...@@ -47,8 +47,6 @@ A `CSSPaintValue` can generate an image from the method `CSSPaintImageGenerator# ...@@ -47,8 +47,6 @@ A `CSSPaintValue` can generate an image from the method `CSSPaintImageGenerator#
calls through to `CSSPaintDefinition#paint` which actually invokes the javascript paint method. calls through to `CSSPaintDefinition#paint` which actually invokes the javascript paint method.
This method returns the `PaintGeneratedImage`. This method returns the `PaintGeneratedImage`.
The `PaintRecord` is produced from a `RecordingImageBufferSurface`.
### Style Invalidation ### Style Invalidation
The `CSSPaintDefinition` keeps a list of both native and custom properties it will invalidate on. The `CSSPaintDefinition` keeps a list of both native and custom properties it will invalidate on.
......
...@@ -977,8 +977,6 @@ jumbo_component("platform") { ...@@ -977,8 +977,6 @@ jumbo_component("platform") {
"graphics/PlaceholderImage.h", "graphics/PlaceholderImage.h",
"graphics/ProfilingCanvas.cpp", "graphics/ProfilingCanvas.cpp",
"graphics/ProfilingCanvas.h", "graphics/ProfilingCanvas.h",
"graphics/RecordingImageBufferSurface.cpp",
"graphics/RecordingImageBufferSurface.h",
"graphics/ReplayingCanvas.cpp", "graphics/ReplayingCanvas.cpp",
"graphics/ReplayingCanvas.h", "graphics/ReplayingCanvas.h",
"graphics/ScopedInterpolationQuality.h", "graphics/ScopedInterpolationQuality.h",
...@@ -1816,7 +1814,6 @@ jumbo_source_set("blink_platform_unittests_sources") { ...@@ -1816,7 +1814,6 @@ jumbo_source_set("blink_platform_unittests_sources") {
"graphics/HighContrastImageClassifierTest.cpp", "graphics/HighContrastImageClassifierTest.cpp",
"graphics/ImageBufferTest.cpp", "graphics/ImageBufferTest.cpp",
"graphics/PaintInvalidationReasonTest.cpp", "graphics/PaintInvalidationReasonTest.cpp",
"graphics/RecordingImageBufferSurfaceTest.cpp",
"graphics/VideoFrameSubmitterTest.cpp", "graphics/VideoFrameSubmitterTest.cpp",
"graphics/compositing/CompositedLayerRasterInvalidatorTest.cpp", "graphics/compositing/CompositedLayerRasterInvalidatorTest.cpp",
"graphics/compositing/PaintArtifactCompositorTest.cpp", "graphics/compositing/PaintArtifactCompositorTest.cpp",
......
...@@ -25,43 +25,10 @@ enum { ...@@ -25,43 +25,10 @@ enum {
// containing layer is the object of a paint invalidation. // containing layer is the object of a paint invalidation.
kExpensiveOverdrawThreshold = 10, kExpensiveOverdrawThreshold = 10,
kExpensivePathPointCount = 50,
kSVGImageSourcesAreExpensive = 1,
kConcavePathsAreExpensive = 1,
kComplexClipsAreExpensive = 1, kComplexClipsAreExpensive = 1,
kBlurredShadowsAreExpensive = 1, kBlurredShadowsAreExpensive = 1,
// Heuristic: When drawing a source image that has more pixels than
// the destination canvas by the following factor or more, the draw
// is considered expensive.
kExpensiveImageSizeRatio = 4,
// Display list fallback heuristic parameters
//============================================
// Frames ending with more than this number of levels remaining
// on the state stack at the end of a frame are too expensive to
// remain in display list mode. This criterion is motivated by an
// O(N) cost in carying over state from one frame to the next when
// in display list mode. The value of this parameter should be high
// enough to almost never kick in other than for cases with unmatched
// save()/restore() calls are low enough to kick in before state
// management becomes measurably expensive.
kExpensiveRecordingStackDepth = 50,
// GPU vs. display list heuristic parameters
//===========================================
// Pixel count beyond which we should always prefer to use display
// lists. Rationale: The allocation of large textures for canvas
// tends to starve the compositor, and increase the probability of
// failure of subsequent allocations required for double buffering.
kPreferDisplayListOverGpuSizeThreshold = 8096 * 4096,
// Disable Acceleration heuristic parameters // Disable Acceleration heuristic parameters
//=========================================== //===========================================
......
...@@ -17,12 +17,10 @@ class PLATFORM_EXPORT CanvasMetrics { ...@@ -17,12 +17,10 @@ class PLATFORM_EXPORT CanvasMetrics {
enum CanvasContextUsage { enum CanvasContextUsage {
kCanvasCreated = 0, kCanvasCreated = 0,
kGPUAccelerated2DCanvasImageBufferCreated = 1, kGPUAccelerated2DCanvasImageBufferCreated = 1,
kDisplayList2DCanvasImageBufferCreated = 2,
kUnaccelerated2DCanvasImageBufferCreated = 3, kUnaccelerated2DCanvasImageBufferCreated = 3,
kAccelerated2DCanvasGPUContextLost = 4, kAccelerated2DCanvasGPUContextLost = 4,
kUnaccelerated2DCanvasImageBufferCreationFailed = 5, kUnaccelerated2DCanvasImageBufferCreationFailed = 5,
kGPUAccelerated2DCanvasImageBufferCreationFailed = 6, kGPUAccelerated2DCanvasImageBufferCreationFailed = 6,
kDisplayList2DCanvasFallbackToRaster = 7,
kGPUAccelerated2DCanvasDeferralDisabled = 8, kGPUAccelerated2DCanvasDeferralDisabled = 8,
kGPUAccelerated2DCanvasSurfaceCreationFailed = 9, kGPUAccelerated2DCanvasSurfaceCreationFailed = 9,
kNumberOfUsages kNumberOfUsages
......
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
#include "platform/geometry/IntRect.h" #include "platform/geometry/IntRect.h"
#include "platform/graphics/CanvasHeuristicParameters.h" #include "platform/graphics/CanvasHeuristicParameters.h"
#include "platform/graphics/GraphicsContext.h" #include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/RecordingImageBufferSurface.h"
#include "platform/graphics/StaticBitmapImage.h" #include "platform/graphics/StaticBitmapImage.h"
#include "platform/graphics/UnacceleratedImageBufferSurface.h" #include "platform/graphics/UnacceleratedImageBufferSurface.h"
#include "platform/graphics/gpu/DrawingBuffer.h" #include "platform/graphics/gpu/DrawingBuffer.h"
...@@ -400,18 +399,6 @@ void ImageBuffer::SetSurface(std::unique_ptr<ImageBufferSurface> surface) { ...@@ -400,18 +399,6 @@ void ImageBuffer::SetSurface(std::unique_ptr<ImageBufferSurface> surface) {
if (!image) if (!image)
return; return;
if (surface->IsRecording() && image->IsTextureBacked()) {
// Using a GPU-backed image with RecordingImageBufferSurface
// will fail at playback time.
sk_sp<SkImage> texture_image =
image->PaintImageForCurrentFrame().GetSkImage();
// Must tear down AcceleratedStaticBitmapImage before calling
// makeNonTextureImage()
image = nullptr;
image = StaticBitmapImage::Create(texture_image->makeNonTextureImage());
}
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc);
surface->Canvas()->drawImage(image->PaintImageForCurrentFrame(), 0, 0); surface->Canvas()->drawImage(image->PaintImageForCurrentFrame(), 0, 0);
surface->SetImageBuffer(this); surface->SetImageBuffer(this);
surface_ = std::move(surface); surface_ = std::move(surface);
......
...@@ -84,9 +84,6 @@ class PLATFORM_EXPORT ImageBuffer { ...@@ -84,9 +84,6 @@ class PLATFORM_EXPORT ImageBuffer {
static bool CanCreateImageBuffer(const IntSize&); static bool CanCreateImageBuffer(const IntSize&);
const IntSize& Size() const { return surface_->Size(); } const IntSize& Size() const { return surface_->Size(); }
bool IsAccelerated() const { return surface_->IsAccelerated(); } bool IsAccelerated() const { return surface_->IsAccelerated(); }
bool IsRecording() const { return surface_->IsRecording(); }
void SetHasExpensiveOp() { surface_->SetHasExpensiveOp(); }
bool IsExpensiveToPaint() const { return surface_->IsExpensiveToPaint(); }
void PrepareSurfaceForPaintingIfNeeded() { void PrepareSurfaceForPaintingIfNeeded() {
surface_->PrepareSurfaceForPaintingIfNeeded(); surface_->PrepareSurfaceForPaintingIfNeeded();
} }
......
...@@ -70,8 +70,6 @@ class PLATFORM_EXPORT ImageBufferSurface { ...@@ -70,8 +70,6 @@ class PLATFORM_EXPORT ImageBufferSurface {
virtual bool Restore() { return false; } virtual bool Restore() { return false; }
virtual WebLayer* Layer() { return nullptr; } virtual WebLayer* Layer() { return nullptr; }
virtual bool IsAccelerated() const { return false; } virtual bool IsAccelerated() const { return false; }
virtual bool IsRecording() const { return false; }
virtual bool IsExpensiveToPaint() { return false; }
virtual void SetFilterQuality(SkFilterQuality) {} virtual void SetFilterQuality(SkFilterQuality) {}
virtual void SetIsHidden(bool) {} virtual void SetIsHidden(bool) {}
virtual void SetImageBuffer(ImageBuffer*) {} virtual void SetImageBuffer(ImageBuffer*) {}
......
// 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 "platform/graphics/RecordingImageBufferSurface.h"
#include <memory>
#include "base/memory/scoped_refptr.h"
#include "platform/graphics/CanvasHeuristicParameters.h"
#include "platform/graphics/CanvasMetrics.h"
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/ImageBuffer.h"
#include "platform/graphics/StaticBitmapImage.h"
#include "platform/graphics/UnacceleratedImageBufferSurface.h"
#include "platform/graphics/paint/PaintRecorder.h"
#include "platform/wtf/CheckedNumeric.h"
#include "platform/wtf/PtrUtil.h"
namespace blink {
RecordingImageBufferSurface::RecordingImageBufferSurface(
const IntSize& size,
AllowFallback allow_fallback,
const CanvasColorParams& color_params)
: ImageBufferSurface(size, color_params),
allow_fallback_(allow_fallback),
image_buffer_(nullptr),
current_frame_pixel_count_(0),
previous_frame_pixel_count_(0),
frame_was_cleared_(true),
did_record_draw_commands_in_current_frame_(false),
current_frame_has_expensive_op_(false),
previous_frame_has_expensive_op_(false),
resource_host_(nullptr) {
InitializeCurrentFrame();
}
RecordingImageBufferSurface::~RecordingImageBufferSurface() {}
void RecordingImageBufferSurface::InitializeCurrentFrame() {
current_frame_ = WTF::WrapUnique(new PaintRecorder);
PaintCanvas* canvas =
current_frame_->beginRecording(Size().Width(), Size().Height());
// Always save an initial frame, to support resetting the top level matrix
// and clip.
canvas->save();
if (resource_host_) {
resource_host_->RestoreCanvasMatrixClipStack(canvas);
}
did_record_draw_commands_in_current_frame_ = false;
current_frame_has_expensive_op_ = false;
current_frame_pixel_count_ = 0;
}
void RecordingImageBufferSurface::SetImageBuffer(ImageBuffer* image_buffer) {
image_buffer_ = image_buffer;
}
bool RecordingImageBufferSurface::WritePixels(const SkImageInfo& orig_info,
const void* pixels,
size_t row_bytes,
int x,
int y) {
if (!fallback_surface_) {
IntRect write_rect(x, y, orig_info.width(), orig_info.height());
if (write_rect.Contains(IntRect(IntPoint(), Size())))
WillOverwriteCanvas();
FallBackToRasterCanvas(kFallbackReasonWritePixels);
if (!fallback_surface_->IsValid())
return false;
}
return fallback_surface_->WritePixels(orig_info, pixels, row_bytes, x, y);
}
void RecordingImageBufferSurface::FallBackToRasterCanvas(
FallbackReason reason) {
DCHECK(allow_fallback_ == kAllowFallback);
CHECK(reason != kFallbackReasonUnknown);
if (fallback_surface_) {
DCHECK(!current_frame_);
return;
}
fallback_surface_ = WTF::WrapUnique(new UnacceleratedImageBufferSurface(
Size(), kInitializeImagePixels, ColorParams()));
// If the fallback surface fails to be created, then early out.
if (!fallback_surface_->IsValid())
return;
if (previous_frame_) {
fallback_surface_->Canvas()->drawPicture(previous_frame_);
previous_frame_.reset();
}
if (current_frame_) {
sk_sp<PaintRecord> record = current_frame_->finishRecordingAsPicture();
if (record)
fallback_surface_->Canvas()->drawPicture(record);
current_frame_.reset();
}
if (resource_host_) {
resource_host_->RestoreCanvasMatrixClipStack(fallback_surface_->Canvas());
}
}
static RecordingImageBufferSurface::FallbackReason
SnapshotReasonToFallbackReason(SnapshotReason reason) {
switch (reason) {
case kSnapshotReasonLowLatencyFrame:
NOTREACHED(); // Low latency frames should not cause fallbacks
// No 'break' on purpose.
case kSnapshotReasonUnknown:
return RecordingImageBufferSurface::kFallbackReasonUnknown;
case kSnapshotReasonGetImageData:
return RecordingImageBufferSurface::
kFallbackReasonSnapshotForGetImageData;
case kSnapshotReasonPaint:
return RecordingImageBufferSurface::kFallbackReasonSnapshotForPaint;
case kSnapshotReasonToDataURL:
return RecordingImageBufferSurface::kFallbackReasonSnapshotForToDataURL;
case kSnapshotReasonToBlob:
return RecordingImageBufferSurface::kFallbackReasonSnapshotForToBlob;
case kSnapshotReasonCanvasListenerCapture:
return RecordingImageBufferSurface::
kFallbackReasonSnapshotForCanvasListenerCapture;
case kSnapshotReasonDrawImage:
return RecordingImageBufferSurface::kFallbackReasonSnapshotForDrawImage;
case kSnapshotReasonCreatePattern:
return RecordingImageBufferSurface::
kFallbackReasonSnapshotForCreatePattern;
case kSnapshotReasonTransferToImageBitmap:
return RecordingImageBufferSurface::
kFallbackReasonSnapshotForTransferToImageBitmap;
case kSnapshotReasonUnitTests:
return RecordingImageBufferSurface::kFallbackReasonSnapshotForUnitTests;
case kSnapshotReasonGetCopiedImage:
return RecordingImageBufferSurface::kFallbackReasonSnapshotGetCopiedImage;
case kSnapshotReasonWebGLDrawImageIntoBuffer:
return RecordingImageBufferSurface::
kFallbackReasonSnapshotWebGLDrawImageIntoBuffer;
case kSnapshotReasonWebGLTexImage2D:
return RecordingImageBufferSurface::
kFallbackReasonSnapshotForWebGLTexImage2D;
case kSnapshotReasonWebGLTexSubImage2D:
return RecordingImageBufferSurface::
kFallbackReasonSnapshotForWebGLTexSubImage2D;
case kSnapshotReasonWebGLTexImage3D:
return RecordingImageBufferSurface::
kFallbackReasonSnapshotForWebGLTexImage3D;
case kSnapshotReasonWebGLTexSubImage3D:
return RecordingImageBufferSurface::
kFallbackReasonSnapshotForWebGLTexSubImage3D;
case kSnapshotReasonCopyToClipboard:
return RecordingImageBufferSurface::
kFallbackReasonSnapshotForCopyToClipboard;
case kSnapshotReasonCreateImageBitmap:
return RecordingImageBufferSurface::
kFallbackReasonSnapshotForCreateImageBitmap;
}
NOTREACHED();
return RecordingImageBufferSurface::kFallbackReasonUnknown;
}
scoped_refptr<StaticBitmapImage> RecordingImageBufferSurface::NewImageSnapshot(
AccelerationHint hint,
SnapshotReason reason) {
if (!fallback_surface_)
FallBackToRasterCanvas(SnapshotReasonToFallbackReason(reason));
if (!fallback_surface_->IsValid())
return nullptr;
return fallback_surface_->NewImageSnapshot(hint, reason);
}
PaintCanvas* RecordingImageBufferSurface::Canvas() {
if (fallback_surface_) {
DCHECK(fallback_surface_->IsValid());
return fallback_surface_->Canvas();
}
DCHECK(current_frame_->getRecordingCanvas());
return current_frame_->getRecordingCanvas();
}
static RecordingImageBufferSurface::FallbackReason
DisableDeferralReasonToFallbackReason(DisableDeferralReason reason) {
switch (reason) {
case kDisableDeferralReasonUnknown:
return RecordingImageBufferSurface::kFallbackReasonUnknown;
case kDisableDeferralReasonExpensiveOverdrawHeuristic:
return RecordingImageBufferSurface::
kFallbackReasonExpensiveOverdrawHeuristic;
case kDisableDeferralReasonUsingTextureBackedPattern:
return RecordingImageBufferSurface::kFallbackReasonTextureBackedPattern;
case kDisableDeferralReasonDrawImageOfVideo:
return RecordingImageBufferSurface::kFallbackReasonDrawImageOfVideo;
case kDisableDeferralReasonDrawImageOfAnimated2dCanvas:
return RecordingImageBufferSurface::
kFallbackReasonDrawImageOfAnimated2dCanvas;
case kDisableDeferralReasonSubPixelTextAntiAliasingSupport:
return RecordingImageBufferSurface::
kFallbackReasonSubPixelTextAntiAliasingSupport;
case kDisableDeferralDrawImageWithTextureBackedSourceImage:
return RecordingImageBufferSurface::
kFallbackReasonDrawImageWithTextureBackedSourceImage;
// The LowEndDevice reason should only be used on Canvas2DLayerBridge.
case kDisableDeferralReasonLowEndDevice:
case kDisableDeferralReasonCount:
NOTREACHED();
break;
}
NOTREACHED();
return RecordingImageBufferSurface::kFallbackReasonUnknown;
}
void RecordingImageBufferSurface::DisableDeferral(
DisableDeferralReason reason) {
if (!fallback_surface_)
FallBackToRasterCanvas(DisableDeferralReasonToFallbackReason(reason));
}
sk_sp<PaintRecord> RecordingImageBufferSurface::GetRecord() {
if (fallback_surface_)
return nullptr;
FallbackReason fallback_reason = kFallbackReasonUnknown;
bool can_use_record = FinalizeFrameInternal(&fallback_reason);
if (can_use_record) {
return previous_frame_;
}
if (!fallback_surface_)
FallBackToRasterCanvas(fallback_reason);
return nullptr;
}
void RecordingImageBufferSurface::FinalizeFrame() {
if (fallback_surface_) {
fallback_surface_->FinalizeFrame();
return;
}
FallbackReason fallback_reason = kFallbackReasonUnknown;
if (!FinalizeFrameInternal(&fallback_reason))
FallBackToRasterCanvas(fallback_reason);
}
void RecordingImageBufferSurface::WillOverwriteCanvas() {
frame_was_cleared_ = true;
previous_frame_.reset();
previous_frame_has_expensive_op_ = false;
previous_frame_pixel_count_ = 0;
if (did_record_draw_commands_in_current_frame_ && !fallback_surface_) {
// Discard previous draw commands
current_frame_->finishRecordingAsPicture();
InitializeCurrentFrame();
}
}
void RecordingImageBufferSurface::DidDraw(const FloatRect& rect) {
did_record_draw_commands_in_current_frame_ = true;
IntRect pixel_bounds = EnclosingIntRect(rect);
CheckedNumeric<int> pixel_count = pixel_bounds.Width();
pixel_count *= pixel_bounds.Height();
pixel_count += current_frame_pixel_count_;
current_frame_pixel_count_ =
pixel_count.ValueOrDefault(std::numeric_limits<int>::max());
}
bool RecordingImageBufferSurface::FinalizeFrameInternal(
FallbackReason* fallback_reason) {
CHECK(!fallback_surface_);
CHECK(current_frame_);
DCHECK(current_frame_->getRecordingCanvas());
DCHECK(fallback_reason);
DCHECK(*fallback_reason == kFallbackReasonUnknown);
if (!did_record_draw_commands_in_current_frame_) {
if (!previous_frame_) {
// Create an initial blank frame
previous_frame_ = current_frame_->finishRecordingAsPicture();
InitializeCurrentFrame();
}
CHECK(current_frame_);
return true;
}
if (!frame_was_cleared_) {
*fallback_reason = kFallbackReasonCanvasNotClearedBetweenFrames;
return false;
}
if (allow_fallback_ == kAllowFallback &&
current_frame_->getRecordingCanvas()->getSaveCount() - 1 >
CanvasHeuristicParameters::kExpensiveRecordingStackDepth) {
// (getSaveCount() decremented to account for the intial recording canvas
// save frame.)
*fallback_reason = kFallbackReasonRunawayStateStack;
return false;
}
previous_frame_ = current_frame_->finishRecordingAsPicture();
previous_frame_has_expensive_op_ = current_frame_has_expensive_op_;
previous_frame_pixel_count_ = current_frame_pixel_count_;
InitializeCurrentFrame();
frame_was_cleared_ = false;
return true;
}
void RecordingImageBufferSurface::Draw(GraphicsContext& context,
const FloatRect& dest_rect,
const FloatRect& src_rect,
SkBlendMode op) {
if (fallback_surface_) {
fallback_surface_->Draw(context, dest_rect, src_rect, op);
return;
}
sk_sp<PaintRecord> record = GetRecord();
if (record) {
context.CompositeRecord(std::move(record), dest_rect, src_rect, op);
} else {
ImageBufferSurface::Draw(context, dest_rect, src_rect, op);
}
}
bool RecordingImageBufferSurface::IsExpensiveToPaint() {
if (fallback_surface_)
return fallback_surface_->IsExpensiveToPaint();
CheckedNumeric<int> overdraw_limit_checked = Size().Width();
overdraw_limit_checked *= Size().Height();
overdraw_limit_checked *=
CanvasHeuristicParameters::kExpensiveOverdrawThreshold;
int overdraw_limit =
overdraw_limit_checked.ValueOrDefault(std::numeric_limits<int>::max());
if (did_record_draw_commands_in_current_frame_) {
if (current_frame_has_expensive_op_)
return true;
if (current_frame_pixel_count_ >= overdraw_limit)
return true;
if (frame_was_cleared_)
return false; // early exit because previous frame is overdrawn
}
if (previous_frame_) {
if (previous_frame_has_expensive_op_)
return true;
if (previous_frame_pixel_count_ >= overdraw_limit)
return true;
}
return false;
}
// Fallback passthroughs
bool RecordingImageBufferSurface::Restore() {
if (fallback_surface_)
return fallback_surface_->Restore();
return ImageBufferSurface::Restore();
}
WebLayer* RecordingImageBufferSurface::Layer() {
if (fallback_surface_)
return fallback_surface_->Layer();
return ImageBufferSurface::Layer();
}
bool RecordingImageBufferSurface::IsAccelerated() const {
if (fallback_surface_)
return fallback_surface_->IsAccelerated();
return ImageBufferSurface::IsAccelerated();
}
void RecordingImageBufferSurface::SetIsHidden(bool hidden) {
if (fallback_surface_)
fallback_surface_->SetIsHidden(hidden);
else
ImageBufferSurface::SetIsHidden(hidden);
}
} // namespace blink
// 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.
#ifndef RecordingImageBufferSurface_h
#define RecordingImageBufferSurface_h
#include <memory>
#include "platform/graphics/CanvasResourceHost.h"
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/ImageBufferSurface.h"
#include "platform/wtf/Allocator.h"
#include "platform/wtf/Noncopyable.h"
#include "public/platform/WebThread.h"
#include "third_party/skia/include/core/SkRefCnt.h"
namespace blink {
class ImageBuffer;
class UnacceleratedImageBufferSurface;
class PLATFORM_EXPORT RecordingImageBufferSurface : public ImageBufferSurface {
WTF_MAKE_NONCOPYABLE(RecordingImageBufferSurface);
USING_FAST_MALLOC(RecordingImageBufferSurface);
public:
enum AllowFallback : bool { kDisallowFallback, kAllowFallback };
// If |AllowFallback| is kDisallowFallback the buffer surface should only be
// used for one frame and should not be used for any operations which need a
// raster surface, (i.e. WritePixels()).
// Only GetRecord() should be used to access the resulting frame.
RecordingImageBufferSurface(const IntSize&,
AllowFallback,
const CanvasColorParams& = CanvasColorParams());
~RecordingImageBufferSurface() override;
// Implementation of ImageBufferSurface interfaces
PaintCanvas* Canvas() override;
void DisableDeferral(DisableDeferralReason) override;
sk_sp<PaintRecord> GetRecord() override;
void SetCanvasResourceHost(CanvasResourceHost* host) {
resource_host_ = host;
}
void DidDraw(const FloatRect&) override;
bool IsValid() const override { return true; }
bool IsRecording() const override { return !fallback_surface_; }
bool WritePixels(const SkImageInfo& orig_info,
const void* pixels,
size_t row_bytes,
int x,
int y) override;
void WillOverwriteCanvas() override;
void FinalizeFrame() override;
void SetImageBuffer(ImageBuffer*) override;
scoped_refptr<StaticBitmapImage> NewImageSnapshot(AccelerationHint,
SnapshotReason) override;
void Draw(GraphicsContext&,
const FloatRect& dest_rect,
const FloatRect& src_rect,
SkBlendMode) override;
bool IsExpensiveToPaint() override;
void SetHasExpensiveOp() override { current_frame_has_expensive_op_ = true; }
// Passthroughs to fallback surface
bool Restore() override;
WebLayer* Layer() override;
bool IsAccelerated() const override;
void SetIsHidden(bool) override;
// This enum is used in a UMA histogram.
enum FallbackReason {
kFallbackReasonUnknown =
0, // This value should never appear in production histograms
kFallbackReasonCanvasNotClearedBetweenFrames = 1,
kFallbackReasonRunawayStateStack = 2,
kFallbackReasonWritePixels = 3,
// kFallbackReasonFlushInitialClear = 4,
// kFallbackReasonFlushForDrawImageOfWebGL = 5,
kFallbackReasonSnapshotForGetImageData = 6,
kFallbackReasonSnapshotForPaint = 8,
kFallbackReasonSnapshotForToDataURL = 9,
kFallbackReasonSnapshotForToBlob = 10,
kFallbackReasonSnapshotForCanvasListenerCapture = 11,
kFallbackReasonSnapshotForDrawImage = 12,
kFallbackReasonSnapshotForCreatePattern = 13,
kFallbackReasonExpensiveOverdrawHeuristic = 14,
kFallbackReasonTextureBackedPattern = 15,
kFallbackReasonDrawImageOfVideo = 16,
kFallbackReasonDrawImageOfAnimated2dCanvas = 17,
kFallbackReasonSubPixelTextAntiAliasingSupport = 18,
kFallbackReasonDrawImageWithTextureBackedSourceImage = 19,
kFallbackReasonSnapshotForTransferToImageBitmap = 20,
kFallbackReasonSnapshotForUnitTests =
21, // This value should never appear in production histograms
kFallbackReasonSnapshotGetCopiedImage = 22,
kFallbackReasonSnapshotWebGLDrawImageIntoBuffer = 23,
kFallbackReasonSnapshotForWebGLTexImage2D = 24,
kFallbackReasonSnapshotForWebGLTexSubImage2D = 25,
kFallbackReasonSnapshotForWebGLTexImage3D = 26,
kFallbackReasonSnapshotForWebGLTexSubImage3D = 27,
kFallbackReasonSnapshotForCopyToClipboard = 28,
kFallbackReasonSnapshotForCreateImageBitmap = 29,
kFallbackReasonCount,
};
private:
void FallBackToRasterCanvas(FallbackReason);
void InitializeCurrentFrame();
bool FinalizeFrameInternal(FallbackReason*);
int ApproximateOpCount();
const AllowFallback allow_fallback_;
std::unique_ptr<PaintRecorder> current_frame_;
sk_sp<PaintRecord> previous_frame_;
std::unique_ptr<UnacceleratedImageBufferSurface> fallback_surface_;
ImageBuffer* image_buffer_;
int initial_save_count_;
int current_frame_pixel_count_;
int previous_frame_pixel_count_;
bool frame_was_cleared_;
bool did_record_draw_commands_in_current_frame_;
bool current_frame_has_expensive_op_;
bool previous_frame_has_expensive_op_;
CanvasResourceHost* resource_host_;
};
} // namespace blink
#endif
// 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 "platform/graphics/RecordingImageBufferSurface.h"
#include <memory>
#include "base/memory/scoped_refptr.h"
#include "platform/WebTaskRunner.h"
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/ImageBuffer.h"
#include "platform/graphics/UnacceleratedImageBufferSurface.h"
#include "platform/graphics/paint/PaintCanvas.h"
#include "platform/graphics/paint/PaintRecord.h"
#include "platform/testing/TestingPlatformSupport.h"
#include "public/platform/Platform.h"
#include "public/platform/WebThread.h"
#include "public/platform/WebTraceLocation.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Test;
namespace blink {
class RecordingImageBufferSurfaceTest : public Test {
protected:
RecordingImageBufferSurfaceTest() {
auto test_surface = std::make_unique<RecordingImageBufferSurface>(
IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback);
test_surface_ = test_surface.get();
// We create an ImageBuffer in order for the |test_surface| to be
// properly initialized with a GraphicsContext
image_buffer_ = ImageBuffer::Create(std::move(test_surface));
EXPECT_TRUE(image_buffer_);
}
public:
RecordingImageBufferSurface* TestSurface() { return test_surface_; }
PaintCanvas* Canvas() { return image_buffer_->Canvas(); }
private:
RecordingImageBufferSurface* test_surface_;
std::unique_ptr<ImageBuffer> image_buffer_;
};
TEST_F(RecordingImageBufferSurfaceTest, testEmptyPicture) {
sk_sp<PaintRecord> record = TestSurface()->GetRecord();
EXPECT_TRUE(record.get());
EXPECT_TRUE(TestSurface()->IsRecording());
}
TEST_F(RecordingImageBufferSurfaceTest, testNoFallbackWithClear) {
TestSurface()->WillOverwriteCanvas();
TestSurface()->GetRecord();
EXPECT_TRUE(TestSurface()->IsRecording());
}
TEST_F(RecordingImageBufferSurfaceTest, testNonAnimatedCanvasUpdate) {
// Acquire picture twice to simulate a static canvas: nothing drawn between
// updates.
TestSurface()->DidDraw(FloatRect(0, 0, 1, 1));
TestSurface()->GetRecord();
TestSurface()->GetRecord();
EXPECT_TRUE(TestSurface()->IsRecording());
}
TEST_F(RecordingImageBufferSurfaceTest, testAnimatedWithoutClear) {
TestSurface()->DidDraw(FloatRect(0, 0, 1, 1));
TestSurface()->GetRecord();
EXPECT_TRUE(TestSurface()->IsRecording());
TestSurface()->DidDraw(FloatRect(0, 0, 1, 1));
TestSurface()->GetRecord();
EXPECT_FALSE(TestSurface()->IsRecording());
}
TEST_F(RecordingImageBufferSurfaceTest, testAnimatedWithClear) {
TestSurface()->GetRecord();
TestSurface()->WillOverwriteCanvas();
TestSurface()->DidDraw(FloatRect(0, 0, 1, 1));
TestSurface()->GetRecord();
EXPECT_TRUE(TestSurface()->IsRecording());
// Clear after use.
TestSurface()->DidDraw(FloatRect(0, 0, 1, 1));
TestSurface()->WillOverwriteCanvas();
TestSurface()->GetRecord();
EXPECT_TRUE(TestSurface()->IsRecording());
}
TEST_F(RecordingImageBufferSurfaceTest, testClearRect) {
TestSurface()->GetRecord();
PaintFlags clear_flags;
clear_flags.setBlendMode(SkBlendMode::kClear);
Canvas()->drawRect(SkRect::MakeWH(TestSurface()->Size().Width(),
TestSurface()->Size().Height()),
clear_flags);
TestSurface()->DidDraw(FloatRect(0, 0, 1, 1));
TestSurface()->GetRecord();
EXPECT_TRUE(TestSurface()->IsRecording());
}
} // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment