blob: 5906a3ac051b64e46dc0379cdf231993555e39a0 [file] [log] [blame]
/*
* Copyright (C) 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.h"
#include "third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h"
#include "third_party/blink/renderer/core/html/canvas/canvas_image_source.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
namespace blink {
CanvasRenderingContext::CanvasRenderingContext(
CanvasRenderingContextHost* host,
const CanvasContextCreationAttributesCore& attrs)
: host_(host),
color_params_(attrs.color_space, attrs.pixel_format, attrs.alpha),
creation_attributes_(attrs) {}
void CanvasRenderingContext::Dispose() {
StopListeningForDidProcessTask();
// HTMLCanvasElement and CanvasRenderingContext have a circular reference.
// When the pair is no longer reachable, their destruction order is non-
// deterministic, so the first of the two to be destroyed needs to notify
// the other in order to break the circular reference. This is to avoid
// an error when CanvasRenderingContext::DidProcessTask() is invoked
// after the HTMLCanvasElement is destroyed.
if (Host()) {
Host()->DetachContext();
host_ = nullptr;
}
}
void CanvasRenderingContext::DidDraw(const SkIRect& dirty_rect) {
Host()->DidDraw(SkRect::Make(dirty_rect));
StartListeningForDidProcessTask();
}
void CanvasRenderingContext::DidDraw() {
Host()->DidDraw();
StartListeningForDidProcessTask();
}
void CanvasRenderingContext::DidProcessTask(
const base::PendingTask& /* pending_task */) {
StopListeningForDidProcessTask();
// The end of a script task that drew content to the canvas is the point
// at which the current frame may be considered complete.
if (Host())
Host()->PreFinalizeFrame();
FinalizeFrame();
if (Host())
Host()->PostFinalizeFrame();
}
void CanvasRenderingContext::RecordUKMCanvasRenderingAPI(
CanvasRenderingAPI canvasRenderingAPI) {
DCHECK(Host());
const auto& ukm_params = Host()->GetUkmParameters();
if (Host()->IsOffscreenCanvas()) {
ukm::builders::ClientRenderingAPI(ukm_params.source_id)
.SetOffscreenCanvas_RenderingContext(
static_cast<int>(canvasRenderingAPI))
.Record(ukm_params.ukm_recorder);
} else {
ukm::builders::ClientRenderingAPI(ukm_params.source_id)
.SetCanvas_RenderingContext(static_cast<int>(canvasRenderingAPI))
.Record(ukm_params.ukm_recorder);
}
}
void CanvasRenderingContext::RecordUKMCanvasDrawnToRenderingAPI(
CanvasRenderingAPI canvasRenderingAPI) {
DCHECK(Host());
const auto& ukm_params = Host()->GetUkmParameters();
if (Host()->IsOffscreenCanvas()) {
ukm::builders::ClientRenderingAPI(ukm_params.source_id)
.SetOffscreenCanvas_RenderingContextDrawnTo(
static_cast<int>(canvasRenderingAPI))
.Record(ukm_params.ukm_recorder);
} else {
ukm::builders::ClientRenderingAPI(ukm_params.source_id)
.SetCanvas_RenderingContextDrawnTo(static_cast<int>(canvasRenderingAPI))
.Record(ukm_params.ukm_recorder);
}
}
CanvasRenderingContext::ContextType CanvasRenderingContext::ContextTypeFromId(
const String& id) {
if (id == "2d")
return kContext2D;
if (id == "experimental-webgl")
return kContextExperimentalWebgl;
if (id == "webgl")
return kContextWebgl;
if (id == "webgl2")
return kContextWebgl2;
if (id == "bitmaprenderer")
return kContextImageBitmap;
if (id == "gpupresent" && RuntimeEnabledFeatures::WebGPUEnabled())
return kContextGPUPresent;
return kContextTypeUnknown;
}
CanvasRenderingContext::ContextType
CanvasRenderingContext::ResolveContextTypeAliases(
CanvasRenderingContext::ContextType type) {
if (type == kContextExperimentalWebgl)
return kContextWebgl;
return type;
}
bool CanvasRenderingContext::WouldTaintOrigin(CanvasImageSource* image_source) {
// Don't taint the canvas on data URLs. This special case is needed here
// because CanvasImageSource::WouldTaintOrigin() can return false for data
// URLs due to restrictions on SVG foreignObject nodes as described in
// https://crbug.com/294129.
// TODO(crbug.com/294129): Remove the restriction on foreignObject nodes, then
// this logic isn't needed, CanvasImageSource::SourceURL() isn't needed, and
// this function can just be image_source->WouldTaintOrigin().
const KURL& source_url = image_source->SourceURL();
const bool has_url = (source_url.IsValid() && !source_url.IsAboutBlankURL());
if (has_url && source_url.ProtocolIsData())
return false;
return image_source->WouldTaintOrigin();
}
void CanvasRenderingContext::Trace(Visitor* visitor) const {
visitor->Trace(host_);
ScriptWrappable::Trace(visitor);
}
void CanvasRenderingContext::StartListeningForDidProcessTask() {
if (listening_for_did_process_task_)
return;
listening_for_did_process_task_ = true;
Thread::Current()->AddTaskObserver(this);
}
void CanvasRenderingContext::StopListeningForDidProcessTask() {
if (!listening_for_did_process_task_)
return;
Thread::Current()->RemoveTaskObserver(this);
listening_for_did_process_task_ = false;
}
} // namespace blink