Diff
Modified: trunk/LayoutTests/ChangeLog (265542 => 265543)
--- trunk/LayoutTests/ChangeLog 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/LayoutTests/ChangeLog 2020-08-12 09:05:54 UTC (rev 265543)
@@ -1,3 +1,12 @@
+2020-08-12 Chris Lord <[email protected]>
+
+ Implement Canvas.transferControlToOffscreen and OffscreenCanvasRenderingContext2D.commit
+ https://bugs.webkit.org/show_bug.cgi?id=202797
+
+ Reviewed by Dean Jackson.
+
+ * platform/glib/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/filter/offscreencanvas.filter.w-expected.txt: Removed.
+
2020-08-11 Lauro Moura <[email protected]>
[GTK] Garden accessibility failures after r265514
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (265542 => 265543)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2020-08-12 09:05:54 UTC (rev 265543)
@@ -1,3 +1,19 @@
+2020-08-12 Chris Lord <[email protected]>
+
+ Implement Canvas.transferControlToOffscreen and OffscreenCanvasRenderingContext2D.commit
+ https://bugs.webkit.org/show_bug.cgi?id=202797
+
+ Reviewed by Dean Jackson.
+
+ * web-platform-tests/html/canvas/offscreen/filter/offscreencanvas.filter.w-expected.txt:
+ * web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.commit-expected.txt:
+ * web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.commit.w-expected.txt:
+ * web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext-expected.txt:
+ * web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext.worker-expected.txt:
+ * web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.resize-expected.txt:
+ * web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen-expected.txt:
+ * web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen.w-expected.txt:
+
2020-08-11 Chris Dumez <[email protected]>
Fix WaveShapperNode's waveshaping curve implementation
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/filter/offscreencanvas.filter.w-expected.txt (265542 => 265543)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/filter/offscreencanvas.filter.w-expected.txt 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/filter/offscreencanvas.filter.w-expected.txt 2020-08-12 09:05:54 UTC (rev 265543)
@@ -1,3 +1,2 @@
+FAIL: Timed out waiting for notifyDone to be called
-PASS offscreencanvas
-
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.commit-expected.txt (265542 => 265543)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.commit-expected.txt 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.commit-expected.txt 2020-08-12 09:05:54 UTC (rev 265543)
@@ -1,4 +1,4 @@
-FAIL Test that calling OffscreenCanvas's commit pushes its contents to its placeholder. placeholder.transferControlToOffscreen is not a function. (In 'placeholder.transferControlToOffscreen()', 'placeholder.transferControlToOffscreen' is undefined)
-FAIL Test that calling commit on an OffscreenCanvas that is not transferred from a HTMLCanvasElement is a noop. ctx.commit is not a function. (In 'ctx.commit()', 'ctx.commit' is undefined)
+PASS Test that calling OffscreenCanvas's commit pushes its contents to its placeholder.
+PASS Test that calling commit on an OffscreenCanvas that is not transferred from a HTMLCanvasElement is a noop.
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.commit.w-expected.txt (265542 => 265543)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.commit.w-expected.txt 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.commit.w-expected.txt 2020-08-12 09:05:54 UTC (rev 265543)
@@ -1,4 +1,4 @@
-FAIL Test that calling OffscreenCanvas's commit pushes its contents to its placeholder. placeholder.transferControlToOffscreen is not a function. (In 'placeholder.transferControlToOffscreen()', 'placeholder.transferControlToOffscreen' is undefined)
+PASS Test that calling OffscreenCanvas's commit pushes its contents to its placeholder.
PASS Test that calling commit on an OffscreenCanvas that is not transferred from a HTMLCanvasElement throws an exception in a worker.
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext-expected.txt (265542 => 265543)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext-expected.txt 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext-expected.txt 2020-08-12 09:05:54 UTC (rev 265543)
@@ -1,7 +1,7 @@
PASS Test that getContext with un-supported string throws a TypeError.
FAIL Test that getContext with supported string returns correct results Argument 1 ('contextType') to OffscreenCanvas.getContext must be one of: "2d", "webgl"
-FAIL Test that getContext twice with different context type returns null the second time The object is in an invalid state.
+PASS Test that getContext twice with different context type returns null the second time
PASS Test that 2dcontext.canvas should return the original OffscreenCanvas
PASS Test that webglcontext.canvas should return the original OffscreenCanvas
FAIL Test that OffscreenCanvasRenderingContext2D with alpha disabled makes the OffscreenCanvas opaque assert_approx_equals: Green channel of the pixel at (5, 5) expected 127 +/- 2 but got 255
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext.worker-expected.txt (265542 => 265543)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext.worker-expected.txt 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext.worker-expected.txt 2020-08-12 09:05:54 UTC (rev 265543)
@@ -1,7 +1,7 @@
PASS Test that getContext with un-supported string throws a TypeError.
-FAIL Test that getContext with supported string returns correct results Can't find variable: OffscreenCanvasRenderingContext2D
-FAIL Test that getContext twice with different context type returns null the second time The object is in an invalid state.
+FAIL Test that getContext with supported string returns correct results Can't find variable: WebGLRenderingContext
+PASS Test that getContext twice with different context type returns null the second time
PASS Test that 2dcontext.canvas should return the original OffscreenCanvas
PASS Test that webglcontext.canvas should return the original OffscreenCanvas
FAIL Test that OffscreenCanvasRenderingContext2D with alpha disabled makes the OffscreenCanvas opaque assert_approx_equals: Green channel of the pixel at (5, 5) expected 127 +/- 2 but got 255
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.resize-expected.txt (265542 => 265543)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.resize-expected.txt 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.resize-expected.txt 2020-08-12 09:05:54 UTC (rev 265543)
@@ -2,11 +2,11 @@
PASS Verify that writing to the width and height attributes of an OffscreenCanvas works when there is no context attached.
PASS Verify that writing to the width and height attributes of an OffscreenCanvas works when there is a 2d context attached.
PASS Verify that writing to the width and height attributes of an OffscreenCanvas works when there is a webgl context attached.
-FAIL Verify that writing to the width or height attribute of a placeholder canvas throws an exception placeholder.transferControlToOffscreen is not a function. (In 'placeholder.transferControlToOffscreen()', 'placeholder.transferControlToOffscreen' is undefined)
-FAIL Verify that writing to the width or height attribute of a placeholder canvas throws an exception even when not changing the value of the attribute. placeholder.transferControlToOffscreen is not a function. (In 'placeholder.transferControlToOffscreen()', 'placeholder.transferControlToOffscreen' is undefined)
+PASS Verify that writing to the width or height attribute of a placeholder canvas throws an exception
+PASS Verify that writing to the width or height attribute of a placeholder canvas throws an exception even when not changing the value of the attribute.
PASS Verify that resizing a 2d context resets its state.
PASS Verify that setting the size of a 2d context to the same size it already had resets its state.
-FAIL Verify that resizing an OffscreenCanvas with a 2d context propagates the new size to its placeholder canvas asynchronously. placeholder.transferControlToOffscreen is not a function. (In 'placeholder.transferControlToOffscreen()', 'placeholder.transferControlToOffscreen' is undefined)
-FAIL Verify that resizing an OffscreenCanvas with a webgl context propagates the new size to its placeholder canvas asynchronously. placeholder.transferControlToOffscreen is not a function. (In 'placeholder.transferControlToOffscreen()', 'placeholder.transferControlToOffscreen' is undefined)
-FAIL Verify that drawImage uses the size of the frame as the intinsic size of a placeholder canvas. placeholder.transferControlToOffscreen is not a function. (In 'placeholder.transferControlToOffscreen()', 'placeholder.transferControlToOffscreen' is undefined)
+PASS Verify that resizing an OffscreenCanvas with a 2d context propagates the new size to its placeholder canvas asynchronously.
+PASS Verify that resizing an OffscreenCanvas with a webgl context propagates the new size to its placeholder canvas asynchronously.
+PASS Verify that drawImage uses the size of the frame as the intinsic size of a placeholder canvas.
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen-expected.txt (265542 => 265543)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen-expected.txt 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen-expected.txt 2020-08-12 09:05:54 UTC (rev 265543)
@@ -1,5 +1,5 @@
-FAIL Test that an OffscreenCanvas generated by transferControlToOffscreen gets correct width and height placeholder.transferControlToOffscreen is not a function. (In 'placeholder.transferControlToOffscreen()', 'placeholder.transferControlToOffscreen' is undefined)
-FAIL Test that calling getContext on a placeholder canvas that has already transferred its control throws an exception placeholder.transferControlToOffscreen is not a function. (In 'placeholder.transferControlToOffscreen()', 'placeholder.transferControlToOffscreen' is undefined)
-FAIL Test that calling transferControlToOffscreen twice throws an exception placeholder.transferControlToOffscreen is not a function. (In 'placeholder.transferControlToOffscreen()', 'placeholder.transferControlToOffscreen' is undefined)
+PASS Test that an OffscreenCanvas generated by transferControlToOffscreen gets correct width and height
+PASS Test that calling getContext on a placeholder canvas that has already transferred its control throws an exception
+PASS Test that calling transferControlToOffscreen twice throws an exception
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen.w-expected.txt (265542 => 265543)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen.w-expected.txt 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen.w-expected.txt 2020-08-12 09:05:54 UTC (rev 265543)
@@ -1,5 +1,5 @@
-FAIL Test that an OffscreenCanvas generated by transferControlToOffscreen gets correct width and height when it is transferred to a worker placeholder.transferControlToOffscreen is not a function. (In 'placeholder.transferControlToOffscreen()', 'placeholder.transferControlToOffscreen' is undefined)
-FAIL Test that calling getContext on a placeholder canvas that is transferred its control to an OffscreenCanvas throws an exception, when the OffscreenCanvas is transferred to a worker placeholder.transferControlToOffscreen is not a function. (In 'placeholder.transferControlToOffscreen()', 'placeholder.transferControlToOffscreen' is undefined)
-FAIL Test that calling transferControlToOffscreen twice throws an exception, when its associated OffscreenCanvas is transferred to a worker placeholder.transferControlToOffscreen is not a function. (In 'placeholder.transferControlToOffscreen()', 'placeholder.transferControlToOffscreen' is undefined)
+PASS Test that an OffscreenCanvas generated by transferControlToOffscreen gets correct width and height when it is transferred to a worker
+PASS Test that calling getContext on a placeholder canvas that is transferred its control to an OffscreenCanvas throws an exception, when the OffscreenCanvas is transferred to a worker
+PASS Test that calling transferControlToOffscreen twice throws an exception, when its associated OffscreenCanvas is transferred to a worker
Modified: trunk/Source/WebCore/ChangeLog (265542 => 265543)
--- trunk/Source/WebCore/ChangeLog 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/Source/WebCore/ChangeLog 2020-08-12 09:05:54 UTC (rev 265543)
@@ -1,3 +1,46 @@
+2020-08-12 Chris Lord <[email protected]>
+
+ Implement Canvas.transferControlToOffscreen and OffscreenCanvasRenderingContext2D.commit
+ https://bugs.webkit.org/show_bug.cgi?id=202797
+
+ Reviewed by Dean Jackson.
+
+ Implement HTMLCanvasElement.transferControlToOffscreen and
+ OffscreenCanvasRenderingContext2D.commit. This allows for
+ (synchronous) display of asynchronously rendered OffscreenCanvas
+ content.
+
+ No new tests. Covered by existing tests.
+
+ * html/HTMLCanvasElement.cpp:
+ (WebCore::HTMLCanvasElement::setHeight):
+ (WebCore::HTMLCanvasElement::setWidth):
+ (WebCore::HTMLCanvasElement::reset):
+ (WebCore::HTMLCanvasElement::transferControlToOffscreen):
+ (WebCore::HTMLCanvasElement::setImageBufferAndMarkDirty):
+ (WebCore::HTMLCanvasElement::isControlledByOffscreen const):
+ * html/HTMLCanvasElement.h:
+ * html/HTMLCanvasElement.idl:
+ * html/OffscreenCanvas.cpp:
+ (WebCore::DetachedOffscreenCanvas::takePlaceholderCanvas):
+ (WebCore::OffscreenCanvas::create):
+ (WebCore::OffscreenCanvas::getContext):
+ (WebCore::OffscreenCanvas::didDraw):
+ (WebCore::OffscreenCanvas::detach):
+ (WebCore::OffscreenCanvas::setPlaceholderCanvas):
+ (WebCore::OffscreenCanvas::pushBufferToPlaceholder):
+ (WebCore::OffscreenCanvas::commitToPlaceholderCanvas):
+ (WebCore::OffscreenCanvas::scheduleCommitToPlaceholderCanvas):
+ (WebCore::OffscreenCanvas::reset):
+ * html/OffscreenCanvas.h:
+ * html/canvas/OffscreenCanvasRenderingContext2D.cpp:
+ (WebCore::OffscreenCanvasRenderingContext2D::commit):
+ * html/canvas/OffscreenCanvasRenderingContext2D.h:
+ * html/canvas/OffscreenCanvasRenderingContext2D.idl:
+ * html/canvas/PlaceholderRenderingContext.cpp:
+ (WebCore::PlaceholderRenderingContext::canvas const):
+ * html/canvas/PlaceholderRenderingContext.h:
+
2020-08-12 Carlos Garcia Campos <[email protected]>
REGRESSION(r261570): [GTK] Fails to send drop event to _javascript_
Modified: trunk/Source/WebCore/html/HTMLCanvasElement.cpp (265542 => 265543)
--- trunk/Source/WebCore/html/HTMLCanvasElement.cpp 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/Source/WebCore/html/HTMLCanvasElement.cpp 2020-08-12 09:05:54 UTC (rev 265543)
@@ -49,6 +49,7 @@
#include "InspectorInstrumentation.h"
#include "JSDOMConvertDictionary.h"
#include "MIMETypeRegistry.h"
+#include "PlaceholderRenderingContext.h"
#include "RenderElement.h"
#include "RenderHTMLCanvas.h"
#include "ResourceLoadObserver.h"
@@ -184,7 +185,7 @@
ExceptionOr<void> HTMLCanvasElement::setHeight(unsigned value)
{
- if (m_context && m_context->isPlaceholder())
+ if (isControlledByOffscreen())
return Exception { InvalidStateError };
setAttributeWithoutSynchronization(heightAttr, AtomString::number(limitToOnlyHTMLNonNegative(value, defaultHeight)));
return { };
@@ -192,7 +193,7 @@
ExceptionOr<void> HTMLCanvasElement::setWidth(unsigned value)
{
- if (m_context && m_context->isPlaceholder())
+ if (isControlledByOffscreen())
return Exception { InvalidStateError };
setAttributeWithoutSynchronization(widthAttr, AtomString::number(limitToOnlyHTMLNonNegative(value, defaultWidth)));
return { };
@@ -566,7 +567,7 @@
void HTMLCanvasElement::reset()
{
- if (m_ignoreReset)
+ if (m_ignoreReset || isControlledByOffscreen())
return;
bool hadImageBuffer = hasCreatedImageBuffer();
@@ -768,6 +769,17 @@
return { };
}
+#if ENABLE(OFFSCREEN_CANVAS)
+ExceptionOr<Ref<OffscreenCanvas>> HTMLCanvasElement::transferControlToOffscreen(ScriptExecutionContext& context)
+{
+ if (m_context)
+ return Exception { InvalidStateError };
+
+ m_context = makeUnique<PlaceholderRenderingContext>(*this);
+ return OffscreenCanvas::create(context, *this);
+}
+#endif
+
RefPtr<ImageData> HTMLCanvasElement::getImageData()
{
#if ENABLE(WEBGL)
@@ -945,8 +957,24 @@
void HTMLCanvasElement::setImageBufferAndMarkDirty(std::unique_ptr<ImageBuffer>&& buffer)
{
+ IntSize oldSize = size();
m_hasCreatedImageBuffer = true;
setImageBuffer(WTFMove(buffer));
+
+ if (isControlledByOffscreen() && oldSize != size()) {
+ setAttributeWithoutSynchronization(widthAttr, AtomString::number(width()));
+ setAttributeWithoutSynchronization(heightAttr, AtomString::number(height()));
+
+ auto renderer = this->renderer();
+ if (is<RenderHTMLCanvas>(renderer)) {
+ auto& canvasRenderer = downcast<RenderHTMLCanvas>(*renderer);
+ canvasRenderer.canvasSizeChanged();
+ canvasRenderer.contentChanged(CanvasChanged);
+ }
+
+ notifyObserversCanvasResized();
+ }
+
didDraw(FloatRect(FloatPoint(), size()));
}
@@ -1052,4 +1080,9 @@
#endif
}
+bool HTMLCanvasElement::isControlledByOffscreen() const
+{
+ return m_context && m_context->isPlaceholder();
}
+
+}
Modified: trunk/Source/WebCore/html/HTMLCanvasElement.h (265542 => 265543)
--- trunk/Source/WebCore/html/HTMLCanvasElement.h 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/Source/WebCore/html/HTMLCanvasElement.h 2020-08-12 09:05:54 UTC (rev 265543)
@@ -50,6 +50,7 @@
class ImageData;
class MediaSample;
class MediaStream;
+class OffscreenCanvas;
class WebGLRenderingContextBase;
class GPUCanvasContext;
struct UncachedString;
@@ -97,6 +98,9 @@
WEBCORE_EXPORT ExceptionOr<UncachedString> toDataURL(const String& mimeType, JSC::JSValue quality);
WEBCORE_EXPORT ExceptionOr<UncachedString> toDataURL(const String& mimeType);
ExceptionOr<void> toBlob(ScriptExecutionContext&, Ref<BlobCallback>&&, const String& mimeType, JSC::JSValue quality);
+#if ENABLE(OFFSCREEN_CANVAS)
+ ExceptionOr<Ref<OffscreenCanvas>> transferControlToOffscreen(ScriptExecutionContext&);
+#endif
// Used for rendering
void didDraw(const FloatRect&) final;
@@ -135,6 +139,8 @@
void setIsSnapshotting(bool isSnapshotting) { m_isSnapshotting = isSnapshotting; }
bool isSnapshotting() const { return m_isSnapshotting; }
+ bool isControlledByOffscreen() const;
+
private:
HTMLCanvasElement(const QualifiedName&, Document&);
Modified: trunk/Source/WebCore/html/HTMLCanvasElement.idl (265542 => 265543)
--- trunk/Source/WebCore/html/HTMLCanvasElement.idl 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/Source/WebCore/html/HTMLCanvasElement.idl 2020-08-12 09:05:54 UTC (rev 265543)
@@ -50,6 +50,7 @@
[MayThrowException] DOMString toDataURL(optional DOMString type, optional any quality);
[CallWith=ScriptExecutionContext, MayThrowException] void toBlob(BlobCallback callback, optional DOMString type, optional any quality);
+ [Conditional=OFFSCREEN_CANVAS, CallWith=ScriptExecutionContext, MayThrowException] OffscreenCanvas transferControlToOffscreen();
[Conditional=MEDIA_STREAM, CallWith=Document, MayThrowException, NewObject] MediaStream captureStream(optional double frameRequestRate);
};
Modified: trunk/Source/WebCore/html/OffscreenCanvas.cpp (265542 => 265543)
--- trunk/Source/WebCore/html/OffscreenCanvas.cpp 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/Source/WebCore/html/OffscreenCanvas.cpp 2020-08-12 09:05:54 UTC (rev 265543)
@@ -31,11 +31,14 @@
#include "CSSValuePool.h"
#include "CanvasRenderingContext.h"
#include "Document.h"
+#include "HTMLCanvasElement.h"
#include "ImageBitmap.h"
+#include "ImageData.h"
#include "JSBlob.h"
#include "JSDOMPromiseDeferred.h"
#include "MIMETypeRegistry.h"
#include "OffscreenCanvasRenderingContext2D.h"
+#include "PlaceholderRenderingContext.h"
#include "WebGLRenderingContext.h"
#include "WorkerGlobalScope.h"
#include <wtf/IsoMallocInlines.h>
@@ -56,6 +59,12 @@
return WTFMove(m_buffer);
}
+WeakPtr<HTMLCanvasElement> DetachedOffscreenCanvas::takePlaceholderCanvas()
+{
+ ASSERT(isMainThread());
+ return std::exchange(m_placeholderCanvas, nullptr);
+}
+
Ref<OffscreenCanvas> OffscreenCanvas::create(ScriptExecutionContext& context, unsigned width, unsigned height)
{
return adoptRef(*new OffscreenCanvas(context, width, height));
@@ -68,9 +77,22 @@
if (!detachedCanvas->originClean())
clone->setOriginTainted();
+ callOnMainThread([detachedCanvas = WTFMove(detachedCanvas), offscreenCanvas = makeRef(clone.get())] () mutable {
+ offscreenCanvas->m_placeholderCanvas = detachedCanvas->takePlaceholderCanvas();
+ offscreenCanvas->scriptExecutionContext()->postTask({ ScriptExecutionContext::Task::CleanupTask,
+ [releaseOffscreenCanvas = WTFMove(offscreenCanvas)] (ScriptExecutionContext&) { } });
+ });
+
return clone;
}
+Ref<OffscreenCanvas> OffscreenCanvas::create(ScriptExecutionContext& context, HTMLCanvasElement& canvas)
+{
+ auto offscreen = adoptRef(*new OffscreenCanvas(context, canvas.width(), canvas.height()));
+ offscreen->setPlaceholderCanvas(canvas);
+ return offscreen;
+}
+
OffscreenCanvas::OffscreenCanvas(ScriptExecutionContext& context, unsigned width, unsigned height)
: CanvasBase(IntSize(width, height))
, ContextDestructionObserver(&context)
@@ -119,7 +141,7 @@
reset();
}
-ExceptionOr<OffscreenRenderingContext> OffscreenCanvas::getContext(JSC::JSGlobalObject& state, RenderingContextType contextType, Vector<JSC::Strong<JSC::Unknown>>&& arguments)
+ExceptionOr<Optional<OffscreenRenderingContext>> OffscreenCanvas::getContext(JSC::JSGlobalObject& state, RenderingContextType contextType, Vector<JSC::Strong<JSC::Unknown>>&& arguments)
{
if (m_detached)
return Exception { InvalidStateError };
@@ -127,22 +149,22 @@
if (contextType == RenderingContextType::_2d) {
if (m_context) {
if (!is<OffscreenCanvasRenderingContext2D>(*m_context))
- return Exception { InvalidStateError };
- return { RefPtr<OffscreenCanvasRenderingContext2D> { &downcast<OffscreenCanvasRenderingContext2D>(*m_context) } };
+ return { { WTF::nullopt } };
+ return { { RefPtr<OffscreenCanvasRenderingContext2D> { &downcast<OffscreenCanvasRenderingContext2D>(*m_context) } } };
}
m_context = makeUnique<OffscreenCanvasRenderingContext2D>(*this);
if (!m_context)
- return { RefPtr<OffscreenCanvasRenderingContext2D> { nullptr } };
+ return { { WTF::nullopt } };
- return { RefPtr<OffscreenCanvasRenderingContext2D> { &downcast<OffscreenCanvasRenderingContext2D>(*m_context) } };
+ return { { RefPtr<OffscreenCanvasRenderingContext2D> { &downcast<OffscreenCanvasRenderingContext2D>(*m_context) } } };
}
#if ENABLE(WEBGL)
if (contextType == RenderingContextType::Webgl) {
if (m_context) {
- if (!is<WebGLRenderingContext>(*m_context))
- return Exception { InvalidStateError };
- return { RefPtr<WebGLRenderingContext> { &downcast<WebGLRenderingContext>(*m_context) } };
+ if (is<WebGLRenderingContext>(*m_context))
+ return { { RefPtr<WebGLRenderingContext> { &downcast<WebGLRenderingContext>(*m_context) } } };
+ return { { WTF::nullopt } };
}
auto scope = DECLARE_THROW_SCOPE(state.vm());
@@ -151,13 +173,13 @@
m_context = WebGLRenderingContextBase::create(*this, attributes, "webgl");
if (!m_context)
- return { RefPtr<WebGLRenderingContext> { nullptr } };
+ return { { WTF::nullopt } };
- return { RefPtr<WebGLRenderingContext> { &downcast<WebGLRenderingContext>(*m_context) } };
+ return { { RefPtr<WebGLRenderingContext> { &downcast<WebGLRenderingContext>(*m_context) } } };
}
#endif
- return Exception { NotSupportedError };
+ return Exception { TypeError };
}
ExceptionOr<RefPtr<ImageBitmap>> OffscreenCanvas::transferToImageBitmap()
@@ -259,6 +281,7 @@
void OffscreenCanvas::didDraw(const FloatRect& rect)
{
clearCopiedImage();
+ scheduleCommitToPlaceholderCanvas();
notifyObserversCanvasChanged(rect);
}
@@ -301,9 +324,75 @@
m_detached = true;
- return makeUnique<DetachedOffscreenCanvas>(takeImageBuffer(), size(), originClean());
+ auto detached = makeUnique<DetachedOffscreenCanvas>(takeImageBuffer(), size(), originClean());
+ detached->m_placeholderCanvas = std::exchange(m_placeholderCanvas, nullptr);
+
+ return detached;
}
+void OffscreenCanvas::setPlaceholderCanvas(HTMLCanvasElement& canvas)
+{
+ ASSERT(!m_context);
+ ASSERT(isMainThread());
+ m_placeholderCanvas = makeWeakPtr(canvas);
+}
+
+void OffscreenCanvas::pushBufferToPlaceholder()
+{
+ callOnMainThread([protectedThis = makeRef(*this), this] () mutable {
+ auto locker = holdLock(m_commitLock);
+
+ if (m_placeholderCanvas && m_hasPendingCommitData) {
+ std::unique_ptr<ImageBuffer> buffer = ImageBuffer::create(FloatSize(m_pendingCommitData->size()), RenderingMode::Unaccelerated);
+ buffer->putImageData(AlphaPremultiplication::Premultiplied, *m_pendingCommitData, IntRect(IntPoint(), m_pendingCommitData->size()));
+ m_placeholderCanvas->setImageBufferAndMarkDirty(WTFMove(buffer));
+ m_hasPendingCommitData = false;
+ }
+
+ scriptExecutionContext()->postTask([releaseThis = WTFMove(protectedThis)] (ScriptExecutionContext&) { });
+ });
+}
+
+void OffscreenCanvas::commitToPlaceholderCanvas()
+{
+ auto* imageBuffer = buffer();
+ if (!imageBuffer)
+ return;
+
+ // FIXME: Transfer texture over if we're using accelerated compositing
+ if (m_context && (m_context->isWebGL() || m_context->isAccelerated()))
+ m_context->paintRenderingResultsToCanvas();
+
+ if (isMainThread()) {
+ if (m_placeholderCanvas) {
+ if (auto bufferCopy = imageBuffer->copyRectToBuffer(FloatRect(FloatPoint(), imageBuffer->logicalSize()), ColorSpace::SRGB, imageBuffer->context()))
+ m_placeholderCanvas->setImageBufferAndMarkDirty(WTFMove(bufferCopy));
+ }
+ return;
+ }
+
+ auto locker = holdLock(m_commitLock);
+
+ bool shouldPushBuffer = !m_hasPendingCommitData;
+ m_pendingCommitData = imageBuffer->getImageData(AlphaPremultiplication::Premultiplied, IntRect(IntPoint(), imageBuffer->logicalSize()));
+ m_hasPendingCommitData = true;
+
+ if (shouldPushBuffer)
+ pushBufferToPlaceholder();
+}
+
+void OffscreenCanvas::scheduleCommitToPlaceholderCanvas()
+{
+ if (!m_hasScheduledCommit) {
+ auto& scriptContext = *scriptExecutionContext();
+ m_hasScheduledCommit = true;
+ scriptContext.postTask([protectedThis = makeRef(*this), this] (ScriptExecutionContext&) {
+ m_hasScheduledCommit = false;
+ commitToPlaceholderCanvas();
+ });
+ }
+}
+
CSSValuePool& OffscreenCanvas::cssValuePool()
{
auto* context = canvasBaseScriptExecutionContext();
@@ -351,6 +440,7 @@
clearCopiedImage();
notifyObserversCanvasResized();
+ scheduleCommitToPlaceholderCanvas();
}
}
Modified: trunk/Source/WebCore/html/OffscreenCanvas.h (265542 => 265543)
--- trunk/Source/WebCore/html/OffscreenCanvas.h 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/Source/WebCore/html/OffscreenCanvas.h 2020-08-12 09:05:54 UTC (rev 265543)
@@ -38,6 +38,7 @@
#include "ScriptWrappable.h"
#include <wtf/Forward.h>
#include <wtf/RefCounted.h>
+#include <wtf/WeakPtr.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
@@ -45,7 +46,9 @@
class CanvasRenderingContext;
class CSSValuePool;
class DeferredPromise;
+class HTMLCanvasElement;
class ImageBitmap;
+class ImageData;
class OffscreenCanvasRenderingContext2D;
class WebGLRenderingContext;
@@ -58,6 +61,8 @@
class DetachedOffscreenCanvas {
WTF_MAKE_NONCOPYABLE(DetachedOffscreenCanvas);
WTF_MAKE_FAST_ALLOCATED;
+ friend class OffscreenCanvas;
+
public:
DetachedOffscreenCanvas(std::unique_ptr<ImageBuffer>&&, const IntSize&, bool originClean);
@@ -71,11 +76,13 @@
return buffer->memoryCost();
return 0;
}
+ WeakPtr<HTMLCanvasElement> takePlaceholderCanvas();
private:
std::unique_ptr<ImageBuffer> m_buffer;
IntSize m_size;
bool m_originClean;
+ WeakPtr<HTMLCanvasElement> m_placeholderCanvas;
};
class OffscreenCanvas final : public RefCounted<OffscreenCanvas>, public CanvasBase, public EventTargetWithInlineData, private ContextDestructionObserver {
@@ -94,6 +101,7 @@
static Ref<OffscreenCanvas> create(ScriptExecutionContext&, unsigned width, unsigned height);
static Ref<OffscreenCanvas> create(ScriptExecutionContext&, std::unique_ptr<DetachedOffscreenCanvas>&&);
+ static Ref<OffscreenCanvas> create(ScriptExecutionContext&, HTMLCanvasElement&);
virtual ~OffscreenCanvas();
unsigned width() const final;
@@ -103,7 +111,7 @@
CanvasRenderingContext* renderingContext() const final { return m_context.get(); }
- ExceptionOr<OffscreenRenderingContext> getContext(JSC::JSGlobalObject&, RenderingContextType, Vector<JSC::Strong<JSC::Unknown>>&& arguments);
+ ExceptionOr<Optional<OffscreenRenderingContext>> getContext(JSC::JSGlobalObject&, RenderingContextType, Vector<JSC::Strong<JSC::Unknown>>&& arguments);
ExceptionOr<RefPtr<ImageBitmap>> transferToImageBitmap();
void convertToBlob(ImageEncodeOptions&&, Ref<DeferredPromise>&&);
@@ -117,6 +125,8 @@
bool canDetach() const;
std::unique_ptr<DetachedOffscreenCanvas> detach();
+ void commitToPlaceholderCanvas();
+
CSSValuePool& cssValuePool();
using RefCounted::ref;
@@ -146,6 +156,10 @@
void clearCopiedImage() const;
+ void setPlaceholderCanvas(HTMLCanvasElement&);
+ void pushBufferToPlaceholder();
+ void scheduleCommitToPlaceholderCanvas();
+
std::unique_ptr<CanvasRenderingContext> m_context;
// m_hasCreatedImageBuffer means we tried to malloc the buffer. We didn't necessarily get it.
@@ -154,6 +168,13 @@
bool m_detached { false };
mutable RefPtr<Image> m_copiedImage;
+
+ bool m_hasScheduledCommit { false };
+ WeakPtr<HTMLCanvasElement> m_placeholderCanvas;
+
+ mutable Lock m_commitLock;
+ bool m_hasPendingCommitData { false };
+ RefPtr<ImageData> m_pendingCommitData;
};
}
Modified: trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.cpp (265542 => 265543)
--- trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.cpp 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.cpp 2020-08-12 09:05:54 UTC (rev 265543)
@@ -48,6 +48,11 @@
OffscreenCanvasRenderingContext2D::~OffscreenCanvasRenderingContext2D() = default;
+void OffscreenCanvasRenderingContext2D::commit()
+{
+ downcast<OffscreenCanvas>(canvasBase()).commitToPlaceholderCanvas();
+}
+
} // namespace WebCore
#endif
Modified: trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.h (265542 => 265543)
--- trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.h 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.h 2020-08-12 09:05:54 UTC (rev 265543)
@@ -42,6 +42,8 @@
bool isOffscreen2d() const override { return true; }
OffscreenCanvas& canvas() const { return downcast<OffscreenCanvas>(canvasBase()); }
+
+ void commit();
};
} // namespace WebCore
Modified: trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.idl (265542 => 265543)
--- trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.idl 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.idl 2020-08-12 09:05:54 UTC (rev 265543)
@@ -27,14 +27,13 @@
CustomIsReachable,
EnabledAtRuntime=OffscreenCanvas,
Conditional=OFFSCREEN_CANVAS,
- Exposed=(Window), // FIXME: OffscreenCanvas - should be Window,Worker
+ Exposed=(Window,Worker),
JSGenerateToJSObject,
JSCustomMarkFunction,
// CallTracingCallback=recordCanvasAction, // FIXME: OffscreenCanvas.
] interface OffscreenCanvasRenderingContext2D {
readonly attribute OffscreenCanvas canvas;
- // FIXME: OffscreenCanvas.
- // void commit();
+ void commit();
// Inspector-only.
// FIXME: OffscreenCanvas.
Modified: trunk/Source/WebCore/html/canvas/PlaceholderRenderingContext.cpp (265542 => 265543)
--- trunk/Source/WebCore/html/canvas/PlaceholderRenderingContext.cpp 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/Source/WebCore/html/canvas/PlaceholderRenderingContext.cpp 2020-08-12 09:05:54 UTC (rev 265543)
@@ -26,6 +26,10 @@
#include "config.h"
#include "PlaceholderRenderingContext.h"
+#if ENABLE(OFFSCREEN_CANVAS)
+
+#include "HTMLCanvasElement.h"
+#include "OffscreenCanvas.h"
#include <wtf/IsoMallocInlines.h>
namespace WebCore {
@@ -37,4 +41,14 @@
{
}
+HTMLCanvasElement* PlaceholderRenderingContext::canvas() const
+{
+ auto& base = canvasBase();
+ if (!is<HTMLCanvasElement>(base))
+ return nullptr;
+ return &downcast<HTMLCanvasElement>(base);
}
+
+}
+
+#endif
Modified: trunk/Source/WebCore/html/canvas/PlaceholderRenderingContext.h (265542 => 265543)
--- trunk/Source/WebCore/html/canvas/PlaceholderRenderingContext.h 2020-08-12 07:35:52 UTC (rev 265542)
+++ trunk/Source/WebCore/html/canvas/PlaceholderRenderingContext.h 2020-08-12 09:05:54 UTC (rev 265543)
@@ -25,15 +25,21 @@
#pragma once
+#if ENABLE(OFFSCREEN_CANVAS)
+
#include "CanvasRenderingContext.h"
namespace WebCore {
+class OffscreenCanvas;
+
class PlaceholderRenderingContext final : public CanvasRenderingContext {
WTF_MAKE_ISO_ALLOCATED(PlaceholderRenderingContext);
public:
PlaceholderRenderingContext(CanvasBase&);
+ HTMLCanvasElement* canvas() const;
+
private:
bool isPlaceholder() const final { return true; }
};
@@ -41,3 +47,5 @@
}
SPECIALIZE_TYPE_TRAITS_CANVASRENDERINGCONTEXT(WebCore::PlaceholderRenderingContext, isPlaceholder())
+
+#endif