Diff
Modified: trunk/LayoutTests/ChangeLog (195645 => 195646)
--- trunk/LayoutTests/ChangeLog 2016-01-27 01:31:36 UTC (rev 195645)
+++ trunk/LayoutTests/ChangeLog 2016-01-27 01:53:18 UTC (rev 195646)
@@ -1,3 +1,15 @@
+2016-01-26 Simon Fraser <[email protected]>
+
+ Allow canvas to use display-list drawing for testing
+ https://bugs.webkit.org/show_bug.cgi?id=153475
+
+ Reviewed by Dean Jackson.
+
+ Simple canvas-based display list test.
+
+ * displaylists/canvas-display-list-expected.txt: Added.
+ * displaylists/canvas-display-list.html: Added.
+
2016-01-26 Chris Dumez <[email protected]>
Setting HTMLInputElement.value to null to set its value to the empty string
Added: trunk/LayoutTests/displaylists/canvas-display-list-expected.txt (0 => 195646)
--- trunk/LayoutTests/displaylists/canvas-display-list-expected.txt (rev 0)
+++ trunk/LayoutTests/displaylists/canvas-display-list-expected.txt 2016-01-27 01:53:18 UTC (rev 195646)
@@ -0,0 +1,13 @@
+
+(set-state
+ (change-flags 256)
+ (fill-color #C80000))
+(fill-rect
+ (extent at (10,10) size 55x50)
+ (rect at (10,10) size 55x50))
+(set-state
+ (change-flags 256)
+ (fill-color #0000C87F))
+(fill-rect
+ (extent at (30,30) size 55x50)
+ (rect at (30,30) size 55x50))
Added: trunk/LayoutTests/displaylists/canvas-display-list.html (0 => 195646)
--- trunk/LayoutTests/displaylists/canvas-display-list.html (rev 0)
+++ trunk/LayoutTests/displaylists/canvas-display-list.html 2016-01-27 01:53:18 UTC (rev 195646)
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <script>
+ function drawCanvas()
+ {
+ var ctx = document.getElementById('canvas').getContext('2d');
+ ctx.fillStyle = "rgb(200,0,0)";
+ ctx.fillRect (10, 10, 55, 50);
+
+ ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
+ ctx.fillRect (30, 30, 55, 50);
+ }
+
+ if (window.testRunner)
+ testRunner.dumpAsText();
+
+ var canvas;
+ function doTest()
+ {
+ document.body.offsetWidth;
+ canvas = document.getElementById('canvas');
+ if (window.internals) {
+ internals.setElementUsesDisplayListDrawing(canvas, true);
+ internals.setElementTracksDisplayListReplay(canvas, true);
+ }
+
+ drawCanvas();
+
+ if (window.testRunner)
+ testRunner.display();
+
+ if (window.internals)
+ document.getElementById('output').textContent = internals.replayDisplayListForElement(canvas);
+ }
+ window.addEventListener('load', doTest, false);
+ </script>
+</head>
+<body>
+<canvas id="canvas" width="300" height="200"></canvas>
+<pre id="output"></pre>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (195645 => 195646)
--- trunk/Source/WebCore/ChangeLog 2016-01-27 01:31:36 UTC (rev 195645)
+++ trunk/Source/WebCore/ChangeLog 2016-01-27 01:53:18 UTC (rev 195646)
@@ -1,3 +1,54 @@
+2016-01-26 Simon Fraser <[email protected]>
+
+ Allow canvas to use display-list drawing for testing
+ https://bugs.webkit.org/show_bug.cgi?id=153475
+
+ Reviewed by Dean Jackson.
+
+ Optionally have 2D <canvas> use display-list drawing, which is only enabled
+ via Internals for now.
+
+ Support displayListAsText() and replayDisplayListAsText() on canvas, so we can
+ use it to test playback optimizations. [Note that displayListAsText() always
+ returns an empty string currently, because the display list is cleared when the
+ canvas is painted to the page.]
+
+ Display list rendering is implemented by giving CanvasRenderingContext2D an
+ optional DisplayListDrawingContext, which packages up a display list, recorder
+ and recording context. The existing paintRenderingResultsToCanvas() is overridden
+ to replay the recorded display list into the primary canvas context.
+
+ Tracked replay display lists are stored in a static map, keyed by the CanvasRenderingContext2D.
+
+ Test: displaylists/canvas-display-list.html
+
+ * html/HTMLCanvasElement.cpp:
+ (WebCore::HTMLCanvasElement::HTMLCanvasElement):
+ (WebCore::HTMLCanvasElement::getContext):
+ (WebCore::HTMLCanvasElement::paint):
+ (WebCore::HTMLCanvasElement::setUsesDisplayListDrawing):
+ (WebCore::HTMLCanvasElement::setTracksDisplayListReplay):
+ (WebCore::HTMLCanvasElement::displayListAsText):
+ (WebCore::HTMLCanvasElement::replayDisplayListAsText):
+ * html/HTMLCanvasElement.h:
+ * html/canvas/CanvasRenderingContext.h:
+ * html/canvas/CanvasRenderingContext2D.cpp:
+ (WebCore::DisplayListDrawingContext::DisplayListDrawingContext):
+ (WebCore::contextDisplayListMap):
+ (WebCore::CanvasRenderingContext2D::~CanvasRenderingContext2D):
+ (WebCore::CanvasRenderingContext2D::setTracksDisplayListReplay):
+ (WebCore::CanvasRenderingContext2D::displayListAsText):
+ (WebCore::CanvasRenderingContext2D::replayDisplayListAsText):
+ (WebCore::CanvasRenderingContext2D::paintRenderingResultsToCanvas):
+ (WebCore::CanvasRenderingContext2D::drawingContext):
+ (WebCore::CanvasRenderingContext2D::CanvasRenderingContext2D): Deleted.
+ * html/canvas/CanvasRenderingContext2D.h:
+ * testing/Internals.cpp:
+ (WebCore::Internals::setElementUsesDisplayListDrawing):
+ (WebCore::Internals::setElementTracksDisplayListReplay):
+ (WebCore::Internals::displayListForElement):
+ (WebCore::Internals::replayDisplayListForElement):
+
2016-01-26 Joseph Pecoraro <[email protected]>
Generalize ResourceUsageData gathering to be used outside of ResourceUsageOverlay
Modified: trunk/Source/WebCore/html/HTMLCanvasElement.cpp (195645 => 195646)
--- trunk/Source/WebCore/html/HTMLCanvasElement.cpp 2016-01-27 01:31:36 UTC (rev 195645)
+++ trunk/Source/WebCore/html/HTMLCanvasElement.cpp 2016-01-27 01:53:18 UTC (rev 195646)
@@ -232,6 +232,10 @@
}
m_context = std::make_unique<CanvasRenderingContext2D>(this, document().inQuirksMode(), usesDashbardCompatibilityMode);
+
+ downcast<CanvasRenderingContext2D>(*m_context).setUsesDisplayListDrawing(m_usesDisplayListDrawing);
+ downcast<CanvasRenderingContext2D>(*m_context).setTracksDisplayListReplay(m_tracksDisplayListReplay);
+
#if USE(IOSURFACE_CANVAS_BACKING_STORE) || ENABLE(ACCELERATED_2D_CANVAS)
// Need to make sure a RenderLayer and compositing layer get created for the Canvas
setNeedsStyleRecalc(SyntheticStyleChange);
@@ -410,6 +414,7 @@
if (m_context) {
if (!paintsIntoCanvasBuffer() && !document().printing())
return;
+
m_context->paintRenderingResultsToCanvas();
}
@@ -589,6 +594,44 @@
return 4 * m_imageBuffer->internalSize().width() * m_imageBuffer->internalSize().height();
}
+void HTMLCanvasElement::setUsesDisplayListDrawing(bool usesDisplayListDrawing)
+{
+ if (usesDisplayListDrawing == m_usesDisplayListDrawing)
+ return;
+
+ m_usesDisplayListDrawing = usesDisplayListDrawing;
+
+ if (m_context && is<CanvasRenderingContext2D>(*m_context))
+ downcast<CanvasRenderingContext2D>(*m_context).setUsesDisplayListDrawing(m_usesDisplayListDrawing);
+}
+
+void HTMLCanvasElement::setTracksDisplayListReplay(bool tracksDisplayListReplay)
+{
+ if (tracksDisplayListReplay == m_tracksDisplayListReplay)
+ return;
+
+ m_tracksDisplayListReplay = tracksDisplayListReplay;
+
+ if (m_context && is<CanvasRenderingContext2D>(*m_context))
+ downcast<CanvasRenderingContext2D>(*m_context).setTracksDisplayListReplay(m_tracksDisplayListReplay);
+}
+
+String HTMLCanvasElement::displayListAsText(DisplayList::AsTextFlags flags) const
+{
+ if (m_context && is<CanvasRenderingContext2D>(*m_context))
+ return downcast<CanvasRenderingContext2D>(*m_context).displayListAsText(flags);
+
+ return String();
+}
+
+String HTMLCanvasElement::replayDisplayListAsText(DisplayList::AsTextFlags flags) const
+{
+ if (m_context && is<CanvasRenderingContext2D>(*m_context))
+ return downcast<CanvasRenderingContext2D>(*m_context).replayDisplayListAsText(flags);
+
+ return String();
+}
+
void HTMLCanvasElement::createImageBuffer() const
{
ASSERT(!m_imageBuffer);
Modified: trunk/Source/WebCore/html/HTMLCanvasElement.h (195645 => 195646)
--- trunk/Source/WebCore/html/HTMLCanvasElement.h 2016-01-27 01:31:36 UTC (rev 195645)
+++ trunk/Source/WebCore/html/HTMLCanvasElement.h 2016-01-27 01:53:18 UTC (rev 195646)
@@ -52,6 +52,10 @@
class ImageBuffer;
class IntSize;
+namespace DisplayList {
+typedef unsigned AsTextFlags;
+}
+
class CanvasObserver {
public:
virtual ~CanvasObserver() { }
@@ -135,6 +139,11 @@
bool shouldAccelerate(const IntSize&) const;
+ WEBCORE_EXPORT void setUsesDisplayListDrawing(bool);
+ WEBCORE_EXPORT void setTracksDisplayListReplay(bool);
+ WEBCORE_EXPORT String displayListAsText(DisplayList::AsTextFlags) const;
+ WEBCORE_EXPORT String replayDisplayListAsText(DisplayList::AsTextFlags) const;
+
size_t memoryCost() const;
private:
@@ -171,6 +180,9 @@
bool m_rendererIsCanvas { false };
bool m_ignoreReset { false };
+ bool m_usesDisplayListDrawing { false };
+ bool m_tracksDisplayListReplay { false };
+
// m_createdImageBuffer means we tried to malloc the buffer. We didn't necessarily get it.
mutable bool m_hasCreatedImageBuffer { false };
mutable bool m_didClearImageBuffer { false };
Modified: trunk/Source/WebCore/html/canvas/CanvasRenderingContext.h (195645 => 195646)
--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext.h 2016-01-27 01:31:36 UTC (rev 195645)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext.h 2016-01-27 01:53:18 UTC (rev 195646)
@@ -81,4 +81,9 @@
} // namespace WebCore
+#define SPECIALIZE_TYPE_TRAITS_CANVASRENDERINGCONTEXT(ToValueTypeName, predicate) \
+SPECIALIZE_TYPE_TRAITS_BEGIN(ToValueTypeName) \
+ static bool isType(const WebCore::CanvasRenderingContext& context) { return context.predicate; } \
+SPECIALIZE_TYPE_TRAITS_END()
+
#endif
Modified: trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp (195645 => 195646)
--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp 2016-01-27 01:31:36 UTC (rev 195645)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp 2016-01-27 01:53:18 UTC (rev 195646)
@@ -40,6 +40,8 @@
#include "CanvasGradient.h"
#include "CanvasPattern.h"
#include "DOMPath.h"
+#include "DisplayListRecorder.h"
+#include "DisplayListReplayer.h"
#include "ExceptionCodePlaceholder.h"
#include "FloatQuad.h"
#include "HTMLImageElement.h"
@@ -55,6 +57,7 @@
#include "StyleResolver.h"
#include "TextMetrics.h"
#include "TextRun.h"
+#include "TextStream.h"
#include <wtf/CheckedArithmetic.h>
#include <wtf/MathExtras.h>
@@ -85,6 +88,25 @@
static const char* const defaultFontFamily = "sans-serif";
static const char* const defaultFont = "10px sans-serif";
+struct DisplayListDrawingContext {
+ GraphicsContext context;
+ DisplayList::Recorder recorder;
+ DisplayList::DisplayList displayList;
+
+ DisplayListDrawingContext(const FloatRect& clip)
+ : recorder(context, displayList, clip, AffineTransform())
+ {
+ }
+};
+
+typedef HashMap<const CanvasRenderingContext2D*, std::unique_ptr<DisplayList::DisplayList>> ContextDisplayListHashMap;
+
+static ContextDisplayListHashMap& contextDisplayListMap()
+{
+ static NeverDestroyed<ContextDisplayListHashMap> sharedHashMap;
+ return sharedHashMap;
+}
+
class CanvasStrokeStyleApplier : public StrokeStyleApplier {
public:
CanvasStrokeStyleApplier(CanvasRenderingContext2D* canvasContext)
@@ -112,7 +134,6 @@
CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, bool usesCSSCompatibilityParseMode, bool usesDashboardCompatibilityMode)
: CanvasRenderingContext(canvas)
, m_stateStack(1)
- , m_unrealizedSaveCount(0)
, m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode)
#if ENABLE(DASHBOARD_SUPPORT)
, m_usesDashboardCompatibilityMode(usesDashboardCompatibilityMode)
@@ -141,6 +162,9 @@
#if !ASSERT_DISABLED
unwindStateStack();
#endif
+
+ if (UNLIKELY(tracksDisplayListReplay()))
+ contextDisplayListMap().remove(this);
}
bool CanvasRenderingContext2D::isAccelerated() const
@@ -162,6 +186,8 @@
m_stateStack.first() = State();
m_path.clear();
m_unrealizedSaveCount = 0;
+
+ m_recordingContext = nullptr;
}
CanvasRenderingContext2D::State::State()
@@ -1907,8 +1933,64 @@
canvas()->didDraw(dirtyRect);
}
+void CanvasRenderingContext2D::setTracksDisplayListReplay(bool tracksDisplayListReplay)
+{
+ if (tracksDisplayListReplay == m_tracksDisplayListReplay)
+ return;
+
+ m_tracksDisplayListReplay = tracksDisplayListReplay;
+ if (!m_tracksDisplayListReplay)
+ contextDisplayListMap().remove(this);
+}
+
+String CanvasRenderingContext2D::displayListAsText(DisplayList::AsTextFlags flags) const
+{
+ if (m_recordingContext)
+ return m_recordingContext->displayList.asText(flags);
+
+ return String();
+}
+
+String CanvasRenderingContext2D::replayDisplayListAsText(DisplayList::AsTextFlags flags) const
+{
+ auto it = contextDisplayListMap().find(this);
+ if (it != contextDisplayListMap().end()) {
+ TextStream stream;
+ stream << it->value->asText(flags);
+ return stream.release();
+ }
+
+ return String();
+}
+
+void CanvasRenderingContext2D::paintRenderingResultsToCanvas()
+{
+ if (UNLIKELY(m_usesDisplayListDrawing)) {
+ if (!m_recordingContext)
+ return;
+
+ FloatRect clip(FloatPoint::zero(), canvas()->size());
+ DisplayList::Replayer replayer(*canvas()->drawingContext(), m_recordingContext->displayList);
+
+ if (UNLIKELY(m_tracksDisplayListReplay)) {
+ auto replayList = replayer.replay(clip, m_tracksDisplayListReplay);
+ contextDisplayListMap().add(this, WTFMove(replayList));
+ } else
+ replayer.replay(clip);
+
+ m_recordingContext->displayList.clear();
+ }
+}
+
GraphicsContext* CanvasRenderingContext2D::drawingContext() const
{
+ if (UNLIKELY(m_usesDisplayListDrawing)) {
+ if (!m_recordingContext)
+ m_recordingContext = std::make_unique<DisplayListDrawingContext>(FloatRect(FloatPoint::zero(), canvas()->size()));
+
+ return &m_recordingContext->context;
+ }
+
return canvas()->drawingContext();
}
Modified: trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h (195645 => 195646)
--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h 2016-01-27 01:31:36 UTC (rev 195645)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h 2016-01-27 01:53:18 UTC (rev 195646)
@@ -237,6 +237,15 @@
High
};
+ bool usesDisplayListDrawing() const { return m_usesDisplayListDrawing; };
+ void setUsesDisplayListDrawing(bool flag) { m_usesDisplayListDrawing = flag; };
+
+ bool tracksDisplayListReplay() const { return m_tracksDisplayListReplay; }
+ void setTracksDisplayListReplay(bool);
+
+ String displayListAsText(DisplayList::AsTextFlags) const;
+ String replayDisplayListAsText(DisplayList::AsTextFlags) const;
+
private:
enum class Direction {
Inherit,
@@ -320,6 +329,8 @@
void didDraw(const FloatRect&, unsigned options = CanvasDidDrawApplyAll);
void didDrawEntireCanvas();
+ void paintRenderingResultsToCanvas() override;
+
GraphicsContext* drawingContext() const;
void unwindStateStack();
@@ -384,13 +395,19 @@
#endif
Vector<State, 1> m_stateStack;
- unsigned m_unrealizedSaveCount;
+ unsigned m_unrealizedSaveCount { 0 };
bool m_usesCSSCompatibilityParseMode;
#if ENABLE(DASHBOARD_SUPPORT)
bool m_usesDashboardCompatibilityMode;
#endif
+
+ bool m_usesDisplayListDrawing { false };
+ bool m_tracksDisplayListReplay { false };
+ mutable std::unique_ptr<struct DisplayListDrawingContext> m_recordingContext;
};
} // namespace WebCore
+SPECIALIZE_TYPE_TRAITS_CANVASRENDERINGCONTEXT(WebCore::CanvasRenderingContext2D, is2d())
+
#endif
Modified: trunk/Source/WebCore/testing/Internals.cpp (195645 => 195646)
--- trunk/Source/WebCore/testing/Internals.cpp 2016-01-27 01:31:36 UTC (rev 195645)
+++ trunk/Source/WebCore/testing/Internals.cpp 2016-01-27 01:53:18 UTC (rev 195646)
@@ -57,6 +57,7 @@
#include "FormController.h"
#include "FrameLoader.h"
#include "FrameView.h"
+#include "HTMLCanvasElement.h"
#include "HTMLIFrameElement.h"
#include "HTMLImageElement.h"
#include "HTMLInputElement.h"
@@ -1982,11 +1983,21 @@
return;
}
- if (!element || !element->renderer() || !element->renderer()->hasLayer()) {
+ if (!element || !element->renderer()) {
ec = INVALID_ACCESS_ERR;
return;
}
+ if (is<HTMLCanvasElement>(*element)) {
+ downcast<HTMLCanvasElement>(*element).setUsesDisplayListDrawing(usesDisplayListDrawing);
+ return;
+ }
+
+ if (!element->renderer()->hasLayer()) {
+ ec = INVALID_ACCESS_ERR;
+ return;
+ }
+
RenderLayer* layer = downcast<RenderLayerModelObject>(element->renderer())->layer();
if (!layer->isComposited()) {
ec = INVALID_ACCESS_ERR;
@@ -2004,11 +2015,21 @@
return;
}
- if (!element || !element->renderer() || !element->renderer()->hasLayer()) {
+ if (!element || !element->renderer()) {
ec = INVALID_ACCESS_ERR;
return;
}
+ if (is<HTMLCanvasElement>(*element)) {
+ downcast<HTMLCanvasElement>(*element).setTracksDisplayListReplay(isTrackingReplay);
+ return;
+ }
+
+ if (!element->renderer()->hasLayer()) {
+ ec = INVALID_ACCESS_ERR;
+ return;
+ }
+
RenderLayer* layer = downcast<RenderLayerModelObject>(element->renderer())->layer();
if (!layer->isComposited()) {
ec = INVALID_ACCESS_ERR;
@@ -2031,21 +2052,29 @@
return String();
}
- if (!element || !element->renderer() || !element->renderer()->hasLayer()) {
+ if (!element || !element->renderer()) {
ec = INVALID_ACCESS_ERR;
return String();
}
-
+
+ DisplayList::AsTextFlags displayListFlags = 0;
+ if (flags & DISPLAY_LIST_INCLUDES_PLATFORM_OPERATIONS)
+ displayListFlags |= DisplayList::AsTextFlag::IncludesPlatformOperations;
+
+ if (is<HTMLCanvasElement>(*element))
+ return downcast<HTMLCanvasElement>(*element).displayListAsText(displayListFlags);
+
+ if (!element->renderer()->hasLayer()) {
+ ec = INVALID_ACCESS_ERR;
+ return String();
+ }
+
RenderLayer* layer = downcast<RenderLayerModelObject>(element->renderer())->layer();
if (!layer->isComposited()) {
ec = INVALID_ACCESS_ERR;
return String();
}
- DisplayList::AsTextFlags displayListFlags = 0;
- if (flags & DISPLAY_LIST_INCLUDES_PLATFORM_OPERATIONS)
- displayListFlags |= DisplayList::AsTextFlag::IncludesPlatformOperations;
-
return layer->backing()->displayListAsText(displayListFlags);
}
@@ -2062,21 +2091,29 @@
return String();
}
- if (!element || !element->renderer() || !element->renderer()->hasLayer()) {
+ if (!element || !element->renderer()) {
ec = INVALID_ACCESS_ERR;
return String();
}
-
+
+ DisplayList::AsTextFlags displayListFlags = 0;
+ if (flags & DISPLAY_LIST_INCLUDES_PLATFORM_OPERATIONS)
+ displayListFlags |= DisplayList::AsTextFlag::IncludesPlatformOperations;
+
+ if (is<HTMLCanvasElement>(*element))
+ return downcast<HTMLCanvasElement>(*element).replayDisplayListAsText(displayListFlags);
+
+ if (!element->renderer()->hasLayer()) {
+ ec = INVALID_ACCESS_ERR;
+ return String();
+ }
+
RenderLayer* layer = downcast<RenderLayerModelObject>(element->renderer())->layer();
if (!layer->isComposited()) {
ec = INVALID_ACCESS_ERR;
return String();
}
- DisplayList::AsTextFlags displayListFlags = 0;
- if (flags & DISPLAY_LIST_INCLUDES_PLATFORM_OPERATIONS)
- displayListFlags |= DisplayList::AsTextFlag::IncludesPlatformOperations;
-
return layer->backing()->replayDisplayListAsText(displayListFlags);
}