diff options
author | jackhou@chromium.org <jackhou@chromium.org> | 2014-12-18 03:53:29 +0000 |
---|---|---|
committer | jackhou@chromium.org <jackhou@chromium.org> | 2014-12-18 03:53:29 +0000 |
commit | a85874ebe58ab86e2413043f6e37e9f55c049c31 (patch) | |
tree | e3d150dad8cbe1c0237dab639f81b3145fd31fa6 /third_party/WebKit | |
parent | 1084b30571ede9c32b2d47c5b42a262724a517fa (diff) | |
download | chromium_src-a85874ebe58ab86e2413043f6e37e9f55c049c31.zip chromium_src-a85874ebe58ab86e2413043f6e37e9f55c049c31.tar.gz chromium_src-a85874ebe58ab86e2413043f6e37e9f55c049c31.tar.bz2 |
Implement image-rendering:pixelated for accelerated 2D canvases.
This CL depends on a CC side change here:
https://codereview.chromium.org/558083002/
BUG=134040, 424025, 317991
Review URL: https://codereview.chromium.org/562583002
git-svn-id: svn://svn.chromium.org/blink/trunk@187428 bbb929c8-8fbe-4397-9dbb-9b2b20218538
Diffstat (limited to 'third_party/WebKit')
19 files changed, 253 insertions, 4 deletions
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/pixelated-canvas-expected.png b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-canvas-expected.png Binary files differnew file mode 100644 index 0000000..ae7bb14 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-canvas-expected.png diff --git a/third_party/WebKit/LayoutTests/fast/canvas/pixelated-canvas-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-canvas-expected.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-canvas-expected.txt @@ -0,0 +1 @@ + diff --git a/third_party/WebKit/LayoutTests/fast/canvas/pixelated-canvas.html b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-canvas.html new file mode 100644 index 0000000..10c2682 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-canvas.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<style> + img { + display: none; + } + canvas { + width: 100px; + height: 100px; + image-rendering: pixelated; + } +</style> +<body> + <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFElEQVQIHWP4z8DwHwyBNJDN8B8AQNEG+t5Ik2kAAAAASUVORK5CYII="> + <!-- Test that drawing a pixelated canvas with another pixelated canvas as source works. --> + <!-- Both canvases should be upscaled without blurring. --> + <canvas class="canvas0" width="4" height="4"></canvas> + <canvas class="canvas1" width="4" height="4"></canvas> +</body> +<script> + // Ignore the render tree. + if (window.testRunner) + window.testRunner.dumpAsTextWithPixelResults(); + + function drawToCanvas(canvas) { + var ctx = canvas.getContext("2d") + ctx.drawImage(document.getElementsByTagName("img")[0], 1, 1); + } + + function draw() { + var canvas0 = document.getElementsByTagName("canvas")[0]; + var canvas1 = document.getElementsByTagName("canvas")[1]; + drawToCanvas(canvas0); + canvas1.getContext("2d").drawImage(canvas0, 0, 0); + } + window.onload = draw; +</script> diff --git a/third_party/WebKit/LayoutTests/fast/canvas/pixelated-expected.png b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-expected.png Binary files differnew file mode 100644 index 0000000..1c5ca15 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-expected.png diff --git a/third_party/WebKit/LayoutTests/fast/canvas/pixelated-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-expected.txt new file mode 100644 index 0000000..1a4baf5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-expected.txt @@ -0,0 +1 @@ + diff --git a/third_party/WebKit/LayoutTests/fast/canvas/pixelated-off-screen-expected.html b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-off-screen-expected.html new file mode 100644 index 0000000..963c9b4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-off-screen-expected.html @@ -0,0 +1,46 @@ +<!DOCTYPE html> +<style> + canvas { + width: 100px; + height: 100px; + image-rendering: pixelated; + } +</style> +<body> + <!-- Draw to a canvas already in the DOM. --> + <!-- The resulting image should be 100x100, consisting of 4 50x50 blocks of solid color, with no blurring of edges --> + <canvas width="2" height="2"></canvas> +</body> +<script> + // Ignore the render tree. + if (window.testRunner) + window.testRunner.dumpAsTextWithPixelResults(); + + var canvas = document.getElementsByTagName("canvas")[0]; + var context = canvas.getContext("2d"); + var imageHandle = context.createImageData(canvas.width, canvas.height); + + var index = 0; + + imageHandle.data[index++] = 255; + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 255; + + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 255; + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 255; + + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 255; + imageHandle.data[index++] = 255; + + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 255; + + context.putImageData(imageHandle, 0, 0); +</script> diff --git a/third_party/WebKit/LayoutTests/fast/canvas/pixelated-off-screen.html b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-off-screen.html new file mode 100644 index 0000000..a0f05b5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-off-screen.html @@ -0,0 +1,49 @@ +<!DOCTYPE html> +<style> + canvas { + width: 100px; + height: 100px; + image-rendering: pixelated; + } +</style> +<body> + <!-- Test drawing a canvas off-screen then appending it to the DOM. --> + <!-- The resulting image should be 100x100, consisting of 4 50x50 blocks of solid color, with no blurring of edges --> +</body> +<script> + // Ignore the render tree. + if (window.testRunner) + window.testRunner.dumpAsTextWithPixelResults(); + + var canvas = document.createElement('canvas'); + canvas.width = 2; + canvas.height = 2; + + var context = canvas.getContext("2d"); + var imageHandle = context.createImageData(canvas.width, canvas.height); + + var index = 0; + + imageHandle.data[index++] = 255; + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 255; + + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 255; + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 255; + + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 255; + imageHandle.data[index++] = 255; + + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 0; + imageHandle.data[index++] = 255; + + context.putImageData(imageHandle, 0, 0); + document.getElementsByTagName("body")[0].appendChild(canvas); +</script> diff --git a/third_party/WebKit/LayoutTests/fast/canvas/pixelated-resize-expected.png b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-resize-expected.png Binary files differnew file mode 100644 index 0000000..5e56bbf --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-resize-expected.png diff --git a/third_party/WebKit/LayoutTests/fast/canvas/pixelated-resize-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-resize-expected.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-resize-expected.txt @@ -0,0 +1 @@ + diff --git a/third_party/WebKit/LayoutTests/fast/canvas/pixelated-resize.html b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-resize.html new file mode 100644 index 0000000..723a0d5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/pixelated-resize.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<style> + img { + display: none; + } + canvas { + width: 100px; + height: 100px; + image-rendering: pixelated; + } +</style> +<body> + <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFElEQVQIHWP4z8DwHwyBNJDN8B8AQNEG+t5Ik2kAAAAASUVORK5CYII="> + <!-- Test that resizing a pixelated canvas works. --> + <!-- The canvas should be upscaled without blurring. --> + <canvas width="4" height="4"></canvas> +</body> +<script> + // Ignore the render tree. + if (window.testRunner) + window.testRunner.dumpAsTextWithPixelResults(); + + function drawToCanvas(canvas) { + var ctx = canvas.getContext("2d") + ctx.drawImage(document.getElementsByTagName("img")[0], 1, 1); + } + + function draw() { + var canvas = document.getElementsByTagName("canvas")[0]; + drawToCanvas(canvas); + // Resize so that the image buffer is reset. + canvas.width = 5; + canvas.style.width = "201px"; + drawToCanvas(canvas); + } + window.onload = draw; +</script> diff --git a/third_party/WebKit/LayoutTests/fast/canvas/pixelated.html b/third_party/WebKit/LayoutTests/fast/canvas/pixelated.html new file mode 100644 index 0000000..3b895d1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/pixelated.html @@ -0,0 +1,45 @@ +<!DOCTYPE html> +<style> + img { + display: none; + } + canvas { + width: 100px; + height: 100px; + image-rendering: pixelated; + } + .canvas2 { + image-rendering: auto; + } +</style> +<body> + <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFElEQVQIHWP4z8DwHwyBNJDN8B8AQNEG+t5Ik2kAAAAASUVORK5CYII="> + <!-- Test that gpu accelerated canvases work with pixelated. --> + <!-- The result is 3 canvases, each with a 2x2 block of colors. Only the middle canvas should be blurred. --> + <canvas class="canvas0" width="4" height="4"></canvas> + <canvas class="canvas1" width="4" height="4"></canvas> + <canvas class="canvas2" width="4" height="4"></canvas> +</body> +<script> + // Ignore the render tree. + if (window.testRunner) + window.testRunner.dumpAsTextWithPixelResults(); + + function drawToCanvas(canvas) { + var ctx = canvas.getContext("2d") + ctx.drawImage(document.getElementsByTagName("img")[0], 1, 1); + } + + function draw() { + drawToCanvas(document.getElementsByTagName("canvas")[0]); + var canvas1 = document.getElementsByTagName("canvas")[1]; + var canvas2 = document.getElementsByTagName("canvas")[2]; + drawToCanvas(canvas1); + drawToCanvas(canvas2); + // The first canvas stays pixelated. Flip the pixelated-ness of the + // other two. + canvas1.style.imageRendering = "auto"; + canvas2.style.imageRendering = "pixelated"; + } + window.onload = draw; +</script> diff --git a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/pixelated-expected.png b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/pixelated-expected.png Binary files differnew file mode 100644 index 0000000..e1e0e2d --- /dev/null +++ b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/pixelated-expected.png diff --git a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/pixelated-expected.txt b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/pixelated-expected.txt new file mode 100644 index 0000000..1a4baf5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/pixelated-expected.txt @@ -0,0 +1 @@ + diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp index 08bbb9b..ceb28f5 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp @@ -149,9 +149,11 @@ RenderObject* HTMLCanvasElement::createRenderer(RenderStyle* style) void HTMLCanvasElement::didRecalcStyle(StyleRecalcChange) { SkPaint::FilterLevel filterLevel = computedStyle()->imageRendering() == ImageRenderingPixelated ? SkPaint::kNone_FilterLevel : SkPaint::kLow_FilterLevel; - if (m_context && m_context->is3d()) { + if (is3D()) { toWebGLRenderingContext(m_context.get())->setFilterLevel(filterLevel); setNeedsCompositingUpdate(); + } else if (hasImageBuffer()) { + m_imageBuffer->setFilterLevel(filterLevel); } } @@ -627,6 +629,10 @@ void HTMLCanvasElement::createImageBufferInternal() m_imageBuffer = ImageBuffer::create(surface.release()); m_imageBuffer->setClient(this); + document().updateRenderTreeIfNeeded(); + RenderStyle* style = computedStyle(); + m_imageBuffer->setFilterLevel((style && (style->imageRendering() == ImageRenderingPixelated)) ? SkPaint::kNone_FilterLevel : SkPaint::kLow_FilterLevel); + m_didFailToCreateImageBuffer = false; updateExternallyAllocatedMemory(); @@ -813,6 +819,8 @@ PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod return createTransparentImage(size()); } + m_imageBuffer->willAccessPixels(); + if (m_context->is3d()) { m_context->paintRenderingResultsToCanvas(BackBuffer); *status = ExternalSourceImageStatus; diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DImageBufferSurface.h b/third_party/WebKit/Source/platform/graphics/Canvas2DImageBufferSurface.h index fb9f71a..8578976 100644 --- a/third_party/WebKit/Source/platform/graphics/Canvas2DImageBufferSurface.h +++ b/third_party/WebKit/Source/platform/graphics/Canvas2DImageBufferSurface.h @@ -61,6 +61,7 @@ public: virtual WebLayer* layer() const override { return m_layerBridge->layer(); } virtual Platform3DObject getBackingTexture() const override { return m_layerBridge->getBackingTexture(); } virtual bool isAccelerated() const override { return m_layerBridge->isAccelerated(); } + virtual void setFilterLevel(SkPaint::FilterLevel filterLevel) override { m_layerBridge->setFilterLevel(filterLevel); }; virtual void setIsHidden(bool hidden) override { m_layerBridge->setIsHidden(hidden); } virtual void setImageBuffer(ImageBuffer* imageBuffer) override { m_layerBridge->setImageBuffer(imageBuffer); } diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp index 8e0eb84..c350a11 100644 --- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp +++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp @@ -91,10 +91,12 @@ Canvas2DLayerBridge::Canvas2DLayerBridge(PassOwnPtr<WebGraphicsContext3DProvider , m_framesPending(0) , m_destructionInProgress(false) , m_rateLimitingEnabled(false) + , m_filterLevel(SkPaint::kLow_FilterLevel) , m_isHidden(false) , m_next(0) , m_prev(0) , m_lastImageId(0) + , m_lastFilter(GL_LINEAR) , m_opacityMode(opacityMode) { ASSERT(m_canvas); @@ -107,6 +109,7 @@ Canvas2DLayerBridge::Canvas2DLayerBridge(PassOwnPtr<WebGraphicsContext3DProvider m_layer->setBlendBackgroundColor(opacityMode != Opaque); GraphicsLayer::registerContentsLayer(m_layer->layer()); m_layer->setRateLimitContext(m_rateLimitingEnabled); + m_layer->setNearestNeighbor(m_filterLevel == SkPaint::kNone_FilterLevel); m_canvas->setNotificationClient(this); #ifndef NDEBUG canvas2DLayerBridgeInstanceCounter.increment(); @@ -147,6 +150,13 @@ void Canvas2DLayerBridge::beginDestruction() ASSERT(!m_bytesAllocated); } +void Canvas2DLayerBridge::setFilterLevel(SkPaint::FilterLevel filterLevel) +{ + ASSERT(!m_destructionInProgress); + m_filterLevel = filterLevel; + m_layer->setNearestNeighbor(m_filterLevel == SkPaint::kNone_FilterLevel); +} + void Canvas2DLayerBridge::setIsHidden(bool hidden) { ASSERT(!m_destructionInProgress); @@ -361,9 +371,11 @@ bool Canvas2DLayerBridge::prepareMailbox(WebExternalTextureMailbox* outMailbox, RefPtr<SkImage> image = adoptRef(m_canvas->newImageSnapshot()); // Early exit if canvas was not drawn to since last prepareMailbox - if (image->uniqueID() == m_lastImageId) + GLenum filter = m_filterLevel == SkPaint::kNone_FilterLevel ? GL_NEAREST : GL_LINEAR; + if (image->uniqueID() == m_lastImageId && filter == m_lastFilter) return false; m_lastImageId = image->uniqueID(); + m_lastFilter = filter; { MailboxInfo tmp; @@ -373,6 +385,8 @@ bool Canvas2DLayerBridge::prepareMailbox(WebExternalTextureMailbox* outMailbox, } MailboxInfo& mailboxInfo = m_mailboxes.first(); + mailboxInfo.m_mailbox.nearestNeighbor = filter == GL_NEAREST; + GrContext* grContext = m_contextProvider->grContext(); if (!grContext) return true; // for testing: skip gl stuff when using a mock graphics context. @@ -385,8 +399,8 @@ bool Canvas2DLayerBridge::prepareMailbox(WebExternalTextureMailbox* outMailbox, mailboxInfo.m_image->getTexture()->textureParamsModified(); webContext->bindTexture(GL_TEXTURE_2D, mailboxInfo.m_image->getTexture()->getTextureHandle()); - webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h index 897d3aa..eabb7f1 100644 --- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h +++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h @@ -75,6 +75,7 @@ public: WebLayer* layer() const; Platform3DObject getBackingTexture(); bool isAccelerated() const { return true; } + void setFilterLevel(SkPaint::FilterLevel); void setIsHidden(bool); void setImageBuffer(ImageBuffer* imageBuffer) { m_imageBuffer = imageBuffer; } @@ -110,6 +111,7 @@ protected: int m_framesSinceMailboxRelease; bool m_destructionInProgress; bool m_rateLimitingEnabled; + SkPaint::FilterLevel m_filterLevel; bool m_isHidden; friend class WTF::DoublyLinkedListNode<Canvas2DLayerBridge>; @@ -135,6 +137,7 @@ protected: }; Deque<MailboxInfo, MaxActiveMailboxes> m_mailboxes; + GLenum m_lastFilter; OpacityMode m_opacityMode; }; diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h index 7ba7651..61d9056 100644 --- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h +++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h @@ -37,6 +37,7 @@ #include "platform/graphics/GraphicsTypes3D.h" #include "platform/graphics/ImageBufferSurface.h" #include "platform/transforms/AffineTransform.h" +#include "third_party/skia/include/core/SkPaint.h" #include "wtf/Forward.h" #include "wtf/OwnPtr.h" #include "wtf/PassOwnPtr.h" @@ -89,6 +90,7 @@ public: bool restoreSurface() const; bool needsClipTracking() const { return m_surface->needsClipTracking(); } + void setFilterLevel(SkPaint::FilterLevel filterLevel) { m_surface->setFilterLevel(filterLevel); } void setIsHidden(bool hidden) { m_surface->setIsHidden(hidden); } // Called by subclasses of ImageBufferSurface to install a new canvas object @@ -106,6 +108,8 @@ public: const SkBitmap& bitmap() const; + void willAccessPixels() { m_surface->willAccessPixels(); } + PassRefPtr<Image> copyImage(BackingStoreCopy = CopyBackingStore, ScaleBehavior = Scaled) const; // Give hints on the faster copyImage Mode, return DontCopyBackingStore if it supports the DontCopyBackingStore behavior // or return CopyBackingStore if it doesn't. diff --git a/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h b/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h index ad55079..f431cfd 100644 --- a/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h +++ b/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h @@ -35,6 +35,7 @@ #include "platform/geometry/IntSize.h" #include "platform/graphics/GraphicsTypes.h" #include "platform/graphics/GraphicsTypes3D.h" +#include "third_party/skia/include/core/SkPaint.h" #include "wtf/FastAllocBase.h" #include "wtf/Noncopyable.h" #include "wtf/PassRefPtr.h" @@ -75,6 +76,7 @@ public: virtual const SkBitmap& cachedBitmap() const; virtual void invalidateCachedBitmap() { } virtual void updateCachedBitmapIfNeeded() { } + virtual void setFilterLevel(SkPaint::FilterLevel) { } virtual void setIsHidden(bool) { } virtual void setImageBuffer(ImageBuffer*) { } virtual PassRefPtr<SkPicture> getPicture(); |