diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/core/html/canvas')
23 files changed, 682 insertions, 330 deletions
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.cc new file mode 100644 index 00000000000..f96458f4847 --- /dev/null +++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.cc @@ -0,0 +1,108 @@ +// Copyright 2021 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 "third_party/blink/renderer/core/html/canvas/canvas_image_source.h" + +#include "gpu/command_buffer/client/shared_image_interface.h" +#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h" +#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h" + +namespace blink { +namespace { + +std::unique_ptr<CanvasResourceProvider> CreateProvider( + base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider, + const SkImageInfo& info, + const scoped_refptr<StaticBitmapImage>& source_image, + bool fallback_to_software) { + IntSize size(info.width(), info.height()); + + const cc::PaintFlags::FilterQuality filter_quality = + cc::PaintFlags::FilterQuality::kLow; + const CanvasResourceParams resource_params(info); + + if (context_provider) { + uint32_t usage_flags = + context_provider->ContextProvider() + ->SharedImageInterface() + ->UsageForMailbox(source_image->GetMailboxHolder().mailbox); + auto resource_provider = CanvasResourceProvider::CreateSharedImageProvider( + size, filter_quality, resource_params, + CanvasResourceProvider::ShouldInitialize::kNo, context_provider, + RasterMode::kGPU, source_image->IsOriginTopLeft(), usage_flags); + if (resource_provider) + return resource_provider; + + if (!fallback_to_software) + return nullptr; + } + + return CanvasResourceProvider::CreateBitmapProvider( + size, filter_quality, resource_params, + CanvasResourceProvider::ShouldInitialize::kNo); +} + +} // anonymous namespace + +scoped_refptr<StaticBitmapImage> GetImageWithAlphaDisposition( + scoped_refptr<StaticBitmapImage>&& image, + const AlphaDisposition alpha_disposition) { + if (!image) + return nullptr; + + SkAlphaType alpha_type = (alpha_disposition == kPremultiplyAlpha) + ? kPremul_SkAlphaType + : kUnpremul_SkAlphaType; + PaintImage paint_image = image->PaintImageForCurrentFrame(); + if (!paint_image) + return nullptr; + + // Only if the content alphaType is not important or it will be recorded and + // be handled in following step, kDontChangeAlpha could be provided to save + // the conversion here. + if (paint_image.GetAlphaType() == alpha_type || + alpha_disposition == kDontChangeAlpha) + return std::move(image); + + SkImageInfo info = + image->PaintImageForCurrentFrame().GetSkImageInfo().makeAlphaType( + alpha_type); + + // To premul, draw the unpremul image on a surface to avoid GPU read back if + // image is texture backed. + if (alpha_type == kPremul_SkAlphaType) { + auto resource_provider = CreateProvider( + image->IsTextureBacked() ? image->ContextProviderWrapper() : nullptr, + info, image, true /* fallback_to_software */); + if (!resource_provider) + return nullptr; + + cc::PaintFlags paint; + paint.setBlendMode(SkBlendMode::kSrc); + resource_provider->Canvas()->drawImage(image->PaintImageForCurrentFrame(), + 0, 0, SkSamplingOptions(), &paint); + return resource_provider->Snapshot(image->CurrentFrameOrientation()); + } + + // To unpremul, read back the pixels. + // TODO(crbug.com/1197369): we should try to keep the output resource(image) + // in GPU when premultiply-alpha or unpremultiply-alpha transforms is + // required. + if (paint_image.GetSkImageInfo().isEmpty()) + return nullptr; + + sk_sp<SkData> dst_pixels = TryAllocateSkData(info.computeMinByteSize()); + if (!dst_pixels) + return nullptr; + + uint8_t* writable_pixels = static_cast<uint8_t*>(dst_pixels->writable_data()); + size_t image_row_bytes = static_cast<size_t>(info.minRowBytes64()); + bool read_successful = + paint_image.readPixels(info, writable_pixels, image_row_bytes, 0, 0); + DCHECK(read_successful); + return StaticBitmapImage::Create(std::move(dst_pixels), info, + image->CurrentFrameOrientation()); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.h b/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.h index cd7d65ec15b..827648a6e2a 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.h +++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.h @@ -32,6 +32,7 @@ #include "third_party/blink/renderer/platform/geometry/float_size.h" #include "third_party/blink/renderer/platform/graphics/graphics_types.h" #include "third_party/blink/renderer/platform/graphics/image_orientation.h" +#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" namespace blink { @@ -47,10 +48,18 @@ enum SourceImageStatus { kInvalidSourceImageStatus, }; +// This is the helper function to get the canvas image with a +// specific alpha op requirements. +scoped_refptr<StaticBitmapImage> GetImageWithAlphaDisposition( + scoped_refptr<StaticBitmapImage>&&, + const AlphaDisposition); + class CORE_EXPORT CanvasImageSource { public: - virtual scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*, - const FloatSize&) = 0; + virtual scoped_refptr<Image> GetSourceImageForCanvas( + SourceImageStatus*, + const FloatSize&, + const AlphaDisposition alpha_disposition = kPremultiplyAlpha) = 0; // IMPORTANT: Result must be independent of whether destinationContext is // already tainted because this function may be used to determine whether @@ -67,6 +76,16 @@ class CORE_EXPORT CanvasImageSource { virtual bool IsOffscreenCanvas() const { return false; } virtual bool IsVideoFrame() const { return false; } + // TODO(crbug.com/dawn/1197369): Implement check + // the usability of the image argument. + // Ref the spec here: + // https://html.spec.whatwg.org/multipage/canvas.html#check-the-usability-of-the-image-argument + virtual bool IsNeutered() const { return false; } + + // Spec about placeholder context: + // https://html.spec.whatwg.org/multipage/canvas.html#offscreencanvas-placeholder + virtual bool IsPlaceholder() const { return false; } + virtual FloatSize ElementSize(const FloatSize& default_object_size, const RespectImageOrientationEnum) const = 0; virtual FloatSize DefaultDestinationSize( diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_performance_monitor.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_performance_monitor.cc index 41dc7fbadfd..a7e6ea145ae 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_performance_monitor.cc +++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_performance_monitor.cc @@ -5,6 +5,7 @@ #include "third_party/blink/renderer/core/html/canvas/canvas_performance_monitor.h" #include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" #include "base/trace_event/trace_event.h" #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h" @@ -18,27 +19,26 @@ using blink::CanvasResourceProvider; const char* const kHostTypeName_Canvas = ".Canvas"; const char* const kHostTypeName_OffscreenCanvas = ".OffscreenCanvas"; -const char* const kThreadTypeName_Main = ".MainThread"; -const char* const kThreadTypeName_Worker = ".Worker"; - -const char* const kContextTypeName_2D = ".2D"; +const char* const kContextTypeName_2D_Accelerated = ".2D.Accelerated"; +const char* const kContextTypeName_2D_Unaccelerated = ".2D.Unaccelerated"; const char* const kContextTypeName_WebGL = ".WebGL"; const char* const kContextTypeName_WebGL2 = ".WebGL2"; const char* const kContextTypeName_WebGPU = ".WebGPU"; const char* const kContextTypeName_ImageBitmap = ".ImageBitmap"; -const char* const kResourceTypeName_Bitmap = ".Bitmap"; -const char* const kResourceTypeName_SharedBitmap = ".SharedBitmap"; -const char* const kResourceTypeName_SharedImage = ".SharedImage"; -const char* const kResourceTypeName_PassThrough = ".PassThrough"; -const char* const kResourceTypeName_SwapChain = ".SwapChain"; -const char* const kResourceTypeName_SkiaDawnSharedImage = - ".SkiaDawnSharedImage"; - const char* const kFilterName_All = ".All"; const char* const kFilterName_Animation = ".Animation"; +const char* const kFilterName_Path = ".Path"; +const char* const kFilterName_Image = ".Image"; +const char* const kFilterName_ImageData = ".ImageData"; +const char* const kFilterName_Rectangle = ".Rectangle"; +const char* const kFilterName_Text = ".Text"; +const char* const kFilterName_DrawArrays = ".DrawArrays"; +const char* const kFilterName_DrawElements = ".DrawElements"; const char* const kMeasurementName_RenderTaskDuration = ".RenderTaskDuration"; +const char* const kMeasurementName_PartitionAlloc = ".PartitionAlloc"; +const char* const kMeasurementName_BlinkGC = ".BlinkGC"; // The inverse of the probability that a given task will be measured. // I.e. a value of X means that each task has a probability 1/X of being @@ -53,22 +53,20 @@ class RenderingContextDescriptionCodec { explicit RenderingContextDescriptionCodec(const uint32_t& key); bool IsOffscreen() const { return key_.get<IsOffscreenField>(); } + bool IsAccelerated() const { return key_.get<IsAcceleratedField>(); } CanvasRenderingContext::ContextType ContextType() const; - CanvasResourceProvider::ResourceProviderType ResourceType() const; uint32_t GetKey() const { return key_.bits(); } bool IsValid() const { return is_valid_; } const char* GetHostTypeName() const; - const char* GetThreadTypeName() const; const char* GetContextTypeName() const; - const char* GetResourceTypeName() const; private: using Key = WTF::SingleThreadedBitField<uint32_t>; using IsOffscreenField = Key::DefineFirstValue<bool, 1>; - using ContextTypeField = IsOffscreenField::DefineNextValue<uint32_t, 8>; - using ResourceTypeField = ContextTypeField::DefineNextValue<uint32_t, 8>; - using PaddingField = ResourceTypeField::DefineNextValue<bool, 1>; + using IsAcceleratedField = IsOffscreenField::DefineNextValue<bool, 1>; + using ContextTypeField = IsAcceleratedField::DefineNextValue<uint32_t, 8>; + using PaddingField = ContextTypeField::DefineNextValue<bool, 1>; Key key_; bool is_valid_; @@ -76,13 +74,13 @@ class RenderingContextDescriptionCodec { RenderingContextDescriptionCodec::RenderingContextDescriptionCodec( const CanvasRenderingContext* context) { - is_valid_ = context->Host() && context->Host()->ResourceProvider(); + is_valid_ = context->Host(); if (!is_valid_) return; key_.set<IsOffscreenField>(context->Host()->IsOffscreenCanvas()); + key_.set<IsAcceleratedField>(context->IsAccelerated()); key_.set<ContextTypeField>(context->GetContextType()); - key_.set<ResourceTypeField>(context->Host()->ResourceProvider()->GetType()); // The padding field ensures at least one bit is set in the key in order // to avoid a key == 0, which is not supported by WTF::HashSet key_.set<PaddingField>(true); @@ -98,30 +96,21 @@ RenderingContextDescriptionCodec::ContextType() const { key_.get<ContextTypeField>()); } -CanvasResourceProvider::ResourceProviderType -RenderingContextDescriptionCodec::ResourceType() const { - return static_cast<CanvasResourceProvider::ResourceProviderType>( - key_.get<ResourceTypeField>()); -} - const char* RenderingContextDescriptionCodec::GetHostTypeName() const { return IsOffscreen() ? kHostTypeName_OffscreenCanvas : kHostTypeName_Canvas; } -const char* RenderingContextDescriptionCodec::GetThreadTypeName() const { - return WTF::IsMainThread() ? kThreadTypeName_Main : kThreadTypeName_Worker; -} - const char* RenderingContextDescriptionCodec::GetContextTypeName() const { switch (ContextType()) { case CanvasRenderingContext::kContext2D: - return kContextTypeName_2D; + return IsAccelerated() ? kContextTypeName_2D_Accelerated + : kContextTypeName_2D_Unaccelerated; case CanvasRenderingContext::kContextExperimentalWebgl: case CanvasRenderingContext::kContextWebgl: return kContextTypeName_WebGL; case CanvasRenderingContext::kContextWebgl2: return kContextTypeName_WebGL2; - case CanvasRenderingContext::kContextGPUPresent: + case CanvasRenderingContext::kContextWebGPU: return kContextTypeName_WebGPU; case CanvasRenderingContext::kContextImageBitmap: return kContextTypeName_ImageBitmap; @@ -131,26 +120,6 @@ const char* RenderingContextDescriptionCodec::GetContextTypeName() const { } } -const char* RenderingContextDescriptionCodec::GetResourceTypeName() const { - switch (ResourceType()) { - case CanvasResourceProvider::kBitmap: - return kResourceTypeName_Bitmap; - case CanvasResourceProvider::kSharedBitmap: - return kResourceTypeName_SharedBitmap; - case CanvasResourceProvider::kSharedImage: - return kResourceTypeName_SharedImage; - case CanvasResourceProvider::kPassThrough: - return kResourceTypeName_PassThrough; - case CanvasResourceProvider::kSwapChain: - return kResourceTypeName_SwapChain; - case CanvasResourceProvider::kSkiaDawnSharedImage: - return kResourceTypeName_SkiaDawnSharedImage; - default: - NOTREACHED(); - return ""; - } -} - } // unnamed namespace namespace blink { @@ -169,15 +138,17 @@ void CanvasPerformanceMonitor::CurrentTaskDrawsToContext( // canvases per render task. measure_current_task_ = !(task_counter_++ % kSamplingProbabilityInv); - if (context->Host() && context->Host()->GetTopExecutionContext() && - context->Host() - ->GetTopExecutionContext() - ->IsInRequestAnimationFrame()) { - call_type_ = CallType::kAnimation; - } else { - // TODO(crbug.com/1206028): Add support for CallType::kUserInput - call_type_ = CallType::kOther; + if (LIKELY(!measure_current_task_)) + return; + + call_type_ = CallType::kOther; + if (context->Host()) { + ExecutionContext* ec = context->Host()->GetTopExecutionContext(); + if (ec && ec->IsInRequestAnimationFrame()) { + call_type_ = CallType::kAnimation; + } } + // TODO(crbug.com/1206028): Add support for CallType::kUserInput } if (LIKELY(!measure_current_task_)) @@ -204,6 +175,11 @@ void CanvasPerformanceMonitor::RecordMetrics(TimeTicks start_time, TimeTicks end_time) { TRACE_EVENT0("blink", "CanvasPerformanceMonitor::RecordMetrics"); TimeDelta elapsed_time = end_time - start_time; + constexpr size_t kKiloByte = 1024; + size_t partition_alloc_kb = WTF::Partitions::TotalActiveBytes() / kKiloByte; + size_t blink_gc_alloc_kb = + ProcessHeap::TotalAllocatedObjectSize() / kKiloByte; + while (!rendering_context_descriptions_.IsEmpty()) { RenderingContextDescriptionCodec desc( rendering_context_descriptions_.TakeAny()); @@ -213,10 +189,9 @@ void CanvasPerformanceMonitor::RecordMetrics(TimeTicks start_time, // info. WTF::String histogram_name_prefix = WTF::String("Blink") + desc.GetHostTypeName(); - WTF::String histogram_name_radical = WTF::String(desc.GetThreadTypeName()) + - desc.GetContextTypeName() + - desc.GetResourceTypeName(); + WTF::String histogram_name_radical = WTF::String(desc.GetContextTypeName()); + // Render task duration metric for all render tasks. { WTF::String histogram_name = histogram_name_prefix + kMeasurementName_RenderTaskDuration + @@ -225,6 +200,7 @@ void CanvasPerformanceMonitor::RecordMetrics(TimeTicks start_time, elapsed_time); } + // Render task duration metric for rAF callbacks only. if (call_type_ == CallType::kAnimation) { WTF::String histogram_name = histogram_name_prefix + kMeasurementName_RenderTaskDuration + @@ -232,7 +208,85 @@ void CanvasPerformanceMonitor::RecordMetrics(TimeTicks start_time, base::UmaHistogramMicrosecondsTimes(histogram_name.Latin1(), elapsed_time); } + + // Filtered histograms that apply to 2D canvases + if (desc.ContextType() == CanvasRenderingContext::kContext2D) { + if (draw_types_ & static_cast<uint32_t>(DrawType::kPath)) { + WTF::String histogram_name = histogram_name_prefix + + kMeasurementName_RenderTaskDuration + + histogram_name_radical + kFilterName_Path; + base::UmaHistogramMicrosecondsTimes(histogram_name.Latin1(), + elapsed_time); + } + if (draw_types_ & static_cast<uint32_t>(DrawType::kImage)) { + WTF::String histogram_name = histogram_name_prefix + + kMeasurementName_RenderTaskDuration + + histogram_name_radical + kFilterName_Image; + base::UmaHistogramMicrosecondsTimes(histogram_name.Latin1(), + elapsed_time); + } + if (draw_types_ & static_cast<uint32_t>(DrawType::kImageData)) { + WTF::String histogram_name = + histogram_name_prefix + kMeasurementName_RenderTaskDuration + + histogram_name_radical + kFilterName_ImageData; + base::UmaHistogramMicrosecondsTimes(histogram_name.Latin1(), + elapsed_time); + } + if (draw_types_ & static_cast<uint32_t>(DrawType::kText)) { + WTF::String histogram_name = histogram_name_prefix + + kMeasurementName_RenderTaskDuration + + histogram_name_radical + kFilterName_Text; + base::UmaHistogramMicrosecondsTimes(histogram_name.Latin1(), + elapsed_time); + } + if (draw_types_ & static_cast<uint32_t>(DrawType::kRectangle)) { + WTF::String histogram_name = + histogram_name_prefix + kMeasurementName_RenderTaskDuration + + histogram_name_radical + kFilterName_Rectangle; + base::UmaHistogramMicrosecondsTimes(histogram_name.Latin1(), + elapsed_time); + } + } else if (desc.ContextType() == CanvasRenderingContext::kContextWebgl || + desc.ContextType() == CanvasRenderingContext::kContextWebgl2 || + desc.ContextType() == + CanvasRenderingContext::kContextExperimentalWebgl) { + // Filtered histograms that apply to WebGL canvases + if (draw_types_ & static_cast<uint32_t>(DrawType::kDrawArrays)) { + WTF::String histogram_name = + histogram_name_prefix + kMeasurementName_RenderTaskDuration + + histogram_name_radical + kFilterName_DrawArrays; + base::UmaHistogramMicrosecondsTimes(histogram_name.Latin1(), + elapsed_time); + } + if (draw_types_ & static_cast<uint32_t>(DrawType::kDrawElements)) { + WTF::String histogram_name = + histogram_name_prefix + kMeasurementName_RenderTaskDuration + + histogram_name_radical + kFilterName_DrawElements; + base::UmaHistogramMicrosecondsTimes(histogram_name.Latin1(), + elapsed_time); + } + } + // TODO(junov) Add filtered histograms that apply to WebGPU canvases + + // PartitionAlloc heap size metric + { + WTF::String histogram_name = histogram_name_prefix + + kMeasurementName_PartitionAlloc + + histogram_name_radical; + base::UmaHistogramMemoryKB(histogram_name.Latin1(), + static_cast<int>(partition_alloc_kb)); + } + + // Blink garbage collected heap size metric + { + WTF::String histogram_name = histogram_name_prefix + + kMeasurementName_BlinkGC + + histogram_name_radical; + base::UmaHistogramMemoryKB(histogram_name.Latin1(), + static_cast<int>(blink_gc_alloc_kb)); + } } + } void CanvasPerformanceMonitor::DidProcessTask(TimeTicks start_time, @@ -244,14 +298,14 @@ void CanvasPerformanceMonitor::DidProcessTask(TimeTicks start_time, RecordMetrics(start_time, end_time); is_render_task_ = false; - draw_flags_ = 0; + draw_types_ = 0; } void CanvasPerformanceMonitor::ResetForTesting() { if (is_render_task_) Thread::Current()->RemoveTaskTimeObserver(this); is_render_task_ = false; - draw_flags_ = 0; + draw_types_ = 0; rendering_context_descriptions_.clear(); call_type_ = CallType::kOther; task_counter_ = 0; diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_performance_monitor.h b/chromium/third_party/blink/renderer/core/html/canvas/canvas_performance_monitor.h index acccbedc3c8..c487142c1d9 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_performance_monitor.h +++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_performance_monitor.h @@ -19,9 +19,30 @@ class CanvasRenderingContext; class CORE_EXPORT CanvasPerformanceMonitor : public base::sequence_manager::TaskTimeObserver { public: + // Flag bits that can be passed to DidDraw. + enum class DrawType { + kOther = 0, + + // It is allowed to re-number the elements of this enum + + // 2D context draw types + kPath = 1 << 0, + kImage = 1 << 1, + kText = 1 << 2, + kRectangle = 1 << 3, + kImageData = 1 << 4, + + // WebGL draw types + kDrawArrays = 1 << 5, + kDrawElements = 1 << 6, + }; + CanvasPerformanceMonitor() = default; void CurrentTaskDrawsToContext(CanvasRenderingContext*); + ALWAYS_INLINE void DidDraw(DrawType draw_type) { + draw_types_ |= static_cast<uint32_t>(draw_type); + } // Call this at the end of unit tests that use CanvasRenderingContext, to // reset state that may otherwise be leaked between tests. @@ -42,7 +63,7 @@ class CORE_EXPORT CanvasPerformanceMonitor }; HashSet<uint32_t> rendering_context_descriptions_; - uint32_t draw_flags_ = 0; + uint32_t draw_types_ = 0; CallType call_type_ = CallType::kOther; uint32_t task_counter_ = 0; bool is_render_task_ = false; diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc index ddb3721cd27..f404040c338 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc +++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc @@ -38,10 +38,12 @@ namespace blink { CanvasRenderingContext::CanvasRenderingContext( CanvasRenderingContextHost* host, - const CanvasContextCreationAttributesCore& attrs) + const CanvasContextCreationAttributesCore& attrs, + CanvasRenderingAPI canvas_rendering_API) : host_(host), color_params_(attrs.color_space, attrs.pixel_format, attrs.alpha), - creation_attributes_(attrs) {} + creation_attributes_(attrs), + canvas_rendering_type_(canvas_rendering_API) {} void CanvasRenderingContext::Dispose() { RenderTaskEnded(); @@ -58,14 +60,19 @@ void CanvasRenderingContext::Dispose() { } } -void CanvasRenderingContext::DidDraw(const SkIRect& dirty_rect) { - Host()->DidDraw(SkRect::Make(dirty_rect)); - DidDrawCommon(); -} +void CanvasRenderingContext::DidDraw( + const SkIRect& dirty_rect, + CanvasPerformanceMonitor::DrawType draw_type) { + Host()->DidDraw(dirty_rect); + + auto& monitor = GetCanvasPerformanceMonitor(); + monitor.DidDraw(draw_type); + if (did_draw_in_current_task_) + return; -void CanvasRenderingContext::DidDraw() { - Host()->DidDraw(); - DidDrawCommon(); + monitor.CurrentTaskDrawsToContext(this); + did_draw_in_current_task_ = true; + Thread::Current()->AddTaskObserver(this); } void CanvasRenderingContext::DidProcessTask( @@ -81,34 +88,33 @@ void CanvasRenderingContext::DidProcessTask( Host()->PostFinalizeFrame(); } -void CanvasRenderingContext::RecordUKMCanvasRenderingAPI( - CanvasRenderingAPI canvasRenderingAPI) { +void CanvasRenderingContext::RecordUKMCanvasRenderingAPI() { DCHECK(Host()); const auto& ukm_params = Host()->GetUkmParameters(); if (Host()->IsOffscreenCanvas()) { ukm::builders::ClientRenderingAPI(ukm_params.source_id) .SetOffscreenCanvas_RenderingContext( - static_cast<int>(canvasRenderingAPI)) + static_cast<int>(canvas_rendering_type_)) .Record(ukm_params.ukm_recorder); } else { ukm::builders::ClientRenderingAPI(ukm_params.source_id) - .SetCanvas_RenderingContext(static_cast<int>(canvasRenderingAPI)) + .SetCanvas_RenderingContext(static_cast<int>(canvas_rendering_type_)) .Record(ukm_params.ukm_recorder); } } -void CanvasRenderingContext::RecordUKMCanvasDrawnToRenderingAPI( - CanvasRenderingAPI canvasRenderingAPI) { +void CanvasRenderingContext::RecordUKMCanvasDrawnToRenderingAPI() { DCHECK(Host()); const auto& ukm_params = Host()->GetUkmParameters(); if (Host()->IsOffscreenCanvas()) { ukm::builders::ClientRenderingAPI(ukm_params.source_id) .SetOffscreenCanvas_RenderingContextDrawnTo( - static_cast<int>(canvasRenderingAPI)) + static_cast<int>(canvas_rendering_type_)) .Record(ukm_params.ukm_recorder); } else { ukm::builders::ClientRenderingAPI(ukm_params.source_id) - .SetCanvas_RenderingContextDrawnTo(static_cast<int>(canvasRenderingAPI)) + .SetCanvas_RenderingContextDrawnTo( + static_cast<int>(canvas_rendering_type_)) .Record(ukm_params.ukm_recorder); } } @@ -126,9 +132,10 @@ CanvasRenderingContext::ContextType CanvasRenderingContext::ContextTypeFromId( return kContextWebgl2; if (id == "bitmaprenderer") return kContextImageBitmap; - if (id == "gpupresent" && + // TODO(crbug.com/1229274): Remove 'gpupresent' type after deprecation period. + if ((id == "webgpu" || id == "gpupresent") && RuntimeEnabledFeatures::WebGPUEnabled(execution_context)) - return kContextGPUPresent; + return kContextWebGPU; return kContextTypeUnknown; } @@ -159,15 +166,7 @@ bool CanvasRenderingContext::WouldTaintOrigin(CanvasImageSource* image_source) { void CanvasRenderingContext::Trace(Visitor* visitor) const { visitor->Trace(host_); ScriptWrappable::Trace(visitor); -} - -void CanvasRenderingContext::DidDrawCommon() { - if (did_draw_in_current_task_) - return; - - GetCanvasPerformanceMonitor().CurrentTaskDrawsToContext(this); - did_draw_in_current_task_ = true; - Thread::Current()->AddTaskObserver(this); + ActiveScriptWrappable::Trace(visitor); } void CanvasRenderingContext::RenderTaskEnded() { diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h index e5af3dfca32..f591ed405a2 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h +++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h @@ -26,8 +26,8 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CANVAS_CANVAS_RENDERING_CONTEXT_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CANVAS_CANVAS_RENDERING_CONTEXT_H_ -#include "base/macros.h" #include "third_party/blink/public/common/privacy_budget/identifiable_token.h" +#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h" #include "third_party/blink/renderer/core/html/canvas/canvas_performance_monitor.h" @@ -51,11 +51,15 @@ class class V8UnionGPUCanvasContextOrImageBitmapRenderingContextOrOffscreenCanvasRenderingContext2DOrWebGL2RenderingContextOrWebGLRenderingContext; -class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable, - public Thread::TaskObserver { +class CORE_EXPORT CanvasRenderingContext + : public ScriptWrappable, + public ActiveScriptWrappable<CanvasRenderingContext>, + public Thread::TaskObserver { USING_PRE_FINALIZER(CanvasRenderingContext, Dispose); public: + CanvasRenderingContext(const CanvasRenderingContext&) = delete; + CanvasRenderingContext& operator=(const CanvasRenderingContext&) = delete; ~CanvasRenderingContext() override = default; // A Canvas can either be "2D" or "webgl" but never both. Requesting a context @@ -71,14 +75,14 @@ class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable, kContextImageBitmap = 5, kContextXRPresent = 6, // WebGL2Compute used to be 7. - kContextGPUPresent = 8, + kContextWebGPU = 8, // WebGPU kContextTypeUnknown = 9, kMaxValue = kContextTypeUnknown, }; // Correspond to CanvasRenderingAPI defined in // tools/metrics/histograms/enums.xml - enum CanvasRenderingAPI { + enum class CanvasRenderingAPI { k2D = 0, kWebgl = 1, kWebgl2 = 2, @@ -86,9 +90,39 @@ class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable, kWebgpu = 4, }; - void RecordUKMCanvasRenderingAPI(CanvasRenderingAPI canvasRenderingAPI); - void RecordUKMCanvasDrawnToRenderingAPI( - CanvasRenderingAPI canvasRenderingAPI); + bool IsRenderingContext2D() const { + return canvas_rendering_type_ == CanvasRenderingAPI::k2D; + } + bool IsImageBitmapRenderingContext() const { + return canvas_rendering_type_ == CanvasRenderingAPI::kBitmaprenderer; + } + bool IsWebGL() const { + return canvas_rendering_type_ == CanvasRenderingAPI::kWebgl || + canvas_rendering_type_ == CanvasRenderingAPI::kWebgl2; + } + bool IsWebGL2() const { + return canvas_rendering_type_ == CanvasRenderingAPI::kWebgl2; + } + bool IsWebGPU() const { + return canvas_rendering_type_ == CanvasRenderingAPI::kWebgpu; + } + + // ActiveScriptWrappable + // As this class inherits from ActiveScriptWrappable, as long as + // HasPendingActivity returns true, we can ensure that the Garbage Collector + // won't try to collect this class. This is needed specifically for the + // offscreencanvas use case. + bool HasPendingActivity() const override { return false; } + ExecutionContext* GetExecutionContext() const { + if (!Host()) + return nullptr; + return Host()->GetTopExecutionContext(); + } + + void RecordUKMCanvasRenderingAPI(); + + // This is only used in WebGL + void RecordUKMCanvasDrawnToRenderingAPI(); static ContextType ContextTypeFromId( const String& id, @@ -126,7 +160,6 @@ class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable, // called when the context is first displayed. virtual void SetIsBeingDisplayed(bool) = 0; virtual bool isContextLost() const { return true; } -#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) // TODO(fserb): remove AsV8RenderingContext and AsV8OffscreenRenderingContext. virtual V8UnionCanvasRenderingContext2DOrGPUCanvasContextOrImageBitmapRenderingContextOrWebGL2RenderingContextOrWebGLRenderingContext* AsV8RenderingContext() { @@ -138,22 +171,24 @@ class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable, NOTREACHED(); return nullptr; } -#else // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) - // TODO(fserb): remove SetCanvasGetContextResult. - virtual void SetCanvasGetContextResult(RenderingContext&) { NOTREACHED(); } - virtual void SetOffscreenCanvasGetContextResult(OffscreenRenderingContext&) { - NOTREACHED(); - } -#endif // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) virtual bool IsPaintable() const = 0; - virtual void DidDraw(const SkIRect& dirty_rect); - virtual void DidDraw(); + void DidDraw(CanvasPerformanceMonitor::DrawType draw_type) { + return DidDraw(Host() ? SkIRect::MakeWH(Host()->width(), Host()->height()) + : SkIRect::MakeEmpty(), + draw_type); + } + void DidDraw(const SkIRect& dirty_rect, CanvasPerformanceMonitor::DrawType); // Return true if the content is updated. virtual bool PaintRenderingResultsToCanvas(SourceDrawingBuffer) { return false; } + virtual bool CopyRenderingResultsFromDrawingBuffer(CanvasResourceProvider*, + SourceDrawingBuffer) { + return false; + } + virtual cc::Layer* CcLayer() const { return nullptr; } enum LostContextMode { @@ -169,6 +204,7 @@ class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable, kSyntheticLostContext, }; virtual void LoseContext(LostContextMode) {} + virtual void SendContextLostEventIfNeeded() {} // This method gets called at the end of script tasks that modified // the contents of the canvas (called didDraw). It marks the completion @@ -180,7 +216,6 @@ class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable, void WillProcessTask(const base::PendingTask&, bool) final {} // Canvas2D-specific interface - virtual bool IsRenderingContext2D() const { return false; } virtual void RestoreCanvasMatrixClipStack(cc::PaintCanvas*) const {} virtual void Reset() {} virtual void ClearRect(double x, double y, double width, double height) {} @@ -199,9 +234,8 @@ class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable, virtual void ResetUsageTracking() {} // WebGL-specific interface - virtual bool Is3d() const { return false; } virtual bool UsingSwapChain() const { return false; } - virtual void SetFilterQuality(SkFilterQuality) { NOTREACHED(); } + virtual void SetFilterQuality(cc::PaintFlags::FilterQuality) { NOTREACHED(); } virtual void Reshape(int width, int height) {} virtual void MarkLayerComposited() { NOTREACHED(); } virtual sk_sp<SkData> PaintRenderingResultsToDataArray(SourceDrawingBuffer) { @@ -217,10 +251,11 @@ class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable, return IntSize(0, 0); } - // OffscreenCanvas-specific methods + // OffscreenCanvas-specific methods. virtual bool PushFrame() { return false; } virtual ImageBitmap* TransferToImageBitmap(ScriptState*) { return nullptr; } + bool WouldTaintOrigin(CanvasImageSource*); void DidMoveToNewDocument(Document*); @@ -244,9 +279,14 @@ class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable, static CanvasPerformanceMonitor& GetCanvasPerformanceMonitor(); + virtual bool IdentifiabilityEncounteredPartiallyDigestedImage() const { + return false; + } + protected: CanvasRenderingContext(CanvasRenderingContextHost*, - const CanvasContextCreationAttributesCore&); + const CanvasContextCreationAttributesCore&, + CanvasRenderingAPI); private: void Dispose(); @@ -255,11 +295,10 @@ class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable, CanvasColorParams color_params_; CanvasContextCreationAttributesCore creation_attributes_; - void DidDrawCommon(); void RenderTaskEnded(); bool did_draw_in_current_task_ = false; - DISALLOW_COPY_AND_ASSIGN(CanvasRenderingContext); + const CanvasRenderingAPI canvas_rendering_type_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_factory.h b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_factory.h index dff8ab7ce2e..7dc60640e95 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_factory.h +++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_factory.h @@ -5,7 +5,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CANVAS_CANVAS_RENDERING_CONTEXT_FACTORY_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CANVAS_CANVAS_RENDERING_CONTEXT_FACTORY_H_ -#include "base/macros.h" #include "base/memory/scoped_refptr.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/document.h" @@ -23,6 +22,9 @@ class CORE_EXPORT CanvasRenderingContextFactory { public: CanvasRenderingContextFactory() = default; + CanvasRenderingContextFactory(const CanvasRenderingContextFactory&) = delete; + CanvasRenderingContextFactory& operator=( + const CanvasRenderingContextFactory&) = delete; virtual ~CanvasRenderingContextFactory() = default; virtual CanvasRenderingContext* Create( @@ -32,8 +34,6 @@ class CORE_EXPORT CanvasRenderingContextFactory { virtual CanvasRenderingContext::ContextType GetContextType() const = 0; virtual void OnError(HTMLCanvasElement*, const String& error) {} virtual void OnError(OffscreenCanvas*, const String& error) {} - - DISALLOW_COPY_AND_ASSIGN(CanvasRenderingContextFactory); }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc index b2327a95a9c..f3ce73c806b 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc +++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc @@ -75,14 +75,23 @@ void CanvasRenderingContextHost::RestoreCanvasMatrixClipStack( RenderingContext()->RestoreCanvasMatrixClipStack(canvas); } -bool CanvasRenderingContextHost::Is3d() const { - return RenderingContext() && RenderingContext()->Is3d(); +bool CanvasRenderingContextHost::IsWebGL() const { + return RenderingContext() && RenderingContext()->IsWebGL(); +} + +bool CanvasRenderingContextHost::IsWebGPU() const { + return RenderingContext() && RenderingContext()->IsWebGPU(); } bool CanvasRenderingContextHost::IsRenderingContext2D() const { return RenderingContext() && RenderingContext()->IsRenderingContext2D(); } +bool CanvasRenderingContextHost::IsImageBitmapRenderingContext() const { + return RenderingContext() && + RenderingContext()->IsImageBitmapRenderingContext(); +} + CanvasResourceProvider* CanvasRenderingContextHost::GetOrCreateCanvasResourceProvider( RasterModeHint hint) { @@ -94,9 +103,12 @@ CanvasRenderingContextHost::GetOrCreateCanvasResourceProviderImpl( RasterModeHint hint) { if (!ResourceProvider() && !did_fail_to_create_resource_provider_) { if (IsValidImageSize(Size())) { - if (Is3d()) { - CreateCanvasResourceProvider3D(); + if (IsWebGPU()) { + CreateCanvasResourceProviderWebGPU(); + } else if (IsWebGL()) { + CreateCanvasResourceProviderWebGL(); } else { + DCHECK(IsRenderingContext2D()); CreateCanvasResourceProvider2D(hint); } } @@ -106,8 +118,24 @@ CanvasRenderingContextHost::GetOrCreateCanvasResourceProviderImpl( return ResourceProvider(); } -void CanvasRenderingContextHost::CreateCanvasResourceProvider3D() { - DCHECK(Is3d()); +void CanvasRenderingContextHost::CreateCanvasResourceProviderWebGPU() { + std::unique_ptr<CanvasResourceProvider> provider; + if (SharedGpuContext::IsGpuCompositingEnabled()) { + provider = CanvasResourceProvider::CreateWebGPUImageProvider( + Size(), ColorParams().GetAsResourceParams(), + /*is_origin_top_left=*/true); + } + ReplaceResourceProvider(std::move(provider)); + if (ResourceProvider() && ResourceProvider()->IsValid()) { + base::UmaHistogramBoolean("Blink.Canvas.ResourceProviderIsAccelerated", + ResourceProvider()->IsAccelerated()); + base::UmaHistogramEnumeration("Blink.Canvas.ResourceProviderType", + ResourceProvider()->GetType()); + } +} + +void CanvasRenderingContextHost::CreateCanvasResourceProviderWebGL() { + DCHECK(IsWebGL()); base::WeakPtr<CanvasResourceDispatcher> dispatcher = GetOrCreateResourceDispatcher() @@ -365,31 +393,19 @@ IdentifiableToken CanvasRenderingContextHost::IdentifiabilityInputDigest( const CanvasRenderingContext* const context) const { const uint64_t context_digest = context ? context->IdentifiableTextToken().ToUkmMetricValue() : 0; - const IdentifiabilityPaintOpDigest* const identifiability_paintop_digest = - ResourceProvider() - ? &(ResourceProvider()->GetIdentifiablityPaintOpDigest()) - : nullptr; - const uint64_t canvas_digest = - identifiability_paintop_digest - ? identifiability_paintop_digest->GetToken().ToUkmMetricValue() - : 0; const uint64_t context_type = context ? context->GetContextType() : CanvasRenderingContext::kContextTypeUnknown; const bool encountered_skipped_ops = - (context && context->IdentifiabilityEncounteredSkippedOps()) || - (identifiability_paintop_digest && - identifiability_paintop_digest->encountered_skipped_ops()); + context && context->IdentifiabilityEncounteredSkippedOps(); const bool encountered_sensitive_ops = context && context->IdentifiabilityEncounteredSensitiveOps(); const bool encountered_partially_digested_image = - identifiability_paintop_digest && - identifiability_paintop_digest->encountered_partially_digested_image(); + context && context->IdentifiabilityEncounteredPartiallyDigestedImage(); // Bits [0-3] are the context type, bits [4-6] are skipped ops, sensitive // ops, and partial image ops bits, respectively. The remaining bits are // for the canvas digest. - uint64_t final_digest = - ((context_digest ^ canvas_digest) << 7) | context_type; + uint64_t final_digest = (context_digest << 7) | context_type; if (encountered_skipped_ops) final_digest |= IdentifiableSurface::CanvasTaintBit::kSkipped; if (encountered_sensitive_ops) diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h index 5a4c9de1d28..9c66ade6af6 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h +++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h @@ -46,8 +46,8 @@ class CORE_EXPORT CanvasRenderingContextHost : public CanvasResourceHost, virtual void DetachContext() = 0; - virtual void DidDraw(const FloatRect& rect) = 0; - virtual void DidDraw() = 0; + virtual void DidDraw(const SkIRect& rect) = 0; + void DidDraw() { DidDraw(SkIRect::MakeWH(width(), height())); } virtual void PreFinalizeFrame() = 0; virtual void PostFinalizeFrame() = 0; @@ -76,8 +76,6 @@ class CORE_EXPORT CanvasRenderingContextHost : public CanvasResourceHost, virtual bool ShouldAccelerate2dContext() const = 0; - virtual bool IsNeutered() const { return false; } - virtual void Commit(scoped_refptr<CanvasResource> canvas_resource, const SkIRect& damage_rect); @@ -103,8 +101,10 @@ class CORE_EXPORT CanvasRenderingContextHost : public CanvasResourceHost, CanvasResourceProvider* GetOrCreateCanvasResourceProvider( RasterModeHint hint) override; - bool Is3d() const; + bool IsWebGL() const; + bool IsWebGPU() const; bool IsRenderingContext2D() const; + bool IsImageBitmapRenderingContext() const; CanvasColorParams ColorParams() const; // blink::CanvasImageSource @@ -116,7 +116,8 @@ class CORE_EXPORT CanvasRenderingContextHost : public CanvasResourceHost, scoped_refptr<StaticBitmapImage> CreateTransparentImage(const IntSize&) const; void CreateCanvasResourceProvider2D(RasterModeHint hint); - void CreateCanvasResourceProvider3D(); + void CreateCanvasResourceProviderWebGL(); + void CreateCanvasResourceProviderWebGPU(); // Computes the digest that corresponds to the "input" of this canvas, // including the context type, and if applicable, canvas digest, and taint diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.cc new file mode 100644 index 00000000000..470a13144c6 --- /dev/null +++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.cc @@ -0,0 +1,40 @@ +// Copyright 2021 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 "third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.h" + +#include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h" +#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h" +#include "v8/include/v8.h" + +namespace blink { + +CanvasResourceTracker* CanvasResourceTracker::For(v8::Isolate* isolate) { + auto* isolate_data = V8PerIsolateData::From(isolate); + auto* canvas_resource_tracker = static_cast<CanvasResourceTracker*>( + isolate_data->CanvasResourceTracker()); + if (!canvas_resource_tracker) { + canvas_resource_tracker = MakeGarbageCollected<CanvasResourceTracker>(); + isolate_data->SetCanvasResourceTracker(canvas_resource_tracker); + } + return canvas_resource_tracker; +} + +void CanvasResourceTracker::Add(CanvasRenderingContextHost* resource, + ExecutionContext* execution_context) { + resource_map_.insert(resource, execution_context); +} + +const CanvasResourceTracker::ResourceMap& +CanvasResourceTracker::GetResourceMap() const { + return resource_map_; +} + +void CanvasResourceTracker::Trace(Visitor* visitor) const { + V8PerIsolateData::GarbageCollectedData::Trace(visitor); + visitor->Trace(resource_map_); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.h b/chromium/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.h new file mode 100644 index 00000000000..5c92a1509f5 --- /dev/null +++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.h @@ -0,0 +1,42 @@ +// Copyright 2021 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 THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CANVAS_CANVAS_RESOURCE_TRACKER_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CANVAS_CANVAS_RESOURCE_TRACKER_H_ + +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h" +#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h" +#include "third_party/blink/renderer/platform/heap/heap.h" +#include "third_party/blink/renderer/platform/heap/member.h" + +namespace v8 { +class Isolate; +} + +namespace blink { + +class CanvasRenderingContextHost; +class ExecutionContext; + +class CORE_EXPORT CanvasResourceTracker final + : public V8PerIsolateData::GarbageCollectedData { + public: + using ResourceMap = HeapHashMap<WeakMember<CanvasRenderingContextHost>, + WeakMember<ExecutionContext>>; + + static CanvasResourceTracker* For(v8::Isolate*); + + void Add(CanvasRenderingContextHost*, ExecutionContext*); + const ResourceMap& GetResourceMap() const; + + void Trace(Visitor*) const override; + + private: + ResourceMap resource_map_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CANVAS_CANVAS_RESOURCE_TRACKER_H_ diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker_test.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker_test.cc new file mode 100644 index 00000000000..cc0069c16cb --- /dev/null +++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker_test.cc @@ -0,0 +1,32 @@ +// Copyright 2021 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 "third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.h" + +#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h" +#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" + +namespace blink { + +class HTMLCanvasResourceTrackerTest : public RenderingTest { + public: + HTMLCanvasResourceTrackerTest() + : RenderingTest(MakeGarbageCollected<SingleChildLocalFrameClient>()) {} +}; + +TEST_F(HTMLCanvasResourceTrackerTest, AddCanvasElement) { + GetDocument().GetSettings()->SetScriptEnabled(true); + SetBodyInnerHTML("<canvas id='canvas'></canvas>"); + auto* canvas = To<HTMLCanvasElement>(GetDocument().getElementById("canvas")); + auto* context = GetDocument().GetExecutionContext(); + const auto& resource_map = + CanvasResourceTracker::For(context->GetIsolate())->GetResourceMap(); + // The map may hold more than a single entry as CanvasResourceTracker is + // instantiated per v8::Isolate which is reused across tests. + const auto it = resource_map.find(canvas); + EXPECT_NE(resource_map.end(), it); + EXPECT_EQ(context, it->value); +} + +} // namespace blink 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 01097a03d36..aa958af9852 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 @@ -37,6 +37,7 @@ #include "base/location.h" #include "base/metrics/histogram_macros.h" #include "base/numerics/checked_math.h" +#include "base/numerics/safe_conversions.h" #include "build/build_config.h" #include "services/metrics/public/cpp/ukm_recorder.h" #include "services/metrics/public/cpp/ukm_source_id.h" @@ -72,6 +73,7 @@ #include "third_party/blink/renderer/core/html/canvas/canvas_font_cache.h" #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h" #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context_factory.h" +#include "third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.h" #include "third_party/blink/renderer/core/html/canvas/image_data.h" #include "third_party/blink/renderer/core/html/forms/html_input_element.h" #include "third_party/blink/renderer/core/html/forms/html_select_element.h" @@ -80,6 +82,7 @@ #include "third_party/blink/renderer/core/html_names.h" #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h" #include "third_party/blink/renderer/core/input_type_names.h" +#include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/layout/hit_test_canvas_result.h" #include "third_party/blink/renderer/core/layout/layout_html_canvas.h" #include "third_party/blink/renderer/core/layout/layout_view.h" @@ -134,6 +137,11 @@ HTMLCanvasElement::HTMLCanvasElement(Document& document) externally_allocated_memory_(0) { UseCounter::Count(document, WebFeature::kHTMLCanvasElement); GetDocument().IncrementNumberOfCanvases(); + auto* execution_context = GetExecutionContext(); + if (execution_context) { + CanvasResourceTracker::For(execution_context->GetIsolate()) + ->Add(this, execution_context); + } } HTMLCanvasElement::~HTMLCanvasElement() { @@ -306,7 +314,8 @@ CanvasRenderingContext* HTMLCanvasElement::GetCanvasRenderingContext( UseCounter::Count(doc, WebFeature::kNewCanvas2DAPI); if (ContentsCcLayer() != old_contents_cc_layer) - OnContentsCcLayerChanged(); + SetNeedsCompositingUpdate(); + return result; } @@ -321,6 +330,15 @@ CanvasRenderingContext* HTMLCanvasElement::GetCanvasRenderingContextInternal( return nullptr; } + // TODO(crbug.com/1229274): Remove 'gpupresent' type after deprecation period. + if (type == "gpupresent") { + auto* console_message = MakeGarbageCollected<ConsoleMessage>( + mojom::blink::ConsoleMessageSource::kRendering, + mojom::blink::ConsoleMessageLevel::kWarning, + "The context type 'gpupresent' is deprecated. Use 'webgpu' instead."); + GetExecutionContext()->AddConsoleMessage(console_message); + } + // Log the aliased context type used. if (!context_) { UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.ContextType", context_type); @@ -356,6 +374,7 @@ CanvasRenderingContext* HTMLCanvasElement::GetCanvasRenderingContextInternal( if (!context_) return nullptr; + context_->RecordUKMCanvasRenderingAPI(); // Since the |context_| is created, free the transparent image, // |transparent_image_| created for this canvas if it exists. if (transparent_image_.get()) { @@ -366,7 +385,7 @@ CanvasRenderingContext* HTMLCanvasElement::GetCanvasRenderingContextInternal( probe::DidCreateCanvasContext(&GetDocument()); - if (Is3d()) + if (IsWebGL()) UpdateMemoryUsage(); LayoutObject* layout_object = GetLayoutObject(); @@ -447,8 +466,8 @@ bool HTMLCanvasElement::IsWebGLBlocked() const { return blocked; } -void HTMLCanvasElement::DidDraw(const FloatRect& rect) { - if (rect.IsEmpty()) +void HTMLCanvasElement::DidDraw(const SkIRect& rect) { + if (rect.isEmpty()) return; if (GetLayoutObject() && GetLayoutObject()->PreviousVisibilityVisible() && GetDocument().GetPage()) @@ -458,18 +477,14 @@ void HTMLCanvasElement::DidDraw(const FloatRect& rect) { GetLayoutObject()->SetShouldCheckForPaintInvalidation(); if (IsRenderingContext2D() && context_->ShouldAntialias() && GetPage() && GetPage()->DeviceScaleFactorDeprecated() > 1.0f) { - FloatRect inflated_rect = rect; + FloatRect inflated_rect = FloatRect(IntRect(rect)); inflated_rect.Inflate(1); dirty_rect_.Unite(inflated_rect); } else { - dirty_rect_.Unite(rect); + dirty_rect_.Unite(FloatRect(IntRect(rect))); } if (IsRenderingContext2D() && canvas2d_bridge_) - canvas2d_bridge_->DidDraw(rect); -} - -void HTMLCanvasElement::DidDraw() { - DidDraw(FloatRect(0, 0, Size().Width(), Size().Height())); + canvas2d_bridge_->DidDraw(); } void HTMLCanvasElement::PreFinalizeFrame() { @@ -580,8 +595,10 @@ void HTMLCanvasElement::DoDeferredPaintInvalidation() { if (dirty_rect_.IsEmpty()) return; - if (canvas2d_bridge_) - canvas2d_bridge_->DoPaintInvalidation(invalidation_rect); + if (canvas2d_bridge_) { + canvas2d_bridge_->DoPaintInvalidation( + EnclosingIntRect(invalidation_rect)); + } } if (context_ && HasImageBitmapContext() && context_->CcLayer()) @@ -643,7 +660,7 @@ void HTMLCanvasElement::Reset() { SetSurfaceSize(new_size); - if (Is3d() && old_size != Size()) + if (IsWebGL() && old_size != Size()) context_->Reshape(width(), height()); if (LayoutObject* layout_object = GetLayoutObject()) { @@ -724,12 +741,13 @@ bool HTMLCanvasElement::LowLatencyEnabled() const { return !!frame_dispatcher_; } -void HTMLCanvasElement::SetFilterQuality(SkFilterQuality filter_quality) { +void HTMLCanvasElement::SetFilterQuality( + cc::PaintFlags::FilterQuality filter_quality) { CanvasResourceHost::SetFilterQuality(filter_quality); if (IsOffscreenCanvasRegistered()) UpdateOffscreenCanvasFilterQuality(filter_quality); - if (context_ && Is3d()) + if (context_ && (IsWebGL() || IsWebGPU())) context_->SetFilterQuality(filter_quality); else if (canvas2d_bridge_) canvas2d_bridge_->SetFilterQuality(filter_quality); @@ -798,10 +816,10 @@ void HTMLCanvasElement::PaintInternal(GraphicsContext& context, // display list rendering: we replay the last full PaintRecord, if Canvas // has been redraw since beginprint happened. - if (IsPrinting() && !Is3d() && canvas2d_bridge_) { + if (IsPrinting() && IsRenderingContext2D() && canvas2d_bridge_) { canvas2d_bridge_->FlushRecording(); if (canvas2d_bridge_->getLastRecord()) { - if (FilterQuality() != kNone_SkFilterQuality) { + if (FilterQuality() != cc::PaintFlags::FilterQuality::kNone) { context.Canvas()->save(); context.Canvas()->translate(r.X(), r.Y()); context.Canvas()->scale(r.Width() / Size().Width(), @@ -831,8 +849,7 @@ void HTMLCanvasElement::PaintInternal(GraphicsContext& context, const ComputedStyle* style = GetComputedStyle(); context.DrawImage(snapshot.get(), Image::kSyncDecode, FloatRect(PixelSnappedIntRect(r)), &src_rect, - style && style->HasFilterInducingProperty(), - composite_operator); + style && style->DisableForceDark(), composite_operator); } } else { // When alpha is false, we should draw to opaque black. @@ -840,7 +857,7 @@ void HTMLCanvasElement::PaintInternal(GraphicsContext& context, context.FillRect(FloatRect(r), Color(0, 0, 0)); } - if (Is3d() && PaintsIntoCanvasBuffer()) + if (IsWebGL() && PaintsIntoCanvasBuffer()) context_->MarkLayerComposited(); } @@ -876,7 +893,7 @@ scoped_refptr<StaticBitmapImage> HTMLCanvasElement::Snapshot( if (OffscreenCanvasFrame()) { // Offscreen Canvas DCHECK(OffscreenCanvasFrame()->OriginClean()); image_bitmap = OffscreenCanvasFrame()->Bitmap(); - } else if (Is3d()) { // WebGL or WebGL2 canvas + } else if (IsWebGL()) { if (context_->CreationAttributes().premultiplied_alpha) { context_->PaintRenderingResultsToCanvas(source_buffer); if (ResourceProvider()) @@ -898,10 +915,9 @@ scoped_refptr<StaticBitmapImage> HTMLCanvasElement::Snapshot( image_bitmap = StaticBitmapImage::Create(std::move(pixel_data), info); } } - } else if (canvas2d_bridge_) { - DCHECK(IsRenderingContext2D()); - image_bitmap = canvas2d_bridge_->NewImageSnapshot(); - } else if (context_) { // Bitmap renderer canvas + } else if (context_) { + DCHECK(IsRenderingContext2D() || IsImageBitmapRenderingContext() || + IsWebGPU()); image_bitmap = context_->GetImage(); } @@ -1242,8 +1258,11 @@ void HTMLCanvasElement::PageVisibilityChanged() { return; context_->SetIsInHiddenPage(hidden); - if (hidden && Is3d()) + if (hidden && (IsWebGL() || IsWebGPU())) DiscardResourceProvider(); + + if (!hidden) + context_->SendContextLostEventIfNeeded(); } void HTMLCanvasElement::ContextDestroyed() { @@ -1255,7 +1274,7 @@ bool HTMLCanvasElement::StyleChangeNeedsDidDraw( const ComputedStyle* old_style, const ComputedStyle& new_style) { // It will only need to redraw for a style change, if the new imageRendering - // is different than the previous one, and only if one of the two ir + // is different than the previous one, and only if one of the two are // pixelated. return old_style && old_style->ImageRendering() != new_style.ImageRendering() && @@ -1265,9 +1284,10 @@ bool HTMLCanvasElement::StyleChangeNeedsDidDraw( void HTMLCanvasElement::StyleDidChange(const ComputedStyle* old_style, const ComputedStyle& new_style) { - SkFilterQuality filter_quality = kLow_SkFilterQuality; + cc::PaintFlags::FilterQuality filter_quality = + cc::PaintFlags::FilterQuality::kLow; if (new_style.ImageRendering() == EImageRendering::kPixelated) - filter_quality = kNone_SkFilterQuality; + filter_quality = cc::PaintFlags::FilterQuality::kNone; SetFilterQuality(filter_quality); style_is_visible_ = new_style.Visibility() == EVisibility::kVisible; if (context_) { @@ -1307,12 +1327,16 @@ void HTMLCanvasElement::WillDrawImageTo2DContext(CanvasImageSource* source) { scoped_refptr<Image> HTMLCanvasElement::GetSourceImageForCanvas( SourceImageStatus* status, - const FloatSize&) { - return GetSourceImageForCanvasInternal(status); + const FloatSize&, + const AlphaDisposition alpha_disposition) { + + return GetSourceImageForCanvasInternal(status, alpha_disposition); } scoped_refptr<StaticBitmapImage> -HTMLCanvasElement::GetSourceImageForCanvasInternal(SourceImageStatus* status) { +HTMLCanvasElement::GetSourceImageForCanvasInternal( + SourceImageStatus* status, + const AlphaDisposition alpha_disposition) { if (!width() || !height()) { *status = kZeroSizeCanvasSourceImageStatus; return nullptr; @@ -1323,34 +1347,25 @@ HTMLCanvasElement::GetSourceImageForCanvasInternal(SourceImageStatus* status) { return nullptr; } + scoped_refptr<StaticBitmapImage> image; + if (OffscreenCanvasFrame()) { - // This may be false even if this HTMLCanvasElement has been transferred + // This may be false to set status to normal if a valid image can be got + // even if this HTMLCanvasElement has been transferred // control to an offscreenCanvas. As offscreencanvas with the // TransferControlToOffscreen is asynchronous, this will need to finish the // first Frame in order to have a first OffscreenCanvasFrame. - *status = kNormalSourceImageStatus; - return OffscreenCanvasFrame()->Bitmap(); - } - - if (!context_) { - scoped_refptr<StaticBitmapImage> result = GetTransparentImage(); - *status = result ? kNormalSourceImageStatus : kInvalidSourceImageStatus; - return result; - } - - if (HasImageBitmapContext()) { - *status = kNormalSourceImageStatus; - scoped_refptr<StaticBitmapImage> result = context_->GetImage(); - if (!result) - result = GetTransparentImage(); - *status = result ? kNormalSourceImageStatus : kInvalidSourceImageStatus; - return result; - } + image = OffscreenCanvasFrame()->Bitmap(); + } else if (!context_) { + image = GetTransparentImage(); + } else if (HasImageBitmapContext()) { + image = context_->GetImage(); - scoped_refptr<StaticBitmapImage> image; - // TODO(ccameron): Canvas should produce sRGB images. - // https://crbug.com/672299 - if (Is3d()) { + if (!image) + image = GetTransparentImage(); + } else if (IsWebGL()) { + // TODO(ccameron): Canvas should produce sRGB images. + // https://crbug.com/672299 // Because WebGL sources always require making a copy of the back buffer, we // use paintRenderingResultsToCanvas instead of getImage in order to keep a // cached copy of the backing in the canvas's resource provider. @@ -1365,11 +1380,15 @@ HTMLCanvasElement::GetSourceImageForCanvasInternal(SourceImageStatus* status) { image = GetTransparentImage(); } - if (image) - *status = kNormalSourceImageStatus; - else + if (!image) { + // All other possible error statuses were checked earlier. *status = kInvalidSourceImageStatus; - return image; + return image; + } + + *status = kNormalSourceImageStatus; + // If the alpha_disposition is already correct, this is a no-op. + return GetImageWithAlphaDisposition(std::move(image), alpha_disposition); } bool HTMLCanvasElement::WouldTaintOrigin() const { @@ -1417,6 +1436,10 @@ bool HTMLCanvasElement::IsOpaque() const { return context_ && !context_->CreationAttributes().alpha; } +bool HTMLCanvasElement::IsVisible() const { + return GetPage() && GetPage()->IsPageVisible(); +} + bool HTMLCanvasElement::IsSupportedInteractiveCanvasFallback( const Element& element) { if (!element.IsDescendantOf(this)) @@ -1521,11 +1544,11 @@ void HTMLCanvasElement::OnWebLayerUpdated() { } void HTMLCanvasElement::RegisterContentsLayer(cc::Layer* layer) { - OnContentsCcLayerChanged(); + SetNeedsCompositingUpdate(); } void HTMLCanvasElement::UnregisterContentsLayer(cc::Layer* layer) { - OnContentsCcLayerChanged(); + SetNeedsCompositingUpdate(); } FontSelector* HTMLCanvasElement::GetFontSelector() { @@ -1536,7 +1559,7 @@ void HTMLCanvasElement::UpdateMemoryUsage() { int non_gpu_buffer_count = 0; int gpu_buffer_count = 0; - if (!IsRenderingContext2D() && !Is3d()) + if (!IsRenderingContext2D() && !IsWebGL()) return; if (ResourceProvider()) { non_gpu_buffer_count++; @@ -1549,7 +1572,7 @@ void HTMLCanvasElement::UpdateMemoryUsage() { } } - if (Is3d()) + if (IsWebGL()) non_gpu_buffer_count += context_->ExternallyAllocatedBufferCountPerPixel(); const int bytes_per_pixel = ColorParams().BytesPerPixel(); @@ -1584,6 +1607,10 @@ void HTMLCanvasElement::UpdateMemoryUsage() { externally_allocated_memory_ = externally_allocated_memory; } +size_t HTMLCanvasElement::GetMemoryUsage() const { + return base::saturated_cast<size_t>(externally_allocated_memory_); +} + void HTMLCanvasElement::ReplaceExisting2dLayerBridge( std::unique_ptr<Canvas2DLayerBridge> new_layer_bridge) { scoped_refptr<StaticBitmapImage> image; @@ -1678,14 +1705,6 @@ cc::Layer* HTMLCanvasElement::ContentsCcLayer() const { return nullptr; } -void HTMLCanvasElement::OnContentsCcLayerChanged() { - // We need to repaint the layer because the foreign layer display item may - // appear, disappear or change. - if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() && - GetLayoutObject() && GetLayoutObject()->HasLayer()) - GetLayoutBoxModelObject()->Layer()->SetNeedsRepaint(); -} - RespectImageOrientationEnum HTMLCanvasElement::RespectImageOrientation() const { // TODO(junov): Computing style here will be problematic for applying the // NoAllocDirectCall IDL attribute to drawImage. diff --git a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.h index 905b0acc561..5b3439d7633 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.h +++ b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.h @@ -85,8 +85,6 @@ typedef CanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextO // It can be a 3D Context (WebGL or WebGL2), 2D Context, // BitmapRenderingContext or it can have no context (Offscreen placeholder). // To check the no context case is good to check if there is a placeholder. -// For 3D and 2D contexts there are Is3D or IsRenderingContext2D functions. -// The remaining case is BitmaprenderingContext. // // TODO (juanmihd): Study if a refactor of context could help in simplifying // this class and without overcomplicating context. @@ -153,8 +151,8 @@ class CORE_EXPORT HTMLCanvasElement final bool HasCanvasCapture() const final { return !listeners_.IsEmpty(); } // Used for rendering - void DidDraw(const FloatRect&) override; - void DidDraw() override; + void DidDraw(const SkIRect&) override; + using CanvasRenderingContextHost::DidDraw; void Paint(GraphicsContext&, const PhysicalRect&, @@ -183,6 +181,7 @@ class CORE_EXPORT HTMLCanvasElement final InsertionNotificationRequest InsertedInto(ContainerNode&) override; bool IsDirty() { return !dirty_rect_.IsEmpty(); } + bool IsVisible() const; void DoDeferredPaintInvalidation(); @@ -201,8 +200,10 @@ class CORE_EXPORT HTMLCanvasElement final void PageVisibilityChanged() override; // CanvasImageSource implementation - scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*, - const FloatSize&) override; + scoped_refptr<Image> GetSourceImageForCanvas( + SourceImageStatus*, + const FloatSize&, + const AlphaDisposition alpha_disposition = kPremultiplyAlpha) override; bool WouldTaintOrigin() const override; FloatSize ElementSize(const FloatSize&, const RespectImageOrientationEnum) const override; @@ -219,12 +220,13 @@ class CORE_EXPORT HTMLCanvasElement final void NotifyGpuContextLost() override; void SetNeedsCompositingUpdate() override; void UpdateMemoryUsage() override; + size_t GetMemoryUsage() const override; bool ShouldAccelerate2dContext() const override; bool LowLatencyEnabled() const override; CanvasResourceProvider* GetOrCreateCanvasResourceProvider( RasterModeHint hint) override; bool IsPrinting() const override; - void SetFilterQuality(SkFilterQuality filter_quality) override; + void SetFilterQuality(cc::PaintFlags::FilterQuality filter_quality) override; // CanvasRenderingContextHost implementation. UkmParameters GetUkmParameters() override; @@ -321,6 +323,8 @@ class CORE_EXPORT HTMLCanvasElement final bool IsCanvasClear() { return canvas_is_clear_; } + bool IsPlaceholder() const override { return IsOffscreenCanvasRegistered(); } + protected: void DidMoveToNewDocument(Document& old_document) override; @@ -376,9 +380,8 @@ class CORE_EXPORT HTMLCanvasElement final const CanvasContextCreationAttributesCore&); scoped_refptr<StaticBitmapImage> GetSourceImageForCanvasInternal( - SourceImageStatus*); - - void OnContentsCcLayerChanged(); + SourceImageStatus*, + const AlphaDisposition alpha_disposition = kPremultiplyAlpha); HeapHashSet<WeakMember<CanvasDrawListener>> listeners_; diff --git a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.idl b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.idl index d8f04c404a2..3a6ff316fd3 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.idl +++ b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.idl @@ -40,7 +40,7 @@ [HighEntropy, MeasureAs=CanvasToBlob, RaisesException] void toBlob(BlobCallback _callback, optional DOMString type = "image/png", optional any quality); - [HighEntropy, RuntimeEnabled=CanvasColorManagement, MeasureAs=CanvasConvertToBlob, RaisesException, CallWith=ScriptState] Promise<Blob> convertToBlob(optional ImageEncodeOptions options = {}); + [HighEntropy, RuntimeEnabled=CanvasColorManagementV2, MeasureAs=CanvasConvertToBlob, RaisesException, CallWith=ScriptState] Promise<Blob> convertToBlob(optional ImageEncodeOptions options = {}); }; // https://html.spec.whatwg.org/C/#blobcallback diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc b/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc index ac778379026..188f7c5df88 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc +++ b/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc @@ -31,7 +31,6 @@ #include "base/sys_byteorder.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h" #include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_uint8_clamped_array.h" #include "third_party/blink/renderer/bindings/core/v8/v8_union_float32array_uint16array_uint8clampedarray.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/html/canvas/predefined_color_space.h" @@ -73,6 +72,11 @@ ImageData* ImageData::ValidateAndCreate( exception_state.ThrowTypeError("Overload resolution failed."); return nullptr; } + if (params.require_canvas_color_management_v2 && + !RuntimeEnabledFeatures::CanvasColorManagementV2Enabled()) { + exception_state.ThrowTypeError("Overload resolution failed."); + return nullptr; + } if (settings && settings->hasColorSpace()) { if (!ColorSpaceNameIsValid(settings->colorSpace(), exception_state)) return nullptr; @@ -374,7 +378,6 @@ ImageDataSettings* ImageData::getSettings() const { } bool ImageData::IsBufferBaseDetached() const { -#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) switch (data_->GetContentType()) { case V8ImageDataArray::ContentType::kFloat32Array: return data_->GetAsFloat32Array()->BufferBase()->IsDetached(); @@ -386,22 +389,12 @@ bool ImageData::IsBufferBaseDetached() const { NOTREACHED(); return false; -#else // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) - if (data_.IsUint8ClampedArray()) - return data_.GetAsUint8ClampedArray()->BufferBase()->IsDetached(); - if (data_.IsUint16Array()) - return data_.GetAsUint16Array()->BufferBase()->IsDetached(); - if (data_.IsFloat32Array()) - return data_.GetAsFloat32Array()->BufferBase()->IsDetached(); - return false; -#endif // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) } SkPixmap ImageData::GetSkPixmap() const { CHECK(!IsBufferBaseDetached()); SkColorType color_type = kRGBA_8888_SkColorType; const void* data = nullptr; -#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) switch (data_->GetContentType()) { case V8ImageDataArray::ContentType::kFloat32Array: color_type = kRGBA_F32_SkColorType; @@ -416,18 +409,6 @@ SkPixmap ImageData::GetSkPixmap() const { data = data_->GetAsUint8ClampedArray()->Data(); break; } -#else // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) - if (data_.IsUint8ClampedArray()) { - color_type = kRGBA_8888_SkColorType; - data = data_.GetAsUint8ClampedArray()->Data(); - } else if (data_.IsUint16Array()) { - color_type = kR16G16B16A16_unorm_SkColorType; - data = data_.GetAsUint16Array()->Data(); - } else if (data_.IsFloat32Array()) { - color_type = kRGBA_F32_SkColorType; - data = data_.GetAsFloat32Array()->Data(); - } -#endif // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) SkImageInfo info = SkImageInfo::Make(width(), height(), color_type, kUnpremul_SkAlphaType, CanvasColorSpaceToSkColorSpace(GetCanvasColorSpace())); @@ -450,7 +431,6 @@ v8::Local<v8::Object> ImageData::AssociateWithWrapper( wrapper = ScriptWrappable::AssociateWithWrapper(isolate, wrapper_type_info, wrapper); -#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) if (data_->IsUint8ClampedArray()) { // Create a V8 object with |data_| and set the "data" property // of the ImageData object to the created v8 object, eliminating the @@ -473,30 +453,6 @@ v8::Local<v8::Object> ImageData::AssociateWithWrapper( return wrapper; } } -#else // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) - if (data_.IsUint8ClampedArray()) { - // Create a V8 object with |data_| and set the "data" property - // of the ImageData object to the created v8 object, eliminating the - // C++ callback when accessing the "data" property. - // - // This is a perf hack breaking the web interop. - - v8::Local<v8::Value> v8_data; - ScriptState* script_state = ScriptState::From(wrapper->CreationContext()); - if (!ToV8Traits<IDLUnionNotINT<ImageDataArray>>::ToV8(script_state, data_) - .ToLocal(&v8_data)) { - return wrapper; - } - bool defined_property; - if (!wrapper - ->DefineOwnProperty(isolate->GetCurrentContext(), - V8AtomicString(isolate, "data"), v8_data, - v8::ReadOnly) - .To(&defined_property)) { - return wrapper; - } - } -#endif // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) return wrapper; } @@ -531,11 +487,7 @@ ImageData::ImageData(const IntSize& size, SECURITY_CHECK( (base::CheckedNumeric<size_t>(size.Width()) * size.Height() * 4) .ValueOrDie() <= data_u8_->length()); -#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) data_ = MakeGarbageCollected<V8ImageDataArray>(data_u8_); -#else // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) - data_.SetUint8ClampedArray(data_u8_); -#endif // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) break; case kUint16ArrayStorageFormat: @@ -545,11 +497,7 @@ ImageData::ImageData(const IntSize& size, SECURITY_CHECK( (base::CheckedNumeric<size_t>(size.Width()) * size.Height() * 4) .ValueOrDie() <= data_u16_->length()); -#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) data_ = MakeGarbageCollected<V8ImageDataArray>(data_u16_); -#else // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) - data_.SetUint16Array(data_u16_); -#endif // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) break; case kFloat32ArrayStorageFormat: @@ -559,11 +507,7 @@ ImageData::ImageData(const IntSize& size, SECURITY_CHECK( (base::CheckedNumeric<size_t>(size.Width()) * size.Height() * 4) .ValueOrDie() <= data_f32_->length()); -#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) data_ = MakeGarbageCollected<V8ImageDataArray>(data_f32_); -#else // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) - data_.SetFloat32Array(data_f32_); -#endif // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) break; default: diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_data.h b/chromium/third_party/blink/renderer/core/html/canvas/image_data.h index e2b7fa76512..f4db41fce14 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/image_data.h +++ b/chromium/third_party/blink/renderer/core/html/canvas/image_data.h @@ -30,7 +30,6 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CANVAS_IMAGE_DATA_H_ #include "base/numerics/checked_math.h" -#include "third_party/blink/renderer/bindings/core/v8/uint8_clamped_array_or_uint16_array_or_float32_array.h" #include "third_party/blink/renderer/bindings/core/v8/v8_image_data_settings.h" #include "third_party/blink/renderer/bindings/core/v8/v8_typedefs.h" #include "third_party/blink/renderer/core/core_export.h" @@ -52,8 +51,6 @@ namespace blink { class ExceptionState; class ImageBitmapOptions; -typedef Uint8ClampedArrayOrUint16ArrayOrFloat32Array ImageDataArray; - constexpr const char* kUint8ClampedArrayStorageFormatName = "uint8"; constexpr const char* kUint16ArrayStorageFormatName = "uint16"; constexpr const char* kFloat32ArrayStorageFormatName = "float32"; @@ -70,16 +67,24 @@ class CORE_EXPORT ImageData final : public ScriptWrappable, DEFINE_WRAPPERTYPEINFO(); public: - // Constructor that takes width, height, and an optional ImageDataSettings. + // Constructors that take width, height, and an optional ImageDataSettings. static ImageData* Create(unsigned width, unsigned height, - const ImageDataSettings* settings, ExceptionState& exception_state) { - return ValidateAndCreate(width, height, absl::nullopt, settings, + return ValidateAndCreate(width, height, absl::nullopt, /*settings=*/nullptr, ValidateAndCreateParams(), exception_state); } + static ImageData* Create(unsigned width, + unsigned height, + const ImageDataSettings* settings, + ExceptionState& exception_state) { + ValidateAndCreateParams params; + params.require_canvas_color_management = true; + return ValidateAndCreate(width, height, absl::nullopt, settings, params, + exception_state); + } - // Constructor that takes Uint8ClampedArray, width, optional height, and + // Constructors that take Uint8ClampedArray, width, optional height, and // optional ImageDataSettings. static ImageData* Create(NotShared<DOMUint8ClampedArray> data, unsigned width, @@ -90,11 +95,20 @@ class CORE_EXPORT ImageData final : public ScriptWrappable, static ImageData* Create(NotShared<DOMUint8ClampedArray> data, unsigned width, unsigned height, - const ImageDataSettings* settings, ExceptionState& exception_state) { - return ValidateAndCreate(width, height, data, settings, + return ValidateAndCreate(width, height, data, /*settings=*/nullptr, ValidateAndCreateParams(), exception_state); } + static ImageData* Create(NotShared<DOMUint8ClampedArray> data, + unsigned width, + unsigned height, + const ImageDataSettings* settings, + ExceptionState& exception_state) { + ValidateAndCreateParams params; + params.require_canvas_color_management = true; + return ValidateAndCreate(width, height, data, settings, params, + exception_state); + } // Constructor that takes DOMUint16Array, width, optional height, and optional // ImageDataSettings. @@ -102,7 +116,7 @@ class CORE_EXPORT ImageData final : public ScriptWrappable, unsigned width, ExceptionState& exception_state) { ValidateAndCreateParams params; - params.require_canvas_color_management = true; + params.require_canvas_color_management_v2 = true; return ValidateAndCreate(width, absl::nullopt, data, nullptr, params, exception_state); } @@ -112,7 +126,7 @@ class CORE_EXPORT ImageData final : public ScriptWrappable, const ImageDataSettings* settings, ExceptionState& exception_state) { ValidateAndCreateParams params; - params.require_canvas_color_management = true; + params.require_canvas_color_management_v2 = true; return ValidateAndCreate(width, height, data, settings, params, exception_state); } @@ -123,7 +137,7 @@ class CORE_EXPORT ImageData final : public ScriptWrappable, unsigned width, ExceptionState& exception_state) { ValidateAndCreateParams params; - params.require_canvas_color_management = true; + params.require_canvas_color_management_v2 = true; return ValidateAndCreate(width, absl::nullopt, data, nullptr, params, exception_state); } @@ -133,7 +147,7 @@ class CORE_EXPORT ImageData final : public ScriptWrappable, const ImageDataSettings* settings, ExceptionState& exception_state) { ValidateAndCreateParams params; - params.require_canvas_color_management = true; + params.require_canvas_color_management_v2 = true; return ValidateAndCreate(width, height, data, settings, params, exception_state); } @@ -151,6 +165,10 @@ class CORE_EXPORT ImageData final : public ScriptWrappable, // This argument is passed by Create functions that should require that the // CanvasColorManagement feature be enabled. bool require_canvas_color_management = false; + // Constructors in IDL files cannot specify RuntimeEnabled restrictions. + // This argument is passed by Create functions that should require that the + // CanvasColorManagementV2 feature be enabled. + bool require_canvas_color_management_v2 = false; // If the caller is guaranteed to write over the result in its entirety, // then this flag may be used to skip initialization of the result's // data. @@ -194,13 +212,7 @@ class CORE_EXPORT ImageData final : public ScriptWrappable, // TODO(https://crbug.com/1198606): Remove this. ImageDataSettings* getSettings() const; -#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) const V8ImageDataArray* data() const { return data_; } -#else // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) - ImageDataArray& data() { return data_; } - const ImageDataArray& data() const { return data_; } - void data(ImageDataArray& result) { result = data_; } -#endif // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) bool IsBufferBaseDetached() const; CanvasColorSpace GetCanvasColorSpace() const; @@ -227,11 +239,7 @@ class CORE_EXPORT ImageData final : public ScriptWrappable, IntSize size_; // TODO(https://crbug.com/1198606): Remove this. Member<ImageDataSettings> settings_; -#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) Member<V8ImageDataArray> data_; -#else // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) - ImageDataArray data_; -#endif // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) NotShared<DOMUint8ClampedArray> data_u8_; NotShared<DOMUint16Array> data_u16_; NotShared<DOMFloat32Array> data_f32_; diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_data.idl b/chromium/third_party/blink/renderer/core/html/canvas/image_data.idl index 1d65418c1d9..f5bd844ead8 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/image_data.idl +++ b/chromium/third_party/blink/renderer/core/html/canvas/image_data.idl @@ -34,17 +34,18 @@ typedef (Uint8ClampedArray or Uint16Array or Float32Array) ImageDataArray; Exposed=(Window,Worker), Serializable ] interface ImageData { - [RaisesException] constructor(unsigned long sw, unsigned long sh, optional ImageDataSettings settings = {}); + [RaisesException] constructor(unsigned long sw, unsigned long sh); + [RaisesException] constructor(unsigned long sw, unsigned long sh, ImageDataSettings settings); [RaisesException] constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh, optional ImageDataSettings settings = {}); [RaisesException] constructor(Uint16Array data, unsigned long sw, optional unsigned long sh, optional ImageDataSettings settings = {}); [RaisesException] constructor(Float32Array data, unsigned long sw, optional unsigned long sh, optional ImageDataSettings settings = {}); // TODO(crbug.com/1198606): Remove this. - [RuntimeEnabled=CanvasColorManagement] ImageDataSettings getSettings(); + [RuntimeEnabled=CanvasColorManagementV2] ImageDataSettings getSettings(); readonly attribute unsigned long width; readonly attribute unsigned long height; - readonly attribute PredefinedColorSpace colorSpace; - [RuntimeEnabled=CanvasColorManagement] readonly attribute ImageDataStorageFormat storageFormat; + [RuntimeEnabled=CanvasColorManagement] readonly attribute PredefinedColorSpace colorSpace; + [RuntimeEnabled=CanvasColorManagementV2] readonly attribute ImageDataStorageFormat storageFormat; readonly attribute ImageDataArray data; }; diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_data_settings.idl b/chromium/third_party/blink/renderer/core/html/canvas/image_data_settings.idl index 08914ae7be6..6a2cbf58ce1 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/image_data_settings.idl +++ b/chromium/third_party/blink/renderer/core/html/canvas/image_data_settings.idl @@ -16,5 +16,5 @@ enum ImageDataStorageFormat { dictionary ImageDataSettings { PredefinedColorSpace colorSpace; - [RuntimeEnabled=CanvasColorManagement] ImageDataStorageFormat storageFormat = "uint8"; + [RuntimeEnabled=CanvasColorManagementV2] ImageDataStorageFormat storageFormat = "uint8"; }; diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.cc b/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.cc index 1b8ca46a6dd..673d2a08cc9 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.cc +++ b/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.cc @@ -47,7 +47,11 @@ bool ImageElementBase::IsImageElement() const { scoped_refptr<Image> ImageElementBase::GetSourceImageForCanvas( SourceImageStatus* status, - const FloatSize& default_object_size) { + const FloatSize& default_object_size, + const AlphaDisposition alpha_disposition) { + // UnpremultiplyAlpha is not implemented yet. + DCHECK_EQ(alpha_disposition, kPremultiplyAlpha); + ImageResourceContent* image_content = CachedImage(); if (!GetImageLoader().ImageComplete() || !image_content) { *status = kIncompleteSourceImageStatus; diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.h b/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.h index 76ef21172e5..fb4af938d22 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.h +++ b/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.h @@ -32,8 +32,10 @@ class CORE_EXPORT ImageElementBase : public CanvasImageSource, const ImageBitmapOptions*, ExceptionState&) override; - scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*, - const FloatSize&) override; + scoped_refptr<Image> GetSourceImageForCanvas( + SourceImageStatus*, + const FloatSize&, + const AlphaDisposition alpha_disposition = kPremultiplyAlpha) override; bool WouldTaintOrigin() const override; diff --git a/chromium/third_party/blink/renderer/core/html/canvas/predefined_color_space.cc b/chromium/third_party/blink/renderer/core/html/canvas/predefined_color_space.cc index 3334575b05e..12350c735ef 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/predefined_color_space.cc +++ b/chromium/third_party/blink/renderer/core/html/canvas/predefined_color_space.cc @@ -11,8 +11,8 @@ namespace blink { bool ColorSpaceNameIsValid(const String& color_space_name, ExceptionState& exception_state) { - if (!RuntimeEnabledFeatures::CanvasColorManagementEnabled()) { - // The enum value 'rec2020' is not valid unless CanvasColorManagement is + if (!RuntimeEnabledFeatures::CanvasColorManagementV2Enabled()) { + // The enum value 'rec2020' is not valid unless CanvasColorManagementV2 is // enabled. if (color_space_name == kRec2020CanvasColorSpaceName) { exception_state.ThrowTypeError( diff --git a/chromium/third_party/blink/renderer/core/html/canvas/predefined_color_space.h b/chromium/third_party/blink/renderer/core/html/canvas/predefined_color_space.h index 685abd76be9..2a5db337763 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/predefined_color_space.h +++ b/chromium/third_party/blink/renderer/core/html/canvas/predefined_color_space.h @@ -12,9 +12,9 @@ namespace blink { // Some values for PredefinedColorSpace are specified in the IDL but are -// supposed to be guarded behind the CanvasColorManagement feature (e.g, +// supposed to be guarded behind the CanvasColorManagementV2 feature (e.g, // 'rec2020'). This function will throw the exception that the IDL would -// have thrown, if CanvasColorManagement is not enabled. +// have thrown, if CanvasColorManagementV2 is not enabled. bool CORE_EXPORT ColorSpaceNameIsValid(const String& color_space_name, ExceptionState& exception_state); |