[Mac] Regression: WebContent process's display name is no longer set
[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 "CanvasRenderingContext.h"
34 #include "CanvasRenderingContext2D.h"
35 #include "Document.h"
36 #include "FloatPoint.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 "ImageBitmapRenderingContext.h"
44 #include "ImageBuffer.h"
45 #include "ImageData.h"
46 #include "InspectorDOMAgent.h"
47 #include "JSCanvasDirection.h"
48 #include "JSCanvasFillRule.h"
49 #include "JSCanvasLineCap.h"
50 #include "JSCanvasLineJoin.h"
51 #include "JSCanvasTextAlign.h"
52 #include "JSCanvasTextBaseline.h"
53 #include "JSExecState.h"
54 #include "JSImageSmoothingQuality.h"
55 #include "Path2D.h"
56 #include "Pattern.h"
57 #include "RecordingSwizzleTypes.h"
58 #include "SVGPathUtilities.h"
59 #include "StringAdaptors.h"
60 #if ENABLE(WEBGL)
61 #include "WebGLRenderingContext.h"
62 #endif
63 #if ENABLE(WEBGL2)
64 #include "WebGL2RenderingContext.h"
65 #endif
66 #if ENABLE(WEBMETAL)
67 #include "WebMetalRenderingContext.h"
68 #endif
69 #include <JavaScriptCore/IdentifiersFactory.h>
70 #include <JavaScriptCore/ScriptCallStackFactory.h>
71
72 namespace WebCore {
73
74 using namespace Inspector;
75
76 Ref<InspectorCanvas> InspectorCanvas::create(CanvasRenderingContext& context)
77 {
78     return adoptRef(*new InspectorCanvas(context));
79 }
80
81 InspectorCanvas::InspectorCanvas(CanvasRenderingContext& context)
82     : m_identifier("canvas:" + IdentifiersFactory::createIdentifier())
83     , m_context(context)
84 {
85 }
86
87 HTMLCanvasElement* InspectorCanvas::canvasElement()
88 {
89     auto* canvasBase = &m_context.canvasBase();
90     if (is<HTMLCanvasElement>(canvasBase))
91         return downcast<HTMLCanvasElement>(canvasBase);
92     return nullptr;
93 }
94
95 void InspectorCanvas::resetRecordingData()
96 {
97     m_initialState = nullptr;
98     m_frames = nullptr;
99     m_currentActions = nullptr;
100     m_actionNeedingSnapshot = nullptr;
101     m_serializedDuplicateData = nullptr;
102     m_indexedDuplicateData.clear();
103     m_recordingName = { };
104     m_bufferLimit = 100 * 1024 * 1024;
105     m_bufferUsed = 0;
106     m_frameCount = std::nullopt;
107     m_framesCaptured = 0;
108
109     m_context.setCallTracingActive(false);
110 }
111
112 bool InspectorCanvas::hasRecordingData() const
113 {
114     return m_bufferUsed > 0;
115 }
116
117 bool InspectorCanvas::currentFrameHasData() const
118 {
119     return !!m_frames;
120 }
121
122 static bool shouldSnapshotBitmapRendererAction(const String& name)
123 {
124     return name == "transferFromImageBitmap";
125 }
126
127 static bool shouldSnapshotWebGLAction(const String& name)
128 {
129     return name == "clear"
130         || name == "drawArrays"
131         || name == "drawElements";
132 }
133
134 void InspectorCanvas::recordAction(const String& name, Vector<RecordCanvasActionVariant>&& parameters)
135 {
136     if (!m_initialState) {
137         m_initialState = buildInitialState();
138         m_bufferUsed += m_initialState->memoryCost();
139     }
140
141     if (!m_frames)
142         m_frames = JSON::ArrayOf<Inspector::Protocol::Recording::Frame>::create();
143
144     if (!m_currentActions) {
145         m_currentActions = JSON::ArrayOf<JSON::Value>::create();
146
147         auto frame = Inspector::Protocol::Recording::Frame::create()
148             .setActions(m_currentActions)
149             .release();
150
151         m_frames->addItem(WTFMove(frame));
152         ++m_framesCaptured;
153
154         m_currentFrameStartTime = MonotonicTime::now();
155     }
156
157     appendActionSnapshotIfNeeded();
158
159     auto action = buildAction(name, WTFMove(parameters));
160     m_bufferUsed += action->memoryCost();
161     m_currentActions->addItem(action.ptr());
162
163     if (is<ImageBitmapRenderingContext>(m_context) && shouldSnapshotBitmapRendererAction(name))
164         m_actionNeedingSnapshot = WTFMove(action);
165 #if ENABLE(WEBGL)
166     else if (is<WebGLRenderingContext>(m_context) && shouldSnapshotWebGLAction(name))
167         m_actionNeedingSnapshot = WTFMove(action);
168 #endif
169 }
170
171 RefPtr<Inspector::Protocol::Recording::InitialState>&& InspectorCanvas::releaseInitialState()
172 {
173     return WTFMove(m_initialState);
174 }
175
176 RefPtr<JSON::ArrayOf<Inspector::Protocol::Recording::Frame>>&& InspectorCanvas::releaseFrames()
177 {
178     appendActionSnapshotIfNeeded();
179
180     return WTFMove(m_frames);
181 }
182
183 RefPtr<JSON::ArrayOf<JSON::Value>>&& InspectorCanvas::releaseData()
184 {
185     m_indexedDuplicateData.clear();
186     return WTFMove(m_serializedDuplicateData);
187 }
188
189 void InspectorCanvas::finalizeFrame()
190 {
191     if (m_frames && m_frames->length() && !std::isnan(m_currentFrameStartTime)) {
192         auto currentFrame = static_cast<Inspector::Protocol::Recording::Frame*>(m_frames->get(m_frames->length() - 1).get());
193         currentFrame->setDuration((MonotonicTime::now() - m_currentFrameStartTime).milliseconds());
194
195         m_currentFrameStartTime = MonotonicTime::nan();
196     }
197
198     m_currentActions = nullptr;
199 }
200
201 void InspectorCanvas::markCurrentFrameIncomplete()
202 {
203     if (!m_currentActions || !m_frames || !m_frames->length())
204         return;
205
206     static_cast<Inspector::Protocol::Recording::Frame*>(m_frames->get(m_frames->length() - 1).get())->setIncomplete(true);
207 }
208
209 void InspectorCanvas::setBufferLimit(long memoryLimit)
210 {
211     m_bufferLimit = std::min<long>(memoryLimit, std::numeric_limits<int>::max());
212 }
213
214 bool InspectorCanvas::hasBufferSpace() const
215 {
216     return m_bufferUsed < m_bufferLimit;
217 }
218
219 void InspectorCanvas::setFrameCount(long frameCount)
220 {
221     if (frameCount > 0)
222         m_frameCount = std::min<long>(frameCount, std::numeric_limits<int>::max());
223     else
224         m_frameCount = std::nullopt;
225 }
226
227 bool InspectorCanvas::overFrameCount() const
228 {
229     return m_frameCount && m_framesCaptured >= m_frameCount.value();
230 }
231
232 Ref<Inspector::Protocol::Canvas::Canvas> InspectorCanvas::buildObjectForCanvas(bool captureBacktrace)
233 {
234     Inspector::Protocol::Canvas::ContextType contextType;
235     if (is<CanvasRenderingContext2D>(m_context))
236         contextType = Inspector::Protocol::Canvas::ContextType::Canvas2D;
237     else if (is<ImageBitmapRenderingContext>(m_context))
238         contextType = Inspector::Protocol::Canvas::ContextType::BitmapRenderer;
239 #if ENABLE(WEBGL)
240     else if (is<WebGLRenderingContext>(m_context))
241         contextType = Inspector::Protocol::Canvas::ContextType::WebGL;
242 #endif
243 #if ENABLE(WEBGL2)
244     else if (is<WebGL2RenderingContext>(m_context))
245         contextType = Inspector::Protocol::Canvas::ContextType::WebGL2;
246 #endif
247 #if ENABLE(WEBMETAL)
248     else if (is<WebMetalRenderingContext>(m_context))
249         contextType = Inspector::Protocol::Canvas::ContextType::WebMetal;
250 #endif
251     else {
252         ASSERT_NOT_REACHED();
253         contextType = Inspector::Protocol::Canvas::ContextType::Canvas2D;
254     }
255
256     auto canvas = Inspector::Protocol::Canvas::Canvas::create()
257         .setCanvasId(m_identifier)
258         .setContextType(contextType)
259         .release();
260
261     if (auto* node = canvasElement()) {
262         String cssCanvasName = node->document().nameForCSSCanvasElement(*node);
263         if (!cssCanvasName.isEmpty())
264             canvas->setCssCanvasName(cssCanvasName);
265
266         // FIXME: <https://webkit.org/b/178282> Web Inspector: send a DOM node with each Canvas payload and eliminate Canvas.requestNode
267     }
268
269     if (is<ImageBitmapRenderingContext>(m_context)) {
270         auto contextAttributes = Inspector::Protocol::Canvas::ContextAttributes::create()
271             .release();
272         contextAttributes->setAlpha(downcast<ImageBitmapRenderingContext>(m_context).hasAlpha());
273         canvas->setContextAttributes(WTFMove(contextAttributes));
274     }
275 #if ENABLE(WEBGL)
276     else if (is<WebGLRenderingContextBase>(m_context)) {
277         if (std::optional<WebGLContextAttributes> attributes = downcast<WebGLRenderingContextBase>(m_context).getContextAttributes()) {
278             auto contextAttributes = Inspector::Protocol::Canvas::ContextAttributes::create()
279                 .release();
280             contextAttributes->setAlpha(attributes->alpha);
281             contextAttributes->setDepth(attributes->depth);
282             contextAttributes->setStencil(attributes->stencil);
283             contextAttributes->setAntialias(attributes->antialias);
284             contextAttributes->setPremultipliedAlpha(attributes->premultipliedAlpha);
285             contextAttributes->setPreserveDrawingBuffer(attributes->preserveDrawingBuffer);
286             contextAttributes->setFailIfMajorPerformanceCaveat(attributes->failIfMajorPerformanceCaveat);
287             canvas->setContextAttributes(WTFMove(contextAttributes));
288         }
289     }
290 #endif
291
292     // FIXME: <https://webkit.org/b/180833> Web Inspector: support OffscreenCanvas for Canvas related operations
293
294     if (auto* node = canvasElement()) {
295         if (size_t memoryCost = node->memoryCost())
296             canvas->setMemoryCost(memoryCost);
297     }
298
299     if (captureBacktrace) {
300         auto stackTrace = Inspector::createScriptCallStack(JSExecState::currentState(), Inspector::ScriptCallStack::maxCallStackSizeToCapture);
301         canvas->setBacktrace(stackTrace->buildInspectorArray());
302     }
303
304     return canvas;
305 }
306
307 void InspectorCanvas::appendActionSnapshotIfNeeded()
308 {
309     if (!m_actionNeedingSnapshot)
310         return;
311
312     m_actionNeedingSnapshot->addItem(indexForData(getCanvasContentAsDataURL()));
313     m_actionNeedingSnapshot = nullptr;
314 }
315
316 String InspectorCanvas::getCanvasContentAsDataURL()
317 {
318     // FIXME: <https://webkit.org/b/180833> Web Inspector: support OffscreenCanvas for Canvas related operations
319
320     auto* node = canvasElement();
321     if (!node)
322         return String();
323
324 #if ENABLE(WEBGL)
325     if (is<WebGLRenderingContextBase>(m_context))
326         downcast<WebGLRenderingContextBase>(m_context).setPreventBufferClearForInspector(true);
327 #endif
328
329     ExceptionOr<UncachedString> result = node->toDataURL("image/png"_s);
330
331 #if ENABLE(WEBGL)
332     if (is<WebGLRenderingContextBase>(m_context))
333         downcast<WebGLRenderingContextBase>(m_context).setPreventBufferClearForInspector(false);
334 #endif
335
336     if (result.hasException())
337         return String();
338
339     return result.releaseReturnValue().string;
340 }
341
342 int InspectorCanvas::indexForData(DuplicateDataVariant data)
343 {
344     size_t index = m_indexedDuplicateData.findMatching([&] (auto item) {
345         if (data == item)
346             return true;
347
348         auto traceA = WTF::get_if<RefPtr<ScriptCallStack>>(data);
349         auto traceB = WTF::get_if<RefPtr<ScriptCallStack>>(item);
350         if (traceA && *traceA && traceB && *traceB)
351             return (*traceA)->isEqual((*traceB).get());
352
353         return false;
354     });
355     if (index != notFound) {
356         ASSERT(index < std::numeric_limits<int>::max());
357         return static_cast<int>(index);
358     }
359
360     if (!m_serializedDuplicateData)
361         m_serializedDuplicateData = JSON::ArrayOf<JSON::Value>::create();
362
363     RefPtr<JSON::Value> item;
364     WTF::switchOn(data,
365         [&] (const RefPtr<HTMLImageElement>& imageElement) {
366             String dataURL = "data:,"_s;
367
368             if (CachedImage* cachedImage = imageElement->cachedImage()) {
369                 Image* image = cachedImage->image();
370                 if (image && image != &Image::nullImage()) {
371                     std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(image->size(), RenderingMode::Unaccelerated);
372                     imageBuffer->context().drawImage(*image, FloatPoint(0, 0));
373                     dataURL = imageBuffer->toDataURL("image/png");
374                 }
375             }
376
377             index = indexForData(dataURL);
378         },
379 #if ENABLE(VIDEO)
380         [&] (RefPtr<HTMLVideoElement>& videoElement) {
381             String dataURL = "data:,"_s;
382
383             unsigned videoWidth = videoElement->videoWidth();
384             unsigned videoHeight = videoElement->videoHeight();
385             std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(FloatSize(videoWidth, videoHeight), RenderingMode::Unaccelerated);
386             if (imageBuffer) {
387                 videoElement->paintCurrentFrameInContext(imageBuffer->context(), FloatRect(0, 0, videoWidth, videoHeight));
388                 dataURL = imageBuffer->toDataURL("image/png");
389             }
390
391             index = indexForData(dataURL);
392         },
393 #endif
394         [&] (RefPtr<HTMLCanvasElement>& canvasElement) {
395             String dataURL = "data:,"_s;
396
397             ExceptionOr<UncachedString> result = canvasElement->toDataURL("image/png"_s);
398             if (!result.hasException())
399                 dataURL = result.releaseReturnValue().string;
400
401             index = indexForData(dataURL);
402         },
403         [&] (const RefPtr<CanvasGradient>& canvasGradient) { item = buildArrayForCanvasGradient(*canvasGradient); },
404         [&] (const RefPtr<CanvasPattern>& canvasPattern) { item = buildArrayForCanvasPattern(*canvasPattern); },
405         [&] (const RefPtr<ImageData>& imageData) { item = buildArrayForImageData(*imageData); },
406         [&] (RefPtr<ImageBitmap>& imageBitmap) {
407             index = indexForData(imageBitmap->buffer()->toDataURL("image/png"));
408         },
409         [&] (const RefPtr<ScriptCallStack>& scriptCallStack) {
410             auto array = JSON::ArrayOf<double>::create();
411             for (size_t i = 0; i < scriptCallStack->size(); ++i)
412                 array->addItem(indexForData(scriptCallStack->at(i)));
413             item = WTFMove(array);
414         },
415         [&] (const ScriptCallFrame& scriptCallFrame) {
416             auto array = JSON::ArrayOf<double>::create();
417             array->addItem(indexForData(scriptCallFrame.functionName()));
418             array->addItem(indexForData(scriptCallFrame.sourceURL()));
419             array->addItem(static_cast<int>(scriptCallFrame.lineNumber()));
420             array->addItem(static_cast<int>(scriptCallFrame.columnNumber()));
421             item = WTFMove(array);
422         },
423         [&] (const String& value) { item = JSON::Value::create(value); }
424     );
425
426     if (item) {
427         m_bufferUsed += item->memoryCost();
428         m_serializedDuplicateData->addItem(WTFMove(item));
429
430         m_indexedDuplicateData.append(data);
431         index = m_indexedDuplicateData.size() - 1;
432     }
433
434     ASSERT(index < std::numeric_limits<int>::max());
435     return static_cast<int>(index);
436 }
437
438 String InspectorCanvas::stringIndexForKey(const String& key)
439 {
440     return String::number(indexForData(key));
441 }
442
443 static Ref<JSON::ArrayOf<double>> buildArrayForAffineTransform(const AffineTransform& affineTransform)
444 {
445     auto array = JSON::ArrayOf<double>::create();
446     array->addItem(affineTransform.a());
447     array->addItem(affineTransform.b());
448     array->addItem(affineTransform.c());
449     array->addItem(affineTransform.d());
450     array->addItem(affineTransform.e());
451     array->addItem(affineTransform.f());
452     return array;
453 }
454
455 template<typename T> static Ref<JSON::ArrayOf<JSON::Value>> buildArrayForVector(const Vector<T>& vector)
456 {
457     auto array = JSON::ArrayOf<JSON::Value>::create();
458     for (auto& item : vector)
459         array->addItem(item);
460     return array;
461 }
462
463 Ref<Inspector::Protocol::Recording::InitialState> InspectorCanvas::buildInitialState()
464 {
465     auto initialStatePayload = Inspector::Protocol::Recording::InitialState::create().release();
466
467     auto attributesPayload = JSON::Object::create();
468     attributesPayload->setInteger("width"_s, m_context.canvasBase().width());
469     attributesPayload->setInteger("height"_s, m_context.canvasBase().height());
470
471     auto statesPayload = JSON::ArrayOf<JSON::Object>::create();
472
473     auto parametersPayload = JSON::ArrayOf<JSON::Value>::create();
474
475     if (is<CanvasRenderingContext2D>(m_context)) {
476         auto& context2d = downcast<CanvasRenderingContext2D>(m_context);
477         for (auto& state : context2d.stateStack()) {
478             RefPtr<JSON::Object> statePayload = JSON::Object::create();
479
480             statePayload->setArray(stringIndexForKey("setTransform"_s), buildArrayForAffineTransform(state.transform));
481             statePayload->setDouble(stringIndexForKey("globalAlpha"_s), context2d.globalAlpha());
482             statePayload->setInteger(stringIndexForKey("globalCompositeOperation"_s), indexForData(context2d.globalCompositeOperation()));
483             statePayload->setDouble(stringIndexForKey("lineWidth"_s), context2d.lineWidth());
484             statePayload->setInteger(stringIndexForKey("lineCap"_s), indexForData(convertEnumerationToString(context2d.lineCap())));
485             statePayload->setInteger(stringIndexForKey("lineJoin"_s), indexForData(convertEnumerationToString(context2d.lineJoin())));
486             statePayload->setDouble(stringIndexForKey("miterLimit"_s), context2d.miterLimit());
487             statePayload->setDouble(stringIndexForKey("shadowOffsetX"_s), context2d.shadowOffsetX());
488             statePayload->setDouble(stringIndexForKey("shadowOffsetY"_s), context2d.shadowOffsetY());
489             statePayload->setDouble(stringIndexForKey("shadowBlur"_s), context2d.shadowBlur());
490             statePayload->setInteger(stringIndexForKey("shadowColor"_s), indexForData(context2d.shadowColor()));
491
492             // The parameter to `setLineDash` is itself an array, so we need to wrap the parameters
493             // list in an array to allow spreading.
494             auto setLineDash = JSON::ArrayOf<JSON::Value>::create();
495             setLineDash->addItem(buildArrayForVector(state.lineDash));
496             statePayload->setArray(stringIndexForKey("setLineDash"_s), WTFMove(setLineDash));
497
498             statePayload->setDouble(stringIndexForKey("lineDashOffset"_s), context2d.lineDashOffset());
499             statePayload->setInteger(stringIndexForKey("font"_s), indexForData(context2d.font()));
500             statePayload->setInteger(stringIndexForKey("textAlign"_s), indexForData(convertEnumerationToString(context2d.textAlign())));
501             statePayload->setInteger(stringIndexForKey("textBaseline"_s), indexForData(convertEnumerationToString(context2d.textBaseline())));
502             statePayload->setInteger(stringIndexForKey("direction"_s), indexForData(convertEnumerationToString(context2d.direction())));
503
504             int strokeStyleIndex;
505             if (auto canvasGradient = state.strokeStyle.canvasGradient())
506                 strokeStyleIndex = indexForData(canvasGradient);
507             else if (auto canvasPattern = state.strokeStyle.canvasPattern())
508                 strokeStyleIndex = indexForData(canvasPattern);
509             else
510                 strokeStyleIndex = indexForData(state.strokeStyle.color());
511             statePayload->setInteger(stringIndexForKey("strokeStyle"_s), strokeStyleIndex);
512
513             int fillStyleIndex;
514             if (auto canvasGradient = state.fillStyle.canvasGradient())
515                 fillStyleIndex = indexForData(canvasGradient);
516             else if (auto canvasPattern = state.fillStyle.canvasPattern())
517                 fillStyleIndex = indexForData(canvasPattern);
518             else
519                 fillStyleIndex = indexForData(state.fillStyle.color());
520             statePayload->setInteger(stringIndexForKey("fillStyle"_s), fillStyleIndex);
521
522             statePayload->setBoolean(stringIndexForKey("imageSmoothingEnabled"_s), context2d.imageSmoothingEnabled());
523             statePayload->setInteger(stringIndexForKey("imageSmoothingQuality"_s), indexForData(convertEnumerationToString(context2d.imageSmoothingQuality())));
524
525             auto setPath = JSON::ArrayOf<JSON::Value>::create();
526             setPath->addItem(indexForData(buildStringFromPath(context2d.getPath()->path())));
527             statePayload->setArray(stringIndexForKey("setPath"_s), WTFMove(setPath));
528
529             statesPayload->addItem(WTFMove(statePayload));
530         }
531     }
532 #if ENABLE(WEBGL)
533     else if (is<WebGLRenderingContextBase>(m_context)) {
534         WebGLRenderingContextBase& contextWebGLBase = downcast<WebGLRenderingContextBase>(m_context);
535         if (std::optional<WebGLContextAttributes> webGLContextAttributes = contextWebGLBase.getContextAttributes()) {
536             RefPtr<JSON::Object> webGLContextAttributesPayload = JSON::Object::create();
537             webGLContextAttributesPayload->setBoolean("alpha"_s, webGLContextAttributes->alpha);
538             webGLContextAttributesPayload->setBoolean("depth"_s, webGLContextAttributes->depth);
539             webGLContextAttributesPayload->setBoolean("stencil"_s, webGLContextAttributes->stencil);
540             webGLContextAttributesPayload->setBoolean("antialias"_s, webGLContextAttributes->antialias);
541             webGLContextAttributesPayload->setBoolean("premultipliedAlpha"_s, webGLContextAttributes->premultipliedAlpha);
542             webGLContextAttributesPayload->setBoolean("preserveDrawingBuffer"_s, webGLContextAttributes->preserveDrawingBuffer);
543             webGLContextAttributesPayload->setBoolean("failIfMajorPerformanceCaveat"_s, webGLContextAttributes->failIfMajorPerformanceCaveat);
544             parametersPayload->addItem(WTFMove(webGLContextAttributesPayload));
545         }
546     }
547 #endif
548
549     initialStatePayload->setAttributes(WTFMove(attributesPayload));
550
551     if (statesPayload->length())
552         initialStatePayload->setStates(WTFMove(statesPayload));
553
554     if (parametersPayload->length())
555         initialStatePayload->setParameters(WTFMove(parametersPayload));
556
557     initialStatePayload->setContent(getCanvasContentAsDataURL());
558
559     return initialStatePayload;
560 }
561
562 Ref<JSON::ArrayOf<JSON::Value>> InspectorCanvas::buildAction(const String& name, Vector<RecordCanvasActionVariant>&& parameters)
563 {
564     auto action = JSON::ArrayOf<JSON::Value>::create();
565     action->addItem(indexForData(name));
566
567     auto parametersData = JSON::ArrayOf<JSON::Value>::create();
568     auto swizzleTypes = JSON::ArrayOf<int>::create();
569
570     auto addParameter = [&parametersData, &swizzleTypes] (auto value, RecordingSwizzleTypes swizzleType) {
571         parametersData->addItem(value);
572         swizzleTypes->addItem(static_cast<int>(swizzleType));
573     };
574
575     for (auto& item : parameters) {
576         WTF::switchOn(item,
577             [&] (CanvasDirection value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
578             [&] (CanvasFillRule value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
579             [&] (CanvasLineCap value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
580             [&] (CanvasLineJoin value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
581             [&] (CanvasTextAlign value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
582             [&] (CanvasTextBaseline value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
583             [&] (const DOMMatrix2DInit& value) {
584                 auto array = JSON::ArrayOf<double>::create();
585                 array->addItem(value.a.value_or(1));
586                 array->addItem(value.b.value_or(0));
587                 array->addItem(value.c.value_or(0));
588                 array->addItem(value.d.value_or(1));
589                 array->addItem(value.e.value_or(0));
590                 array->addItem(value.f.value_or(0));
591                 addParameter(array.ptr(), RecordingSwizzleTypes::DOMMatrix);
592             },
593             [&] (const Element*) {
594                 // Elements are not serializable, so add a string as a placeholder since the actual
595                 // element cannot be reconstructed in the frontend.
596                 addParameter(indexForData("Element"), RecordingSwizzleTypes::None);
597             },
598             [&] (HTMLImageElement* value) { addParameter(indexForData(value), RecordingSwizzleTypes::Image); },
599             [&] (ImageBitmap* value) { addParameter(indexForData(value), RecordingSwizzleTypes::ImageBitmap); },
600             [&] (ImageData* value) { addParameter(indexForData(value), RecordingSwizzleTypes::ImageData); },
601             [&] (ImageSmoothingQuality value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
602             [&] (const Path2D* value) { addParameter(indexForData(buildStringFromPath(value->path())), RecordingSwizzleTypes::Path2D); },
603 #if ENABLE(WEBGL)
604             // FIXME: <https://webkit.org/b/176009> Web Inspector: send data for WebGL objects during a recording instead of a placeholder string
605             [&] (const WebGLBuffer*) { addParameter(0, RecordingSwizzleTypes::WebGLBuffer); },
606             [&] (const WebGLFramebuffer*) { addParameter(0, RecordingSwizzleTypes::WebGLFramebuffer); },
607             [&] (const WebGLProgram*) { addParameter(0, RecordingSwizzleTypes::WebGLProgram); },
608             [&] (const WebGLRenderbuffer*) { addParameter(0, RecordingSwizzleTypes::WebGLRenderbuffer); },
609             [&] (const WebGLShader*) { addParameter(0, RecordingSwizzleTypes::WebGLShader); },
610             [&] (const WebGLTexture*) { addParameter(0, RecordingSwizzleTypes::WebGLTexture); },
611             [&] (const WebGLUniformLocation*) { addParameter(0, RecordingSwizzleTypes::WebGLUniformLocation); },
612 #endif
613             [&] (const RefPtr<ArrayBuffer>&) { addParameter(0, RecordingSwizzleTypes::TypedArray); },
614             [&] (const RefPtr<ArrayBufferView>&) { addParameter(0, RecordingSwizzleTypes::TypedArray); },
615             [&] (const RefPtr<CanvasGradient>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::CanvasGradient); },
616             [&] (const RefPtr<CanvasPattern>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::CanvasPattern); },
617             [&] (const RefPtr<Float32Array>&) { addParameter(0, RecordingSwizzleTypes::TypedArray); },
618             [&] (const RefPtr<HTMLCanvasElement>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::Image); },
619             [&] (const RefPtr<HTMLImageElement>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::Image); },
620 #if ENABLE(VIDEO)
621             [&] (const RefPtr<HTMLVideoElement>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::Image); },
622 #endif
623             [&] (const RefPtr<ImageBitmap>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::ImageBitmap); },
624             [&] (const RefPtr<ImageData>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::ImageData); },
625             [&] (const RefPtr<Int32Array>&) { addParameter(0, RecordingSwizzleTypes::TypedArray); },
626             [&] (const Vector<float>& value) { addParameter(buildArrayForVector(value).ptr(), RecordingSwizzleTypes::Array); },
627             [&] (const Vector<int>& value) { addParameter(buildArrayForVector(value).ptr(), RecordingSwizzleTypes::Array); },
628             [&] (const String& value) { addParameter(indexForData(value), RecordingSwizzleTypes::String); },
629             [&] (double value) { addParameter(value, RecordingSwizzleTypes::Number); },
630             [&] (float value) { addParameter(value, RecordingSwizzleTypes::Number); },
631             [&] (int64_t value) { addParameter(static_cast<double>(value), RecordingSwizzleTypes::Number); },
632             [&] (uint32_t value) { addParameter(static_cast<double>(value), RecordingSwizzleTypes::Number); },
633             [&] (int32_t value) { addParameter(value, RecordingSwizzleTypes::Number); },
634             [&] (uint8_t value) { addParameter(static_cast<int>(value), RecordingSwizzleTypes::Number); },
635             [&] (bool value) { addParameter(value, RecordingSwizzleTypes::Boolean); }
636         );
637     }
638
639     action->addItem(WTFMove(parametersData));
640     action->addItem(WTFMove(swizzleTypes));
641
642     RefPtr<ScriptCallStack> trace = Inspector::createScriptCallStack(JSExecState::currentState(), Inspector::ScriptCallStack::maxCallStackSizeToCapture);
643     action->addItem(indexForData(WTFMove(trace)));
644
645     return action;
646 }
647
648 Ref<JSON::ArrayOf<JSON::Value>> InspectorCanvas::buildArrayForCanvasGradient(const CanvasGradient& canvasGradient)
649 {
650     const auto& gradient = canvasGradient.gradient();
651     
652     String type = gradient.type() == Gradient::Type::Radial ? "radial-gradient"_s : gradient.type() == Gradient::Type::Linear ? "linear-gradient"_s : "conic-gradient"_s;
653
654     auto parameters = JSON::ArrayOf<float>::create();
655     WTF::switchOn(gradient.data(),
656         [&parameters] (const Gradient::LinearData& data) {
657             parameters->addItem(data.point0.x());
658             parameters->addItem(data.point0.y());
659             parameters->addItem(data.point1.x());
660             parameters->addItem(data.point1.y());
661         },
662         [&parameters] (const Gradient::RadialData& data) {
663             parameters->addItem(data.point0.x());
664             parameters->addItem(data.point0.y());
665             parameters->addItem(data.startRadius);
666             parameters->addItem(data.point1.x());
667             parameters->addItem(data.point1.y());
668             parameters->addItem(data.endRadius);
669         },
670         [&parameters] (const Gradient::ConicData& data) {
671             parameters->addItem(data.point0.x());
672             parameters->addItem(data.point0.y());
673             parameters->addItem(data.angleRadians);
674         }
675     );
676
677     auto stops = JSON::ArrayOf<JSON::Value>::create();
678     for (auto& colorStop : gradient.stops()) {
679         auto stop = JSON::ArrayOf<JSON::Value>::create();
680         stop->addItem(colorStop.offset);
681         stop->addItem(indexForData(colorStop.color.cssText()));
682         stops->addItem(WTFMove(stop));
683     }
684
685     auto array = JSON::ArrayOf<JSON::Value>::create();
686     array->addItem(indexForData(type));
687     array->addItem(WTFMove(parameters));
688     array->addItem(WTFMove(stops));
689     return array;
690 }
691
692 Ref<JSON::ArrayOf<JSON::Value>> InspectorCanvas::buildArrayForCanvasPattern(const CanvasPattern& canvasPattern)
693 {
694     Image& tileImage = canvasPattern.pattern().tileImage();
695     auto imageBuffer = ImageBuffer::create(tileImage.size(), RenderingMode::Unaccelerated);
696     imageBuffer->context().drawImage(tileImage, FloatPoint(0, 0));
697
698     String repeat;
699     bool repeatX = canvasPattern.pattern().repeatX();
700     bool repeatY = canvasPattern.pattern().repeatY();
701     if (repeatX && repeatY)
702         repeat = "repeat"_s;
703     else if (repeatX && !repeatY)
704         repeat = "repeat-x"_s;
705     else if (!repeatX && repeatY)
706         repeat = "repeat-y"_s;
707     else
708         repeat = "no-repeat"_s;
709
710     auto array = JSON::ArrayOf<JSON::Value>::create();
711     array->addItem(indexForData(imageBuffer->toDataURL("image/png")));
712     array->addItem(indexForData(repeat));
713     return array;
714 }
715
716 Ref<JSON::ArrayOf<JSON::Value>> InspectorCanvas::buildArrayForImageData(const ImageData& imageData)
717 {
718     auto data = JSON::ArrayOf<int>::create();
719     for (size_t i = 0; i < imageData.data()->length(); ++i)
720         data->addItem(imageData.data()->item(i));
721
722     auto array = JSON::ArrayOf<JSON::Value>::create();
723     array->addItem(WTFMove(data));
724     array->addItem(imageData.width());
725     array->addItem(imageData.height());
726     return array;
727 }
728
729 } // namespace WebCore
730