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) {
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(
const Path& path,
CanvasRenderingContext2DState::PaintType paint_type,
......@@ -638,17 +625,11 @@ void BaseRenderingContext2D::DrawPathInternal(
if (!DrawingCanvas())
return;
if (Draw([&sk_path](PaintCanvas* c, const PaintFlags* flags) // draw lambda
{ c->drawPath(sk_path, *flags); },
[](const SkIRect& rect) // overdraw test lambda
{ return false; },
bounds, paint_type)) {
if (IsPathExpensive(path)) {
ImageBuffer* buffer = GetImageBuffer();
if (buffer)
buffer->SetHasExpensiveOp();
}
}
Draw([&sk_path](PaintCanvas* c, const PaintFlags* flags) // draw lambda
{ c->drawPath(sk_path, *flags); },
[](const SkIRect& rect) // overdraw test lambda
{ return false; },
bounds, paint_type);
}
static SkPath::FillType ParseWinding(const String& winding_rule_string) {
......@@ -751,10 +732,6 @@ void BaseRenderingContext2D::ClipInternal(const Path& path,
ModifiableState().ClipPath(sk_path, clip_antialiasing_);
c->clipPath(sk_path, SkClipOp::kIntersect,
clip_antialiasing_ == kAntiAliased);
if (CanvasHeuristicParameters::kComplexClipsAreExpensive &&
!sk_path.isRect(nullptr) && HasImageBuffer()) {
GetImageBuffer()->SetHasExpensiveOp();
}
}
void BaseRenderingContext2D::clip(const String& winding_rule_string) {
......@@ -1143,12 +1120,6 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state,
double start_time = 0;
Optional<CustomCountHistogram> timer;
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();
if (GetImageBuffer() && GetImageBuffer()->IsAccelerated()) {
if (image_source->IsVideoElement()) {
......@@ -1222,7 +1193,7 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state,
SourceImageStatus source_image_status = kInvalidSourceImageStatus;
if (!image_source->IsVideoElement()) {
AccelerationHint hint =
(GetImageBuffer() && GetImageBuffer()->IsAccelerated())
(HasImageBuffer() && GetImageBuffer()->IsAccelerated())
? kPreferAcceleration
: kPreferNoAcceleration;
image = image_source->GetSourceImageForCanvas(&source_image_status, hint,
......@@ -1310,22 +1281,6 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state,
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() &&
WouldTaintOrigin(image_source, ExecutionContext::From(script_state)))
SetOriginTainted();
......@@ -1601,12 +1556,6 @@ ImageData* BaseRenderingContext2D::getImageData(
Optional<ScopedUsHistogramTimer> timer;
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()) {
DEFINE_THREAD_SAFE_STATIC_LOCAL(
CustomCountHistogram, scoped_us_counter_gpu,
......@@ -1717,12 +1666,6 @@ void BaseRenderingContext2D::putImageData(ImageData* data,
Optional<ScopedUsHistogramTimer> timer;
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()) {
DEFINE_THREAD_SAFE_STATIC_LOCAL(
CustomCountHistogram, scoped_us_counter_gpu,
......@@ -1853,7 +1796,7 @@ void BaseRenderingContext2D::CheckOverdraw(
image_type == CanvasRenderingContext2DState::kNoImage) {
if (flags->HasShader()) {
if (flags->ShaderIsOpaque() && alpha == 0xFF)
GetImageBuffer()->WillOverwriteCanvas();
this->WillOverwriteCanvas();
return;
}
}
......@@ -1867,7 +1810,7 @@ void BaseRenderingContext2D::CheckOverdraw(
return;
}
GetImageBuffer()->WillOverwriteCanvas();
this->WillOverwriteCanvas();
}
float BaseRenderingContext2D::GetFontBaseline(
......
......@@ -224,8 +224,11 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
virtual int Width() const = 0;
virtual int Height() const = 0;
virtual bool HasImageBuffer() const = 0;
virtual ImageBuffer* GetImageBuffer() const = 0;
virtual bool HasImageBuffer() const { return false; }
virtual ImageBuffer* GetImageBuffer() const {
NOTREACHED();
return nullptr;
};
virtual bool ParseColorOrCurrentColor(Color&,
const String& color_string) const = 0;
......@@ -369,6 +372,11 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
virtual void DidInvokeGPUReadbackInCurrentFrame() {}
virtual bool IsPaint2D() const { return false; }
virtual void WillOverwriteCanvas() {
if (HasImageBuffer()) {
GetImageBuffer()->WillOverwriteCanvas();
}
}
private:
void RealizeSaves();
......
......@@ -371,13 +371,6 @@ void CanvasRenderingContext2D::DidDraw(const SkIRect& dirty_rect) {
if (dirty_rect.isEmpty())
return;
if (CanvasHeuristicParameters::kBlurredShadowsAreExpensive &&
GetState().ShouldDrawShadows() && GetState().ShadowBlur() > 0) {
ImageBuffer* buffer = GetImageBuffer();
if (buffer)
buffer->SetHasExpensiveOp();
}
CanvasRenderingContext::DidDraw(dirty_rect);
}
......
......@@ -14,9 +14,7 @@
#include "platform/bindings/ScriptState.h"
#include "platform/bindings/V8BindingMacros.h"
#include "platform/bindings/V8ObjectConstructor.h"
#include "platform/graphics/ImageBuffer.h"
#include "platform/graphics/PaintGeneratedImage.h"
#include "platform/graphics/RecordingImageBufferSurface.h"
#include "platform/wtf/PtrUtil.h"
namespace blink {
......@@ -99,10 +97,7 @@ scoped_refptr<Image> CSSPaintDefinition::Paint(
}
PaintRenderingContext2D* rendering_context = PaintRenderingContext2D::Create(
ImageBuffer::Create(WTF::WrapUnique(new RecordingImageBufferSurface(
container_size, RecordingImageBufferSurface::kDisallowFallback,
color_params))),
context_settings_, zoom);
container_size, color_params, context_settings_, zoom);
PaintSize* paint_size = PaintSize::Create(specified_size);
StylePropertyMapReadonly* style_map =
FilteredComputedStylePropertyMap::Create(layout_object.GetNode(),
......@@ -130,8 +125,8 @@ scoped_refptr<Image> CSSPaintDefinition::Paint(
return nullptr;
}
return PaintGeneratedImage::Create(
rendering_context->GetImageBuffer()->GetRecord(), container_size);
return PaintGeneratedImage::Create(rendering_context->GetRecord(),
container_size);
}
void CSSPaintDefinition::MaybeCreatePaintInstance() {
......
......@@ -4,39 +4,58 @@
#include "modules/csspaint/PaintRenderingContext2D.h"
#include "platform/graphics/ImageBuffer.h"
#include "platform/graphics/paint/PaintCanvas.h"
#include <memory>
namespace blink {
PaintRenderingContext2D::PaintRenderingContext2D(
std::unique_ptr<ImageBuffer> image_buffer,
const IntSize& container_size,
const CanvasColorParams& color_params,
const PaintRenderingContext2DSettings& context_settings,
float zoom)
: image_buffer_(std::move(image_buffer)),
: container_size_(container_size),
color_params_(color_params),
context_settings_(context_settings) {
InitializePaintRecorder();
clip_antialiasing_ = kAntiAliased;
ModifiableState().SetShouldAntialias(true);
// RecordingImageBufferSurface doesn't call ImageBufferSurface::clear
// explicitly.
DCHECK(image_buffer_);
image_buffer_->Canvas()->clear(context_settings.alpha() ? SK_ColorTRANSPARENT
: SK_ColorBLACK);
image_buffer_->DidDraw(FloatRect(0, 0, Width(), Height()));
Canvas()->clear(context_settings.alpha() ? SK_ColorTRANSPARENT
: SK_ColorBLACK);
did_record_draw_commands_in_paint_recorder_ = true;
Canvas()->scale(zoom, zoom);
}
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 {
DCHECK(image_buffer_);
return image_buffer_->Size().Width();
return container_size_.Width();
}
int PaintRenderingContext2D::Height() const {
DCHECK(image_buffer_);
return image_buffer_->Size().Height();
return container_size_.Height();
}
bool PaintRenderingContext2D::ParseColorOrCurrentColor(
......@@ -50,17 +69,11 @@ bool PaintRenderingContext2D::ParseColorOrCurrentColor(
}
PaintCanvas* PaintRenderingContext2D::DrawingCanvas() const {
return image_buffer_->Canvas();
return Canvas();
}
PaintCanvas* PaintRenderingContext2D::ExistingDrawingCanvas() const {
DCHECK(image_buffer_);
return image_buffer_->Canvas();
}
void PaintRenderingContext2D::DidDraw(const SkIRect& dirty_rect) {
DCHECK(image_buffer_);
return image_buffer_->DidDraw(SkRect::Make(dirty_rect));
return Canvas();
}
void PaintRenderingContext2D::ValidateStateStack() const {
......@@ -80,4 +93,25 @@ sk_sp<PaintFilter> PaintRenderingContext2D::StateGetFilter() {
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
......@@ -10,7 +10,6 @@
#include "modules/canvas/canvas2d/BaseRenderingContext2D.h"
#include "modules/csspaint/PaintRenderingContext2DSettings.h"
#include "platform/bindings/ScriptWrappable.h"
#include "platform/graphics/ImageBuffer.h"
namespace blink {
......@@ -25,10 +24,11 @@ class MODULES_EXPORT PaintRenderingContext2D : public ScriptWrappable,
public:
static PaintRenderingContext2D* Create(
std::unique_ptr<ImageBuffer> image_buffer,
const IntSize& container_size,
const CanvasColorParams& color_params,
const PaintRenderingContext2DSettings& context_settings,
float zoom) {
return new PaintRenderingContext2D(std::move(image_buffer),
return new PaintRenderingContext2D(container_size, color_params,
context_settings, zoom);
}
......@@ -37,8 +37,6 @@ class MODULES_EXPORT PaintRenderingContext2D : public ScriptWrappable,
BaseRenderingContext2D::Trace(visitor);
}
// BaseRenderingContext2D
// PaintRenderingContext2D doesn't have any pixel readback so the origin
// is always clean, and unable to taint it.
bool OriginClean() const final { return true; }
......@@ -50,16 +48,13 @@ class MODULES_EXPORT PaintRenderingContext2D : public ScriptWrappable,
int Width() 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;
PaintCanvas* DrawingCanvas() const final;
PaintCanvas* ExistingDrawingCanvas() const final;
void DisableDeferral(DisableDeferralReason) final {}
void DidDraw(const SkIRect& dirty_rect) final;
void DidDraw(const SkIRect&) final;
bool StateHasFilter() final;
sk_sp<PaintFilter> StateGetFilter() final;
......@@ -72,16 +67,27 @@ class MODULES_EXPORT PaintRenderingContext2D : public ScriptWrappable,
// PaintRenderingContext2D cannot lose it's context.
bool isContextLost() const final { return false; }
sk_sp<PaintRecord> GetRecord();
protected:
bool IsPaint2D() const override { return true; }
void WillOverwriteCanvas() override;
private:
PaintRenderingContext2D(std::unique_ptr<ImageBuffer>,
PaintRenderingContext2D(const IntSize& container_size,
const CanvasColorParams&,
const PaintRenderingContext2DSettings&,
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_;
bool did_record_draw_commands_in_paint_recorder_;
};
} // namespace blink
......
......@@ -25,7 +25,7 @@ void PaintRenderingContext2DTest::SetUp() {
PaintRenderingContext2DSettings context_settings;
context_settings.setAlpha(false);
ctx_ = PaintRenderingContext2D::Create(
ImageBuffer::Create(IntSize(kWidth, kHeight)), context_settings, kZoom);
IntSize(kWidth, kHeight), CanvasColorParams(), context_settings, kZoom);
}
void TrySettingStrokeStyle(PaintRenderingContext2D* ctx,
......
......@@ -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.
This method returns the `PaintGeneratedImage`.
The `PaintRecord` is produced from a `RecordingImageBufferSurface`.
### Style Invalidation
The `CSSPaintDefinition` keeps a list of both native and custom properties it will invalidate on.
......
......@@ -977,8 +977,6 @@ jumbo_component("platform") {
"graphics/PlaceholderImage.h",
"graphics/ProfilingCanvas.cpp",
"graphics/ProfilingCanvas.h",
"graphics/RecordingImageBufferSurface.cpp",
"graphics/RecordingImageBufferSurface.h",
"graphics/ReplayingCanvas.cpp",
"graphics/ReplayingCanvas.h",
"graphics/ScopedInterpolationQuality.h",
......@@ -1816,7 +1814,6 @@ jumbo_source_set("blink_platform_unittests_sources") {
"graphics/HighContrastImageClassifierTest.cpp",
"graphics/ImageBufferTest.cpp",
"graphics/PaintInvalidationReasonTest.cpp",
"graphics/RecordingImageBufferSurfaceTest.cpp",
"graphics/VideoFrameSubmitterTest.cpp",
"graphics/compositing/CompositedLayerRasterInvalidatorTest.cpp",
"graphics/compositing/PaintArtifactCompositorTest.cpp",
......
......@@ -25,43 +25,10 @@ enum {
// containing layer is the object of a paint invalidation.
kExpensiveOverdrawThreshold = 10,
kExpensivePathPointCount = 50,
kSVGImageSourcesAreExpensive = 1,
kConcavePathsAreExpensive = 1,
kComplexClipsAreExpensive = 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
//===========================================
......
......@@ -17,12 +17,10 @@ class PLATFORM_EXPORT CanvasMetrics {
enum CanvasContextUsage {
kCanvasCreated = 0,
kGPUAccelerated2DCanvasImageBufferCreated = 1,
kDisplayList2DCanvasImageBufferCreated = 2,
kUnaccelerated2DCanvasImageBufferCreated = 3,
kAccelerated2DCanvasGPUContextLost = 4,
kUnaccelerated2DCanvasImageBufferCreationFailed = 5,
kGPUAccelerated2DCanvasImageBufferCreationFailed = 6,
kDisplayList2DCanvasFallbackToRaster = 7,
kGPUAccelerated2DCanvasDeferralDisabled = 8,
kGPUAccelerated2DCanvasSurfaceCreationFailed = 9,
kNumberOfUsages
......
......@@ -39,7 +39,6 @@
#include "platform/geometry/IntRect.h"
#include "platform/graphics/CanvasHeuristicParameters.h"
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/RecordingImageBufferSurface.h"
#include "platform/graphics/StaticBitmapImage.h"
#include "platform/graphics/UnacceleratedImageBufferSurface.h"
#include "platform/graphics/gpu/DrawingBuffer.h"
......@@ -400,18 +399,6 @@ void ImageBuffer::SetSurface(std::unique_ptr<ImageBufferSurface> surface) {
if (!image)
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->SetImageBuffer(this);
surface_ = std::move(surface);
......
......@@ -84,9 +84,6 @@ class PLATFORM_EXPORT ImageBuffer {
static bool CanCreateImageBuffer(const IntSize&);
const IntSize& Size() const { return surface_->Size(); }
bool IsAccelerated() const { return surface_->IsAccelerated(); }
bool IsRecording() const { return surface_->IsRecording(); }
void SetHasExpensiveOp() { surface_->SetHasExpensiveOp(); }
bool IsExpensiveToPaint() const { return surface_->IsExpensiveToPaint(); }
void PrepareSurfaceForPaintingIfNeeded() {
surface_->PrepareSurfaceForPaintingIfNeeded();
}
......
......@@ -70,8 +70,6 @@ class PLATFORM_EXPORT ImageBufferSurface {
virtual bool Restore() { return false; }
virtual WebLayer* Layer() { return nullptr; }
virtual bool IsAccelerated() const { return false; }
virtual bool IsRecording() const { return false; }
virtual bool IsExpensiveToPaint() { return false; }
virtual void SetFilterQuality(SkFilterQuality) {}
virtual void SetIsHidden(bool) {}
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.
#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