summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc
blob: 66271ef4cc5bbd8f0b8e9054b5c665289cbe8562 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Copyright 2016 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/modules/canvas/htmlcanvas/html_canvas_element_module.h"

#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
#include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h"
#include "third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_helpers.h"
#include "third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_module.h"
#include "third_party/blink/renderer/platform/instrumentation/histogram.h"

namespace blink {

void HTMLCanvasElementModule::getContext(
    HTMLCanvasElement& canvas,
    const String& type,
    const CanvasContextCreationAttributesModule* attributes,
    ExceptionState& exception_state,
    RenderingContext& result) {
  if (canvas.SurfaceLayerBridge() && !canvas.LowLatencyEnabled()) {
    // The existence of canvas surfaceLayerBridge indicates that
    // HTMLCanvasElement.transferControlToOffscreen() has been called.
    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                      "Cannot get context from a canvas that "
                                      "has transferred its control to "
                                      "offscreen.");
    return;
  }

  CanvasRenderingContext* context = canvas.GetCanvasRenderingContext(
      type, ToCanvasContextCreationAttributes(attributes));
  if (context)
    context->SetCanvasGetContextResult(result);
}

OffscreenCanvas* HTMLCanvasElementModule::transferControlToOffscreen(
    ExecutionContext* execution_context,
    HTMLCanvasElement& canvas,
    ExceptionState& exception_state) {
  OffscreenCanvas* offscreen_canvas = nullptr;
  if (canvas.SurfaceLayerBridge()) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kInvalidStateError,
        "Cannot transfer control from a canvas for more than one time.");
  } else {
    canvas.CreateLayer();
    offscreen_canvas = TransferControlToOffscreenInternal(
        execution_context, canvas, exception_state);
  }

  UMA_HISTOGRAM_BOOLEAN("Blink.OffscreenCanvas.TransferControlToOffscreen",
                        bool(offscreen_canvas));
  return offscreen_canvas;
}

OffscreenCanvas* HTMLCanvasElementModule::TransferControlToOffscreenInternal(
    ExecutionContext* execution_context,
    HTMLCanvasElement& canvas,
    ExceptionState& exception_state) {
  if (canvas.RenderingContext()) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kInvalidStateError,
        "Cannot transfer control from a canvas that has a rendering context.");
    return nullptr;
  }
  OffscreenCanvas* offscreen_canvas = OffscreenCanvas::Create(
      execution_context, canvas.width(), canvas.height());
  offscreen_canvas->SetFilterQuality(canvas.FilterQuality());

  // If this canvas is cross-origin, then the associated offscreen canvas
  // should prefer using the low-power GPU.
  LocalFrame* frame = canvas.GetDocument().GetFrame();
  if (!(frame && frame->IsCrossOriginSubframe()))
    offscreen_canvas->AllowHighPerformancePowerPreference();

  DOMNodeId canvas_id = DOMNodeIds::IdForNode(&canvas);
  offscreen_canvas->SetPlaceholderCanvasId(canvas_id);
  canvas.RegisterPlaceholderCanvas(static_cast<int>(canvas_id));

  SurfaceLayerBridge* bridge = canvas.SurfaceLayerBridge();
  if (bridge) {
    offscreen_canvas->SetFrameSinkId(bridge->GetFrameSinkId().client_id(),
                                     bridge->GetFrameSinkId().sink_id());
  }
  return offscreen_canvas;
}
}  // namespace blink