86e01a724e986e230778042aa66ef3dcb9d22333
[WebKit-https.git] / Source / WebCore / inspector / InspectorCanvas.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "InspectorCanvas.h"
28
29 #include "AffineTransform.h"
30 #include "CachedImage.h"
31 #include "CanvasGradient.h"
32 #include "CanvasPattern.h"
33 #include "CanvasRenderingContext2D.h"
34 #include "Document.h"
35 #include "FloatPoint.h"
36 #include "Frame.h"
37 #include "Gradient.h"
38 #include "HTMLCanvasElement.h"
39 #include "HTMLImageElement.h"
40 #include "HTMLVideoElement.h"
41 #include "Image.h"
42 #include "ImageBitmap.h"
43 #include "ImageBuffer.h"
44 #include "ImageData.h"
45 #include "InspectorDOMAgent.h"
46 #include "InspectorPageAgent.h"
47 #include "InstrumentingAgents.h"
48 #include "JSCanvasDirection.h"
49 #include "JSCanvasFillRule.h"
50 #include "JSCanvasLineCap.h"
51 #include "JSCanvasLineJoin.h"
52 #include "JSCanvasTextAlign.h"
53 #include "JSCanvasTextBaseline.h"
54 #include "JSImageSmoothingQuality.h"
55 #include "JSMainThreadExecState.h"
56 #include "Path2D.h"
57 #include "Pattern.h"
58 #include "RecordingSwizzleTypes.h"
59 #include "SVGPathUtilities.h"
60 #include "StringAdaptors.h"
61 #if ENABLE(WEBGL)
62 #include "WebGLRenderingContext.h"
63 #endif
64 #if ENABLE(WEBGL2)
65 #include "WebGL2RenderingContext.h"
66 #endif
67 #if ENABLE(WEBGPU)
68 #include "WebGPURenderingContext.h"
69 #endif
70 #include <inspector/IdentifiersFactory.h>
71 #include <inspector/ScriptCallStack.h>
72 #include <inspector/ScriptCallStackFactory.h>
73 #include <wtf/CurrentTime.h>
74
75
76 namespace WebCore {
77 using namespace Inspector;
78
79 Ref<InspectorCanvas> InspectorCanvas::create(HTMLCanvasElement& canvas, const String& cssCanvasName)
80 {
81     return adoptRef(*new InspectorCanvas(canvas, cssCanvasName));
82 }
83
84 InspectorCanvas::InspectorCanvas(HTMLCanvasElement& canvas, const String& cssCanvasName)
85     : m_identifier("canvas:" + IdentifiersFactory::createIdentifier())
86     , m_canvas(canvas)
87     , m_cssCanvasName(cssCanvasName)
88 {
89 }
90
91 InspectorCanvas::~InspectorCanvas()
92 {
93     resetRecordingData();
94 }
95
96 void InspectorCanvas::resetRecordingData()
97 {
98     m_initialState = nullptr;
99     m_frames = nullptr;
100     m_currentActions = nullptr;
101     m_actionNeedingSnapshot = nullptr;
102     m_serializedDuplicateData = nullptr;
103     m_indexedDuplicateData.clear();
104     m_bufferLimit = 100 * 1024 * 1024;
105     m_bufferUsed = 0;
106     m_singleFrame = true;
107
108     m_canvas.renderingContext()->setCallTracingActive(false);
109 }
110
111 bool InspectorCanvas::hasRecordingData() const
112 {
113     return m_initialState && m_frames;
114 }
115
116 static bool shouldSnapshotWebGLAction(const String& name)
117 {
118     return name == "clear"
119         || name == "drawArrays"
120         || name == "drawElements";
121 }
122
123 void InspectorCanvas::recordAction(const String& name, Vector<RecordCanvasActionVariant>&& parameters)
124 {
125     if (!hasRecordingData()) {
126         m_initialState = buildInitialState();
127         m_bufferUsed += m_initialState->memoryCost();
128
129         m_frames = Inspector::Protocol::Array<Inspector::Protocol::Recording::Frame>::create();
130     }
131
132     if (!m_currentActions) {
133         m_currentActions = Inspector::Protocol::Array<InspectorValue>::create();
134
135         auto frame = Inspector::Protocol::Recording::Frame::create()
136             .setActions(m_currentActions)
137             .release();
138
139         m_frames->addItem(WTFMove(frame));
140
141         m_currentFrameStartTime = monotonicallyIncreasingTimeMS();
142     }
143
144     appendActionSnapshotIfNeeded();
145
146     auto action = buildAction(name, WTFMove(parameters));
147     m_bufferUsed += action->memoryCost();
148     m_currentActions->addItem(action);
149
150 #if ENABLE(WEBGL)
151     if (is<WebGLRenderingContext>(m_canvas.renderingContext()) && shouldSnapshotWebGLAction(name))
152         m_actionNeedingSnapshot = action;
153 #endif
154 }
155
156 RefPtr<Inspector::Protocol::Recording::InitialState>&& InspectorCanvas::releaseInitialState()
157 {
158     return WTFMove(m_initialState);
159 }
160
161 RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Recording::Frame>>&& InspectorCanvas::releaseFrames()
162 {
163     appendActionSnapshotIfNeeded();
164
165     return WTFMove(m_frames);
166 }
167
168 RefPtr<Inspector::Protocol::Array<InspectorValue>>&& InspectorCanvas::releaseData()
169 {
170     m_indexedDuplicateData.clear();
171     return WTFMove(m_serializedDuplicateData);
172 }
173
174 void InspectorCanvas::finalizeFrame()
175 {
176     if (m_frames->length() && !std::isnan(m_currentFrameStartTime)) {
177         auto currentFrame = static_cast<Inspector::Protocol::Recording::Frame*>(m_frames->get(m_frames->length() - 1).get());
178         currentFrame->setDuration(monotonicallyIncreasingTimeMS() - m_currentFrameStartTime);
179
180         m_currentFrameStartTime = NAN;
181     }
182
183     m_currentActions = nullptr;
184 }
185
186 void InspectorCanvas::markCurrentFrameIncomplete()
187 {
188     if (!m_currentActions)
189         return;
190
191     static_cast<Inspector::Protocol::Recording::Frame*>(m_frames->get(m_frames->length() - 1).get())->setIncomplete(true);
192 }
193
194 void InspectorCanvas::setBufferLimit(long memoryLimit)
195 {
196     m_bufferLimit = std::min<long>(memoryLimit, std::numeric_limits<int>::max());
197 }
198
199 bool InspectorCanvas::hasBufferSpace() const
200 {
201     return m_bufferUsed < m_bufferLimit;
202 }
203
204 Ref<Inspector::Protocol::Canvas::Canvas> InspectorCanvas::buildObjectForCanvas(InstrumentingAgents& instrumentingAgents, bool captureBacktrace)
205 {
206     Document& document = m_canvas.document();
207     Frame* frame = document.frame();
208     CanvasRenderingContext* context = m_canvas.renderingContext();
209
210     Inspector::Protocol::Canvas::ContextType contextType;
211     if (is<CanvasRenderingContext2D>(context))
212         contextType = Inspector::Protocol::Canvas::ContextType::Canvas2D;
213 #if ENABLE(WEBGL)
214     else if (is<WebGLRenderingContext>(context))
215         contextType = Inspector::Protocol::Canvas::ContextType::WebGL;
216 #endif
217 #if ENABLE(WEBGL2)
218     else if (is<WebGL2RenderingContext>(context))
219         contextType = Inspector::Protocol::Canvas::ContextType::WebGL2;
220 #endif
221 #if ENABLE(WEBGPU)
222     else if (is<WebGPURenderingContext>(context))
223         contextType = Inspector::Protocol::Canvas::ContextType::WebGPU;
224 #endif
225     else {
226         ASSERT_NOT_REACHED();
227         contextType = Inspector::Protocol::Canvas::ContextType::Canvas2D;
228     }
229
230     auto canvas = Inspector::Protocol::Canvas::Canvas::create()
231         .setCanvasId(m_identifier)
232         .setFrameId(instrumentingAgents.inspectorPageAgent()->frameId(frame))
233         .setContextType(contextType)
234         .release();
235
236     if (!m_cssCanvasName.isEmpty())
237         canvas->setCssCanvasName(m_cssCanvasName);
238     else {
239         InspectorDOMAgent* domAgent = instrumentingAgents.inspectorDOMAgent();
240         int nodeId = domAgent->boundNodeId(&m_canvas);
241         if (!nodeId) {
242             if (int documentNodeId = domAgent->boundNodeId(&m_canvas.document())) {
243                 ErrorString ignored;
244                 nodeId = domAgent->pushNodeToFrontend(ignored, documentNodeId, &m_canvas);
245             }
246         }
247
248         if (nodeId)
249             canvas->setNodeId(nodeId);
250     }
251
252 #if ENABLE(WEBGL)
253     if (is<WebGLRenderingContextBase>(context)) {
254         if (std::optional<WebGLContextAttributes> attributes = downcast<WebGLRenderingContextBase>(context)->getContextAttributes()) {
255             canvas->setContextAttributes(Inspector::Protocol::Canvas::ContextAttributes::create()
256                 .setAlpha(attributes->alpha)
257                 .setDepth(attributes->depth)
258                 .setStencil(attributes->stencil)
259                 .setAntialias(attributes->antialias)
260                 .setPremultipliedAlpha(attributes->premultipliedAlpha)
261                 .setPreserveDrawingBuffer(attributes->preserveDrawingBuffer)
262                 .setFailIfMajorPerformanceCaveat(attributes->failIfMajorPerformanceCaveat)
263                 .release());
264         }
265     }
266 #endif
267
268     if (size_t memoryCost = m_canvas.memoryCost())
269         canvas->setMemoryCost(memoryCost);
270
271     if (captureBacktrace) {
272         auto stackTrace = Inspector::createScriptCallStack(JSMainThreadExecState::currentState(), Inspector::ScriptCallStack::maxCallStackSizeToCapture);
273         canvas->setBacktrace(stackTrace->buildInspectorArray());
274     }
275
276     return canvas;
277 }
278
279 void InspectorCanvas::appendActionSnapshotIfNeeded()
280 {
281     if (!m_actionNeedingSnapshot)
282         return;
283
284     m_actionNeedingSnapshot->addItem(indexForData(getCanvasContentAsDataURL()));
285     m_actionNeedingSnapshot = nullptr;
286 }
287
288 String InspectorCanvas::getCanvasContentAsDataURL()
289 {
290 #if ENABLE(WEBGL)
291     CanvasRenderingContext* canvasRenderingContext = m_canvas.renderingContext();
292     if (is<WebGLRenderingContextBase>(canvasRenderingContext))
293         downcast<WebGLRenderingContextBase>(canvasRenderingContext)->setPreventBufferClearForInspector(true);
294 #endif
295
296     ExceptionOr<UncachedString> result = m_canvas.toDataURL(ASCIILiteral("image/png"));
297
298 #if ENABLE(WEBGL)
299     if (is<WebGLRenderingContextBase>(canvasRenderingContext))
300         downcast<WebGLRenderingContextBase>(canvasRenderingContext)->setPreventBufferClearForInspector(false);
301 #endif
302
303     if (result.hasException())
304         return String();
305
306     return result.releaseReturnValue().string;
307 }
308
309 int InspectorCanvas::indexForData(DuplicateDataVariant data)
310 {
311     size_t index = m_indexedDuplicateData.find(data);
312     if (index != notFound) {
313         ASSERT(index < std::numeric_limits<int>::max());
314         return static_cast<int>(index);
315     }
316
317     if (!m_serializedDuplicateData)
318         m_serializedDuplicateData = Inspector::Protocol::Array<InspectorValue>::create();
319
320     RefPtr<InspectorValue> item;
321     WTF::switchOn(data,
322         [&] (const HTMLImageElement* imageElement) {
323             String dataURL = ASCIILiteral("data:,");
324
325             if (CachedImage* cachedImage = imageElement->cachedImage()) {
326                 Image* image = cachedImage->image();
327                 if (image && image != &Image::nullImage()) {
328                     std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(image->size(), RenderingMode::Unaccelerated);
329                     imageBuffer->context().drawImage(*image, FloatPoint(0, 0));
330                     dataURL = imageBuffer->toDataURL("image/png");
331                 }
332             }
333
334             item = InspectorValue::create(dataURL);
335         },
336 #if ENABLE(VIDEO)
337         [&] (HTMLVideoElement* videoElement) {
338             String dataURL = ASCIILiteral("data:,");
339
340             unsigned videoWidth = videoElement->videoWidth();
341             unsigned videoHeight = videoElement->videoHeight();
342             std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(FloatSize(videoWidth, videoHeight), RenderingMode::Unaccelerated);
343             if (imageBuffer) {
344                 videoElement->paintCurrentFrameInContext(imageBuffer->context(), FloatRect(0, 0, videoWidth, videoHeight));
345                 dataURL = imageBuffer->toDataURL("image/png");
346             }
347
348             item = InspectorValue::create(dataURL);
349         },
350 #endif
351         [&] (HTMLCanvasElement* canvasElement) {
352             String dataURL = ASCIILiteral("data:,");
353
354             ExceptionOr<UncachedString> result = canvasElement->toDataURL(ASCIILiteral("image/png"));
355             if (!result.hasException())
356                 dataURL = result.releaseReturnValue().string;
357
358             item = InspectorValue::create(dataURL);
359         },
360         [&] (const CanvasGradient* canvasGradient) { item = buildArrayForCanvasGradient(*canvasGradient); },
361         [&] (const CanvasPattern* canvasPattern) { item = buildArrayForCanvasPattern(*canvasPattern); },
362         [&] (const ImageData* imageData) { item = buildArrayForImageData(*imageData); },
363         [&] (const ImageBitmap* imageBitmap) { item = buildArrayForImageBitmap(*imageBitmap); },
364         [&] (const ScriptCallFrame& scriptCallFrame) {
365             auto array = Inspector::Protocol::Array<double>::create();
366             array->addItem(indexForData(scriptCallFrame.functionName()));
367             array->addItem(indexForData(scriptCallFrame.sourceURL()));
368             array->addItem(static_cast<int>(scriptCallFrame.lineNumber()));
369             array->addItem(static_cast<int>(scriptCallFrame.columnNumber()));
370             item = WTFMove(array);
371         },
372         [&] (const String& value) { item = InspectorValue::create(value); }
373     );
374
375     m_bufferUsed += item->memoryCost();
376     m_serializedDuplicateData->addItem(WTFMove(item));
377
378     m_indexedDuplicateData.append(data);
379     index = m_indexedDuplicateData.size() - 1;
380
381     ASSERT(index < std::numeric_limits<int>::max());
382     return static_cast<int>(index);
383 }
384
385 static RefPtr<Inspector::Protocol::Array<double>> buildArrayForAffineTransform(const AffineTransform& affineTransform)
386 {
387     RefPtr<Inspector::Protocol::Array<double>> array = Inspector::Protocol::Array<double>::create();
388     array->addItem(affineTransform.a());
389     array->addItem(affineTransform.b());
390     array->addItem(affineTransform.c());
391     array->addItem(affineTransform.d());
392     array->addItem(affineTransform.e());
393     array->addItem(affineTransform.f());
394     return array;
395 }
396
397 template <typename T>
398 static RefPtr<Inspector::Protocol::Array<InspectorValue>> buildArrayForVector(const Vector<T>& vector)
399 {
400     RefPtr<Inspector::Protocol::Array<InspectorValue>> array = Inspector::Protocol::Array<InspectorValue>::create();
401     for (auto& item : vector)
402         array->addItem(item);
403     return array;
404 }
405
406 RefPtr<Inspector::Protocol::Recording::InitialState> InspectorCanvas::buildInitialState()
407 {
408     RefPtr<Inspector::Protocol::Recording::InitialState> initialState = Inspector::Protocol::Recording::InitialState::create()
409         .release();
410
411     auto attributes = InspectorObject::create();
412     attributes->setInteger(ASCIILiteral("width"), canvas().width());
413     attributes->setInteger(ASCIILiteral("height"), canvas().height());
414
415     auto parameters = Inspector::Protocol::Array<InspectorValue>::create();
416
417     CanvasRenderingContext* canvasRenderingContext = canvas().renderingContext();
418     if (is<CanvasRenderingContext2D>(canvasRenderingContext)) {
419         const CanvasRenderingContext2D* context2d = downcast<CanvasRenderingContext2D>(canvasRenderingContext);
420         const CanvasRenderingContext2D::State& state = context2d->state();
421
422         attributes->setArray(ASCIILiteral("setTransform"), buildArrayForAffineTransform(state.transform));
423         attributes->setDouble(ASCIILiteral("globalAlpha"), context2d->globalAlpha());
424         attributes->setInteger(ASCIILiteral("globalCompositeOperation"), indexForData(context2d->globalCompositeOperation()));
425         attributes->setDouble(ASCIILiteral("lineWidth"), context2d->lineWidth());
426         attributes->setInteger(ASCIILiteral("lineCap"), indexForData(convertEnumerationToString(context2d->lineCap())));
427         attributes->setInteger(ASCIILiteral("lineJoin"), indexForData(convertEnumerationToString(context2d->lineJoin())));
428         attributes->setDouble(ASCIILiteral("miterLimit"), context2d->miterLimit());
429         attributes->setDouble(ASCIILiteral("shadowOffsetX"), context2d->shadowOffsetX());
430         attributes->setDouble(ASCIILiteral("shadowOffsetY"), context2d->shadowOffsetY());
431         attributes->setDouble(ASCIILiteral("shadowBlur"), context2d->shadowBlur());
432         attributes->setInteger(ASCIILiteral("shadowColor"), indexForData(context2d->shadowColor()));
433
434         // The parameter to `setLineDash` is itself an array, so we need to wrap the parameters
435         // list in an array to allow spreading.
436         auto setLineDash = Inspector::Protocol::Array<InspectorValue>::create();
437         setLineDash->addItem(buildArrayForVector(state.lineDash));
438         attributes->setArray(ASCIILiteral("setLineDash"), WTFMove(setLineDash));
439
440         attributes->setDouble(ASCIILiteral("lineDashOffset"), context2d->lineDashOffset());
441         attributes->setInteger(ASCIILiteral("font"), indexForData(context2d->font()));
442         attributes->setInteger(ASCIILiteral("textAlign"), indexForData(convertEnumerationToString(context2d->textAlign())));
443         attributes->setInteger(ASCIILiteral("textBaseline"), indexForData(convertEnumerationToString(context2d->textBaseline())));
444         attributes->setInteger(ASCIILiteral("direction"), indexForData(convertEnumerationToString(context2d->direction())));
445
446         int strokeStyleIndex;
447         if (CanvasGradient* canvasGradient = state.strokeStyle.canvasGradient())
448             strokeStyleIndex = indexForData(canvasGradient);
449         else if (CanvasPattern* canvasPattern = state.strokeStyle.canvasPattern())
450             strokeStyleIndex = indexForData(canvasPattern);
451         else
452             strokeStyleIndex = indexForData(state.strokeStyle.color());
453         attributes->setInteger(ASCIILiteral("strokeStyle"), strokeStyleIndex);
454
455         int fillStyleIndex;
456         if (CanvasGradient* canvasGradient = state.fillStyle.canvasGradient())
457             fillStyleIndex = indexForData(canvasGradient);
458         else if (CanvasPattern* canvasPattern = state.fillStyle.canvasPattern())
459             fillStyleIndex = indexForData(canvasPattern);
460         else
461             fillStyleIndex = indexForData(state.fillStyle.color());
462         attributes->setInteger(ASCIILiteral("fillStyle"), fillStyleIndex);
463
464         attributes->setBoolean(ASCIILiteral("imageSmoothingEnabled"), context2d->imageSmoothingEnabled());
465         attributes->setInteger(ASCIILiteral("imageSmoothingQuality"), indexForData(convertEnumerationToString(context2d->imageSmoothingQuality())));
466
467         auto setPath = Inspector::Protocol::Array<InspectorValue>::create();
468         setPath->addItem(indexForData(buildStringFromPath(context2d->getPath()->path())));
469         attributes->setArray(ASCIILiteral("setPath"), WTFMove(setPath));
470     }
471 #if ENABLE(WEBGL)
472     else if (is<WebGLRenderingContextBase>(canvasRenderingContext)) {
473         WebGLRenderingContextBase* contextWebGLBase = downcast<WebGLRenderingContextBase>(canvasRenderingContext);
474         if (std::optional<WebGLContextAttributes> attributes = contextWebGLBase->getContextAttributes()) {
475             RefPtr<InspectorObject> contextAttributes = InspectorObject::create();
476             contextAttributes->setBoolean(ASCIILiteral("alpha"), attributes->alpha);
477             contextAttributes->setBoolean(ASCIILiteral("depth"), attributes->depth);
478             contextAttributes->setBoolean(ASCIILiteral("stencil"), attributes->stencil);
479             contextAttributes->setBoolean(ASCIILiteral("antialias"), attributes->antialias);
480             contextAttributes->setBoolean(ASCIILiteral("premultipliedAlpha"), attributes->premultipliedAlpha);
481             contextAttributes->setBoolean(ASCIILiteral("preserveDrawingBuffer"), attributes->preserveDrawingBuffer);
482             contextAttributes->setBoolean(ASCIILiteral("failIfMajorPerformanceCaveat"), attributes->failIfMajorPerformanceCaveat);
483             parameters->addItem(WTFMove(contextAttributes));
484         }
485     }
486 #endif
487
488     initialState->setAttributes(WTFMove(attributes));
489
490     if (parameters->length())
491         initialState->setParameters(WTFMove(parameters));
492
493     initialState->setContent(getCanvasContentAsDataURL());
494
495     return initialState;
496 }
497
498 RefPtr<Inspector::Protocol::Array<Inspector::InspectorValue>> InspectorCanvas::buildAction(const String& name, Vector<RecordCanvasActionVariant>&& parameters)
499 {
500     RefPtr<Inspector::Protocol::Array<InspectorValue>> action = Inspector::Protocol::Array<InspectorValue>::create();
501     action->addItem(indexForData(name));
502
503     RefPtr<Inspector::Protocol::Array<InspectorValue>> parametersData = Inspector::Protocol::Array<Inspector::InspectorValue>::create();
504     RefPtr<Inspector::Protocol::Array<int>> swizzleTypes = Inspector::Protocol::Array<int>::create();
505
506     auto addParameter = [&parametersData, &swizzleTypes] (auto value, RecordingSwizzleTypes swizzleType) {
507         parametersData->addItem(value);
508         swizzleTypes->addItem(static_cast<int>(swizzleType));
509     };
510
511     for (RecordCanvasActionVariant& item : parameters) {
512         WTF::switchOn(item,
513             [&] (CanvasDirection value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
514             [&] (CanvasFillRule value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
515             [&] (CanvasLineCap value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
516             [&] (CanvasLineJoin value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
517             [&] (CanvasTextAlign value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
518             [&] (CanvasTextBaseline value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
519             [&] (const DOMMatrix2DInit& value) {
520                 RefPtr<Inspector::Protocol::Array<double>> array = Inspector::Protocol::Array<double>::create();
521                 array->addItem(value.a.value_or(1));
522                 array->addItem(value.b.value_or(0));
523                 array->addItem(value.c.value_or(0));
524                 array->addItem(value.d.value_or(1));
525                 array->addItem(value.e.value_or(0));
526                 array->addItem(value.f.value_or(0));
527                 addParameter(WTFMove(array), RecordingSwizzleTypes::DOMMatrix);
528             },
529             [&] (const Element*) {
530                 // Elements are not serializable, so add a string as a placeholder since the actual
531                 // element cannot be reconstructed in the frontend.
532                 addParameter(indexForData("Element"), RecordingSwizzleTypes::None);
533             },
534             [&] (HTMLImageElement* value) { addParameter(indexForData(value), RecordingSwizzleTypes::Image); },
535             [&] (ImageData* value) { addParameter(indexForData(value), RecordingSwizzleTypes::ImageData); },
536             [&] (ImageSmoothingQuality value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
537             [&] (const Path2D* value) { addParameter(indexForData(buildStringFromPath(value->path())), RecordingSwizzleTypes::Path2D); },
538 #if ENABLE(WEBGL)
539             // FIXME: <https://webkit.org/b/176009> Web Inspector: send data for WebGL objects during a recording instead of a placeholder string
540             [&] (const WebGLBuffer*) { addParameter(0, RecordingSwizzleTypes::WebGLBuffer); },
541             [&] (const WebGLFramebuffer*) { addParameter(0, RecordingSwizzleTypes::WebGLFramebuffer); },
542             [&] (const WebGLProgram*) { addParameter(0, RecordingSwizzleTypes::WebGLProgram); },
543             [&] (const WebGLRenderbuffer*) { addParameter(0, RecordingSwizzleTypes::WebGLRenderbuffer); },
544             [&] (const WebGLShader*) { addParameter(0, RecordingSwizzleTypes::WebGLShader); },
545             [&] (const WebGLTexture*) { addParameter(0, RecordingSwizzleTypes::WebGLTexture); },
546             [&] (const WebGLUniformLocation*) { addParameter(0, RecordingSwizzleTypes::WebGLUniformLocation); },
547 #endif
548             [&] (const RefPtr<ArrayBuffer>&) { addParameter(0, RecordingSwizzleTypes::TypedArray); },
549             [&] (const RefPtr<ArrayBufferView>&) { addParameter(0, RecordingSwizzleTypes::TypedArray); },
550             [&] (const RefPtr<CanvasGradient>& value) { addParameter(indexForData(value.get()), RecordingSwizzleTypes::CanvasGradient); },
551             [&] (const RefPtr<CanvasPattern>& value) { addParameter(indexForData(value.get()), RecordingSwizzleTypes::CanvasPattern); },
552             [&] (const RefPtr<Float32Array>&) { addParameter(0, RecordingSwizzleTypes::TypedArray); },
553             [&] (RefPtr<HTMLCanvasElement>& value) { addParameter(indexForData(value.get()), RecordingSwizzleTypes::Image); },
554             [&] (const RefPtr<HTMLImageElement>& value) { addParameter(indexForData(value.get()), RecordingSwizzleTypes::Image); },
555 #if ENABLE(VIDEO)
556             [&] (RefPtr<HTMLVideoElement>& value) { addParameter(indexForData(value.get()), RecordingSwizzleTypes::Image); },
557 #endif
558             [&] (const RefPtr<ImageBitmap>& value) { addParameter(indexForData(value.get()), RecordingSwizzleTypes::ImageBitmap); },
559             [&] (const RefPtr<ImageData>& value) { addParameter(indexForData(value.get()), RecordingSwizzleTypes::ImageData); },
560             [&] (const RefPtr<Int32Array>&) { addParameter(0, RecordingSwizzleTypes::TypedArray); },
561             [&] (const Vector<float>& value) { addParameter(buildArrayForVector(value), RecordingSwizzleTypes::Array); },
562             [&] (const Vector<int>& value) { addParameter(buildArrayForVector(value), RecordingSwizzleTypes::Array); },
563             [&] (const String& value) { addParameter(indexForData(value), RecordingSwizzleTypes::String); },
564             [&] (double value) { addParameter(value, RecordingSwizzleTypes::Number); },
565             [&] (float value) { addParameter(value, RecordingSwizzleTypes::Number); },
566             [&] (int64_t value) { addParameter(static_cast<double>(value), RecordingSwizzleTypes::Number); },
567             [&] (uint32_t value) { addParameter(static_cast<double>(value), RecordingSwizzleTypes::Number); },
568             [&] (int32_t value) { addParameter(value, RecordingSwizzleTypes::Number); },
569             [&] (uint8_t value) { addParameter(static_cast<int>(value), RecordingSwizzleTypes::Number); },
570             [&] (bool value) { addParameter(value, RecordingSwizzleTypes::Boolean); }
571         );
572     }
573
574     action->addItem(WTFMove(parametersData));
575     action->addItem(WTFMove(swizzleTypes));
576
577     RefPtr<Inspector::Protocol::Array<double>> trace = Inspector::Protocol::Array<double>::create();
578     auto stackTrace = Inspector::createScriptCallStack(JSMainThreadExecState::currentState(), Inspector::ScriptCallStack::maxCallStackSizeToCapture);
579     for (size_t i = 0; i < stackTrace->size(); ++i)
580         trace->addItem(indexForData(stackTrace->at(i)));
581     action->addItem(WTFMove(trace));
582
583     return action;
584 }
585
586 RefPtr<Inspector::Protocol::Array<InspectorValue>> InspectorCanvas::buildArrayForCanvasGradient(const CanvasGradient& canvasGradient)
587 {
588     const Gradient& gradient = canvasGradient.gradient();
589     bool isRadial = gradient.isRadial();
590
591     String type = isRadial ? ASCIILiteral("radial-gradient") : ASCIILiteral("linear-gradient");
592
593     RefPtr<Inspector::Protocol::Array<float>> parameters = Inspector::Protocol::Array<float>::create();
594     parameters->addItem(gradient.p0().x());
595     parameters->addItem(gradient.p0().y());
596     if (isRadial)
597         parameters->addItem(gradient.startRadius());
598     parameters->addItem(gradient.p1().x());
599     parameters->addItem(gradient.p1().y());
600     if (isRadial)
601         parameters->addItem(gradient.endRadius());
602
603     RefPtr<Inspector::Protocol::Array<InspectorValue>> stops = Inspector::Protocol::Array<InspectorValue>::create();
604     for (const Gradient::ColorStop& colorStop : gradient.stops()) {
605         RefPtr<Inspector::Protocol::Array<InspectorValue>> stop = Inspector::Protocol::Array<InspectorValue>::create();
606         stop->addItem(colorStop.offset);
607         stop->addItem(indexForData(colorStop.color.cssText()));
608         stops->addItem(WTFMove(stop));
609     }
610
611     RefPtr<Inspector::Protocol::Array<Inspector::InspectorValue>> array = Inspector::Protocol::Array<Inspector::InspectorValue>::create();
612     array->addItem(indexForData(type));
613     array->addItem(WTFMove(parameters));
614     array->addItem(WTFMove(stops));
615     return array;
616 }
617
618 RefPtr<Inspector::Protocol::Array<InspectorValue>> InspectorCanvas::buildArrayForCanvasPattern(const CanvasPattern& canvasPattern)
619 {
620     Image& tileImage = canvasPattern.pattern().tileImage();
621     std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(tileImage.size(), RenderingMode::Unaccelerated);
622     imageBuffer->context().drawImage(tileImage, FloatPoint(0, 0));
623
624     String repeat;
625     bool repeatX = canvasPattern.pattern().repeatX();
626     bool repeatY = canvasPattern.pattern().repeatY();
627     if (repeatX && repeatY)
628         repeat = ASCIILiteral("repeat");
629     else if (repeatX && !repeatY)
630         repeat = ASCIILiteral("repeat-x");
631     else if (!repeatX && repeatY)
632         repeat = ASCIILiteral("repeat-y");
633     else
634         repeat = ASCIILiteral("no-repeat");
635
636     RefPtr<Inspector::Protocol::Array<Inspector::InspectorValue>> array = Inspector::Protocol::Array<Inspector::InspectorValue>::create();
637     array->addItem(indexForData(imageBuffer->toDataURL("image/png")));
638     array->addItem(indexForData(repeat));
639     return array;
640 }
641
642 RefPtr<Inspector::Protocol::Array<InspectorValue>> InspectorCanvas::buildArrayForImageData(const ImageData& imageData)
643 {
644     RefPtr<Inspector::Protocol::Array<int>> data = Inspector::Protocol::Array<int>::create();
645     for (size_t i = 0; i < imageData.data()->length(); ++i)
646         data->addItem(imageData.data()->item(i));
647
648     RefPtr<Inspector::Protocol::Array<Inspector::InspectorValue>> array = Inspector::Protocol::Array<Inspector::InspectorValue>::create();
649     array->addItem(WTFMove(data));
650     array->addItem(imageData.width());
651     array->addItem(imageData.height());
652     return array;
653 }
654
655 RefPtr<Inspector::Protocol::Array<InspectorValue>> InspectorCanvas::buildArrayForImageBitmap(const ImageBitmap& imageBitmap)
656 {
657     // FIXME: Needs to include the data somehow.
658     RefPtr<Inspector::Protocol::Array<Inspector::InspectorValue>> array = Inspector::Protocol::Array<Inspector::InspectorValue>::create();
659     array->addItem(static_cast<int>(imageBitmap.width()));
660     array->addItem(static_cast<int>(imageBitmap.height()));
661     return array;
662 }
663
664 } // namespace WebCore
665