diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/third_party/WebKit/Source/platform/graphics | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/third_party/WebKit/Source/platform/graphics')
199 files changed, 9369 insertions, 11440 deletions
diff --git a/chromium/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp b/chromium/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp index 80dfafe42b5..a62674ff7b0 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp @@ -28,6 +28,7 @@ #include "platform/graphics/BitmapImage.h" #include "platform/Timer.h" +#include "platform/TraceEvent.h" #include "platform/geometry/FloatRect.h" #include "platform/graphics/GraphicsContextStateSaver.h" #include "platform/graphics/ImageObserver.h" @@ -235,13 +236,24 @@ bool BitmapImage::dataChanged(bool allDataReceived) // Feed all the data we've seen so far to the image decoder. m_allDataReceived = allDataReceived; - m_source.setData(data(), allDataReceived); + ASSERT(data()); + m_source.setData(*data(), allDataReceived); m_haveFrameCount = false; m_hasUniformFrameSize = true; return isSizeAvailable(); } +bool BitmapImage::isAllDataReceived() const +{ + return m_allDataReceived; +} + +bool BitmapImage::hasColorProfile() const +{ + return m_source.hasColorProfile(); +} + String BitmapImage::filenameExtension() const { return m_source.filenameExtension(); @@ -332,7 +344,7 @@ bool BitmapImage::ensureFrameIsCached(size_t index) PassRefPtr<NativeImageSkia> BitmapImage::frameAtIndex(size_t index) { if (!ensureFrameIsCached(index)) - return 0; + return nullptr; return m_frames[index].m_frame; } @@ -387,7 +399,7 @@ ImageOrientation BitmapImage::frameOrientationAtIndex(size_t index) return m_source.orientationAtIndex(index); } -#if !ASSERT_DISABLED +#if ASSERT_ENABLED bool BitmapImage::notSolidColor() { return size().width() != 1 || size().height() != 1 || frameCount() > 1; @@ -414,7 +426,7 @@ bool BitmapImage::shouldAnimate() return (repetitionCount(false) != cAnimationNone && !m_animationFinished && imageObserver()); } -void BitmapImage::startAnimation(bool catchUpIfNecessary) +void BitmapImage::startAnimation(CatchUpAnimation catchUpIfNecessary) { if (m_frameTimer || !shouldAnimate() || frameCount() <= 1) return; @@ -462,10 +474,10 @@ void BitmapImage::startAnimation(bool catchUpIfNecessary) if (nextFrame == 0 && m_repetitionsComplete == 0 && m_desiredFrameStartTime < time) m_desiredFrameStartTime = time; - if (!catchUpIfNecessary || time < m_desiredFrameStartTime) { + if (catchUpIfNecessary == DoNotCatchUp || time < m_desiredFrameStartTime) { // Haven't yet reached time for next frame to start; delay until then. m_frameTimer = new Timer<BitmapImage>(this, &BitmapImage::advanceAnimation); - m_frameTimer->startOneShot(std::max(m_desiredFrameStartTime - time, 0.)); + m_frameTimer->startOneShot(std::max(m_desiredFrameStartTime - time, 0.), FROM_HERE); } else { // We've already reached or passed the time for the next frame to start. // See if we've also passed the time for frames after that to start, in @@ -505,7 +517,7 @@ void BitmapImage::startAnimation(bool catchUpIfNecessary) // situation the best we can do is to simply change frames as fast // as possible, so force startAnimation() to set a zero-delay timer // and bail out if we're not caught up. - startAnimation(false); + startAnimation(DoNotCatchUp); } } } @@ -530,6 +542,15 @@ void BitmapImage::resetAnimation() destroyDecodedDataIfNecessary(); } +bool BitmapImage::maybeAnimated() +{ + if (m_animationFinished) + return false; + if (frameCount() > 1) + return true; + return m_source.repetitionCount() != cAnimationNone; +} + void BitmapImage::advanceAnimation(Timer<BitmapImage>*) { internalAdvanceAnimation(false); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/BitmapImage.h b/chromium/third_party/WebKit/Source/platform/graphics/BitmapImage.h index 59941a4abc6..9b2c9f851ea 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/BitmapImage.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/BitmapImage.h @@ -67,6 +67,8 @@ public: virtual bool getHotSpot(IntPoint&) const OVERRIDE; virtual bool dataChanged(bool allDataReceived) OVERRIDE; + bool isAllDataReceived() const; + bool hasColorProfile() const; virtual String filenameExtension() const OVERRIDE; // It may look unusual that there is no start animation call as public API. This is because @@ -74,13 +76,14 @@ public: // automatically pause once all observers no longer want to render the image anywhere. virtual void stopAnimation() OVERRIDE; virtual void resetAnimation() OVERRIDE; + virtual bool maybeAnimated() OVERRIDE; virtual PassRefPtr<NativeImageSkia> nativeImageForCurrentFrame() OVERRIDE; virtual bool currentFrameKnownToBeOpaque() OVERRIDE; ImageOrientation currentFrameOrientation(); -#if !ASSERT_DISABLED +#if ASSERT_ENABLED virtual bool notSolidColor() OVERRIDE; #endif @@ -138,7 +141,7 @@ protected: // Animation. int repetitionCount(bool imageKnownToBeComplete); // |imageKnownToBeComplete| should be set if the caller knows the entire image has been decoded. bool shouldAnimate(); - virtual void startAnimation(bool catchUpIfNecessary = true) OVERRIDE; + virtual void startAnimation(CatchUpAnimation = CatchUp) OVERRIDE; void advanceAnimation(Timer<BitmapImage>*); // Function that does the real work of advancing the animation. When @@ -153,8 +156,8 @@ protected: // changed. void checkForSolidColor(); - virtual bool mayFillWithSolidColor(); - virtual Color solidColor() const; + virtual bool mayFillWithSolidColor() OVERRIDE; + virtual Color solidColor() const OVERRIDE; ImageSource m_source; mutable IntSize m_size; // The size to use for the overall image (will just be the size of the first image). diff --git a/chromium/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp b/chromium/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp new file mode 100644 index 00000000000..1fa2ea249cd --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2013, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "platform/graphics/BitmapImage.h" + +#include "platform/SharedBuffer.h" +#include "platform/graphics/DeferredImageDecoder.h" +#include "platform/graphics/ImageObserver.h" +#include "public/platform/Platform.h" +#include "public/platform/WebUnitTestSupport.h" + +#include <gtest/gtest.h> + +namespace WebCore { + +class BitmapImageTest : public ::testing::Test { +public: + class FakeImageObserver : public ImageObserver { + public: + FakeImageObserver() : m_lastDecodedSizeChangedDelta(0) { } + + virtual void decodedSizeChanged(const Image*, int delta) + { + m_lastDecodedSizeChangedDelta = delta; + } + virtual void didDraw(const Image*) OVERRIDE { } + virtual bool shouldPauseAnimation(const Image*) OVERRIDE { return false; } + virtual void animationAdvanced(const Image*) OVERRIDE { } + virtual void changedInRect(const Image*, const IntRect&) { } + + int m_lastDecodedSizeChangedDelta; + }; + + static PassRefPtr<SharedBuffer> readFile(const char* fileName) + { + String filePath = blink::Platform::current()->unitTestSupport()->webKitRootDir(); + filePath.append(fileName); + return blink::Platform::current()->unitTestSupport()->readFromFile(filePath); + } + + // Accessors to BitmapImage's protected methods. + void destroyDecodedData(bool destroyAll) { m_image->destroyDecodedData(destroyAll); } + size_t frameCount() { return m_image->frameCount(); } + void setCurrentFrame(size_t frame) { m_image->m_currentFrame = frame; } + size_t frameDecodedSize(size_t frame) { return m_image->m_frames[frame].m_frameBytes; } + size_t decodedFramesCount() const { return m_image->m_frames.size(); } + + void loadImage(const char* fileName) + { + RefPtr<SharedBuffer> imageData = readFile(fileName); + ASSERT_TRUE(imageData.get()); + + m_image->setData(imageData, true); + EXPECT_EQ(0u, decodedSize()); + + size_t frameCount = m_image->frameCount(); + for (size_t i = 0; i < frameCount; ++i) + m_image->frameAtIndex(i); + } + + size_t decodedSize() + { + // In the context of this test, the following loop will give the correct result, but only because the test + // forces all frames to be decoded in loadImage() above. There is no general guarantee that frameDecodedSize() + // is up-to-date. Because of how multi frame images (like GIF) work, requesting one frame to be decoded may + // require other previous frames to be decoded as well. In those cases frameDecodedSize() wouldn't return the + // correct thing for the previous frame because the decoded size wouldn't have propagated upwards to the + // BitmapImage frame cache. + size_t size = 0; + for (size_t i = 0; i < decodedFramesCount(); ++i) + size += frameDecodedSize(i); + return size; + } + + void advanceAnimation() + { + m_image->advanceAnimation(0); + } + +protected: + virtual void SetUp() OVERRIDE + { + DeferredImageDecoder::setEnabled(false); + m_image = BitmapImage::create(&m_imageObserver); + } + + FakeImageObserver m_imageObserver; + RefPtr<BitmapImage> m_image; +}; + +// Fails on the WebKit XP (deps) bot, see http://crbug.com/327104 +#if OS(WIN) +TEST_F(BitmapImageTest, DISABLED_destroyDecodedDataExceptCurrentFrame) +#else +TEST_F(BitmapImageTest, destroyDecodedDataExceptCurrentFrame) +#endif +{ + loadImage("/LayoutTests/fast/images/resources/animated-10color.gif"); + size_t totalSize = decodedSize(); + size_t frame = frameCount() / 2; + setCurrentFrame(frame); + size_t size = frameDecodedSize(frame); + destroyDecodedData(false); + EXPECT_LT(m_imageObserver.m_lastDecodedSizeChangedDelta, 0); + EXPECT_GE(m_imageObserver.m_lastDecodedSizeChangedDelta, -static_cast<int>(totalSize - size)); +} + +// Fails on the WebKit XP (deps) bot, see http://crbug.com/327104 +#if OS(WIN) +TEST_F(BitmapImageTest, DISABLED_destroyAllDecodedData) +#else +TEST_F(BitmapImageTest, destroyAllDecodedData) +#endif +{ + loadImage("/LayoutTests/fast/images/resources/animated-10color.gif"); + size_t totalSize = decodedSize(); + EXPECT_GT(totalSize, 0u); + destroyDecodedData(true); + EXPECT_EQ(-static_cast<int>(totalSize), m_imageObserver.m_lastDecodedSizeChangedDelta); + EXPECT_EQ(0u, decodedSize()); +} + +TEST_F(BitmapImageTest, maybeAnimated) +{ + loadImage("/LayoutTests/fast/images/resources/gif-loop-count.gif"); + for (size_t i = 0; i < frameCount(); ++i) { + EXPECT_TRUE(m_image->maybeAnimated()); + advanceAnimation(); + } + EXPECT_FALSE(m_image->maybeAnimated()); +} + +TEST_F(BitmapImageTest, isAllDataReceived) +{ + RefPtr<SharedBuffer> imageData = readFile("/LayoutTests/fast/images/resources/green.jpg"); + ASSERT_TRUE(imageData.get()); + + RefPtr<BitmapImage> image = BitmapImage::create(); + EXPECT_FALSE(image->isAllDataReceived()); + + image->setData(imageData, false); + EXPECT_FALSE(image->isAllDataReceived()); + + image->setData(imageData, true); + EXPECT_TRUE(image->isAllDataReceived()); + + image->setData(SharedBuffer::create("data", sizeof("data")), false); + EXPECT_FALSE(image->isAllDataReceived()); + + image->setData(imageData, true); + EXPECT_TRUE(image->isAllDataReceived()); +} + +#if USE(QCMSLIB) + +TEST_F(BitmapImageTest, jpegHasColorProfile) +{ + loadImage("/LayoutTests/fast/images/resources/icc-v2-gbr.jpg"); + EXPECT_EQ(1u, decodedFramesCount()); + EXPECT_TRUE(m_image->hasColorProfile()); +} + +TEST_F(BitmapImageTest, pngHasColorProfile) +{ + loadImage("/LayoutTests/fast/images/resources/palatted-color-png-gamma-one-color-profile.png"); + EXPECT_EQ(1u, decodedFramesCount()); + EXPECT_TRUE(m_image->hasColorProfile()); +} + +TEST_F(BitmapImageTest, webpHasColorProfile) +{ + loadImage("/LayoutTests/fast/images/resources/webp-color-profile-lossy.webp"); + EXPECT_EQ(1u, decodedFramesCount()); + EXPECT_TRUE(m_image->hasColorProfile()); +} + +#endif // USE(QCMSLIB) + +} // namespace diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DImageBufferSurface.h b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DImageBufferSurface.h index e14bb5d9424..b56f1ec89b9 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DImageBufferSurface.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DImageBufferSurface.h @@ -37,7 +37,7 @@ namespace WebCore { // This shim necessary because ImageBufferSurfaces are not allowed to be RefCounted -class Canvas2DImageBufferSurface : public ImageBufferSurface { +class Canvas2DImageBufferSurface FINAL : public ImageBufferSurface { public: Canvas2DImageBufferSurface(const IntSize& size, OpacityMode opacityMode = NonOpaque, int msaaSampleCount = 1) : ImageBufferSurface(size, opacityMode) @@ -55,10 +55,13 @@ public: // ImageBufferSurface implementation virtual void willUse() OVERRIDE { m_layerBridge->willUse(); } virtual SkCanvas* canvas() const OVERRIDE { return m_layerBridge->canvas(); } - virtual bool isValid() const OVERRIDE { return m_layerBridge && m_layerBridge->isValid(); } + virtual bool isValid() const OVERRIDE { return m_layerBridge && m_layerBridge->checkSurfaceValid(); } + virtual bool restore() OVERRIDE { return m_layerBridge->restoreSurface(); } virtual blink::WebLayer* layer() const OVERRIDE { return m_layerBridge->layer(); } virtual Platform3DObject getBackingTexture() const OVERRIDE { return m_layerBridge->getBackingTexture(); } - virtual bool isAccelerated() const { return m_layerBridge->isAccelerated(); } + virtual bool isAccelerated() const OVERRIDE { return m_layerBridge->isAccelerated(); } + virtual void setIsHidden(bool hidden) OVERRIDE { m_layerBridge->setIsHidden(hidden); } + virtual void setImageBuffer(ImageBuffer* imageBuffer) OVERRIDE { m_layerBridge->setImageBuffer(imageBuffer); } private: RefPtr<Canvas2DLayerBridge> m_layerBridge; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp index 492dc2b439a..d31443542cd 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp @@ -33,22 +33,29 @@ #include "platform/TraceEvent.h" #include "platform/graphics/Canvas2DLayerManager.h" #include "platform/graphics/GraphicsLayer.h" -#include "platform/graphics/gpu/SharedGraphicsContext3D.h" #include "public/platform/Platform.h" #include "public/platform/WebCompositorSupport.h" #include "public/platform/WebGraphicsContext3D.h" +#include "public/platform/WebGraphicsContext3DProvider.h" +#include "wtf/RefCountedLeakCounter.h" using blink::WebExternalTextureLayer; using blink::WebGraphicsContext3D; +namespace { +enum { + InvalidMailboxIndex = -1, +}; + +DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, canvas2DLayerBridgeInstanceCounter, ("Canvas2DLayerBridge")); +} + namespace WebCore { -static PassRefPtr<SkSurface> createSkSurface(GraphicsContext3D* context3D, const IntSize& size, int msaaSampleCount) +static PassRefPtr<SkSurface> createSkSurface(GrContext* gr, const IntSize& size, int msaaSampleCount = 0) { - ASSERT(!context3D->webContext()->isContextLost()); - GrContext* gr = context3D->grContext(); if (!gr) - return 0; + return nullptr; gr->resetContext(); SkImageInfo info; info.fWidth = size.width(); @@ -61,31 +68,38 @@ static PassRefPtr<SkSurface> createSkSurface(GraphicsContext3D* context3D, const PassRefPtr<Canvas2DLayerBridge> Canvas2DLayerBridge::create(const IntSize& size, OpacityMode opacityMode, int msaaSampleCount) { TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation"); - RefPtr<GraphicsContext3D> context = SharedGraphicsContext3D::get(); - RefPtr<SkSurface> surface(createSkSurface(context.get(), size, msaaSampleCount)); + OwnPtr<blink::WebGraphicsContext3DProvider> contextProvider = adoptPtr(blink::Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); + if (!contextProvider) + return nullptr; + RefPtr<SkSurface> surface(createSkSurface(contextProvider->grContext(), size, msaaSampleCount)); if (!surface) - return 0; + return nullptr; RefPtr<Canvas2DLayerBridge> layerBridge; OwnPtr<SkDeferredCanvas> canvas = adoptPtr(SkDeferredCanvas::Create(surface.get())); - layerBridge = adoptRef(new Canvas2DLayerBridge(context, canvas.release(), msaaSampleCount, opacityMode)); + layerBridge = adoptRef(new Canvas2DLayerBridge(contextProvider.release(), canvas.release(), msaaSampleCount, opacityMode)); return layerBridge.release(); } -Canvas2DLayerBridge::Canvas2DLayerBridge(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<SkDeferredCanvas> canvas, int msaaSampleCount, OpacityMode opacityMode) +Canvas2DLayerBridge::Canvas2DLayerBridge(PassOwnPtr<blink::WebGraphicsContext3DProvider> contextProvider, PassOwnPtr<SkDeferredCanvas> canvas, int msaaSampleCount, OpacityMode opacityMode) : m_canvas(canvas) - , m_context(context) + , m_contextProvider(contextProvider) + , m_imageBuffer(0) , m_msaaSampleCount(msaaSampleCount) , m_bytesAllocated(0) , m_didRecordDrawCommand(false) - , m_surfaceIsValid(true) + , m_isSurfaceValid(true) , m_framesPending(0) + , m_framesSinceMailboxRelease(0) , m_destructionInProgress(false) , m_rateLimitingEnabled(false) + , m_isHidden(false) , m_next(0) , m_prev(0) , m_lastImageId(0) + , m_releasedMailboxInfoIndex(InvalidMailboxIndex) { ASSERT(m_canvas); + ASSERT(m_contextProvider); // Used by browser tests to detect the use of a Canvas2DLayerBridge. TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation"); m_layer = adoptPtr(blink::Platform::current()->compositorSupport()->createExternalTextureLayer(this)); @@ -94,44 +108,86 @@ Canvas2DLayerBridge::Canvas2DLayerBridge(PassRefPtr<GraphicsContext3D> context, GraphicsLayer::registerContentsLayer(m_layer->layer()); m_layer->setRateLimitContext(m_rateLimitingEnabled); m_canvas->setNotificationClient(this); +#ifndef NDEBUG + canvas2DLayerBridgeInstanceCounter.increment(); +#endif } Canvas2DLayerBridge::~Canvas2DLayerBridge() { ASSERT(m_destructionInProgress); + ASSERT(!Canvas2DLayerManager::get().isInList(this)); m_layer.clear(); + freeReleasedMailbox(); +#if ASSERT_ENABLED Vector<MailboxInfo>::iterator mailboxInfo; - for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) { + for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); ++mailboxInfo) { ASSERT(mailboxInfo->m_status != MailboxInUse); - if (mailboxInfo->m_status == MailboxReleased) { - if (mailboxInfo->m_mailbox.syncPoint) { - context()->waitSyncPoint(mailboxInfo->m_mailbox.syncPoint); - mailboxInfo->m_mailbox.syncPoint = 0; - } - // Invalidate texture state in case the compositor altered it since the copy-on-write. - mailboxInfo->m_image->getTexture()->invalidateCachedState(); - } + ASSERT(mailboxInfo->m_status != MailboxReleased || m_contextProvider->context3d()->isContextLost() || !m_isSurfaceValid); } +#endif m_mailboxes.clear(); +#ifndef NDEBUG + canvas2DLayerBridgeInstanceCounter.decrement(); +#endif } void Canvas2DLayerBridge::beginDestruction() { ASSERT(!m_destructionInProgress); + setRateLimitingEnabled(false); + m_canvas->silentFlush(); + m_imageBuffer = 0; + freeTransientResources(); + setIsHidden(true); m_destructionInProgress = true; GraphicsLayer::unregisterContentsLayer(m_layer->layer()); m_canvas->setNotificationClient(0); + m_canvas.clear(); m_layer->clearTexture(); - Canvas2DLayerManager::get().layerToBeDestroyed(this); // Orphaning the layer is required to trigger the recration of a new layer // in the case where destruction is caused by a canvas resize. Test: // virtual/gpu/fast/canvas/canvas-resize-after-paint-without-layout.html m_layer->layer()->removeFromParent(); + // To anyone who ever hits this assert: Please update crbug.com/344666 + // with repro steps. + ASSERT(!m_bytesAllocated); +} + +void Canvas2DLayerBridge::setIsHidden(bool hidden) +{ + ASSERT(!m_destructionInProgress); + bool newHiddenValue = hidden || m_destructionInProgress; + if (m_isHidden == newHiddenValue) + return; + + m_isHidden = newHiddenValue; + if (isHidden()) { + freeTransientResources(); + } +} + +void Canvas2DLayerBridge::freeTransientResources() +{ + ASSERT(!m_destructionInProgress); + freeReleasedMailbox(); + flush(); + freeMemoryIfPossible(bytesAllocated()); + ASSERT(!hasTransientResources()); +} + +bool Canvas2DLayerBridge::hasTransientResources() const +{ + return !m_destructionInProgress && (hasReleasedMailbox() || bytesAllocated()); } void Canvas2DLayerBridge::limitPendingFrames() { ASSERT(!m_destructionInProgress); + if (isHidden()) { + freeTransientResources(); + return; + } if (m_didRecordDrawCommand) { m_framesPending++; m_didRecordDrawCommand = false; @@ -144,20 +200,24 @@ void Canvas2DLayerBridge::limitPendingFrames() flush(); } } + ++m_framesSinceMailboxRelease; + if (releasedMailboxHasExpired()) { + freeReleasedMailbox(); + } } void Canvas2DLayerBridge::prepareForDraw() { ASSERT(!m_destructionInProgress); ASSERT(m_layer); - if (!isValid()) { + if (!checkSurfaceValid()) { if (m_canvas) { // drop pending commands because there is no surface to draw to m_canvas->silentFlush(); } return; } - m_context->makeContextCurrent(); + context()->makeContextCurrent(); } void Canvas2DLayerBridge::storageAllocatedForRecordingChanged(size_t bytesAllocated) @@ -165,12 +225,11 @@ void Canvas2DLayerBridge::storageAllocatedForRecordingChanged(size_t bytesAlloca ASSERT(!m_destructionInProgress); intptr_t delta = (intptr_t)bytesAllocated - (intptr_t)m_bytesAllocated; m_bytesAllocated = bytesAllocated; - Canvas2DLayerManager::get().layerAllocatedStorageChanged(this, delta); + Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this, delta); } size_t Canvas2DLayerBridge::storageAllocatedForRecording() { - ASSERT(!m_destructionInProgress); return m_canvas->storageAllocatedForRecording(); } @@ -192,7 +251,7 @@ void Canvas2DLayerBridge::skippedPendingDrawCommands() void Canvas2DLayerBridge::setRateLimitingEnabled(bool enabled) { - ASSERT(!m_destructionInProgress || !enabled); + ASSERT(!m_destructionInProgress); if (m_rateLimitingEnabled != enabled) { m_rateLimitingEnabled = enabled; m_layer->setRateLimitContext(m_rateLimitingEnabled); @@ -203,9 +262,9 @@ size_t Canvas2DLayerBridge::freeMemoryIfPossible(size_t bytesToFree) { ASSERT(!m_destructionInProgress); size_t bytesFreed = m_canvas->freeMemoryIfPossible(bytesToFree); - if (bytesFreed) - Canvas2DLayerManager::get().layerAllocatedStorageChanged(this, -((intptr_t)bytesFreed)); m_bytesAllocated -= bytesFreed; + if (bytesFreed) + Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this, -((intptr_t)bytesFreed)); return bytesFreed; } @@ -214,112 +273,175 @@ void Canvas2DLayerBridge::flush() ASSERT(!m_destructionInProgress); if (m_canvas->hasPendingCommands()) { TRACE_EVENT0("cc", "Canvas2DLayerBridge::flush"); + freeReleasedMailbox(); // To avoid unnecessary triple-buffering m_canvas->flush(); } } +bool Canvas2DLayerBridge::releasedMailboxHasExpired() +{ + // This heuristic indicates that the canvas is not being + // actively presented by the compositor (3 frames rendered since + // last mailbox release), suggesting that double buffering is not required. + return hasReleasedMailbox() && m_framesSinceMailboxRelease > 2; +} + +Canvas2DLayerBridge::MailboxInfo* Canvas2DLayerBridge::releasedMailboxInfo() +{ + return hasReleasedMailbox() ? &m_mailboxes[m_releasedMailboxInfoIndex] : 0; +} + +bool Canvas2DLayerBridge::hasReleasedMailbox() const +{ + return m_releasedMailboxInfoIndex != InvalidMailboxIndex; +} + +void Canvas2DLayerBridge::freeReleasedMailbox() +{ + if (m_contextProvider->context3d()->isContextLost() || !m_isSurfaceValid) + return; + MailboxInfo* mailboxInfo = releasedMailboxInfo(); + if (!mailboxInfo) + return; + + ASSERT(mailboxInfo->m_status == MailboxReleased); + if (mailboxInfo->m_mailbox.syncPoint) { + context()->waitSyncPoint(mailboxInfo->m_mailbox.syncPoint); + mailboxInfo->m_mailbox.syncPoint = 0; + } + // Invalidate texture state in case the compositor altered it since the copy-on-write. + if (mailboxInfo->m_image) { + if (isHidden() || releasedMailboxHasExpired()) + mailboxInfo->m_image->getTexture()->resetFlag(static_cast<GrTextureFlags>(GrTexture::kReturnToCache_FlagBit)); + mailboxInfo->m_image->getTexture()->textureParamsModified(); + mailboxInfo->m_image.clear(); + } + mailboxInfo->m_status = MailboxAvailable; + m_releasedMailboxInfoIndex = InvalidMailboxIndex; + Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this); +} + blink::WebGraphicsContext3D* Canvas2DLayerBridge::context() { // Check on m_layer is necessary because context() may be called during // the destruction of m_layer - if (m_layer) { - isValid(); // To ensure rate limiter is disabled if context is lost. + if (m_layer && !m_destructionInProgress) + checkSurfaceValid(); // To ensure rate limiter is disabled if context is lost. + return m_contextProvider->context3d(); +} + +bool Canvas2DLayerBridge::checkSurfaceValid() +{ + ASSERT(!m_destructionInProgress); + if (m_destructionInProgress || !m_isSurfaceValid) + return false; + if (m_contextProvider->context3d()->isContextLost()) { + m_isSurfaceValid = false; + if (m_imageBuffer) + m_imageBuffer->notifySurfaceInvalid(); + setRateLimitingEnabled(false); } - return m_context->webContext(); + return m_isSurfaceValid; } -bool Canvas2DLayerBridge::isValid() +bool Canvas2DLayerBridge::restoreSurface() { - ASSERT(m_layer); + ASSERT(!m_destructionInProgress); if (m_destructionInProgress) return false; - if (m_context->webContext()->isContextLost() || !m_surfaceIsValid) { - // Attempt to recover. - m_layer->clearTexture(); - m_mailboxes.clear(); - RefPtr<GraphicsContext3D> sharedContext = SharedGraphicsContext3D::get(); - if (!sharedContext || sharedContext->webContext()->isContextLost()) { - m_surfaceIsValid = false; - } else { - m_context = sharedContext; - IntSize size(m_canvas->getTopDevice()->width(), m_canvas->getTopDevice()->height()); - RefPtr<SkSurface> surface(createSkSurface(m_context.get(), size, m_msaaSampleCount)); - if (surface.get()) { - m_canvas->setSurface(surface.get()); - m_surfaceIsValid = true; - // FIXME: draw sad canvas picture into new buffer crbug.com/243842 - } else { - // Surface allocation failed. Set m_surfaceIsValid to false to - // trigger subsequent retry. - m_surfaceIsValid = false; - } + ASSERT(m_layer && !m_isSurfaceValid); + + blink::WebGraphicsContext3D* sharedContext = 0; + // We must clear the mailboxes before calling m_layer->clearTexture() to prevent + // re-entry via mailboxReleased from operating on defunct GrContext objects. + m_mailboxes.clear(); + m_releasedMailboxInfoIndex = InvalidMailboxIndex; + m_layer->clearTexture(); + m_contextProvider = adoptPtr(blink::Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); + if (m_contextProvider) + sharedContext = m_contextProvider->context3d(); + + if (sharedContext && !sharedContext->isContextLost()) { + IntSize size(m_canvas->getTopDevice()->width(), m_canvas->getTopDevice()->height()); + RefPtr<SkSurface> surface(createSkSurface(m_contextProvider->grContext(), size, m_msaaSampleCount)); + if (surface.get()) { + m_canvas->setSurface(surface.get()); + m_isSurfaceValid = true; + // FIXME: draw sad canvas picture into new buffer crbug.com/243842 } } - if (!m_surfaceIsValid) - setRateLimitingEnabled(false); - return m_surfaceIsValid; + + return m_isSurfaceValid; } bool Canvas2DLayerBridge::prepareMailbox(blink::WebExternalTextureMailbox* outMailbox, blink::WebExternalBitmap* bitmap) { + if (m_destructionInProgress) { + // It can be hit in the following sequence. + // 1. Canvas draws something. + // 2. The compositor begins the frame. + // 3. Javascript makes a context be lost. + // 4. Here. + return false; + } if (bitmap) { // Using accelerated 2d canvas with software renderer, which - // should only happen in tests that use fake graphics contexts. - // In this case, we do not care about producing any results for - // compositing. + // should only happen in tests that use fake graphics contexts + // or in Android WebView in software mode. In this case, we do + // not care about producing any results for this canvas. m_canvas->silentFlush(); + m_lastImageId = 0; return false; } - if (!isValid()) + if (!checkSurfaceValid()) return false; + + blink::WebGraphicsContext3D* webContext = context(); + // Release to skia textures that were previouosly released by the // compositor. We do this before acquiring the next snapshot in // order to cap maximum gpu memory consumption. - m_context->makeContextCurrent(); + webContext->makeContextCurrent(); flush(); - Vector<MailboxInfo>::iterator mailboxInfo; - for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) { - if (mailboxInfo->m_status == MailboxReleased) { - if (mailboxInfo->m_mailbox.syncPoint) { - context()->waitSyncPoint(mailboxInfo->m_mailbox.syncPoint); - mailboxInfo->m_mailbox.syncPoint = 0; - } - // Invalidate texture state in case the compositor altered it since the copy-on-write. - mailboxInfo->m_image->getTexture()->invalidateCachedState(); - mailboxInfo->m_image.reset(0); - mailboxInfo->m_status = MailboxAvailable; - } - } - SkAutoTUnref<SkImage> image(m_canvas->newImageSnapshot()); + + RefPtr<SkImage> image = adoptRef(m_canvas->newImageSnapshot()); + // Early exit if canvas was not drawn to since last prepareMailbox if (image->uniqueID() == m_lastImageId) return false; m_lastImageId = image->uniqueID(); - mailboxInfo = createMailboxInfo(); + MailboxInfo* mailboxInfo = createMailboxInfo(); mailboxInfo->m_status = MailboxInUse; - mailboxInfo->m_image.swap(&image); - // Because of texture sharing with the compositor, we must invalidate - // the state cached in skia so that the deferred copy on write - // in SkSurface_Gpu does not make any false assumptions. - mailboxInfo->m_image->getTexture()->invalidateCachedState(); + mailboxInfo->m_image = image; ASSERT(mailboxInfo->m_mailbox.syncPoint == 0); ASSERT(mailboxInfo->m_image.get()); ASSERT(mailboxInfo->m_image->getTexture()); - m_context->bindTexture(GL_TEXTURE_2D, mailboxInfo->m_image->getTexture()->getTextureHandle()); - m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailboxInfo->m_mailbox.name); - context()->flush(); - mailboxInfo->m_mailbox.syncPoint = context()->insertSyncPoint(); - m_context->bindTexture(GL_TEXTURE_2D, 0); + // Because of texture sharing with the compositor, we must invalidate + // the state cached in skia so that the deferred copy on write + // in SkSurface_Gpu does not make any false assumptions. + 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_WRAP_S, GL_CLAMP_TO_EDGE); + webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + webContext->produceTextureCHROMIUM(GL_TEXTURE_2D, mailboxInfo->m_mailbox.name); + if (isHidden()) { + // With hidden canvases, we release the SkImage immediately because + // there is no need for animations to be double buffered. + mailboxInfo->m_image.clear(); + } else { + webContext->flush(); + mailboxInfo->m_mailbox.syncPoint = webContext->insertSyncPoint(); + } + webContext->bindTexture(GL_TEXTURE_2D, 0); // Because we are changing the texture binding without going through skia, // we must dirty the context. - m_context->grContext()->resetContext(kTextureBinding_GrGLBackendState); + m_contextProvider->grContext()->resetContext(kTextureBinding_GrGLBackendState); // set m_parentLayerBridge to make sure 'this' stays alive as long as it has // live mailboxes @@ -355,15 +477,24 @@ Canvas2DLayerBridge::MailboxInfo* Canvas2DLayerBridge::createMailboxInfo() { void Canvas2DLayerBridge::mailboxReleased(const blink::WebExternalTextureMailbox& mailbox) { + freeReleasedMailbox(); // Never have more than one mailbox in the released state. Vector<MailboxInfo>::iterator mailboxInfo; - for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) { - if (!memcmp(mailboxInfo->m_mailbox.name, mailbox.name, sizeof(mailbox.name))) { + for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); ++mailboxInfo) { + if (nameEquals(mailboxInfo->m_mailbox, mailbox)) { mailboxInfo->m_mailbox.syncPoint = mailbox.syncPoint; ASSERT(mailboxInfo->m_status == MailboxInUse); mailboxInfo->m_status = MailboxReleased; // Trigger Canvas2DLayerBridge self-destruction if this is the // last live mailbox and the layer bridge is not externally // referenced. + m_releasedMailboxInfoIndex = mailboxInfo - m_mailboxes.begin(); + m_framesSinceMailboxRelease = 0; + if (isHidden()) { + freeReleasedMailbox(); + } else { + ASSERT(!m_destructionInProgress); + Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this); + } ASSERT(mailboxInfo->m_parentLayerBridge.get() == this); mailboxInfo->m_parentLayerBridge.clear(); return; @@ -373,6 +504,7 @@ void Canvas2DLayerBridge::mailboxReleased(const blink::WebExternalTextureMailbox blink::WebLayer* Canvas2DLayerBridge::layer() const { + ASSERT(!m_destructionInProgress); ASSERT(m_layer); return m_layer->layer(); } @@ -387,11 +519,11 @@ void Canvas2DLayerBridge::willUse() Platform3DObject Canvas2DLayerBridge::getBackingTexture() { ASSERT(!m_destructionInProgress); - if (!isValid()) + if (!checkSurfaceValid()) return 0; willUse(); m_canvas->flush(); - m_context->flush(); + context()->flush(); GrRenderTarget* renderTarget = m_canvas->getTopDevice()->accessRenderTarget(); if (renderTarget) { return renderTarget->asTexture()->getTextureHandle(); @@ -401,10 +533,10 @@ Platform3DObject Canvas2DLayerBridge::getBackingTexture() Canvas2DLayerBridge::MailboxInfo::MailboxInfo(const MailboxInfo& other) { // This copy constructor should only be used for Vector reallocation - // Assuming 'other' is to be destroyed, we swap m_image ownership + // Assuming 'other' is to be destroyed, we transfer m_image ownership // rather than do a refcount dance. memcpy(&m_mailbox, &other.m_mailbox, sizeof(m_mailbox)); - m_image.swap(const_cast<SkAutoTUnref<SkImage>*>(&other.m_image)); + m_image = const_cast<MailboxInfo*>(&other)->m_image.release(); m_status = other.m_status; } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h index d259c5fcd9d..f2fd4aaaf6f 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h @@ -30,11 +30,11 @@ #include "SkImage.h" #include "platform/PlatformExport.h" #include "platform/geometry/IntSize.h" -#include "platform/graphics/GraphicsContext3D.h" #include "platform/graphics/ImageBufferSurface.h" #include "public/platform/WebExternalTextureLayer.h" #include "public/platform/WebExternalTextureLayerClient.h" #include "public/platform/WebExternalTextureMailbox.h" +#include "third_party/khronos/GLES2/gl2.h" #include "wtf/DoublyLinkedList.h" #include "wtf/PassOwnPtr.h" #include "wtf/RefCounted.h" @@ -42,20 +42,23 @@ namespace blink { class WebGraphicsContext3D; +class WebGraphicsContext3DProvider; } class Canvas2DLayerBridgeTest; namespace WebCore { +class ImageBuffer; + class PLATFORM_EXPORT Canvas2DLayerBridge : public blink::WebExternalTextureLayerClient, public SkDeferredCanvas::NotificationClient, public DoublyLinkedListNode<Canvas2DLayerBridge>, public RefCounted<Canvas2DLayerBridge> { WTF_MAKE_NONCOPYABLE(Canvas2DLayerBridge); public: static PassRefPtr<Canvas2DLayerBridge> create(const IntSize&, OpacityMode, int msaaSampleCount); + virtual ~Canvas2DLayerBridge(); // blink::WebExternalTextureLayerClient implementation. - virtual blink::WebGraphicsContext3D* context() OVERRIDE; virtual bool prepareMailbox(blink::WebExternalTextureMailbox*, blink::WebExternalBitmap*) OVERRIDE; virtual void mailboxReleased(const blink::WebExternalTextureMailbox&) OVERRIDE; @@ -68,34 +71,47 @@ public: // ImageBufferSurface implementation void willUse(); SkCanvas* canvas() const { return m_canvas.get(); } - bool isValid(); + bool checkSurfaceValid(); + bool restoreSurface(); blink::WebLayer* layer() const; Platform3DObject getBackingTexture(); bool isAccelerated() const { return true; } + void setIsHidden(bool); + void setImageBuffer(ImageBuffer* imageBuffer) { m_imageBuffer = imageBuffer; } // Methods used by Canvas2DLayerManager virtual size_t freeMemoryIfPossible(size_t); // virtual for mocking virtual void flush(); // virtual for mocking virtual size_t storageAllocatedForRecording(); // virtual for faking - size_t bytesAllocated() const {return m_bytesAllocated;} + size_t bytesAllocated() const { return m_bytesAllocated; } void limitPendingFrames(); + void freeReleasedMailbox(); + bool hasReleasedMailbox() const; + void freeTransientResources(); + bool hasTransientResources() const; + bool isHidden() { return m_isHidden; } void beginDestruction(); protected: - Canvas2DLayerBridge(PassRefPtr<GraphicsContext3D>, PassOwnPtr<SkDeferredCanvas>, int, OpacityMode); + Canvas2DLayerBridge(PassOwnPtr<blink::WebGraphicsContext3DProvider>, PassOwnPtr<SkDeferredCanvas>, int, OpacityMode); void setRateLimitingEnabled(bool); + bool releasedMailboxHasExpired(); + blink::WebGraphicsContext3D* context(); OwnPtr<SkDeferredCanvas> m_canvas; OwnPtr<blink::WebExternalTextureLayer> m_layer; - RefPtr<GraphicsContext3D> m_context; + OwnPtr<blink::WebGraphicsContext3DProvider> m_contextProvider; + ImageBuffer* m_imageBuffer; int m_msaaSampleCount; size_t m_bytesAllocated; bool m_didRecordDrawCommand; - bool m_surfaceIsValid; + bool m_isSurfaceValid; int m_framesPending; + int m_framesSinceMailboxRelease; bool m_destructionInProgress; bool m_rateLimitingEnabled; + bool m_isHidden; friend class WTF::DoublyLinkedListNode<Canvas2DLayerBridge>; friend class ::Canvas2DLayerBridgeTest; @@ -110,7 +126,7 @@ protected: struct MailboxInfo { blink::WebExternalTextureMailbox m_mailbox; - SkAutoTUnref<SkImage> m_image; + RefPtr<SkImage> m_image; MailboxStatus m_status; RefPtr<Canvas2DLayerBridge> m_parentLayerBridge; @@ -118,9 +134,11 @@ protected: MailboxInfo() {} }; MailboxInfo* createMailboxInfo(); + MailboxInfo* releasedMailboxInfo(); uint32_t m_lastImageId; Vector<MailboxInfo> m_mailboxes; + int m_releasedMailboxInfoIndex; }; } #endif diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp new file mode 100644 index 00000000000..29d4aa17b63 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "platform/graphics/Canvas2DLayerBridge.h" + +#include "SkDeferredCanvas.h" +#include "SkSurface.h" +#include "platform/graphics/ImageBuffer.h" +#include "platform/graphics/test/MockWebGraphicsContext3D.h" +#include "public/platform/Platform.h" +#include "public/platform/WebExternalBitmap.h" +#include "public/platform/WebGraphicsContext3DProvider.h" +#include "public/platform/WebThread.h" +#include "third_party/skia/include/core/SkDevice.h" +#include "wtf/RefPtr.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +using namespace WebCore; +using namespace blink; +using testing::InSequence; +using testing::Return; +using testing::Test; + +namespace { + +class MockCanvasContext : public MockWebGraphicsContext3D { +public: + MOCK_METHOD0(flush, void(void)); + MOCK_METHOD0(createTexture, unsigned(void)); + MOCK_METHOD1(deleteTexture, void(unsigned)); +}; + +class MockWebGraphicsContext3DProvider : public WebGraphicsContext3DProvider { +public: + MockWebGraphicsContext3DProvider(WebGraphicsContext3D* context3d) + : m_context3d(context3d) { } + + WebGraphicsContext3D* context3d() + { + return m_context3d; + } + + GrContext* grContext() + { + return 0; + } + +private: + WebGraphicsContext3D* m_context3d; +}; + +class Canvas2DLayerBridgePtr { +public: + Canvas2DLayerBridgePtr(PassRefPtr<Canvas2DLayerBridge> layerBridge) + : m_layerBridge(layerBridge) { } + + ~Canvas2DLayerBridgePtr() + { + m_layerBridge->beginDestruction(); + } + + Canvas2DLayerBridge* operator->() { return m_layerBridge.get(); } + Canvas2DLayerBridge* get() { return m_layerBridge.get(); } + +private: + RefPtr<Canvas2DLayerBridge> m_layerBridge; +}; + +class NullWebExternalBitmap : public WebExternalBitmap { +public: + virtual WebSize size() + { + return WebSize(); + } + + virtual void setSize(WebSize) + { + } + + virtual uint8* pixels() + { + return 0; + } +}; + +} // namespace + +class Canvas2DLayerBridgeTest : public Test { +protected: + void fullLifecycleTest() + { + MockCanvasContext mainMock; + OwnPtr<MockWebGraphicsContext3DProvider> mainMockProvider = adoptPtr(new MockWebGraphicsContext3DProvider(&mainMock)); + RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterPMColor(300, 150)); + OwnPtr<SkDeferredCanvas> canvas = adoptPtr(SkDeferredCanvas::Create(surface.get())); + + ::testing::Mock::VerifyAndClearExpectations(&mainMock); + + { + Canvas2DLayerBridgePtr bridge(adoptRef(new Canvas2DLayerBridge(mainMockProvider.release(), canvas.release(), 0, NonOpaque))); + + ::testing::Mock::VerifyAndClearExpectations(&mainMock); + + EXPECT_CALL(mainMock, flush()); + unsigned textureId = bridge->getBackingTexture(); + EXPECT_EQ(textureId, 0u); + + ::testing::Mock::VerifyAndClearExpectations(&mainMock); + } // bridge goes out of scope here + + ::testing::Mock::VerifyAndClearExpectations(&mainMock); + } + + void prepareMailboxWithBitmapTest() + { + MockCanvasContext mainMock; + RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterPMColor(300, 150)); + OwnPtr<SkDeferredCanvas> canvas = adoptPtr(SkDeferredCanvas::Create(surface.get())); + OwnPtr<MockWebGraphicsContext3DProvider> mainMockProvider = adoptPtr(new MockWebGraphicsContext3DProvider(&mainMock)); + Canvas2DLayerBridgePtr bridge(adoptRef(new Canvas2DLayerBridge(mainMockProvider.release(), canvas.release(), 0, NonOpaque))); + bridge->m_lastImageId = 1; + + NullWebExternalBitmap bitmap; + bridge->prepareMailbox(0, &bitmap); + EXPECT_EQ(0u, bridge->m_lastImageId); + } +}; + +namespace { + +TEST_F(Canvas2DLayerBridgeTest, testFullLifecycleSingleThreaded) +{ + fullLifecycleTest(); +} + +TEST_F(Canvas2DLayerBridgeTest, prepareMailboxWithBitmapTest) +{ + prepareMailboxWithBitmapTest(); +} + +} // namespace diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManager.cpp b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManager.cpp index 5d21312a0fe..3e56351950b 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManager.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManager.cpp @@ -31,11 +31,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using blink::WebThread; namespace { + enum { DefaultMaxBytesAllocated = 64*1024*1024, DefaultTargetBytesAllocated = 16*1024*1024, }; -} + +} // unnamed namespace namespace WebCore { @@ -81,8 +83,14 @@ void Canvas2DLayerManager::didProcessTask() ASSERT(m_taskObserverActive); blink::Platform::current()->currentThread()->removeTaskObserver(this); m_taskObserverActive = false; - for (Canvas2DLayerBridge* layer = m_layerList.head(); layer; layer = layer->next()) - layer->limitPendingFrames(); + Canvas2DLayerBridge* layer = m_layerList.head(); + while (layer) { + Canvas2DLayerBridge* currentLayer = layer; + // must increment iterator before calling limitPendingFrames, which + // may result in the layer being removed from the list. + layer = layer->next(); + currentLayer->limitPendingFrames(); + } } void Canvas2DLayerManager::layerDidDraw(Canvas2DLayerBridge* layer) @@ -92,8 +100,7 @@ void Canvas2DLayerManager::layerDidDraw(Canvas2DLayerBridge* layer) m_layerList.remove(layer); m_layerList.push(layer); // Set as MRU } - } else - addLayerToList(layer); + } if (!m_taskObserverActive) { m_taskObserverActive = true; @@ -102,48 +109,42 @@ void Canvas2DLayerManager::layerDidDraw(Canvas2DLayerBridge* layer) } } -void Canvas2DLayerManager::addLayerToList(Canvas2DLayerBridge* layer) -{ - ASSERT(!isInList(layer)); - m_bytesAllocated += layer->bytesAllocated(); - m_layerList.push(layer); // Set as MRU -} - -void Canvas2DLayerManager::layerAllocatedStorageChanged(Canvas2DLayerBridge* layer, intptr_t deltaBytes) +void Canvas2DLayerManager::layerTransientResourceAllocationChanged(Canvas2DLayerBridge* layer, intptr_t deltaBytes) { - if (!isInList(layer)) - addLayerToList(layer); - else { - ASSERT((intptr_t)m_bytesAllocated + deltaBytes >= 0); - m_bytesAllocated = (intptr_t)m_bytesAllocated + deltaBytes; + ASSERT((intptr_t)m_bytesAllocated + deltaBytes >= 0); + m_bytesAllocated = (intptr_t)m_bytesAllocated + deltaBytes; + if (!isInList(layer) && layer->hasTransientResources()) { + m_layerList.push(layer); + } else if (isInList(layer) && !layer->hasTransientResources()) { + m_layerList.remove(layer); + layer->setNext(0); + layer->setPrev(0); } + if (deltaBytes > 0) freeMemoryIfNecessary(); } -void Canvas2DLayerManager::layerToBeDestroyed(Canvas2DLayerBridge* layer) -{ - if (isInList(layer)) - removeLayerFromList(layer); -} - void Canvas2DLayerManager::freeMemoryIfNecessary() { - if (m_bytesAllocated > m_maxBytesAllocated) { + if (m_bytesAllocated >= m_maxBytesAllocated) { // Pass 1: Free memory from caches Canvas2DLayerBridge* layer = m_layerList.tail(); // LRU - while (m_bytesAllocated > m_targetBytesAllocated && layer) { - layer->freeMemoryIfPossible(m_bytesAllocated - m_targetBytesAllocated); + while (layer && m_bytesAllocated > m_targetBytesAllocated) { + Canvas2DLayerBridge* currentLayer = layer; layer = layer->prev(); + currentLayer->freeMemoryIfPossible(m_bytesAllocated - m_targetBytesAllocated); + ASSERT(isInList(currentLayer) == currentLayer->hasTransientResources()); } // Pass 2: Flush canvases - Canvas2DLayerBridge* leastRecentlyUsedLayer = m_layerList.tail(); - while (m_bytesAllocated > m_targetBytesAllocated && leastRecentlyUsedLayer) { - leastRecentlyUsedLayer->flush(); - leastRecentlyUsedLayer->freeMemoryIfPossible(~0); - removeLayerFromList(leastRecentlyUsedLayer); - leastRecentlyUsedLayer = m_layerList.tail(); + layer = m_layerList.tail(); + while (m_bytesAllocated > m_targetBytesAllocated && layer) { + Canvas2DLayerBridge* currentLayer = layer; + layer = layer->prev(); + currentLayer->flush(); + currentLayer->freeMemoryIfPossible(m_bytesAllocated - m_targetBytesAllocated); + ASSERT(isInList(currentLayer) == currentLayer->hasTransientResources()); } } } @@ -151,13 +152,11 @@ void Canvas2DLayerManager::freeMemoryIfNecessary() void Canvas2DLayerManager::removeLayerFromList(Canvas2DLayerBridge* layer) { ASSERT(isInList(layer)); - m_bytesAllocated -= layer->bytesAllocated(); - m_layerList.remove(layer); - layer->setNext(0); - layer->setPrev(0); + ASSERT(!layer->hasTransientResources()); + } -bool Canvas2DLayerManager::isInList(Canvas2DLayerBridge* layer) +bool Canvas2DLayerManager::isInList(Canvas2DLayerBridge* layer) const { return layer->prev() || m_layerList.head() == layer; } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManager.h b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManager.h index e2c4e042e65..231fc85b72b 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManager.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManager.h @@ -35,18 +35,19 @@ namespace WebCore { class PLATFORM_EXPORT Canvas2DLayerManager : public blink::WebThread::TaskObserver { public: static Canvas2DLayerManager& get(); + void init(size_t maxBytesAllocated, size_t targetBytesAllocated); virtual ~Canvas2DLayerManager(); - void layerAllocatedStorageChanged(Canvas2DLayerBridge*, intptr_t deltaBytes); + void layerTransientResourceAllocationChanged(Canvas2DLayerBridge*, intptr_t deltaBytes = 0); void layerDidDraw(Canvas2DLayerBridge*); - void layerToBeDestroyed(Canvas2DLayerBridge*); + + bool isInList(Canvas2DLayerBridge*) const; private: Canvas2DLayerManager(); // internal methods void freeMemoryIfNecessary(); - bool isInList(Canvas2DLayerBridge*); void addLayerToList(Canvas2DLayerBridge*); void removeLayerFromList(Canvas2DLayerBridge*); virtual void willProcessTask() OVERRIDE; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManagerTest.cpp b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManagerTest.cpp new file mode 100644 index 00000000000..a2f6b0c5da0 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManagerTest.cpp @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "platform/graphics/Canvas2DLayerManager.h" + +#include "SkDevice.h" +#include "SkSurface.h" +#include "platform/graphics/test/MockWebGraphicsContext3D.h" +#include "public/platform/Platform.h" +#include "public/platform/WebGraphicsContext3DProvider.h" +#include "public/platform/WebThread.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +using namespace WebCore; +using testing::InSequence; +using testing::Return; +using testing::Test; + +namespace { + +class MockWebGraphicsContext3DProvider : public blink::WebGraphicsContext3DProvider { +public: + MockWebGraphicsContext3DProvider(blink::WebGraphicsContext3D* context3d) + : m_context3d(context3d) { } + + blink::WebGraphicsContext3D* context3d() + { + return m_context3d; + } + + GrContext* grContext() + { + return 0; + } + +private: + blink::WebGraphicsContext3D* m_context3d; +}; + +class FakeCanvas2DLayerBridge : public Canvas2DLayerBridge { +public: + FakeCanvas2DLayerBridge(blink::WebGraphicsContext3D* context, PassOwnPtr<SkDeferredCanvas> canvas) + : Canvas2DLayerBridge(adoptPtr(new MockWebGraphicsContext3DProvider(context)), canvas, 0, NonOpaque) + , m_freeableBytes(0) + , m_freeMemoryIfPossibleCount(0) + , m_flushCount(0) + { + } + + virtual size_t storageAllocatedForRecording() OVERRIDE + { + // Because the fake layer has no canvas to query, just + // return status quo. Allocation changes that would normally be + // initiated by the canvas can be faked by invoking + // storageAllocatedForRecordingChanged directly from the test code. + return m_bytesAllocated; + } + + void fakeFreeableBytes(size_t size) + { + m_freeableBytes = size; + } + + virtual size_t freeMemoryIfPossible(size_t size) OVERRIDE + { + m_freeMemoryIfPossibleCount++; + size_t bytesFreed = size < m_freeableBytes ? size : m_freeableBytes; + m_freeableBytes -= bytesFreed; + if (bytesFreed) + storageAllocatedForRecordingChanged(m_bytesAllocated - bytesFreed); + return bytesFreed; + } + + virtual void flush() OVERRIDE + { + flushedDrawCommands(); + m_freeableBytes = bytesAllocated(); + m_flushCount++; + } + +public: + size_t m_freeableBytes; + int m_freeMemoryIfPossibleCount; + int m_flushCount; +}; + +class FakeCanvas2DLayerBridgePtr { +public: + FakeCanvas2DLayerBridgePtr(PassRefPtr<FakeCanvas2DLayerBridge> layerBridge) + : m_layerBridge(layerBridge) { } + + ~FakeCanvas2DLayerBridgePtr() + { + m_layerBridge->beginDestruction(); + } + + FakeCanvas2DLayerBridge* operator->() { return m_layerBridge.get(); } + FakeCanvas2DLayerBridge* get() { return m_layerBridge.get(); } + +private: + RefPtr<FakeCanvas2DLayerBridge> m_layerBridge; +}; + +static PassOwnPtr<SkDeferredCanvas> createCanvas() +{ + RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterPMColor(1, 1)); + return adoptPtr(SkDeferredCanvas::Create(surface.get())); +} + +} // unnamed namespace + +class Canvas2DLayerManagerTest : public Test { +protected: + void storageAllocationTrackingTest() + { + Canvas2DLayerManager& manager = Canvas2DLayerManager::get(); + manager.init(10, 10); + { + OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink::MockWebGraphicsContext3D); + OwnPtr<SkDeferredCanvas> canvas1 = createCanvas(); + FakeCanvas2DLayerBridgePtr layer1(adoptRef(new FakeCanvas2DLayerBridge(webContext.get(), canvas1.release()))); + EXPECT_EQ((size_t)0, manager.m_bytesAllocated); + layer1->storageAllocatedForRecordingChanged(1); + EXPECT_EQ((size_t)1, manager.m_bytesAllocated); + // Test allocation increase + layer1->storageAllocatedForRecordingChanged(2); + EXPECT_EQ((size_t)2, manager.m_bytesAllocated); + // Test allocation decrease + layer1->storageAllocatedForRecordingChanged(1); + EXPECT_EQ((size_t)1, manager.m_bytesAllocated); + { + OwnPtr<SkDeferredCanvas> canvas2 = createCanvas(); + FakeCanvas2DLayerBridgePtr layer2(adoptRef(new FakeCanvas2DLayerBridge(webContext.get(), canvas2.release()))); + EXPECT_EQ((size_t)1, manager.m_bytesAllocated); + // verify multi-layer allocation tracking + layer2->storageAllocatedForRecordingChanged(2); + EXPECT_EQ((size_t)3, manager.m_bytesAllocated); + } + // Verify tracking after destruction + EXPECT_EQ((size_t)1, manager.m_bytesAllocated); + } + } + + void evictionTest() + { + OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink::MockWebGraphicsContext3D); + Canvas2DLayerManager& manager = Canvas2DLayerManager::get(); + manager.init(10, 5); + OwnPtr<SkDeferredCanvas> canvas = createCanvas(); + FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(webContext.get(), canvas.release()))); + layer->fakeFreeableBytes(10); + layer->storageAllocatedForRecordingChanged(8); // under the max + EXPECT_EQ(0, layer->m_freeMemoryIfPossibleCount); + layer->storageAllocatedForRecordingChanged(12); // over the max + EXPECT_EQ(1, layer->m_freeMemoryIfPossibleCount); + EXPECT_EQ((size_t)3, layer->m_freeableBytes); + EXPECT_EQ(0, layer->m_flushCount); // eviction succeeded without triggering a flush + EXPECT_EQ((size_t)5, layer->bytesAllocated()); + } + + void hiddenCanvasTest() + { + OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink::MockWebGraphicsContext3D); + Canvas2DLayerManager& manager = Canvas2DLayerManager::get(); + manager.init(20, 5); + OwnPtr<SkDeferredCanvas> canvas = createCanvas(); + FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(webContext.get(), canvas.release()))); + layer->fakeFreeableBytes(5); + layer->storageAllocatedForRecordingChanged(10); + EXPECT_EQ(0, layer->m_freeMemoryIfPossibleCount); + EXPECT_EQ(0, layer->m_flushCount); + EXPECT_EQ((size_t)10, layer->bytesAllocated()); + layer->setIsHidden(true); + EXPECT_EQ(1, layer->m_freeMemoryIfPossibleCount); + EXPECT_EQ((size_t)0, layer->m_freeableBytes); + EXPECT_EQ((size_t)0, layer->bytesAllocated()); + EXPECT_EQ(1, layer->m_flushCount); + } + + void addRemoveLayerTest() + { + OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink::MockWebGraphicsContext3D); + Canvas2DLayerManager& manager = Canvas2DLayerManager::get(); + manager.init(10, 5); + OwnPtr<SkDeferredCanvas> canvas = createCanvas(); + FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(webContext.get(), canvas.release()))); + EXPECT_FALSE(manager.isInList(layer.get())); + layer->storageAllocatedForRecordingChanged(5); + EXPECT_TRUE(manager.isInList(layer.get())); + layer->storageAllocatedForRecordingChanged(0); + EXPECT_FALSE(manager.isInList(layer.get())); + } + + void flushEvictionTest() + { + OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink::MockWebGraphicsContext3D); + Canvas2DLayerManager& manager = Canvas2DLayerManager::get(); + manager.init(10, 5); + OwnPtr<SkDeferredCanvas> canvas = createCanvas(); + FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(webContext.get(), canvas.release()))); + layer->fakeFreeableBytes(1); // Not enough freeable bytes, will cause aggressive eviction by flushing + layer->storageAllocatedForRecordingChanged(8); // under the max + EXPECT_EQ(0, layer->m_freeMemoryIfPossibleCount); + layer->storageAllocatedForRecordingChanged(12); // over the max + EXPECT_EQ(2, layer->m_freeMemoryIfPossibleCount); // Two tries, one before flush, one after flush + EXPECT_EQ((size_t)5, layer->m_freeableBytes); + EXPECT_EQ(1, layer->m_flushCount); // flush was attempted + EXPECT_EQ((size_t)5, layer->bytesAllocated()); + EXPECT_TRUE(manager.isInList(layer.get())); + } + + void doDeferredFrameTestTask(FakeCanvas2DLayerBridge* layer, bool skipCommands) + { + EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive); + layer->willUse(); + layer->storageAllocatedForRecordingChanged(1); + EXPECT_TRUE(Canvas2DLayerManager::get().m_taskObserverActive); + if (skipCommands) { + layer->willUse(); + layer->skippedPendingDrawCommands(); + } + blink::Platform::current()->currentThread()->exitRunLoop(); + } + + class DeferredFrameTestTask : public blink::WebThread::Task { + public: + DeferredFrameTestTask(Canvas2DLayerManagerTest* test, FakeCanvas2DLayerBridge* layer, bool skipCommands) + { + m_test = test; + m_layer = layer; + m_skipCommands = skipCommands; + } + + virtual void run() OVERRIDE + { + m_test->doDeferredFrameTestTask(m_layer, m_skipCommands); + } + private: + Canvas2DLayerManagerTest* m_test; + FakeCanvas2DLayerBridge* m_layer; + bool m_skipCommands; + }; + + void deferredFrameTest() + { + OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink::MockWebGraphicsContext3D); + Canvas2DLayerManager::get().init(10, 10); + OwnPtr<SkDeferredCanvas> canvas = createCanvas(); + FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(webContext.get(), canvas.release()))); + blink::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, layer.get(), true)); + blink::Platform::current()->currentThread()->enterRunLoop(); + // Verify that didProcessTask was called upon completion + EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive); + // Verify that no flush was performed because frame is fresh + EXPECT_EQ(0, layer->m_flushCount); + + // Verify that no flushes are triggered as long as frame are fresh + blink::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, layer.get(), true)); + blink::Platform::current()->currentThread()->enterRunLoop(); + EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive); + EXPECT_EQ(0, layer->m_flushCount); + + blink::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, layer.get(), true)); + blink::Platform::current()->currentThread()->enterRunLoop(); + EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive); + EXPECT_EQ(0, layer->m_flushCount); + + // Verify that a flush is triggered when queue is accumulating a multi-frame backlog. + blink::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, layer.get(), false)); + blink::Platform::current()->currentThread()->enterRunLoop(); + EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive); + EXPECT_EQ(1, layer->m_flushCount); + + blink::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, layer.get(), false)); + blink::Platform::current()->currentThread()->enterRunLoop(); + EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive); + EXPECT_EQ(2, layer->m_flushCount); + } +}; + +namespace { + +TEST_F(Canvas2DLayerManagerTest, testStorageAllocationTracking) +{ + storageAllocationTrackingTest(); +} + +TEST_F(Canvas2DLayerManagerTest, testEviction) +{ + evictionTest(); +} + +TEST_F(Canvas2DLayerManagerTest, testFlushEviction) +{ + flushEvictionTest(); +} + +TEST_F(Canvas2DLayerManagerTest, testDeferredFrame) +{ + deferredFrameTest(); +} + +TEST_F(Canvas2DLayerManagerTest, testHiddenCanvas) +{ + hiddenCanvasTest(); +} + +TEST_F(Canvas2DLayerManagerTest, testAddRemoveLayer) +{ + addRemoveLayerTest(); +} + +} // unnamed namespace + diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Color.cpp b/chromium/third_party/WebKit/Source/platform/graphics/Color.cpp index 97b568a1a9e..db081a70a37 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/Color.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/Color.cpp @@ -26,17 +26,19 @@ #include "config.h" #include "platform/graphics/Color.h" +#include "platform/Decimal.h" #include "wtf/Assertions.h" -#include "wtf/DecimalNumber.h" #include "wtf/HexNumber.h" #include "wtf/MathExtras.h" +#include "wtf/dtoa.h" #include "wtf/text/StringBuilder.h" using namespace std; namespace WebCore { -#if !COMPILER(MSVC) +#if !COMPILER(MSVC) || COMPILER(CLANG) +// FIXME: Use C++11 strong enums to avoid static data member with initializer definition problems. const RGBA32 Color::black; const RGBA32 Color::white; const RGBA32 Color::darkGray; @@ -177,27 +179,42 @@ int differenceSquared(const Color& c1, const Color& c2) return dR * dR + dG * dG + dB * dB; } -Color::Color(const String& name) +bool Color::setFromString(const String& name) { - if (name[0] == '#') { - if (name.is8Bit()) - m_valid = parseHexColor(name.characters8() + 1, name.length() - 1, m_color); - else - m_valid = parseHexColor(name.characters16() + 1, name.length() - 1, m_color); - } else { - setNamedColor(name); - } + if (name[0] != '#') + return setNamedColor(name); + if (name.is8Bit()) + return parseHexColor(name.characters8() + 1, name.length() - 1, m_color); + return parseHexColor(name.characters16() + 1, name.length() - 1, m_color); } -Color::Color(const char* name) +String Color::serializedAsCSSComponentValue() const { - if (name[0] == '#') { - m_valid = parseHexColor(&name[1], m_color); - } else { - const NamedColor* foundColor = findColor(name, strlen(name)); - m_color = foundColor ? foundColor->ARGBValue : 0; - m_valid = foundColor; + StringBuilder result; + result.reserveCapacity(32); + bool colorHasAlpha = hasAlpha(); + if (colorHasAlpha) + result.append("rgba(", 5); + else + result.append("rgb(", 4); + + result.appendNumber(static_cast<unsigned char>(red())); + result.append(", ", 2); + + result.appendNumber(static_cast<unsigned char>(green())); + result.append(", ", 2); + + result.appendNumber(static_cast<unsigned char>(blue())); + if (colorHasAlpha) { + result.append(", ", 2); + + NumberToStringBuffer buffer; + const char* alphaString = numberToFixedPrecisionString(alpha() / 255.0f, 6, buffer, true); + result.append(alphaString, strlen(alphaString)); } + + result.append(')'); + return result.toString(); } String Color::serialized() const @@ -228,9 +245,7 @@ String Color::serialized() const if (!alpha()) result.append('0'); else { - NumberToLStringBuffer buffer; - unsigned length = DecimalNumber(alpha() / 255.0).toStringDecimal(buffer, WTF::NumberToStringBufferLength); - result.append(buffer, length); + result.append(Decimal::fromDouble(alpha() / 255.0).toString()); } result.append(')'); @@ -260,11 +275,11 @@ static inline const NamedColor* findNamedColor(const String& name) return findColor(buffer, length); } -void Color::setNamedColor(const String& name) +bool Color::setNamedColor(const String& name) { const NamedColor* foundColor = findNamedColor(name); m_color = foundColor ? foundColor->ARGBValue : 0; - m_valid = foundColor; + return foundColor; } Color Color::light() const @@ -312,6 +327,11 @@ Color Color::dark() const alpha()); } +Color Color::combineWithAlpha(float otherAlpha) const +{ + return colorWithOverrideAlpha(rgb(), (alpha() / 255.f) * otherAlpha); +} + static int blendComponent(int c, int a) { // We use white. diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Color.h b/chromium/third_party/WebKit/Source/platform/graphics/Color.h index 9664906a8f7..ce371ab23f8 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/Color.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/Color.h @@ -62,16 +62,14 @@ const NamedColor* findColor(register const char* str, register unsigned len); class PLATFORM_EXPORT Color { WTF_MAKE_FAST_ALLOCATED; public: - Color() : m_color(0), m_valid(false) { } - Color(RGBA32 color, bool valid = true) : m_color(color), m_valid(valid) { ASSERT(!m_color || m_valid); } - Color(int r, int g, int b) : m_color(makeRGB(r, g, b)), m_valid(true) { } - Color(int r, int g, int b, int a) : m_color(makeRGBA(r, g, b, a)), m_valid(true) { } + Color() : m_color(Color::transparent) { } + Color(RGBA32 color) : m_color(color) { } + Color(int r, int g, int b) : m_color(makeRGB(r, g, b)) { } + Color(int r, int g, int b, int a) : m_color(makeRGBA(r, g, b, a)) { } // Color is currently limited to 32bit RGBA, perhaps some day we'll support better colors - Color(float r, float g, float b, float a) : m_color(makeRGBA32FromFloats(r, g, b, a)), m_valid(true) { } + Color(float r, float g, float b, float a) : m_color(makeRGBA32FromFloats(r, g, b, a)) { } // Creates a new color from the specific CMYK and alpha values. - Color(float c, float m, float y, float k, float a) : m_color(makeRGBAFromCMYKA(c, m, y, k, a)), m_valid(true) { } - explicit Color(const String&); - explicit Color(const char*); + Color(float c, float m, float y, float k, float a) : m_color(makeRGBAFromCMYKA(c, m, y, k, a)) { } static Color createUnchecked(int r, int g, int b) { @@ -88,13 +86,18 @@ public: // - http://www.whatwg.org/specs/web-apps/current-work/#serialization-of-a-color String serialized() const; + // Returns the color serialized according to CSSOM + // - http://dev.w3.org/csswg/cssom/#serialize-a-css-component-value + String serializedAsCSSComponentValue() const; + // Returns the color serialized as either #RRGGBB or #RRGGBBAA // The latter format is not a valid CSS color, and should only be seen in DRT dumps. String nameForRenderTreeAsText() const; - void setNamedColor(const String&); - - bool isValid() const { return m_valid; } + // Returns whether parsing succeeded. The resulting Color is arbitrary + // if parsing fails. + bool setFromString(const String&); + bool setNamedColor(const String&); bool hasAlpha() const { return alpha() < 255; } @@ -104,8 +107,8 @@ public: int alpha() const { return alphaChannel(m_color); } RGBA32 rgb() const { return m_color; } // Preserve the alpha. - void setRGB(int r, int g, int b) { m_color = makeRGB(r, g, b); m_valid = true; } - void setRGB(RGBA32 rgb) { m_color = rgb; m_valid = true; } + void setRGB(int r, int g, int b) { m_color = makeRGB(r, g, b); } + void setRGB(RGBA32 rgb) { m_color = rgb; } void getRGBA(float& r, float& g, float& b, float& a) const; void getRGBA(double& r, double& g, double& b, double& a) const; void getHSL(double& h, double& s, double& l) const; @@ -113,6 +116,8 @@ public: Color light() const; Color dark() const; + Color combineWithAlpha(float otherAlpha) const; + // This is an implementation of Porter-Duff's "source-over" equation Color blend(const Color&) const; Color blendWithWhite() const; @@ -130,12 +135,11 @@ public: private: RGBA32 m_color; - bool m_valid; }; inline bool operator==(const Color& a, const Color& b) { - return a.rgb() == b.rgb() && a.isValid() == b.isValid(); + return a.rgb() == b.rgb(); } inline bool operator!=(const Color& a, const Color& b) @@ -148,10 +152,6 @@ PLATFORM_EXPORT RGBA32 premultipliedARGBFromColor(const Color&); inline Color blend(const Color& from, const Color& to, double progress, bool blendPremultiplied = true) { - // We need to preserve the state of the valid flag at the end of the animation - if (progress == 1 && !to.isValid()) - return Color(); - if (blendPremultiplied) { // Contrary to the name, RGBA32 actually stores ARGB, so we can initialize Color directly from premultipliedARGBFromColor(). // Also, premultipliedARGBFromColor() bails on zero alpha, so special-case that. diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ColorSpace.cpp b/chromium/third_party/WebKit/Source/platform/graphics/ColorSpace.cpp new file mode 100644 index 00000000000..b33b64db0e2 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/ColorSpace.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2008, Google Inc. All rights reserved. + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "platform/graphics/ColorSpace.h" + +#include "wtf/MathExtras.h" + +namespace WebCore { + +namespace ColorSpaceUtilities { + +static const uint8_t* getLinearRgbLUT() +{ + static uint8_t linearRgbLUT[256]; + static bool initialized; + if (!initialized) { + for (unsigned i = 0; i < 256; i++) { + float color = i / 255.0f; + color = (color <= 0.04045f ? color / 12.92f : pow((color + 0.055f) / 1.055f, 2.4f)); + color = std::max(0.0f, color); + color = std::min(1.0f, color); + linearRgbLUT[i] = static_cast<uint8_t>(round(color * 255)); + } + initialized = true; + } + return linearRgbLUT; +} + +static const uint8_t* getDeviceRgbLUT() +{ + static uint8_t deviceRgbLUT[256]; + static bool initialized; + if (!initialized) { + for (unsigned i = 0; i < 256; i++) { + float color = i / 255.0f; + color = (powf(color, 1.0f / 2.4f) * 1.055f) - 0.055f; + color = std::max(0.0f, color); + color = std::min(1.0f, color); + deviceRgbLUT[i] = static_cast<uint8_t>(round(color * 255)); + } + initialized = true; + } + return deviceRgbLUT; +} + +const uint8_t* getConversionLUT(ColorSpace dstColorSpace, ColorSpace srcColorSpace) +{ + // Identity. + if (srcColorSpace == dstColorSpace) + return 0; + + // Only sRGB/DeviceRGB <-> linearRGB are supported at the moment. + if ((srcColorSpace != ColorSpaceLinearRGB && srcColorSpace != ColorSpaceDeviceRGB) + || (dstColorSpace != ColorSpaceLinearRGB && dstColorSpace != ColorSpaceDeviceRGB)) + return 0; + + if (dstColorSpace == ColorSpaceLinearRGB) + return getLinearRgbLUT(); + if (dstColorSpace == ColorSpaceDeviceRGB) + return getDeviceRgbLUT(); + + ASSERT_NOT_REACHED(); + return 0; +} + +Color convertColor(const Color& srcColor, ColorSpace dstColorSpace, ColorSpace srcColorSpace) +{ + const uint8_t* lookupTable = getConversionLUT(dstColorSpace, srcColorSpace); + if (!lookupTable) + return srcColor; + + return Color(lookupTable[srcColor.red()], lookupTable[srcColor.green()], lookupTable[srcColor.blue()], srcColor.alpha()); +} + +} // namespace ColorSpaceUtilities + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ColorSpace.h b/chromium/third_party/WebKit/Source/platform/graphics/ColorSpace.h index 06918f7ff1f..9b1735a2463 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/ColorSpace.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/ColorSpace.h @@ -27,6 +27,7 @@ #define ColorSpace_h #include "platform/PlatformExport.h" +#include "platform/graphics/Color.h" namespace WebCore { @@ -36,6 +37,20 @@ enum ColorSpace { ColorSpaceLinearRGB }; +namespace ColorSpaceUtilities { + +// Get a pointer to a 8-bit lookup table that will convert color components +// in the |srcColorSpace| to the |dstColorSpace|. +// If the conversion cannot be performed, or is a no-op (identity transform), +// then 0 is returned. +// (Note that a round-trip - f(B,A)[f(A,B)[x]] - is not lossless in general.) +const uint8_t* getConversionLUT(ColorSpace dstColorSpace, ColorSpace srcColorSpace = ColorSpaceDeviceRGB); + +// Convert a Color assumed to be in the |srcColorSpace| into the |dstColorSpace|. +Color convertColor(const Color& srcColor, ColorSpace dstColorSpace, ColorSpace srcColorSpace = ColorSpaceDeviceRGB); + +} // namespace ColorSpaceUtilities + } // namespace WebCore #endif // ColorSpace_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/CompositingReasons.h b/chromium/third_party/WebKit/Source/platform/graphics/CompositingReasons.h new file mode 100644 index 00000000000..b4aa6f895c2 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/CompositingReasons.h @@ -0,0 +1,328 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CompositingReasons_h +#define CompositingReasons_h + +#include "wtf/MathExtras.h" +#include <stdint.h> + +namespace WebCore { + +const uint64_t CompositingReasonNone = 0; +const uint64_t CompositingReasonAll = ~static_cast<uint64_t>(0); + +// Intrinsic reasons that can be known right away by the layer +const uint64_t CompositingReason3DTransform = UINT64_C(1) << 0; +const uint64_t CompositingReasonVideo = UINT64_C(1) << 1; +const uint64_t CompositingReasonCanvas = UINT64_C(1) << 2; +const uint64_t CompositingReasonPlugin = UINT64_C(1) << 3; +const uint64_t CompositingReasonIFrame = UINT64_C(1) << 4; +const uint64_t CompositingReasonBackfaceVisibilityHidden = UINT64_C(1) << 5; +const uint64_t CompositingReasonActiveAnimation = UINT64_C(1) << 6; +const uint64_t CompositingReasonTransitionProperty = UINT64_C(1) << 7; +const uint64_t CompositingReasonFilters = UINT64_C(1) << 8; +const uint64_t CompositingReasonPositionFixed = UINT64_C(1) << 9; +const uint64_t CompositingReasonOverflowScrollingTouch = UINT64_C(1) << 10; +const uint64_t CompositingReasonOverflowScrollingParent = UINT64_C(1) << 11; +const uint64_t CompositingReasonOutOfFlowClipping = UINT64_C(1) << 12; +const uint64_t CompositingReasonVideoOverlay = UINT64_C(1) << 13; +const uint64_t CompositingReasonWillChangeCompositingHint = UINT64_C(1) << 14; + +// Overlap reasons that require knowing what's behind you in paint-order before knowing the answer +const uint64_t CompositingReasonAssumedOverlap = UINT64_C(1) << 15; +const uint64_t CompositingReasonOverlap = UINT64_C(1) << 16; +const uint64_t CompositingReasonNegativeZIndexChildren = UINT64_C(1) << 17; +const uint64_t CompositingReasonScrollsWithRespectToSquashingLayer = UINT64_C(1) << 18; +const uint64_t CompositingReasonSquashingSparsityExceeded = UINT64_C(1) << 19; +const uint64_t CompositingReasonSquashingClippingContainerMismatch = UINT64_C(1) << 20; +const uint64_t CompositingReasonSquashingOpacityAncestorMismatch = UINT64_C(1) << 21; +const uint64_t CompositingReasonSquashingTransformAncestorMismatch = UINT64_C(1) << 22; +const uint64_t CompositingReasonSquashingFilterAncestorMismatch = UINT64_C(1) << 23; +const uint64_t CompositingReasonSquashingWouldBreakPaintOrder = UINT64_C(1) << 24; +const uint64_t CompositingReasonSquashingVideoIsDisallowed = UINT64_C(1) << 25; +const uint64_t CompositingReasonSquashedLayerClipsCompositingDescendants = UINT64_C(1) << 26; + +// Subtree reasons that require knowing what the status of your subtree is before knowing the answer +const uint64_t CompositingReasonTransformWithCompositedDescendants = UINT64_C(1) << 27; +const uint64_t CompositingReasonOpacityWithCompositedDescendants = UINT64_C(1) << 28; +const uint64_t CompositingReasonMaskWithCompositedDescendants = UINT64_C(1) << 29; +const uint64_t CompositingReasonReflectionWithCompositedDescendants = UINT64_C(1) << 30; +const uint64_t CompositingReasonFilterWithCompositedDescendants = UINT64_C(1) << 31; +const uint64_t CompositingReasonBlendingWithCompositedDescendants = UINT64_C(1) << 32; +const uint64_t CompositingReasonClipsCompositingDescendants = UINT64_C(1) << 33; +const uint64_t CompositingReasonPerspectiveWith3DDescendants = UINT64_C(1) << 34; +const uint64_t CompositingReasonPreserve3DWith3DDescendants = UINT64_C(1) << 35; +const uint64_t CompositingReasonReflectionOfCompositedParent = UINT64_C(1) << 36; +const uint64_t CompositingReasonIsolateCompositedDescendants = UINT64_C(1) << 37; + +// The root layer is a special case that may be forced to be a layer, but also it needs to be +// a layer if anything else in the subtree is composited. +const uint64_t CompositingReasonRoot = UINT64_C(1) << 38; + +// CompositedLayerMapping internal hierarchy reasons +const uint64_t CompositingReasonLayerForAncestorClip = UINT64_C(1) << 39; +const uint64_t CompositingReasonLayerForDescendantClip = UINT64_C(1) << 40; +const uint64_t CompositingReasonLayerForPerspective = UINT64_C(1) << 41; +const uint64_t CompositingReasonLayerForHorizontalScrollbar = UINT64_C(1) << 42; +const uint64_t CompositingReasonLayerForVerticalScrollbar = UINT64_C(1) << 43; +const uint64_t CompositingReasonLayerForScrollCorner = UINT64_C(1) << 44; +const uint64_t CompositingReasonLayerForScrollingContents = UINT64_C(1) << 45; +const uint64_t CompositingReasonLayerForScrollingContainer = UINT64_C(1) << 46; +const uint64_t CompositingReasonLayerForSquashingContents = UINT64_C(1) << 47; +const uint64_t CompositingReasonLayerForSquashingContainer = UINT64_C(1) << 48; +const uint64_t CompositingReasonLayerForForeground = UINT64_C(1) << 49; +const uint64_t CompositingReasonLayerForBackground = UINT64_C(1) << 50; +const uint64_t CompositingReasonLayerForMask = UINT64_C(1) << 51; +const uint64_t CompositingReasonLayerForClippingMask = UINT64_C(1) << 52; +const uint64_t CompositingReasonLayerForScrollingBlockSelection = UINT64_C(1) << 53; + +// Various combinations of compositing reasons are defined here also, for more intutive and faster bitwise logic. +const uint64_t CompositingReasonComboAllDirectReasons = + CompositingReason3DTransform + | CompositingReasonVideo + | CompositingReasonCanvas + | CompositingReasonPlugin + | CompositingReasonIFrame + | CompositingReasonBackfaceVisibilityHidden + | CompositingReasonActiveAnimation + | CompositingReasonTransitionProperty + | CompositingReasonFilters + | CompositingReasonPositionFixed + | CompositingReasonOverflowScrollingTouch + | CompositingReasonOverflowScrollingParent + | CompositingReasonOutOfFlowClipping + | CompositingReasonVideoOverlay + | CompositingReasonWillChangeCompositingHint; + +const uint64_t CompositingReasonComboAllStyleDeterminedReasons = + CompositingReason3DTransform + | CompositingReasonBackfaceVisibilityHidden + | CompositingReasonActiveAnimation + | CompositingReasonTransitionProperty + | CompositingReasonFilters + | CompositingReasonWillChangeCompositingHint; + +const uint64_t CompositingReasonComboReasonsThatRequireOwnBacking = + CompositingReasonComboAllDirectReasons + | CompositingReasonOverlap + | CompositingReasonAssumedOverlap + | CompositingReasonNegativeZIndexChildren + | CompositingReasonScrollsWithRespectToSquashingLayer + | CompositingReasonSquashingSparsityExceeded + | CompositingReasonSquashingClippingContainerMismatch + | CompositingReasonSquashingOpacityAncestorMismatch + | CompositingReasonSquashingTransformAncestorMismatch + | CompositingReasonSquashingFilterAncestorMismatch + | CompositingReasonSquashingWouldBreakPaintOrder + | CompositingReasonSquashingVideoIsDisallowed + | CompositingReasonSquashedLayerClipsCompositingDescendants + | CompositingReasonTransformWithCompositedDescendants + | CompositingReasonOpacityWithCompositedDescendants + | CompositingReasonMaskWithCompositedDescendants + | CompositingReasonFilterWithCompositedDescendants + | CompositingReasonBlendingWithCompositedDescendants + | CompositingReasonIsolateCompositedDescendants + | CompositingReasonPreserve3DWith3DDescendants; // preserve-3d has to create backing store to ensure that 3d-transformed elements intersect. + +const uint64_t CompositingReasonComboSquashableReasons = + CompositingReasonOverlap + | CompositingReasonAssumedOverlap + | CompositingReasonOverflowScrollingParent; + +typedef uint64_t CompositingReasons; + +// Any reasons other than overlap or assumed overlap will require the layer to be separately compositing. +inline bool requiresCompositing(CompositingReasons reasons) +{ + return reasons & ~CompositingReasonComboSquashableReasons; +} + +// If the layer has overlap or assumed overlap, but no other reasons, then it should be squashed. +inline bool requiresSquashing(CompositingReasons reasons) +{ + return !requiresCompositing(reasons) && (reasons & CompositingReasonComboSquashableReasons); +} + +struct CompositingReasonStringMap { + CompositingReasons reason; + const char* shortName; + const char* description; +}; + +// FIXME: This static data shouldn't be in a header. When it's in the header +// it's copied into every compilation unit that includes the header. +static const CompositingReasonStringMap compositingReasonStringMap[] = { + { CompositingReasonNone, + "Unknown", + "No reason given" }, + { CompositingReason3DTransform, + "transform3D", + "Has a 3d transform" }, + { CompositingReasonVideo, + "video", + "Is an accelerated video" }, + { CompositingReasonCanvas, + "canvas", + "Is an accelerated canvas" }, + { CompositingReasonPlugin, + "plugin", + "Is an accelerated plugin" }, + { CompositingReasonIFrame, + "iFrame", + "Is an accelerated iFrame" }, + { CompositingReasonBackfaceVisibilityHidden, + "backfaceVisibilityHidden", + "Has backface-visibility: hidden" }, + { CompositingReasonActiveAnimation, + "activeAnimation", + "Has an active accelerated animation or transition" }, + { CompositingReasonTransitionProperty, + "transitionProperty", + "Has an acceleratable transition property (active or inactive)" }, + { CompositingReasonFilters, + "filters", + "Has an accelerated filter" }, + { CompositingReasonPositionFixed, + "positionFixed", + "Is fixed position" }, + { 0, 0, 0 }, // Available. + { CompositingReasonOverflowScrollingTouch, + "overflowScrollingTouch", + "Is a scrollable overflow element" }, + { CompositingReasonOverflowScrollingParent, + "overflowScrollingParent", + "Scroll parent is not an ancestor" }, + { CompositingReasonOutOfFlowClipping, + "outOfFlowClipping", + "Has clipping ancestor" }, + { CompositingReasonVideoOverlay, + "videoOverlay", + "Is overlay controls for video" }, + { CompositingReasonWillChangeCompositingHint, + "willChange", + "Has a will-change compositing hint" }, + { 0, 0, 0 }, // Available. + { CompositingReasonAssumedOverlap, + "assumedOverlap", + "Might overlap other composited content" }, + { CompositingReasonOverlap, + "overlap", + "Overlaps other composited content" }, + { CompositingReasonNegativeZIndexChildren, + "negativeZIndexChildren", + "Parent with composited negative z-index content" }, + { CompositingReasonScrollsWithRespectToSquashingLayer, + "scrollsWithRespectToSquashingLayer", + "Cannot be squashed since this layer scrolls with respect to the squashing layer" }, + { CompositingReasonSquashingSparsityExceeded, + "squashingSparsityExceeded", + "Cannot be squashed as the squashing layer would become too sparse" }, + { CompositingReasonSquashingClippingContainerMismatch, + "squashingClippingContainerMismatch", + "Cannot be squashed because this layer has a different clipping container than the squashing layer" }, + { CompositingReasonSquashingOpacityAncestorMismatch, + "squashingOpacityAncestorMismatch", + "Cannot be squashed because this layer has a different opacity ancestor than the squashing layer" }, + { CompositingReasonSquashingTransformAncestorMismatch, + "squashingTransformAncestorMismatch", + "Cannot be squashed because this layer has a different transform ancestor than the squashing layer" }, + { CompositingReasonSquashingFilterAncestorMismatch, + "squashingFilterAncestorMismatch", + "Cannot be squashed because this layer has a different filter ancestor than the squashing layer" }, + { CompositingReasonSquashingWouldBreakPaintOrder, + "squashingWouldBreakPaintOrder", + "Cannot be squashed without breaking paint order" }, + { CompositingReasonSquashingVideoIsDisallowed, + "squashingVideoIsDisallowed", + "Squashing video is not supported" }, + { CompositingReasonSquashedLayerClipsCompositingDescendants, + "squashedLayerClipsCompositingDescendants", + "Squashing a layer that clips composited descendants is not supported." }, + { CompositingReasonTransformWithCompositedDescendants, + "transformWithCompositedDescendants", + "Has a transform that needs to be known by compositor because of composited descendants" }, + { CompositingReasonOpacityWithCompositedDescendants, + "opacityWithCompositedDescendants", + "Has opacity that needs to be applied by compositor because of composited descendants" }, + { CompositingReasonMaskWithCompositedDescendants, + "maskWithCompositedDescendants", + "Has a mask that needs to be known by compositor because of composited descendants" }, + { CompositingReasonReflectionWithCompositedDescendants, + "reflectionWithCompositedDescendants", + "Has a reflection that needs to be known by compositor because of composited descendants" }, + { CompositingReasonFilterWithCompositedDescendants, + "filterWithCompositedDescendants", + "Has a filter effect that needs to be known by compositor because of composited descendants" }, + { CompositingReasonBlendingWithCompositedDescendants, + "blendingWithCompositedDescendants", + "Has a blenidng effect that needs to be known by compositor because of composited descendants" }, + { CompositingReasonClipsCompositingDescendants, + "clipsCompositingDescendants", + "Has a clip that needs to be known by compositor because of composited descendants" }, + { CompositingReasonPerspectiveWith3DDescendants, + "perspectiveWith3DDescendants", + "Has a perspective transform that needs to be known by compositor because of 3d descendants" }, + { CompositingReasonPreserve3DWith3DDescendants, + "preserve3DWith3DDescendants", + "Has a preserves-3d property that needs to be known by compositor because of 3d descendants" }, + { CompositingReasonReflectionOfCompositedParent, + "reflectionOfCompositedParent", + "Is a reflection of a composited layer" }, + { CompositingReasonIsolateCompositedDescendants, + "isolateCompositedDescendants", + "Should isolate descendants to apply a blend effect" }, + { CompositingReasonRoot, + "root", + "Is the root layer" }, + { CompositingReasonLayerForAncestorClip, + "layerForAncestorClip", + "Secondary layer, applies a clip due to a sibling in the compositing tree" }, + { CompositingReasonLayerForDescendantClip, + "layerForDescendantClip", + "Secondary layer, to clip descendants of the owning layer" }, + { CompositingReasonLayerForPerspective, + "layerForPerspective", + "Secondary layer, to house the perspective transform for all descendants" }, + { CompositingReasonLayerForHorizontalScrollbar, + "layerForHorizontalScrollbar", + "Secondary layer, the horizontal scrollbar layer" }, + { CompositingReasonLayerForVerticalScrollbar, + "layerForVerticalScrollbar", + "Secondary layer, the vertical scrollbar layer" }, + { CompositingReasonLayerForScrollCorner, + "layerForScrollCorner", + "Secondary layer, the scroll corner layer" }, + { CompositingReasonLayerForScrollingContents, + "layerForScrollingContents", + "Secondary layer, to house contents that can be scrolled" }, + { CompositingReasonLayerForScrollingContainer, + "layerForScrollingContainer", + "Secondary layer, used to position the scolling contents while scrolling" }, + { CompositingReasonLayerForSquashingContents, + "layerForSquashingContents", + "Secondary layer, home for a group of squashable content" }, + { CompositingReasonLayerForSquashingContainer, + "layerForSquashingContainer", + "Secondary layer, no-op layer to place the squashing layer correctly in the composited layer tree" }, + { CompositingReasonLayerForForeground, + "layerForForeground", + "Secondary layer, to contain any normal flow and positive z-index contents on top of a negative z-index layer" }, + { CompositingReasonLayerForBackground, + "layerForBackground", + "Secondary layer, to contain acceleratable background content" }, + { CompositingReasonLayerForMask, + "layerForMask", + "Secondary layer, to contain the mask contents" }, + { CompositingReasonLayerForClippingMask, + "layerForClippingMask", + "Secondary layer, for clipping mask" }, + { CompositingReasonLayerForScrollingBlockSelection, + "layerForScrollingBlockSelection", + "Secondary layer, to house block selection gaps for composited scrolling with no scrolling contents" }, +}; + +} // namespace WebCore + +#endif // CompositingReasons_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.cpp b/chromium/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.cpp index dcbcabf3777..667e2553ecc 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.cpp @@ -62,22 +62,22 @@ void CrossfadeGeneratedImage::drawCrossfade(GraphicsContext* context) // Draw the image we're fading away from. context->save(); if (m_crossfadeSize != fromImageSize) { - context->scale(FloatSize( + context->scale( static_cast<float>(m_crossfadeSize.width()) / fromImageSize.width(), - static_cast<float>(m_crossfadeSize.height()) / fromImageSize.height())); + static_cast<float>(m_crossfadeSize.height()) / fromImageSize.height()); } - context->setAlpha(inversePercentage); + context->setAlphaAsFloat(inversePercentage); context->drawImage(m_fromImage, IntPoint()); context->restore(); // Draw the image we're fading towards. context->save(); if (m_crossfadeSize != toImageSize) { - context->scale(FloatSize( + context->scale( static_cast<float>(m_crossfadeSize.width()) / toImageSize.width(), - static_cast<float>(m_crossfadeSize.height()) / toImageSize.height())); + static_cast<float>(m_crossfadeSize.height()) / toImageSize.height()); } - context->setAlpha(m_percentage); + context->setAlphaAsFloat(m_percentage); context->drawImage(m_toImage, IntPoint(), CompositePlusLighter); context->restore(); @@ -91,7 +91,7 @@ void CrossfadeGeneratedImage::draw(GraphicsContext* context, const FloatRect& ds context->clip(dstRect); context->translate(dstRect.x(), dstRect.y()); if (dstRect.size() != srcRect.size()) - context->scale(FloatSize(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height())); + context->scale(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height()); context->translate(-srcRect.x(), -srcRect.y()); drawCrossfade(context); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.h b/chromium/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.h index 8d96298f126..5be008518e3 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.h @@ -43,12 +43,12 @@ public: return adoptRef(new CrossfadeGeneratedImage(fromImage, toImage, percentage, crossfadeSize, size)); } - virtual void setContainerSize(const IntSize&) { } - virtual bool usesContainerSize() const { return false; } - virtual bool hasRelativeWidth() const { return false; } - virtual bool hasRelativeHeight() const { return false; } + virtual void setContainerSize(const IntSize&) OVERRIDE { } + virtual bool usesContainerSize() const OVERRIDE { return false; } + virtual bool hasRelativeWidth() const OVERRIDE { return false; } + virtual bool hasRelativeHeight() const OVERRIDE { return false; } - virtual IntSize size() const { return m_crossfadeSize; } + virtual IntSize size() const OVERRIDE { return m_crossfadeSize; } protected: virtual void draw(GraphicsContext*, const FloatRect&, const FloatRect&, diff --git a/chromium/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp b/chromium/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp index 55ff319432f..a32fc04b4c9 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp @@ -47,27 +47,26 @@ DecodingImageGenerator::~DecodingImageGenerator() { } -SkData* DecodingImageGenerator::refEncodedData() +SkData* DecodingImageGenerator::onRefEncodedData() { // FIXME: If the image has been clipped or scaled, do not return the original // encoded data, since on playback it will not be known how the clipping/scaling // was done. - RefPtr<SharedBuffer> buffer = 0; + RefPtr<SharedBuffer> buffer = nullptr; bool allDataReceived = false; m_frameGenerator->copyData(&buffer, &allDataReceived); - if (buffer && allDataReceived) { + if (buffer && allDataReceived) return SkData::NewWithCopy(buffer->data(), buffer->size()); - } return 0; } -bool DecodingImageGenerator::getInfo(SkImageInfo* info) +bool DecodingImageGenerator::onGetInfo(SkImageInfo* info) { *info = m_imageInfo; return true; } -bool DecodingImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) +bool DecodingImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) { TRACE_EVENT1("webkit", "DecodingImageGenerator::getPixels", "index", static_cast<int>(m_frameIndex)); @@ -79,7 +78,7 @@ bool DecodingImageGenerator::getPixels(const SkImageInfo& info, void* pixels, si ASSERT(info.fAlphaType == m_imageInfo.fAlphaType); PlatformInstrumentation::willDecodeLazyPixelRef(m_generationId); bool decoded = m_frameGenerator->decodeAndScale(m_imageInfo, m_frameIndex, pixels, rowBytes); - PlatformInstrumentation::didDecodeLazyPixelRef(m_generationId); + PlatformInstrumentation::didDecodeLazyPixelRef(); return decoded; } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.h b/chromium/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.h index edea6418259..fe5cb00b60d 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.h @@ -42,18 +42,18 @@ class ImageFrameGenerator; // // This class does not own an ImageDecode. It does not own encoded data. It serves // as and adapter to ImageFrameGenerator which actually performs decoding. -class DecodingImageGenerator : public SkImageGenerator { +class DecodingImageGenerator FINAL : public SkImageGenerator { public: DecodingImageGenerator(PassRefPtr<ImageFrameGenerator>, const SkImageInfo&, size_t index); virtual ~DecodingImageGenerator(); - // SkImageGenerator implementation. - virtual SkData* refEncodedData(); - virtual bool getInfo(SkImageInfo*); - virtual bool getPixels(const SkImageInfo&, void* pixels, size_t rowBytes); - void setGenerationId(size_t id) { m_generationId = id; } +protected: + virtual SkData* onRefEncodedData() OVERRIDE; + virtual bool onGetInfo(SkImageInfo*) OVERRIDE; + virtual bool onGetPixels(const SkImageInfo&, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) OVERRIDE; + private: RefPtr<ImageFrameGenerator> m_frameGenerator; SkImageInfo m_imageInfo; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp b/chromium/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp index 557ce37339c..4f3822ee4e4 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp @@ -36,22 +36,21 @@ namespace WebCore { namespace { -// URI label for a lazily decoded SkPixelRef. -const char labelLazyDecoded[] = "lazy"; - // URI label for SkDiscardablePixelRef. const char labelDiscardable[] = "discardable"; } // namespace bool DeferredImageDecoder::s_enabled = false; -bool DeferredImageDecoder::s_skiaDiscardableMemoryEnabled = false; DeferredImageDecoder::DeferredImageDecoder(PassOwnPtr<ImageDecoder> actualDecoder) : m_allDataReceived(false) + , m_lastDataSize(0) + , m_dataChanged(false) , m_actualDecoder(actualDecoder) , m_orientation(DefaultImageOrientation) , m_repetitionCount(cAnimationNone) + , m_hasColorProfile(false) { } @@ -74,21 +73,19 @@ bool DeferredImageDecoder::isLazyDecoded(const SkBitmap& bitmap) { return bitmap.pixelRef() && bitmap.pixelRef()->getURI() - && (!memcmp(bitmap.pixelRef()->getURI(), labelLazyDecoded, sizeof(labelLazyDecoded)) - || !memcmp(bitmap.pixelRef()->getURI(), labelDiscardable, sizeof(labelDiscardable))); + && !memcmp(bitmap.pixelRef()->getURI(), labelDiscardable, sizeof(labelDiscardable)); } void DeferredImageDecoder::setEnabled(bool enabled) { s_enabled = enabled; -#if !OS(ANDROID) - // FIXME: This code is temporary to enable discardable memory for - // non-Android platforms. In the future all platforms will be - // the same and we can remove this code. - s_skiaDiscardableMemoryEnabled = enabled; if (enabled) ImageDecodingStore::setImageCachingEnabled(false); -#endif +} + +bool DeferredImageDecoder::enabled() +{ + return s_enabled; } String DeferredImageDecoder::filenameExtension() const @@ -110,17 +107,21 @@ ImageFrame* DeferredImageDecoder::frameBufferAtIndex(size_t index) return 0; } -void DeferredImageDecoder::setData(SharedBuffer* data, bool allDataReceived) +void DeferredImageDecoder::setData(SharedBuffer& data, bool allDataReceived) { if (m_actualDecoder) { - m_data = data; + const bool firstData = !m_data; + const bool moreData = data.size() > m_lastDataSize; + m_dataChanged = firstData || moreData; + m_data = RefPtr<SharedBuffer>(data); + m_lastDataSize = data.size(); m_allDataReceived = allDataReceived; - m_actualDecoder->setData(data, allDataReceived); + m_actualDecoder->setData(&data, allDataReceived); prepareLazyDecodedFrames(); } if (m_frameGenerator) - m_frameGenerator->setData(data, allDataReceived); + m_frameGenerator->setData(&data, allDataReceived); } bool DeferredImageDecoder::isSizeAvailable() @@ -130,6 +131,11 @@ bool DeferredImageDecoder::isSizeAvailable() return m_actualDecoder ? m_actualDecoder->isSizeAvailable() : true; } +bool DeferredImageDecoder::hasColorProfile() const +{ + return m_actualDecoder ? m_actualDecoder->hasColorProfile() : m_hasColorProfile; +} + IntSize DeferredImageDecoder::size() const { return m_actualDecoder ? m_actualDecoder->size() : m_size; @@ -137,7 +143,7 @@ IntSize DeferredImageDecoder::size() const IntSize DeferredImageDecoder::frameSizeAtIndex(size_t index) const { - // FIXME: Frame size is assumed to be uniform. This might not be true for + // FIXME: LocalFrame size is assumed to be uniform. This might not be true for // future supported codecs. return m_actualDecoder ? m_actualDecoder->frameSizeAtIndex(index) : m_size; } @@ -205,6 +211,7 @@ void DeferredImageDecoder::activateLazyDecoding() m_size = m_actualDecoder->size(); m_orientation = m_actualDecoder->orientation(); m_filenameExtension = m_actualDecoder->filenameExtension(); + m_hasColorProfile = m_actualDecoder->hasColorProfile(); const bool isSingleFrame = m_actualDecoder->repetitionCount() == cAnimationNone || (m_allDataReceived && m_actualDecoder->frameCount() == 1u); m_frameGenerator = ImageFrameGenerator::create(SkISize::Make(m_actualDecoder->decodedSize().width(), m_actualDecoder->decodedSize().height()), m_data, m_allDataReceived, !isSingleFrame); } @@ -221,6 +228,11 @@ void DeferredImageDecoder::prepareLazyDecodedFrames() const size_t previousSize = m_lazyDecodedFrames.size(); m_lazyDecodedFrames.resize(m_actualDecoder->frameCount()); + + // We have encountered a broken image file. Simply bail. + if (m_lazyDecodedFrames.size() < previousSize) + return; + for (size_t i = previousSize; i < m_lazyDecodedFrames.size(); ++i) { OwnPtr<ImageFrame> frame(adoptPtr(new ImageFrame())); frame->setSkBitmap(createBitmap(i)); @@ -231,8 +243,17 @@ void DeferredImageDecoder::prepareLazyDecodedFrames() // The last lazy decoded frame created from previous call might be // incomplete so update its state. - if (previousSize) - m_lazyDecodedFrames[previousSize - 1]->setStatus(m_actualDecoder->frameIsCompleteAtIndex(previousSize - 1) ? ImageFrame::FrameComplete : ImageFrame::FramePartial); + if (previousSize) { + const size_t lastFrame = previousSize - 1; + m_lazyDecodedFrames[lastFrame]->setStatus(m_actualDecoder->frameIsCompleteAtIndex(lastFrame) ? ImageFrame::FrameComplete : ImageFrame::FramePartial); + + // If data has changed then create a new bitmap. This forces + // Skia to decode again. + if (m_dataChanged) { + m_dataChanged = false; + m_lazyDecodedFrames[lastFrame]->setSkBitmap(createBitmap(lastFrame)); + } + } if (m_allDataReceived) { m_repetitionCount = m_actualDecoder->repetitionCount(); @@ -241,18 +262,8 @@ void DeferredImageDecoder::prepareLazyDecodedFrames() } } -// Creates either a SkBitmap backed by SkDiscardablePixelRef or a SkBitmap using the -// legacy LazyDecodingPixelRef. -SkBitmap DeferredImageDecoder::createBitmap(size_t index) -{ - // This code is temporary until the transition to SkDiscardablePixelRef is complete. - if (s_skiaDiscardableMemoryEnabled) - return createSkiaDiscardableBitmap(index); - return createLazyDecodingBitmap(index); -} - // Creates a SkBitmap that is backed by SkDiscardablePixelRef. -SkBitmap DeferredImageDecoder::createSkiaDiscardableBitmap(size_t index) +SkBitmap DeferredImageDecoder::createBitmap(size_t index) { IntSize decodedSize = m_actualDecoder->decodedSize(); ASSERT(decodedSize.width() > 0); @@ -261,7 +272,11 @@ SkBitmap DeferredImageDecoder::createSkiaDiscardableBitmap(size_t index) SkImageInfo info; info.fWidth = decodedSize.width(); info.fHeight = decodedSize.height(); +#if SK_B32_SHIFT // Little-endian RGBA pixels. (Android) + info.fColorType = kRGBA_8888_SkColorType; +#else info.fColorType = kBGRA_8888_SkColorType; +#endif info.fAlphaType = kPremul_SkAlphaType; SkBitmap bitmap; @@ -273,34 +288,6 @@ SkBitmap DeferredImageDecoder::createSkiaDiscardableBitmap(size_t index) return bitmap; } -SkBitmap DeferredImageDecoder::createLazyDecodingBitmap(size_t index) -{ - IntSize decodedSize = m_actualDecoder->decodedSize(); - ASSERT(decodedSize.width() > 0); - ASSERT(decodedSize.height() > 0); - - SkImageInfo info; - info.fWidth = decodedSize.width(); - info.fHeight = decodedSize.height(); - info.fColorType = kPMColor_SkColorType; - info.fAlphaType = kPremul_SkAlphaType; - - // Creates a lazily decoded SkPixelRef that references the entire image without scaling. - SkBitmap bitmap; - bitmap.setConfig(info); - bitmap.setPixelRef(new LazyDecodingPixelRef(info, m_frameGenerator, index))->unref(); - - // Use the URI to identify this as a lazily decoded SkPixelRef of type LazyDecodingPixelRef. - // FIXME: It would be more useful to give the actual image URI. - bitmap.pixelRef()->setURI(labelLazyDecoded); - - // Inform the bitmap that we will never change the pixels. This is a performance hint - // subsystems that may try to cache this bitmap (e.g. pictures, pipes, gpu, pdf, etc.) - bitmap.setImmutable(); - - return bitmap; -} - bool DeferredImageDecoder::hotSpot(IntPoint& hotSpot) const { // TODO: Implement. diff --git a/chromium/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.h b/chromium/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.h index 91710475f38..2aa48c6a090 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.h @@ -52,14 +52,16 @@ public: static bool isLazyDecoded(const SkBitmap&); static void setEnabled(bool); + static bool enabled(); String filenameExtension() const; ImageFrame* frameBufferAtIndex(size_t index); - void setData(SharedBuffer* data, bool allDataReceived); + void setData(SharedBuffer& data, bool allDataReceived); bool isSizeAvailable(); + bool hasColorProfile() const; IntSize size() const; IntSize frameSizeAtIndex(size_t index) const; size_t frameCount(); @@ -79,25 +81,24 @@ private: explicit DeferredImageDecoder(PassOwnPtr<ImageDecoder> actualDecoder); void prepareLazyDecodedFrames(); SkBitmap createBitmap(size_t index); - SkBitmap createSkiaDiscardableBitmap(size_t index); - SkBitmap createLazyDecodingBitmap(size_t index); void activateLazyDecoding(); - void setData(PassRefPtr<SharedBuffer>, bool allDataReceived); RefPtr<SharedBuffer> m_data; bool m_allDataReceived; + unsigned m_lastDataSize; + bool m_dataChanged; OwnPtr<ImageDecoder> m_actualDecoder; String m_filenameExtension; IntSize m_size; ImageOrientation m_orientation; int m_repetitionCount; + bool m_hasColorProfile; Vector<OwnPtr<ImageFrame> > m_lazyDecodedFrames; RefPtr<ImageFrameGenerator> m_frameGenerator; static bool s_enabled; - static bool s_skiaDiscardableMemoryEnabled; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/DeferredImageDecoderTest.cpp b/chromium/third_party/WebKit/Source/platform/graphics/DeferredImageDecoderTest.cpp index 4048eb72c23..c4a953efa42 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/DeferredImageDecoderTest.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/DeferredImageDecoderTest.cpp @@ -29,6 +29,7 @@ #include "SkBitmapDevice.h" #include "SkCanvas.h" #include "SkPicture.h" +#include "SkPictureRecorder.h" #include "platform/SharedBuffer.h" #include "platform/Task.h" #include "platform/graphics/ImageDecodingStore.h" @@ -59,12 +60,6 @@ const unsigned char whitePNG[] = { 0x42, 0x60, 0x82, }; -static SkCanvas* createRasterCanvas(int width, int height) -{ - SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(SkBitmap::kARGB_8888_Config, width, height)); - return new SkCanvas(device); -} - struct Rasterizer { SkCanvas* canvas; SkPicture* picture; @@ -76,14 +71,15 @@ class DeferredImageDecoderTest : public ::testing::Test, public MockImageDecoder public: virtual void SetUp() OVERRIDE { - ImageDecodingStore::initializeOnce(); + ImageDecodingStore::instance()->setCacheLimitInBytes(1024 * 1024); DeferredImageDecoder::setEnabled(true); m_data = SharedBuffer::create(whitePNG, sizeof(whitePNG)); OwnPtr<MockImageDecoder> decoder = MockImageDecoder::create(this); m_actualDecoder = decoder.get(); m_actualDecoder->setSize(1, 1); m_lazyDecoder = DeferredImageDecoder::createForTesting(decoder.release()); - m_canvas.reset(createRasterCanvas(100, 100)); + m_canvas.reset(SkCanvas::NewRasterN32(100, 100)); + ASSERT_TRUE(m_canvas); m_frameBufferRequestCount = 0; m_frameCount = 1; m_repetitionCount = cAnimationNone; @@ -94,7 +90,7 @@ public: virtual void TearDown() OVERRIDE { - ImageDecodingStore::shutdown(); + ImageDecodingStore::instance()->clear(); } virtual void decoderBeingDestroyed() OVERRIDE @@ -141,7 +137,6 @@ protected: // Don't own this but saves the pointer to query states. MockImageDecoder* m_actualDecoder; OwnPtr<DeferredImageDecoder> m_lazyDecoder; - SkPicture m_picture; SkAutoTUnref<SkCanvas> m_canvas; int m_frameBufferRequestCount; RefPtr<SharedBuffer> m_data; @@ -154,82 +149,85 @@ protected: TEST_F(DeferredImageDecoderTest, drawIntoSkPicture) { - m_lazyDecoder->setData(m_data.get(), true); + m_lazyDecoder->setData(*m_data, true); RefPtr<NativeImageSkia> image = m_lazyDecoder->frameBufferAtIndex(0)->asNewNativeImage(); EXPECT_EQ(1, image->bitmap().width()); EXPECT_EQ(1, image->bitmap().height()); EXPECT_FALSE(image->bitmap().isNull()); EXPECT_TRUE(image->bitmap().isImmutable()); - SkCanvas* tempCanvas = m_picture.beginRecording(100, 100); + SkPictureRecorder recorder; + SkCanvas* tempCanvas = recorder.beginRecording(100, 100, 0, 0); tempCanvas->drawBitmap(image->bitmap(), 0, 0); - m_picture.endRecording(); + RefPtr<SkPicture> picture = adoptRef(recorder.endRecording()); EXPECT_EQ(0, m_frameBufferRequestCount); - m_canvas->drawPicture(m_picture); + m_canvas->drawPicture(picture.get()); EXPECT_EQ(0, m_frameBufferRequestCount); SkBitmap canvasBitmap; - canvasBitmap.setConfig(SkBitmap::kARGB_8888_Config, 100, 100); + ASSERT_TRUE(canvasBitmap.allocN32Pixels(100, 100)); ASSERT_TRUE(m_canvas->readPixels(&canvasBitmap, 0, 0)); SkAutoLockPixels autoLock(canvasBitmap); EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), canvasBitmap.getColor(0, 0)); } -TEST_F(DeferredImageDecoderTest, DISABLED_drawScaledIntoSkPicture) +TEST_F(DeferredImageDecoderTest, drawIntoSkPictureProgressive) { - m_lazyDecoder->setData(m_data.get(), true); - RefPtr<NativeImageSkia> image = m_lazyDecoder->frameBufferAtIndex(0)->asNewNativeImage(); - SkBitmap scaledBitmap = image->resizedBitmap(SkISize::Make(50, 51), SkIRect::MakeWH(50, 51)); - EXPECT_FALSE(scaledBitmap.isNull()); - EXPECT_TRUE(scaledBitmap.isImmutable()); - EXPECT_EQ(50, scaledBitmap.width()); - EXPECT_EQ(51, scaledBitmap.height()); - EXPECT_EQ(0, m_frameBufferRequestCount); + RefPtr<SharedBuffer> partialData = SharedBuffer::create(m_data->data(), m_data->size() - 10); - SkCanvas* tempCanvas = m_picture.beginRecording(100, 100); - tempCanvas->drawBitmap(scaledBitmap, 0, 0); - m_picture.endRecording(); - EXPECT_EQ(0, m_frameBufferRequestCount); + // Received only half the file. + m_lazyDecoder->setData(*partialData, false); + RefPtr<NativeImageSkia> image = m_lazyDecoder->frameBufferAtIndex(0)->asNewNativeImage(); + SkPictureRecorder recorder; + SkCanvas* tempCanvas = recorder.beginRecording(100, 100, 0, 0); + tempCanvas->drawBitmap(image->bitmap(), 0, 0); + RefPtr<SkPicture> picture = adoptRef(recorder.endRecording()); + m_canvas->drawPicture(picture.get()); - m_canvas->drawPicture(m_picture); - EXPECT_EQ(0, m_frameBufferRequestCount); + // Fully received the file and draw the SkPicture again. + m_lazyDecoder->setData(*m_data, true); + image = m_lazyDecoder->frameBufferAtIndex(0)->asNewNativeImage(); + tempCanvas = recorder.beginRecording(100, 100, 0, 0); + tempCanvas->drawBitmap(image->bitmap(), 0, 0); + picture = adoptRef(recorder.endRecording()); + m_canvas->drawPicture(picture.get()); SkBitmap canvasBitmap; - canvasBitmap.setConfig(SkBitmap::kARGB_8888_Config, 100, 100); + ASSERT_TRUE(canvasBitmap.allocN32Pixels(100, 100)); ASSERT_TRUE(m_canvas->readPixels(&canvasBitmap, 0, 0)); SkAutoLockPixels autoLock(canvasBitmap); EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), canvasBitmap.getColor(0, 0)); - EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), canvasBitmap.getColor(49, 50)); } static void rasterizeMain(SkCanvas* canvas, SkPicture* picture) { - canvas->drawPicture(*picture); + canvas->drawPicture(picture); } TEST_F(DeferredImageDecoderTest, decodeOnOtherThread) { - m_lazyDecoder->setData(m_data.get(), true); + m_lazyDecoder->setData(*m_data, true); RefPtr<NativeImageSkia> image = m_lazyDecoder->frameBufferAtIndex(0)->asNewNativeImage(); EXPECT_EQ(1, image->bitmap().width()); EXPECT_EQ(1, image->bitmap().height()); EXPECT_FALSE(image->bitmap().isNull()); EXPECT_TRUE(image->bitmap().isImmutable()); - SkCanvas* tempCanvas = m_picture.beginRecording(100, 100); + SkPictureRecorder recorder; + SkCanvas* tempCanvas = recorder.beginRecording(100, 100, 0, 0); tempCanvas->drawBitmap(image->bitmap(), 0, 0); - m_picture.endRecording(); + RefPtr<SkPicture> picture = adoptRef(recorder.endRecording()); EXPECT_EQ(0, m_frameBufferRequestCount); // Create a thread to rasterize SkPicture. OwnPtr<blink::WebThread> thread = adoptPtr(blink::Platform::current()->createThread("RasterThread")); - thread->postTask(new Task(WTF::bind(&rasterizeMain, m_canvas.get(), &m_picture))); + thread->postTask(new Task(WTF::bind(&rasterizeMain, m_canvas.get(), picture.get()))); thread.clear(); EXPECT_EQ(0, m_frameBufferRequestCount); SkBitmap canvasBitmap; - canvasBitmap.setConfig(SkBitmap::kARGB_8888_Config, 100, 100); + ASSERT_TRUE(canvasBitmap.allocN32Pixels(100, 100)); ASSERT_TRUE(m_canvas->readPixels(&canvasBitmap, 0, 0)); SkAutoLockPixels autoLock(canvasBitmap); EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), canvasBitmap.getColor(0, 0)); @@ -238,19 +236,25 @@ TEST_F(DeferredImageDecoderTest, decodeOnOtherThread) TEST_F(DeferredImageDecoderTest, singleFrameImageLoading) { m_status = ImageFrame::FramePartial; - m_lazyDecoder->setData(m_data.get(), false); + m_lazyDecoder->setData(*m_data, false); EXPECT_FALSE(m_lazyDecoder->frameIsCompleteAtIndex(0)); ImageFrame* frame = m_lazyDecoder->frameBufferAtIndex(0); + unsigned firstId = frame->getSkBitmap().getGenerationID(); EXPECT_EQ(ImageFrame::FramePartial, frame->status()); EXPECT_TRUE(m_actualDecoder); m_status = ImageFrame::FrameComplete; - m_lazyDecoder->setData(m_data.get(), true); + m_data->append(" ", 1); + m_lazyDecoder->setData(*m_data, true); EXPECT_FALSE(m_actualDecoder); EXPECT_TRUE(m_lazyDecoder->frameIsCompleteAtIndex(0)); frame = m_lazyDecoder->frameBufferAtIndex(0); + unsigned secondId = frame->getSkBitmap().getGenerationID(); EXPECT_EQ(ImageFrame::FrameComplete, frame->status()); EXPECT_FALSE(m_frameBufferRequestCount); + EXPECT_NE(firstId, secondId); + + EXPECT_EQ(secondId, m_lazyDecoder->frameBufferAtIndex(0)->getSkBitmap().getGenerationID()); } TEST_F(DeferredImageDecoderTest, multiFrameImageLoading) @@ -259,8 +263,9 @@ TEST_F(DeferredImageDecoderTest, multiFrameImageLoading) m_frameCount = 1; m_frameDuration = 10; m_status = ImageFrame::FramePartial; - m_lazyDecoder->setData(m_data.get(), false); + m_lazyDecoder->setData(*m_data, false); EXPECT_EQ(ImageFrame::FramePartial, m_lazyDecoder->frameBufferAtIndex(0)->status()); + unsigned firstId = m_lazyDecoder->frameBufferAtIndex(0)->getSkBitmap().getGenerationID(); EXPECT_FALSE(m_lazyDecoder->frameIsCompleteAtIndex(0)); EXPECT_EQ(10.0f, m_lazyDecoder->frameBufferAtIndex(0)->duration()); EXPECT_EQ(10.0f, m_lazyDecoder->frameDurationAtIndex(0)); @@ -268,9 +273,12 @@ TEST_F(DeferredImageDecoderTest, multiFrameImageLoading) m_frameCount = 2; m_frameDuration = 20; m_status = ImageFrame::FrameComplete; - m_lazyDecoder->setData(m_data.get(), false); + m_data->append(" ", 1); + m_lazyDecoder->setData(*m_data, false); EXPECT_EQ(ImageFrame::FrameComplete, m_lazyDecoder->frameBufferAtIndex(0)->status()); EXPECT_EQ(ImageFrame::FrameComplete, m_lazyDecoder->frameBufferAtIndex(1)->status()); + unsigned secondId = m_lazyDecoder->frameBufferAtIndex(0)->getSkBitmap().getGenerationID(); + EXPECT_NE(firstId, secondId); EXPECT_TRUE(m_lazyDecoder->frameIsCompleteAtIndex(0)); EXPECT_TRUE(m_lazyDecoder->frameIsCompleteAtIndex(1)); EXPECT_EQ(20.0f, m_lazyDecoder->frameDurationAtIndex(1)); @@ -281,11 +289,12 @@ TEST_F(DeferredImageDecoderTest, multiFrameImageLoading) m_frameCount = 3; m_frameDuration = 30; m_status = ImageFrame::FrameComplete; - m_lazyDecoder->setData(m_data.get(), true); + m_lazyDecoder->setData(*m_data, true); EXPECT_FALSE(m_actualDecoder); EXPECT_EQ(ImageFrame::FrameComplete, m_lazyDecoder->frameBufferAtIndex(0)->status()); EXPECT_EQ(ImageFrame::FrameComplete, m_lazyDecoder->frameBufferAtIndex(1)->status()); EXPECT_EQ(ImageFrame::FrameComplete, m_lazyDecoder->frameBufferAtIndex(2)->status()); + EXPECT_EQ(secondId, m_lazyDecoder->frameBufferAtIndex(0)->getSkBitmap().getGenerationID()); EXPECT_TRUE(m_lazyDecoder->frameIsCompleteAtIndex(0)); EXPECT_TRUE(m_lazyDecoder->frameIsCompleteAtIndex(1)); EXPECT_TRUE(m_lazyDecoder->frameIsCompleteAtIndex(2)); @@ -301,7 +310,7 @@ TEST_F(DeferredImageDecoderTest, multiFrameImageLoading) TEST_F(DeferredImageDecoderTest, decodedSize) { m_decodedSize = IntSize(22, 33); - m_lazyDecoder->setData(m_data.get(), true); + m_lazyDecoder->setData(*m_data, true); RefPtr<NativeImageSkia> image = m_lazyDecoder->frameBufferAtIndex(0)->asNewNativeImage(); EXPECT_EQ(m_decodedSize.width(), image->bitmap().width()); EXPECT_EQ(m_decodedSize.height(), image->bitmap().height()); @@ -311,12 +320,26 @@ TEST_F(DeferredImageDecoderTest, decodedSize) useMockImageDecoderFactory(); // The following code should not fail any assert. - SkCanvas* tempCanvas = m_picture.beginRecording(100, 100); + SkPictureRecorder recorder; + SkCanvas* tempCanvas = recorder.beginRecording(100, 100, 0, 0); tempCanvas->drawBitmap(image->bitmap(), 0, 0); - m_picture.endRecording(); + RefPtr<SkPicture> picture = adoptRef(recorder.endRecording()); EXPECT_EQ(0, m_frameBufferRequestCount); - m_canvas->drawPicture(m_picture); + m_canvas->drawPicture(picture.get()); EXPECT_EQ(1, m_frameBufferRequestCount); } +TEST_F(DeferredImageDecoderTest, smallerFrameCount) +{ + m_frameCount = 1; + m_lazyDecoder->setData(*m_data, false); + EXPECT_EQ(m_frameCount, m_lazyDecoder->frameCount()); + m_frameCount = 2; + m_lazyDecoder->setData(*m_data, false); + EXPECT_EQ(m_frameCount, m_lazyDecoder->frameCount()); + m_frameCount = 0; + m_lazyDecoder->setData(*m_data, true); + EXPECT_EQ(m_frameCount, m_lazyDecoder->frameCount()); +} + } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/DiscardablePixelRef.cpp b/chromium/third_party/WebKit/Source/platform/graphics/DiscardablePixelRef.cpp index 1671e701278..2029a32897a 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/DiscardablePixelRef.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/DiscardablePixelRef.cpp @@ -27,7 +27,7 @@ #include "platform/graphics/DiscardablePixelRef.h" #include "public/platform/Platform.h" -#include "wtf/StdLibExtras.h" +#include <string.h> namespace WebCore { @@ -44,16 +44,16 @@ bool DiscardablePixelRefAllocator::allocPixelRef(SkBitmap* dst, SkColorTable* ct // It should not be possible to have a non-null color table in Blink. ASSERT(!ctable); - Sk64 size = dst->getSize64(); - if (size.isNeg() || !size.is32()) + int64_t size = dst->computeSize64(); + if (size < 0 || !sk_64_isS32(size)) return false; - SkImageInfo info; - if (!dst->asImageInfo(&info)) + const SkImageInfo& info = dst->info(); + if (kUnknown_SkColorType == info.colorType()) return false; - SkAutoTUnref<DiscardablePixelRef> pixelRef(new DiscardablePixelRef(info, adoptPtr(new SkMutex()))); - if (pixelRef->allocAndLockDiscardableMemory(size.get32())) { + SkAutoTUnref<DiscardablePixelRef> pixelRef(new DiscardablePixelRef(info, dst->rowBytes(), adoptPtr(new SkMutex()))); + if (pixelRef->allocAndLockDiscardableMemory(sk_64_asS32(size))) { pixelRef->setURI(labelDiscardable); dst->setPixelRef(pixelRef.get()); // This method is only called when a DiscardablePixelRef is created to back a SkBitmap. @@ -68,10 +68,11 @@ bool DiscardablePixelRefAllocator::allocPixelRef(SkBitmap* dst, SkColorTable* ct return dst->allocPixels(); } -DiscardablePixelRef::DiscardablePixelRef(const SkImageInfo& info, PassOwnPtr<SkMutex> mutex) +DiscardablePixelRef::DiscardablePixelRef(const SkImageInfo& info, size_t rowBytes, PassOwnPtr<SkMutex> mutex) : SkPixelRef(info, mutex.get()) , m_lockedMemory(0) , m_mutex(mutex) + , m_rowBytes(rowBytes) { } @@ -89,13 +90,18 @@ bool DiscardablePixelRef::allocAndLockDiscardableMemory(size_t bytes) return false; } -void* DiscardablePixelRef::onLockPixels(SkColorTable** ctable) +bool DiscardablePixelRef::onNewLockPixels(LockRec* rec) { if (!m_lockedMemory && m_discardable->lock()) m_lockedMemory = m_discardable->data(); - *ctable = 0; - return m_lockedMemory; + if (m_lockedMemory) { + rec->fPixels = m_lockedMemory; + rec->fColorTable = 0; + rec->fRowBytes = m_rowBytes; + return true; + } + return false; } void DiscardablePixelRef::onUnlockPixels() @@ -107,10 +113,7 @@ void DiscardablePixelRef::onUnlockPixels() bool DiscardablePixelRef::isDiscardable(SkPixelRef* pixelRef) { - // FIXME: DEFINE_STATIC_LOCAL is not thread safe. - // ImageDecodingStore provides the synchronization for this. - DEFINE_STATIC_LOCAL(const SkString, discardable, (labelDiscardable)); - return pixelRef && pixelRef->getURI() && discardable.equals(pixelRef->getURI()); + return pixelRef && pixelRef->getURI() && !strcmp(pixelRef->getURI(), labelDiscardable); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/DiscardablePixelRef.h b/chromium/third_party/WebKit/Source/platform/graphics/DiscardablePixelRef.h index 5e535576d13..bfed77f1c90 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/DiscardablePixelRef.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/DiscardablePixelRef.h @@ -41,14 +41,14 @@ class PLATFORM_EXPORT DiscardablePixelRefAllocator : public SkBitmap::Allocator // SkBitmap::Allocator implementation. The discardable memory allocated // after this call is locked and will not be purged until next // onUnlockPixels(). - virtual bool allocPixelRef(SkBitmap*, SkColorTable*); + virtual bool allocPixelRef(SkBitmap*, SkColorTable*) OVERRIDE; }; // PixelRef object whose memory can be discarded when pixels are unlocked. class PLATFORM_EXPORT DiscardablePixelRef : public SkPixelRef { public: - DiscardablePixelRef(const SkImageInfo&, PassOwnPtr<SkMutex>); - ~DiscardablePixelRef(); + DiscardablePixelRef(const SkImageInfo&, size_t rowBytes, PassOwnPtr<SkMutex>); + virtual ~DiscardablePixelRef(); static bool isDiscardable(SkPixelRef*); bool allocAndLockDiscardableMemory(size_t); @@ -57,13 +57,14 @@ public: protected: // SkPixelRef implementation. - virtual void* onLockPixels(SkColorTable**); - virtual void onUnlockPixels(); + virtual bool onNewLockPixels(LockRec*) OVERRIDE; + virtual void onUnlockPixels() OVERRIDE; private: void* m_lockedMemory; OwnPtr<blink::WebDiscardableMemory> m_discardable; OwnPtr<SkMutex> m_mutex; + size_t m_rowBytes; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/DisplayList.cpp b/chromium/third_party/WebKit/Source/platform/graphics/DisplayList.cpp index c16d3517cdc..f8fa9ff4eda 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/DisplayList.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/DisplayList.cpp @@ -31,13 +31,15 @@ #include "config.h" #include "platform/graphics/DisplayList.h" +#include "platform/geometry/IntSize.h" #include "third_party/skia/include/core/SkPicture.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" +#include "wtf/PassOwnPtr.h" namespace WebCore { DisplayList::DisplayList(const FloatRect& bounds) : m_bounds(bounds) - , m_picture(adoptRef(new SkPicture())) { } @@ -55,4 +57,20 @@ SkPicture* DisplayList::picture() const return m_picture.get(); } +SkCanvas* DisplayList::beginRecording(const IntSize& size, uint32_t recordFlags) +{ + m_picture.clear(); + if (!m_recorder) + m_recorder = adoptPtr(new SkPictureRecorder); + return m_recorder->beginRecording(size.width(), size.height(), 0, recordFlags); +} + +void DisplayList::endRecording() +{ + if (m_recorder) { + m_picture = adoptRef(m_recorder->endRecording()); + m_recorder.clear(); + } +} + } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/DisplayList.h b/chromium/third_party/WebKit/Source/platform/graphics/DisplayList.h index ca745e5b5ff..e1d050b2b12 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/DisplayList.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/DisplayList.h @@ -37,10 +37,14 @@ #include "wtf/RefCounted.h" #include "wtf/RefPtr.h" +class SkCanvas; class SkPicture; +class SkPictureRecorder; namespace WebCore { +class IntSize; + class PLATFORM_EXPORT DisplayList FINAL : public WTF::RefCounted<DisplayList> { WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(DisplayList); @@ -49,11 +53,21 @@ public: ~DisplayList(); const FloatRect& bounds() const; + + // This entry point will return 0 when the DisplayList is in the + // midst of recording (i.e., between a beginRecording/endRecording pair) + // and if no recording has ever been completed. Otherwise it will return + // the picture created by the last endRecording call. SkPicture* picture() const; + SkCanvas* beginRecording(const IntSize&, uint32_t recordFlags = 0); + bool isRecording() const { return m_recorder; } + void endRecording(); + private: FloatRect m_bounds; RefPtr<SkPicture> m_picture; + OwnPtr<SkPictureRecorder> m_recorder; }; } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/DrawLooper.cpp b/chromium/third_party/WebKit/Source/platform/graphics/DrawLooperBuilder.cpp index 814f5d672c5..fef526e07ca 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/DrawLooper.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/DrawLooperBuilder.cpp @@ -29,7 +29,7 @@ */ #include "config.h" -#include "platform/graphics/DrawLooper.h" +#include "platform/graphics/DrawLooperBuilder.h" #include "platform/geometry/FloatSize.h" #include "platform/graphics/Color.h" @@ -39,37 +39,45 @@ #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkXfermode.h" #include "third_party/skia/include/effects/SkBlurMaskFilter.h" -#include "third_party/skia/include/effects/SkLayerDrawLooper.h" +#include "wtf/RefPtr.h" namespace WebCore { -DrawLooper::DrawLooper() : m_skDrawLooper(adoptRef(new SkLayerDrawLooper)) { } +DrawLooperBuilder::DrawLooperBuilder() { } -DrawLooper::~DrawLooper() { } +DrawLooperBuilder::~DrawLooperBuilder() { } -SkDrawLooper* DrawLooper::skDrawLooper() const +PassOwnPtr<DrawLooperBuilder> DrawLooperBuilder::create() { - return m_skDrawLooper.get(); + return adoptPtr(new DrawLooperBuilder); } -void DrawLooper::addUnmodifiedContent() +PassRefPtr<SkDrawLooper> DrawLooperBuilder::detachDrawLooper() +{ + return adoptRef(m_skDrawLooperBuilder.detachLooper()); +} + +void DrawLooperBuilder::addUnmodifiedContent() { SkLayerDrawLooper::LayerInfo info; - m_skDrawLooper->addLayerOnTop(info); + m_skDrawLooperBuilder.addLayerOnTop(info); +} + +// This replicates the old skia behavior when it used to take radius for blur. Now it takes sigma. +static SkScalar RadiusToSigma(SkScalar radius) +{ + SkASSERT(radius > 0); + return 0.57735f * radius + 0.5f; } -void DrawLooper::addShadow(const FloatSize& offset, float blur, const Color& color, +void DrawLooperBuilder::addShadow(const FloatSize& offset, float blur, const Color& color, ShadowTransformMode shadowTransformMode, ShadowAlphaMode shadowAlphaMode) { // Detect when there's no effective shadow. - if (!color.isValid() || !color.alpha()) + if (!color.alpha()) return; - SkColor skColor; - if (color.isValid()) - skColor = color.rgb(); - else - skColor = SkColorSetARGB(0xFF / 3, 0, 0, 0); // "std" apple shadow color. + SkColor skColor = color.rgb(); SkLayerDrawLooper::LayerInfo info; @@ -90,14 +98,14 @@ void DrawLooper::addShadow(const FloatSize& offset, float blur, const Color& col info.fOffset.set(offset.width(), offset.height()); info.fPostTranslate = (shadowTransformMode == ShadowIgnoresTransforms); - SkPaint* paint = m_skDrawLooper->addLayerOnTop(info); + SkPaint* paint = m_skDrawLooperBuilder.addLayerOnTop(info); if (blur) { + const SkScalar sigma = RadiusToSigma(blur / 2); uint32_t mfFlags = SkBlurMaskFilter::kHighQuality_BlurFlag; if (shadowTransformMode == ShadowIgnoresTransforms) mfFlags |= SkBlurMaskFilter::kIgnoreTransform_BlurFlag; - RefPtr<SkMaskFilter> mf = adoptRef(SkBlurMaskFilter::Create( - (double)blur / 2.0, SkBlurMaskFilter::kNormal_BlurStyle, mfFlags)); + RefPtr<SkMaskFilter> mf = adoptRef(SkBlurMaskFilter::Create(kNormal_SkBlurStyle, sigma, mfFlags)); paint->setMaskFilter(mf.get()); } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/DrawLooper.h b/chromium/third_party/WebKit/Source/platform/graphics/DrawLooperBuilder.h index 4a66910c300..79cce8da67f 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/DrawLooper.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/DrawLooperBuilder.h @@ -28,25 +28,26 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DrawLooper_h -#define DrawLooper_h +#ifndef DrawLooperBuilder_h +#define DrawLooperBuilder_h #include "platform/PlatformExport.h" +#include "third_party/skia/include/effects/SkLayerDrawLooper.h" #include "wtf/Noncopyable.h" -#include "wtf/RefPtr.h" +#include "wtf/PassOwnPtr.h" +#include "wtf/PassRefPtr.h" class SkDrawLooper; -class SkLayerDrawLooper; namespace WebCore { class Color; class FloatSize; -class PLATFORM_EXPORT DrawLooper { +class PLATFORM_EXPORT DrawLooperBuilder FINAL { // Implementing the copy constructor properly would require writing code to - // copy the underlying SkDrawLooper. - WTF_MAKE_NONCOPYABLE(DrawLooper); + // copy the underlying SkLayerDrawLooper::Builder. + WTF_MAKE_NONCOPYABLE(DrawLooperBuilder); public: enum ShadowTransformMode { @@ -58,12 +59,14 @@ public: ShadowIgnoresAlpha }; - DrawLooper(); - ~DrawLooper(); + DrawLooperBuilder(); + ~DrawLooperBuilder(); - // Callees should not modify this looper other than to iterate over it. - // A downcast to SkLayerDrawLooper* is tantamount to a const_cast. - SkDrawLooper* skDrawLooper() const; + static PassOwnPtr<DrawLooperBuilder> create(); + + // Creates the SkDrawLooper and passes ownership to the caller. The builder + // should not be used any more after calling this method. + PassRefPtr<SkDrawLooper> detachDrawLooper(); void addUnmodifiedContent(); void addShadow(const FloatSize& offset, float blur, const Color&, @@ -71,9 +74,9 @@ public: ShadowAlphaMode = ShadowRespectsAlpha); private: - RefPtr<SkLayerDrawLooper> m_skDrawLooper; + SkLayerDrawLooper::Builder m_skDrawLooperBuilder; }; } // namespace WebCore -#endif // DrawLooper_h +#endif // DrawLooperBuilder_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Extensions3D.cpp b/chromium/third_party/WebKit/Source/platform/graphics/Extensions3D.cpp deleted file mode 100644 index 6d0a61e6864..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/Extensions3D.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include "platform/graphics/Extensions3D.h" - -#include "platform/graphics/GraphicsContext3D.h" -#include "public/platform/WebGraphicsContext3D.h" -#include "wtf/text/CString.h" - -namespace WebCore { - -Extensions3D::Extensions3D(GraphicsContext3D* context) - : m_context(context) -{ -} - -Extensions3D::~Extensions3D() -{ -} - -bool Extensions3D::supports(const String& name) -{ - return m_context->supportsExtension(name); -} - -void Extensions3D::ensureEnabled(const String& name) -{ - bool result = m_context->ensureExtensionEnabled(name); - ASSERT_UNUSED(result, result); -} - -bool Extensions3D::isEnabled(const String& name) -{ - return m_context->isExtensionEnabled(name); -} - -int Extensions3D::getGraphicsResetStatusARB() -{ - return static_cast<int>(m_context->webContext()->getGraphicsResetStatusARB()); -} - -void Extensions3D::blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter) -{ - m_context->webContext()->blitFramebufferCHROMIUM(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); -} - -void Extensions3D::renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height) -{ - m_context->webContext()->renderbufferStorageMultisampleCHROMIUM(target, samples, internalformat, width, height); -} - -void* Extensions3D::mapBufferSubDataCHROMIUM(unsigned target, int offset, int size, unsigned access) -{ - return m_context->webContext()->mapBufferSubDataCHROMIUM(target, offset, size, access); -} - -void Extensions3D::unmapBufferSubDataCHROMIUM(const void* data) -{ - m_context->webContext()->unmapBufferSubDataCHROMIUM(data); -} - -void* Extensions3D::mapTexSubImage2DCHROMIUM(unsigned target, int level, int xoffset, int yoffset, int width, int height, unsigned format, unsigned type, unsigned access) -{ - return m_context->webContext()->mapTexSubImage2DCHROMIUM(target, level, xoffset, yoffset, width, height, format, type, access); -} - -void Extensions3D::unmapTexSubImage2DCHROMIUM(const void* data) -{ - m_context->webContext()->unmapTexSubImage2DCHROMIUM(data); -} - -Platform3DObject Extensions3D::createVertexArrayOES() -{ - return m_context->webContext()->createVertexArrayOES(); -} - -void Extensions3D::deleteVertexArrayOES(Platform3DObject array) -{ - m_context->webContext()->deleteVertexArrayOES(array); -} - -GC3Dboolean Extensions3D::isVertexArrayOES(Platform3DObject array) -{ - return m_context->webContext()->isVertexArrayOES(array); -} - -void Extensions3D::bindVertexArrayOES(Platform3DObject array) -{ - m_context->webContext()->bindVertexArrayOES(array); -} - -String Extensions3D::getTranslatedShaderSourceANGLE(Platform3DObject shader) -{ - return m_context->webContext()->getTranslatedShaderSourceANGLE(shader); -} - -void Extensions3D::rateLimitOffscreenContextCHROMIUM() -{ - m_context->webContext()->rateLimitOffscreenContextCHROMIUM(); -} - -void Extensions3D::paintFramebufferToCanvas(int framebuffer, int width, int height, bool premultiplyAlpha, ImageBuffer* imageBuffer) -{ - m_context->paintFramebufferToCanvas(framebuffer, width, height, premultiplyAlpha, imageBuffer); -} - -void Extensions3D::texImageIOSurface2DCHROMIUM(unsigned target, int width, int height, uint32_t ioSurfaceId, unsigned plane) -{ - m_context->webContext()->texImageIOSurface2DCHROMIUM(target, width, height, ioSurfaceId, plane); -} - -void Extensions3D::texStorage2DEXT(unsigned int target, int levels, unsigned int internalFormat, int width, int height) -{ - m_context->webContext()->texStorage2DEXT(target, levels, internalFormat, width, height); -} - -Platform3DObject Extensions3D::createQueryEXT() -{ - return m_context->webContext()->createQueryEXT(); -} - -void Extensions3D::deleteQueryEXT(Platform3DObject query) -{ - m_context->webContext()->deleteQueryEXT(query); -} - -GC3Dboolean Extensions3D::isQueryEXT(Platform3DObject query) -{ - return m_context->webContext()->isQueryEXT(query); -} - -void Extensions3D::beginQueryEXT(GC3Denum target, Platform3DObject query) -{ - m_context->webContext()->beginQueryEXT(target, query); -} - -void Extensions3D::endQueryEXT(GC3Denum target) -{ - m_context->webContext()->endQueryEXT(target); -} - -void Extensions3D::getQueryivEXT(GC3Denum target, GC3Denum pname, GC3Dint* params) -{ - m_context->webContext()->getQueryivEXT(target, pname, params); -} - -void Extensions3D::getQueryObjectuivEXT(Platform3DObject query, GC3Denum pname, GC3Duint* params) -{ - m_context->webContext()->getQueryObjectuivEXT(query, pname, params); -} - -bool Extensions3D::canUseCopyTextureCHROMIUM(GC3Denum destFormat, GC3Denum destType, GC3Dint level) -{ - // FIXME: restriction of (RGB || RGBA)/UNSIGNED_BYTE/(Level 0) should be lifted when - // WebGraphicsContext3D::copyTextureCHROMIUM(...) are fully functional. - if ((destFormat == GL_RGB || destFormat == GL_RGBA) - && destType == GL_UNSIGNED_BYTE - && !level) - return true; - return false; -} - -void Extensions3D::copyTextureCHROMIUM(GC3Denum target, Platform3DObject sourceId, Platform3DObject destId, GC3Dint level, GC3Denum internalFormat, GC3Denum destType) -{ - m_context->webContext()->copyTextureCHROMIUM(target, sourceId, destId, level, internalFormat, destType); -} - -void Extensions3D::shallowFlushCHROMIUM() -{ - return m_context->webContext()->shallowFlushCHROMIUM(); -} - -void Extensions3D::insertEventMarkerEXT(const String& marker) -{ - m_context->webContext()->insertEventMarkerEXT(marker.utf8().data()); -} - -void Extensions3D::pushGroupMarkerEXT(const String& marker) -{ - m_context->webContext()->pushGroupMarkerEXT(marker.utf8().data()); -} - -void Extensions3D::popGroupMarkerEXT(void) -{ - m_context->webContext()->popGroupMarkerEXT(); -} - -void Extensions3D::drawBuffersEXT(GC3Dsizei n, const GC3Denum* bufs) -{ - m_context->webContext()->drawBuffersEXT(n, bufs); -} - -void Extensions3D::drawArraysInstancedANGLE(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount) -{ - m_context->webContext()->drawArraysInstancedANGLE(mode, first, count, primcount); -} - -void Extensions3D::drawElementsInstancedANGLE(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, GC3Dsizei primcount) -{ - m_context->webContext()->drawElementsInstancedANGLE(mode, count, type, offset, primcount); -} - -void Extensions3D::vertexAttribDivisorANGLE(GC3Duint index, GC3Duint divisor) -{ - m_context->webContext()->vertexAttribDivisorANGLE(index, divisor); -} - -void Extensions3D::loseContextCHROMIUM(GC3Denum current, GC3Denum other) -{ - m_context->webContext()->loseContextCHROMIUM(current, other); -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Extensions3D.h b/chromium/third_party/WebKit/Source/platform/graphics/Extensions3D.h deleted file mode 100644 index 4fd8bae351c..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/Extensions3D.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef Extensions3D_h -#define Extensions3D_h - -#include "platform/PlatformExport.h" -#include "platform/graphics/GraphicsTypes3D.h" - -#include "wtf/text/WTFString.h" - -namespace WebCore { - -class GraphicsContext3D; -class ImageBuffer; - -// The supported extensions are defined below. -// -// Calling any extension function not supported by the current context -// must be a no-op; in particular, it may not have side effects. In -// this situation, if the function has a return value, 0 is returned. -class PLATFORM_EXPORT Extensions3D { -public: - ~Extensions3D(); - - // Supported extensions: - // GL_EXT_texture_format_BGRA8888 - // GL_EXT_read_format_bgra - // GL_ARB_robustness - // GL_ARB_texture_non_power_of_two / GL_OES_texture_npot - // GL_EXT_packed_depth_stencil / GL_OES_packed_depth_stencil - // GL_ANGLE_framebuffer_blit / GL_ANGLE_framebuffer_multisample - // GL_OES_texture_float - // GL_OES_texture_float_linear - // GL_OES_texture_half_float - // GL_OES_texture_half_float_linear - // GL_OES_standard_derivatives - // GL_OES_rgb8_rgba8 - // GL_OES_vertex_array_object - // GL_OES_element_index_uint - // GL_ANGLE_translated_shader_source - // GL_ARB_texture_rectangle (only the subset required to - // implement IOSurface binding; it's recommended to support - // this only on Mac OS X to limit the amount of code dependent - // on this extension) - // GL_EXT_texture_compression_dxt1 - // GL_EXT_texture_compression_s3tc - // GL_OES_compressed_ETC1_RGB8_texture - // GL_IMG_texture_compression_pvrtc - // EXT_texture_filter_anisotropic - // GL_EXT_debug_marker - // GL_CHROMIUM_copy_texture - // GL_CHROMIUM_flipy - // GL_ARB_draw_buffers / GL_EXT_draw_buffers - // GL_ANGLE_instanced_arrays - - // GL_CHROMIUM_shallow_flush : only supported if an ipc command buffer is used. - // GL_CHROMIUM_resource_safe : indicating that textures/renderbuffers are always initialized before read/write. - // GL_CHROMIUM_strict_attribs : indicating a GL error is generated for out-of-bounds buffer accesses. - // GL_CHROMIUM_post_sub_buffer - // GL_CHROMIUM_map_sub - // GL_CHROMIUM_swapbuffers_complete_callback - // GL_CHROMIUM_rate_limit_offscreen_context - // GL_CHROMIUM_paint_framebuffer_canvas - // GL_CHROMIUM_iosurface (Mac OS X specific) - // GL_CHROMIUM_command_buffer_query - // GL_ANGLE_texture_usage - // GL_EXT_debug_marker - // GL_EXT_texture_storage - // GL_EXT_occlusion_query_boolean - - // Takes full name of extension; for example, - // "GL_EXT_texture_format_BGRA8888". - bool supports(const String&); - - // Certain OpenGL and WebGL implementations may support enabling - // extensions lazily. This method may only be called with - // extension names for which supports returns true. - void ensureEnabled(const String&); - - // Takes full name of extension: for example, "GL_EXT_texture_format_BGRA8888". - // Checks to see whether the given extension is actually enabled (see ensureEnabled). - // Has no other side-effects. - bool isEnabled(const String&); - - enum ExtensionsEnumType { - // GL_EXT_texture_format_BGRA8888 enums - BGRA_EXT = 0x80E1, - - // GL_ARB_robustness/GL_CHROMIUM_lose_context enums - GUILTY_CONTEXT_RESET_ARB = 0x8253, - INNOCENT_CONTEXT_RESET_ARB = 0x8254, - UNKNOWN_CONTEXT_RESET_ARB = 0x8255, - - // GL_EXT/OES_packed_depth_stencil enums - DEPTH24_STENCIL8 = 0x88F0, - - // GL_ANGLE_framebuffer_blit names - READ_FRAMEBUFFER = 0x8CA8, - DRAW_FRAMEBUFFER = 0x8CA9, - DRAW_FRAMEBUFFER_BINDING = 0x8CA6, - READ_FRAMEBUFFER_BINDING = 0x8CAA, - - // GL_ANGLE_framebuffer_multisample names - RENDERBUFFER_SAMPLES = 0x8CAB, - FRAMEBUFFER_INCOMPLETE_MULTISAMPLE = 0x8D56, - MAX_SAMPLES = 0x8D57, - - // GL_OES_standard_derivatives names - FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B, - - // GL_OES_rgb8_rgba8 names - RGB8_OES = 0x8051, - RGBA8_OES = 0x8058, - - // GL_OES_vertex_array_object names - VERTEX_ARRAY_BINDING_OES = 0x85B5, - - // GL_ANGLE_translated_shader_source - TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE = 0x93A0, - - // GL_ARB_texture_rectangle - TEXTURE_RECTANGLE_ARB = 0x84F5, - TEXTURE_BINDING_RECTANGLE_ARB = 0x84F6, - - // GL_EXT_texture_compression_dxt1 - // GL_EXT_texture_compression_s3tc - COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0, - COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1, - COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2, - COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3, - - // GL_OES_compressed_ETC1_RGB8_texture - ETC1_RGB8_OES = 0x8D64, - - // GL_IMG_texture_compression_pvrtc - COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00, - COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01, - COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02, - COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03, - - // GL_AMD_compressed_ATC_texture - COMPRESSED_ATC_RGB_AMD = 0x8C92, - COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD = 0x8C93, - COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD = 0x87EE, - - // GL_EXT_texture_filter_anisotropic - TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE, - MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF, - - // GL_CHROMIUM_flipy - UNPACK_FLIP_Y_CHROMIUM = 0x9240, - - // GL_CHROMIUM_copy_texture - UNPACK_PREMULTIPLY_ALPHA_CHROMIUM = 0x9241, - UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM = 0x9242, - - // GL_ARB_draw_buffers / GL_EXT_draw_buffers - MAX_DRAW_BUFFERS_EXT = 0x8824, - DRAW_BUFFER0_EXT = 0x8825, - DRAW_BUFFER1_EXT = 0x8826, - DRAW_BUFFER2_EXT = 0x8827, - DRAW_BUFFER3_EXT = 0x8828, - DRAW_BUFFER4_EXT = 0x8829, - DRAW_BUFFER5_EXT = 0x882A, - DRAW_BUFFER6_EXT = 0x882B, - DRAW_BUFFER7_EXT = 0x882C, - DRAW_BUFFER8_EXT = 0x882D, - DRAW_BUFFER9_EXT = 0x882E, - DRAW_BUFFER10_EXT = 0x882F, - DRAW_BUFFER11_EXT = 0x8830, - DRAW_BUFFER12_EXT = 0x8831, - DRAW_BUFFER13_EXT = 0x8832, - DRAW_BUFFER14_EXT = 0x8833, - DRAW_BUFFER15_EXT = 0x8834, - MAX_COLOR_ATTACHMENTS_EXT = 0x8CDF, - COLOR_ATTACHMENT0_EXT = 0x8CE0, - COLOR_ATTACHMENT1_EXT = 0x8CE1, - COLOR_ATTACHMENT2_EXT = 0x8CE2, - COLOR_ATTACHMENT3_EXT = 0x8CE3, - COLOR_ATTACHMENT4_EXT = 0x8CE4, - COLOR_ATTACHMENT5_EXT = 0x8CE5, - COLOR_ATTACHMENT6_EXT = 0x8CE6, - COLOR_ATTACHMENT7_EXT = 0x8CE7, - COLOR_ATTACHMENT8_EXT = 0x8CE8, - COLOR_ATTACHMENT9_EXT = 0x8CE9, - COLOR_ATTACHMENT10_EXT = 0x8CEA, - COLOR_ATTACHMENT11_EXT = 0x8CEB, - COLOR_ATTACHMENT12_EXT = 0x8CEC, - COLOR_ATTACHMENT13_EXT = 0x8CED, - COLOR_ATTACHMENT14_EXT = 0x8CEE, - COLOR_ATTACHMENT15_EXT = 0x8CEF, - - // GL_CHROMIUM_map_sub (enums inherited from GL_ARB_vertex_buffer_object) - READ_ONLY = 0x88B8, - WRITE_ONLY = 0x88B9, - - // GL_EXT_texture_storage - BGRA8_EXT = 0x93A1, - - // GL_EXT_occlusion_query_boolean - ANY_SAMPLES_PASSED_EXT = 0x8C2F, - ANY_SAMPLES_PASSED_CONSERVATIVE_EXT = 0x8D6A, - CURRENT_QUERY_EXT = 0x8865, - QUERY_RESULT_EXT = 0x8866, - QUERY_RESULT_AVAILABLE_EXT = 0x8867, - - // GL_CHROMIUM_command_buffer_query - COMMANDS_ISSUED_CHROMIUM = 0x84F2, - - // GL_ANGLE_instanced_arrays - VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE - }; - - // GL_ARB_robustness - // Note: This method's behavior differs from the GL_ARB_robustness - // specification in the following way: - // The implementation must not reset the error state during this call. - // If getGraphicsResetStatusARB returns an error, it should continue - // returning the same error. Restoring the GraphicsContext3D is handled - // externally. - int getGraphicsResetStatusARB(); - - // GL_ANGLE_framebuffer_blit - void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter); - - // GL_ANGLE_framebuffer_multisample - void renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height); - - // GL_OES_vertex_array_object - Platform3DObject createVertexArrayOES(); - void deleteVertexArrayOES(Platform3DObject); - GC3Dboolean isVertexArrayOES(Platform3DObject); - void bindVertexArrayOES(Platform3DObject); - - // GL_ANGLE_translated_shader_source - String getTranslatedShaderSourceANGLE(Platform3DObject); - - // GL_CHROMIUM_copy_texture - // canUseCopyTextureCHROMIUM(...) is used to check if copyTextureCHROMIUM(...) can work for the specified - // format, type and level for the destination texture. - bool canUseCopyTextureCHROMIUM(GC3Denum destFormat, GC3Denum destType, GC3Dint level); - void copyTextureCHROMIUM(GC3Denum, Platform3DObject, Platform3DObject, GC3Dint, GC3Denum, GC3Denum); - - // GL_EXT_debug_marker - void insertEventMarkerEXT(const String&); - void pushGroupMarkerEXT(const String&); - void popGroupMarkerEXT(void); - - // GL_ARB_draw_buffers / GL_EXT_draw_buffers - void drawBuffersEXT(GC3Dsizei n, const GC3Denum* bufs); - - // GL_CHROMIUM_map_sub - void* mapBufferSubDataCHROMIUM(unsigned target, int offset, int size, unsigned access); - void unmapBufferSubDataCHROMIUM(const void*); - void* mapTexSubImage2DCHROMIUM(unsigned target, int level, int xoffset, int yoffset, int width, int height, unsigned format, unsigned type, unsigned access); - void unmapTexSubImage2DCHROMIUM(const void*); - - // GL_CHROMIUM_rate_limit_offscreen_context - void rateLimitOffscreenContextCHROMIUM(); - - // GL_CHROMIUM_paint_framebuffer_canvas - void paintFramebufferToCanvas(int framebuffer, int width, int height, bool premultiplyAlpha, ImageBuffer*); - - // GL_CHROMIUM_iosurface - // To avoid needing to expose extraneous enums, assumes internal format - // RGBA, format BGRA, and type UNSIGNED_INT_8_8_8_8_REV. - void texImageIOSurface2DCHROMIUM(unsigned target, int width, int height, uint32_t ioSurfaceId, unsigned plane); - - // GL_EXT_texture_storage - void texStorage2DEXT(unsigned target, int levels, unsigned internalformat, int width, int height); - - // GL_EXT_occlusion_query - Platform3DObject createQueryEXT(); - void deleteQueryEXT(Platform3DObject); - GC3Dboolean isQueryEXT(Platform3DObject); - void beginQueryEXT(GC3Denum, Platform3DObject); - void endQueryEXT(GC3Denum); - void getQueryivEXT(GC3Denum, GC3Denum, GC3Dint*); - void getQueryObjectuivEXT(Platform3DObject, GC3Denum, GC3Duint*); - - // GL_CHROMIUM_shallow_flush - void shallowFlushCHROMIUM(); - - // GL_ANGLE_instanced_arrays - void drawArraysInstancedANGLE(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount); - void drawElementsInstancedANGLE(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, GC3Dsizei primcount); - void vertexAttribDivisorANGLE(GC3Duint index, GC3Duint divisor); - - // GL_CHROMIUM_lose_context - void loseContextCHROMIUM(GC3Denum, GC3Denum); - -private: - // Instances of this class are strictly owned by the GraphicsContext3D implementation and do not - // need to be instantiated by any other code. - friend class GraphicsContext3D; - explicit Extensions3D(GraphicsContext3D*); - - // Weak pointer back to GraphicsContext3D. - GraphicsContext3D* m_context; -}; - -} // namespace WebCore - -#endif // Extensions3D_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/FrameData.cpp b/chromium/third_party/WebKit/Source/platform/graphics/FrameData.cpp index cdbae1ff0cf..3e1c9d26449 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/FrameData.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/FrameData.cpp @@ -32,7 +32,7 @@ namespace WebCore { FrameData::FrameData() - : m_frame(0) + : m_frame(nullptr) , m_orientation(DefaultImageOrientation) , m_duration(0) , m_haveMetadata(false) diff --git a/chromium/third_party/WebKit/Source/platform/graphics/FrameData.h b/chromium/third_party/WebKit/Source/platform/graphics/FrameData.h index f27857f468c..740eec3ea72 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/FrameData.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/FrameData.h @@ -34,16 +34,6 @@ #include "wtf/VectorTraits.h" namespace WebCore { -struct FrameData; -} - -namespace WTF { -template<> struct VectorTraits<WebCore::FrameData> : public SimpleClassVectorTraits { - static const bool canInitializeWithMemset = false; // Not all FrameData members initialize to 0. -}; -} - -namespace WebCore { class NativeImageSkia; @@ -68,4 +58,10 @@ public: } // namespace WebCore +namespace WTF { +template<> struct VectorTraits<WebCore::FrameData> : public SimpleClassVectorTraits<WebCore::FrameData> { + static const bool canInitializeWithMemset = false; // Not all FrameData members initialize to 0. +}; +} + #endif // FrameData_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Gradient.cpp b/chromium/third_party/WebKit/Source/platform/graphics/Gradient.cpp index f81ad11061a..91c4f47f4cb 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/Gradient.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/Gradient.cpp @@ -29,38 +29,41 @@ #include "platform/graphics/Gradient.h" #include "platform/geometry/FloatRect.h" -#include "platform/graphics/Color.h" #include "platform/graphics/GraphicsContext.h" #include "platform/graphics/skia/SkiaUtils.h" +#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColorShader.h" #include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/effects/SkGradientShader.h" +typedef Vector<SkScalar, 8> ColorStopOffsetVector; +typedef Vector<SkColor, 8> ColorStopColorVector; + namespace WebCore { Gradient::Gradient(const FloatPoint& p0, const FloatPoint& p1) - : m_radial(false) - , m_p0(p0) + : m_p0(p0) , m_p1(p1) , m_r0(0) , m_r1(0) , m_aspectRatio(1) + , m_radial(false) , m_stopsSorted(false) - , m_spreadMethod(SpreadMethodPad) , m_drawInPMColorSpace(false) + , m_spreadMethod(SpreadMethodPad) { } Gradient::Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1, float aspectRatio) - : m_radial(true) - , m_p0(p0) + : m_p0(p0) , m_p1(p1) , m_r0(r0) , m_r1(r1) , m_aspectRatio(aspectRatio) + , m_radial(true) , m_stopsSorted(false) - , m_spreadMethod(SpreadMethodPad) , m_drawInPMColorSpace(false) + , m_spreadMethod(SpreadMethodPad) { } @@ -68,32 +71,23 @@ Gradient::~Gradient() { } -void Gradient::addColorStop(float value, const Color& color) +static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b) { - float r; - float g; - float b; - float a; - color.getRGBA(r, g, b, a); - m_stops.append(ColorStop(value, r, g, b, a)); - - m_stopsSorted = false; - m_gradient.clear(); + return a.stop < b.stop; } void Gradient::addColorStop(const Gradient::ColorStop& stop) { - m_stops.append(stop); + if (m_stops.isEmpty()) { + m_stopsSorted = true; + } else { + m_stopsSorted = m_stopsSorted && compareStops(m_stops.last(), stop); + } - m_stopsSorted = false; + m_stops.append(stop); m_gradient.clear(); } -static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b) -{ - return a.stop < b.stop; -} - void Gradient::sortStopsIfNecessary() { if (m_stopsSorted) @@ -110,7 +104,7 @@ void Gradient::sortStopsIfNecessary() bool Gradient::hasAlpha() const { for (size_t i = 0; i < m_stops.size(); i++) { - if (m_stops[i].alpha < 1) + if (m_stops[i].color.hasAlpha()) return true; } @@ -143,18 +137,7 @@ void Gradient::setGradientSpaceTransform(const AffineTransform& gradientSpaceTra return; m_gradientSpaceTransformation = gradientSpaceTransformation; - if (m_gradient) - m_gradient->setLocalMatrix(affineTransformToSkMatrix(m_gradientSpaceTransformation)); -} - -static inline U8CPU F2B(float x) -{ - return static_cast<int>(x * 255); -} - -static SkColor makeSkColor(float a, float r, float g, float b) -{ - return SkColorSetARGB(F2B(a), F2B(r), F2B(g), F2B(b)); + m_gradient.clear(); } // Determine the total number of stops needed, including pseudo-stops at the @@ -173,19 +156,25 @@ static size_t totalStopsNeeded(const Gradient::ColorStop* stopData, size_t count return countUsed; } +// FIXME: This would be more at home as Color::operator SkColor. +static inline SkColor makeSkColor(const Color& c) +{ + return SkColorSetARGB(c.alpha(), c.red(), c.green(), c.blue()); +} + // Collect sorted stop position and color information into the pos and colors // buffers, ensuring stops at both 0.0 and 1.0. The buffers must be large // enough to hold information for all stops, including the new endpoints if // stops at 0.0 and 1.0 aren't already included. static void fillStops(const Gradient::ColorStop* stopData, - size_t count, SkScalar* pos, SkColor* colors) + size_t count, ColorStopOffsetVector& pos, ColorStopColorVector& colors) { const Gradient::ColorStop* stop = stopData; size_t start = 0; if (count < 1) { // A gradient with no stops must be transparent black. pos[0] = WebCoreFloatToSkScalar(0.0); - colors[0] = makeSkColor(0.0, 0.0, 0.0, 0.0); + colors[0] = SK_ColorTRANSPARENT; start = 1; } else if (stop->stop > 0.0) { // Copy the first stop to 0.0. The first stop position may have a slight @@ -193,13 +182,13 @@ static void fillStops(const Gradient::ColorStop* stopData, // 0.0 comes through cleanly and people aren't likely to want a gradient // with a stop at (0 + epsilon). pos[0] = WebCoreFloatToSkScalar(0.0); - colors[0] = makeSkColor(stop->alpha, stop->red, stop->green, stop->blue); + colors[0] = makeSkColor(stop->color); start = 1; } for (size_t i = start; i < start + count; i++) { pos[i] = WebCoreFloatToSkScalar(stop->stop); - colors[i] = makeSkColor(stop->alpha, stop->red, stop->green, stop->blue); + colors[i] = makeSkColor(stop->color); ++stop; } @@ -223,11 +212,8 @@ SkShader* Gradient::shader() ASSERT(countUsed >= 2); ASSERT(countUsed >= m_stops.size()); - // FIXME: Why is all this manual pointer math needed?! - SkAutoMalloc storage(countUsed * (sizeof(SkColor) + sizeof(SkScalar))); - SkColor* colors = (SkColor*)storage.get(); - SkScalar* pos = (SkScalar*)(colors + countUsed); - + ColorStopOffsetVector pos(countUsed); + ColorStopColorVector colors(countUsed); fillStops(m_stops.data(), m_stops.size(), pos, colors); SkShader::TileMode tile = SkShader::kClamp_TileMode; @@ -245,36 +231,36 @@ SkShader* Gradient::shader() uint32_t shouldDrawInPMColorSpace = m_drawInPMColorSpace ? SkGradientShader::kInterpolateColorsInPremul_Flag : 0; if (m_radial) { + if (aspectRatio() != 1) { + // CSS3 elliptical gradients: apply the elliptical scaling at the + // gradient center point. + m_gradientSpaceTransformation.translate(m_p0.x(), m_p0.y()); + m_gradientSpaceTransformation.scale(1, 1 / aspectRatio()); + m_gradientSpaceTransformation.translate(-m_p0.x(), -m_p0.y()); + ASSERT(m_p0 == m_p1); + } + SkMatrix localMatrix = affineTransformToSkMatrix(m_gradientSpaceTransformation); + // Since the two-point radial gradient is slower than the plain radial, // only use it if we have to. if (m_p0 == m_p1 && m_r0 <= 0.0f) { - m_gradient = adoptRef(SkGradientShader::CreateRadial(m_p1, m_r1, colors, pos, static_cast<int>(countUsed), tile, 0, shouldDrawInPMColorSpace)); + m_gradient = adoptRef(SkGradientShader::CreateRadial(m_p1.data(), m_r1, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix)); } else { // The radii we give to Skia must be positive. If we're given a // negative radius, ask for zero instead. SkScalar radius0 = m_r0 >= 0.0f ? WebCoreFloatToSkScalar(m_r0) : 0; SkScalar radius1 = m_r1 >= 0.0f ? WebCoreFloatToSkScalar(m_r1) : 0; - m_gradient = adoptRef(SkGradientShader::CreateTwoPointConical(m_p0, radius0, m_p1, radius1, colors, pos, static_cast<int>(countUsed), tile, 0, shouldDrawInPMColorSpace)); - } - - if (aspectRatio() != 1) { - // CSS3 elliptical gradients: apply the elliptical scaling at the - // gradient center point. - m_gradientSpaceTransformation.translate(m_p0.x(), m_p0.y()); - m_gradientSpaceTransformation.scale(1, 1 / aspectRatio()); - m_gradientSpaceTransformation.translate(-m_p0.x(), -m_p0.y()); - ASSERT(m_p0 == m_p1); + m_gradient = adoptRef(SkGradientShader::CreateTwoPointConical(m_p0.data(), radius0, m_p1.data(), radius1, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix)); } } else { - SkPoint pts[2] = { m_p0, m_p1 }; - m_gradient = adoptRef(SkGradientShader::CreateLinear(pts, colors, pos, static_cast<int>(countUsed), tile, 0, shouldDrawInPMColorSpace)); + SkPoint pts[2] = { m_p0.data(), m_p1.data() }; + SkMatrix localMatrix = affineTransformToSkMatrix(m_gradientSpaceTransformation); + m_gradient = adoptRef(SkGradientShader::CreateLinear(pts, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix)); } if (!m_gradient) { // use last color, since our "geometry" was degenerate (e.g. radius==0) m_gradient = adoptRef(new SkColorShader(colors[countUsed - 1])); - } else { - m_gradient->setLocalMatrix(affineTransformToSkMatrix(m_gradientSpaceTransformation)); } return m_gradient.get(); } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Gradient.h b/chromium/third_party/WebKit/Source/platform/graphics/Gradient.h index 0fa5814555f..ff48b9f9a2e 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/Gradient.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/Gradient.h @@ -31,6 +31,7 @@ #include "platform/PlatformExport.h" #include "platform/geometry/FloatPoint.h" +#include "platform/graphics/Color.h" #include "platform/graphics/GraphicsTypes.h" #include "platform/transforms/AffineTransform.h" #include "wtf/PassRefPtr.h" @@ -42,7 +43,6 @@ class SkShader; namespace WebCore { -class Color; class FloatRect; class IntSize; @@ -60,18 +60,15 @@ public: struct ColorStop { float stop; - float red; - float green; - float blue; - float alpha; + Color color; - ColorStop() : stop(0), red(0), green(0), blue(0), alpha(0) { } - ColorStop(float s, float r, float g, float b, float a) : stop(s), red(r), green(g), blue(b), alpha(a) { } + ColorStop(float s, const Color& c) : stop(s), color(c) { } }; void addColorStop(const ColorStop&); - void addColorStop(float, const Color&); + void addColorStop(float value, const Color& color) { addColorStop(ColorStop(value, color)); } bool hasAlpha() const; + bool shaderChanged() const { return !m_gradient; } bool isRadial() const { return m_radial; } bool isZeroSize() const { return m_p0.x() == m_p1.x() && m_p0.y() == m_p1.y() && (!m_radial || m_r0 == m_r1); } @@ -118,8 +115,6 @@ public: SkShader* shader(); - void setStopsSorted(bool s) { m_stopsSorted = s; } - void setDrawsInPMColorSpace(bool drawInPMColorSpace); void setSpreadMethod(GradientSpreadMethod); @@ -135,20 +130,18 @@ private: void sortStopsIfNecessary(); - // Keep any parameters relevant to rendering in sync with the structure in Gradient::hash(). - bool m_radial; FloatPoint m_p0; FloatPoint m_p1; float m_r0; float m_r1; float m_aspectRatio; // For elliptical gradient, width / height. - mutable Vector<ColorStop, 2> m_stops; - mutable bool m_stopsSorted; + Vector<ColorStop, 2> m_stops; + bool m_radial; + bool m_stopsSorted; + bool m_drawInPMColorSpace; GradientSpreadMethod m_spreadMethod; AffineTransform m_gradientSpaceTransformation; - bool m_drawInPMColorSpace; - RefPtr<SkShader> m_gradient; }; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.cpp b/chromium/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.cpp index 90eabf6658f..772612b029e 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.cpp @@ -38,7 +38,7 @@ void GradientGeneratedImage::draw(GraphicsContext* destContext, const FloatRect& destContext->clip(destRect); destContext->translate(destRect.x(), destRect.y()); if (destRect.size() != srcRect.size()) - destContext->scale(FloatSize(destRect.width() / srcRect.width(), destRect.height() / srcRect.height())); + destContext->scale(destRect.width() / srcRect.width(), destRect.height() / srcRect.height()); destContext->translate(-srcRect.x(), -srcRect.y()); destContext->setFillGradient(m_gradient); destContext->fillRect(FloatRect(FloatPoint(), m_size)); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp index 251011bc443..9b479b7a2ba 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp @@ -27,6 +27,7 @@ #include "config.h" #include "platform/graphics/GraphicsContext.h" +#include "platform/TraceEvent.h" #include "platform/geometry/IntRect.h" #include "platform/geometry/RoundedRect.h" #include "platform/graphics/BitmapImage.h" @@ -39,9 +40,11 @@ #include "third_party/skia/include/core/SkAnnotation.h" #include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkData.h" +#include "third_party/skia/include/core/SkDevice.h" #include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkRRect.h" #include "third_party/skia/include/core/SkRefCnt.h" +#include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/effects/SkBlurMaskFilter.h" #include "third_party/skia/include/effects/SkCornerPathEffect.h" #include "third_party/skia/include/effects/SkLumaColorFilter.h" @@ -50,10 +53,6 @@ #include "wtf/Assertions.h" #include "wtf/MathExtras.h" -#if OS(MACOSX) -#include <ApplicationServices/ApplicationServices.h> -#endif - using namespace std; using blink::WebBlendMode; @@ -64,20 +63,20 @@ namespace { class CompatibleImageBufferSurface : public ImageBufferSurface { WTF_MAKE_NONCOPYABLE(CompatibleImageBufferSurface); WTF_MAKE_FAST_ALLOCATED; public: - CompatibleImageBufferSurface(PassRefPtr<SkBaseDevice> device, const IntSize& size, OpacityMode opacityMode) + CompatibleImageBufferSurface(PassRefPtr<SkSurface> surface, const IntSize& size, OpacityMode opacityMode) : ImageBufferSurface(size, opacityMode) + , m_surface(surface) { - m_canvas = adoptPtr(new SkCanvas(device.get())); // Takes a ref on device } virtual ~CompatibleImageBufferSurface() { } - virtual SkCanvas* canvas() const OVERRIDE { return m_canvas.get(); } - virtual bool isValid() const OVERRIDE { return m_canvas; } - virtual bool isAccelerated() const OVERRIDE { return isValid() && m_canvas->getTopDevice()->accessRenderTarget(); } + virtual SkCanvas* canvas() const OVERRIDE { return m_surface ? m_surface->getCanvas() : 0; } + virtual bool isValid() const OVERRIDE { return m_surface; } + virtual bool isAccelerated() const OVERRIDE { return isValid() && m_surface->getCanvas()->getTopDevice()->accessRenderTarget(); } virtual Platform3DObject getBackingTexture() const OVERRIDE { ASSERT(isAccelerated()); - GrRenderTarget* renderTarget = m_canvas->getTopDevice()->accessRenderTarget(); + GrRenderTarget* renderTarget = m_surface->getCanvas()->getTopDevice()->accessRenderTarget(); if (renderTarget) { return renderTarget->asTexture()->getTextureHandle(); } @@ -85,15 +84,16 @@ public: }; private: - OwnPtr<SkCanvas> m_canvas; + RefPtr<SkSurface> m_surface; }; } // unnamed namespace -struct GraphicsContext::DeferredSaveState { - DeferredSaveState(unsigned mask, int count) : m_flags(mask), m_restoreCount(count) { } +struct GraphicsContext::CanvasSaveState { + CanvasSaveState(bool pendingSave, int count) + : m_pendingSave(pendingSave), m_restoreCount(count) { } - unsigned m_flags; + bool m_pendingSave; int m_restoreCount; }; @@ -110,14 +110,18 @@ struct GraphicsContext::RecordingState { const SkMatrix m_savedMatrix; }; -GraphicsContext::GraphicsContext(SkCanvas* canvas) +GraphicsContext::GraphicsContext(SkCanvas* canvas, DisabledMode disableContextOrPainting) : m_canvas(canvas) - , m_deferredSaveFlags(0) + , m_paintStateStack() + , m_paintStateIndex(0) + , m_pendingCanvasSave(false) , m_annotationMode(0) -#if !ASSERT_DISABLED +#if ASSERT_ENABLED , m_annotationCount(0) , m_layerCount(0) + , m_disableDestructionChecks(false) #endif + , m_disabledState(disableContextOrPainting) , m_trackOpaqueRegion(false) , m_trackTextRegion(false) , m_useHighResMarker(false) @@ -125,78 +129,80 @@ GraphicsContext::GraphicsContext(SkCanvas* canvas) , m_accelerated(false) , m_isCertainlyOpaque(true) , m_printing(false) + , m_antialiasHairlineImages(false) { - m_stateStack.append(adoptPtr(new GraphicsContextState())); - m_state = m_stateStack.last().get(); -} + if (!canvas) + m_disabledState |= PaintingDisabled; -GraphicsContext::~GraphicsContext() -{ - ASSERT(m_stateStack.size() == 1); - ASSERT(!m_annotationCount); - ASSERT(!m_layerCount); - ASSERT(m_recordingStateStack.isEmpty()); + // FIXME: Do some tests to determine how many states are typically used, and allocate + // several here. + m_paintStateStack.append(GraphicsContextState::create()); + m_paintState = m_paintStateStack.last().get(); } -const SkBitmap* GraphicsContext::bitmap() const -{ - TRACE_EVENT0("skia", "GraphicsContext::bitmap"); - return &m_canvas->getDevice()->accessBitmap(false); -} - -const SkBitmap& GraphicsContext::layerBitmap(AccessMode access) const +GraphicsContext::~GraphicsContext() { - return m_canvas->getTopDevice()->accessBitmap(access == ReadWrite); +#if ASSERT_ENABLED + if (!m_disableDestructionChecks) { + ASSERT(!m_paintStateIndex); + ASSERT(!m_paintState->saveCount()); + ASSERT(!m_annotationCount); + ASSERT(!m_layerCount); + ASSERT(m_recordingStateStack.isEmpty()); + ASSERT(m_canvasStateStack.isEmpty()); + } +#endif } void GraphicsContext::save() { - if (paintingDisabled()) + if (contextDisabled()) return; - m_stateStack.append(m_state->clone()); - m_state = m_stateStack.last().get(); + m_paintState->incrementSaveCount(); - m_saveStateStack.append(DeferredSaveState(m_deferredSaveFlags, m_canvas->getSaveCount())); - m_deferredSaveFlags |= SkCanvas::kMatrixClip_SaveFlag; + m_canvasStateStack.append(CanvasSaveState(m_pendingCanvasSave, m_canvas->getSaveCount())); + m_pendingCanvasSave = true; } void GraphicsContext::restore() { - if (paintingDisabled()) + if (contextDisabled()) return; - if (m_stateStack.size() == 1) { + if (!m_paintStateIndex && !m_paintState->saveCount()) { WTF_LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty"); return; } - m_stateStack.removeLast(); - m_state = m_stateStack.last().get(); + if (m_paintState->saveCount()) { + m_paintState->decrementSaveCount(); + } else { + m_paintStateIndex--; + m_paintState = m_paintStateStack[m_paintStateIndex].get(); + } - DeferredSaveState savedState = m_saveStateStack.last(); - m_saveStateStack.removeLast(); - m_deferredSaveFlags = savedState.m_flags; + CanvasSaveState savedState = m_canvasStateStack.last(); + m_canvasStateStack.removeLast(); + m_pendingCanvasSave = savedState.m_pendingSave; m_canvas->restoreToCount(savedState.m_restoreCount); } -void GraphicsContext::saveLayer(const SkRect* bounds, const SkPaint* paint, SkCanvas::SaveFlags saveFlags) +void GraphicsContext::saveLayer(const SkRect* bounds, const SkPaint* paint) { - if (paintingDisabled()) + if (contextDisabled()) return; - realizeSave(SkCanvas::kMatrixClip_SaveFlag); + realizeCanvasSave(); - m_canvas->saveLayer(bounds, paint, saveFlags); - if (bounds) - m_canvas->clipRect(*bounds); + m_canvas->saveLayer(bounds, paint); if (m_trackOpaqueRegion) m_opaqueRegion.pushCanvasLayer(paint); } void GraphicsContext::restoreLayer() { - if (paintingDisabled()) + if (contextDisabled()) return; m_canvas->restore(); @@ -207,7 +213,7 @@ void GraphicsContext::restoreLayer() void GraphicsContext::beginAnnotation(const char* rendererName, const char* paintPhase, const String& elementId, const String& elementClass, const String& elementTag) { - if (paintingDisabled()) + if (contextDisabled()) return; canvas()->beginCommentGroup("GraphicsContextAnnotation"); @@ -220,34 +226,27 @@ void GraphicsContext::beginAnnotation(const char* rendererName, const char* pain for (AnnotationList::const_iterator it = annotations.begin(); it != end; ++it) canvas()->addComment(it->first, it->second.ascii().data()); -#if !ASSERT_DISABLED +#if ASSERT_ENABLED ++m_annotationCount; #endif } void GraphicsContext::endAnnotation() { - if (paintingDisabled()) + if (contextDisabled()) return; canvas()->endCommentGroup(); ASSERT(m_annotationCount > 0); -#if !ASSERT_DISABLED +#if ASSERT_ENABLED --m_annotationCount; #endif } -void GraphicsContext::setStrokeColor(const Color& color) -{ - m_state->m_strokeData.setColor(color); - m_state->m_strokeData.clearGradient(); - m_state->m_strokeData.clearPattern(); -} - void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern) { - if (paintingDisabled()) + if (contextDisabled()) return; ASSERT(pattern); @@ -255,13 +254,12 @@ void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern) setStrokeColor(Color::black); return; } - m_state->m_strokeData.clearGradient(); - m_state->m_strokeData.setPattern(pattern); + mutableState()->setStrokePattern(pattern); } void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient) { - if (paintingDisabled()) + if (contextDisabled()) return; ASSERT(gradient); @@ -269,20 +267,12 @@ void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient) setStrokeColor(Color::black); return; } - m_state->m_strokeData.setGradient(gradient); - m_state->m_strokeData.clearPattern(); -} - -void GraphicsContext::setFillColor(const Color& color) -{ - m_state->m_fillColor = color; - m_state->m_fillGradient.clear(); - m_state->m_fillPattern.clear(); + mutableState()->setStrokeGradient(gradient); } void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern) { - if (paintingDisabled()) + if (contextDisabled()) return; ASSERT(pattern); @@ -290,13 +280,13 @@ void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern) setFillColor(Color::black); return; } - m_state->m_fillGradient.clear(); - m_state->m_fillPattern = pattern; + + mutableState()->setFillPattern(pattern); } void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient) { - if (paintingDisabled()) + if (contextDisabled()) return; ASSERT(gradient); @@ -304,81 +294,64 @@ void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient) setFillColor(Color::black); return; } - m_state->m_fillGradient = gradient; - m_state->m_fillPattern.clear(); + + mutableState()->setFillGradient(gradient); } void GraphicsContext::setShadow(const FloatSize& offset, float blur, const Color& color, - DrawLooper::ShadowTransformMode shadowTransformMode, - DrawLooper::ShadowAlphaMode shadowAlphaMode) + DrawLooperBuilder::ShadowTransformMode shadowTransformMode, + DrawLooperBuilder::ShadowAlphaMode shadowAlphaMode) { - if (paintingDisabled()) + if (contextDisabled()) return; - if (!color.isValid() || !color.alpha() || (!offset.width() && !offset.height() && !blur)) { + if (!color.alpha() || (!offset.width() && !offset.height() && !blur)) { clearShadow(); return; } - DrawLooper drawLooper; - drawLooper.addShadow(offset, blur, color, shadowTransformMode, shadowAlphaMode); - drawLooper.addUnmodifiedContent(); - setDrawLooper(drawLooper); + OwnPtr<DrawLooperBuilder> drawLooperBuilder = DrawLooperBuilder::create(); + drawLooperBuilder->addShadow(offset, blur, color, shadowTransformMode, shadowAlphaMode); + drawLooperBuilder->addUnmodifiedContent(); + setDrawLooper(drawLooperBuilder.release()); } -void GraphicsContext::setDrawLooper(const DrawLooper& drawLooper) +void GraphicsContext::setDrawLooper(PassOwnPtr<DrawLooperBuilder> drawLooperBuilder) { - if (paintingDisabled()) + if (contextDisabled()) return; - m_state->m_looper = drawLooper.skDrawLooper(); + mutableState()->setDrawLooper(drawLooperBuilder->detachDrawLooper()); } void GraphicsContext::clearDrawLooper() { - if (paintingDisabled()) + if (contextDisabled()) return; - m_state->m_looper.clear(); + mutableState()->clearDrawLooper(); } bool GraphicsContext::hasShadow() const { - return !!m_state->m_looper; -} - -int GraphicsContext::getNormalizedAlpha() const -{ - int alpha = roundf(m_state->m_alpha * 256); - if (alpha > 255) - alpha = 255; - else if (alpha < 0) - alpha = 0; - return alpha; -} - -bool GraphicsContext::getClipBounds(SkRect* bounds) const -{ - if (paintingDisabled()) - return false; - return m_canvas->getClipBounds(bounds); + return !!immutableState()->drawLooper(); } bool GraphicsContext::getTransformedClipBounds(FloatRect* bounds) const { - if (paintingDisabled()) + if (contextDisabled()) return false; SkIRect skIBounds; if (!m_canvas->getClipDeviceBounds(&skIBounds)) return false; - SkRect skBounds = SkRect::MakeFromIRect(skIBounds); + SkRect skBounds = SkRect::Make(skIBounds); *bounds = FloatRect(skBounds); return true; } SkMatrix GraphicsContext::getTotalMatrix() const { - if (paintingDisabled()) + if (contextDisabled()) return SkMatrix::I(); if (!isRecording()) @@ -391,16 +364,9 @@ SkMatrix GraphicsContext::getTotalMatrix() const return totalMatrix; } -bool GraphicsContext::isPrintingDevice() const -{ - if (paintingDisabled()) - return false; - return m_canvas->getTopDevice()->getDeviceCapabilities() & SkBaseDevice::kVector_Capability; -} - void GraphicsContext::adjustTextRenderMode(SkPaint* paint) { - if (paintingDisabled()) + if (contextDisabled()) return; if (!paint->isLCDRenderText()) @@ -413,9 +379,9 @@ bool GraphicsContext::couldUseLCDRenderedText() { // Our layers only have a single alpha channel. This means that subpixel // rendered text cannot be composited correctly when the layer is - // collapsed. Therefore, subpixel text is disabled when we are drawing + // collapsed. Therefore, subpixel text is contextDisabled when we are drawing // onto a layer. - if (paintingDisabled() || isDrawingToLayer() || !isCertainlyOpaque()) + if (contextDisabled() || m_canvas->isDrawingToLayer() || !isCertainlyOpaque()) return false; return shouldSmoothFonts(); @@ -423,94 +389,94 @@ bool GraphicsContext::couldUseLCDRenderedText() void GraphicsContext::setCompositeOperation(CompositeOperator compositeOperation, WebBlendMode blendMode) { - m_state->m_compositeOperator = compositeOperation; - m_state->m_blendMode = blendMode; - m_state->m_xferMode = WebCoreCompositeToSkiaComposite(compositeOperation, blendMode); + if (contextDisabled()) + return; + mutableState()->setCompositeOperation(compositeOperation, blendMode); } SkColorFilter* GraphicsContext::colorFilter() { - return m_state->m_colorFilter.get(); + return immutableState()->colorFilter(); } void GraphicsContext::setColorFilter(ColorFilter colorFilter) { + GraphicsContextState* stateToSet = mutableState(); + // We only support one active color filter at the moment. If (when) this becomes a problem, // we should switch to using color filter chains (Skia work in progress). - ASSERT(!m_state->m_colorFilter); - m_state->m_colorFilter = WebCoreColorFilterToSkiaColorFilter(colorFilter); + ASSERT(!stateToSet->colorFilter()); + stateToSet->setColorFilter(WebCoreColorFilterToSkiaColorFilter(colorFilter)); } -bool GraphicsContext::readPixels(SkBitmap* bitmap, int x, int y, SkCanvas::Config8888 config8888) +bool GraphicsContext::readPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, int x, int y) { - if (paintingDisabled()) + if (contextDisabled()) return false; - return m_canvas->readPixels(bitmap, x, y, config8888); + return m_canvas->readPixels(info, pixels, rowBytes, x, y); } void GraphicsContext::setMatrix(const SkMatrix& matrix) { - if (paintingDisabled()) + if (contextDisabled()) return; - realizeSave(SkCanvas::kMatrix_SaveFlag); + realizeCanvasSave(); m_canvas->setMatrix(matrix); } -bool GraphicsContext::concat(const SkMatrix& matrix) +void GraphicsContext::concat(const SkMatrix& matrix) { - if (paintingDisabled()) - return false; + if (contextDisabled()) + return; - realizeSave(SkCanvas::kMatrix_SaveFlag); + if (matrix.isIdentity()) + return; - return m_canvas->concat(matrix); + realizeCanvasSave(); + + m_canvas->concat(matrix); } void GraphicsContext::beginTransparencyLayer(float opacity, const FloatRect* bounds) { - beginLayer(opacity, m_state->m_compositeOperator, bounds); + beginLayer(opacity, immutableState()->compositeOperator(), bounds); } -void GraphicsContext::beginLayer(float opacity, CompositeOperator op, const FloatRect* bounds, ColorFilter colorFilter) +void GraphicsContext::beginLayer(float opacity, CompositeOperator op, const FloatRect* bounds, ColorFilter colorFilter, ImageFilter* imageFilter) { - if (paintingDisabled()) + if (contextDisabled()) return; - // We need the "alpha" layer flag here because the base layer is opaque - // (the surface of the page) but layers on top may have transparent parts. - // Without explicitly setting the alpha flag, the layer will inherit the - // opaque setting of the base and some things won't work properly. - SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag); - SkPaint layerPaint; layerPaint.setAlpha(static_cast<unsigned char>(opacity * 255)); - layerPaint.setXfermode(WebCoreCompositeToSkiaComposite(op, m_state->m_blendMode).get()); + layerPaint.setXfermode(WebCoreCompositeToSkiaComposite(op, m_paintState->blendMode()).get()); layerPaint.setColorFilter(WebCoreColorFilterToSkiaColorFilter(colorFilter).get()); + layerPaint.setImageFilter(imageFilter); if (bounds) { SkRect skBounds = WebCoreFloatRectToSKRect(*bounds); - saveLayer(&skBounds, &layerPaint, saveFlags); + saveLayer(&skBounds, &layerPaint); } else { - saveLayer(0, &layerPaint, saveFlags); + saveLayer(0, &layerPaint); } -#if !ASSERT_DISABLED +#if ASSERT_ENABLED ++m_layerCount; #endif } void GraphicsContext::endLayer() { - if (paintingDisabled()) + if (contextDisabled()) return; restoreLayer(); ASSERT(m_layerCount > 0); -#if !ASSERT_DISABLED +#if ASSERT_ENABLED --m_layerCount; #endif } @@ -522,16 +488,17 @@ void GraphicsContext::beginRecording(const FloatRect& bounds) SkCanvas* savedCanvas = m_canvas; SkMatrix savedMatrix = getTotalMatrix(); - IntRect recordingRect = enclosingIntRect(bounds); - m_canvas = displayList->picture()->beginRecording(recordingRect.width(), recordingRect.height(), - SkPicture::kUsePathBoundsForClip_RecordingFlag); + if (!contextDisabled()) { + IntRect recordingRect = enclosingIntRect(bounds); + m_canvas = displayList->beginRecording(recordingRect.size()); - // We want the bounds offset mapped to (0, 0), such that the display list content - // is fully contained within the SkPictureRecord's bounds. - if (!toFloatSize(bounds.location()).isZero()) { - m_canvas->translate(-bounds.x(), -bounds.y()); - // To avoid applying the offset repeatedly in getTotalMatrix(), we pre-apply it here. - savedMatrix.preTranslate(bounds.x(), bounds.y()); + // We want the bounds offset mapped to (0, 0), such that the display list content + // is fully contained within the SkPictureRecord's bounds. + if (!toFloatSize(bounds.location()).isZero()) { + m_canvas->translate(-bounds.x(), -bounds.y()); + // To avoid applying the offset repeatedly in getTotalMatrix(), we pre-apply it here. + savedMatrix.preTranslate(bounds.x(), bounds.y()); + } } m_recordingStateStack.append(RecordingState(savedCanvas, savedMatrix, displayList)); @@ -542,8 +509,10 @@ PassRefPtr<DisplayList> GraphicsContext::endRecording() ASSERT(!m_recordingStateStack.isEmpty()); RecordingState recording = m_recordingStateStack.last(); - ASSERT(recording.m_displayList->picture()->getRecordingCanvas()); - recording.m_displayList->picture()->endRecording(); + if (!contextDisabled()) { + ASSERT(recording.m_displayList->isRecording()); + recording.m_displayList->endRecording(); + } m_recordingStateStack.removeLast(); m_canvas = recording.m_savedCanvas; @@ -558,49 +527,27 @@ bool GraphicsContext::isRecording() const void GraphicsContext::drawDisplayList(DisplayList* displayList) { - ASSERT(!displayList->picture()->getRecordingCanvas()); + ASSERT(displayList); + ASSERT(!displayList->isRecording()); - if (paintingDisabled() || !displayList) + if (contextDisabled() || displayList->bounds().isEmpty()) return; - realizeSave(SkCanvas::kMatrixClip_SaveFlag); + realizeCanvasSave(); const FloatRect& bounds = displayList->bounds(); if (bounds.x() || bounds.y()) m_canvas->translate(bounds.x(), bounds.y()); - m_canvas->drawPicture(*displayList->picture()); + m_canvas->drawPicture(displayList->picture()); if (bounds.x() || bounds.y()) m_canvas->translate(-bounds.x(), -bounds.y()); } -void GraphicsContext::setupPaintForFilling(SkPaint* paint) const -{ - if (paintingDisabled()) - return; - - setupPaintCommon(paint); - - setupShader(paint, m_state->m_fillGradient.get(), m_state->m_fillPattern.get(), m_state->m_fillColor.rgb()); -} - -float GraphicsContext::setupPaintForStroking(SkPaint* paint, int length) const -{ - if (paintingDisabled()) - return 0.0f; - - setupPaintCommon(paint); - - setupShader(paint, m_state->m_strokeData.gradient(), m_state->m_strokeData.pattern(), - m_state->m_strokeData.color().rgb()); - - return m_state->m_strokeData.setupPaint(paint, length); -} - void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias) { - if (paintingDisabled()) + if (contextDisabled()) return; if (numPoints <= 1) @@ -609,40 +556,18 @@ void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* poin SkPath path; setPathFromConvexPoints(&path, numPoints, points); - SkPaint paint; - setupPaintForFilling(&paint); + SkPaint paint(immutableState()->fillPaint()); paint.setAntiAlias(shouldAntialias); drawPath(path, paint); - if (strokeStyle() != NoStroke) { - paint.reset(); - setupPaintForStroking(&paint); - drawPath(path, paint); - } -} - -// This method is only used to draw the little circles used in lists. -void GraphicsContext::drawEllipse(const IntRect& elipseRect) -{ - if (paintingDisabled()) - return; - - SkRect rect = elipseRect; - SkPaint paint; - setupPaintForFilling(&paint); - drawOval(rect, paint); - - if (strokeStyle() != NoStroke) { - paint.reset(); - setupPaintForStroking(&paint); - drawOval(rect, paint); - } + if (strokeStyle() != NoStroke) + drawPath(path, immutableState()->strokePaint()); } void GraphicsContext::drawFocusRing(const Path& focusRingPath, int width, int offset, const Color& color) { // FIXME: Implement support for offset. - if (paintingDisabled()) + if (contextDisabled()) return; SkPaint paint; @@ -656,7 +581,7 @@ void GraphicsContext::drawFocusRing(const Path& focusRingPath, int width, int of void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color) { - if (paintingDisabled()) + if (contextDisabled()) return; unsigned rectCount = rects.size(); @@ -698,6 +623,9 @@ static inline IntRect areaCastingShadowInHole(const IntRect& holeRect, int shado void GraphicsContext::drawInnerShadow(const RoundedRect& rect, const Color& shadowColor, const IntSize shadowOffset, int shadowBlur, int shadowSpread, Edges clippedEdges) { + if (contextDisabled()) + return; + IntRect holeRect(rect.rect()); holeRect.inflate(-shadowSpread); @@ -737,26 +665,24 @@ void GraphicsContext::drawInnerShadow(const RoundedRect& rect, const Color& shad clip(rect.rect()); } - DrawLooper drawLooper; - drawLooper.addShadow(shadowOffset, shadowBlur, shadowColor, - DrawLooper::ShadowRespectsTransforms, DrawLooper::ShadowIgnoresAlpha); - setDrawLooper(drawLooper); + OwnPtr<DrawLooperBuilder> drawLooperBuilder = DrawLooperBuilder::create(); + drawLooperBuilder->addShadow(shadowOffset, shadowBlur, shadowColor, + DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::ShadowIgnoresAlpha); + setDrawLooper(drawLooperBuilder.release()); fillRectWithRoundedHole(outerRect, roundedHole, fillColor); restore(); clearDrawLooper(); } -// This is only used to draw borders. void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) { - if (paintingDisabled()) + if (contextDisabled()) return; StrokeStyle penStyle = strokeStyle(); if (penStyle == NoStroke) return; - SkPaint paint; FloatPoint p1 = point1; FloatPoint p2 = point2; bool isVerticalLine = (p1.x() == p2.x()); @@ -766,13 +692,12 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) // be the sum of the displacement component vectors give or take 1 - // probably worth the speed up of no square root, which also won't be exact. FloatSize disp = p2 - p1; - int length = SkScalarRound(disp.width() + disp.height()); - setupPaintForStroking(&paint, length); + int length = SkScalarRoundToInt(disp.width() + disp.height()); + SkPaint paint(immutableState()->strokePaint(length)); if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) { // Do a rect fill of our endpoints. This ensures we always have the // appearance of being a border. We then draw the actual dotted/dashed line. - SkRect r1, r2; r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width); r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width); @@ -791,7 +716,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) } adjustLineToPixelBoundaries(p1, p2, width, penStyle); - SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 }; + SkPoint pts[2] = { p1.data(), p2.data() }; m_canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint); @@ -801,7 +726,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt, float width, DocumentMarkerLineStyle style) { - if (paintingDisabled()) + if (contextDisabled()) return; int deviceScaleFactor = m_useHighResMarker ? 2 : 1; @@ -816,12 +741,11 @@ void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt, float widt // Match the artwork used by the Mac. const int rowPixels = 4 * deviceScaleFactor; const int colPixels = 3 * deviceScaleFactor; - misspellBitmap[index] = new SkBitmap; - misspellBitmap[index]->setConfig(SkBitmap::kARGB_8888_Config, - rowPixels, colPixels); - misspellBitmap[index]->allocPixels(); + SkBitmap bitmap; + if (!bitmap.allocN32Pixels(rowPixels, colPixels)) + return; - misspellBitmap[index]->eraseARGB(0, 0, 0, 0); + bitmap.eraseARGB(0, 0, 0, 0); const uint32_t transparentColor = 0x00000000; if (deviceScaleFactor == 1) { @@ -834,7 +758,7 @@ void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt, float widt // c d c c d c // e f e e f e for (int x = 0; x < colPixels; ++x) { - uint32_t* row = misspellBitmap[index]->getAddr32(0, x); + uint32_t* row = bitmap.getAddr32(0, x); row[0] = colors[index][x * 2]; row[1] = colors[index][x * 2 + 1]; row[2] = colors[index][x * 2]; @@ -855,7 +779,7 @@ void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt, float widt // n o p p o n // q r s s r q for (int x = 0; x < colPixels; ++x) { - uint32_t* row = misspellBitmap[index]->getAddr32(0, x); + uint32_t* row = bitmap.getAddr32(0, x); row[0] = colors[index][x * 3]; row[1] = colors[index][x * 3 + 1]; row[2] = colors[index][x * 3 + 2]; @@ -867,23 +791,27 @@ void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt, float widt } } else ASSERT_NOT_REACHED(); + + misspellBitmap[index] = new SkBitmap(bitmap); #else // We use a 2-pixel-high misspelling indicator because that seems to be // what WebKit is designed for, and how much room there is in a typical // page for it. const int rowPixels = 32 * deviceScaleFactor; // Must be multiple of 4 for pattern below. const int colPixels = 2 * deviceScaleFactor; - misspellBitmap[index] = new SkBitmap; - misspellBitmap[index]->setConfig(SkBitmap::kARGB_8888_Config, rowPixels, colPixels); - misspellBitmap[index]->allocPixels(); + SkBitmap bitmap; + if (!bitmap.allocN32Pixels(rowPixels, colPixels)) + return; - misspellBitmap[index]->eraseARGB(0, 0, 0, 0); + bitmap.eraseARGB(0, 0, 0, 0); if (deviceScaleFactor == 1) - draw1xMarker(misspellBitmap[index], index); + draw1xMarker(&bitmap, index); else if (deviceScaleFactor == 2) - draw2xMarker(misspellBitmap[index], index); + draw2xMarker(&bitmap, index); else ASSERT_NOT_REACHED(); + + misspellBitmap[index] = new SkBitmap(bitmap); #endif } @@ -905,11 +833,10 @@ void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt, float widt originY *= deviceScaleFactor; #endif + SkMatrix localMatrix; + localMatrix.setTranslate(originX, originY); RefPtr<SkShader> shader = adoptRef(SkShader::CreateBitmapShader( - *misspellBitmap[index], SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); - SkMatrix matrix; - matrix.setTranslate(originX, originY); - shader->setLocalMatrix(matrix); + *misspellBitmap[index], SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix)); SkPaint paint; paint.setShader(shader.get()); @@ -919,7 +846,7 @@ void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt, float widt if (deviceScaleFactor == 2) { save(); - scale(FloatSize(0.5, 0.5)); + scale(0.5, 0.5); } drawRect(rect, paint); if (deviceScaleFactor == 2) @@ -928,44 +855,47 @@ void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt, float widt void GraphicsContext::drawLineForText(const FloatPoint& pt, float width, bool printing) { - if (paintingDisabled()) + if (contextDisabled()) return; if (width <= 0) return; - int thickness = SkMax32(static_cast<int>(strokeThickness()), 1); - SkRect r; - r.fLeft = WebCoreFloatToSkScalar(pt.x()); - // Avoid anti-aliasing lines. Currently, these are always horizontal. - // Round to nearest pixel to match text and other content. - r.fTop = WebCoreFloatToSkScalar(floorf(pt.y() + 0.5f)); - r.fRight = r.fLeft + WebCoreFloatToSkScalar(width); - r.fBottom = r.fTop + SkIntToScalar(thickness); - SkPaint paint; switch (strokeStyle()) { case NoStroke: case SolidStroke: case DoubleStroke: - case WavyStroke: - setupPaintForFilling(&paint); - break; + case WavyStroke: { + int thickness = SkMax32(static_cast<int>(strokeThickness()), 1); + SkRect r; + r.fLeft = WebCoreFloatToSkScalar(pt.x()); + // Avoid anti-aliasing lines. Currently, these are always horizontal. + // Round to nearest pixel to match text and other content. + r.fTop = WebCoreFloatToSkScalar(floorf(pt.y() + 0.5f)); + r.fRight = r.fLeft + WebCoreFloatToSkScalar(width); + r.fBottom = r.fTop + SkIntToScalar(thickness); + paint = immutableState()->fillPaint(); + // Text lines are drawn using the stroke color. + paint.setColor(effectiveStrokeColor()); + drawRect(r, paint); + return; + } case DottedStroke: - case DashedStroke: - setupPaintForStroking(&paint); - break; + case DashedStroke: { + int y = floorf(pt.y() + std::max<float>(strokeThickness() / 2.0f, 0.5f)); + drawLine(IntPoint(pt.x(), y), IntPoint(pt.x() + width, y)); + return; + } } - // Text lines are drawn using the stroke color. - paint.setColor(effectiveStrokeColor()); - drawRect(r, paint); + ASSERT_NOT_REACHED(); } // Draws a filled rectangle with a stroked border. void GraphicsContext::drawRect(const IntRect& rect) { - if (paintingDisabled()) + if (contextDisabled()) return; ASSERT(!rect.isEmpty()); @@ -973,34 +903,26 @@ void GraphicsContext::drawRect(const IntRect& rect) return; SkRect skRect = rect; - SkPaint paint; - int fillcolorNotTransparent = m_state->m_fillColor.rgb() & 0xFF000000; - if (fillcolorNotTransparent) { - setupPaintForFilling(&paint); + int fillcolorNotTransparent = immutableState()->fillColor().rgb() & 0xFF000000; + if (fillcolorNotTransparent) + drawRect(skRect, immutableState()->fillPaint()); + + if (immutableState()->strokeData().style() != NoStroke + && immutableState()->strokeData().color().alpha()) { + // Stroke a width: 1 inset border + SkPaint paint(immutableState()->fillPaint()); + paint.setColor(effectiveStrokeColor()); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(1); + + skRect.inset(0.5f, 0.5f); drawRect(skRect, paint); } - - if (m_state->m_strokeData.style() != NoStroke && (m_state->m_strokeData.color().rgb() & 0xFF000000)) { - // We do a fill of four rects to simulate the stroke of a border. - paint.reset(); - setupPaintForFilling(&paint); - // need to jam in the strokeColor - paint.setColor(this->effectiveStrokeColor()); - - SkRect topBorder = { skRect.fLeft, skRect.fTop, skRect.fRight, skRect.fTop + 1 }; - drawRect(topBorder, paint); - SkRect bottomBorder = { skRect.fLeft, skRect.fBottom - 1, skRect.fRight, skRect.fBottom }; - drawRect(bottomBorder, paint); - SkRect leftBorder = { skRect.fLeft, skRect.fTop + 1, skRect.fLeft + 1, skRect.fBottom - 1 }; - drawRect(leftBorder, paint); - SkRect rightBorder = { skRect.fRight - 1, skRect.fTop + 1, skRect.fRight, skRect.fBottom - 1 }; - drawRect(rightBorder, paint); - } } void GraphicsContext::drawText(const Font& font, const TextRunPaintInfo& runInfo, const FloatPoint& point) { - if (paintingDisabled()) + if (contextDisabled()) return; font.drawText(this, runInfo, point); @@ -1008,7 +930,7 @@ void GraphicsContext::drawText(const Font& font, const TextRunPaintInfo& runInfo void GraphicsContext::drawEmphasisMarks(const Font& font, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) { - if (paintingDisabled()) + if (contextDisabled()) return; font.drawEmphasisMarks(this, runInfo, mark, point); @@ -1016,7 +938,7 @@ void GraphicsContext::drawEmphasisMarks(const Font& font, const TextRunPaintInfo void GraphicsContext::drawBidiText(const Font& font, const TextRunPaintInfo& runInfo, const FloatPoint& point, Font::CustomFontNotReadyAction customFontNotReadyAction) { - if (paintingDisabled()) + if (contextDisabled()) return; // sub-run painting is not supported for Bidi text. @@ -1056,7 +978,7 @@ void GraphicsContext::drawBidiText(const Font& font, const TextRunPaintInfo& run void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, int from, int to) { - if (paintingDisabled()) + if (contextDisabled()) return; fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor); @@ -1069,21 +991,16 @@ void GraphicsContext::drawImage(Image* image, const IntPoint& p, CompositeOperat drawImage(image, FloatRect(IntRect(p, image->size())), FloatRect(FloatPoint(), FloatSize(image->size())), op, shouldRespectImageOrientation); } -void GraphicsContext::drawImage(Image* image, const IntRect& r, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale) +void GraphicsContext::drawImage(Image* image, const IntRect& r, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation) { if (!image) return; - drawImage(image, FloatRect(r), FloatRect(FloatPoint(), FloatSize(image->size())), op, shouldRespectImageOrientation, useLowQualityScale); -} - -void GraphicsContext::drawImage(Image* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation) -{ - drawImage(image, FloatRect(IntRect(dest, srcRect.size())), FloatRect(srcRect), op, shouldRespectImageOrientation); + drawImage(image, FloatRect(r), FloatRect(FloatPoint(), FloatSize(image->size())), op, shouldRespectImageOrientation); } -void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale) +void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation) { - drawImage(image, dest, src, op, blink::WebBlendModeNormal, shouldRespectImageOrientation, useLowQualityScale); + drawImage(image, dest, src, op, blink::WebBlendModeNormal, shouldRespectImageOrientation); } void GraphicsContext::drawImage(Image* image, const FloatRect& dest) @@ -1093,42 +1010,24 @@ void GraphicsContext::drawImage(Image* image, const FloatRect& dest) drawImage(image, dest, FloatRect(IntRect(IntPoint(), image->size()))); } -void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, WebBlendMode blendMode, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale) -{ if (paintingDisabled() || !image) +void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, WebBlendMode blendMode, RespectImageOrientationEnum shouldRespectImageOrientation) +{ + if (contextDisabled() || !image) return; - - InterpolationQuality previousInterpolationQuality = InterpolationDefault; - - if (useLowQualityScale) { - previousInterpolationQuality = imageInterpolationQuality(); - setImageInterpolationQuality(InterpolationLow); - } - image->draw(this, dest, src, op, blendMode, shouldRespectImageOrientation); - - if (useLowQualityScale) - setImageInterpolationQuality(previousInterpolationQuality); } -void GraphicsContext::drawTiledImage(Image* image, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale, WebBlendMode blendMode, const IntSize& repeatSpacing) +void GraphicsContext::drawTiledImage(Image* image, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, WebBlendMode blendMode, const IntSize& repeatSpacing) { - if (paintingDisabled() || !image) + if (contextDisabled() || !image) return; - - if (useLowQualityScale) { - InterpolationQuality previousInterpolationQuality = imageInterpolationQuality(); - setImageInterpolationQuality(InterpolationLow); - image->drawTiled(this, destRect, srcPoint, tileSize, op, blendMode, repeatSpacing); - setImageInterpolationQuality(previousInterpolationQuality); - } else { - image->drawTiled(this, destRect, srcPoint, tileSize, op, blendMode, repeatSpacing); - } + image->drawTiled(this, destRect, srcPoint, tileSize, op, blendMode, repeatSpacing); } void GraphicsContext::drawTiledImage(Image* image, const IntRect& dest, const IntRect& srcRect, - const FloatSize& tileScaleFactor, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale) + const FloatSize& tileScaleFactor, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op) { - if (paintingDisabled() || !image) + if (contextDisabled() || !image) return; if (hRule == Image::StretchTile && vRule == Image::StretchTile) { @@ -1137,81 +1036,54 @@ void GraphicsContext::drawTiledImage(Image* image, const IntRect& dest, const In return; } - if (useLowQualityScale) { - InterpolationQuality previousInterpolationQuality = imageInterpolationQuality(); - setImageInterpolationQuality(InterpolationLow); - image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, op); - setImageInterpolationQuality(previousInterpolationQuality); - } else { - image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, op); - } + image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, op); } -void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntPoint& p, CompositeOperator op, WebBlendMode blendMode) +void GraphicsContext::drawImageBuffer(ImageBuffer* image, const FloatRect& dest, + const FloatRect* src, CompositeOperator op) { - if (!image) + if (contextDisabled() || !image) return; - drawImageBuffer(image, FloatRect(IntRect(p, image->size())), FloatRect(FloatPoint(), FloatSize(image->size())), op, blendMode); -} -void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntRect& r, CompositeOperator op, WebBlendMode blendMode, bool useLowQualityScale) -{ - if (!image) - return; - drawImageBuffer(image, FloatRect(r), FloatRect(FloatPoint(), FloatSize(image->size())), op, blendMode, useLowQualityScale); + image->draw(this, dest, src, op); } -void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op, WebBlendMode blendMode) +void GraphicsContext::writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y) { - drawImageBuffer(image, FloatRect(IntRect(dest, srcRect.size())), FloatRect(srcRect), op, blendMode); -} + if (contextDisabled()) + return; -void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, WebBlendMode blendMode, bool useLowQualityScale) -{ - drawImageBuffer(image, FloatRect(dest), FloatRect(srcRect), op, blendMode, useLowQualityScale); -} + m_canvas->writePixels(info, pixels, rowBytes, x, y); -void GraphicsContext::drawImageBuffer(ImageBuffer* image, const FloatRect& dest) -{ - if (!image) - return; - drawImageBuffer(image, dest, FloatRect(IntRect(IntPoint(), image->size()))); -} + if (m_trackOpaqueRegion) { + SkRect rect = SkRect::MakeXYWH(x, y, info.width(), info.height()); + SkPaint paint; -void GraphicsContext::drawImageBuffer(ImageBuffer* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, WebBlendMode blendMode, bool useLowQualityScale) -{ - if (paintingDisabled() || !image) - return; + paint.setXfermodeMode(SkXfermode::kSrc_Mode); + if (kOpaque_SkAlphaType != info.alphaType()) + paint.setAlpha(0x80); // signal to m_opaqueRegion that we are not fully opaque - if (useLowQualityScale) { - InterpolationQuality previousInterpolationQuality = imageInterpolationQuality(); - setImageInterpolationQuality(InterpolationLow); - image->draw(this, dest, src, op, blendMode, useLowQualityScale); - setImageInterpolationQuality(previousInterpolationQuality); - } else { - image->draw(this, dest, src, op, blendMode, useLowQualityScale); + m_opaqueRegion.didDrawRect(this, rect, paint, 0); + // more efficient would be to call markRectAsOpaque or MarkRectAsNonOpaque directly, + // rather than cons-ing up a paint with an xfermode and alpha } } -void GraphicsContext::writePixels(const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) +void GraphicsContext::writePixels(const SkBitmap& bitmap, int x, int y) { - if (paintingDisabled()) + if (contextDisabled()) return; - m_canvas->writePixels(bitmap, x, y, config8888); - - if (m_trackOpaqueRegion) { - SkRect rect = SkRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()); - SkPaint paint; - - paint.setXfermodeMode(SkXfermode::kSrc_Mode); - m_opaqueRegion.didDrawRect(this, rect, paint, &bitmap); + if (!bitmap.getTexture()) { + SkAutoLockPixels alp(bitmap); + if (bitmap.getPixels()) + writePixels(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes(), x, y); } } void GraphicsContext::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint) { - if (paintingDisabled()) + if (contextDisabled()) return; m_canvas->drawBitmap(bitmap, left, top, paint); @@ -1225,10 +1097,11 @@ void GraphicsContext::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar void GraphicsContext::drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint* paint) { - if (paintingDisabled()) + if (contextDisabled()) return; - SkCanvas::DrawBitmapRectFlags flags = m_state->m_shouldClampToSourceRect ? SkCanvas::kNone_DrawBitmapRectFlag : SkCanvas::kBleed_DrawBitmapRectFlag; + SkCanvas::DrawBitmapRectFlags flags = + immutableState()->shouldClampToSourceRect() ? SkCanvas::kNone_DrawBitmapRectFlag : SkCanvas::kBleed_DrawBitmapRectFlag; m_canvas->drawBitmapRectToRect(bitmap, src, dst, paint, flags); @@ -1238,7 +1111,7 @@ void GraphicsContext::drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, void GraphicsContext::drawOval(const SkRect& oval, const SkPaint& paint) { - if (paintingDisabled()) + if (contextDisabled()) return; m_canvas->drawOval(oval, paint); @@ -1249,7 +1122,7 @@ void GraphicsContext::drawOval(const SkRect& oval, const SkPaint& paint) void GraphicsContext::drawPath(const SkPath& path, const SkPaint& paint) { - if (paintingDisabled()) + if (contextDisabled()) return; m_canvas->drawPath(path, paint); @@ -1260,7 +1133,7 @@ void GraphicsContext::drawPath(const SkPath& path, const SkPaint& paint) void GraphicsContext::drawRect(const SkRect& rect, const SkPaint& paint) { - if (paintingDisabled()) + if (contextDisabled()) return; m_canvas->drawRect(rect, paint); @@ -1271,6 +1144,9 @@ void GraphicsContext::drawRect(const SkRect& rect, const SkPaint& paint) void GraphicsContext::didDrawRect(const SkRect& rect, const SkPaint& paint, const SkBitmap* bitmap) { + if (contextDisabled()) + return; + if (m_trackOpaqueRegion) m_opaqueRegion.didDrawRect(this, rect, paint, bitmap); } @@ -1278,7 +1154,7 @@ void GraphicsContext::didDrawRect(const SkRect& rect, const SkPaint& paint, cons void GraphicsContext::drawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkRect& textRect, const SkPaint& paint) { - if (paintingDisabled()) + if (contextDisabled()) return; m_canvas->drawPosText(text, byteLength, pos, paint); @@ -1289,81 +1165,79 @@ void GraphicsContext::drawPosText(const void* text, size_t byteLength, m_opaqueRegion.didDrawUnbounded(this, paint, OpaqueRegionSkia::FillOrStroke); } -void GraphicsContext::drawPosTextH(const void* text, size_t byteLength, - const SkScalar xpos[], SkScalar constY, const SkRect& textRect, const SkPaint& paint) -{ - if (paintingDisabled()) - return; - - m_canvas->drawPosTextH(text, byteLength, xpos, constY, paint); - didDrawTextInRect(textRect); - - // FIXME: compute bounds for positioned text. - if (m_trackOpaqueRegion) - m_opaqueRegion.didDrawUnbounded(this, paint, OpaqueRegionSkia::FillOrStroke); -} - -void GraphicsContext::drawTextOnPath(const void* text, size_t byteLength, - const SkPath& path, const SkRect& textRect, const SkMatrix* matrix, const SkPaint& paint) -{ - if (paintingDisabled()) - return; - - m_canvas->drawTextOnPath(text, byteLength, path, matrix, paint); - didDrawTextInRect(textRect); - - // FIXME: compute bounds for positioned text. - if (m_trackOpaqueRegion) - m_opaqueRegion.didDrawUnbounded(this, paint, OpaqueRegionSkia::FillOrStroke); -} - void GraphicsContext::fillPath(const Path& pathToFill) { - if (paintingDisabled() || pathToFill.isEmpty()) + if (contextDisabled() || pathToFill.isEmpty()) return; // Use const_cast and temporarily modify the fill type instead of copying the path. SkPath& path = const_cast<SkPath&>(pathToFill.skPath()); SkPath::FillType previousFillType = path.getFillType(); - SkPath::FillType temporaryFillType = m_state->m_fillRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType; + SkPath::FillType temporaryFillType = + immutableState()->fillRule() == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType; path.setFillType(temporaryFillType); - SkPaint paint; - setupPaintForFilling(&paint); - drawPath(path, paint); + drawPath(path, immutableState()->fillPaint()); path.setFillType(previousFillType); } void GraphicsContext::fillRect(const FloatRect& rect) { - if (paintingDisabled()) + if (contextDisabled()) return; SkRect r = rect; - SkPaint paint; - setupPaintForFilling(&paint); - drawRect(r, paint); + drawRect(r, immutableState()->fillPaint()); } void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) { - if (paintingDisabled()) + if (contextDisabled()) return; SkRect r = rect; - SkPaint paint; - setupPaintCommon(&paint); + SkPaint paint = immutableState()->fillPaint(); paint.setColor(color.rgb()); drawRect(r, paint); } +void GraphicsContext::fillBetweenRoundedRects(const IntRect& outer, const IntSize& outerTopLeft, const IntSize& outerTopRight, const IntSize& outerBottomLeft, const IntSize& outerBottomRight, + const IntRect& inner, const IntSize& innerTopLeft, const IntSize& innerTopRight, const IntSize& innerBottomLeft, const IntSize& innerBottomRight, const Color& color) { + if (contextDisabled()) + return; + + SkVector outerRadii[4]; + SkVector innerRadii[4]; + setRadii(outerRadii, outerTopLeft, outerTopRight, outerBottomRight, outerBottomLeft); + setRadii(innerRadii, innerTopLeft, innerTopRight, innerBottomRight, innerBottomLeft); + + SkRRect rrOuter; + SkRRect rrInner; + rrOuter.setRectRadii(outer, outerRadii); + rrInner.setRectRadii(inner, innerRadii); + + SkPaint paint(immutableState()->fillPaint()); + paint.setColor(color.rgb()); + + m_canvas->drawDRRect(rrOuter, rrInner, paint); + + if (m_trackOpaqueRegion) + m_opaqueRegion.didDrawBounded(this, rrOuter.getBounds(), paint); +} + +void GraphicsContext::fillBetweenRoundedRects(const RoundedRect& outer, const RoundedRect& inner, const Color& color) +{ + fillBetweenRoundedRects(outer.rect(), outer.radii().topLeft(), outer.radii().topRight(), outer.radii().bottomLeft(), outer.radii().bottomRight(), + inner.rect(), inner.radii().topLeft(), inner.radii().topRight(), inner.radii().bottomLeft(), inner.radii().bottomRight(), color); +} + void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) { - if (paintingDisabled()) + if (contextDisabled()) return; if (topLeft.width() + topRight.width() > rect.width() @@ -1383,8 +1257,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef SkRRect rr; rr.setRectRadii(rect, radii); - SkPaint paint; - setupPaintForFilling(&paint); + SkPaint paint(immutableState()->fillPaint()); paint.setColor(color.rgb()); m_canvas->drawRRect(rr, paint); @@ -1395,34 +1268,36 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef void GraphicsContext::fillEllipse(const FloatRect& ellipse) { - if (paintingDisabled()) + if (contextDisabled()) return; SkRect rect = ellipse; - SkPaint paint; - setupPaintForFilling(&paint); - drawOval(rect, paint); + drawOval(rect, immutableState()->fillPaint()); } void GraphicsContext::strokePath(const Path& pathToStroke) { - if (paintingDisabled() || pathToStroke.isEmpty()) + if (contextDisabled() || pathToStroke.isEmpty()) return; const SkPath& path = pathToStroke.skPath(); - SkPaint paint; - setupPaintForStroking(&paint); - drawPath(path, paint); + drawPath(path, immutableState()->strokePaint()); +} + +void GraphicsContext::strokeRect(const FloatRect& rect) +{ + strokeRect(rect, strokeThickness()); } void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) { - if (paintingDisabled()) + if (contextDisabled()) return; - SkPaint paint; - setupPaintForStroking(&paint); + SkPaint paint(immutableState()->strokePaint()); paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth)); + // Reset the dash effect to account for the width + immutableState()->strokeData().setupPaintDashPathEffect(&paint, 0); // strokerect has special rules for CSS when the rect is degenerate: // if width==0 && height==0, do nothing // if width==0 || height==0, then just draw line for the other dimension @@ -1444,20 +1319,22 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) void GraphicsContext::strokeEllipse(const FloatRect& ellipse) { - if (paintingDisabled()) + if (contextDisabled()) return; - SkRect rect(ellipse); - SkPaint paint; - setupPaintForStroking(&paint); - drawOval(rect, paint); + drawOval(ellipse, immutableState()->strokePaint()); } -void GraphicsContext::clipRoundedRect(const RoundedRect& rect) +void GraphicsContext::clipRoundedRect(const RoundedRect& rect, SkRegion::Op regionOp) { - if (paintingDisabled()) + if (contextDisabled()) return; + if (!rect.isRounded()) { + clipRect(rect.rect(), NotAntiAliased, regionOp); + return; + } + SkVector radii[4]; RoundedRect::Radii wkRadii = rect.radii(); setRadii(radii, wkRadii.topLeft(), wkRadii.topRight(), wkRadii.bottomRight(), wkRadii.bottomLeft()); @@ -1465,12 +1342,12 @@ void GraphicsContext::clipRoundedRect(const RoundedRect& rect) SkRRect r; r.setRectRadii(rect.rect(), radii); - clipRRect(r, AntiAliased); + clipRRect(r, AntiAliased, regionOp); } void GraphicsContext::clipOut(const Path& pathToClip) { - if (paintingDisabled()) + if (contextDisabled()) return; // Use const_cast and temporarily toggle the inverse fill type instead of copying the path. @@ -1482,7 +1359,7 @@ void GraphicsContext::clipOut(const Path& pathToClip) void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule) { - if (paintingDisabled() || pathToClip.isEmpty()) + if (contextDisabled() || pathToClip.isEmpty()) return; // Use const_cast and temporarily modify the fill type instead of copying the path. @@ -1498,7 +1375,7 @@ void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule) void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased) { - if (paintingDisabled()) + if (contextDisabled()) return; if (numPoints <= 1) @@ -1511,22 +1388,15 @@ void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* poin void GraphicsContext::clipOutRoundedRect(const RoundedRect& rect) { - if (paintingDisabled()) + if (contextDisabled()) return; - if (!rect.isRounded()) { - clipOut(rect.rect()); - return; - } - - Path path; - path.addRoundedRect(rect); - clipOut(path); + clipRoundedRect(rect, SkRegion::kDifference_Op); } void GraphicsContext::canvasClip(const Path& pathToClip, WindRule clipRule) { - if (paintingDisabled()) + if (contextDisabled()) return; // Use const_cast and temporarily modify the fill type instead of copying the path. @@ -1540,69 +1410,94 @@ void GraphicsContext::canvasClip(const Path& pathToClip, WindRule clipRule) path.setFillType(previousFillType); } -bool GraphicsContext::clipRect(const SkRect& rect, AntiAliasingMode aa, SkRegion::Op op) +void GraphicsContext::clipRect(const SkRect& rect, AntiAliasingMode aa, SkRegion::Op op) { - if (paintingDisabled()) - return false; + if (contextDisabled()) + return; - realizeSave(SkCanvas::kClip_SaveFlag); + realizeCanvasSave(); - return m_canvas->clipRect(rect, op, aa == AntiAliased); + m_canvas->clipRect(rect, op, aa == AntiAliased); } -bool GraphicsContext::clipPath(const SkPath& path, AntiAliasingMode aa, SkRegion::Op op) +void GraphicsContext::clipPath(const SkPath& path, AntiAliasingMode aa, SkRegion::Op op) { - if (paintingDisabled()) - return false; + if (contextDisabled()) + return; - realizeSave(SkCanvas::kClip_SaveFlag); + realizeCanvasSave(); - return m_canvas->clipPath(path, op, aa == AntiAliased); + m_canvas->clipPath(path, op, aa == AntiAliased); } -bool GraphicsContext::clipRRect(const SkRRect& rect, AntiAliasingMode aa, SkRegion::Op op) +void GraphicsContext::clipRRect(const SkRRect& rect, AntiAliasingMode aa, SkRegion::Op op) { - if (paintingDisabled()) - return false; + if (contextDisabled()) + return; + + realizeCanvasSave(); + + m_canvas->clipRRect(rect, op, aa == AntiAliased); +} + +void GraphicsContext::beginCull(const FloatRect& rect) +{ + if (contextDisabled()) + return; + + realizeCanvasSave(); + m_canvas->pushCull(rect); +} - realizeSave(SkCanvas::kClip_SaveFlag); +void GraphicsContext::endCull() +{ + if (contextDisabled()) + return; - return m_canvas->clipRRect(rect, op, aa == AntiAliased); + realizeCanvasSave(); + + m_canvas->popCull(); } void GraphicsContext::rotate(float angleInRadians) { - if (paintingDisabled()) + if (contextDisabled()) return; - realizeSave(SkCanvas::kMatrix_SaveFlag); + realizeCanvasSave(); m_canvas->rotate(WebCoreFloatToSkScalar(angleInRadians * (180.0f / 3.14159265f))); } -void GraphicsContext::translate(float w, float h) +void GraphicsContext::translate(float x, float y) { - if (paintingDisabled()) + if (contextDisabled()) + return; + + if (!x && !y) return; - realizeSave(SkCanvas::kMatrix_SaveFlag); + realizeCanvasSave(); - m_canvas->translate(WebCoreFloatToSkScalar(w), WebCoreFloatToSkScalar(h)); + m_canvas->translate(WebCoreFloatToSkScalar(x), WebCoreFloatToSkScalar(y)); } -void GraphicsContext::scale(const FloatSize& size) +void GraphicsContext::scale(float x, float y) { - if (paintingDisabled()) + if (contextDisabled()) + return; + + if (x == 1.0f && y == 1.0f) return; - realizeSave(SkCanvas::kMatrix_SaveFlag); + realizeCanvasSave(); - m_canvas->scale(WebCoreFloatToSkScalar(size.width()), WebCoreFloatToSkScalar(size.height())); + m_canvas->scale(WebCoreFloatToSkScalar(x), WebCoreFloatToSkScalar(y)); } void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) { - if (paintingDisabled()) + if (contextDisabled()) return; SkAutoDataUnref url(SkData::NewWithCString(link.string().utf8().data())); @@ -1611,7 +1506,7 @@ void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) void GraphicsContext::setURLFragmentForRect(const String& destName, const IntRect& rect) { - if (paintingDisabled()) + if (contextDisabled()) return; SkAutoDataUnref skDestName(SkData::NewWithCString(destName.utf8().data())); @@ -1620,16 +1515,16 @@ void GraphicsContext::setURLFragmentForRect(const String& destName, const IntRec void GraphicsContext::addURLTargetAtPoint(const String& name, const IntPoint& pos) { - if (paintingDisabled()) + if (contextDisabled()) return; SkAutoDataUnref nameData(SkData::NewWithCString(name.utf8().data())); SkAnnotateNamedDestination(m_canvas, SkPoint::Make(pos.x(), pos.y()), nameData); } -AffineTransform GraphicsContext::getCTM(IncludeDeviceScale) const +AffineTransform GraphicsContext::getCTM() const { - if (paintingDisabled()) + if (contextDisabled()) return AffineTransform(); SkMatrix m = getTotalMatrix(); @@ -1643,7 +1538,7 @@ AffineTransform GraphicsContext::getCTM(IncludeDeviceScale) const void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, CompositeOperator op) { - if (paintingDisabled()) + if (contextDisabled()) return; CompositeOperator previousOperator = compositeOperation(); @@ -1654,6 +1549,9 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, Compos void GraphicsContext::fillRoundedRect(const RoundedRect& rect, const Color& color) { + if (contextDisabled()) + return; + if (rect.isRounded()) fillRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight(), color); else @@ -1662,7 +1560,7 @@ void GraphicsContext::fillRoundedRect(const RoundedRect& rect, const Color& colo void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedRect& roundedHoleRect, const Color& color) { - if (paintingDisabled()) + if (contextDisabled()) return; Path path; @@ -1687,12 +1585,11 @@ void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const Rounded void GraphicsContext::clearRect(const FloatRect& rect) { - if (paintingDisabled()) + if (contextDisabled()) return; SkRect r = rect; - SkPaint paint; - setupPaintForFilling(&paint); + SkPaint paint(immutableState()->fillPaint()); paint.setXfermodeMode(SkXfermode::kClear_Mode); drawRect(r, paint); } @@ -1732,51 +1629,24 @@ PassOwnPtr<ImageBuffer> GraphicsContext::createCompatibleBuffer(const IntSize& s // resolution than one pixel per unit. Also set up a corresponding scale factor on the // graphics context. - AffineTransform transform = getCTM(DefinitelyIncludeDeviceScale); + AffineTransform transform = getCTM(); IntSize scaledSize(static_cast<int>(ceil(size.width() * transform.xScale())), static_cast<int>(ceil(size.height() * transform.yScale()))); - RefPtr<SkBaseDevice> device = adoptRef(m_canvas->getTopDevice()->createCompatibleDevice(SkBitmap::kARGB_8888_Config, size.width(), size.height(), opacityMode == Opaque)); - if (!device) + SkAlphaType alphaType = (opacityMode == Opaque) ? kOpaque_SkAlphaType : kPremul_SkAlphaType; + SkImageInfo info = SkImageInfo::MakeN32(size.width(), size.height(), alphaType); + RefPtr<SkSurface> skSurface = adoptRef(m_canvas->newSurface(info)); + if (!skSurface) return nullptr; - OwnPtr<ImageBufferSurface> surface = adoptPtr(new CompatibleImageBufferSurface(device.release(), scaledSize, opacityMode)); + OwnPtr<ImageBufferSurface> surface = adoptPtr(new CompatibleImageBufferSurface(skSurface.release(), scaledSize, opacityMode)); ASSERT(surface->isValid()); OwnPtr<ImageBuffer> buffer = adoptPtr(new ImageBuffer(surface.release())); - buffer->context()->scale(FloatSize(static_cast<float>(scaledSize.width()) / size.width(), - static_cast<float>(scaledSize.height()) / size.height())); + buffer->context()->scale(static_cast<float>(scaledSize.width()) / size.width(), + static_cast<float>(scaledSize.height()) / size.height()); return buffer.release(); } -void GraphicsContext::addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int startAngle) -{ - SkIRect ir; - int rx = SkMin32(SkScalarRound(rect.width()), size.width()); - int ry = SkMin32(SkScalarRound(rect.height()), size.height()); - - ir.set(-rx, -ry, rx, ry); - switch (startAngle) { - case 0: - ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom); - break; - case 90: - ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom); - break; - case 180: - ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop); - break; - case 270: - ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop); - break; - default: - ASSERT(0); - } - - SkRect r; - r.set(ir); - path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false); -} - void GraphicsContext::setPathFromConvexPoints(SkPath* path, size_t numPoints, const FloatPoint* points) { path->incReserve(numPoints); @@ -1799,35 +1669,15 @@ void GraphicsContext::setPathFromConvexPoints(SkPath* path, size_t numPoints, co path->setConvexity(convexity); } -void GraphicsContext::setupPaintCommon(SkPaint* paint) const -{ -#if defined(SK_DEBUG) - { - SkPaint defaultPaint; - SkASSERT(*paint == defaultPaint); - } -#endif - - paint->setAntiAlias(m_state->m_shouldAntialias); - - if (!SkXfermode::IsMode(m_state->m_xferMode.get(), SkXfermode::kSrcOver_Mode)) - paint->setXfermode(m_state->m_xferMode.get()); - - if (m_state->m_looper) - paint->setLooper(m_state->m_looper.get()); - - paint->setColorFilter(m_state->m_colorFilter.get()); -} - void GraphicsContext::drawOuterPath(const SkPath& path, SkPaint& paint, int width) { #if OS(MACOSX) paint.setAlpha(64); paint.setStrokeWidth(width); - paint.setPathEffect(new SkCornerPathEffect((width - 1) * 0.5f))->unref(); + paint.setPathEffect(SkCornerPathEffect::Create((width - 1) * 0.5f))->unref(); #else paint.setStrokeWidth(1); - paint.setPathEffect(new SkCornerPathEffect(1))->unref(); + paint.setPathEffect(SkCornerPathEffect::Create(1))->unref(); #endif drawPath(path, paint); } @@ -1869,16 +1719,10 @@ PassRefPtr<SkColorFilter> GraphicsContext::WebCoreColorFilterToSkiaColorFilter(C break; } - return 0; + return nullptr; } -#if OS(MACOSX) -CGColorSpaceRef PLATFORM_EXPORT deviceRGBColorSpaceRef() -{ - static CGColorSpaceRef deviceSpace = CGColorSpaceCreateDeviceRGB(); - return deviceSpace; -} -#else +#if !OS(MACOSX) void GraphicsContext::draw2xMarker(SkBitmap* bitmap, int index) { const SkPMColor lineColor = lineColors(index); @@ -1970,31 +1814,10 @@ const SkPMColor GraphicsContext::antiColors2(int index) } #endif -void GraphicsContext::setupShader(SkPaint* paint, Gradient* grad, Pattern* pat, SkColor color) const -{ - RefPtr<SkShader> shader; - - if (grad) { - shader = grad->shader(); - color = SK_ColorBLACK; - } else if (pat) { - shader = pat->shader(); - color = SK_ColorBLACK; - paint->setFilterBitmap(imageInterpolationQuality() != InterpolationNone); - } - - paint->setColor(m_state->applyAlpha(color)); - - if (!shader) - return; - - paint->setShader(shader.get()); -} - void GraphicsContext::didDrawTextInRect(const SkRect& textRect) { if (m_trackTextRegion) { - TRACE_EVENT0("skia", "PlatformContextSkia::trackTextRegion"); + TRACE_EVENT0("skia", "GraphicsContext::didDrawTextInRect"); m_textRegion.join(textRect); } } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext.h b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext.h index d756c011043..ab1eeccedc9 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext.h @@ -29,19 +29,15 @@ #define GraphicsContext_h #include "platform/PlatformExport.h" -#include "platform/TraceEvent.h" #include "platform/fonts/Font.h" #include "platform/geometry/FloatRect.h" #include "platform/graphics/DashArray.h" -#include "platform/graphics/DrawLooper.h" +#include "platform/graphics/DrawLooperBuilder.h" #include "platform/graphics/ImageBufferSurface.h" #include "platform/graphics/ImageOrientation.h" #include "platform/graphics/GraphicsContextAnnotation.h" #include "platform/graphics/GraphicsContextState.h" #include "platform/graphics/skia/OpaqueRegionSkia.h" -#include "platform/graphics/skia/SkiaUtils.h" -// TODO(robertphillips): replace this include with "class SkBaseDevice;" -#include "third_party/skia/include/core/SkDevice.h" #include "wtf/FastAllocBase.h" #include "wtf/Forward.h" #include "wtf/Noncopyable.h" @@ -59,6 +55,8 @@ class DisplayList; class ImageBuffer; class KURL; +typedef SkImageFilter ImageFilter; + class PLATFORM_EXPORT GraphicsContext { WTF_MAKE_NONCOPYABLE(GraphicsContext); WTF_MAKE_FAST_ALLOCATED; public: @@ -71,99 +69,131 @@ public: ReadWrite }; - explicit GraphicsContext(SkCanvas*); + enum DisabledMode { + NothingDisabled = 0, // Run as normal. + PaintingDisabled = 1, // Do not issue painting calls to the canvas but maintain state correctly. + FullyDisabled = 2 // Do absolutely minimal work to remove the cost of the context from performance tests. + }; + + explicit GraphicsContext(SkCanvas*, DisabledMode = NothingDisabled); ~GraphicsContext(); - // Returns the canvas used for painting, NOT guaranteed to be non-null. + // Returns the canvas used for painting. Must not be called if painting is disabled. // Accessing the backing canvas this way flushes all queued save ops, // so it should be avoided. Use the corresponding draw/matrix/clip methods instead. SkCanvas* canvas() { + ASSERT(!paintingDisabled()); + // Flush any pending saves. - realizeSave(SkCanvas::kMatrixClip_SaveFlag); + realizeCanvasSave(); return m_canvas; } - const SkCanvas* canvas() const { return m_canvas; } - bool paintingDisabled() const { return !m_canvas; } - - const SkBitmap* bitmap() const; - const SkBitmap& layerBitmap(AccessMode = ReadOnly) const; + const SkCanvas* canvas() const + { + ASSERT(!paintingDisabled()); + return m_canvas; + } + bool paintingDisabled() const { return m_disabledState & PaintingDisabled; } + bool contextDisabled() const { return m_disabledState; } + + // This is just a heuristic that currently happens to work. We need either + // a more reliable way to know that we are recording, or (better) we need + // to obviate the need for this query, and address whatever the caller + // needed in some other way. + // See bug# 372110 + bool isRecordingCanvas() const + { + return m_canvas->imageInfo().colorType() == kUnknown_SkColorType; + } // ---------- State management methods ----------------- void save(); void restore(); + unsigned saveCount() { return m_canvasStateStack.size(); } +#if ASSERT_ENABLED + void disableDestructionChecks() { m_disableDestructionChecks = true; } +#endif - void saveLayer(const SkRect* bounds, const SkPaint*, SkCanvas::SaveFlags = SkCanvas::kARGB_ClipLayer_SaveFlag); + void saveLayer(const SkRect* bounds, const SkPaint*); void restoreLayer(); - float strokeThickness() const { return m_state->m_strokeData.thickness(); } - void setStrokeThickness(float thickness) { m_state->m_strokeData.setThickness(thickness); } + float strokeThickness() const { return immutableState()->strokeData().thickness(); } + void setStrokeThickness(float thickness) { mutableState()->setStrokeThickness(thickness); } - StrokeStyle strokeStyle() const { return m_state->m_strokeData.style(); } - void setStrokeStyle(StrokeStyle style) { m_state->m_strokeData.setStyle(style); } + StrokeStyle strokeStyle() const { return immutableState()->strokeData().style(); } + void setStrokeStyle(StrokeStyle style) { mutableState()->setStrokeStyle(style); } - Color strokeColor() const { return m_state->m_strokeData.color(); } - void setStrokeColor(const Color&); + Color strokeColor() const { return immutableState()->strokeData().color(); } + void setStrokeColor(const Color& color) { mutableState()->setStrokeColor(color); } + SkColor effectiveStrokeColor() const { return immutableState()->effectiveStrokeColor(); } - Pattern* strokePattern() const { return m_state->m_strokeData.pattern(); } + Pattern* strokePattern() const { return immutableState()->strokeData().pattern(); } void setStrokePattern(PassRefPtr<Pattern>); - Gradient* strokeGradient() const { return m_state->m_strokeData.gradient(); } + Gradient* strokeGradient() const { return immutableState()->strokeData().gradient(); } void setStrokeGradient(PassRefPtr<Gradient>); - void setLineCap(LineCap cap) { m_state->m_strokeData.setLineCap(cap); } - void setLineDash(const DashArray& dashes, float dashOffset) { m_state->m_strokeData.setLineDash(dashes, dashOffset); } - void setLineJoin(LineJoin join) { m_state->m_strokeData.setLineJoin(join); } - void setMiterLimit(float limit) { m_state->m_strokeData.setMiterLimit(limit); } + void setLineCap(LineCap cap) { mutableState()->setLineCap(cap); } + void setLineDash(const DashArray& dashes, float dashOffset) { mutableState()->setLineDash(dashes, dashOffset); } + void setLineJoin(LineJoin join) { mutableState()->setLineJoin(join); } + void setMiterLimit(float limit) { mutableState()->setMiterLimit(limit); } - WindRule fillRule() const { return m_state->m_fillRule; } - void setFillRule(WindRule fillRule) { m_state->m_fillRule = fillRule; } + WindRule fillRule() const { return immutableState()->fillRule(); } + void setFillRule(WindRule fillRule) { mutableState()->setFillRule(fillRule); } - Color fillColor() const { return m_state->m_fillColor; } - void setFillColor(const Color&); - SkColor effectiveFillColor() const { return m_state->applyAlpha(m_state->m_fillColor.rgb()); } + Color fillColor() const { return immutableState()->fillColor(); } + void setFillColor(const Color& color) { mutableState()->setFillColor(color); } + SkColor effectiveFillColor() const { return immutableState()->effectiveFillColor(); } void setFillPattern(PassRefPtr<Pattern>); - Pattern* fillPattern() const { return m_state->m_fillPattern.get(); } + Pattern* fillPattern() const { return immutableState()->fillPattern(); } void setFillGradient(PassRefPtr<Gradient>); - Gradient* fillGradient() const { return m_state->m_fillGradient.get(); } - - SkDrawLooper* drawLooper() const { return m_state->m_looper.get(); } - SkColor effectiveStrokeColor() const { return m_state->applyAlpha(m_state->m_strokeData.color().rgb()); } + Gradient* fillGradient() const { return immutableState()->fillGradient(); } - int getNormalizedAlpha() const; + SkDrawLooper* drawLooper() const { return immutableState()->drawLooper(); } - bool getClipBounds(SkRect* bounds) const; bool getTransformedClipBounds(FloatRect* bounds) const; SkMatrix getTotalMatrix() const; - bool isPrintingDevice() const; - void setShouldAntialias(bool antialias) { m_state->m_shouldAntialias = antialias; } - bool shouldAntialias() const { return m_state->m_shouldAntialias; } + void setShouldAntialias(bool antialias) { mutableState()->setShouldAntialias(antialias); } + bool shouldAntialias() const { return immutableState()->shouldAntialias(); } + + // Disable the anti-aliasing optimization for scales/multiple-of-90-degrees + // rotations of thin ("hairline") images. + // Note: This will only be reliable when the device pixel scale/ratio is + // fixed (e.g. when drawing to context backed by an ImageBuffer). + void disableAntialiasingOptimizationForHairlineImages() { ASSERT(!isRecording()); m_antialiasHairlineImages = true; } + bool shouldAntialiasHairlineImages() const { return m_antialiasHairlineImages; } - void setShouldClampToSourceRect(bool clampToSourceRect) { m_state->m_shouldClampToSourceRect = clampToSourceRect; } - bool shouldClampToSourceRect() const { return m_state->m_shouldClampToSourceRect; } + void setShouldClampToSourceRect(bool clampToSourceRect) { mutableState()->setShouldClampToSourceRect(clampToSourceRect); } + bool shouldClampToSourceRect() const { return immutableState()->shouldClampToSourceRect(); } - void setShouldSmoothFonts(bool smoothFonts) { m_state->m_shouldSmoothFonts = smoothFonts; } - bool shouldSmoothFonts() const { return m_state->m_shouldSmoothFonts; } + void setShouldSmoothFonts(bool smoothFonts) { mutableState()->setShouldSmoothFonts(smoothFonts); } + bool shouldSmoothFonts() const { return immutableState()->shouldSmoothFonts(); } // Turn off LCD text for the paint if not supported on this context. void adjustTextRenderMode(SkPaint*); bool couldUseLCDRenderedText(); - TextDrawingModeFlags textDrawingMode() const { return m_state->m_textDrawingMode; } - void setTextDrawingMode(TextDrawingModeFlags mode) { m_state->m_textDrawingMode = mode; } + void setTextDrawingMode(TextDrawingModeFlags mode) { mutableState()->setTextDrawingMode(mode); } + TextDrawingModeFlags textDrawingMode() const { return immutableState()->textDrawingMode(); } - void setAlpha(float alpha) { m_state->m_alpha = alpha; } + void setAlphaAsFloat(float alpha) { mutableState()->setAlphaAsFloat(alpha);} + int getNormalizedAlpha() const + { + int alpha = immutableState()->alpha(); + return alpha > 255 ? 255 : alpha; + } - void setImageInterpolationQuality(InterpolationQuality quality) { m_state->m_interpolationQuality = quality; } - InterpolationQuality imageInterpolationQuality() const { return m_state->m_interpolationQuality; } + void setImageInterpolationQuality(InterpolationQuality quality) { mutableState()->setInterpolationQuality(quality); } + InterpolationQuality imageInterpolationQuality() const { return immutableState()->interpolationQuality(); } void setCompositeOperation(CompositeOperator, blink::WebBlendMode = blink::WebBlendModeNormal); - CompositeOperator compositeOperation() const { return m_state->m_compositeOperator; } - blink::WebBlendMode blendModeOperation() const { return m_state->m_blendMode; } + CompositeOperator compositeOperation() const { return immutableState()->compositeOperator(); } + blink::WebBlendMode blendModeOperation() const { return immutableState()->blendMode(); } // Change the way document markers are rendered. // Any deviceScaleFactor higher than 1.5 is enough to justify setting this flag. @@ -171,7 +201,7 @@ public: // If true we are (most likely) rendering to a web page and the // canvas has been prepared with an opaque background. If false, - // the canvas may havbe transparency (as is the case when rendering + // the canvas may have transparency (as is the case when rendering // to a canvas object). void setCertainlyOpaque(bool isOpaque) { m_isCertainlyOpaque = isOpaque; } bool isCertainlyOpaque() const { return m_isCertainlyOpaque; } @@ -206,16 +236,13 @@ public: // ---------- End state management methods ----------------- // Get the contents of the image buffer - bool readPixels(SkBitmap*, int, int, SkCanvas::Config8888 = SkCanvas::kNative_Premul_Config8888); + bool readPixels(const SkImageInfo&, void* pixels, size_t rowBytes, int x, int y); - // Sets up the paint for the current fill style. - void setupPaintForFilling(SkPaint*) const; + // Get the current fill style. + const SkPaint& fillPaint() const { return immutableState()->fillPaint(); } - // Sets up the paint for stroking. Returns a float representing the - // effective width of the pen. If a non-zero length is provided, the - // number of dashes/dots on a dashed/dotted line will be adjusted to - // start and end that length with a dash/dot. - float setupPaintForStroking(SkPaint*, int length = 0) const; + // Get the current stroke style. + const SkPaint& strokePaint() const { return immutableState()->strokePaint(); } // These draw methods will do both stroking and filling. // FIXME: ...except drawRect(), which fills properly but always strokes @@ -223,7 +250,6 @@ public: // stroke color). void drawRect(const IntRect&); void drawLine(const IntPoint&, const IntPoint&); - void drawEllipse(const IntRect&); void drawConvexPolygon(size_t numPoints, const FloatPoint*, bool shouldAntialias = false); void fillPath(const Path&); @@ -240,33 +266,33 @@ public: void clearRect(const FloatRect&); + void strokeRect(const FloatRect&); void strokeRect(const FloatRect&, float lineWidth); + void fillBetweenRoundedRects(const IntRect&, const IntSize& outerTopLeft, const IntSize& outerTopRight, const IntSize& outerBottomLeft, const IntSize& outerBottomRight, + const IntRect&, const IntSize& innerTopLeft, const IntSize& innerTopRight, const IntSize& innerBottomLeft, const IntSize& innerBottomRight, const Color&); + void fillBetweenRoundedRects(const RoundedRect&, const RoundedRect&, const Color&); + void drawDisplayList(DisplayList*); void drawImage(Image*, const IntPoint&, CompositeOperator = CompositeSourceOver, RespectImageOrientationEnum = DoNotRespectImageOrientation); - void drawImage(Image*, const IntRect&, CompositeOperator = CompositeSourceOver, RespectImageOrientationEnum = DoNotRespectImageOrientation, bool useLowQualityScale = false); - void drawImage(Image*, const IntPoint& destPoint, const IntRect& srcRect, CompositeOperator = CompositeSourceOver, RespectImageOrientationEnum = DoNotRespectImageOrientation); + void drawImage(Image*, const IntRect&, CompositeOperator = CompositeSourceOver, RespectImageOrientationEnum = DoNotRespectImageOrientation); void drawImage(Image*, const FloatRect& destRect); - void drawImage(Image*, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator = CompositeSourceOver, RespectImageOrientationEnum = DoNotRespectImageOrientation, bool useLowQualityScale = false); - void drawImage(Image*, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator, blink::WebBlendMode, RespectImageOrientationEnum = DoNotRespectImageOrientation, bool useLowQualityScale = false); + void drawImage(Image*, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator = CompositeSourceOver, RespectImageOrientationEnum = DoNotRespectImageOrientation); + void drawImage(Image*, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator, blink::WebBlendMode, RespectImageOrientationEnum = DoNotRespectImageOrientation); void drawTiledImage(Image*, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, - CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false, blink::WebBlendMode = blink::WebBlendModeNormal, const IntSize& repeatSpacing = IntSize()); + CompositeOperator = CompositeSourceOver, blink::WebBlendMode = blink::WebBlendModeNormal, const IntSize& repeatSpacing = IntSize()); void drawTiledImage(Image*, const IntRect& destRect, const IntRect& srcRect, const FloatSize& tileScaleFactor, Image::TileRule hRule = Image::StretchTile, Image::TileRule vRule = Image::StretchTile, - CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); + CompositeOperator = CompositeSourceOver); - void drawImageBuffer(ImageBuffer*, const IntPoint&, CompositeOperator = CompositeSourceOver, blink::WebBlendMode = blink::WebBlendModeNormal); - void drawImageBuffer(ImageBuffer*, const IntRect&, CompositeOperator = CompositeSourceOver, blink::WebBlendMode = blink::WebBlendModeNormal, bool useLowQualityScale = false); - void drawImageBuffer(ImageBuffer*, const IntPoint& destPoint, const IntRect& srcRect, CompositeOperator = CompositeSourceOver, blink::WebBlendMode = blink::WebBlendModeNormal); - void drawImageBuffer(ImageBuffer*, const IntRect& destRect, const IntRect& srcRect, CompositeOperator = CompositeSourceOver, blink::WebBlendMode = blink::WebBlendModeNormal, bool useLowQualityScale = false); - void drawImageBuffer(ImageBuffer*, const FloatRect& destRect); - void drawImageBuffer(ImageBuffer*, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator = CompositeSourceOver, blink::WebBlendMode = blink::WebBlendModeNormal, bool useLowQualityScale = false); + void drawImageBuffer(ImageBuffer*, const FloatRect& destRect, const FloatRect* srcRect = 0, CompositeOperator = CompositeSourceOver); // These methods write to the canvas and modify the opaque region, if tracked. // Also drawLine(const IntPoint& point1, const IntPoint& point2) and fillRoundedRect - void writePixels(const SkBitmap&, int x, int y, SkCanvas::Config8888 = SkCanvas::kNative_Premul_Config8888); + void writePixels(const SkImageInfo&, const void* pixels, size_t rowBytes, int x, int y); + void writePixels(const SkBitmap&, int x, int y); void drawBitmap(const SkBitmap&, SkScalar, SkScalar, const SkPaint* = 0); void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint* = 0); void drawOval(const SkRect&, const SkPaint&); @@ -278,17 +304,15 @@ public: void didDrawRect(const SkRect&, const SkPaint&, const SkBitmap* = 0); void drawRect(const SkRect&, const SkPaint&); void drawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkRect& textRect, const SkPaint&); - void drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkRect& textRect, const SkPaint&); - void drawTextOnPath(const void* text, size_t byteLength, const SkPath&, const SkRect& textRect, const SkMatrix*, const SkPaint&); - void clip(const IntRect& rect) { clip(FloatRect(rect)); } + void clip(const IntRect& rect) { clipRect(rect); } void clip(const FloatRect& rect) { clipRect(rect); } - void clipRoundedRect(const RoundedRect&); + void clipRoundedRect(const RoundedRect&, SkRegion::Op = SkRegion::kIntersect_Op); void clipOut(const IntRect& rect) { clipRect(rect, NotAntiAliased, SkRegion::kDifference_Op); } void clipOutRoundedRect(const RoundedRect&); void clipPath(const Path&, WindRule = RULE_EVENODD); void clipConvexPolygon(size_t numPoints, const FloatPoint*, bool antialias = true); - bool clipRect(const SkRect&, AntiAliasingMode = NotAntiAliased, SkRegion::Op = SkRegion::kIntersect_Op); + void clipRect(const SkRect&, AntiAliasingMode = NotAntiAliased, SkRegion::Op = SkRegion::kIntersect_Op); void drawText(const Font&, const TextRunPaintInfo&, const FloatPoint&); void drawEmphasisMarks(const Font&, const TextRunPaintInfo&, const AtomicString& mark, const FloatPoint&); @@ -303,9 +327,12 @@ public: void drawLineForDocumentMarker(const FloatPoint&, float width, DocumentMarkerLineStyle); void beginTransparencyLayer(float opacity, const FloatRect* = 0); - void beginLayer(float opacity, CompositeOperator, const FloatRect* = 0, ColorFilter = ColorFilterNone); + void beginLayer(float opacity, CompositeOperator, const FloatRect* = 0, ColorFilter = ColorFilterNone, ImageFilter* = 0); void endLayer(); + void beginCull(const FloatRect&); + void endCull(); + // Instead of being dispatched to the active canvas, draw commands following beginRecording() // are stored in a display list that can be replayed at a later time. void beginRecording(const FloatRect& bounds); @@ -313,13 +340,14 @@ public: bool hasShadow() const; void setShadow(const FloatSize& offset, float blur, const Color&, - DrawLooper::ShadowTransformMode = DrawLooper::ShadowRespectsTransforms, - DrawLooper::ShadowAlphaMode = DrawLooper::ShadowRespectsAlpha); + DrawLooperBuilder::ShadowTransformMode = DrawLooperBuilder::ShadowRespectsTransforms, + DrawLooperBuilder::ShadowAlphaMode = DrawLooperBuilder::ShadowRespectsAlpha); void clearShadow() { clearDrawLooper(); } // It is assumed that this draw looper is used only for shadows // (i.e. a draw looper is set if and only if there is a shadow). - void setDrawLooper(const DrawLooper&); + // The builder passed into this method will be destroyed. + void setDrawLooper(PassOwnPtr<DrawLooperBuilder>); void clearDrawLooper(); void drawFocusRing(const Vector<IntRect>&, int width, int offset, const Color&); @@ -342,20 +370,21 @@ public: void clipOut(const Path&); // ---------- Transformation methods ----------------- - enum IncludeDeviceScale { DefinitelyIncludeDeviceScale, PossiblyIncludeDeviceScale }; - AffineTransform getCTM(IncludeDeviceScale includeScale = PossiblyIncludeDeviceScale) const; + // Note that the getCTM method returns only the current transform from Blink's perspective, + // which is not the final transform used to place content on screen. It cannot be relied upon + // for testing where a point will appear on screen or how large it will be. + AffineTransform getCTM() const; void concatCTM(const AffineTransform& affine) { concat(affineTransformToSkMatrix(affine)); } void setCTM(const AffineTransform& affine) { setMatrix(affineTransformToSkMatrix(affine)); } void setMatrix(const SkMatrix&); - void scale(const FloatSize&); + void scale(float x, float y); void rotate(float angleInRadians); - void translate(const FloatSize& size) { translate(size.width(), size.height()); } void translate(float x, float y); // This function applies the device scale factor to the context, making the context capable of // acting as a base-level context for a HiDPI environment. - void applyDeviceScaleFactor(float deviceScaleFactor) { scale(FloatSize(deviceScaleFactor, deviceScaleFactor)); } + void applyDeviceScaleFactor(float deviceScaleFactor) { scale(deviceScaleFactor, deviceScaleFactor); } // ---------- End transformation methods ----------------- // URL drawing @@ -374,7 +403,14 @@ public: void endAnnotation(); private: - static void addCornerArc(SkPath*, const SkRect&, const IntSize&, int); + const GraphicsContextState* immutableState() const { return m_paintState; } + + GraphicsContextState* mutableState() + { + realizePaintSave(); + return m_paintState; + } + static void setPathFromConvexPoints(SkPath*, size_t, const FloatPoint*); static void setRadii(SkVector*, IntSize, IntSize, IntSize, IntSize); @@ -391,91 +427,93 @@ private: static void draw2xMarker(SkBitmap*, int); #endif - // Return value % max, but account for value possibly being negative. - static int fastMod(int value, int max) - { - bool isNeg = false; - if (value < 0) { - value = -value; - isNeg = true; - } - if (value >= max) - value %= max; - if (isNeg) - value = -value; - return value; - } - - // Sets up the common flags on a paint for antialiasing, effects, etc. - // This is implicitly called by setupPaintFill and setupPaintStroke, but - // you may wish to call it directly sometimes if you don't want that other - // behavior. - void setupPaintCommon(SkPaint*) const; - // Helpers for drawing a focus ring (drawFocusRing) void drawOuterPath(const SkPath&, SkPaint&, int); void drawInnerPath(const SkPath&, SkPaint&, int); // SkCanvas wrappers. - bool isDrawingToLayer() const { return m_canvas->isDrawingToLayer(); } - - bool clipPath(const SkPath&, AntiAliasingMode = NotAntiAliased, SkRegion::Op = SkRegion::kIntersect_Op); - bool clipRRect(const SkRRect&, AntiAliasingMode = NotAntiAliased, SkRegion::Op = SkRegion::kIntersect_Op); - - bool concat(const SkMatrix&); + void clipPath(const SkPath&, AntiAliasingMode = NotAntiAliased, SkRegion::Op = SkRegion::kIntersect_Op); + void clipRRect(const SkRRect&, AntiAliasingMode = NotAntiAliased, SkRegion::Op = SkRegion::kIntersect_Op); - // common code between setupPaintFor[Filling,Stroking] - void setupShader(SkPaint*, Gradient*, Pattern*, SkColor) const; + void concat(const SkMatrix&); - // Apply deferred saves - void realizeSave(SkCanvas::SaveFlags flags) + // Apply deferred paint state saves + void realizePaintSave() { - if (m_deferredSaveFlags & flags) { - m_canvas->save((SkCanvas::SaveFlags)m_deferredSaveFlags); - m_deferredSaveFlags = 0; + if (contextDisabled()) + return; + + if (m_paintState->saveCount()) { + m_paintState->decrementSaveCount(); + ++m_paintStateIndex; + if (m_paintStateStack.size() == m_paintStateIndex) { + m_paintStateStack.append(GraphicsContextState::createAndCopy(*m_paintState)); + m_paintState = m_paintStateStack[m_paintStateIndex].get(); + } else { + GraphicsContextState* priorPaintState = m_paintState; + m_paintState = m_paintStateStack[m_paintStateIndex].get(); + m_paintState->copy(*priorPaintState); + } } } + // Apply deferred canvas state saves + void realizeCanvasSave() + { + if (!m_pendingCanvasSave || contextDisabled()) + return; + + m_canvas->save(); + m_pendingCanvasSave = false; + } + void didDrawTextInRect(const SkRect& textRect); void fillRectWithRoundedHole(const IntRect&, const RoundedRect& roundedHoleRect, const Color&); bool isRecording() const; - // null indicates painting is disabled. Never delete this object. + // null indicates painting is contextDisabled. Never delete this object. SkCanvas* m_canvas; - // Pointer to the current drawing state. This is a cached value of m_stateStack.last(). - GraphicsContextState* m_state; - // States stack. Enables local drawing state change with save()/restore() calls. - // Use OwnPtr to avoid copying the large state structure. - Vector<OwnPtr<GraphicsContextState> > m_stateStack; - - // Currently pending save flags. - // FIXME: While defined as a bitmask of SkCanvas::SaveFlags, this is mostly used as a bool. - // It will come in handy when adding granular save() support (clip vs. matrix vs. paint). - // crbug.com/233713 - struct DeferredSaveState; - unsigned m_deferredSaveFlags; - Vector<DeferredSaveState> m_saveStateStack; + // Paint states stack. Enables local drawing state change with save()/restore() calls. + // This state controls the appearance of drawn content. + // We do not delete from this stack to avoid memory churn. + Vector<OwnPtr<GraphicsContextState> > m_paintStateStack; + // Current index on the stack. May not be the last thing on the stack. + unsigned m_paintStateIndex; + // Raw pointer to the current state. + GraphicsContextState* m_paintState; + + // Currently pending save flags for Skia Canvas state. + // Canvas state includes the canavs, it's matrix and clips. Think of it as _where_ + // the draw operations will happen. + struct CanvasSaveState; + Vector<CanvasSaveState> m_canvasStateStack; + bool m_pendingCanvasSave; AnnotationModeFlags m_annotationMode; struct RecordingState; Vector<RecordingState> m_recordingStateStack; -#if !ASSERT_DISABLED +#if ASSERT_ENABLED unsigned m_annotationCount; unsigned m_layerCount; + bool m_disableDestructionChecks; #endif // Tracks the region painted opaque via the GraphicsContext. OpaqueRegionSkia m_opaqueRegion; - bool m_trackOpaqueRegion : 1; // Tracks the region where text is painted via the GraphicsContext. - bool m_trackTextRegion : 1; SkRect m_textRegion; + unsigned m_disabledState; + + // Activation for the above region tracking features + bool m_trackOpaqueRegion : 1; + bool m_trackTextRegion : 1; + // Are we on a high DPI display? If so, spelling and grammar markers are larger. bool m_useHighResMarker : 1; // FIXME: Make this go away: crbug.com/236892 @@ -483,6 +521,7 @@ private: bool m_accelerated : 1; bool m_isCertainlyOpaque : 1; bool m_printing : 1; + bool m_antialiasHairlineImages : 1; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext3D.cpp b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext3D.cpp deleted file mode 100644 index 7981c3a640b..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext3D.cpp +++ /dev/null @@ -1,944 +0,0 @@ -/* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * Copyright (C) 2010 Google Inc. All rights reserved. - * Copyright (C) 2010 Mozilla Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include "platform/graphics/GraphicsContext3D.h" -#include "platform/CheckedInt.h" -#include "platform/graphics/GraphicsContext.h" -#include "platform/graphics/ImageBuffer.h" -#include "platform/graphics/ImageObserver.h" -#include "platform/graphics/gpu/DrawingBuffer.h" -#include "platform/image-decoders/ImageDecoder.h" -#include "third_party/skia/include/gpu/GrContext.h" -#include "third_party/skia/include/gpu/gl/GrGLInterface.h" -#include "wtf/CPU.h" -#include "wtf/text/CString.h" -#include "wtf/text/StringHash.h" - -#include "public/platform/Platform.h" -#include "public/platform/WebGraphicsContext3D.h" -#include "public/platform/WebGraphicsContext3DProvider.h" - -namespace WebCore { - -namespace { - -void getDrawingParameters(DrawingBuffer* drawingBuffer, blink::WebGraphicsContext3D* graphicsContext3D, - Platform3DObject* frameBufferId, int* width, int* height) -{ - ASSERT(drawingBuffer); - *frameBufferId = drawingBuffer->framebuffer(); - *width = drawingBuffer->size().width(); - *height = drawingBuffer->size().height(); -} - -} // anonymous namespace - -GraphicsContext3D::GraphicsContext3D(PassOwnPtr<blink::WebGraphicsContext3D> webContext, bool preserveDrawingBuffer) - : m_impl(webContext.get()) - , m_ownedWebContext(webContext) - , m_initializedAvailableExtensions(false) - , m_layerComposited(false) - , m_preserveDrawingBuffer(preserveDrawingBuffer) - , m_packAlignment(4) - , m_resourceSafety(ResourceSafetyUnknown) - , m_grContext(0) -{ -} - -GraphicsContext3D::GraphicsContext3D(PassOwnPtr<blink::WebGraphicsContext3DProvider> provider, bool preserveDrawingBuffer) - : m_provider(provider) - , m_impl(m_provider->context3d()) - , m_initializedAvailableExtensions(false) - , m_layerComposited(false) - , m_preserveDrawingBuffer(preserveDrawingBuffer) - , m_packAlignment(4) - , m_resourceSafety(ResourceSafetyUnknown) - , m_grContext(m_provider->grContext()) -{ -} - -GraphicsContext3D::~GraphicsContext3D() -{ - setContextLostCallback(nullptr); - setErrorMessageCallback(nullptr); -} - -// Macros to assist in delegating from GraphicsContext3D to -// WebGraphicsContext3D. - -#define DELEGATE_TO_WEBCONTEXT(name) \ -void GraphicsContext3D::name() \ -{ \ - m_impl->name(); \ -} - -#define DELEGATE_TO_WEBCONTEXT_R(name, rt) \ -rt GraphicsContext3D::name() \ -{ \ - return m_impl->name(); \ -} - -#define DELEGATE_TO_WEBCONTEXT_1(name, t1) \ -void GraphicsContext3D::name(t1 a1) \ -{ \ - m_impl->name(a1); \ -} - -#define DELEGATE_TO_WEBCONTEXT_1R(name, t1, rt) \ -rt GraphicsContext3D::name(t1 a1) \ -{ \ - return m_impl->name(a1); \ -} - -#define DELEGATE_TO_WEBCONTEXT_2(name, t1, t2) \ -void GraphicsContext3D::name(t1 a1, t2 a2) \ -{ \ - m_impl->name(a1, a2); \ -} - -#define DELEGATE_TO_WEBCONTEXT_2R(name, t1, t2, rt) \ -rt GraphicsContext3D::name(t1 a1, t2 a2) \ -{ \ - return m_impl->name(a1, a2); \ -} - -#define DELEGATE_TO_WEBCONTEXT_3(name, t1, t2, t3) \ -void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3) \ -{ \ - m_impl->name(a1, a2, a3); \ -} - -#define DELEGATE_TO_WEBCONTEXT_3R(name, t1, t2, t3, rt) \ -rt GraphicsContext3D::name(t1 a1, t2 a2, t3 a3) \ -{ \ - return m_impl->name(a1, a2, a3); \ -} - -#define DELEGATE_TO_WEBCONTEXT_4(name, t1, t2, t3, t4) \ -void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4) \ -{ \ - m_impl->name(a1, a2, a3, a4); \ -} - -#define DELEGATE_TO_WEBCONTEXT_4R(name, t1, t2, t3, t4, rt) \ -rt GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4) \ -{ \ - return m_impl->name(a1, a2, a3, a4); \ -} - -#define DELEGATE_TO_WEBCONTEXT_5(name, t1, t2, t3, t4, t5) \ -void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) \ -{ \ - m_impl->name(a1, a2, a3, a4, a5); \ -} - -#define DELEGATE_TO_WEBCONTEXT_6(name, t1, t2, t3, t4, t5, t6) \ -void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) \ -{ \ - m_impl->name(a1, a2, a3, a4, a5, a6); \ -} - -#define DELEGATE_TO_WEBCONTEXT_6R(name, t1, t2, t3, t4, t5, t6, rt) \ -rt GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) \ -{ \ - return m_impl->name(a1, a2, a3, a4, a5, a6); \ -} - -#define DELEGATE_TO_WEBCONTEXT_7(name, t1, t2, t3, t4, t5, t6, t7) \ -void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7) \ -{ \ - m_impl->name(a1, a2, a3, a4, a5, a6, a7); \ -} - -#define DELEGATE_TO_WEBCONTEXT_7R(name, t1, t2, t3, t4, t5, t6, t7, rt) \ -rt GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7) \ -{ \ - return m_impl->name(a1, a2, a3, a4, a5, a6, a7); \ -} - -#define DELEGATE_TO_WEBCONTEXT_8(name, t1, t2, t3, t4, t5, t6, t7, t8) \ -void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8) \ -{ \ - m_impl->name(a1, a2, a3, a4, a5, a6, a7, a8); \ -} - -#define DELEGATE_TO_WEBCONTEXT_9(name, t1, t2, t3, t4, t5, t6, t7, t8, t9) \ -void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8, t9 a9) \ -{ \ - m_impl->name(a1, a2, a3, a4, a5, a6, a7, a8, a9); \ -} - -#define DELEGATE_TO_WEBCONTEXT_9R(name, t1, t2, t3, t4, t5, t6, t7, t8, t9, rt) \ -rt GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8, t9 a9) \ -{ \ - return m_impl->name(a1, a2, a3, a4, a5, a6, a7, a8, a9); \ -} - -class GraphicsContext3DContextLostCallbackAdapter : public blink::WebGraphicsContext3D::WebGraphicsContextLostCallback { -public: - GraphicsContext3DContextLostCallbackAdapter(PassOwnPtr<GraphicsContext3D::ContextLostCallback> callback) - : m_contextLostCallback(callback) { } - virtual ~GraphicsContext3DContextLostCallbackAdapter() { } - - virtual void onContextLost() - { - if (m_contextLostCallback) - m_contextLostCallback->onContextLost(); - } -private: - OwnPtr<GraphicsContext3D::ContextLostCallback> m_contextLostCallback; -}; - -class GraphicsContext3DErrorMessageCallbackAdapter : public blink::WebGraphicsContext3D::WebGraphicsErrorMessageCallback { -public: - GraphicsContext3DErrorMessageCallbackAdapter(PassOwnPtr<GraphicsContext3D::ErrorMessageCallback> callback) - : m_errorMessageCallback(callback) { } - virtual ~GraphicsContext3DErrorMessageCallbackAdapter() { } - - virtual void onErrorMessage(const blink::WebString& message, blink::WGC3Dint id) - { - if (m_errorMessageCallback) - m_errorMessageCallback->onErrorMessage(message, id); - } -private: - OwnPtr<GraphicsContext3D::ErrorMessageCallback> m_errorMessageCallback; -}; - -void GraphicsContext3D::setContextLostCallback(PassOwnPtr<GraphicsContext3D::ContextLostCallback> callback) -{ - if (m_ownedWebContext) { - m_contextLostCallbackAdapter = adoptPtr(new GraphicsContext3DContextLostCallbackAdapter(callback)); - m_ownedWebContext->setContextLostCallback(m_contextLostCallbackAdapter.get()); - } -} - -void GraphicsContext3D::setErrorMessageCallback(PassOwnPtr<GraphicsContext3D::ErrorMessageCallback> callback) -{ - if (m_ownedWebContext) { - m_errorMessageCallbackAdapter = adoptPtr(new GraphicsContext3DErrorMessageCallbackAdapter(callback)); - m_ownedWebContext->setErrorMessageCallback(m_errorMessageCallbackAdapter.get()); - } -} - -PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs) -{ - blink::WebGraphicsContext3D::Attributes webAttributes; - webAttributes.alpha = attrs.alpha; - webAttributes.depth = attrs.depth; - webAttributes.stencil = attrs.stencil; - webAttributes.antialias = attrs.antialias; - webAttributes.premultipliedAlpha = attrs.premultipliedAlpha; - webAttributes.noExtensions = attrs.noExtensions; - webAttributes.shareResources = attrs.shareResources; - webAttributes.preferDiscreteGPU = attrs.preferDiscreteGPU; - webAttributes.failIfMajorPerformanceCaveat = attrs.failIfMajorPerformanceCaveat; - webAttributes.topDocumentURL = attrs.topDocumentURL.string(); - - OwnPtr<blink::WebGraphicsContext3D> webContext = adoptPtr(blink::Platform::current()->createOffscreenGraphicsContext3D(webAttributes)); - if (!webContext) - return 0; - - return GraphicsContext3D::createGraphicsContextFromWebContext(webContext.release(), attrs.preserveDrawingBuffer); -} - -PassRefPtr<GraphicsContext3D> GraphicsContext3D::createGraphicsContextFromProvider(PassOwnPtr<blink::WebGraphicsContext3DProvider> provider, bool preserveDrawingBuffer) -{ - RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(provider, preserveDrawingBuffer)); - return context.release(); -} - -PassRefPtr<GraphicsContext3D> GraphicsContext3D::createGraphicsContextFromWebContext(PassOwnPtr<blink::WebGraphicsContext3D> webContext, bool preserveDrawingBuffer) -{ - RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(webContext, preserveDrawingBuffer)); - return context.release(); -} - -GrContext* GraphicsContext3D::grContext() -{ - return m_grContext; -} - -DELEGATE_TO_WEBCONTEXT_R(makeContextCurrent, bool) -DELEGATE_TO_WEBCONTEXT_R(lastFlushID, uint32_t) - -DELEGATE_TO_WEBCONTEXT_1(activeTexture, GC3Denum) -DELEGATE_TO_WEBCONTEXT_2(attachShader, Platform3DObject, Platform3DObject) - -void GraphicsContext3D::bindAttribLocation(Platform3DObject program, GC3Duint index, const String& name) -{ - m_impl->bindAttribLocation(program, index, name.utf8().data()); -} - -DELEGATE_TO_WEBCONTEXT_2(bindBuffer, GC3Denum, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_2(bindFramebuffer, GC3Denum, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_2(bindRenderbuffer, GC3Denum, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_2(bindTexture, GC3Denum, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_4(blendColor, GC3Dclampf, GC3Dclampf, GC3Dclampf, GC3Dclampf) -DELEGATE_TO_WEBCONTEXT_1(blendEquation, GC3Denum) -DELEGATE_TO_WEBCONTEXT_2(blendEquationSeparate, GC3Denum, GC3Denum) -DELEGATE_TO_WEBCONTEXT_2(blendFunc, GC3Denum, GC3Denum) -DELEGATE_TO_WEBCONTEXT_4(blendFuncSeparate, GC3Denum, GC3Denum, GC3Denum, GC3Denum) - -void GraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage) -{ - bufferData(target, size, 0, usage); -} - -DELEGATE_TO_WEBCONTEXT_4(bufferData, GC3Denum, GC3Dsizeiptr, const void*, GC3Denum) -DELEGATE_TO_WEBCONTEXT_4(bufferSubData, GC3Denum, GC3Dintptr, GC3Dsizeiptr, const void*) - -DELEGATE_TO_WEBCONTEXT_1R(checkFramebufferStatus, GC3Denum, GC3Denum) -DELEGATE_TO_WEBCONTEXT_1(clear, GC3Dbitfield) -DELEGATE_TO_WEBCONTEXT_4(clearColor, GC3Dclampf, GC3Dclampf, GC3Dclampf, GC3Dclampf) -DELEGATE_TO_WEBCONTEXT_1(clearDepth, GC3Dclampf) -DELEGATE_TO_WEBCONTEXT_1(clearStencil, GC3Dint) -DELEGATE_TO_WEBCONTEXT_4(colorMask, GC3Dboolean, GC3Dboolean, GC3Dboolean, GC3Dboolean) -DELEGATE_TO_WEBCONTEXT_1(compileShader, Platform3DObject) - -DELEGATE_TO_WEBCONTEXT_8(compressedTexImage2D, GC3Denum, GC3Dint, GC3Denum, GC3Dint, GC3Dint, GC3Dsizei, GC3Dsizei, const void*) -DELEGATE_TO_WEBCONTEXT_9(compressedTexSubImage2D, GC3Denum, GC3Dint, GC3Dint, GC3Dint, GC3Dint, GC3Dint, GC3Denum, GC3Dsizei, const void*) -DELEGATE_TO_WEBCONTEXT_8(copyTexImage2D, GC3Denum, GC3Dint, GC3Denum, GC3Dint, GC3Dint, GC3Dsizei, GC3Dsizei, GC3Dint) -DELEGATE_TO_WEBCONTEXT_8(copyTexSubImage2D, GC3Denum, GC3Dint, GC3Dint, GC3Dint, GC3Dint, GC3Dint, GC3Dsizei, GC3Dsizei) -DELEGATE_TO_WEBCONTEXT_1(cullFace, GC3Denum) -DELEGATE_TO_WEBCONTEXT_1(depthFunc, GC3Denum) -DELEGATE_TO_WEBCONTEXT_1(depthMask, GC3Dboolean) -DELEGATE_TO_WEBCONTEXT_2(depthRange, GC3Dclampf, GC3Dclampf) -DELEGATE_TO_WEBCONTEXT_2(detachShader, Platform3DObject, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_1(disable, GC3Denum) -DELEGATE_TO_WEBCONTEXT_1(disableVertexAttribArray, GC3Duint) -DELEGATE_TO_WEBCONTEXT_3(drawArrays, GC3Denum, GC3Dint, GC3Dsizei) -DELEGATE_TO_WEBCONTEXT_4(drawElements, GC3Denum, GC3Dsizei, GC3Denum, GC3Dintptr) - -DELEGATE_TO_WEBCONTEXT_1(enable, GC3Denum) -DELEGATE_TO_WEBCONTEXT_1(enableVertexAttribArray, GC3Duint) -DELEGATE_TO_WEBCONTEXT(finish) -DELEGATE_TO_WEBCONTEXT(flush) -DELEGATE_TO_WEBCONTEXT_4(framebufferRenderbuffer, GC3Denum, GC3Denum, GC3Denum, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_5(framebufferTexture2D, GC3Denum, GC3Denum, GC3Denum, Platform3DObject, GC3Dint) -DELEGATE_TO_WEBCONTEXT_1(frontFace, GC3Denum) -DELEGATE_TO_WEBCONTEXT_1(generateMipmap, GC3Denum) - -bool GraphicsContext3D::getActiveAttrib(Platform3DObject program, GC3Duint index, ActiveInfo& info) -{ - blink::WebGraphicsContext3D::ActiveInfo webInfo; - if (!m_impl->getActiveAttrib(program, index, webInfo)) - return false; - info.name = webInfo.name; - info.type = webInfo.type; - info.size = webInfo.size; - return true; -} - -bool GraphicsContext3D::getActiveUniform(Platform3DObject program, GC3Duint index, ActiveInfo& info) -{ - blink::WebGraphicsContext3D::ActiveInfo webInfo; - if (!m_impl->getActiveUniform(program, index, webInfo)) - return false; - info.name = webInfo.name; - info.type = webInfo.type; - info.size = webInfo.size; - return true; -} - -DELEGATE_TO_WEBCONTEXT_4(getAttachedShaders, Platform3DObject, GC3Dsizei, GC3Dsizei*, Platform3DObject*) - -GC3Dint GraphicsContext3D::getAttribLocation(Platform3DObject program, const String& name) -{ - return m_impl->getAttribLocation(program, name.utf8().data()); -} - -DELEGATE_TO_WEBCONTEXT_2(getBooleanv, GC3Denum, GC3Dboolean*) -DELEGATE_TO_WEBCONTEXT_3(getBufferParameteriv, GC3Denum, GC3Denum, GC3Dint*) - -GraphicsContext3D::Attributes GraphicsContext3D::getContextAttributes() -{ - blink::WebGraphicsContext3D::Attributes webAttributes = m_impl->getContextAttributes(); - GraphicsContext3D::Attributes attributes; - attributes.alpha = webAttributes.alpha; - attributes.depth = webAttributes.depth; - attributes.stencil = webAttributes.stencil; - attributes.antialias = webAttributes.antialias; - attributes.premultipliedAlpha = webAttributes.premultipliedAlpha; - attributes.preserveDrawingBuffer = m_preserveDrawingBuffer; - attributes.preferDiscreteGPU = webAttributes.preferDiscreteGPU; - return attributes; -} - -DELEGATE_TO_WEBCONTEXT_R(getError, GC3Denum) -DELEGATE_TO_WEBCONTEXT_2(getFloatv, GC3Denum, GC3Dfloat*) -DELEGATE_TO_WEBCONTEXT_4(getFramebufferAttachmentParameteriv, GC3Denum, GC3Denum, GC3Denum, GC3Dint*) -DELEGATE_TO_WEBCONTEXT_2(getIntegerv, GC3Denum, GC3Dint*) -DELEGATE_TO_WEBCONTEXT_3(getProgramiv, Platform3DObject, GC3Denum, GC3Dint*) -DELEGATE_TO_WEBCONTEXT_1R(getProgramInfoLog, Platform3DObject, String) -DELEGATE_TO_WEBCONTEXT_3(getRenderbufferParameteriv, GC3Denum, GC3Denum, GC3Dint*) -DELEGATE_TO_WEBCONTEXT_3(getShaderiv, Platform3DObject, GC3Denum, GC3Dint*) -DELEGATE_TO_WEBCONTEXT_1R(getShaderInfoLog, Platform3DObject, String) -DELEGATE_TO_WEBCONTEXT_4(getShaderPrecisionFormat, GC3Denum, GC3Denum, GC3Dint*, GC3Dint*) -DELEGATE_TO_WEBCONTEXT_1R(getShaderSource, Platform3DObject, String) -DELEGATE_TO_WEBCONTEXT_1R(getString, GC3Denum, String) -DELEGATE_TO_WEBCONTEXT_3(getTexParameterfv, GC3Denum, GC3Denum, GC3Dfloat*) -DELEGATE_TO_WEBCONTEXT_3(getTexParameteriv, GC3Denum, GC3Denum, GC3Dint*) -DELEGATE_TO_WEBCONTEXT_3(getUniformfv, Platform3DObject, GC3Dint, GC3Dfloat*) -DELEGATE_TO_WEBCONTEXT_3(getUniformiv, Platform3DObject, GC3Dint, GC3Dint*) - -GC3Dint GraphicsContext3D::getUniformLocation(Platform3DObject program, const String& name) -{ - return m_impl->getUniformLocation(program, name.utf8().data()); -} - -DELEGATE_TO_WEBCONTEXT_3(getVertexAttribfv, GC3Duint, GC3Denum, GC3Dfloat*) -DELEGATE_TO_WEBCONTEXT_3(getVertexAttribiv, GC3Duint, GC3Denum, GC3Dint*) -DELEGATE_TO_WEBCONTEXT_2R(getVertexAttribOffset, GC3Duint, GC3Denum, GC3Dsizeiptr) - -DELEGATE_TO_WEBCONTEXT_2(hint, GC3Denum, GC3Denum) -DELEGATE_TO_WEBCONTEXT_1R(isBuffer, Platform3DObject, GC3Dboolean) -DELEGATE_TO_WEBCONTEXT_1R(isEnabled, GC3Denum, GC3Dboolean) -DELEGATE_TO_WEBCONTEXT_1R(isFramebuffer, Platform3DObject, GC3Dboolean) -DELEGATE_TO_WEBCONTEXT_1R(isProgram, Platform3DObject, GC3Dboolean) -DELEGATE_TO_WEBCONTEXT_1R(isRenderbuffer, Platform3DObject, GC3Dboolean) -DELEGATE_TO_WEBCONTEXT_1R(isShader, Platform3DObject, GC3Dboolean) -DELEGATE_TO_WEBCONTEXT_1R(isTexture, Platform3DObject, GC3Dboolean) -DELEGATE_TO_WEBCONTEXT_1(lineWidth, GC3Dfloat) -DELEGATE_TO_WEBCONTEXT_1(linkProgram, Platform3DObject) - -void GraphicsContext3D::pixelStorei(GC3Denum pname, GC3Dint param) -{ - if (pname == GL_PACK_ALIGNMENT) - m_packAlignment = param; - m_impl->pixelStorei(pname, param); -} - -DELEGATE_TO_WEBCONTEXT_2(polygonOffset, GC3Dfloat, GC3Dfloat) - -DELEGATE_TO_WEBCONTEXT_7(readPixels, GC3Dint, GC3Dint, GC3Dsizei, GC3Dsizei, GC3Denum, GC3Denum, void*) - -DELEGATE_TO_WEBCONTEXT(releaseShaderCompiler) -DELEGATE_TO_WEBCONTEXT_4(renderbufferStorage, GC3Denum, GC3Denum, GC3Dsizei, GC3Dsizei) -DELEGATE_TO_WEBCONTEXT_2(sampleCoverage, GC3Dclampf, GC3Dboolean) -DELEGATE_TO_WEBCONTEXT_4(scissor, GC3Dint, GC3Dint, GC3Dsizei, GC3Dsizei) - -void GraphicsContext3D::shaderSource(Platform3DObject shader, const String& string) -{ - m_impl->shaderSource(shader, string.utf8().data()); -} - -DELEGATE_TO_WEBCONTEXT_3(stencilFunc, GC3Denum, GC3Dint, GC3Duint) -DELEGATE_TO_WEBCONTEXT_4(stencilFuncSeparate, GC3Denum, GC3Denum, GC3Dint, GC3Duint) -DELEGATE_TO_WEBCONTEXT_1(stencilMask, GC3Duint) -DELEGATE_TO_WEBCONTEXT_2(stencilMaskSeparate, GC3Denum, GC3Duint) -DELEGATE_TO_WEBCONTEXT_3(stencilOp, GC3Denum, GC3Denum, GC3Denum) -DELEGATE_TO_WEBCONTEXT_4(stencilOpSeparate, GC3Denum, GC3Denum, GC3Denum, GC3Denum) - -DELEGATE_TO_WEBCONTEXT_9(texImage2D, GC3Denum, GC3Dint, GC3Denum, GC3Dsizei, GC3Dsizei, GC3Dint, GC3Denum, GC3Denum, const void*) -DELEGATE_TO_WEBCONTEXT_3(texParameterf, GC3Denum, GC3Denum, GC3Dfloat) -DELEGATE_TO_WEBCONTEXT_3(texParameteri, GC3Denum, GC3Denum, GC3Dint) -DELEGATE_TO_WEBCONTEXT_9(texSubImage2D, GC3Denum, GC3Dint, GC3Dint, GC3Dint, GC3Dsizei, GC3Dsizei, GC3Denum, GC3Denum, const void*) - -DELEGATE_TO_WEBCONTEXT_2(uniform1f, GC3Dint, GC3Dfloat) -DELEGATE_TO_WEBCONTEXT_3(uniform1fv, GC3Dint, GC3Dsizei, GC3Dfloat*) -DELEGATE_TO_WEBCONTEXT_2(uniform1i, GC3Dint, GC3Dint) -DELEGATE_TO_WEBCONTEXT_3(uniform1iv, GC3Dint, GC3Dsizei, GC3Dint*) -DELEGATE_TO_WEBCONTEXT_3(uniform2f, GC3Dint, GC3Dfloat, GC3Dfloat) -DELEGATE_TO_WEBCONTEXT_3(uniform2fv, GC3Dint, GC3Dsizei, GC3Dfloat*) -DELEGATE_TO_WEBCONTEXT_3(uniform2i, GC3Dint, GC3Dint, GC3Dint) -DELEGATE_TO_WEBCONTEXT_3(uniform2iv, GC3Dint, GC3Dsizei, GC3Dint*) -DELEGATE_TO_WEBCONTEXT_4(uniform3f, GC3Dint, GC3Dfloat, GC3Dfloat, GC3Dfloat) -DELEGATE_TO_WEBCONTEXT_3(uniform3fv, GC3Dint, GC3Dsizei, GC3Dfloat*) -DELEGATE_TO_WEBCONTEXT_4(uniform3i, GC3Dint, GC3Dint, GC3Dint, GC3Dint) -DELEGATE_TO_WEBCONTEXT_3(uniform3iv, GC3Dint, GC3Dsizei, GC3Dint*) -DELEGATE_TO_WEBCONTEXT_5(uniform4f, GC3Dint, GC3Dfloat, GC3Dfloat, GC3Dfloat, GC3Dfloat) -DELEGATE_TO_WEBCONTEXT_3(uniform4fv, GC3Dint, GC3Dsizei, GC3Dfloat*) -DELEGATE_TO_WEBCONTEXT_5(uniform4i, GC3Dint, GC3Dint, GC3Dint, GC3Dint, GC3Dint) -DELEGATE_TO_WEBCONTEXT_3(uniform4iv, GC3Dint, GC3Dsizei, GC3Dint*) -DELEGATE_TO_WEBCONTEXT_4(uniformMatrix2fv, GC3Dint, GC3Dsizei, GC3Dboolean, GC3Dfloat*) -DELEGATE_TO_WEBCONTEXT_4(uniformMatrix3fv, GC3Dint, GC3Dsizei, GC3Dboolean, GC3Dfloat*) -DELEGATE_TO_WEBCONTEXT_4(uniformMatrix4fv, GC3Dint, GC3Dsizei, GC3Dboolean, GC3Dfloat*) - -DELEGATE_TO_WEBCONTEXT_1(useProgram, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_1(validateProgram, Platform3DObject) - -DELEGATE_TO_WEBCONTEXT_2(vertexAttrib1f, GC3Duint, GC3Dfloat) -DELEGATE_TO_WEBCONTEXT_2(vertexAttrib1fv, GC3Duint, GC3Dfloat*) -DELEGATE_TO_WEBCONTEXT_3(vertexAttrib2f, GC3Duint, GC3Dfloat, GC3Dfloat) -DELEGATE_TO_WEBCONTEXT_2(vertexAttrib2fv, GC3Duint, GC3Dfloat*) -DELEGATE_TO_WEBCONTEXT_4(vertexAttrib3f, GC3Duint, GC3Dfloat, GC3Dfloat, GC3Dfloat) -DELEGATE_TO_WEBCONTEXT_2(vertexAttrib3fv, GC3Duint, GC3Dfloat*) -DELEGATE_TO_WEBCONTEXT_5(vertexAttrib4f, GC3Duint, GC3Dfloat, GC3Dfloat, GC3Dfloat, GC3Dfloat) -DELEGATE_TO_WEBCONTEXT_2(vertexAttrib4fv, GC3Duint, GC3Dfloat*) -DELEGATE_TO_WEBCONTEXT_6(vertexAttribPointer, GC3Duint, GC3Dint, GC3Denum, GC3Dboolean, GC3Dsizei, GC3Dintptr) - -DELEGATE_TO_WEBCONTEXT_4(viewport, GC3Dint, GC3Dint, GC3Dsizei, GC3Dsizei) - -void GraphicsContext3D::markContextChanged() -{ - m_layerComposited = false; -} - -bool GraphicsContext3D::layerComposited() const -{ - return m_layerComposited; -} - -void GraphicsContext3D::markLayerComposited() -{ - m_layerComposited = true; -} - -void GraphicsContext3D::paintRenderingResultsToCanvas(ImageBuffer* imageBuffer, DrawingBuffer* drawingBuffer) -{ - Platform3DObject framebufferId; - int width, height; - getDrawingParameters(drawingBuffer, m_impl, &framebufferId, &width, &height); - paintFramebufferToCanvas(framebufferId, width, height, !getContextAttributes().premultipliedAlpha, imageBuffer); -} - -PassRefPtr<Uint8ClampedArray> GraphicsContext3D::paintRenderingResultsToImageData(DrawingBuffer* drawingBuffer, int& width, int& height) -{ - if (getContextAttributes().premultipliedAlpha) - return 0; - - Platform3DObject framebufferId; - getDrawingParameters(drawingBuffer, m_impl, &framebufferId, &width, &height); - - Checked<int, RecordOverflow> dataSize = 4; - dataSize *= width; - dataSize *= height; - if (dataSize.hasOverflowed()) - return 0; - - RefPtr<Uint8ClampedArray> pixels = Uint8ClampedArray::createUninitialized(width * height * 4); - - m_impl->bindFramebuffer(GL_FRAMEBUFFER, framebufferId); - readBackFramebuffer(pixels->data(), width, height, ReadbackRGBA, AlphaDoNothing); - flipVertically(pixels->data(), width, height); - - return pixels.release(); -} - -void GraphicsContext3D::readBackFramebuffer(unsigned char* pixels, int width, int height, ReadbackOrder readbackOrder, AlphaOp op) -{ - if (m_packAlignment > 4) - m_impl->pixelStorei(GL_PACK_ALIGNMENT, 1); - m_impl->readPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - if (m_packAlignment > 4) - m_impl->pixelStorei(GL_PACK_ALIGNMENT, m_packAlignment); - - size_t bufferSize = 4 * width * height; - - if (readbackOrder == ReadbackSkia) { -#if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT - // Swizzle red and blue channels to match SkBitmap's byte ordering. - // TODO(kbr): expose GL_BGRA as extension. - for (size_t i = 0; i < bufferSize; i += 4) { - std::swap(pixels[i], pixels[i + 2]); - } -#endif - } - - if (op == AlphaDoPremultiply) { - for (size_t i = 0; i < bufferSize; i += 4) { - pixels[i + 0] = std::min(255, pixels[i + 0] * pixels[i + 3] / 255); - pixels[i + 1] = std::min(255, pixels[i + 1] * pixels[i + 3] / 255); - pixels[i + 2] = std::min(255, pixels[i + 2] * pixels[i + 3] / 255); - } - } else if (op != AlphaDoNothing) { - ASSERT_NOT_REACHED(); - } -} - -DELEGATE_TO_WEBCONTEXT_R(createBuffer, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_R(createFramebuffer, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_R(createProgram, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_R(createRenderbuffer, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_1R(createShader, GC3Denum, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_R(createTexture, Platform3DObject) - -DELEGATE_TO_WEBCONTEXT_1(deleteBuffer, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_1(deleteFramebuffer, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_1(deleteProgram, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_1(deleteRenderbuffer, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_1(deleteShader, Platform3DObject) -DELEGATE_TO_WEBCONTEXT_1(deleteTexture, Platform3DObject) - -DELEGATE_TO_WEBCONTEXT_1(synthesizeGLError, GC3Denum) - -Extensions3D* GraphicsContext3D::extensions() -{ - if (!m_extensions) - m_extensions = adoptPtr(new Extensions3D(this)); - return m_extensions.get(); -} - -bool GraphicsContext3D::texImage2DResourceSafe(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, GC3Dint unpackAlignment) -{ - ASSERT(unpackAlignment == 1 || unpackAlignment == 2 || unpackAlignment == 4 || unpackAlignment == 8); - texImage2D(target, level, internalformat, width, height, border, format, type, 0); - return true; -} - -bool GraphicsContext3D::computeFormatAndTypeParameters(GC3Denum format, - GC3Denum type, - unsigned int* componentsPerPixel, - unsigned int* bytesPerComponent) -{ - switch (format) { - case GL_ALPHA: - case GL_LUMINANCE: - case GL_DEPTH_COMPONENT: - case GL_DEPTH_STENCIL_OES: - *componentsPerPixel = 1; - break; - case GL_LUMINANCE_ALPHA: - *componentsPerPixel = 2; - break; - case GL_RGB: - *componentsPerPixel = 3; - break; - case GL_RGBA: - case Extensions3D::BGRA_EXT: // GL_EXT_texture_format_BGRA8888 - *componentsPerPixel = 4; - break; - default: - return false; - } - switch (type) { - case GL_UNSIGNED_BYTE: - *bytesPerComponent = sizeof(GC3Dubyte); - break; - case GL_UNSIGNED_SHORT: - *bytesPerComponent = sizeof(GC3Dushort); - break; - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_5_5_5_1: - *componentsPerPixel = 1; - *bytesPerComponent = sizeof(GC3Dushort); - break; - case GL_UNSIGNED_INT_24_8_OES: - case GL_UNSIGNED_INT: - *bytesPerComponent = sizeof(GC3Duint); - break; - case GL_FLOAT: // OES_texture_float - *bytesPerComponent = sizeof(GC3Dfloat); - break; - case GL_HALF_FLOAT_OES: // OES_texture_half_float - *bytesPerComponent = sizeof(GC3Dhalffloat); - break; - default: - return false; - } - return true; -} - -GC3Denum GraphicsContext3D::computeImageSizeInBytes(GC3Denum format, GC3Denum type, GC3Dsizei width, GC3Dsizei height, GC3Dint alignment, - unsigned int* imageSizeInBytes, unsigned int* paddingInBytes) -{ - ASSERT(imageSizeInBytes); - ASSERT(alignment == 1 || alignment == 2 || alignment == 4 || alignment == 8); - if (width < 0 || height < 0) - return GL_INVALID_VALUE; - unsigned int bytesPerComponent, componentsPerPixel; - if (!computeFormatAndTypeParameters(format, type, &bytesPerComponent, &componentsPerPixel)) - return GL_INVALID_ENUM; - if (!width || !height) { - *imageSizeInBytes = 0; - if (paddingInBytes) - *paddingInBytes = 0; - return GL_NO_ERROR; - } - CheckedInt<uint32_t> checkedValue(bytesPerComponent * componentsPerPixel); - checkedValue *= width; - if (!checkedValue.isValid()) - return GL_INVALID_VALUE; - unsigned int validRowSize = checkedValue.value(); - unsigned int padding = 0; - unsigned int residual = validRowSize % alignment; - if (residual) { - padding = alignment - residual; - checkedValue += padding; - } - // Last row needs no padding. - checkedValue *= (height - 1); - checkedValue += validRowSize; - if (!checkedValue.isValid()) - return GL_INVALID_VALUE; - *imageSizeInBytes = checkedValue.value(); - if (paddingInBytes) - *paddingInBytes = padding; - return GL_NO_ERROR; -} - -GraphicsContext3D::ImageExtractor::ImageExtractor(Image* image, ImageHtmlDomSource imageHtmlDomSource, bool premultiplyAlpha, bool ignoreGammaAndColorProfile) -{ - m_image = image; - m_imageHtmlDomSource = imageHtmlDomSource; - m_extractSucceeded = extractImage(premultiplyAlpha, ignoreGammaAndColorProfile); -} - -GraphicsContext3D::ImageExtractor::~ImageExtractor() -{ - if (m_skiaImage) - m_skiaImage->bitmap().unlockPixels(); -} - -bool GraphicsContext3D::ImageExtractor::extractImage(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) -{ - if (!m_image) - return false; - m_skiaImage = m_image->nativeImageForCurrentFrame(); - m_alphaOp = AlphaDoNothing; - bool hasAlpha = m_skiaImage ? !m_skiaImage->bitmap().isOpaque() : true; - if ((!m_skiaImage || ignoreGammaAndColorProfile || (hasAlpha && !premultiplyAlpha)) && m_image->data()) { - // Attempt to get raw unpremultiplied image data. - OwnPtr<ImageDecoder> decoder(ImageDecoder::create( - *(m_image->data()), ImageSource::AlphaNotPremultiplied, - ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied)); - if (!decoder) - return false; - decoder->setData(m_image->data(), true); - if (!decoder->frameCount()) - return false; - ImageFrame* frame = decoder->frameBufferAtIndex(0); - if (!frame || frame->status() != ImageFrame::FrameComplete) - return false; - hasAlpha = frame->hasAlpha(); - m_nativeImage = frame->asNewNativeImage(); - if (!m_nativeImage.get() || !m_nativeImage->isDataComplete() || !m_nativeImage->bitmap().width() || !m_nativeImage->bitmap().height()) - return false; - SkBitmap::Config skiaConfig = m_nativeImage->bitmap().config(); - if (skiaConfig != SkBitmap::kARGB_8888_Config) - return false; - m_skiaImage = m_nativeImage.get(); - if (hasAlpha && premultiplyAlpha) - m_alphaOp = AlphaDoPremultiply; - } else if (!premultiplyAlpha && hasAlpha) { - // 1. For texImage2D with HTMLVideoElment input, assume no PremultiplyAlpha had been applied and the alpha value for each pixel is 0xFF - // which is true at present and may be changed in the future and needs adjustment accordingly. - // 2. For texImage2D with HTMLCanvasElement input in which Alpha is already Premultiplied in this port, - // do AlphaDoUnmultiply if UNPACK_PREMULTIPLY_ALPHA_WEBGL is set to false. - if (m_imageHtmlDomSource != HtmlDomVideo) - m_alphaOp = AlphaDoUnmultiply; - } - if (!m_skiaImage) - return false; - - m_imageSourceFormat = SK_B32_SHIFT ? DataFormatRGBA8 : DataFormatBGRA8; - m_imageWidth = m_skiaImage->bitmap().width(); - m_imageHeight = m_skiaImage->bitmap().height(); - if (!m_imageWidth || !m_imageHeight) - return false; - m_imageSourceUnpackAlignment = 0; - m_skiaImage->bitmap().lockPixels(); - m_imagePixelData = m_skiaImage->bitmap().getPixels(); - return true; -} - -unsigned GraphicsContext3D::getClearBitsByFormat(GC3Denum format) -{ - switch (format) { - case GL_ALPHA: - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - case GL_RGB: - case GL_RGB565: - case GL_RGBA: - case GL_RGBA4: - case GL_RGB5_A1: - return GL_COLOR_BUFFER_BIT; - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT: - return GL_DEPTH_BUFFER_BIT; - case GL_STENCIL_INDEX8: - return GL_STENCIL_BUFFER_BIT; - case GL_DEPTH_STENCIL_OES: - return GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; - default: - return 0; - } -} - -unsigned GraphicsContext3D::getChannelBitsByFormat(GC3Denum format) -{ - switch (format) { - case GL_ALPHA: - return ChannelAlpha; - case GL_LUMINANCE: - return ChannelRGB; - case GL_LUMINANCE_ALPHA: - return ChannelRGBA; - case GL_RGB: - case GL_RGB565: - return ChannelRGB; - case GL_RGBA: - case GL_RGBA4: - case GL_RGB5_A1: - return ChannelRGBA; - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT: - return ChannelDepth; - case GL_STENCIL_INDEX8: - return ChannelStencil; - case GL_DEPTH_STENCIL_OES: - return ChannelDepth | ChannelStencil; - default: - return 0; - } -} - -void GraphicsContext3D::paintFramebufferToCanvas(int framebuffer, int width, int height, bool premultiplyAlpha, ImageBuffer* imageBuffer) -{ - unsigned char* pixels = 0; - - const SkBitmap& canvasBitmap = imageBuffer->bitmap(); - const SkBitmap* readbackBitmap = 0; - ASSERT(canvasBitmap.config() == SkBitmap::kARGB_8888_Config); - if (canvasBitmap.width() == width && canvasBitmap.height() == height) { - // This is the fastest and most common case. We read back - // directly into the canvas's backing store. - readbackBitmap = &canvasBitmap; - m_resizingBitmap.reset(); - } else { - // We need to allocate a temporary bitmap for reading back the - // pixel data. We will then use Skia to rescale this bitmap to - // the size of the canvas's backing store. - if (m_resizingBitmap.width() != width || m_resizingBitmap.height() != height) { - m_resizingBitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); - if (!m_resizingBitmap.allocPixels()) - return; - } - readbackBitmap = &m_resizingBitmap; - } - - // Read back the frame buffer. - SkAutoLockPixels bitmapLock(*readbackBitmap); - pixels = static_cast<unsigned char*>(readbackBitmap->getPixels()); - - m_impl->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); - readBackFramebuffer(pixels, width, height, ReadbackSkia, premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing); - flipVertically(pixels, width, height); - - readbackBitmap->notifyPixelsChanged(); - if (m_resizingBitmap.readyToDraw()) { - // We need to draw the resizing bitmap into the canvas's backing store. - SkCanvas canvas(canvasBitmap); - SkRect dst; - dst.set(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(canvasBitmap.width()), SkIntToScalar(canvasBitmap.height())); - canvas.drawBitmapRect(m_resizingBitmap, 0, dst); - } -} - -namespace { - -void splitStringHelper(const String& str, HashSet<String>& set) -{ - Vector<String> substrings; - str.split(" ", substrings); - for (size_t i = 0; i < substrings.size(); ++i) - set.add(substrings[i]); -} - -String mapExtensionName(const String& name) -{ - if (name == "GL_ANGLE_framebuffer_blit" - || name == "GL_ANGLE_framebuffer_multisample") - return "GL_CHROMIUM_framebuffer_multisample"; - return name; -} - -} // anonymous namespace - -void GraphicsContext3D::initializeExtensions() -{ - if (m_initializedAvailableExtensions) - return; - - m_initializedAvailableExtensions = true; - bool success = m_impl->makeContextCurrent(); - ASSERT(success); - if (!success) - return; - - String extensionsString = m_impl->getString(GL_EXTENSIONS); - splitStringHelper(extensionsString, m_enabledExtensions); - - String requestableExtensionsString = m_impl->getRequestableExtensionsCHROMIUM(); - splitStringHelper(requestableExtensionsString, m_requestableExtensions); -} - - -bool GraphicsContext3D::supportsExtension(const String& name) -{ - initializeExtensions(); - String mappedName = mapExtensionName(name); - return m_enabledExtensions.contains(mappedName) || m_requestableExtensions.contains(mappedName); -} - -bool GraphicsContext3D::ensureExtensionEnabled(const String& name) -{ - initializeExtensions(); - - String mappedName = mapExtensionName(name); - if (m_enabledExtensions.contains(mappedName)) - return true; - - if (m_requestableExtensions.contains(mappedName)) { - m_impl->requestExtensionCHROMIUM(mappedName.ascii().data()); - m_enabledExtensions.clear(); - m_requestableExtensions.clear(); - m_initializedAvailableExtensions = false; - } - - initializeExtensions(); - fprintf(stderr, "m_enabledExtensions.contains(%s) == %d\n", mappedName.ascii().data(), m_enabledExtensions.contains(mappedName)); - return m_enabledExtensions.contains(mappedName); -} - -bool GraphicsContext3D::isExtensionEnabled(const String& name) -{ - initializeExtensions(); - String mappedName = mapExtensionName(name); - return m_enabledExtensions.contains(mappedName); -} - -void GraphicsContext3D::flipVertically(uint8_t* framebuffer, int width, int height) -{ - m_scanline.resize(width * 4); - uint8* scanline = &m_scanline[0]; - unsigned rowBytes = width * 4; - unsigned count = height / 2; - for (unsigned i = 0; i < count; i++) { - uint8* rowA = framebuffer + i * rowBytes; - uint8* rowB = framebuffer + (height - i - 1) * rowBytes; - memcpy(scanline, rowB, rowBytes); - memcpy(rowB, rowA, rowBytes); - memcpy(rowA, scanline, rowBytes); - } -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext3D.h b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext3D.h deleted file mode 100644 index a4466548f51..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext3D.h +++ /dev/null @@ -1,551 +0,0 @@ -/* - * Copyright (C) 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef GraphicsContext3D_h -#define GraphicsContext3D_h - -#include "platform/PlatformExport.h" -#include "platform/geometry/IntRect.h" -#include "platform/graphics/Extensions3D.h" -#include "platform/graphics/GraphicsTypes3D.h" -#include "platform/graphics/Image.h" -#include "platform/weborigin/KURL.h" -#include "third_party/khronos/GLES2/gl2.h" -#include "third_party/khronos/GLES2/gl2ext.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "wtf/HashMap.h" -#include "wtf/HashSet.h" -#include "wtf/ListHashSet.h" -#include "wtf/Noncopyable.h" -#include "wtf/OwnPtr.h" -#include "wtf/PassOwnPtr.h" -#include "wtf/RefCounted.h" -#include "wtf/text/WTFString.h" - -// FIXME: Find a better way to avoid the name confliction for NO_ERROR. -#if OS(WIN) -#undef NO_ERROR -#endif - -class GrContext; - -namespace blink { -class WebGraphicsContext3D; -class WebGraphicsContext3DProvider; -} - -namespace WebCore { -class DrawingBuffer; -class Extensions3D; -class GraphicsContext3DContextLostCallbackAdapter; -class GraphicsContext3DErrorMessageCallbackAdapter; -class Image; -class ImageBuffer; -class IntRect; -class IntSize; - -struct ActiveInfo { - String name; - GC3Denum type; - GC3Dint size; -}; - -class PLATFORM_EXPORT GraphicsContext3D : public RefCounted<GraphicsContext3D> { -public: - // Context creation attributes. - struct Attributes { - Attributes() - : alpha(true) - , depth(true) - , stencil(false) - , antialias(true) - , premultipliedAlpha(true) - , preserveDrawingBuffer(false) - , noExtensions(false) - , shareResources(true) - , preferDiscreteGPU(false) - , failIfMajorPerformanceCaveat(false) - { - } - - bool alpha; - bool depth; - bool stencil; - bool antialias; - bool premultipliedAlpha; - bool preserveDrawingBuffer; - bool noExtensions; - bool shareResources; - bool preferDiscreteGPU; - bool failIfMajorPerformanceCaveat; - KURL topDocumentURL; - }; - - class ContextLostCallback { - public: - virtual void onContextLost() = 0; - virtual ~ContextLostCallback() {} - }; - - class ErrorMessageCallback { - public: - virtual void onErrorMessage(const String& message, GC3Dint id) = 0; - virtual ~ErrorMessageCallback() { } - }; - - void setContextLostCallback(PassOwnPtr<ContextLostCallback>); - void setErrorMessageCallback(PassOwnPtr<ErrorMessageCallback>); - - static PassRefPtr<GraphicsContext3D> create(Attributes); - - // Callers must make the context current before using it AND check that the context was created successfully - // via ContextLost before using the context in any way. Once made current on a thread, the context cannot - // be used on any other thread. - static PassRefPtr<GraphicsContext3D> createGraphicsContextFromWebContext(PassOwnPtr<blink::WebGraphicsContext3D>, bool preserveDrawingBuffer = false); - static PassRefPtr<GraphicsContext3D> createGraphicsContextFromProvider(PassOwnPtr<blink::WebGraphicsContext3DProvider>, bool preserveDrawingBuffer = false); - - ~GraphicsContext3D(); - - GrContext* grContext(); - blink::WebGraphicsContext3D* webContext() const { return m_impl; } - - bool makeContextCurrent(); - - uint32_t lastFlushID(); - - // Helper to texImage2D with pixel==0 case: pixels are initialized to 0. - // Return true if no GL error is synthesized. - // By default, alignment is 4, the OpenGL default setting. - bool texImage2DResourceSafe(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, GC3Dint alignment = 4); - - //---------------------------------------------------------------------- - // Helpers for texture uploading and pixel readback. - // - - // Computes the components per pixel and bytes per component - // for the given format and type combination. Returns false if - // either was an invalid enum. - static bool computeFormatAndTypeParameters(GC3Denum format, - GC3Denum type, - unsigned int* componentsPerPixel, - unsigned int* bytesPerComponent); - - // Computes the image size in bytes. If paddingInBytes is not null, padding - // is also calculated in return. Returns NO_ERROR if succeed, otherwise - // return the suggested GL error indicating the cause of the failure: - // INVALID_VALUE if width/height is negative or overflow happens. - // INVALID_ENUM if format/type is illegal. - static GC3Denum computeImageSizeInBytes(GC3Denum format, - GC3Denum type, - GC3Dsizei width, - GC3Dsizei height, - GC3Dint alignment, - unsigned int* imageSizeInBytes, - unsigned int* paddingInBytes); - - // Attempt to enumerate all possible native image formats to - // reduce the amount of temporary allocations during texture - // uploading. This enum must be public because it is accessed - // by non-member functions. - enum DataFormat { - DataFormatRGBA8 = 0, - DataFormatRGBA16F, - DataFormatRGBA32F, - DataFormatRGB8, - DataFormatRGB16F, - DataFormatRGB32F, - DataFormatBGR8, - DataFormatBGRA8, - DataFormatARGB8, - DataFormatABGR8, - DataFormatRGBA5551, - DataFormatRGBA4444, - DataFormatRGB565, - DataFormatR8, - DataFormatR16F, - DataFormatR32F, - DataFormatRA8, - DataFormatRA16F, - DataFormatRA32F, - DataFormatAR8, - DataFormatA8, - DataFormatA16F, - DataFormatA32F, - DataFormatNumFormats - }; - - // Check if the format is one of the formats from the ImageData or DOM elements. - // The formats from ImageData is always RGBA8. - // The formats from DOM elements vary with Graphics ports. It can only be RGBA8 or BGRA8. - static ALWAYS_INLINE bool srcFormatComeFromDOMElementOrImageData(DataFormat SrcFormat) - { - return SrcFormat == DataFormatBGRA8 || SrcFormat == DataFormatRGBA8; - } - - //---------------------------------------------------------------------- - // Entry points for WebGL. - // - - void activeTexture(GC3Denum texture); - void attachShader(Platform3DObject program, Platform3DObject shader); - void bindAttribLocation(Platform3DObject, GC3Duint index, const String& name); - void bindBuffer(GC3Denum target, Platform3DObject); - void bindFramebuffer(GC3Denum target, Platform3DObject); - void bindRenderbuffer(GC3Denum target, Platform3DObject); - void bindTexture(GC3Denum target, Platform3DObject); - void blendColor(GC3Dclampf red, GC3Dclampf green, GC3Dclampf blue, GC3Dclampf alpha); - void blendEquation(GC3Denum mode); - void blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha); - void blendFunc(GC3Denum sfactor, GC3Denum dfactor); - void blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha); - - void bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage); - void bufferData(GC3Denum target, GC3Dsizeiptr size, const void* data, GC3Denum usage); - void bufferSubData(GC3Denum target, GC3Dintptr offset, GC3Dsizeiptr size, const void* data); - - GC3Denum checkFramebufferStatus(GC3Denum target); - void clear(GC3Dbitfield mask); - void clearColor(GC3Dclampf red, GC3Dclampf green, GC3Dclampf blue, GC3Dclampf alpha); - void clearDepth(GC3Dclampf depth); - void clearStencil(GC3Dint s); - void colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha); - void compileShader(Platform3DObject); - - void compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Dsizei imageSize, const void* data); - void compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Dsizei imageSize, const void* data); - void copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border); - void copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height); - void cullFace(GC3Denum mode); - void depthFunc(GC3Denum func); - void depthMask(GC3Dboolean flag); - void depthRange(GC3Dclampf zNear, GC3Dclampf zFar); - void detachShader(Platform3DObject, Platform3DObject); - void disable(GC3Denum cap); - void disableVertexAttribArray(GC3Duint index); - void drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count); - void drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset); - - void enable(GC3Denum cap); - void enableVertexAttribArray(GC3Duint index); - void finish(); - void flush(); - void framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, Platform3DObject); - void framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, Platform3DObject, GC3Dint level); - void frontFace(GC3Denum mode); - void generateMipmap(GC3Denum target); - - bool getActiveAttrib(Platform3DObject program, GC3Duint index, ActiveInfo&); - bool getActiveUniform(Platform3DObject program, GC3Duint index, ActiveInfo&); - void getAttachedShaders(Platform3DObject program, GC3Dsizei maxCount, GC3Dsizei* count, Platform3DObject* shaders); - GC3Dint getAttribLocation(Platform3DObject, const String& name); - void getBooleanv(GC3Denum pname, GC3Dboolean* value); - void getBufferParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value); - Attributes getContextAttributes(); - GC3Denum getError(); - void getFloatv(GC3Denum pname, GC3Dfloat* value); - void getFramebufferAttachmentParameteriv(GC3Denum target, GC3Denum attachment, GC3Denum pname, GC3Dint* value); - void getIntegerv(GC3Denum pname, GC3Dint* value); - void getProgramiv(Platform3DObject program, GC3Denum pname, GC3Dint* value); - String getProgramInfoLog(Platform3DObject); - void getRenderbufferParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value); - void getShaderiv(Platform3DObject, GC3Denum pname, GC3Dint* value); - String getShaderInfoLog(Platform3DObject); - void getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, GC3Dint* range, GC3Dint* precision); - String getShaderSource(Platform3DObject); - String getString(GC3Denum name); - void getTexParameterfv(GC3Denum target, GC3Denum pname, GC3Dfloat* value); - void getTexParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value); - void getUniformfv(Platform3DObject program, GC3Dint location, GC3Dfloat* value); - void getUniformiv(Platform3DObject program, GC3Dint location, GC3Dint* value); - GC3Dint getUniformLocation(Platform3DObject, const String& name); - void getVertexAttribfv(GC3Duint index, GC3Denum pname, GC3Dfloat* value); - void getVertexAttribiv(GC3Duint index, GC3Denum pname, GC3Dint* value); - GC3Dsizeiptr getVertexAttribOffset(GC3Duint index, GC3Denum pname); - - void hint(GC3Denum target, GC3Denum mode); - GC3Dboolean isBuffer(Platform3DObject); - GC3Dboolean isEnabled(GC3Denum cap); - GC3Dboolean isFramebuffer(Platform3DObject); - GC3Dboolean isProgram(Platform3DObject); - GC3Dboolean isRenderbuffer(Platform3DObject); - GC3Dboolean isShader(Platform3DObject); - GC3Dboolean isTexture(Platform3DObject); - void lineWidth(GC3Dfloat); - void linkProgram(Platform3DObject); - void pixelStorei(GC3Denum pname, GC3Dint param); - void polygonOffset(GC3Dfloat factor, GC3Dfloat units); - - void readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data); - - void releaseShaderCompiler(); - - void renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height); - void sampleCoverage(GC3Dclampf value, GC3Dboolean invert); - void scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height); - void shaderSource(Platform3DObject, const String& string); - void stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask); - void stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask); - void stencilMask(GC3Duint mask); - void stencilMaskSeparate(GC3Denum face, GC3Duint mask); - void stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass); - void stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass); - - void texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels); - void texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param); - void texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param); - void texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, const void* pixels); - - void uniform1f(GC3Dint location, GC3Dfloat x); - void uniform1fv(GC3Dint location, GC3Dsizei, GC3Dfloat* v); - void uniform1i(GC3Dint location, GC3Dint x); - void uniform1iv(GC3Dint location, GC3Dsizei, GC3Dint* v); - void uniform2f(GC3Dint location, GC3Dfloat x, GC3Dfloat y); - void uniform2fv(GC3Dint location, GC3Dsizei, GC3Dfloat* v); - void uniform2i(GC3Dint location, GC3Dint x, GC3Dint y); - void uniform2iv(GC3Dint location, GC3Dsizei, GC3Dint* v); - void uniform3f(GC3Dint location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z); - void uniform3fv(GC3Dint location, GC3Dsizei, GC3Dfloat* v); - void uniform3i(GC3Dint location, GC3Dint x, GC3Dint y, GC3Dint z); - void uniform3iv(GC3Dint location, GC3Dsizei, GC3Dint* v); - void uniform4f(GC3Dint location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w); - void uniform4fv(GC3Dint location, GC3Dsizei, GC3Dfloat* v); - void uniform4i(GC3Dint location, GC3Dint x, GC3Dint y, GC3Dint z, GC3Dint w); - void uniform4iv(GC3Dint location, GC3Dsizei, GC3Dint* v); - void uniformMatrix2fv(GC3Dint location, GC3Dsizei, GC3Dboolean transpose, GC3Dfloat* value); - void uniformMatrix3fv(GC3Dint location, GC3Dsizei, GC3Dboolean transpose, GC3Dfloat* value); - void uniformMatrix4fv(GC3Dint location, GC3Dsizei, GC3Dboolean transpose, GC3Dfloat* value); - - void useProgram(Platform3DObject); - void validateProgram(Platform3DObject); - - void vertexAttrib1f(GC3Duint index, GC3Dfloat x); - void vertexAttrib1fv(GC3Duint index, GC3Dfloat* values); - void vertexAttrib2f(GC3Duint index, GC3Dfloat x, GC3Dfloat y); - void vertexAttrib2fv(GC3Duint index, GC3Dfloat* values); - void vertexAttrib3f(GC3Duint index, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z); - void vertexAttrib3fv(GC3Duint index, GC3Dfloat* values); - void vertexAttrib4f(GC3Duint index, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w); - void vertexAttrib4fv(GC3Duint index, GC3Dfloat* values); - void vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, - GC3Dsizei stride, GC3Dintptr offset); - - void viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height); - - void markContextChanged(); - void markLayerComposited(); - bool layerComposited() const; - - void paintRenderingResultsToCanvas(ImageBuffer*, DrawingBuffer*); - PassRefPtr<Uint8ClampedArray> paintRenderingResultsToImageData(DrawingBuffer*, int&, int&); - - // Support for buffer creation and deletion - Platform3DObject createBuffer(); - Platform3DObject createFramebuffer(); - Platform3DObject createProgram(); - Platform3DObject createRenderbuffer(); - Platform3DObject createShader(GC3Denum); - Platform3DObject createTexture(); - - void deleteBuffer(Platform3DObject); - void deleteFramebuffer(Platform3DObject); - void deleteProgram(Platform3DObject); - void deleteRenderbuffer(Platform3DObject); - void deleteShader(Platform3DObject); - void deleteTexture(Platform3DObject); - - // Synthesizes an OpenGL error which will be returned from a - // later call to getError. This is used to emulate OpenGL ES - // 2.0 behavior on the desktop and to enforce additional error - // checking mandated by WebGL. - // - // Per the behavior of glGetError, this stores at most one - // instance of any given error, and returns them from calls to - // getError in the order they were added. - void synthesizeGLError(GC3Denum error); - - // Support for extensions. Returns a non-null object, though not - // all methods it contains may necessarily be supported on the - // current hardware. Must call Extensions3D::supports() to - // determine this. - Extensions3D* extensions(); - - static unsigned getClearBitsByFormat(GC3Denum); - - enum ChannelBits { - ChannelRed = 1, - ChannelGreen = 2, - ChannelBlue = 4, - ChannelAlpha = 8, - ChannelDepth = 16, - ChannelStencil = 32, - ChannelRGB = ChannelRed | ChannelGreen | ChannelBlue, - ChannelRGBA = ChannelRGB | ChannelAlpha, - }; - - static unsigned getChannelBitsByFormat(GC3Denum); - - // Possible alpha operations that may need to occur during - // pixel packing. FIXME: kAlphaDoUnmultiply is lossy and must - // be removed. - enum AlphaOp { - AlphaDoNothing = 0, - AlphaDoPremultiply = 1, - AlphaDoUnmultiply = 2 - }; - - enum ImageHtmlDomSource { - HtmlDomImage = 0, - HtmlDomCanvas = 1, - HtmlDomVideo = 2, - HtmlDomNone = 3 - }; - - class PLATFORM_EXPORT ImageExtractor { - public: - ImageExtractor(Image*, ImageHtmlDomSource, bool premultiplyAlpha, bool ignoreGammaAndColorProfile); - - ~ImageExtractor(); - - bool extractSucceeded() { return m_extractSucceeded; } - const void* imagePixelData() { return m_imagePixelData; } - unsigned imageWidth() { return m_imageWidth; } - unsigned imageHeight() { return m_imageHeight; } - DataFormat imageSourceFormat() { return m_imageSourceFormat; } - AlphaOp imageAlphaOp() { return m_alphaOp; } - unsigned imageSourceUnpackAlignment() { return m_imageSourceUnpackAlignment; } - ImageHtmlDomSource imageHtmlDomSource() { return m_imageHtmlDomSource; } - private: - // Extract the image and keeps track of its status, such as width, height, Source Alignment, format and AlphaOp etc. - // This needs to lock the resources or relevant data if needed and return true upon success - bool extractImage(bool premultiplyAlpha, bool ignoreGammaAndColorProfile); - - RefPtr<NativeImageSkia> m_nativeImage; - RefPtr<NativeImageSkia> m_skiaImage; - Image* m_image; - ImageHtmlDomSource m_imageHtmlDomSource; - bool m_extractSucceeded; - const void* m_imagePixelData; - unsigned m_imageWidth; - unsigned m_imageHeight; - DataFormat m_imageSourceFormat; - AlphaOp m_alphaOp; - unsigned m_imageSourceUnpackAlignment; - }; - - // The Following functions are implemented in GraphicsContext3DImagePacking.cpp - - // Packs the contents of the given Image which is passed in |pixels| into the passed Vector - // according to the given format and type, and obeying the flipY and AlphaOp flags. - // Returns true upon success. - static bool packImageData(Image*, const void* pixels, GC3Denum format, GC3Denum type, bool flipY, AlphaOp, DataFormat sourceFormat, unsigned width, unsigned height, unsigned sourceUnpackAlignment, Vector<uint8_t>& data); - - // Extracts the contents of the given ImageData into the passed Vector, - // packing the pixel data according to the given format and type, - // and obeying the flipY and premultiplyAlpha flags. Returns true - // upon success. - static bool extractImageData(const uint8_t*, const IntSize&, GC3Denum format, GC3Denum type, bool flipY, bool premultiplyAlpha, Vector<uint8_t>& data); - - // Helper function which extracts the user-supplied texture - // data, applying the flipY and premultiplyAlpha parameters. - // If the data is not tightly packed according to the passed - // unpackAlignment, the output data will be tightly packed. - // Returns true if successful, false if any error occurred. - static bool extractTextureData(unsigned width, unsigned height, GC3Denum format, GC3Denum type, unsigned unpackAlignment, bool flipY, bool premultiplyAlpha, const void* pixels, Vector<uint8_t>& data); - - // End GraphicsContext3DImagePacking.cpp functions - - // This is the order of bytes to use when doing a readback. - enum ReadbackOrder { - ReadbackRGBA, - ReadbackSkia - }; - - // Helper function which does a readback from the currently-bound - // framebuffer into a buffer of a certain size with 4-byte pixels. - void readBackFramebuffer(unsigned char* pixels, int width, int height, ReadbackOrder, AlphaOp); - -private: - friend class Extensions3D; - - GraphicsContext3D(PassOwnPtr<blink::WebGraphicsContext3D>, bool preserveDrawingBuffer); - GraphicsContext3D(PassOwnPtr<blink::WebGraphicsContext3DProvider>, bool preserveDrawingBuffer); - - // Helper for packImageData/extractImageData/extractTextureData which implement packing of pixel - // data into the specified OpenGL destination format and type. - // A sourceUnpackAlignment of zero indicates that the source - // data is tightly packed. Non-zero values may take a slow path. - // Destination data will have no gaps between rows. - // Implemented in GraphicsContext3DImagePacking.cpp - static bool packPixels(const uint8_t* sourceData, DataFormat sourceDataFormat, unsigned width, unsigned height, unsigned sourceUnpackAlignment, unsigned destinationFormat, unsigned destinationType, AlphaOp, void* destinationData, bool flipY); - - void paintFramebufferToCanvas(int framebuffer, int width, int height, bool premultiplyAlpha, ImageBuffer*); - // Helper function to flip a bitmap vertically. - void flipVertically(uint8_t* data, int width, int height); - - // Extensions3D support. - bool supportsExtension(const String& name); - bool ensureExtensionEnabled(const String& name); - bool isExtensionEnabled(const String& name); - - void initializeExtensions(); - - bool preserveDrawingBuffer() const { return m_preserveDrawingBuffer; } - - OwnPtr<blink::WebGraphicsContext3DProvider> m_provider; - blink::WebGraphicsContext3D* m_impl; - OwnPtr<GraphicsContext3DContextLostCallbackAdapter> m_contextLostCallbackAdapter; - OwnPtr<GraphicsContext3DErrorMessageCallbackAdapter> m_errorMessageCallbackAdapter; - OwnPtr<blink::WebGraphicsContext3D> m_ownedWebContext; - OwnPtr<Extensions3D> m_extensions; - bool m_initializedAvailableExtensions; - HashSet<String> m_enabledExtensions; - HashSet<String> m_requestableExtensions; - bool m_layerComposited; - bool m_preserveDrawingBuffer; - int m_packAlignment; - - enum ResourceSafety { - ResourceSafetyUnknown, - ResourceSafe, - ResourceUnsafe - }; - ResourceSafety m_resourceSafety; - - // If the width and height of the Canvas's backing store don't - // match those that we were given in the most recent call to - // reshape(), then we need an intermediate bitmap to read back the - // frame buffer into. This seems to happen when CSS styles are - // used to resize the Canvas. - SkBitmap m_resizingBitmap; - - GrContext* m_grContext; - - // Used to flip a bitmap vertically. - Vector<uint8_t> m_scanline; -}; - -} // namespace WebCore - -#endif // GraphicsContext3D_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextCullSaver.h b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextCullSaver.h new file mode 100644 index 00000000000..1b1023ddea8 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextCullSaver.h @@ -0,0 +1,46 @@ +#ifndef GraphicsContextCullSaver_h +#define GraphicsContextCullSaver_h + +#include "platform/graphics/GraphicsContext.h" + +namespace WebCore { + +class FloatRect; + +class GraphicsContextCullSaver { + WTF_MAKE_FAST_ALLOCATED; +public: + GraphicsContextCullSaver(GraphicsContext& context) + : m_context(context) + , m_cullApplied(false) + { + } + + GraphicsContextCullSaver(GraphicsContext& context, const FloatRect& rect) + : m_context(context) + , m_cullApplied(true) + { + context.beginCull(rect); + } + + ~GraphicsContextCullSaver() + { + if (m_cullApplied) + m_context.endCull(); + } + + void cull(const FloatRect& rect) + { + ASSERT(!m_cullApplied); + m_context.beginCull(rect); + m_cullApplied = true; + } + +private: + GraphicsContext& m_context; + bool m_cullApplied; +}; + +} // namespace WebCore + +#endif // GraphicsContextCullSaver_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextRecorder.cpp b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextRecorder.cpp index ef7fb7e7268..4b7d9781afa 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextRecorder.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextRecorder.cpp @@ -32,17 +32,27 @@ #include "platform/graphics/GraphicsContextRecorder.h" #include "platform/graphics/ImageBuffer.h" +#include "platform/graphics/ImageSource.h" +#include "platform/image-decoders/ImageDecoder.h" +#include "platform/image-decoders/ImageFrame.h" +#include "platform/image-encoders/skia/PNGImageEncoder.h" #include "third_party/skia/include/core/SkBitmapDevice.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" +#include "third_party/skia/include/core/SkStream.h" +#include "wtf/HexNumber.h" +#include "wtf/text/Base64.h" +#include "wtf/text/TextEncoding.h" namespace WebCore { GraphicsContext* GraphicsContextRecorder::record(const IntSize& size, bool isCertainlyOpaque) { ASSERT(!m_picture); + ASSERT(!m_recorder); ASSERT(!m_context); - m_picture = adoptRef(new SkPicture()); m_isCertainlyOpaque = isCertainlyOpaque; - SkCanvas* canvas = m_picture->beginRecording(size.width(), size.height()); + m_recorder = adoptPtr(new SkPictureRecorder); + SkCanvas* canvas = m_recorder->beginRecording(size.width(), size.height(), 0, 0); m_context = adoptPtr(new GraphicsContext(canvas)); m_context->setTrackOpaqueRegion(isCertainlyOpaque); m_context->setCertainlyOpaque(isCertainlyOpaque); @@ -51,8 +61,9 @@ GraphicsContext* GraphicsContextRecorder::record(const IntSize& size, bool isCer PassRefPtr<GraphicsContextSnapshot> GraphicsContextRecorder::stop() { - m_picture->endRecording(); m_context.clear(); + m_picture = adoptRef(m_recorder->endRecording()); + m_recorder.clear(); return adoptRef(new GraphicsContextSnapshot(m_picture.release(), m_isCertainlyOpaque)); } @@ -153,10 +164,838 @@ private: Vector<double>* m_currentTimings; }; +class LoggingCanvas : public SkCanvas { +public: + LoggingCanvas(int width, int height) : SkCanvas(width, height) + { + m_log = JSONArray::create(); + } -PassOwnPtr<ImageBuffer> GraphicsContextSnapshot::replay(unsigned fromStep, unsigned toStep) const + void clear(SkColor color) OVERRIDE + { + addItemWithParams("clear")->setString("color", stringForSkColor(color)); + } + + void drawPaint(const SkPaint& paint) OVERRIDE + { + addItemWithParams("drawPaint")->setObject("paint", objectForSkPaint(paint)); + } + + void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawPoints"); + params->setString("pointMode", pointModeName(mode)); + params->setArray("points", arrayForSkPoints(count, pts)); + params->setObject("paint", objectForSkPaint(paint)); + } + + void drawRect(const SkRect& rect, const SkPaint& paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawRect"); + params->setObject("rect", objectForSkRect(rect)); + params->setObject("paint", objectForSkPaint(paint)); + } + + void drawOval(const SkRect& oval, const SkPaint& paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawOval"); + params->setObject("oval", objectForSkRect(oval)); + params->setObject("paint", objectForSkPaint(paint)); + } + + void drawRRect(const SkRRect& rrect, const SkPaint& paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawRRect"); + params->setObject("rrect", objectForSkRRect(rrect)); + params->setObject("paint", objectForSkPaint(paint)); + } + + void drawPath(const SkPath& path, const SkPaint& paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawPath"); + params->setObject("path", objectForSkPath(path)); + params->setObject("paint", objectForSkPaint(paint)); + } + + void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawBitmap"); + params->setNumber("left", left); + params->setNumber("top", top); + params->setObject("bitmap", objectForSkBitmap(bitmap)); + params->setObject("paint", objectForSkPaint(*paint)); + } + + void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint* paint, DrawBitmapRectFlags flags) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawBitmapRectToRect"); + params->setObject("bitmap", objectForSkBitmap(bitmap)); + params->setObject("src", objectForSkRect(*src)); + params->setObject("dst", objectForSkRect(dst)); + params->setObject("paint", objectForSkPaint(*paint)); + params->setNumber("flags", flags); + } + + void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, const SkPaint* paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawBitmapMatrix"); + params->setObject("bitmap", objectForSkBitmap(bitmap)); + params->setArray("matrix", arrayForSkMatrix(m)); + params->setObject("paint", objectForSkPaint(*paint)); + } + + void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawBitmapNine"); + params->setObject("bitmap", objectForSkBitmap(bitmap)); + params->setObject("center", objectForSkIRect(center)); + params->setObject("dst", objectForSkRect(dst)); + params->setObject("paint", objectForSkPaint(*paint)); + } + + void drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawSprite"); + params->setObject("bitmap", objectForSkBitmap(bitmap)); + params->setNumber("left", left); + params->setNumber("top", top); + params->setObject("paint", objectForSkPaint(*paint)); + } + + void drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkXfermode* xmode, + const uint16_t indices[], int indexCount, const SkPaint& paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawVertices"); + params->setObject("paint", objectForSkPaint(paint)); + } + + void drawData(const void* data, size_t length) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawData"); + params->setNumber("length", length); + } + + void beginCommentGroup(const char* description) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("beginCommentGroup"); + params->setString("description", description); + } + + void addComment(const char* keyword, const char* value) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("addComment"); + params->setString("key", keyword); + params->setString("value", value); + } + + void endCommentGroup() OVERRIDE + { + addItem("endCommentGroup"); + } + + void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawDRRect"); + params->setObject("outer", objectForSkRRect(outer)); + params->setObject("inner", objectForSkRRect(inner)); + params->setObject("paint", objectForSkPaint(paint)); + } + + void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawText"); + params->setString("text", stringForText(text, byteLength, paint)); + params->setNumber("x", x); + params->setNumber("y", y); + params->setObject("paint", objectForSkPaint(paint)); + } + + void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawPosText"); + params->setString("text", stringForText(text, byteLength, paint)); + size_t pointsCount = paint.countText(text, byteLength); + params->setArray("pos", arrayForSkPoints(pointsCount, pos)); + params->setObject("paint", objectForSkPaint(paint)); + } + + void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawPosTextH"); + params->setString("text", stringForText(text, byteLength, paint)); + size_t pointsCount = paint.countText(text, byteLength); + params->setArray("xpos", arrayForSkScalars(pointsCount, xpos)); + params->setNumber("constY", constY); + params->setObject("paint", objectForSkPaint(paint)); + } + + void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("drawTextOnPath"); + params->setString("text", stringForText(text, byteLength, paint)); + params->setObject("path", objectForSkPath(path)); + params->setArray("matrix", arrayForSkMatrix(*matrix)); + params->setObject("paint", objectForSkPaint(paint)); + } + + void onPushCull(const SkRect& cullRect) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("pushCull"); + params->setObject("cullRect", objectForSkRect(cullRect)); + } + + void onPopCull() OVERRIDE + { + addItem("popCull"); + } + + void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle style) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("clipRect"); + params->setObject("rect", objectForSkRect(rect)); + params->setString("SkRegion::Op", regionOpName(op)); + params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style); + } + + void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle style) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("clipRRect"); + params->setObject("rrect", objectForSkRRect(rrect)); + params->setString("SkRegion::Op", regionOpName(op)); + params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style); + } + + void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle style) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("clipPath"); + params->setObject("path", objectForSkPath(path)); + params->setString("SkRegion::Op", regionOpName(op)); + params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style); + } + + void onClipRegion(const SkRegion& region, SkRegion::Op op) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("clipRegion"); + params->setString("op", regionOpName(op)); + } + + void onDrawPicture(const SkPicture* picture) OVERRIDE + { + addItemWithParams("drawPicture")->setObject("picture", objectForSkPicture(*picture)); + } + + void didSetMatrix(const SkMatrix& matrix) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("setMatrix"); + params->setArray("matrix", arrayForSkMatrix(matrix)); + this->SkCanvas::didSetMatrix(matrix); + } + + void didConcat(const SkMatrix& matrix) OVERRIDE + { + switch (matrix.getType()) { + case SkMatrix::kTranslate_Mask: + translate(matrix.getTranslateX(), matrix.getTranslateY()); + break; + case SkMatrix::kScale_Mask: + scale(matrix.getScaleX(), matrix.getScaleY()); + break; + default: + concat(matrix); + } + this->SkCanvas::didConcat(matrix); + } + + void willRestore() OVERRIDE + { + addItem("restore"); + this->SkCanvas::willRestore(); + } + + SaveLayerStrategy willSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("saveLayer"); + if (bounds) + params->setObject("bounds", objectForSkRect(*bounds)); + params->setObject("paint", objectForSkPaint(*paint)); + params->setString("saveFlags", saveFlagsToString(flags)); + this->SkCanvas::willSaveLayer(bounds, paint, flags); + return kNoLayer_SaveLayerStrategy; + } + + void willSave() OVERRIDE + { + RefPtr<JSONObject> params = addItemWithParams("save"); + this->SkCanvas::willSave(); + } + + bool isClipEmpty() const OVERRIDE + { + return false; + } + + bool isClipRect() const OVERRIDE + { + return true; + } + +#ifdef SK_SUPPORT_LEGACY_GETCLIPTYPE + ClipType getClipType() const OVERRIDE + { + return kRect_ClipType; + } +#endif + + bool getClipBounds(SkRect* bounds) const OVERRIDE + { + if (bounds) + bounds->setXYWH(0, 0, SkIntToScalar(this->imageInfo().fWidth), SkIntToScalar(this->imageInfo().fHeight)); + return true; + } + + bool getClipDeviceBounds(SkIRect* bounds) const OVERRIDE + { + if (bounds) + bounds->setLargest(); + return true; + } + + PassRefPtr<JSONArray> log() + { + return m_log; + } + +private: + RefPtr<JSONArray> m_log; + + PassRefPtr<JSONObject> addItem(const String& name) + { + RefPtr<JSONObject> item = JSONObject::create(); + item->setString("method", name); + m_log->pushObject(item); + return item.release(); + } + + PassRefPtr<JSONObject> addItemWithParams(const String& name) + { + RefPtr<JSONObject> item = addItem(name); + RefPtr<JSONObject> params = JSONObject::create(); + item->setObject("params", params); + return params.release(); + } + + PassRefPtr<JSONObject> objectForSkRect(const SkRect& rect) + { + RefPtr<JSONObject> rectItem = JSONObject::create(); + rectItem->setNumber("left", rect.left()); + rectItem->setNumber("top", rect.top()); + rectItem->setNumber("right", rect.right()); + rectItem->setNumber("bottom", rect.bottom()); + return rectItem.release(); + } + + PassRefPtr<JSONObject> objectForSkIRect(const SkIRect& rect) + { + RefPtr<JSONObject> rectItem = JSONObject::create(); + rectItem->setNumber("left", rect.left()); + rectItem->setNumber("top", rect.top()); + rectItem->setNumber("right", rect.right()); + rectItem->setNumber("bottom", rect.bottom()); + return rectItem.release(); + } + + String pointModeName(PointMode mode) + { + switch (mode) { + case SkCanvas::kPoints_PointMode: return "Points"; + case SkCanvas::kLines_PointMode: return "Lines"; + case SkCanvas::kPolygon_PointMode: return "Polygon"; + default: + ASSERT_NOT_REACHED(); + return "?"; + }; + } + + PassRefPtr<JSONObject> objectForSkPoint(const SkPoint& point) + { + RefPtr<JSONObject> pointItem = JSONObject::create(); + pointItem->setNumber("x", point.x()); + pointItem->setNumber("y", point.y()); + return pointItem.release(); + } + + PassRefPtr<JSONArray> arrayForSkPoints(size_t count, const SkPoint points[]) + { + RefPtr<JSONArray> pointsArrayItem = JSONArray::create(); + for (size_t i = 0; i < count; ++i) + pointsArrayItem->pushObject(objectForSkPoint(points[i])); + return pointsArrayItem.release(); + } + + PassRefPtr<JSONObject> objectForSkPicture(const SkPicture& picture) + { + RefPtr<JSONObject> pictureItem = JSONObject::create(); + pictureItem->setNumber("width", picture.width()); + pictureItem->setNumber("height", picture.height()); + return pictureItem.release(); + } + + PassRefPtr<JSONObject> objectForRadius(const SkRRect& rrect, SkRRect::Corner corner) + { + RefPtr<JSONObject> radiusItem = JSONObject::create(); + SkVector radius = rrect.radii(corner); + radiusItem->setNumber("xRadius", radius.x()); + radiusItem->setNumber("yRadius", radius.y()); + return radiusItem.release(); + } + + String rrectTypeName(SkRRect::Type type) + { + switch (type) { + case SkRRect::kEmpty_Type: return "Empty"; + case SkRRect::kRect_Type: return "Rect"; + case SkRRect::kOval_Type: return "Oval"; + case SkRRect::kSimple_Type: return "Simple"; + case SkRRect::kNinePatch_Type: return "Nine-patch"; + case SkRRect::kComplex_Type: return "Complex"; + default: + ASSERT_NOT_REACHED(); + return "?"; + }; + } + + String radiusName(SkRRect::Corner corner) + { + switch (corner) { + case SkRRect::kUpperLeft_Corner: return "upperLeftRadius"; + case SkRRect::kUpperRight_Corner: return "upperRightRadius"; + case SkRRect::kLowerRight_Corner: return "lowerRightRadius"; + case SkRRect::kLowerLeft_Corner: return "lowerLeftRadius"; + default: + ASSERT_NOT_REACHED(); + return "?"; + } + } + + PassRefPtr<JSONObject> objectForSkRRect(const SkRRect& rrect) + { + RefPtr<JSONObject> rrectItem = JSONObject::create(); + rrectItem->setString("type", rrectTypeName(rrect.type())); + rrectItem->setNumber("left", rrect.rect().left()); + rrectItem->setNumber("top", rrect.rect().top()); + rrectItem->setNumber("right", rrect.rect().right()); + rrectItem->setNumber("bottom", rrect.rect().bottom()); + for (int i = 0; i < 4; ++i) + rrectItem->setObject(radiusName((SkRRect::Corner) i), objectForRadius(rrect, (SkRRect::Corner) i)); + return rrectItem.release(); + } + + String fillTypeName(SkPath::FillType type) + { + switch (type) { + case SkPath::kWinding_FillType: return "Winding"; + case SkPath::kEvenOdd_FillType: return "EvenOdd"; + case SkPath::kInverseWinding_FillType: return "InverseWinding"; + case SkPath::kInverseEvenOdd_FillType: return "InverseEvenOdd"; + default: + ASSERT_NOT_REACHED(); + return "?"; + }; + } + + String convexityName(SkPath::Convexity convexity) + { + switch (convexity) { + case SkPath::kUnknown_Convexity: return "Unknown"; + case SkPath::kConvex_Convexity: return "Convex"; + case SkPath::kConcave_Convexity: return "Concave"; + default: + ASSERT_NOT_REACHED(); + return "?"; + }; + } + + String verbName(SkPath::Verb verb) + { + switch (verb) { + case SkPath::kMove_Verb: return "Move"; + case SkPath::kLine_Verb: return "Line"; + case SkPath::kQuad_Verb: return "Quad"; + case SkPath::kConic_Verb: return "Conic"; + case SkPath::kCubic_Verb: return "Cubic"; + case SkPath::kClose_Verb: return "Close"; + case SkPath::kDone_Verb: return "Done"; + default: + ASSERT_NOT_REACHED(); + return "?"; + }; + } + + struct VerbParams { + String name; + unsigned pointCount; + unsigned pointOffset; + + VerbParams(const String& name, unsigned pointCount, unsigned pointOffset) + : name(name) + , pointCount(pointCount) + , pointOffset(pointOffset) { } + }; + + VerbParams segmentParams(SkPath::Verb verb) + { + switch (verb) { + case SkPath::kMove_Verb: return VerbParams("Move", 1, 0); + case SkPath::kLine_Verb: return VerbParams("Line", 1, 1); + case SkPath::kQuad_Verb: return VerbParams("Quad", 2, 1); + case SkPath::kConic_Verb: return VerbParams("Conic", 2, 1); + case SkPath::kCubic_Verb: return VerbParams("Cubic", 3, 1); + case SkPath::kClose_Verb: return VerbParams("Close", 0, 0); + case SkPath::kDone_Verb: return VerbParams("Done", 0, 0); + default: + ASSERT_NOT_REACHED(); + return VerbParams("?", 0, 0); + }; + } + + PassRefPtr<JSONObject> objectForSkPath(const SkPath& path) + { + RefPtr<JSONObject> pathItem = JSONObject::create(); + pathItem->setString("fillType", fillTypeName(path.getFillType())); + pathItem->setString("convexity", convexityName(path.getConvexity())); + pathItem->setBoolean("isRect", path.isRect(0)); + SkPath::Iter iter(path, false); + SkPoint points[4]; + RefPtr<JSONArray> pathPointsArray = JSONArray::create(); + for (SkPath::Verb verb = iter.next(points, false); verb != SkPath::kDone_Verb; verb = iter.next(points, false)) { + VerbParams verbParams = segmentParams(verb); + RefPtr<JSONObject> pathPointItem = JSONObject::create(); + pathPointItem->setString("verb", verbParams.name); + ASSERT(verbParams.pointCount + verbParams.pointOffset <= WTF_ARRAY_LENGTH(points)); + pathPointItem->setArray("points", arrayForSkPoints(verbParams.pointCount, points + verbParams.pointOffset)); + if (SkPath::kConic_Verb == verb) + pathPointItem->setNumber("conicWeight", iter.conicWeight()); + pathPointsArray->pushObject(pathPointItem); + } + pathItem->setArray("pathPoints", pathPointsArray); + pathItem->setObject("bounds", objectForSkRect(path.getBounds())); + return pathItem.release(); + } + + String configName(SkBitmap::Config config) + { + switch (config) { + case SkBitmap::kNo_Config: return "None"; + case SkBitmap::kA8_Config: return "A8"; + case SkBitmap::kIndex8_Config: return "Index8"; + case SkBitmap::kRGB_565_Config: return "RGB565"; + case SkBitmap::kARGB_4444_Config: return "ARGB4444"; + case SkBitmap::kARGB_8888_Config: return "ARGB8888"; + default: + ASSERT_NOT_REACHED(); + return "?"; + }; + } + + PassRefPtr<JSONObject> objectForBitmapData(const SkBitmap& bitmap) + { + RefPtr<JSONObject> dataItem = JSONObject::create(); + Vector<unsigned char> output; + WebCore::PNGImageEncoder::encode(bitmap, &output); + dataItem->setString("base64", WTF::base64Encode(reinterpret_cast<char*>(output.data()), output.size())); + dataItem->setString("mimeType", "image/png"); + return dataItem.release(); + } + + PassRefPtr<JSONObject> objectForSkBitmap(const SkBitmap& bitmap) + { + RefPtr<JSONObject> bitmapItem = JSONObject::create(); + bitmapItem->setNumber("width", bitmap.width()); + bitmapItem->setNumber("height", bitmap.height()); + bitmapItem->setString("config", configName(bitmap.config())); + bitmapItem->setBoolean("opaque", bitmap.isOpaque()); + bitmapItem->setBoolean("immutable", bitmap.isImmutable()); + bitmapItem->setBoolean("volatile", bitmap.isVolatile()); + bitmapItem->setNumber("genID", bitmap.getGenerationID()); + bitmapItem->setObject("data", objectForBitmapData(bitmap)); + return bitmapItem.release(); + } + + PassRefPtr<JSONObject> objectForSkShader(const SkShader& shader) + { + RefPtr<JSONObject> shaderItem = JSONObject::create(); + const SkMatrix localMatrix = shader.getLocalMatrix(); + if (!localMatrix.isIdentity()) + shaderItem->setArray("localMatrix", arrayForSkMatrix(localMatrix)); + return shaderItem.release(); + } + + String stringForSkColor(const SkColor& color) + { + String colorString = "#"; + appendUnsignedAsHex(color, colorString); + return colorString; + } + + void appendFlagToString(String* flagsString, bool isSet, const String& name) + { + if (!isSet) + return; + if (flagsString->length()) + flagsString->append("|"); + flagsString->append(name); + } + + String stringForSkPaintFlags(const SkPaint& paint) + { + if (!paint.getFlags()) + return "none"; + String flagsString = ""; + appendFlagToString(&flagsString, paint.isAntiAlias(), "AntiAlias"); + appendFlagToString(&flagsString, paint.isDither(), "Dither"); + appendFlagToString(&flagsString, paint.isUnderlineText(), "UnderlinText"); + appendFlagToString(&flagsString, paint.isStrikeThruText(), "StrikeThruText"); + appendFlagToString(&flagsString, paint.isFakeBoldText(), "FakeBoldText"); + appendFlagToString(&flagsString, paint.isLinearText(), "LinearText"); + appendFlagToString(&flagsString, paint.isSubpixelText(), "SubpixelText"); + appendFlagToString(&flagsString, paint.isDevKernText(), "DevKernText"); + appendFlagToString(&flagsString, paint.isLCDRenderText(), "LCDRenderText"); + appendFlagToString(&flagsString, paint.isEmbeddedBitmapText(), "EmbeddedBitmapText"); + appendFlagToString(&flagsString, paint.isAutohinted(), "Autohinted"); + appendFlagToString(&flagsString, paint.isVerticalText(), "VerticalText"); + appendFlagToString(&flagsString, paint.getFlags() & SkPaint::kGenA8FromLCD_Flag, "GenA8FromLCD"); + return flagsString; + } + + String filterLevelName(SkPaint::FilterLevel filterLevel) + { + switch (filterLevel) { + case SkPaint::kNone_FilterLevel: return "None"; + case SkPaint::kLow_FilterLevel: return "Low"; + case SkPaint::kMedium_FilterLevel: return "Medium"; + case SkPaint::kHigh_FilterLevel: return "High"; + default: + ASSERT_NOT_REACHED(); + return "?"; + }; + } + + String textAlignName(SkPaint::Align align) + { + switch (align) { + case SkPaint::kLeft_Align: return "Left"; + case SkPaint::kCenter_Align: return "Center"; + case SkPaint::kRight_Align: return "Right"; + default: + ASSERT_NOT_REACHED(); + return "?"; + }; + } + + String strokeCapName(SkPaint::Cap cap) + { + switch (cap) { + case SkPaint::kButt_Cap: return "Butt"; + case SkPaint::kRound_Cap: return "Round"; + case SkPaint::kSquare_Cap: return "Square"; + default: + ASSERT_NOT_REACHED(); + return "?"; + }; + } + + String strokeJoinName(SkPaint::Join join) + { + switch (join) { + case SkPaint::kMiter_Join: return "Miter"; + case SkPaint::kRound_Join: return "Round"; + case SkPaint::kBevel_Join: return "Bevel"; + default: + ASSERT_NOT_REACHED(); + return "?"; + }; + } + + String styleName(SkPaint::Style style) + { + switch (style) { + case SkPaint::kFill_Style: return "Fill"; + case SkPaint::kStroke_Style: return "Stroke"; + case SkPaint::kStrokeAndFill_Style: return "StrokeAndFill"; + default: + ASSERT_NOT_REACHED(); + return "?"; + }; + } + + String textEncodingName(SkPaint::TextEncoding encoding) + { + switch (encoding) { + case SkPaint::kUTF8_TextEncoding: return "UTF-8"; + case SkPaint::kUTF16_TextEncoding: return "UTF-16"; + case SkPaint::kUTF32_TextEncoding: return "UTF-32"; + case SkPaint::kGlyphID_TextEncoding: return "GlyphID"; + default: + ASSERT_NOT_REACHED(); + return "?"; + }; + } + + String hintingName(SkPaint::Hinting hinting) + { + switch (hinting) { + case SkPaint::kNo_Hinting: return "None"; + case SkPaint::kSlight_Hinting: return "Slight"; + case SkPaint::kNormal_Hinting: return "Normal"; + case SkPaint::kFull_Hinting: return "Full"; + default: + ASSERT_NOT_REACHED(); + return "?"; + }; + } + + PassRefPtr<JSONObject> objectForSkPaint(const SkPaint& paint) + { + RefPtr<JSONObject> paintItem = JSONObject::create(); + paintItem->setNumber("textSize", paint.getTextSize()); + paintItem->setNumber("textScaleX", paint.getTextScaleX()); + paintItem->setNumber("textSkewX", paint.getTextSkewX()); + if (SkShader* shader = paint.getShader()) + paintItem->setObject("shader", objectForSkShader(*shader)); + paintItem->setString("color", stringForSkColor(paint.getColor())); + paintItem->setNumber("strokeWidth", paint.getStrokeWidth()); + paintItem->setNumber("strokeMiter", paint.getStrokeMiter()); + paintItem->setString("flags", stringForSkPaintFlags(paint)); + paintItem->setString("filterLevel", filterLevelName(paint.getFilterLevel())); + paintItem->setString("textAlign", textAlignName(paint.getTextAlign())); + paintItem->setString("strokeCap", strokeCapName(paint.getStrokeCap())); + paintItem->setString("strokeJoin", strokeJoinName(paint.getStrokeJoin())); + paintItem->setString("styleName", styleName(paint.getStyle())); + paintItem->setString("textEncoding", textEncodingName(paint.getTextEncoding())); + paintItem->setString("hinting", hintingName(paint.getHinting())); + return paintItem.release(); + } + + PassRefPtr<JSONArray> arrayForSkMatrix(const SkMatrix& matrix) + { + RefPtr<JSONArray> matrixArray = JSONArray::create(); + for (int i = 0; i < 9; ++i) + matrixArray->pushNumber(matrix[i]); + return matrixArray.release(); + } + + PassRefPtr<JSONArray> arrayForSkScalars(size_t n, const SkScalar scalars[]) + { + RefPtr<JSONArray> scalarsArray = JSONArray::create(); + for (size_t i = 0; i < n; ++i) + scalarsArray->pushNumber(scalars[i]); + return scalarsArray.release(); + } + + String regionOpName(SkRegion::Op op) + { + switch (op) { + case SkRegion::kDifference_Op: return "kDifference_Op"; + case SkRegion::kIntersect_Op: return "kIntersect_Op"; + case SkRegion::kUnion_Op: return "kUnion_Op"; + case SkRegion::kXOR_Op: return "kXOR_Op"; + case SkRegion::kReverseDifference_Op: return "kReverseDifference_Op"; + case SkRegion::kReplace_Op: return "kReplace_Op"; + default: return "Unknown type"; + }; + } + + void translate(SkScalar dx, SkScalar dy) + { + RefPtr<JSONObject> params = addItemWithParams("translate"); + params->setNumber("dx", dx); + params->setNumber("dy", dy); + } + + void scale(SkScalar scaleX, SkScalar scaleY) + { + RefPtr<JSONObject> params = addItemWithParams("scale"); + params->setNumber("scaleX", scaleX); + params->setNumber("scaleY", scaleY); + } + + void concat(const SkMatrix& matrix) + { + RefPtr<JSONObject> params = addItemWithParams("concat"); + params->setArray("matrix", arrayForSkMatrix(matrix)); + } + + String saveFlagsToString(SkCanvas::SaveFlags flags) + { + String flagsString = ""; + if (flags & SkCanvas::kHasAlphaLayer_SaveFlag) + flagsString.append("kHasAlphaLayer_SaveFlag "); + if (flags & SkCanvas::kFullColorLayer_SaveFlag) + flagsString.append("kFullColorLayer_SaveFlag "); + if (flags & SkCanvas::kClipToLayer_SaveFlag) + flagsString.append("kClipToLayer_SaveFlag "); + return flagsString; + } + + String textEncodingCanonicalName(SkPaint::TextEncoding encoding) + { + String name = textEncodingName(encoding); + if (encoding == SkPaint::kUTF16_TextEncoding || encoding == SkPaint::kUTF32_TextEncoding) + name.append("LE"); + return name; + } + + String stringForUTFText(const void* text, size_t length, SkPaint::TextEncoding encoding) + { + return WTF::TextEncoding(textEncodingCanonicalName(encoding)).decode((const char*)text, length); + } + + String stringForText(const void* text, size_t byteLength, const SkPaint& paint) + { + SkPaint::TextEncoding encoding = paint.getTextEncoding(); + switch (encoding) { + case SkPaint::kUTF8_TextEncoding: + case SkPaint::kUTF16_TextEncoding: + case SkPaint::kUTF32_TextEncoding: + return stringForUTFText(text, byteLength, encoding); + case SkPaint::kGlyphID_TextEncoding: { + WTF::Vector<SkUnichar> dataVector(byteLength / 2); + SkUnichar* textData = dataVector.data(); + paint.glyphsToUnichars(static_cast<const uint16_t*>(text), byteLength / 2, textData); + return WTF::UTF32LittleEndianEncoding().decode(reinterpret_cast<const char*>(textData), byteLength * 2); + } + default: + ASSERT_NOT_REACHED(); + return "?"; + } + } +}; + +static bool decodeBitmap(const void* data, size_t length, SkBitmap* result) +{ + RefPtr<SharedBuffer> buffer = SharedBuffer::create(static_cast<const char*>(data), length); + OwnPtr<ImageDecoder> imageDecoder = ImageDecoder::create(*buffer, ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileIgnored); + if (!imageDecoder) + return false; + imageDecoder->setData(buffer.get(), true); + ImageFrame* frame = imageDecoder->frameBufferAtIndex(0); + if (!frame) + return true; + *result = frame->getSkBitmap(); + return true; +} + +PassRefPtr<GraphicsContextSnapshot> GraphicsContextSnapshot::load(const char* data, size_t size) { + SkMemoryStream stream(data, size); + RefPtr<SkPicture> picture = adoptRef(SkPicture::CreateFromStream(&stream, decodeBitmap)); + if (!picture) + return nullptr; + return adoptRef(new GraphicsContextSnapshot(picture, false)); +} +PassOwnPtr<ImageBuffer> GraphicsContextSnapshot::replay(unsigned fromStep, unsigned toStep) const +{ OwnPtr<ImageBuffer> imageBuffer = createImageBuffer(); FragmentSnapshotPlayer player(m_picture, imageBuffer->context()->canvas()); player.play(fromStep, toStep); @@ -177,4 +1016,12 @@ PassOwnPtr<ImageBuffer> GraphicsContextSnapshot::createImageBuffer() const return ImageBuffer::create(IntSize(m_picture->width(), m_picture->height()), m_isCertainlyOpaque ? Opaque : NonOpaque); } +PassRefPtr<JSONArray> GraphicsContextSnapshot::snapshotCommandLog() const +{ + LoggingCanvas canvas(m_picture->width(), m_picture->height()); + FragmentSnapshotPlayer player(m_picture, &canvas); + player.play(0, 0); + return canvas.log(); +} + } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextRecorder.h b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextRecorder.h index 341fb70fe7f..a7e8b15568b 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextRecorder.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextRecorder.h @@ -31,9 +31,11 @@ #ifndef GraphicsContextRecorder_h #define GraphicsContextRecorder_h +#include "platform/JSONValues.h" #include "platform/PlatformExport.h" #include "platform/graphics/GraphicsContext.h" #include "third_party/skia/include/core/SkPicture.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" #include "wtf/RefCounted.h" namespace WebCore { @@ -43,8 +45,11 @@ WTF_MAKE_NONCOPYABLE(GraphicsContextSnapshot); public: typedef Vector<Vector<double> > Timings; + static PassRefPtr<GraphicsContextSnapshot> load(const char*, size_t); + PassOwnPtr<ImageBuffer> replay(unsigned fromStep = 0, unsigned toStep = 0) const; PassOwnPtr<Timings> profile(unsigned minIterations, double minDuration) const; + PassRefPtr<JSONArray> snapshotCommandLog() const; private: friend class GraphicsContextRecorder; @@ -66,6 +71,7 @@ public: private: RefPtr<SkPicture> m_picture; OwnPtr<GraphicsContext> m_context; + OwnPtr<SkPictureRecorder> m_recorder; bool m_isCertainlyOpaque; }; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextState.cpp b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextState.cpp new file mode 100644 index 00000000000..2084636f46e --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextState.cpp @@ -0,0 +1,256 @@ +// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" +#include "platform/graphics/GraphicsContextState.h" + +#include "platform/graphics/skia/SkiaUtils.h" + +namespace WebCore { + +GraphicsContextState::GraphicsContextState() + : m_fillColor(Color::black) + , m_fillRule(RULE_NONZERO) + , m_textDrawingMode(TextModeFill) + , m_alpha(256) + , m_xferMode(nullptr) + , m_compositeOperator(CompositeSourceOver) + , m_blendMode(blink::WebBlendModeNormal) + , m_interpolationQuality(InterpolationDefault) + , m_saveCount(0) + , m_shouldAntialias(true) + , m_shouldSmoothFonts(true) + , m_shouldClampToSourceRect(true) +{ + m_strokePaint.setStyle(SkPaint::kStroke_Style); + m_strokePaint.setStrokeWidth(SkFloatToScalar(m_strokeData.thickness())); + m_strokePaint.setColor(applyAlpha(m_strokeData.color().rgb())); + m_strokePaint.setStrokeCap(SkPaint::kDefault_Cap); + m_strokePaint.setStrokeJoin(SkPaint::kDefault_Join); + m_strokePaint.setStrokeMiter(SkFloatToScalar(m_strokeData.miterLimit())); + m_strokePaint.setFilterLevel(WebCoreInterpolationQualityToSkFilterLevel(m_interpolationQuality)); + m_strokePaint.setAntiAlias(m_shouldAntialias); + m_fillPaint.setColor(applyAlpha(m_fillColor.rgb())); + m_fillPaint.setFilterLevel(WebCoreInterpolationQualityToSkFilterLevel(m_interpolationQuality)); + m_fillPaint.setAntiAlias(m_shouldAntialias); +} + +GraphicsContextState::GraphicsContextState(const GraphicsContextState& other) + : m_strokePaint(other.m_strokePaint) + , m_fillPaint(other.m_fillPaint) + , m_strokeData(other.m_strokeData) + , m_fillColor(other.m_fillColor) + , m_fillRule(other.m_fillRule) + , m_fillGradient(other.m_fillGradient) + , m_fillPattern(other.m_fillPattern) + , m_looper(other.m_looper) + , m_textDrawingMode(other.m_textDrawingMode) + , m_alpha(other.m_alpha) + , m_xferMode(other.m_xferMode) + , m_colorFilter(other.m_colorFilter) + , m_compositeOperator(other.m_compositeOperator) + , m_blendMode(other.m_blendMode) + , m_interpolationQuality(other.m_interpolationQuality) + , m_saveCount(0) + , m_shouldAntialias(other.m_shouldAntialias) + , m_shouldSmoothFonts(other.m_shouldSmoothFonts) + , m_shouldClampToSourceRect(other.m_shouldClampToSourceRect) { } + +void GraphicsContextState::copy(const GraphicsContextState& source) +{ + this->~GraphicsContextState(); + new (this) GraphicsContextState(source); +} + +const SkPaint& GraphicsContextState::strokePaint(int strokedPathLength) const +{ + if (m_strokeData.gradient() && m_strokeData.gradient()->shaderChanged()) + m_strokePaint.setShader(m_strokeData.gradient()->shader()); + m_strokeData.setupPaintDashPathEffect(&m_strokePaint, strokedPathLength); + return m_strokePaint; +} + +const SkPaint& GraphicsContextState::fillPaint() const +{ + if (m_fillGradient && m_fillGradient->shaderChanged()) + m_fillPaint.setShader(m_fillGradient->shader()); + return m_fillPaint; +} + +void GraphicsContextState::setStrokeStyle(StrokeStyle style) +{ + m_strokeData.setStyle(style); +} + +void GraphicsContextState::setStrokeThickness(float thickness) +{ + m_strokeData.setThickness(thickness); + m_strokePaint.setStrokeWidth(SkFloatToScalar(thickness)); +} + +void GraphicsContextState::setStrokeColor(const Color& color) +{ + m_strokeData.clearGradient(); + m_strokeData.clearPattern(); + m_strokeData.setColor(color); + m_strokePaint.setColor(applyAlpha(color.rgb())); + m_strokePaint.setShader(0); +} + +void GraphicsContextState::setStrokeGradient(const PassRefPtr<Gradient> gradient) +{ + m_strokeData.setColor(Color::black); + m_strokeData.clearPattern(); + m_strokeData.setGradient(gradient); + m_strokePaint.setColor(applyAlpha(SK_ColorBLACK)); + m_strokePaint.setShader(m_strokeData.gradient()->shader()); +} + +void GraphicsContextState::clearStrokeGradient() +{ + m_strokeData.clearGradient(); + ASSERT(!m_strokeData.pattern()); + m_strokePaint.setColor(applyAlpha(m_strokeData.color().rgb())); +} + +void GraphicsContextState::setStrokePattern(const PassRefPtr<Pattern> pattern) +{ + m_strokeData.setColor(Color::black); + m_strokeData.clearGradient(); + m_strokeData.setPattern(pattern); + m_strokePaint.setColor(applyAlpha(SK_ColorBLACK)); + m_strokePaint.setShader(m_strokeData.pattern()->shader()); +} + +void GraphicsContextState::clearStrokePattern() +{ + m_strokeData.clearPattern(); + ASSERT(!m_strokeData.gradient()); + m_strokePaint.setColor(applyAlpha(m_strokeData.color().rgb())); +} + +void GraphicsContextState::setLineCap(LineCap cap) +{ + m_strokeData.setLineCap(cap); + m_strokePaint.setStrokeCap((SkPaint::Cap)cap); +} + +void GraphicsContextState::setLineJoin(LineJoin join) +{ + m_strokeData.setLineJoin(join); + m_strokePaint.setStrokeJoin((SkPaint::Join)join); +} + +void GraphicsContextState::setMiterLimit(float miterLimit) +{ + m_strokeData.setMiterLimit(miterLimit); + m_strokePaint.setStrokeMiter(SkFloatToScalar(miterLimit)); +} + +void GraphicsContextState::setFillColor(const Color& color) +{ + m_fillColor = color; + m_fillGradient.clear(); + m_fillPattern.clear(); + m_fillPaint.setColor(applyAlpha(color.rgb())); + m_fillPaint.setShader(0); +} + +void GraphicsContextState::setFillGradient(const PassRefPtr<Gradient> gradient) +{ + m_fillColor = Color::black; + m_fillPattern.clear(); + m_fillGradient = gradient; + m_fillPaint.setColor(applyAlpha(SK_ColorBLACK)); + m_fillPaint.setShader(m_fillGradient->shader()); +} + +void GraphicsContextState::clearFillGradient() +{ + m_fillGradient.clear(); + ASSERT(!m_fillPattern); + m_fillPaint.setColor(applyAlpha(m_fillColor.rgb())); +} + +void GraphicsContextState::setFillPattern(const PassRefPtr<Pattern> pattern) +{ + m_fillColor = Color::black; + m_fillGradient.clear(); + m_fillPattern = pattern; + m_fillPaint.setColor(applyAlpha(SK_ColorBLACK)); + m_fillPaint.setShader(m_fillPattern->shader()); +} + +void GraphicsContextState::clearFillPattern() +{ + m_fillPattern.clear(); + ASSERT(!m_fillGradient); + m_fillPaint.setColor(applyAlpha(m_fillColor.rgb())); +} + +// Shadow. (This will need tweaking if we use draw loopers for other things.) +void GraphicsContextState::setDrawLooper(PassRefPtr<SkDrawLooper> drawLooper) +{ + m_looper = drawLooper; + m_strokePaint.setLooper(m_looper.get()); + m_fillPaint.setLooper(m_looper.get()); +} + +void GraphicsContextState::clearDrawLooper() +{ + m_looper.clear(); + m_strokePaint.setLooper(0); + m_fillPaint.setLooper(0); +} + +void GraphicsContextState::setAlphaAsFloat(float alpha) +{ + if (alpha < 0) { + m_alpha = 0; + } else { + m_alpha = roundf(alpha * 256); + if (m_alpha > 256) + m_alpha = 256; + } + m_strokePaint.setColor(applyAlpha(m_strokeData.color().rgb())); + m_fillPaint.setColor(applyAlpha(m_fillColor.rgb())); +} + +void GraphicsContextState::setLineDash(const DashArray& dashes, float dashOffset) +{ + m_strokeData.setLineDash(dashes, dashOffset); +} + +void GraphicsContextState::setColorFilter(PassRefPtr<SkColorFilter> colorFilter) +{ + m_colorFilter = colorFilter; + m_strokePaint.setColorFilter(m_colorFilter.get()); + m_fillPaint.setColorFilter(m_colorFilter.get()); +} + +void GraphicsContextState::setCompositeOperation(CompositeOperator compositeOperation, blink::WebBlendMode blendMode) +{ + m_compositeOperator = compositeOperation; + m_blendMode = blendMode; + m_xferMode = WebCoreCompositeToSkiaComposite(compositeOperation, blendMode); + m_strokePaint.setXfermode(m_xferMode.get()); + m_fillPaint.setXfermode(m_xferMode.get()); +} + +void GraphicsContextState::setInterpolationQuality(InterpolationQuality quality) +{ + m_interpolationQuality = quality; + m_strokePaint.setFilterLevel(WebCoreInterpolationQualityToSkFilterLevel(quality)); + m_fillPaint.setFilterLevel(WebCoreInterpolationQualityToSkFilterLevel(quality)); +} + +void GraphicsContextState::setShouldAntialias(bool shouldAntialias) +{ + m_shouldAntialias = shouldAntialias; + m_strokePaint.setAntiAlias(shouldAntialias); + m_fillPaint.setAntiAlias(shouldAntialias); +} + + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextState.h b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextState.h index d7e20da33f1..a3adc04d479 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextState.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextState.h @@ -29,15 +29,15 @@ #ifndef GraphicsContextState_h #define GraphicsContextState_h +#include "platform/graphics/DrawLooperBuilder.h" #include "platform/graphics/Gradient.h" #include "platform/graphics/GraphicsTypes.h" #include "platform/graphics/Path.h" #include "platform/graphics/Pattern.h" #include "platform/graphics/StrokeData.h" +#include "platform/graphics/skia/SkiaUtils.h" #include "third_party/skia/include/core/SkColorFilter.h" -#include "third_party/skia/include/core/SkColorPriv.h" -#include "third_party/skia/include/core/SkDrawLooper.h" -#include "third_party/skia/include/effects/SkDashPathEffect.h" +#include "third_party/skia/include/core/SkPaint.h" #include "wtf/PassOwnPtr.h" #include "wtf/RefPtr.h" @@ -45,96 +45,144 @@ namespace WebCore { // Encapsulates the state information we store for each pushed graphics state. // Only GraphicsContext can use this class. -class GraphicsContextState { -private: - friend class GraphicsContext; - - GraphicsContextState() - : m_fillColor(Color::black) - , m_fillRule(RULE_NONZERO) - , m_textDrawingMode(TextModeFill) - , m_alpha(1) - , m_xferMode(0) - , m_compositeOperator(CompositeSourceOver) - , m_blendMode(blink::WebBlendModeNormal) -#if USE(LOW_QUALITY_IMAGE_INTERPOLATION) - , m_interpolationQuality(InterpolationLow) -#else - , m_interpolationQuality(InterpolationHigh) -#endif - , m_shouldAntialias(true) - , m_shouldSmoothFonts(true) - , m_shouldClampToSourceRect(true) +class PLATFORM_EXPORT GraphicsContextState FINAL { +public: + static PassOwnPtr<GraphicsContextState> create() { + return adoptPtr(new GraphicsContextState()); } - GraphicsContextState(const GraphicsContextState& other) - : m_strokeData(other.m_strokeData) - , m_fillColor(other.m_fillColor) - , m_fillRule(other.m_fillRule) - , m_fillGradient(other.m_fillGradient) - , m_fillPattern(other.m_fillPattern) - , m_looper(other.m_looper) - , m_textDrawingMode(other.m_textDrawingMode) - , m_alpha(other.m_alpha) - , m_xferMode(other.m_xferMode) - , m_colorFilter(other.m_colorFilter) - , m_compositeOperator(other.m_compositeOperator) - , m_blendMode(other.m_blendMode) - , m_interpolationQuality(other.m_interpolationQuality) - , m_shouldAntialias(other.m_shouldAntialias) - , m_shouldSmoothFonts(other.m_shouldSmoothFonts) - , m_shouldClampToSourceRect(other.m_shouldClampToSourceRect) + static PassOwnPtr<GraphicsContextState> createAndCopy(const GraphicsContextState& other) { + return adoptPtr(new GraphicsContextState(other)); } + void copy(const GraphicsContextState&); + + // SkPaint objects that reflect the current state. If the length of the + // path to be stroked is known, pass it in for correct dash or dot placement. + const SkPaint& strokePaint(int strokedPathLength = 0) const; + const SkPaint& fillPaint() const; + + uint16_t saveCount() const { return m_saveCount; } + void incrementSaveCount() { ++m_saveCount; } + void decrementSaveCount() { --m_saveCount; } + + // Stroke data + const StrokeData& strokeData() const { return m_strokeData; } + + void setStrokeStyle(StrokeStyle); + + void setStrokeThickness(float); + + SkColor effectiveStrokeColor() const { return applyAlpha(m_strokeData.color().rgb()); } + void setStrokeColor(const Color&); + + void setStrokeGradient(const PassRefPtr<Gradient>); + void clearStrokeGradient(); + + void setStrokePattern(const PassRefPtr<Pattern>); + void clearStrokePattern(); + + void setLineCap(LineCap); + + void setLineJoin(LineJoin); + + void setMiterLimit(float); + + void setLineDash(const DashArray&, float); + + // Fill data + Color fillColor() const { return m_fillColor; } + SkColor effectiveFillColor() const { return applyAlpha(m_fillColor.rgb()); } + void setFillColor(const Color&); + + Gradient* fillGradient() const { return m_fillGradient.get(); } + void setFillGradient(const PassRefPtr<Gradient>); + void clearFillGradient(); + + Pattern* fillPattern() const { return m_fillPattern.get(); } + void setFillPattern(const PassRefPtr<Pattern>); + void clearFillPattern(); + + // Path fill rule + WindRule fillRule() const { return m_fillRule; } + void setFillRule(WindRule rule) { m_fillRule = rule; } + + // Shadow. (This will need tweaking if we use draw loopers for other things.) + SkDrawLooper* drawLooper() const { return m_looper.get(); } + void setDrawLooper(PassRefPtr<SkDrawLooper>); + void clearDrawLooper(); + + // Text. (See TextModeFill & friends.) + TextDrawingModeFlags textDrawingMode() const { return m_textDrawingMode; } + void setTextDrawingMode(TextDrawingModeFlags mode) { m_textDrawingMode = mode; } + + // Common shader state. + int alpha() const { return m_alpha; } + void setAlphaAsFloat(float); + + SkColorFilter* colorFilter() const { return m_colorFilter.get(); } + void setColorFilter(PassRefPtr<SkColorFilter>); + + // Compositing control, for the CSS and Canvas compositing spec. + void setCompositeOperation(CompositeOperator, blink::WebBlendMode); + CompositeOperator compositeOperator() const { return m_compositeOperator; } + blink::WebBlendMode blendMode() const { return m_blendMode; } + SkXfermode* xferMode() const { return m_xferMode.get(); } + + // Image interpolation control. + InterpolationQuality interpolationQuality() const { return m_interpolationQuality; } + void setInterpolationQuality(InterpolationQuality); + + bool shouldAntialias() const { return m_shouldAntialias; } + void setShouldAntialias(bool); + + bool shouldSmoothFonts() const { return m_shouldSmoothFonts; } + void setShouldSmoothFonts(bool shouldSmoothFonts) { m_shouldSmoothFonts = shouldSmoothFonts; } + + bool shouldClampToSourceRect() const { return m_shouldClampToSourceRect; } + void setShouldClampToSourceRect(bool shouldClampToSourceRect) { m_shouldClampToSourceRect = shouldClampToSourceRect; } + +private: + GraphicsContextState(); + explicit GraphicsContextState(const GraphicsContextState&); + GraphicsContextState& operator=(const GraphicsContextState&); + // Helper function for applying the state's alpha value to the given input // color to produce a new output color. SkColor applyAlpha(SkColor c) const { - int s = roundf(m_alpha * 256); - if (s >= 256) - return c; - if (s < 0) - return 0; - - int a = SkAlphaMul(SkColorGetA(c), s); + int a = SkAlphaMul(SkColorGetA(c), m_alpha); return (c & 0x00FFFFFF) | (a << 24); } - // Returns a new State with all of this object's inherited properties copied. - PassOwnPtr<GraphicsContextState> clone() { return adoptPtr(new GraphicsContextState(*this)); } - - // Not supported. No implementations. - void operator=(const GraphicsContextState&); + // These are mutbale to enable gradient updates when the paints are fetched for use. + mutable SkPaint m_strokePaint; + mutable SkPaint m_fillPaint; - // Stroke. StrokeData m_strokeData; - // Fill. Color m_fillColor; WindRule m_fillRule; RefPtr<Gradient> m_fillGradient; RefPtr<Pattern> m_fillPattern; - // Shadow. (This will need tweaking if we use draw loopers for other things.) RefPtr<SkDrawLooper> m_looper; - // Text. (See TextModeFill & friends.) TextDrawingModeFlags m_textDrawingMode; - // Common shader state. - float m_alpha; + int m_alpha; RefPtr<SkXfermode> m_xferMode; RefPtr<SkColorFilter> m_colorFilter; - // Compositing control, for the CSS and Canvas compositing spec. CompositeOperator m_compositeOperator; blink::WebBlendMode m_blendMode; - // Image interpolation control. InterpolationQuality m_interpolationQuality; + uint16_t m_saveCount; + bool m_shouldAntialias : 1; bool m_shouldSmoothFonts : 1; bool m_shouldClampToSourceRect : 1; @@ -143,4 +191,3 @@ private: } // namespace WebCore #endif // GraphicsContextState_h - diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextTest.cpp b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextTest.cpp new file mode 100644 index 00000000000..dbf9861c786 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContextTest.cpp @@ -0,0 +1,1123 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "platform/graphics/GraphicsContext.h" + +#include "platform/graphics/BitmapImage.h" +#include "platform/graphics/DisplayList.h" +#include "platform/graphics/ImageBuffer.h" +#include "platform/graphics/skia/NativeImageSkia.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkPicture.h" +#include <gtest/gtest.h> + +using namespace WebCore; + +namespace { + +#define EXPECT_EQ_RECT(a, b) \ + EXPECT_EQ(a.x(), b.x()); \ + EXPECT_EQ(a.y(), b.y()); \ + EXPECT_EQ(a.width(), b.width()); \ + EXPECT_EQ(a.height(), b.height()); + +#define EXPECT_PIXELS_MATCH(bitmap, opaqueRect) \ +{ \ + SkAutoLockPixels locker(bitmap); \ + for (int y = opaqueRect.y(); y < opaqueRect.maxY(); ++y) \ + for (int x = opaqueRect.x(); x < opaqueRect.maxX(); ++x) { \ + int alpha = *bitmap.getAddr32(x, y) >> 24; \ + EXPECT_EQ(255, alpha); \ + } \ +} + +#define EXPECT_PIXELS_MATCH_EXACT(bitmap, opaqueRect) \ +{ \ + SkAutoLockPixels locker(bitmap); \ + for (int y = 0; y < bitmap.height(); ++y) \ + for (int x = 0; x < bitmap.width(); ++x) { \ + int alpha = *bitmap.getAddr32(x, y) >> 24; \ + bool opaque = opaqueRect.contains(x, y); \ + EXPECT_EQ(opaque, alpha == 255); \ + } \ +} + +TEST(GraphicsContextTest, trackOpaqueTest) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(400, 400)); + bitmap.eraseColor(0); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 90, 90), alpha, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(99, 13, 10, 90), opaque, CompositePlusLighter); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(99, 13, 10, 90), opaque, CompositeSourceIn); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(99, 13, 10, 90), alpha, CompositeSourceIn); + EXPECT_EQ_RECT(IntRect(10, 10, 89, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(8, 8, 3, 90), opaque, CompositeSourceOut); + EXPECT_EQ_RECT(IntRect(11, 10, 88, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(30, 30, 290, 290), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(30, 30, 290, 290), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(40, 20, 290, 50), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(30, 30, 290, 290), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 390, 50), opaque, CompositeSourceIn); + EXPECT_EQ_RECT(IntRect(30, 30, 290, 290), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 390, 50), alpha); + EXPECT_EQ_RECT(IntRect(30, 30, 290, 290), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 390, 50), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(30, 10, 290, 310), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); +} + +TEST(GraphicsContextTest, trackOpaqueClipTest) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(400, 400)); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.clearRect(FloatRect(10, 10, 90, 90)); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + + context.save(); + context.clip(FloatRect(0, 0, 10, 10)); + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + context.restore(); + + context.clearRect(FloatRect(10, 10, 90, 90)); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + + context.save(); + context.clip(FloatRect(20, 20, 10, 10)); + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 10, 10), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.clearRect(FloatRect(10, 10, 90, 90)); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + + // The intersection of the two clips becomes empty. + context.clip(FloatRect(30, 20, 10, 10)); + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + context.restore(); + + context.clearRect(FloatRect(10, 10, 90, 90)); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + + // The transform and the clip need to interact correctly (transform first) + context.save(); + context.translate(10, 10); + context.clip(FloatRect(20, 20, 10, 10)); + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(30, 30, 10, 10), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + context.restore(); + + context.clearRect(FloatRect(10, 10, 90, 90)); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + + // The transform and the clip need to interact correctly (clip first) + context.save(); + context.clip(FloatRect(20, 20, 10, 10)); + context.translate(10, 10); + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 10, 10), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + context.restore(); + + context.clearRect(FloatRect(10, 10, 90, 90)); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + + Path path; + path.moveTo(FloatPoint(0, 0)); + path.addLineTo(FloatPoint(100, 0)); + + // Non-rectangular clips just cause the paint to be considered non-opaque. + context.save(); + context.clipPath(path, RULE_EVENODD); + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + context.restore(); + + // Another non-rectangular clip. + context.save(); + context.clip(IntRect(30, 30, 20, 20)); + context.clipOut(IntRect(30, 30, 10, 10)); + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + context.restore(); +} + +TEST(GraphicsContextTest, trackImageMask) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(400, 400)); + bitmap.eraseColor(0); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + // Image masks are done by drawing a bitmap into a transparency layer that uses DstIn to mask + // out a transparency layer below that is filled with the mask color. In the end this should + // not be marked opaque. + + context.setCompositeOperation(CompositeSourceOver); + context.beginTransparencyLayer(1); + context.fillRect(FloatRect(10, 10, 10, 10), opaque, CompositeSourceOver); + + context.setCompositeOperation(CompositeDestinationIn); + context.beginTransparencyLayer(1); + + OwnPtr<ImageBuffer> alphaImage = ImageBuffer::create(IntSize(100, 100)); + alphaImage->context()->fillRect(IntRect(0, 0, 100, 100), alpha); + + context.setCompositeOperation(CompositeSourceOver); + context.drawImageBuffer(alphaImage.get(), FloatRect(10, 10, 10, 10)); + + context.endLayer(); + context.endLayer(); + + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH_EXACT(bitmap, context.opaqueRegion().asRect()); +} + +TEST(GraphicsContextTest, trackImageMaskWithOpaqueRect) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(400, 400)); + bitmap.eraseColor(0); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + // Image masks are done by drawing a bitmap into a transparency layer that uses DstIn to mask + // out a transparency layer below that is filled with the mask color. In the end this should + // not be marked opaque. + + context.setCompositeOperation(CompositeSourceOver); + context.beginTransparencyLayer(1); + context.fillRect(FloatRect(10, 10, 10, 10), opaque, CompositeSourceOver); + + context.setCompositeOperation(CompositeDestinationIn); + context.beginTransparencyLayer(1); + + OwnPtr<ImageBuffer> alphaImage = ImageBuffer::create(IntSize(100, 100)); + alphaImage->context()->fillRect(IntRect(0, 0, 100, 100), alpha); + + context.setCompositeOperation(CompositeSourceOver); + context.drawImageBuffer(alphaImage.get(), FloatRect(10, 10, 10, 10)); + + // We can't have an opaque mask actually, but we can pretend here like it would look if we did. + context.fillRect(FloatRect(12, 12, 3, 3), opaque, CompositeSourceOver); + + context.endLayer(); + context.endLayer(); + + EXPECT_EQ_RECT(IntRect(12, 12, 3, 3), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH_EXACT(bitmap, context.opaqueRegion().asRect()); +} + +TEST(GraphicsContextTest, trackOpaqueJoinTest) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(400, 400)); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + context.fillRect(FloatRect(20, 20, 10, 10), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 10, 10), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + // Doesn't join + context.fillRect(FloatRect(31, 20, 10, 10), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 10, 10), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + // Does join + context.fillRect(FloatRect(30, 20, 10, 10), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 20, 10), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + // Doesn't join + context.fillRect(FloatRect(20, 31, 20, 10), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 20, 10), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + // Does join + context.fillRect(FloatRect(20, 30, 20, 10), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 20, 20), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + // Doesn't join + context.fillRect(FloatRect(9, 20, 10, 20), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 20, 20), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + // Does join + context.fillRect(FloatRect(10, 20, 10, 20), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 20, 30, 20), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + // Doesn't join + context.fillRect(FloatRect(10, 9, 30, 10), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 20, 30, 20), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + // Does join + context.fillRect(FloatRect(10, 10, 30, 10), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 30, 30), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); +} + +TEST(GraphicsContextTest, trackOpaqueLineTest) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(200, 200)); + bitmap.eraseColor(0); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + context.setShouldAntialias(false); + context.setMiterLimit(0); + context.setStrokeThickness(4); + context.setLineCap(SquareCap); + context.setStrokeStyle(SolidStroke); + context.setCompositeOperation(CompositeSourceOver); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.setCompositeOperation(CompositeSourceIn); + + context.save(); + context.setStrokeColor(alpha); + context.drawLine(IntPoint(0, 0), IntPoint(100, 0)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.save(); + context.setStrokeColor(opaque); + context.drawLine(IntPoint(0, 10), IntPoint(100, 10)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.save(); + context.setStrokeColor(alpha); + context.drawLine(IntPoint(0, 10), IntPoint(100, 10)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 13, 90, 87), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.save(); + context.setStrokeColor(alpha); + context.drawLine(IntPoint(0, 11), IntPoint(100, 11)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 14, 90, 86), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.setShouldAntialias(true); + context.setCompositeOperation(CompositeSourceOver); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.setCompositeOperation(CompositeSourceIn); + + context.save(); + context.setStrokeColor(alpha); + context.drawLine(IntPoint(0, 0), IntPoint(100, 0)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.setShouldAntialias(false); + context.save(); + context.setStrokeColor(opaque); + context.drawLine(IntPoint(0, 10), IntPoint(100, 10)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.setShouldAntialias(true); + context.save(); + context.setStrokeColor(opaque); + context.drawLine(IntPoint(0, 10), IntPoint(100, 10)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 13, 90, 87), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.save(); + context.setStrokeColor(alpha); + context.drawLine(IntPoint(0, 11), IntPoint(100, 11)); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 14, 90, 86), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); +} + +TEST(GraphicsContextTest, trackOpaquePathTest) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(200, 200)); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.setShouldAntialias(false); + context.setMiterLimit(1); + context.setStrokeThickness(5); + context.setLineCap(SquareCap); + context.setStrokeStyle(SolidStroke); + context.setCompositeOperation(CompositeSourceIn); + + Path path; + + context.setFillColor(alpha); + path.moveTo(FloatPoint(0, 0)); + path.addLineTo(FloatPoint(100, 0)); + context.fillPath(path); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + path.clear(); + + context.setFillColor(opaque); + path.moveTo(FloatPoint(0, 10)); + path.addLineTo(FloatPoint(100, 13)); + context.fillPath(path); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + path.clear(); + + context.setFillColor(alpha); + path.moveTo(FloatPoint(0, 10)); + path.addLineTo(FloatPoint(100, 13)); + context.fillPath(path); + EXPECT_EQ_RECT(IntRect(10, 13, 90, 87), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + path.clear(); + + context.setFillColor(alpha); + path.moveTo(FloatPoint(0, 14)); + path.addLineTo(FloatPoint(100, 10)); + context.fillPath(path); + EXPECT_EQ_RECT(IntRect(10, 14, 90, 86), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + path.clear(); +} + +TEST(GraphicsContextTest, trackOpaqueImageTest) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(200, 200)); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + SkBitmap opaqueBitmap; + ASSERT_TRUE(opaqueBitmap.allocN32Pixels(10, 10, true /* opaque */)); + + for (int y = 0; y < opaqueBitmap.height(); ++y) + for (int x = 0; x < opaqueBitmap.width(); ++x) + *opaqueBitmap.getAddr32(x, y) = 0xFFFFFFFF; + RefPtr<BitmapImage> opaqueImage = BitmapImage::create(NativeImageSkia::create(opaqueBitmap)); + EXPECT_TRUE(opaqueImage->currentFrameKnownToBeOpaque()); + + SkBitmap alphaBitmap; + ASSERT_TRUE(alphaBitmap.allocN32Pixels(10, 10)); + + for (int y = 0; y < alphaBitmap.height(); ++y) + for (int x = 0; x < alphaBitmap.width(); ++x) + *alphaBitmap.getAddr32(x, y) = 0x00000000; + RefPtr<BitmapImage> alphaImage = BitmapImage::create(NativeImageSkia::create(alphaBitmap)); + EXPECT_FALSE(alphaImage->currentFrameKnownToBeOpaque()); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawImage(opaqueImage.get(), IntPoint(0, 0)); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + context.drawImage(alphaImage.get(), IntPoint(0, 0)); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawImage(opaqueImage.get(), IntPoint(5, 5)); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + context.drawImage(alphaImage.get(), IntPoint(5, 5)); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawImage(opaqueImage.get(), IntPoint(10, 10)); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + context.drawImage(alphaImage.get(), IntPoint(10, 10)); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawImage(alphaImage.get(), IntPoint(20, 10), CompositeSourceIn); + EXPECT_EQ_RECT(IntRect(10, 20, 90, 80), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.save(); + context.setAlphaAsFloat(0.5); + context.drawImage(opaqueImage.get(), IntPoint(25, 15), CompositeSourceIn); + context.restore(); + EXPECT_EQ_RECT(IntRect(10, 25, 90, 75), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawImage(alphaImage.get(), IntPoint(10, 20), CompositeSourceIn); + EXPECT_EQ_RECT(IntRect(20, 10, 80, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.save(); + context.setAlphaAsFloat(0.5); + context.drawImage(opaqueImage.get(), IntPoint(15, 25), CompositeSourceIn); + context.restore(); + EXPECT_EQ_RECT(IntRect(25, 10, 75, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); +} + +TEST(GraphicsContextTest, trackOpaqueOvalTest) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(200, 200)); + bitmap.eraseColor(0); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillEllipse(FloatRect(10, 10, 90, 90)); + context.strokeEllipse(FloatRect(10, 10, 90, 90)); + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.setCompositeOperation(CompositeSourceIn); + + context.setShouldAntialias(false); + + context.setFillColor(opaque); + context.fillEllipse(FloatRect(10, 10, 50, 30)); + context.strokeEllipse(FloatRect(10, 10, 50, 30)); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.setFillColor(alpha); + context.fillEllipse(FloatRect(10, 10, 30, 50)); + context.strokeEllipse(FloatRect(10, 10, 30, 50)); + EXPECT_EQ_RECT(IntRect(40, 10, 60, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.setShouldAntialias(true); + + context.setFillColor(opaque); + context.fillEllipse(FloatRect(10, 10, 50, 30)); + context.strokeEllipse(FloatRect(10, 10, 50, 30)); + EXPECT_EQ_RECT(IntRect(40, 41, 60, 59), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.setFillColor(alpha); + context.fillEllipse(FloatRect(20, 10, 30, 50)); + context.strokeEllipse(FloatRect(20, 10, 30, 50)); + EXPECT_EQ_RECT(IntRect(51, 41, 49, 59), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); +} + +TEST(GraphicsContextTest, trackOpaqueRoundedRectTest) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(200, 200)); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + IntSize radii(10, 10); + + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRoundedRect(IntRect(10, 10, 90, 90), radii, radii, radii, radii, opaque); + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.setCompositeOperation(CompositeSourceIn); + context.setShouldAntialias(false); + + context.fillRoundedRect(IntRect(10, 10, 50, 30), radii, radii, radii, radii, opaque); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRoundedRect(IntRect(10, 10, 30, 50), radii, radii, radii, radii, alpha); + EXPECT_EQ_RECT(IntRect(40, 10, 60, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRoundedRect(IntRect(10, 0, 50, 30), radii, radii, radii, radii, alpha); + EXPECT_EQ_RECT(IntRect(40, 30, 60, 70), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRoundedRect(IntRect(30, 0, 70, 50), radii, radii, radii, radii, opaque); + EXPECT_EQ_RECT(IntRect(40, 30, 60, 70), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); +} + +TEST(GraphicsContextTest, trackOpaqueTextTest) +{ + int width = 200, height = 200; + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(width, height)); + bitmap.eraseColor(0); + SkCanvas canvas(bitmap); + SkRect textRect = SkRect::MakeWH(width, height); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + SkPaint opaquePaint; + opaquePaint.setColor(opaque.rgb()); + opaquePaint.setXfermodeMode(SkXfermode::kSrc_Mode); + SkPaint alphaPaint; + alphaPaint.setColor(alpha.rgb()); + alphaPaint.setXfermodeMode(SkXfermode::kSrc_Mode); + + SkPoint point = SkPoint::Make(0, 0); + + context.fillRect(FloatRect(50, 50, 50, 50), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(50, 50, 50, 50), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawPosText("A", 1, &point, textRect, opaquePaint); + EXPECT_EQ_RECT(IntRect(50, 50, 50, 50), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawPosText("A", 1, &point, textRect, alphaPaint); + EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(50, 50, 50, 50), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(50, 50, 50, 50), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(50, 50, 50, 50), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(50, 50, 50, 50), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); +} + +TEST(GraphicsContextTest, trackOpaqueWritePixelsTest) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(200, 200)); + bitmap.eraseColor(0); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + + SkBitmap opaqueBitmap; + ASSERT_TRUE(opaqueBitmap.allocN32Pixels(10, 10, true /* opaque */)); + for (int y = 0; y < opaqueBitmap.height(); ++y) + for (int x = 0; x < opaqueBitmap.width(); ++x) + *opaqueBitmap.getAddr32(x, y) = 0xFFFFFFFF; + + SkBitmap alphaBitmap; + ASSERT_TRUE(alphaBitmap.allocN32Pixels(10, 10)); + for (int y = 0; y < alphaBitmap.height(); ++y) + for (int x = 0; x < alphaBitmap.width(); ++x) + *alphaBitmap.getAddr32(x, y) = 0x00000000; + + SkPaint paint; + paint.setXfermodeMode(SkXfermode::kSrc_Mode); + + context.writePixels(opaqueBitmap, 50, 50); + EXPECT_EQ_RECT(IntRect(50, 50, 10, 10), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.writePixels(alphaBitmap, 10, 0); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.writePixels(alphaBitmap, 10, 1); + EXPECT_EQ_RECT(IntRect(10, 11, 90, 89), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.writePixels(alphaBitmap, 0, 10); + EXPECT_EQ_RECT(IntRect(10, 11, 90, 89), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.writePixels(alphaBitmap, 1, 10); + EXPECT_EQ_RECT(IntRect(11, 11, 89, 89), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); +} + +TEST(GraphicsContextTest, trackOpaqueDrawBitmapTest) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(200, 200)); + bitmap.eraseColor(0); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + + SkBitmap opaqueBitmap; + ASSERT_TRUE(opaqueBitmap.allocN32Pixels(10, 10, true /* opaque */)); + for (int y = 0; y < opaqueBitmap.height(); ++y) + for (int x = 0; x < opaqueBitmap.width(); ++x) + *opaqueBitmap.getAddr32(x, y) = 0xFFFFFFFF; + + SkBitmap alphaBitmap; + ASSERT_TRUE(alphaBitmap.allocN32Pixels(10, 10)); + for (int y = 0; y < alphaBitmap.height(); ++y) + for (int x = 0; x < alphaBitmap.width(); ++x) + *alphaBitmap.getAddr32(x, y) = 0x00000000; + + SkPaint paint; + paint.setXfermodeMode(SkXfermode::kSrc_Mode); + + context.drawBitmap(opaqueBitmap, 10, 10, &paint); + EXPECT_EQ_RECT(IntRect(10, 10, 10, 10), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.fillRect(FloatRect(10, 10, 90, 90), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawBitmap(alphaBitmap, 10, 0, &paint); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawBitmap(alphaBitmap, 10, 1, &paint); + EXPECT_EQ_RECT(IntRect(10, 11, 90, 89), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawBitmap(alphaBitmap, 0, 10, &paint); + EXPECT_EQ_RECT(IntRect(10, 11, 90, 89), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawBitmap(alphaBitmap, 1, 10, &paint); + EXPECT_EQ_RECT(IntRect(11, 11, 89, 89), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); +} + +TEST(GraphicsContextTest, trackOpaqueDrawBitmapRectTest) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(200, 200)); + bitmap.eraseColor(0); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + + SkBitmap opaqueBitmap; + ASSERT_TRUE(opaqueBitmap.allocN32Pixels(10, 10, true /* opaque */)); + for (int y = 0; y < opaqueBitmap.height(); ++y) + for (int x = 0; x < opaqueBitmap.width(); ++x) + *opaqueBitmap.getAddr32(x, y) = 0xFFFFFFFF; + + SkBitmap alphaBitmap; + ASSERT_TRUE(alphaBitmap.allocN32Pixels(10, 10)); + for (int y = 0; y < alphaBitmap.height(); ++y) + for (int x = 0; x < alphaBitmap.width(); ++x) + *alphaBitmap.getAddr32(x, y) = 0x00000000; + + SkPaint paint; + paint.setXfermodeMode(SkXfermode::kSrc_Mode); + + context.drawBitmapRect(opaqueBitmap, 0, SkRect::MakeXYWH(10, 10, 90, 90), &paint); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawBitmapRect(alphaBitmap, 0, SkRect::MakeXYWH(10, 0, 10, 10), &paint); + EXPECT_EQ_RECT(IntRect(10, 10, 90, 90), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawBitmapRect(alphaBitmap, 0, SkRect::MakeXYWH(10, 0, 10, 11), &paint); + EXPECT_EQ_RECT(IntRect(10, 11, 90, 89), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawBitmapRect(alphaBitmap, 0, SkRect::MakeXYWH(0, 10, 10, 10), &paint); + EXPECT_EQ_RECT(IntRect(10, 11, 90, 89), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.drawBitmapRect(alphaBitmap, 0, SkRect::MakeXYWH(0, 10, 11, 10), &paint); + EXPECT_EQ_RECT(IntRect(11, 11, 89, 89), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); +} + +TEST(GraphicsContextTest, contextTransparencyLayerTest) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(400, 400)); + bitmap.eraseColor(0); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + context.fillRect(FloatRect(20, 20, 10, 10), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(20, 20, 10, 10), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); + + context.clearRect(FloatRect(20, 20, 10, 10)); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + + context.beginTransparencyLayer(0.5); + context.save(); + context.fillRect(FloatRect(20, 20, 10, 10), opaque, CompositeSourceOver); + context.restore(); + context.endLayer(); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + + context.clearRect(FloatRect(20, 20, 10, 10)); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + + context.beginTransparencyLayer(0.5); + context.fillRect(FloatRect(20, 20, 10, 10), opaque, CompositeSourceOver); + context.endLayer(); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); +} + +TEST(GraphicsContextTest, UnboundedDrawsAreClipped) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(400, 400)); + bitmap.eraseColor(0); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + Path path; + context.setShouldAntialias(false); + context.setMiterLimit(1); + context.setStrokeThickness(5); + context.setLineCap(SquareCap); + context.setStrokeStyle(SolidStroke); + + // Make skia unable to compute fast bounds for our paths. + DashArray dashArray; + dashArray.append(1); + dashArray.append(0); + context.setLineDash(dashArray, 0); + + // Make the device opaque in 10,10 40x40. + context.fillRect(FloatRect(10, 10, 40, 40), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 40, 40), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH_EXACT(bitmap, context.opaqueRegion().asRect()); + + // Clip to the left edge of the opaque area. + context.clip(IntRect(10, 10, 10, 40)); + + // Draw a path that gets clipped. This should destroy the opaque area but only inside the clip. + context.setCompositeOperation(CompositeSourceOut); + context.setFillColor(alpha); + path.moveTo(FloatPoint(10, 10)); + path.addLineTo(FloatPoint(40, 40)); + context.strokePath(path); + + EXPECT_EQ_RECT(IntRect(20, 10, 30, 40), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH(bitmap, context.opaqueRegion().asRect()); +} + +TEST(GraphicsContextTest, PreserveOpaqueOnlyMattersForFirstLayer) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(400, 400)); + bitmap.eraseColor(0); + SkCanvas canvas(bitmap); + + GraphicsContext context(&canvas); + context.setTrackOpaqueRegion(true); + + Color opaque(1.0f, 0.0f, 0.0f, 1.0f); + Color alpha(0.0f, 0.0f, 0.0f, 0.0f); + + Path path; + context.setShouldAntialias(false); + context.setMiterLimit(1); + context.setStrokeThickness(5); + context.setLineCap(SquareCap); + context.setStrokeStyle(SolidStroke); + + // Make skia unable to compute fast bounds for our paths. + DashArray dashArray; + dashArray.append(1); + dashArray.append(0); + context.setLineDash(dashArray, 0); + + // Make the device opaque in 10,10 40x40. + context.fillRect(FloatRect(10, 10, 40, 40), opaque, CompositeSourceOver); + EXPECT_EQ_RECT(IntRect(10, 10, 40, 40), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH_EXACT(bitmap, context.opaqueRegion().asRect()); + + // Begin a layer that preserves opaque. + context.setCompositeOperation(CompositeSourceOver); + context.beginTransparencyLayer(0.5); + + // Begin a layer that does not preserve opaque. + context.setCompositeOperation(CompositeSourceOut); + context.beginTransparencyLayer(0.5); + + // This should not destroy the device opaqueness. + context.fillRect(FloatRect(10, 10, 40, 40), opaque, CompositeSourceOver); + + // This should not destroy the device opaqueness either. + context.setFillColor(opaque); + path.moveTo(FloatPoint(10, 10)); + path.addLineTo(FloatPoint(40, 40)); + context.strokePath(path); + + context.endLayer(); + context.endLayer(); + EXPECT_EQ_RECT(IntRect(10, 10, 40, 40), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH_EXACT(bitmap, context.opaqueRegion().asRect()); + + // Now begin a layer that does not preserve opaque and draw through it to the device. + context.setCompositeOperation(CompositeSourceOut); + context.beginTransparencyLayer(0.5); + + // This should destroy the device opaqueness. + context.fillRect(FloatRect(10, 10, 40, 40), opaque, CompositeSourceOver); + + context.endLayer(); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH_EXACT(bitmap, context.opaqueRegion().asRect()); + + // Now we draw with a path for which it cannot compute fast bounds. This should destroy the entire opaque region. + + context.setCompositeOperation(CompositeSourceOut); + context.beginTransparencyLayer(0.5); + + // This should nuke the device opaqueness. + context.setFillColor(opaque); + path.moveTo(FloatPoint(10, 10)); + path.addLineTo(FloatPoint(40, 40)); + context.strokePath(path); + + context.endLayer(); + EXPECT_EQ_RECT(IntRect(), context.opaqueRegion().asRect()); + EXPECT_PIXELS_MATCH_EXACT(bitmap, context.opaqueRegion().asRect()); +} + +#define DISPATCH1(c1, c2, op, param1) do { c1.op(param1); c2.op(param1); } while (0); +#define DISPATCH2(c1, c2, op, param1, param2) do { c1.op(param1, param2); c2.op(param1, param2); } while (0); + +TEST(GraphicsContextTest, RecordingTotalMatrix) +{ + SkBitmap bitmap; + ASSERT_TRUE(bitmap.allocN32Pixels(400, 400)); + bitmap.eraseColor(0); + SkCanvas canvas(bitmap); + GraphicsContext context(&canvas); + + SkCanvas controlCanvas(400, 400); + GraphicsContext controlContext(&controlCanvas); + + EXPECT_EQ(context.getCTM(), controlContext.getCTM()); + DISPATCH2(context, controlContext, scale, 2, 2); + EXPECT_EQ(context.getCTM(), controlContext.getCTM()); + + controlContext.save(); + context.beginRecording(FloatRect(0, 0, 200, 200)); + DISPATCH2(context, controlContext, translate, 10, 10); + EXPECT_EQ(context.getCTM(), controlContext.getCTM()); + + controlContext.save(); + context.beginRecording(FloatRect(10, 10, 100, 100)); + DISPATCH1(context, controlContext, rotate, 45); + EXPECT_EQ(context.getCTM(), controlContext.getCTM()); + + controlContext.restore(); + context.endRecording(); + EXPECT_EQ(context.getCTM(), controlContext.getCTM()); + + controlContext.restore(); + context.endRecording(); + EXPECT_EQ(context.getCTM(), controlContext.getCTM()); +} + +TEST(GraphicsContextTest, DisplayList) +{ + FloatRect rect(0, 0, 1, 1); + RefPtr<DisplayList> dl = adoptRef(new DisplayList(rect)); + + // picture() returns 0 initially + SkPicture* pic = dl->picture(); + EXPECT_FALSE(pic); + + // endRecording without a beginRecording does nothing + dl->endRecording(); + pic = dl->picture(); + EXPECT_FALSE(pic); + + // Two beginRecordings in a row generate two canvases. + // Unfortunately the new one could be allocated in the same + // spot as the old one so ref the first one to prolong its life. + IntSize size(1, 1); + SkCanvas* canvas1 = dl->beginRecording(size); + EXPECT_TRUE(canvas1); + canvas1->ref(); + SkCanvas* canvas2 = dl->beginRecording(size); + EXPECT_TRUE(canvas2); + + EXPECT_NE(canvas1, canvas2); + EXPECT_EQ(1, canvas1->getRefCnt()); + canvas1->unref(); + + EXPECT_TRUE(dl->isRecording()); + + // picture() returns 0 during recording + pic = dl->picture(); + EXPECT_FALSE(pic); + + // endRecording finally makes the picture accessible + dl->endRecording(); + pic = dl->picture(); + EXPECT_TRUE(pic); + EXPECT_EQ(1, pic->getRefCnt()); +} + +} // namespace diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp index d256fc7a0c1..6129a2e721f 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp @@ -31,8 +31,8 @@ #include "SkMatrix44.h" #include "platform/geometry/FloatRect.h" #include "platform/geometry/LayoutRect.h" -#include "platform/graphics/GraphicsContext.h" #include "platform/graphics/GraphicsLayerFactory.h" +#include "platform/graphics/Image.h" #include "platform/graphics/filters/SkiaImageFilterBuilder.h" #include "platform/graphics/skia/NativeImageSkia.h" #include "platform/scroll/ScrollableArea.h" @@ -52,6 +52,8 @@ #include "wtf/HashSet.h" #include "wtf/text/WTFString.h" +#include <algorithm> + #ifndef NDEBUG #include <stdio.h> #endif @@ -78,12 +80,12 @@ PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerFactory* factory, G GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client) : m_client(client) - , m_anchorPoint(0.5f, 0.5f, 0) + , m_backgroundColor(Color::transparent) , m_opacity(1) - , m_zPosition(0) , m_blendMode(blink::WebBlendModeNormal) + , m_hasTransformOrigin(false) , m_contentsOpaque(false) - , m_preserves3D(false) + , m_shouldFlattenTransform(true) , m_backfaceVisibility(true) , m_masksToBounds(false) , m_drawsContent(false) @@ -92,7 +94,6 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client) , m_hasScrollParent(false) , m_hasClipParent(false) , m_paintingPhase(GraphicsLayerPaintAllWithOverflowClip) - , m_contentsOrientation(CompositingCoordinatesTopDown) , m_parent(0) , m_maskLayer(0) , m_contentsClippingMaskLayer(0) @@ -102,8 +103,7 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client) , m_contentsLayer(0) , m_contentsLayerId(0) , m_scrollableArea(0) - , m_compositingReasons(blink::CompositingReasonUnknown) - , m_debugInfo(0) + , m_3dRenderingContext(0) { #ifndef NDEBUG if (m_client) @@ -147,6 +147,8 @@ void GraphicsLayer::setParent(GraphicsLayer* layer) m_parent = layer; } +#if ASSERT_ENABLED + bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const { for (GraphicsLayer* curr = parent(); curr; curr = curr->parent()) { @@ -157,7 +159,9 @@ bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const return false; } -bool GraphicsLayer::setChildren(const Vector<GraphicsLayer*>& newChildren) +#endif + +bool GraphicsLayer::setChildren(const GraphicsLayerVector& newChildren) { // If the contents of the arrays are the same, nothing to do. if (newChildren == m_children) @@ -278,8 +282,8 @@ bool GraphicsLayer::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChil void GraphicsLayer::removeAllChildren() { - while (m_children.size()) { - GraphicsLayer* curLayer = m_children[0]; + while (!m_children.isEmpty()) { + GraphicsLayer* curLayer = m_children.last(); ASSERT(curLayer->parent()); curLayer->removeFromParent(); } @@ -288,14 +292,8 @@ void GraphicsLayer::removeAllChildren() void GraphicsLayer::removeFromParent() { if (m_parent) { - unsigned i; - for (i = 0; i < m_parent->m_children.size(); i++) { - if (this == m_parent->m_children[i]) { - m_parent->m_children.remove(i); - break; - } - } - + // We use reverseFind so that removeAllChildren() isn't n^2. + m_parent->m_children.remove(m_parent->m_children.reverseFind(this)); setParent(0); } @@ -339,34 +337,6 @@ void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const I m_client->paintContents(this, context, m_paintingPhase, clip); } -void GraphicsLayer::setZPosition(float position) -{ - m_zPosition = position; -} - -float GraphicsLayer::accumulatedOpacity() const -{ - if (!preserves3D()) - return 1; - - return m_opacity * (parent() ? parent()->accumulatedOpacity() : 1); -} - -void GraphicsLayer::distributeOpacity(float accumulatedOpacity) -{ - // If this is a transform layer we need to distribute our opacity to all our children - - // Incoming accumulatedOpacity is the contribution from our parent(s). We mutiply this by our own - // opacity to get the total contribution - accumulatedOpacity *= m_opacity; - - if (preserves3D()) { - size_t numChildren = children().size(); - for (size_t i = 0; i < numChildren; ++i) - children()[i]->distributeOpacity(accumulatedOpacity); - } -} - void GraphicsLayer::updateChildList() { WebLayer* childHost = m_layer->layer(); @@ -381,13 +351,8 @@ void GraphicsLayer::updateChildList() childHost->addChild(m_contentsLayer); } - const Vector<GraphicsLayer*>& childLayers = children(); - size_t numChildren = childLayers.size(); - for (size_t i = 0; i < numChildren; ++i) { - GraphicsLayer* curChild = childLayers[i]; - - childHost->addChild(curChild->platformLayer()); - } + for (size_t i = 0; i < m_children.size(); ++i) + childHost->addChild(m_children[i]->platformLayer()); for (size_t i = 0; i < m_linkHighlights.size(); ++i) childHost->addChild(m_linkHighlights[i]->layer()); @@ -482,7 +447,7 @@ void GraphicsLayer::setupContentsLayer(WebLayer* contentsLayer) m_contentsLayerId = m_contentsLayer->id(); m_contentsLayer->setWebLayerClient(this); - m_contentsLayer->setAnchorPoint(FloatPoint(0, 0)); + m_contentsLayer->setTransformOrigin(FloatPoint3D()); m_contentsLayer->setUseParentBackfaceVisibility(true); // It is necessary to call setDrawsContent as soon as we receive the new contentsLayer, for @@ -494,6 +459,8 @@ void GraphicsLayer::setupContentsLayer(WebLayer* contentsLayer) m_layer->layer()->insertChild(m_contentsLayer, 0); WebLayer* borderWebLayer = m_contentsClippingMaskLayer ? m_contentsClippingMaskLayer->platformLayer() : 0; m_contentsLayer->setMaskLayer(borderWebLayer); + + m_contentsLayer->setRenderingContext(m_3dRenderingContext); } void GraphicsLayer::clearContentsLayerIfUnregistered() @@ -505,18 +472,16 @@ void GraphicsLayer::clearContentsLayerIfUnregistered() m_contentsLayerId = 0; } -void GraphicsLayer::setDebugInfo(blink::WebGraphicsLayerDebugInfo* debugInfo) +GraphicsLayerDebugInfo& GraphicsLayer::debugInfo() { - if (m_debugInfo) - delete m_debugInfo; - m_debugInfo = debugInfo; + return m_debugInfo; } -blink::WebGraphicsLayerDebugInfo* GraphicsLayer::takeDebugInfo() +blink::WebGraphicsLayerDebugInfo* GraphicsLayer::takeDebugInfoFor(WebLayer* layer) { - blink::WebGraphicsLayerDebugInfo* tempDebugInfo = m_debugInfo; - m_debugInfo = 0; - return tempDebugInfo; + GraphicsLayerDebugInfo* clone = m_debugInfo.clone(); + clone->setDebugName(debugName(layer)); + return clone; } WebLayer* GraphicsLayer::contentsLayerIfRegistered() @@ -525,15 +490,6 @@ WebLayer* GraphicsLayer::contentsLayerIfRegistered() return m_contentsLayer; } -double GraphicsLayer::backingStoreMemoryEstimate() const -{ - if (!drawsContent()) - return 0; - - // Effects of page and device scale are ignored; subclasses should override to take these into account. - return static_cast<double>(4 * size().width()) * size().height(); -} - void GraphicsLayer::resetTrackedRepaints() { repaintRectMap().remove(this); @@ -563,10 +519,10 @@ void GraphicsLayer::collectTrackedRepaintRects(Vector<FloatRect>& rects) const RepaintMap::iterator repaintIt = repaintRectMap().find(this); if (repaintIt != repaintRectMap().end()) - rects.append(repaintIt->value); + rects.appendVector(repaintIt->value); } -void GraphicsLayer::dumpLayer(TextStream& ts, int indent, LayerTreeFlags flags) const +void GraphicsLayer::dumpLayer(TextStream& ts, int indent, LayerTreeFlags flags, RenderingContextMap& renderingContextMap) const { writeIndent(ts, indent); ts << "(" << "GraphicsLayer"; @@ -577,12 +533,23 @@ void GraphicsLayer::dumpLayer(TextStream& ts, int indent, LayerTreeFlags flags) } ts << "\n"; - dumpProperties(ts, indent, flags); + dumpProperties(ts, indent, flags, renderingContextMap); writeIndent(ts, indent); ts << ")\n"; } -void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeFlags flags) const +static bool compareFloatRects(const FloatRect& a, const FloatRect& b) +{ + if (a.x() != b.x()) + return a.x() > b.x(); + if (a.y() != b.y()) + return a.y() > b.y(); + if (a.width() != b.width()) + return a.width() > b.width(); + return a.height() > b.height(); +} + +void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeFlags flags, RenderingContextMap& renderingContextMap) const { if (m_position != FloatPoint()) { writeIndent(ts, indent + 1); @@ -594,9 +561,9 @@ void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeFlags fl ts << "(bounds origin " << m_boundsOrigin.x() << " " << m_boundsOrigin.y() << ")\n"; } - if (m_anchorPoint != FloatPoint3D(0.5f, 0.5f, 0)) { + if (m_hasTransformOrigin && m_transformOrigin != FloatPoint3D(m_size.width() * 0.5f, m_size.height() * 0.5f, 0)) { writeIndent(ts, indent + 1); - ts << "(anchor " << m_anchorPoint.x() << " " << m_anchorPoint.y() << ")\n"; + ts << "(transformOrigin " << m_transformOrigin.x() << " " << m_transformOrigin.y() << ")\n"; } if (m_size != IntSize()) { @@ -624,9 +591,21 @@ void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeFlags fl ts << "(contentsOpaque " << m_contentsOpaque << ")\n"; } - if (m_preserves3D) { + if (!m_shouldFlattenTransform) { + writeIndent(ts, indent + 1); + ts << "(shouldFlattenTransform " << m_shouldFlattenTransform << ")\n"; + } + + if (m_3dRenderingContext) { + RenderingContextMap::const_iterator it = renderingContextMap.find(m_3dRenderingContext); + int contextId = renderingContextMap.size() + 1; + if (it == renderingContextMap.end()) + renderingContextMap.set(m_3dRenderingContext, contextId); + else + contextId = it->value; + writeIndent(ts, indent + 1); - ts << "(preserves3D " << m_preserves3D << ")\n"; + ts << "(3dRenderingContext " << contextId << ")\n"; } if (m_drawsContent) { @@ -654,7 +633,7 @@ void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeFlags fl ts << ")\n"; } - if (m_backgroundColor.isValid() && m_backgroundColor != Color::transparent) { + if (m_backgroundColor.alpha()) { writeIndent(ts, indent + 1); ts << "(backgroundColor " << m_backgroundColor.nameForRenderTreeAsText() << ")\n"; } @@ -668,24 +647,13 @@ void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeFlags fl ts << "[" << m_transform.m41() << " " << m_transform.m42() << " " << m_transform.m43() << " " << m_transform.m44() << "])\n"; } - // Avoid dumping the sublayer transform on the root layer, because it's used for geometry flipping, whose behavior - // differs between platforms. - if (parent() && !m_childrenTransform.isIdentity()) { - writeIndent(ts, indent + 1); - ts << "(childrenTransform "; - ts << "[" << m_childrenTransform.m11() << " " << m_childrenTransform.m12() << " " << m_childrenTransform.m13() << " " << m_childrenTransform.m14() << "] "; - ts << "[" << m_childrenTransform.m21() << " " << m_childrenTransform.m22() << " " << m_childrenTransform.m23() << " " << m_childrenTransform.m24() << "] "; - ts << "[" << m_childrenTransform.m31() << " " << m_childrenTransform.m32() << " " << m_childrenTransform.m33() << " " << m_childrenTransform.m34() << "] "; - ts << "[" << m_childrenTransform.m41() << " " << m_childrenTransform.m42() << " " << m_childrenTransform.m43() << " " << m_childrenTransform.m44() << "])\n"; - } - if (m_replicaLayer) { writeIndent(ts, indent + 1); ts << "(replica layer"; if (flags & LayerTreeIncludesDebugInfo) ts << " " << m_replicaLayer; ts << ")\n"; - m_replicaLayer->dumpLayer(ts, indent + 2, flags); + m_replicaLayer->dumpLayer(ts, indent + 2, flags, renderingContextMap); } if (m_replicatedLayer) { @@ -697,47 +665,49 @@ void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeFlags fl } if ((flags & LayerTreeIncludesRepaintRects) && repaintRectMap().contains(this) && !repaintRectMap().get(this).isEmpty()) { + Vector<FloatRect> repaintRectsCopy = repaintRectMap().get(this); + std::sort(repaintRectsCopy.begin(), repaintRectsCopy.end(), &compareFloatRects); writeIndent(ts, indent + 1); ts << "(repaint rects\n"; - for (size_t i = 0; i < repaintRectMap().get(this).size(); ++i) { - if (repaintRectMap().get(this)[i].isEmpty()) + for (size_t i = 0; i < repaintRectsCopy.size(); ++i) { + if (repaintRectsCopy[i].isEmpty()) continue; writeIndent(ts, indent + 2); ts << "(rect "; - ts << repaintRectMap().get(this)[i].x() << " "; - ts << repaintRectMap().get(this)[i].y() << " "; - ts << repaintRectMap().get(this)[i].width() << " "; - ts << repaintRectMap().get(this)[i].height(); + ts << repaintRectsCopy[i].x() << " "; + ts << repaintRectsCopy[i].y() << " "; + ts << repaintRectsCopy[i].width() << " "; + ts << repaintRectsCopy[i].height(); ts << ")\n"; } writeIndent(ts, indent + 1); ts << ")\n"; } - if ((flags & LayerTreeIncludesPaintingPhases) && paintingPhase()) { + if ((flags & LayerTreeIncludesPaintingPhases) && m_paintingPhase) { writeIndent(ts, indent + 1); ts << "(paintingPhases\n"; - if (paintingPhase() & GraphicsLayerPaintBackground) { + if (m_paintingPhase & GraphicsLayerPaintBackground) { writeIndent(ts, indent + 2); ts << "GraphicsLayerPaintBackground\n"; } - if (paintingPhase() & GraphicsLayerPaintForeground) { + if (m_paintingPhase & GraphicsLayerPaintForeground) { writeIndent(ts, indent + 2); ts << "GraphicsLayerPaintForeground\n"; } - if (paintingPhase() & GraphicsLayerPaintMask) { + if (m_paintingPhase & GraphicsLayerPaintMask) { writeIndent(ts, indent + 2); ts << "GraphicsLayerPaintMask\n"; } - if (paintingPhase() & GraphicsLayerPaintChildClippingMask) { + if (m_paintingPhase & GraphicsLayerPaintChildClippingMask) { writeIndent(ts, indent + 2); ts << "GraphicsLayerPaintChildClippingMask\n"; } - if (paintingPhase() & GraphicsLayerPaintOverflowContents) { + if (m_paintingPhase & GraphicsLayerPaintOverflowContents) { writeIndent(ts, indent + 2); ts << "GraphicsLayerPaintOverflowContents\n"; } - if (paintingPhase() & GraphicsLayerPaintCompositedScroll) { + if (m_paintingPhase & GraphicsLayerPaintCompositedScroll) { writeIndent(ts, indent + 2); ts << "GraphicsLayerPaintCompositedScroll\n"; } @@ -756,13 +726,26 @@ void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeFlags fl } } + if (flags & LayerTreeIncludesDebugInfo) { + writeIndent(ts, indent + 1); + ts << "(compositingReasons\n"; + for (size_t i = 0; i < WTF_ARRAY_LENGTH(compositingReasonStringMap); ++i) { + if (m_debugInfo.compositingReasons() & compositingReasonStringMap[i].reason) { + writeIndent(ts, indent + 2); + ts << compositingReasonStringMap[i].description << "\n"; + } + } + writeIndent(ts, indent + 1); + ts << ")\n"; + } + if (m_children.size()) { writeIndent(ts, indent + 1); ts << "(children " << m_children.size() << "\n"; unsigned i; for (i = 0; i < m_children.size(); i++) - m_children[i]->dumpLayer(ts, indent + 2, flags); + m_children[i]->dumpLayer(ts, indent + 2, flags, renderingContextMap); writeIndent(ts, indent + 1); ts << ")\n"; } @@ -772,11 +755,12 @@ String GraphicsLayer::layerTreeAsText(LayerTreeFlags flags) const { TextStream ts; - dumpLayer(ts, 0, flags); + RenderingContextMap renderingContextMap; + dumpLayer(ts, 0, flags, renderingContextMap); return ts.release(); } -blink::WebString GraphicsLayer::debugName(blink::WebLayer* webLayer) +String GraphicsLayer::debugName(blink::WebLayer* webLayer) const { String name; if (!m_client) @@ -802,23 +786,20 @@ blink::WebString GraphicsLayer::debugName(blink::WebLayer* webLayer) return name; } -void GraphicsLayer::setCompositingReasons(blink::WebCompositingReasons reasons) +void GraphicsLayer::setCompositingReasons(CompositingReasons reasons) { - m_compositingReasons = reasons; - m_layer->layer()->setCompositingReasons(reasons); + m_debugInfo.setCompositingReasons(reasons); } -void GraphicsLayer::setPosition(const FloatPoint& point) +void GraphicsLayer::setOwnerNodeId(int nodeId) { - m_position = point; - platformLayer()->setPosition(m_position); + m_debugInfo.setOwnerNodeId(nodeId); } -void GraphicsLayer::setAnchorPoint(const FloatPoint3D& point) +void GraphicsLayer::setPosition(const FloatPoint& point) { - m_anchorPoint = point; - platformLayer()->setAnchorPoint(FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())); - platformLayer()->setAnchorPointZ(m_anchorPoint.z()); + m_position = point; + platformLayer()->setPosition(m_position); } void GraphicsLayer::setSize(const FloatSize& size) @@ -845,19 +826,33 @@ void GraphicsLayer::setTransform(const TransformationMatrix& transform) platformLayer()->setTransform(TransformationMatrix::toSkMatrix44(m_transform)); } -void GraphicsLayer::setChildrenTransform(const TransformationMatrix& transform) +void GraphicsLayer::setTransformOrigin(const FloatPoint3D& transformOrigin) { - m_childrenTransform = transform; - platformLayer()->setSublayerTransform(TransformationMatrix::toSkMatrix44(m_childrenTransform)); + m_hasTransformOrigin = true; + m_transformOrigin = transformOrigin; + platformLayer()->setTransformOrigin(transformOrigin); } -void GraphicsLayer::setPreserves3D(bool preserves3D) +void GraphicsLayer::setShouldFlattenTransform(bool shouldFlatten) { - if (preserves3D == m_preserves3D) + if (shouldFlatten == m_shouldFlattenTransform) return; - m_preserves3D = preserves3D; - m_layer->layer()->setPreserves3D(m_preserves3D); + m_shouldFlattenTransform = shouldFlatten; + + m_layer->layer()->setShouldFlattenTransform(shouldFlatten); +} + +void GraphicsLayer::setRenderingContext(int context) +{ + if (m_3dRenderingContext == context) + return; + + m_3dRenderingContext = context; + m_layer->layer()->setRenderingContext(context); + + if (m_contentsLayer) + m_contentsLayer->setRenderingContext(m_3dRenderingContext); } void GraphicsLayer::setMasksToBounds(bool masksToBounds) @@ -973,7 +968,7 @@ void GraphicsLayer::setContentsNeedsDisplay() { if (WebLayer* contentsLayer = contentsLayerIfRegistered()) { contentsLayer->invalidate(); - addRepaintRect(contentsRect()); + addRepaintRect(m_contentsRect); } } @@ -1008,7 +1003,7 @@ void GraphicsLayer::setContentsRect(const IntRect& rect) void GraphicsLayer::setContentsToImage(Image* image) { - RefPtr<NativeImageSkia> nativeImage = image ? image->nativeImageForCurrentFrame() : 0; + RefPtr<NativeImageSkia> nativeImage = image ? image->nativeImageForCurrentFrame() : nullptr; if (nativeImage) { if (!m_imageLayer) { m_imageLayer = adoptPtr(Platform::current()->compositorSupport()->createImageLayer()); @@ -1033,7 +1028,7 @@ void GraphicsLayer::setContentsToNinePatch(Image* image, const IntRect& aperture unregisterContentsLayer(m_ninePatchLayer->layer()); m_ninePatchLayer.clear(); } - RefPtr<NativeImageSkia> nativeImage = image ? image->nativeImageForCurrentFrame() : 0; + RefPtr<NativeImageSkia> nativeImage = image ? image->nativeImageForCurrentFrame() : nullptr; if (nativeImage) { m_ninePatchLayer = adoptPtr(Platform::current()->compositorSupport()->createNinePatchLayer()); m_ninePatchLayer->setBitmap(nativeImage->bitmap(), aperture); @@ -1043,27 +1038,6 @@ void GraphicsLayer::setContentsToNinePatch(Image* image, const IntRect& aperture setContentsTo(m_ninePatchLayer ? m_ninePatchLayer->layer() : 0); } -void GraphicsLayer::setContentsToSolidColor(const Color& color) -{ - if (color == m_contentsSolidColor) - return; - - m_contentsSolidColor = color; - if (color.isValid() && color.alpha()) { - if (!m_solidColorLayer) { - m_solidColorLayer = adoptPtr(Platform::current()->compositorSupport()->createSolidColorLayer()); - registerContentsLayer(m_solidColorLayer->layer()); - } - m_solidColorLayer->setBackgroundColor(color.rgb()); - } else { - if (!m_solidColorLayer) - return; - unregisterContentsLayer(m_solidColorLayer->layer()); - m_solidColorLayer.clear(); - } - setContentsTo(m_solidColorLayer ? m_solidColorLayer->layer() : 0); -} - bool GraphicsLayer::addAnimation(PassOwnPtr<WebAnimation> popAnimation) { OwnPtr<WebAnimation> animation(popAnimation); @@ -1153,9 +1127,6 @@ static bool copyWebCoreFilterOperationsToWebFilterOperations(const FilterOperati webFilters.appendDropShadowFilter(WebPoint(dropShadowOp.x(), dropShadowOp.y()), dropShadowOp.stdDeviation(), dropShadowOp.color().rgb()); break; } - case FilterOperation::CUSTOM: - case FilterOperation::VALIDATED_CUSTOM: - return false; // Not supported. case FilterOperation::NONE: break; } @@ -1191,6 +1162,14 @@ void GraphicsLayer::setBackgroundFilters(const FilterOperations& filters) m_layer->layer()->setBackgroundFilters(*webFilters); } +void GraphicsLayer::setPaintingPhase(GraphicsLayerPaintingPhase phase) +{ + if (m_paintingPhase == phase) + return; + m_paintingPhase = phase; + setNeedsDisplay(); +} + void GraphicsLayer::addLinkHighlight(LinkHighlightClient* linkHighlight) { ASSERT(linkHighlight && !m_linkHighlights.contains(linkHighlight)); @@ -1214,6 +1193,8 @@ void GraphicsLayer::setScrollableArea(ScrollableArea* scrollableArea, bool isMai // Main frame scrolling may involve pinch zoom and gets routed through // WebViewImpl explicitly rather than via GraphicsLayer::didScroll. + // TODO(bokan): With pinch virtual viewport the special case will no + // longer be needed, remove once old-style pinch is gone. if (isMainFrame) m_layer->layer()->setScrollClient(0); else @@ -1226,13 +1207,13 @@ void GraphicsLayer::paint(GraphicsContext& context, const IntRect& clip) } -void GraphicsLayer::notifyAnimationStarted(double wallClockTime, double monotonicTime, WebAnimation::TargetProperty) +void GraphicsLayer::notifyAnimationStarted(double monotonicTime, WebAnimation::TargetProperty) { if (m_client) - m_client->notifyAnimationStarted(this, wallClockTime, monotonicTime); + m_client->notifyAnimationStarted(this, monotonicTime); } -void GraphicsLayer::notifyAnimationFinished(double, double, WebAnimation::TargetProperty) +void GraphicsLayer::notifyAnimationFinished(double, WebAnimation::TargetProperty) { // Do nothing. } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h index ca16a0a91bb..256f68e78fb 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h @@ -34,11 +34,11 @@ #include "platform/geometry/IntRect.h" #include "platform/graphics/Color.h" #include "platform/graphics/GraphicsLayerClient.h" +#include "platform/graphics/GraphicsLayerDebugInfo.h" #include "platform/graphics/OpaqueRectTrackingContentLayerDelegate.h" #include "platform/graphics/filters/FilterOperations.h" #include "platform/transforms/TransformationMatrix.h" #include "public/platform/WebAnimationDelegate.h" -#include "public/platform/WebCompositingReasons.h" #include "public/platform/WebContentLayer.h" #include "public/platform/WebImageLayer.h" #include "public/platform/WebLayerClient.h" @@ -52,7 +52,6 @@ namespace blink { class GraphicsLayerFactoryChromium; class WebAnimation; -class WebGraphicsLayerDebugInfo; class WebLayer; } @@ -60,6 +59,7 @@ namespace WebCore { class FloatRect; class GraphicsContext; +class GraphicsLayer; class GraphicsLayerFactory; class Image; class ScrollableArea; @@ -76,6 +76,8 @@ protected: virtual ~LinkHighlightClient() { } }; +typedef Vector<GraphicsLayer*, 64> GraphicsLayerVector; + // GraphicsLayer is an abstraction for a rendering surface with backing store, // which may have associated transformation and animations. @@ -89,21 +91,20 @@ public: GraphicsLayerClient* client() const { return m_client; } // blink::WebLayerClient implementation. - virtual blink::WebString debugName(blink::WebLayer*) OVERRIDE; - virtual blink::WebGraphicsLayerDebugInfo* takeDebugInfo() OVERRIDE; + virtual blink::WebGraphicsLayerDebugInfo* takeDebugInfoFor(blink::WebLayer*) OVERRIDE; + + GraphicsLayerDebugInfo& debugInfo(); - void setCompositingReasons(blink::WebCompositingReasons); - blink::WebCompositingReasons compositingReasons() const { return m_compositingReasons; } + void setCompositingReasons(CompositingReasons); + CompositingReasons compositingReasons() const { return m_debugInfo.compositingReasons(); } + void setOwnerNodeId(int); GraphicsLayer* parent() const { return m_parent; }; void setParent(GraphicsLayer*); // Internal use only. - // Returns true if the layer has the given layer as an ancestor (excluding self). - bool hasAncestor(GraphicsLayer*) const; - const Vector<GraphicsLayer*>& children() const { return m_children; } // Returns true if the child list changed. - bool setChildren(const Vector<GraphicsLayer*>&); + bool setChildren(const GraphicsLayerVector&); // Add child layers. If the child is already parented, it will be removed from its old parent. void addChild(GraphicsLayer*); @@ -123,16 +124,11 @@ public: // The given layer will replicate this layer and its children; the replica renders behind this layer. void setReplicatedByLayer(GraphicsLayer*); - // Whether this layer is being replicated by another layer. - bool isReplicated() const { return m_replicaLayer; } // The layer that replicates this layer (if any). GraphicsLayer* replicaLayer() const { return m_replicaLayer; } // The layer being replicated. GraphicsLayer* replicatedLayer() const { return m_replicatedLayer; } - const FloatPoint& replicatedLayerPosition() const { return m_replicatedLayerPosition; } - void setReplicatedLayerPosition(const FloatPoint& p) { m_replicatedLayerPosition = p; } - enum ShouldSetNeedsDisplay { DontSetNeedsDisplay, SetNeedsDisplay @@ -146,10 +142,8 @@ public: const FloatPoint& position() const { return m_position; } void setPosition(const FloatPoint&); - // Anchor point: (0, 0) is top left, (1, 1) is bottom right. The anchor point - // affects the origin of the transforms. - const FloatPoint3D& anchorPoint() const { return m_anchorPoint; } - void setAnchorPoint(const FloatPoint3D&); + const FloatPoint3D& transformOrigin() const { return m_transformOrigin; } + void setTransformOrigin(const FloatPoint3D&); // The size of the layer. const FloatSize& size() const { return m_size; } @@ -161,14 +155,8 @@ public: const TransformationMatrix& transform() const { return m_transform; } void setTransform(const TransformationMatrix&); - - const TransformationMatrix& childrenTransform() const { return m_childrenTransform; } - void setChildrenTransform(const TransformationMatrix&); - - bool preserves3D() const { return m_preserves3D; } - void setPreserves3D(bool); - - bool masksToBounds() const { return m_masksToBounds; } + void setShouldFlattenTransform(bool); + void setRenderingContext(int id); void setMasksToBounds(bool); bool drawsContent() const { return m_drawsContent; } @@ -180,12 +168,9 @@ public: void setScrollParent(blink::WebLayer*); void setClipParent(blink::WebLayer*); - void setDebugInfo(blink::WebGraphicsLayerDebugInfo*); - // For special cases, e.g. drawing missing tiles on Android. // The compositor should never paint this color in normal cases because the RenderLayer // will paint background by itself. - const Color& backgroundColor() const { return m_backgroundColor; } void setBackgroundColor(const Color&); // opaque means that we know the layer contents have no alpha @@ -198,21 +183,15 @@ public: float opacity() const { return m_opacity; } void setOpacity(float); - blink::WebBlendMode blendMode() const { return m_blendMode; } void setBlendMode(blink::WebBlendMode); - - bool isRootForIsolatedGroup() const { return m_isRootForIsolatedGroup; } void setIsRootForIsolatedGroup(bool); - const FilterOperations& filters() const { return m_filters; } - // Returns true if filter can be rendered by the compositor bool setFilters(const FilterOperations&); void setBackgroundFilters(const FilterOperations&); // Some GraphicsLayers paint only the foreground or the background content - GraphicsLayerPaintingPhase paintingPhase() const { return m_paintingPhase; } - void setPaintingPhase(GraphicsLayerPaintingPhase phase) { m_paintingPhase = phase; } + void setPaintingPhase(GraphicsLayerPaintingPhase); void setNeedsDisplay(); // mark the given rect (in layer coords) as needing dispay. Never goes deep. @@ -221,7 +200,6 @@ public: void setContentsNeedsDisplay(); // Set that the position/size of the contents (image or video). - IntRect contentsRect() const { return m_contentsRect; } void setContentsRect(const IntRect&); // Return true if the animation is handled by the compositing system. If this returns @@ -234,8 +212,6 @@ public: // Layer contents void setContentsToImage(Image*); void setContentsToNinePatch(Image*, const IntRect& aperture); - // Pass an invalid color to remove the contents layer. - void setContentsToSolidColor(const Color&); void setContentsToPlatformLayer(blink::WebLayer* layer) { setContentsTo(layer); } bool hasContentsLayer() const { return m_contentsLayer; } @@ -245,33 +221,15 @@ public: // For hosting this GraphicsLayer in a native layer hierarchy. blink::WebLayer* platformLayer() const; - enum CompositingCoordinatesOrientation { CompositingCoordinatesTopDown, CompositingCoordinatesBottomUp }; - - // Flippedness of the contents of this layer. Does not affect sublayer geometry. - void setContentsOrientation(CompositingCoordinatesOrientation orientation) { m_contentsOrientation = orientation; } - CompositingCoordinatesOrientation contentsOrientation() const { return m_contentsOrientation; } - - void dumpLayer(TextStream&, int indent, LayerTreeFlags) const; + typedef HashMap<int, int> RenderingContextMap; + void dumpLayer(TextStream&, int indent, LayerTreeFlags, RenderingContextMap&) const; int paintCount() const { return m_paintCount; } - // z-position is the z-equivalent of position(). It's only used for debugging purposes. - float zPosition() const { return m_zPosition; } - void setZPosition(float); - - void distributeOpacity(float); - float accumulatedOpacity() const; - - // If the exposed rect of this layer changes, returns true if this or descendant layers need a flush, - // for example to allocate new tiles. - bool visibleRectChangeRequiresFlush(const FloatRect& /* clipRect */) const { return false; } - // Return a string with a human readable form of the layer tree, If debug is true // pointers for the layers and timing data will be included in the returned string. String layerTreeAsText(LayerTreeFlags = LayerTreeNormal) const; - - // Return an estimate of the backing store memory cost (in bytes). May be incorrect for tiled layers. - double backingStoreMemoryEstimate() const; + String debugName(blink::WebLayer*) const; void resetTrackedRepaints(); void addRepaintRect(const FloatRect&); @@ -296,8 +254,8 @@ public: virtual void paint(GraphicsContext&, const IntRect& clip) OVERRIDE; // WebAnimationDelegate implementation. - virtual void notifyAnimationStarted(double wallClockTime, double monotonicTime, blink::WebAnimation::TargetProperty) OVERRIDE; - virtual void notifyAnimationFinished(double wallClockTime, double monotonicTime, blink::WebAnimation::TargetProperty) OVERRIDE; + virtual void notifyAnimationStarted(double monotonicTime, blink::WebAnimation::TargetProperty) OVERRIDE; + virtual void notifyAnimationFinished(double monotonicTime, blink::WebAnimation::TargetProperty) OVERRIDE; // WebLayerScrollClient implementation. virtual void didScroll() OVERRIDE; @@ -315,6 +273,10 @@ private: // can be batched before updating. void addChildInternal(GraphicsLayer*); +#if ASSERT_ENABLED + bool hasAncestor(GraphicsLayer*) const; +#endif + // This method is used by platform GraphicsLayer classes to clear the filters // when compositing is not done in hardware. It is not virtual, so the caller // needs to notifiy the change to the platform layer as needed. @@ -324,7 +286,7 @@ private: int incrementPaintCount() { return ++m_paintCount; } - void dumpProperties(TextStream&, int indent, LayerTreeFlags) const; + void dumpProperties(TextStream&, int indent, LayerTreeFlags, RenderingContextMap&) const; // Helper functions used by settors to keep layer's the state consistent. void updateChildList(); @@ -343,23 +305,22 @@ private: // Position is relative to the parent GraphicsLayer FloatPoint m_position; - FloatPoint3D m_anchorPoint; FloatSize m_size; FloatPoint m_boundsOrigin; TransformationMatrix m_transform; - TransformationMatrix m_childrenTransform; + FloatPoint3D m_transformOrigin; Color m_backgroundColor; float m_opacity; - float m_zPosition; blink::WebBlendMode m_blendMode; FilterOperations m_filters; + bool m_hasTransformOrigin : 1; bool m_contentsOpaque : 1; - bool m_preserves3D: 1; + bool m_shouldFlattenTransform: 1; bool m_backfaceVisibility : 1; bool m_masksToBounds : 1; bool m_drawsContent : 1; @@ -370,7 +331,6 @@ private: bool m_hasClipParent : 1; GraphicsLayerPaintingPhase m_paintingPhase; - CompositingCoordinatesOrientation m_contentsOrientation; // affects orientation of layer contents Vector<GraphicsLayer*> m_children; GraphicsLayer* m_parent; @@ -390,8 +350,6 @@ private: OwnPtr<blink::WebContentLayer> m_layer; OwnPtr<blink::WebImageLayer> m_imageLayer; OwnPtr<blink::WebNinePatchLayer> m_ninePatchLayer; - Color m_contentsSolidColor; - OwnPtr<blink::WebSolidColorLayer> m_solidColorLayer; blink::WebLayer* m_contentsLayer; // We don't have ownership of m_contentsLayer, but we do want to know if a given layer is the // same as our current layer in setContentsTo(). Since m_contentsLayer may be deleted at this point, @@ -404,16 +362,15 @@ private: OwnPtr<OpaqueRectTrackingContentLayerDelegate> m_opaqueRectTrackingContentLayerDelegate; ScrollableArea* m_scrollableArea; - blink::WebCompositingReasons m_compositingReasons; - blink::WebGraphicsLayerDebugInfo* m_debugInfo; + GraphicsLayerDebugInfo m_debugInfo; + int m_3dRenderingContext; }; - } // namespace WebCore #ifndef NDEBUG // Outside the WebCore namespace for ease of invocation from gdb. -void showGraphicsLayerTree(const WebCore::GraphicsLayer* layer); +void PLATFORM_EXPORT showGraphicsLayerTree(const WebCore::GraphicsLayer*); #endif #endif // GraphicsLayer_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayerClient.h b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayerClient.h index f46e3020c8b..aec703d0a7a 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayerClient.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayerClient.h @@ -64,15 +64,9 @@ public: virtual ~GraphicsLayerClient() {} // Callback for when hardware-accelerated animation started. - virtual void notifyAnimationStarted(const GraphicsLayer*, double wallClockTime, double monotonicTime) = 0; + virtual void notifyAnimationStarted(const GraphicsLayer*, double monotonicTime) = 0; virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) = 0; - virtual void didCommitChangesForLayer(const GraphicsLayer*) const { } - - // Provides current transform (taking transform-origin and animations into account). Input matrix has been - // initialized to identity already. Returns false if the layer has no transform. - virtual bool getCurrentTransform(const GraphicsLayer*, TransformationMatrix&) const { return false; } - virtual bool isTrackingRepaints() const { return false; } virtual String debugName(const GraphicsLayer*) = 0; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp new file mode 100644 index 00000000000..93cd1d05d04 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 Google Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include "platform/graphics/GraphicsLayerDebugInfo.h" + +#include "wtf/text/CString.h" + +namespace WebCore { + +GraphicsLayerDebugInfo::GraphicsLayerDebugInfo() + : m_compositingReasons(CompositingReasonNone) +{ +} + +GraphicsLayerDebugInfo::~GraphicsLayerDebugInfo() { } + +void GraphicsLayerDebugInfo::appendAsTraceFormat(blink::WebString* out) const +{ + RefPtr<JSONObject> jsonObject = JSONObject::create(); + appendLayoutRects(jsonObject.get()); + appendCompositingReasons(jsonObject.get()); + appendDebugName(jsonObject.get()); + appendOwnerNodeId(jsonObject.get()); + *out = jsonObject->toJSONString(); +} + +GraphicsLayerDebugInfo* GraphicsLayerDebugInfo::clone() const +{ + GraphicsLayerDebugInfo* toReturn = new GraphicsLayerDebugInfo(); + for (size_t i = 0; i < m_currentLayoutRects.size(); ++i) + toReturn->currentLayoutRects().append(m_currentLayoutRects[i]); + toReturn->setCompositingReasons(m_compositingReasons); + toReturn->setOwnerNodeId(m_ownerNodeId); + return toReturn; +} + +void GraphicsLayerDebugInfo::appendLayoutRects(JSONObject* jsonObject) const +{ + RefPtr<JSONArray> jsonArray = JSONArray::create(); + for (size_t i = 0; i < m_currentLayoutRects.size(); i++) { + const LayoutRect& rect = m_currentLayoutRects[i]; + RefPtr<JSONObject> rectContainer = JSONObject::create(); + RefPtr<JSONArray> rectArray = JSONArray::create(); + rectArray->pushNumber(rect.x().toFloat()); + rectArray->pushNumber(rect.y().toFloat()); + rectArray->pushNumber(rect.maxX().toFloat()); + rectArray->pushNumber(rect.maxY().toFloat()); + rectContainer->setArray("geometry_rect", rectArray); + jsonArray->pushObject(rectContainer); + } + jsonObject->setArray("layout_rects", jsonArray); +} + +void GraphicsLayerDebugInfo::appendCompositingReasons(JSONObject* jsonObject) const +{ + RefPtr<JSONArray> jsonArray = JSONArray::create(); + for (size_t i = 0; i < WTF_ARRAY_LENGTH(compositingReasonStringMap); ++i) { + if (!(m_compositingReasons & compositingReasonStringMap[i].reason)) + continue; + jsonArray->pushString(compositingReasonStringMap[i].description); + } + jsonObject->setArray("compositing_reasons", jsonArray); +} + +void GraphicsLayerDebugInfo::appendDebugName(JSONObject* jsonObject) const +{ + if (m_debugName.isEmpty()) + return; + + jsonObject->setString("layer_name", m_debugName); +} + +void GraphicsLayerDebugInfo::appendOwnerNodeId(JSONObject* jsonObject) const +{ + if (!m_ownerNodeId) + return; + + jsonObject->setNumber("owner_node", m_ownerNodeId); +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.cpp b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.h index d6c3159bafc..6953cf48ef8 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Google Inc. All rights reserved. + * Copyright (C) 2014 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -28,34 +28,45 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" -#include "platform/graphics/gpu/AcceleratedImageBufferSurface.h" +#ifndef GraphicsLayerDebugInfo_h +#define GraphicsLayerDebugInfo_h -#include "platform/graphics/gpu/SharedGraphicsContext3D.h" -#include "third_party/skia/include/gpu/SkGpuDevice.h" +#include "platform/JSONValues.h" +#include "platform/geometry/LayoutRect.h" +#include "platform/graphics/CompositingReasons.h" +#include "public/platform/WebGraphicsLayerDebugInfo.h" + +#include "wtf/Vector.h" namespace WebCore { -AcceleratedImageBufferSurface::AcceleratedImageBufferSurface(const IntSize& size, OpacityMode opacityMode, int msaaSampleCount) - : ImageBufferSurface(size, opacityMode) -{ - GrContext* grContext = SharedGraphicsContext3D::get()->grContext(); - if (!grContext) - return; - RefPtr<SkGpuDevice> device = adoptRef(new SkGpuDevice(grContext, SkBitmap::kARGB_8888_Config, size.width(), size.height(), msaaSampleCount)); - if (!device->accessRenderTarget()) - return; - m_canvas = adoptPtr(new SkCanvas(device.get())); - clear(); -} - -Platform3DObject AcceleratedImageBufferSurface::getBackingTexture() const -{ - GrRenderTarget* renderTarget = m_canvas->getTopDevice()->accessRenderTarget(); - if (renderTarget) { - return renderTarget->asTexture()->getTextureHandle(); - } - return 0; -} +class GraphicsLayerDebugInfo FINAL : public blink::WebGraphicsLayerDebugInfo { +public: + GraphicsLayerDebugInfo(); + virtual ~GraphicsLayerDebugInfo(); + + virtual void appendAsTraceFormat(blink::WebString* out) const OVERRIDE; + + GraphicsLayerDebugInfo* clone() const; + + void setDebugName(const String& name) { m_debugName = name; } + CompositingReasons compositingReasons() const { return m_compositingReasons; } + void setCompositingReasons(CompositingReasons reasons) { m_compositingReasons = reasons; } + void setOwnerNodeId(int id) { m_ownerNodeId = id; } + Vector<LayoutRect>& currentLayoutRects() { return m_currentLayoutRects; } + +private: + void appendLayoutRects(JSONObject*) const; + void appendCompositingReasons(JSONObject*) const; + void appendDebugName(JSONObject*) const; + void appendOwnerNodeId(JSONObject*) const; + + String m_debugName; + CompositingReasons m_compositingReasons; + int m_ownerNodeId; + Vector<LayoutRect> m_currentLayoutRects; +}; } // namespace WebCore + +#endif diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp new file mode 100644 index 00000000000..b6ed1b6741c --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "platform/graphics/GraphicsLayer.h" + +#include "platform/scroll/ScrollableArea.h" +#include "platform/transforms/Matrix3DTransformOperation.h" +#include "platform/transforms/RotateTransformOperation.h" +#include "platform/transforms/TranslateTransformOperation.h" +#include "public/platform/Platform.h" +#include "public/platform/WebCompositorSupport.h" +#include "public/platform/WebFloatAnimationCurve.h" +#include "public/platform/WebGraphicsContext3D.h" +#include "public/platform/WebLayer.h" +#include "public/platform/WebLayerTreeView.h" +#include "public/platform/WebUnitTestSupport.h" +#include "wtf/PassOwnPtr.h" + +#include <gtest/gtest.h> + +using namespace WebCore; +using namespace blink; + +namespace { + +class MockGraphicsLayerClient : public GraphicsLayerClient { +public: + virtual void notifyAnimationStarted(const GraphicsLayer*, double monotonicTime) OVERRIDE { } + virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) OVERRIDE { } + virtual String debugName(const GraphicsLayer*) OVERRIDE { return String(); } +}; + +class GraphicsLayerForTesting : public GraphicsLayer { +public: + explicit GraphicsLayerForTesting(GraphicsLayerClient* client) + : GraphicsLayer(client) { }; + + virtual blink::WebLayer* contentsLayer() const { return GraphicsLayer::contentsLayer(); } +}; + +class GraphicsLayerTest : public testing::Test { +public: + GraphicsLayerTest() + { + m_clipLayer = adoptPtr(new GraphicsLayerForTesting(&m_client)); + m_graphicsLayer = adoptPtr(new GraphicsLayerForTesting(&m_client)); + m_clipLayer->addChild(m_graphicsLayer.get()); + m_graphicsLayer->platformLayer()->setScrollClipLayer( + m_clipLayer->platformLayer()); + m_platformLayer = m_graphicsLayer->platformLayer(); + m_layerTreeView = adoptPtr(Platform::current()->unitTestSupport()->createLayerTreeViewForTesting()); + ASSERT(m_layerTreeView); + m_layerTreeView->setRootLayer(*m_clipLayer->platformLayer()); + m_layerTreeView->registerViewportLayers( + m_clipLayer->platformLayer(), m_graphicsLayer->platformLayer(), 0); + m_layerTreeView->setViewportSize(WebSize(1, 1)); + } + + virtual ~GraphicsLayerTest() + { + m_graphicsLayer.clear(); + m_layerTreeView.clear(); + } + +protected: + WebLayer* m_platformLayer; + OwnPtr<GraphicsLayerForTesting> m_graphicsLayer; + OwnPtr<GraphicsLayerForTesting> m_clipLayer; + +private: + OwnPtr<WebLayerTreeView> m_layerTreeView; + MockGraphicsLayerClient m_client; +}; + +TEST_F(GraphicsLayerTest, updateLayerShouldFlattenTransformWithAnimations) +{ + ASSERT_FALSE(m_platformLayer->hasActiveAnimation()); + + OwnPtr<WebFloatAnimationCurve> curve = adoptPtr(Platform::current()->compositorSupport()->createFloatAnimationCurve()); + curve->add(WebFloatKeyframe(0.0, 0.0)); + OwnPtr<WebAnimation> floatAnimation(adoptPtr(Platform::current()->compositorSupport()->createAnimation(*curve, WebAnimation::TargetPropertyOpacity))); + int animationId = floatAnimation->id(); + ASSERT_TRUE(m_platformLayer->addAnimation(floatAnimation.leakPtr())); + + ASSERT_TRUE(m_platformLayer->hasActiveAnimation()); + + m_graphicsLayer->setShouldFlattenTransform(false); + + m_platformLayer = m_graphicsLayer->platformLayer(); + ASSERT_TRUE(m_platformLayer); + + ASSERT_TRUE(m_platformLayer->hasActiveAnimation()); + m_platformLayer->removeAnimation(animationId); + ASSERT_FALSE(m_platformLayer->hasActiveAnimation()); + + m_graphicsLayer->setShouldFlattenTransform(true); + + m_platformLayer = m_graphicsLayer->platformLayer(); + ASSERT_TRUE(m_platformLayer); + + ASSERT_FALSE(m_platformLayer->hasActiveAnimation()); +} + +class FakeScrollableArea : public ScrollableArea { +public: + virtual bool isActive() const OVERRIDE { return false; } + virtual int scrollSize(ScrollbarOrientation) const OVERRIDE { return 100; } + virtual bool isScrollCornerVisible() const OVERRIDE { return false; } + virtual IntRect scrollCornerRect() const OVERRIDE { return IntRect(); } + virtual int visibleWidth() const OVERRIDE { return 10; } + virtual int visibleHeight() const OVERRIDE { return 10; } + virtual IntSize contentsSize() const OVERRIDE { return IntSize(100, 100); } + virtual bool scrollbarsCanBeActive() const OVERRIDE { return false; } + virtual IntRect scrollableAreaBoundingBox() const OVERRIDE { return IntRect(); } + virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&) OVERRIDE { } + virtual void invalidateScrollCornerRect(const IntRect&) OVERRIDE { } + virtual bool userInputScrollable(ScrollbarOrientation) const OVERRIDE { return true; } + virtual bool shouldPlaceVerticalScrollbarOnLeft() const OVERRIDE { return false; } + virtual int pageStep(ScrollbarOrientation) const OVERRIDE { return 0; } + virtual IntPoint minimumScrollPosition() const OVERRIDE { return IntPoint(); } + virtual IntPoint maximumScrollPosition() const OVERRIDE + { + return IntPoint(contentsSize().width() - visibleWidth(), contentsSize().height() - visibleHeight()); + } + + virtual void setScrollOffset(const IntPoint& scrollOffset) OVERRIDE { m_scrollPosition = scrollOffset; } + virtual IntPoint scrollPosition() const OVERRIDE { return m_scrollPosition; } + +private: + IntPoint m_scrollPosition; +}; + +TEST_F(GraphicsLayerTest, applyScrollToScrollableArea) +{ + FakeScrollableArea scrollableArea; + m_graphicsLayer->setScrollableArea(&scrollableArea, false); + + WebPoint scrollPosition(7, 9); + m_platformLayer->setScrollPosition(scrollPosition); + m_graphicsLayer->didScroll(); + + EXPECT_EQ(scrollPosition, WebPoint(scrollableArea.scrollPosition())); +} + +} // namespace diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h index 1482dfbefc9..b0938f3fe27 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h @@ -43,11 +43,15 @@ enum StrokeStyle { }; enum InterpolationQuality { - InterpolationDefault, - InterpolationNone, - InterpolationLow, - InterpolationMedium, - InterpolationHigh + InterpolationNone = SkPaint::kNone_FilterLevel, + InterpolationLow = SkPaint::kLow_FilterLevel, + InterpolationMedium = SkPaint::kMedium_FilterLevel, + InterpolationHigh = SkPaint::kHigh_FilterLevel, +#if USE(LOW_QUALITY_IMAGE_INTERPOLATION) + InterpolationDefault = InterpolationLow, +#else + InterpolationDefault = InterpolationHigh, +#endif }; enum CompositeOperator { diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsTypes3D.h b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsTypes3D.h index a4ed898127b..0bef5e1645c 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsTypes3D.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/GraphicsTypes3D.h @@ -26,36 +26,36 @@ #ifndef GraphicsTypes3D_h #define GraphicsTypes3D_h +#include "third_party/khronos/GLES2/gl2.h" +#include "third_party/khronos/GLES2/gl2ext.h" #include "wtf/Forward.h" #include <stdint.h> -// GC3D types and enums match the corresponding GL types and enums as defined -// in OpenGL ES 2.0 header file gl2.h from khronos.org. -typedef unsigned GC3Denum; -typedef unsigned char GC3Dboolean; -typedef unsigned GC3Dbitfield; -typedef signed char GC3Dbyte; -typedef unsigned char GC3Dubyte; -typedef short GC3Dshort; -typedef unsigned short GC3Dushort; -typedef int GC3Dint; -typedef int GC3Dsizei; -typedef unsigned GC3Duint; -typedef float GC3Dfloat; -typedef unsigned short GC3Dhalffloat; -typedef float GC3Dclampf; -typedef intptr_t GC3Dintptr; -typedef intptr_t GC3Dsizeiptr; -typedef char GC3Dchar; - -typedef GC3Duint Platform3DObject; +typedef unsigned Platform3DObject; // WebGL-specific enums -const GC3Denum GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL = 0x821A; -const GC3Denum GC3D_UNPACK_FLIP_Y_WEBGL = 0x9240; -const GC3Denum GC3D_UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241; -const GC3Denum GC3D_CONTEXT_LOST_WEBGL = 0x9242; -const GC3Denum GC3D_UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243; -const GC3Denum GC3D_BROWSER_DEFAULT_WEBGL = 0x9244; +const unsigned GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL = 0x821A; +const unsigned GC3D_UNPACK_FLIP_Y_WEBGL = 0x9240; +const unsigned GC3D_UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241; +const unsigned GC3D_CONTEXT_LOST_WEBGL = 0x9242; +const unsigned GC3D_UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243; +const unsigned GC3D_BROWSER_DEFAULT_WEBGL = 0x9244; + +// GL_CHROMIUM_flipy +const unsigned GC3D_UNPACK_FLIP_Y_CHROMIUM = 0x9240; + +// GL_CHROMIUM_copy_texture +const unsigned GC3D_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM = 0x9241; +const unsigned GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM = 0x9242; + +// GL_AMD_compressed_ATC_texture +const unsigned GC3D_COMPRESSED_ATC_RGB_AMD = 0x8C92; +const unsigned GC3D_COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD = 0x8C93; +const unsigned GC3D_COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD = 0x87EE; + +// GL_CHROMIUM_image +const unsigned GC3D_IMAGE_ROWBYTES_CHROMIUM = 0x78F0; +const unsigned GC3D_IMAGE_MAP_CHROMIUM = 0x78F1; +const unsigned GC3D_IMAGE_SCANOUT_CHROMIUM = 0x78F2; #endif diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Image.h b/chromium/third_party/WebKit/Source/platform/graphics/Image.h index cc3cc9604f1..706f15ca133 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/Image.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/Image.h @@ -98,23 +98,27 @@ public: // Animation begins whenever someone draws the image, so startAnimation() is not normally called. // It will automatically pause once all observers no longer want to render the image anywhere. - virtual void startAnimation(bool /*catchUpIfNecessary*/ = true) { } + enum CatchUpAnimation { DoNotCatchUp, CatchUp }; + virtual void startAnimation(CatchUpAnimation = CatchUp) { } virtual void stopAnimation() {} virtual void resetAnimation() {} + // True if this image can potentially animate. + virtual bool maybeAnimated() { return false; } + // Typically the ImageResource that owns us. ImageObserver* imageObserver() const { return m_imageObserver; } void setImageObserver(ImageObserver* observer) { m_imageObserver = observer; } enum TileRule { StretchTile, RoundTile, SpaceTile, RepeatTile }; - virtual PassRefPtr<NativeImageSkia> nativeImageForCurrentFrame() { return 0; } + virtual PassRefPtr<NativeImageSkia> nativeImageForCurrentFrame() { return nullptr; } virtual void drawPattern(GraphicsContext*, const FloatRect&, const FloatSize&, const FloatPoint& phase, CompositeOperator, const FloatRect&, blink::WebBlendMode = blink::WebBlendModeNormal, const IntSize& repeatSpacing = IntSize()); -#if !ASSERT_DISABLED +#if ASSERT_ENABLED virtual bool notSolidColor() { return true; } #endif diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp b/chromium/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp index 76de0de00a8..c4439d2c953 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp @@ -33,21 +33,25 @@ #include "config.h" #include "platform/graphics/ImageBuffer.h" +#include "GrContext.h" #include "platform/MIMETypeRegistry.h" #include "platform/geometry/IntRect.h" #include "platform/graphics/BitmapImage.h" -#include "platform/graphics/Extensions3D.h" #include "platform/graphics/GraphicsContext.h" -#include "platform/graphics/GraphicsContext3D.h" +#include "platform/graphics/GraphicsTypes3D.h" +#include "platform/graphics/ImageBufferClient.h" #include "platform/graphics/UnacceleratedImageBufferSurface.h" #include "platform/graphics/gpu/DrawingBuffer.h" -#include "platform/graphics/gpu/SharedGraphicsContext3D.h" +#include "platform/graphics/gpu/Extensions3DUtil.h" #include "platform/graphics/skia/NativeImageSkia.h" #include "platform/graphics/skia/SkiaUtils.h" #include "platform/image-encoders/skia/JPEGImageEncoder.h" #include "platform/image-encoders/skia/PNGImageEncoder.h" #include "platform/image-encoders/skia/WEBPImageEncoder.h" #include "public/platform/Platform.h" +#include "public/platform/WebExternalTextureMailbox.h" +#include "public/platform/WebGraphicsContext3D.h" +#include "public/platform/WebGraphicsContext3DProvider.h" #include "third_party/skia/include/effects/SkTableColorFilter.h" #include "wtf/MathExtras.h" #include "wtf/text/Base64.h" @@ -74,7 +78,9 @@ PassOwnPtr<ImageBuffer> ImageBuffer::create(const IntSize& size, OpacityMode opa ImageBuffer::ImageBuffer(PassOwnPtr<ImageBufferSurface> surface) : m_surface(surface) + , m_client(0) { + m_surface->setImageBuffer(this); if (m_surface->canvas()) { m_context = adoptPtr(new GraphicsContext(m_surface->canvas())); m_context->setCertainlyOpaque(m_surface->opacityMode() == Opaque); @@ -88,6 +94,8 @@ ImageBuffer::~ImageBuffer() GraphicsContext* ImageBuffer::context() const { + if (!isSurfaceValid()) + return 0; m_surface->willUse(); ASSERT(m_context.get()); return m_context.get(); @@ -99,23 +107,34 @@ const SkBitmap& ImageBuffer::bitmap() const return m_surface->bitmap(); } -bool ImageBuffer::isValid() const +bool ImageBuffer::isSurfaceValid() const { return m_surface->isValid(); } +bool ImageBuffer::restoreSurface() const +{ + return m_surface->isValid() || m_surface->restore(); +} + +void ImageBuffer::notifySurfaceInvalid() +{ + if (m_client) + m_client->notifySurfaceInvalid(); +} + static SkBitmap deepSkBitmapCopy(const SkBitmap& bitmap) { SkBitmap tmp; - if (!bitmap.deepCopyTo(&tmp, bitmap.config())) - bitmap.copyTo(&tmp, bitmap.config()); + if (!bitmap.deepCopyTo(&tmp)) + bitmap.copyTo(&tmp, bitmap.colorType()); return tmp; } PassRefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, ScaleBehavior) const { - if (!isValid()) + if (!isSurfaceValid()) return BitmapImage::create(NativeImageSkia::create()); const SkBitmap& bitmap = m_surface->bitmap(); @@ -132,29 +151,54 @@ blink::WebLayer* ImageBuffer::platformLayer() const return m_surface->layer(); } -bool ImageBuffer::copyToPlatformTexture(GraphicsContext3D& context, Platform3DObject texture, GC3Denum internalFormat, GC3Denum destType, GC3Dint level, bool premultiplyAlpha, bool flipY) +bool ImageBuffer::copyToPlatformTexture(blink::WebGraphicsContext3D* context, Platform3DObject texture, GLenum internalFormat, GLenum destType, GLint level, bool premultiplyAlpha, bool flipY) { - if (!m_surface->isAccelerated() || !platformLayer() || !isValid()) + if (!m_surface->isAccelerated() || !platformLayer() || !isSurfaceValid()) + return false; + + if (!Extensions3DUtil::canUseCopyTextureCHROMIUM(internalFormat, destType, level)) return false; - if (!context.makeContextCurrent()) + OwnPtr<blink::WebGraphicsContext3DProvider> provider = adoptPtr(blink::Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); + if (!provider) return false; + blink::WebGraphicsContext3D* sharedContext = provider->context3d(); + if (!sharedContext || !sharedContext->makeContextCurrent()) + return false; + + OwnPtr<blink::WebExternalTextureMailbox> mailbox = adoptPtr(new blink::WebExternalTextureMailbox); + + // Contexts may be in a different share group. We must transfer the texture through a mailbox first + sharedContext->genMailboxCHROMIUM(mailbox->name); + sharedContext->produceTextureDirectCHROMIUM(getBackingTexture(), GL_TEXTURE_2D, mailbox->name); + sharedContext->flush(); - Extensions3D* extensions = context.extensions(); - if (!extensions->supports("GL_CHROMIUM_copy_texture") || !extensions->supports("GL_CHROMIUM_flipy") - || !extensions->canUseCopyTextureCHROMIUM(internalFormat, destType, level)) + mailbox->syncPoint = sharedContext->insertSyncPoint(); + + if (!context->makeContextCurrent()) return false; + context->waitSyncPoint(mailbox->syncPoint); + Platform3DObject sourceTexture = context->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox->name); + // The canvas is stored in a premultiplied format, so unpremultiply if necessary. - context.pixelStorei(Extensions3D::UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, !premultiplyAlpha); + context->pixelStorei(GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, !premultiplyAlpha); // The canvas is stored in an inverted position, so the flip semantics are reversed. - context.pixelStorei(Extensions3D::UNPACK_FLIP_Y_CHROMIUM, !flipY); - extensions->copyTextureCHROMIUM(GL_TEXTURE_2D, getBackingTexture(), texture, level, internalFormat, destType); + context->pixelStorei(GC3D_UNPACK_FLIP_Y_CHROMIUM, !flipY); + context->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, texture, level, internalFormat, destType); + + context->pixelStorei(GC3D_UNPACK_FLIP_Y_CHROMIUM, false); + context->pixelStorei(GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, false); + + context->deleteTexture(sourceTexture); + + context->flush(); + sharedContext->waitSyncPoint(context->insertSyncPoint()); + + // Undo grContext texture binding changes introduced in this function + provider->grContext()->resetContext(kTextureBinding_GrGLBackendState); - context.pixelStorei(Extensions3D::UNPACK_FLIP_Y_CHROMIUM, false); - context.pixelStorei(Extensions3D::UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, false); - context.flush(); return true; } @@ -169,28 +213,40 @@ Platform3DObject ImageBuffer::getBackingTexture() return m_surface->getBackingTexture(); } -bool ImageBuffer::copyRenderingResultsFromDrawingBuffer(DrawingBuffer* drawingBuffer) +bool ImageBuffer::copyRenderingResultsFromDrawingBuffer(DrawingBuffer* drawingBuffer, bool fromFrontBuffer) { if (!drawingBuffer) return false; - RefPtr<GraphicsContext3D> context3D = SharedGraphicsContext3D::get(); + OwnPtr<blink::WebGraphicsContext3DProvider> provider = adoptPtr(blink::Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); + if (!provider) + return false; + blink::WebGraphicsContext3D* context3D = provider->context3d(); Platform3DObject tex = m_surface->getBackingTexture(); if (!context3D || !tex) return false; - return drawingBuffer->copyToPlatformTexture(*(context3D.get()), tex, GL_RGBA, - GL_UNSIGNED_BYTE, 0, true, false); + m_surface->invalidateCachedBitmap(); + return drawingBuffer->copyToPlatformTexture(context3D, tex, GL_RGBA, + GL_UNSIGNED_BYTE, 0, true, false, fromFrontBuffer); } -void ImageBuffer::draw(GraphicsContext* context, const FloatRect& destRect, const FloatRect& srcRect, - CompositeOperator op, blink::WebBlendMode blendMode, bool useLowQualityScale) +void ImageBuffer::draw(GraphicsContext* context, const FloatRect& destRect, const FloatRect* srcPtr, CompositeOperator op) { - if (!isValid()) + if (!isSurfaceValid()) return; - const SkBitmap& bitmap = m_surface->bitmap(); + FloatRect srcRect = srcPtr ? *srcPtr : FloatRect(FloatPoint(), size()); + SkBitmap bitmap = m_surface->bitmap(); + // For ImageBufferSurface that enables cachedBitmap, Use the cached Bitmap for CPU side usage + // if it is available, otherwise generate and use it. + if (!context->isAccelerated() && m_surface->isAccelerated() && m_surface->cachedBitmapEnabled() && isSurfaceValid()) { + m_surface->updateCachedBitmapIfNeeded(); + bitmap = m_surface->cachedBitmap(); + } + RefPtr<Image> image = BitmapImage::create(NativeImageSkia::create(drawNeedsCopy(m_context.get(), context) ? deepSkBitmapCopy(bitmap) : bitmap)); - context->drawImage(image.get(), destRect, srcRect, op, blendMode, DoNotRespectImageOrientation, useLowQualityScale); + + context->drawImage(image.get(), destRect, srcRect, op, blink::WebBlendModeNormal, DoNotRespectImageOrientation); } void ImageBuffer::flush() @@ -203,7 +259,7 @@ void ImageBuffer::flush() void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const FloatSize& scale, const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect, blink::WebBlendMode blendMode, const IntSize& repeatSpacing) { - if (!isValid()) + if (!isSurfaceValid()) return; const SkBitmap& bitmap = m_surface->bitmap(); @@ -211,60 +267,21 @@ void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect image->drawPattern(context, srcRect, scale, phase, op, destRect, blendMode, repeatSpacing); } -static const Vector<uint8_t>& getLinearRgbLUT() -{ - DEFINE_STATIC_LOCAL(Vector<uint8_t>, linearRgbLUT, ()); - if (linearRgbLUT.isEmpty()) { - linearRgbLUT.reserveCapacity(256); - for (unsigned i = 0; i < 256; i++) { - float color = i / 255.0f; - color = (color <= 0.04045f ? color / 12.92f : pow((color + 0.055f) / 1.055f, 2.4f)); - color = std::max(0.0f, color); - color = std::min(1.0f, color); - linearRgbLUT.append(static_cast<uint8_t>(round(color * 255))); - } - } - return linearRgbLUT; -} - -static const Vector<uint8_t>& getDeviceRgbLUT() -{ - DEFINE_STATIC_LOCAL(Vector<uint8_t>, deviceRgbLUT, ()); - if (deviceRgbLUT.isEmpty()) { - deviceRgbLUT.reserveCapacity(256); - for (unsigned i = 0; i < 256; i++) { - float color = i / 255.0f; - color = (powf(color, 1.0f / 2.4f) * 1.055f) - 0.055f; - color = std::max(0.0f, color); - color = std::min(1.0f, color); - deviceRgbLUT.append(static_cast<uint8_t>(round(color * 255))); - } - } - return deviceRgbLUT; -} - void ImageBuffer::transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstColorSpace) { - if (srcColorSpace == dstColorSpace) - return; - - // only sRGB <-> linearRGB are supported at the moment - if ((srcColorSpace != ColorSpaceLinearRGB && srcColorSpace != ColorSpaceDeviceRGB) - || (dstColorSpace != ColorSpaceLinearRGB && dstColorSpace != ColorSpaceDeviceRGB)) + const uint8_t* lookUpTable = ColorSpaceUtilities::getConversionLUT(dstColorSpace, srcColorSpace); + if (!lookUpTable) return; // FIXME: Disable color space conversions on accelerated canvases (for now). - if (context()->isAccelerated() || !isValid()) + if (context()->isAccelerated() || !isSurfaceValid()) return; const SkBitmap& bitmap = m_surface->bitmap(); if (bitmap.isNull()) return; - const Vector<uint8_t>& lookUpTable = dstColorSpace == ColorSpaceLinearRGB ? - getLinearRgbLUT() : getDeviceRgbLUT(); - - ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); + ASSERT(bitmap.colorType() == kPMColor_SkColorType); IntSize size = m_surface->size(); SkAutoLockPixels bitmapLock(bitmap); for (int y = 0; y < size.height(); ++y) { @@ -283,18 +300,9 @@ void ImageBuffer::transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstCo PassRefPtr<SkColorFilter> ImageBuffer::createColorSpaceFilter(ColorSpace srcColorSpace, ColorSpace dstColorSpace) { - if ((srcColorSpace == dstColorSpace) - || (srcColorSpace != ColorSpaceLinearRGB && srcColorSpace != ColorSpaceDeviceRGB) - || (dstColorSpace != ColorSpaceLinearRGB && dstColorSpace != ColorSpaceDeviceRGB)) - return 0; - - const uint8_t* lut = 0; - if (dstColorSpace == ColorSpaceLinearRGB) - lut = &getLinearRgbLUT()[0]; - else if (dstColorSpace == ColorSpaceDeviceRGB) - lut = &getDeviceRgbLUT()[0]; - else - return 0; + const uint8_t* lut = ColorSpaceUtilities::getConversionLUT(dstColorSpace, srcColorSpace); + if (!lut) + return nullptr; return adoptRef(SkTableColorFilter::CreateARGB(0, lut, lut, lut)); } @@ -304,50 +312,40 @@ PassRefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, GraphicsContext* { float area = 4.0f * rect.width() * rect.height(); if (area > static_cast<float>(std::numeric_limits<int>::max())) - return 0; + return nullptr; RefPtr<Uint8ClampedArray> result = Uint8ClampedArray::createUninitialized(rect.width() * rect.height() * 4); - unsigned char* data = result->data(); - if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > size.width() || rect.maxY() > size.height()) result->zeroFill(); - unsigned destBytesPerRow = 4 * rect.width(); - SkBitmap destBitmap; - destBitmap.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height(), destBytesPerRow); - destBitmap.setPixels(data); - - SkCanvas::Config8888 config8888; - if (multiplied == Premultiplied) - config8888 = SkCanvas::kRGBA_Premul_Config8888; - else - config8888 = SkCanvas::kRGBA_Unpremul_Config8888; + SkAlphaType alphaType = (multiplied == Premultiplied) ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; + SkImageInfo info = SkImageInfo::Make(rect.width(), rect.height(), kRGBA_8888_SkColorType, alphaType); - context->readPixels(&destBitmap, rect.x(), rect.y(), config8888); + context->readPixels(info, result->data(), 4 * rect.width(), rect.x(), rect.y()); return result.release(); } PassRefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const { - if (!isValid()) + if (!isSurfaceValid()) return Uint8ClampedArray::create(rect.width() * rect.height() * 4); return getImageData<Unmultiplied>(rect, context(), m_surface->size()); } PassRefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const { - if (!isValid()) + if (!isSurfaceValid()) return Uint8ClampedArray::create(rect.width() * rect.height() * 4); return getImageData<Premultiplied>(rect, context(), m_surface->size()); } void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint) { - if (!isValid()) + if (!isSurfaceValid()) return; ASSERT(sourceRect.width() > 0); @@ -360,11 +358,6 @@ void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, c ASSERT(originX >= 0); ASSERT(originX < sourceRect.maxX()); - int endX = destPoint.x() + sourceRect.maxX(); - ASSERT(endX <= m_surface->size().width()); - - int numColumns = endX - destX; - int originY = sourceRect.y(); int destY = destPoint.y() + sourceRect.y(); ASSERT(destY >= 0); @@ -372,22 +365,12 @@ void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, c ASSERT(originY >= 0); ASSERT(originY < sourceRect.maxY()); - int endY = destPoint.y() + sourceRect.maxY(); - ASSERT(endY <= m_surface->size().height()); - int numRows = endY - destY; - - unsigned srcBytesPerRow = 4 * sourceSize.width(); - SkBitmap srcBitmap; - srcBitmap.setConfig(SkBitmap::kARGB_8888_Config, numColumns, numRows, srcBytesPerRow); - srcBitmap.setPixels(source->data() + originY * srcBytesPerRow + originX * 4); - - SkCanvas::Config8888 config8888; - if (multiplied == Premultiplied) - config8888 = SkCanvas::kRGBA_Premul_Config8888; - else - config8888 = SkCanvas::kRGBA_Unpremul_Config8888; + const size_t srcBytesPerRow = 4 * sourceSize.width(); + const void* srcAddr = source->data() + originY * srcBytesPerRow + originX * 4; + const SkAlphaType alphaType = (multiplied == Premultiplied) ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; + SkImageInfo info = SkImageInfo::Make(sourceRect.width(), sourceRect.height(), kRGBA_8888_SkColorType, alphaType); - context()->writePixels(srcBitmap, destX, destY, config8888); + context()->writePixels(info, srcAddr, srcBytesPerRow, destX, destY); } template <typename T> @@ -421,7 +404,7 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); Vector<char> encodedImage; - if (!isValid() || !encodeImage(m_surface->bitmap(), mimeType, quality, &encodedImage)) + if (!isSurfaceValid() || !encodeImage(m_surface->bitmap(), mimeType, quality, &encodedImage)) return "data:,"; Vector<char> base64Data; base64Encode(encodedImage, base64Data); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ImageBuffer.h b/chromium/third_party/WebKit/Source/platform/graphics/ImageBuffer.h index bc8465fbfba..936979db27c 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/ImageBuffer.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageBuffer.h @@ -33,7 +33,6 @@ #include "platform/geometry/IntSize.h" #include "platform/graphics/Canvas2DLayerBridge.h" #include "platform/graphics/ColorSpace.h" -#include "platform/graphics/GraphicsContext.h" #include "platform/graphics/GraphicsTypes.h" #include "platform/graphics/GraphicsTypes3D.h" #include "platform/graphics/ImageBufferSurface.h" @@ -47,11 +46,16 @@ class SkCanvas; +namespace blink { +class WebGraphicsContext3D; +} + namespace WebCore { class DrawingBuffer; -class GraphicsContext3D; +class GraphicsContext; class Image; +class ImageBufferClient; class IntPoint; class IntRect; @@ -78,8 +82,14 @@ public: ~ImageBuffer(); + void setClient(ImageBufferClient* client) { m_client = client; } + const IntSize& size() const { return m_surface->size(); } bool isAccelerated() const { return m_surface->isAccelerated(); } + bool isSurfaceValid() const; + bool restoreSurface() const; + + void setIsHidden(bool hidden) { m_surface->setIsHidden(hidden); } GraphicsContext* context() const; @@ -103,18 +113,21 @@ public: // FIXME: current implementations of this method have the restriction that they only work // with textures that are RGB or RGBA format, UNSIGNED_BYTE type and level 0, as specified in // Extensions3D::canUseCopyTextureCHROMIUM(). - bool copyToPlatformTexture(GraphicsContext3D&, Platform3DObject, GC3Denum, GC3Denum, GC3Dint, bool, bool); + // Destroys the TEXTURE_2D binding for the active texture unit of the passed context + bool copyToPlatformTexture(blink::WebGraphicsContext3D*, Platform3DObject, GLenum, GLenum, GLint, bool, bool); Platform3DObject getBackingTexture(); - bool copyRenderingResultsFromDrawingBuffer(DrawingBuffer*); + + bool copyRenderingResultsFromDrawingBuffer(DrawingBuffer*, bool fromFrontBuffer = false); void flush(); + void notifySurfaceInvalid(); + private: ImageBuffer(PassOwnPtr<ImageBufferSurface>); - bool isValid() const; - void draw(GraphicsContext*, const FloatRect&, const FloatRect& = FloatRect(0, 0, -1, -1), CompositeOperator = CompositeSourceOver, blink::WebBlendMode = blink::WebBlendModeNormal, bool useLowQualityScale = false); + void draw(GraphicsContext*, const FloatRect&, const FloatRect* = 0, CompositeOperator = CompositeSourceOver); void drawPattern(GraphicsContext*, const FloatRect&, const FloatSize&, const FloatPoint&, CompositeOperator, const FloatRect&, blink::WebBlendMode, const IntSize& repeatSpacing = IntSize()); static PassRefPtr<SkColorFilter> createColorSpaceFilter(ColorSpace srcColorSpace, ColorSpace dstColorSpace); @@ -126,6 +139,7 @@ private: OwnPtr<ImageBufferSurface> m_surface; OwnPtr<GraphicsContext> m_context; + ImageBufferClient* m_client; }; struct ImageDataBuffer { diff --git a/chromium/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.h b/chromium/third_party/WebKit/Source/platform/graphics/ImageBufferClient.h index 1293abc3ac1..4843f501033 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageBufferClient.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Google Inc. All rights reserved. + * Copyright (c) 2014, Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -28,30 +28,18 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef AcceleratedImageBufferSurface_h -#define AcceleratedImageBufferSurface_h - -#include "platform/graphics/ImageBufferSurface.h" -#include "wtf/OwnPtr.h" +#ifndef ImageBufferClient_h +#define ImageBufferClient_h namespace WebCore { -class PLATFORM_EXPORT AcceleratedImageBufferSurface : public ImageBufferSurface { - WTF_MAKE_NONCOPYABLE(AcceleratedImageBufferSurface); WTF_MAKE_FAST_ALLOCATED; +class ImageBufferClient { public: - AcceleratedImageBufferSurface(const IntSize&, OpacityMode = NonOpaque, int msaaSampleCount = 0); - virtual ~AcceleratedImageBufferSurface() { } - - virtual SkCanvas* canvas() const OVERRIDE { return m_canvas.get();} - virtual bool isValid() const OVERRIDE { return m_canvas; } - virtual bool isAccelerated() const OVERRIDE { return true; } - virtual Platform3DObject getBackingTexture() const OVERRIDE; - -private: - OwnPtr<SkCanvas> m_canvas; + virtual ~ImageBufferClient() { } + virtual void notifySurfaceInvalid() = 0; }; - -} // namespace WebCore +} #endif + diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.cpp b/chromium/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.cpp index c5e22dbdd03..2869f4cc29a 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.cpp @@ -32,11 +32,19 @@ #include "platform/graphics/ImageBufferSurface.h" +#include "platform/graphics/ImageBuffer.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkDevice.h" namespace WebCore { +ImageBufferSurface::ImageBufferSurface(const IntSize& size, OpacityMode opacityMode) + : m_opacityMode(opacityMode) + , m_size(size) +{ + setIsHidden(false); +} + void ImageBufferSurface::clear() { // Clear the background transparent or opaque, as required. It would be nice if this wasn't @@ -56,5 +64,10 @@ const SkBitmap& ImageBufferSurface::bitmap() const return canvas()->getTopDevice()->accessBitmap(false); } +const SkBitmap& ImageBufferSurface::cachedBitmap() const +{ + DEFINE_STATIC_LOCAL(SkBitmap, nullBitmap, ()); + return nullBitmap; +} } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h b/chromium/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h index a415cfa9e18..a240f3776b4 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h @@ -44,6 +44,8 @@ namespace blink { class WebLayer; } namespace WebCore { +class ImageBuffer; + enum OpacityMode { NonOpaque, Opaque, @@ -58,21 +60,25 @@ public: virtual const SkBitmap& bitmap() const; virtual void willUse() { } // Called by ImageBuffer before reading or writing to the surface. virtual bool isValid() const = 0; + virtual bool restore() { return false; }; virtual blink::WebLayer* layer() const { return 0; }; virtual bool isAccelerated() const { return false; } virtual Platform3DObject getBackingTexture() const { return 0; } + virtual bool cachedBitmapEnabled() const { return false; } + virtual const SkBitmap& cachedBitmap() const; + virtual void invalidateCachedBitmap() { } + virtual void updateCachedBitmapIfNeeded() { } + virtual void setIsHidden(bool) { } + virtual void setImageBuffer(ImageBuffer*) { } OpacityMode opacityMode() const { return m_opacityMode; } const IntSize& size() const { return m_size; } + void notifyIsValidChanged(bool isValid) const; protected: + ImageBufferSurface(const IntSize&, OpacityMode); void clear(); - ImageBufferSurface(const IntSize& size, OpacityMode opacityMode) - : m_opacityMode(opacityMode) - , m_size(size) - { } - private: OpacityMode m_opacityMode; IntSize m_size; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ImageDecodingStore.cpp b/chromium/third_party/WebKit/Source/platform/graphics/ImageDecodingStore.cpp index 5e7bb4d43af..3d5e9dd65e2 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/ImageDecodingStore.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageDecodingStore.cpp @@ -27,6 +27,7 @@ #include "platform/graphics/ImageDecodingStore.h" #include "platform/TraceEvent.h" +#include "wtf/Threading.h" namespace WebCore { @@ -37,15 +38,8 @@ namespace { // with a lot of (very) large images. static const size_t maxTotalSizeOfDiscardableEntries = 256 * 1024 * 1024; static const size_t defaultMaxTotalSizeOfHeapEntries = 32 * 1024 * 1024; -static ImageDecodingStore* s_instance = 0; static bool s_imageCachingEnabled = true; -static void setInstance(ImageDecodingStore* imageDecodingStore) -{ - delete s_instance; - s_instance = imageDecodingStore; -} - } // namespace ImageDecodingStore::ImageDecodingStore() @@ -69,17 +63,8 @@ ImageDecodingStore::~ImageDecodingStore() ImageDecodingStore* ImageDecodingStore::instance() { - return s_instance; -} - -void ImageDecodingStore::initializeOnce() -{ - setInstance(ImageDecodingStore::create().leakPtr()); -} - -void ImageDecodingStore::shutdown() -{ - setInstance(0); + AtomicallyInitializedStatic(ImageDecodingStore*, store = ImageDecodingStore::create().leakPtr()); + return store; } void ImageDecodingStore::setImageCachingEnabled(bool enabled) @@ -367,7 +352,7 @@ void ImageDecodingStore::insertCacheInternal(PassOwnPtr<T> cacheEntry, U* cacheM typename U::KeyType key = cacheEntry->cacheKey(); typename V::AddResult result = identifierMap->add(cacheEntry->generator(), typename V::MappedType()); - result.iterator->value.add(key); + result.storedValue->value.add(key); cacheMap->add(key, cacheEntry); TRACE_COUNTER1("webkit", "ImageDecodingStoreDiscardableMemoryUsageBytes", m_discardableMemoryUsageInBytes); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ImageDecodingStore.h b/chromium/third_party/WebKit/Source/platform/graphics/ImageDecodingStore.h index 6a7d9f8f621..bd740f9ad59 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/ImageDecodingStore.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageDecodingStore.h @@ -89,8 +89,6 @@ public: ~ImageDecodingStore(); static ImageDecodingStore* instance(); - static void initializeOnce(); - static void shutdown(); // Why do we need this? // ImageDecodingStore is used in two code paths: @@ -137,8 +135,8 @@ private: // Image cache entry is identified by: // 1. Pointer to ImageFrameGenerator. // 2. Size of the image. - // 3. Frame index. - // 4. Frame generation. Increments on each progressive decode. + // 3. LocalFrame index. + // 4. LocalFrame generation. Increments on each progressive decode. // // The use of generation ID is to allow multiple versions of an image frame // be stored in the cache. Each generation comes from a progressive decode. @@ -192,7 +190,7 @@ private: CacheEntry* m_next; }; - class ImageCacheEntry : public CacheEntry { + class ImageCacheEntry FINAL : public CacheEntry { public: static PassOwnPtr<ImageCacheEntry> createAndUse(const ImageFrameGenerator* generator, PassOwnPtr<ScaledImageFragment> image) { @@ -207,8 +205,8 @@ private: // FIXME: getSafeSize() returns size in bytes truncated to a 32-bits integer. // Find a way to get the size in 64-bits. - virtual size_t memoryUsageInBytes() const { return cachedImage()->bitmap().getSafeSize(); } - virtual CacheType type() const { return TypeImage; } + virtual size_t memoryUsageInBytes() const OVERRIDE { return cachedImage()->bitmap().getSafeSize(); } + virtual CacheType type() const OVERRIDE { return TypeImage; } static ImageCacheKey makeCacheKey(const ImageFrameGenerator* generator, const SkISize& size, size_t index, size_t generation) { @@ -222,7 +220,7 @@ private: OwnPtr<ScaledImageFragment> m_cachedImage; }; - class DecoderCacheEntry : public CacheEntry { + class DecoderCacheEntry FINAL : public CacheEntry { public: static PassOwnPtr<DecoderCacheEntry> create(const ImageFrameGenerator* generator, PassOwnPtr<ImageDecoder> decoder, bool isDiscardable) { @@ -236,8 +234,8 @@ private: { } - virtual size_t memoryUsageInBytes() const { return m_size.width() * m_size.height() * 4; } - virtual CacheType type() const { return TypeDecoder; } + virtual size_t memoryUsageInBytes() const OVERRIDE { return m_size.width() * m_size.height() * 4; } + virtual CacheType type() const OVERRIDE { return TypeDecoder; } static DecoderCacheKey makeCacheKey(const ImageFrameGenerator* generator, const SkISize& size) { diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ImageDecodingStoreTest.cpp b/chromium/third_party/WebKit/Source/platform/graphics/ImageDecodingStoreTest.cpp index 7ac6cb2c3c2..ef4cf128336 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/ImageDecodingStoreTest.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageDecodingStoreTest.cpp @@ -41,7 +41,7 @@ class ImageDecodingStoreTest : public ::testing::Test, public MockImageDecoderCl public: virtual void SetUp() { - ImageDecodingStore::initializeOnce(); + ImageDecodingStore::instance()->setCacheLimitInBytes(1024 * 1024); ImageDecodingStore::instance()->setImageCachingEnabled(true); m_data = SharedBuffer::create(); m_generator = ImageFrameGenerator::create(SkISize::Make(100, 100), m_data, true); @@ -50,7 +50,7 @@ public: virtual void TearDown() { - ImageDecodingStore::shutdown(); + ImageDecodingStore::instance()->clear(); } virtual void decoderBeingDestroyed() @@ -77,22 +77,26 @@ protected: PassOwnPtr<ScaledImageFragment> createCompleteImage(const SkISize& size, bool discardable = false, size_t index = 0) { SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height()); - if (!discardable) + bitmap.setInfo(SkImageInfo::MakeN32Premul(size)); + if (!discardable) { bitmap.allocPixels(); - else - bitmap.setPixelRef(new MockDiscardablePixelRef())->unref(); + } else { + MockDiscardablePixelRef::Allocator mockDiscardableAllocator; + bitmap.allocPixels(&mockDiscardableAllocator, 0); + } return ScaledImageFragment::createComplete(size, index, bitmap); } PassOwnPtr<ScaledImageFragment> createIncompleteImage(const SkISize& size, bool discardable = false, size_t generation = 0) { SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height()); - if (!discardable) + bitmap.setInfo(SkImageInfo::MakeN32Premul(size)); + if (!discardable) { bitmap.allocPixels(); - else - bitmap.setPixelRef(new MockDiscardablePixelRef())->unref(); + } else { + MockDiscardablePixelRef::Allocator mockDiscardableAllocator; + bitmap.allocPixels(&mockDiscardableAllocator, 0); + } return ScaledImageFragment::createPartial(size, 0, generation, bitmap); } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp b/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp index 1c04365f94f..a51db79f686 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp @@ -35,35 +35,55 @@ #include "platform/image-decoders/ImageDecoder.h" #include "skia/ext/image_operations.h" +#include "third_party/skia/include/core/SkMallocPixelRef.h" namespace WebCore { -namespace { +// Creates a SkPixelRef such that the memory for pixels is given by an external body. +// This is used to write directly to the memory given by Skia during decoding. +class ImageFrameGenerator::ExternalMemoryAllocator : public SkBitmap::Allocator { +public: + ExternalMemoryAllocator(const SkImageInfo& info, void* pixels, size_t rowBytes) + : m_info(info) + , m_pixels(pixels) + , m_rowBytes(rowBytes) + { + } -skia::ImageOperations::ResizeMethod resizeMethod() -{ - return skia::ImageOperations::RESIZE_LANCZOS3; -} + virtual bool allocPixelRef(SkBitmap* dst, SkColorTable* ctable) OVERRIDE + { + const SkImageInfo& info = dst->info(); + if (kUnknown_SkColorType == info.colorType()) + return false; -} // namespace + if (info != m_info || m_rowBytes != dst->rowBytes()) + return false; + + if (!dst->installPixels(m_info, m_pixels, m_rowBytes)) + return false; + dst->lockPixels(); + return true; + } + +private: + SkImageInfo m_info; + void* m_pixels; + size_t m_rowBytes; +}; ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, PassRefPtr<SharedBuffer> data, bool allDataReceived, bool isMultiFrame) : m_fullSize(fullSize) , m_isMultiFrame(isMultiFrame) , m_decodeFailedAndEmpty(false) , m_decodeCount(ScaledImageFragment::FirstPartialImage) - , m_allocator(adoptPtr(new DiscardablePixelRefAllocator())) + , m_discardableAllocator(adoptPtr(new DiscardablePixelRefAllocator())) { setData(data.get(), allDataReceived); } ImageFrameGenerator::~ImageFrameGenerator() { - // FIXME: This check is not really thread-safe. This should be changed to: - // ImageDecodingStore::removeCacheFromInstance(this); - // Which uses a lock internally. - if (ImageDecodingStore::instance()) - ImageDecodingStore::instance()->removeCacheIndexedByGenerator(this); + ImageDecodingStore::instance()->removeCacheIndexedByGenerator(this); } void ImageFrameGenerator::setData(PassRefPtr<SharedBuffer> data, bool allDataReceived) @@ -95,11 +115,7 @@ const ScaledImageFragment* ImageFrameGenerator::decodeAndScale(const SkISize& sc TRACE_EVENT2("webkit", "ImageFrameGenerator::decodeAndScale", "generator", this, "decodeCount", static_cast<int>(m_decodeCount)); - cachedImage = tryToScale(0, scaledSize, index); - if (cachedImage) - return cachedImage; - - cachedImage = tryToResumeDecodeAndScale(scaledSize, index); + cachedImage = tryToResumeDecode(scaledSize, index); if (cachedImage) return cachedImage; return 0; @@ -108,33 +124,49 @@ const ScaledImageFragment* ImageFrameGenerator::decodeAndScale(const SkISize& sc bool ImageFrameGenerator::decodeAndScale(const SkImageInfo& info, size_t index, void* pixels, size_t rowBytes) { // This method is called to populate a discardable memory owned by Skia. - // Ideally we want the decoder to write directly to |pixels| but this - // simple implementation copies from a decoded bitmap. + + // Prevents concurrent decode or scale operations on the same image data. + MutexLocker lock(m_decodeMutex); // This implementation does not support scaling so check the requested size. - ASSERT(m_fullSize.width() == info.fWidth); - ASSERT(m_fullSize.height() == info.fHeight); + SkISize scaledSize = SkISize::Make(info.fWidth, info.fHeight); + ASSERT(m_fullSize == scaledSize); + + if (m_decodeFailedAndEmpty) + return 0; + + TRACE_EVENT2("webkit", "ImageFrameGenerator::decodeAndScale", "generator", this, "decodeCount", static_cast<int>(m_decodeCount)); // Don't use discardable memory for decoding if Skia is providing output - // memory. By clearing the memory allocator decoding will use heap memory. + // memory. Instead use ExternalMemoryAllocator such that we can + // write directly to the memory given by Skia. // // TODO: // This is not pretty because this class is used in two different code // paths: discardable memory decoding on Android and discardable memory // in Skia. Once the transition to caching in Skia is complete we can get // rid of the logic that handles discardable memory. - m_allocator.clear(); + m_discardableAllocator.clear(); + m_externalAllocator = adoptPtr(new ExternalMemoryAllocator(info, pixels, rowBytes)); - const ScaledImageFragment* cachedImage = decodeAndScale(SkISize::Make(info.fWidth, info.fHeight), index); + const ScaledImageFragment* cachedImage = tryToResumeDecode(scaledSize, index); if (!cachedImage) return false; - ASSERT(cachedImage->bitmap().width() == info.fWidth); - ASSERT(cachedImage->bitmap().height() == info.fHeight); + // Don't keep the allocator because it contains a pointer to memory + // that we do not own. + m_externalAllocator.clear(); + + ASSERT(cachedImage->bitmap().width() == scaledSize.width()); + ASSERT(cachedImage->bitmap().height() == scaledSize.height()); - bool copied = cachedImage->bitmap().copyPixelsTo(pixels, rowBytes * info.fHeight, rowBytes); + bool result = true; + // Check to see if decoder has written directly to the memory provided + // by Skia. If not make a copy. + if (cachedImage->bitmap().getPixels() != pixels) + result = cachedImage->bitmap().copyPixelsTo(pixels, rowBytes * info.fHeight, rowBytes); ImageDecodingStore::instance()->unlockCache(this, cachedImage); - return copied; + return result; } const ScaledImageFragment* ImageFrameGenerator::tryToLockCompleteCache(const SkISize& scaledSize, size_t index) @@ -145,34 +177,7 @@ const ScaledImageFragment* ImageFrameGenerator::tryToLockCompleteCache(const SkI return 0; } -const ScaledImageFragment* ImageFrameGenerator::tryToScale(const ScaledImageFragment* fullSizeImage, const SkISize& scaledSize, size_t index) -{ - TRACE_EVENT0("webkit", "ImageFrameGenerator::tryToScale"); - - // If the requested scaled size is the same as the full size then exit - // early. This saves a cache lookup. - if (scaledSize == m_fullSize) - return 0; - - if (!fullSizeImage && !ImageDecodingStore::instance()->lockCache(this, m_fullSize, index, &fullSizeImage)) - return 0; - - // This call allocates the DiscardablePixelRef and lock/unlocks it - // afterwards. So the memory allocated to the scaledBitmap can be - // discarded after this call. Need to lock the scaledBitmap and - // check the pixels before using it next time. - SkBitmap scaledBitmap = skia::ImageOperations::Resize(fullSizeImage->bitmap(), resizeMethod(), scaledSize.width(), scaledSize.height(), m_allocator.get()); - - OwnPtr<ScaledImageFragment> scaledImage; - if (fullSizeImage->isComplete()) - scaledImage = ScaledImageFragment::createComplete(scaledSize, fullSizeImage->index(), scaledBitmap); - else - scaledImage = ScaledImageFragment::createPartial(scaledSize, fullSizeImage->index(), nextGenerationId(), scaledBitmap); - ImageDecodingStore::instance()->unlockCache(this, fullSizeImage); - return ImageDecodingStore::instance()->insertAndLockCache(this, scaledImage.release()); -} - -const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecodeAndScale(const SkISize& scaledSize, size_t index) +const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecode(const SkISize& scaledSize, size_t index) { TRACE_EVENT1("webkit", "ImageFrameGenerator::tryToResumeDecodeAndScale", "index", static_cast<int>(index)); @@ -218,9 +223,7 @@ const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecodeAndScale(const ImageDecodingStore::instance()->insertDecoder(this, decoderContainer.release(), DiscardablePixelRef::isDiscardable(cachedImage->bitmap().pixelRef())); } - if (m_fullSize == scaledSize) - return cachedImage; - return tryToScale(cachedImage, scaledSize, index); + return cachedImage; } PassOwnPtr<ScaledImageFragment> ImageFrameGenerator::decode(size_t index, ImageDecoder** decoder) @@ -230,10 +233,12 @@ PassOwnPtr<ScaledImageFragment> ImageFrameGenerator::decode(size_t index, ImageD ASSERT(decoder); SharedBuffer* data = 0; bool allDataReceived = false; + bool newDecoder = false; m_data.data(&data, &allDataReceived); // Try to create an ImageDecoder if we are not given one. if (!*decoder) { + newDecoder = true; if (m_imageDecoderFactory) *decoder = m_imageDecoderFactory->create().leakPtr(); @@ -244,10 +249,18 @@ PassOwnPtr<ScaledImageFragment> ImageFrameGenerator::decode(size_t index, ImageD return nullptr; } - // TODO: this is very ugly. We need to refactor the way how we can pass a - // memory allocator to image decoders. - if (!m_isMultiFrame) - (*decoder)->setMemoryAllocator(m_allocator.get()); + // This variable is set to true if we can skip a memcpy of the decoded bitmap. + bool canSkipBitmapCopy = false; + + if (!m_isMultiFrame && newDecoder && allDataReceived) { + // If we're using an external memory allocator that means we're decoding + // directly into the output memory and we can save one memcpy. + canSkipBitmapCopy = true; + if (m_externalAllocator) + (*decoder)->setMemoryAllocator(m_externalAllocator.get()); + else + (*decoder)->setMemoryAllocator(m_discardableAllocator.get()); + } (*decoder)->setData(data, allDataReceived); // If this call returns a newly allocated DiscardablePixelRef, then // ImageFrame::m_bitmap and the contained DiscardablePixelRef are locked. @@ -257,11 +270,15 @@ PassOwnPtr<ScaledImageFragment> ImageFrameGenerator::decode(size_t index, ImageD ImageFrame* frame = (*decoder)->frameBufferAtIndex(index); (*decoder)->setData(0, false); // Unref SharedBuffer from ImageDecoder. (*decoder)->clearCacheExceptFrame(index); + (*decoder)->setMemoryAllocator(0); if (!frame || frame->status() == ImageFrame::FrameEmpty) return nullptr; - const bool isComplete = frame->status() == ImageFrame::FrameComplete; + // A cache object is considered complete if we can decode a complete frame. + // Or we have received all data. The image might not be fully decoded in + // the latter case. + const bool isCacheComplete = frame->status() == ImageFrame::FrameComplete || allDataReceived; SkBitmap fullSizeBitmap = frame->getSkBitmap(); if (fullSizeBitmap.isNull()) return nullptr; @@ -278,14 +295,25 @@ PassOwnPtr<ScaledImageFragment> ImageFrameGenerator::decode(size_t index, ImageD } ASSERT(fullSizeBitmap.width() == m_fullSize.width() && fullSizeBitmap.height() == m_fullSize.height()); - if (isComplete) + // We early out and do not copy the memory if decoder writes directly to + // the memory provided by Skia and the decode was complete. + if (canSkipBitmapCopy && isCacheComplete) return ScaledImageFragment::createComplete(m_fullSize, index, fullSizeBitmap); - // If the image is partial we need to return a copy. This is to avoid future - // decode operations writing to the same bitmap. + // If the image is progressively decoded we need to return a copy. + // This is to avoid future decode operations writing to the same bitmap. + // FIXME: Note that discardable allocator is used. This is because the code + // is still used in the Android discardable memory path. When this code is + // used in the Skia discardable memory path |m_discardableAllocator| is empty. + // This is confusing and should be cleaned up when we can deprecate the use + // case for Android discardable memory. SkBitmap copyBitmap; - return fullSizeBitmap.copyTo(©Bitmap, fullSizeBitmap.config(), m_allocator.get()) ? - ScaledImageFragment::createPartial(m_fullSize, index, nextGenerationId(), copyBitmap) : nullptr; + if (!fullSizeBitmap.copyTo(©Bitmap, fullSizeBitmap.colorType(), m_discardableAllocator.get())) + return nullptr; + + if (isCacheComplete) + return ScaledImageFragment::createComplete(m_fullSize, index, copyBitmap); + return ScaledImageFragment::createPartial(m_fullSize, index, nextGenerationId(), copyBitmap); } bool ImageFrameGenerator::hasAlpha(size_t index) diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h b/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h index 32817b48a67..2f7d49be02e 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h @@ -86,18 +86,18 @@ public: bool hasAlpha(size_t); private: + class ExternalMemoryAllocator; friend class ImageFrameGeneratorTest; friend class DeferredImageDecoderTest; // For testing. |factory| will overwrite the default ImageDecoder creation logic if |factory->create()| returns non-zero. void setImageDecoderFactory(PassOwnPtr<ImageDecoderFactory> factory) { m_imageDecoderFactory = factory; } // For testing. - SkBitmap::Allocator* allocator() const { return m_allocator.get(); } - void setAllocator(PassOwnPtr<SkBitmap::Allocator> allocator) { m_allocator = allocator; } + SkBitmap::Allocator* allocator() const { return m_discardableAllocator.get(); } + void setAllocator(PassOwnPtr<SkBitmap::Allocator> allocator) { m_discardableAllocator = allocator; } // These methods are called while m_decodeMutex is locked. const ScaledImageFragment* tryToLockCompleteCache(const SkISize& scaledSize, size_t index); - const ScaledImageFragment* tryToScale(const ScaledImageFragment* fullSizeImage, const SkISize& scaledSize, size_t index); - const ScaledImageFragment* tryToResumeDecodeAndScale(const SkISize& scaledSize, size_t index); + const ScaledImageFragment* tryToResumeDecode(const SkISize& scaledSize, size_t index); // Use the given decoder to decode. If a decoder is not given then try to create one. PassOwnPtr<ScaledImageFragment> decode(size_t index, ImageDecoder**); @@ -113,7 +113,8 @@ private: bool m_decodeFailedAndEmpty; Vector<bool> m_hasAlpha; size_t m_decodeCount; - OwnPtr<SkBitmap::Allocator> m_allocator; + OwnPtr<SkBitmap::Allocator> m_discardableAllocator; + OwnPtr<ExternalMemoryAllocator> m_externalAllocator; OwnPtr<ImageDecoderFactory> m_imageDecoderFactory; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGeneratorTest.cpp b/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGeneratorTest.cpp index 1f74b5b34a7..81d860fb341 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGeneratorTest.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageFrameGeneratorTest.cpp @@ -40,7 +40,6 @@ namespace { // Helper methods to generate standard sizes. SkISize fullSize() { return SkISize::Make(100, 100); } -SkISize scaledSize() { return SkISize::Make(50, 50); } } // namespace @@ -48,10 +47,10 @@ class ImageFrameGeneratorTest : public ::testing::Test, public MockImageDecoderC public: virtual void SetUp() OVERRIDE { - ImageDecodingStore::initializeOnce(); + ImageDecodingStore::instance()->setCacheLimitInBytes(1024 * 1024); ImageDecodingStore::instance()->setImageCachingEnabled(true); m_data = SharedBuffer::create(); - m_generator = ImageFrameGenerator::create(fullSize(), m_data, true); + m_generator = ImageFrameGenerator::create(fullSize(), m_data, false); useMockImageDecoderFactory(); m_decodersDestroyed = 0; m_frameBufferRequestCount = 0; @@ -60,7 +59,7 @@ public: virtual void TearDown() OVERRIDE { - ImageDecodingStore::shutdown(); + ImageDecodingStore::instance()->clear(); } virtual void decoderBeingDestroyed() OVERRIDE @@ -93,8 +92,8 @@ protected: PassOwnPtr<ScaledImageFragment> createCompleteImage(const SkISize& size) { SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height()); - bitmap.allocPixels(); + if (!bitmap.allocN32Pixels(size.width(), size.height())) + return nullptr; return ScaledImageFragment::createComplete(size, 0, bitmap); } @@ -116,7 +115,9 @@ protected: PassOwnPtr<ScaledImageFragment> decode(size_t index) { ImageDecoder* decoder = 0; - return m_generator->decode(index, &decoder); + OwnPtr<ScaledImageFragment> fragment = m_generator->decode(index, &decoder); + delete decoder; + return fragment.release(); } RefPtr<SharedBuffer> m_data; @@ -129,8 +130,10 @@ protected: TEST_F(ImageFrameGeneratorTest, cacheHit) { + OwnPtr<ScaledImageFragment> completeImageTemp = createCompleteImage(fullSize()); + ASSERT_TRUE(completeImageTemp); const ScaledImageFragment* fullImage = ImageDecodingStore::instance()->insertAndLockCache( - m_generator.get(), createCompleteImage(fullSize())); + m_generator.get(), completeImageTemp.release()); EXPECT_EQ(fullSize(), fullImage->scaledSize()); ImageDecodingStore::instance()->unlockCache(m_generator.get(), fullImage); @@ -142,62 +145,11 @@ TEST_F(ImageFrameGeneratorTest, cacheHit) EXPECT_EQ(0, m_frameBufferRequestCount); } -TEST_F(ImageFrameGeneratorTest, cacheMissWithScale) -{ - const ScaledImageFragment* fullImage = ImageDecodingStore::instance()->insertAndLockCache( - m_generator.get(), createCompleteImage(fullSize())); - EXPECT_EQ(fullSize(), fullImage->scaledSize()); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), fullImage); - - // Cache miss because of scaled size not found. - const ScaledImageFragment* scaledImage = m_generator->decodeAndScale(scaledSize()); - EXPECT_NE(fullImage, scaledImage); - EXPECT_EQ(scaledSize(), scaledImage->scaledSize()); - EXPECT_TRUE(m_generator->hasAlpha(0)); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), scaledImage); - - // Cache hit. - const ScaledImageFragment* tempImage = m_generator->decodeAndScale(scaledSize()); - EXPECT_EQ(scaledImage, tempImage); - EXPECT_EQ(scaledSize(), tempImage->scaledSize()); - EXPECT_TRUE(m_generator->hasAlpha(0)); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); - EXPECT_EQ(0, m_frameBufferRequestCount); -} - -TEST_F(ImageFrameGeneratorTest, cacheMissWithDecodeAndScale) -{ - setFrameStatus(ImageFrame::FrameComplete); - - // Cache miss. - const ScaledImageFragment* scaledImage = m_generator->decodeAndScale(scaledSize()); - EXPECT_EQ(1, m_frameBufferRequestCount); - EXPECT_EQ(scaledSize(), scaledImage->scaledSize()); - EXPECT_FALSE(m_generator->hasAlpha(0)); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), scaledImage); - EXPECT_EQ(1, m_decodersDestroyed); - - // Cache hit. - const ScaledImageFragment* fullImage = m_generator->decodeAndScale(fullSize()); - EXPECT_NE(scaledImage, fullImage); - EXPECT_EQ(fullSize(), fullImage->scaledSize()); - EXPECT_FALSE(m_generator->hasAlpha(0)); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), fullImage); - - // Cache hit. - const ScaledImageFragment* tempImage = m_generator->decodeAndScale(scaledSize()); - EXPECT_EQ(scaledImage, tempImage); - EXPECT_EQ(scaledSize(), tempImage->scaledSize()); - EXPECT_FALSE(m_generator->hasAlpha(0)); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); - EXPECT_EQ(1, m_frameBufferRequestCount); -} - TEST_F(ImageFrameGeneratorTest, cacheMissWithIncompleteDecode) { setFrameStatus(ImageFrame::FramePartial); - const ScaledImageFragment* tempImage= m_generator->decodeAndScale(fullSize()); + const ScaledImageFragment* tempImage = m_generator->decodeAndScale(fullSize()); EXPECT_FALSE(tempImage->isComplete()); EXPECT_EQ(1, m_frameBufferRequestCount); ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); @@ -216,29 +168,6 @@ TEST_F(ImageFrameGeneratorTest, cacheMissWithIncompleteDecode) EXPECT_EQ(0, m_decodersDestroyed); } -TEST_F(ImageFrameGeneratorTest, cacheMissWithIncompleteDecodeAndScale) -{ - setFrameStatus(ImageFrame::FramePartial); - - const ScaledImageFragment* tempImage= m_generator->decodeAndScale(scaledSize()); - EXPECT_FALSE(tempImage->isComplete()); - EXPECT_EQ(1, m_frameBufferRequestCount); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); - EXPECT_EQ(3, ImageDecodingStore::instance()->cacheEntries()); - EXPECT_EQ(2, ImageDecodingStore::instance()->imageCacheEntries()); - EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); - - addNewData(); - tempImage = m_generator->decodeAndScale(scaledSize()); - EXPECT_FALSE(tempImage->isComplete()); - EXPECT_EQ(2, m_frameBufferRequestCount); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); - EXPECT_EQ(5, ImageDecodingStore::instance()->cacheEntries()); - EXPECT_EQ(4, ImageDecodingStore::instance()->imageCacheEntries()); - EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); - EXPECT_EQ(0, m_decodersDestroyed); -} - TEST_F(ImageFrameGeneratorTest, incompleteDecodeBecomesComplete) { setFrameStatus(ImageFrame::FramePartial); @@ -270,42 +199,6 @@ TEST_F(ImageFrameGeneratorTest, incompleteDecodeBecomesComplete) ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); } -TEST_F(ImageFrameGeneratorTest, incompleteDecodeAndScaleBecomesComplete) -{ - setFrameStatus(ImageFrame::FramePartial); - - const ScaledImageFragment* tempImage = m_generator->decodeAndScale(scaledSize()); - EXPECT_FALSE(tempImage->isComplete()); - EXPECT_EQ(1, m_frameBufferRequestCount); - EXPECT_EQ(0, m_decodersDestroyed); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); - EXPECT_EQ(3, ImageDecodingStore::instance()->cacheEntries()); - EXPECT_EQ(2, ImageDecodingStore::instance()->imageCacheEntries()); - EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); - - setFrameStatus(ImageFrame::FrameComplete); - addNewData(); - - tempImage = m_generator->decodeAndScale(scaledSize()); - EXPECT_TRUE(tempImage->isComplete()); - EXPECT_EQ(2, m_frameBufferRequestCount); - EXPECT_EQ(1, m_decodersDestroyed); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); - EXPECT_EQ(4, ImageDecodingStore::instance()->cacheEntries()); - EXPECT_EQ(4, ImageDecodingStore::instance()->imageCacheEntries()); - EXPECT_EQ(0, ImageDecodingStore::instance()->decoderCacheEntries()); - - tempImage = m_generator->decodeAndScale(scaledSize()); - EXPECT_TRUE(tempImage->isComplete()); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); - - tempImage = m_generator->decodeAndScale(fullSize()); - EXPECT_TRUE(tempImage->isComplete()); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); - - EXPECT_EQ(2, m_frameBufferRequestCount); -} - static void decodeThreadMain(ImageFrameGenerator* generator) { const ScaledImageFragment* tempImage = generator->decodeAndScale(fullSize()); @@ -325,7 +218,7 @@ TEST_F(ImageFrameGeneratorTest, incompleteDecodeBecomesCompleteMultiThreaded) EXPECT_EQ(1, ImageDecodingStore::instance()->imageCacheEntries()); EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); - // Frame can now be decoded completely. + // LocalFrame can now be decoded completely. setFrameStatus(ImageFrame::FrameComplete); addNewData(); OwnPtr<blink::WebThread> thread = adoptPtr(blink::Platform::current()->createThread("DecodeThread")); @@ -344,34 +237,6 @@ TEST_F(ImageFrameGeneratorTest, incompleteDecodeBecomesCompleteMultiThreaded) ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); } -TEST_F(ImageFrameGeneratorTest, concurrentIncompleteDecodeAndScale) -{ - setFrameStatus(ImageFrame::FramePartial); - - const ScaledImageFragment* fullImage = m_generator->decodeAndScale(fullSize()); - const ScaledImageFragment* scaledImage = m_generator->decodeAndScale(scaledSize()); - EXPECT_FALSE(fullImage->isComplete()); - EXPECT_FALSE(scaledImage->isComplete()); - EXPECT_EQ(2, m_frameBufferRequestCount); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), fullImage); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), scaledImage); - EXPECT_EQ(4, ImageDecodingStore::instance()->cacheEntries()); - EXPECT_EQ(3, ImageDecodingStore::instance()->imageCacheEntries()); - EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); - EXPECT_EQ(0, m_decodersDestroyed); - - addNewData(); - setFrameStatus(ImageFrame::FrameComplete); - scaledImage = m_generator->decodeAndScale(scaledSize()); - EXPECT_TRUE(scaledImage->isComplete()); - EXPECT_EQ(3, m_frameBufferRequestCount); - ImageDecodingStore::instance()->unlockCache(m_generator.get(), scaledImage); - EXPECT_EQ(5, ImageDecodingStore::instance()->cacheEntries()); - EXPECT_EQ(5, ImageDecodingStore::instance()->imageCacheEntries()); - EXPECT_EQ(0, ImageDecodingStore::instance()->decoderCacheEntries()); - EXPECT_EQ(1, m_decodersDestroyed); -} - TEST_F(ImageFrameGeneratorTest, incompleteBitmapCopied) { setFrameStatus(ImageFrame::FramePartial); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ImageLayerChromiumTest.cpp b/chromium/third_party/WebKit/Source/platform/graphics/ImageLayerChromiumTest.cpp new file mode 100644 index 00000000000..0ae7d518523 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageLayerChromiumTest.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "platform/graphics/Image.h" + +#include "platform/graphics/GraphicsLayer.h" +#include "platform/graphics/skia/NativeImageSkia.h" +#include "public/platform/WebImageLayer.h" +#include "wtf/PassOwnPtr.h" + +#include <gtest/gtest.h> + +using namespace WebCore; + +namespace { + +class MockGraphicsLayerClient : public GraphicsLayerClient { +public: + virtual void notifyAnimationStarted(const GraphicsLayer*, double monotonicTime) OVERRIDE { } + virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) OVERRIDE { } + virtual String debugName(const GraphicsLayer*) OVERRIDE { return String(); } +}; + +class TestImage : public Image { +public: + + static PassRefPtr<TestImage> create(const IntSize& size, bool isOpaque) + { + return adoptRef(new TestImage(size, isOpaque)); + } + + explicit TestImage(const IntSize& size, bool isOpaque) + : Image(0) + , m_size(size) + { + SkBitmap bitmap; + EXPECT_TRUE(bitmap.allocN32Pixels(size.width(), size.height(), isOpaque)); + m_nativeImage = NativeImageSkia::create(bitmap); + } + + virtual bool isBitmapImage() const OVERRIDE + { + return true; + } + + virtual bool currentFrameKnownToBeOpaque() OVERRIDE + { + return m_nativeImage->bitmap().isOpaque(); + } + + virtual IntSize size() const OVERRIDE + { + return m_size; + } + + virtual PassRefPtr<NativeImageSkia> nativeImageForCurrentFrame() OVERRIDE + { + if (m_size.isZero()) + return nullptr; + + return m_nativeImage; + } + + // Stub implementations of pure virtual Image functions. + virtual void destroyDecodedData(bool) OVERRIDE + { + } + + virtual void draw(GraphicsContext*, const FloatRect&, const FloatRect&, CompositeOperator, blink::WebBlendMode) OVERRIDE + { + } + +private: + + IntSize m_size; + + RefPtr<NativeImageSkia> m_nativeImage; +}; + +class GraphicsLayerForTesting : public GraphicsLayer { +public: + explicit GraphicsLayerForTesting(GraphicsLayerClient* client) + : GraphicsLayer(client) { }; + + virtual blink::WebLayer* contentsLayer() const { return GraphicsLayer::contentsLayer(); } +}; + +TEST(ImageLayerChromiumTest, opaqueImages) +{ + MockGraphicsLayerClient client; + OwnPtr<GraphicsLayerForTesting> graphicsLayer = adoptPtr(new GraphicsLayerForTesting(&client)); + ASSERT_TRUE(graphicsLayer.get()); + + RefPtr<Image> opaqueImage = TestImage::create(IntSize(100, 100), true /* opaque */); + ASSERT_TRUE(opaqueImage.get()); + RefPtr<Image> nonOpaqueImage = TestImage::create(IntSize(100, 100), false /* opaque */); + ASSERT_TRUE(nonOpaqueImage.get()); + + ASSERT_FALSE(graphicsLayer->contentsLayer()); + + graphicsLayer->setContentsToImage(opaqueImage.get()); + ASSERT_TRUE(graphicsLayer->contentsLayer()->opaque()); + + graphicsLayer->setContentsToImage(nonOpaqueImage.get()); + ASSERT_FALSE(graphicsLayer->contentsLayer()->opaque()); +} + +} // namespace diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ImageSource.cpp b/chromium/third_party/WebKit/Source/platform/graphics/ImageSource.cpp index dee22c39154..68ce34edfc3 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/ImageSource.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageSource.cpp @@ -55,14 +55,14 @@ bool ImageSource::initialized() const return m_decoder; } -void ImageSource::setData(SharedBuffer* data, bool allDataReceived) +void ImageSource::setData(SharedBuffer& data, bool allDataReceived) { // Make the decoder by sniffing the bytes. // This method will examine the data and instantiate an instance of the appropriate decoder plugin. // If insufficient bytes are available to determine the image type, no decoder plugin will be // made. if (!m_decoder) - m_decoder = DeferredImageDecoder::create(*data, m_alphaOption, m_gammaAndColorProfileOption); + m_decoder = DeferredImageDecoder::create(data, m_alphaOption, m_gammaAndColorProfileOption); if (m_decoder) m_decoder->setData(data, allDataReceived); @@ -78,6 +78,11 @@ bool ImageSource::isSizeAvailable() return m_decoder && m_decoder->isSizeAvailable(); } +bool ImageSource::hasColorProfile() const +{ + return m_decoder && m_decoder->hasColorProfile(); +} + IntSize ImageSource::size(RespectImageOrientationEnum shouldRespectOrientation) const { return frameSizeAtIndex(0, shouldRespectOrientation); @@ -113,16 +118,16 @@ size_t ImageSource::frameCount() const PassRefPtr<NativeImageSkia> ImageSource::createFrameAtIndex(size_t index) { if (!m_decoder) - return 0; + return nullptr; ImageFrame* buffer = m_decoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == ImageFrame::FrameEmpty) - return 0; + return nullptr; // Zero-height images can cause problems for some ports. If we have an // empty image dimension, just bail. if (size().isEmpty()) - return 0; + return nullptr; // Return the buffer contents as a native image. For some ports, the data // is already in a native container, and this just increments its refcount. diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ImageSource.h b/chromium/third_party/WebKit/Source/platform/graphics/ImageSource.h index bf84e295c04..e599781c08b 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/ImageSource.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/ImageSource.h @@ -42,8 +42,8 @@ class IntSize; class NativeImageSkia; class SharedBuffer; -// Right now GIFs are the only recognized image format that supports animation. -// The animation system and the constants below are designed with this in mind. +// GIF and WebP support animation. The explanation below is in terms of GIF, +// but the same constants are used for WebP, too. // GIFs have an optional 16-bit unsigned loop count that describes how an // animated GIF should be cycled. If the loop count is absent, the animation // cycles once; if it is 0, the animation cycles infinitely; otherwise the @@ -98,15 +98,19 @@ public: bool initialized() const; - void setData(SharedBuffer* data, bool allDataReceived); + void setData(SharedBuffer& data, bool allDataReceived); String filenameExtension() const; bool isSizeAvailable(); + bool hasColorProfile() const; IntSize size(RespectImageOrientationEnum = DoNotRespectImageOrientation) const; IntSize frameSizeAtIndex(size_t, RespectImageOrientationEnum = DoNotRespectImageOrientation) const; bool getHotSpot(IntPoint&) const; + // Returns one of the cAnimationXXX constants at the top of the file, or + // a loop count. In the latter case, the actual number of times the animation + // cycles is one more than the loop count. See comment atop the file. int repetitionCount(); size_t frameCount() const; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/LazyDecodingPixelRef.cpp b/chromium/third_party/WebKit/Source/platform/graphics/LazyDecodingPixelRef.cpp index 26115ee88df..af3f781f4e3 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/LazyDecodingPixelRef.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/LazyDecodingPixelRef.cpp @@ -50,7 +50,7 @@ SkData* LazyDecodingPixelRef::onRefEncodedData() { // If the image has been clipped or scaled, do not return the original encoded data, since // on playback it will not be known how the clipping/scaling was done. - RefPtr<SharedBuffer> buffer = 0; + RefPtr<SharedBuffer> buffer = nullptr; bool allDataReceived = false; m_frameGenerator->copyData(&buffer, &allDataReceived); if (buffer && allDataReceived) { @@ -60,9 +60,9 @@ SkData* LazyDecodingPixelRef::onRefEncodedData() return 0; } -void* LazyDecodingPixelRef::onLockPixels(SkColorTable**) +bool LazyDecodingPixelRef::onNewLockPixels(LockRec* rec) { - TRACE_EVENT_ASYNC_BEGIN0("webkit", "LazyDecodingPixelRef::lockPixels", this); + TRACE_EVENT_ASYNC_BEGIN0("webkit", "LazyDecodingPixelRef::onNewLockPixels", this); ASSERT(!m_lockedImageResource); @@ -75,14 +75,17 @@ void* LazyDecodingPixelRef::onLockPixels(SkColorTable**) if (!m_lockedImageResource) { PlatformInstrumentation::willDecodeLazyPixelRef(getGenerationID()); m_lockedImageResource = m_frameGenerator->decodeAndScale(size, m_frameIndex); - PlatformInstrumentation::didDecodeLazyPixelRef(getGenerationID()); + PlatformInstrumentation::didDecodeLazyPixelRef(); } if (!m_lockedImageResource) - return 0; + return false; ASSERT(!m_lockedImageResource->bitmap().isNull()); ASSERT(m_lockedImageResource->scaledSize() == size); - return m_lockedImageResource->bitmap().getAddr(0, 0); + rec->fPixels = m_lockedImageResource->bitmap().getAddr(0, 0); + rec->fColorTable = 0; + rec->fRowBytes = m_lockedImageResource->bitmap().rowBytes(); + return true; } void LazyDecodingPixelRef::onUnlockPixels() diff --git a/chromium/third_party/WebKit/Source/platform/graphics/LazyDecodingPixelRef.h b/chromium/third_party/WebKit/Source/platform/graphics/LazyDecodingPixelRef.h index c1a137e9725..80ceeaf8153 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/LazyDecodingPixelRef.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/LazyDecodingPixelRef.h @@ -45,7 +45,7 @@ namespace WebCore { class ImageFrameGenerator; class ScaledImageFragment; -class LazyDecodingPixelRef : public LazyPixelRef { +class LazyDecodingPixelRef FINAL : public LazyPixelRef { public: LazyDecodingPixelRef(const SkImageInfo&, PassRefPtr<ImageFrameGenerator>, size_t index); virtual ~LazyDecodingPixelRef(); @@ -57,17 +57,17 @@ public: // Returns true if the image might already be decoded in the cache. // Optimistic version of PrepareToDecode; requires less locking. - virtual bool MaybeDecoded(); - virtual bool PrepareToDecode(const LazyPixelRef::PrepareParams&); - virtual void Decode(); + virtual bool MaybeDecoded() OVERRIDE; + virtual bool PrepareToDecode(const LazyPixelRef::PrepareParams&) OVERRIDE; + virtual void Decode() OVERRIDE; protected: // SkPixelRef implementation. - virtual void* onLockPixels(SkColorTable**); - virtual void onUnlockPixels(); - virtual bool onLockPixelsAreWritable() const; + virtual bool onNewLockPixels(LockRec*) OVERRIDE; + virtual void onUnlockPixels() OVERRIDE; + virtual bool onLockPixelsAreWritable() const OVERRIDE; - virtual SkData* onRefEncodedData() SK_OVERRIDE; + virtual SkData* onRefEncodedData() OVERRIDE; private: RefPtr<ImageFrameGenerator> m_frameGenerator; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/OpaqueRectTrackingContentLayerDelegate.cpp b/chromium/third_party/WebKit/Source/platform/graphics/OpaqueRectTrackingContentLayerDelegate.cpp index 174970257a1..9b2266822ac 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/OpaqueRectTrackingContentLayerDelegate.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/OpaqueRectTrackingContentLayerDelegate.cpp @@ -48,13 +48,16 @@ OpaqueRectTrackingContentLayerDelegate::~OpaqueRectTrackingContentLayerDelegate( { } -void OpaqueRectTrackingContentLayerDelegate::paintContents(SkCanvas* canvas, const WebRect& clip, bool canPaintLCDText, WebFloatRect& opaque) +void OpaqueRectTrackingContentLayerDelegate::paintContents( + SkCanvas* canvas, const WebRect& clip, bool canPaintLCDText, WebFloatRect& opaque, + blink::WebContentLayerClient::GraphicsContextStatus contextStatus) { static const unsigned char* annotationsEnabled = 0; if (UNLIKELY(!annotationsEnabled)) annotationsEnabled = EventTracer::getTraceCategoryEnabledFlag(TRACE_DISABLED_BY_DEFAULT("blink.graphics_context_annotations")); - GraphicsContext context(canvas); + GraphicsContext context(canvas, + contextStatus == blink::WebContentLayerClient::GraphicsContextEnabled ? GraphicsContext::NothingDisabled : GraphicsContext::FullyDisabled); context.setTrackOpaqueRegion(!m_opaque); context.setCertainlyOpaque(m_opaque); context.setShouldSmoothFonts(canPaintLCDText); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/OpaqueRectTrackingContentLayerDelegate.h b/chromium/third_party/WebKit/Source/platform/graphics/OpaqueRectTrackingContentLayerDelegate.h index e870b9cf92d..02f1d60b73c 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/OpaqueRectTrackingContentLayerDelegate.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/OpaqueRectTrackingContentLayerDelegate.h @@ -56,7 +56,8 @@ public: void setOpaque(bool opaque) { m_opaque = opaque; } // blink::WebContentLayerClient implementation. - virtual void paintContents(SkCanvas*, const blink::WebRect& clip, bool canPaintLCDText, blink::WebFloatRect& opaque) OVERRIDE; + virtual void paintContents(SkCanvas*, const blink::WebRect& clip, bool canPaintLCDText, blink::WebFloatRect& opaque, + blink::WebContentLayerClient::GraphicsContextStatus = GraphicsContextEnabled) OVERRIDE; private: GraphicsContextPainter* m_painter; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/OpaqueRectTrackingContentLayerDelegateTest.cpp b/chromium/third_party/WebKit/Source/platform/graphics/OpaqueRectTrackingContentLayerDelegateTest.cpp new file mode 100644 index 00000000000..40e7ced5cbb --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/OpaqueRectTrackingContentLayerDelegateTest.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "platform/graphics/OpaqueRectTrackingContentLayerDelegate.h" + +#include "platform/geometry/IntRect.h" +#include "platform/graphics/Color.h" +#include "platform/graphics/GraphicsContext.h" +#include "public/platform/WebFloatRect.h" +#include "public/platform/WebRect.h" +#include "skia/ext/platform_canvas.h" + +#include <gtest/gtest.h> + +using blink::WebRect; +using blink::WebFloatRect; +using namespace WebCore; + +namespace { + +struct PaintCallback { + virtual void operator()(GraphicsContext&, const IntRect&) = 0; +}; + +class TestLayerPainterChromium : public GraphicsContextPainter { +public: + TestLayerPainterChromium(PaintCallback& callback) : m_callback(callback) { } + + virtual void paint(GraphicsContext& context, const IntRect& contentRect) OVERRIDE + { + m_callback(context, contentRect); + } + +private: + PaintCallback& m_callback; +}; + +// Paint callback functions + +struct PaintFillOpaque : public PaintCallback { + virtual void operator()(GraphicsContext& context, const IntRect& contentRect) OVERRIDE + { + Color opaque(255, 0, 0, 255); + IntRect top(contentRect.x(), contentRect.y(), contentRect.width(), contentRect.height() / 2); + IntRect bottom(contentRect.x(), contentRect.y() + contentRect.height() / 2, contentRect.width(), contentRect.height() / 2); + context.fillRect(top, opaque); + context.fillRect(bottom, opaque); + } +}; + +struct PaintFillAlpha : public PaintCallback { + virtual void operator()(GraphicsContext& context, const IntRect& contentRect) + { + Color alpha(0, 0, 0, 0); + context.fillRect(contentRect, alpha); + } +}; + +struct PaintFillPartialOpaque : public PaintCallback { + PaintFillPartialOpaque(IntRect opaqueRect) + : m_opaqueRect(opaqueRect) + { + } + + virtual void operator()(GraphicsContext& context, const IntRect& contentRect) + { + Color alpha(0, 0, 0, 0); + context.fillRect(contentRect, alpha); + + IntRect fillOpaque = m_opaqueRect; + fillOpaque.intersect(contentRect); + + Color opaque(255, 255, 255, 255); + context.fillRect(fillOpaque, opaque); + } + + IntRect m_opaqueRect; +}; + +#define EXPECT_EQ_RECT(a, b) \ + EXPECT_EQ(a.x, b.x); \ + EXPECT_EQ(a.width, b.width); \ + EXPECT_EQ(a.y, b.y); \ + EXPECT_EQ(a.height, b.height); + +class OpaqueRectTrackingContentLayerDelegateTest : public testing::Test { +public: + OpaqueRectTrackingContentLayerDelegateTest() + : m_skCanvas(adoptPtr(skia::CreateBitmapCanvas(canvasRect().width, canvasRect().height, false))) + { + } + + SkCanvas* skCanvas() { return m_skCanvas.get(); } + WebRect canvasRect() { return WebRect(0, 0, 400, 400); } + +private: + OwnPtr<SkCanvas> m_skCanvas; +}; + +TEST_F(OpaqueRectTrackingContentLayerDelegateTest, testOpaqueRectPresentAfterOpaquePaint) +{ + PaintFillOpaque fillOpaque; + TestLayerPainterChromium painter(fillOpaque); + + OpaqueRectTrackingContentLayerDelegate delegate(&painter); + + WebFloatRect opaqueRect; + delegate.paintContents(skCanvas(), canvasRect(), false, opaqueRect); + EXPECT_EQ_RECT(WebFloatRect(0, 0, 400, 400), opaqueRect); +} + +TEST_F(OpaqueRectTrackingContentLayerDelegateTest, testOpaqueRectNotPresentAfterNonOpaquePaint) +{ + PaintFillAlpha fillAlpha; + TestLayerPainterChromium painter(fillAlpha); + OpaqueRectTrackingContentLayerDelegate delegate(&painter); + + WebFloatRect opaqueRect; + delegate.paintContents(skCanvas(), canvasRect(), false, opaqueRect); + EXPECT_EQ_RECT(WebFloatRect(0, 0, 0, 0), opaqueRect); +} + +TEST_F(OpaqueRectTrackingContentLayerDelegateTest, testOpaqueRectNotPresentForOpaqueLayerWithOpaquePaint) +{ + PaintFillOpaque fillOpaque; + TestLayerPainterChromium painter(fillOpaque); + OpaqueRectTrackingContentLayerDelegate delegate(&painter); + + delegate.setOpaque(true); + + WebFloatRect opaqueRect; + delegate.paintContents(skCanvas(), canvasRect(), false, opaqueRect); + EXPECT_EQ_RECT(WebFloatRect(0, 0, 0, 0), opaqueRect); +} + +TEST_F(OpaqueRectTrackingContentLayerDelegateTest, testOpaqueRectNotPresentForOpaqueLayerWithNonOpaquePaint) +{ + PaintFillOpaque fillAlpha; + TestLayerPainterChromium painter(fillAlpha); + OpaqueRectTrackingContentLayerDelegate delegate(&painter); + + delegate.setOpaque(true); + + WebFloatRect opaqueRect; + delegate.paintContents(skCanvas(), canvasRect(), false, opaqueRect); + EXPECT_EQ_RECT(WebFloatRect(0, 0, 0, 0), opaqueRect); +} + +TEST_F(OpaqueRectTrackingContentLayerDelegateTest, testPartialOpaqueRectNoTransform) +{ + IntRect partialRect(100, 200, 50, 75); + PaintFillPartialOpaque fillPartial(partialRect); + TestLayerPainterChromium painter(fillPartial); + OpaqueRectTrackingContentLayerDelegate delegate(&painter); + + WebFloatRect opaqueRect; + delegate.paintContents(skCanvas(), canvasRect(), false, opaqueRect); + EXPECT_EQ_RECT(WebFloatRect(partialRect.x(), partialRect.y(), partialRect.width(), partialRect.height()), opaqueRect); +} + +TEST_F(OpaqueRectTrackingContentLayerDelegateTest, testPartialOpaqueRectTranslation) +{ + IntRect partialRect(100, 200, 50, 75); + PaintFillPartialOpaque fillPartial(partialRect); + TestLayerPainterChromium painter(fillPartial); + OpaqueRectTrackingContentLayerDelegate delegate(&painter); + + WebFloatRect opaqueRect; + WebRect contentRect(11, 12, 389, 388); + delegate.paintContents(skCanvas(), contentRect, false, opaqueRect); + EXPECT_EQ_RECT(WebFloatRect(partialRect.x(), partialRect.y(), partialRect.width(), partialRect.height()), opaqueRect); +} + +} // namespace diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Path.cpp b/chromium/third_party/WebKit/Source/platform/graphics/Path.cpp index e04f4a8ea7b..44c455e4e2a 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/Path.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/Path.cpp @@ -36,7 +36,6 @@ #include "platform/graphics/GraphicsContext.h" #include "platform/graphics/skia/SkiaUtils.h" #include "platform/transforms/AffineTransform.h" -#include "third_party/skia/include/core/SkPathMeasure.h" #include "third_party/skia/include/pathops/SkPathOps.h" #include "wtf/MathExtras.h" @@ -177,10 +176,8 @@ float Path::normalAngleAtLength(float length, bool& ok) const return normal; } -bool Path::pointAndNormalAtLength(float length, FloatPoint& point, float& normal) const +static bool calculatePointAndNormalOnPath(SkPathMeasure& measure, SkScalar length, FloatPoint& point, float& normalAngle, SkScalar* accumulatedLength = 0) { - SkPathMeasure measure(m_path, false); - do { SkScalar contourLength = measure.getLength(); if (length <= contourLength) { @@ -188,19 +185,58 @@ bool Path::pointAndNormalAtLength(float length, FloatPoint& point, float& normal SkPoint position; if (measure.getPosTan(length, &position, &tangent)) { - normal = rad2deg(SkScalarToFloat(SkScalarATan2(tangent.fY, tangent.fX))); + normalAngle = rad2deg(SkScalarToFloat(SkScalarATan2(tangent.fY, tangent.fX))); point = FloatPoint(SkScalarToFloat(position.fX), SkScalarToFloat(position.fY)); return true; } } length -= contourLength; + if (accumulatedLength) + *accumulatedLength += contourLength; } while (measure.nextContour()); + return false; +} + +bool Path::pointAndNormalAtLength(float length, FloatPoint& point, float& normal) const +{ + SkPathMeasure measure(m_path, false); + + if (calculatePointAndNormalOnPath(measure, WebCoreFloatToSkScalar(length), point, normal)) + return true; normal = 0; point = FloatPoint(0, 0); return false; } +Path::PositionCalculator::PositionCalculator(const Path& path) + : m_path(path.skPath()) + , m_pathMeasure(path.skPath(), false) + , m_accumulatedLength(0) +{ +} + +bool Path::PositionCalculator::pointAndNormalAtLength(float length, FloatPoint& point, float& normalAngle) +{ + SkScalar skLength = WebCoreFloatToSkScalar(length); + if (skLength >= 0) { + if (skLength < m_accumulatedLength) { + // Reset path measurer to rewind (and restart from 0). + m_pathMeasure.setPath(&m_path, false); + m_accumulatedLength = 0; + } else { + skLength -= m_accumulatedLength; + } + + if (calculatePointAndNormalOnPath(m_pathMeasure, skLength, point, normalAngle, &m_accumulatedLength)) + return true; + } + + normalAngle = 0; + point = FloatPoint(0, 0); + return false; +} + void Path::clear() { m_path.reset(); @@ -248,27 +284,27 @@ void Path::setWindRule(const WindRule rule) void Path::moveTo(const FloatPoint& point) { - m_path.moveTo(point); + m_path.moveTo(point.data()); } void Path::addLineTo(const FloatPoint& point) { - m_path.lineTo(point); + m_path.lineTo(point.data()); } void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& ep) { - m_path.quadTo(cp, ep); + m_path.quadTo(cp.data(), ep.data()); } void Path::addBezierCurveTo(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& ep) { - m_path.cubicTo(p1, p2, ep); + m_path.cubicTo(p1.data(), p2.data(), ep.data()); } void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) { - m_path.arcTo(p1, p2, WebCoreFloatToSkScalar(radius)); + m_path.arcTo(p1.data(), p2.data(), WebCoreFloatToSkScalar(radius)); } void Path::closeSubpath() @@ -279,7 +315,7 @@ void Path::closeSubpath() void Path::addEllipse(const FloatPoint& p, float radiusX, float radiusY, float startAngle, float endAngle, bool anticlockwise) { ASSERT(ellipseIsRenderable(startAngle, endAngle)); - ASSERT(startAngle >= 0 && startAngle < 2 * piFloat); + ASSERT(startAngle >= 0 && startAngle < twoPiFloat); ASSERT((anticlockwise && (startAngle - endAngle) >= 0) || (!anticlockwise && (endAngle - startAngle) >= 0)); SkScalar cx = WebCoreFloatToSkScalar(p.x()); @@ -327,7 +363,7 @@ void Path::addRect(const FloatRect& rect) void Path::addEllipse(const FloatPoint& p, float radiusX, float radiusY, float rotation, float startAngle, float endAngle, bool anticlockwise) { ASSERT(ellipseIsRenderable(startAngle, endAngle)); - ASSERT(startAngle >= 0 && startAngle < 2 * piFloat); + ASSERT(startAngle >= 0 && startAngle < twoPiFloat); ASSERT((anticlockwise && (startAngle - endAngle) >= 0) || (!anticlockwise && (endAngle - startAngle) >= 0)); if (!rotation) { @@ -336,7 +372,7 @@ void Path::addEllipse(const FloatPoint& p, float radiusX, float radiusY, float r } // Add an arc after the relevant transform. - AffineTransform ellipseTransform = AffineTransform::translation(p.x(), p.y()).rotate(rad2deg(rotation)); + AffineTransform ellipseTransform = AffineTransform::translation(p.x(), p.y()).rotateRadians(rotation); ASSERT(ellipseTransform.isInvertible()); AffineTransform inverseEllipseTransform = ellipseTransform.inverse(); transform(inverseEllipseTransform); @@ -436,6 +472,11 @@ void Path::addBeziersForRoundedRect(const FloatRect& rect, const FloatSize& topL closeSubpath(); } +void Path::addPath(const Path& src, const AffineTransform& transform) +{ + m_path.addPath(src.skPath(), affineTransformToSkMatrix(transform)); +} + void Path::translate(const FloatSize& size) { m_path.offset(WebCoreFloatToSkScalar(size.width()), WebCoreFloatToSkScalar(size.height())); @@ -446,11 +487,11 @@ bool Path::unionPath(const Path& other) return Op(m_path, other.m_path, kUnion_PathOp, &m_path); } -#if !ASSERT_DISABLED +#if ASSERT_ENABLED bool ellipseIsRenderable(float startAngle, float endAngle) { - return (std::abs(endAngle - startAngle) < 2 * piFloat) - || WebCoreFloatNearlyEqual(std::abs(endAngle - startAngle), 2 * piFloat); + return (std::abs(endAngle - startAngle) < twoPiFloat) + || WebCoreFloatNearlyEqual(std::abs(endAngle - startAngle), twoPiFloat); } #endif diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Path.h b/chromium/third_party/WebKit/Source/platform/graphics/Path.h index 1970b97d500..f6bdd439bb5 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/Path.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/Path.h @@ -33,6 +33,7 @@ #include "platform/geometry/RoundedRect.h" #include "platform/graphics/WindRule.h" #include "third_party/skia/include/core/SkPath.h" +#include "third_party/skia/include/core/SkPathMeasure.h" #include "wtf/FastAllocBase.h" #include "wtf/Forward.h" @@ -85,6 +86,25 @@ public: float normalAngleAtLength(float length, bool& ok) const; bool pointAndNormalAtLength(float length, FloatPoint&, float&) const; + // Helper for computing a sequence of positions and normals (normal angles) on a path. + // The best possible access pattern will be one where the |length| value is + // strictly increasing. + // For other access patterns, performance will vary depending on curvature + // and number of segments, but should never be worse than that of the + // state-less method on Path. + class PLATFORM_EXPORT PositionCalculator { + WTF_MAKE_NONCOPYABLE(PositionCalculator); + public: + explicit PositionCalculator(const Path&); + + bool pointAndNormalAtLength(float length, FloatPoint&, float&); + + private: + SkPath m_path; + SkPathMeasure m_pathMeasure; + SkScalar m_accumulatedLength; + }; + void clear(); bool isEmpty() const; // Gets the current point of the current path, which is conceptually the final point reached by the path so far. @@ -111,6 +131,8 @@ public: void addRoundedRect(const FloatRect&, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius); void addRoundedRect(const RoundedRect&); + void addPath(const Path&, const AffineTransform&); + void translate(const FloatSize&); const SkPath& skPath() const { return m_path; } @@ -130,7 +152,7 @@ private: SkPath m_path; }; -#if !ASSERT_DISABLED +#if ASSERT_ENABLED PLATFORM_EXPORT bool ellipseIsRenderable(float startAngle, float endAngle); #endif diff --git a/chromium/third_party/WebKit/Source/platform/graphics/PathTraversalState.cpp b/chromium/third_party/WebKit/Source/platform/graphics/PathTraversalState.cpp index 406c5b180cd..862ae8686e0 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/PathTraversalState.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/PathTraversalState.cpp @@ -25,8 +25,6 @@ namespace WebCore { -static const float kPathSegmentLengthTolerance = 0.00001f; - static inline FloatPoint midPoint(const FloatPoint& first, const FloatPoint& second) { return FloatPoint((first.x() + second.x()) / 2.0f, (first.y() + second.y()) / 2.0f); @@ -43,7 +41,13 @@ struct QuadraticBezier { : start(s) , control(c) , end(e) + , splitDepth(0) + { + } + + double magnitudeSquared() const { + return ((double)(start.dot(start)) + (double)(control.dot(control)) + (double)(end.dot(end))) / 9.0; } float approximateDistance() const @@ -62,11 +66,14 @@ struct QuadraticBezier { left.start = start; right.end = end; + + left.splitDepth = right.splitDepth = splitDepth + 1; } FloatPoint start; FloatPoint control; FloatPoint end; + unsigned short splitDepth; }; struct CubicBezier { @@ -76,7 +83,13 @@ struct CubicBezier { , control1(c1) , control2(c2) , end(e) + , splitDepth(0) + { + } + + double magnitudeSquared() const { + return ((double)(start.dot(start)) + (double)(control1.dot(control1)) + (double)(control2.dot(control2)) + (double)(end.dot(end))) / 16.0; } float approximateDistance() const @@ -99,24 +112,26 @@ struct CubicBezier { FloatPoint leftControl2ToRightControl1 = midPoint(left.control2, right.control1); left.end = leftControl2ToRightControl1; right.start = leftControl2ToRightControl1; + + left.splitDepth = right.splitDepth = splitDepth + 1; } FloatPoint start; FloatPoint control1; FloatPoint control2; FloatPoint end; + unsigned short splitDepth; }; -// FIXME: This function is possibly very slow due to the ifs required for proper path measuring -// A simple speed-up would be to use an additional boolean template parameter to control whether -// to use the "fast" version of this function with no PathTraversalState updating, vs. the slow -// version which does update the PathTraversalState. We'll have to shark it to see if that's necessary. -// Another check which is possible up-front (to send us down the fast path) would be to check if -// approximateDistance() + current total distance > desired distance template<class CurveType> static float curveLength(PathTraversalState& traversalState, CurveType curve) { - static const unsigned curveStackDepthLimit = 20; + static const unsigned short curveSplitDepthLimit = 20; + static const double pathSegmentLengthToleranceSquared = 1.e-16; + + double curveScaleForToleranceSquared = curve.magnitudeSquared(); + if (curveScaleForToleranceSquared < pathSegmentLengthToleranceSquared) + return 0; Vector<CurveType> curveStack; curveStack.append(curve); @@ -124,7 +139,8 @@ static float curveLength(PathTraversalState& traversalState, CurveType curve) float totalLength = 0; do { float length = curve.approximateDistance(); - if ((length - distanceLine(curve.start, curve.end)) > kPathSegmentLengthTolerance && curveStack.size() <= curveStackDepthLimit) { + double lengthDiscrepancy = length - distanceLine(curve.start, curve.end); + if ((lengthDiscrepancy * lengthDiscrepancy) / curveScaleForToleranceSquared > pathSegmentLengthToleranceSquared && curve.splitDepth < curveSplitDepthLimit) { CurveType leftCurve; CurveType rightCurve; curve.split(leftCurve, rightCurve); @@ -159,20 +175,20 @@ PathTraversalState::PathTraversalState(PathTraversalAction action) float PathTraversalState::closeSubpath() { float distance = distanceLine(m_current, m_start); - m_current = m_control1 = m_control2 = m_start; + m_current = m_start; return distance; } float PathTraversalState::moveTo(const FloatPoint& point) { - m_current = m_start = m_control1 = m_control2 = point; + m_current = m_start = point; return 0; } float PathTraversalState::lineTo(const FloatPoint& point) { float distance = distanceLine(m_current, point); - m_current = m_control1 = m_control2 = point; + m_current = point; return distance; } @@ -180,9 +196,6 @@ float PathTraversalState::quadraticBezierTo(const FloatPoint& newControl, const { float distance = curveLength<QuadraticBezier>(*this, QuadraticBezier(m_current, newControl, newEnd)); - m_control1 = newControl; - m_control2 = newEnd; - if (m_action != TraversalPointAtLength && m_action != TraversalNormalAngleAtLength) m_current = newEnd; @@ -193,9 +206,6 @@ float PathTraversalState::cubicBezierTo(const FloatPoint& newControl1, const Flo { float distance = curveLength<CubicBezier>(*this, CubicBezier(m_current, newControl1, newControl2, newEnd)); - m_control1 = newEnd; - m_control2 = newControl2; - if (m_action != TraversalPointAtLength && m_action != TraversalNormalAngleAtLength) m_current = newEnd; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/PathTraversalState.h b/chromium/third_party/WebKit/Source/platform/graphics/PathTraversalState.h index e2ecbe8d15b..f29dedc07c7 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/PathTraversalState.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/PathTraversalState.h @@ -56,8 +56,6 @@ public: FloatPoint m_current; FloatPoint m_start; - FloatPoint m_control1; - FloatPoint m_control2; float m_totalLength; unsigned m_segmentIndex; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Pattern.cpp b/chromium/third_party/WebKit/Source/platform/graphics/Pattern.cpp index 6e21b821660..3d7c0acf957 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/Pattern.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/Pattern.cpp @@ -57,11 +57,13 @@ SkShader* Pattern::shader() if (m_pattern) return m_pattern.get(); + SkMatrix localMatrix = affineTransformToSkMatrix(m_patternSpaceTransformation); + // If we don't have a bitmap, return a transparent shader. if (!m_tileImage) m_pattern = adoptRef(new SkColorShader(SK_ColorTRANSPARENT)); else if (m_repeatX && m_repeatY) - m_pattern = adoptRef(SkShader::CreateBitmapShader(m_tileImage->bitmap(), SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); + m_pattern = adoptRef(SkShader::CreateBitmapShader(m_tileImage->bitmap(), SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix)); else { // Skia does not have a "draw the tile only once" option. Clamp_TileMode // repeats the last line of the image after drawing one tile. To avoid @@ -76,20 +78,24 @@ SkShader* Pattern::shader() // Create a transparent bitmap 1 pixel wider and/or taller than the // original, then copy the orignal into it. // FIXME: Is there a better way to pad (not scale) an image in skia? + SkImageInfo info = m_tileImage->bitmap().info(); + info.fWidth += expandW; + info.fHeight += expandH; + // we explicitly require non-opaquness, since we are going to add a transparent strip. + info.fAlphaType = kPremul_SkAlphaType; + SkBitmap bm2; - bm2.setConfig(m_tileImage->bitmap().config(), m_tileImage->bitmap().width() + expandW, m_tileImage->bitmap().height() + expandH); - bm2.allocPixels(); + bm2.allocPixels(info); bm2.eraseARGB(0x00, 0x00, 0x00, 0x00); SkCanvas canvas(bm2); canvas.drawBitmap(m_tileImage->bitmap(), 0, 0); bm2.setImmutable(); - m_pattern = adoptRef(SkShader::CreateBitmapShader(bm2, tileModeX, tileModeY)); + m_pattern = adoptRef(SkShader::CreateBitmapShader(bm2, tileModeX, tileModeY, &localMatrix)); // Clamp to int, since that's what the adjust function takes. m_externalMemoryAllocated = static_cast<int>(std::min(static_cast<size_t>(INT_MAX), bm2.getSafeSize())); v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(m_externalMemoryAllocated); } - m_pattern->setLocalMatrix(affineTransformToSkMatrix(m_patternSpaceTransformation)); return m_pattern.get(); } @@ -97,7 +103,7 @@ void Pattern::setPatternSpaceTransform(const AffineTransform& patternSpaceTransf { m_patternSpaceTransformation = patternSpaceTransformation; if (m_pattern) - m_pattern->setLocalMatrix(affineTransformToSkMatrix(m_patternSpaceTransformation)); + m_pattern.clear(); } } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/StrokeData.cpp b/chromium/third_party/WebKit/Source/platform/graphics/StrokeData.cpp index 75fb7ca6314..61b4f87826d 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/StrokeData.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/StrokeData.cpp @@ -54,19 +54,23 @@ void StrokeData::setLineDash(const DashArray& dashes, float dashOffset) for (unsigned i = 0; i < count; i++) intervals[i] = dashes[i % dashLength]; - m_dash = adoptRef(new SkDashPathEffect(intervals.get(), count, dashOffset)); + m_dash = adoptRef(SkDashPathEffect::Create(intervals.get(), count, dashOffset)); } -float StrokeData::setupPaint(SkPaint* paint, int length) const +void StrokeData::setupPaint(SkPaint* paint, int length) const { - float width = m_thickness; - paint->setStyle(SkPaint::kStroke_Style); - paint->setStrokeWidth(SkFloatToScalar(width)); + paint->setStrokeWidth(SkFloatToScalar(m_thickness)); paint->setStrokeCap(m_lineCap); paint->setStrokeJoin(m_lineJoin); paint->setStrokeMiter(SkFloatToScalar(m_miterLimit)); + setupPaintDashPathEffect(paint, length); +} + +void StrokeData::setupPaintDashPathEffect(SkPaint* paint, int length) const +{ + float width = m_thickness; if (m_dash) { paint->setPathEffect(m_dash.get()); } else { @@ -75,7 +79,8 @@ float StrokeData::setupPaint(SkPaint* paint, int length) const case SolidStroke: case DoubleStroke: case WavyStroke: // FIXME: https://code.google.com/p/chromium/issues/detail?id=229574 - break; + paint->setPathEffect(0); + return; case DashedStroke: width = dashRatio * width; // Fall through. @@ -100,12 +105,10 @@ float StrokeData::setupPaint(SkPaint* paint, int length) const } SkScalar dashLengthSk = SkIntToScalar(dashLength); SkScalar intervals[2] = { dashLengthSk, dashLengthSk }; - RefPtr<SkDashPathEffect> pathEffect = adoptRef(new SkDashPathEffect(intervals, 2, SkIntToScalar(phase))); + RefPtr<SkDashPathEffect> pathEffect = adoptRef(SkDashPathEffect::Create(intervals, 2, SkIntToScalar(phase))); paint->setPathEffect(pathEffect.get()); } } - - return width; } } // namespace diff --git a/chromium/third_party/WebKit/Source/platform/graphics/StrokeData.h b/chromium/third_party/WebKit/Source/platform/graphics/StrokeData.h index 177012d5999..2a075a995a3 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/StrokeData.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/StrokeData.h @@ -56,10 +56,10 @@ public: } StrokeStyle style() const { return m_style; } - void setStyle(const StrokeStyle style) { m_style = style; } + void setStyle(StrokeStyle style) { m_style = style; } float thickness() const { return m_thickness; } - void setThickness(const float thickness) { m_thickness = thickness; } + void setThickness(float thickness) { m_thickness = thickness; } Color color() const { return m_color; } void setColor(const Color& color) { m_color = color; } @@ -73,22 +73,26 @@ public: void clearPattern() { m_pattern.clear(); } LineCap lineCap() const { return (LineCap)m_lineCap; } - void setLineCap(const LineCap cap) { m_lineCap = (SkPaint::Cap)cap; } + void setLineCap(LineCap cap) { m_lineCap = (SkPaint::Cap)cap; } LineJoin lineJoin() const { return (LineJoin)m_lineJoin; } - void setLineJoin(const LineJoin join) { m_lineJoin = (SkPaint::Join)join; } + void setLineJoin(LineJoin join) { m_lineJoin = (SkPaint::Join)join; } float miterLimit() const { return m_miterLimit; } - void setMiterLimit(const float miterLimit) { m_miterLimit = miterLimit; } + void setMiterLimit(float miterLimit) { m_miterLimit = miterLimit; } - void setLineDash(const DashArray&, const float); + void setLineDash(const DashArray&, float); // Sets everything on the paint except the pattern, gradient and color. - // GraphicsContext::setupShader does that. Returns a float representing the - // effective width of the pen. If a non-zero length is provided, the - // number of dashes/dots on a dashed/dotted line will be adjusted to - // start and end that length with a dash/dot. - float setupPaint(SkPaint*, int length = 0) const; + // If a non-zero length is provided, the number of dashes/dots on a + // dashed/dotted line will be adjusted to start and end that length with a + // dash/dot. + void setupPaint(SkPaint*, int length = 0) const; + + // Setup any DashPathEffect on the paint. If a non-zero length is provided, + // and no line dash has been set, the number of dashes/dots on a dashed/dotted + // line will be adjusted to start and end that length with a dash/dot. + void setupPaintDashPathEffect(SkPaint*, int) const; private: StrokeStyle m_style; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/ThreadSafeDataTransport.cpp b/chromium/third_party/WebKit/Source/platform/graphics/ThreadSafeDataTransport.cpp index 8b18648b364..a75eba87cd3 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/ThreadSafeDataTransport.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/ThreadSafeDataTransport.cpp @@ -33,6 +33,7 @@ namespace WebCore { ThreadSafeDataTransport::ThreadSafeDataTransport() : m_readBuffer(SharedBuffer::create()) + , m_allDataReceived(false) , m_readPosition(0) { } @@ -53,7 +54,7 @@ void ThreadSafeDataTransport::setData(SharedBuffer* buffer, bool allDataReceived } MutexLocker locker(m_mutex); - m_newBufferQueue.append(newBufferQueue); + m_newBufferQueue.appendVector(newBufferQueue); m_allDataReceived = allDataReceived; } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/UnacceleratedImageBufferSurface.cpp b/chromium/third_party/WebKit/Source/platform/graphics/UnacceleratedImageBufferSurface.cpp index 40812df5e77..50b12726a23 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/UnacceleratedImageBufferSurface.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/UnacceleratedImageBufferSurface.cpp @@ -32,20 +32,16 @@ #include "platform/graphics/UnacceleratedImageBufferSurface.h" #include "third_party/skia/include/core/SkCanvas.h" -#include "wtf/PassOwnPtr.h" +#include "wtf/PassRefPtr.h" namespace WebCore { UnacceleratedImageBufferSurface::UnacceleratedImageBufferSurface(const IntSize& size, OpacityMode opacityMode) : ImageBufferSurface(size, opacityMode) + , m_canvas(adoptRef(SkCanvas::NewRasterN32(size.width(), size.height()))) { - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height()); - bitmap.allocPixels(); - if (bitmap.isNull()) - return; - m_canvas = adoptPtr(new SkCanvas(bitmap)); - clear(); + if (m_canvas) + clear(); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/UnacceleratedImageBufferSurface.h b/chromium/third_party/WebKit/Source/platform/graphics/UnacceleratedImageBufferSurface.h index 5ee66b49f46..407cdcbf311 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/UnacceleratedImageBufferSurface.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/UnacceleratedImageBufferSurface.h @@ -32,7 +32,7 @@ #define UnacceleratedImageBufferSurface_h #include "platform/graphics/ImageBufferSurface.h" -#include "wtf/OwnPtr.h" +#include "wtf/RefPtr.h" namespace WebCore { @@ -46,7 +46,7 @@ public: virtual bool isValid() const OVERRIDE { return m_canvas; } private: - OwnPtr<SkCanvas> m_canvas; + RefPtr<SkCanvas> m_canvas; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/angle/ANGLEPlatformBridge.cpp b/chromium/third_party/WebKit/Source/platform/graphics/angle/ANGLEPlatformBridge.cpp deleted file mode 100644 index c683b2ab88a..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/angle/ANGLEPlatformBridge.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include "platform/graphics/angle/ANGLEPlatformBridge.h" - -#include "wtf/OwnPtr.h" -#include "wtf/PassOwnPtr.h" - -namespace WebCore { - -typedef size_t ANGLEGetInfoType; - -inline static ANGLEGetInfoType getValidationResultValue(const ShHandle compiler, ShShaderInfo shaderInfo) -{ - ANGLEGetInfoType value = 0; - ShGetInfo(compiler, shaderInfo, &value); - return value; -} - -static bool getSymbolInfo(ShHandle compiler, ShShaderInfo symbolType, Vector<ANGLEShaderSymbol>& symbols) -{ - ShShaderInfo symbolMaxNameLengthType; - - switch (symbolType) { - case SH_ACTIVE_ATTRIBUTES: - symbolMaxNameLengthType = SH_ACTIVE_ATTRIBUTE_MAX_LENGTH; - break; - case SH_ACTIVE_UNIFORMS: - symbolMaxNameLengthType = SH_ACTIVE_UNIFORM_MAX_LENGTH; - break; - default: - ASSERT_NOT_REACHED(); - return false; - } - - ANGLEGetInfoType numSymbols = getValidationResultValue(compiler, symbolType); - - ANGLEGetInfoType maxNameLength = getValidationResultValue(compiler, symbolMaxNameLengthType); - if (maxNameLength <= 1) - return false; - - ANGLEGetInfoType maxMappedNameLength = getValidationResultValue(compiler, SH_MAPPED_NAME_MAX_LENGTH); - if (maxMappedNameLength <= 1) - return false; - - // The maximum allowed symbol name length is 256 characters. - Vector<char, 256> nameBuffer(maxNameLength); - Vector<char, 256> mappedNameBuffer(maxMappedNameLength); - - for (ANGLEGetInfoType i = 0; i < numSymbols; ++i) { - ANGLEShaderSymbol symbol; - ANGLEGetInfoType nameLength = 0; - switch (symbolType) { - case SH_ACTIVE_ATTRIBUTES: - symbol.symbolType = SHADER_SYMBOL_TYPE_ATTRIBUTE; -#if ANGLE_SH_VERSION >= 112 - ShGetVariableInfo(compiler, symbolType, i, &nameLength, &symbol.size, &symbol.dataType, &symbol.precision, &symbol.staticUse, nameBuffer.data(), mappedNameBuffer.data()); -#else - ShGetVariableInfo(compiler, symbolType, i, &nameLength, &symbol.size, &symbol.dataType, &symbol.precision, nameBuffer.data(), mappedNameBuffer.data()); -#endif - break; - case SH_ACTIVE_UNIFORMS: - symbol.symbolType = SHADER_SYMBOL_TYPE_UNIFORM; -#if ANGLE_SH_VERSION >= 112 - ShGetVariableInfo(compiler, symbolType, i, &nameLength, &symbol.size, &symbol.dataType, &symbol.precision, &symbol.staticUse, nameBuffer.data(), mappedNameBuffer.data()); -#else - ShGetVariableInfo(compiler, symbolType, i, &nameLength, &symbol.size, &symbol.dataType, &symbol.precision, nameBuffer.data(), mappedNameBuffer.data()); -#endif - break; - default: - ASSERT_NOT_REACHED(); - return false; - } - if (!nameLength) - return false; - - // The ShGetActive* calls above are guaranteed to produce null-terminated strings for - // nameBuffer and mappedNameBuffer. Also, the character set for symbol names - // is a subset of Latin-1 as specified by the OpenGL ES Shading Language, Section 3.1 and - // WebGL, Section "Characters Outside the GLSL Source Character Set". - - String name = String(nameBuffer.data()); - String mappedName = String(mappedNameBuffer.data()); - - // ANGLE returns array names in the format "array[0]". - // The only way to know if a symbol is an array is to check if it ends with "[0]". - // We can't check the size because regular symbols and arrays of length 1 both have a size of 1. - symbol.isArray = name.endsWith("[0]") && mappedName.endsWith("[0]"); - if (symbol.isArray) { - // Add a symbol for the array name without the "[0]" suffix. - name.truncate(name.length() - 3); - mappedName.truncate(mappedName.length() - 3); - } - - symbol.name = name; - symbol.mappedName = mappedName; - symbols.append(symbol); - - if (symbol.isArray) { - // Add symbols for each array element. - symbol.isArray = false; - for (int i = 0; i < symbol.size; i++) { - String arrayBrackets = "[" + String::number(i) + "]"; - symbol.name = name + arrayBrackets; - symbol.mappedName = mappedName + arrayBrackets; - symbols.append(symbol); - } - } - } - return true; -} - -ANGLEPlatformBridge::ANGLEPlatformBridge(ShShaderOutput shaderOutput, ShShaderSpec shaderSpec) - : builtCompilers(false) - , m_fragmentCompiler(0) - , m_vertexCompiler(0) - , m_shaderOutput(shaderOutput) - , m_shaderSpec(shaderSpec) -{ - // This is a no-op if it's already initialized. - ShInitialize(); -} - -ANGLEPlatformBridge::~ANGLEPlatformBridge() -{ - cleanupCompilers(); -} - -void ANGLEPlatformBridge::cleanupCompilers() -{ - if (m_fragmentCompiler) - ShDestruct(m_fragmentCompiler); - m_fragmentCompiler = 0; - if (m_vertexCompiler) - ShDestruct(m_vertexCompiler); - m_vertexCompiler = 0; - - builtCompilers = false; -} - -void ANGLEPlatformBridge::setResources(ShBuiltInResources resources) -{ - // Resources are (possibly) changing - cleanup compilers if we had them already - cleanupCompilers(); - - m_resources = resources; -} - -bool ANGLEPlatformBridge::compileShaderSource(const char* shaderSource, ANGLEShaderType shaderType, String& translatedShaderSource, String& shaderValidationLog, Vector<ANGLEShaderSymbol>& symbols, int extraCompileOptions) -{ - if (!builtCompilers) { - m_fragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, m_shaderSpec, m_shaderOutput, &m_resources); - m_vertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, m_shaderSpec, m_shaderOutput, &m_resources); - if (!m_fragmentCompiler || !m_vertexCompiler) { - cleanupCompilers(); - return false; - } - - builtCompilers = true; - } - - ShHandle compiler; - - if (shaderType == SHADER_TYPE_VERTEX) - compiler = m_vertexCompiler; - else - compiler = m_fragmentCompiler; - - const char* const shaderSourceStrings[] = { shaderSource }; - -#if ANGLE_SH_VERSION >= 111 - bool validateSuccess = ShCompile(compiler, shaderSourceStrings, 1, SH_OBJECT_CODE | SH_VARIABLES | extraCompileOptions); -#else - bool validateSuccess = ShCompile(compiler, shaderSourceStrings, 1, SH_OBJECT_CODE | SH_ATTRIBUTES_UNIFORMS | extraCompileOptions); -#endif - if (!validateSuccess) { - int logSize = getValidationResultValue(compiler, SH_INFO_LOG_LENGTH); - if (logSize > 1) { - OwnPtr<char[]> logBuffer = adoptArrayPtr(new char[logSize]); - if (logBuffer) { - ShGetInfoLog(compiler, logBuffer.get()); - shaderValidationLog = logBuffer.get(); - } - } - return false; - } - - int translationLength = getValidationResultValue(compiler, SH_OBJECT_CODE_LENGTH); - if (translationLength > 1) { - OwnPtr<char[]> translationBuffer = adoptArrayPtr(new char[translationLength]); - if (!translationBuffer) - return false; - ShGetObjectCode(compiler, translationBuffer.get()); - translatedShaderSource = translationBuffer.get(); - } - - if (!getSymbolInfo(compiler, SH_ACTIVE_ATTRIBUTES, symbols)) - return false; - if (!getSymbolInfo(compiler, SH_ACTIVE_UNIFORMS, symbols)) - return false; - - return true; -} - -} diff --git a/chromium/third_party/WebKit/Source/platform/graphics/angle/ANGLEPlatformBridge.h b/chromium/third_party/WebKit/Source/platform/graphics/angle/ANGLEPlatformBridge.h deleted file mode 100644 index 614f241b126..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/angle/ANGLEPlatformBridge.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ANGLEPlatformBridge_h -#define ANGLEPlatformBridge_h - -#include "platform/PlatformExport.h" -#include "wtf/text/CString.h" -#include "wtf/text/WTFString.h" -#include <GLSLANG/ShaderLang.h> - -namespace WebCore { - -enum ANGLEShaderType { - SHADER_TYPE_VERTEX = SH_VERTEX_SHADER, - SHADER_TYPE_FRAGMENT = SH_FRAGMENT_SHADER, -}; - -enum ANGLEShaderSymbolType { - SHADER_SYMBOL_TYPE_ATTRIBUTE, - SHADER_SYMBOL_TYPE_UNIFORM -}; - -struct PLATFORM_EXPORT ANGLEShaderSymbol { - ANGLEShaderSymbolType symbolType; - String name; - String mappedName; - ShDataType dataType; - int size; - bool isArray; - ShPrecisionType precision; -#if ANGLE_SH_VERSION >= 112 - int staticUse; -#endif - - bool isSampler() const - { - return symbolType == SHADER_SYMBOL_TYPE_UNIFORM - && (dataType == SH_SAMPLER_2D - || dataType == SH_SAMPLER_CUBE - || dataType == SH_SAMPLER_2D_RECT_ARB - || dataType == SH_SAMPLER_EXTERNAL_OES); - } -}; - -class PLATFORM_EXPORT ANGLEPlatformBridge { -public: - - ANGLEPlatformBridge(ShShaderOutput = SH_GLSL_OUTPUT, ShShaderSpec = SH_WEBGL_SPEC); - ~ANGLEPlatformBridge(); - - ShBuiltInResources getResources() { return m_resources; } - void setResources(ShBuiltInResources); - - bool compileShaderSource(const char* shaderSource, ANGLEShaderType, String& translatedShaderSource, String& shaderValidationLog, Vector<ANGLEShaderSymbol>& symbols, int extraCompileOptions = 0); - -private: - - void cleanupCompilers(); - - bool builtCompilers; - - ShHandle m_fragmentCompiler; - ShHandle m_vertexCompiler; - - ShShaderOutput m_shaderOutput; - ShShaderSpec m_shaderSpec; - - ShBuiltInResources m_resources; -}; - -} // namespace WebCore - -#endif diff --git a/chromium/third_party/WebKit/Source/platform/graphics/cg/GraphicsContextCG.h b/chromium/third_party/WebKit/Source/platform/graphics/cg/GraphicsContextCG.h deleted file mode 100644 index c2c1a5f52b7..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/cg/GraphicsContextCG.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef GraphicsContextCG_h -#define GraphicsContextCG_h - -#include "platform/graphics/GraphicsContext.h" - -typedef struct CGColorSpace *CGColorSpaceRef; - -namespace WebCore { - -CGColorSpaceRef PLATFORM_EXPORT deviceRGBColorSpaceRef(); -CGColorSpaceRef PLATFORM_EXPORT sRGBColorSpaceRef(); -CGColorSpaceRef PLATFORM_EXPORT linearRGBColorSpaceRef(); - -} - -#endif diff --git a/chromium/third_party/WebKit/Source/platform/graphics/cpu/arm/GraphicsContext3DNEON.h b/chromium/third_party/WebKit/Source/platform/graphics/cpu/arm/WebGLImageConversionNEON.h index c043fedd4a9..1729ecca737 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/cpu/arm/GraphicsContext3DNEON.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/cpu/arm/WebGLImageConversionNEON.h @@ -23,8 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef GraphicsContext3DNEON_h -#define GraphicsContext3DNEON_h +#ifndef WebGLImageConversionNEON_h +#define WebGLImageConversionNEON_h #if HAVE(ARM_NEON_INTRINSICS) @@ -301,4 +301,4 @@ ALWAYS_INLINE void packOneRowOfRGBA8ToUnsignedShort565(const uint8_t*& source, u #endif // HAVE(ARM_NEON_INTRINSICS) -#endif // GraphicsContext3DNEON_h +#endif // WebGLImageConversionNEON_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/cpu/arm/filters/FELightingNEON.h b/chromium/third_party/WebKit/Source/platform/graphics/cpu/arm/filters/FELightingNEON.h deleted file mode 100644 index 69939a582a4..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/cpu/arm/filters/FELightingNEON.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2011 University of Szeged - * Copyright (C) 2011 Zoltan Herczeg - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FELightingNEON_h -#define FELightingNEON_h - -#if CPU(ARM_NEON) && CPU(ARM_TRADITIONAL) && COMPILER(GCC) - -#include "platform/graphics/filters/FELighting.h" -#include "wtf/Alignment.h" -#include "wtf/CPU.h" -#include "wtf/ParallelJobs.h" - -namespace WebCore { - -// Otherwise: Distant Light. -#define FLAG_POINT_LIGHT 0x01 -#define FLAG_SPOT_LIGHT 0x02 -#define FLAG_CONE_EXPONENT_IS_1 0x04 - -// Otherwise: Diffuse light. -#define FLAG_SPECULAR_LIGHT 0x10 -#define FLAG_DIFFUSE_CONST_IS_1 0x20 -#define FLAG_SPECULAR_EXPONENT_IS_1 0x40 - -// Must be aligned to 16 bytes. -struct FELightingFloatArgumentsForNeon { - float surfaceScale; - float minusSurfaceScaleDividedByFour; - float diffuseConstant; - float padding1; - - float coneCutOffLimit; - float coneFullLight; - float coneCutOffRange; - float constOne; - - float lightX; - float lightY; - float lightZ; - float padding2; - - float directionX; - float directionY; - float directionZ; - float padding3; - - float colorRed; - float colorGreen; - float colorBlue; - float padding4; -}; - -struct FELightingPaintingDataForNeon { - unsigned char* pixels; - float yStart; - int widthDecreasedByTwo; - int absoluteHeight; - // Combination of FLAG constants above. - int flags; - int specularExponent; - int coneExponent; - FELightingFloatArgumentsForNeon* floatArguments; - short* paintingConstants; -}; - -short* feLightingConstantsForNeon(); - -extern "C" { -void neonDrawLighting(FELightingPaintingDataForNeon*); -} - -inline void FELighting::platformApplyNeon(LightingData& data, LightSource::PaintingData& paintingData) -{ - WTF_ALIGNED(FELightingFloatArgumentsForNeon, floatArguments, 16); - - FELightingPaintingDataForNeon neonData = { - data.pixels->data(), - 1, - data.widthDecreasedByOne - 1, - data.heightDecreasedByOne - 1, - 0, - 0, - 0, - &floatArguments, - feLightingConstantsForNeon() - }; - - // Set light source arguments. - floatArguments.constOne = 1; - - floatArguments.colorRed = m_lightingColor.red(); - floatArguments.colorGreen = m_lightingColor.green(); - floatArguments.colorBlue = m_lightingColor.blue(); - floatArguments.padding4 = 0; - - if (m_lightSource->type() == LS_POINT) { - neonData.flags |= FLAG_POINT_LIGHT; - PointLightSource* pointLightSource = static_cast<PointLightSource*>(m_lightSource.get()); - floatArguments.lightX = pointLightSource->position().x(); - floatArguments.lightY = pointLightSource->position().y(); - floatArguments.lightZ = pointLightSource->position().z(); - floatArguments.padding2 = 0; - } else if (m_lightSource->type() == LS_SPOT) { - neonData.flags |= FLAG_SPOT_LIGHT; - SpotLightSource* spotLightSource = static_cast<SpotLightSource*>(m_lightSource.get()); - floatArguments.lightX = spotLightSource->position().x(); - floatArguments.lightY = spotLightSource->position().y(); - floatArguments.lightZ = spotLightSource->position().z(); - floatArguments.padding2 = 0; - - floatArguments.directionX = paintingData.directionVector.x(); - floatArguments.directionY = paintingData.directionVector.y(); - floatArguments.directionZ = paintingData.directionVector.z(); - floatArguments.padding3 = 0; - - floatArguments.coneCutOffLimit = paintingData.coneCutOffLimit; - floatArguments.coneFullLight = paintingData.coneFullLight; - floatArguments.coneCutOffRange = paintingData.coneCutOffLimit - paintingData.coneFullLight; - neonData.coneExponent = getPowerCoefficients(spotLightSource->specularExponent()); - if (spotLightSource->specularExponent() == 1) - neonData.flags |= FLAG_CONE_EXPONENT_IS_1; - } else { - ASSERT(m_lightSource->type() == LS_DISTANT); - floatArguments.lightX = paintingData.lightVector.x(); - floatArguments.lightY = paintingData.lightVector.y(); - floatArguments.lightZ = paintingData.lightVector.z(); - floatArguments.padding2 = 1; - } - - // Set lighting arguments. - floatArguments.surfaceScale = data.surfaceScale; - floatArguments.minusSurfaceScaleDividedByFour = -data.surfaceScale / 4; - if (m_lightingType == FELighting::DiffuseLighting) { - floatArguments.diffuseConstant = m_diffuseConstant; - } else { - neonData.flags |= FLAG_SPECULAR_LIGHT; - floatArguments.diffuseConstant = m_specularConstant; - neonData.specularExponent = getPowerCoefficients(m_specularExponent); - if (m_specularExponent == 1) - neonData.flags |= FLAG_SPECULAR_EXPONENT_IS_1; - } - if (floatArguments.diffuseConstant == 1) - neonData.flags |= FLAG_DIFFUSE_CONST_IS_1; - - int optimalThreadNumber = ((data.widthDecreasedByOne - 1) * (data.heightDecreasedByOne - 1)) / s_minimalRectDimension; - if (optimalThreadNumber > 1) { - // Initialize parallel jobs - ParallelJobs<FELightingPaintingDataForNeon> parallelJobs(&WebCore::FELighting::platformApplyNeonWorker, optimalThreadNumber); - - // Fill the parameter array - int job = parallelJobs.numberOfJobs(); - if (job > 1) { - int yStart = 1; - int yStep = (data.heightDecreasedByOne - 1) / job; - for (--job; job >= 0; --job) { - FELightingPaintingDataForNeon& params = parallelJobs.parameter(job); - params = neonData; - params.yStart = yStart; - params.pixels += (yStart - 1) * (data.widthDecreasedByOne + 1) * 4; - if (job > 0) { - params.absoluteHeight = yStep; - yStart += yStep; - } else { - params.absoluteHeight = data.heightDecreasedByOne - yStart; - } - } - parallelJobs.execute(); - return; - } - } - - neonDrawLighting(&neonData); -} - -} // namespace WebCore - -#endif // CPU(ARM_NEON) && COMPILER(GCC) - -#endif // FELightingNEON_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/DistantLightSource.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/DistantLightSource.cpp index 6da197cbb89..b44c393ab9b 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/DistantLightSource.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/DistantLightSource.cpp @@ -35,7 +35,7 @@ namespace WebCore { -void DistantLightSource::initPaintingData(PaintingData& paintingData) +void DistantLightSource::initPaintingData(PaintingData& paintingData) const { float azimuth = deg2rad(m_azimuth); float elevation = deg2rad(m_elevation); @@ -45,7 +45,7 @@ void DistantLightSource::initPaintingData(PaintingData& paintingData) paintingData.lightVectorLength = 1; } -void DistantLightSource::updatePaintingData(PaintingData&, int, int, float) +void DistantLightSource::updatePaintingData(PaintingData&, int, int, float) const { } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/DistantLightSource.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/DistantLightSource.h index b64b94da7fb..65814e0504e 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/DistantLightSource.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/DistantLightSource.h @@ -34,16 +34,21 @@ public: return adoptRef(new DistantLightSource(azimuth, elevation)); } + virtual PassRefPtr<LightSource> create(const FloatPoint3D& scale, const FloatSize& offset) const OVERRIDE + { + return adoptRef(new DistantLightSource(m_azimuth, m_elevation)); + } + float azimuth() const { return m_azimuth; } float elevation() const { return m_elevation; } virtual bool setAzimuth(float) OVERRIDE; virtual bool setElevation(float) OVERRIDE; - virtual void initPaintingData(PaintingData&); - virtual void updatePaintingData(PaintingData&, int x, int y, float z); + virtual void initPaintingData(PaintingData&) const OVERRIDE; + virtual void updatePaintingData(PaintingData&, int x, int y, float z) const OVERRIDE; - virtual TextStream& externalRepresentation(TextStream&) const; + virtual TextStream& externalRepresentation(TextStream&) const OVERRIDE; private: DistantLightSource(float azimuth, float elevation) diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEBlend.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEBlend.cpp index 88aff9f783e..fbf94c35ebc 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEBlend.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEBlend.cpp @@ -201,50 +201,13 @@ static SkXfermode::Mode toSkiaMode(BlendModeType mode) } } -bool FEBlend::applySkia() -{ - // For now, only use the skia implementation for accelerated rendering. - if (!filter()->isAccelerated()) - return false; - - FilterEffect* in = inputEffect(0); - FilterEffect* in2 = inputEffect(1); - - if (!in || !in2) - return false; - - ImageBuffer* resultImage = createImageBufferResult(); - if (!resultImage) - return false; - - RefPtr<Image> foreground = in->asImageBuffer()->copyImage(DontCopyBackingStore); - RefPtr<Image> background = in2->asImageBuffer()->copyImage(DontCopyBackingStore); - - RefPtr<NativeImageSkia> foregroundNativeImage = foreground->nativeImageForCurrentFrame(); - RefPtr<NativeImageSkia> backgroundNativeImage = background->nativeImageForCurrentFrame(); - - if (!foregroundNativeImage || !backgroundNativeImage) - return false; - - SkBitmap foregroundBitmap = foregroundNativeImage->bitmap(); - SkBitmap backgroundBitmap = backgroundNativeImage->bitmap(); - - SkAutoTUnref<SkImageFilter> backgroundSource(new SkBitmapSource(backgroundBitmap)); - SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(toSkiaMode(m_mode))); - SkAutoTUnref<SkImageFilter> blend(new SkXfermodeImageFilter(mode, backgroundSource)); - SkPaint paint; - paint.setImageFilter(blend); - resultImage->context()->drawBitmap(foregroundBitmap, 0, 0, &paint); - return true; -} - PassRefPtr<SkImageFilter> FEBlend::createImageFilter(SkiaImageFilterBuilder* builder) { RefPtr<SkImageFilter> foreground(builder->build(inputEffect(0), operatingColorSpace())); RefPtr<SkImageFilter> background(builder->build(inputEffect(1), operatingColorSpace())); SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(toSkiaMode(m_mode))); SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset()); - return adoptRef(new SkXfermodeImageFilter(mode, background.get(), foreground.get(), &cropRect)); + return adoptRef(SkXfermodeImageFilter::Create(mode, background.get(), foreground.get(), &cropRect)); } static TextStream& operator<<(TextStream& ts, const BlendModeType& type) diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEBlend.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEBlend.h index 628c3ee408f..08e850e069c 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEBlend.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEBlend.h @@ -50,13 +50,12 @@ public: unsigned colorArrayLength); virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; private: FEBlend(Filter*, BlendModeType); virtual void applySoftware() OVERRIDE; - virtual bool applySkia() OVERRIDE; BlendModeType m_mode; }; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEColorMatrix.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEColorMatrix.cpp index e56df350beb..b87769dd4eb 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEColorMatrix.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEColorMatrix.cpp @@ -73,109 +73,6 @@ bool FEColorMatrix::setValues(const Vector<float> &values) return true; } -inline void matrix(float& red, float& green, float& blue, float& alpha, const Vector<float>& values) -{ - float r = values[0] * red + values[1] * green + values[2] * blue + values[3] * alpha + values[4] * 255; - float g = values[5] * red + values[6] * green + values[7] * blue + values[8] * alpha + values[9] * 255; - float b = values[10] * red + values[11] * green + values[12] * blue + values[13] * alpha + values[14] * 255; - float a = values[15] * red + values[16] * green + values[17] * blue + values[18] * alpha + values[19] * 255; - - red = r; - green = g; - blue = b; - alpha = a; -} - -inline void saturateAndHueRotate(float& red, float& green, float& blue, const float* components) -{ - float r = red * components[0] + green * components[1] + blue * components[2]; - float g = red * components[3] + green * components[4] + blue * components[5]; - float b = red * components[6] + green * components[7] + blue * components[8]; - - red = r; - green = g; - blue = b; -} - -inline void luminance(float& red, float& green, float& blue, float& alpha) -{ - alpha = 0.2125 * red + 0.7154 * green + 0.0721 * blue; - red = 0; - green = 0; - blue = 0; -} - -template<ColorMatrixType filterType> -void effectType(Uint8ClampedArray* pixelArray, const Vector<float>& values) -{ - unsigned pixelArrayLength = pixelArray->length(); - float components[9]; - - if (filterType == FECOLORMATRIX_TYPE_SATURATE) - FEColorMatrix::calculateSaturateComponents(components, values[0]); - else if (filterType == FECOLORMATRIX_TYPE_HUEROTATE) - FEColorMatrix::calculateHueRotateComponents(components, values[0]); - - for (unsigned pixelByteOffset = 0; pixelByteOffset < pixelArrayLength; pixelByteOffset += 4) { - float red = pixelArray->item(pixelByteOffset); - float green = pixelArray->item(pixelByteOffset + 1); - float blue = pixelArray->item(pixelByteOffset + 2); - float alpha = pixelArray->item(pixelByteOffset + 3); - - switch (filterType) { - case FECOLORMATRIX_TYPE_MATRIX: - matrix(red, green, blue, alpha, values); - break; - case FECOLORMATRIX_TYPE_SATURATE: - case FECOLORMATRIX_TYPE_HUEROTATE: - saturateAndHueRotate(red, green, blue, components); - break; - case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: - luminance(red, green, blue, alpha); - break; - } - - pixelArray->set(pixelByteOffset, red); - pixelArray->set(pixelByteOffset + 1, green); - pixelArray->set(pixelByteOffset + 2, blue); - pixelArray->set(pixelByteOffset + 3, alpha); - } -} - -void FEColorMatrix::applySoftware() -{ - FilterEffect* in = inputEffect(0); - - ImageBuffer* resultImage = createImageBufferResult(); - if (!resultImage) - return; - - resultImage->context()->drawImageBuffer(in->asImageBuffer(), drawingRegionOfInputImage(in->absolutePaintRect())); - - IntRect imageRect(IntPoint(), absolutePaintRect().size()); - RefPtr<Uint8ClampedArray> pixelArray = resultImage->getUnmultipliedImageData(imageRect); - - switch (m_type) { - case FECOLORMATRIX_TYPE_UNKNOWN: - break; - case FECOLORMATRIX_TYPE_MATRIX: - effectType<FECOLORMATRIX_TYPE_MATRIX>(pixelArray.get(), m_values); - break; - case FECOLORMATRIX_TYPE_SATURATE: - effectType<FECOLORMATRIX_TYPE_SATURATE>(pixelArray.get(), m_values); - break; - case FECOLORMATRIX_TYPE_HUEROTATE: - effectType<FECOLORMATRIX_TYPE_HUEROTATE>(pixelArray.get(), m_values); - break; - case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: - effectType<FECOLORMATRIX_TYPE_LUMINANCETOALPHA>(pixelArray.get(), m_values); - setIsAlphaImage(true); - break; - } - - resultImage->putByteArray(Unmultiplied, pixelArray.get(), imageRect.size(), imageRect, IntPoint()); -} - static void saturateMatrix(float s, SkScalar matrix[20]) { matrix[0] = 0.213f + 0.787f * s; @@ -249,31 +146,44 @@ static SkColorFilter* createColorFilter(ColorMatrixType type, const float* value luminanceToAlphaMatrix(matrix); break; } - return new SkColorMatrixFilter(matrix); + return SkColorMatrixFilter::Create(matrix); } -bool FEColorMatrix::applySkia() +void FEColorMatrix::applySoftware() { ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) - return false; + return; FilterEffect* in = inputEffect(0); - SkRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); + IntRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); SkAutoTUnref<SkColorFilter> filter(createColorFilter(m_type, m_values.data())); RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore); RefPtr<NativeImageSkia> nativeImage = image->nativeImageForCurrentFrame(); if (!nativeImage) - return false; + return; SkPaint paint; paint.setColorFilter(filter); paint.setXfermodeMode(SkXfermode::kSrc_Mode); - resultImage->context()->drawBitmap(nativeImage->bitmap(), drawingRegion.fLeft, drawingRegion.fTop, &paint); - return true; + resultImage->context()->drawBitmap(nativeImage->bitmap(), drawingRegion.x(), drawingRegion.y(), &paint); + + if (affectsTransparentPixels()) { + IntRect fullRect = IntRect(IntPoint(), absolutePaintRect().size()); + resultImage->context()->clipOut(drawingRegion); + resultImage->context()->fillRect(fullRect, Color(m_values[4], m_values[9], m_values[14], m_values[19])); + } + return; +} + +bool FEColorMatrix::affectsTransparentPixels() +{ + // Because the input pixels are premultiplied, the only way clear pixels can be + // painted is if the additive component for the alpha is not 0. + return m_type == FECOLORMATRIX_TYPE_MATRIX && m_values[19] > 0; } PassRefPtr<SkImageFilter> FEColorMatrix::createImageFilter(SkiaImageFilterBuilder* builder) diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEColorMatrix.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEColorMatrix.h index cd7cf1b5d06..4612161960d 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEColorMatrix.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEColorMatrix.h @@ -49,7 +49,7 @@ public: virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; static inline void calculateSaturateComponents(float* components, float value); static inline void calculateHueRotateComponents(float* components, float value); @@ -58,41 +58,13 @@ private: FEColorMatrix(Filter*, ColorMatrixType, const Vector<float>&); virtual void applySoftware() OVERRIDE; - virtual bool applySkia() OVERRIDE; + + virtual bool affectsTransparentPixels() OVERRIDE; ColorMatrixType m_type; Vector<float> m_values; }; -inline void FEColorMatrix::calculateSaturateComponents(float* components, float value) -{ - components[0] = (0.213 + 0.787 * value); - components[1] = (0.715 - 0.715 * value); - components[2] = (0.072 - 0.072 * value); - components[3] = (0.213 - 0.213 * value); - components[4] = (0.715 + 0.285 * value); - components[5] = (0.072 - 0.072 * value); - components[6] = (0.213 - 0.213 * value); - components[7] = (0.715 - 0.715 * value); - components[8] = (0.072 + 0.928 * value); -} - -inline void FEColorMatrix::calculateHueRotateComponents(float* components, float value) -{ - float cosHue = cos(value * piFloat / 180); - float sinHue = sin(value * piFloat / 180); - components[0] = 0.213 + cosHue * 0.787 - sinHue * 0.213; - components[1] = 0.715 - cosHue * 0.715 - sinHue * 0.715; - components[2] = 0.072 - cosHue * 0.072 + sinHue * 0.928; - components[3] = 0.213 - cosHue * 0.213 + sinHue * 0.143; - components[4] = 0.715 + cosHue * 0.285 + sinHue * 0.140; - components[5] = 0.072 - cosHue * 0.072 - sinHue * 0.283; - components[6] = 0.213 - cosHue * 0.213 - sinHue * 0.787; - components[7] = 0.715 - cosHue * 0.715 + sinHue * 0.715; - components[8] = 0.072 + cosHue * 0.928 + sinHue * 0.072; -} - - } // namespace WebCore #endif // FEColorMatrix_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComponentTransfer.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComponentTransfer.cpp index c5545830712..2ef679ccc9c 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComponentTransfer.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComponentTransfer.cpp @@ -153,48 +153,51 @@ static void gamma(unsigned char* values, const ComponentTransferFunction& transf void FEComponentTransfer::applySoftware() { FilterEffect* in = inputEffect(0); - - Uint8ClampedArray* pixelArray = createUnmultipliedImageResult(); - if (!pixelArray) - return; - - unsigned char rValues[256], gValues[256], bValues[256], aValues[256]; - getValues(rValues, gValues, bValues, aValues); - unsigned char* tables[] = { rValues, gValues, bValues, aValues }; - - IntRect drawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); - in->copyUnmultipliedImage(pixelArray, drawingRect); - - unsigned pixelArrayLength = pixelArray->length(); - for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) { - for (unsigned channel = 0; channel < 4; ++channel) { - unsigned char c = pixelArray->item(pixelOffset + channel); - pixelArray->set(pixelOffset + channel, tables[channel][c]); - } - } -} - -bool FEComponentTransfer::applySkia() -{ - FilterEffect* in = inputEffect(0); ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) - return false; + return; RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore); RefPtr<NativeImageSkia> nativeImage = image->nativeImageForCurrentFrame(); if (!nativeImage) - return false; + return; unsigned char rValues[256], gValues[256], bValues[256], aValues[256]; getValues(rValues, gValues, bValues, aValues); + IntRect destRect = drawingRegionOfInputImage(in->absolutePaintRect()); SkPaint paint; paint.setColorFilter(SkTableColorFilter::CreateARGB(aValues, rValues, gValues, bValues))->unref(); paint.setXfermodeMode(SkXfermode::kSrc_Mode); - resultImage->context()->drawBitmap(nativeImage->bitmap(), 0, 0, &paint); + resultImage->context()->drawBitmap(nativeImage->bitmap(), destRect.x(), destRect.y(), &paint); - return true; + if (affectsTransparentPixels()) { + IntRect fullRect = IntRect(IntPoint(), absolutePaintRect().size()); + resultImage->context()->clipOut(destRect); + resultImage->context()->fillRect(fullRect, Color(rValues[0], gValues[0], bValues[0], aValues[0])); + } +} + +bool FEComponentTransfer::affectsTransparentPixels() +{ + double intercept = 0; + switch (m_alphaFunc.type) { + case FECOMPONENTTRANSFER_TYPE_UNKNOWN: + case FECOMPONENTTRANSFER_TYPE_IDENTITY: + break; + case FECOMPONENTTRANSFER_TYPE_TABLE: + case FECOMPONENTTRANSFER_TYPE_DISCRETE: + if (m_alphaFunc.tableValues.size() > 0) + intercept = m_alphaFunc.tableValues[0]; + break; + case FECOMPONENTTRANSFER_TYPE_LINEAR: + intercept = m_alphaFunc.intercept; + break; + case FECOMPONENTTRANSFER_TYPE_GAMMA: + intercept = m_alphaFunc.offset; + break; + } + return 255 * intercept >= 1; } PassRefPtr<SkImageFilter> FEComponentTransfer::createImageFilter(SkiaImageFilterBuilder* builder) diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComponentTransfer.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComponentTransfer.h index d71e82f02ff..f65cdaca699 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComponentTransfer.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComponentTransfer.h @@ -79,14 +79,15 @@ public: virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; private: FEComponentTransfer(Filter*, const ComponentTransferFunction& redFunc, const ComponentTransferFunction& greenFunc, const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc); virtual void applySoftware() OVERRIDE; - virtual bool applySkia() OVERRIDE; + + virtual bool affectsTransparentPixels() OVERRIDE; void getValues(unsigned char rValues[256], unsigned char gValues[256], unsigned char bValues[256], unsigned char aValues[256]); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComposite.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComposite.cpp index 2348d80b2bd..a284840343d 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComposite.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComposite.cpp @@ -232,25 +232,61 @@ inline void FEComposite::platformArithmeticSoftware(Uint8ClampedArray* source, U #endif } -void FEComposite::determineAbsolutePaintRect() +FloatRect FEComposite::determineAbsolutePaintRect(const FloatRect& originalRequestedRect) { + FloatRect requestedRect = originalRequestedRect; + if (clipsToBounds()) + requestedRect.intersect(maxEffectRect()); + + // We may be called multiple times if result is used more than once. Return + // quickly if nothing new is required. + if (absolutePaintRect().contains(enclosingIntRect(requestedRect))) + return requestedRect; + + // No mapPaintRect required for FEComposite. + FloatRect input1Rect = inputEffect(1)->determineAbsolutePaintRect(requestedRect); + FloatRect affectedRect; switch (m_type) { case FECOMPOSITE_OPERATOR_IN: + // 'in' has output only in the intersection of both inputs. + affectedRect = intersection(input1Rect, inputEffect(0)->determineAbsolutePaintRect(input1Rect)); + break; case FECOMPOSITE_OPERATOR_ATOP: - // For In and Atop the first effect just influences the result of - // the second effect. So just use the absolute paint rect of the second effect here. - setAbsolutePaintRect(inputEffect(1)->absolutePaintRect()); - return; + // 'atop' has output only in the extents of the second input. + // Make sure first input knows where it needs to produce output. + inputEffect(0)->determineAbsolutePaintRect(input1Rect); + affectedRect = input1Rect; + break; case FECOMPOSITE_OPERATOR_ARITHMETIC: - // Arithmetic may influnce the compele filter primitive region. So we can't - // optimize the paint region here. - setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); - return; + if (k4() > 0) { + // Make sure first input knows where it needs to produce output. + inputEffect(0)->determineAbsolutePaintRect(requestedRect); + // Arithmetic with non-zero k4 may influnce the complete filter primitive + // region. So we can't optimize the paint region here. + affectedRect = requestedRect; + break; + } + if (k2() <= 0) { + // Input 0 does not appear where input 1 is not present. + FloatRect input0Rect = inputEffect(0)->determineAbsolutePaintRect(input1Rect); + if (k3() > 0) { + affectedRect = input1Rect; + } else { + // Just k1 is positive. Use intersection. + affectedRect = intersection(input1Rect, input0Rect); + } + break; + } + // else fall through to use union default: // Take the union of both input effects. - FilterEffect::determineAbsolutePaintRect(); - return; + affectedRect = unionRect(input1Rect, inputEffect(0)->determineAbsolutePaintRect(requestedRect)); + break; } + + affectedRect.intersect(requestedRect); + addAbsolutePaintRect(affectedRect); + return affectedRect; } void FEComposite::applySoftware() @@ -296,25 +332,27 @@ void FEComposite::applySoftware() if (destinationRect.isEmpty()) break; IntPoint destinationPoint(destinationRect.x() - absolutePaintRect().x(), destinationRect.y() - absolutePaintRect().y()); - IntRect sourceRect(IntPoint(destinationRect.x() - in->absolutePaintRect().x(), + FloatRect sourceRect(IntPoint(destinationRect.x() - in->absolutePaintRect().x(), destinationRect.y() - in->absolutePaintRect().y()), destinationRect.size()); - IntRect source2Rect(IntPoint(destinationRect.x() - in2->absolutePaintRect().x(), + FloatRect source2Rect(IntPoint(destinationRect.x() - in2->absolutePaintRect().x(), destinationRect.y() - in2->absolutePaintRect().y()), destinationRect.size()); - filterContext->drawImageBuffer(imageBuffer2, destinationPoint, source2Rect); - filterContext->drawImageBuffer(imageBuffer, destinationPoint, sourceRect, CompositeSourceIn); + filterContext->drawImageBuffer(imageBuffer2, + FloatRect(destinationPoint, imageBuffer2->size()), &source2Rect); + filterContext->drawImageBuffer(imageBuffer, + FloatRect(destinationPoint, imageBuffer->size()), &sourceRect, CompositeSourceIn); break; } case FECOMPOSITE_OPERATOR_OUT: filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect())); - filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()), IntRect(IntPoint(), imageBuffer2->size()), CompositeDestinationOut); + filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()), 0, CompositeDestinationOut); break; case FECOMPOSITE_OPERATOR_ATOP: filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect())); - filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), IntRect(IntPoint(), imageBuffer->size()), CompositeSourceAtop); + filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), 0, CompositeSourceAtop); break; case FECOMPOSITE_OPERATOR_XOR: filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect())); - filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), IntRect(IntPoint(), imageBuffer->size()), CompositeXOR); + filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), 0, CompositeXOR); break; default: break; @@ -342,15 +380,25 @@ SkXfermode::Mode toXfermode(WebCore::CompositeOperationType mode) PassRefPtr<SkImageFilter> FEComposite::createImageFilter(SkiaImageFilterBuilder* builder) { - RefPtr<SkImageFilter> foreground(builder->build(inputEffect(0), operatingColorSpace())); - RefPtr<SkImageFilter> background(builder->build(inputEffect(1), operatingColorSpace())); - if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) { - SkAutoTUnref<SkXfermode> mode(SkArithmeticMode::Create(SkFloatToScalar(m_k1), SkFloatToScalar(m_k2), SkFloatToScalar(m_k3), SkFloatToScalar(m_k4))); - return adoptRef(new SkXfermodeImageFilter(mode, background.get(), foreground.get())); - } + return createImageFilterInternal(builder, true); +} + +PassRefPtr<SkImageFilter> FEComposite::createImageFilterWithoutValidation(SkiaImageFilterBuilder* builder) +{ + return createImageFilterInternal(builder, false); +} + +PassRefPtr<SkImageFilter> FEComposite::createImageFilterInternal(SkiaImageFilterBuilder* builder, bool requiresPMColorValidation) +{ + RefPtr<SkImageFilter> foreground(builder->build(inputEffect(0), operatingColorSpace(), !mayProduceInvalidPreMultipliedPixels())); + RefPtr<SkImageFilter> background(builder->build(inputEffect(1), operatingColorSpace(), !mayProduceInvalidPreMultipliedPixels())); SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset()); - SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(toXfermode(m_type))); - return adoptRef(new SkXfermodeImageFilter(mode, background.get(), foreground.get(), &cropRect)); + RefPtr<SkXfermode> mode; + if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) + mode = adoptRef(SkArithmeticMode::Create(SkFloatToScalar(m_k1), SkFloatToScalar(m_k2), SkFloatToScalar(m_k3), SkFloatToScalar(m_k4), requiresPMColorValidation)); + else + mode = adoptRef(SkXfermode::Create(toXfermode(m_type))); + return adoptRef(SkXfermodeImageFilter::Create(mode.get(), background.get(), foreground.get(), &cropRect)); } static TextStream& operator<<(TextStream& ts, const CompositeOperationType& type) diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComposite.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComposite.h index afe24b7c07e..54a94e2eeca 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComposite.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEComposite.h @@ -60,19 +60,21 @@ public: virtual void correctFilterResultIfNeeded() OVERRIDE; - virtual void determineAbsolutePaintRect(); + virtual FloatRect determineAbsolutePaintRect(const FloatRect& requestedRect) OVERRIDE; - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; + virtual PassRefPtr<SkImageFilter> createImageFilterWithoutValidation(SkiaImageFilterBuilder*) OVERRIDE; protected: - virtual bool requiresValidPreMultipliedPixels() OVERRIDE { return m_type != FECOMPOSITE_OPERATOR_ARITHMETIC; } + virtual bool mayProduceInvalidPreMultipliedPixels() OVERRIDE { return m_type == FECOMPOSITE_OPERATOR_ARITHMETIC; } private: FEComposite(Filter*, const CompositeOperationType&, float, float, float, float); virtual void applySoftware() OVERRIDE; + PassRefPtr<SkImageFilter> createImageFilterInternal(SkiaImageFilterBuilder*, bool requiresPMColorValidation); inline void platformArithmeticSoftware(Uint8ClampedArray* source, Uint8ClampedArray* destination, float k1, float k2, float k3, float k4); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEConvolveMatrix.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEConvolveMatrix.cpp index 454541e0b80..418f19b4604 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEConvolveMatrix.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEConvolveMatrix.cpp @@ -59,6 +59,14 @@ PassRefPtr<FEConvolveMatrix> FEConvolveMatrix::create(Filter* filter, const IntS preserveAlpha, kernelMatrix)); } +FloatRect FEConvolveMatrix::mapPaintRect(const FloatRect& rect, bool forward) +{ + FloatRect result = rect; + + result.moveBy(forward ? -m_targetOffset : m_targetOffset - m_kernelSize); + result.expand(m_kernelSize); + return result; +} IntSize FEConvolveMatrix::kernelSize() const { @@ -527,7 +535,7 @@ PassRefPtr<SkImageFilter> FEConvolveMatrix::createImageFilter(SkiaImageFilterBui for (int i = 0; i < numElements; ++i) kernel[i] = SkFloatToScalar(m_kernelMatrix[numElements - 1 - i]); SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset()); - return adoptRef(new SkMatrixConvolutionImageFilter(kernelSize, kernel.get(), gain, bias, target, tileMode, convolveAlpha, input.get(), &cropRect)); + return adoptRef(SkMatrixConvolutionImageFilter::Create(kernelSize, kernel.get(), gain, bias, target, tileMode, convolveAlpha, input.get(), &cropRect)); } static TextStream& operator<<(TextStream& ts, const EdgeModeType& type) diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEConvolveMatrix.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEConvolveMatrix.h index 2191c08a6b8..154ff1ddacb 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEConvolveMatrix.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEConvolveMatrix.h @@ -71,9 +71,9 @@ public: virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; - virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); } + virtual FloatRect mapPaintRect(const FloatRect&, bool forward = true) OVERRIDE FINAL; - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; private: diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDiffuseLighting.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDiffuseLighting.cpp index b82fed523a0..cfba8d98260 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDiffuseLighting.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDiffuseLighting.cpp @@ -78,6 +78,7 @@ float FEDiffuseLighting::diffuseConstant() const bool FEDiffuseLighting::setDiffuseConstant(float diffuseConstant) { + diffuseConstant = std::max(diffuseConstant, 0.0f); if (m_diffuseConstant == diffuseConstant) return false; m_diffuseConstant = diffuseConstant; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDiffuseLighting.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDiffuseLighting.h index f93bc5ac0ed..8f2933bfffa 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDiffuseLighting.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDiffuseLighting.h @@ -53,7 +53,7 @@ public: const LightSource* lightSource() const; void setLightSource(PassRefPtr<LightSource>); - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; private: FEDiffuseLighting(Filter*, const Color&, float, float, float, float, PassRefPtr<LightSource>); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDisplacementMap.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDisplacementMap.cpp index ad31826126c..3c6544e8296 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDisplacementMap.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDisplacementMap.cpp @@ -49,6 +49,14 @@ PassRefPtr<FEDisplacementMap> FEDisplacementMap::create(Filter* filter, ChannelS return adoptRef(new FEDisplacementMap(filter, xChannelSelector, yChannelSelector, scale)); } +FloatRect FEDisplacementMap::mapPaintRect(const FloatRect& rect, bool) +{ + FloatRect result = rect; + result.inflateX(filter()->applyHorizontalScale(m_scale / 2)); + result.inflateY(filter()->applyVerticalScale(m_scale / 2)); + return result; +} + ChannelSelectorType FEDisplacementMap::xChannelSelector() const { return m_xChannelSelector; @@ -168,48 +176,6 @@ static SkDisplacementMapEffect::ChannelSelectorType toSkiaMode(ChannelSelectorTy } } -bool FEDisplacementMap::applySkia() -{ - // For now, only use the skia implementation for accelerated rendering. - if (!filter()->isAccelerated()) - return false; - - FilterEffect* in = inputEffect(0); - FilterEffect* in2 = inputEffect(1); - - if (!in || !in2) - return false; - - ImageBuffer* resultImage = createImageBufferResult(); - if (!resultImage) - return false; - - RefPtr<Image> color = in->asImageBuffer()->copyImage(DontCopyBackingStore); - RefPtr<Image> displ = in2->asImageBuffer()->copyImage(DontCopyBackingStore); - - RefPtr<NativeImageSkia> colorNativeImage = color->nativeImageForCurrentFrame(); - RefPtr<NativeImageSkia> displNativeImage = displ->nativeImageForCurrentFrame(); - - if (!colorNativeImage || !displNativeImage) - return false; - - SkBitmap colorBitmap = colorNativeImage->bitmap(); - SkBitmap displBitmap = displNativeImage->bitmap(); - - SkAutoTUnref<SkImageFilter> colorSource(new SkBitmapSource(colorBitmap)); - SkAutoTUnref<SkImageFilter> displSource(new SkBitmapSource(displBitmap)); - SkDisplacementMapEffect::ChannelSelectorType typeX = toSkiaMode(m_xChannelSelector); - SkDisplacementMapEffect::ChannelSelectorType typeY = toSkiaMode(m_yChannelSelector); - // FIXME : Only applyHorizontalScale is used and applyVerticalScale is ignored - // This can be fixed by adding a 2nd scale parameter to SkDisplacementMapEffect - SkAutoTUnref<SkImageFilter> displEffect(new SkDisplacementMapEffect( - typeX, typeY, SkFloatToScalar(filter()->applyHorizontalScale(m_scale)), displSource, colorSource)); - SkPaint paint; - paint.setImageFilter(displEffect); - resultImage->context()->drawBitmap(colorBitmap, 0, 0, &paint); - return true; -} - PassRefPtr<SkImageFilter> FEDisplacementMap::createImageFilter(SkiaImageFilterBuilder* builder) { RefPtr<SkImageFilter> color = builder->build(inputEffect(0), operatingColorSpace()); @@ -219,7 +185,7 @@ PassRefPtr<SkImageFilter> FEDisplacementMap::createImageFilter(SkiaImageFilterBu SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset()); // FIXME : Only applyHorizontalScale is used and applyVerticalScale is ignored // This can be fixed by adding a 2nd scale parameter to SkDisplacementMapEffect - return adoptRef(new SkDisplacementMapEffect(typeX, typeY, SkFloatToScalar(filter()->applyHorizontalScale(m_scale)), displ.get(), color.get(), &cropRect)); + return adoptRef(SkDisplacementMapEffect::Create(typeX, typeY, SkFloatToScalar(filter()->applyHorizontalScale(m_scale)), displ.get(), color.get(), &cropRect)); } static TextStream& operator<<(TextStream& ts, const ChannelSelectorType& type) diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDisplacementMap.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDisplacementMap.h index 91e151ef887..27601d71f9d 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDisplacementMap.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDisplacementMap.h @@ -50,18 +50,17 @@ public: float scale() const; bool setScale(float); - void setResultColorSpace(ColorSpace) OVERRIDE; + virtual void setResultColorSpace(ColorSpace) OVERRIDE; virtual void transformResultColorSpace(FilterEffect*, const int) OVERRIDE; - virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); } + virtual FloatRect mapPaintRect(const FloatRect&, bool forward = true) OVERRIDE FINAL; - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; private: FEDisplacementMap(Filter*, ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, float); virtual void applySoftware() OVERRIDE; - virtual bool applySkia() OVERRIDE; virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDropShadow.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDropShadow.cpp index 4e645b4f69d..443a52c998b 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDropShadow.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDropShadow.cpp @@ -49,21 +49,6 @@ PassRefPtr<FEDropShadow> FEDropShadow::create(Filter* filter, float stdX, float return adoptRef(new FEDropShadow(filter, stdX, stdY, dx, dy, shadowColor, shadowOpacity)); } -void FEDropShadow::determineAbsolutePaintRect() -{ - Filter* filter = this->filter(); - ASSERT_UNUSED(filter, filter); - - FloatRect absolutePaintRect = mapRect(inputEffect(0)->absolutePaintRect()); - - if (clipsToBounds()) - absolutePaintRect.intersect(maxEffectRect()); - else - absolutePaintRect.unite(maxEffectRect()); - - setAbsolutePaintRect(enclosingIntRect(absolutePaintRect)); -} - FloatRect FEDropShadow::mapRect(const FloatRect& rect, bool forward) { FloatRect result = rect; @@ -77,13 +62,11 @@ FloatRect FEDropShadow::mapRect(const FloatRect& rect, bool forward) offsetRect.move(-filter->applyHorizontalScale(m_dx), -filter->applyVerticalScale(m_dy)); result.unite(offsetRect); - unsigned kernelSizeX = 0; - unsigned kernelSizeY = 0; - FEGaussianBlur::calculateKernelSize(filter, kernelSizeX, kernelSizeY, m_stdX, m_stdY); + IntSize kernelSize = FEGaussianBlur::calculateKernelSize(filter, FloatPoint(m_stdX, m_stdY)); // We take the half kernel size and multiply it with three, because we run box blur three times. - result.inflateX(3 * kernelSizeX * 0.5f); - result.inflateY(3 * kernelSizeY * 0.5f); + result.inflateX(3 * kernelSize.width() * 0.5f); + result.inflateY(3 * kernelSize.height() * 0.5f); return result; } @@ -103,8 +86,9 @@ void FEDropShadow::applySoftware() GraphicsContext* resultContext = resultImage->context(); ASSERT(resultContext); - SkAutoTUnref<SkImageFilter> blurFilter(new SkBlurImageFilter(blurRadius.width(), blurRadius.height())); - SkAutoTUnref<SkColorFilter> colorFilter(SkColorFilter::CreateModeFilter(m_shadowColor.rgb(), SkXfermode::kSrcIn_Mode)); + Color color = adaptColorToOperatingColorSpace(m_shadowColor.combineWithAlpha(m_shadowOpacity)); + SkAutoTUnref<SkImageFilter> blurFilter(SkBlurImageFilter::Create(blurRadius.width(), blurRadius.height())); + SkAutoTUnref<SkColorFilter> colorFilter(SkColorFilter::CreateModeFilter(color.rgb(), SkXfermode::kSrcIn_Mode)); SkPaint paint; paint.setImageFilter(blurFilter.get()); paint.setColorFilter(colorFilter.get()); @@ -126,9 +110,10 @@ PassRefPtr<SkImageFilter> FEDropShadow::createImageFilter(SkiaImageFilterBuilder float dx = filter()->applyHorizontalScale(m_dx); float dy = filter()->applyVerticalScale(m_dy); float stdX = filter()->applyHorizontalScale(m_stdX); - float stdY = filter()->applyHorizontalScale(m_stdY); + float stdY = filter()->applyVerticalScale(m_stdY); + Color color = adaptColorToOperatingColorSpace(m_shadowColor.combineWithAlpha(m_shadowOpacity)); SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset()); - return adoptRef(new SkDropShadowImageFilter(SkFloatToScalar(dx), SkFloatToScalar(dy), SkFloatToScalar(stdX), SkFloatToScalar(stdY), m_shadowColor.rgb(), input.get(), &cropRect)); + return adoptRef(SkDropShadowImageFilter::Create(SkFloatToScalar(dx), SkFloatToScalar(dy), SkFloatToScalar(stdX), SkFloatToScalar(stdY), color.rgb(), input.get(), &cropRect)); } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDropShadow.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDropShadow.h index a3d9d956272..38d643ee135 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDropShadow.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEDropShadow.h @@ -49,12 +49,9 @@ public: float shadowOpacity() const { return m_shadowOpacity; } void setShadowOpacity(float shadowOpacity) { m_shadowOpacity = shadowOpacity; } - static float calculateStdDeviation(float); - - virtual void determineAbsolutePaintRect(); virtual FloatRect mapRect(const FloatRect&, bool forward = true) OVERRIDE FINAL; - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; private: diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEFlood.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEFlood.cpp index 03ed1f439c3..3bd7991f542 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEFlood.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEFlood.cpp @@ -40,7 +40,6 @@ FEFlood::FEFlood(Filter* filter, const Color& floodColor, float floodOpacity) , m_floodOpacity(floodOpacity) { FilterEffect::setOperatingColorSpace(ColorSpaceDeviceRGB); - FilterEffect::setResultColorSpace(ColorSpaceDeviceRGB); } PassRefPtr<FEFlood> FEFlood::create(Filter* filter, const Color& floodColor, float floodOpacity) @@ -80,13 +79,14 @@ void FEFlood::applySoftware() if (!resultImage) return; - Color color = colorWithOverrideAlpha(floodColor().rgb(), floodOpacity()); + Color color = floodColor().combineWithAlpha(floodOpacity()); resultImage->context()->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()), color); + FilterEffect::setResultColorSpace(ColorSpaceDeviceRGB); } PassRefPtr<SkImageFilter> FEFlood::createImageFilter(SkiaImageFilterBuilder* builder) { - Color color = colorWithOverrideAlpha(floodColor().rgb(), floodOpacity()); + Color color = floodColor().combineWithAlpha(floodOpacity()); SkImageFilter::CropRect rect = getCropRect(builder->cropOffset()); SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(color.rgb(), SkXfermode::kSrc_Mode)); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEFlood.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEFlood.h index 918811c7ac2..ee91a997d23 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEFlood.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEFlood.h @@ -41,14 +41,12 @@ public: // feFlood does not perform color interpolation of any kind, so the result is always in the current // color space regardless of the value of color-interpolation-filters. - void setOperatingColorSpace(ColorSpace) OVERRIDE { } - void setResultColorSpace(ColorSpace) OVERRIDE { } + virtual void setOperatingColorSpace(ColorSpace) OVERRIDE { } + virtual void setResultColorSpace(ColorSpace) OVERRIDE { } virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; - virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); } - - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; private: FEFlood(Filter*, const Color&, float); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEGaussianBlur.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEGaussianBlur.cpp index 150aac53213..82554826e56 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEGaussianBlur.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEGaussianBlur.cpp @@ -41,10 +41,10 @@ using namespace std; static inline float gaussianKernelFactor() { - return 3 / 4.f * sqrtf(2 * piFloat); + return 3 / 4.f * sqrtf(twoPiFloat); } -static const unsigned gMaxKernelSize = 1000; +static const int gMaxKernelSize = 1000; namespace WebCore { @@ -80,238 +80,69 @@ void FEGaussianBlur::setStdDeviationY(float y) m_stdY = y; } -inline void boxBlur(Uint8ClampedArray* srcPixelArray, Uint8ClampedArray* dstPixelArray, - unsigned dx, int dxLeft, int dxRight, int stride, int strideLine, int effectWidth, int effectHeight, bool alphaImage) +IntSize FEGaussianBlur::calculateUnscaledKernelSize(const FloatPoint& std) { - for (int y = 0; y < effectHeight; ++y) { - int line = y * strideLine; - for (int channel = 3; channel >= 0; --channel) { - int sum = 0; - // Fill the kernel - int maxKernelSize = min(dxRight, effectWidth); - for (int i = 0; i < maxKernelSize; ++i) - sum += srcPixelArray->item(line + i * stride + channel); - - // Blurring - for (int x = 0; x < effectWidth; ++x) { - int pixelByteOffset = line + x * stride + channel; - dstPixelArray->set(pixelByteOffset, static_cast<unsigned char>(sum / dx)); - if (x >= dxLeft) - sum -= srcPixelArray->item(pixelByteOffset - dxLeft * stride); - if (x + dxRight < effectWidth) - sum += srcPixelArray->item(pixelByteOffset + dxRight * stride); - } - if (alphaImage) // Source image is black, it just has different alpha values - break; - } - } -} - -inline void FEGaussianBlur::platformApplyGeneric(Uint8ClampedArray* srcPixelArray, Uint8ClampedArray* tmpPixelArray, unsigned kernelSizeX, unsigned kernelSizeY, IntSize& paintSize) -{ - int stride = 4 * paintSize.width(); - int dxLeft = 0; - int dxRight = 0; - int dyLeft = 0; - int dyRight = 0; - Uint8ClampedArray* src = srcPixelArray; - Uint8ClampedArray* dst = tmpPixelArray; - - for (int i = 0; i < 3; ++i) { - if (kernelSizeX) { - kernelPosition(i, kernelSizeX, dxLeft, dxRight); -#if HAVE(ARM_NEON_INTRINSICS) - if (!isAlphaImage()) - boxBlurNEON(src, dst, kernelSizeX, dxLeft, dxRight, 4, stride, paintSize.width(), paintSize.height()); - else - boxBlur(src, dst, kernelSizeX, dxLeft, dxRight, 4, stride, paintSize.width(), paintSize.height(), true); -#else - boxBlur(src, dst, kernelSizeX, dxLeft, dxRight, 4, stride, paintSize.width(), paintSize.height(), isAlphaImage()); -#endif - swap(src, dst); - } - - if (kernelSizeY) { - kernelPosition(i, kernelSizeY, dyLeft, dyRight); -#if HAVE(ARM_NEON_INTRINSICS) - if (!isAlphaImage()) - boxBlurNEON(src, dst, kernelSizeY, dyLeft, dyRight, stride, 4, paintSize.height(), paintSize.width()); - else - boxBlur(src, dst, kernelSizeY, dyLeft, dyRight, stride, 4, paintSize.height(), paintSize.width(), true); -#else - boxBlur(src, dst, kernelSizeY, dyLeft, dyRight, stride, 4, paintSize.height(), paintSize.width(), isAlphaImage()); -#endif - swap(src, dst); - } - } - - // The final result should be stored in srcPixelArray. - if (dst == srcPixelArray) { - ASSERT(src->length() == dst->length()); - memcpy(dst->data(), src->data(), src->length()); - } - -} - -void FEGaussianBlur::platformApplyWorker(PlatformApplyParameters* parameters) -{ - IntSize paintSize(parameters->width, parameters->height); - parameters->filter->platformApplyGeneric(parameters->srcPixelArray.get(), parameters->dstPixelArray.get(), - parameters->kernelSizeX, parameters->kernelSizeY, paintSize); -} - -inline void FEGaussianBlur::platformApply(Uint8ClampedArray* srcPixelArray, Uint8ClampedArray* tmpPixelArray, unsigned kernelSizeX, unsigned kernelSizeY, IntSize& paintSize) -{ - int scanline = 4 * paintSize.width(); - int extraHeight = 3 * kernelSizeY * 0.5f; - int optimalThreadNumber = (paintSize.width() * paintSize.height()) / (s_minimalRectDimension + extraHeight * paintSize.width()); - - if (optimalThreadNumber > 1) { - ParallelJobs<PlatformApplyParameters> parallelJobs(&platformApplyWorker, optimalThreadNumber); - - int jobs = parallelJobs.numberOfJobs(); - if (jobs > 1) { - // Split the job into "blockHeight"-sized jobs but there a few jobs that need to be slightly larger since - // blockHeight * jobs < total size. These extras are handled by the remainder "jobsWithExtra". - const int blockHeight = paintSize.height() / jobs; - const int jobsWithExtra = paintSize.height() % jobs; - - int currentY = 0; - for (int job = 0; job < jobs; job++) { - PlatformApplyParameters& params = parallelJobs.parameter(job); - params.filter = this; - - int startY = !job ? 0 : currentY - extraHeight; - currentY += job < jobsWithExtra ? blockHeight + 1 : blockHeight; - int endY = job == jobs - 1 ? currentY : currentY + extraHeight; - - int blockSize = (endY - startY) * scanline; - if (!job) { - params.srcPixelArray = srcPixelArray; - params.dstPixelArray = tmpPixelArray; - } else { - params.srcPixelArray = Uint8ClampedArray::createUninitialized(blockSize); - params.dstPixelArray = Uint8ClampedArray::createUninitialized(blockSize); - memcpy(params.srcPixelArray->data(), srcPixelArray->data() + startY * scanline, blockSize); - } - - params.width = paintSize.width(); - params.height = endY - startY; - params.kernelSizeX = kernelSizeX; - params.kernelSizeY = kernelSizeY; - } - - parallelJobs.execute(); - - // Copy together the parts of the image. - currentY = 0; - for (int job = 1; job < jobs; job++) { - PlatformApplyParameters& params = parallelJobs.parameter(job); - int sourceOffset; - int destinationOffset; - int size; - int adjustedBlockHeight = job < jobsWithExtra ? blockHeight + 1 : blockHeight; - - currentY += adjustedBlockHeight; - sourceOffset = extraHeight * scanline; - destinationOffset = currentY * scanline; - size = adjustedBlockHeight * scanline; - - memcpy(srcPixelArray->data() + destinationOffset, params.srcPixelArray->data() + sourceOffset, size); - } - return; - } - // Fallback to single threaded mode. - } - - // The selection here eventually should happen dynamically on some platforms. - platformApplyGeneric(srcPixelArray, tmpPixelArray, kernelSizeX, kernelSizeY, paintSize); -} - -void FEGaussianBlur::calculateUnscaledKernelSize(unsigned& kernelSizeX, unsigned& kernelSizeY, float stdX, float stdY) -{ - ASSERT(stdX >= 0 && stdY >= 0); - - kernelSizeX = 0; - if (stdX) - kernelSizeX = max<unsigned>(2, static_cast<unsigned>(floorf(stdX * gaussianKernelFactor() + 0.5f))); - kernelSizeY = 0; - if (stdY) - kernelSizeY = max<unsigned>(2, static_cast<unsigned>(floorf(stdY * gaussianKernelFactor() + 0.5f))); + ASSERT(std.x() >= 0 && std.y() >= 0); + IntSize kernelSize; // Limit the kernel size to 1000. A bigger radius won't make a big difference for the result image but // inflates the absolute paint rect to much. This is compatible with Firefox' behavior. - if (kernelSizeX > gMaxKernelSize) - kernelSizeX = gMaxKernelSize; - if (kernelSizeY > gMaxKernelSize) - kernelSizeY = gMaxKernelSize; -} + if (std.x()) { + int size = max<unsigned>(2, static_cast<unsigned>(floorf(std.x() * gaussianKernelFactor() + 0.5f))); + kernelSize.setWidth(min(size, gMaxKernelSize)); + } -void FEGaussianBlur::calculateKernelSize(Filter* filter, unsigned& kernelSizeX, unsigned& kernelSizeY, float stdX, float stdY) -{ - stdX = filter->applyHorizontalScale(stdX); - stdY = filter->applyVerticalScale(stdY); + if (std.y()) { + int size = max<unsigned>(2, static_cast<unsigned>(floorf(std.y() * gaussianKernelFactor() + 0.5f))); + kernelSize.setHeight(min(size, gMaxKernelSize)); + } - calculateUnscaledKernelSize(kernelSizeX, kernelSizeY, stdX, stdY); + return kernelSize; } -void FEGaussianBlur::determineAbsolutePaintRect() +IntSize FEGaussianBlur::calculateKernelSize(Filter* filter, const FloatPoint& std) { - FloatRect absolutePaintRect = mapRect(inputEffect(0)->absolutePaintRect()); - - if (clipsToBounds()) - absolutePaintRect.intersect(maxEffectRect()); - else - absolutePaintRect.unite(maxEffectRect()); + FloatPoint stdError(filter->applyHorizontalScale(std.x()), filter->applyVerticalScale(std.y())); - setAbsolutePaintRect(enclosingIntRect(absolutePaintRect)); + return calculateUnscaledKernelSize(stdError); } FloatRect FEGaussianBlur::mapRect(const FloatRect& rect, bool) { FloatRect result = rect; - unsigned kernelSizeX = 0; - unsigned kernelSizeY = 0; - calculateKernelSize(filter(), kernelSizeX, kernelSizeY, m_stdX, m_stdY); + IntSize kernelSize = calculateKernelSize(filter(), FloatPoint(m_stdX, m_stdY)); // We take the half kernel size and multiply it with three, because we run box blur three times. - result.inflateX(3 * kernelSizeX * 0.5f); - result.inflateY(3 * kernelSizeY * 0.5f); + result.inflateX(3 * kernelSize.width() * 0.5f); + result.inflateY(3 * kernelSize.height() * 0.5f); return result; } -void FEGaussianBlur::applySoftware() +FloatRect FEGaussianBlur::determineAbsolutePaintRect(const FloatRect& originalRequestedRect) { - FilterEffect* in = inputEffect(0); - - Uint8ClampedArray* srcPixelArray = createPremultipliedImageResult(); - if (!srcPixelArray) - return; - - setIsAlphaImage(in->isAlphaImage()); - - IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); - in->copyPremultipliedImage(srcPixelArray, effectDrawingRect); - - if (!m_stdX && !m_stdY) - return; - - unsigned kernelSizeX = 0; - unsigned kernelSizeY = 0; - calculateKernelSize(filter(), kernelSizeX, kernelSizeY, m_stdX, m_stdY); + FloatRect requestedRect = originalRequestedRect; + if (clipsToBounds()) + requestedRect.intersect(maxEffectRect()); - IntSize paintSize = absolutePaintRect().size(); - RefPtr<Uint8ClampedArray> tmpImageData = Uint8ClampedArray::createUninitialized(paintSize.width() * paintSize.height() * 4); - Uint8ClampedArray* tmpPixelArray = tmpImageData.get(); + FilterEffect* input = inputEffect(0); + FloatRect inputRect = input->determineAbsolutePaintRect(mapRect(requestedRect, false)); + FloatRect outputRect = mapRect(inputRect, true); + outputRect.intersect(requestedRect); + addAbsolutePaintRect(outputRect); - platformApply(srcPixelArray, tmpPixelArray, kernelSizeX, kernelSizeY, paintSize); + // Blur needs space for both input and output pixels in the paint area. + // Input is also clipped to subregion. + if (clipsToBounds()) + inputRect.intersect(maxEffectRect()); + addAbsolutePaintRect(inputRect); + return outputRect; } -bool FEGaussianBlur::applySkia() +void FEGaussianBlur::applySoftware() { ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) - return false; + return; FilterEffect* in = inputEffect(0); @@ -326,13 +157,13 @@ bool FEGaussianBlur::applySkia() SkPaint paint; GraphicsContext* dstContext = resultImage->context(); - paint.setImageFilter(new SkBlurImageFilter(stdX, stdY))->unref(); + paint.setImageFilter(SkBlurImageFilter::Create(stdX, stdY))->unref(); - dstContext->saveLayer(0, &paint); + SkRect bounds = SkRect::MakeWH(absolutePaintRect().width(), absolutePaintRect().height()); + dstContext->saveLayer(&bounds, &paint); paint.setColor(0xFFFFFFFF); dstContext->drawImage(image.get(), drawingRegion.location(), CompositeCopy); dstContext->restoreLayer(); - return true; } PassRefPtr<SkImageFilter> FEGaussianBlur::createImageFilter(SkiaImageFilterBuilder* builder) @@ -341,7 +172,7 @@ PassRefPtr<SkImageFilter> FEGaussianBlur::createImageFilter(SkiaImageFilterBuild float stdX = filter()->applyHorizontalScale(m_stdX); float stdY = filter()->applyVerticalScale(m_stdY); SkImageFilter::CropRect rect = getCropRect(builder->cropOffset()); - return adoptRef(new SkBlurImageFilter(SkFloatToScalar(stdX), SkFloatToScalar(stdY), input.get(), &rect)); + return adoptRef(SkBlurImageFilter::Create(SkFloatToScalar(stdX), SkFloatToScalar(stdY), input.get(), &rect)); } TextStream& FEGaussianBlur::externalRepresentation(TextStream& ts, int indent) const @@ -354,10 +185,4 @@ TextStream& FEGaussianBlur::externalRepresentation(TextStream& ts, int indent) c return ts; } -float FEGaussianBlur::calculateStdDeviation(float radius) -{ - // Blur radius represents 2/3 times the kernel size, the dest pixel is half of the radius applied 3 times - return max((radius * 2 / 3.f - 0.5f) / gaussianKernelFactor(), 0.f); -} - } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEGaussianBlur.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEGaussianBlur.h index 1974bea46d6..c10d220d941 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEGaussianBlur.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEGaussianBlur.h @@ -38,14 +38,12 @@ public: float stdDeviationY() const; void setStdDeviationY(float); - static float calculateStdDeviation(float); - - virtual void determineAbsolutePaintRect(); virtual FloatRect mapRect(const FloatRect&, bool forward = true) OVERRIDE FINAL; - static void calculateKernelSize(Filter*, unsigned& kernelSizeX, unsigned& kernelSizeY, float stdX, float stdY); - static void calculateUnscaledKernelSize(unsigned& kernelSizeX, unsigned& kernelSizeY, float stdX, float stdY); + virtual FloatRect determineAbsolutePaintRect(const FloatRect& requestedRect) OVERRIDE; + static IntSize calculateKernelSize(Filter*, const FloatPoint& std); + static IntSize calculateUnscaledKernelSize(const FloatPoint& std); - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; private: static const int s_minimalRectDimension = 100 * 100; // Empirical data limit for parallel jobs @@ -63,51 +61,16 @@ private: unsigned kernelSizeY; }; - static void platformApplyWorker(PlatformApplyParameters*); - FEGaussianBlur(Filter*, float, float); virtual void applySoftware() OVERRIDE; - virtual bool applySkia() OVERRIDE; - static inline void kernelPosition(int boxBlur, unsigned& std, int& dLeft, int& dRight); - inline void platformApply(Uint8ClampedArray* srcPixelArray, Uint8ClampedArray* tmpPixelArray, unsigned kernelSizeX, unsigned kernelSizeY, IntSize& paintSize); - - inline void platformApplyGeneric(Uint8ClampedArray* srcPixelArray, Uint8ClampedArray* tmpPixelArray, unsigned kernelSizeX, unsigned kernelSizeY, IntSize& paintSize); virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; float m_stdX; float m_stdY; }; -inline void FEGaussianBlur::kernelPosition(int boxBlur, unsigned& std, int& dLeft, int& dRight) -{ - // check http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement for details - switch (boxBlur) { - case 0: - if (!(std % 2)) { - dLeft = std / 2 - 1; - dRight = std - dLeft; - } else { - dLeft = std / 2; - dRight = std - dLeft; - } - break; - case 1: - if (!(std % 2)) { - dLeft++; - dRight--; - } - break; - case 2: - if (!(std % 2)) { - dRight++; - std++; - } - break; - } -} - } // namespace WebCore #endif // FEGaussianBlur_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FELighting.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FELighting.cpp index 92efec12059..8e6bc1818ac 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FELighting.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FELighting.cpp @@ -29,7 +29,6 @@ #include "platform/graphics/filters/FELighting.h" #include "SkLightingImageFilter.h" -#include "platform/graphics/cpu/arm/filters/FELightingNEON.h" #include "platform/graphics/filters/DistantLightSource.h" #include "platform/graphics/filters/ParallelJobs.h" #include "platform/graphics/filters/SkiaImageFilterBuilder.h" @@ -45,14 +44,22 @@ FELighting::FELighting(Filter* filter, LightingType lightingType, const Color& l , m_lightSource(lightSource) , m_lightingColor(lightingColor) , m_surfaceScale(surfaceScale) - , m_diffuseConstant(diffuseConstant) - , m_specularConstant(specularConstant) - , m_specularExponent(specularExponent) + , m_diffuseConstant(std::max(diffuseConstant, 0.0f)) + , m_specularConstant(std::max(specularConstant, 0.0f)) + , m_specularExponent(std::min(std::max(specularExponent, 1.0f), 128.0f)) , m_kernelUnitLengthX(kernelUnitLengthX) , m_kernelUnitLengthY(kernelUnitLengthY) { } +FloatRect FELighting::mapPaintRect(const FloatRect& rect, bool) +{ + FloatRect result = rect; + // The areas affected need to be a pixel bigger to accommodate the Sobel kernel. + result.inflate(1); + return result; +} + const static int cPixelSize = 4; const static int cAlphaChannelOffset = 3; const static unsigned char cOpaqueAlpha = static_cast<unsigned char>(0xff); @@ -179,7 +186,7 @@ inline void FELighting::LightingData::bottomRight(int offset, IntPoint& normalVe inline void FELighting::inlineSetPixel(int offset, LightingData& data, LightSource::PaintingData& paintingData, int lightX, int lightY, float factorX, float factorY, IntPoint& normal2DVector) { - m_lightSource->updatePaintingData(paintingData, lightX, lightY, static_cast<float>(data.pixels->item(offset + cAlphaChannelOffset)) * data.surfaceScale); + data.lightSource->updatePaintingData(paintingData, lightX, lightY, static_cast<float>(data.pixels->item(offset + cAlphaChannelOffset)) * data.surfaceScale); float lightStrength; if (!normal2DVector.x() && !normal2DVector.y()) { @@ -286,12 +293,21 @@ inline void FELighting::platformApplyGeneric(LightingData& data, LightSource::Pa inline void FELighting::platformApply(LightingData& data, LightSource::PaintingData& paintingData) { - // The selection here eventually should happen dynamically on some platforms. -#if CPU(ARM_NEON) && CPU(ARM_TRADITIONAL) && COMPILER(GCC) - platformApplyNeon(data, paintingData); -#else platformApplyGeneric(data, paintingData); -#endif +} + +void FELighting::getTransform(FloatPoint3D* scale, FloatSize* offset) const +{ + FloatRect initialEffectRect = effectBoundaries(); + FloatRect absoluteEffectRect = filter()->mapLocalRectToAbsoluteRect(initialEffectRect); + FloatPoint absoluteLocation(absolutePaintRect().location()); + FloatSize positionOffset(absoluteLocation - absoluteEffectRect.location()); + offset->setWidth(positionOffset.width()); + offset->setHeight(positionOffset.height()); + scale->setX(initialEffectRect.width() > 0.0f && initialEffectRect.width() > 0.0f ? absoluteEffectRect.width() / initialEffectRect.width() : 1.0f); + scale->setY(initialEffectRect.height() > 0.0f && initialEffectRect.height() > 0.0f ? absoluteEffectRect.height() / initialEffectRect.height() : 1.0f); + // X and Y scale should be the same, but, if not, do a best effort by averaging the 2 for Z scale + scale->setZ(0.5f * (scale->x() + scale->y())); } bool FELighting::drawLighting(Uint8ClampedArray* pixels, int width, int height) @@ -312,8 +328,14 @@ bool FELighting::drawLighting(Uint8ClampedArray* pixels, int width, int height) data.widthMultipliedByPixelSize = width * cPixelSize; data.widthDecreasedByOne = width - 1; data.heightDecreasedByOne = height - 1; - paintingData.colorVector = FloatPoint3D(m_lightingColor.red(), m_lightingColor.green(), m_lightingColor.blue()); - m_lightSource->initPaintingData(paintingData); + FloatPoint3D worldScale; + FloatSize originOffset; + getTransform(&worldScale, &originOffset); + RefPtr<LightSource> lightSource = m_lightSource->create(worldScale, originOffset); + data.lightSource = lightSource.get(); + Color lightColor = adaptColorToOperatingColorSpace(m_lightingColor); + paintingData.colorVector = FloatPoint3D(lightColor.red(), lightColor.green(), lightColor.blue()); + data.lightSource->initPaintingData(paintingData); // Top/Left corner. IntPoint normalVector; @@ -413,7 +435,8 @@ void FELighting::applySoftware() PassRefPtr<SkImageFilter> FELighting::createImageFilter(SkiaImageFilterBuilder* builder) { SkImageFilter::CropRect rect = getCropRect(builder ? builder->cropOffset() : FloatSize()); - RefPtr<SkImageFilter> input(builder ? builder->build(inputEffect(0), operatingColorSpace()) : 0); + Color lightColor = adaptColorToOperatingColorSpace(m_lightingColor); + RefPtr<SkImageFilter> input(builder ? builder->build(inputEffect(0), operatingColorSpace()) : nullptr); switch (m_lightSource->type()) { case LS_DISTANT: { DistantLightSource* distantLightSource = static_cast<DistantLightSource*>(m_lightSource.get()); @@ -423,16 +446,16 @@ PassRefPtr<SkImageFilter> FELighting::createImageFilter(SkiaImageFilterBuilder* sinf(azimuthRad) * cosf(elevationRad), sinf(elevationRad)); if (m_specularConstant > 0) - return adoptRef(SkLightingImageFilter::CreateDistantLitSpecular(direction, m_lightingColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get(), &rect)); - return adoptRef(SkLightingImageFilter::CreateDistantLitDiffuse(direction, m_lightingColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get(), &rect)); + return adoptRef(SkLightingImageFilter::CreateDistantLitSpecular(direction, lightColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get(), &rect)); + return adoptRef(SkLightingImageFilter::CreateDistantLitDiffuse(direction, lightColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get(), &rect)); } case LS_POINT: { PointLightSource* pointLightSource = static_cast<PointLightSource*>(m_lightSource.get()); FloatPoint3D position = pointLightSource->position(); SkPoint3 skPosition(position.x(), position.y(), position.z()); if (m_specularConstant > 0) - return adoptRef(SkLightingImageFilter::CreatePointLitSpecular(skPosition, m_lightingColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get(), &rect)); - return adoptRef(SkLightingImageFilter::CreatePointLitDiffuse(skPosition, m_lightingColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get(), &rect)); + return adoptRef(SkLightingImageFilter::CreatePointLitSpecular(skPosition, lightColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get(), &rect)); + return adoptRef(SkLightingImageFilter::CreatePointLitDiffuse(skPosition, lightColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get(), &rect)); } case LS_SPOT: { SpotLightSource* spotLightSource = static_cast<SpotLightSource*>(m_lightSource.get()); @@ -443,43 +466,13 @@ PassRefPtr<SkImageFilter> FELighting::createImageFilter(SkiaImageFilterBuilder* if (!limitingConeAngle || limitingConeAngle > 90 || limitingConeAngle < -90) limitingConeAngle = 90; if (m_specularConstant > 0) - return adoptRef(SkLightingImageFilter::CreateSpotLitSpecular(location, target, specularExponent, limitingConeAngle, m_lightingColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get(), &rect)); - return adoptRef(SkLightingImageFilter::CreateSpotLitDiffuse(location, target, specularExponent, limitingConeAngle, m_lightingColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get(), &rect)); + return adoptRef(SkLightingImageFilter::CreateSpotLitSpecular(location, target, specularExponent, limitingConeAngle, lightColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get(), &rect)); + return adoptRef(SkLightingImageFilter::CreateSpotLitDiffuse(location, target, specularExponent, limitingConeAngle, lightColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get(), &rect)); } default: ASSERT_NOT_REACHED(); - return 0; + return nullptr; } } -bool FELighting::applySkia() -{ - // For now, only use the skia implementation for accelerated rendering. - if (!filter()->isAccelerated()) - return false; - - ImageBuffer* resultImage = createImageBufferResult(); - if (!resultImage) - return false; - - FilterEffect* in = inputEffect(0); - - IntRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); - - setIsAlphaImage(in->isAlphaImage()); - - RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore); - RefPtr<NativeImageSkia> nativeImage = image->nativeImageForCurrentFrame(); - if (!nativeImage) - return false; - - GraphicsContext* dstContext = resultImage->context(); - - SkPaint paint; - RefPtr<SkImageFilter> filter = createImageFilter(0); - paint.setImageFilter(filter.get()); - dstContext->drawBitmap(nativeImage->bitmap(), drawingRegion.location().x(), drawingRegion.location().y(), &paint); - return true; -} - } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FELighting.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FELighting.h index 32fdc122005..123fe51619f 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FELighting.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FELighting.h @@ -40,14 +40,10 @@ namespace WebCore { -struct FELightingPaintingDataForNeon; - class PLATFORM_EXPORT FELighting : public FilterEffect { public: virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; - virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); } - protected: static const int s_minimalRectDimension = 100 * 100; // Empirical data limit for parallel jobs @@ -63,6 +59,7 @@ protected: int widthMultipliedByPixelSize; int widthDecreasedByOne; int heightDecreasedByOne; + const LightSource* lightSource; inline void topLeft(int offset, IntPoint& normalVector); inline void topRow(int offset, IntPoint& normalVector); @@ -86,8 +83,10 @@ protected: int yEnd; }; + virtual FloatRect mapPaintRect(const FloatRect&, bool forward = true) OVERRIDE FINAL; + virtual bool affectsTransparentPixels() OVERRIDE { return true; } + static void platformApplyGenericWorker(PlatformApplyGenericParameters*); - static void platformApplyNeonWorker(FELightingPaintingDataForNeon*); FELighting(Filter*, LightingType, const Color&, float, float, float, float, float, float, PassRefPtr<LightSource>); @@ -104,9 +103,6 @@ protected: inline void platformApplyGenericPaint(LightingData&, LightSource::PaintingData&, int startX, int startY); inline void platformApplyGeneric(LightingData&, LightSource::PaintingData&); - static int getPowerCoefficients(float exponent); - inline void platformApplyNeon(LightingData&, LightSource::PaintingData&); - LightingType m_lightingType; RefPtr<LightSource> m_lightSource; @@ -120,7 +116,8 @@ protected: private: virtual void applySoftware() OVERRIDE; - virtual bool applySkia() OVERRIDE; + + void getTransform(FloatPoint3D* scale, FloatSize* offset) const; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMerge.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMerge.cpp index c31440d44c4..3845ffe0e22 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMerge.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMerge.cpp @@ -68,7 +68,7 @@ PassRefPtr<SkImageFilter> FEMerge::createImageFilter(SkiaImageFilterBuilder* bui inputs[i] = inputRefs[i].get(); } SkImageFilter::CropRect rect = getCropRect(builder->cropOffset()); - return adoptRef(new SkMergeImageFilter(inputs.get(), size, 0, &rect)); + return adoptRef(SkMergeImageFilter::Create(inputs.get(), size, 0, &rect)); } TextStream& FEMerge::externalRepresentation(TextStream& ts, int indent) const diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMerge.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMerge.h index 05e374e58e4..22fd7fc560f 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMerge.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMerge.h @@ -35,7 +35,7 @@ public: virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; private: FEMerge(Filter*); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMorphology.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMorphology.cpp index 5201a45dcde..00483e803b0 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMorphology.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMorphology.cpp @@ -26,6 +26,8 @@ #include "platform/graphics/filters/FEMorphology.h" #include "SkMorphologyImageFilter.h" +#include "platform/graphics/GraphicsContext.h" +#include "platform/graphics/Image.h" #include "platform/graphics/filters/ParallelJobs.h" #include "platform/graphics/filters/SkiaImageFilterBuilder.h" #include "platform/text/TextStream.h" @@ -80,16 +82,6 @@ float FEMorphology::radiusY() const return m_radiusY; } -void FEMorphology::determineAbsolutePaintRect() -{ - FloatRect paintRect = mapRect(inputEffect(0)->absolutePaintRect()); - if (clipsToBounds()) - paintRect.intersect(maxEffectRect()); - else - paintRect.unite(maxEffectRect()); - setAbsolutePaintRect(enclosingIntRect(paintRect)); -} - FloatRect FEMorphology::mapRect(const FloatRect& rect, bool) { FloatRect result = rect; @@ -106,135 +98,11 @@ bool FEMorphology::setRadiusY(float radiusY) return true; } -void FEMorphology::platformApplyGeneric(PaintingData* paintingData, int yStart, int yEnd) -{ - Uint8ClampedArray* srcPixelArray = paintingData->srcPixelArray; - Uint8ClampedArray* dstPixelArray = paintingData->dstPixelArray; - const int width = paintingData->width; - const int height = paintingData->height; - const int effectWidth = width * 4; - const int radiusX = paintingData->radiusX; - const int radiusY = paintingData->radiusY; - - Vector<unsigned char> extrema; - for (int y = yStart; y < yEnd; ++y) { - int extremaStartY = max(0, y - radiusY); - int extremaEndY = min(height - 1, y + radiusY); - for (unsigned clrChannel = 0; clrChannel < 4; ++clrChannel) { - extrema.clear(); - // Compute extremas for each columns - for (int x = 0; x <= radiusX; ++x) { - unsigned char columnExtrema = srcPixelArray->item(extremaStartY * effectWidth + 4 * x + clrChannel); - for (int eY = extremaStartY + 1; eY < extremaEndY; ++eY) { - unsigned char pixel = srcPixelArray->item(eY * effectWidth + 4 * x + clrChannel); - if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) - || (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema)) { - columnExtrema = pixel; - } - } - - extrema.append(columnExtrema); - } - - // Kernel is filled, get extrema of next column - for (int x = 0; x < width; ++x) { - const int endX = min(x + radiusX, width - 1); - unsigned char columnExtrema = srcPixelArray->item(extremaStartY * effectWidth + endX * 4 + clrChannel); - for (int i = extremaStartY + 1; i <= extremaEndY; ++i) { - unsigned char pixel = srcPixelArray->item(i * effectWidth + endX * 4 + clrChannel); - if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) - || (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema)) - columnExtrema = pixel; - } - if (x - radiusX >= 0) - extrema.remove(0); - if (x + radiusX <= width) - extrema.append(columnExtrema); - - unsigned char entireExtrema = extrema[0]; - for (unsigned kernelIndex = 1; kernelIndex < extrema.size(); ++kernelIndex) { - if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && extrema[kernelIndex] <= entireExtrema) - || (m_type == FEMORPHOLOGY_OPERATOR_DILATE && extrema[kernelIndex] >= entireExtrema)) - entireExtrema = extrema[kernelIndex]; - } - dstPixelArray->set(y * effectWidth + 4 * x + clrChannel, entireExtrema); - } - } - } -} - -void FEMorphology::platformApplyWorker(PlatformApplyParameters* param) -{ - param->filter->platformApplyGeneric(param->paintingData, param->startY, param->endY); -} - -void FEMorphology::platformApply(PaintingData* paintingData) -{ - int optimalThreadNumber = (paintingData->width * paintingData->height) / s_minimalArea; - if (optimalThreadNumber > 1) { - ParallelJobs<PlatformApplyParameters> parallelJobs(&WebCore::FEMorphology::platformApplyWorker, optimalThreadNumber); - int numOfThreads = parallelJobs.numberOfJobs(); - if (numOfThreads > 1) { - // Split the job into "jobSize"-sized jobs but there a few jobs that need to be slightly larger since - // jobSize * jobs < total size. These extras are handled by the remainder "jobsWithExtra". - const int jobSize = paintingData->height / numOfThreads; - const int jobsWithExtra = paintingData->height % numOfThreads; - int currentY = 0; - for (int job = numOfThreads - 1; job >= 0; --job) { - PlatformApplyParameters& param = parallelJobs.parameter(job); - param.filter = this; - param.startY = currentY; - currentY += job < jobsWithExtra ? jobSize + 1 : jobSize; - param.endY = currentY; - param.paintingData = paintingData; - } - parallelJobs.execute(); - return; - } - // Fallback to single thread model - } - - platformApplyGeneric(paintingData, 0, paintingData->height); -} - - void FEMorphology::applySoftware() { - FilterEffect* in = inputEffect(0); - - Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult(); - if (!dstPixelArray) - return; - - setIsAlphaImage(in->isAlphaImage()); - if (m_radiusX <= 0 || m_radiusY <= 0) { - dstPixelArray->zeroFill(); - return; - } - - Filter* filter = this->filter(); - int radiusX = static_cast<int>(floorf(filter->applyHorizontalScale(m_radiusX))); - int radiusY = static_cast<int>(floorf(filter->applyVerticalScale(m_radiusY))); - - IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); - RefPtr<Uint8ClampedArray> srcPixelArray = in->asPremultipliedImage(effectDrawingRect); - - PaintingData paintingData; - paintingData.srcPixelArray = srcPixelArray.get(); - paintingData.dstPixelArray = dstPixelArray; - paintingData.width = effectDrawingRect.width(); - paintingData.height = effectDrawingRect.height(); - paintingData.radiusX = min(effectDrawingRect.width() - 1, radiusX); - paintingData.radiusY = min(effectDrawingRect.height() - 1, radiusY); - - platformApply(&paintingData); -} - -bool FEMorphology::applySkia() -{ ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) - return false; + return; FilterEffect* in = inputEffect(0); @@ -250,14 +118,14 @@ bool FEMorphology::applySkia() SkPaint paint; GraphicsContext* dstContext = resultImage->context(); if (m_type == FEMORPHOLOGY_OPERATOR_DILATE) - paint.setImageFilter(new SkDilateImageFilter(radiusX, radiusY))->unref(); + paint.setImageFilter(SkDilateImageFilter::Create(radiusX, radiusY))->unref(); else if (m_type == FEMORPHOLOGY_OPERATOR_ERODE) - paint.setImageFilter(new SkErodeImageFilter(radiusX, radiusY))->unref(); + paint.setImageFilter(SkErodeImageFilter::Create(radiusX, radiusY))->unref(); - dstContext->saveLayer(0, &paint); + SkRect bounds = SkRect::MakeWH(absolutePaintRect().width(), absolutePaintRect().height()); + dstContext->saveLayer(&bounds, &paint); dstContext->drawImage(image.get(), drawingRegion.location(), CompositeCopy); dstContext->restoreLayer(); - return true; } PassRefPtr<SkImageFilter> FEMorphology::createImageFilter(SkiaImageFilterBuilder* builder) @@ -267,8 +135,8 @@ PassRefPtr<SkImageFilter> FEMorphology::createImageFilter(SkiaImageFilterBuilder SkScalar radiusY = SkFloatToScalar(filter()->applyVerticalScale(m_radiusY)); SkImageFilter::CropRect rect = getCropRect(builder->cropOffset()); if (m_type == FEMORPHOLOGY_OPERATOR_DILATE) - return adoptRef(new SkDilateImageFilter(radiusX, radiusY, input.get(), &rect)); - return adoptRef(new SkErodeImageFilter(radiusX, radiusY, input.get(), &rect)); + return adoptRef(SkDilateImageFilter::Create(radiusX, radiusY, input.get(), &rect)); + return adoptRef(SkErodeImageFilter::Create(radiusX, radiusY, input.get(), &rect)); } static TextStream& operator<<(TextStream& ts, const MorphologyOperatorType& type) diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMorphology.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMorphology.h index 6b596bf6ea5..6ed926a3341 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMorphology.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEMorphology.h @@ -48,10 +48,9 @@ public: virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; - virtual void determineAbsolutePaintRect(); virtual FloatRect mapRect(const FloatRect&, bool forward = true) OVERRIDE FINAL; - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; struct PaintingData { Uint8ClampedArray* srcPixelArray; @@ -71,15 +70,10 @@ public: PaintingData* paintingData; }; - static void platformApplyWorker(PlatformApplyParameters*); - - inline void platformApply(PaintingData*); - inline void platformApplyGeneric(PaintingData*, const int yStart, const int yEnd); private: FEMorphology(Filter*, MorphologyOperatorType, float radiusX, float radiusY); virtual void applySoftware() OVERRIDE; - virtual bool applySkia() OVERRIDE; MorphologyOperatorType m_type; float m_radiusX; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEOffset.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEOffset.cpp index d9a27788890..a978882eae4 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEOffset.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEOffset.cpp @@ -66,25 +66,13 @@ void FEOffset::setDy(float dy) m_dy = dy; } -void FEOffset::determineAbsolutePaintRect() -{ - FloatRect paintRect = inputEffect(0)->absolutePaintRect(); - Filter* filter = this->filter(); - paintRect.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy)); - if (clipsToBounds()) - paintRect.intersect(maxEffectRect()); - else - paintRect.unite(maxEffectRect()); - setAbsolutePaintRect(enclosingIntRect(paintRect)); -} - FloatRect FEOffset::mapRect(const FloatRect& rect, bool forward) { FloatRect result = rect; if (forward) - result.move(filter()->applyHorizontalScale(m_dx), filter()->applyHorizontalScale(m_dy)); + result.move(filter()->applyHorizontalScale(m_dx), filter()->applyVerticalScale(m_dy)); else - result.move(-filter()->applyHorizontalScale(m_dx), -filter()->applyHorizontalScale(m_dy)); + result.move(-filter()->applyHorizontalScale(m_dx), -filter()->applyVerticalScale(m_dy)); return result; } @@ -109,7 +97,7 @@ PassRefPtr<SkImageFilter> FEOffset::createImageFilter(SkiaImageFilterBuilder* bu RefPtr<SkImageFilter> input(builder->build(inputEffect(0), operatingColorSpace())); Filter* filter = this->filter(); SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset()); - return adoptRef(new SkOffsetImageFilter(SkFloatToScalar(filter->applyHorizontalScale(m_dx)), SkFloatToScalar(filter->applyVerticalScale(m_dy)), input.get(), &cropRect)); + return adoptRef(SkOffsetImageFilter::Create(SkFloatToScalar(filter->applyHorizontalScale(m_dx)), SkFloatToScalar(filter->applyVerticalScale(m_dy)), input.get(), &cropRect)); } TextStream& FEOffset::externalRepresentation(TextStream& ts, int indent) const diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEOffset.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEOffset.h index 6ed388d8cb8..774497c6f53 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FEOffset.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FEOffset.h @@ -38,10 +38,9 @@ public: float dy() const; void setDy(float); - virtual void determineAbsolutePaintRect(); virtual FloatRect mapRect(const FloatRect&, bool forward = true) OVERRIDE FINAL; - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FESpecularLighting.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FESpecularLighting.cpp index 5a87f10d0d8..cc3ed427d44 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FESpecularLighting.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FESpecularLighting.cpp @@ -80,6 +80,7 @@ float FESpecularLighting::specularConstant() const bool FESpecularLighting::setSpecularConstant(float specularConstant) { + specularConstant = std::max(specularConstant, 0.0f); if (m_specularConstant == specularConstant) return false; m_specularConstant = specularConstant; @@ -93,6 +94,7 @@ float FESpecularLighting::specularExponent() const bool FESpecularLighting::setSpecularExponent(float specularExponent) { + specularExponent = std::min(std::max(specularExponent, 1.0f), 128.0f); if (m_specularExponent == specularExponent) return false; m_specularExponent = specularExponent; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FESpecularLighting.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FESpecularLighting.h index fd33b0c086b..fd314ab8432 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FESpecularLighting.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FESpecularLighting.h @@ -54,7 +54,7 @@ public: const LightSource* lightSource() const; void setLightSource(PassRefPtr<LightSource>); - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; private: FESpecularLighting(Filter*, const Color&, float, float, float, float, float, PassRefPtr<LightSource>); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FETile.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FETile.cpp index 2e865d3141f..bcbe9fb7d80 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FETile.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FETile.cpp @@ -29,7 +29,6 @@ #include "platform/graphics/Pattern.h" #include "platform/graphics/UnacceleratedImageBufferSurface.h" #include "platform/graphics/filters/SkiaImageFilterBuilder.h" -#include "platform/graphics/gpu/AcceleratedImageBufferSurface.h" #include "platform/text/TextStream.h" #include "platform/transforms/AffineTransform.h" #include "third_party/skia/include/core/SkDevice.h" @@ -46,6 +45,11 @@ PassRefPtr<FETile> FETile::create(Filter* filter) return adoptRef(new FETile(filter)); } +FloatRect FETile::mapPaintRect(const FloatRect& rect, bool forward) +{ + return forward ? maxEffectRect() : inputEffect(0)->maxEffectRect(); +} + void FETile::applySoftware() { FilterEffect* in = inputEffect(0); @@ -64,25 +68,21 @@ void FETile::applySoftware() if (in->filterEffectType() == FilterEffectTypeSourceInput) { Filter* filter = this->filter(); tileRect = filter->absoluteFilterRegion(); - tileRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); } OwnPtr<ImageBufferSurface> surface; IntSize intTileSize = roundedIntSize(tileRect.size()); - if (filter()->isAccelerated()) { - surface = adoptPtr(new AcceleratedImageBufferSurface(intTileSize)); - } - if (!surface || !surface->isValid()) { - surface = adoptPtr(new UnacceleratedImageBufferSurface(intTileSize)); - } + surface = adoptPtr(new UnacceleratedImageBufferSurface(intTileSize)); OwnPtr<ImageBuffer> tileImage = ImageBuffer::create(surface.release()); if (!tileImage) return; GraphicsContext* tileImageContext = tileImage->context(); - tileImageContext->scale(FloatSize(intTileSize.width() / tileRect.width(), intTileSize.height() / tileRect.height())); + tileImageContext->scale(intTileSize.width() / tileRect.width(), intTileSize.height() / tileRect.height()); tileImageContext->translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y()); - tileImageContext->drawImageBuffer(in->asImageBuffer(), in->absolutePaintRect().location()); + + if (ImageBuffer* tileImageBuffer = in->asImageBuffer()) + tileImageContext->drawImageBuffer(tileImageBuffer, IntRect(in->absolutePaintRect().location(), tileImageBuffer->size())); RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(CopyBackingStore), true, true); @@ -94,11 +94,27 @@ void FETile::applySoftware() filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size())); } +static FloatRect getRect(FilterEffect* effect) +{ + FloatRect result = effect->filter()->filterRegion(); + FloatRect boundaries = effect->effectBoundaries(); + if (effect->hasX()) + result.setX(boundaries.x()); + if (effect->hasY()) + result.setY(boundaries.y()); + if (effect->hasWidth()) + result.setWidth(boundaries.width()); + if (effect->hasHeight()) + result.setHeight(boundaries.height()); + return result; +} + PassRefPtr<SkImageFilter> FETile::createImageFilter(SkiaImageFilterBuilder* builder) { RefPtr<SkImageFilter> input(builder->build(inputEffect(0), operatingColorSpace())); - FloatRect srcRect = inputEffect(0) ? inputEffect(0)->effectBoundaries() : FloatRect(); - return adoptRef(new SkTileImageFilter(srcRect, effectBoundaries(), input.get())); + FloatRect srcRect = inputEffect(0) ? getRect(inputEffect(0)) : filter()->filterRegion(); + FloatRect dstRect = getRect(this); + return adoptRef(SkTileImageFilter::Create(srcRect, dstRect, input.get())); } TextStream& FETile::externalRepresentation(TextStream& ts, int indent) const diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FETile.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FETile.h index ece013c816d..5d882338ca7 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FETile.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FETile.h @@ -34,11 +34,11 @@ public: virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; - virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); } + virtual FloatRect mapPaintRect(const FloatRect&, bool forward = true) OVERRIDE FINAL; - virtual FilterEffectType filterEffectType() const { return FilterEffectTypeTile; } + virtual FilterEffectType filterEffectType() const OVERRIDE { return FilterEffectTypeTile; } - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; private: FETile(Filter*); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FETurbulence.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FETurbulence.cpp index a6a4e826182..cb123da3e2b 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FETurbulence.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FETurbulence.cpp @@ -364,8 +364,6 @@ void FETurbulence::applySoftware() PaintingData paintingData(m_seed, roundedIntSize(filterPrimitiveSubregion().size())); initPaint(paintingData); - float baseFrequencyX = 1.0f / filter()->applyHorizontalScale(1.0f / m_baseFrequencyX); - float baseFrequencyY = 1.0f / filter()->applyVerticalScale(1.0f / m_baseFrequencyY); int optimalThreadNumber = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension; if (optimalThreadNumber > 1) { @@ -389,8 +387,8 @@ void FETurbulence::applySoftware() params.startY = startY; startY += i < jobsWithExtra ? stepY + 1 : stepY; params.endY = startY; - params.baseFrequencyX = baseFrequencyX; - params.baseFrequencyY = baseFrequencyY; + params.baseFrequencyX = m_baseFrequencyX; + params.baseFrequencyY = m_baseFrequencyY; } // Execute parallel jobs @@ -400,44 +398,32 @@ void FETurbulence::applySoftware() } // Fallback to single threaded mode if there is no room for a new thread or the paint area is too small. - fillRegion(pixelArray, paintingData, 0, absolutePaintRect().height(), baseFrequencyX, baseFrequencyY); + fillRegion(pixelArray, paintingData, 0, absolutePaintRect().height(), m_baseFrequencyX, m_baseFrequencyY); } -SkShader* FETurbulence::createShader(const IntRect& filterRegion) +SkShader* FETurbulence::createShader() { - const SkISize size = SkISize::Make(filterRegion.width(), filterRegion.height()); - float baseFrequencyX = 1.0f / filter()->applyHorizontalScale(1.0f / m_baseFrequencyX); - const float baseFrequencyY = 1.0f / filter()->applyVerticalScale(1.0f / m_baseFrequencyY); + const SkISize size = SkISize::Make(effectBoundaries().width(), effectBoundaries().height()); + // Frequency should be scaled by page zoom, but not by primitiveUnits. + // So we apply only the transform scale (as Filter::apply*Scale() do) + // and not the target bounding box scale (as SVGFilter::apply*Scale() + // would do). Note also that we divide by the scale since this is + // a frequency, not a period. + const AffineTransform& absoluteTransform = filter()->absoluteTransform(); + float baseFrequencyX = m_baseFrequencyX / absoluteTransform.a(); + float baseFrequencyY = m_baseFrequencyY / absoluteTransform.d(); return (type() == FETURBULENCE_TYPE_FRACTALNOISE) ? SkPerlinNoiseShader::CreateFractalNoise(SkFloatToScalar(baseFrequencyX), SkFloatToScalar(baseFrequencyY), numOctaves(), SkFloatToScalar(seed()), stitchTiles() ? &size : 0) : - SkPerlinNoiseShader::CreateTubulence(SkFloatToScalar(baseFrequencyX), + SkPerlinNoiseShader::CreateTurbulence(SkFloatToScalar(baseFrequencyX), SkFloatToScalar(baseFrequencyY), numOctaves(), SkFloatToScalar(seed()), stitchTiles() ? &size : 0); } -bool FETurbulence::applySkia() -{ - // For now, only use the skia implementation for accelerated rendering. - if (!filter()->isAccelerated()) - return false; - - ImageBuffer* resultImage = createImageBufferResult(); - if (!resultImage) - return false; - - const IntRect filterRegion(IntPoint::zero(), absolutePaintRect().size()); - - SkPaint paint; - paint.setShader(createShader(filterRegion))->unref(); - resultImage->context()->drawRect((SkRect)filterRegion, paint); - return true; -} - PassRefPtr<SkImageFilter> FETurbulence::createImageFilter(SkiaImageFilterBuilder* builder) { - SkAutoTUnref<SkShader> shader(createShader(IntRect())); + SkAutoTUnref<SkShader> shader(createShader()); SkImageFilter::CropRect rect = getCropRect(builder->cropOffset()); return adoptRef(SkRectShaderImageFilter::Create(shader, &rect)); } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FETurbulence.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FETurbulence.h index 6b249e454c9..f5c230b26a7 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FETurbulence.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FETurbulence.h @@ -60,9 +60,7 @@ public: static void fillRegionWorker(void*); - virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); } - - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; private: static const int s_blockSize = 256; @@ -118,9 +116,8 @@ private: FETurbulence(Filter*, TurbulenceType, float, float, int, float, bool); virtual void applySoftware() OVERRIDE; - virtual bool applySkia() OVERRIDE; virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; - SkShader* createShader(const IntRect& filterRegion); + SkShader* createShader(); inline void initPaint(PaintingData&); float noise2D(int channel, PaintingData&, StitchData&, const FloatPoint&); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/Filter.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/Filter.h index 705aa5e19e4..d16659a0aff 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/Filter.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/Filter.h @@ -25,6 +25,7 @@ #include "platform/geometry/FloatRect.h" #include "platform/geometry/FloatSize.h" #include "platform/graphics/ImageBuffer.h" +#include "third_party/skia/include/core/SkImageFilter.h" #include "wtf/RefCounted.h" namespace WebCore { @@ -33,50 +34,85 @@ class FilterEffect; class PLATFORM_EXPORT Filter : public RefCounted<Filter> { public: - Filter(const AffineTransform& absoluteTransform) : m_isAccelerated(false), m_absoluteTransform(absoluteTransform) { } + Filter(const AffineTransform& absoluteTransform) + : m_absoluteTransform(absoluteTransform) + , m_inverseTransform(absoluteTransform.inverse()) + { + // Filters can only accept scaling and translating transformations, as coordinates + // in most primitives are given in horizontal and vertical directions. + ASSERT(!absoluteTransform.b() && !absoluteTransform.c()); + } virtual ~Filter() { } void setSourceImage(PassOwnPtr<ImageBuffer> sourceImage) { m_sourceImage = sourceImage; } ImageBuffer* sourceImage() { return m_sourceImage.get(); } - FloatSize filterResolution() const { return m_filterResolution; } - void setFilterResolution(const FloatSize& filterResolution) { m_filterResolution = filterResolution; } - const AffineTransform& absoluteTransform() const { return m_absoluteTransform; } - void setAbsoluteTransform(const AffineTransform& absoluteTransform) { m_absoluteTransform = absoluteTransform; } - FloatPoint mapAbsolutePointToLocalPoint(const FloatPoint& point) const { return m_absoluteTransform.inverse().mapPoint(point); } - bool isAccelerated() const { return m_isAccelerated; } - void setIsAccelerated(bool isAccelerated) { m_isAccelerated = isAccelerated; } + void setAbsoluteTransform(const AffineTransform& absoluteTransform) + { + // Filters can only accept scaling and translating transformations, as coordinates + // in most primitives are given in horizontal and vertical directions. + ASSERT(!absoluteTransform.b() && !absoluteTransform.c()); + m_absoluteTransform = absoluteTransform; + m_inverseTransform = absoluteTransform.inverse(); + m_absoluteFilterRegion = m_absoluteTransform.mapRect(m_filterRegion); + } + FloatPoint mapAbsolutePointToLocalPoint(const FloatPoint& point) const { return m_inverseTransform.mapPoint(point); } + FloatRect mapLocalRectToAbsoluteRect(const FloatRect& rect) const { return m_absoluteTransform.mapRect(rect); } + FloatRect mapAbsoluteRectToLocalRect(const FloatRect& rect) const { return m_inverseTransform.mapRect(rect); } virtual float applyHorizontalScale(float value) const { - float filterRegionScale = absoluteFilterRegion().isEmpty() || filterRegion().isEmpty() ? - 1.0f : absoluteFilterRegion().width() / filterRegion().width(); - return value * m_filterResolution.width() * filterRegionScale; + return value * m_absoluteTransform.a(); } virtual float applyVerticalScale(float value) const { - float filterRegionScale = absoluteFilterRegion().isEmpty() || filterRegion().isEmpty() ? - 1.0f : absoluteFilterRegion().height() / filterRegion().height(); - return value * m_filterResolution.height() * filterRegionScale; + return value * m_absoluteTransform.d(); } + virtual FloatPoint3D resolve3dPoint(const FloatPoint3D& point) const { return point; } - virtual FloatRect sourceImageRect() const = 0; + virtual IntRect sourceImageRect() const = 0; FloatRect absoluteFilterRegion() const { return m_absoluteFilterRegion; } - void setAbsoluteFilterRegion(const FloatRect& rect) { m_absoluteFilterRegion = rect; } FloatRect filterRegion() const { return m_filterRegion; } - void setFilterRegion(const FloatRect& rect) { m_filterRegion = rect; } + void setFilterRegion(const FloatRect& rect) + { + m_filterRegion = rect; + m_absoluteFilterRegion = m_absoluteTransform.mapRect(m_filterRegion); + } + + // The methods enableCache() and disableCache() are temporary, and we + // should address the real issue inside skia, thus simplifying what the + // clients have to know, and can remove these. + // Also note that this cache should no longer be used by Blink once the + // NON impl-side painting path is removed. + void enableCache() + { + if (!m_cache) + m_cache = adoptRef(SkImageFilter::Cache::Create(1)); + SkImageFilter::SetExternalCache(m_cache.get()); + } + + void disableCache() + { + SkImageFilter::SetExternalCache(0); + } + + void removeFromCache(SkImageFilter* filter) + { + if (m_cache) + m_cache->remove(filter); + } private: OwnPtr<ImageBuffer> m_sourceImage; - FloatSize m_filterResolution; - bool m_isAccelerated; AffineTransform m_absoluteTransform; + AffineTransform m_inverseTransform; FloatRect m_absoluteFilterRegion; FloatRect m_filterRegion; + RefPtr<SkImageFilter::Cache> m_cache; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp index 2b1324298ac..518173bebe3 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp @@ -28,7 +28,6 @@ #include "platform/graphics/ImageBuffer.h" #include "platform/graphics/UnacceleratedImageBufferSurface.h" #include "platform/graphics/filters/Filter.h" -#include "platform/graphics/gpu/AcceleratedImageBufferSurface.h" #if HAVE(ARM_NEON_INTRINSICS) #include <arm_neon.h> @@ -36,6 +35,8 @@ namespace WebCore { +static const float kMaxFilterArea = 4096 * 4096; + FilterEffect::FilterEffect(Filter* filter) : m_alphaImage(false) , m_filter(filter) @@ -54,27 +55,49 @@ FilterEffect::~FilterEffect() { } -inline bool isFilterSizeValid(IntRect rect) +float FilterEffect::maxFilterArea() +{ + return kMaxFilterArea; +} + +bool FilterEffect::isFilterSizeValid(const FloatRect& rect) { - if (rect.width() < 0 || rect.width() > kMaxFilterSize - || rect.height() < 0 || rect.height() > kMaxFilterSize) + if (rect.width() < 0 || rect.height() < 0 + || (rect.height() * rect.width() > kMaxFilterArea)) return false; + return true; } -void FilterEffect::determineAbsolutePaintRect() +FloatRect FilterEffect::determineAbsolutePaintRect(const FloatRect& originalRequestedRect) { - m_absolutePaintRect = IntRect(); + FloatRect requestedRect = originalRequestedRect; + // Filters in SVG clip to primitive subregion, while CSS doesn't. + if (m_clipsToBounds) + requestedRect.intersect(maxEffectRect()); + + // We may be called multiple times if result is used more than once. Return + // quickly if if nothing new is required. + if (absolutePaintRect().contains(enclosingIntRect(requestedRect))) + return requestedRect; + + FloatRect inputRect = mapPaintRect(requestedRect, false); + FloatRect inputUnion; unsigned size = m_inputEffects.size(); + for (unsigned i = 0; i < size; ++i) - m_absolutePaintRect.unite(m_inputEffects.at(i)->absolutePaintRect()); + inputUnion.unite(m_inputEffects.at(i)->determineAbsolutePaintRect(inputRect)); + inputUnion = mapPaintRect(inputUnion, true); - // Filters in SVG clip to primitive subregion, while CSS doesn't. - if (m_clipsToBounds) - m_absolutePaintRect.intersect(enclosingIntRect(m_maxEffectRect)); - else - m_absolutePaintRect.unite(enclosingIntRect(m_maxEffectRect)); + if (affectsTransparentPixels() || !size) { + inputUnion = requestedRect; + } else { + // Rect may have inflated. Re-intersect with request. + inputUnion.intersect(requestedRect); + } + addAbsolutePaintRect(inputUnion); + return inputUnion; } FloatRect FilterEffect::mapRectRecursive(const FloatRect& rect) @@ -94,7 +117,7 @@ FloatRect FilterEffect::getSourceRect(const FloatRect& destRect, const FloatRect FloatRect sourceRect = mapRect(destRect, false); FloatRect sourceClipRect = mapRect(destClipRect, false); - FloatRect boundaries = effectBoundaries(); + FloatRect boundaries = filter()->mapLocalRectToAbsoluteRect(effectBoundaries()); if (hasX()) sourceClipRect.setX(boundaries.x()); if (hasY()) @@ -136,14 +159,33 @@ FilterEffect* FilterEffect::inputEffect(unsigned number) const return m_inputEffects.at(number).get(); } +void FilterEffect::addAbsolutePaintRect(const FloatRect& paintRect) +{ + IntRect intPaintRect(enclosingIntRect(paintRect)); + if (m_absolutePaintRect.contains(intPaintRect)) + return; + intPaintRect.unite(m_absolutePaintRect); + // Make sure we are not holding on to a smaller rendering. + clearResult(); + m_absolutePaintRect = intPaintRect; +} + void FilterEffect::apply() { + // Recursively determine paint rects first, so that we don't redraw images + // if a smaller section is requested first. + determineAbsolutePaintRect(maxEffectRect()); + applyRecursive(); +} + +void FilterEffect::applyRecursive() +{ if (hasResult()) return; unsigned size = m_inputEffects.size(); for (unsigned i = 0; i < size; ++i) { FilterEffect* in = m_inputEffects.at(i).get(); - in->apply(); + in->applyRecursive(); if (!in->hasResult()) return; @@ -151,20 +193,16 @@ void FilterEffect::apply() transformResultColorSpace(in, i); } - determineAbsolutePaintRect(); setResultColorSpace(m_operatingColorSpace); if (!isFilterSizeValid(m_absolutePaintRect)) return; - if (requiresValidPreMultipliedPixels()) { + if (!mayProduceInvalidPreMultipliedPixels()) { for (unsigned i = 0; i < size; ++i) inputEffect(i)->correctFilterResultIfNeeded(); } - if (applySkia()) - return; - applySoftware(); } @@ -225,6 +263,12 @@ void FilterEffect::clearResult() m_unmultipliedImageResult.clear(); if (m_premultipliedImageResult) m_premultipliedImageResult.clear(); + + m_absolutePaintRect = IntRect(); + for (int i = 0; i < 4; i++) { + filter()->removeFromCache(m_imageFilters[i].get()); + m_imageFilters[i] = nullptr; + } } void FilterEffect::clearResultsRecursive() @@ -246,10 +290,7 @@ ImageBuffer* FilterEffect::asImageBuffer() if (m_imageBufferResult) return m_imageBufferResult.get(); OwnPtr<ImageBufferSurface> surface; - if (m_filter->isAccelerated()) - surface = adoptPtr(new AcceleratedImageBufferSurface(m_absolutePaintRect.size())); - if (!m_filter->isAccelerated() || !surface->isValid()) - surface = adoptPtr(new UnacceleratedImageBufferSurface(m_absolutePaintRect.size())); + surface = adoptPtr(new UnacceleratedImageBufferSurface(m_absolutePaintRect.size())); m_imageBufferResult = ImageBuffer::create(surface.release()); if (!m_imageBufferResult) return 0; @@ -387,13 +428,11 @@ void FilterEffect::copyPremultipliedImage(Uint8ClampedArray* destination, const ImageBuffer* FilterEffect::createImageBufferResult() { // Only one result type is allowed. - if (m_absolutePaintRect.isEmpty()) - return 0; + ASSERT(!hasResult()); + ASSERT(isFilterSizeValid(m_absolutePaintRect)); + OwnPtr<ImageBufferSurface> surface; - if (m_filter->isAccelerated()) - surface = adoptPtr(new AcceleratedImageBufferSurface(m_absolutePaintRect.size())); - if (!m_filter->isAccelerated() || !surface->isValid()) - surface = adoptPtr(new UnacceleratedImageBufferSurface(m_absolutePaintRect.size())); + surface = adoptPtr(new UnacceleratedImageBufferSurface(m_absolutePaintRect.size())); m_imageBufferResult = ImageBuffer::create(surface.release()); return m_imageBufferResult.get(); } @@ -422,6 +461,12 @@ Uint8ClampedArray* FilterEffect::createPremultipliedImageResult() return m_premultipliedImageResult.get(); } +Color FilterEffect::adaptColorToOperatingColorSpace(const Color& deviceColor) +{ + // |deviceColor| is assumed to be DeviceRGB. + return ColorSpaceUtilities::convertColor(deviceColor, operatingColorSpace()); +} + void FilterEffect::transformResultColorSpace(ColorSpace dstColorSpace) { if (!hasResult() || dstColorSpace == m_resultColorSpace) @@ -448,7 +493,8 @@ TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const FloatRect FilterEffect::determineFilterPrimitiveSubregion(DetermineSubregionFlags flags) { - ASSERT(filter()); + Filter* filter = this->filter(); + ASSERT(filter); // FETile, FETurbulence, FEFlood don't have input effects, take the filter region as unite rect. FloatRect subregion; @@ -456,15 +502,19 @@ FloatRect FilterEffect::determineFilterPrimitiveSubregion(DetermineSubregionFlag subregion = inputEffect(0)->determineFilterPrimitiveSubregion(flags); for (unsigned i = 1; i < numberOfInputEffects; ++i) subregion.unite(inputEffect(i)->determineFilterPrimitiveSubregion(flags)); - } else - subregion = filter()->filterRegion(); + } else { + subregion = filter->filterRegion(); + } // After calling determineFilterPrimitiveSubregion on the target effect, reset the subregion again for <feTile>. if (filterEffectType() == FilterEffectTypeTile) - subregion = filter()->filterRegion(); + subregion = filter->filterRegion(); - if (flags & MapRectForward) - subregion = mapRect(subregion); + if (flags & MapRectForward) { + // mapRect works on absolute rectangles. + subregion = filter->mapAbsoluteRectToLocalRect(mapRect( + filter->mapLocalRectToAbsoluteRect(subregion))); + } FloatRect boundaries = effectBoundaries(); if (hasX()) @@ -478,15 +528,11 @@ FloatRect FilterEffect::determineFilterPrimitiveSubregion(DetermineSubregionFlag setFilterPrimitiveSubregion(subregion); - FloatRect absoluteSubregion = filter()->absoluteTransform().mapRect(subregion); - FloatSize filterResolution = filter()->filterResolution(); - absoluteSubregion.scale(filterResolution.width(), filterResolution.height()); + FloatRect absoluteSubregion = filter->mapLocalRectToAbsoluteRect(subregion); // Clip every filter effect to the filter region. if (flags & ClipToFilterRegion) { - FloatRect absoluteScaledFilterRegion = filter()->absoluteFilterRegion(); - absoluteScaledFilterRegion.scale(filterResolution.width(), filterResolution.height()); - absoluteSubregion.intersect(absoluteScaledFilterRegion); + absoluteSubregion.intersect(filter->absoluteFilterRegion()); } setMaxEffectRect(absoluteSubregion); @@ -495,34 +541,63 @@ FloatRect FilterEffect::determineFilterPrimitiveSubregion(DetermineSubregionFlag PassRefPtr<SkImageFilter> FilterEffect::createImageFilter(SkiaImageFilterBuilder* builder) { - return 0; + return nullptr; +} + +PassRefPtr<SkImageFilter> FilterEffect::createImageFilterWithoutValidation(SkiaImageFilterBuilder* builder) +{ + return createImageFilter(builder); } SkImageFilter::CropRect FilterEffect::getCropRect(const FloatSize& cropOffset) const { - SkRect rect = SkRect::MakeEmpty(); + FloatRect rect = filter()->filterRegion(); uint32_t flags = 0; FloatRect boundaries = effectBoundaries(); - FloatSize resolution = filter()->filterResolution(); - boundaries.scale(resolution.width(), resolution.height()); boundaries.move(cropOffset); if (hasX()) { - rect.fLeft = boundaries.x(); + rect.setX(boundaries.x()); flags |= SkImageFilter::CropRect::kHasLeft_CropEdge; + flags |= SkImageFilter::CropRect::kHasRight_CropEdge; } if (hasY()) { - rect.fTop = boundaries.y(); + rect.setY(boundaries.y()); flags |= SkImageFilter::CropRect::kHasTop_CropEdge; + flags |= SkImageFilter::CropRect::kHasBottom_CropEdge; } if (hasWidth()) { - rect.fRight = rect.fLeft + boundaries.width(); + rect.setWidth(boundaries.width()); flags |= SkImageFilter::CropRect::kHasRight_CropEdge; } if (hasHeight()) { - rect.fBottom = rect.fTop + boundaries.height(); + rect.setHeight(boundaries.height()); flags |= SkImageFilter::CropRect::kHasBottom_CropEdge; } + rect = filter()->mapLocalRectToAbsoluteRect(rect); return SkImageFilter::CropRect(rect, flags); } +static int getImageFilterIndex(ColorSpace colorSpace, bool requiresPMColorValidation) +{ + // Map the (colorspace, bool) tuple to an integer index as follows: + // 0 == linear colorspace, no PM validation + // 1 == device colorspace, no PM validation + // 2 == linear colorspace, PM validation + // 3 == device colorspace, PM validation + return (colorSpace == ColorSpaceLinearRGB ? 0x1 : 0x0) | (requiresPMColorValidation ? 0x2 : 0x0); +} + +SkImageFilter* FilterEffect::getImageFilter(ColorSpace colorSpace, bool requiresPMColorValidation) const +{ + int index = getImageFilterIndex(colorSpace, requiresPMColorValidation); + return m_imageFilters[index].get(); +} + +void FilterEffect::setImageFilter(ColorSpace colorSpace, bool requiresPMColorValidation, PassRefPtr<SkImageFilter> imageFilter) +{ + int index = getImageFilterIndex(colorSpace, requiresPMColorValidation); + filter()->removeFromCache(m_imageFilters[index].get()); + m_imageFilters[index] = imageFilter; +} + } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.h index 3f0d2c4ccf1..7e050fa2427 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.h @@ -26,6 +26,7 @@ #include "platform/PlatformExport.h" #include "platform/geometry/FloatRect.h" #include "platform/geometry/IntRect.h" +#include "platform/graphics/Color.h" #include "platform/graphics/ColorSpace.h" #include "third_party/skia/include/core/SkImageFilter.h" @@ -36,8 +37,6 @@ #include "wtf/Uint8ClampedArray.h" #include "wtf/Vector.h" -static const float kMaxFilterSize = 5000.0f; - namespace WebCore { class Filter; @@ -68,6 +67,9 @@ class PLATFORM_EXPORT FilterEffect : public RefCounted<FilterEffect> { public: virtual ~FilterEffect(); + static bool isFilterSizeValid(const FloatRect&); + static float maxFilterArea(); + void clearResult(); void clearResultsRecursive(); @@ -88,6 +90,10 @@ public: || m_unmultipliedImageResult || m_premultipliedImageResult; } + inline bool hasImageFilter() const + { + return m_imageFilters[0] || m_imageFilters[1] || m_imageFilters[2] || m_imageFilters[3]; + } IntRect drawingRegionOfInputImage(const IntRect&) const; IntRect requestedRegionOfInputImageData(const IntRect&) const; @@ -97,7 +103,6 @@ public: void setIsAlphaImage(bool alphaImage) { m_alphaImage = alphaImage; } IntRect absolutePaintRect() const { return m_absolutePaintRect; } - void setAbsolutePaintRect(const IntRect& absolutePaintRect) { m_absolutePaintRect = absolutePaintRect; } FloatRect maxEffectRect() const { return m_maxEffectRect; } void setMaxEffectRect(const FloatRect& maxEffectRect) { m_maxEffectRect = maxEffectRect; } @@ -110,8 +115,7 @@ public: virtual void correctFilterResultIfNeeded() { } virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*); - - virtual void determineAbsolutePaintRect(); + virtual PassRefPtr<SkImageFilter> createImageFilterWithoutValidation(SkiaImageFilterBuilder*); // Mapping a rect forwards determines which which destination pixels a // given source rect would affect. Mapping a rect backwards determines @@ -120,10 +124,19 @@ public: // each other. For example, for FEGaussianBlur, they are the same // transformation. virtual FloatRect mapRect(const FloatRect& rect, bool forward = true) { return rect; } + // A version of the above that is used for calculating paint rects. We can't + // use mapRect above for that, because that is also used for calculating effect + // regions for CSS filters and has undesirable effects for tile and + // displacement map. + virtual FloatRect mapPaintRect(const FloatRect& rect, bool forward) + { + return mapRect(rect, forward); + } FloatRect mapRectRecursive(const FloatRect&); // This is a recursive version of a backwards mapRect(), which also takes // into account the filter primitive subregion of each effect. + // Note: This works in absolute coordinates! FloatRect getSourceRect(const FloatRect& destRect, const FloatRect& clipRect); virtual FilterEffectType filterEffectType() const { return FilterEffectTypeUnknown; } @@ -165,25 +178,35 @@ public: void transformResultColorSpace(ColorSpace); FloatRect determineFilterPrimitiveSubregion(DetermineSubregionFlags = DetermineSubregionNone); + void determineAllAbsolutePaintRects(); + + virtual FloatRect determineAbsolutePaintRect(const FloatRect& requestedAbsoluteRect); + virtual bool affectsTransparentPixels() { return false; } + + // Return false if the filter will only operate correctly on valid RGBA values, with + // alpha in [0,255] and each color component in [0, alpha]. + virtual bool mayProduceInvalidPreMultipliedPixels() { return false; } + + SkImageFilter* getImageFilter(ColorSpace, bool requiresPMColorValidation) const; + void setImageFilter(ColorSpace, bool requiresPMColorValidation, PassRefPtr<SkImageFilter>); protected: FilterEffect(Filter*); - ImageBuffer* createImageBufferResult(); Uint8ClampedArray* createUnmultipliedImageResult(); Uint8ClampedArray* createPremultipliedImageResult(); - // Return true if the filter will only operate correctly on valid RGBA values, with - // alpha in [0,255] and each color component in [0, alpha]. - virtual bool requiresValidPreMultipliedPixels() { return true; } + Color adaptColorToOperatingColorSpace(const Color& deviceColor); // If a pre-multiplied image, check every pixel for validity and correct if necessary. void forceValidPreMultipliedPixels(); SkImageFilter::CropRect getCropRect(const FloatSize& cropOffset) const; + void addAbsolutePaintRect(const FloatRect& absolutePaintRect); + private: + void applyRecursive(); virtual void applySoftware() = 0; - virtual bool applySkia() { return false; } inline void copyImageBytes(Uint8ClampedArray* source, Uint8ClampedArray* destination, const IntRect&); @@ -221,6 +244,8 @@ private: ColorSpace m_operatingColorSpace; ColorSpace m_resultColorSpace; + + RefPtr<SkImageFilter> m_imageFilters[4]; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterOperation.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterOperation.h index ddc69dd3dde..b0559ddb0fa 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterOperation.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterOperation.h @@ -54,8 +54,6 @@ public: CONTRAST, BLUR, DROP_SHADOW, - CUSTOM, - VALIDATED_CUSTOM, NONE }; @@ -72,8 +70,6 @@ public: case CONTRAST: case BLUR: case DROP_SHADOW: - case CUSTOM: - case VALIDATED_CUSTOM: return true; case REFERENCE: return false; @@ -115,16 +111,16 @@ private: class PLATFORM_EXPORT ReferenceFilterOperation : public FilterOperation { public: - static PassRefPtr<ReferenceFilterOperation> create(const String& url, const String& fragment) + static PassRefPtr<ReferenceFilterOperation> create(const String& url, const AtomicString& fragment) { return adoptRef(new ReferenceFilterOperation(url, fragment)); } - virtual bool affectsOpacity() const { return true; } - virtual bool movesPixels() const { return true; } + virtual bool affectsOpacity() const OVERRIDE { return true; } + virtual bool movesPixels() const OVERRIDE { return true; } const String& url() const { return m_url; } - const String& fragment() const { return m_fragment; } + const AtomicString& fragment() const { return m_fragment; } ReferenceFilter* filter() const { return m_filter.get(); } void setFilter(PassRefPtr<ReferenceFilter> filter) { m_filter = filter; } @@ -133,10 +129,10 @@ private: virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress) const OVERRIDE { ASSERT_NOT_REACHED(); - return 0; + return nullptr; } - virtual bool operator==(const FilterOperation& o) const + virtual bool operator==(const FilterOperation& o) const OVERRIDE { if (!isSameType(o)) return false; @@ -144,7 +140,7 @@ private: return m_url == other->m_url; } - ReferenceFilterOperation(const String& url, const String& fragment) + ReferenceFilterOperation(const String& url, const AtomicString& fragment) : FilterOperation(REFERENCE) , m_url(url) , m_fragment(fragment) @@ -152,7 +148,7 @@ private: } String m_url; - String m_fragment; + AtomicString m_fragment; RefPtr<ReferenceFilter> m_filter; }; @@ -172,7 +168,7 @@ public: private: virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress) const OVERRIDE; - virtual bool operator==(const FilterOperation& o) const + virtual bool operator==(const FilterOperation& o) const OVERRIDE { if (!isSameType(o)) return false; @@ -207,12 +203,12 @@ public: double amount() const { return m_amount; } - virtual bool affectsOpacity() const { return m_type == OPACITY; } + virtual bool affectsOpacity() const OVERRIDE { return m_type == OPACITY; } private: virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress) const OVERRIDE; - virtual bool operator==(const FilterOperation& o) const + virtual bool operator==(const FilterOperation& o) const OVERRIDE { if (!isSameType(o)) return false; @@ -239,20 +235,20 @@ DEFINE_TYPE_CASTS(BasicComponentTransferFilterOperation, FilterOperation, op, is class PLATFORM_EXPORT BlurFilterOperation : public FilterOperation { public: - static PassRefPtr<BlurFilterOperation> create(Length stdDeviation) + static PassRefPtr<BlurFilterOperation> create(const Length& stdDeviation) { return adoptRef(new BlurFilterOperation(stdDeviation)); } - Length stdDeviation() const { return m_stdDeviation; } + const Length& stdDeviation() const { return m_stdDeviation; } - virtual bool affectsOpacity() const { return true; } - virtual bool movesPixels() const { return true; } + virtual bool affectsOpacity() const OVERRIDE { return true; } + virtual bool movesPixels() const OVERRIDE { return true; } private: virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress) const OVERRIDE; - virtual bool operator==(const FilterOperation& o) const + virtual bool operator==(const FilterOperation& o) const OVERRIDE { if (!isSameType(o)) return false; @@ -260,7 +256,7 @@ private: return m_stdDeviation == other->m_stdDeviation; } - BlurFilterOperation(Length stdDeviation) + BlurFilterOperation(const Length& stdDeviation) : FilterOperation(BLUR) , m_stdDeviation(stdDeviation) { @@ -284,13 +280,13 @@ public: int stdDeviation() const { return m_stdDeviation; } Color color() const { return m_color; } - virtual bool affectsOpacity() const { return true; } - virtual bool movesPixels() const { return true; } + virtual bool affectsOpacity() const OVERRIDE { return true; } + virtual bool movesPixels() const OVERRIDE { return true; } private: virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress) const OVERRIDE; - virtual bool operator==(const FilterOperation& o) const + virtual bool operator==(const FilterOperation& o) const OVERRIDE { if (!isSameType(o)) return false; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterOperations.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterOperations.cpp index d2692bd3167..08c8709ffab 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterOperations.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterOperations.cpp @@ -34,14 +34,12 @@ namespace WebCore { static inline IntSize outsetSizeForBlur(float stdDeviation) { - unsigned kernelSizeX = 0; - unsigned kernelSizeY = 0; - FEGaussianBlur::calculateUnscaledKernelSize(kernelSizeX, kernelSizeY, stdDeviation, stdDeviation); + IntSize kernelSize = FEGaussianBlur::calculateUnscaledKernelSize(FloatPoint(stdDeviation, stdDeviation)); IntSize outset; // We take the half kernel size and multiply it with three, because we run box blur three times. - outset.setWidth(3 * kernelSizeX * 0.5f); - outset.setHeight(3 * kernelSizeY * 0.5f); + outset.setWidth(3 * kernelSize.width() * 0.5f); + outset.setHeight(3 * kernelSize.height() * 0.5f); return outset; } @@ -90,16 +88,6 @@ bool FilterOperations::canInterpolateWith(const FilterOperations& other) const return true; } -bool FilterOperations::hasCustomFilter() const -{ - for (size_t i = 0; i < m_operations.size(); ++i) { - FilterOperation::OperationType type = m_operations.at(i)->type(); - if (type == FilterOperation::CUSTOM || type == FilterOperation::VALIDATED_CUSTOM) - return true; - } - return false; -} - bool FilterOperations::hasReferenceFilter() const { for (size_t i = 0; i < m_operations.size(); ++i) { @@ -160,12 +148,6 @@ FilterOutsets FilterOperations::outsets() const } break; } - case FilterOperation::CUSTOM: - case FilterOperation::VALIDATED_CUSTOM: { - // FIXME: Need to include the filter margins here. - // https://bugs.webkit.org/show_bug.cgi?id=71400 - break; - } default: break; } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterOperations.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterOperations.h index c220b828adb..4413b1d868b 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterOperations.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterOperations.h @@ -70,7 +70,6 @@ public: bool hasFilterThatAffectsOpacity() const; bool hasFilterThatMovesPixels() const; - bool hasCustomFilter() const; bool hasReferenceFilter() const; private: Vector<RefPtr<FilterOperation> > m_operations; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/gpu/SharedGraphicsContext3D.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterOperationsTest.cpp index 47ace4a032a..93bcf28fe1f 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/gpu/SharedGraphicsContext3D.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterOperationsTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Google Inc. All rights reserved. + * Copyright (C) 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,27 +23,39 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SharedGraphicsContext3D_h -#define SharedGraphicsContext3D_h +#include "config.h" +#include "platform/graphics/filters/FilterOperations.h" -#include "platform/PlatformExport.h" -#include "platform/graphics/GraphicsContext3D.h" -#include "wtf/RefCounted.h" -#include "wtf/RefPtr.h" +#include <gtest/gtest.h> -namespace WebCore { +using namespace WebCore; +using namespace blink; -class PLATFORM_EXPORT SharedGraphicsContext3D { -public: - // The caller may ref this pointer, and hang onto it as long as they like. - // However, the context should be checked periodically to determine if it - // has been lost. The easiest way to do that is to simply call this - // function again. Note that the return value may be 0 if the - // GPU is unavailable. - static PassRefPtr<GraphicsContext3D> get(); -}; +namespace { +TEST(FilterOperationsTest, getOutsetsBlur) +{ + FilterOperations ops; + ops.operations().append(BlurFilterOperation::create(Length(20.0, WebCore::Fixed))); + EXPECT_TRUE(ops.hasOutsets()); + FilterOutsets outsets = ops.outsets(); + EXPECT_EQ(57, outsets.top()); + EXPECT_EQ(57, outsets.right()); + EXPECT_EQ(57, outsets.bottom()); + EXPECT_EQ(57, outsets.left()); } -#endif // SharedGraphicsContext3D_h +TEST(FilterOperationsTest, getOutsetsDropShadow) +{ + FilterOperations ops; + ops.operations().append(DropShadowFilterOperation::create(IntPoint(3, 8), 20, Color(1, 2, 3))); + EXPECT_TRUE(ops.hasOutsets()); + FilterOutsets outsets = ops.outsets(); + EXPECT_EQ(49, outsets.top()); + EXPECT_EQ(60, outsets.right()); + EXPECT_EQ(65, outsets.bottom()); + EXPECT_EQ(54, outsets.left()); +} + +} diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/ImageFilterBuilderTest.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/ImageFilterBuilderTest.cpp new file mode 100644 index 00000000000..5c131e9899b --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/ImageFilterBuilderTest.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "SkImageFilter.h" +#include "platform/graphics/filters/FEBlend.h" +#include "platform/graphics/filters/FEGaussianBlur.h" +#include "platform/graphics/filters/FEMerge.h" +#include "platform/graphics/filters/FilterOperations.h" +#include "platform/graphics/filters/ReferenceFilter.h" +#include "platform/graphics/filters/SkiaImageFilterBuilder.h" +#include "platform/graphics/filters/SourceGraphic.h" +#include <gtest/gtest.h> + +using testing::Test; +using namespace WebCore; + +class ImageFilterBuilderTest : public Test { +protected: + void colorSpaceTest() + { + // Build filter tree + RefPtr<ReferenceFilter> referenceFilter = ReferenceFilter::create(); + + // Add a dummy source graphic input + RefPtr<FilterEffect> sourceEffect = referenceFilter->sourceGraphic(); + sourceEffect->setOperatingColorSpace(ColorSpaceDeviceRGB); + + // Add a blur effect (with input : source) + RefPtr<FilterEffect> blurEffect = + FEGaussianBlur::create(referenceFilter.get(), 3.0f, 3.0f); + blurEffect->setOperatingColorSpace(ColorSpaceLinearRGB); + blurEffect->inputEffects().append(sourceEffect); + + // Add a blend effect (with inputs : blur, source) + RefPtr<FilterEffect> blendEffect = + FEBlend::create(referenceFilter.get(), FEBLEND_MODE_NORMAL); + blendEffect->setOperatingColorSpace(ColorSpaceDeviceRGB); + FilterEffectVector& blendInputs = blendEffect->inputEffects(); + blendInputs.reserveCapacity(2); + blendInputs.append(sourceEffect); + blendInputs.append(blurEffect); + + // Add a merge effect (with inputs : blur, blend) + RefPtr<FilterEffect> mergeEffect = FEMerge::create(referenceFilter.get()); + mergeEffect->setOperatingColorSpace(ColorSpaceLinearRGB); + FilterEffectVector& mergeInputs = mergeEffect->inputEffects(); + mergeInputs.reserveCapacity(2); + mergeInputs.append(blurEffect); + mergeInputs.append(blendEffect); + referenceFilter->setLastEffect(mergeEffect); + + // Get SkImageFilter resulting tree + SkiaImageFilterBuilder builder; + RefPtr<SkImageFilter> filter = builder.build(referenceFilter->lastEffect(), ColorSpaceDeviceRGB); + + // Let's check that the resulting tree looks like this : + // ColorSpace (Linear->Device) : CS (L->D) + // | + // Merge (L) + // | | + // | CS (D->L) + // | | + // | Blend (D) + // | / | + // | CS (L->D) | + // | / | + // Blur (L) | + // \ | + // CS (D->L) | + // \ | + // Source Graphic (D) + + EXPECT_EQ(filter->countInputs(), 1); // Should be CS (L->D) + SkImageFilter* child = filter->getInput(0); // Should be Merge + EXPECT_EQ(child->asColorFilter(0), false); + EXPECT_EQ(child->countInputs(), 2); + child = child->getInput(1); // Should be CS (D->L) + EXPECT_EQ(child->asColorFilter(0), true); + EXPECT_EQ(child->countInputs(), 1); + child = child->getInput(0); // Should be Blend + EXPECT_EQ(child->asColorFilter(0), false); + EXPECT_EQ(child->countInputs(), 2); + child = child->getInput(0); // Should be CS (L->D) + EXPECT_EQ(child->asColorFilter(0), true); + EXPECT_EQ(child->countInputs(), 1); + child = child->getInput(0); // Should be Blur + EXPECT_EQ(child->asColorFilter(0), false); + EXPECT_EQ(child->countInputs(), 1); + child = child->getInput(0); // Should be CS (D->L) + EXPECT_EQ(child->asColorFilter(0), true); + EXPECT_EQ(child->countInputs(), 1); + } +}; + +namespace { + +TEST_F(ImageFilterBuilderTest, testColorSpace) +{ + colorSpaceTest(); +} + +} // namespace diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/LightSource.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/LightSource.h index 255f66935b1..ecd9271c408 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/LightSource.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/LightSource.h @@ -57,7 +57,6 @@ public: FloatPoint3D privateColorVector; float coneCutOffLimit; float coneFullLight; - int specularExponent; }; LightSource(LightType type) @@ -69,10 +68,12 @@ public: LightType type() const { return m_type; } virtual TextStream& externalRepresentation(TextStream&) const = 0; - virtual void initPaintingData(PaintingData&) = 0; + virtual PassRefPtr<LightSource> create(const FloatPoint3D& scale, const FloatSize& offset) const = 0; + + virtual void initPaintingData(PaintingData&) const = 0; // z is a float number, since it is the alpha value scaled by a user // specified "surfaceScale" constant, which type is <number> in the SVG standard - virtual void updatePaintingData(PaintingData&, int x, int y, float z) = 0; + virtual void updatePaintingData(PaintingData&, int x, int y, float z) const = 0; virtual bool setAzimuth(float) { return false; } virtual bool setElevation(float) { return false; } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/ParallelJobs.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/ParallelJobs.h index 17909017bc6..5c3d17f050a 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/ParallelJobs.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/ParallelJobs.h @@ -64,9 +64,10 @@ public: ParallelJobs(WorkerFunction func, size_t requestedJobNumber) : m_func(func) { - m_parameters.grow(requestedJobNumber); + size_t numberOfJobs = std::max(static_cast<size_t>(2), std::min(requestedJobNumber, blink::Platform::current()->numberOfProcessors())); + m_parameters.grow(numberOfJobs); // The main thread can execute one job, so only create requestJobNumber - 1 threads. - for (size_t i = 0; i < requestedJobNumber - 1; ++i) { + for (size_t i = 0; i < numberOfJobs - 1; ++i) { OwnPtr<blink::WebThread> thread = adoptPtr(blink::Platform::current()->createThread("Unfortunate parallel worker")); m_threads.append(thread.release()); } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/PointLightSource.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/PointLightSource.cpp index c88c2ea4b19..5acacbc43c4 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/PointLightSource.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/PointLightSource.cpp @@ -35,11 +35,11 @@ namespace WebCore { -void PointLightSource::initPaintingData(PaintingData&) +void PointLightSource::initPaintingData(PaintingData&) const { } -void PointLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z) +void PointLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z) const { paintingData.lightVector.setX(m_position.x() - x); paintingData.lightVector.setY(m_position.y() - y); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/PointLightSource.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/PointLightSource.h index 6638e89ede8..112f0168e7a 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/PointLightSource.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/PointLightSource.h @@ -34,15 +34,21 @@ public: return adoptRef(new PointLightSource(position)); } + virtual PassRefPtr<LightSource> create(const FloatPoint3D& scale, const FloatSize& offset) const OVERRIDE + { + FloatPoint3D position(m_position.x() * scale.x() - offset.width(), m_position.y() * scale.y() - offset.height(), m_position.z() * scale.z()); + return adoptRef(new PointLightSource(position)); + } + const FloatPoint3D& position() const { return m_position; } virtual bool setX(float) OVERRIDE; virtual bool setY(float) OVERRIDE; virtual bool setZ(float) OVERRIDE; - virtual void initPaintingData(PaintingData&); - virtual void updatePaintingData(PaintingData&, int x, int y, float z); + virtual void initPaintingData(PaintingData&) const OVERRIDE; + virtual void updatePaintingData(PaintingData&, int x, int y, float z) const OVERRIDE; - virtual TextStream& externalRepresentation(TextStream&) const; + virtual TextStream& externalRepresentation(TextStream&) const OVERRIDE; private: PointLightSource(const FloatPoint3D& position) diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/ReferenceFilter.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/ReferenceFilter.cpp index 3367d7ce836..9a3788b7e65 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/ReferenceFilter.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/ReferenceFilter.cpp @@ -41,8 +41,6 @@ ReferenceFilter::ReferenceFilter() : Filter(AffineTransform()) , m_sourceGraphic(SourceGraphic::create(this)) { - // FIXME: This should come from the filter DOM node's filterRes attribute. - setFilterResolution(FloatSize(1, 1)); } void ReferenceFilter::setLastEffect(PassRefPtr<FilterEffect> effect) diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/ReferenceFilter.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/ReferenceFilter.h index bc9fa3159ef..450490d58e2 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/ReferenceFilter.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/ReferenceFilter.h @@ -48,7 +48,7 @@ public: return adoptRef(new ReferenceFilter()); } - virtual FloatRect sourceImageRect() const { return FloatRect(); }; + virtual IntRect sourceImageRect() const OVERRIDE { return IntRect(); }; void setLastEffect(PassRefPtr<FilterEffect>); FilterEffect* lastEffect() const { return m_lastEffect.get(); } @@ -57,7 +57,7 @@ public: private: ReferenceFilter(); - ~ReferenceFilter(); + virtual ~ReferenceFilter(); RefPtr<SourceGraphic> m_sourceGraphic; RefPtr<FilterEffect> m_lastEffect; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.cpp index abbaf2bba59..5c6404c6c12 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.cpp @@ -30,26 +30,24 @@ #include "SkColorFilterImageFilter.h" #include "SkColorMatrixFilter.h" #include "SkDropShadowImageFilter.h" +#include "SkMatrixImageFilter.h" #include "SkTableColorFilter.h" #include "platform/graphics/ImageBuffer.h" #include "platform/graphics/filters/FilterEffect.h" #include "platform/graphics/filters/FilterOperations.h" #include "platform/graphics/filters/SourceGraphic.h" +#include "platform/graphics/skia/SkiaUtils.h" #include "public/platform/WebPoint.h" -namespace { +namespace WebCore { -PassRefPtr<SkImageFilter> createMatrixImageFilter(SkScalar matrix[20], SkImageFilter* input) +SkiaImageFilterBuilder::SkiaImageFilterBuilder() + : m_context(0) { - RefPtr<SkColorFilter> colorFilter(adoptRef(new SkColorMatrixFilter(matrix))); - return adoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), input)); } -}; - -namespace WebCore { - -SkiaImageFilterBuilder::SkiaImageFilterBuilder() +SkiaImageFilterBuilder::SkiaImageFilterBuilder(GraphicsContext* context) + : m_context(context) { } @@ -57,22 +55,23 @@ SkiaImageFilterBuilder::~SkiaImageFilterBuilder() { } -PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::build(FilterEffect* effect, ColorSpace colorSpace) +PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::build(FilterEffect* effect, ColorSpace colorSpace, bool destinationRequiresValidPreMultipliedPixels) { if (!effect) - return 0; - - FilterColorSpacePair key(effect, colorSpace); - FilterBuilderHashMap::iterator it = m_map.find(key); - if (it != m_map.end()) { - return it->value; - } else { - // Note that we may still need the color transform even if the filter is null - RefPtr<SkImageFilter> origFilter = effect->createImageFilter(this); - RefPtr<SkImageFilter> filter = transformColorSpace(origFilter.get(), effect->operatingColorSpace(), colorSpace); - m_map.set(key, filter); - return filter.release(); - } + return nullptr; + + bool requiresPMColorValidation = effect->mayProduceInvalidPreMultipliedPixels() && destinationRequiresValidPreMultipliedPixels; + + if (SkImageFilter* filter = effect->getImageFilter(colorSpace, requiresPMColorValidation)) + return filter; + + // Note that we may still need the color transform even if the filter is null + RefPtr<SkImageFilter> origFilter = requiresPMColorValidation ? effect->createImageFilter(this) : effect->createImageFilterWithoutValidation(this); + RefPtr<SkImageFilter> filter = transformColorSpace(origFilter.get(), effect->operatingColorSpace(), colorSpace); + effect->setImageFilter(colorSpace, requiresPMColorValidation, filter.get()); + if (filter.get() != origFilter.get()) + effect->setImageFilter(effect->operatingColorSpace(), requiresPMColorValidation, origFilter.get()); + return filter.release(); } PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::transformColorSpace( @@ -91,12 +90,7 @@ bool SkiaImageFilterBuilder::buildFilterOperations(const FilterOperations& opera return false; ColorSpace currentColorSpace = ColorSpaceDeviceRGB; - - RefPtr<SkImageFilter> noopFilter; - SkScalar matrix[20]; - memset(matrix, 0, 20 * sizeof(SkScalar)); - matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f; - noopFilter = createMatrixImageFilter(matrix, 0); + SkImageFilter* const nullFilter = 0; for (size_t i = 0; i < operations.size(); ++i) { const FilterOperation& op = *operations.at(i); @@ -106,21 +100,22 @@ bool SkiaImageFilterBuilder::buildFilterOperations(const FilterOperations& opera ReferenceFilter* referenceFilter = toReferenceFilterOperation(op).filter(); if (referenceFilter && referenceFilter->lastEffect()) { FilterEffect* filterEffect = referenceFilter->lastEffect(); - // Link SourceGraphic to a noop filter that serves as a placholder for - // the previous filter in the chain. We don't know what color space the - // interior nodes will request, so we have to populate the map with both - // options. (Only one of these will actually have a color transform on it.) - FilterColorSpacePair deviceKey(referenceFilter->sourceGraphic(), ColorSpaceDeviceRGB); - FilterColorSpacePair linearKey(referenceFilter->sourceGraphic(), ColorSpaceLinearRGB); - m_map.set(deviceKey, transformColorSpace(noopFilter.get(), currentColorSpace, ColorSpaceDeviceRGB)); - m_map.set(linearKey, transformColorSpace(noopFilter.get(), currentColorSpace, ColorSpaceLinearRGB)); + // Prepopulate SourceGraphic with two image filters: one with a null image + // filter, and the other with a colorspace conversion filter. + // We don't know what color space the interior nodes will request, so we have to + // initialize SourceGraphic with both options. + // Since we know SourceGraphic is always PM-valid, we also use + // these for the PM-validated options. + RefPtr<SkImageFilter> deviceFilter = transformColorSpace(nullFilter, currentColorSpace, ColorSpaceDeviceRGB); + RefPtr<SkImageFilter> linearFilter = transformColorSpace(nullFilter, currentColorSpace, ColorSpaceLinearRGB); + FilterEffect* sourceGraphic = referenceFilter->sourceGraphic(); + sourceGraphic->setImageFilter(ColorSpaceDeviceRGB, false, deviceFilter.get()); + sourceGraphic->setImageFilter(ColorSpaceLinearRGB, false, linearFilter.get()); + sourceGraphic->setImageFilter(ColorSpaceDeviceRGB, true, deviceFilter.get()); + sourceGraphic->setImageFilter(ColorSpaceLinearRGB, true, linearFilter.get()); currentColorSpace = filterEffect->operatingColorSpace(); filter = SkiaImageFilterBuilder::build(filterEffect, currentColorSpace); - // We might have no reference to the SourceGraphic's Skia filter now, so make - // sure we don't keep it in the map anymore. - m_map.remove(deviceKey); - m_map.remove(linearKey); filters->appendReferenceFilter(filter.get()); } break; @@ -181,21 +176,21 @@ bool SkiaImageFilterBuilder::buildFilterOperations(const FilterOperations& opera filters->appendDropShadowFilter(blink::WebPoint(drop.x(), drop.y()), drop.stdDeviation(), drop.color().rgb()); break; } - case FilterOperation::VALIDATED_CUSTOM: - case FilterOperation::CUSTOM: - return false; // Not supported. case FilterOperation::NONE: break; } } if (currentColorSpace != ColorSpaceDeviceRGB) { // Transform to device color space at the end of processing, if required - RefPtr<SkImageFilter> filter; - filter = transformColorSpace(noopFilter.get(), currentColorSpace, ColorSpaceDeviceRGB); - if (filter != noopFilter) - filters->appendReferenceFilter(filter.get()); + RefPtr<SkImageFilter> filter = transformColorSpace(nullFilter, currentColorSpace, ColorSpaceDeviceRGB); + filters->appendReferenceFilter(filter.get()); } return true; } +PassRefPtr<SkImageFilter> SkiaImageFilterBuilder::buildTransform(const AffineTransform& transform, SkImageFilter* input) +{ + return adoptRef(SkMatrixImageFilter::Create(affineTransformToSkMatrix(transform), SkPaint::kHigh_FilterLevel, input)); +} + }; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.h index 33adf2026e6..a44280b181d 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.h @@ -30,46 +30,37 @@ #include "platform/geometry/FloatSize.h" #include "platform/graphics/ColorSpace.h" #include "public/platform/WebFilterOperations.h" -#include "wtf/HashMap.h" class SkImageFilter; namespace WebCore { +class AffineTransform; class FilterEffect; class FilterOperations; +class GraphicsContext; class PLATFORM_EXPORT SkiaImageFilterBuilder { public: SkiaImageFilterBuilder(); + explicit SkiaImageFilterBuilder(GraphicsContext*); ~SkiaImageFilterBuilder(); - PassRefPtr<SkImageFilter> build(FilterEffect*, ColorSpace); + PassRefPtr<SkImageFilter> build(FilterEffect*, ColorSpace, bool requiresPMColorValidation = true); bool buildFilterOperations(const FilterOperations&, blink::WebFilterOperations*); + PassRefPtr<SkImageFilter> buildTransform(const AffineTransform&, SkImageFilter* input); PassRefPtr<SkImageFilter> transformColorSpace( SkImageFilter* input, ColorSpace srcColorSpace, ColorSpace dstColorSpace); void setCropOffset(const FloatSize& cropOffset) { m_cropOffset = cropOffset; }; FloatSize cropOffset() { return m_cropOffset; } + GraphicsContext* context() { return m_context; } private: - typedef std::pair<FilterEffect*, ColorSpace> FilterColorSpacePair; - typedef HashMap<FilterColorSpacePair, RefPtr<SkImageFilter> > FilterBuilderHashMap; - FilterBuilderHashMap m_map; FloatSize m_cropOffset; + GraphicsContext* m_context; }; } // namespace WebCore -namespace WTF { - -template<> struct DefaultHash<WebCore::FilterEffect*> { - typedef PtrHash<WebCore::FilterEffect*> Hash; -}; -template<> struct DefaultHash<WebCore::ColorSpace> { - typedef IntHash<unsigned> Hash; -}; - -} // namespace WTF - #endif diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceAlpha.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceAlpha.cpp index 1a1df1ba8bb..f00370fbef2 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceAlpha.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceAlpha.cpp @@ -25,6 +25,8 @@ #include "platform/graphics/GraphicsContext.h" #include "platform/graphics/filters/Filter.h" #include "platform/text/TextStream.h" +#include "third_party/skia/include/effects/SkColorFilterImageFilter.h" +#include "third_party/skia/include/effects/SkColorMatrixFilter.h" #include "wtf/StdLibExtras.h" #include "wtf/text/WTFString.h" @@ -41,12 +43,12 @@ const AtomicString& SourceAlpha::effectName() return s_effectName; } -void SourceAlpha::determineAbsolutePaintRect() +FloatRect SourceAlpha::determineAbsolutePaintRect(const FloatRect& requestedRect) { - Filter* filter = this->filter(); - FloatRect paintRect = filter->sourceImageRect(); - paintRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); - setAbsolutePaintRect(enclosingIntRect(paintRect)); + FloatRect srcRect = filter()->sourceImageRect(); + srcRect.intersect(requestedRect); + addAbsolutePaintRect(srcRect); + return srcRect; } void SourceAlpha::applySoftware() @@ -61,7 +63,25 @@ void SourceAlpha::applySoftware() FloatRect imageRect(FloatPoint(), absolutePaintRect().size()); GraphicsContext* filterContext = resultImage->context(); filterContext->fillRect(imageRect, Color::black); - filterContext->drawImageBuffer(filter->sourceImage(), IntPoint(), CompositeDestinationIn); + + IntRect srcRect = filter->sourceImageRect(); + if (ImageBuffer* sourceImageBuffer = filter->sourceImage()) { + filterContext->drawImageBuffer(sourceImageBuffer, + FloatRect(IntPoint(srcRect.location() - absolutePaintRect().location()), sourceImageBuffer->size()), + 0, CompositeDestinationIn); + } +} + +PassRefPtr<SkImageFilter> SourceAlpha::createImageFilter(SkiaImageFilterBuilder* builder) +{ + SkScalar matrix[20] = { + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, SK_Scalar1, 0 + }; + RefPtr<SkColorFilter> colorFilter(adoptRef(SkColorMatrixFilter::Create(matrix))); + return adoptRef(SkColorFilterImageFilter::Create(colorFilter.get())); } TextStream& SourceAlpha::externalRepresentation(TextStream& ts, int indent) const diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceAlpha.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceAlpha.h index 519a31af32f..ee1de7f5379 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceAlpha.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceAlpha.h @@ -32,11 +32,12 @@ public: static const AtomicString& effectName(); - virtual void determineAbsolutePaintRect(); + virtual FloatRect determineAbsolutePaintRect(const FloatRect& requestedRect) OVERRIDE; - virtual FilterEffectType filterEffectType() const { return FilterEffectTypeSourceInput; } + virtual FilterEffectType filterEffectType() const OVERRIDE { return FilterEffectTypeSourceInput; } - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; + virtual PassRefPtr<SkImageFilter> createImageFilter(SkiaImageFilterBuilder*) OVERRIDE; private: SourceAlpha(Filter* filter) diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceGraphic.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceGraphic.cpp index c1d69768c04..f9c1195e5bc 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceGraphic.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceGraphic.cpp @@ -40,12 +40,12 @@ const AtomicString& SourceGraphic::effectName() return s_effectName; } -void SourceGraphic::determineAbsolutePaintRect() +FloatRect SourceGraphic::determineAbsolutePaintRect(const FloatRect& requestedRect) { - Filter* filter = this->filter(); - FloatRect paintRect = filter->sourceImageRect(); - paintRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); - setAbsolutePaintRect(enclosingIntRect(paintRect)); + FloatRect srcRect = filter()->sourceImageRect(); + srcRect.intersect(requestedRect); + addAbsolutePaintRect(srcRect); + return srcRect; } void SourceGraphic::applySoftware() @@ -55,7 +55,11 @@ void SourceGraphic::applySoftware() if (!resultImage || !filter->sourceImage()) return; - resultImage->context()->drawImageBuffer(filter->sourceImage(), IntPoint()); + IntRect srcRect = filter->sourceImageRect(); + if (ImageBuffer* sourceImageBuffer = filter->sourceImage()) { + resultImage->context()->drawImageBuffer(sourceImageBuffer, + FloatRect(IntPoint(srcRect.location() - absolutePaintRect().location()), sourceImageBuffer->size())); + } } TextStream& SourceGraphic::externalRepresentation(TextStream& ts, int indent) const diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceGraphic.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceGraphic.h index eeeae633f77..582ab51e722 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceGraphic.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/SourceGraphic.h @@ -33,11 +33,11 @@ public: static const AtomicString& effectName(); - virtual void determineAbsolutePaintRect(); + virtual FloatRect determineAbsolutePaintRect(const FloatRect& requestedRect) OVERRIDE; - virtual FilterEffectType filterEffectType() const { return FilterEffectTypeSourceInput; } + virtual FilterEffectType filterEffectType() const OVERRIDE { return FilterEffectTypeSourceInput; } - virtual TextStream& externalRepresentation(TextStream&, int indention) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const OVERRIDE; private: SourceGraphic(Filter* filter) diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/SpotLightSource.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/SpotLightSource.cpp index 9aeb26341ae..aec1320062f 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/SpotLightSource.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/SpotLightSource.cpp @@ -40,7 +40,7 @@ namespace WebCore { // according to the SVG 1.1 SE light regression tests static const float antiAliasTreshold = 0.016f; -void SpotLightSource::initPaintingData(PaintingData& paintingData) +void SpotLightSource::initPaintingData(PaintingData& paintingData) const { paintingData.privateColorVector = paintingData.colorVector; paintingData.directionVector.setX(m_direction.x() - m_position.x()); @@ -60,17 +60,9 @@ void SpotLightSource::initPaintingData(PaintingData& paintingData) paintingData.coneCutOffLimit = cosf(deg2rad(180.0f - limitingConeAngle)); paintingData.coneFullLight = paintingData.coneCutOffLimit - antiAliasTreshold; } - - // Optimization for common specularExponent values - if (!m_specularExponent) - paintingData.specularExponent = 0; - else if (m_specularExponent == 1.0f) - paintingData.specularExponent = 1; - else // It is neither 0.0f nor 1.0f - paintingData.specularExponent = 2; } -void SpotLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z) +void SpotLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z) const { paintingData.lightVector.setX(m_position.x() - x); paintingData.lightVector.setY(m_position.y() - y); @@ -88,16 +80,10 @@ void SpotLightSource::updatePaintingData(PaintingData& paintingData, int x, int // Set the color of the pixel float lightStrength; - switch (paintingData.specularExponent) { - case 0: - lightStrength = 1.0f; // -cosineOfAngle ^ 0 == 1 - break; - case 1: + if (1.0f == m_specularExponent) { lightStrength = -cosineOfAngle; // -cosineOfAngle ^ 1 == -cosineOfAngle - break; - default: + } else { lightStrength = powf(-cosineOfAngle, m_specularExponent); - break; } if (cosineOfAngle > paintingData.coneFullLight) @@ -161,6 +147,7 @@ bool SpotLightSource::setPointsAtZ(float pointsAtZ) bool SpotLightSource::setSpecularExponent(float specularExponent) { + specularExponent = std::min(std::max(specularExponent, 1.0f), 128.0f); if (m_specularExponent == specularExponent) return false; m_specularExponent = specularExponent; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/SpotLightSource.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/SpotLightSource.h index ce8ce27f1ef..2b8599457f5 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/SpotLightSource.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/SpotLightSource.h @@ -35,6 +35,13 @@ public: return adoptRef(new SpotLightSource(position, direction, specularExponent, limitingConeAngle)); } + virtual PassRefPtr<LightSource> create(const FloatPoint3D& scale, const FloatSize& offset) const OVERRIDE + { + FloatPoint3D position(m_position.x() * scale.x() - offset.width(), m_position.y() * scale.y() - offset.height(), m_position.z() * scale.z()); + FloatPoint3D direction(m_direction.x() * scale.x() - offset.width(), m_direction.y() * scale.y() - offset.height(), m_direction.z() * scale.z()); + return adoptRef(new SpotLightSource(position, direction, m_specularExponent, m_limitingConeAngle)); + } + const FloatPoint3D& position() const { return m_position; } const FloatPoint3D& direction() const { return m_direction; } float specularExponent() const { return m_specularExponent; } @@ -50,10 +57,10 @@ public: virtual bool setSpecularExponent(float) OVERRIDE; virtual bool setLimitingConeAngle(float) OVERRIDE; - virtual void initPaintingData(PaintingData&); - virtual void updatePaintingData(PaintingData&, int x, int y, float z); + virtual void initPaintingData(PaintingData&) const OVERRIDE; + virtual void updatePaintingData(PaintingData&, int x, int y, float z) const OVERRIDE; - virtual TextStream& externalRepresentation(TextStream&) const; + virtual TextStream& externalRepresentation(TextStream&) const OVERRIDE; private: SpotLightSource(const FloatPoint3D& position, const FloatPoint3D& direction, @@ -61,7 +68,7 @@ private: : LightSource(LS_SPOT) , m_position(position) , m_direction(direction) - , m_specularExponent(specularExponent) + , m_specularExponent(std::min(std::max(specularExponent, 1.0f), 128.0f)) , m_limitingConeAngle(limitingConeAngle) { } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterArrayParameter.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterArrayParameter.cpp deleted file mode 100644 index 138fef6ef36..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterArrayParameter.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/CustomFilterArrayParameter.h" - -#include "platform/animation/AnimationUtilities.h" - -namespace WebCore { - -PassRefPtr<CustomFilterParameter> CustomFilterArrayParameter::blend(const CustomFilterParameter* from, double progress) -{ - if (!from || !isSameType(*from)) - return this; - - const CustomFilterArrayParameter* fromArray = static_cast<const CustomFilterArrayParameter*>(from); - - if (size() != fromArray->size()) - return this; - - RefPtr<CustomFilterArrayParameter> result = CustomFilterArrayParameter::create(name()); - for (size_t i = 0; i < size(); ++i) - result->addValue(WebCore::blend(fromArray->valueAt(i), valueAt(i), progress)); - - return result.release(); -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterArrayParameter.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterArrayParameter.h deleted file mode 100644 index a58d1525c30..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterArrayParameter.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterArrayParameter_h -#define CustomFilterArrayParameter_h - -#include "platform/PlatformExport.h" -#include "platform/graphics/filters/custom/CustomFilterParameter.h" -#include "wtf/Vector.h" - -namespace WebCore { - -class PLATFORM_EXPORT CustomFilterArrayParameter : public CustomFilterParameter { -public: - static PassRefPtr<CustomFilterArrayParameter> create(const String& name) - { - return adoptRef(new CustomFilterArrayParameter(name)); - } - - unsigned size() const { return m_data.size(); } - double valueAt(unsigned index) const { return m_data.at(index); } - - void addValue(double value) { m_data.append(value); } - - virtual PassRefPtr<CustomFilterParameter> blend(const CustomFilterParameter* from, double progress); - - virtual bool operator==(const CustomFilterParameter& o) const - { - if (!isSameType(o)) - return false; - - const CustomFilterArrayParameter* other = static_cast<const CustomFilterArrayParameter*>(&o); - return m_data == other->m_data; - } - -private: - CustomFilterArrayParameter(const String& name) - : CustomFilterParameter(Array, name) - { - } - - Vector<double> m_data; -}; - -} // namespace WebCore - - -#endif // CustomFilterArrayParameter_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterCompiledProgram.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterCompiledProgram.cpp deleted file mode 100644 index 2e5d853dcc9..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterCompiledProgram.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/CustomFilterCompiledProgram.h" - -namespace WebCore { - -CustomFilterCompiledProgram::CustomFilterCompiledProgram(PassRefPtr<GraphicsContext3D> context, const String& validatedVertexShader, const String& validatedFragmentShader, CustomFilterProgramType programType) - : m_context(context) - , m_program(0) - , m_positionAttribLocation(-1) - , m_texAttribLocation(-1) - , m_meshAttribLocation(-1) - , m_triangleAttribLocation(-1) - , m_meshBoxLocation(-1) - , m_projectionMatrixLocation(-1) - , m_tileSizeLocation(-1) - , m_meshSizeLocation(-1) - , m_samplerLocation(-1) - , m_samplerSizeLocation(-1) - , m_contentSamplerLocation(-1) - , m_isInitialized(false) -{ - m_context->makeContextCurrent(); - - Platform3DObject vertexShader = compileShader(GL_VERTEX_SHADER, validatedVertexShader); - if (!vertexShader) - return; - - Platform3DObject fragmentShader = compileShader(GL_FRAGMENT_SHADER, validatedFragmentShader); - if (!fragmentShader) { - m_context->deleteShader(vertexShader); - return; - } - - m_program = linkProgram(vertexShader, fragmentShader); - - m_context->deleteShader(vertexShader); - m_context->deleteShader(fragmentShader); - - if (!m_program) - return; - - initializeParameterLocations(programType); - - m_isInitialized = true; -} - -Platform3DObject CustomFilterCompiledProgram::compileShader(GC3Denum shaderType, const String& shaderString) -{ - ASSERT(!shaderString.isNull()); - - Platform3DObject shader = m_context->createShader(shaderType); - m_context->shaderSource(shader, shaderString); - m_context->compileShader(shader); - - int compiled = 0; - m_context->getShaderiv(shader, GL_COMPILE_STATUS, &compiled); - if (!compiled) { - // FIXME: This is an invalid shader. Throw some errors. - // https://bugs.webkit.org/show_bug.cgi?id=74416 - m_context->deleteShader(shader); - return 0; - } - - return shader; -} - -Platform3DObject CustomFilterCompiledProgram::linkProgram(Platform3DObject vertexShader, Platform3DObject fragmentShader) -{ - Platform3DObject program = m_context->createProgram(); - m_context->attachShader(program, vertexShader); - m_context->attachShader(program, fragmentShader); - m_context->linkProgram(program); - - int linked = 0; - m_context->getProgramiv(program, GL_LINK_STATUS, &linked); - if (!linked) { - // FIXME: Invalid vertex/fragment shader combination. Throw some errors here. - // https://bugs.webkit.org/show_bug.cgi?id=74416 - m_context->deleteProgram(program); - return 0; - } - - return program; -} - -void CustomFilterCompiledProgram::initializeParameterLocations(CustomFilterProgramType programType) -{ - m_positionAttribLocation = m_context->getAttribLocation(m_program, "a_position"); - m_texAttribLocation = m_context->getAttribLocation(m_program, "a_texCoord"); - m_meshAttribLocation = m_context->getAttribLocation(m_program, "a_meshCoord"); - m_triangleAttribLocation = m_context->getAttribLocation(m_program, "a_triangleCoord"); - m_meshBoxLocation = m_context->getUniformLocation(m_program, "u_meshBox"); - m_tileSizeLocation = m_context->getUniformLocation(m_program, "u_tileSize"); - m_meshSizeLocation = m_context->getUniformLocation(m_program, "u_meshSize"); - m_projectionMatrixLocation = m_context->getUniformLocation(m_program, "u_projectionMatrix"); - m_samplerSizeLocation = m_context->getUniformLocation(m_program, "u_textureSize"); - m_contentSamplerLocation = m_context->getUniformLocation(m_program, "u_contentTexture"); - if (programType == ProgramTypeBlendsElementTexture) { - // When the author uses the CSS mix function in a custom filter, WebKit adds the internal - // symbol css_u_texture to the shader code, which references the texture of the element. - m_samplerLocation = m_context->getUniformLocation(m_program, "css_u_texture"); - } -} - -int CustomFilterCompiledProgram::uniformLocationByName(const String& name) -{ - ASSERT(m_isInitialized); - // FIXME: Improve this by caching the uniform locations. - return m_context->getUniformLocation(m_program, name); -} - -CustomFilterCompiledProgram::~CustomFilterCompiledProgram() -{ - if (m_program) { - m_context->makeContextCurrent(); - m_context->deleteProgram(m_program); - } -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterCompiledProgram.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterCompiledProgram.h deleted file mode 100644 index 54b6a0a7f6c..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterCompiledProgram.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterCompiledProgram_h -#define CustomFilterCompiledProgram_h - -#include "platform/graphics/GraphicsContext3D.h" -#include "platform/graphics/filters/custom/CustomFilterProgramInfo.h" -#include "wtf/RefCounted.h" -#include "wtf/text/WTFString.h" - -namespace WebCore { - -class CustomFilterGlobalContext; - -class CustomFilterCompiledProgram: public RefCounted<CustomFilterCompiledProgram> { -public: - static PassRefPtr<CustomFilterCompiledProgram> create(PassRefPtr<GraphicsContext3D> context, const String& validatedVertexShader, const String& validatedFragmentShader, CustomFilterProgramType programType) - { - return adoptRef(new CustomFilterCompiledProgram(context, validatedVertexShader, validatedFragmentShader, programType)); - } - - ~CustomFilterCompiledProgram(); - - int positionAttribLocation() const { return m_positionAttribLocation; } - int texAttribLocation() const { return m_texAttribLocation; } - int meshAttribLocation() const { return m_meshAttribLocation; } - int triangleAttribLocation() const { return m_triangleAttribLocation; } - int meshBoxLocation() const { return m_meshBoxLocation; } - int projectionMatrixLocation() const { return m_projectionMatrixLocation; } - int tileSizeLocation() const { return m_tileSizeLocation; } - int meshSizeLocation() const { return m_meshSizeLocation; } - int samplerLocation() const { return m_samplerLocation; } - int contentSamplerLocation() const { return m_contentSamplerLocation; } - int samplerSizeLocation() const { return m_samplerSizeLocation; } - - int uniformLocationByName(const String&); - - bool isInitialized() const { return m_isInitialized; } - - Platform3DObject program() const { return m_program; } -private: - CustomFilterCompiledProgram(PassRefPtr<GraphicsContext3D>, const String& validatedVertexShader, const String& validatedFragmentShader, CustomFilterProgramType); - - Platform3DObject compileShader(GC3Denum shaderType, const String& shaderString); - Platform3DObject linkProgram(Platform3DObject vertexShader, Platform3DObject fragmentShader); - void initializeParameterLocations(CustomFilterProgramType); - - RefPtr<GraphicsContext3D> m_context; - Platform3DObject m_program; - - int m_positionAttribLocation; - int m_texAttribLocation; - int m_meshAttribLocation; - int m_triangleAttribLocation; - int m_meshBoxLocation; - int m_projectionMatrixLocation; - int m_tileSizeLocation; - int m_meshSizeLocation; - int m_samplerLocation; - int m_samplerSizeLocation; - int m_contentSamplerLocation; - - bool m_isInitialized; -}; - -} - -#endif diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterConstants.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterConstants.h deleted file mode 100644 index 5c3b2143e2a..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterConstants.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterConstants_h -#define CustomFilterConstants_h - -namespace WebCore { - -enum CustomFilterMeshConstants { - // Vertex attribute sizes - PositionAttribSize = 4, - TexAttribSize = 2, - MeshAttribSize = 2, - TriangleAttribSize = 3, - // Vertex attribute offsets - PositionAttribOffset = 0, - TexAttribOffset = PositionAttribOffset + PositionAttribSize * sizeof(float), - MeshAttribOffset = TexAttribOffset + TexAttribSize * sizeof(float), - TriangleAttribOffset = MeshAttribOffset + MeshAttribSize * sizeof(float) -}; - -enum CustomFilterMeshType { - MeshTypeAttached, - MeshTypeDetached -}; - -enum CustomFilterProgramType { - ProgramTypeNoElementTexture, - ProgramTypeBlendsElementTexture -}; - -} // namespace WebCore - -#endif // CustomFilterConstants_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterGlobalContext.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterGlobalContext.cpp deleted file mode 100644 index a3727ae3446..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterGlobalContext.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/CustomFilterGlobalContext.h" - -#include "platform/graphics/GraphicsContext3D.h" -#include "platform/graphics/filters/custom/CustomFilterValidatedProgram.h" - -namespace WebCore { - -CustomFilterGlobalContext::CustomFilterGlobalContext() -{ -} - -CustomFilterGlobalContext::~CustomFilterGlobalContext() -{ - for (CustomFilterValidatedProgramsMap::iterator iter = m_programs.begin(); iter != m_programs.end(); ++iter) - iter->value->detachFromGlobalContext(); -} - -ANGLEPlatformBridge* CustomFilterGlobalContext::webglShaderValidator() -{ - if (!m_webglShaderValidator) - m_webglShaderValidator = createShaderValidator(SH_WEBGL_SPEC); - return m_webglShaderValidator.get(); -} - -ANGLEPlatformBridge* CustomFilterGlobalContext::mixShaderValidator() -{ - if (!m_mixShaderValidator) - m_mixShaderValidator = createShaderValidator(SH_CSS_SHADERS_SPEC); - return m_mixShaderValidator.get(); -} - -PassOwnPtr<ANGLEPlatformBridge> CustomFilterGlobalContext::createShaderValidator(ShShaderSpec shaderSpec) -{ - OwnPtr<ANGLEPlatformBridge> validator = adoptPtr(new ANGLEPlatformBridge(SH_ESSL_OUTPUT, shaderSpec)); - ShBuiltInResources resources; - ShInitBuiltInResources(&resources); - validator->setResources(resources); - return validator.release(); -} - -void CustomFilterGlobalContext::prepareContextIfNeeded() -{ - if (m_context.get()) - return; - - GraphicsContext3D::Attributes attributes; - attributes.preserveDrawingBuffer = true; - attributes.premultipliedAlpha = false; - attributes.shareResources = true; - attributes.preferDiscreteGPU = true; - m_context = GraphicsContext3D::create(attributes); - if (!m_context) - return; - m_context->makeContextCurrent(); - m_context->enable(GL_DEPTH_TEST); -} - -PassRefPtr<CustomFilterValidatedProgram> CustomFilterGlobalContext::getValidatedProgram(const CustomFilterProgramInfo& programInfo) -{ - CustomFilterValidatedProgramsMap::iterator iter = m_programs.find(programInfo); - if (iter != m_programs.end()) - return iter->value; - - RefPtr<CustomFilterValidatedProgram> validatedProgram = CustomFilterValidatedProgram::create(this, programInfo); - m_programs.set(programInfo, validatedProgram.get()); - return validatedProgram.release(); -} - -void CustomFilterGlobalContext::removeValidatedProgram(const CustomFilterValidatedProgram* program) -{ - CustomFilterValidatedProgramsMap::iterator iter = m_programs.find(program->programInfo()); - ASSERT_WITH_SECURITY_IMPLICATION(iter != m_programs.end()); - m_programs.remove(iter); - -#ifndef NDEBUG - // Check that there's no way we could have the same program under a different key. - for (iter = m_programs.begin(); iter != m_programs.end(); ++iter) - ASSERT(iter->value != program); -#endif -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterGlobalContext.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterGlobalContext.h deleted file mode 100644 index 01f54d5fa92..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterGlobalContext.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterGlobalContext_h -#define CustomFilterGlobalContext_h - -#include "platform/graphics/angle/ANGLEPlatformBridge.h" -#include "platform/graphics/filters/custom/CustomFilterProgramInfo.h" -#include "wtf/HashMap.h" -#include "wtf/Noncopyable.h" -#include "wtf/RefPtr.h" - -namespace WebCore { - -class CustomFilterValidatedProgram; -class GraphicsContext3D; - -typedef HashMap<CustomFilterProgramInfo, CustomFilterValidatedProgram*> CustomFilterValidatedProgramsMap; - -class PLATFORM_EXPORT CustomFilterGlobalContext { - WTF_MAKE_NONCOPYABLE(CustomFilterGlobalContext); -public: - CustomFilterGlobalContext(); - ~CustomFilterGlobalContext(); - - GraphicsContext3D* context() const { return m_context.get(); } - - // CSS shaders not referenced from the CSS mix function should be validated just like regular WebGL shaders. - // This ANGLE validator uses the SH_WEBGL_SPEC flag. - ANGLEPlatformBridge* webglShaderValidator(); - - // CSS shaders referenced from the CSS mix function should be validated slightly differently than WebGL shaders. - // This ANGLE validator uses the SH_CSS_SHADERS_SPEC flag. - // Under this flag, most notably: - // - The "gl_FragColor" built-in is not available. - // - Instead, the "css_MixColor" and "css_ColorMatrix" built-ins are available. - // - The "css_" prefix is reserved. - // - In the translated source that ANGLE returns, ANGLE renames the author's "main" function to "css_main". - // The complete details are documented in ANGLE/ShaderLang.h. - ANGLEPlatformBridge* mixShaderValidator(); - - void prepareContextIfNeeded(); - - PassRefPtr<CustomFilterValidatedProgram> getValidatedProgram(const CustomFilterProgramInfo&); - void removeValidatedProgram(const CustomFilterValidatedProgram*); -private: - static PassOwnPtr<ANGLEPlatformBridge> createShaderValidator(ShShaderSpec); - - RefPtr<GraphicsContext3D> m_context; - OwnPtr<ANGLEPlatformBridge> m_webglShaderValidator; - OwnPtr<ANGLEPlatformBridge> m_mixShaderValidator; - CustomFilterValidatedProgramsMap m_programs; -}; - -} // namespace WebCore - -#endif // CustomFilterGlobalContext_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterMesh.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterMesh.cpp deleted file mode 100644 index cb4c59cfc37..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterMesh.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/CustomFilterMesh.h" - -#include "platform/graphics/GraphicsContext3D.h" -#include "platform/graphics/filters/custom/CustomFilterMeshGenerator.h" - -namespace WebCore { - -CustomFilterMesh::CustomFilterMesh(GraphicsContext3D* context, unsigned columns, unsigned rows, - const FloatRect& meshBox, CustomFilterMeshType meshType) - : m_context(context) - , m_verticesBufferObject(0) - , m_elementsBufferObject(0) - , m_meshBox(meshBox) - , m_meshType(meshType) -{ - CustomFilterMeshGenerator generator(columns, rows, meshBox, meshType); - m_indicesCount = generator.indicesCount(); - m_bytesPerVertex = generator.floatsPerVertex() * sizeof(float); - - m_context->makeContextCurrent(); - - m_verticesBufferObject = m_context->createBuffer(); - m_context->bindBuffer(GL_ARRAY_BUFFER, m_verticesBufferObject); - m_context->bufferData(GL_ARRAY_BUFFER, generator.vertices().size() * sizeof(float), generator.vertices().data(), GL_STATIC_DRAW); - - m_elementsBufferObject = m_context->createBuffer(); - m_context->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementsBufferObject); - m_context->bufferData(GL_ELEMENT_ARRAY_BUFFER, generator.indices().size() * sizeof(uint16_t), generator.indices().data(), GL_STATIC_DRAW); -} - -CustomFilterMesh::~CustomFilterMesh() -{ - m_context->makeContextCurrent(); - m_context->deleteBuffer(m_verticesBufferObject); - m_context->deleteBuffer(m_elementsBufferObject); -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterMesh.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterMesh.h deleted file mode 100644 index b9e8a1b5f11..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterMesh.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterMesh_h -#define CustomFilterMesh_h - -#include "platform/geometry/FloatRect.h" -#include "platform/graphics/GraphicsTypes3D.h" -#include "platform/graphics/filters/custom/CustomFilterOperation.h" -#include "wtf/RefCounted.h" - -namespace WebCore { - -class GraphicsContext3D; - -class PLATFORM_EXPORT CustomFilterMesh : public RefCounted<CustomFilterMesh> { -public: - static PassRefPtr<CustomFilterMesh> create(GraphicsContext3D* context, unsigned cols, unsigned rows, const FloatRect& meshBox, CustomFilterMeshType meshType) - { - return adoptRef(new CustomFilterMesh(context, cols, rows, meshBox, meshType)); - } - ~CustomFilterMesh(); - - Platform3DObject verticesBufferObject() const { return m_verticesBufferObject; } - unsigned bytesPerVertex() const { return m_bytesPerVertex; } - - Platform3DObject elementsBufferObject() const { return m_elementsBufferObject; } - unsigned indicesCount() const { return m_indicesCount; } - - const FloatRect& meshBox() const { return m_meshBox; } - CustomFilterMeshType meshType() const { return m_meshType; } - -private: - CustomFilterMesh(GraphicsContext3D*, unsigned cols, unsigned rows, const FloatRect& meshBox, CustomFilterMeshType); - - GraphicsContext3D* m_context; - - Platform3DObject m_verticesBufferObject; - unsigned m_bytesPerVertex; - - Platform3DObject m_elementsBufferObject; - unsigned m_indicesCount; - - FloatRect m_meshBox; - CustomFilterMeshType m_meshType; -}; - -} // namespace WebCore - -#endif // CustomFilterMesh_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterMeshGenerator.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterMeshGenerator.cpp deleted file mode 100644 index 3e373009979..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterMeshGenerator.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/CustomFilterMeshGenerator.h" - -#ifndef NDEBUG -#include <stdio.h> // Needed for printf used in dumpBuffers. -#endif - -namespace WebCore { - -#ifndef NDEBUG -// Use "call 'WebCore::s_dumpCustomFilterMeshBuffers' = 1" in GDB to activate printing of the mesh buffers. -static bool s_dumpCustomFilterMeshBuffers = false; -#endif - -CustomFilterMeshGenerator::CustomFilterMeshGenerator(unsigned columns, unsigned rows, const FloatRect& meshBox, CustomFilterMeshType meshType) - : m_meshType(meshType) - , m_points(columns + 1, rows + 1) - , m_tiles(columns, rows) - , m_tileSizeInPixels(meshBox.width() / m_tiles.width(), meshBox.height() / m_tiles.height()) - , m_tileSizeInDeviceSpace(1.0f / m_tiles.width(), 1.0f / m_tiles.height()) - , m_meshBox(meshBox) -{ - // Build the two buffers needed to draw triangles: - // * m_vertices has a number of float attributes that will be passed to the vertex shader - // for each computed vertex. This number is calculated in floatsPerVertex() based on the meshType. - // * m_indices is a buffer that will have 3 indices per triangle. Each index will point inside - // the m_vertices buffer. - m_vertices.reserveCapacity(verticesCount() * floatsPerVertex()); - m_indices.reserveCapacity(indicesCount()); - - // Based on the meshType there can be two types of meshes. - // * attached: each triangle uses vertices from the neighbor triangles. This is useful to save some GPU memory - // when there's no need to explode the tiles. - // * detached: each triangle has its own vertices. This means each triangle can be moved independently and a vec3 - // attribute is passed, so that each vertex can be uniquely identified. - if (m_meshType == MeshTypeAttached) - generateAttachedMesh(); - else - generateDetachedMesh(); - -#ifndef NDEBUG - if (s_dumpCustomFilterMeshBuffers) - dumpBuffers(); -#endif -} - -void CustomFilterMeshGenerator::addAttachedMeshIndex(int quadX, int quadY, int triangleX, int triangleY, int) -{ - m_indices.append((quadY + triangleY) * m_points.width() + (quadX + triangleX)); -} - -void CustomFilterMeshGenerator::generateAttachedMesh() -{ - for (int j = 0; j < m_points.height(); ++j) { - for (int i = 0; i < m_points.width(); ++i) - addAttachedMeshVertexAttributes(i, j); - } - - for (int j = 0; j < m_tiles.height(); ++j) { - for (int i = 0; i < m_tiles.width(); ++i) - addTile<&CustomFilterMeshGenerator::addAttachedMeshIndex>(i, j); - } -} - -void CustomFilterMeshGenerator::addDetachedMeshVertexAndIndex(int quadX, int quadY, int triangleX, int triangleY, int triangle) -{ - addDetachedMeshVertexAttributes(quadX, quadY, triangleX, triangleY, triangle); - m_indices.append(m_indices.size()); -} - -void CustomFilterMeshGenerator::generateDetachedMesh() -{ - for (int j = 0; j < m_tiles.height(); ++j) { - for (int i = 0; i < m_tiles.width(); ++i) - addTile<&CustomFilterMeshGenerator::addDetachedMeshVertexAndIndex>(i, j); - } -} - -void CustomFilterMeshGenerator::addPositionAttribute(int quadX, int quadY) -{ - // vec4 a_position - m_vertices.append(m_tileSizeInPixels.width() * quadX - 0.5f + m_meshBox.x()); - m_vertices.append(m_tileSizeInPixels.height() * quadY - 0.5f + m_meshBox.y()); - m_vertices.append(0.0f); // z - m_vertices.append(1.0f); -} - -void CustomFilterMeshGenerator::addTexCoordAttribute(int quadX, int quadY) -{ - // vec2 a_texCoord - m_vertices.append(m_tileSizeInPixels.width() * quadX + m_meshBox.x()); - m_vertices.append(m_tileSizeInPixels.height() * quadY + m_meshBox.y()); -} - -void CustomFilterMeshGenerator::addMeshCoordAttribute(int quadX, int quadY) -{ - // vec2 a_meshCoord - m_vertices.append(m_tileSizeInDeviceSpace.width() * quadX); - m_vertices.append(m_tileSizeInDeviceSpace.height() * quadY); -} - -void CustomFilterMeshGenerator::addTriangleCoordAttribute(int quadX, int quadY, int triangle) -{ - // vec3 a_triangleCoord - m_vertices.append(quadX); - m_vertices.append(quadY); - m_vertices.append(triangle); -} - -void CustomFilterMeshGenerator::addAttachedMeshVertexAttributes(int quadX, int quadY) -{ - addPositionAttribute(quadX, quadY); - addTexCoordAttribute(quadX, quadY); - addMeshCoordAttribute(quadX, quadY); -} - -void CustomFilterMeshGenerator::addDetachedMeshVertexAttributes(int quadX, int quadY, int triangleX, int triangleY, int triangle) -{ - addAttachedMeshVertexAttributes(quadX + triangleX, quadY + triangleY); - addTriangleCoordAttribute(quadX, quadY, triangle); -} - -#ifndef NDEBUG -void CustomFilterMeshGenerator::dumpBuffers() const -{ - printf("Mesh buffers: Points.width(): %d, Points.height(): %d meshBox: %f, %f, %f, %f, type: %s\n", - m_points.width(), m_points.height(), m_meshBox.x(), m_meshBox.y(), m_meshBox.width(), m_meshBox.height(), - (m_meshType == MeshTypeAttached) ? "Attached" : "Detached"); - printf("---Vertex:\n\t"); - for (unsigned i = 0; i < m_vertices.size(); ++i) { - printf("%f ", m_vertices.at(i)); - if (!((i + 1) % floatsPerVertex())) - printf("\n\t"); - } - printf("\n---Indices: "); - for (unsigned i = 0; i < m_indices.size(); ++i) - printf("%d ", m_indices.at(i)); - printf("\n"); -} -#endif - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterMeshGenerator.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterMeshGenerator.h deleted file mode 100644 index d4fc6441611..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterMeshGenerator.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterMeshGenerator_h -#define CustomFilterMeshGenerator_h - -#include "platform/PlatformExport.h" -#include "platform/geometry/FloatRect.h" -#include "platform/graphics/filters/custom/CustomFilterConstants.h" - -namespace WebCore { - -class PLATFORM_EXPORT CustomFilterMeshGenerator { -public: - // Lines and columns are the values passed in CSS. The result is vertex mesh that has 'rows' numbers of rows - // and 'columns' number of columns with a total of 'rows + 1' * 'columns + 1' vertices. - // MeshBox is the filtered area calculated defined using the border-box, padding-box, content-box or filter-box - // attributes. A value of (0, 0, 1, 1) will cover the entire output surface. - CustomFilterMeshGenerator(unsigned columns, unsigned rows, const FloatRect& meshBox, CustomFilterMeshType); - - const Vector<float>& vertices() const { return m_vertices; } - const Vector<uint16_t>& indices() const { return m_indices; } - - const IntSize& points() const { return m_points; } - unsigned pointsCount() const { return m_points.width() * m_points.height(); } - - const IntSize& tiles() const { return m_tiles; } - unsigned tilesCount() const { return m_tiles.width() * m_tiles.height(); } - - unsigned indicesCount() const - { - const unsigned trianglesPerTile = 2; - const unsigned indicesPerTriangle = 3; - return tilesCount() * trianglesPerTile * indicesPerTriangle; - } - - unsigned floatsPerVertex() const - { - static const unsigned AttachedMeshVertexSize = PositionAttribSize + TexAttribSize + MeshAttribSize; - static const unsigned DetachedMeshVertexSize = AttachedMeshVertexSize + TriangleAttribSize; - return m_meshType == MeshTypeAttached ? AttachedMeshVertexSize : DetachedMeshVertexSize; - } - - unsigned verticesCount() const - { - return m_meshType == MeshTypeAttached ? pointsCount() : indicesCount(); - } - -private: - typedef void (CustomFilterMeshGenerator::*AddTriangleVertexFunction)(int quadX, int quadY, int triangleX, int triangleY, int triangle); - - template <AddTriangleVertexFunction addTriangleVertex> - void addTile(int quadX, int quadY) - { - ((*this).*(addTriangleVertex))(quadX, quadY, 0, 0, 1); - ((*this).*(addTriangleVertex))(quadX, quadY, 1, 0, 2); - ((*this).*(addTriangleVertex))(quadX, quadY, 1, 1, 3); - ((*this).*(addTriangleVertex))(quadX, quadY, 0, 0, 4); - ((*this).*(addTriangleVertex))(quadX, quadY, 1, 1, 5); - ((*this).*(addTriangleVertex))(quadX, quadY, 0, 1, 6); - } - - void addAttachedMeshIndex(int quadX, int quadY, int triangleX, int triangleY, int triangle); - - void generateAttachedMesh(); - - void addDetachedMeshVertexAndIndex(int quadX, int quadY, int triangleX, int triangleY, int triangle); - - void generateDetachedMesh(); - void addPositionAttribute(int quadX, int quadY); - void addTexCoordAttribute(int quadX, int quadY); - void addMeshCoordAttribute(int quadX, int quadY); - void addTriangleCoordAttribute(int quadX, int quadY, int triangle); - void addAttachedMeshVertexAttributes(int quadX, int quadY); - void addDetachedMeshVertexAttributes(int quadX, int quadY, int triangleX, int triangleY, int triangle); - -#ifndef NDEBUG - void dumpBuffers() const; -#endif - -private: - Vector<float> m_vertices; - Vector<uint16_t> m_indices; - - CustomFilterMeshType m_meshType; - IntSize m_points; - IntSize m_tiles; - FloatSize m_tileSizeInPixels; - FloatSize m_tileSizeInDeviceSpace; - FloatRect m_meshBox; -}; - -} // namespace WebCore - -#endif // CustomFilterMeshGenerator_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterNumberParameter.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterNumberParameter.cpp deleted file mode 100644 index 1fbfa58f6a9..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterNumberParameter.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/CustomFilterNumberParameter.h" - -#include "platform/animation/AnimationUtilities.h" - -namespace WebCore { - -PassRefPtr<CustomFilterParameter> CustomFilterNumberParameter::blend(const CustomFilterParameter* from, double progress) -{ - if (!from || !isSameType(*from)) - return this; - const CustomFilterNumberParameter* fromNumber = static_cast<const CustomFilterNumberParameter*>(from); - if (size() != fromNumber->size()) - return this; - RefPtr<CustomFilterNumberParameter> result = CustomFilterNumberParameter::create(name()); - for (size_t i = 0; i < size(); ++i) - result->addValue(WebCore::blend(fromNumber->valueAt(i), valueAt(i), progress)); - return result.release(); -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterNumberParameter.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterNumberParameter.h deleted file mode 100644 index ed2e838fcd9..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterNumberParameter.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterNumberParameter_h -#define CustomFilterNumberParameter_h - -#include "platform/PlatformExport.h" -#include "platform/graphics/filters/custom/CustomFilterParameter.h" -#include "wtf/Vector.h" - -namespace WebCore { - -class PLATFORM_EXPORT CustomFilterNumberParameter : public CustomFilterParameter { -public: - static PassRefPtr<CustomFilterNumberParameter> create(const String& name) - { - return adoptRef(new CustomFilterNumberParameter(name)); - } - - unsigned size() const { return m_data.size(); } - double valueAt(unsigned index) const { return m_data.at(index); } - - void addValue(double value) { m_data.append(value); } - - virtual PassRefPtr<CustomFilterParameter> blend(const CustomFilterParameter* from, double progress); - - virtual bool operator==(const CustomFilterParameter& o) const - { - if (!isSameType(o)) - return false; - const CustomFilterNumberParameter* other = static_cast<const CustomFilterNumberParameter*>(&o); - return m_data == other->m_data; - } - -private: - CustomFilterNumberParameter(const String& name) - : CustomFilterParameter(Number, name) - { - } - - Vector<double, 4> m_data; -}; - -} // namespace WebCore - - -#endif // CustomFilterNumberParameter_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterOperation.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterOperation.cpp deleted file mode 100644 index cf13a4998a3..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterOperation.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/CustomFilterOperation.h" - -#include "platform/graphics/filters/custom/CustomFilterParameter.h" - -namespace WebCore { - -CustomFilterOperation::CustomFilterOperation(PassRefPtr<CustomFilterProgram> program, const CustomFilterParameterList& sortedParameters, unsigned meshRows, unsigned meshColumns, CustomFilterMeshType meshType) - : FilterOperation(CUSTOM) - , m_program(program) - , m_parameters(sortedParameters) - , m_meshRows(meshRows) - , m_meshColumns(meshColumns) - , m_meshType(meshType) -{ -} - -CustomFilterOperation::~CustomFilterOperation() -{ -} - -PassRefPtr<FilterOperation> CustomFilterOperation::blend(const FilterOperation* from, double progress) const -{ - if (!from) { - // FIXME: There's no way to decide what is the "passthrough filter" for shaders using the current CSS Syntax. - // https://bugs.webkit.org/show_bug.cgi?id=84903 - // https://www.w3.org/Bugs/Public/show_bug.cgi?id=16861 - return const_cast<CustomFilterOperation*>(this); - } - - ASSERT_WITH_SECURITY_IMPLICATION(from->isSameType(*this)); - const CustomFilterOperation* fromOp = toCustomFilterOperation(from); - if (m_program.get() != fromOp->m_program.get() - || m_meshRows != fromOp->m_meshRows - || m_meshColumns != fromOp->m_meshColumns - || m_meshType != fromOp->m_meshType) - return const_cast<CustomFilterOperation*>(this); - - CustomFilterParameterList animatedParameters; - m_parameters.blend(fromOp->m_parameters, progress, animatedParameters); - return CustomFilterOperation::create(m_program, animatedParameters, m_meshRows, m_meshColumns, m_meshType); -} - -} // namespace WebCore - diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterOperation.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterOperation.h deleted file mode 100644 index 945a534b108..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterOperation.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterOperation_h -#define CustomFilterOperation_h - -#include "platform/geometry/LayoutSize.h" -#include "platform/graphics/filters/FilterOperation.h" -#include "platform/graphics/filters/custom/CustomFilterConstants.h" -#include "platform/graphics/filters/custom/CustomFilterParameterList.h" -#include "platform/graphics/filters/custom/CustomFilterProgram.h" - -namespace WebCore { - -// CSS Shaders - -class PLATFORM_EXPORT CustomFilterOperation : public FilterOperation { -public: - static PassRefPtr<CustomFilterOperation> create(PassRefPtr<CustomFilterProgram> program, const CustomFilterParameterList& sortedParameters, unsigned meshRows, unsigned meshColumns, CustomFilterMeshType meshType) - { - return adoptRef(new CustomFilterOperation(program, sortedParameters, meshRows, meshColumns, meshType)); - } - - CustomFilterProgram* program() const { return m_program.get(); } - void setProgram(PassRefPtr<CustomFilterProgram> program) { m_program = program; } - - const CustomFilterParameterList& parameters() const { return m_parameters; } - - unsigned meshRows() const { return m_meshRows; } - unsigned meshColumns() const { return m_meshColumns; } - - CustomFilterMeshType meshType() const { return m_meshType; } - - virtual ~CustomFilterOperation(); - - virtual bool affectsOpacity() const { return true; } - virtual bool movesPixels() const { return true; } - - -protected: - CustomFilterOperation(PassRefPtr<CustomFilterProgram>, const CustomFilterParameterList&, unsigned meshRows, unsigned meshColumns, CustomFilterMeshType); - -private: - virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress) const OVERRIDE; - virtual bool operator==(const FilterOperation& o) const - { - if (!isSameType(o)) - return false; - - const CustomFilterOperation* other = static_cast<const CustomFilterOperation*>(&o); - return m_program.get() == other->m_program.get() - && m_meshRows == other->m_meshRows - && m_meshColumns == other->m_meshColumns - && m_meshType == other->m_meshType - && m_parameters == other->m_parameters; - } - - RefPtr<CustomFilterProgram> m_program; - CustomFilterParameterList m_parameters; - - unsigned m_meshRows; - unsigned m_meshColumns; - CustomFilterMeshType m_meshType; -}; - -DEFINE_FILTER_OPERATION_TYPE_CASTS(CustomFilterOperation, CUSTOM); - -} // namespace WebCore - - -#endif // CustomFilterOperation_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterParameter.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterParameter.h deleted file mode 100644 index 13e1277528a..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterParameter.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterParameter_h -#define CustomFilterParameter_h - -#include "platform/PlatformExport.h" -#include "wtf/PassRefPtr.h" -#include "wtf/RefCounted.h" -#include "wtf/text/WTFString.h" - -namespace WebCore { - -class PLATFORM_EXPORT CustomFilterParameter : public RefCounted<CustomFilterParameter> { -public: - // FIXME: Implement other parameters types: - // booleans: https://bugs.webkit.org/show_bug.cgi?id=76438 - // textures: https://bugs.webkit.org/show_bug.cgi?id=71442 - // 3d-transforms: https://bugs.webkit.org/show_bug.cgi?id=71443 - // mat2, mat3, mat4: https://bugs.webkit.org/show_bug.cgi?id=71444 - enum ParameterType { - Array, - Number, - Transform - }; - - virtual ~CustomFilterParameter() { } - - ParameterType parameterType() const { return m_type; } - const String& name() const { return m_name; } - - bool isSameType(const CustomFilterParameter& other) const { return parameterType() == other.parameterType(); } - - virtual PassRefPtr<CustomFilterParameter> blend(const CustomFilterParameter*, double progress) = 0; - virtual bool operator==(const CustomFilterParameter&) const = 0; - bool operator!=(const CustomFilterParameter& o) const { return !(*this == o); } -protected: - CustomFilterParameter(ParameterType type, const String& name) - : m_name(name) - , m_type(type) - { - } - -private: - String m_name; - ParameterType m_type; -}; - -} // namespace WebCore - - -#endif // CustomFilterParameter_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterParameterList.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterParameterList.cpp deleted file mode 100644 index d10aae8498e..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterParameterList.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/CustomFilterParameterList.h" - -#include "wtf/text/StringHash.h" - -namespace WebCore { - -CustomFilterParameterList::CustomFilterParameterList() -{ -} - -CustomFilterParameterList::CustomFilterParameterList(size_t size) - : m_parameters(size) -{ -} - -bool CustomFilterParameterList::operator==(const CustomFilterParameterList& other) const -{ - if (size() != other.size()) - return false; - for (size_t i = 0; i < size(); ++i) { - if (at(i).get() != other.at(i).get() - && *at(i).get() != *other.at(i).get()) - return false; - } - return true; -} - -#ifndef NDEBUG -bool CustomFilterParameterList::checkAlphabeticalOrder() const -{ - for (unsigned i = 1; i < size(); ++i) { - // Break for equal or not-sorted parameters. - if (!codePointCompareLessThan(at(i - 1)->name(), at(i)->name())) - return false; - } - return true; -} -#endif - -void CustomFilterParameterList::blend(const CustomFilterParameterList& fromList, - double progress, CustomFilterParameterList& resultList) const -{ -#ifndef NDEBUG - // This method expects both lists to be sorted by parameter name and the result list is also sorted. - ASSERT(checkAlphabeticalOrder()); - ASSERT(fromList.checkAlphabeticalOrder()); -#endif - size_t fromListIndex = 0, toListIndex = 0; - while (fromListIndex < fromList.size() && toListIndex < size()) { - CustomFilterParameter* paramFrom = fromList.at(fromListIndex).get(); - CustomFilterParameter* paramTo = at(toListIndex).get(); - if (paramFrom->name() == paramTo->name()) { - resultList.append(paramTo->blend(paramFrom, progress)); - ++fromListIndex; - ++toListIndex; - continue; - } - if (codePointCompareLessThan(paramFrom->name(), paramTo->name())) { - resultList.append(paramFrom); - ++fromListIndex; - continue; - } - resultList.append(paramTo); - ++toListIndex; - } - for (; fromListIndex < fromList.size(); ++fromListIndex) - resultList.append(fromList.at(fromListIndex)); - for (; toListIndex < size(); ++toListIndex) - resultList.append(at(toListIndex)); -#ifndef NDEBUG - ASSERT(resultList.checkAlphabeticalOrder()); -#endif -} - -static bool sortParametersByNameComparator(const RefPtr<CustomFilterParameter>& a, const RefPtr<CustomFilterParameter>& b) -{ - return codePointCompareLessThan(a->name(), b->name()); -} - -void CustomFilterParameterList::sortParametersByName() -{ - std::sort(m_parameters.begin(), m_parameters.end(), sortParametersByNameComparator); -} - -} // namespace WebCore - diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterParameterList.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterParameterList.h deleted file mode 100644 index 0dd3dcd9a0e..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterParameterList.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterParameterList_h -#define CustomFilterParameterList_h - -#include "platform/PlatformExport.h" -#include "platform/geometry/LayoutSize.h" -#include "platform/graphics/filters/custom/CustomFilterParameter.h" -#include "wtf/Vector.h" - -namespace WebCore { - -class PLATFORM_EXPORT CustomFilterParameterList { -public: - CustomFilterParameterList(); - explicit CustomFilterParameterList(size_t); - - void blend(const CustomFilterParameterList& from, double progress, CustomFilterParameterList& resultList) const; - bool operator==(const CustomFilterParameterList&) const; - - PassRefPtr<CustomFilterParameter> at(size_t index) const { return m_parameters.at(index); } - size_t size() const { return m_parameters.size(); } - void append(const PassRefPtr<CustomFilterParameter>& parameter) { m_parameters.append(parameter); } - void sortParametersByName(); -private: -#ifndef NDEBUG - bool checkAlphabeticalOrder() const; -#endif - typedef Vector<RefPtr<CustomFilterParameter> > CustomFilterParameterVector; - CustomFilterParameterVector m_parameters; -}; - -} // namespace WebCore - - -#endif // CustomFilterParameterList_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgram.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgram.cpp deleted file mode 100644 index ebaff283493..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgram.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/CustomFilterProgram.h" - -#include "platform/graphics/filters/custom/CustomFilterProgramClient.h" - -namespace WebCore { - -CustomFilterProgram::CustomFilterProgram(CustomFilterProgramType programType, const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType) - : m_programType(programType) - , m_mixSettings(mixSettings) - , m_meshType(meshType) -{ - // Keep the constructor protected to prevent creating this object directly. -} - -CustomFilterProgram::~CustomFilterProgram() -{ - // All the clients should keep a reference to this object. - ASSERT(m_clients.isEmpty()); -} - -void CustomFilterProgram::addClient(CustomFilterProgramClient* client) -{ - if (m_clients.isEmpty()) { - // Notify the StyleCustomFilterProgram that we now have at least a client - // and the loading can begin. - // Note: If the shader is already cached the first client will be notified, - // even if the filter was already built. Add the client only after notifying - // the cache about them, so that we avoid a useless recreation of the filters chain. - willHaveClients(); - } - m_clients.add(client); -} - -void CustomFilterProgram::removeClient(CustomFilterProgramClient* client) -{ - m_clients.remove(client); - if (m_clients.isEmpty()) { - // We have no clients anymore, the cached resources can be purged from memory. - didRemoveLastClient(); - } -} - -void CustomFilterProgram::notifyClients() -{ - for (CustomFilterProgramClientList::iterator iter = m_clients.begin(), end = m_clients.end(); iter != end; ++iter) - iter->key->notifyCustomFilterProgramLoaded(this); -} - -CustomFilterProgramInfo CustomFilterProgram::programInfo() const -{ - ASSERT(isLoaded()); - return CustomFilterProgramInfo(vertexShaderString(), fragmentShaderString(), m_programType, m_mixSettings, m_meshType); -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgram.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgram.h deleted file mode 100644 index 1b949786d8e..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgram.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterProgram_h -#define CustomFilterProgram_h - -#include "platform/graphics/filters/custom/CustomFilterProgramInfo.h" - -#include "wtf/HashCountedSet.h" -#include "wtf/RefCounted.h" -#include "wtf/text/WTFString.h" - -namespace WebCore { - -class GraphicsContext3D; -class CustomFilterCompiledProgram; -class CustomFilterProgramClient; - -// This is the base class for the StyleCustomFilterProgram class which knows how to keep -// references to the cached shaders. -class PLATFORM_EXPORT CustomFilterProgram: public RefCounted<CustomFilterProgram> { -public: - virtual ~CustomFilterProgram(); - - virtual bool isLoaded() const = 0; - - void addClient(CustomFilterProgramClient*); - void removeClient(CustomFilterProgramClient*); - - CustomFilterProgramInfo programInfo() const; - - virtual String vertexShaderString() const = 0; - virtual String fragmentShaderString() const = 0; - CustomFilterProgramType programType() const { return m_programType; } - CustomFilterProgramMixSettings mixSettings() const { return m_mixSettings; } - CustomFilterMeshType meshType() const { return m_meshType; } - -protected: - // StyleCustomFilterProgram can notify the clients that the cached resources are - // loaded and it is ready to create CustomFilterCompiledProgram objects. - void notifyClients(); - - virtual void willHaveClients() = 0; - virtual void didRemoveLastClient() = 0; - - // Keep the constructor protected to prevent creating this object directly. - CustomFilterProgram(CustomFilterProgramType, const CustomFilterProgramMixSettings&, CustomFilterMeshType); - -private: - // CustomFilterPrograms are unique combinations of shaders and can be - // compared using just the pointer value instead. - // These will catch anyone doing a value equal comparison. - bool operator==(const CustomFilterProgram&) const; - bool operator!=(const CustomFilterProgram&) const; - - typedef HashCountedSet<CustomFilterProgramClient*> CustomFilterProgramClientList; - CustomFilterProgramClientList m_clients; - CustomFilterProgramType m_programType; - CustomFilterProgramMixSettings m_mixSettings; - CustomFilterMeshType m_meshType; -}; - -} - - -#endif diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgramClient.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgramClient.cpp deleted file mode 100644 index 85a378f6bac..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgramClient.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/CustomFilterProgramClient.h" - -namespace WebCore { - -CustomFilterProgramClient::~CustomFilterProgramClient() -{ -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgramClient.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgramClient.h deleted file mode 100644 index b13098b9ab8..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgramClient.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterProgramClient_h -#define CustomFilterProgramClient_h - -#include "platform/PlatformExport.h" - -namespace WebCore { - -class CustomFilterProgram; - -class PLATFORM_EXPORT CustomFilterProgramClient { -public: - virtual ~CustomFilterProgramClient(); - - virtual void notifyCustomFilterProgramLoaded(CustomFilterProgram*) = 0; -}; - -} - - -#endif // CustomFilterProgramClient_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgramInfo.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgramInfo.cpp deleted file mode 100644 index a767e6edb90..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgramInfo.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/CustomFilterProgramInfo.h" - -#include "wtf/HashFunctions.h" -#include "wtf/text/StringHash.h" - -namespace WebCore { - -static unsigned hashPossiblyNullString(const String& string) -{ - return string.isNull() ? 0 : DefaultHash<String>::Hash::hash(string); -} - -CustomFilterProgramInfo::CustomFilterProgramInfo() -{ -} - -bool CustomFilterProgramInfo::isEmptyValue() const -{ - return m_vertexShaderString.isNull() - && m_fragmentShaderString.isNull(); -} - -CustomFilterProgramInfo::CustomFilterProgramInfo(WTF::HashTableDeletedValueType) - : m_vertexShaderString(WTF::HashTableDeletedValue) - , m_fragmentShaderString(WTF::HashTableDeletedValue) -{ -} - -bool CustomFilterProgramInfo::isHashTableDeletedValue() const -{ - return m_vertexShaderString.isHashTableDeletedValue() - && m_fragmentShaderString.isHashTableDeletedValue(); -} - -CustomFilterProgramInfo::CustomFilterProgramInfo(const String& vertexShader, const String& fragmentShader, CustomFilterProgramType programType, const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType) - : m_vertexShaderString(vertexShader) - , m_fragmentShaderString(fragmentShader) - , m_programType(programType) - , m_mixSettings(mixSettings) - , m_meshType(meshType) -{ - // At least one of the shaders needs to be non-null. - ASSERT(!m_vertexShaderString.isNull() || !m_fragmentShaderString.isNull()); -} - -unsigned CustomFilterProgramInfo::hash() const -{ - // At least one of the shaders needs to be non-null. - ASSERT(!m_vertexShaderString.isNull() || !m_fragmentShaderString.isNull()); - - bool blendsElementTexture = (m_programType == ProgramTypeBlendsElementTexture); - uintptr_t hashCodes[6] = { - hashPossiblyNullString(m_vertexShaderString), - hashPossiblyNullString(m_fragmentShaderString), - blendsElementTexture, - static_cast<uintptr_t>(blendsElementTexture ? m_mixSettings.blendMode : 0), - static_cast<uintptr_t>(blendsElementTexture ? m_mixSettings.compositeOperator : 0), - m_meshType - }; - return StringHasher::hashMemory<sizeof(hashCodes)>(&hashCodes); -} - -bool CustomFilterProgramInfo::operator==(const CustomFilterProgramInfo& o) const -{ - ASSERT(!isHashTableDeletedValue()); - ASSERT(!o.isHashTableDeletedValue()); - - return m_programType == o.m_programType - && (m_programType != ProgramTypeBlendsElementTexture || m_mixSettings == o.m_mixSettings) - && m_meshType == o.m_meshType - && m_vertexShaderString == o.m_vertexShaderString - && m_fragmentShaderString == o.m_fragmentShaderString; -} - -} // namespace WebCore - diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgramInfo.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgramInfo.h deleted file mode 100644 index 079cd402ede..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterProgramInfo.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterProgramInfo_h -#define CustomFilterProgramInfo_h - -#include "platform/PlatformExport.h" -#include "platform/graphics/GraphicsTypes.h" -#include "platform/graphics/filters/custom/CustomFilterConstants.h" -#include "wtf/HashTableDeletedValueType.h" -#include "wtf/HashTraits.h" -#include "wtf/text/WTFString.h" - -namespace WebCore { - - -struct CustomFilterProgramMixSettings { - CustomFilterProgramMixSettings() - : blendMode(blink::WebBlendModeNormal) - , compositeOperator(CompositeSourceAtop) - { - } - - bool operator==(const CustomFilterProgramMixSettings& o) const - { - return blendMode == o.blendMode && compositeOperator == o.compositeOperator; - } - - blink::WebBlendMode blendMode; - CompositeOperator compositeOperator; -}; - -// CustomFilterProgramInfo is the key used to link CustomFilterProgram with CustomFilterCompiledProgram. -// It can be used as a key in a HashMap, with the note that at least one of Strings needs to be non-null. -// Null strings are placeholders for the default shader. -class PLATFORM_EXPORT CustomFilterProgramInfo { -public: - CustomFilterProgramInfo(const String&, const String&, CustomFilterProgramType, const CustomFilterProgramMixSettings&, CustomFilterMeshType); - - CustomFilterProgramInfo(); - bool isEmptyValue() const; - - CustomFilterProgramInfo(WTF::HashTableDeletedValueType); - bool isHashTableDeletedValue() const; - - unsigned hash() const; - bool operator==(const CustomFilterProgramInfo&) const; - - const String& vertexShaderString() const { return m_vertexShaderString; } - const String& fragmentShaderString() const { return m_fragmentShaderString; } - CustomFilterProgramType programType() const { return m_programType; } - const CustomFilterProgramMixSettings& mixSettings() const { return m_mixSettings; } - CustomFilterMeshType meshType() const { return m_meshType; } -private: - String m_vertexShaderString; - String m_fragmentShaderString; - CustomFilterProgramType m_programType; - CustomFilterProgramMixSettings m_mixSettings; - CustomFilterMeshType m_meshType; -}; - -struct CustomFilterProgramInfoHash { - static unsigned hash(const CustomFilterProgramInfo& programInfo) { return programInfo.hash(); } - static bool equal(const CustomFilterProgramInfo& a, const CustomFilterProgramInfo& b) { return a == b; } - static const bool safeToCompareToEmptyOrDeleted = false; -}; - -struct CustomFilterProgramInfoHashTraits : WTF::SimpleClassHashTraits<CustomFilterProgramInfo> { - static const bool hasIsEmptyValueFunction = true; - static bool isEmptyValue(const CustomFilterProgramInfo& info) { return info.isEmptyValue(); } -}; - -} // namespace WebCore - -namespace WTF { - -template<> struct HashTraits<WebCore::CustomFilterProgramInfo> : WebCore::CustomFilterProgramInfoHashTraits { }; -template<> struct DefaultHash<WebCore::CustomFilterProgramInfo> { - typedef WebCore::CustomFilterProgramInfoHash Hash; -}; - -} - -#endif // CustomFilterProgramInfo_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterRenderer.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterRenderer.cpp deleted file mode 100644 index c8480321696..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterRenderer.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. - * Copyright (C) 2012 Company 100, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/CustomFilterRenderer.h" - -#include "platform/graphics/GraphicsContext3D.h" -#include "platform/graphics/filters/custom/CustomFilterArrayParameter.h" -#include "platform/graphics/filters/custom/CustomFilterCompiledProgram.h" -#include "platform/graphics/filters/custom/CustomFilterMesh.h" -#include "platform/graphics/filters/custom/CustomFilterNumberParameter.h" -#include "platform/graphics/filters/custom/CustomFilterParameter.h" -#include "platform/graphics/filters/custom/CustomFilterTransformParameter.h" -#include "platform/transforms/TransformationMatrix.h" - -namespace WebCore { - -static void orthogonalProjectionMatrix(TransformationMatrix& matrix, float left, float right, float bottom, float top) -{ - ASSERT(matrix.isIdentity()); - - float deltaX = right - left; - float deltaY = top - bottom; - if (!deltaX || !deltaY) - return; - matrix.setM11(2.0f / deltaX); - matrix.setM41(-(right + left) / deltaX); - matrix.setM22(2.0f / deltaY); - matrix.setM42(-(top + bottom) / deltaY); - - // Use big enough near/far values, so that simple rotations of rather large objects will not - // get clipped. 10000 should cover most of the screen resolutions. - const float farValue = 10000; - const float nearValue = -10000; - matrix.setM33(-2.0f / (farValue - nearValue)); - matrix.setM43(- (farValue + nearValue) / (farValue - nearValue)); - matrix.setM44(1.0f); -} - -PassRefPtr<CustomFilterRenderer> CustomFilterRenderer::create(PassRefPtr<GraphicsContext3D> context, CustomFilterProgramType programType, const CustomFilterParameterList& parameters, - unsigned meshRows, unsigned meshColumns, CustomFilterMeshType meshType) -{ - return adoptRef(new CustomFilterRenderer(context, programType, parameters, meshRows, meshColumns, meshType)); -} - -CustomFilterRenderer::CustomFilterRenderer(PassRefPtr<GraphicsContext3D> context, CustomFilterProgramType programType, const CustomFilterParameterList& parameters, - unsigned meshRows, unsigned meshColumns, CustomFilterMeshType meshType) - : m_context(context) - , m_programType(programType) - , m_parameters(parameters) - , m_meshRows(meshRows) - , m_meshColumns(meshColumns) - , m_meshType(meshType) -{ -} - -CustomFilterRenderer::~CustomFilterRenderer() -{ -} - -bool CustomFilterRenderer::premultipliedAlpha() const -{ - return m_programType == ProgramTypeBlendsElementTexture; -} - -bool CustomFilterRenderer::programNeedsInputTexture() const -{ - ASSERT(m_compiledProgram.get()); - return m_compiledProgram->samplerLocation() != -1; -} - -void CustomFilterRenderer::draw(Platform3DObject inputTexture, const IntSize& size) -{ - // FIXME: We would need something like CustomFilterRendererState that will contain the size and other parameters in the future. We should pass that to bindProgramBuffers instead of storing it. - // https://bugs.webkit.org/show_bug.cgi?id=100107 - m_contextSize = size; - - bindProgramAndBuffers(inputTexture); - m_context->drawElements(GL_TRIANGLES, m_mesh->indicesCount(), GL_UNSIGNED_SHORT, 0); - unbindVertexAttributes(); -} - -void CustomFilterRenderer::setCompiledProgram(PassRefPtr<CustomFilterCompiledProgram> compiledProgram) -{ - m_compiledProgram = compiledProgram; -} - -bool CustomFilterRenderer::prepareForDrawing() -{ - m_context->makeContextCurrent(); - if (!m_compiledProgram || !m_compiledProgram->isInitialized()) - return false; - initializeMeshIfNeeded(); - return true; -} - -void CustomFilterRenderer::initializeMeshIfNeeded() -{ - if (m_mesh.get()) - return; - - // FIXME: Sharing the mesh would just save the time needed to upload it to the GPU, so I assume we could - // benchmark that for performance. - // https://bugs.webkit.org/show_bug.cgi?id=88429 - m_mesh = CustomFilterMesh::create(m_context.get(), m_meshColumns, m_meshRows, FloatRect(0, 0, 1, 1), m_meshType); -} - -void CustomFilterRenderer::bindVertexAttribute(int attributeLocation, unsigned size, unsigned offset) -{ - if (attributeLocation != -1) { - m_context->vertexAttribPointer(attributeLocation, size, GL_FLOAT, false, m_mesh->bytesPerVertex(), offset); - m_context->enableVertexAttribArray(attributeLocation); - } -} - -void CustomFilterRenderer::unbindVertexAttribute(int attributeLocation) -{ - if (attributeLocation != -1) - m_context->disableVertexAttribArray(attributeLocation); -} - -void CustomFilterRenderer::bindProgramArrayParameters(int uniformLocation, CustomFilterArrayParameter* arrayParameter) -{ - unsigned parameterSize = arrayParameter->size(); - Vector<GC3Dfloat> floatVector; - - for (unsigned i = 0; i < parameterSize; ++i) - floatVector.append(arrayParameter->valueAt(i)); - - m_context->uniform1fv(uniformLocation, parameterSize, floatVector.data()); -} - -void CustomFilterRenderer::bindProgramNumberParameters(int uniformLocation, CustomFilterNumberParameter* numberParameter) -{ - switch (numberParameter->size()) { - case 1: - m_context->uniform1f(uniformLocation, numberParameter->valueAt(0)); - break; - case 2: - m_context->uniform2f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1)); - break; - case 3: - m_context->uniform3f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1), numberParameter->valueAt(2)); - break; - case 4: - m_context->uniform4f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1), numberParameter->valueAt(2), numberParameter->valueAt(3)); - break; - default: - ASSERT_NOT_REACHED(); - } -} - -void CustomFilterRenderer::bindProgramTransformParameter(int uniformLocation, CustomFilterTransformParameter* transformParameter) -{ - TransformationMatrix matrix; - if (m_contextSize.width() && m_contextSize.height()) { - // The viewport is a box with the size of 1 unit, so we are scaling up here to make sure that translations happen using real pixel - // units. At the end we scale back down in order to map it back to the original box. Note that transforms come in reverse order, because it is - // supposed to multiply to the left of the coordinates of the vertices. - // Note that the origin (0, 0) of the viewport is in the middle of the context, so there's no need to change the origin of the transform - // in order to rotate around the middle of mesh. - matrix.scale3d(1.0 / m_contextSize.width(), 1.0 / m_contextSize.height(), 1); - transformParameter->applyTransform(matrix, m_contextSize); - matrix.scale3d(m_contextSize.width(), m_contextSize.height(), 1); - } - float glMatrix[16]; - matrix.toColumnMajorFloatArray(glMatrix); - m_context->uniformMatrix4fv(uniformLocation, 1, false, &glMatrix[0]); -} - -void CustomFilterRenderer::bindProgramParameters() -{ - // FIXME: Find a way to reset uniforms that are not specified in CSS. This is needed to avoid using values - // set by other previous rendered filters. - // https://bugs.webkit.org/show_bug.cgi?id=76440 - - size_t parametersSize = m_parameters.size(); - for (size_t i = 0; i < parametersSize; ++i) { - CustomFilterParameter* parameter = m_parameters.at(i).get(); - int uniformLocation = m_compiledProgram->uniformLocationByName(parameter->name()); - if (uniformLocation == -1) - continue; - switch (parameter->parameterType()) { - case CustomFilterParameter::Array: - bindProgramArrayParameters(uniformLocation, static_cast<CustomFilterArrayParameter*>(parameter)); - break; - case CustomFilterParameter::Number: - bindProgramNumberParameters(uniformLocation, static_cast<CustomFilterNumberParameter*>(parameter)); - break; - case CustomFilterParameter::Transform: - bindProgramTransformParameter(uniformLocation, static_cast<CustomFilterTransformParameter*>(parameter)); - break; - } - } -} - -void CustomFilterRenderer::bindProgramAndBuffers(Platform3DObject inputTexture) -{ - ASSERT(m_compiledProgram->isInitialized()); - - m_context->useProgram(m_compiledProgram->program()); - - if (programNeedsInputTexture()) { - // We should be binding the DOM element texture sampler only if the author is using the CSS mix function. - ASSERT(m_programType == ProgramTypeBlendsElementTexture); - ASSERT(m_compiledProgram->samplerLocation() != -1); - - m_context->activeTexture(GL_TEXTURE0); - m_context->uniform1i(m_compiledProgram->samplerLocation(), 0); - m_context->bindTexture(GL_TEXTURE_2D, inputTexture); - m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - - if (m_compiledProgram->projectionMatrixLocation() != -1) { - TransformationMatrix projectionMatrix; - orthogonalProjectionMatrix(projectionMatrix, -0.5, 0.5, -0.5, 0.5); - float glProjectionMatrix[16]; - projectionMatrix.toColumnMajorFloatArray(glProjectionMatrix); - m_context->uniformMatrix4fv(m_compiledProgram->projectionMatrixLocation(), 1, false, &glProjectionMatrix[0]); - } - - ASSERT(m_meshColumns); - ASSERT(m_meshRows); - - if (m_compiledProgram->meshSizeLocation() != -1) - m_context->uniform2f(m_compiledProgram->meshSizeLocation(), m_meshColumns, m_meshRows); - - if (m_compiledProgram->tileSizeLocation() != -1) - m_context->uniform2f(m_compiledProgram->tileSizeLocation(), 1.0 / m_meshColumns, 1.0 / m_meshRows); - - if (m_compiledProgram->meshBoxLocation() != -1) { - // FIXME: This will change when filter margins will be implemented, - // see https://bugs.webkit.org/show_bug.cgi?id=71400 - m_context->uniform4f(m_compiledProgram->meshBoxLocation(), -0.5, -0.5, 1.0, 1.0); - } - - if (m_compiledProgram->samplerSizeLocation() != -1) - m_context->uniform2f(m_compiledProgram->samplerSizeLocation(), m_contextSize.width(), m_contextSize.height()); - - m_context->bindBuffer(GL_ARRAY_BUFFER, m_mesh->verticesBufferObject()); - m_context->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_mesh->elementsBufferObject()); - - bindVertexAttribute(m_compiledProgram->positionAttribLocation(), PositionAttribSize, PositionAttribOffset); - bindVertexAttribute(m_compiledProgram->texAttribLocation(), TexAttribSize, TexAttribOffset); - bindVertexAttribute(m_compiledProgram->meshAttribLocation(), MeshAttribSize, MeshAttribOffset); - if (m_meshType == MeshTypeDetached) - bindVertexAttribute(m_compiledProgram->triangleAttribLocation(), TriangleAttribSize, TriangleAttribOffset); - - bindProgramParameters(); -} - -void CustomFilterRenderer::unbindVertexAttributes() -{ - unbindVertexAttribute(m_compiledProgram->positionAttribLocation()); - unbindVertexAttribute(m_compiledProgram->texAttribLocation()); - unbindVertexAttribute(m_compiledProgram->meshAttribLocation()); - if (m_meshType == MeshTypeDetached) - unbindVertexAttribute(m_compiledProgram->triangleAttribLocation()); -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterRenderer.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterRenderer.h deleted file mode 100644 index 059fc42a448..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterRenderer.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. - * Copyright (C) 2012 Company 100, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterRenderer_h -#define CustomFilterRenderer_h - -#include "platform/geometry/IntSize.h" -#include "platform/graphics/GraphicsTypes3D.h" -#include "platform/graphics/filters/custom/CustomFilterConstants.h" -#include "platform/graphics/filters/custom/CustomFilterParameterList.h" -#include "wtf/RefCounted.h" -#include "wtf/RefPtr.h" - -namespace WebCore { - -class CustomFilterArrayParameter; -class CustomFilterCompiledProgram; -class CustomFilterMesh; -class CustomFilterNumberParameter; -class CustomFilterTransformParameter; -class GraphicsContext3D; - -class CustomFilterRenderer : public RefCounted<CustomFilterRenderer> { -public: - static PassRefPtr<CustomFilterRenderer> create(PassRefPtr<GraphicsContext3D>, CustomFilterProgramType, const CustomFilterParameterList&, - unsigned meshRows, unsigned meshColumns, CustomFilterMeshType); - ~CustomFilterRenderer(); - - bool premultipliedAlpha() const; - bool programNeedsInputTexture() const; - - bool prepareForDrawing(); - - void draw(Platform3DObject, const IntSize&); - - CustomFilterCompiledProgram* compiledProgram() const { return m_compiledProgram.get(); } - void setCompiledProgram(PassRefPtr<CustomFilterCompiledProgram>); - -private: - CustomFilterRenderer(PassRefPtr<GraphicsContext3D>, CustomFilterProgramType, const CustomFilterParameterList&, - unsigned meshRows, unsigned meshColumns, CustomFilterMeshType); - - void initializeCompiledProgramIfNeeded(); - void initializeMeshIfNeeded(); - - void bindVertexAttribute(int attributeLocation, unsigned size, unsigned offset); - void unbindVertexAttribute(int attributeLocation); - void bindProgramArrayParameters(int uniformLocation, CustomFilterArrayParameter*); - void bindProgramNumberParameters(int uniformLocation, CustomFilterNumberParameter*); - void bindProgramTransformParameter(int uniformLocation, CustomFilterTransformParameter*); - void bindProgramParameters(); - void bindProgramAndBuffers(Platform3DObject inputTexture); - void unbindVertexAttributes(); - - RefPtr<GraphicsContext3D> m_context; - RefPtr<CustomFilterCompiledProgram> m_compiledProgram; - CustomFilterProgramType m_programType; - RefPtr<CustomFilterMesh> m_mesh; - IntSize m_contextSize; - - CustomFilterParameterList m_parameters; - - unsigned m_meshRows; - unsigned m_meshColumns; - CustomFilterMeshType m_meshType; -}; - -} // namespace WebCore - -#endif // CustomFilterRenderer_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterTransformParameter.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterTransformParameter.cpp deleted file mode 100644 index 317130288e1..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterTransformParameter.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/CustomFilterTransformParameter.h" - -#include "platform/geometry/FloatSize.h" - -namespace WebCore { - -PassRefPtr<CustomFilterParameter> CustomFilterTransformParameter::blend(const CustomFilterParameter* fromParameter, double progress) -{ - if (!fromParameter || !isSameType(*fromParameter)) - return this; - - const CustomFilterTransformParameter* fromTransformParameter = static_cast<const CustomFilterTransformParameter*>(fromParameter); - const TransformOperations& from = fromTransformParameter->operations(); - const TransformOperations& to = operations(); - if (from == to) - return this; - - RefPtr<CustomFilterTransformParameter> result = CustomFilterTransformParameter::create(name()); - if (from.size() && to.size()) - result->setOperations(to.blend(from, progress)); - else - result->setOperations(progress > 0.5 ? to : from); - return result; -} - -bool CustomFilterTransformParameter::operator==(const CustomFilterParameter& o) const -{ - if (!isSameType(o)) - return false; - const CustomFilterTransformParameter* other = static_cast<const CustomFilterTransformParameter*>(&o); - return m_operations == other->m_operations; -} - -void CustomFilterTransformParameter::applyTransform(TransformationMatrix& transform, const FloatSize& boxSize) const -{ - for (unsigned i = 0, size = m_operations.size(); i < size; ++i) - m_operations.at(i)->apply(transform, boxSize); -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterTransformParameter.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterTransformParameter.h deleted file mode 100644 index 62dc58e05ea..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterTransformParameter.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterTransformParameter_h -#define CustomFilterTransformParameter_h - -#include "platform/PlatformExport.h" -#include "platform/graphics/filters/custom/CustomFilterParameter.h" -#include "platform/transforms/TransformOperations.h" - -namespace WebCore { - -class FloatSize; -class TransformationMatrix; - -class PLATFORM_EXPORT CustomFilterTransformParameter : public CustomFilterParameter { -public: - static PassRefPtr<CustomFilterTransformParameter> create(const String& name) - { - return adoptRef(new CustomFilterTransformParameter(name)); - } - - virtual PassRefPtr<CustomFilterParameter> blend(const CustomFilterParameter* fromParameter, double progress); - - virtual bool operator==(const CustomFilterParameter&) const; - - void applyTransform(TransformationMatrix&, const FloatSize& boxSize) const; - - const TransformOperations& operations() const { return m_operations; } - void setOperations(const TransformOperations& value) { m_operations = value; } - -private: - CustomFilterTransformParameter(const String& name) - : CustomFilterParameter(Transform, name) - { - } - virtual ~CustomFilterTransformParameter() - { - } - - TransformOperations m_operations; -}; - -} // namespace WebCore - -#endif // CustomFilterTransformParameter_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterValidatedProgram.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterValidatedProgram.cpp deleted file mode 100644 index 63e384383be..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterValidatedProgram.cpp +++ /dev/null @@ -1,617 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/CustomFilterValidatedProgram.h" - -#include "platform/NotImplemented.h" -#include "platform/graphics/angle/ANGLEPlatformBridge.h" -#include "platform/graphics/filters/custom/CustomFilterConstants.h" -#include "platform/graphics/filters/custom/CustomFilterGlobalContext.h" -#include "wtf/HashMap.h" -#include "wtf/Vector.h" -#include "wtf/text/StringBuilder.h" -#include "wtf/text/StringHash.h" - -namespace WebCore { - -#define SHADER(Src) (#Src) - -typedef HashMap<String, ShDataType> SymbolNameToTypeMap; - -static SymbolNameToTypeMap* builtInAttributeNameToTypeMap() -{ - static SymbolNameToTypeMap* nameToTypeMap = 0; - if (!nameToTypeMap) { - nameToTypeMap = new SymbolNameToTypeMap; - nameToTypeMap->set("a_meshCoord", SH_FLOAT_VEC2); - nameToTypeMap->set("a_position", SH_FLOAT_VEC4); - nameToTypeMap->set("a_texCoord", SH_FLOAT_VEC2); - nameToTypeMap->set("a_triangleCoord", SH_FLOAT_VEC3); - } - return nameToTypeMap; -} - -static SymbolNameToTypeMap* builtInUniformNameToTypeMap() -{ - static SymbolNameToTypeMap* nameToTypeMap = 0; - if (!nameToTypeMap) { - nameToTypeMap = new SymbolNameToTypeMap; - nameToTypeMap->set("u_meshBox", SH_FLOAT_VEC4); - nameToTypeMap->set("u_meshSize", SH_FLOAT_VEC2); - nameToTypeMap->set("u_projectionMatrix", SH_FLOAT_MAT4); - nameToTypeMap->set("u_textureSize", SH_FLOAT_VEC2); - nameToTypeMap->set("u_tileSize", SH_FLOAT_VEC2); - } - return nameToTypeMap; -} - -static bool validateSymbols(const Vector<ANGLEShaderSymbol>& symbols, CustomFilterMeshType meshType) -{ - for (size_t i = 0; i < symbols.size(); ++i) { - const ANGLEShaderSymbol& symbol = symbols[i]; - switch (symbol.symbolType) { - case SHADER_SYMBOL_TYPE_ATTRIBUTE: { - SymbolNameToTypeMap* attributeNameToTypeMap = builtInAttributeNameToTypeMap(); - SymbolNameToTypeMap::iterator builtInAttribute = attributeNameToTypeMap->find(symbol.name); - if (builtInAttribute == attributeNameToTypeMap->end()) { - // The author defined a custom attribute. - // FIXME: Report the validation error. - // https://bugs.webkit.org/show_bug.cgi?id=74416 - return false; - } - if (meshType == MeshTypeAttached && symbol.name == "a_triangleCoord") { - // a_triangleCoord is only available for detached meshes. - // FIXME: Report the validation error. - // https://bugs.webkit.org/show_bug.cgi?id=74416 - return false; - } - if (symbol.dataType != builtInAttribute->value) { - // The author defined one of the built-in attributes with the wrong type. - // FIXME: Report the validation error. - // https://bugs.webkit.org/show_bug.cgi?id=74416 - return false; - } - break; - } - case SHADER_SYMBOL_TYPE_UNIFORM: { - if (symbol.isSampler()) { - // FIXME: For now, we restrict shaders with any sampler defined. - // When we implement texture parameters, we will allow shaders whose samplers are bound to valid textures. - // We must not allow OpenGL to give unbound samplers a default value of 0 because that references the element texture, - // which should be inaccessible to the author's shader code. - // https://bugs.webkit.org/show_bug.cgi?id=96230 - return false; - } - - SymbolNameToTypeMap* uniformNameToTypeMap = builtInUniformNameToTypeMap(); - SymbolNameToTypeMap::iterator builtInUniform = uniformNameToTypeMap->find(symbol.name); - if (builtInUniform != uniformNameToTypeMap->end() && (symbol.isArray || symbol.dataType != builtInUniform->value)) { - // The author defined one of the built-in uniforms with the wrong type. - // FIXME: Report the validation error. - // https://bugs.webkit.org/show_bug.cgi?id=74416 - return false; - } - break; - } - default: - ASSERT_NOT_REACHED(); - break; - } - } - - return true; -} - -String CustomFilterValidatedProgram::defaultVertexShaderString() -{ - DEFINE_STATIC_LOCAL(String, vertexShaderString, (SHADER( - attribute mediump vec4 a_position; - uniform mediump mat4 u_projectionMatrix; - - void main() - { - gl_Position = u_projectionMatrix * a_position; - } - ))); - return vertexShaderString; -} - -String CustomFilterValidatedProgram::defaultFragmentShaderString() -{ - DEFINE_STATIC_LOCAL(String, fragmentShaderString, (SHADER( - void main() - { - } - ))); - return fragmentShaderString; -} - -CustomFilterValidatedProgram::CustomFilterValidatedProgram(CustomFilterGlobalContext* globalContext, const CustomFilterProgramInfo& programInfo) - : m_globalContext(globalContext) - , m_programInfo(programInfo) - , m_isInitialized(false) -{ - platformInit(); - - String originalVertexShader = programInfo.vertexShaderString(); - if (originalVertexShader.isNull()) - originalVertexShader = defaultVertexShaderString(); - - String originalFragmentShader = programInfo.fragmentShaderString(); - if (originalFragmentShader.isNull()) - originalFragmentShader = defaultFragmentShaderString(); - - // Shaders referenced from the CSS mix function use a different validator than regular WebGL shaders. See core/platform/graphics/filters/custom/CustomFilterGlobalContext.h for more details. - bool blendsElementTexture = (programInfo.programType() == ProgramTypeBlendsElementTexture); - ANGLEPlatformBridge* validator = blendsElementTexture ? m_globalContext->mixShaderValidator() : m_globalContext->webglShaderValidator(); - String vertexShaderLog, fragmentShaderLog; - Vector<ANGLEShaderSymbol> symbols; - bool vertexShaderValid = validator->compileShaderSource(originalVertexShader.utf8().data(), SHADER_TYPE_VERTEX, m_validatedVertexShader, vertexShaderLog, symbols); - bool fragmentShaderValid = validator->compileShaderSource(originalFragmentShader.utf8().data(), SHADER_TYPE_FRAGMENT, m_validatedFragmentShader, fragmentShaderLog, symbols); - if (!vertexShaderValid || !fragmentShaderValid) { - // FIXME: Report the validation errors. - // https://bugs.webkit.org/show_bug.cgi?id=74416 - return; - } - - if (!validateSymbols(symbols, m_programInfo.meshType())) { - // FIXME: Report validation errors. - // https://bugs.webkit.org/show_bug.cgi?id=74416 - return; - } - - // We need to add texture access, blending, and compositing code to shaders that are referenced from the CSS mix function. - if (blendsElementTexture) { - rewriteMixVertexShader(symbols); - rewriteMixFragmentShader(); - } - - m_isInitialized = true; -} - -PassRefPtr<CustomFilterCompiledProgram> CustomFilterValidatedProgram::compiledProgram() -{ - ASSERT(m_isInitialized && m_globalContext && !m_validatedVertexShader.isNull() && !m_validatedFragmentShader.isNull()); - if (!m_compiledProgram) { - m_compiledProgram = CustomFilterCompiledProgram::create(m_globalContext->context(), m_validatedVertexShader, m_validatedFragmentShader, m_programInfo.programType()); - ASSERT(m_compiledProgram->isInitialized()); - ASSERT(m_compiledProgram->samplerLocation() != -1 || !needsInputTexture()); - } - return m_compiledProgram; -} - -bool CustomFilterValidatedProgram::needsInputTexture() const -{ - return m_programInfo.programType() == ProgramTypeBlendsElementTexture - && m_programInfo.mixSettings().compositeOperator != CompositeClear - && m_programInfo.mixSettings().compositeOperator != CompositeCopy; -} - -void CustomFilterValidatedProgram::rewriteMixVertexShader(const Vector<ANGLEShaderSymbol>& symbols) -{ - ASSERT(m_programInfo.programType() == ProgramTypeBlendsElementTexture); - - // If the author defined a_texCoord, we can use it to shuttle the texture coordinate to the fragment shader. - // Note that vertex attributes are read-only in GLSL, so the author could not have changed a_texCoord's value. - // Also, note that we would have already rejected the shader if the author defined a_texCoord with the wrong type. - bool texCoordAttributeDefined = false; - for (size_t i = 0; i < symbols.size(); ++i) { - if (symbols[i].name == "a_texCoord") - texCoordAttributeDefined = true; - } - - if (!texCoordAttributeDefined) - m_validatedVertexShader.append("attribute mediump vec2 a_texCoord;"); - - // During validation, ANGLE renamed the author's "main" function to "css_main". - // We write our own "main" function and call "css_main" from it. - // This makes rewriting easy and ensures that our code runs after all author code. - m_validatedVertexShader.append(SHADER( - varying mediump vec2 css_v_texCoord; - - void main() - { - css_main(); - css_v_texCoord = a_texCoord; - } - )); -} - -void CustomFilterValidatedProgram::rewriteMixFragmentShader() -{ - ASSERT(m_programInfo.programType() == ProgramTypeBlendsElementTexture); - - StringBuilder builder; - // ANGLE considered these symbols as built-ins during validation under the SH_CSS_SHADERS_SPEC flag. - // Now, we have to define these symbols in order to make this shader valid GLSL. - // We define these symbols before the author's shader code, which makes them accessible to author code. - builder.append(SHADER( - mediump vec4 css_MixColor = vec4(0.0); - mediump mat4 css_ColorMatrix = mat4(1.0); - )); - builder.append(m_validatedFragmentShader); - builder.append(blendFunctionString(m_programInfo.mixSettings().blendMode)); - builder.append(compositeFunctionString(m_programInfo.mixSettings().compositeOperator)); - // We define symbols like "css_u_texture" after the author's shader code, which makes them inaccessible to author code. - // In particular, "css_u_texture" represents the DOM element texture, so it's important to keep it inaccessible to - // author code for security reasons. - builder.append(SHADER( - uniform sampler2D css_u_texture; - varying mediump vec2 css_v_texCoord; - - void main() - { - css_main(); - mediump vec4 originalColor = texture2D(css_u_texture, css_v_texCoord); - mediump vec4 multipliedColor = clamp(css_ColorMatrix * originalColor, 0.0, 1.0); - mediump vec4 clampedMixColor = clamp(css_MixColor, 0.0, 1.0); - mediump vec3 blendedColor = css_BlendColor(multipliedColor.rgb, clampedMixColor.rgb); - mediump vec3 weightedColor = (1.0 - multipliedColor.a) * clampedMixColor.rgb + multipliedColor.a * blendedColor; - gl_FragColor = css_Composite(multipliedColor.rgb, multipliedColor.a, weightedColor.rgb, clampedMixColor.a); - } - )); - m_validatedFragmentShader = builder.toString(); -} - -String CustomFilterValidatedProgram::blendFunctionString(blink::WebBlendMode blendMode) -{ - // Implemented using the same symbol names as the Compositing and Blending spec: - // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnormal - // Cs: is the source color in css_BlendColor() and the source color component in css_BlendComponent() - // Cb: is the backdrop color in css_BlendColor() and the backdrop color component in css_BlendComponent() - const char* blendColorExpression = "vec3(css_BlendComponent(Cb.r, Cs.r), css_BlendComponent(Cb.g, Cs.g), css_BlendComponent(Cb.b, Cs.b))"; - const char* blendComponentExpression = "Co = 0.0;"; - bool needsLuminosityHelperFunctions = false; - bool needsSaturationHelperFunctions = false; - String blendFunctionString; - switch (blendMode) { - case blink::WebBlendModeNormal: - blendColorExpression = "Cs"; - break; - case blink::WebBlendModeMultiply: - blendColorExpression = "Cs * Cb"; - break; - case blink::WebBlendModeScreen: - blendColorExpression = "Cb + Cs - (Cb * Cs)"; - break; - case blink::WebBlendModeDarken: - blendColorExpression = "min(Cb, Cs)"; - break; - case blink::WebBlendModeLighten: - blendColorExpression = "max(Cb, Cs)"; - break; - case blink::WebBlendModeDifference: - blendColorExpression = "abs(Cb - Cs)"; - break; - case blink::WebBlendModeExclusion: - blendColorExpression = "Cb + Cs - 2.0 * Cb * Cs"; - break; - case blink::WebBlendModeOverlay: - /* - Co = HardLight(Cs, Cb) - = if(Cb <= 0.5) - Multiply(Cs, 2 x Cb) - else - Screen(Cs, 2 x Cb - 1) - = if(Cb <= 0.5) - Cs x (2 x Cb) - else - Cs + (2 x Cb - 1) - (Cs x (2 x Cb - 1)) - */ - blendComponentExpression = SHADER( - if (Cb <= 0.5) - Co = Cs * (2.0 * Cb); - else - Co = Cs + (2.0 * Cb - 1.0) - (Cs * (2.0 * Cb - 1.0)); - ); - break; - case blink::WebBlendModeColorDodge: - /* - Co = if(Cs < 1) - min(1, Cb / (1 - Cs)) - else - 1 - */ - blendComponentExpression = SHADER( - if (Cs < 1.0) - Co = min(1.0, Cb / (1.0 - Cs)); - else - Co = 1.0; - ); - break; - case blink::WebBlendModeColorBurn: - /* - Co = if(Cs > 0) - 1 - min(1, (1 - Cb) / Cs) - else - 0 - */ - blendComponentExpression = SHADER( - if (Cs > 0.0) - Co = 1.0 - min(1.0, (1.0 - Cb) / Cs); - else - Co = 0.0; - ); - break; - case blink::WebBlendModeHardLight: - /* - Co = if(Cs <= 0.5) - Multiply(Cb, 2 x Cs) - else - Screen(Cb, 2 x Cs -1) - = if(Cs <= 0.5) - Cb x (2 x Cs) - else - Cb + (2 x Cs - 1) - (Cb x (2 x Cs - 1)) - */ - blendComponentExpression = SHADER( - if (Cs <= 0.5) - Co = Cb * (2.0 * Cs); - else - Co = Cb + (2.0 * Cs - 1.0) - (Cb * (2.0 * Cs - 1.0)); - ); - break; - case blink::WebBlendModeSoftLight: - /* - Co = if(Cs <= 0.5) - Cb - (1 - 2 x Cs) x Cb x (1 - Cb) - else - Cb + (2 x Cs - 1) x (D(Cb) - Cb) - - with - - D(Cb) = if(Cb <= 0.25) - (16 * Cb - 12) x Cb + 4) x Cb - else - sqrt(Cb) - */ - blendComponentExpression = SHADER( - mediump float D; - if (Cb <= 0.25) - D = ((16.0 * Cb - 12.0) * Cb + 4.0) * Cb; - else - D = sqrt(Cb); - - if (Cs <= 0.5) - Co = Cb - (1.0 - 2.0 * Cs) * Cb * (1.0 - Cb); - else - Co = Cb + (2.0 * Cs - 1.0) * (D - Cb); - ); - break; - case blink::WebBlendModeColor: - needsLuminosityHelperFunctions = true; - blendColorExpression = "css_SetLum(Cs, css_Lum(Cb))"; - break; - case blink::WebBlendModeLuminosity: - needsLuminosityHelperFunctions = true; - blendColorExpression = "css_SetLum(Cb, css_Lum(Cs))"; - break; - case blink::WebBlendModeHue: - needsLuminosityHelperFunctions = true; - needsSaturationHelperFunctions = true; - blendColorExpression = "css_SetLum(css_SetSat(Cs, css_Sat(Cb)), css_Lum(Cb))"; - break; - case blink::WebBlendModeSaturation: - needsLuminosityHelperFunctions = true; - needsSaturationHelperFunctions = true; - blendColorExpression = "css_SetLum(css_SetSat(Cb, css_Sat(Cs)), css_Lum(Cb))"; - break; - default: - ASSERT_NOT_REACHED(); - } - - if (needsLuminosityHelperFunctions) { - blendFunctionString.append(SHADER( - mediump float css_Lum(mediump vec3 C) - { - return 0.3 * C.r + 0.59 * C.g + 0.11 * C.b; - } - mediump vec3 css_ClipColor(mediump vec3 C) - { - mediump float L = css_Lum(C); - mediump float n = min(min(C.r, C.g), C.b); - mediump float x = max(max(C.r, C.g), C.b); - if (n < 0.0) - C = L + (((C - L) * L) / (L - n)); - if (x > 1.0) - C = L + (((C - L) * (1.0 - L) / (x - L))); - return C; - } - mediump vec3 css_SetLum(mediump vec3 C, mediump float l) - { - C += l - css_Lum(C); - return css_ClipColor(C); - } - )); - } - - if (needsSaturationHelperFunctions) { - blendFunctionString.append(SHADER( - mediump float css_Sat(mediump vec3 C) - { - mediump float cMin = min(min(C.r, C.g), C.b); - mediump float cMax = max(max(C.r, C.g), C.b); - return cMax - cMin; - } - void css_SetSatHelper(inout mediump float cMin, inout mediump float cMid, inout mediump float cMax, mediump float s) - { - if (cMax > cMin) { - cMid = (((cMid - cMin) * s) / (cMax - cMin)); - cMax = s; - } else { - cMid = cMax = 0.0; - } - cMin = 0.0; - } - mediump vec3 css_SetSat(mediump vec3 C, mediump float s) - { - if (C.r <= C.g) { - if (C.g <= C.b) { - css_SetSatHelper(C.r, C.g, C.b, s); - } else { - if (C.r <= C.b) - css_SetSatHelper(C.r, C.b, C.g, s); - else - css_SetSatHelper(C.b, C.r, C.g, s); - } - } else { - if (C.r <= C.b) { - css_SetSatHelper(C.g, C.r, C.b, s); - } else { - if (C.g <= C.b) - css_SetSatHelper(C.g, C.b, C.r, s); - else - css_SetSatHelper(C.b, C.g, C.r, s); - } - } - return C; - } - )); - } - - blendFunctionString.append(String::format(SHADER( - mediump float css_BlendComponent(mediump float Cb, mediump float Cs) - { - mediump float Co; - %s - return Co; - } - mediump vec3 css_BlendColor(mediump vec3 Cb, mediump vec3 Cs) - { - return %s; - } - ), blendComponentExpression, blendColorExpression)); - - return blendFunctionString; -} - -String CustomFilterValidatedProgram::compositeFunctionString(CompositeOperator compositeOperator) -{ - // Use the same symbol names as the Compositing and Blending spec: - // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnormal - // Cs: is the source color - // Cb: is the backdrop color - // as: is the source alpha - // ab: is the backdrop alpha - // Fa: is defined by the Porter Duff operator in use - // Fb: is defined by the Porter Duff operator in use - const char* Fa = 0; - const char* Fb = 0; - switch (compositeOperator) { - case CompositeSourceAtop: - Fa = "ab"; - Fb = "1.0 - as"; - break; - case CompositeClear: - Fa = "0.0"; - Fb = "0.0"; - break; - case CompositeCopy: - Fa = "1.0"; - Fb = "0.0"; - break; - case CompositeSourceOver: - Fa = "1.0"; - Fb = "1.0 - as"; - break; - case CompositeSourceIn: - Fa = "ab"; - Fb = "0.0"; - break; - case CompositeSourceOut: - Fa = "1.0 - ab"; - Fb = "0.0"; - break; - case CompositeDestinationOver: - Fa = "1.0 - ab"; - Fb = "1.0"; - break; - case CompositeDestinationIn: - Fa = "0.0"; - Fb = "as"; - break; - case CompositeDestinationOut: - Fa = "0.0"; - Fb = "1.0 - as"; - break; - case CompositeDestinationAtop: - Fa = "1.0 - ab"; - Fb = "as"; - break; - case CompositeXOR: - Fa = "1.0 - ab"; - Fb = "1.0 - as"; - break; - case CompositePlusLighter: - notImplemented(); - return String(); - default: - // The CSS parser should not have accepted any other composite operators. - ASSERT_NOT_REACHED(); - return String(); - } - - ASSERT(Fa && Fb); - // Use the general formula for compositing, lifted from the spec: - // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#generalformula - return String::format(SHADER( - mediump vec4 css_Composite(mediump vec3 Cb, mediump float ab, mediump vec3 Cs, mediump float as) - { - mediump float Fa = %s; - mediump float Fb = %s; - return vec4(as * Fa * Cs + ab * Fb * Cb, as * Fa + ab * Fb); - } - ), Fa, Fb); -} - -CustomFilterValidatedProgram::~CustomFilterValidatedProgram() -{ - platformDestroy(); - - if (m_globalContext) - m_globalContext->removeValidatedProgram(this); -} - -CustomFilterProgramInfo CustomFilterValidatedProgram::validatedProgramInfo() const -{ - ASSERT(m_isInitialized); - return CustomFilterProgramInfo(m_validatedVertexShader, m_validatedFragmentShader, m_programInfo.programType(), m_programInfo.mixSettings(), m_programInfo.meshType()); -} - -void CustomFilterValidatedProgram::platformInit() -{ -} - -void CustomFilterValidatedProgram::platformDestroy() -{ -} - -} // namespace WebCore - diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterValidatedProgram.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterValidatedProgram.h deleted file mode 100644 index fed78481ae8..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/CustomFilterValidatedProgram.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CustomFilterValidatedProgram_h -#define CustomFilterValidatedProgram_h - -#include "platform/graphics/filters/custom/CustomFilterCompiledProgram.h" -#include "platform/graphics/filters/custom/CustomFilterProgramInfo.h" -#include "wtf/PassRefPtr.h" -#include "wtf/RefCounted.h" -#include "wtf/RefPtr.h" -#include "wtf/text/WTFString.h" - -// PlatformCompiledProgram defines a type that is compatible with the framework used to implement accelerated compositing on a particular platform. -namespace WebCore { - -struct ANGLEShaderSymbol; -class CustomFilterCompiledProgram; -class CustomFilterGlobalContext; - -// -// A unique combination of vertex shader and fragment shader is only validated and compiled once. -// All shaders are validated through ANGLE in CustomFilterValidatedProgram before being compiled by the GraphicsContext3D in CustomFilterCompiledProgram. -// For shaders that use the CSS mix function, CustomFilterValidatedProgram adds shader code to perform DOM texture access, blending, and compositing. -// -// The CustomFilterGlobalContext caches the validated programs. -// CustomFilterValidatedProgram owns a CustomFilterCompiledProgram if validation and compilation succeeds. -// Thus, compiled programs are cached via their validated program owners. -// -// CustomFilterGlobalContext has a weak reference to the CustomFilterValidatedProgram. -// Thus, the CustomFilterValidatedProgram destructor needs to notify the CustomFilterGlobalContext to remove the program from the cache. -// FECustomFilter is the reference owner of the CustomFilterValidatedProgram. -// Thus, a validated and compiled shader is only kept alive as long as there is at least one visible layer that applies the shader. -// -class PLATFORM_EXPORT CustomFilterValidatedProgram : public RefCounted<CustomFilterValidatedProgram> { -public: - static PassRefPtr<CustomFilterValidatedProgram> create(CustomFilterGlobalContext* globalContext, const CustomFilterProgramInfo& programInfo) - { - return adoptRef(new CustomFilterValidatedProgram(globalContext, programInfo)); - } - - ~CustomFilterValidatedProgram(); - - const CustomFilterProgramInfo& programInfo() const { return m_programInfo; } - CustomFilterProgramInfo validatedProgramInfo() const; - - PassRefPtr<CustomFilterCompiledProgram> compiledProgram(); - - const String& validatedVertexShader() const - { - ASSERT(m_isInitialized); - return m_validatedVertexShader; - } - - const String& validatedFragmentShader() const - { - ASSERT(m_isInitialized); - return m_validatedFragmentShader; - } - - bool isInitialized() const { return m_isInitialized; } - - // 'detachFromGlobalContext' is called when the CustomFilterGlobalContext is deleted, and there's no need for the callback anymore. - // Note that CustomFilterGlobalContext does not keep a strong reference to the CustomFilterValidatedProgram. - void detachFromGlobalContext() { m_globalContext = 0; } -private: - CustomFilterValidatedProgram(CustomFilterGlobalContext*, const CustomFilterProgramInfo&); - - void platformInit(); - void platformDestroy(); - - static String defaultVertexShaderString(); - static String defaultFragmentShaderString(); - - static String blendFunctionString(blink::WebBlendMode); - static String compositeFunctionString(CompositeOperator); - - void rewriteMixVertexShader(const Vector<ANGLEShaderSymbol>& symbols); - void rewriteMixFragmentShader(); - - bool needsInputTexture() const; - - CustomFilterGlobalContext* m_globalContext; - CustomFilterProgramInfo m_programInfo; - - String m_validatedVertexShader; - String m_validatedFragmentShader; - - RefPtr<CustomFilterCompiledProgram> m_compiledProgram; - - bool m_isInitialized; -}; - -} - - -#endif diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/FECustomFilter.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/FECustomFilter.cpp deleted file mode 100644 index bcce901401a..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/FECustomFilter.cpp +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/FECustomFilter.h" - -#include "platform/graphics/Extensions3D.h" -#include "platform/graphics/GraphicsContext3D.h" -#include "platform/graphics/filters/custom/CustomFilterRenderer.h" -#include "platform/graphics/filters/custom/CustomFilterValidatedProgram.h" -#include "platform/text/TextStream.h" -#include "wtf/Uint8ClampedArray.h" - -namespace WebCore { - -FECustomFilter::FECustomFilter(Filter* filter, PassRefPtr<GraphicsContext3D> context, PassRefPtr<CustomFilterValidatedProgram> validatedProgram, const CustomFilterParameterList& parameters, - unsigned meshRows, unsigned meshColumns, CustomFilterMeshType meshType) - : FilterEffect(filter) - , m_context(context) - , m_validatedProgram(validatedProgram) - , m_inputTexture(0) - , m_frameBuffer(0) - , m_depthBuffer(0) - , m_destTexture(0) - , m_triedMultisampleBuffer(false) - , m_multisampleFrameBuffer(0) - , m_multisampleRenderBuffer(0) - , m_multisampleDepthBuffer(0) -{ - // We will not pass a CustomFilterCompiledProgram here, as we only want to compile it when we actually need it in the first paint. - m_customFilterRenderer = CustomFilterRenderer::create(m_context, m_validatedProgram->programInfo().programType(), parameters, meshRows, meshColumns, meshType); -} - -PassRefPtr<FECustomFilter> FECustomFilter::create(Filter* filter, PassRefPtr<GraphicsContext3D> context, PassRefPtr<CustomFilterValidatedProgram> validatedProgram, const CustomFilterParameterList& parameters, - unsigned meshRows, unsigned meshColumns, CustomFilterMeshType meshType) -{ - return adoptRef(new FECustomFilter(filter, context, validatedProgram, parameters, meshRows, meshColumns, meshType)); -} - -FECustomFilter::~FECustomFilter() -{ - deleteRenderBuffers(); -} - -void FECustomFilter::deleteRenderBuffers() -{ - ASSERT(m_context); - m_context->makeContextCurrent(); - if (m_inputTexture) { - m_context->deleteTexture(m_inputTexture); - m_inputTexture = 0; - } - if (m_frameBuffer) { - // Make sure to unbind any framebuffer from the context first, otherwise - // some platforms might refuse to bind the same buffer id again. - m_context->bindFramebuffer(GL_FRAMEBUFFER, 0); - m_context->deleteFramebuffer(m_frameBuffer); - m_frameBuffer = 0; - } - if (m_depthBuffer) { - m_context->deleteRenderbuffer(m_depthBuffer); - m_depthBuffer = 0; - } - if (m_destTexture) { - m_context->deleteTexture(m_destTexture); - m_destTexture = 0; - } - deleteMultisampleRenderBuffers(); -} - -void FECustomFilter::deleteMultisampleRenderBuffers() -{ - if (m_multisampleFrameBuffer) { - // Make sure to unbind any framebuffer from the context first, otherwise - // some platforms might refuse to bind the same buffer id again. - m_context->bindFramebuffer(GL_FRAMEBUFFER, 0); - m_context->deleteFramebuffer(m_multisampleFrameBuffer); - m_multisampleFrameBuffer = 0; - } - if (m_multisampleRenderBuffer) { - m_context->deleteRenderbuffer(m_multisampleRenderBuffer); - m_multisampleRenderBuffer = 0; - } - if (m_multisampleDepthBuffer) { - m_context->deleteRenderbuffer(m_multisampleDepthBuffer); - m_multisampleDepthBuffer = 0; - } -} - -void FECustomFilter::applySoftware() -{ - if (!applyShader()) - clearShaderResult(); -} - -void FECustomFilter::clearShaderResult() -{ - clearResult(); - Uint8ClampedArray* dstPixelArray = createUnmultipliedImageResult(); - if (!dstPixelArray) - return; - - FilterEffect* in = inputEffect(0); - setIsAlphaImage(in->isAlphaImage()); - IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); - in->copyUnmultipliedImage(dstPixelArray, effectDrawingRect); -} - -void FECustomFilter::drawFilterMesh(Platform3DObject inputTexture) -{ - bool multisample = canUseMultisampleBuffers(); - m_context->bindFramebuffer(GL_FRAMEBUFFER, multisample ? m_multisampleFrameBuffer : m_frameBuffer); - m_context->viewport(0, 0, m_contextSize.width(), m_contextSize.height()); - - m_context->clearColor(0, 0, 0, 0); - m_context->clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - m_customFilterRenderer->draw(inputTexture, m_contextSize); - - if (multisample) - resolveMultisampleBuffer(); -} - -bool FECustomFilter::prepareForDrawing() -{ - m_context->makeContextCurrent(); - - // Lazily inject the compiled program into the CustomFilterRenderer. - if (!m_customFilterRenderer->compiledProgram()) - m_customFilterRenderer->setCompiledProgram(m_validatedProgram->compiledProgram()); - - if (!m_customFilterRenderer->prepareForDrawing()) - return false; - - // Only allocate a texture if the program needs one and the caller doesn't allocate one by itself. - if ((m_customFilterRenderer->programNeedsInputTexture() && !ensureInputTexture()) || !ensureFrameBuffer()) - return false; - - return true; -} - -bool FECustomFilter::applyShader() -{ - Uint8ClampedArray* dstPixelArray = m_customFilterRenderer->premultipliedAlpha() ? createPremultipliedImageResult() : createUnmultipliedImageResult(); - if (!dstPixelArray) - return false; - - if (!prepareForDrawing()) - return false; - - FilterEffect* in = inputEffect(0); - IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); - IntSize newContextSize(effectDrawingRect.size()); - if (!resizeContextIfNeeded(newContextSize)) - return false; - - bool needsInputTexture = m_customFilterRenderer->programNeedsInputTexture(); - if (needsInputTexture) { - RefPtr<Uint8ClampedArray> srcPixelArray = in->asUnmultipliedImage(effectDrawingRect); - uploadInputTexture(srcPixelArray.get()); - } - drawFilterMesh(needsInputTexture ? m_inputTexture : 0); - - ASSERT(static_cast<size_t>(newContextSize.width() * newContextSize.height() * 4) == dstPixelArray->length()); - m_context->readPixels(0, 0, newContextSize.width(), newContextSize.height(), GL_RGBA, GL_UNSIGNED_BYTE, dstPixelArray->data()); - - return true; -} - -bool FECustomFilter::ensureInputTexture() -{ - if (!m_inputTexture) - m_inputTexture = m_context->createTexture(); - return m_inputTexture; -} - -void FECustomFilter::uploadInputTexture(Uint8ClampedArray* srcPixelArray) -{ - m_context->bindTexture(GL_TEXTURE_2D, m_inputTexture); - m_context->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_contextSize.width(), m_contextSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, srcPixelArray->data()); -} - -bool FECustomFilter::ensureFrameBuffer() -{ - if (!m_frameBuffer) - m_frameBuffer = m_context->createFramebuffer(); - if (!m_depthBuffer) - m_depthBuffer = m_context->createRenderbuffer(); - if (!m_destTexture) - m_destTexture = m_context->createTexture(); - return m_frameBuffer && m_depthBuffer && m_destTexture; -} - -bool FECustomFilter::createMultisampleBuffer() -{ - ASSERT(!m_triedMultisampleBuffer); - m_triedMultisampleBuffer = true; - - Extensions3D* extensions = m_context->extensions(); - if (!extensions - || !extensions->supports("GL_ANGLE_framebuffer_multisample") - || !extensions->supports("GL_ANGLE_framebuffer_blit") - || !extensions->supports("GL_OES_rgb8_rgba8")) - return false; - - extensions->ensureEnabled("GL_ANGLE_framebuffer_blit"); - extensions->ensureEnabled("GL_ANGLE_framebuffer_multisample"); - extensions->ensureEnabled("GL_OES_rgb8_rgba8"); - - if (!m_multisampleFrameBuffer) - m_multisampleFrameBuffer = m_context->createFramebuffer(); - if (!m_multisampleRenderBuffer) - m_multisampleRenderBuffer = m_context->createRenderbuffer(); - if (!m_multisampleDepthBuffer) - m_multisampleDepthBuffer = m_context->createRenderbuffer(); - - return true; -} - -void FECustomFilter::resolveMultisampleBuffer() -{ - ASSERT(m_triedMultisampleBuffer && m_multisampleFrameBuffer && m_multisampleRenderBuffer && m_multisampleDepthBuffer); - m_context->bindFramebuffer(Extensions3D::READ_FRAMEBUFFER, m_multisampleFrameBuffer); - m_context->bindFramebuffer(Extensions3D::DRAW_FRAMEBUFFER, m_frameBuffer); - - ASSERT(m_context->extensions()); - m_context->extensions()->blitFramebuffer(0, 0, m_contextSize.width(), m_contextSize.height(), 0, 0, m_contextSize.width(), m_contextSize.height(), GL_COLOR_BUFFER_BIT, GL_NEAREST); - - m_context->bindFramebuffer(Extensions3D::READ_FRAMEBUFFER, 0); - m_context->bindFramebuffer(Extensions3D::DRAW_FRAMEBUFFER, 0); - - m_context->bindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer); -} - -bool FECustomFilter::canUseMultisampleBuffers() const -{ - return m_triedMultisampleBuffer && m_multisampleFrameBuffer && m_multisampleRenderBuffer && m_multisampleDepthBuffer; -} - -bool FECustomFilter::resizeMultisampleBuffers(const IntSize& newContextSize) -{ - if (!m_triedMultisampleBuffer && !createMultisampleBuffer()) - return false; - - if (!canUseMultisampleBuffers()) - return false; - - static const int kMaxSampleCount = 4; - int maxSupportedSampleCount = 0; - m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSupportedSampleCount); - int sampleCount = std::min(kMaxSampleCount, maxSupportedSampleCount); - if (!sampleCount) { - deleteMultisampleRenderBuffers(); - return false; - } - - Extensions3D* extensions = m_context->extensions(); - ASSERT(extensions); - - m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFrameBuffer); - - m_context->bindRenderbuffer(GL_RENDERBUFFER, m_multisampleRenderBuffer); - extensions->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, Extensions3D::RGBA8_OES, newContextSize.width(), newContextSize.height()); - m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_multisampleRenderBuffer); - - m_context->bindRenderbuffer(GL_RENDERBUFFER, m_multisampleDepthBuffer); - extensions->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_DEPTH_COMPONENT16, newContextSize.width(), newContextSize.height()); - m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_multisampleDepthBuffer); - - m_context->bindRenderbuffer(GL_RENDERBUFFER, 0); - - if (m_context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - deleteMultisampleRenderBuffers(); - return false; - } - - return true; -} - -bool FECustomFilter::resizeContextIfNeeded(const IntSize& newContextSize) -{ - if (newContextSize.isEmpty()) - return false; - if (m_contextSize == newContextSize) - return true; - - int maxTextureSize = 0; - m_context->getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); - if (newContextSize.height() > maxTextureSize || newContextSize.width() > maxTextureSize) - return false; - - return resizeContext(newContextSize); -} - -bool FECustomFilter::resizeContext(const IntSize& newContextSize) -{ - bool multisample = resizeMultisampleBuffers(newContextSize); - - m_context->bindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer); - m_context->bindTexture(GL_TEXTURE_2D, m_destTexture); - // We are going to clear the output buffer anyway, so we can safely initialize the destination texture with garbage data. - // FIXME: GraphicsContext3D::texImage2DDirect is not implemented on Chromium. - m_context->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, newContextSize.width(), newContextSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_destTexture, 0); - - // We don't need the depth buffer for the texture framebuffer, if we already - // have a multisample buffer. - if (!multisample) { - m_context->bindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer); - m_context->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, newContextSize.width(), newContextSize.height()); - m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer); - } - - if (m_context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - return false; - - if (multisample) { - // Clear the framebuffer first, otherwise the first blit will fail. - m_context->clearColor(0, 0, 0, 0); - m_context->clear(GL_COLOR_BUFFER_BIT); - } - - m_context->bindRenderbuffer(GL_RENDERBUFFER, 0); - - m_contextSize = newContextSize; - return true; -} - -TextStream& FECustomFilter::externalRepresentation(TextStream& ts, int indent) const -{ - writeIndent(ts, indent); - ts << "[feCustomFilter"; - FilterEffect::externalRepresentation(ts); - ts << "]\n"; - inputEffect(0)->externalRepresentation(ts, indent + 1); - return ts; -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/FECustomFilter.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/FECustomFilter.h deleted file mode 100644 index b2fb50b9d45..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/FECustomFilter.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef FECustomFilter_h -#define FECustomFilter_h - -#include "platform/graphics/GraphicsTypes3D.h" -#include "platform/graphics/filters/Filter.h" -#include "platform/graphics/filters/FilterEffect.h" -#include "platform/graphics/filters/custom/CustomFilterConstants.h" -#include "platform/graphics/filters/custom/CustomFilterOperation.h" -#include "wtf/RefPtr.h" - -namespace WebCore { - -class CustomFilterRenderer; -class CustomFilterValidatedProgram; -class GraphicsContext3D; -class IntSize; - -class PLATFORM_EXPORT FECustomFilter : public FilterEffect { -public: - static PassRefPtr<FECustomFilter> create(Filter*, PassRefPtr<GraphicsContext3D>, PassRefPtr<CustomFilterValidatedProgram>, const CustomFilterParameterList&, - unsigned meshRows, unsigned meshColumns, CustomFilterMeshType); - - virtual TextStream& externalRepresentation(TextStream&, int indention) const; - -private: - FECustomFilter(Filter*, PassRefPtr<GraphicsContext3D>, PassRefPtr<CustomFilterValidatedProgram>, const CustomFilterParameterList&, - unsigned meshRows, unsigned meshColumns, CustomFilterMeshType); - ~FECustomFilter(); - - virtual void applySoftware() OVERRIDE; - - bool applyShader(); - void clearShaderResult(); - bool initializeContext(); - - bool prepareForDrawing(); - - void drawFilterMesh(Platform3DObject inputTexture); - bool ensureInputTexture(); - void uploadInputTexture(Uint8ClampedArray* srcPixelArray); - bool resizeContextIfNeeded(const IntSize&); - bool resizeContext(const IntSize&); - - bool canUseMultisampleBuffers() const; - bool createMultisampleBuffer(); - bool resizeMultisampleBuffers(const IntSize&); - void resolveMultisampleBuffer(); - void deleteMultisampleRenderBuffers(); - - bool ensureFrameBuffer(); - void deleteRenderBuffers(); - - RefPtr<GraphicsContext3D> m_context; - RefPtr<CustomFilterValidatedProgram> m_validatedProgram; - RefPtr<CustomFilterRenderer> m_customFilterRenderer; - IntSize m_contextSize; - - Platform3DObject m_inputTexture; - Platform3DObject m_frameBuffer; - Platform3DObject m_depthBuffer; - Platform3DObject m_destTexture; - - bool m_triedMultisampleBuffer; - Platform3DObject m_multisampleFrameBuffer; - Platform3DObject m_multisampleRenderBuffer; - Platform3DObject m_multisampleDepthBuffer; -}; - -} // namespace WebCore - -#endif // FECustomFilter_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/ValidatedCustomFilterOperation.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/ValidatedCustomFilterOperation.cpp deleted file mode 100644 index c01b3af9e67..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/ValidatedCustomFilterOperation.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#include "platform/graphics/filters/custom/ValidatedCustomFilterOperation.h" - -#include "platform/graphics/filters/custom/CustomFilterParameter.h" -#include "platform/graphics/filters/custom/CustomFilterValidatedProgram.h" - -namespace WebCore { - -ValidatedCustomFilterOperation::ValidatedCustomFilterOperation(PassRefPtr<CustomFilterValidatedProgram> validatedProgram, - const CustomFilterParameterList& sortedParameters, unsigned meshRows, unsigned meshColumns, CustomFilterMeshType meshType) - : FilterOperation(VALIDATED_CUSTOM) - , m_validatedProgram(validatedProgram) - , m_parameters(sortedParameters) - , m_meshRows(meshRows) - , m_meshColumns(meshColumns) - , m_meshType(meshType) -{ -} - -ValidatedCustomFilterOperation::~ValidatedCustomFilterOperation() -{ -} - -PassRefPtr<FilterOperation> ValidatedCustomFilterOperation::blend(const FilterOperation*, double) const -{ - ASSERT_NOT_REACHED(); - return const_cast<ValidatedCustomFilterOperation*>(this); -} - -} // namespace WebCore - diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/ValidatedCustomFilterOperation.h b/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/ValidatedCustomFilterOperation.h deleted file mode 100644 index 9542914869d..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/filters/custom/ValidatedCustomFilterOperation.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef ValidatedCustomFilterOperation_h -#define ValidatedCustomFilterOperation_h - -#include "platform/graphics/filters/FilterOperation.h" -#include "platform/graphics/filters/custom/CustomFilterConstants.h" -#include "platform/graphics/filters/custom/CustomFilterParameterList.h" - -namespace WebCore { - -class CustomFilterValidatedProgram; - -class PLATFORM_EXPORT ValidatedCustomFilterOperation : public FilterOperation { -public: - static PassRefPtr<ValidatedCustomFilterOperation> create(PassRefPtr<CustomFilterValidatedProgram> validatedProgram, - const CustomFilterParameterList& sortedParameters, unsigned meshRows, unsigned meshColumns, CustomFilterMeshType meshType) - { - return adoptRef(new ValidatedCustomFilterOperation(validatedProgram, sortedParameters, meshRows, meshColumns, meshType)); - } - - virtual ~ValidatedCustomFilterOperation(); - - virtual bool affectsOpacity() const { return true; } - virtual bool movesPixels() const { return true; } - - - CustomFilterValidatedProgram* validatedProgram() const { return m_validatedProgram.get(); } - const CustomFilterParameterList& parameters() const { return m_parameters; } - - unsigned meshRows() const { return m_meshRows; } - unsigned meshColumns() const { return m_meshColumns; } - - CustomFilterMeshType meshType() const { return m_meshType; } - -private: - virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress) const OVERRIDE; - virtual bool operator==(const FilterOperation& o) const - { - if (!isSameType(o)) - return false; - - const ValidatedCustomFilterOperation* other = static_cast<const ValidatedCustomFilterOperation*>(&o); - return m_validatedProgram.get() == other->m_validatedProgram.get() - && m_meshRows == other->m_meshRows - && m_meshColumns == other->m_meshColumns - && m_meshType == other->m_meshType - && m_parameters == other->m_parameters; - } - - ValidatedCustomFilterOperation(PassRefPtr<CustomFilterValidatedProgram>, const CustomFilterParameterList&, unsigned meshRows, unsigned meshColumns, CustomFilterMeshType); - - RefPtr<CustomFilterValidatedProgram> m_validatedProgram; - - CustomFilterParameterList m_parameters; - unsigned m_meshRows; - unsigned m_meshColumns; - CustomFilterMeshType m_meshType; -}; - -DEFINE_FILTER_OPERATION_TYPE_CASTS(ValidatedCustomFilterOperation, VALIDATED_CUSTOM); - -} // namespace WebCore - - -#endif // ValidatedCustomFilterOperation_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp b/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp index 54c13e20d7e..0ec4bf91790 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp @@ -32,33 +32,41 @@ #include "platform/graphics/gpu/DrawingBuffer.h" +#include "platform/RuntimeEnabledFeatures.h" #include <algorithm> #include "platform/TraceEvent.h" -#include "platform/graphics/Extensions3D.h" #include "platform/graphics/GraphicsLayer.h" +#include "platform/graphics/gpu/Extensions3DUtil.h" #include "public/platform/Platform.h" #include "public/platform/WebCompositorSupport.h" #include "public/platform/WebExternalBitmap.h" #include "public/platform/WebExternalTextureLayer.h" #include "public/platform/WebGraphicsContext3D.h" +#include "public/platform/WebGraphicsContext3DProvider.h" +#ifndef NDEBUG +#include "wtf/RefCountedLeakCounter.h" +#endif using namespace std; namespace WebCore { +namespace { // Global resource ceiling (expressed in terms of pixels) for DrawingBuffer creation and resize. // When this limit is set, DrawingBuffer::create() and DrawingBuffer::reset() calls that would // exceed the global cap will instead clear the buffer. -static const int s_maximumResourceUsePixels = 16 * 1024 * 1024; -static int s_currentResourceUsePixels = 0; -static const float s_resourceAdjustedRatio = 0.5; +const int s_maximumResourceUsePixels = 16 * 1024 * 1024; +int s_currentResourceUsePixels = 0; +const float s_resourceAdjustedRatio = 0.5; -static const bool s_allowContextEvictionOnCreate = true; -static const int s_maxScaleAttempts = 3; +const bool s_allowContextEvictionOnCreate = true; +const int s_maxScaleAttempts = 3; + +DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, drawingBufferCounter, ("DrawingBuffer")); class ScopedTextureUnit0BindingRestorer { public: - ScopedTextureUnit0BindingRestorer(GraphicsContext3D* context, GC3Denum activeTextureUnit, Platform3DObject textureUnitZeroId) + ScopedTextureUnit0BindingRestorer(blink::WebGraphicsContext3D* context, GLenum activeTextureUnit, Platform3DObject textureUnitZeroId) : m_context(context) , m_oldActiveTextureUnit(activeTextureUnit) , m_oldTextureUnitZeroId(textureUnitZeroId) @@ -72,48 +80,58 @@ public: } private: - GraphicsContext3D* m_context; - GC3Denum m_oldActiveTextureUnit; + blink::WebGraphicsContext3D* m_context; + GLenum m_oldActiveTextureUnit; Platform3DObject m_oldTextureUnitZeroId; }; -PassRefPtr<DrawingBuffer> DrawingBuffer::create(GraphicsContext3D* context, const IntSize& size, PreserveDrawingBuffer preserve, PassRefPtr<ContextEvictionManager> contextEvictionManager) +} // namespace + +PassRefPtr<DrawingBuffer> DrawingBuffer::create(PassOwnPtr<blink::WebGraphicsContext3D> context, const IntSize& size, PreserveDrawingBuffer preserve, blink::WebGraphicsContext3D::Attributes requestedAttributes, PassRefPtr<ContextEvictionManager> contextEvictionManager) { - Extensions3D* extensions = context->extensions(); - bool multisampleSupported = extensions->supports("GL_ANGLE_framebuffer_blit") - && extensions->supports("GL_ANGLE_framebuffer_multisample") - && extensions->supports("GL_OES_rgb8_rgba8"); + ASSERT(context); + OwnPtr<Extensions3DUtil> extensionsUtil = Extensions3DUtil::create(context.get()); + if (!extensionsUtil) { + // This might be the first time we notice that the WebGraphicsContext3D is lost. + return nullptr; + } + bool multisampleSupported = extensionsUtil->supportsExtension("GL_CHROMIUM_framebuffer_multisample") + && extensionsUtil->supportsExtension("GL_OES_rgb8_rgba8"); if (multisampleSupported) { - extensions->ensureEnabled("GL_ANGLE_framebuffer_blit"); - extensions->ensureEnabled("GL_ANGLE_framebuffer_multisample"); - extensions->ensureEnabled("GL_OES_rgb8_rgba8"); + extensionsUtil->ensureExtensionEnabled("GL_CHROMIUM_framebuffer_multisample"); + extensionsUtil->ensureExtensionEnabled("GL_OES_rgb8_rgba8"); } - bool packedDepthStencilSupported = extensions->supports("GL_OES_packed_depth_stencil"); + bool packedDepthStencilSupported = extensionsUtil->supportsExtension("GL_OES_packed_depth_stencil"); if (packedDepthStencilSupported) - extensions->ensureEnabled("GL_OES_packed_depth_stencil"); + extensionsUtil->ensureExtensionEnabled("GL_OES_packed_depth_stencil"); - RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(context, size, multisampleSupported, packedDepthStencilSupported, preserve, contextEvictionManager)); + RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(context, extensionsUtil.release(), multisampleSupported, packedDepthStencilSupported, preserve, requestedAttributes, contextEvictionManager)); + if (!drawingBuffer->initialize(size)) { + drawingBuffer->beginDestruction(); + return PassRefPtr<DrawingBuffer>(); + } return drawingBuffer.release(); } -DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, - const IntSize& size, - bool multisampleExtensionSupported, - bool packedDepthStencilExtensionSupported, - PreserveDrawingBuffer preserve, - PassRefPtr<ContextEvictionManager> contextEvictionManager) +DrawingBuffer::DrawingBuffer(PassOwnPtr<blink::WebGraphicsContext3D> context, + PassOwnPtr<Extensions3DUtil> extensionsUtil, + bool multisampleExtensionSupported, + bool packedDepthStencilExtensionSupported, + PreserveDrawingBuffer preserve, + blink::WebGraphicsContext3D::Attributes requestedAttributes, + PassRefPtr<ContextEvictionManager> contextEvictionManager) : m_preserveDrawingBuffer(preserve) , m_scissorEnabled(false) , m_texture2DBinding(0) , m_framebufferBinding(0) , m_activeTextureUnit(GL_TEXTURE0) , m_context(context) + , m_extensionsUtil(extensionsUtil) , m_size(-1, -1) + , m_requestedAttributes(requestedAttributes) , m_multisampleExtensionSupported(multisampleExtensionSupported) , m_packedDepthStencilExtensionSupported(packedDepthStencilExtensionSupported) , m_fbo(0) - , m_colorBuffer(0) - , m_frontColorBuffer(0) , m_depthStencilBuffer(0) , m_depthBuffer(0) , m_stencilBuffer(0) @@ -121,54 +139,85 @@ DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, , m_multisampleColorBuffer(0) , m_contentsChanged(true) , m_contentsChangeCommitted(false) + , m_layerComposited(false) + , m_multisampleMode(None) , m_internalColorFormat(0) , m_colorFormat(0) , m_internalRenderbufferFormat(0) , m_maxTextureSize(0) + , m_sampleCount(0) + , m_packAlignment(4) + , m_destructionInProgress(false) , m_contextEvictionManager(contextEvictionManager) { // Used by browser tests to detect the use of a DrawingBuffer. TRACE_EVENT_INSTANT0("test_gpu", "DrawingBufferCreation"); - initialize(size); +#ifndef NDEBUG + drawingBufferCounter.increment(); +#endif } DrawingBuffer::~DrawingBuffer() { - releaseResources(); + ASSERT(m_destructionInProgress); + ASSERT(m_textureMailboxes.isEmpty()); + m_layer.clear(); + m_context.clear(); +#ifndef NDEBUG + drawingBufferCounter.decrement(); +#endif } void DrawingBuffer::markContentsChanged() { m_contentsChanged = true; m_contentsChangeCommitted = false; + m_layerComposited = false; +} + +bool DrawingBuffer::layerComposited() const +{ + return m_layerComposited; +} + +void DrawingBuffer::markLayerComposited() +{ + m_layerComposited = true; } blink::WebGraphicsContext3D* DrawingBuffer::context() { - if (!m_context) - return 0; - return m_context->webContext(); + return m_context.get(); } bool DrawingBuffer::prepareMailbox(blink::WebExternalTextureMailbox* outMailbox, blink::WebExternalBitmap* bitmap) { - if (!m_context || !m_contentsChanged || !m_lastColorBuffer) + if (!m_contentsChanged) return false; + if (m_destructionInProgress) { + // It can be hit in the following sequence. + // 1. WebGL draws something. + // 2. The compositor begins the frame. + // 3. Javascript makes a context lost using WEBGL_lose_context extension. + // 4. Here. + return false; + } + m_context->makeContextCurrent(); - // Resolve the multisampled buffer into the texture referenced by m_lastColorBuffer mailbox. - if (multisample()) + // Resolve the multisampled buffer into m_colorBuffer texture. + if (m_multisampleMode != None) commit(); if (bitmap) { bitmap->setSize(size()); unsigned char* pixels = bitmap->pixels(); - bool needPremultiply = m_attributes.alpha && !m_attributes.premultipliedAlpha; - GraphicsContext3D::AlphaOp op = needPremultiply ? GraphicsContext3D::AlphaDoPremultiply : GraphicsContext3D::AlphaDoNothing; + bool needPremultiply = m_actualAttributes.alpha && !m_actualAttributes.premultipliedAlpha; + WebGLImageConversion::AlphaOp op = needPremultiply ? WebGLImageConversion::AlphaDoPremultiply : WebGLImageConversion::AlphaDoNothing; if (pixels) - m_context->readBackFramebuffer(pixels, size().width(), size().height(), GraphicsContext3D::ReadbackSkia, op); + readBackFramebuffer(pixels, size().width(), size().height(), ReadbackSkia, op); } // We must restore the texture binding since creating new textures, @@ -176,134 +225,221 @@ bool DrawingBuffer::prepareMailbox(blink::WebExternalTextureMailbox* outMailbox, ScopedTextureUnit0BindingRestorer restorer(m_context.get(), m_activeTextureUnit, m_texture2DBinding); // First try to recycle an old buffer. - RefPtr<MailboxInfo> nextFrontColorBuffer = recycledMailbox(); + RefPtr<MailboxInfo> frontColorBufferMailbox = recycledMailbox(); // No buffer available to recycle, create a new one. - if (!nextFrontColorBuffer) { - unsigned newColorBuffer = createColorTexture(m_size); + if (!frontColorBufferMailbox) { + TextureInfo newTexture; + newTexture.textureId = createColorTexture(); + allocateTextureMemory(&newTexture, m_size); // Bad things happened, abandon ship. - if (!newColorBuffer) + if (!newTexture.textureId) return false; - nextFrontColorBuffer = createNewMailbox(newColorBuffer); + frontColorBufferMailbox = createNewMailbox(newTexture); } if (m_preserveDrawingBuffer == Discard) { - m_colorBuffer = nextFrontColorBuffer->textureId; - swap(nextFrontColorBuffer, m_lastColorBuffer); + swap(frontColorBufferMailbox->textureInfo, m_colorBuffer); // It appears safe to overwrite the context's framebuffer binding in the Discard case since there will always be a // WebGLRenderingContext::clearIfComposited() call made before the next draw call which restores the framebuffer binding. // If this stops being true at some point, we should track the current framebuffer binding in the DrawingBuffer and restore // it after attaching the new back buffer here. m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo); - m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer, 0); + if (m_multisampleMode == ImplicitResolve) + m_context->framebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0, m_sampleCount); + else + m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0); } else { - Extensions3D* extensions = m_context->extensions(); - extensions->copyTextureCHROMIUM(GL_TEXTURE_2D, m_colorBuffer, nextFrontColorBuffer->textureId, 0, GL_RGBA, GL_UNSIGNED_BYTE); + m_context->copyTextureCHROMIUM(GL_TEXTURE_2D, m_colorBuffer.textureId, frontColorBufferMailbox->textureInfo.textureId, 0, GL_RGBA, GL_UNSIGNED_BYTE); } - if (multisample() && !m_framebufferBinding) + if (m_multisampleMode != None && !m_framebufferBinding) bind(); else restoreFramebufferBinding(); m_contentsChanged = false; - context()->bindTexture(GL_TEXTURE_2D, nextFrontColorBuffer->textureId); - context()->produceTextureCHROMIUM(GL_TEXTURE_2D, nextFrontColorBuffer->mailbox.name); - context()->flush(); - m_context->markLayerComposited(); - - *outMailbox = nextFrontColorBuffer->mailbox; - m_frontColorBuffer = nextFrontColorBuffer->textureId; + m_context->bindTexture(GL_TEXTURE_2D, frontColorBufferMailbox->textureInfo.textureId); + m_context->produceTextureCHROMIUM(GL_TEXTURE_2D, frontColorBufferMailbox->mailbox.name); + m_context->flush(); + frontColorBufferMailbox->mailbox.syncPoint = m_context->insertSyncPoint(); + frontColorBufferMailbox->mailbox.allowOverlay = frontColorBufferMailbox->textureInfo.imageId != 0; + markLayerComposited(); + + // set m_parentDrawingBuffer to make sure 'this' stays alive as long as it has live mailboxes + ASSERT(!frontColorBufferMailbox->m_parentDrawingBuffer); + frontColorBufferMailbox->m_parentDrawingBuffer = this; + *outMailbox = frontColorBufferMailbox->mailbox; + m_frontColorBuffer = frontColorBufferMailbox->textureInfo; return true; } void DrawingBuffer::mailboxReleased(const blink::WebExternalTextureMailbox& mailbox) { + if (m_destructionInProgress) { + mailboxReleasedWhileDestructionInProgress(mailbox); + return; + } + for (size_t i = 0; i < m_textureMailboxes.size(); i++) { - RefPtr<MailboxInfo> mailboxInfo = m_textureMailboxes[i]; - if (!memcmp(mailboxInfo->mailbox.name, mailbox.name, sizeof(mailbox.name))) { - mailboxInfo->mailbox.syncPoint = mailbox.syncPoint; - m_recycledMailboxes.append(mailboxInfo.release()); - return; - } - } - ASSERT_NOT_REACHED(); + RefPtr<MailboxInfo> mailboxInfo = m_textureMailboxes[i]; + if (nameEquals(mailboxInfo->mailbox, mailbox)) { + mailboxInfo->mailbox.syncPoint = mailbox.syncPoint; + ASSERT(mailboxInfo->m_parentDrawingBuffer.get() == this); + mailboxInfo->m_parentDrawingBuffer.clear(); + m_recycledMailboxQueue.prepend(mailboxInfo->mailbox); + return; + } + } + ASSERT_NOT_REACHED(); +} + +void DrawingBuffer::mailboxReleasedWhileDestructionInProgress(const blink::WebExternalTextureMailbox& mailbox) +{ + ASSERT(m_textureMailboxes.size()); + m_context->makeContextCurrent(); + // Ensure not to call the destructor until deleteMailbox() is completed. + RefPtr<DrawingBuffer> self = this; + deleteMailbox(mailbox); } PassRefPtr<DrawingBuffer::MailboxInfo> DrawingBuffer::recycledMailbox() { - if (!m_context || m_recycledMailboxes.isEmpty()) + if (m_recycledMailboxQueue.isEmpty()) return PassRefPtr<MailboxInfo>(); - RefPtr<MailboxInfo> mailboxInfo = m_recycledMailboxes.last().release(); - m_recycledMailboxes.removeLast(); + blink::WebExternalTextureMailbox mailbox = m_recycledMailboxQueue.takeLast(); + RefPtr<MailboxInfo> mailboxInfo; + for (size_t i = 0; i < m_textureMailboxes.size(); i++) { + if (nameEquals(m_textureMailboxes[i]->mailbox, mailbox)) { + mailboxInfo = m_textureMailboxes[i]; + break; + } + } + ASSERT(mailboxInfo); if (mailboxInfo->mailbox.syncPoint) { - context()->waitSyncPoint(mailboxInfo->mailbox.syncPoint); + m_context->waitSyncPoint(mailboxInfo->mailbox.syncPoint); mailboxInfo->mailbox.syncPoint = 0; } - context()->bindTexture(GL_TEXTURE_2D, mailboxInfo->textureId); - context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailboxInfo->mailbox.name); - if (mailboxInfo->size != m_size) { - m_context->texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, m_size.width(), m_size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE); + m_context->bindTexture(GL_TEXTURE_2D, mailboxInfo->textureInfo.textureId); + allocateTextureMemory(&mailboxInfo->textureInfo, m_size); mailboxInfo->size = m_size; } return mailboxInfo.release(); } -PassRefPtr<DrawingBuffer::MailboxInfo> DrawingBuffer::createNewMailbox(unsigned textureId) +PassRefPtr<DrawingBuffer::MailboxInfo> DrawingBuffer::createNewMailbox(const TextureInfo& info) { RefPtr<MailboxInfo> returnMailbox = adoptRef(new MailboxInfo()); - context()->genMailboxCHROMIUM(returnMailbox->mailbox.name); - returnMailbox->textureId = textureId; + m_context->genMailboxCHROMIUM(returnMailbox->mailbox.name); + returnMailbox->textureInfo = info; returnMailbox->size = m_size; m_textureMailboxes.append(returnMailbox); return returnMailbox.release(); } -void DrawingBuffer::initialize(const IntSize& size) +void DrawingBuffer::deleteMailbox(const blink::WebExternalTextureMailbox& mailbox) { - ASSERT(m_context); - m_attributes = m_context->getContextAttributes(); + for (size_t i = 0; i < m_textureMailboxes.size(); i++) { + if (nameEquals(m_textureMailboxes[i]->mailbox, mailbox)) { + if (mailbox.syncPoint) + m_context->waitSyncPoint(mailbox.syncPoint); + + deleteChromiumImageForTexture(&m_textureMailboxes[i]->textureInfo); + + m_context->deleteTexture(m_textureMailboxes[i]->textureInfo.textureId); + m_textureMailboxes.remove(i); + return; + } + } + ASSERT_NOT_REACHED(); +} - if (m_attributes.alpha) { +bool DrawingBuffer::initialize(const IntSize& size) +{ + if (!m_context->makeContextCurrent()) { + // Most likely the GPU process exited and the attempt to reconnect to it failed. + // Need to try to restore the context again later. + return false; + } + + if (m_context->isContextLost()) { + // Need to try to restore the context again later. + return false; + } + + if (m_requestedAttributes.alpha) { m_internalColorFormat = GL_RGBA; m_colorFormat = GL_RGBA; - m_internalRenderbufferFormat = Extensions3D::RGBA8_OES; + m_internalRenderbufferFormat = GL_RGBA8_OES; } else { m_internalColorFormat = GL_RGB; m_colorFormat = GL_RGB; - m_internalRenderbufferFormat = Extensions3D::RGB8_OES; + m_internalRenderbufferFormat = GL_RGB8_OES; } m_context->getIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize); + int maxSampleCount = 0; + m_multisampleMode = None; + if (m_requestedAttributes.antialias && m_multisampleExtensionSupported) { + m_context->getIntegerv(GL_MAX_SAMPLES_ANGLE, &maxSampleCount); + m_multisampleMode = ExplicitResolve; + if (m_extensionsUtil->supportsExtension("GL_EXT_multisampled_render_to_texture")) + m_multisampleMode = ImplicitResolve; + } + m_sampleCount = std::min(4, maxSampleCount); + m_fbo = m_context->createFramebuffer(); m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo); - m_colorBuffer = createColorTexture(); - m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer, 0); + m_colorBuffer.textureId = createColorTexture(); + if (m_multisampleMode == ImplicitResolve) + m_context->framebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0, m_sampleCount); + else + m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0); createSecondaryBuffers(); - reset(size); - m_lastColorBuffer = createNewMailbox(m_colorBuffer); -} - -unsigned DrawingBuffer::frontColorBuffer() const -{ - return m_frontColorBuffer; + // We first try to initialize everything with the requested attributes. + if (!reset(size)) + return false; + // If that succeeds, we then see what we actually got and update our actual attributes to reflect that. + m_actualAttributes = m_requestedAttributes; + if (m_requestedAttributes.alpha) { + blink::WGC3Dint alphaBits = 0; + m_context->getIntegerv(GL_ALPHA_BITS, &alphaBits); + m_actualAttributes.alpha = alphaBits > 0; + } + if (m_requestedAttributes.depth) { + blink::WGC3Dint depthBits = 0; + m_context->getIntegerv(GL_DEPTH_BITS, &depthBits); + m_actualAttributes.depth = depthBits > 0; + } + if (m_requestedAttributes.stencil) { + blink::WGC3Dint stencilBits = 0; + m_context->getIntegerv(GL_STENCIL_BITS, &stencilBits); + m_actualAttributes.stencil = stencilBits > 0; + } + m_actualAttributes.antialias = multisample(); + return true; } -bool DrawingBuffer::copyToPlatformTexture(GraphicsContext3D& context, Platform3DObject texture, GC3Denum internalFormat, GC3Denum destType, GC3Dint level, bool premultiplyAlpha, bool flipY) +bool DrawingBuffer::copyToPlatformTexture(blink::WebGraphicsContext3D* context, Platform3DObject texture, GLenum internalFormat, GLenum destType, GLint level, bool premultiplyAlpha, bool flipY, bool fromFrontBuffer) { - if (!m_context || !m_context->makeContextCurrent()) + if (!m_context->makeContextCurrent()) return false; + + GLint textureId = m_colorBuffer.textureId; + if (fromFrontBuffer) + textureId = m_frontColorBuffer.textureId; + if (m_contentsChanged) { - if (multisample()) { + if (m_multisampleMode != None) { commit(); if (!m_framebufferBinding) bind(); @@ -312,30 +448,43 @@ bool DrawingBuffer::copyToPlatformTexture(GraphicsContext3D& context, Platform3D } m_context->flush(); } - Platform3DObject sourceTexture = colorBuffer(); - if (!context.makeContextCurrent()) + if (!Extensions3DUtil::canUseCopyTextureCHROMIUM(internalFormat, destType, level)) return false; - Extensions3D* extensions = context.extensions(); - if (!extensions->supports("GL_CHROMIUM_copy_texture") || !extensions->supports("GL_CHROMIUM_flipy") - || !extensions->canUseCopyTextureCHROMIUM(internalFormat, destType, level)) + + // Contexts may be in a different share group. We must transfer the texture through a mailbox first + RefPtr<MailboxInfo> bufferMailbox = adoptRef(new MailboxInfo()); + m_context->genMailboxCHROMIUM(bufferMailbox->mailbox.name); + m_context->produceTextureDirectCHROMIUM(textureId, GL_TEXTURE_2D, bufferMailbox->mailbox.name); + m_context->flush(); + + bufferMailbox->mailbox.syncPoint = m_context->insertSyncPoint(); + + if (!context->makeContextCurrent()) return false; + context->waitSyncPoint(bufferMailbox->mailbox.syncPoint); + Platform3DObject sourceTexture = context->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, bufferMailbox->mailbox.name); + bool unpackPremultiplyAlphaNeeded = false; bool unpackUnpremultiplyAlphaNeeded = false; - if (m_attributes.alpha && m_attributes.premultipliedAlpha && !premultiplyAlpha) + if (m_actualAttributes.alpha && m_actualAttributes.premultipliedAlpha && !premultiplyAlpha) unpackUnpremultiplyAlphaNeeded = true; - else if (m_attributes.alpha && !m_attributes.premultipliedAlpha && premultiplyAlpha) + else if (m_actualAttributes.alpha && !m_actualAttributes.premultipliedAlpha && premultiplyAlpha) unpackPremultiplyAlphaNeeded = true; - context.pixelStorei(Extensions3D::UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, unpackUnpremultiplyAlphaNeeded); - context.pixelStorei(Extensions3D::UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, unpackPremultiplyAlphaNeeded); - context.pixelStorei(Extensions3D::UNPACK_FLIP_Y_CHROMIUM, flipY); - extensions->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, texture, level, internalFormat, destType); - context.pixelStorei(Extensions3D::UNPACK_FLIP_Y_CHROMIUM, false); - context.pixelStorei(Extensions3D::UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, false); - context.pixelStorei(Extensions3D::UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false); - context.flush(); + context->pixelStorei(GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, unpackUnpremultiplyAlphaNeeded); + context->pixelStorei(GC3D_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, unpackPremultiplyAlphaNeeded); + context->pixelStorei(GC3D_UNPACK_FLIP_Y_CHROMIUM, flipY); + context->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, texture, level, internalFormat, destType); + context->pixelStorei(GC3D_UNPACK_FLIP_Y_CHROMIUM, false); + context->pixelStorei(GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, false); + context->pixelStorei(GC3D_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false); + + context->deleteTexture(sourceTexture); + + context->flush(); + m_context->waitSyncPoint(context->insertSyncPoint()); return true; } @@ -347,15 +496,12 @@ Platform3DObject DrawingBuffer::framebuffer() const blink::WebLayer* DrawingBuffer::platformLayer() { - if (!m_context) - return 0; - if (!m_layer) { m_layer = adoptPtr(blink::Platform::current()->compositorSupport()->createExternalTextureLayer(this)); - m_layer->setOpaque(!m_attributes.alpha); - m_layer->setBlendBackgroundColor(m_attributes.alpha); - m_layer->setPremultipliedAlpha(m_attributes.premultipliedAlpha); + m_layer->setOpaque(!m_actualAttributes.alpha); + m_layer->setBlendBackgroundColor(m_actualAttributes.alpha); + m_layer->setPremultipliedAlpha(m_actualAttributes.premultipliedAlpha); GraphicsLayer::registerContentsLayer(m_layer->layer()); } @@ -364,17 +510,40 @@ blink::WebLayer* DrawingBuffer::platformLayer() void DrawingBuffer::paintCompositedResultsToCanvas(ImageBuffer* imageBuffer) { - if (!m_context || !m_context->makeContextCurrent() || m_context->extensions()->getGraphicsResetStatusARB() != GL_NO_ERROR) + if (!m_context->makeContextCurrent() || m_context->getGraphicsResetStatusARB() != GL_NO_ERROR) return; - Extensions3D* extensions = m_context->extensions(); - if (!imageBuffer) return; Platform3DObject tex = imageBuffer->getBackingTexture(); if (tex) { - extensions->copyTextureCHROMIUM(GL_TEXTURE_2D, m_frontColorBuffer, + RefPtr<MailboxInfo> bufferMailbox = adoptRef(new MailboxInfo()); + m_context->genMailboxCHROMIUM(bufferMailbox->mailbox.name); + m_context->bindTexture(GL_TEXTURE_2D, m_frontColorBuffer.textureId); + m_context->produceTextureCHROMIUM(GL_TEXTURE_2D, bufferMailbox->mailbox.name); + m_context->flush(); + + bufferMailbox->mailbox.syncPoint = m_context->insertSyncPoint(); + OwnPtr<blink::WebGraphicsContext3DProvider> provider = + adoptPtr(blink::Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); + if (!provider) + return; + blink::WebGraphicsContext3D* context = provider->context3d(); + if (!context || !context->makeContextCurrent()) + return; + + Platform3DObject sourceTexture = context->createTexture(); + GLint boundTexture = 0; + context->getIntegerv(GL_TEXTURE_BINDING_2D, &boundTexture); + context->bindTexture(GL_TEXTURE_2D, sourceTexture); + context->waitSyncPoint(bufferMailbox->mailbox.syncPoint); + context->consumeTextureCHROMIUM(GL_TEXTURE_2D, bufferMailbox->mailbox.name); + context->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, tex, 0, GL_RGBA, GL_UNSIGNED_BYTE); + context->bindTexture(GL_TEXTURE_2D, boundTexture); + context->deleteTexture(sourceTexture); + context->flush(); + m_context->waitSyncPoint(context->insertSyncPoint()); return; } @@ -382,20 +551,21 @@ void DrawingBuffer::paintCompositedResultsToCanvas(ImageBuffer* imageBuffer) // We have to make a copy of it here and bind that copy instead. // FIXME: That's not true any more, provided we don't change texture // parameters. - unsigned sourceTexture = createColorTexture(m_size); - extensions->copyTextureCHROMIUM(GL_TEXTURE_2D, m_frontColorBuffer, sourceTexture, 0, GL_RGBA, GL_UNSIGNED_BYTE); + unsigned sourceTexture = createColorTexture(); + texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, m_size.width(), m_size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE); + m_context->copyTextureCHROMIUM(GL_TEXTURE_2D, m_frontColorBuffer.textureId, sourceTexture, 0, GL_RGBA, GL_UNSIGNED_BYTE); // Since we're using the same context as WebGL, we have to restore any state we change (in this case, just the framebuffer binding). // FIXME: The WebGLRenderingContext tracks the current framebuffer binding, it would be slightly more efficient to use this value // rather than querying it off of the context. - GC3Dint previousFramebuffer = 0; + GLint previousFramebuffer = 0; m_context->getIntegerv(GL_FRAMEBUFFER_BINDING, &previousFramebuffer); Platform3DObject framebuffer = m_context->createFramebuffer(); m_context->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sourceTexture, 0); - extensions->paintFramebufferToCanvas(framebuffer, size().width(), size().height(), !m_attributes.premultipliedAlpha, imageBuffer); + paintFramebufferToCanvas(framebuffer, size().width(), size().height(), !m_actualAttributes.premultipliedAlpha, imageBuffer); m_context->deleteFramebuffer(framebuffer); m_context->deleteTexture(sourceTexture); @@ -407,45 +577,48 @@ void DrawingBuffer::clearPlatformLayer() if (m_layer) m_layer->clearTexture(); - if (m_context) - m_context->flush(); + m_context->flush(); } -void DrawingBuffer::releaseResources() +void DrawingBuffer::beginDestruction() { - if (m_context) { - m_context->makeContextCurrent(); + ASSERT(!m_destructionInProgress); + m_destructionInProgress = true; - clearPlatformLayer(); + m_context->makeContextCurrent(); - for (size_t i = 0; i < m_textureMailboxes.size(); i++) - m_context->deleteTexture(m_textureMailboxes[i]->textureId); + clearPlatformLayer(); - if (m_multisampleColorBuffer) - m_context->deleteRenderbuffer(m_multisampleColorBuffer); + while (!m_recycledMailboxQueue.isEmpty()) + deleteMailbox(m_recycledMailboxQueue.takeLast()); - if (m_depthStencilBuffer) - m_context->deleteRenderbuffer(m_depthStencilBuffer); + if (m_multisampleFBO) + m_context->deleteFramebuffer(m_multisampleFBO); - if (m_depthBuffer) - m_context->deleteRenderbuffer(m_depthBuffer); + if (m_fbo) + m_context->deleteFramebuffer(m_fbo); - if (m_stencilBuffer) - m_context->deleteRenderbuffer(m_stencilBuffer); + if (m_multisampleColorBuffer) + m_context->deleteRenderbuffer(m_multisampleColorBuffer); - if (m_multisampleFBO) - m_context->deleteFramebuffer(m_multisampleFBO); + if (m_depthStencilBuffer) + m_context->deleteRenderbuffer(m_depthStencilBuffer); - if (m_fbo) - m_context->deleteFramebuffer(m_fbo); + if (m_depthBuffer) + m_context->deleteRenderbuffer(m_depthBuffer); - m_context.clear(); + if (m_stencilBuffer) + m_context->deleteRenderbuffer(m_stencilBuffer); + + if (m_colorBuffer.textureId) { + deleteChromiumImageForTexture(&m_colorBuffer); + m_context->deleteTexture(m_colorBuffer.textureId); } setSize(IntSize()); - m_colorBuffer = 0; - m_frontColorBuffer = 0; + m_colorBuffer = TextureInfo(); + m_frontColorBuffer = TextureInfo(); m_multisampleColorBuffer = 0; m_depthStencilBuffer = 0; m_depthBuffer = 0; @@ -454,21 +627,12 @@ void DrawingBuffer::releaseResources() m_fbo = 0; m_contextEvictionManager.clear(); - m_lastColorBuffer.clear(); - m_recycledMailboxes.clear(); - m_textureMailboxes.clear(); - - if (m_layer) { + if (m_layer) GraphicsLayer::unregisterContentsLayer(m_layer->layer()); - m_layer.clear(); - } } -unsigned DrawingBuffer::createColorTexture(const IntSize& size) +unsigned DrawingBuffer::createColorTexture() { - if (!m_context) - return 0; - unsigned offscreenColorTexture = m_context->createTexture(); if (!offscreenColorTexture) return 0; @@ -478,8 +642,6 @@ unsigned DrawingBuffer::createColorTexture(const IntSize& size) m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (!size.isEmpty()) - m_context->texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, size.width(), size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE); return offscreenColorTexture; } @@ -487,7 +649,7 @@ unsigned DrawingBuffer::createColorTexture(const IntSize& size) void DrawingBuffer::createSecondaryBuffers() { // create a multisample FBO - if (multisample()) { + if (m_multisampleMode == ExplicitResolve) { m_multisampleFBO = m_context->createFramebuffer(); m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO); m_multisampleColorBuffer = m_context->createRenderbuffer(); @@ -499,17 +661,19 @@ bool DrawingBuffer::resizeFramebuffer(const IntSize& size) // resize regular FBO m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo); - m_context->bindTexture(GL_TEXTURE_2D, m_colorBuffer); - m_context->texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, size.width(), size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE); - if (m_lastColorBuffer) - m_lastColorBuffer->size = size; + m_context->bindTexture(GL_TEXTURE_2D, m_colorBuffer.textureId); + + allocateTextureMemory(&m_colorBuffer, size); - m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer, 0); + if (m_multisampleMode == ImplicitResolve) + m_context->framebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0, m_sampleCount); + else + m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0); m_context->bindTexture(GL_TEXTURE_2D, 0); - if (!multisample()) - resizeDepthStencil(size, 0); + if (m_multisampleMode != ExplicitResolve) + resizeDepthStencil(size); if (m_context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) return false; @@ -518,22 +682,17 @@ bool DrawingBuffer::resizeFramebuffer(const IntSize& size) bool DrawingBuffer::resizeMultisampleFramebuffer(const IntSize& size) { - if (multisample()) { - int maxSampleCount = 0; - - m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSampleCount); - int sampleCount = std::min(4, maxSampleCount); - + if (m_multisampleMode == ExplicitResolve) { m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO); m_context->bindRenderbuffer(GL_RENDERBUFFER, m_multisampleColorBuffer); - m_context->extensions()->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, m_internalRenderbufferFormat, size.width(), size.height()); + m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, m_internalRenderbufferFormat, size.width(), size.height()); if (m_context->getError() == GL_OUT_OF_MEMORY) return false; m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_multisampleColorBuffer); - resizeDepthStencil(size, sampleCount); + resizeDepthStencil(size); if (m_context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) return false; } @@ -541,35 +700,44 @@ bool DrawingBuffer::resizeMultisampleFramebuffer(const IntSize& size) return true; } -void DrawingBuffer::resizeDepthStencil(const IntSize& size, int sampleCount) +void DrawingBuffer::resizeDepthStencil(const IntSize& size) { - if (m_attributes.depth && m_attributes.stencil && m_packedDepthStencilExtensionSupported) { + if (!m_requestedAttributes.depth && !m_requestedAttributes.stencil) + return; + + if (m_packedDepthStencilExtensionSupported) { if (!m_depthStencilBuffer) m_depthStencilBuffer = m_context->createRenderbuffer(); m_context->bindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer); - if (multisample()) - m_context->extensions()->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, Extensions3D::DEPTH24_STENCIL8, size.width(), size.height()); + if (m_multisampleMode == ImplicitResolve) + m_context->renderbufferStorageMultisampleEXT(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH24_STENCIL8_OES, size.width(), size.height()); + else if (m_multisampleMode == ExplicitResolve) + m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH24_STENCIL8_OES, size.width(), size.height()); else - m_context->renderbufferStorage(GL_RENDERBUFFER, Extensions3D::DEPTH24_STENCIL8, size.width(), size.height()); + m_context->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, size.width(), size.height()); m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer); m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer); } else { - if (m_attributes.depth) { + if (m_requestedAttributes.depth) { if (!m_depthBuffer) m_depthBuffer = m_context->createRenderbuffer(); m_context->bindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer); - if (multisample()) - m_context->extensions()->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_DEPTH_COMPONENT16, size.width(), size.height()); + if (m_multisampleMode == ImplicitResolve) + m_context->renderbufferStorageMultisampleEXT(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH_COMPONENT16, size.width(), size.height()); + else if (m_multisampleMode == ExplicitResolve) + m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH_COMPONENT16, size.width(), size.height()); else m_context->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.width(), size.height()); m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer); } - if (m_attributes.stencil) { + if (m_requestedAttributes.stencil) { if (!m_stencilBuffer) m_stencilBuffer = m_context->createRenderbuffer(); m_context->bindRenderbuffer(GL_RENDERBUFFER, m_stencilBuffer); - if (multisample()) - m_context->extensions()->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_STENCIL_INDEX8, size.width(), size.height()); + if (m_multisampleMode == ImplicitResolve) + m_context->renderbufferStorageMultisampleEXT(GL_RENDERBUFFER, m_sampleCount, GL_STENCIL_INDEX8, size.width(), size.height()); + else if (m_multisampleMode == ExplicitResolve) + m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, GL_STENCIL_INDEX8, size.width(), size.height()); else m_context->renderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, size.width(), size.height()); m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilBuffer); @@ -580,48 +748,46 @@ void DrawingBuffer::resizeDepthStencil(const IntSize& size, int sampleCount) -void DrawingBuffer::clearFramebuffers(GC3Dbitfield clearMask) +void DrawingBuffer::clearFramebuffers(GLbitfield clearMask) { - if (!m_context) - return; - - m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo); - - m_context->clear(clearMask); - - // The multisample fbo was just cleared, but we also need to clear the non-multisampled buffer too. + // We will clear the multisample FBO, but we also need to clear the non-multisampled buffer. if (m_multisampleFBO) { m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo); m_context->clear(GL_COLOR_BUFFER_BIT); - m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO); } + + m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo); + m_context->clear(clearMask); } -void DrawingBuffer::setSize(const IntSize& size) { +void DrawingBuffer::setSize(const IntSize& size) +{ if (m_size == size) return; - s_currentResourceUsePixels += pixelDelta(size); + s_currentResourceUsePixels += pixelDelta(size, m_size); m_size = size; } -int DrawingBuffer::pixelDelta(const IntSize& size) { - return (max(0, size.width()) * max(0, size.height())) - (max(0, m_size.width()) * max(0, m_size.height())); +int DrawingBuffer::pixelDelta(const IntSize& newSize, const IntSize& curSize) +{ + return (max(0, newSize.width()) * max(0, newSize.height())) - (max(0, curSize.width()) * max(0, curSize.height())); } -IntSize DrawingBuffer::adjustSize(const IntSize& size) { - IntSize adjustedSize = size; +IntSize DrawingBuffer::adjustSize(const IntSize& desiredSize, const IntSize& curSize, int maxTextureSize) +{ + IntSize adjustedSize = desiredSize; // Clamp if the desired size is greater than the maximum texture size for the device. - if (adjustedSize.height() > m_maxTextureSize) - adjustedSize.setHeight(m_maxTextureSize); + if (adjustedSize.height() > maxTextureSize) + adjustedSize.setHeight(maxTextureSize); - if (adjustedSize.width() > m_maxTextureSize) - adjustedSize.setWidth(m_maxTextureSize); + if (adjustedSize.width() > maxTextureSize) + adjustedSize.setWidth(maxTextureSize); // Try progressively smaller sizes until we find a size that fits or reach a scale limit. int scaleAttempts = 0; - while ((s_currentResourceUsePixels + pixelDelta(adjustedSize)) > s_maximumResourceUsePixels) { + while ((s_currentResourceUsePixels + pixelDelta(adjustedSize, curSize)) > s_maximumResourceUsePixels) { scaleAttempts++; if (scaleAttempts > s_maxScaleAttempts) return IntSize(); @@ -635,8 +801,9 @@ IntSize DrawingBuffer::adjustSize(const IntSize& size) { return adjustedSize; } -IntSize DrawingBuffer::adjustSizeWithContextEviction(const IntSize& size, bool& evictContext) { - IntSize adjustedSize = adjustSize(size); +IntSize DrawingBuffer::adjustSizeWithContextEviction(const IntSize& size, bool& evictContext) +{ + IntSize adjustedSize = adjustSize(size, m_size, m_maxTextureSize); if (!adjustedSize.isEmpty()) { evictContext = false; return adjustedSize; // Buffer fits without evicting a context. @@ -647,28 +814,26 @@ IntSize DrawingBuffer::adjustSizeWithContextEviction(const IntSize& size, bool& int pixelDelta = oldestSize.width() * oldestSize.height(); s_currentResourceUsePixels -= pixelDelta; - adjustedSize = adjustSize(size); + adjustedSize = adjustSize(size, m_size, m_maxTextureSize); s_currentResourceUsePixels += pixelDelta; evictContext = !adjustedSize.isEmpty(); return adjustedSize; } -void DrawingBuffer::reset(const IntSize& newSize) +bool DrawingBuffer::reset(const IntSize& newSize) { - if (!m_context) - return; - + ASSERT(!newSize.isEmpty()); IntSize adjustedSize; bool evictContext = false; bool isNewContext = m_size.isEmpty(); if (s_allowContextEvictionOnCreate && isNewContext) adjustedSize = adjustSizeWithContextEviction(newSize, evictContext); else - adjustedSize = adjustSize(newSize); + adjustedSize = adjustSize(newSize, m_size, m_maxTextureSize); if (adjustedSize.isEmpty()) - return; + return false; if (evictContext) m_contextEvictionManager->forciblyLoseOldestContext("WARNING: WebGL contexts have exceeded the maximum allowed backbuffer area. Oldest context will be lost."); @@ -686,33 +851,31 @@ void DrawingBuffer::reset(const IntSize& newSize) setSize(adjustedSize); if (adjustedSize.isEmpty()) - return; + return false; } m_context->disable(GL_SCISSOR_TEST); m_context->clearColor(0, 0, 0, 0); m_context->colorMask(true, true, true, true); - GC3Dbitfield clearMask = GL_COLOR_BUFFER_BIT; - if (m_attributes.depth) { + GLbitfield clearMask = GL_COLOR_BUFFER_BIT; + if (m_actualAttributes.depth) { m_context->clearDepth(1.0f); clearMask |= GL_DEPTH_BUFFER_BIT; m_context->depthMask(true); } - if (m_attributes.stencil) { + if (m_actualAttributes.stencil) { m_context->clearStencil(0); clearMask |= GL_STENCIL_BUFFER_BIT; m_context->stencilMaskSeparate(GL_FRONT, 0xFFFFFFFF); } clearFramebuffers(clearMask); + return true; } void DrawingBuffer::commit(long x, long y, long width, long height) { - if (!m_context) - return; - if (width < 0) width = m_size.width(); if (height < 0) @@ -721,14 +884,14 @@ void DrawingBuffer::commit(long x, long y, long width, long height) m_context->makeContextCurrent(); if (m_multisampleFBO && !m_contentsChangeCommitted) { - m_context->bindFramebuffer(Extensions3D::READ_FRAMEBUFFER, m_multisampleFBO); - m_context->bindFramebuffer(Extensions3D::DRAW_FRAMEBUFFER, m_fbo); + m_context->bindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, m_multisampleFBO); + m_context->bindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, m_fbo); if (m_scissorEnabled) m_context->disable(GL_SCISSOR_TEST); // Use NEAREST, because there is no scale performed during the blit. - m_context->extensions()->blitFramebuffer(x, y, width, height, x, y, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + m_context->blitFramebufferCHROMIUM(x, y, width, height, x, y, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); if (m_scissorEnabled) m_context->enable(GL_SCISSOR_TEST); @@ -740,7 +903,7 @@ void DrawingBuffer::commit(long x, long y, long width, long height) void DrawingBuffer::restoreFramebufferBinding() { - if (!m_context || !m_framebufferBinding) + if (!m_framebufferBinding) return; m_context->bindFramebuffer(GL_FRAMEBUFFER, m_framebufferBinding); @@ -748,15 +911,162 @@ void DrawingBuffer::restoreFramebufferBinding() bool DrawingBuffer::multisample() const { - return m_attributes.antialias && m_multisampleExtensionSupported; + return m_multisampleMode != None; } void DrawingBuffer::bind() { - if (!m_context) - return; - m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo); } +void DrawingBuffer::setPackAlignment(GLint param) +{ + m_packAlignment = param; +} + +void DrawingBuffer::paintRenderingResultsToCanvas(ImageBuffer* imageBuffer) +{ + paintFramebufferToCanvas(framebuffer(), size().width(), size().height(), !m_actualAttributes.premultipliedAlpha, imageBuffer); +} + +PassRefPtr<Uint8ClampedArray> DrawingBuffer::paintRenderingResultsToImageData(int& width, int& height) +{ + if (m_actualAttributes.premultipliedAlpha) + return nullptr; + + width = size().width(); + height = size().height(); + + Checked<int, RecordOverflow> dataSize = 4; + dataSize *= width; + dataSize *= height; + if (dataSize.hasOverflowed()) + return nullptr; + + RefPtr<Uint8ClampedArray> pixels = Uint8ClampedArray::createUninitialized(width * height * 4); + + m_context->bindFramebuffer(GL_FRAMEBUFFER, framebuffer()); + readBackFramebuffer(pixels->data(), width, height, ReadbackRGBA, WebGLImageConversion::AlphaDoNothing); + flipVertically(pixels->data(), width, height); + + return pixels.release(); +} + +void DrawingBuffer::paintFramebufferToCanvas(int framebuffer, int width, int height, bool premultiplyAlpha, ImageBuffer* imageBuffer) +{ + unsigned char* pixels = 0; + + const SkBitmap& canvasBitmap = imageBuffer->bitmap(); + const SkBitmap* readbackBitmap = 0; + ASSERT(canvasBitmap.colorType() == kPMColor_SkColorType); + if (canvasBitmap.width() == width && canvasBitmap.height() == height) { + // This is the fastest and most common case. We read back + // directly into the canvas's backing store. + readbackBitmap = &canvasBitmap; + m_resizingBitmap.reset(); + } else { + // We need to allocate a temporary bitmap for reading back the + // pixel data. We will then use Skia to rescale this bitmap to + // the size of the canvas's backing store. + if (m_resizingBitmap.width() != width || m_resizingBitmap.height() != height) { + if (!m_resizingBitmap.allocN32Pixels(width, height)) + return; + } + readbackBitmap = &m_resizingBitmap; + } + + // Read back the frame buffer. + SkAutoLockPixels bitmapLock(*readbackBitmap); + pixels = static_cast<unsigned char*>(readbackBitmap->getPixels()); + + m_context->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); + readBackFramebuffer(pixels, width, height, ReadbackSkia, premultiplyAlpha ? WebGLImageConversion::AlphaDoPremultiply : WebGLImageConversion::AlphaDoNothing); + flipVertically(pixels, width, height); + + readbackBitmap->notifyPixelsChanged(); + if (m_resizingBitmap.readyToDraw()) { + // We need to draw the resizing bitmap into the canvas's backing store. + SkCanvas canvas(canvasBitmap); + SkRect dst; + dst.set(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(canvasBitmap.width()), SkIntToScalar(canvasBitmap.height())); + canvas.drawBitmapRect(m_resizingBitmap, 0, dst); + } +} + +void DrawingBuffer::readBackFramebuffer(unsigned char* pixels, int width, int height, ReadbackOrder readbackOrder, WebGLImageConversion::AlphaOp op) +{ + if (m_packAlignment > 4) + m_context->pixelStorei(GL_PACK_ALIGNMENT, 1); + m_context->readPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + if (m_packAlignment > 4) + m_context->pixelStorei(GL_PACK_ALIGNMENT, m_packAlignment); + + size_t bufferSize = 4 * width * height; + + if (readbackOrder == ReadbackSkia) { +#if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT + // Swizzle red and blue channels to match SkBitmap's byte ordering. + // TODO(kbr): expose GL_BGRA as extension. + for (size_t i = 0; i < bufferSize; i += 4) { + std::swap(pixels[i], pixels[i + 2]); + } +#endif + } + + if (op == WebGLImageConversion::AlphaDoPremultiply) { + for (size_t i = 0; i < bufferSize; i += 4) { + pixels[i + 0] = std::min(255, pixels[i + 0] * pixels[i + 3] / 255); + pixels[i + 1] = std::min(255, pixels[i + 1] * pixels[i + 3] / 255); + pixels[i + 2] = std::min(255, pixels[i + 2] * pixels[i + 3] / 255); + } + } else if (op != WebGLImageConversion::AlphaDoNothing) { + ASSERT_NOT_REACHED(); + } +} + +void DrawingBuffer::flipVertically(uint8_t* framebuffer, int width, int height) +{ + m_scanline.resize(width * 4); + uint8* scanline = &m_scanline[0]; + unsigned rowBytes = width * 4; + unsigned count = height / 2; + for (unsigned i = 0; i < count; i++) { + uint8* rowA = framebuffer + i * rowBytes; + uint8* rowB = framebuffer + (height - i - 1) * rowBytes; + memcpy(scanline, rowB, rowBytes); + memcpy(rowB, rowA, rowBytes); + memcpy(rowA, scanline, rowBytes); + } +} + +void DrawingBuffer::texImage2DResourceSafe(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLint unpackAlignment) +{ + ASSERT(unpackAlignment == 1 || unpackAlignment == 2 || unpackAlignment == 4 || unpackAlignment == 8); + m_context->texImage2D(target, level, internalformat, width, height, border, format, type, 0); +} + +void DrawingBuffer::allocateTextureMemory(TextureInfo* info, const IntSize& size) +{ + if (RuntimeEnabledFeatures::webGLImageChromiumEnabled()) { + deleteChromiumImageForTexture(info); + + info->imageId = m_context->createImageCHROMIUM(size.width(), size.height(), GL_RGBA8_OES, GC3D_IMAGE_SCANOUT_CHROMIUM); + if (info->imageId) { + m_context->bindTexImage2DCHROMIUM(GL_TEXTURE_2D, info->imageId); + return; + } + } + + texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, size.width(), size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE); +} + +void DrawingBuffer::deleteChromiumImageForTexture(TextureInfo* info) +{ + if (info->imageId) { + m_context->releaseTexImage2DCHROMIUM(GL_TEXTURE_2D, info->imageId); + m_context->destroyImageCHROMIUM(info->imageId); + info->imageId = 0; + } +} + } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h b/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h index f1d7afc47de..4c457b7c7b7 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h @@ -33,11 +33,15 @@ #include "platform/PlatformExport.h" #include "platform/geometry/IntSize.h" -#include "platform/graphics/GraphicsContext3D.h" #include "platform/graphics/GraphicsTypes3D.h" - +#include "platform/graphics/gpu/WebGLImageConversion.h" #include "public/platform/WebExternalTextureLayerClient.h" #include "public/platform/WebExternalTextureMailbox.h" +#include "public/platform/WebGraphicsContext3D.h" +#include "third_party/khronos/GLES2/gl2.h" +#include "third_party/khronos/GLES2/gl2ext.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "wtf/Deque.h" #include "wtf/Noncopyable.h" #include "wtf/OwnPtr.h" #include "wtf/PassOwnPtr.h" @@ -50,8 +54,9 @@ class WebLayer; } namespace WebCore { -class GraphicsContext3D; +class Extensions3DUtil; class ImageData; +class ImageBuffer; // Abstract interface to allow basic context eviction management class PLATFORM_EXPORT ContextEvictionManager : public RefCounted<ContextEvictionManager> { @@ -65,10 +70,27 @@ public: // Manages a rendering target (framebuffer + attachment) for a canvas. Can publish its rendering // results to a blink::WebLayer for compositing. class PLATFORM_EXPORT DrawingBuffer : public RefCounted<DrawingBuffer>, public blink::WebExternalTextureLayerClient { + // If we used CHROMIUM_image as the backing storage for our buffers, + // we need to know the mapping from texture id to image. + struct TextureInfo { + Platform3DObject textureId; + blink::WGC3Duint imageId; + + TextureInfo() + : textureId(0) + , imageId(0) + { + } + }; + struct MailboxInfo : public RefCounted<MailboxInfo> { blink::WebExternalTextureMailbox mailbox; - unsigned textureId; + TextureInfo textureInfo; IntSize size; + // This keeps the parent drawing buffer alive as long as the compositor is + // referring to one of the mailboxes DrawingBuffer produced. The parent drawing buffer is + // cleared when the compositor returns the mailbox. See mailboxReleased(). + RefPtr<DrawingBuffer> m_parentDrawingBuffer; }; public: enum PreserveDrawingBuffer { @@ -76,24 +98,22 @@ public: Discard }; - static PassRefPtr<DrawingBuffer> create(GraphicsContext3D*, const IntSize&, PreserveDrawingBuffer, PassRefPtr<ContextEvictionManager>); + static PassRefPtr<DrawingBuffer> create(PassOwnPtr<blink::WebGraphicsContext3D>, const IntSize&, PreserveDrawingBuffer, blink::WebGraphicsContext3D::Attributes requestedAttributes, PassRefPtr<ContextEvictionManager>); - ~DrawingBuffer(); + virtual ~DrawingBuffer(); - // Clear all resources from this object, as well as context. Called when context is destroyed - // to prevent invalid accesses to the resources. - void releaseResources(); + // Destruction will be completed after all mailboxes are released. + void beginDestruction(); // Issues a glClear() on all framebuffers associated with this DrawingBuffer. The caller is responsible for // making the context current and setting the clear values and masks. Modifies the framebuffer binding. - void clearFramebuffers(GC3Dbitfield clearMask); + void clearFramebuffers(GLbitfield clearMask); // Given the desired buffer size, provides the largest dimensions that will fit in the pixel budget. - IntSize adjustSize(const IntSize&); - void reset(const IntSize&); + static IntSize adjustSize(const IntSize& desiredSize, const IntSize& curSize, int maxTextureSize); + bool reset(const IntSize&); void bind(); IntSize size() const { return m_size; } - bool isZeroSized() const { return m_size.isEmpty(); } // Copies the multisample color buffer to the normal color buffer and leaves m_fbo bound. void commit(long x = 0, long y = 0, long width = -1, long height = -1); @@ -113,40 +133,59 @@ public: // Track the currently active texture unit. Texture unit 0 is used as host for a scratch // texture. - void setActiveTextureUnit(GC3Dint textureUnit) { m_activeTextureUnit = textureUnit; } + void setActiveTextureUnit(GLint textureUnit) { m_activeTextureUnit = textureUnit; } bool multisample() const; Platform3DObject framebuffer() const; void markContentsChanged(); + void markLayerComposited(); + bool layerComposited() const; blink::WebLayer* platformLayer(); void paintCompositedResultsToCanvas(ImageBuffer*); + blink::WebGraphicsContext3D* context(); + + // Returns the actual context attributes for this drawing buffer which may differ from the + // requested context attributes due to implementation limits. + blink::WebGraphicsContext3D::Attributes getActualAttributes() const { return m_actualAttributes; } + // WebExternalTextureLayerClient implementation. - virtual blink::WebGraphicsContext3D* context() OVERRIDE; virtual bool prepareMailbox(blink::WebExternalTextureMailbox*, blink::WebExternalBitmap*) OVERRIDE; virtual void mailboxReleased(const blink::WebExternalTextureMailbox&) OVERRIDE; - bool copyToPlatformTexture(GraphicsContext3D&, Platform3DObject texture, GC3Denum internalFormat, - GC3Denum destType, GC3Dint level, bool premultiplyAlpha, bool flipY); + // Destroys the TEXTURE_2D binding for the owned context + bool copyToPlatformTexture(blink::WebGraphicsContext3D*, Platform3DObject texture, GLenum internalFormat, + GLenum destType, GLint level, bool premultiplyAlpha, bool flipY, bool fromFrontBuffer = false); -private: - DrawingBuffer(GraphicsContext3D*, const IntSize&, bool multisampleExtensionSupported, - bool packedDepthStencilExtensionSupported, PreserveDrawingBuffer, PassRefPtr<ContextEvictionManager>); + void setPackAlignment(GLint param); + + void paintRenderingResultsToCanvas(ImageBuffer*); + PassRefPtr<Uint8ClampedArray> paintRenderingResultsToImageData(int&, int&); - void initialize(const IntSize&); +protected: // For unittests + DrawingBuffer( + PassOwnPtr<blink::WebGraphicsContext3D>, + PassOwnPtr<Extensions3DUtil>, + bool multisampleExtensionSupported, + bool packedDepthStencilExtensionSupported, + PreserveDrawingBuffer, + blink::WebGraphicsContext3D::Attributes requestedAttributes, + PassRefPtr<ContextEvictionManager>); - Platform3DObject frontColorBuffer() const; - Platform3DObject colorBuffer() const { return m_colorBuffer; } + bool initialize(const IntSize&); - unsigned createColorTexture(const IntSize& size = IntSize()); +private: + void mailboxReleasedWhileDestructionInProgress(const blink::WebExternalTextureMailbox&); + + unsigned createColorTexture(); // Create the depth/stencil and multisample buffers, if needed. void createSecondaryBuffers(); bool resizeFramebuffer(const IntSize&); bool resizeMultisampleFramebuffer(const IntSize&); - void resizeDepthStencil(const IntSize&, int sampleCount); + void resizeDepthStencil(const IntSize&); // Bind to the m_framebufferBinding if it's not 0. void restoreFramebufferBinding(); @@ -154,31 +193,57 @@ private: void clearPlatformLayer(); PassRefPtr<MailboxInfo> recycledMailbox(); - PassRefPtr<MailboxInfo> createNewMailbox(unsigned); + PassRefPtr<MailboxInfo> createNewMailbox(const TextureInfo&); + void deleteMailbox(const blink::WebExternalTextureMailbox&); // Updates the current size of the buffer, ensuring that s_currentResourceUsePixels is updated. void setSize(const IntSize& size); // Calculates the difference in pixels between the current buffer size and the proposed size. - int pixelDelta(const IntSize& size); + static int pixelDelta(const IntSize& newSize, const IntSize& curSize); // Given the desired buffer size, provides the largest dimensions that will fit in the pixel budget // Returns true if the buffer will only fit if the oldest WebGL context is forcibly lost IntSize adjustSizeWithContextEviction(const IntSize&, bool& evictContext); + void paintFramebufferToCanvas(int framebuffer, int width, int height, bool premultiplyAlpha, ImageBuffer*); + + // This is the order of bytes to use when doing a readback. + enum ReadbackOrder { + ReadbackRGBA, + ReadbackSkia + }; + + // Helper function which does a readback from the currently-bound + // framebuffer into a buffer of a certain size with 4-byte pixels. + void readBackFramebuffer(unsigned char* pixels, int width, int height, ReadbackOrder, WebGLImageConversion::AlphaOp); + + // Helper function to flip a bitmap vertically. + void flipVertically(uint8_t* data, int width, int height); + + // Helper to texImage2D with pixel==0 case: pixels are initialized to 0. + // By default, alignment is 4, the OpenGL default setting. + void texImage2DResourceSafe(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLint alignment = 4); + // Allocate buffer storage to be sent to compositor using either texImage2D or CHROMIUM_image based on available support. + void allocateTextureMemory(TextureInfo*, const IntSize&); + void deleteChromiumImageForTexture(TextureInfo*); + PreserveDrawingBuffer m_preserveDrawingBuffer; bool m_scissorEnabled; Platform3DObject m_texture2DBinding; Platform3DObject m_framebufferBinding; - GC3Denum m_activeTextureUnit; + GLenum m_activeTextureUnit; - RefPtr<GraphicsContext3D> m_context; + OwnPtr<blink::WebGraphicsContext3D> m_context; + OwnPtr<Extensions3DUtil> m_extensionsUtil; IntSize m_size; + blink::WebGraphicsContext3D::Attributes m_requestedAttributes; bool m_multisampleExtensionSupported; bool m_packedDepthStencilExtensionSupported; Platform3DObject m_fbo; - Platform3DObject m_colorBuffer; - Platform3DObject m_frontColorBuffer; + // DrawingBuffer's output is double-buffered. m_colorBuffer is the back buffer. + TextureInfo m_colorBuffer; + TextureInfo m_frontColorBuffer; // This is used when we have OES_packed_depth_stencil. Platform3DObject m_depthStencilBuffer; @@ -196,22 +261,43 @@ private: // True if commit() has been called since the last time markContentsChanged() had been called. bool m_contentsChangeCommitted; + bool m_layerComposited; - GraphicsContext3D::Attributes m_attributes; + enum MultisampleMode { + None, + ImplicitResolve, + ExplicitResolve, + }; + + MultisampleMode m_multisampleMode; + + blink::WebGraphicsContext3D::Attributes m_actualAttributes; unsigned m_internalColorFormat; unsigned m_colorFormat; unsigned m_internalRenderbufferFormat; int m_maxTextureSize; + int m_sampleCount; + int m_packAlignment; + bool m_destructionInProgress; OwnPtr<blink::WebExternalTextureLayer> m_layer; // All of the mailboxes that this DrawingBuffer has ever created. Vector<RefPtr<MailboxInfo> > m_textureMailboxes; - // Mailboxes that were released by the compositor and can be used again by this DrawingBuffer. - Vector<RefPtr<MailboxInfo> > m_recycledMailboxes; - RefPtr<MailboxInfo> m_lastColorBuffer; + // Mailboxes that were released by the compositor can be used again by this DrawingBuffer. + Deque<blink::WebExternalTextureMailbox> m_recycledMailboxQueue; RefPtr<ContextEvictionManager> m_contextEvictionManager; + + // If the width and height of the Canvas's backing store don't + // match those that we were given in the most recent call to + // reshape(), then we need an intermediate bitmap to read back the + // frame buffer into. This seems to happen when CSS styles are + // used to resize the Canvas. + SkBitmap m_resizingBitmap; + + // Used to flip a bitmap vertically. + Vector<uint8_t> m_scanline; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp b/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp new file mode 100644 index 00000000000..767fcfdbff1 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp @@ -0,0 +1,623 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "platform/graphics/gpu/DrawingBuffer.h" + +#include "platform/RuntimeEnabledFeatures.h" +#include "platform/graphics/ImageBuffer.h" +#include "platform/graphics/UnacceleratedImageBufferSurface.h" +#include "platform/graphics/gpu/Extensions3DUtil.h" +#include "platform/graphics/test/MockWebGraphicsContext3D.h" +#include "public/platform/Platform.h" +#include "public/platform/WebExternalTextureMailbox.h" +#include "wtf/RefPtr.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +using namespace WebCore; +using namespace blink; +using testing::Test; +using testing::_; + +namespace { + +class FakeContextEvictionManager : public ContextEvictionManager { +public: + void forciblyLoseOldestContext(const String& reason) { } + IntSize oldestContextSize() { return IntSize(); } +}; + +class WebGraphicsContext3DForTests : public MockWebGraphicsContext3D { +public: + WebGraphicsContext3DForTests() + : MockWebGraphicsContext3D() + , m_boundTexture(0) + , m_currentMailboxByte(0) + , m_mostRecentlyWaitedSyncPoint(0) + , m_currentImageId(1) { } + + virtual void bindTexture(WGC3Denum target, WebGLId texture) + { + if (target == GL_TEXTURE_2D) { + m_boundTexture = texture; + } + } + + virtual void texImage2D(WGC3Denum target, WGC3Dint level, WGC3Denum internalformat, WGC3Dsizei width, WGC3Dsizei height, WGC3Dint border, WGC3Denum format, WGC3Denum type, const void* pixels) + { + if (target == GL_TEXTURE_2D && !level) { + m_textureSizes.set(m_boundTexture, IntSize(width, height)); + } + } + + virtual void genMailboxCHROMIUM(WGC3Dbyte* mailbox) + { + ++m_currentMailboxByte; + WebExternalTextureMailbox temp; + memset(mailbox, m_currentMailboxByte, sizeof(temp.name)); + } + + virtual void produceTextureCHROMIUM(WGC3Denum target, const WGC3Dbyte* mailbox) + { + ASSERT_EQ(target, static_cast<WGC3Denum>(GL_TEXTURE_2D)); + m_mostRecentlyProducedSize = m_textureSizes.get(m_boundTexture); + } + + IntSize mostRecentlyProducedSize() + { + return m_mostRecentlyProducedSize; + } + + virtual unsigned insertSyncPoint() + { + static unsigned syncPointGenerator = 0; + return ++syncPointGenerator; + } + + virtual void waitSyncPoint(unsigned syncPoint) + { + m_mostRecentlyWaitedSyncPoint = syncPoint; + } + + virtual WGC3Duint createImageCHROMIUM(WGC3Dsizei width, WGC3Dsizei height, WGC3Denum internalformat, WGC3Denum usage) + { + m_imageSizes.set(m_currentImageId, IntSize(width, height)); + return m_currentImageId++; + } + + MOCK_METHOD1(destroyImageMock, void(WGC3Duint imageId)); + void destroyImageCHROMIUM(WGC3Duint imageId) + { + m_imageSizes.remove(imageId); + // No textures should be bound to this. + ASSERT(m_imageToTextureMap.find(imageId) == m_imageToTextureMap.end()); + m_imageSizes.remove(imageId); + destroyImageMock(imageId); + } + + MOCK_METHOD1(bindTexImage2DMock, void(WGC3Dint imageId)); + void bindTexImage2DCHROMIUM(WGC3Denum target, WGC3Dint imageId) + { + if (target == GL_TEXTURE_2D) { + m_textureSizes.set(m_boundTexture, m_imageSizes.find(imageId)->value); + m_imageToTextureMap.set(imageId, m_boundTexture); + bindTexImage2DMock(imageId); + } + } + + MOCK_METHOD1(releaseTexImage2DMock, void(WGC3Dint imageId)); + void releaseTexImage2DCHROMIUM(WGC3Denum target, WGC3Dint imageId) + { + if (target == GL_TEXTURE_2D) { + m_imageSizes.set(m_currentImageId, IntSize()); + m_imageToTextureMap.remove(imageId); + releaseTexImage2DMock(imageId); + } + } + + unsigned mostRecentlyWaitedSyncPoint() + { + return m_mostRecentlyWaitedSyncPoint; + } + + WGC3Duint nextImageIdToBeCreated() + { + return m_currentImageId; + } + +private: + WebGLId m_boundTexture; + HashMap<WebGLId, IntSize> m_textureSizes; + WGC3Dbyte m_currentMailboxByte; + IntSize m_mostRecentlyProducedSize; + unsigned m_mostRecentlyWaitedSyncPoint; + WGC3Duint m_currentImageId; + HashMap<WGC3Duint, IntSize> m_imageSizes; + HashMap<WGC3Duint, WebGLId> m_imageToTextureMap; +}; + +static const int initialWidth = 100; +static const int initialHeight = 100; +static const int alternateHeight = 50; + +class DrawingBufferForTests : public DrawingBuffer { +public: + static PassRefPtr<DrawingBufferForTests> create(PassOwnPtr<blink::WebGraphicsContext3D> context, + const IntSize& size, PreserveDrawingBuffer preserve, PassRefPtr<ContextEvictionManager> contextEvictionManager) + { + OwnPtr<Extensions3DUtil> extensionsUtil = Extensions3DUtil::create(context.get()); + RefPtr<DrawingBufferForTests> drawingBuffer = + adoptRef(new DrawingBufferForTests(context, extensionsUtil.release(), preserve, contextEvictionManager)); + if (!drawingBuffer->initialize(size)) { + drawingBuffer->beginDestruction(); + return PassRefPtr<DrawingBufferForTests>(); + } + return drawingBuffer.release(); + } + + DrawingBufferForTests(PassOwnPtr<blink::WebGraphicsContext3D> context, + PassOwnPtr<Extensions3DUtil> extensionsUtil, + PreserveDrawingBuffer preserve, + PassRefPtr<ContextEvictionManager> contextEvictionManager) + : DrawingBuffer(context, extensionsUtil, false /* multisampleExtensionSupported */, + false /* packedDepthStencilExtensionSupported */, preserve, blink::WebGraphicsContext3D::Attributes(), contextEvictionManager) + , m_live(0) + { } + + virtual ~DrawingBufferForTests() + { + if (m_live) + *m_live = false; + } + + bool* m_live; +}; + +class DrawingBufferTest : public Test { +protected: + virtual void SetUp() + { + RefPtr<FakeContextEvictionManager> contextEvictionManager = adoptRef(new FakeContextEvictionManager()); + OwnPtr<WebGraphicsContext3DForTests> context = adoptPtr(new WebGraphicsContext3DForTests); + m_context = context.get(); + m_drawingBuffer = DrawingBufferForTests::create(context.release(), + IntSize(initialWidth, initialHeight), DrawingBuffer::Preserve, contextEvictionManager.release()); + } + + WebGraphicsContext3DForTests* webContext() + { + return m_context; + } + + WebGraphicsContext3DForTests* m_context; + RefPtr<DrawingBufferForTests> m_drawingBuffer; +}; + +TEST_F(DrawingBufferTest, testPaintRenderingResultsToCanvas) +{ + OwnPtr<ImageBufferSurface> imageBufferSurface = adoptPtr(new UnacceleratedImageBufferSurface(IntSize(initialWidth, initialHeight))); + EXPECT_FALSE(!imageBufferSurface); + EXPECT_TRUE(imageBufferSurface->isValid()); + OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(imageBufferSurface.release()); + EXPECT_FALSE(!imageBuffer); + EXPECT_FALSE(imageBuffer->isAccelerated()); + EXPECT_FALSE(imageBuffer->bitmap().isNull()); + m_drawingBuffer->paintRenderingResultsToCanvas(imageBuffer.get()); + EXPECT_FALSE(imageBuffer->isAccelerated()); + EXPECT_FALSE(imageBuffer->bitmap().isNull()); + m_drawingBuffer->beginDestruction(); +} + +TEST_F(DrawingBufferTest, verifyResizingProperlyAffectsMailboxes) +{ + blink::WebExternalTextureMailbox mailbox; + + IntSize initialSize(initialWidth, initialHeight); + IntSize alternateSize(initialWidth, alternateHeight); + + // Produce one mailbox at size 100x100. + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0)); + EXPECT_EQ(initialSize, webContext()->mostRecentlyProducedSize()); + + // Resize to 100x50. + m_drawingBuffer->reset(IntSize(initialWidth, alternateHeight)); + m_drawingBuffer->mailboxReleased(mailbox); + + // Produce a mailbox at this size. + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0)); + EXPECT_EQ(alternateSize, webContext()->mostRecentlyProducedSize()); + + // Reset to initial size. + m_drawingBuffer->reset(IntSize(initialWidth, initialHeight)); + m_drawingBuffer->mailboxReleased(mailbox); + + // Prepare another mailbox and verify that it's the correct size. + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0)); + EXPECT_EQ(initialSize, webContext()->mostRecentlyProducedSize()); + + // Prepare one final mailbox and verify that it's the correct size. + m_drawingBuffer->mailboxReleased(mailbox); + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0)); + EXPECT_EQ(initialSize, webContext()->mostRecentlyProducedSize()); + m_drawingBuffer->beginDestruction(); +} + +TEST_F(DrawingBufferTest, verifyDestructionCompleteAfterAllMailboxesReleased) +{ + bool live = true; + m_drawingBuffer->m_live = &live; + + blink::WebExternalTextureMailbox mailbox1; + blink::WebExternalTextureMailbox mailbox2; + blink::WebExternalTextureMailbox mailbox3; + + IntSize initialSize(initialWidth, initialHeight); + + // Produce mailboxes. + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox1, 0)); + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox2, 0)); + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox3, 0)); + + m_drawingBuffer->markContentsChanged(); + m_drawingBuffer->mailboxReleased(mailbox1); + + m_drawingBuffer->beginDestruction(); + EXPECT_EQ(live, true); + + DrawingBufferForTests* weakPointer = m_drawingBuffer.get(); + m_drawingBuffer.clear(); + EXPECT_EQ(live, true); + + weakPointer->markContentsChanged(); + weakPointer->mailboxReleased(mailbox2); + EXPECT_EQ(live, true); + + weakPointer->markContentsChanged(); + weakPointer->mailboxReleased(mailbox3); + EXPECT_EQ(live, false); +} + +class TextureMailboxWrapper { +public: + explicit TextureMailboxWrapper(const blink::WebExternalTextureMailbox& mailbox) + : m_mailbox(mailbox) + { } + + bool operator==(const TextureMailboxWrapper& other) const + { + return !memcmp(m_mailbox.name, other.m_mailbox.name, sizeof(m_mailbox.name)); + } + +private: + blink::WebExternalTextureMailbox m_mailbox; +}; + +TEST_F(DrawingBufferTest, verifyRecyclingMailboxesByFIFO) +{ + blink::WebExternalTextureMailbox mailbox1; + blink::WebExternalTextureMailbox mailbox2; + blink::WebExternalTextureMailbox mailbox3; + + // Produce mailboxes. + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox1, 0)); + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox2, 0)); + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox3, 0)); + + // Release mailboxes by specific order; 2, 3, 1. + m_drawingBuffer->markContentsChanged(); + m_drawingBuffer->mailboxReleased(mailbox2); + m_drawingBuffer->markContentsChanged(); + m_drawingBuffer->mailboxReleased(mailbox3); + m_drawingBuffer->markContentsChanged(); + m_drawingBuffer->mailboxReleased(mailbox1); + + // The first recycled mailbox must be 2. + blink::WebExternalTextureMailbox recycledMailbox; + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&recycledMailbox, 0)); + EXPECT_EQ(TextureMailboxWrapper(mailbox2), TextureMailboxWrapper(recycledMailbox)); + + // The second recycled mailbox must be 3. + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&recycledMailbox, 0)); + EXPECT_EQ(TextureMailboxWrapper(mailbox3), TextureMailboxWrapper(recycledMailbox)); + + // The third recycled mailbox must be 1. + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&recycledMailbox, 0)); + EXPECT_EQ(TextureMailboxWrapper(mailbox1), TextureMailboxWrapper(recycledMailbox)); + + m_drawingBuffer->mailboxReleased(mailbox1); + m_drawingBuffer->mailboxReleased(mailbox2); + m_drawingBuffer->mailboxReleased(mailbox3); + m_drawingBuffer->beginDestruction(); +} + +TEST_F(DrawingBufferTest, verifyInsertAndWaitSyncPointCorrectly) +{ + blink::WebExternalTextureMailbox mailbox; + + // Produce mailboxes. + m_drawingBuffer->markContentsChanged(); + EXPECT_EQ(0u, webContext()->mostRecentlyWaitedSyncPoint()); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0)); + // prepareMailbox() does not wait for any sync point. + EXPECT_EQ(0u, webContext()->mostRecentlyWaitedSyncPoint()); + + unsigned waitSyncPoint = webContext()->insertSyncPoint(); + mailbox.syncPoint = waitSyncPoint; + m_drawingBuffer->mailboxReleased(mailbox); + // m_drawingBuffer will wait for the sync point when recycling. + EXPECT_EQ(0u, webContext()->mostRecentlyWaitedSyncPoint()); + + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0)); + // m_drawingBuffer waits for the sync point when recycling in prepareMailbox(). + EXPECT_EQ(waitSyncPoint, webContext()->mostRecentlyWaitedSyncPoint()); + + m_drawingBuffer->beginDestruction(); + waitSyncPoint = webContext()->insertSyncPoint(); + mailbox.syncPoint = waitSyncPoint; + m_drawingBuffer->mailboxReleased(mailbox); + // m_drawingBuffer waits for the sync point because the destruction is in progress. + EXPECT_EQ(waitSyncPoint, webContext()->mostRecentlyWaitedSyncPoint()); +} + +class DrawingBufferImageChromiumTest : public DrawingBufferTest { +protected: + virtual void SetUp() + { + RefPtr<FakeContextEvictionManager> contextEvictionManager = adoptRef(new FakeContextEvictionManager()); + OwnPtr<WebGraphicsContext3DForTests> context = adoptPtr(new WebGraphicsContext3DForTests); + m_context = context.get(); + RuntimeEnabledFeatures::setWebGLImageChromiumEnabled(true); + m_imageId0 = webContext()->nextImageIdToBeCreated(); + EXPECT_CALL(*webContext(), bindTexImage2DMock(m_imageId0)).Times(1); + m_drawingBuffer = DrawingBufferForTests::create(context.release(), + IntSize(initialWidth, initialHeight), DrawingBuffer::Preserve, contextEvictionManager.release()); + testing::Mock::VerifyAndClearExpectations(webContext()); + } + + virtual void TearDown() + { + RuntimeEnabledFeatures::setWebGLImageChromiumEnabled(false); + } + WGC3Duint m_imageId0; +}; + +TEST_F(DrawingBufferImageChromiumTest, verifyResizingReallocatesImages) +{ + blink::WebExternalTextureMailbox mailbox; + + IntSize initialSize(initialWidth, initialHeight); + IntSize alternateSize(initialWidth, alternateHeight); + + WGC3Duint m_imageId1 = webContext()->nextImageIdToBeCreated(); + EXPECT_CALL(*webContext(), bindTexImage2DMock(m_imageId1)).Times(1); + // Produce one mailbox at size 100x100. + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0)); + EXPECT_EQ(initialSize, webContext()->mostRecentlyProducedSize()); + EXPECT_TRUE(mailbox.allowOverlay); + testing::Mock::VerifyAndClearExpectations(webContext()); + + WGC3Duint m_imageId2 = webContext()->nextImageIdToBeCreated(); + EXPECT_CALL(*webContext(), bindTexImage2DMock(m_imageId2)).Times(1); + EXPECT_CALL(*webContext(), destroyImageMock(m_imageId0)).Times(1); + EXPECT_CALL(*webContext(), releaseTexImage2DMock(m_imageId0)).Times(1); + // Resize to 100x50. + m_drawingBuffer->reset(IntSize(initialWidth, alternateHeight)); + m_drawingBuffer->mailboxReleased(mailbox); + testing::Mock::VerifyAndClearExpectations(webContext()); + + WGC3Duint m_imageId3 = webContext()->nextImageIdToBeCreated(); + EXPECT_CALL(*webContext(), bindTexImage2DMock(m_imageId3)).Times(1); + EXPECT_CALL(*webContext(), destroyImageMock(m_imageId1)).Times(1); + EXPECT_CALL(*webContext(), releaseTexImage2DMock(m_imageId1)).Times(1); + // Produce a mailbox at this size. + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0)); + EXPECT_EQ(alternateSize, webContext()->mostRecentlyProducedSize()); + EXPECT_TRUE(mailbox.allowOverlay); + testing::Mock::VerifyAndClearExpectations(webContext()); + + WGC3Duint m_imageId4 = webContext()->nextImageIdToBeCreated(); + EXPECT_CALL(*webContext(), bindTexImage2DMock(m_imageId4)).Times(1); + EXPECT_CALL(*webContext(), destroyImageMock(m_imageId2)).Times(1); + EXPECT_CALL(*webContext(), releaseTexImage2DMock(m_imageId2)).Times(1); + // Reset to initial size. + m_drawingBuffer->reset(IntSize(initialWidth, initialHeight)); + m_drawingBuffer->mailboxReleased(mailbox); + testing::Mock::VerifyAndClearExpectations(webContext()); + + WGC3Duint m_imageId5 = webContext()->nextImageIdToBeCreated(); + EXPECT_CALL(*webContext(), bindTexImage2DMock(m_imageId5)).Times(1); + EXPECT_CALL(*webContext(), destroyImageMock(m_imageId3)).Times(1); + EXPECT_CALL(*webContext(), releaseTexImage2DMock(m_imageId3)).Times(1); + // Prepare another mailbox and verify that it's the correct size. + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0)); + EXPECT_EQ(initialSize, webContext()->mostRecentlyProducedSize()); + EXPECT_TRUE(mailbox.allowOverlay); + testing::Mock::VerifyAndClearExpectations(webContext()); + + // Prepare one final mailbox and verify that it's the correct size. + m_drawingBuffer->mailboxReleased(mailbox); + m_drawingBuffer->markContentsChanged(); + EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0)); + EXPECT_EQ(initialSize, webContext()->mostRecentlyProducedSize()); + EXPECT_TRUE(mailbox.allowOverlay); + m_drawingBuffer->mailboxReleased(mailbox); + + EXPECT_CALL(*webContext(), destroyImageMock(m_imageId5)).Times(1); + EXPECT_CALL(*webContext(), releaseTexImage2DMock(m_imageId5)).Times(1); + EXPECT_CALL(*webContext(), destroyImageMock(m_imageId4)).Times(1); + EXPECT_CALL(*webContext(), releaseTexImage2DMock(m_imageId4)).Times(1); + m_drawingBuffer->beginDestruction(); + testing::Mock::VerifyAndClearExpectations(webContext()); +} + +class DepthStencilTrackingContext : public MockWebGraphicsContext3D { +public: + DepthStencilTrackingContext() + : m_nextRenderBufferId(1) + , m_stencilAttachment(0) + , m_depthAttachment(0) { } + virtual ~DepthStencilTrackingContext() { } + + int numAllocatedRenderBuffer() const { return m_nextRenderBufferId - 1; } + WebGLId stencilAttachment() const { return m_stencilAttachment; } + WebGLId depthAttachment() const { return m_depthAttachment; } + + virtual WebString getString(WGC3Denum type) OVERRIDE + { + if (type == GL_EXTENSIONS) { + return WebString::fromUTF8("GL_OES_packed_depth_stencil"); + } + return WebString(); + } + + virtual WebGLId createRenderbuffer() OVERRIDE + { + return ++m_nextRenderBufferId; + } + + virtual void framebufferRenderbuffer(WGC3Denum target, WGC3Denum attachment, WGC3Denum renderbuffertarget, WebGLId renderbuffer) OVERRIDE + { + if (attachment == GL_STENCIL_ATTACHMENT) { + m_stencilAttachment = renderbuffer; + } else { + m_depthAttachment = renderbuffer; + } + } + + virtual void getIntegerv(WGC3Denum ptype, WGC3Dint* value) OVERRIDE + { + switch (ptype) { + case GL_DEPTH_BITS: + *value = m_depthAttachment ? 24 : 0; + return; + case GL_STENCIL_BITS: + *value = m_stencilAttachment ? 8 : 0; + return; + } + MockWebGraphicsContext3D::getIntegerv(ptype, value); + } + +private: + WebGLId m_nextRenderBufferId; + WebGLId m_stencilAttachment; + WebGLId m_depthAttachment; +}; + +struct DepthStencilTestCase { + DepthStencilTestCase(bool requestStencil, bool requestDepth, int expectedRenderBuffers, bool expectDepthStencil, const char* const testCaseName) + : requestStencil(requestStencil) + , requestDepth(requestDepth) + , expectDepthStencil(expectDepthStencil) + , expectedRenderBuffers(expectedRenderBuffers) + , testCaseName(testCaseName) { } + + bool requestStencil; + bool requestDepth; + bool expectDepthStencil; + int expectedRenderBuffers; + const char* const testCaseName; +}; + +// This tests that when the packed depth+stencil extension is supported DrawingBuffer always allocates +// a single packed renderbuffer if either is requested and properly computes the actual context attributes +// as defined by WebGL. We always allocate a packed buffer in this case since many desktop OpenGL drivers +// that support this extension do not consider a framebuffer with only a depth or a stencil buffer attached +// to be complete. +TEST(DrawingBufferDepthStencilTest, packedDepthStencilSupported) +{ + DepthStencilTestCase cases[] = { + DepthStencilTestCase(false, false, false, 0, "neither"), + DepthStencilTestCase(true, false, true, 1, "stencil only"), + DepthStencilTestCase(false, true, true, 1, "depth only"), + DepthStencilTestCase(true, true, true, 1, "both"), + }; + + for (size_t i = 0; i < arraysize(cases); i++) { + SCOPED_TRACE(cases[i].testCaseName); + OwnPtr<DepthStencilTrackingContext> context = adoptPtr(new DepthStencilTrackingContext); + DepthStencilTrackingContext* trackingContext = context.get(); + DrawingBuffer::PreserveDrawingBuffer preserve = DrawingBuffer::Preserve; + RefPtr<ContextEvictionManager> contextEvictionManager = adoptRef(new FakeContextEvictionManager); + + blink::WebGraphicsContext3D::Attributes requestedAttributes; + requestedAttributes.stencil = cases[i].requestStencil; + requestedAttributes.depth = cases[i].requestDepth; + RefPtr<DrawingBuffer> drawingBuffer = DrawingBuffer::create(context.release(), IntSize(10, 10), preserve, requestedAttributes, contextEvictionManager); + + EXPECT_EQ(cases[i].requestDepth, drawingBuffer->getActualAttributes().depth); + EXPECT_EQ(cases[i].requestStencil, drawingBuffer->getActualAttributes().stencil); + EXPECT_EQ(cases[i].expectedRenderBuffers, trackingContext->numAllocatedRenderBuffer()); + if (cases[i].expectDepthStencil) { + EXPECT_EQ(trackingContext->stencilAttachment(), trackingContext->depthAttachment()); + } else if (cases[i].requestStencil || cases[i].requestDepth) { + EXPECT_NE(trackingContext->stencilAttachment(), trackingContext->depthAttachment()); + } else { + EXPECT_EQ(0u, trackingContext->stencilAttachment()); + EXPECT_EQ(0u, trackingContext->depthAttachment()); + } + + drawingBuffer->reset(IntSize(10, 20)); + EXPECT_EQ(cases[i].requestDepth, drawingBuffer->getActualAttributes().depth); + EXPECT_EQ(cases[i].requestStencil, drawingBuffer->getActualAttributes().stencil); + EXPECT_EQ(cases[i].expectedRenderBuffers, trackingContext->numAllocatedRenderBuffer()); + if (cases[i].expectDepthStencil) { + EXPECT_EQ(trackingContext->stencilAttachment(), trackingContext->depthAttachment()); + } else if (cases[i].requestStencil || cases[i].requestDepth) { + EXPECT_NE(trackingContext->stencilAttachment(), trackingContext->depthAttachment()); + } else { + EXPECT_EQ(0u, trackingContext->stencilAttachment()); + EXPECT_EQ(0u, trackingContext->depthAttachment()); + } + + drawingBuffer->beginDestruction(); + } +} + +} // namespace diff --git a/chromium/third_party/WebKit/Source/platform/graphics/gpu/Extensions3DUtil.cpp b/chromium/third_party/WebKit/Source/platform/graphics/gpu/Extensions3DUtil.cpp new file mode 100644 index 00000000000..7da33ee5211 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/gpu/Extensions3DUtil.cpp @@ -0,0 +1,101 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" +#include "platform/graphics/gpu/Extensions3DUtil.h" + +#include "public/platform/WebGraphicsContext3D.h" +#include "wtf/text/CString.h" +#include "wtf/text/StringHash.h" + +namespace WebCore { + +namespace { + +void splitStringHelper(const String& str, HashSet<String>& set) +{ + Vector<String> substrings; + str.split(" ", substrings); + for (size_t i = 0; i < substrings.size(); ++i) + set.add(substrings[i]); +} + +} // anonymous namespace + +PassOwnPtr<Extensions3DUtil> Extensions3DUtil::create(blink::WebGraphicsContext3D* context) +{ + OwnPtr<Extensions3DUtil> out = adoptPtr(new Extensions3DUtil(context)); + if (!out->initializeExtensions()) + return nullptr; + return out.release(); +} + +Extensions3DUtil::Extensions3DUtil(blink::WebGraphicsContext3D* context) + : m_context(context) +{ +} + +Extensions3DUtil::~Extensions3DUtil() +{ +} + +bool Extensions3DUtil::initializeExtensions() +{ + if (!m_context->makeContextCurrent()) { + // Most likely the GPU process exited and the attempt to reconnect to it failed. + // Need to try to restore the context again later. + return false; + } + + if (m_context->isContextLost()) { + // Need to try to restore the context again later. + return false; + } + + String extensionsString = m_context->getString(GL_EXTENSIONS); + splitStringHelper(extensionsString, m_enabledExtensions); + + String requestableExtensionsString = m_context->getRequestableExtensionsCHROMIUM(); + splitStringHelper(requestableExtensionsString, m_requestableExtensions); + + return true; +} + + +bool Extensions3DUtil::supportsExtension(const String& name) +{ + return m_enabledExtensions.contains(name) || m_requestableExtensions.contains(name); +} + +bool Extensions3DUtil::ensureExtensionEnabled(const String& name) +{ + if (m_enabledExtensions.contains(name)) + return true; + + if (m_requestableExtensions.contains(name)) { + m_context->requestExtensionCHROMIUM(name.ascii().data()); + m_enabledExtensions.clear(); + m_requestableExtensions.clear(); + initializeExtensions(); + } + return m_enabledExtensions.contains(name); +} + +bool Extensions3DUtil::isExtensionEnabled(const String& name) +{ + return m_enabledExtensions.contains(name); +} + +bool Extensions3DUtil::canUseCopyTextureCHROMIUM(GLenum destFormat, GLenum destType, GLint level) +{ + // FIXME: restriction of (RGB || RGBA)/UNSIGNED_BYTE/(Level 0) should be lifted when + // WebGraphicsContext3D::copyTextureCHROMIUM(...) are fully functional. + if ((destFormat == GL_RGB || destFormat == GL_RGBA) + && destType == GL_UNSIGNED_BYTE + && !level) + return true; + return false; +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/gpu/Extensions3DUtil.h b/chromium/third_party/WebKit/Source/platform/graphics/gpu/Extensions3DUtil.h new file mode 100644 index 00000000000..3251192950e --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/gpu/Extensions3DUtil.h @@ -0,0 +1,44 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef Extensions3DUtil_h +#define Extensions3DUtil_h + +#include "platform/PlatformExport.h" +#include "platform/graphics/GraphicsTypes3D.h" +#include "third_party/khronos/GLES2/gl2.h" +#include "third_party/khronos/GLES2/gl2ext.h" +#include "wtf/HashSet.h" +#include "wtf/text/WTFString.h" + +namespace blink { +class WebGraphicsContext3D; +} + +namespace WebCore { + +class PLATFORM_EXPORT Extensions3DUtil { +public: + // Creates a new Extensions3DUtil. If the passed WebGraphicsContext3D has been spontaneously lost, returns null. + static PassOwnPtr<Extensions3DUtil> create(blink::WebGraphicsContext3D*); + ~Extensions3DUtil(); + + bool supportsExtension(const String& name); + bool ensureExtensionEnabled(const String& name); + bool isExtensionEnabled(const String& name); + + static bool canUseCopyTextureCHROMIUM(GLenum destFormat, GLenum destType, GLint level); + +private: + Extensions3DUtil(blink::WebGraphicsContext3D*); + bool initializeExtensions(); + + blink::WebGraphicsContext3D* m_context; + HashSet<String> m_enabledExtensions; + HashSet<String> m_requestableExtensions; +}; + +} // namespace WebCore + +#endif // Extensions3DUtil_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/gpu/SharedGraphicsContext3D.cpp b/chromium/third_party/WebKit/Source/platform/graphics/gpu/SharedGraphicsContext3D.cpp deleted file mode 100644 index 9ce882a824c..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/gpu/SharedGraphicsContext3D.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#include "config.h" - -#include "platform/graphics/gpu/SharedGraphicsContext3D.h" - -#include "platform/graphics/Extensions3D.h" -#include "public/platform/Platform.h" -#include "public/platform/WebGraphicsContext3D.h" -#include "public/platform/WebGraphicsContext3DProvider.h" -#include "wtf/MainThread.h" - -namespace WebCore { - -class SharedGraphicsContext3DImpl { -public: - SharedGraphicsContext3DImpl() : m_context(0) { } - - PassRefPtr<GraphicsContext3D> getOrCreateContext() - { - bool wasCreated = false; - - OwnPtr<blink::WebGraphicsContext3DProvider> provider = adoptPtr(blink::Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); - - blink::WebGraphicsContext3D* webContext = 0; - GrContext* grContext = 0; - - if (provider) { - webContext = provider->context3d(); - grContext = provider->grContext(); - } - - if (webContext && grContext) { - blink::WebGraphicsContext3D* oldWebContext = m_context ? m_context->webContext() : 0; - GrContext* oldGrContext = m_context ? m_context->grContext() : 0; - if (webContext != oldWebContext || grContext != oldGrContext) - m_context.clear(); - - if (!m_context) { - m_context = GraphicsContext3D::createGraphicsContextFromProvider(provider.release()); - wasCreated = true; - } - } - - if (m_context && wasCreated) - m_context->extensions()->pushGroupMarkerEXT("SharedGraphicsContext"); - return m_context; - } - -private: - RefPtr<GraphicsContext3D> m_context; -}; - -PassRefPtr<GraphicsContext3D> SharedGraphicsContext3D::get() -{ - DEFINE_STATIC_LOCAL(SharedGraphicsContext3DImpl, impl, ()); - return impl.getOrCreateContext(); -} - -} // namespace WebCore - diff --git a/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageBufferSurface.cpp b/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageBufferSurface.cpp index a9869c98d2e..3b1cfa187be 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageBufferSurface.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageBufferSurface.cpp @@ -32,20 +32,30 @@ #include "platform/graphics/gpu/WebGLImageBufferSurface.h" -#include "platform/graphics/gpu/SharedGraphicsContext3D.h" #include "platform/graphics/skia/GaneshUtils.h" +#include "public/platform/Platform.h" +#include "public/platform/WebGraphicsContext3DProvider.h" +#include "third_party/skia/include/core/SkPixelRef.h" +#include "wtf/PassOwnPtr.h" namespace WebCore { WebGLImageBufferSurface::WebGLImageBufferSurface(const IntSize& size, OpacityMode opacityMode) : ImageBufferSurface(size, opacityMode) { - GrContext* gr = SharedGraphicsContext3D::get()->grContext(); + m_contextProvider = adoptPtr(blink::Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); + if (!m_contextProvider) + return; + GrContext* gr = m_contextProvider->grContext(); if (!gr) return; ensureTextureBackedSkBitmap(gr, m_bitmap, size, kDefault_GrSurfaceOrigin, kRGBA_8888_GrPixelConfig); } +WebGLImageBufferSurface::~WebGLImageBufferSurface() +{ +} + Platform3DObject WebGLImageBufferSurface::getBackingTexture() const { GrTexture* texture = m_bitmap.getTexture(); @@ -54,4 +64,16 @@ Platform3DObject WebGLImageBufferSurface::getBackingTexture() const return texture->getTextureHandle(); } +void WebGLImageBufferSurface::invalidateCachedBitmap() +{ + m_cachedBitmap.reset(); +} + +void WebGLImageBufferSurface::updateCachedBitmapIfNeeded() +{ + if (m_cachedBitmap.isNull() && m_bitmap.pixelRef()) { + (m_bitmap.pixelRef())->readPixels(&m_cachedBitmap); + } +} + } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageBufferSurface.h b/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageBufferSurface.h index 0725ff271e2..a148e907be0 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageBufferSurface.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageBufferSurface.h @@ -33,6 +33,11 @@ #include "platform/graphics/ImageBufferSurface.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "wtf/OwnPtr.h" + +namespace blink { +class WebGraphicsContext3DProvider; +} namespace WebCore { @@ -41,16 +46,24 @@ class PLATFORM_EXPORT WebGLImageBufferSurface : public ImageBufferSurface { WTF_MAKE_NONCOPYABLE(WebGLImageBufferSurface); WTF_MAKE_FAST_ALLOCATED; public: WebGLImageBufferSurface(const IntSize&, OpacityMode = NonOpaque); - virtual ~WebGLImageBufferSurface() { } + virtual ~WebGLImageBufferSurface(); virtual SkCanvas* canvas() const OVERRIDE { return 0; } virtual const SkBitmap& bitmap() const OVERRIDE { return m_bitmap; } virtual bool isValid() const OVERRIDE { return m_bitmap.pixelRef(); } virtual bool isAccelerated() const OVERRIDE { return true; } virtual Platform3DObject getBackingTexture() const OVERRIDE; + virtual bool cachedBitmapEnabled() const OVERRIDE { return true; } + virtual const SkBitmap& cachedBitmap() const OVERRIDE { return m_cachedBitmap; } + virtual void invalidateCachedBitmap() OVERRIDE; + virtual void updateCachedBitmapIfNeeded() OVERRIDE; private: SkBitmap m_bitmap; + // This raw-pixel based SkBitmap works as a cache at CPU side to avoid heavy cost + // on readback from GPU side to CPU side in some cases. + SkBitmap m_cachedBitmap; + OwnPtr<blink::WebGraphicsContext3DProvider> m_contextProvider; }; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext3DImagePacking.cpp b/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.cpp index 60cae8f5ae0..d90b4dddfac 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/GraphicsContext3DImagePacking.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.cpp @@ -1,90 +1,71 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * Copyright (C) 2010 Mozilla Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. #include "config.h" -#include "platform/graphics/GraphicsContext3D.h" +#include "platform/graphics/gpu/WebGLImageConversion.h" -#include "platform/graphics/cpu/arm/GraphicsContext3DNEON.h" -#include "platform/image-decoders/ImageDecoder.h" +#include "platform/CheckedInt.h" #include "platform/graphics/ImageObserver.h" +#include "platform/graphics/cpu/arm/WebGLImageConversionNEON.h" +#include "platform/image-decoders/ImageDecoder.h" +#include "wtf/OwnPtr.h" +#include "wtf/PassOwnPtr.h" namespace WebCore { namespace { -GraphicsContext3D::DataFormat getDataFormat(GC3Denum destinationFormat, GC3Denum destinationType) +WebGLImageConversion::DataFormat getDataFormat(GLenum destinationFormat, GLenum destinationType) { - GraphicsContext3D::DataFormat dstFormat = GraphicsContext3D::DataFormatRGBA8; + WebGLImageConversion::DataFormat dstFormat = WebGLImageConversion::DataFormatRGBA8; switch (destinationType) { case GL_UNSIGNED_BYTE: switch (destinationFormat) { case GL_RGB: - dstFormat = GraphicsContext3D::DataFormatRGB8; + dstFormat = WebGLImageConversion::DataFormatRGB8; break; case GL_RGBA: - dstFormat = GraphicsContext3D::DataFormatRGBA8; + dstFormat = WebGLImageConversion::DataFormatRGBA8; break; case GL_ALPHA: - dstFormat = GraphicsContext3D::DataFormatA8; + dstFormat = WebGLImageConversion::DataFormatA8; break; case GL_LUMINANCE: - dstFormat = GraphicsContext3D::DataFormatR8; + dstFormat = WebGLImageConversion::DataFormatR8; break; case GL_LUMINANCE_ALPHA: - dstFormat = GraphicsContext3D::DataFormatRA8; + dstFormat = WebGLImageConversion::DataFormatRA8; break; default: ASSERT_NOT_REACHED(); } break; case GL_UNSIGNED_SHORT_4_4_4_4: - dstFormat = GraphicsContext3D::DataFormatRGBA4444; + dstFormat = WebGLImageConversion::DataFormatRGBA4444; break; case GL_UNSIGNED_SHORT_5_5_5_1: - dstFormat = GraphicsContext3D::DataFormatRGBA5551; + dstFormat = WebGLImageConversion::DataFormatRGBA5551; break; case GL_UNSIGNED_SHORT_5_6_5: - dstFormat = GraphicsContext3D::DataFormatRGB565; + dstFormat = WebGLImageConversion::DataFormatRGB565; break; case GL_HALF_FLOAT_OES: // OES_texture_half_float switch (destinationFormat) { case GL_RGB: - dstFormat = GraphicsContext3D::DataFormatRGB16F; + dstFormat = WebGLImageConversion::DataFormatRGB16F; break; case GL_RGBA: - dstFormat = GraphicsContext3D::DataFormatRGBA16F; + dstFormat = WebGLImageConversion::DataFormatRGBA16F; break; case GL_ALPHA: - dstFormat = GraphicsContext3D::DataFormatA16F; + dstFormat = WebGLImageConversion::DataFormatA16F; break; case GL_LUMINANCE: - dstFormat = GraphicsContext3D::DataFormatR16F; + dstFormat = WebGLImageConversion::DataFormatR16F; break; case GL_LUMINANCE_ALPHA: - dstFormat = GraphicsContext3D::DataFormatRA16F; + dstFormat = WebGLImageConversion::DataFormatRA16F; break; default: ASSERT_NOT_REACHED(); @@ -93,19 +74,19 @@ GraphicsContext3D::DataFormat getDataFormat(GC3Denum destinationFormat, GC3Denum case GL_FLOAT: // OES_texture_float switch (destinationFormat) { case GL_RGB: - dstFormat = GraphicsContext3D::DataFormatRGB32F; + dstFormat = WebGLImageConversion::DataFormatRGB32F; break; case GL_RGBA: - dstFormat = GraphicsContext3D::DataFormatRGBA32F; + dstFormat = WebGLImageConversion::DataFormatRGBA32F; break; case GL_ALPHA: - dstFormat = GraphicsContext3D::DataFormatA32F; + dstFormat = WebGLImageConversion::DataFormatA32F; break; case GL_LUMINANCE: - dstFormat = GraphicsContext3D::DataFormatR32F; + dstFormat = WebGLImageConversion::DataFormatR32F; break; case GL_LUMINANCE_ALPHA: - dstFormat = GraphicsContext3D::DataFormatRA32F; + dstFormat = WebGLImageConversion::DataFormatRA32F; break; default: ASSERT_NOT_REACHED(); @@ -254,9 +235,9 @@ void unpack(const SourceType*, DstType*, unsigned) ASSERT_NOT_REACHED(); } -template<> void unpack<GraphicsContext3D::DataFormatRGB8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatRGB8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[0]; destination[1] = source[1]; destination[2] = source[2]; @@ -266,9 +247,9 @@ template<> void unpack<GraphicsContext3D::DataFormatRGB8, uint8_t, uint8_t>(cons } } -template<> void unpack<GraphicsContext3D::DataFormatBGR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatBGR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[2]; destination[1] = source[1]; destination[2] = source[0]; @@ -278,9 +259,9 @@ template<> void unpack<GraphicsContext3D::DataFormatBGR8, uint8_t, uint8_t>(cons } } -template<> void unpack<GraphicsContext3D::DataFormatARGB8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatARGB8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[1]; destination[1] = source[2]; destination[2] = source[3]; @@ -290,9 +271,9 @@ template<> void unpack<GraphicsContext3D::DataFormatARGB8, uint8_t, uint8_t>(con } } -template<> void unpack<GraphicsContext3D::DataFormatABGR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatABGR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[3]; destination[1] = source[2]; destination[2] = source[1]; @@ -302,11 +283,11 @@ template<> void unpack<GraphicsContext3D::DataFormatABGR8, uint8_t, uint8_t>(con } } -template<> void unpack<GraphicsContext3D::DataFormatBGRA8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatBGRA8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { const uint32_t* source32 = reinterpret_cast_ptr<const uint32_t*>(source); uint32_t* destination32 = reinterpret_cast_ptr<uint32_t*>(destination); - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { uint32_t bgra = source32[i]; #if CPU(BIG_ENDIAN) uint32_t brMask = 0xff00ff00; @@ -320,12 +301,12 @@ template<> void unpack<GraphicsContext3D::DataFormatBGRA8, uint8_t, uint8_t>(con } } -template<> void unpack<GraphicsContext3D::DataFormatRGBA5551, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatRGBA5551, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow) { #if HAVE(ARM_NEON_INTRINSICS) SIMD::unpackOneRowOfRGBA5551ToRGBA8(source, destination, pixelsPerRow); #endif - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { uint16_t packedValue = source[0]; uint8_t r = packedValue >> 11; uint8_t g = (packedValue >> 6) & 0x1F; @@ -339,12 +320,12 @@ template<> void unpack<GraphicsContext3D::DataFormatRGBA5551, uint16_t, uint8_t> } } -template<> void unpack<GraphicsContext3D::DataFormatRGBA4444, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatRGBA4444, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow) { #if HAVE(ARM_NEON_INTRINSICS) SIMD::unpackOneRowOfRGBA4444ToRGBA8(source, destination, pixelsPerRow); #endif - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { uint16_t packedValue = source[0]; uint8_t r = packedValue >> 12; uint8_t g = (packedValue >> 8) & 0x0F; @@ -359,12 +340,12 @@ template<> void unpack<GraphicsContext3D::DataFormatRGBA4444, uint16_t, uint8_t> } } -template<> void unpack<GraphicsContext3D::DataFormatRGB565, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatRGB565, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow) { #if HAVE(ARM_NEON_INTRINSICS) SIMD::unpackOneRowOfRGB565ToRGBA8(source, destination, pixelsPerRow); #endif - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { uint16_t packedValue = source[0]; uint8_t r = packedValue >> 11; uint8_t g = (packedValue >> 5) & 0x3F; @@ -378,9 +359,9 @@ template<> void unpack<GraphicsContext3D::DataFormatRGB565, uint16_t, uint8_t>(c } } -template<> void unpack<GraphicsContext3D::DataFormatR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[0]; destination[1] = source[0]; destination[2] = source[0]; @@ -390,9 +371,9 @@ template<> void unpack<GraphicsContext3D::DataFormatR8, uint8_t, uint8_t>(const } } -template<> void unpack<GraphicsContext3D::DataFormatRA8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatRA8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[0]; destination[1] = source[0]; destination[2] = source[0]; @@ -402,9 +383,9 @@ template<> void unpack<GraphicsContext3D::DataFormatRA8, uint8_t, uint8_t>(const } } -template<> void unpack<GraphicsContext3D::DataFormatAR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatAR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[1]; destination[1] = source[1]; destination[2] = source[1]; @@ -414,9 +395,9 @@ template<> void unpack<GraphicsContext3D::DataFormatAR8, uint8_t, uint8_t>(const } } -template<> void unpack<GraphicsContext3D::DataFormatA8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatA8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = 0x0; destination[1] = 0x0; destination[2] = 0x0; @@ -426,10 +407,10 @@ template<> void unpack<GraphicsContext3D::DataFormatA8, uint8_t, uint8_t>(const } } -template<> void unpack<GraphicsContext3D::DataFormatRGBA8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatRGBA8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow) { const float scaleFactor = 1.0f / 255.0f; - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[0] * scaleFactor; destination[1] = source[1] * scaleFactor; destination[2] = source[2] * scaleFactor; @@ -439,10 +420,10 @@ template<> void unpack<GraphicsContext3D::DataFormatRGBA8, uint8_t, float>(const } } -template<> void unpack<GraphicsContext3D::DataFormatBGRA8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatBGRA8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow) { const float scaleFactor = 1.0f / 255.0f; - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[2] * scaleFactor; destination[1] = source[1] * scaleFactor; destination[2] = source[0] * scaleFactor; @@ -452,7 +433,7 @@ template<> void unpack<GraphicsContext3D::DataFormatBGRA8, uint8_t, float>(const } } -template<> void unpack<GraphicsContext3D::DataFormatABGR8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatABGR8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow) { const float scaleFactor = 1.0f / 255.0f; for (unsigned i = 0; i < pixelsPerRow; ++i) { @@ -465,7 +446,7 @@ template<> void unpack<GraphicsContext3D::DataFormatABGR8, uint8_t, float>(const } } -template<> void unpack<GraphicsContext3D::DataFormatARGB8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatARGB8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow) { const float scaleFactor = 1.0f / 255.0f; for (unsigned i = 0; i < pixelsPerRow; ++i) { @@ -478,7 +459,7 @@ template<> void unpack<GraphicsContext3D::DataFormatARGB8, uint8_t, float>(const } } -template<> void unpack<GraphicsContext3D::DataFormatRGB8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatRGB8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow) { const float scaleFactor = 1.0f / 255.0f; for (unsigned i = 0; i < pixelsPerRow; ++i) { @@ -491,7 +472,7 @@ template<> void unpack<GraphicsContext3D::DataFormatRGB8, uint8_t, float>(const } } -template<> void unpack<GraphicsContext3D::DataFormatBGR8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatBGR8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow) { const float scaleFactor = 1.0f / 255.0f; for (unsigned i = 0; i < pixelsPerRow; ++i) { @@ -504,9 +485,9 @@ template<> void unpack<GraphicsContext3D::DataFormatBGR8, uint8_t, float>(const } } -template<> void unpack<GraphicsContext3D::DataFormatRGB32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatRGB32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[0]; destination[1] = source[1]; destination[2] = source[2]; @@ -516,9 +497,9 @@ template<> void unpack<GraphicsContext3D::DataFormatRGB32F, float, float>(const } } -template<> void unpack<GraphicsContext3D::DataFormatR32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatR32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[0]; destination[1] = source[0]; destination[2] = source[0]; @@ -528,9 +509,9 @@ template<> void unpack<GraphicsContext3D::DataFormatR32F, float, float>(const fl } } -template<> void unpack<GraphicsContext3D::DataFormatRA32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatRA32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[0]; destination[1] = source[0]; destination[2] = source[0]; @@ -540,9 +521,9 @@ template<> void unpack<GraphicsContext3D::DataFormatRA32F, float, float>(const f } } -template<> void unpack<GraphicsContext3D::DataFormatA32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void unpack<WebGLImageConversion::DataFormatA32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = 0; destination[1] = 0; destination[2] = 0; @@ -562,27 +543,27 @@ void pack(const SourceType*, DstType*, unsigned) ASSERT_NOT_REACHED(); } -template<> void pack<GraphicsContext3D::DataFormatA8, GraphicsContext3D::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatA8, WebGLImageConversion::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[3]; source += 4; destination += 1; } } -template<> void pack<GraphicsContext3D::DataFormatR8, GraphicsContext3D::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatR8, WebGLImageConversion::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[0]; source += 4; destination += 1; } } -template<> void pack<GraphicsContext3D::DataFormatR8, GraphicsContext3D::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatR8, WebGLImageConversion::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] / 255.0f; uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor); destination[0] = sourceR; @@ -592,9 +573,9 @@ template<> void pack<GraphicsContext3D::DataFormatR8, GraphicsContext3D::AlphaDo } // FIXME: this routine is lossy and must be removed. -template<> void pack<GraphicsContext3D::DataFormatR8, GraphicsContext3D::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatR8, WebGLImageConversion::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f; uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor); destination[0] = sourceR; @@ -603,9 +584,9 @@ template<> void pack<GraphicsContext3D::DataFormatR8, GraphicsContext3D::AlphaDo } } -template<> void pack<GraphicsContext3D::DataFormatRA8, GraphicsContext3D::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRA8, WebGLImageConversion::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[0]; destination[1] = source[3]; source += 4; @@ -613,9 +594,9 @@ template<> void pack<GraphicsContext3D::DataFormatRA8, GraphicsContext3D::AlphaD } } -template<> void pack<GraphicsContext3D::DataFormatRA8, GraphicsContext3D::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRA8, WebGLImageConversion::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] / 255.0f; uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor); destination[0] = sourceR; @@ -626,9 +607,9 @@ template<> void pack<GraphicsContext3D::DataFormatRA8, GraphicsContext3D::AlphaD } // FIXME: this routine is lossy and must be removed. -template<> void pack<GraphicsContext3D::DataFormatRA8, GraphicsContext3D::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRA8, WebGLImageConversion::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f; uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor); destination[0] = sourceR; @@ -638,9 +619,9 @@ template<> void pack<GraphicsContext3D::DataFormatRA8, GraphicsContext3D::AlphaD } } -template<> void pack<GraphicsContext3D::DataFormatRGB8, GraphicsContext3D::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGB8, WebGLImageConversion::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[0]; destination[1] = source[1]; destination[2] = source[2]; @@ -649,9 +630,9 @@ template<> void pack<GraphicsContext3D::DataFormatRGB8, GraphicsContext3D::Alpha } } -template<> void pack<GraphicsContext3D::DataFormatRGB8, GraphicsContext3D::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGB8, WebGLImageConversion::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] / 255.0f; uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor); uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor); @@ -665,9 +646,9 @@ template<> void pack<GraphicsContext3D::DataFormatRGB8, GraphicsContext3D::Alpha } // FIXME: this routine is lossy and must be removed. -template<> void pack<GraphicsContext3D::DataFormatRGB8, GraphicsContext3D::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGB8, WebGLImageConversion::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f; uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor); uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor); @@ -681,14 +662,14 @@ template<> void pack<GraphicsContext3D::DataFormatRGB8, GraphicsContext3D::Alpha } -template<> void pack<GraphicsContext3D::DataFormatRGBA8, GraphicsContext3D::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA8, WebGLImageConversion::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { memcpy(destination, source, pixelsPerRow * 4); } -template<> void pack<GraphicsContext3D::DataFormatRGBA8, GraphicsContext3D::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA8, WebGLImageConversion::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] / 255.0f; uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor); uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor); @@ -703,9 +684,9 @@ template<> void pack<GraphicsContext3D::DataFormatRGBA8, GraphicsContext3D::Alph } // FIXME: this routine is lossy and must be removed. -template<> void pack<GraphicsContext3D::DataFormatRGBA8, GraphicsContext3D::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA8, WebGLImageConversion::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f; uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor); uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor); @@ -719,12 +700,12 @@ template<> void pack<GraphicsContext3D::DataFormatRGBA8, GraphicsContext3D::Alph } } -template<> void pack<GraphicsContext3D::DataFormatRGBA4444, GraphicsContext3D::AlphaDoNothing, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA4444, WebGLImageConversion::AlphaDoNothing, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) { #if HAVE(ARM_NEON_INTRINSICS) SIMD::packOneRowOfRGBA8ToUnsignedShort4444(source, destination, pixelsPerRow); #endif - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { *destination = (((source[0] & 0xF0) << 8) | ((source[1] & 0xF0) << 4) | (source[2] & 0xF0) @@ -734,9 +715,9 @@ template<> void pack<GraphicsContext3D::DataFormatRGBA4444, GraphicsContext3D::A } } -template<> void pack<GraphicsContext3D::DataFormatRGBA4444, GraphicsContext3D::AlphaDoPremultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA4444, WebGLImageConversion::AlphaDoPremultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] / 255.0f; uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor); uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor); @@ -751,9 +732,9 @@ template<> void pack<GraphicsContext3D::DataFormatRGBA4444, GraphicsContext3D::A } // FIXME: this routine is lossy and must be removed. -template<> void pack<GraphicsContext3D::DataFormatRGBA4444, GraphicsContext3D::AlphaDoUnmultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA4444, WebGLImageConversion::AlphaDoUnmultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f; uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor); uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor); @@ -767,12 +748,12 @@ template<> void pack<GraphicsContext3D::DataFormatRGBA4444, GraphicsContext3D::A } } -template<> void pack<GraphicsContext3D::DataFormatRGBA5551, GraphicsContext3D::AlphaDoNothing, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA5551, WebGLImageConversion::AlphaDoNothing, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) { #if HAVE(ARM_NEON_INTRINSICS) SIMD::packOneRowOfRGBA8ToUnsignedShort5551(source, destination, pixelsPerRow); #endif - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { *destination = (((source[0] & 0xF8) << 8) | ((source[1] & 0xF8) << 3) | ((source[2] & 0xF8) >> 2) @@ -782,9 +763,9 @@ template<> void pack<GraphicsContext3D::DataFormatRGBA5551, GraphicsContext3D::A } } -template<> void pack<GraphicsContext3D::DataFormatRGBA5551, GraphicsContext3D::AlphaDoPremultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA5551, WebGLImageConversion::AlphaDoPremultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] / 255.0f; uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor); uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor); @@ -799,9 +780,9 @@ template<> void pack<GraphicsContext3D::DataFormatRGBA5551, GraphicsContext3D::A } // FIXME: this routine is lossy and must be removed. -template<> void pack<GraphicsContext3D::DataFormatRGBA5551, GraphicsContext3D::AlphaDoUnmultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA5551, WebGLImageConversion::AlphaDoUnmultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f; uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor); uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor); @@ -815,12 +796,12 @@ template<> void pack<GraphicsContext3D::DataFormatRGBA5551, GraphicsContext3D::A } } -template<> void pack<GraphicsContext3D::DataFormatRGB565, GraphicsContext3D::AlphaDoNothing, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGB565, WebGLImageConversion::AlphaDoNothing, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) { #if HAVE(ARM_NEON_INTRINSICS) SIMD::packOneRowOfRGBA8ToUnsignedShort565(source, destination, pixelsPerRow); #endif - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { *destination = (((source[0] & 0xF8) << 8) | ((source[1] & 0xFC) << 3) | ((source[2] & 0xF8) >> 3)); @@ -829,9 +810,9 @@ template<> void pack<GraphicsContext3D::DataFormatRGB565, GraphicsContext3D::Alp } } -template<> void pack<GraphicsContext3D::DataFormatRGB565, GraphicsContext3D::AlphaDoPremultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGB565, WebGLImageConversion::AlphaDoPremultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] / 255.0f; uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor); uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor); @@ -845,9 +826,9 @@ template<> void pack<GraphicsContext3D::DataFormatRGB565, GraphicsContext3D::Alp } // FIXME: this routine is lossy and must be removed. -template<> void pack<GraphicsContext3D::DataFormatRGB565, GraphicsContext3D::AlphaDoUnmultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGB565, WebGLImageConversion::AlphaDoUnmultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f; uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor); uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor); @@ -860,9 +841,9 @@ template<> void pack<GraphicsContext3D::DataFormatRGB565, GraphicsContext3D::Alp } } -template<> void pack<GraphicsContext3D::DataFormatRGB32F, GraphicsContext3D::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGB32F, WebGLImageConversion::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[0]; destination[1] = source[1]; destination[2] = source[2]; @@ -871,9 +852,9 @@ template<> void pack<GraphicsContext3D::DataFormatRGB32F, GraphicsContext3D::Alp } } -template<> void pack<GraphicsContext3D::DataFormatRGB32F, GraphicsContext3D::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGB32F, WebGLImageConversion::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3]; destination[0] = source[0] * scaleFactor; destination[1] = source[1] * scaleFactor; @@ -883,9 +864,9 @@ template<> void pack<GraphicsContext3D::DataFormatRGB32F, GraphicsContext3D::Alp } } -template<> void pack<GraphicsContext3D::DataFormatRGB32F, GraphicsContext3D::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGB32F, WebGLImageConversion::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f; destination[0] = source[0] * scaleFactor; destination[1] = source[1] * scaleFactor; @@ -896,14 +877,14 @@ template<> void pack<GraphicsContext3D::DataFormatRGB32F, GraphicsContext3D::Alp } // Used only during RGBA8 or BGRA8 -> floating-point uploads. -template<> void pack<GraphicsContext3D::DataFormatRGBA32F, GraphicsContext3D::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA32F, WebGLImageConversion::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { memcpy(destination, source, pixelsPerRow * 4 * sizeof(float)); } -template<> void pack<GraphicsContext3D::DataFormatRGBA32F, GraphicsContext3D::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA32F, WebGLImageConversion::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3]; destination[0] = source[0] * scaleFactor; destination[1] = source[1] * scaleFactor; @@ -914,9 +895,9 @@ template<> void pack<GraphicsContext3D::DataFormatRGBA32F, GraphicsContext3D::Al } } -template<> void pack<GraphicsContext3D::DataFormatRGBA32F, GraphicsContext3D::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA32F, WebGLImageConversion::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f; destination[0] = source[0] * scaleFactor; destination[1] = source[1] * scaleFactor; @@ -927,27 +908,27 @@ template<> void pack<GraphicsContext3D::DataFormatRGBA32F, GraphicsContext3D::Al } } -template<> void pack<GraphicsContext3D::DataFormatA32F, GraphicsContext3D::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatA32F, WebGLImageConversion::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[3]; source += 4; destination += 1; } } -template<> void pack<GraphicsContext3D::DataFormatR32F, GraphicsContext3D::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatR32F, WebGLImageConversion::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[0]; source += 4; destination += 1; } } -template<> void pack<GraphicsContext3D::DataFormatR32F, GraphicsContext3D::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatR32F, WebGLImageConversion::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3]; destination[0] = source[0] * scaleFactor; source += 4; @@ -955,9 +936,9 @@ template<> void pack<GraphicsContext3D::DataFormatR32F, GraphicsContext3D::Alpha } } -template<> void pack<GraphicsContext3D::DataFormatR32F, GraphicsContext3D::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatR32F, WebGLImageConversion::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f; destination[0] = source[0] * scaleFactor; source += 4; @@ -965,9 +946,9 @@ template<> void pack<GraphicsContext3D::DataFormatR32F, GraphicsContext3D::Alpha } } -template<> void pack<GraphicsContext3D::DataFormatRA32F, GraphicsContext3D::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRA32F, WebGLImageConversion::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = source[0]; destination[1] = source[3]; source += 4; @@ -975,9 +956,9 @@ template<> void pack<GraphicsContext3D::DataFormatRA32F, GraphicsContext3D::Alph } } -template<> void pack<GraphicsContext3D::DataFormatRA32F, GraphicsContext3D::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRA32F, WebGLImageConversion::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3]; destination[0] = source[0] * scaleFactor; destination[1] = source[3]; @@ -986,9 +967,9 @@ template<> void pack<GraphicsContext3D::DataFormatRA32F, GraphicsContext3D::Alph } } -template<> void pack<GraphicsContext3D::DataFormatRA32F, GraphicsContext3D::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRA32F, WebGLImageConversion::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow) { - for (unsigned int i = 0; i < pixelsPerRow; ++i) { + for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f; destination[0] = source[0] * scaleFactor; destination[1] = source[3]; @@ -997,7 +978,7 @@ template<> void pack<GraphicsContext3D::DataFormatRA32F, GraphicsContext3D::Alph } } -template<> void pack<GraphicsContext3D::DataFormatRGBA16F, GraphicsContext3D::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA16F, WebGLImageConversion::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) { for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = convertFloatToHalfFloat(source[0]); @@ -1009,7 +990,7 @@ template<> void pack<GraphicsContext3D::DataFormatRGBA16F, GraphicsContext3D::Al } } -template<> void pack<GraphicsContext3D::DataFormatRGBA16F, GraphicsContext3D::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA16F, WebGLImageConversion::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) { for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3]; @@ -1022,7 +1003,7 @@ template<> void pack<GraphicsContext3D::DataFormatRGBA16F, GraphicsContext3D::Al } } -template<> void pack<GraphicsContext3D::DataFormatRGBA16F, GraphicsContext3D::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGBA16F, WebGLImageConversion::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) { for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f; @@ -1035,7 +1016,7 @@ template<> void pack<GraphicsContext3D::DataFormatRGBA16F, GraphicsContext3D::Al } } -template<> void pack<GraphicsContext3D::DataFormatRGB16F, GraphicsContext3D::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGB16F, WebGLImageConversion::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) { for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = convertFloatToHalfFloat(source[0]); @@ -1046,7 +1027,7 @@ template<> void pack<GraphicsContext3D::DataFormatRGB16F, GraphicsContext3D::Alp } } -template<> void pack<GraphicsContext3D::DataFormatRGB16F, GraphicsContext3D::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGB16F, WebGLImageConversion::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) { for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3]; @@ -1058,7 +1039,7 @@ template<> void pack<GraphicsContext3D::DataFormatRGB16F, GraphicsContext3D::Alp } } -template<> void pack<GraphicsContext3D::DataFormatRGB16F, GraphicsContext3D::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRGB16F, WebGLImageConversion::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) { for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f; @@ -1070,7 +1051,7 @@ template<> void pack<GraphicsContext3D::DataFormatRGB16F, GraphicsContext3D::Alp } } -template<> void pack<GraphicsContext3D::DataFormatRA16F, GraphicsContext3D::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRA16F, WebGLImageConversion::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) { for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = convertFloatToHalfFloat(source[0]); @@ -1080,7 +1061,7 @@ template<> void pack<GraphicsContext3D::DataFormatRA16F, GraphicsContext3D::Alph } } -template<> void pack<GraphicsContext3D::DataFormatRA16F, GraphicsContext3D::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRA16F, WebGLImageConversion::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) { for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3]; @@ -1091,7 +1072,7 @@ template<> void pack<GraphicsContext3D::DataFormatRA16F, GraphicsContext3D::Alph } } -template<> void pack<GraphicsContext3D::DataFormatRA16F, GraphicsContext3D::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatRA16F, WebGLImageConversion::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) { for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f; @@ -1102,7 +1083,7 @@ template<> void pack<GraphicsContext3D::DataFormatRA16F, GraphicsContext3D::Alph } } -template<> void pack<GraphicsContext3D::DataFormatR16F, GraphicsContext3D::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatR16F, WebGLImageConversion::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) { for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = convertFloatToHalfFloat(source[0]); @@ -1111,7 +1092,7 @@ template<> void pack<GraphicsContext3D::DataFormatR16F, GraphicsContext3D::Alpha } } -template<> void pack<GraphicsContext3D::DataFormatR16F, GraphicsContext3D::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatR16F, WebGLImageConversion::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) { for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3]; @@ -1121,7 +1102,7 @@ template<> void pack<GraphicsContext3D::DataFormatR16F, GraphicsContext3D::Alpha } } -template<> void pack<GraphicsContext3D::DataFormatR16F, GraphicsContext3D::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatR16F, WebGLImageConversion::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) { for (unsigned i = 0; i < pixelsPerRow; ++i) { float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f; @@ -1131,7 +1112,7 @@ template<> void pack<GraphicsContext3D::DataFormatR16F, GraphicsContext3D::Alpha } } -template<> void pack<GraphicsContext3D::DataFormatA16F, GraphicsContext3D::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) +template<> void pack<WebGLImageConversion::DataFormatA16F, WebGLImageConversion::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow) { for (unsigned i = 0; i < pixelsPerRow; ++i) { destination[0] = convertFloatToHalfFloat(source[3]); @@ -1142,73 +1123,73 @@ template<> void pack<GraphicsContext3D::DataFormatA16F, GraphicsContext3D::Alpha bool HasAlpha(int format) { - return format == GraphicsContext3D::DataFormatA8 - || format == GraphicsContext3D::DataFormatA16F - || format == GraphicsContext3D::DataFormatA32F - || format == GraphicsContext3D::DataFormatRA8 - || format == GraphicsContext3D::DataFormatAR8 - || format == GraphicsContext3D::DataFormatRA16F - || format == GraphicsContext3D::DataFormatRA32F - || format == GraphicsContext3D::DataFormatRGBA8 - || format == GraphicsContext3D::DataFormatBGRA8 - || format == GraphicsContext3D::DataFormatARGB8 - || format == GraphicsContext3D::DataFormatABGR8 - || format == GraphicsContext3D::DataFormatRGBA16F - || format == GraphicsContext3D::DataFormatRGBA32F - || format == GraphicsContext3D::DataFormatRGBA4444 - || format == GraphicsContext3D::DataFormatRGBA5551; + return format == WebGLImageConversion::DataFormatA8 + || format == WebGLImageConversion::DataFormatA16F + || format == WebGLImageConversion::DataFormatA32F + || format == WebGLImageConversion::DataFormatRA8 + || format == WebGLImageConversion::DataFormatAR8 + || format == WebGLImageConversion::DataFormatRA16F + || format == WebGLImageConversion::DataFormatRA32F + || format == WebGLImageConversion::DataFormatRGBA8 + || format == WebGLImageConversion::DataFormatBGRA8 + || format == WebGLImageConversion::DataFormatARGB8 + || format == WebGLImageConversion::DataFormatABGR8 + || format == WebGLImageConversion::DataFormatRGBA16F + || format == WebGLImageConversion::DataFormatRGBA32F + || format == WebGLImageConversion::DataFormatRGBA4444 + || format == WebGLImageConversion::DataFormatRGBA5551; } bool HasColor(int format) { - return format == GraphicsContext3D::DataFormatRGBA8 - || format == GraphicsContext3D::DataFormatRGBA16F - || format == GraphicsContext3D::DataFormatRGBA32F - || format == GraphicsContext3D::DataFormatRGB8 - || format == GraphicsContext3D::DataFormatRGB16F - || format == GraphicsContext3D::DataFormatRGB32F - || format == GraphicsContext3D::DataFormatBGR8 - || format == GraphicsContext3D::DataFormatBGRA8 - || format == GraphicsContext3D::DataFormatARGB8 - || format == GraphicsContext3D::DataFormatABGR8 - || format == GraphicsContext3D::DataFormatRGBA5551 - || format == GraphicsContext3D::DataFormatRGBA4444 - || format == GraphicsContext3D::DataFormatRGB565 - || format == GraphicsContext3D::DataFormatR8 - || format == GraphicsContext3D::DataFormatR16F - || format == GraphicsContext3D::DataFormatR32F - || format == GraphicsContext3D::DataFormatRA8 - || format == GraphicsContext3D::DataFormatRA16F - || format == GraphicsContext3D::DataFormatRA32F - || format == GraphicsContext3D::DataFormatAR8; + return format == WebGLImageConversion::DataFormatRGBA8 + || format == WebGLImageConversion::DataFormatRGBA16F + || format == WebGLImageConversion::DataFormatRGBA32F + || format == WebGLImageConversion::DataFormatRGB8 + || format == WebGLImageConversion::DataFormatRGB16F + || format == WebGLImageConversion::DataFormatRGB32F + || format == WebGLImageConversion::DataFormatBGR8 + || format == WebGLImageConversion::DataFormatBGRA8 + || format == WebGLImageConversion::DataFormatARGB8 + || format == WebGLImageConversion::DataFormatABGR8 + || format == WebGLImageConversion::DataFormatRGBA5551 + || format == WebGLImageConversion::DataFormatRGBA4444 + || format == WebGLImageConversion::DataFormatRGB565 + || format == WebGLImageConversion::DataFormatR8 + || format == WebGLImageConversion::DataFormatR16F + || format == WebGLImageConversion::DataFormatR32F + || format == WebGLImageConversion::DataFormatRA8 + || format == WebGLImageConversion::DataFormatRA16F + || format == WebGLImageConversion::DataFormatRA32F + || format == WebGLImageConversion::DataFormatAR8; } template<int Format> struct IsFloatFormat { static const bool Value = - Format == GraphicsContext3D::DataFormatRGBA32F - || Format == GraphicsContext3D::DataFormatRGB32F - || Format == GraphicsContext3D::DataFormatRA32F - || Format == GraphicsContext3D::DataFormatR32F - || Format == GraphicsContext3D::DataFormatA32F; + Format == WebGLImageConversion::DataFormatRGBA32F + || Format == WebGLImageConversion::DataFormatRGB32F + || Format == WebGLImageConversion::DataFormatRA32F + || Format == WebGLImageConversion::DataFormatR32F + || Format == WebGLImageConversion::DataFormatA32F; }; template<int Format> struct IsHalfFloatFormat { static const bool Value = - Format == GraphicsContext3D::DataFormatRGBA16F - || Format == GraphicsContext3D::DataFormatRGB16F - || Format == GraphicsContext3D::DataFormatRA16F - || Format == GraphicsContext3D::DataFormatR16F - || Format == GraphicsContext3D::DataFormatA16F; + Format == WebGLImageConversion::DataFormatRGBA16F + || Format == WebGLImageConversion::DataFormatRGB16F + || Format == WebGLImageConversion::DataFormatRA16F + || Format == WebGLImageConversion::DataFormatR16F + || Format == WebGLImageConversion::DataFormatA16F; }; template<int Format> struct Is16bppFormat { static const bool Value = - Format == GraphicsContext3D::DataFormatRGBA5551 - || Format == GraphicsContext3D::DataFormatRGBA4444 - || Format == GraphicsContext3D::DataFormatRGB565; + Format == WebGLImageConversion::DataFormatRGBA5551 + || Format == WebGLImageConversion::DataFormatRGBA4444 + || Format == WebGLImageConversion::DataFormatRGB565; }; template<int Format, bool IsFloat = IsFloatFormat<Format>::Value, bool IsHalfFloat = IsHalfFloatFormat<Format>::Value, bool Is16bpp = Is16bppFormat<Format>::Value> @@ -1233,42 +1214,42 @@ struct DataTypeForFormat<Format, false, false, true> { template<int Format> struct IntermediateFormat { - static const int Value = (IsFloatFormat<Format>::Value || IsHalfFloatFormat<Format>::Value) ? GraphicsContext3D::DataFormatRGBA32F : GraphicsContext3D::DataFormatRGBA8; + static const int Value = (IsFloatFormat<Format>::Value || IsHalfFloatFormat<Format>::Value) ? WebGLImageConversion::DataFormatRGBA32F : WebGLImageConversion::DataFormatRGBA8; }; -unsigned TexelBytesForFormat(GraphicsContext3D::DataFormat format) +unsigned TexelBytesForFormat(WebGLImageConversion::DataFormat format) { switch (format) { - case GraphicsContext3D::DataFormatR8: - case GraphicsContext3D::DataFormatA8: + case WebGLImageConversion::DataFormatR8: + case WebGLImageConversion::DataFormatA8: return 1; - case GraphicsContext3D::DataFormatRA8: - case GraphicsContext3D::DataFormatAR8: - case GraphicsContext3D::DataFormatRGBA5551: - case GraphicsContext3D::DataFormatRGBA4444: - case GraphicsContext3D::DataFormatRGB565: - case GraphicsContext3D::DataFormatA16F: - case GraphicsContext3D::DataFormatR16F: + case WebGLImageConversion::DataFormatRA8: + case WebGLImageConversion::DataFormatAR8: + case WebGLImageConversion::DataFormatRGBA5551: + case WebGLImageConversion::DataFormatRGBA4444: + case WebGLImageConversion::DataFormatRGB565: + case WebGLImageConversion::DataFormatA16F: + case WebGLImageConversion::DataFormatR16F: return 2; - case GraphicsContext3D::DataFormatRGB8: - case GraphicsContext3D::DataFormatBGR8: + case WebGLImageConversion::DataFormatRGB8: + case WebGLImageConversion::DataFormatBGR8: return 3; - case GraphicsContext3D::DataFormatRGBA8: - case GraphicsContext3D::DataFormatARGB8: - case GraphicsContext3D::DataFormatABGR8: - case GraphicsContext3D::DataFormatBGRA8: - case GraphicsContext3D::DataFormatR32F: - case GraphicsContext3D::DataFormatA32F: - case GraphicsContext3D::DataFormatRA16F: + case WebGLImageConversion::DataFormatRGBA8: + case WebGLImageConversion::DataFormatARGB8: + case WebGLImageConversion::DataFormatABGR8: + case WebGLImageConversion::DataFormatBGRA8: + case WebGLImageConversion::DataFormatR32F: + case WebGLImageConversion::DataFormatA32F: + case WebGLImageConversion::DataFormatRA16F: return 4; - case GraphicsContext3D::DataFormatRGB16F: + case WebGLImageConversion::DataFormatRGB16F: return 6; - case GraphicsContext3D::DataFormatRA32F: - case GraphicsContext3D::DataFormatRGBA16F: + case WebGLImageConversion::DataFormatRA32F: + case WebGLImageConversion::DataFormatRGBA16F: return 8; - case GraphicsContext3D::DataFormatRGB32F: + case WebGLImageConversion::DataFormatRGB32F: return 12; - case GraphicsContext3D::DataFormatRGBA32F: + case WebGLImageConversion::DataFormatRGBA32F: return 16; default: return 0; @@ -1289,17 +1270,17 @@ public: ASSERT(m_unpackedIntermediateSrcData.get()); } - void convert(GraphicsContext3D::DataFormat srcFormat, GraphicsContext3D::DataFormat dstFormat, GraphicsContext3D::AlphaOp); + void convert(WebGLImageConversion::DataFormat srcFormat, WebGLImageConversion::DataFormat dstFormat, WebGLImageConversion::AlphaOp); bool Success() const { return m_success; } private: - template<GraphicsContext3D::DataFormat SrcFormat> - void convert(GraphicsContext3D::DataFormat dstFormat, GraphicsContext3D::AlphaOp); + template<WebGLImageConversion::DataFormat SrcFormat> + void convert(WebGLImageConversion::DataFormat dstFormat, WebGLImageConversion::AlphaOp); - template<GraphicsContext3D::DataFormat SrcFormat, GraphicsContext3D::DataFormat DstFormat> - void convert(GraphicsContext3D::AlphaOp); + template<WebGLImageConversion::DataFormat SrcFormat, WebGLImageConversion::DataFormat DstFormat> + void convert(WebGLImageConversion::AlphaOp); - template<GraphicsContext3D::DataFormat SrcFormat, GraphicsContext3D::DataFormat DstFormat, GraphicsContext3D::AlphaOp alphaOp> + template<WebGLImageConversion::DataFormat SrcFormat, WebGLImageConversion::DataFormat DstFormat, WebGLImageConversion::AlphaOp alphaOp> void convert(); const unsigned m_width, m_height; @@ -1310,63 +1291,63 @@ private: OwnPtr<uint8_t[]> m_unpackedIntermediateSrcData; }; -void FormatConverter::convert(GraphicsContext3D::DataFormat srcFormat, GraphicsContext3D::DataFormat dstFormat, GraphicsContext3D::AlphaOp alphaOp) +void FormatConverter::convert(WebGLImageConversion::DataFormat srcFormat, WebGLImageConversion::DataFormat dstFormat, WebGLImageConversion::AlphaOp alphaOp) { #define FORMATCONVERTER_CASE_SRCFORMAT(SrcFormat) \ case SrcFormat: \ return convert<SrcFormat>(dstFormat, alphaOp); switch (srcFormat) { - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatR8) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatA8) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatR32F) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatA32F) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRA8) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRA32F) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRGB8) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatBGR8) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRGB565) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRGB32F) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRGBA8) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatARGB8) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatABGR8) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatAR8) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatBGRA8) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRGBA5551) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRGBA4444) - FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRGBA32F) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatR8) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatA8) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatR32F) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatA32F) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRA8) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRA32F) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGB8) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatBGR8) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGB565) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGB32F) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGBA8) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatARGB8) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatABGR8) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatAR8) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatBGRA8) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGBA5551) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGBA4444) + FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGBA32F) default: ASSERT_NOT_REACHED(); } #undef FORMATCONVERTER_CASE_SRCFORMAT } -template<GraphicsContext3D::DataFormat SrcFormat> -void FormatConverter::convert(GraphicsContext3D::DataFormat dstFormat, GraphicsContext3D::AlphaOp alphaOp) +template<WebGLImageConversion::DataFormat SrcFormat> +void FormatConverter::convert(WebGLImageConversion::DataFormat dstFormat, WebGLImageConversion::AlphaOp alphaOp) { #define FORMATCONVERTER_CASE_DSTFORMAT(DstFormat) \ case DstFormat: \ return convert<SrcFormat, DstFormat>(alphaOp); switch (dstFormat) { - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatR8) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatR16F) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatR32F) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatA8) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatA16F) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatA32F) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRA8) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRA16F) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRA32F) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGB8) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGB565) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGB16F) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGB32F) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGBA8) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGBA5551) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGBA4444) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGBA16F) - FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGBA32F) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatR8) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatR16F) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatR32F) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatA8) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatA16F) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatA32F) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRA8) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRA16F) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRA32F) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGB8) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGB565) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGB16F) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGB32F) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA8) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA5551) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA4444) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA16F) + FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA32F) default: ASSERT_NOT_REACHED(); } @@ -1374,29 +1355,29 @@ void FormatConverter::convert(GraphicsContext3D::DataFormat dstFormat, GraphicsC #undef FORMATCONVERTER_CASE_DSTFORMAT } -template<GraphicsContext3D::DataFormat SrcFormat, GraphicsContext3D::DataFormat DstFormat> -void FormatConverter::convert(GraphicsContext3D::AlphaOp alphaOp) +template<WebGLImageConversion::DataFormat SrcFormat, WebGLImageConversion::DataFormat DstFormat> +void FormatConverter::convert(WebGLImageConversion::AlphaOp alphaOp) { #define FORMATCONVERTER_CASE_ALPHAOP(alphaOp) \ case alphaOp: \ return convert<SrcFormat, DstFormat, alphaOp>(); switch (alphaOp) { - FORMATCONVERTER_CASE_ALPHAOP(GraphicsContext3D::AlphaDoNothing) - FORMATCONVERTER_CASE_ALPHAOP(GraphicsContext3D::AlphaDoPremultiply) - FORMATCONVERTER_CASE_ALPHAOP(GraphicsContext3D::AlphaDoUnmultiply) + FORMATCONVERTER_CASE_ALPHAOP(WebGLImageConversion::AlphaDoNothing) + FORMATCONVERTER_CASE_ALPHAOP(WebGLImageConversion::AlphaDoPremultiply) + FORMATCONVERTER_CASE_ALPHAOP(WebGLImageConversion::AlphaDoUnmultiply) default: ASSERT_NOT_REACHED(); } #undef FORMATCONVERTER_CASE_ALPHAOP } -template<GraphicsContext3D::DataFormat SrcFormat, GraphicsContext3D::DataFormat DstFormat, GraphicsContext3D::AlphaOp alphaOp> +template<WebGLImageConversion::DataFormat SrcFormat, WebGLImageConversion::DataFormat DstFormat, WebGLImageConversion::AlphaOp alphaOp> void FormatConverter::convert() { // Many instantiations of this template function will never be entered, so we try // to return immediately in these cases to avoid the compiler to generate useless code. - if (SrcFormat == DstFormat && alphaOp == GraphicsContext3D::AlphaDoNothing) { + if (SrcFormat == DstFormat && alphaOp == WebGLImageConversion::AlphaDoNothing) { ASSERT_NOT_REACHED(); return; } @@ -1406,17 +1387,17 @@ void FormatConverter::convert() } // Only textures uploaded from DOM elements or ImageData can allow DstFormat != SrcFormat. - const bool srcFormatComesFromDOMElementOrImageData = GraphicsContext3D::srcFormatComeFromDOMElementOrImageData(SrcFormat); + const bool srcFormatComesFromDOMElementOrImageData = WebGLImageConversion::srcFormatComeFromDOMElementOrImageData(SrcFormat); if (!srcFormatComesFromDOMElementOrImageData && SrcFormat != DstFormat) { ASSERT_NOT_REACHED(); return; } // Likewise, only textures uploaded from DOM elements or ImageData can possibly have to be unpremultiplied. - if (!srcFormatComesFromDOMElementOrImageData && alphaOp == GraphicsContext3D::AlphaDoUnmultiply) { + if (!srcFormatComesFromDOMElementOrImageData && alphaOp == WebGLImageConversion::AlphaDoUnmultiply) { ASSERT_NOT_REACHED(); return; } - if ((!HasAlpha(SrcFormat) || !HasColor(SrcFormat) || !HasColor(DstFormat)) && alphaOp != GraphicsContext3D::AlphaDoNothing) { + if ((!HasAlpha(SrcFormat) || !HasColor(SrcFormat) || !HasColor(DstFormat)) && alphaOp != WebGLImageConversion::AlphaDoNothing) { ASSERT_NOT_REACHED(); return; } @@ -1427,8 +1408,8 @@ void FormatConverter::convert() typedef typename DataTypeForFormat<IntermediateSrcFormat>::Type IntermediateSrcType; const ptrdiff_t srcStrideInElements = m_srcStride / sizeof(SrcType); const ptrdiff_t dstStrideInElements = m_dstStride / sizeof(DstType); - const bool trivialUnpack = (SrcFormat == GraphicsContext3D::DataFormatRGBA8 && !IsFloatFormat<DstFormat>::Value && !IsHalfFloatFormat<DstFormat>::Value) || SrcFormat == GraphicsContext3D::DataFormatRGBA32F; - const bool trivialPack = (DstFormat == GraphicsContext3D::DataFormatRGBA8 || DstFormat == GraphicsContext3D::DataFormatRGBA32F) && alphaOp == GraphicsContext3D::AlphaDoNothing && m_dstStride > 0; + const bool trivialUnpack = (SrcFormat == WebGLImageConversion::DataFormatRGBA8 && !IsFloatFormat<DstFormat>::Value && !IsHalfFloatFormat<DstFormat>::Value) || SrcFormat == WebGLImageConversion::DataFormatRGBA32F; + const bool trivialPack = (DstFormat == WebGLImageConversion::DataFormatRGBA8 || DstFormat == WebGLImageConversion::DataFormatRGBA32F) && alphaOp == WebGLImageConversion::AlphaDoNothing && m_dstStride > 0; ASSERT(!trivialUnpack || !trivialPack); const SrcType *srcRowStart = static_cast<const SrcType*>(m_srcStart); @@ -1459,11 +1440,222 @@ void FormatConverter::convert() } // anonymous namespace -bool GraphicsContext3D::packImageData( +bool WebGLImageConversion::computeFormatAndTypeParameters(GLenum format, GLenum type, unsigned* componentsPerPixel, unsigned* bytesPerComponent) +{ + switch (format) { + case GL_ALPHA: + case GL_LUMINANCE: + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + *componentsPerPixel = 1; + break; + case GL_LUMINANCE_ALPHA: + *componentsPerPixel = 2; + break; + case GL_RGB: + *componentsPerPixel = 3; + break; + case GL_RGBA: + case GL_BGRA_EXT: // GL_EXT_texture_format_BGRA8888 + *componentsPerPixel = 4; + break; + default: + return false; + } + switch (type) { + case GL_UNSIGNED_BYTE: + *bytesPerComponent = sizeof(GLubyte); + break; + case GL_UNSIGNED_SHORT: + *bytesPerComponent = sizeof(GLushort); + break; + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + *componentsPerPixel = 1; + *bytesPerComponent = sizeof(GLushort); + break; + case GL_UNSIGNED_INT_24_8_OES: + case GL_UNSIGNED_INT: + *bytesPerComponent = sizeof(GLuint); + break; + case GL_FLOAT: // OES_texture_float + *bytesPerComponent = sizeof(GLfloat); + break; + case GL_HALF_FLOAT_OES: // OES_texture_half_float + *bytesPerComponent = sizeof(GLushort); + break; + default: + return false; + } + return true; +} + +GLenum WebGLImageConversion::computeImageSizeInBytes(GLenum format, GLenum type, GLsizei width, GLsizei height, GLint alignment, unsigned* imageSizeInBytes, unsigned* paddingInBytes) +{ + ASSERT(imageSizeInBytes); + ASSERT(alignment == 1 || alignment == 2 || alignment == 4 || alignment == 8); + if (width < 0 || height < 0) + return GL_INVALID_VALUE; + unsigned bytesPerComponent, componentsPerPixel; + if (!computeFormatAndTypeParameters(format, type, &bytesPerComponent, &componentsPerPixel)) + return GL_INVALID_ENUM; + if (!width || !height) { + *imageSizeInBytes = 0; + if (paddingInBytes) + *paddingInBytes = 0; + return GL_NO_ERROR; + } + CheckedInt<uint32_t> checkedValue(bytesPerComponent * componentsPerPixel); + checkedValue *= width; + if (!checkedValue.isValid()) + return GL_INVALID_VALUE; + unsigned validRowSize = checkedValue.value(); + unsigned padding = 0; + unsigned residual = validRowSize % alignment; + if (residual) { + padding = alignment - residual; + checkedValue += padding; + } + // Last row needs no padding. + checkedValue *= (height - 1); + checkedValue += validRowSize; + if (!checkedValue.isValid()) + return GL_INVALID_VALUE; + *imageSizeInBytes = checkedValue.value(); + if (paddingInBytes) + *paddingInBytes = padding; + return GL_NO_ERROR; +} + +WebGLImageConversion::ImageExtractor::ImageExtractor(Image* image, ImageHtmlDomSource imageHtmlDomSource, bool premultiplyAlpha, bool ignoreGammaAndColorProfile) +{ + m_image = image; + m_imageHtmlDomSource = imageHtmlDomSource; + m_extractSucceeded = extractImage(premultiplyAlpha, ignoreGammaAndColorProfile); +} + +WebGLImageConversion::ImageExtractor::~ImageExtractor() +{ + if (m_skiaImage) + m_skiaImage->bitmap().unlockPixels(); +} + +bool WebGLImageConversion::ImageExtractor::extractImage(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) +{ + if (!m_image) + return false; + m_skiaImage = m_image->nativeImageForCurrentFrame(); + m_alphaOp = AlphaDoNothing; + bool hasAlpha = m_skiaImage ? !m_skiaImage->bitmap().isOpaque() : true; + if ((!m_skiaImage || ignoreGammaAndColorProfile || (hasAlpha && !premultiplyAlpha)) && m_image->data()) { + // Attempt to get raw unpremultiplied image data. + OwnPtr<ImageDecoder> decoder(ImageDecoder::create( + *(m_image->data()), ImageSource::AlphaNotPremultiplied, + ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied)); + if (!decoder) + return false; + decoder->setData(m_image->data(), true); + if (!decoder->frameCount()) + return false; + ImageFrame* frame = decoder->frameBufferAtIndex(0); + if (!frame || frame->status() != ImageFrame::FrameComplete) + return false; + hasAlpha = frame->hasAlpha(); + m_nativeImage = frame->asNewNativeImage(); + if (!m_nativeImage.get() || !m_nativeImage->isDataComplete() || !m_nativeImage->bitmap().width() || !m_nativeImage->bitmap().height()) + return false; + if (m_nativeImage->bitmap().colorType() != kPMColor_SkColorType) + return false; + m_skiaImage = m_nativeImage.get(); + if (hasAlpha && premultiplyAlpha) + m_alphaOp = AlphaDoPremultiply; + } else if (!premultiplyAlpha && hasAlpha) { + // 1. For texImage2D with HTMLVideoElment input, assume no PremultiplyAlpha had been applied and the alpha value for each pixel is 0xFF + // which is true at present and may be changed in the future and needs adjustment accordingly. + // 2. For texImage2D with HTMLCanvasElement input in which Alpha is already Premultiplied in this port, + // do AlphaDoUnmultiply if UNPACK_PREMULTIPLY_ALPHA_WEBGL is set to false. + if (m_imageHtmlDomSource != HtmlDomVideo) + m_alphaOp = AlphaDoUnmultiply; + } + if (!m_skiaImage) + return false; + + m_imageSourceFormat = SK_B32_SHIFT ? DataFormatRGBA8 : DataFormatBGRA8; + m_imageWidth = m_skiaImage->bitmap().width(); + m_imageHeight = m_skiaImage->bitmap().height(); + if (!m_imageWidth || !m_imageHeight) { + m_skiaImage.clear(); + return false; + } + // Fail if the image was downsampled because of memory limits. + if (m_imageWidth != (unsigned)m_image->size().width() || m_imageHeight != (unsigned)m_image->size().height()) { + m_skiaImage.clear(); + return false; + } + m_imageSourceUnpackAlignment = 0; + m_skiaImage->bitmap().lockPixels(); + m_imagePixelData = m_skiaImage->bitmap().getPixels(); + return true; +} + +unsigned WebGLImageConversion::getClearBitsByFormat(GLenum format) +{ + switch (format) { + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_RGB: + case GL_RGB565: + case GL_RGBA: + case GL_RGBA4: + case GL_RGB5_A1: + return GL_COLOR_BUFFER_BIT; + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT: + return GL_DEPTH_BUFFER_BIT; + case GL_STENCIL_INDEX8: + return GL_STENCIL_BUFFER_BIT; + case GL_DEPTH_STENCIL_OES: + return GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; + default: + return 0; + } +} + +unsigned WebGLImageConversion::getChannelBitsByFormat(GLenum format) +{ + switch (format) { + case GL_ALPHA: + return ChannelAlpha; + case GL_LUMINANCE: + return ChannelRGB; + case GL_LUMINANCE_ALPHA: + return ChannelRGBA; + case GL_RGB: + case GL_RGB565: + return ChannelRGB; + case GL_RGBA: + case GL_RGBA4: + case GL_RGB5_A1: + return ChannelRGBA; + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT: + return ChannelDepth; + case GL_STENCIL_INDEX8: + return ChannelStencil; + case GL_DEPTH_STENCIL_OES: + return ChannelDepth | ChannelStencil; + default: + return 0; + } +} + +bool WebGLImageConversion::packImageData( Image* image, const void* pixels, - GC3Denum format, - GC3Denum type, + GLenum format, + GLenum type, bool flipY, AlphaOp alphaOp, DataFormat sourceFormat, @@ -1488,11 +1680,11 @@ bool GraphicsContext3D::packImageData( return true; } -bool GraphicsContext3D::extractImageData( +bool WebGLImageConversion::extractImageData( const uint8_t* imageData, const IntSize& imageDataSize, - GC3Denum format, - GC3Denum type, + GLenum format, + GLenum type, bool flipY, bool premultiplyAlpha, Vector<uint8_t>& data) @@ -1514,10 +1706,10 @@ bool GraphicsContext3D::extractImageData( return true; } -bool GraphicsContext3D::extractTextureData( +bool WebGLImageConversion::extractTextureData( unsigned width, unsigned height, - GC3Denum format, GC3Denum type, + GLenum format, GLenum type, unsigned unpackAlignment, bool flipY, bool premultiplyAlpha, const void* pixels, @@ -1539,7 +1731,7 @@ bool GraphicsContext3D::extractTextureData( return true; } -bool GraphicsContext3D::packPixels( +bool WebGLImageConversion::packPixels( const uint8_t* sourceData, DataFormat sourceDataFormat, unsigned width, @@ -1585,4 +1777,3 @@ bool GraphicsContext3D::packPixels( } } // namespace WebCore - diff --git a/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.h b/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.h new file mode 100644 index 00000000000..c595c2d80f7 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.h @@ -0,0 +1,168 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WebGLImageConversion_h +#define WebGLImageConversion_h + +#include "platform/PlatformExport.h" +#include "platform/graphics/Image.h" +#include "third_party/khronos/GLES2/gl2.h" +#include "third_party/khronos/GLES2/gl2ext.h" +#include "wtf/RefPtr.h" + +namespace WebCore { +class Image; +class IntSize; + +// Helper functions for texture uploading and pixel readback. +class PLATFORM_EXPORT WebGLImageConversion { +public: + // Attempt to enumerate all possible native image formats to + // reduce the amount of temporary allocations during texture + // uploading. This enum must be public because it is accessed + // by non-member functions. + enum DataFormat { + DataFormatRGBA8 = 0, + DataFormatRGBA16F, + DataFormatRGBA32F, + DataFormatRGB8, + DataFormatRGB16F, + DataFormatRGB32F, + DataFormatBGR8, + DataFormatBGRA8, + DataFormatARGB8, + DataFormatABGR8, + DataFormatRGBA5551, + DataFormatRGBA4444, + DataFormatRGB565, + DataFormatR8, + DataFormatR16F, + DataFormatR32F, + DataFormatRA8, + DataFormatRA16F, + DataFormatRA32F, + DataFormatAR8, + DataFormatA8, + DataFormatA16F, + DataFormatA32F, + DataFormatNumFormats + }; + + enum ChannelBits { + ChannelRed = 1, + ChannelGreen = 2, + ChannelBlue = 4, + ChannelAlpha = 8, + ChannelDepth = 16, + ChannelStencil = 32, + ChannelRGB = ChannelRed | ChannelGreen | ChannelBlue, + ChannelRGBA = ChannelRGB | ChannelAlpha, + }; + + // Possible alpha operations that may need to occur during + // pixel packing. FIXME: kAlphaDoUnmultiply is lossy and must + // be removed. + enum AlphaOp { + AlphaDoNothing = 0, + AlphaDoPremultiply = 1, + AlphaDoUnmultiply = 2 + }; + + enum ImageHtmlDomSource { + HtmlDomImage = 0, + HtmlDomCanvas = 1, + HtmlDomVideo = 2, + HtmlDomNone = 3 + }; + + class PLATFORM_EXPORT ImageExtractor { + public: + ImageExtractor(Image*, ImageHtmlDomSource, bool premultiplyAlpha, bool ignoreGammaAndColorProfile); + + ~ImageExtractor(); + + bool extractSucceeded() { return m_extractSucceeded; } + const void* imagePixelData() { return m_imagePixelData; } + unsigned imageWidth() { return m_imageWidth; } + unsigned imageHeight() { return m_imageHeight; } + DataFormat imageSourceFormat() { return m_imageSourceFormat; } + AlphaOp imageAlphaOp() { return m_alphaOp; } + unsigned imageSourceUnpackAlignment() { return m_imageSourceUnpackAlignment; } + ImageHtmlDomSource imageHtmlDomSource() { return m_imageHtmlDomSource; } + private: + // Extract the image and keeps track of its status, such as width, height, Source Alignment, format and AlphaOp etc. + // This needs to lock the resources or relevant data if needed and return true upon success + bool extractImage(bool premultiplyAlpha, bool ignoreGammaAndColorProfile); + + RefPtr<NativeImageSkia> m_nativeImage; + RefPtr<NativeImageSkia> m_skiaImage; + Image* m_image; + ImageHtmlDomSource m_imageHtmlDomSource; + bool m_extractSucceeded; + const void* m_imagePixelData; + unsigned m_imageWidth; + unsigned m_imageHeight; + DataFormat m_imageSourceFormat; + AlphaOp m_alphaOp; + unsigned m_imageSourceUnpackAlignment; + }; + + // Computes the components per pixel and bytes per component + // for the given format and type combination. Returns false if + // either was an invalid enum. + static bool computeFormatAndTypeParameters(GLenum format, GLenum type, unsigned* componentsPerPixel, unsigned* bytesPerComponent); + + // Computes the image size in bytes. If paddingInBytes is not null, padding + // is also calculated in return. Returns NO_ERROR if succeed, otherwise + // return the suggested GL error indicating the cause of the failure: + // INVALID_VALUE if width/height is negative or overflow happens. + // INVALID_ENUM if format/type is illegal. + static GLenum computeImageSizeInBytes(GLenum format, GLenum type, GLsizei width, GLsizei height, GLint alignment, unsigned* imageSizeInBytes, unsigned* paddingInBytes); + + // Check if the format is one of the formats from the ImageData or DOM elements. + // The formats from ImageData is always RGBA8. + // The formats from DOM elements vary with Graphics ports. It can only be RGBA8 or BGRA8. + static ALWAYS_INLINE bool srcFormatComeFromDOMElementOrImageData(DataFormat SrcFormat) + { + return SrcFormat == DataFormatBGRA8 || SrcFormat == DataFormatRGBA8; + } + + static unsigned getClearBitsByFormat(GLenum); + static unsigned getChannelBitsByFormat(GLenum); + + // The Following functions are implemented in GraphicsContext3DImagePacking.cpp + + // Packs the contents of the given Image which is passed in |pixels| into the passed Vector + // according to the given format and type, and obeying the flipY and AlphaOp flags. + // Returns true upon success. + static bool packImageData(Image*, const void* pixels, GLenum format, GLenum type, bool flipY, AlphaOp, DataFormat sourceFormat, unsigned width, unsigned height, unsigned sourceUnpackAlignment, Vector<uint8_t>& data); + + // Extracts the contents of the given ImageData into the passed Vector, + // packing the pixel data according to the given format and type, + // and obeying the flipY and premultiplyAlpha flags. Returns true + // upon success. + static bool extractImageData(const uint8_t*, const IntSize&, GLenum format, GLenum type, bool flipY, bool premultiplyAlpha, Vector<uint8_t>& data); + + // Helper function which extracts the user-supplied texture + // data, applying the flipY and premultiplyAlpha parameters. + // If the data is not tightly packed according to the passed + // unpackAlignment, the output data will be tightly packed. + // Returns true if successful, false if any error occurred. + static bool extractTextureData(unsigned width, unsigned height, GLenum format, GLenum type, unsigned unpackAlignment, bool flipY, bool premultiplyAlpha, const void* pixels, Vector<uint8_t>& data); + + // End GraphicsContext3DImagePacking.cpp functions + +private: + // Helper for packImageData/extractImageData/extractTextureData which implement packing of pixel + // data into the specified OpenGL destination format and type. + // A sourceUnpackAlignment of zero indicates that the source + // data is tightly packed. Non-zero values may take a slow path. + // Destination data will have no gaps between rows. + // Implemented in GraphicsContext3DImagePacking.cpp + static bool packPixels(const uint8_t* sourceData, DataFormat sourceDataFormat, unsigned width, unsigned height, unsigned sourceUnpackAlignment, unsigned destinationFormat, unsigned destinationType, AlphaOp, void* destinationData, bool flipY); +}; + +} // namespace WebCore + +#endif // WebGLImageConversion_h diff --git a/chromium/third_party/WebKit/Source/platform/graphics/media/MediaPlayer.h b/chromium/third_party/WebKit/Source/platform/graphics/media/MediaPlayer.h index dba4c80d321..182feb7eb5e 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/media/MediaPlayer.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/media/MediaPlayer.h @@ -28,30 +28,35 @@ #include "platform/PlatformExport.h" #include "platform/graphics/GraphicsTypes3D.h" +#include "public/platform/WebMediaPlayer.h" #include "wtf/Forward.h" #include "wtf/Noncopyable.h" namespace blink { +class WebGraphicsContext3D; +class WebContentDecryptionModule; class WebInbandTextTrack; class WebLayer; +class WebMediaSource; } namespace WebCore { class AudioSourceProvider; class GraphicsContext; -class GraphicsContext3D; class IntRect; -class IntSize; class KURL; class MediaPlayer; -class HTMLMediaSource; class TimeRanges; +// GL types as defined in OpenGL ES 2.0 header file gl2.h from khronos.org. +// That header cannot be included directly due to a conflict with NPAPI headers. +// See crbug.com/328085. +typedef unsigned GC3Denum; +typedef int GC3Dint; + class MediaPlayerClient { public: - enum CORSMode { Unspecified, Anonymous, UseCredentials }; - virtual ~MediaPlayerClient() { } // the network state has changed @@ -73,6 +78,10 @@ public: virtual void mediaPlayerRequestSeek(double) = 0; + // The URL for video poster image. + // FIXME: Remove this when WebMediaPlayerClientImpl::loadInternal does not depend on it. + virtual KURL mediaPlayerPosterURL() = 0; + // Presentation-related methods // a new frame of video is available virtual void mediaPlayerRepaint() = 0; @@ -80,20 +89,12 @@ public: // the movie size has changed virtual void mediaPlayerSizeChanged() = 0; - enum MediaKeyErrorCode { UnknownError = 1, ClientError, ServiceError, OutputError, HardwareChangeError, DomainError }; - virtual void mediaPlayerKeyAdded(const String& /* keySystem */, const String& /* sessionId */) = 0; - virtual void mediaPlayerKeyError(const String& /* keySystem */, const String& /* sessionId */, MediaKeyErrorCode, unsigned short /* systemCode */) = 0; - virtual void mediaPlayerKeyMessage(const String& /* keySystem */, const String& /* sessionId */, const unsigned char* /* message */, unsigned /* messageLength */, const KURL& /* defaultURL */) = 0; - virtual bool mediaPlayerKeyNeeded(const String& /* keySystem */, const String& /* sessionId */, const unsigned char* /* initData */, unsigned /* initDataLength */) = 0; - virtual bool mediaPlayerKeyNeeded(Uint8Array*) = 0; - - virtual CORSMode mediaPlayerCORSMode() const = 0; - virtual void mediaPlayerSetWebLayer(blink::WebLayer*) = 0; - virtual void mediaPlayerSetOpaque(bool) = 0; - virtual void mediaPlayerDidAddTrack(blink::WebInbandTextTrack*) = 0; - virtual void mediaPlayerDidRemoveTrack(blink::WebInbandTextTrack*) = 0; + virtual void mediaPlayerDidAddTextTrack(blink::WebInbandTextTrack*) = 0; + virtual void mediaPlayerDidRemoveTextTrack(blink::WebInbandTextTrack*) = 0; + + virtual void mediaPlayerMediaSourceOpened(blink::WebMediaSource*) = 0; }; typedef PassOwnPtr<MediaPlayer> (*CreateMediaEnginePlayer)(MediaPlayerClient*); @@ -109,20 +110,12 @@ public: MediaPlayer() { } virtual ~MediaPlayer() { } - virtual void load(const String& url) = 0; - virtual void load(const String& url, PassRefPtr<HTMLMediaSource>) = 0; - - virtual void prepareToPlay() = 0; + virtual void load(blink::WebMediaPlayer::LoadType, const String& url, blink::WebMediaPlayer::CORSMode) = 0; virtual void play() = 0; virtual void pause() = 0; - virtual bool supportsFullscreen() const = 0; virtual bool supportsSave() const = 0; - virtual IntSize naturalSize() const = 0; - - virtual bool hasVideo() const = 0; - virtual bool hasAudio() const = 0; virtual double duration() const = 0; @@ -137,52 +130,32 @@ public: virtual bool paused() const = 0; - virtual void setVolume(double) = 0; - virtual void setMuted(bool) = 0; + virtual void setPoster(const KURL&) = 0; enum NetworkState { Empty, Idle, Loading, Loaded, FormatError, NetworkError, DecodeError }; virtual NetworkState networkState() const = 0; - enum ReadyState { HaveNothing, HaveMetadata, HaveCurrentData, HaveFutureData, HaveEnoughData }; - virtual ReadyState readyState() const = 0; - virtual double maxTimeSeekable() const = 0; virtual PassRefPtr<TimeRanges> buffered() const = 0; virtual bool didLoadingProgress() const = 0; virtual void paint(GraphicsContext*, const IntRect&) = 0; - virtual bool copyVideoTextureToPlatformTexture(GraphicsContext3D*, Platform3DObject, GC3Dint, GC3Denum, GC3Denum, bool, bool) = 0; + virtual bool copyVideoTextureToPlatformTexture(blink::WebGraphicsContext3D*, Platform3DObject, GC3Dint, GC3Denum, GC3Denum, bool, bool) = 0; enum Preload { None, MetaData, Auto }; virtual void setPreload(Preload) = 0; - virtual void showFullscreenOverlay() = 0; - virtual void hideFullscreenOverlay() = 0; - virtual bool canShowFullscreenOverlay() const = 0; - virtual bool hasSingleSecurityOrigin() const = 0; - virtual bool didPassCORSAccessCheck() const = 0; - // Time value in the movie's time scale. It is only necessary to override this if the media // engine uses rational numbers to represent media time. virtual double mediaTimeForTimeValue(double timeValue) const = 0; - virtual unsigned decodedFrameCount() const = 0; - virtual unsigned droppedFrameCount() const = 0; - virtual unsigned corruptedFrameCount() const = 0; - virtual unsigned audioDecodedByteCount() const = 0; - virtual unsigned videoDecodedByteCount() const = 0; - #if ENABLE(WEB_AUDIO) virtual AudioSourceProvider* audioSourceProvider() = 0; #endif - - enum MediaKeyException { NoError, InvalidPlayerState, KeySystemNotSupported, InvalidAccess }; - virtual MediaKeyException addKey(const String&, const unsigned char*, unsigned, const unsigned char*, unsigned, const String&) = 0; - virtual MediaKeyException generateKeyRequest(const String&, const unsigned char*, unsigned) = 0; - virtual MediaKeyException cancelKeyRequest(const String&, const String&) = 0; + virtual blink::WebMediaPlayer* webMediaPlayer() const = 0; }; } diff --git a/chromium/third_party/WebKit/Source/platform/graphics/skia/GaneshUtils.cpp b/chromium/third_party/WebKit/Source/platform/graphics/skia/GaneshUtils.cpp index 149137e441d..19088745806 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/skia/GaneshUtils.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/skia/GaneshUtils.cpp @@ -61,8 +61,8 @@ bool ensureTextureBackedSkBitmap(GrContext* gr, SkBitmap& bitmap, const IntSize& SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, texture.get())); if (!pixelRef) return false; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height()); - bitmap.setPixelRef(pixelRef, 0)->unref(); + bitmap.setInfo(info); + bitmap.setPixelRef(pixelRef)->unref(); } return true; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/skia/NativeImageSkia.cpp b/chromium/third_party/WebKit/Source/platform/graphics/skia/NativeImageSkia.cpp index 969d23549f9..f0db318605e 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/skia/NativeImageSkia.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/skia/NativeImageSkia.cpp @@ -46,6 +46,7 @@ #include "third_party/skia/include/core/SkScalar.h" #include "third_party/skia/include/core/SkShader.h" +#include <algorithm> #include <math.h> #include <limits> @@ -56,7 +57,7 @@ static bool nearlyIntegral(float value) return fabs(value - floorf(value)) < std::numeric_limits<float>::epsilon(); } -ResamplingMode NativeImageSkia::computeResamplingMode(const SkMatrix& matrix, float srcWidth, float srcHeight, float destWidth, float destHeight) const +InterpolationQuality NativeImageSkia::computeInterpolationQuality(const SkMatrix& matrix, float srcWidth, float srcHeight, float destWidth, float destHeight) const { // The percent change below which we will not resample. This usually means // an off-by-one error on the web page, and just doing nearest neighbor @@ -81,7 +82,7 @@ ResamplingMode NativeImageSkia::computeResamplingMode(const SkMatrix& matrix, fl bool heightNearlyEqual = diffHeight < std::numeric_limits<float>::epsilon(); // We don't need to resample if the source and destination are the same. if (widthNearlyEqual && heightNearlyEqual) - return NoResampling; + return InterpolationNone; if (srcWidth <= kSmallImageSizeThreshold || srcHeight <= kSmallImageSizeThreshold @@ -94,11 +95,11 @@ ResamplingMode NativeImageSkia::computeResamplingMode(const SkMatrix& matrix, fl // when the source image is only one pixel wide in that dimension. if ((!nearlyIntegral(destWidth) && srcWidth > 1 + std::numeric_limits<float>::epsilon()) || (!nearlyIntegral(destHeight) && srcHeight > 1 + std::numeric_limits<float>::epsilon())) - return LinearResampling; + return InterpolationLow; // Otherwise, don't resample small images. These are often used for // borders and rules (think 1x1 images used to make lines). - return NoResampling; + return InterpolationNone; } if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= destWidth) { @@ -109,11 +110,11 @@ ResamplingMode NativeImageSkia::computeResamplingMode(const SkMatrix& matrix, fl // (which might be large) and then is stretching it to fill some part // of the page. if (widthNearlyEqual || heightNearlyEqual) - return NoResampling; + return InterpolationNone; // The image is growing a lot and in more than one direction. Resampling // is slow and doesn't give us very much when growing a lot. - return LinearResampling; + return InterpolationLow; } if ((diffWidth / srcWidth < kFractionalChangeThreshold) @@ -121,40 +122,40 @@ ResamplingMode NativeImageSkia::computeResamplingMode(const SkMatrix& matrix, fl // It is disappointingly common on the web for image sizes to be off by // one or two pixels. We don't bother resampling if the size difference // is a small fraction of the original size. - return NoResampling; + return InterpolationNone; } // When the image is not yet done loading, use linear. We don't cache the // partially resampled images, and as they come in incrementally, it causes // us to have to resample the whole thing every time. if (!isDataComplete()) - return LinearResampling; + return InterpolationLow; // Everything else gets resampled. // High quality interpolation only enabled for scaling and translation. if (!(matrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask))) - return AwesomeResampling; + return InterpolationHigh; - return LinearResampling; + return InterpolationLow; } -static ResamplingMode limitResamplingMode(GraphicsContext* context, ResamplingMode resampling) +static InterpolationQuality limitInterpolationQuality(GraphicsContext* context, InterpolationQuality resampling) { - switch (context->imageInterpolationQuality()) { - case InterpolationNone: - return NoResampling; - case InterpolationMedium: - // For now we treat InterpolationMedium and InterpolationLow the same. - case InterpolationLow: - if (resampling == AwesomeResampling) - return LinearResampling; - break; - case InterpolationHigh: - case InterpolationDefault: - break; - } + return std::min(resampling, context->imageInterpolationQuality()); +} + +static SkPaint::FilterLevel convertToSkiaFilterLevel(bool useBicubicFilter, InterpolationQuality resampling) +{ + // FIXME: If we get rid of this special case, this function can go away entirely. + if (useBicubicFilter) + return SkPaint::kHigh_FilterLevel; + + // InterpolationHigh if useBicubicFilter is false means that we do + // a manual high quality resampling before drawing to Skia. + if (resampling == InterpolationHigh) + return SkPaint::kNone_FilterLevel; - return resampling; + return static_cast<SkPaint::FilterLevel>(resampling); } // This function is used to scale an image and extract a scaled fragment. @@ -223,6 +224,8 @@ SkBitmap NativeImageSkia::extractScaledImageFragment(const SkRect& srcRect, floa void NativeImageSkia::drawResampledBitmap(GraphicsContext* context, SkPaint& paint, const SkRect& srcRect, const SkRect& destRect) const { TRACE_EVENT0("skia", "drawResampledBitmap"); + if (context->paintingDisabled()) + return; // We want to scale |destRect| with transformation in the canvas to obtain // the final scale. The final scale is a combination of scale transform // in canvas and explicit scaling (srcRect and destRect). @@ -233,7 +236,8 @@ void NativeImageSkia::drawResampledBitmap(GraphicsContext* context, SkPaint& pai // This part of code limits scaling only to visible portion in the SkRect destRectVisibleSubset; - ClipRectToCanvas(context, destRect, &destRectVisibleSubset); + if (!context->canvas()->getClipBounds(&destRectVisibleSubset)) + return; // ClipRectToCanvas often overshoots, resulting in a larger region than our // original destRect. Intersecting gets us back inside. @@ -295,6 +299,8 @@ SkBitmap NativeImageSkia::resizedBitmap(const SkISize& scaledImageSize, const Sk bool shouldCache = isDataComplete() && shouldCacheResampling(scaledImageSize, scaledImageSubset); + TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ResizeImage", "cached", shouldCache); + // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. PlatformInstrumentation::willResizeImage(shouldCache); SkBitmap resizedImage = skia::ImageOperations::Resize(m_image, skia::ImageOperations::RESIZE_LANCZOS3, scaledImageSize.width(), scaledImageSize.height(), scaledImageSubset); resizedImage.setImmutable(); @@ -312,9 +318,33 @@ SkBitmap NativeImageSkia::resizedBitmap(const SkISize& scaledImageSize, const Sk return resizedSubset; } -static bool hasNon90rotation(GraphicsContext* context) +static bool shouldDrawAntiAliased(GraphicsContext* context, const SkRect& destRect) { - return !context->getTotalMatrix().rectStaysRect(); + if (!context->shouldAntialias()) + return false; + const SkMatrix totalMatrix = context->getTotalMatrix(); + // Don't disable anti-aliasing if we're rotated or skewed. + if (!totalMatrix.rectStaysRect()) + return true; + // Disable anti-aliasing for scales or n*90 degree rotations. + // Allow to opt out of the optimization though for "hairline" geometry + // images - using the shouldAntialiasHairlineImages() GraphicsContext flag. + if (!context->shouldAntialiasHairlineImages()) + return false; + // Check if the dimensions of the destination are "small" (less than one + // device pixel). To prevent sudden drop-outs. Since we know that + // kRectStaysRect_Mask is set, the matrix either has scale and no skew or + // vice versa. We can query the kAffine_Mask flag to determine which case + // it is. + // FIXME: This queries the CTM while drawing, which is generally + // discouraged. Always drawing with AA can negatively impact performance + // though - that's why it's not always on. + SkScalar widthExpansion, heightExpansion; + if (totalMatrix.getType() & SkMatrix::kAffine_Mask) + widthExpansion = totalMatrix[SkMatrix::kMSkewY], heightExpansion = totalMatrix[SkMatrix::kMSkewX]; + else + widthExpansion = totalMatrix[SkMatrix::kMScaleX], heightExpansion = totalMatrix[SkMatrix::kMScaleY]; + return destRect.width() * fabs(widthExpansion) < 1 || destRect.height() * fabs(heightExpansion) < 1; } void NativeImageSkia::draw(GraphicsContext* context, const SkRect& srcRect, const SkRect& destRect, PassRefPtr<SkXfermode> compOp) const @@ -325,14 +355,17 @@ void NativeImageSkia::draw(GraphicsContext* context, const SkRect& srcRect, cons paint.setColorFilter(context->colorFilter()); paint.setAlpha(context->getNormalizedAlpha()); paint.setLooper(context->drawLooper()); - // only antialias if we're rotated or skewed - paint.setAntiAlias(hasNon90rotation(context)); + paint.setAntiAlias(shouldDrawAntiAliased(context, destRect)); - ResamplingMode resampling; + bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap()); + + InterpolationQuality resampling; if (context->isAccelerated()) { - resampling = LinearResampling; + resampling = InterpolationLow; } else if (context->printing()) { - resampling = NoResampling; + resampling = InterpolationNone; + } else if (isLazyDecoded) { + resampling = InterpolationHigh; } else { // Take into account scale applied to the canvas when computing sampling mode (e.g. CSS scale or page scale). SkRect destRectTarget = destRect; @@ -340,30 +373,27 @@ void NativeImageSkia::draw(GraphicsContext* context, const SkRect& srcRect, cons if (!(totalMatrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask))) totalMatrix.mapRect(&destRectTarget, destRect); - resampling = computeResamplingMode(totalMatrix, + resampling = computeInterpolationQuality(totalMatrix, SkScalarToFloat(srcRect.width()), SkScalarToFloat(srcRect.height()), SkScalarToFloat(destRectTarget.width()), SkScalarToFloat(destRectTarget.height())); } - if (resampling == NoResampling) { + if (resampling == InterpolationNone) { // FIXME: This is to not break tests (it results in the filter bitmap flag - // being set to true). We need to decide if we respect NoResampling - // being returned from computeResamplingMode. - resampling = LinearResampling; + // being set to true). We need to decide if we respect InterpolationNone + // being returned from computeInterpolationQuality. + resampling = InterpolationLow; } - resampling = limitResamplingMode(context, resampling); - paint.setFilterBitmap(resampling == LinearResampling); + resampling = limitInterpolationQuality(context, resampling); - bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap()); // FIXME: Bicubic filtering in Skia is only applied to defer-decoded images // as an experiment. Once this filtering code path becomes stable we should // turn this on for all cases, including non-defer-decoded images. - bool useBicubicFilter = resampling == AwesomeResampling && isLazyDecoded; + bool useBicubicFilter = resampling == InterpolationHigh && isLazyDecoded; - if (useBicubicFilter) - paint.setFilterLevel(SkPaint::kHigh_FilterLevel); + paint.setFilterLevel(convertToSkiaFilterLevel(useBicubicFilter, resampling)); - if (resampling == AwesomeResampling && !useBicubicFilter) { + if (resampling == InterpolationHigh && !useBicubicFilter) { // Resample the image and then draw the result to canvas with bilinear // filtering. drawResampledBitmap(context, paint, srcRect, destRect); @@ -381,12 +411,13 @@ void NativeImageSkia::draw(GraphicsContext* context, const SkRect& srcRect, cons static SkBitmap createBitmapWithSpace(const SkBitmap& bitmap, int spaceWidth, int spaceHeight) { - SkBitmap result; - result.setConfig(bitmap.config(), - bitmap.width() + spaceWidth, - bitmap.height() + spaceHeight); - result.allocPixels(); + SkImageInfo info = bitmap.info(); + info.fWidth += spaceWidth; + info.fHeight += spaceHeight; + info.fAlphaType = kPremul_SkAlphaType; + SkBitmap result; + result.allocPixels(info); result.eraseColor(SK_ColorTRANSPARENT); bitmap.copyPixelsTo(reinterpret_cast<uint8_t*>(result.getPixels()), result.rowBytes() * result.height(), result.rowBytes()); @@ -409,8 +440,9 @@ void NativeImageSkia::drawPattern( return; // nothing to draw SkMatrix totalMatrix = context->getTotalMatrix(); - SkScalar ctmScaleX = totalMatrix.getScaleX(); - SkScalar ctmScaleY = totalMatrix.getScaleY(); + AffineTransform ctm = context->getCTM(); + SkScalar ctmScaleX = ctm.xScale(); + SkScalar ctmScaleY = ctm.yScale(); totalMatrix.preScale(scale.width(), scale.height()); // Figure out what size the bitmap will be in the destination. The @@ -422,82 +454,82 @@ void NativeImageSkia::drawPattern( float destBitmapWidth = SkScalarToFloat(destRectTarget.width()); float destBitmapHeight = SkScalarToFloat(destRectTarget.height()); + bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap()); + // Compute the resampling mode. - ResamplingMode resampling; + InterpolationQuality resampling; if (context->isAccelerated() || context->printing()) - resampling = LinearResampling; + resampling = InterpolationLow; + else if (isLazyDecoded) + resampling = InterpolationHigh; else - resampling = computeResamplingMode(totalMatrix, normSrcRect.width(), normSrcRect.height(), destBitmapWidth, destBitmapHeight); - resampling = limitResamplingMode(context, resampling); + resampling = computeInterpolationQuality(totalMatrix, normSrcRect.width(), normSrcRect.height(), destBitmapWidth, destBitmapHeight); + resampling = limitInterpolationQuality(context, resampling); + + SkMatrix localMatrix; + // We also need to translate it such that the origin of the pattern is the + // origin of the destination rect, which is what WebKit expects. Skia uses + // the coordinate system origin as the base for the pattern. If WebKit wants + // a shifted image, it will shift it from there using the localMatrix. + const float adjustedX = phase.x() + normSrcRect.x() * scale.width(); + const float adjustedY = phase.y() + normSrcRect.y() * scale.height(); + localMatrix.setTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjustedY)); - SkMatrix shaderTransform; RefPtr<SkShader> shader; - bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap()); // Bicubic filter is only applied to defer-decoded images, see // NativeImageSkia::draw for details. - bool useBicubicFilter = resampling == AwesomeResampling && isLazyDecoded; + bool useBicubicFilter = resampling == InterpolationHigh && isLazyDecoded; - if (resampling == AwesomeResampling && !useBicubicFilter) { + if (resampling == InterpolationHigh && !useBicubicFilter) { // Do nice resampling. float scaleX = destBitmapWidth / normSrcRect.width(); float scaleY = destBitmapHeight / normSrcRect.height(); SkRect scaledSrcRect; + // Since we are resizing the bitmap, we need to remove the scale + // applied to the pixels in the bitmap shader. This means we need + // CTM * localMatrix to have identity scale. Since we + // can't modify CTM (or the rectangle will be drawn in the wrong + // place), we must set localMatrix's scale to the inverse of + // CTM scale. + localMatrix.preScale(ctmScaleX ? 1 / ctmScaleX : 1, ctmScaleY ? 1 / ctmScaleY : 1); + // The image fragment generated here is not exactly what is // requested. The scale factor used is approximated and image // fragment is slightly larger to align to integer // boundaries. SkBitmap resampled = extractScaledImageFragment(normSrcRect, scaleX, scaleY, &scaledSrcRect); if (repeatSpacing.isZero()) { - shader = adoptRef(SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); + shader = adoptRef(SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix)); } else { shader = adoptRef(SkShader::CreateBitmapShader( createBitmapWithSpace(resampled, repeatSpacing.width() * ctmScaleX, repeatSpacing.height() * ctmScaleY), - SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); + SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix)); } - - // Since we just resized the bitmap, we need to remove the scale - // applied to the pixels in the bitmap shader. This means we need - // CTM * shaderTransform to have identity scale. Since we - // can't modify CTM (or the rectangle will be drawn in the wrong - // place), we must set shaderTransform's scale to the inverse of - // CTM scale. - shaderTransform.setScale(ctmScaleX ? 1 / ctmScaleX : 1, ctmScaleY ? 1 / ctmScaleY : 1); } else { + // Because no resizing occurred, the shader transform should be + // set to the pattern's transform, which just includes scale. + localMatrix.preScale(scale.width(), scale.height()); + // No need to resample before drawing. SkBitmap srcSubset; bitmap().extractSubset(&srcSubset, enclosingIntRect(normSrcRect)); if (repeatSpacing.isZero()) { - shader = adoptRef(SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); + shader = adoptRef(SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix)); } else { shader = adoptRef(SkShader::CreateBitmapShader( createBitmapWithSpace(srcSubset, repeatSpacing.width() * ctmScaleX, repeatSpacing.height() * ctmScaleY), - SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); + SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix)); } - - // Because no resizing occurred, the shader transform should be - // set to the pattern's transform, which just includes scale. - shaderTransform.setScale(scale.width(), scale.height()); } - // We also need to translate it such that the origin of the pattern is the - // origin of the destination rect, which is what WebKit expects. Skia uses - // the coordinate system origin as the base for the pattern. If WebKit wants - // a shifted image, it will shift it from there using the shaderTransform. - float adjustedX = phase.x() + normSrcRect.x() * scale.width(); - float adjustedY = phase.y() + normSrcRect.y() * scale.height(); - shaderTransform.postTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjustedY)); - shader->setLocalMatrix(shaderTransform); - SkPaint paint; paint.setShader(shader.get()); paint.setXfermode(WebCoreCompositeToSkiaComposite(compositeOp, blendMode).get()); paint.setColorFilter(context->colorFilter()); + paint.setFilterLevel(convertToSkiaFilterLevel(useBicubicFilter, resampling)); - paint.setFilterBitmap(resampling == LinearResampling); - if (useBicubicFilter) - paint.setFilterLevel(SkPaint::kHigh_FilterLevel); if (isLazyDecoded) PlatformInstrumentation::didDrawLazyPixelRef(bitmap().getGenerationID()); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/skia/NativeImageSkia.h b/chromium/third_party/WebKit/Source/platform/graphics/skia/NativeImageSkia.h index 97b7bcd76bd..aebf1d1a4b8 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/skia/NativeImageSkia.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/skia/NativeImageSkia.h @@ -52,20 +52,6 @@ class FloatRect; class FloatSize; class GraphicsContext; -// Used by computeResamplingMode to tell how bitmaps should be resampled. -enum ResamplingMode { - // Nearest neighbor resampling. Used when we detect that the page is - // trying to make a pattern by stretching a small bitmap very large. - NoResampling, - - // Default skia resampling. Used for large growing of images where high - // quality resampling doesn't get us very much except a slowdown. - LinearResampling, - - // High quality resampling. - AwesomeResampling, -}; - // This object is used as the "native image" in our port. When WebKit uses // PassNativeImagePtr / NativeImagePtr, it is a smart pointer to this type. // It has an SkBitmap, and also stores a cached resized image. @@ -98,18 +84,11 @@ public: // resized version if there is one. int decodedSize() const; - // Sets the immutable flag on the bitmap, indicating that the image data - // will not be modified any further. This is called by the image decoder - // when all data is complete, used by us to know whether we can cache - // resized images, and used by Skia for various optimizations. - void setDataComplete() { m_image.setImmutable(); } - // Returns true if the entire image has been decoded. bool isDataComplete() const { return m_image.isImmutable(); } // Get reference to the internal SkBitmap representing this image. const SkBitmap& bitmap() const { return m_image; } - SkBitmap& bitmap() { return m_image; } // We can keep a resized version of the bitmap cached on this object. // This function will return true if there is a cached version of the given @@ -173,7 +152,7 @@ private: // entire thing, it's best to just do it up front. bool shouldCacheResampling(const SkISize& scaledImageSize, const SkIRect& scaledImageSubset) const; - ResamplingMode computeResamplingMode(const SkMatrix&, float srcWidth, float srcHeight, float destWidth, float destHeight) const; + InterpolationQuality computeInterpolationQuality(const SkMatrix&, float srcWidth, float srcHeight, float destWidth, float destHeight) const; SkBitmap extractScaledImageFragment(const SkRect& srcRect, float scaleX, float scaleY, SkRect* scaledSrcRect) const; void drawResampledBitmap(GraphicsContext*, SkPaint&, const SkRect& srcRect, const SkRect& destRect) const; diff --git a/chromium/third_party/WebKit/Source/platform/graphics/skia/OpaqueRegionSkia.cpp b/chromium/third_party/WebKit/Source/platform/graphics/skia/OpaqueRegionSkia.cpp index 060b1754c97..d0976723bd9 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/skia/OpaqueRegionSkia.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/skia/OpaqueRegionSkia.cpp @@ -47,10 +47,13 @@ OpaqueRegionSkia::OpaqueRegionSkia() IntRect OpaqueRegionSkia::asRect() const { // Returns the largest enclosed rect. - int left = SkScalarCeil(m_opaqueRect.fLeft); - int top = SkScalarCeil(m_opaqueRect.fTop); - int right = SkScalarFloor(m_opaqueRect.fRight); - int bottom = SkScalarFloor(m_opaqueRect.fBottom); + // TODO: actually, this logic looks like its returning the smallest. + // to return largest, shouldn't we take floor of left/top + // and the ceil of right/bottom? + int left = SkScalarCeilToInt(m_opaqueRect.fLeft); + int top = SkScalarCeilToInt(m_opaqueRect.fTop); + int right = SkScalarFloorToInt(m_opaqueRect.fRight); + int bottom = SkScalarFloorToInt(m_opaqueRect.fBottom); return IntRect(left, top, right-left, bottom-top); } @@ -147,7 +150,7 @@ static inline bool paintIsOpaque(const SkPaint& paint, OpaqueRegionSkia::DrawTyp static inline bool getDeviceClipAsRect(const GraphicsContext* context, SkRect& deviceClipRect) { // Get the current clip in device coordinate space. - if (context->canvas()->getClipType() != SkCanvas::kRect_ClipType) + if (!context->canvas()->isClipRect()) return false; SkIRect deviceClipIRect; @@ -169,6 +172,7 @@ void OpaqueRegionSkia::pushCanvasLayer(const SkPaint* paint) void OpaqueRegionSkia::popCanvasLayer(const GraphicsContext* context) { + ASSERT(!context->paintingDisabled()); ASSERT(!m_canvasLayerStack.isEmpty()); if (m_canvasLayerStack.isEmpty()) return; @@ -195,6 +199,7 @@ void OpaqueRegionSkia::setImageMask(const SkRect& imageOpaqueRect) void OpaqueRegionSkia::didDrawRect(const GraphicsContext* context, const SkRect& fillRect, const SkPaint& paint, const SkBitmap* sourceBitmap) { + ASSERT(!context->paintingDisabled()); // Any stroking may put alpha in pixels even if the filling part does not. if (paint.getStyle() != SkPaint::kFill_Style) { bool fillsBounds = false; @@ -214,6 +219,7 @@ void OpaqueRegionSkia::didDrawRect(const GraphicsContext* context, const SkRect& void OpaqueRegionSkia::didDrawPath(const GraphicsContext* context, const SkPath& path, const SkPaint& paint) { + ASSERT(!context->paintingDisabled()); SkRect rect; if (path.isRect(&rect)) { didDrawRect(context, rect, paint, 0); @@ -232,6 +238,7 @@ void OpaqueRegionSkia::didDrawPath(const GraphicsContext* context, const SkPath& void OpaqueRegionSkia::didDrawPoints(const GraphicsContext* context, SkCanvas::PointMode mode, int numPoints, const SkPoint points[], const SkPaint& paint) { + ASSERT(!context->paintingDisabled()); if (!numPoints) return; @@ -260,6 +267,7 @@ void OpaqueRegionSkia::didDrawPoints(const GraphicsContext* context, SkCanvas::P void OpaqueRegionSkia::didDrawBounded(const GraphicsContext* context, const SkRect& bounds, const SkPaint& paint) { + ASSERT(!context->paintingDisabled()); bool fillsBounds = false; if (!paint.canComputeFastBounds()) @@ -273,6 +281,7 @@ void OpaqueRegionSkia::didDrawBounded(const GraphicsContext* context, const SkRe void OpaqueRegionSkia::didDraw(const GraphicsContext* context, const SkRect& rect, const SkPaint& paint, const SkBitmap* sourceBitmap, bool fillsBounds, DrawType drawType) { + ASSERT(!context->paintingDisabled()); SkRect targetRect = rect; // Apply the transform to device coordinate space. @@ -299,6 +308,7 @@ void OpaqueRegionSkia::didDraw(const GraphicsContext* context, const SkRect& rec void OpaqueRegionSkia::didDrawUnbounded(const GraphicsContext* context, const SkPaint& paint, DrawType drawType) { + ASSERT(!context->paintingDisabled()); bool drawsOpaque = paintIsOpaque(paint, drawType, 0); bool preservesOpaque = xfermodePreservesOpaque(paint, drawsOpaque); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/skia/SkiaUtils.cpp b/chromium/third_party/WebKit/Source/platform/graphics/skia/SkiaUtils.cpp index 882209b7626..ac2a0b397be 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/skia/SkiaUtils.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/skia/SkiaUtils.cpp @@ -128,12 +128,6 @@ SkColor SkPMColorToColor(SkPMColor pm) InvScaleByte(SkGetPackedB32(pm), scale)); } -void ClipRectToCanvas(const GraphicsContext* context, const SkRect& srcRect, SkRect* destRect) -{ - if (!context->getClipBounds(destRect) || !destRect->intersect(srcRect)) - destRect->setEmpty(); -} - bool SkPathContainsPoint(const SkPath& originalPath, const FloatPoint& point, SkPath::FillType ft) { SkRect bounds = originalPath.getBounds(); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/skia/SkiaUtils.h b/chromium/third_party/WebKit/Source/platform/graphics/skia/SkiaUtils.h index 0d94406974f..0b4082b7953 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/skia/SkiaUtils.h +++ b/chromium/third_party/WebKit/Source/platform/graphics/skia/SkiaUtils.h @@ -34,6 +34,7 @@ #define SkiaUtils_h #include "SkMatrix.h" +#include "SkPaint.h" #include "SkPath.h" #include "SkXfermode.h" #include "platform/PlatformExport.h" @@ -56,6 +57,13 @@ PassRefPtr<SkXfermode> WebCoreCompositeToSkiaComposite(CompositeOperator, blink: // move this guy into SkColor.h SkColor SkPMColorToColor(SkPMColor); +inline SkPaint::FilterLevel WebCoreInterpolationQualityToSkFilterLevel(InterpolationQuality quality) +{ + // FIXME: this reflects existing client mappings, but should probably + // be expanded to map higher level interpolations more accurately. + return quality != InterpolationNone ? SkPaint::kLow_FilterLevel : SkPaint::kNone_FilterLevel; +} + // Skia has problems when passed infinite, etc floats, filter them to 0. inline SkScalar WebCoreFloatToSkScalar(float f) { @@ -78,13 +86,6 @@ inline bool WebCoreFloatNearlyEqual(float a, float b) return SkScalarNearlyEqual(WebCoreFloatToSkScalar(a), WebCoreFloatToSkScalar(b)); } -// Computes the smallest rectangle that, which when drawn to the given canvas, -// will cover the same area as the source rectangle. It will clip to the canvas' -// clip, doing the necessary coordinate transforms. -// -// srcRect and destRect can be the same. -void ClipRectToCanvas(const GraphicsContext*, const SkRect& srcRect, SkRect* destRect); - // Determine if a given WebKit point is contained in a path bool PLATFORM_EXPORT SkPathContainsPoint(const SkPath&, const FloatPoint&, SkPath::FillType); diff --git a/chromium/third_party/WebKit/Source/platform/graphics/win/TransparencyWin.cpp b/chromium/third_party/WebKit/Source/platform/graphics/win/TransparencyWin.cpp deleted file mode 100644 index 5c7b56e2d07..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/win/TransparencyWin.cpp +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include "platform/graphics/win/TransparencyWin.h" - -#include "SkColorPriv.h" -#include "platform/fonts/SimpleFontData.h" -#include "platform/graphics/GraphicsContext.h" -#include "platform/graphics/skia/SkiaUtils.h" -#include "skia/ext/platform_canvas.h" - -namespace WebCore { - -namespace { - -// The maximum size in pixels of the buffer we'll keep around for drawing text -// into. Buffers larger than this will be destroyed when we're done with them. -const int maxCachedBufferPixelSize = 65536; - -inline const SkBitmap& bitmapForContext(const GraphicsContext& context) -{ - return context.layerBitmap(); -} - -void compositeToCopy(GraphicsContext& sourceLayers, GraphicsContext& destContext, const AffineTransform& matrix) -{ - // Make a list of all devices. The iterator goes top-down, and we want - // bottom-up. Note that each layer can also have an offset in canvas - // coordinates, which is the (x, y) position. - struct DeviceInfo { - DeviceInfo(SkBaseDevice* d, int lx, int ly) - : device(d) - , x(lx) - , y(ly) { } - SkBaseDevice* device; - int x; - int y; - }; - Vector<DeviceInfo> devices; - SkCanvas* sourceCanvas = sourceLayers.canvas(); - SkCanvas::LayerIter iter(sourceCanvas, false); - while (!iter.done()) { - devices.append(DeviceInfo(iter.device(), iter.x(), iter.y())); - iter.next(); - } - - // Create a temporary canvas for the compositing into the destination. - SkBitmap* destBmp = const_cast<SkBitmap*>(&bitmapForContext(destContext)); - SkCanvas destCanvas(*destBmp); - destCanvas.setMatrix(affineTransformToSkMatrix(matrix)); - - for (int i = devices.size() - 1; i >= 0; i--) { - const SkBitmap& srcBmp = devices[i].device->accessBitmap(false); - - SkRect destRect; - destRect.fLeft = devices[i].x; - destRect.fTop = devices[i].y; - destRect.fRight = destRect.fLeft + srcBmp.width(); - destRect.fBottom = destRect.fTop + srcBmp.height(); - - destCanvas.drawBitmapRect(srcBmp, 0, destRect); - } -} - -} // namespace - -// If either of these pointers is non-null, both must be valid and point to -// bitmaps of the same size. -class TransparencyWin::OwnedBuffers { -public: - OwnedBuffers(const IntSize& size, bool needReferenceBuffer) - { - m_destBitmap = ImageBuffer::create(size); - - if (needReferenceBuffer) { - m_referenceBitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height()); - m_referenceBitmap.allocPixels(); - m_referenceBitmap.eraseARGB(0, 0, 0, 0); - } - } - - ImageBuffer* destBitmap() { return m_destBitmap.get(); } - - // This bitmap will be empty if you don't specify needReferenceBuffer to the - // constructor. - SkBitmap* referenceBitmap() { return &m_referenceBitmap; } - - // Returns whether the current layer will fix a buffer of the given size. - bool canHandleSize(const IntSize& size) const - { - return m_destBitmap->size().width() >= size.width() && m_destBitmap->size().height() >= size.height(); - } - -private: - // The destination bitmap we're drawing into. - OwnPtr<ImageBuffer> m_destBitmap; - - // This could be an ImageBuffer but this is an optimization. Since this is - // only ever used as a reference, we don't need to make a full - // PlatformCanvas using Skia on Windows. Just allocating a regular SkBitmap - // is much faster since it's just a Malloc rather than a GDI call. - SkBitmap m_referenceBitmap; -}; - -TransparencyWin::OwnedBuffers* TransparencyWin::m_cachedBuffers = 0; - -TransparencyWin::TransparencyWin() - : m_destContext(0) - , m_orgTransform() - , m_layerMode(NoLayer) - , m_transformMode(KeepTransform) - , m_drawContext(0) - , m_savedOnDrawContext(false) - , m_layerBuffer(0) - , m_referenceBitmap(0) - , m_validLayer(false) -{ -} - -TransparencyWin::~TransparencyWin() -{ - // This should be false, since calling composite() is mandatory. - ASSERT(!m_savedOnDrawContext); -} - -void TransparencyWin::composite() -{ - // Matches the save() in initializeNewTextContext (or the constructor for - // SCALE) to put the context back into the same state we found it. - if (m_savedOnDrawContext) { - m_drawContext->restore(); - m_savedOnDrawContext = false; - } - - switch (m_layerMode) { - case NoLayer: - break; - case OpaqueCompositeLayer: - case WhiteLayer: - compositeOpaqueComposite(); - break; - case TextComposite: - compositeTextComposite(); - break; - } -} - -void TransparencyWin::init(GraphicsContext* dest, LayerMode layerMode, TransformMode transformMode, const IntRect& region) -{ - m_destContext = dest; - m_orgTransform = dest->getCTM(); - m_layerMode = layerMode; - m_transformMode = transformMode; - m_sourceRect = region; - - computeLayerSize(); - setupLayer(); - setupTransform(region); -} - -void TransparencyWin::computeLayerSize() -{ - if (m_transformMode == Untransform) { - // The meaning of the "transformed" source rect is a little ambigous - // here. The rest of the code doesn't care about it in the Untransform - // case since we're using our own happy coordinate system. So we set it - // to be the source rect since that matches how the code below actually - // uses the variable: to determine how to translate things to account - // for the offset of the layer. - m_transformedSourceRect = m_sourceRect; - } else if (m_transformMode == KeepTransform && m_layerMode != TextComposite) { - // FIXME: support clipping for other modes - IntRect clippedSourceRect = m_sourceRect; - SkRect clipBounds; - if (m_destContext->getClipBounds(&clipBounds)) { - FloatRect clipRect(clipBounds.left(), clipBounds.top(), clipBounds.width(), clipBounds.height()); - clippedSourceRect.intersect(enclosingIntRect(clipRect)); - } - m_transformedSourceRect = m_orgTransform.mapRect(clippedSourceRect); - } else { - m_transformedSourceRect = m_orgTransform.mapRect(m_sourceRect); - } - - m_layerSize = IntSize(m_transformedSourceRect.width(), m_transformedSourceRect.height()); -} - -void TransparencyWin::setupLayer() -{ - switch (m_layerMode) { - case NoLayer: - setupLayerForNoLayer(); - break; - case OpaqueCompositeLayer: - setupLayerForOpaqueCompositeLayer(); - break; - case TextComposite: - setupLayerForTextComposite(); - break; - case WhiteLayer: - setupLayerForWhiteLayer(); - break; - } -} - -void TransparencyWin::setupLayerForNoLayer() -{ - m_drawContext = m_destContext; // Draw to the source context. - m_validLayer = true; -} - -void TransparencyWin::setupLayerForOpaqueCompositeLayer() -{ - initializeNewContext(); - if (!m_validLayer) - return; - - AffineTransform mapping; - mapping.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y()); - if (m_transformMode == Untransform) { - // Compute the inverse mapping from the canvas space to the - // coordinate space of our bitmap. - mapping *= m_orgTransform.inverse(); - } - compositeToCopy(*m_destContext, *m_drawContext, mapping); - - // Save the reference layer so we can tell what changed. - SkCanvas referenceCanvas(*m_referenceBitmap); - referenceCanvas.drawBitmap(bitmapForContext(*m_drawContext), 0, 0); - // Layer rect represents the part of the original layer. -} - -void TransparencyWin::setupLayerForTextComposite() -{ - ASSERT(m_transformMode == KeepTransform); - // Fall through to filling with white. - setupLayerForWhiteLayer(); -} - -void TransparencyWin::setupLayerForWhiteLayer() -{ - initializeNewContext(); - if (!m_validLayer) - return; - - m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white); - // Layer rect represents the part of the original layer. -} - -void TransparencyWin::setupTransform(const IntRect& region) -{ - switch (m_transformMode) { - case KeepTransform: - setupTransformForKeepTransform(region); - break; - case Untransform: - setupTransformForUntransform(); - break; - case ScaleTransform: - setupTransformForScaleTransform(); - break; - } -} - -void TransparencyWin::setupTransformForKeepTransform(const IntRect& region) -{ - if (!m_validLayer) - return; - - if (m_layerMode != NoLayer) { - // Need to save things since we're modifying the transform. - m_drawContext->save(); - m_savedOnDrawContext = true; - - // Account for the fact that the layer may be offset from the - // original. This only happens when we create a layer that has the - // same coordinate space as the parent. - AffineTransform xform; - xform.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y()); - - // We're making a layer, so apply the old transform to the new one - // so it's maintained. We know the new layer has the identity - // transform now, we we can just multiply it. - xform *= m_orgTransform; - m_drawContext->concatCTM(xform); - } - m_drawRect = m_sourceRect; -} - -void TransparencyWin::setupTransformForUntransform() -{ - ASSERT(m_layerMode != NoLayer); - // We now have a new layer with the identity transform, which is the - // Untransformed space we'll use for drawing. - m_drawRect = IntRect(IntPoint(0, 0), m_layerSize); -} - -void TransparencyWin::setupTransformForScaleTransform() -{ - if (!m_validLayer) - return; - - if (m_layerMode == NoLayer) { - // Need to save things since we're modifying the layer. - m_drawContext->save(); - m_savedOnDrawContext = true; - - // Undo the transform on the current layer when we're re-using the - // current one. - m_drawContext->concatCTM(m_drawContext->getCTM().inverse()); - - // We're drawing to the original layer with just a different size. - m_drawRect = m_transformedSourceRect; - } else { - // Just go ahead and use the layer's coordinate space to draw into. - // It will have the scaled size, and an identity transform loaded. - m_drawRect = IntRect(IntPoint(0, 0), m_layerSize); - } -} - -void TransparencyWin::setTextCompositeColor(Color color) -{ - m_textCompositeColor = color; -} - -void TransparencyWin::initializeNewContext() -{ - int pixelSize = m_layerSize.width() * m_layerSize.height(); - if (pixelSize <= 0) - return; - - if (pixelSize > maxCachedBufferPixelSize) { - // Create a 1-off buffer for drawing into. We only need the reference - // buffer if we're making an OpaqueCompositeLayer. - bool needReferenceBitmap = m_layerMode == OpaqueCompositeLayer; - m_ownedBuffers = adoptPtr(new OwnedBuffers(m_layerSize, needReferenceBitmap)); - m_layerBuffer = m_ownedBuffers->destBitmap(); - if (!m_layerBuffer) - return; - - m_drawContext = m_layerBuffer->context(); - if (needReferenceBitmap) { - m_referenceBitmap = m_ownedBuffers->referenceBitmap(); - if (!m_referenceBitmap || !m_referenceBitmap->getPixels()) - return; - } - m_validLayer = true; - return; - } - - if (m_cachedBuffers && m_cachedBuffers->canHandleSize(m_layerSize)) { - // We can re-use the existing buffer. We don't need to clear it since - // all layer modes will clear it in their initialization. - m_layerBuffer = m_cachedBuffers->destBitmap(); - m_drawContext = m_cachedBuffers->destBitmap()->context(); - bitmapForContext(*m_drawContext).eraseARGB(0, 0, 0, 0); - m_referenceBitmap = m_cachedBuffers->referenceBitmap(); - m_referenceBitmap->eraseARGB(0, 0, 0, 0); - m_validLayer = true; - return; - } - - // Create a new cached buffer. - if (m_cachedBuffers) - delete m_cachedBuffers; - m_cachedBuffers = new OwnedBuffers(m_layerSize, true); - - m_layerBuffer = m_cachedBuffers->destBitmap(); - m_drawContext = m_cachedBuffers->destBitmap()->context(); - m_referenceBitmap = m_cachedBuffers->referenceBitmap(); - m_validLayer = true; -} - -void TransparencyWin::compositeOpaqueComposite() -{ - if (!m_validLayer) - return; - - m_destContext->save(); - - SkBitmap* bitmap = const_cast<SkBitmap*>( - &bitmapForContext(*m_layerBuffer->context())); - - // This function will be called for WhiteLayer as well, which we don't want - // to change. - if (m_layerMode == OpaqueCompositeLayer) { - // Fix up our bitmap, making it contain only the pixels which changed - // and transparent everywhere else. - SkAutoLockPixels sourceLock(*m_referenceBitmap); - SkAutoLockPixels lock(*bitmap); - for (int y = 0; y < bitmap->height(); y++) { - uint32_t* source = m_referenceBitmap->getAddr32(0, y); - uint32_t* dest = bitmap->getAddr32(0, y); - for (int x = 0; x < bitmap->width(); x++) { - // Clear out any pixels that were untouched. - if (dest[x] == source[x]) - dest[x] = 0; - else - dest[x] |= (0xFF << SK_A32_SHIFT); - } - } - } else { - makeLayerOpaque(); - } - - SkRect destRect; - if (m_transformMode != Untransform) { - // We want to use Untransformed space. - // - // Note that we DON'T call m_layerBuffer->image() here. This actually - // makes a copy of the image, which is unnecessary and slow. Instead, we - // just draw the image from inside the destination context. - SkMatrix identity; - identity.reset(); - m_destContext->setMatrix(identity); - - destRect.set(m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.maxX(), m_transformedSourceRect.maxY()); - } else { - destRect.set(m_sourceRect.x(), m_sourceRect.y(), m_sourceRect.maxX(), m_sourceRect.maxY()); - } - - SkPaint paint; - paint.setFilterBitmap(true); - paint.setAntiAlias(true); - - // Note that we need to specify the source layer subset, since the bitmap - // may have been cached and it could be larger than what we're using. - SkRect sourceRect = SkRect::MakeWH( - SkIntToScalar(m_layerSize.width()), - SkIntToScalar(m_layerSize.height())); - m_destContext->drawBitmapRect(*bitmap, &sourceRect, destRect, &paint); - m_destContext->restore(); -} - -void TransparencyWin::compositeTextComposite() -{ - if (!m_validLayer) - return; - - const SkBitmap& bitmap = m_layerBuffer->context()->layerBitmap(GraphicsContext::ReadWrite); - SkColor textColor = m_textCompositeColor.rgb(); - for (int y = 0; y < m_layerSize.height(); y++) { - uint32_t* row = bitmap.getAddr32(0, y); - for (int x = 0; x < m_layerSize.width(); x++) { - // The alpha is the average of the R, G, and B channels. - int alpha = (SkGetPackedR32(row[x]) + SkGetPackedG32(row[x]) + SkGetPackedB32(row[x])) / 3; - - // Apply that alpha to the text color and write the result. - row[x] = SkAlphaMulQ(textColor, SkAlpha255To256(255 - alpha)); - } - } - - // Now the layer has text with the proper color and opacity. - m_destContext->save(); - - // We want to use Untransformed space (see above) - SkMatrix identity; - identity.reset(); - m_destContext->setMatrix(identity); - SkRect destRect = { m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.maxX(), m_transformedSourceRect.maxY() }; - - // Note that we need to specify the source layer subset, since the bitmap - // may have been cached and it could be larger than what we're using. - SkRect sourceRect = SkRect::MakeWH( - SkIntToScalar(m_layerSize.width()), - SkIntToScalar(m_layerSize.height())); - m_destContext->drawBitmapRect(bitmap, &sourceRect, destRect, 0); - m_destContext->restore(); -} - -void TransparencyWin::makeLayerOpaque() -{ - if (!m_validLayer) - return; - - SkBitmap& bitmap = const_cast<SkBitmap&>(m_drawContext->layerBitmap(GraphicsContext::ReadWrite)); - for (int y = 0; y < m_layerSize.height(); y++) { - uint32_t* row = bitmap.getAddr32(0, y); - for (int x = 0; x < m_layerSize.width(); x++) - row[x] |= 0xFF000000; - } -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/graphics/win/TransparencyWin.h b/chromium/third_party/WebKit/Source/platform/graphics/win/TransparencyWin.h deleted file mode 100644 index 66f4cbd8606..00000000000 --- a/chromium/third_party/WebKit/Source/platform/graphics/win/TransparencyWin.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TransparencyWin_h -#define TransparencyWin_h - -#include "platform/graphics/ImageBuffer.h" -#include "platform/transforms/AffineTransform.h" -#include "wtf/Noncopyable.h" -#include "wtf/OwnPtr.h" -#include <windows.h> - -class SkBitmap; -class SkCanvas; - -namespace WebCore { - -class GraphicsContext; -class TransparencyWin_NoLayer_Test; -class TransparencyWin_WhiteLayer_Test; -class TransparencyWin_TextComposite_Test; -class TransparencyWin_OpaqueCompositeLayer_Test; - -// Helper class that abstracts away drawing ClearType text and Windows form -// controls either to the original context directly, or to an offscreen context -// that is composited later manually. This is to get around Windows' inability -// to handle the alpha channel, semitransparent text, and transformed form -// controls. -class PLATFORM_EXPORT TransparencyWin { - WTF_MAKE_NONCOPYABLE(TransparencyWin); -public: - enum LayerMode { - // No extra layer is created. Drawing will happen to the source. - // Valid only with KeepTransform and ScaleTransform. The region being - // drawn onto must be opaque, since the modified region will be forced - // to opaque when drawing is complete. - NoLayer, - - // Makes a temporary layer consisting of the composited layers below - // it. This result must be opaque. When complete, the result will be - // compared to the original, and the difference will be added to a thee - // destination layer. - // - // This mode only works if the lower layers are opque (normally the - // case for a web page) and layers are only drawn in the stack order, - // meaning you can never draw underneath a layer. - // - // This doesn't technically produce the correct answer in all cases. If - // you have an opaque base, a transparency layer, than a semitransparent - // drawing on top, the result will actually be blended in twice. But - // this isn't a very important case. This mode is used for form - // controls which are always opaque except for occationally some - // antialiasing. It means form control antialiasing will be too light in - // some cases, but only if you have extra layers. - OpaqueCompositeLayer, - - // Allows semitransparent text to be drawn on any background (even if it - // is itself semitransparent), but disables ClearType. - // - // It makes a trmporary layer filled with white. This is composited with - // the lower layer with a custom color applied to produce the result. - // The caller must draw the text in black, and set the desired final - // text color by calling setTextCompositeColor(). - // - // Only valid with KeepTransform, which is the only mode where drawing - // text in this fashion makes sense. - TextComposite, - - // Makes a temporary layer filled with white. When complete, the layer - // will be forced to be opqaue (since Windows may have messed up the - // alpha channel) and composited down. Any areas not drawn into will - // remain white. - // - // This is the mode of last resort. If the opacity of the final image - // is unknown and we can't do the text trick (since we know its color), - // then we have to live with potential white halos. This is used for - // form control drawing, for example. - WhiteLayer, - }; - - enum TransformMode { - // There are no changes to the transform. Use this when drawing - // horizontal text. The current transform must not have rotation. - KeepTransform, - - // Drawing happens in an Untransformed space, and then that bitmap is - // transformed according to the current context when it is copied down. - // Requires that a layer be created (layer mode is not NoLayer). - Untransform, - - // When the current transform only has a scaling factor applied and - // you're drawing form elements, use this parameter. This will unscale - // the coordinate space, so the OS will just draw the form controls - // larger or smaller depending on the destination size. - ScaleTransform, - }; - - // You MUST call init() below. - // |region| is expressed relative to the current transformation. - TransparencyWin(); - ~TransparencyWin(); - - // Initializes the members if you use the 0-argument constructor. Don't call - // this if you use the multiple-argument constructor. - void init(GraphicsContext*, LayerMode, TransformMode, const IntRect&); - - // Combines the source and destination bitmaps using the given mode. - // Calling this function before the destructor runs is mandatory in most - // cases, and harmless otherwise. The mandatory cases are: - // (m_layerMode != NoLayer) || (m_transformMode == ScaleTransform) - void composite(); - - // Returns the context for drawing into, which may be the destination - // context, or a temporary one. - GraphicsContext* context() const { return m_drawContext; } - - // When the mode is TextComposite, this sets the color that the text will - // get. See the enum above for more. - void setTextCompositeColor(Color); - - // Returns the input bounds translated into the destination space. This is - // not necessary for KeepTransform since the rectangle will be unchanged. - const IntRect& drawRect() { return m_drawRect; } - -private: - friend TransparencyWin_NoLayer_Test; - friend TransparencyWin_WhiteLayer_Test; - friend TransparencyWin_TextComposite_Test; - friend TransparencyWin_OpaqueCompositeLayer_Test; - - class OwnedBuffers; - - void computeLayerSize(); - - // Sets up a new layer, if any. setupLayer() will call the appopriate layer- - // specific helper. Must be called after computeLayerSize(); - void setupLayer(); - void setupLayerForNoLayer(); - void setupLayerForOpaqueCompositeLayer(); - void setupLayerForTextComposite(); - void setupLayerForWhiteLayer(); - - // Sets up the transformation on the newly created layer. setupTransform() - // will call the appropriate transform-specific helper. Must be called after - // setupLayer(). - void setupTransform(const IntRect& region); - void setupTransformForKeepTransform(const IntRect& region); - void setupTransformForUntransform(); - void setupTransformForScaleTransform(); - - void initializeNewContext(); - - void compositeOpaqueComposite(); - void compositeTextComposite(); - - // Fixes the alpha channel to make the region inside m_transformedRect - // opaque. - void makeLayerOpaque(); - - // The context our drawing will eventually end up in. - GraphicsContext* m_destContext; - - // The original transform from the destination context. - AffineTransform m_orgTransform; - - LayerMode m_layerMode; - TransformMode m_transformMode; - - // The rectangle we're drawing in the destination's coordinate space - IntRect m_sourceRect; - - // The source rectangle transformed into pixels in the final image. For - // Untransform this has no meaning, since the destination might not be a - // rectangle. - IntRect m_transformedSourceRect; - - // The size of the layer we created. If there's no layer, this is the size - // of the region we're using in the source. - IntSize m_layerSize; - - // The rectangle we're drawing to in the draw context's coordinate space. - // This will be the same as the source rectangle except for ScaleTransform - // where we create a new virtual coordinate space for the layer. - IntRect m_drawRect; - - // Points to the graphics context to draw text to, which will either be - // the original context or the copy, depending on our mode. - GraphicsContext* m_drawContext; - - // This flag is set when we call save() on the draw context during - // initialization. It allows us to avoid doing an extra save()/restore() - // when one is unnecessary. - bool m_savedOnDrawContext; - - // Used only when m_mode = TextComposite, this is the color that the text - // will end up being once we figure out the transparency. - Color m_textCompositeColor; - - // Layer we're drawing to. - ImageBuffer* m_layerBuffer; - - // When the layer type is OpaqueCompositeLayer, this will contain a copy - // of the original contents of the m_layerBuffer before Windows drew on it. - // It allows us to re-create what Windows did to the layer. It is an - // SkBitmap instead of an ImageBuffer because an SkBitmap is lighter-weight - // (ImageBuffers are also GDI surfaces, which we don't need here). - SkBitmap* m_referenceBitmap; - - // If the given size of bitmap can be cached, they will be stored here. Both - // the bitmap and the reference are guaranteed to be allocated if this - // member is non-null. - static OwnedBuffers* m_cachedBuffers; - - // If a buffer was too big to be cached, it will be created temporarily, and - // this member tracks its scope to make sure it gets deleted. Always use - // m_layerBuffer, which will either point to this object, or the statically - // cached one. Don't access directly. - OwnPtr<OwnedBuffers> m_ownedBuffers; - - // Sometimes we're asked to create layers that have negative dimensions. - // This API is not designed to fail to initialize, so we hide the fact - // that they are illegal and can't be rendered (failing silently, drawing - // nothing). - bool m_validLayer; -}; - -} // namespace WebCore - -#endif // TransaprencyWin_h |