summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc')
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc124
1 files changed, 93 insertions, 31 deletions
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 4489838b4ed..1e3ed7bc5c6 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -114,6 +114,10 @@ constexpr int kDefaultCanvasHeight = 150;
constexpr int kUndefinedQualityValue = -1.0;
constexpr int kMinimumAccelerated2dCanvasSize = 128 * 129;
+// A default size used for canvas memory allocation when canvas size is greater
+// than 2^20.
+constexpr uint32_t kMaximumCanvasSize = 2 << 20;
+
} // namespace
HTMLCanvasElement::HTMLCanvasElement(Document& document)
@@ -138,9 +142,10 @@ HTMLCanvasElement::~HTMLCanvasElement() {
}
void HTMLCanvasElement::Dispose() {
- if (OffscreenCanvasFrame()) {
- ReleaseOffscreenCanvasFrame();
- }
+ // We need to record metrics before we dispose of anything
+ if (context_)
+ UMA_HISTOGRAM_BOOLEAN("Blink.Canvas.HasRendered", bool(ResourceProvider()));
+
// It's possible that the placeholder frame has been disposed but its ID still
// exists. Make sure that it gets unregistered here
UnregisterPlaceholderCanvas();
@@ -150,12 +155,8 @@ void HTMLCanvasElement::Dispose() {
DiscardResourceProvider();
if (context_) {
- UMA_HISTOGRAM_BOOLEAN("Blink.Canvas.HasRendered", bool(ResourceProvider()));
- if (context_->Host()) {
- UMA_HISTOGRAM_BOOLEAN("Blink.Canvas.IsComposited",
- context_->IsComposited());
+ if (context_->Host())
context_->DetachHost();
- }
context_ = nullptr;
}
@@ -286,9 +287,9 @@ CanvasRenderingContext* HTMLCanvasElement::GetCanvasRenderingContext(
auto* old_contents_cc_layer = ContentsCcLayer();
auto* result = GetCanvasRenderingContextInternal(type, attributes);
+ Document& doc = GetDocument();
if (IdentifiabilityStudySettings::Get()->ShouldSample(
IdentifiableSurface::Type::kCanvasRenderingContext)) {
- Document& doc = GetDocument();
IdentifiabilityMetricBuilder(doc.UkmSourceID())
.Set(IdentifiableSurface::FromTypeAndToken(
IdentifiableSurface::Type::kCanvasRenderingContext,
@@ -296,6 +297,10 @@ CanvasRenderingContext* HTMLCanvasElement::GetCanvasRenderingContext(
!!result)
.Record(doc.UkmRecorder());
}
+ if (attributes.color_space != kSRGBCanvasColorSpaceName ||
+ attributes.pixel_format != kUint8CanvasPixelFormatName) {
+ UseCounter::Count(doc, WebFeature::kCanvasUseColorSpace);
+ }
if (ContentsCcLayer() != old_contents_cc_layer)
OnContentsCcLayerChanged();
@@ -377,10 +382,16 @@ CanvasRenderingContext* HTMLCanvasElement::GetCanvasRenderingContextInternal(
}
if (context_->CreationAttributes().desynchronized) {
- CreateLayer();
+ if (!CreateLayer())
+ return nullptr;
SetNeedsUnbufferedInputEvents(true);
frame_dispatcher_ = std::make_unique<CanvasResourceDispatcher>(
- nullptr, surface_layer_bridge_->GetFrameSinkId().client_id(),
+ nullptr,
+ GetPage()
+ ->GetPageScheduler()
+ ->GetAgentGroupScheduler()
+ .CompositorTaskRunner(),
+ surface_layer_bridge_->GetFrameSinkId().client_id(),
surface_layer_bridge_->GetFrameSinkId().sink_id(),
CanvasResourceDispatcher::kInvalidPlaceholderCanvasId, size_);
// We don't actually need the begin frame signal when in low latency mode,
@@ -469,6 +480,12 @@ void HTMLCanvasElement::DidDraw() {
void HTMLCanvasElement::PreFinalizeFrame() {
RecordCanvasSizeToUMA(size_);
+ // PreFinalizeFrame indicates the end of a script task that may have rendered
+ // into the canvas, now is a good time to unlock cache entries.
+ auto* resource_provider = ResourceProvider();
+ if (resource_provider)
+ resource_provider->ReleaseLockedImages();
+
// Low-latency 2d canvases produce their frames after the resource gets single
// buffered.
if (LowLatencyEnabled() && !dirty_rect_.IsEmpty() &&
@@ -1060,6 +1077,32 @@ void HTMLCanvasElement::toBlob(V8BlobCallback* callback,
}
}
+bool HTMLCanvasElement::IsPresentationAttribute(
+ const QualifiedName& name) const {
+ if (name == html_names::kWidthAttr || name == html_names::kHeightAttr)
+ return true;
+ return HTMLElement::IsPresentationAttribute(name);
+}
+
+void HTMLCanvasElement::CollectStyleForPresentationAttribute(
+ const QualifiedName& name,
+ const AtomicString& value,
+ MutableCSSPropertyValueSet* style) {
+ if (name == html_names::kWidthAttr) {
+ if (FastHasAttribute(html_names::kHeightAttr)) {
+ const AtomicString& height = FastGetAttribute(html_names::kHeightAttr);
+ ApplyAspectRatioToStyle(value, height, style);
+ }
+ } else if (name == html_names::kHeightAttr) {
+ if (FastHasAttribute(html_names::kWidthAttr)) {
+ const AtomicString& width = FastGetAttribute(html_names::kWidthAttr);
+ ApplyAspectRatioToStyle(width, value, style);
+ }
+ } else {
+ HTMLElement::CollectStyleForPresentationAttribute(name, value, style);
+ }
+}
+
void HTMLCanvasElement::AddListener(CanvasDrawListener* listener) {
listeners_.insert(listener);
}
@@ -1100,9 +1143,8 @@ bool HTMLCanvasElement::ShouldAccelerate() const {
return false;
// The command line flag --disable-accelerated-2d-canvas toggles this option
- if (!RuntimeEnabledFeatures::Accelerated2dCanvasEnabled()) {
+ if (!RuntimeEnabledFeatures::Accelerated2dCanvasEnabled())
return false;
- }
// Webview crashes with accelerated small canvases (crbug.com/1004304)
// Experimenting to see if this still causes crashes (crbug.com/1136603)
@@ -1393,7 +1435,7 @@ ScriptPromise HTMLCanvasElement::CreateImageBitmap(
void HTMLCanvasElement::SetOffscreenCanvasResource(
scoped_refptr<CanvasResource> image,
- unsigned resource_id) {
+ viz::ResourceId resource_id) {
OffscreenCanvasPlaceholder::SetOffscreenCanvasResource(std::move(image),
resource_id);
SetSize(OffscreenCanvasFrame()->Size());
@@ -1484,20 +1526,23 @@ String HTMLCanvasElement::GetIdFromControl(const Element* element) {
return String();
}
-void HTMLCanvasElement::CreateLayer() {
+bool HTMLCanvasElement::CreateLayer() {
DCHECK(!surface_layer_bridge_);
LocalFrame* frame = GetDocument().GetFrame();
// We do not design transferControlToOffscreen() for frame-less HTML canvas.
- if (frame) {
- surface_layer_bridge_ = std::make_unique<::blink::SurfaceLayerBridge>(
- frame->GetPage()->GetChromeClient().GetFrameSinkId(frame),
- ::blink::SurfaceLayerBridge::ContainsVideo::kNo, this,
- base::NullCallback());
- // Creates a placeholder layer first before Surface is created.
- surface_layer_bridge_->CreateSolidColorLayer();
- // This may cause the canvas to be composited.
- SetNeedsCompositingUpdate();
- }
+ if (!frame)
+ return false;
+
+ surface_layer_bridge_ = std::make_unique<::blink::SurfaceLayerBridge>(
+ frame->GetPage()->GetChromeClient().GetFrameSinkId(frame),
+ ::blink::SurfaceLayerBridge::ContainsVideo::kNo, this,
+ base::NullCallback());
+ // Creates a placeholder layer first before Surface is created.
+ surface_layer_bridge_->CreateSolidColorLayer();
+ // This may cause the canvas to be composited.
+ SetNeedsCompositingUpdate();
+
+ return true;
}
void HTMLCanvasElement::OnWebLayerUpdated() {
@@ -1539,12 +1584,15 @@ void HTMLCanvasElement::UpdateMemoryUsage() {
const int bytes_per_pixel = ColorParams().BytesPerPixel();
intptr_t gpu_memory_usage = 0;
+ uint32_t canvas_width = std::min(kMaximumCanvasSize, width());
+ uint32_t canvas_height = std::min(kMaximumCanvasSize, height());
+
if (gpu_buffer_count) {
// Switch from cpu mode to gpu mode
base::CheckedNumeric<intptr_t> checked_usage =
gpu_buffer_count * bytes_per_pixel;
- checked_usage *= width();
- checked_usage *= height();
+ checked_usage *= canvas_width;
+ checked_usage *= canvas_height;
gpu_memory_usage =
checked_usage.ValueOrDefault(std::numeric_limits<intptr_t>::max());
}
@@ -1553,8 +1601,8 @@ void HTMLCanvasElement::UpdateMemoryUsage() {
// in all cases.
base::CheckedNumeric<intptr_t> checked_usage =
non_gpu_buffer_count * bytes_per_pixel;
- checked_usage *= width();
- checked_usage *= height();
+ checked_usage *= canvas_width;
+ checked_usage *= canvas_height;
checked_usage += gpu_memory_usage;
intptr_t externally_allocated_memory =
checked_usage.ValueOrDefault(std::numeric_limits<intptr_t>::max());
@@ -1607,8 +1655,22 @@ void HTMLCanvasElement::ReplaceExisting2dLayerBridge(
// TODO(jochin): Consider using ResourceProvider()->RestoreBackBuffer() here
// to avoid all of this clip stack manipulation.
- if (image)
- canvas2d_bridge_->DrawFullImage(image->PaintImageForCurrentFrame());
+ if (image) {
+ auto paint_image = image->PaintImageForCurrentFrame();
+ if (!canvas2d_bridge_->IsAccelerated() && paint_image.IsTextureBacked()) {
+ // If new bridge is unaccelrated we must read back |paint_image| here.
+ // DrawFullImage will record the image and potentially raster on a worker
+ // thread, but texture backed PaintImages can't be used on a different
+ // thread.
+ auto sk_image = paint_image.GetSwSkImage();
+ auto content_id = paint_image.GetContentIdForFrame(0);
+ auto builder =
+ cc::PaintImageBuilder::WithProperties(std::move(paint_image))
+ .set_image(sk_image, content_id);
+ paint_image = builder.TakePaintImage();
+ }
+ canvas2d_bridge_->DrawFullImage(paint_image);
+ }
RestoreCanvasMatrixClipStack(canvas);
canvas2d_bridge_->DidRestoreCanvasMatrixClipStack(canvas);