diff options
author | Konstantin Tokarev <annulen@yandex.ru> | 2017-01-27 08:36:56 +0300 |
---|---|---|
committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:31:42 +0000 |
commit | 6b406688a4020916ba2966e6e5252d9c1385970f (patch) | |
tree | 65af619b76adb44fee03f2e496a2e4dc5c455dd8 /Source/WebCore/platform | |
parent | 46167faa61861b01a0e4e8e774da9febc3c2956e (diff) | |
download | qtwebkit-6b406688a4020916ba2966e6e5252d9c1385970f.tar.gz |
Imported WebKit commit bdab88b903fe1a254c80af20161183976670cd3b
Change-Id: Idc1156f4a64df4e7d89e90d4e03451f004c8ae6d
Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/WebCore/platform')
44 files changed, 2105 insertions, 319 deletions
diff --git a/Source/WebCore/platform/FileSystem.h b/Source/WebCore/platform/FileSystem.h index f3844b8df..2c46e4da0 100644 --- a/Source/WebCore/platform/FileSystem.h +++ b/Source/WebCore/platform/FileSystem.h @@ -178,6 +178,7 @@ bool excludeFromBackup(const String&); // Returns true if successful. WEBCORE_EXPORT Vector<String> listDirectory(const String& path, const String& filter = String()); WEBCORE_EXPORT CString fileSystemRepresentation(const String&); +String stringFromFileSystemRepresentation(const char*); inline bool isHandleValid(const PlatformFileHandle& handle) { return handle != invalidPlatformFileHandle; } diff --git a/Source/WebCore/platform/cf/SharedBufferCF.cpp b/Source/WebCore/platform/cf/SharedBufferCF.cpp new file mode 100644 index 000000000..21af320d9 --- /dev/null +++ b/Source/WebCore/platform/cf/SharedBufferCF.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2008, 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. + * 3. Neither the name of Apple Inc. ("Apple") 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 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 "SharedBuffer.h" + +#include <wtf/OSAllocator.h> +#include <wtf/cf/TypeCastsCF.h> + +namespace WebCore { + +SharedBuffer::SharedBuffer(CFDataRef cfData) + : m_buffer(adoptRef(new DataBuffer)) + , m_cfData(cfData) + , m_vnodeToken(VNodeTracker::singleton().token()) +{ +} + +// Using Foundation allows for an even more efficient implementation of this function, +// so only use this version for non-Foundation. +#if !USE(FOUNDATION) +RetainPtr<CFDataRef> SharedBuffer::createCFData() +{ + if (m_cfData) + return m_cfData; + + // Internal data in SharedBuffer can be segmented. We need to get the contiguous buffer. + const Vector<char>& contiguousBuffer = buffer(); + return adoptCF(CFDataCreate(0, reinterpret_cast<const UInt8*>(contiguousBuffer.data()), contiguousBuffer.size())); +} +#endif + +PassRefPtr<SharedBuffer> SharedBuffer::wrapCFData(CFDataRef data) +{ + return adoptRef(new SharedBuffer(data)); +} + +bool SharedBuffer::hasPlatformData() const +{ + return m_cfData; +} + +const char* SharedBuffer::platformData() const +{ + return reinterpret_cast<const char*>(CFDataGetBytePtr(m_cfData.get())); +} + +unsigned SharedBuffer::platformDataSize() const +{ + return CFDataGetLength(m_cfData.get()); +} + +void SharedBuffer::hintMemoryNotNeededSoon() +{ + if (!hasPlatformData()) + return; + OSAllocator::hintMemoryNotNeededSoon(const_cast<char*>(platformData()), platformDataSize()); +} + +void SharedBuffer::maybeTransferPlatformData() +{ + if (!m_cfData) + return; + + ASSERT(!m_size); + + // Hang on to the m_cfData pointer in a local pointer as append() will re-enter maybeTransferPlatformData() + // and we need to make sure to early return when it does. + RetainPtr<CFDataRef> cfData = adoptCF(m_cfData.leakRef()); + + append(reinterpret_cast<const char*>(CFDataGetBytePtr(cfData.get())), CFDataGetLength(cfData.get())); +} + +void SharedBuffer::clearPlatformData() +{ + m_cfData = 0; +} + +bool SharedBuffer::tryReplaceContentsWithPlatformBuffer(SharedBuffer& newContents) +{ + if (!newContents.m_cfData) + return false; + + clear(); + m_cfData = newContents.m_cfData; + return true; +} + +bool SharedBuffer::maybeAppendPlatformData(SharedBuffer* newContents) +{ + if (size() || !newContents->m_cfData) + return false; + m_cfData = newContents->m_cfData; + return true; +} + +#if USE(NETWORK_CFDATA_ARRAY_CALLBACK) +PassRefPtr<SharedBuffer> SharedBuffer::wrapCFDataArray(CFArrayRef cfDataArray) +{ + return adoptRef(new SharedBuffer(cfDataArray)); +} + +SharedBuffer::SharedBuffer(CFArrayRef cfDataArray) + : m_buffer(adoptRef(new DataBuffer)) + , m_cfData(nullptr) +{ + CFIndex dataArrayCount = CFArrayGetCount(cfDataArray); + for (CFIndex index = 0; index < dataArrayCount; ++index) + append(checked_cf_cast<CFDataRef>(CFArrayGetValueAtIndex(cfDataArray, index))); +} + +void SharedBuffer::append(CFDataRef data) +{ + ASSERT(data); + m_dataArray.append(data); + m_size += CFDataGetLength(data); +} + +void SharedBuffer::copyBufferAndClear(char* destination, unsigned bytesToCopy) const +{ + if (m_dataArray.isEmpty()) + return; + + CFIndex bytesLeft = bytesToCopy; + for (auto& cfData : m_dataArray) { + CFIndex dataLen = CFDataGetLength(cfData.get()); + ASSERT(bytesLeft >= dataLen); + memcpy(destination, CFDataGetBytePtr(cfData.get()), dataLen); + destination += dataLen; + bytesLeft -= dataLen; + } + m_dataArray.clear(); +} + +unsigned SharedBuffer::copySomeDataFromDataArray(const char*& someData, unsigned position) const +{ + unsigned totalOffset = 0; + for (auto& cfData : m_dataArray) { + unsigned dataLen = static_cast<unsigned>(CFDataGetLength(cfData.get())); + ASSERT(totalOffset <= position); + unsigned localOffset = position - totalOffset; + if (localOffset < dataLen) { + someData = reinterpret_cast<const char *>(CFDataGetBytePtr(cfData.get())) + localOffset; + return dataLen - localOffset; + } + totalOffset += dataLen; + } + return 0; +} + +const char *SharedBuffer::singleDataArrayBuffer() const +{ + // If we had previously copied data into m_buffer in copyDataArrayAndClear() or some other + // function, then we can't return a pointer to the CFDataRef buffer. + if (m_buffer->data.size()) + return 0; + + if (m_dataArray.size() != 1) + return 0; + + return reinterpret_cast<const char*>(CFDataGetBytePtr(m_dataArray.at(0).get())); +} + +bool SharedBuffer::maybeAppendDataArray(SharedBuffer* data) +{ + if (m_buffer->data.size() || m_cfData || !data->m_dataArray.size()) + return false; +#if !ASSERT_DISABLED + unsigned originalSize = size(); +#endif + for (auto& cfData : data->m_dataArray) + append(cfData.get()); + ASSERT(size() == originalSize + data->size()); + return true; +} +#endif + +} diff --git a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h index 50684426a..dc5082a45 100644 --- a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h +++ b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h @@ -38,6 +38,11 @@ #include "OpenGLESShims.h" #elif PLATFORM(QT) #include <qopengl.h> + +#ifndef GL_SAMPLER_2D_RECT_ARB +#define GL_SAMPLER_2D_RECT_ARB 0x8B63 +#endif + #elif PLATFORM(GTK) || PLATFORM(EFL) #if USE(OPENGL_ES_2) #include <GLES2/gl2.h> diff --git a/Source/WebCore/platform/graphics/GraphicsContext.cpp b/Source/WebCore/platform/graphics/GraphicsContext.cpp index 4dfef933f..b4c6f46c4 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext.cpp +++ b/Source/WebCore/platform/graphics/GraphicsContext.cpp @@ -993,7 +993,7 @@ void GraphicsContext::setPlatformShouldSmoothFonts(bool) } #endif -#if !USE(CG) && !USE(CAIRO) +#if !USE(CG) && !USE(CAIRO) && !PLATFORM(QT) bool GraphicsContext::isAcceleratedContext() const { return false; diff --git a/Source/WebCore/platform/graphics/GraphicsContext3D.h b/Source/WebCore/platform/graphics/GraphicsContext3D.h index 940394e3b..e7d7f9a7f 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext3D.h +++ b/Source/WebCore/platform/graphics/GraphicsContext3D.h @@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE class QPainter; class QRect; class QOpenGLContext; +class QOpenGLExtensions; class QSurface; QT_END_NAMESPACE #elif PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN_CAIRO) @@ -95,14 +96,9 @@ const Platform3DObject NullPlatform3DObject = 0; namespace WebCore { class Extensions3D; -#if USE(OPENGL_ES_2) +class Extensions3DOpenGLCommon; class Extensions3DOpenGLES; -#else class Extensions3DOpenGL; -#endif -#if PLATFORM(QT) -class Extensions3DQt; -#endif class HostWindow; class Image; class ImageBuffer; @@ -690,7 +686,7 @@ public: ALREADY_SIGNALED = 0x911A, TIMEOUT_EXPIRED = 0x911B, CONDITION_SATISFIED = 0x911C, -#if PLATFORM(WIN) +#if OS(WINDOWS) WAIT_FAILED_WIN = 0x911D, #else WAIT_FAILED = 0x911D, @@ -1417,17 +1413,15 @@ private: String mappedSymbolName(Platform3DObject shaders[2], size_t count, const String& name); String originalSymbolName(Platform3DObject program, ANGLEShaderSymbolType, const String& name); +#if !PLATFORM(QT) ANGLEWebKitBridge m_compiler; +#endif std::unique_ptr<ShaderNameHash> nameHashMapForShaders; -#if (PLATFORM(QT) && defined(QT_OPENGL_ES_2)) || ((PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN)) && USE(OPENGL_ES_2)) - friend class Extensions3DOpenGLES; - std::unique_ptr<Extensions3DOpenGLES> m_extensions; -#else + std::unique_ptr<Extensions3DOpenGLCommon> m_extensions; friend class Extensions3DOpenGL; - std::unique_ptr<Extensions3DOpenGL> m_extensions; -#endif + friend class Extensions3DOpenGLES; friend class Extensions3DOpenGLCommon; Attributes m_attrs; @@ -1470,9 +1464,18 @@ private: // Errors raised by synthesizeGLError(). ListHashSet<GC3Denum> m_syntheticErrors; +#if PLATFORM(QT) + QOpenGLExtensions* m_functions; +#endif + friend class GraphicsContext3DPrivate; std::unique_ptr<GraphicsContext3DPrivate> m_private; - + +#if PLATFORM(QT) + // Must be initialized after m_private so that isGLES2Compliant works + ANGLEWebKitBridge m_compiler; +#endif + WebGLRenderingContextBase* m_webglContext; }; diff --git a/Source/WebCore/platform/graphics/GraphicsContext3DPrivate.cpp b/Source/WebCore/platform/graphics/GraphicsContext3DPrivate.cpp index 15cd4df00..aeaefbca0 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext3DPrivate.cpp +++ b/Source/WebCore/platform/graphics/GraphicsContext3DPrivate.cpp @@ -121,6 +121,45 @@ void GraphicsContext3DPrivate::paintToTextureMapper(TextureMapper& textureMapper m_context->markLayerComposited(); + // FIXME: We do not support mask for the moment with TextureMapperImageBuffer. + if (textureMapper->accelerationMode() != TextureMapper::OpenGLMode) { + GraphicsContext* context = textureMapper->graphicsContext(); + context->save(); + context->platformContext()->setGlobalAlpha(opacity); + + const int height = m_context->m_currentHeight; + const int width = m_context->m_currentWidth; + int totalBytes = width * height * 4; + + auto pixels = std::make_unique<unsigned char[]>(totalBytes); + if (!pixels) + return; + + // OpenGL keeps the pixels stored bottom up, so we need to flip the image here. + context->translate(0, height); + context->scale(FloatSize(1, -1)); + + context->concatCTM(matrix.toAffineTransform()); + + m_context->readRenderingResults(pixels.get(), totalBytes); + + // Premultiply alpha. + for (int i = 0; i < totalBytes; i += 4) + if (pixels[i + 3] != 255) { + pixels[i + 0] = min(255, pixels[i + 0] * pixels[i + 3] / 255); + pixels[i + 1] = min(255, pixels[i + 1] * pixels[i + 3] / 255); + pixels[i + 2] = min(255, pixels[i + 2] * pixels[i + 3] / 255); + } + + RefPtr<cairo_surface_t> imageSurface = adoptRef(cairo_image_surface_create_for_data( + const_cast<unsigned char*>(pixels.get()), CAIRO_FORMAT_ARGB32, width, height, width * 4)); + + context->platformContext()->drawSurfaceToContext(imageSurface.get(), targetRect, IntRect(0, 0, width, height), context); + + context->restore(); + return; + } + #if USE(TEXTURE_MAPPER_GL) if (m_context->m_attrs.antialias && m_context->m_state.boundFBO == m_context->m_multisampleFBO) { GLContext* previousActiveContext = GLContext::getCurrent(); diff --git a/Source/WebCore/platform/graphics/ImageBuffer.cpp b/Source/WebCore/platform/graphics/ImageBuffer.cpp index 2ace73c28..d3c3ae644 100644 --- a/Source/WebCore/platform/graphics/ImageBuffer.cpp +++ b/Source/WebCore/platform/graphics/ImageBuffer.cpp @@ -153,10 +153,12 @@ void ImageBuffer::convertToLuminanceMask() } #if !USE(CAIRO) +#if !PLATFORM(QT) PlatformLayer* ImageBuffer::platformLayer() const { return 0; } +#endif bool ImageBuffer::copyToPlatformTexture(GraphicsContext3D&, GC3Denum, Platform3DObject, GC3Denum, bool, bool) { diff --git a/Source/WebCore/platform/graphics/ImageBuffer.h b/Source/WebCore/platform/graphics/ImageBuffer.h index 04f9ef93a..6f48d3db9 100644 --- a/Source/WebCore/platform/graphics/ImageBuffer.h +++ b/Source/WebCore/platform/graphics/ImageBuffer.h @@ -40,6 +40,12 @@ #include <wtf/PassRefPtr.h> #include <wtf/Vector.h> +#if PLATFORM(QT) +QT_BEGIN_NAMESPACE +class QOpenGLContext; +QT_END_NAMESPACE +#endif + namespace WebCore { class FloatRect; @@ -80,6 +86,9 @@ public: } static std::unique_ptr<ImageBuffer> createCompatibleBuffer(const FloatSize&, float resolutionScale, ColorSpace, const GraphicsContext&, bool hasAlpha); +#if PLATFORM(QT) && ENABLE(ACCELERATED_2D_CANVAS) + static std::unique_ptr<ImageBuffer> createCompatibleBuffer(const IntSize&, float resolutionScale, ColorSpace, QOpenGLContext*); +#endif WEBCORE_EXPORT ~ImageBuffer(); @@ -164,6 +173,9 @@ private: // This constructor will place its success into the given out-variable // so that create() knows when it should return failure. WEBCORE_EXPORT ImageBuffer(const FloatSize&, float resolutionScale, ColorSpace, RenderingMode, bool& success); +#if PLATFORM(QT) && ENABLE(ACCELERATED_2D_CANVAS) + ImageBuffer(const IntSize&, float resolutionScale, ColorSpace, QOpenGLContext*, bool& success); +#endif }; #if USE(CG) diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp index 310a02247..428f432e6 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp @@ -625,6 +625,9 @@ void MediaPlayerPrivateGStreamerBase::paint(GraphicsContext& context, const Floa #if USE(TEXTURE_MAPPER_GL) && !USE(COORDINATED_GRAPHICS) void MediaPlayerPrivateGStreamerBase::paintToTextureMapper(TextureMapper& textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity) { + if (textureMapper.accelerationMode() != TextureMapper::OpenGLMode) + return; + if (!m_player->visible()) return; diff --git a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp index a0bc40357..51d5db650 100644 --- a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp @@ -36,7 +36,14 @@ #include <OpenGLES/ES2/glext.h> #elif PLATFORM(MAC) #include <OpenGL/gl.h> -#elif PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(QT) || PLATFORM(WIN) +#elif PLATFORM(QT) +#define FUNCTIONS m_context->m_functions +#include "OpenGLShimsQt.h" +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) +#define VAO_FUNCTIONS m_vaoFunctions +#include "OpenGLShimsQtVAO.h" +#endif +#elif PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN) #include "OpenGLShims.h" #endif @@ -44,15 +51,25 @@ #include "GraphicsContext3DIOS.h" #endif +// Note this implementation serves a double role for Qt where it also handles OpenGLES. + namespace WebCore { Extensions3DOpenGL::Extensions3DOpenGL(GraphicsContext3D* context) : Extensions3DOpenGLCommon(context) { +#if PLATFORM(QT) && QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + context->makeContextCurrent(); + m_vaoFunctions = new QOpenGLVertexArrayObjectHelper(context->platformGraphicsContext3D()); +#endif } Extensions3DOpenGL::~Extensions3DOpenGL() { +#if PLATFORM(QT) && QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + delete m_vaoFunctions; + m_vaoFunctions = 0; +#endif } @@ -119,6 +136,8 @@ GC3Dboolean Extensions3DOpenGL::isVertexArrayOES(Platform3DObject array) #elif defined(GL_APPLE_vertex_array_object) && GL_APPLE_vertex_array_object return glIsVertexArrayAPPLE(array); #endif + + m_context->synthesizeGLError(GL_INVALID_OPERATION); return GL_FALSE; } @@ -157,6 +176,23 @@ bool Extensions3DOpenGL::supportsExtension(const String& name) { // GL_ANGLE_framebuffer_blit and GL_ANGLE_framebuffer_multisample are "fake". They are implemented using other // extensions. In particular GL_EXT_framebuffer_blit and GL_EXT_framebuffer_multisample/GL_APPLE_framebuffer_multisample. +#if PLATFORM(QT) + m_context->makeContextCurrent(); + + if (name == "GL_ANGLE_framebuffer_blit" || name == "GL_EXT_framebuffer_blit") + return m_context->m_functions->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit); + if (name == "GL_ANGLE_framebuffer_multisample" || name == "GL_EXT_framebuffer_multisample") + return m_context->m_functions->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample); + + if (name == "GL_OES_texture_npot" || name == "GL_ARB_texture_non_power_of_two") + return m_context->m_functions->hasOpenGLFeature(QOpenGLFunctions::NPOTTextures); + if (name == "GL_OES_packed_depth_stencil" || name == "GL_EXT_packed_depth_stencil") + return m_context->m_functions->hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil); + + // FIXME: We don't have the robustness methods from Extensions3DOpenGLES. + if (name == "GL_EXT_robustness") + return false; +#else if (name == "GL_ANGLE_framebuffer_blit") return m_availableExtensions.contains("GL_EXT_framebuffer_blit"); if (name == "GL_ANGLE_framebuffer_multisample") @@ -165,6 +201,7 @@ bool Extensions3DOpenGL::supportsExtension(const String& name) #else return m_availableExtensions.contains("GL_EXT_framebuffer_multisample"); #endif +#endif // !PLATFORM(QT) if (name == "GL_ANGLE_instanced_arrays") { return (m_availableExtensions.contains("GL_ARB_instanced_arrays") || m_availableExtensions.contains("GL_EXT_instanced_arrays")) @@ -185,6 +222,10 @@ bool Extensions3DOpenGL::supportsExtension(const String& name) return m_availableExtensions.contains("GL_EXT_frag_depth"); #endif +#if PLATFORM(QT) + if (!m_context->isGLES2Compliant()) { +#endif + // Desktop GL always supports GL_OES_rgb8_rgba8. if (name == "GL_OES_rgb8_rgba8") return true; @@ -194,17 +235,27 @@ bool Extensions3DOpenGL::supportsExtension(const String& name) if (name == "GL_OES_texture_float" || name == "GL_OES_texture_half_float" || name == "GL_OES_texture_float_linear" || name == "GL_OES_texture_half_float_linear") return m_availableExtensions.contains("GL_ARB_texture_float") || m_availableExtensions.contains("GL_OES_texture_float"); +#if PLATFORM(QT) + } +#endif + // GL_OES_vertex_array_object if (name == "GL_OES_vertex_array_object") { -#if (PLATFORM(GTK) || PLATFORM(QT) || PLATFORM(EFL)) +#if (PLATFORM(GTK) || PLATFORM(EFL)) return m_availableExtensions.contains("GL_ARB_vertex_array_object"); #elif PLATFORM(IOS) return m_availableExtensions.contains("GL_OES_vertex_array_object"); +#elif PLATFORM(QT) + return isVertexArrayObjectSupported(); #else return m_availableExtensions.contains("GL_APPLE_vertex_array_object"); #endif } +#if PLATFORM(QT) + if (!m_context->isGLES2Compliant()) { +#endif + // Desktop GL always supports the standard derivative functions if (name == "GL_OES_standard_derivatives") return true; @@ -212,6 +263,10 @@ bool Extensions3DOpenGL::supportsExtension(const String& name) // Desktop GL always supports UNSIGNED_INT indices if (name == "GL_OES_element_index_uint") return true; + +#if PLATFORM(QT) + } +#endif if (name == "GL_EXT_shader_texture_lod") return m_availableExtensions.contains("GL_EXT_shader_texture_lod"); @@ -222,7 +277,7 @@ bool Extensions3DOpenGL::supportsExtension(const String& name) if (name == "GL_EXT_draw_buffers") { #if PLATFORM(IOS) return m_availableExtensions.contains(name); -#elif PLATFORM(MAC) || PLATFORM(GTK) +#elif PLATFORM(MAC) || PLATFORM(GTK) || (PLATFORM(QT) && QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) return m_availableExtensions.contains("GL_ARB_draw_buffers"); #else // FIXME: implement support for other platforms. @@ -243,7 +298,7 @@ void Extensions3DOpenGL::drawBuffersEXT(GC3Dsizei n, const GC3Denum* bufs) // FIXME: implement support for other platforms. #if PLATFORM(MAC) ::glDrawBuffersARB(n, bufs); -#elif PLATFORM(GTK) +#elif PLATFORM(GTK) || (PLATFORM(QT) && QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) ::glDrawBuffers(n, bufs); #else UNUSED_PARAM(n); @@ -254,7 +309,7 @@ void Extensions3DOpenGL::drawBuffersEXT(GC3Dsizei n, const GC3Denum* bufs) void Extensions3DOpenGL::drawArraysInstanced(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount) { m_context->makeContextCurrent(); -#if PLATFORM(GTK) +#if PLATFORM(GTK) || (PLATFORM(QT) && QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) ::glDrawArraysInstanced(mode, first, count, primcount); #elif PLATFORM(COCOA) ::glDrawArraysInstancedARB(mode, first, count, primcount); @@ -269,7 +324,7 @@ void Extensions3DOpenGL::drawArraysInstanced(GC3Denum mode, GC3Dint first, GC3Ds void Extensions3DOpenGL::drawElementsInstanced(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, GC3Dsizei primcount) { m_context->makeContextCurrent(); -#if PLATFORM(GTK) +#if PLATFORM(GTK) || (PLATFORM(QT) && QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) ::glDrawElementsInstanced(mode, count, type, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)), primcount); #elif PLATFORM(COCOA) ::glDrawElementsInstancedARB(mode, count, type, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)), primcount); @@ -285,7 +340,7 @@ void Extensions3DOpenGL::drawElementsInstanced(GC3Denum mode, GC3Dsizei count, G void Extensions3DOpenGL::vertexAttribDivisor(GC3Duint index, GC3Duint divisor) { m_context->makeContextCurrent(); -#if PLATFORM(GTK) +#if PLATFORM(GTK) || (PLATFORM(QT) && QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) ::glVertexAttribDivisor(index, divisor); #elif PLATFORM(COCOA) ::glVertexAttribDivisorARB(index, divisor); @@ -300,12 +355,21 @@ String Extensions3DOpenGL::getExtensions() return String(reinterpret_cast<const char*>(::glGetString(GL_EXTENSIONS))); } -#if (PLATFORM(GTK) || PLATFORM(QT) || PLATFORM(EFL) || PLATFORM(WIN) || PLATFORM(IOS)) +#if (PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN) || PLATFORM(IOS)) bool Extensions3DOpenGL::isVertexArrayObjectSupported() { static const bool supportsVertexArrayObject = supports("GL_OES_vertex_array_object"); return supportsVertexArrayObject; } +#elif PLATFORM(QT) +bool Extensions3DOpenGL::isVertexArrayObjectSupported() +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + return m_vaoFunctions && m_vaoFunctions->isValid(); +#else + return false; +#endif +} #endif } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h index 2938110c5..fd3512fa2 100644 --- a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h +++ b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h @@ -32,6 +32,12 @@ #include <wtf/HashSet.h> #include <wtf/text/StringHash.h> +#if PLATFORM(QT) +QT_BEGIN_NAMESPACE +class QOpenGLVertexArrayObjectHelper; +QT_END_NAMESPACE +#endif + namespace WebCore { class Extensions3DOpenGL : public Extensions3DOpenGLCommon { @@ -65,6 +71,10 @@ protected: private: bool isVertexArrayObjectSupported(); #endif + +#if PLATFORM(QT) && QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + QOpenGLVertexArrayObjectHelper *m_vaoFunctions; +#endif }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGLCommon.cpp b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGLCommon.cpp index 93e8cfd8f..62430006b 100644 --- a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGLCommon.cpp +++ b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGLCommon.cpp @@ -35,13 +35,16 @@ #if PLATFORM(IOS) #include <OpenGLES/ES2/glext.h> #else -#if USE(OPENGL_ES_2) +#if PLATFORM(QT) +#define FUNCTIONS m_context->m_functions +#include "OpenGLShimsQt.h" +#elif USE(OPENGL_ES_2) #include "OpenGLESShims.h" #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> #elif PLATFORM(MAC) #include <OpenGL/gl.h> -#elif PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(QT) || PLATFORM(WIN) +#elif PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN) #include "OpenGLShims.h" #endif #endif diff --git a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGLES.cpp b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGLES.cpp index 9199cb84e..27dc6bd5f 100644 --- a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGLES.cpp +++ b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGLES.cpp @@ -195,10 +195,14 @@ void Extensions3DOpenGLES::setEXTContextLostCallback(std::unique_ptr<GraphicsCon void Extensions3DOpenGLES::readnPixelsEXT(int x, int y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, GC3Dsizei bufSize, void *data) { if (m_glReadnPixelsEXT) { +#if PLATFORM(QT) + m_context->flush(); +#else m_context->makeContextCurrent(); // FIXME: remove the two glFlush calls when the driver bug is fixed, i.e., // all previous rendering calls should be done before reading pixels. ::glFlush(); +#endif // FIXME: If non-BlackBerry platforms use this, they will need to implement // their anti-aliasing code here. diff --git a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp index e1e244985..85da831cc 100644 --- a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp @@ -1,6 +1,9 @@ /* * Copyright (C) 2010, 2013 Apple Inc. All rights reserved. * Copyright (C) 2011 Google Inc. All rights reserved. + * Copyright (C) 2012 ChangSeok Oh <shivamidow@gmail.com> + * Copyright (C) 2012 Research In Motion Limited. All rights reserved. + * Copyright (C) 2014 Digia Plc. and/or its subsidiary(-ies). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -21,11 +24,13 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" +// Note this implementation serves a double role for Qt where it also handles OpenGLES. + #if ENABLE(GRAPHICS_CONTEXT_3D) #include "GraphicsContext3D.h" @@ -55,16 +60,66 @@ #define GL_RGB32F_ARB 0x8815 #elif PLATFORM(MAC) #include <OpenGL/gl.h> -#elif PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(QT) || PLATFORM(WIN) +#elif PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN) #include "OpenGLShims.h" #endif +#if PLATFORM(QT) + +#define FUNCTIONS m_functions +#include "OpenGLShimsQt.h" +#include <QOpenGLContext> + +#define scopedScissor(c, s) scopedScissor(m_functions, c, s) +#define scopedDither(c, s) scopedDither(m_functions, c, s) +#define scopedDepth(c, s) scopedDepth(m_functions, c, s) +#define scopedStencil(c, s) scopedStencil(m_functions, c, s) + +#ifndef GL_BGRA +#define GL_BGRA 0x80E1 +#endif + +#ifndef GL_READ_FRAMEBUFFER +#define GL_READ_FRAMEBUFFER 0x8CA8 +#endif + +#ifndef GL_DRAW_FRAMEBUFFER +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#endif + +#ifndef GL_MAX_VARYING_FLOATS +#define GL_MAX_VARYING_FLOATS 0x8B4B +#endif + +#ifndef GL_ALPHA16F_ARB +#define GL_ALPHA16F_ARB 0x881C +#endif + +#ifndef GL_LUMINANCE16F_ARB +#define GL_LUMINANCE16F_ARB 0x881E +#endif + +#ifndef GL_LUMINANCE_ALPHA16F_ARB +#define GL_LUMINANCE_ALPHA16F_ARB 0x881F +#endif + +#ifndef GL_HALF_FLOAT_OES +#define GL_HALF_FLOAT_OES 0x8D61 +#endif + +#endif + namespace WebCore { void GraphicsContext3D::releaseShaderCompiler() { makeContextCurrent(); +#if PLATFORM(QT) + ASSERT(m_private); + m_functions->glReleaseShaderCompiler(); +#else notImplemented(); +#endif } void GraphicsContext3D::readPixelsAndConvertToBGRAIfNecessary(int x, int y, int width, int height, unsigned char* pixels) @@ -93,13 +148,41 @@ void GraphicsContext3D::readPixelsAndConvertToBGRAIfNecessary(int x, int y, int for (int i = 0; i < totalBytes; i += 4) std::swap(pixels[i], pixels[i + 2]); #endif - } else + } else { +#if PLATFORM(QT) + ASSERT(m_private); + bool readBGRA = !isGLES2Compliant() || platformGraphicsContext3D()->hasExtension("GL_EXT_read_format_bgra"); + + if (readBGRA) + glReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_BYTE, pixels); + else + glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + int totalBytes = width * height * 4; + if (!readBGRA) { + for (int i = 0; i < totalBytes; i += 4) + std::swap(pixels[i], pixels[i + 2]); // Convert to BGRA. + } +#else ::glReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels); +#endif + } } void GraphicsContext3D::validateAttributes() { +#if PLATFORM(QT) + if (isGLES2Compliant()) + validateDepthStencil("GL_OES_packed_depth_stencil"); + else + validateDepthStencil("GL_EXT_packed_depth_stencil"); + + if (m_attrs.antialias && isGLES2Compliant()) { + if (!m_functions->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample) || !m_functions->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit)) + m_attrs.antialias = false; + } +#else validateDepthStencil("GL_EXT_packed_depth_stencil"); +#endif } bool GraphicsContext3D::reshapeFBOs(const IntSize& size) @@ -107,13 +190,17 @@ bool GraphicsContext3D::reshapeFBOs(const IntSize& size) const int width = size.width(); const int height = size.height(); GLuint colorFormat, internalDepthStencilFormat = 0; + GLuint pixelDataType = 0; if (m_attrs.alpha) { - m_internalColorFormat = GL_RGBA8; + m_internalColorFormat = isGLES2Compliant() ? GL_RGBA : GL_RGBA8; colorFormat = GL_RGBA; + pixelDataType = GL_UNSIGNED_BYTE; } else { - m_internalColorFormat = GL_RGB8; + m_internalColorFormat = isGLES2Compliant() ? GL_RGB : GL_RGB8; colorFormat = GL_RGB; + pixelDataType = isGLES2Compliant() ? GL_UNSIGNED_SHORT_5_6_5 : GL_UNSIGNED_BYTE; } + if (m_attrs.stencil || m_attrs.depth) { // We don't allow the logic where stencil is required and depth is not. // See GraphicsContext3D::validateAttributes. @@ -131,7 +218,7 @@ bool GraphicsContext3D::reshapeFBOs(const IntSize& size) } // Resize multisample FBO. - if (m_attrs.antialias) { + if (m_attrs.antialias && !isGLES2Compliant()) { GLint maxSampleCount; ::glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSampleCount); GLint sampleCount = std::min(8, maxSampleCount); @@ -169,12 +256,12 @@ bool GraphicsContext3D::reshapeFBOs(const IntSize& size) setRenderbufferStorageFromDrawable(m_currentWidth, m_currentHeight); #else ::glBindTexture(GL_TEXTURE_2D, m_texture); - ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); + ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, pixelDataType, 0); ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0); if (m_compositorTexture) { ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture); - ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); + ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, pixelDataType, 0); ::glBindTexture(GL_TEXTURE_2D, 0); #if USE(COORDINATED_GRAPHICS_THREADED) ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_compositorFBO); @@ -188,7 +275,7 @@ bool GraphicsContext3D::reshapeFBOs(const IntSize& size) attachDepthAndStencilBufferIfNeeded(internalDepthStencilFormat, width, height); bool mustRestoreFBO = true; - if (m_attrs.antialias) { + if (m_attrs.antialias && !isGLES2Compliant()) { ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); if (m_state.boundFBO == m_multisampleFBO) mustRestoreFBO = false; @@ -203,6 +290,10 @@ bool GraphicsContext3D::reshapeFBOs(const IntSize& size) void GraphicsContext3D::attachDepthAndStencilBufferIfNeeded(GLuint internalDepthStencilFormat, int width, int height) { if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth)) { +#if PLATFORM(QT) + bool supportPackedDepthStencilBuffer = internalDepthStencilFormat == GL_DEPTH24_STENCIL8_EXT; + if (supportPackedDepthStencilBuffer || !isGLES2Compliant()) { +#endif ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthStencilBuffer); ::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalDepthStencilFormat, width, height); if (m_attrs.stencil) @@ -210,6 +301,21 @@ void GraphicsContext3D::attachDepthAndStencilBufferIfNeeded(GLuint internalDepth if (m_attrs.depth) ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer); ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); +#if PLATFORM(QT) + } else { + if (m_attrs.stencil) { + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_stencilBuffer); + ::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8, width, height); + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_stencilBuffer); + } + if (m_attrs.depth) { + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer); + ::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, width, height); + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer); + } + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + } +#endif } if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { @@ -220,6 +326,18 @@ void GraphicsContext3D::attachDepthAndStencilBufferIfNeeded(GLuint internalDepth void GraphicsContext3D::resolveMultisamplingIfNecessary(const IntRect& rect) { +#if PLATFORM(QT) + Q_ASSERT(m_private); + if (!m_attrs.antialias) + return; + + // QTFIXME: Probably not needed, iOS uses following code successfully + if (isGLES2Compliant()) { + notImplemented(); + return; + } +#endif + TemporaryOpenGLSetting scopedScissor(GL_SCISSOR_TEST, GL_FALSE); TemporaryOpenGLSetting scopedDither(GL_DITHER, GL_FALSE); TemporaryOpenGLSetting scopedDepth(GL_DEPTH_TEST, GL_FALSE); @@ -249,6 +367,9 @@ void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalfo { makeContextCurrent(); #if !PLATFORM(IOS) +#if PLATFORM(QT) + if (!isGLES2Compliant()) { +#endif switch (internalformat) { case DEPTH_STENCIL: internalformat = GL_DEPTH24_STENCIL8_EXT; @@ -264,6 +385,9 @@ void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalfo internalformat = GL_RGB; break; } +#if PLATFORM(QT) + } +#endif #endif ::glRenderbufferStorageEXT(target, internalformat, width, height); } @@ -275,6 +399,12 @@ void GraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value) // whereas GLES2 return the number of vectors (each vector has 4 components). // Therefore, the value returned by desktop GL needs to be divided by 4. makeContextCurrent(); +#if PLATFORM(QT) + if (isGLES2Compliant()) { + ::glGetIntegerv(pname, value); + return; + } +#endif switch (pname) { #if !PLATFORM(IOS) case MAX_FRAGMENT_UNIFORM_VECTORS: @@ -307,12 +437,19 @@ void GraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value) void GraphicsContext3D::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, GC3Dint* range, GC3Dint* precision) { +#if !PLATFORM(QT) UNUSED_PARAM(shaderType); +#endif ASSERT(range); ASSERT(precision); makeContextCurrent(); +#if PLATFORM(QT) + m_functions->glGetShaderPrecisionFormat(shaderType, precisionType, range, precision); + return; +#endif + switch (precisionType) { case GraphicsContext3D::LOW_INT: case GraphicsContext3D::MEDIUM_INT: @@ -346,6 +483,9 @@ bool GraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum inte GC3Denum openGLFormat = format; GC3Denum openGLInternalFormat = internalformat; #if !PLATFORM(IOS) +#if PLATFORM(QT) + if (!isGLES2Compliant()) { +#endif if (type == GL_FLOAT) { if (format == GL_RGBA) openGLInternalFormat = GL_RGBA32F_ARB; @@ -370,6 +510,9 @@ bool GraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum inte openGLFormat = GL_RGBA; else if (format == Extensions3D::SRGB_EXT) openGLFormat = GL_RGB; +#if PLATFORM(QT) + } +#endif #endif texImage2DDirect(target, level, openGLInternalFormat, width, height, border, openGLFormat, type, pixels); return true; @@ -404,6 +547,7 @@ Extensions3D* GraphicsContext3D::getExtensions() void GraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data) { + ASSERT(m_private); // FIXME: remove the two glFlush calls when the driver bug is fixed, i.e., // all previous rendering calls should be done before reading pixels. makeContextCurrent(); diff --git a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp index f1509fb5f..03460cf2c 100644 --- a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp +++ b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp @@ -67,11 +67,20 @@ #define GL_RGBA32F_ARB 0x8814 #define GL_RGB32F_ARB 0x8815 #else -#if USE(OPENGL_ES_2) +#if PLATFORM(QT) +#define FUNCTIONS m_functions +#include "OpenGLShimsQt.h" + +#define glGetError(...) m_functions->glGetError(__VA_ARGS__) +#define glIsEnabled(...) m_functions->glIsEnabled(__VA_ARGS__) + +#define scopedScissor(c, s) scopedScissor(m_functions, c, s) +#define scopedDither(c, s) scopedDither(m_functions, c, s) +#elif USE(OPENGL_ES_2) #include "OpenGLESShims.h" #elif PLATFORM(MAC) #include <OpenGL/gl.h> -#elif PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(QT) || PLATFORM(WIN) +#elif PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN) #include "OpenGLShims.h" #endif #endif @@ -403,7 +412,7 @@ bool GraphicsContext3D::checkVaryingsPacking(Platform3DObject vertexShader, Plat } GC3Dint maxVaryingVectors = 0; -#if !PLATFORM(IOS) && !((PLATFORM(WIN) || PLATFORM(GTK)) && USE(OPENGL_ES_2)) +#if !PLATFORM(IOS) && !((PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(QT)) && USE(OPENGL_ES_2)) GC3Dint maxVaryingFloats = 0; ::glGetIntegerv(GL_MAX_VARYING_FLOATS, &maxVaryingFloats); maxVaryingVectors = maxVaryingFloats / 4; @@ -1012,7 +1021,7 @@ GC3Denum GraphicsContext3D::getError() } makeContextCurrent(); - return ::glGetError(); + return glGetError(); } String GraphicsContext3D::getString(GC3Denum name) @@ -1039,7 +1048,7 @@ GC3Dboolean GraphicsContext3D::isBuffer(Platform3DObject buffer) GC3Dboolean GraphicsContext3D::isEnabled(GC3Denum cap) { makeContextCurrent(); - return ::glIsEnabled(cap); + return glIsEnabled(cap); } GC3Dboolean GraphicsContext3D::isFramebuffer(Platform3DObject framebuffer) @@ -1382,6 +1391,7 @@ void GraphicsContext3D::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsize ::glViewport(x, y, width, height); } +#if !PLATFORM(QT) || ENABLE(WEBGL2) Platform3DObject GraphicsContext3D::createVertexArray() { makeContextCurrent(); @@ -1432,6 +1442,7 @@ void GraphicsContext3D::bindVertexArray(Platform3DObject array) UNUSED_PARAM(array); #endif } +#endif void GraphicsContext3D::getBooleanv(GC3Denum pname, GC3Dboolean* value) { diff --git a/Source/WebCore/platform/graphics/opengl/TemporaryOpenGLSetting.cpp b/Source/WebCore/platform/graphics/opengl/TemporaryOpenGLSetting.cpp index b948c3a15..c502a0c3b 100644 --- a/Source/WebCore/platform/graphics/opengl/TemporaryOpenGLSetting.cpp +++ b/Source/WebCore/platform/graphics/opengl/TemporaryOpenGLSetting.cpp @@ -39,16 +39,25 @@ #elif PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN) #include "OpenGLShims.h" #elif PLATFORM(QT) -#include <qopengl.h> +#define FUNCTIONS m_functions +#include "OpenGLShimsQt.h" +#define glIsEnabled(...) m_functions->glIsEnabled(__VA_ARGS__) #endif namespace WebCore { +#if PLATFORM(QT) +TemporaryOpenGLSetting::TemporaryOpenGLSetting(QOpenGLExtensions* functions, GC3Denum capability, GC3Denum scopedState) +#else TemporaryOpenGLSetting::TemporaryOpenGLSetting(GLenum capability, GLenum scopedState) +#endif : m_capability(capability) , m_scopedState(scopedState) +#if PLATFORM(QT) + , m_functions(functions) +#endif { - m_originalState = ::glIsEnabled(m_capability); + m_originalState = glIsEnabled(m_capability); if (m_originalState == m_scopedState) return; diff --git a/Source/WebCore/platform/graphics/opengl/TemporaryOpenGLSetting.h b/Source/WebCore/platform/graphics/opengl/TemporaryOpenGLSetting.h index 833f8b6be..736b57fa1 100644 --- a/Source/WebCore/platform/graphics/opengl/TemporaryOpenGLSetting.h +++ b/Source/WebCore/platform/graphics/opengl/TemporaryOpenGLSetting.h @@ -31,6 +31,12 @@ #include <wtf/Noncopyable.h> +#if PLATFORM(QT) +QT_BEGIN_NAMESPACE +class QOpenGLExtensions; +QT_END_NAMESPACE +#endif + namespace WebCore { // TemporaryOpenGLSetting<> is useful for temporarily disabling (or enabling) a particular OpenGL @@ -43,13 +49,21 @@ namespace WebCore { class TemporaryOpenGLSetting { WTF_MAKE_NONCOPYABLE(TemporaryOpenGLSetting); public: +#if PLATFORM(QT) + TemporaryOpenGLSetting(QOpenGLExtensions*, GC3Denum capability, GC3Denum scopedState); +#else TemporaryOpenGLSetting(GC3Denum capability, GC3Denum scopedState); +#endif ~TemporaryOpenGLSetting(); private: const GC3Denum m_capability; const GC3Denum m_scopedState; GC3Denum m_originalState; + +#if PLATFORM(QT) + QOpenGLExtensions* m_functions { nullptr }; +#endif }; } diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp index a0b76cc88..7f2f07b60 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp +++ b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp @@ -19,13 +19,7 @@ #include "config.h" #include "GraphicsContext3D.h" -#if ENABLE(GRAPHICS_CONTEXT_3D) - -#if USE(OPENGL_ES_2) -#include "Extensions3DOpenGLES.h" -#else -#include "Extensions3DOpenGL.h" -#endif +#include "Extensions3DOpenGLCommon.h" #include "GraphicsContext.h" #include "GraphicsSurface.h" #include "HostWindow.h" @@ -33,32 +27,51 @@ #include "ImageData.h" #include "NativeImageQt.h" #include "NotImplemented.h" -#include "OpenGLShims.h" #include "QWebPageClient.h" #include "SharedBuffer.h" #include "TextureMapperPlatformLayer.h" +#include <QOffscreenSurface> +#include <private/qopenglextensions_p.h> #include <qpa/qplatformpixmap.h> #include <wtf/text/CString.h> -#include <QOffscreenSurface> - #if USE(TEXTURE_MAPPER_GL) #include <texmap/TextureMapperGL.h> #endif +#if ENABLE(GRAPHICS_CONTEXT_3D) + +QT_BEGIN_NAMESPACE +extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize&, bool alpha_format, bool include_alpha); +QT_END_NAMESPACE + namespace WebCore { #if !defined(GLchar) typedef char GLchar; #endif -#if !defined(GL_DEPTH24_STENCIL8) -#define GL_DEPTH24_STENCIL8 0x88F0 +#ifndef GL_VERTEX_PROGRAM_POINT_SIZE +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 #endif -class GraphicsContext3DPrivate final - : public TextureMapperPlatformLayer -{ +#ifndef GL_POINT_SPRITE +#define GL_POINT_SPRITE 0x8861 +#endif + +#ifndef GL_DEPTH24_STENCIL8 +#define GL_DEPTH24_STENCIL8 0x88F0 +#endif + +#ifndef GL_READ_FRAMEBUFFER +#define GL_READ_FRAMEBUFFER 0x8CA8 +#endif + +#ifndef GL_DRAW_FRAMEBUFFER +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#endif + +class GraphicsContext3DPrivate final : public TextureMapperPlatformLayer, public QOpenGLExtensions { public: GraphicsContext3DPrivate(GraphicsContext3D*, HostWindow*, GraphicsContext3D::RenderStyle); ~GraphicsContext3DPrivate(); @@ -71,13 +84,16 @@ public: #endif QRectF boundingRect() const; - void blitMultisampleFramebuffer() const; - void blitMultisampleFramebufferAndRestoreContext() const; + void blitMultisampleFramebuffer(); + void blitMultisampleFramebufferAndRestoreContext(); bool makeCurrentIfNeeded() const; void createOffscreenBuffers(); void initializeANGLE(); void createGraphicsSurfaces(const IntSize&); + bool isOpenGLES() const; + bool isValid() const; + GraphicsContext3D* m_context; HostWindow* m_hostWindow; PlatformGraphicsSurface3D m_surface; @@ -87,10 +103,43 @@ public: GraphicsSurface::Flags m_surfaceFlags; RefPtr<GraphicsSurface> m_graphicsSurface; #endif + + // Register as a child of a Qt context to make the necessary when it may be destroyed before the GraphicsContext3D instance + class QtContextWatcher : public QObject { + public: + QtContextWatcher(QObject* ctx, GraphicsContext3DPrivate* watcher) + : QObject(ctx), m_watcher(watcher) { } + ~QtContextWatcher() { m_watcher->m_platformContext = 0; m_watcher->m_platformContextWatcher = 0; } + + private: + GraphicsContext3DPrivate* m_watcher; + }; + QtContextWatcher* m_platformContextWatcher; }; +bool GraphicsContext3DPrivate::isOpenGLES() const +{ + if (m_platformContext) + return m_platformContext->isOpenGLES(); +#if USE(OPENGL_ES_2) + return true; +#else + return false; +#endif +} + +bool GraphicsContext3DPrivate::isValid() const +{ + if (!m_platformContext || !m_platformContext->isValid()) + return false; + return m_platformContext->isOpenGLES() || m_platformContext->format().majorVersion() >= 2; +} + bool GraphicsContext3D::isGLES2Compliant() const { + if (m_private) + return m_private->isOpenGLES(); + ASSERT_NOT_REACHED(); #if USE(OPENGL_ES_2) return true; #else @@ -104,17 +153,23 @@ GraphicsContext3DPrivate::GraphicsContext3DPrivate(GraphicsContext3D* context, H , m_surface(0) , m_platformContext(0) , m_surfaceOwner(0) + , m_platformContextWatcher(0) { if (renderStyle == GraphicsContext3D::RenderToCurrentGLContext) { m_platformContext = QOpenGLContext::currentContext(); if (m_platformContext) m_surface = m_platformContext->surface(); + + // Watcher needed to invalidate the GL context if destroyed before this instance + m_platformContextWatcher = new QtContextWatcher(m_platformContext, this); + + initializeOpenGLFunctions(); return; } QOpenGLContext* shareContext = 0; - if (hostWindow && hostWindow->platformPageClient() && hostWindow->platformPageClient()->makeOpenGLContextCurrentIfAvailable()) - shareContext = QOpenGLContext::currentContext(); + if (hostWindow && hostWindow->platformPageClient()) + shareContext = hostWindow->platformPageClient()->openGLContextIfAvailable(); QOffscreenSurface* surface = new QOffscreenSurface; surface->create(); @@ -125,15 +180,18 @@ GraphicsContext3DPrivate::GraphicsContext3DPrivate(GraphicsContext3D* context, H if (shareContext) m_platformContext->setShareContext(shareContext); - if (!m_platformContext->create()) + if (!m_platformContext->create()) { + delete m_platformContext; + m_platformContext = 0; return; + } makeCurrentIfNeeded(); + initializeOpenGLFunctions(); #if USE(GRAPHICS_SURFACE) IntSize surfaceSize(m_context->m_currentWidth, m_context->m_currentHeight); - m_surfaceFlags = GraphicsSurface::SupportsTextureTarget - | GraphicsSurface::SupportsSharing; + m_surfaceFlags = GraphicsSurface::SupportsTextureTarget | GraphicsSurface::SupportsSharing; if (!surfaceSize.isEmpty()) m_graphicsSurface = GraphicsSurface::create(surfaceSize, m_surfaceFlags, m_platformContext); @@ -145,31 +203,31 @@ void GraphicsContext3DPrivate::createOffscreenBuffers() glGenFramebuffers(/* count */ 1, &m_context->m_fbo); glGenTextures(1, &m_context->m_texture); - glBindTexture(GraphicsContext3D::TEXTURE_2D, m_context->m_texture); - glTexParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); - glTexParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); - glTexParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); - glTexParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); - glBindTexture(GraphicsContext3D::TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_2D, m_context->m_texture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, 0); // Create a multisample FBO. if (m_context->m_attrs.antialias) { glGenFramebuffers(1, &m_context->m_multisampleFBO); - glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_context->m_multisampleFBO); + glBindFramebuffer(GL_FRAMEBUFFER, m_context->m_multisampleFBO); m_context->m_state.boundFBO = m_context->m_multisampleFBO; glGenRenderbuffers(1, &m_context->m_multisampleColorBuffer); if (m_context->m_attrs.stencil || m_context->m_attrs.depth) glGenRenderbuffers(1, &m_context->m_multisampleDepthStencilBuffer); } else { // Bind canvas FBO. - glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_context->m_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, m_context->m_fbo); m_context->m_state.boundFBO = m_context->m_fbo; -#if USE(OPENGL_ES_2) - if (m_context->m_attrs.depth) - glGenRenderbuffers(1, &m_context->m_depthBuffer); - if (m_context->m_attrs.stencil) - glGenRenderbuffers(1, &m_context->m_stencilBuffer); -#endif + if (isOpenGLES()) { + if (m_context->m_attrs.depth) + glGenRenderbuffers(1, &m_context->m_depthBuffer); + if (m_context->m_attrs.stencil) + glGenRenderbuffers(1, &m_context->m_stencilBuffer); + } if (m_context->m_attrs.stencil || m_context->m_attrs.depth) glGenRenderbuffers(1, &m_context->m_depthStencilBuffer); } @@ -206,11 +264,9 @@ GraphicsContext3DPrivate::~GraphicsContext3DPrivate() { delete m_surfaceOwner; m_surfaceOwner = 0; -} -static inline quint32 swapBgrToRgb(quint32 pixel) -{ - return (((pixel << 16) | (pixel >> 16)) & 0x00ff00ff) | (pixel & 0xff00ff00); + delete m_platformContextWatcher; + m_platformContextWatcher = 0; } void GraphicsContext3DPrivate::paintToTextureMapper(TextureMapper& textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity) @@ -218,34 +274,15 @@ void GraphicsContext3DPrivate::paintToTextureMapper(TextureMapper& textureMapper m_context->markLayerComposited(); blitMultisampleFramebufferAndRestoreContext(); - // FIXME: For now we have OpenGLMode only -// if (textureMapper->accelerationMode() == TextureMapper::OpenGLMode) { + if (textureMapper.accelerationMode() == TextureMapper::OpenGLMode) { TextureMapperGL& texmapGL = static_cast<TextureMapperGL&>(textureMapper); -#if USE(GRAPHICS_SURFACE) - ASSERT(m_graphicsSurface); - // CGL only provides us the context, but not the view the context is currently bound to. - // To make sure the context is bound the the right surface we have to do a makeCurrent through QOpenGL again. - // FIXME: Remove this code as soon as GraphicsSurfaceMac makes use of NSOpenGL. - QOpenGLContext* currentContext = QOpenGLContext::currentContext(); - QSurface* currentSurface = currentContext->surface(); - makeCurrentIfNeeded(); - - m_graphicsSurface->copyFromTexture(m_context->m_texture, IntRect(0, 0, m_context->m_currentWidth, m_context->m_currentHeight)); - - // CGL only provides us the context, but not the view the context is currently bound to. - // To make sure the context is bound the the right surface we have to do a makeCurrent through QOpenGL again. - // FIXME: Remove this code as soon as GraphicsSurfaceMac makes use of NSOpenGL. - currentContext->makeCurrent(currentSurface); - - m_graphicsSurface->paintToTextureMapper(texmapGL, targetRect, matrix, opacity); -#else TextureMapperGL::Flags flags = TextureMapperGL::ShouldFlipTexture | (m_context->m_attrs.alpha ? TextureMapperGL::ShouldBlend : 0); IntSize textureSize(m_context->m_currentWidth, m_context->m_currentHeight); texmapGL.drawTexture(m_context->m_texture, flags, textureSize, targetRect, matrix, opacity); -#endif return; -// } + } + // Alternatively read pixels to a memory buffer. GraphicsContext* context = textureMapper.graphicsContext(); QPainter* painter = context->platformContext(); painter->save(); @@ -255,36 +292,13 @@ void GraphicsContext3DPrivate::paintToTextureMapper(TextureMapper& textureMapper const int height = m_context->m_currentHeight; const int width = m_context->m_currentWidth; - // Alternatively read pixels to a memory buffer. - QImage offscreenImage(width, height, QImage::Format_ARGB32); - quint32* imagePixels = reinterpret_cast<quint32*>(offscreenImage.bits()); - + painter->beginNativePainting(); makeCurrentIfNeeded(); - glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_context->m_fbo); - glReadPixels(/* x */ 0, /* y */ 0, width, height, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, imagePixels); - glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_context->m_state.boundFBO); - - // OpenGL gives us ABGR on 32 bits, and with the origin at the bottom left - // We need RGB32 or ARGB32_PM, with the origin at the top left. - quint32* pixelsSrc = imagePixels; - const int halfHeight = height / 2; - for (int row = 0; row < halfHeight; ++row) { - const int targetIdx = (height - 1 - row) * width; - quint32* pixelsDst = imagePixels + targetIdx; - for (int column = 0; column < width; ++column) { - quint32 tempPixel = *pixelsSrc; - *pixelsSrc = swapBgrToRgb(*pixelsDst); - *pixelsDst = swapBgrToRgb(tempPixel); - ++pixelsSrc; - ++pixelsDst; - } - } - if (static_cast<int>(height) % 2) { - for (int column = 0; column < width; ++column) { - *pixelsSrc = swapBgrToRgb(*pixelsSrc); - ++pixelsSrc; - } - } + glBindFramebuffer(GL_FRAMEBUFFER, m_context->m_fbo); + QImage offscreenImage = qt_gl_read_framebuffer(QSize(width, height), true, true); + glBindFramebuffer(GL_FRAMEBUFFER, m_context->m_state.boundFBO); + + painter->endNativePainting(); painter->drawImage(targetRect, offscreenImage); painter->restore(); @@ -318,19 +332,21 @@ QRectF GraphicsContext3DPrivate::boundingRect() const return QRectF(QPointF(0, 0), QSizeF(m_context->m_currentWidth, m_context->m_currentHeight)); } -void GraphicsContext3DPrivate::blitMultisampleFramebuffer() const +void GraphicsContext3DPrivate::blitMultisampleFramebuffer() { if (!m_context->m_attrs.antialias) return; -#if !USE(OPENGL_ES_2) - glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, m_context->m_multisampleFBO); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, m_context->m_fbo); - glBlitFramebuffer(0, 0, m_context->m_currentWidth, m_context->m_currentHeight, 0, 0, m_context->m_currentWidth, m_context->m_currentHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); -#endif - glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_context->m_state.boundFBO); + + if (!isOpenGLES()) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_context->m_multisampleFBO); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_context->m_fbo); + glBlitFramebuffer(0, 0, m_context->m_currentWidth, m_context->m_currentHeight, 0, 0, m_context->m_currentWidth, m_context->m_currentHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); + } + + glBindFramebuffer(GL_FRAMEBUFFER, m_context->m_state.boundFBO); } -void GraphicsContext3DPrivate::blitMultisampleFramebufferAndRestoreContext() const +void GraphicsContext3DPrivate::blitMultisampleFramebufferAndRestoreContext() { const QOpenGLContext* currentContext = QOpenGLContext::currentContext(); QSurface* currentSurface = 0; @@ -352,6 +368,8 @@ void GraphicsContext3DPrivate::blitMultisampleFramebufferAndRestoreContext() con bool GraphicsContext3DPrivate::makeCurrentIfNeeded() const { + if (!m_platformContext) + return false; const QOpenGLContext* currentContext = QOpenGLContext::currentContext(); if (currentContext == m_platformContext) return true; @@ -382,39 +400,34 @@ PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attri GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle) : m_currentWidth(0) , m_currentHeight(0) - , m_compiler(isGLES2Compliant() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT) , m_attrs(attrs) , m_renderStyle(renderStyle) , m_texture(0) , m_compositorTexture(0) , m_fbo(0) -#if USE(OPENGL_ES_2) , m_depthBuffer(0) , m_stencilBuffer(0) -#endif , m_depthStencilBuffer(0) , m_layerComposited(false) , m_internalColorFormat(0) , m_multisampleFBO(0) , m_multisampleDepthStencilBuffer(0) , m_multisampleColorBuffer(0) + , m_functions(0) , m_private(std::make_unique<GraphicsContext3DPrivate>(this, hostWindow, renderStyle)) + , m_compiler(isGLES2Compliant() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT) + , m_webglContext(nullptr) { - validateAttributes(); - if (!m_private->m_surface || !m_private->m_platformContext) { LOG_ERROR("GraphicsContext3D: GL context creation failed."); m_private = nullptr; return; } - static bool initialized = false; - static bool success = true; - if (!initialized) { - success = initializeOpenGLShims(); - initialized = true; - } - if (!success) { + m_functions = m_private.get(); + validateAttributes(); + + if (!m_private->isValid()) { m_private = nullptr; return; } @@ -424,13 +437,13 @@ GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWi m_private->initializeANGLE(); -#if !USE(OPENGL_ES_2) - glEnable(GL_POINT_SPRITE); - glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); -#endif + if (!isGLES2Compliant()) { + m_functions->glEnable(GL_POINT_SPRITE); + m_functions->glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + } if (renderStyle != RenderToCurrentGLContext) - glClearColor(0.0, 0.0, 0.0, 0.0); + m_functions->glClearColor(0.0, 0.0, 0.0, 0.0); } GraphicsContext3D::~GraphicsContext3D() @@ -439,23 +452,26 @@ GraphicsContext3D::~GraphicsContext3D() if (!m_private) return; - makeContextCurrent(); - glDeleteTextures(1, &m_texture); - glDeleteFramebuffers(1, &m_fbo); - if (m_attrs.antialias) { - glDeleteRenderbuffers(1, &m_multisampleColorBuffer); - glDeleteFramebuffers(1, &m_multisampleFBO); - if (m_attrs.stencil || m_attrs.depth) - glDeleteRenderbuffers(1, &m_multisampleDepthStencilBuffer); - } else if (m_attrs.stencil || m_attrs.depth) { -#if USE(OPENGL_ES_2) - if (m_attrs.depth) - glDeleteRenderbuffers(1, &m_depthBuffer); - if (m_attrs.stencil) - glDeleteRenderbuffers(1, &m_stencilBuffer); -#endif - glDeleteRenderbuffers(1, &m_depthStencilBuffer); + if (makeContextCurrent()) { + m_functions->glDeleteTextures(1, &m_texture); + m_functions->glDeleteFramebuffers(1, &m_fbo); + if (m_attrs.antialias) { + m_functions->glDeleteRenderbuffers(1, &m_multisampleColorBuffer); + m_functions->glDeleteFramebuffers(1, &m_multisampleFBO); + if (m_attrs.stencil || m_attrs.depth) + m_functions->glDeleteRenderbuffers(1, &m_multisampleDepthStencilBuffer); + } else if (m_attrs.stencil || m_attrs.depth) { + if (isGLES2Compliant()) { + if (m_attrs.depth) + m_functions->glDeleteRenderbuffers(1, &m_depthBuffer); + if (m_attrs.stencil) + m_functions->glDeleteRenderbuffers(1, &m_stencilBuffer); + } + m_functions->glDeleteRenderbuffers(1, &m_depthStencilBuffer); + } } + + m_functions = 0; } PlatformGraphicsContext3D GraphicsContext3D::platformGraphicsContext3D() @@ -475,7 +491,7 @@ PlatformLayer* GraphicsContext3D::platformLayer() const bool GraphicsContext3D::makeContextCurrent() { - if (!m_private || m_renderStyle == RenderToCurrentGLContext) + if (!m_private) return false; return m_private->makeCurrentIfNeeded(); } diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index d1ab885d9..00bcb8532 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -49,6 +49,7 @@ #include "FloatConversion.h" #include "Font.h" #include "ImageBuffer.h" +#include "ImageBufferDataQt.h" #include "NotImplemented.h" #include "Path.h" #include "Pattern.h" @@ -959,15 +960,8 @@ void GraphicsContext::clipToImageBuffer(ImageBuffer& buffer, const FloatRect& de if (paintingDisabled()) return; - RefPtr<Image> image = buffer.copyImage(DontCopyBackingStore); - QPixmap* nativeImage = image->nativeImageForCurrentFrame(); - if (!nativeImage) - return; - IntRect rect = enclosingIntRect(destRect); - QPixmap alphaMask = *nativeImage; - - pushTransparencyLayerInternal(rect, 1.0, alphaMask); + buffer.m_data.m_impl->clip(*this, rect); } void drawFocusRingForPath(QPainter* p, const QPainterPath& path, const Color& color, bool antiAliasing) @@ -1553,7 +1547,7 @@ void GraphicsContext::setCTM(const AffineTransform& transform) m_data->p()->setWorldTransform(transform); } -#if ENABLE(3D_RENDERING) +#if ENABLE(3D_TRANSFORMS) TransformationMatrix GraphicsContext::get3DTransform() const { if (paintingDisabled()) @@ -1757,6 +1751,10 @@ void GraphicsContext::takeOwnershipOfPlatformContext() m_data->takeOwnershipOfPlatformContext(); } +bool GraphicsContext::isAcceleratedContext() const +{ + return (platformContext()->paintEngine()->type() == QPaintEngine::OpenGL2); } +} // vim: ts=4 sw=4 et diff --git a/Source/WebCore/platform/graphics/qt/ImageBufferDataQt.cpp b/Source/WebCore/platform/graphics/qt/ImageBufferDataQt.cpp new file mode 100644 index 000000000..b277fd421 --- /dev/null +++ b/Source/WebCore/platform/graphics/qt/ImageBufferDataQt.cpp @@ -0,0 +1,538 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2008 Holger Hans Peter Freyther + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. + * Copyright (C) 2014 Digia Plc. and/or its subsidiary(-ies) + * + * 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 "ImageBuffer.h" + +#include "GraphicsContext.h" +#include "GraphicsSurface.h" +#include "ImageData.h" +#include "IntRect.h" +#include "StillImageQt.h" + +#include <QImage> +#include <QPaintEngine> +#include <QPainter> +#include <QPixmap> + +#if ENABLE(ACCELERATED_2D_CANVAS) +#include "QFramebufferPaintDevice.h" +#include "TextureMapper.h" +#include "TextureMapperGL.h" +#include "TextureMapperPlatformLayer.h" +#include <QOffscreenSurface> +#include <QOpenGLContext> +#include <QOpenGLFramebufferObject> +#include <QOpenGLPaintDevice> +#include <QThreadStorage> +#include <private/qopenglpaintengine_p.h> +#endif + +namespace WebCore { + +#if ENABLE(ACCELERATED_2D_CANVAS) + +class QOpenGLContextThreadStorage { +public: + QOpenGLContext* context() + { + QOpenGLContext*& context = storage.localData(); + if (!context) { + context = new QOpenGLContext; + context->create(); + } + return context; + } + +private: + QThreadStorage<QOpenGLContext*> storage; +}; + +Q_GLOBAL_STATIC(QOpenGLContextThreadStorage, imagebuffer_opengl_context) + +// The owner of the surface needs to be separate from QFramebufferPaintDevice, since the surface +// must already be current with the QFramebufferObject constructor is called. +class ImageBufferContext { +public: + ImageBufferContext(QOpenGLContext* sharedContext) + : m_ownSurface(0) + { + if (sharedContext) + m_format = sharedContext->format(); + + m_context = sharedContext ? sharedContext : imagebuffer_opengl_context->context(); + + m_surface = m_context->surface(); + } + ~ImageBufferContext() + { + if (QOpenGLContext::currentContext() == m_context && m_context->surface() == m_ownSurface) + m_context->doneCurrent(); + delete m_ownSurface; + } + void createSurfaceIfNeeded() + { + if (m_surface) + return; + + m_ownSurface = new QOffscreenSurface; + m_ownSurface->setFormat(m_format); + m_ownSurface->create(); + + m_surface = m_ownSurface; + } + void makeCurrentIfNeeded() + { + if (QOpenGLContext::currentContext() != m_context) { + createSurfaceIfNeeded(); + + m_context->makeCurrent(m_surface); + } + } + QOpenGLContext* context() { return m_context; } + +private: + QSurface* m_surface; + QOffscreenSurface* m_ownSurface; + QOpenGLContext* m_context; + QSurfaceFormat m_format; +}; + +// ---------------------- ImageBufferDataPrivateAccelerated + +struct ImageBufferDataPrivateAccelerated final : public TextureMapperPlatformLayer, public ImageBufferDataPrivate { + ImageBufferDataPrivateAccelerated(const IntSize&, QOpenGLContext* sharedContext); + virtual ~ImageBufferDataPrivateAccelerated(); + + QPaintDevice* paintDevice() final { return m_paintDevice; } + QImage toQImage() const final; + RefPtr<Image> image() const final; + RefPtr<Image> copyImage() const final; + RefPtr<Image> takeImage() final; + bool isAccelerated() const final { return true; } + PlatformLayer* platformLayer() final { return this; } + + void invalidateState() const; + void draw(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, + CompositeOperator, BlendMode, bool ownContext) final; + void drawPattern(GraphicsContext& destContext, const FloatRect& srcRect, const AffineTransform& patternTransform, + const FloatPoint& phase, const FloatSize& spacing, CompositeOperator, + const FloatRect& destRect, BlendMode, bool ownContext) final; + void clip(GraphicsContext&, const IntRect& floatRect) const final; + void platformTransformColorSpace(const Vector<int>& lookUpTable) final; + + // TextureMapperPlatformLayer: + void paintToTextureMapper(TextureMapper&, const FloatRect&, const TransformationMatrix& modelViewMatrix = TransformationMatrix(), float opacity = 1.0) final; +#if USE(GRAPHICS_SURFACE) + IntSize platformLayerSize() const final; + uint32_t copyToGraphicsSurface() final; + GraphicsSurfaceToken graphicsSurfaceToken() const final; + RefPtr<GraphicsSurface> m_graphicsSurface; +#endif +private: + QFramebufferPaintDevice* m_paintDevice; + ImageBufferContext* m_context; +}; + +ImageBufferDataPrivateAccelerated::ImageBufferDataPrivateAccelerated(const IntSize& size, QOpenGLContext* sharedContext) +{ + m_context = new ImageBufferContext(sharedContext); + m_context->makeCurrentIfNeeded(); + + m_paintDevice = new QFramebufferPaintDevice(size); +} + +ImageBufferDataPrivateAccelerated::~ImageBufferDataPrivateAccelerated() +{ + if (client()) + client()->platformLayerWillBeDestroyed(); + delete m_paintDevice; + delete m_context; +} + +QImage ImageBufferDataPrivateAccelerated::toQImage() const +{ + invalidateState(); + return m_paintDevice->toImage(); +} + +RefPtr<Image> ImageBufferDataPrivateAccelerated::image() const +{ + return copyImage(); +} + +RefPtr<Image> ImageBufferDataPrivateAccelerated::copyImage() const +{ + return StillImage::create(QPixmap::fromImage(toQImage())); +} + +RefPtr<Image> ImageBufferDataPrivateAccelerated::takeImage() +{ + return StillImage::create(QPixmap::fromImage(toQImage())); +} + +void ImageBufferDataPrivateAccelerated::invalidateState() const +{ + // This will flush pending QPainter operations and force ensureActiveTarget() to be called on the next paint. + QOpenGL2PaintEngineEx* acceleratedPaintEngine = static_cast<QOpenGL2PaintEngineEx*>(m_paintDevice->paintEngine()); + acceleratedPaintEngine->invalidateState(); +} + +void ImageBufferDataPrivateAccelerated::draw(GraphicsContext& destContext, const FloatRect& destRect, + const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode, bool /*ownContext*/) +{ + if (destContext.isAcceleratedContext()) { + invalidateState(); + + // If accelerated compositing is disabled, this may be the painter of the QGLWidget, which is a QGL2PaintEngineEx. + QOpenGL2PaintEngineEx* acceleratedPaintEngine = dynamic_cast<QOpenGL2PaintEngineEx*>(destContext.platformContext()->paintEngine()); // toQOpenGL2PaintEngineEx(destContext.platformContext()->paintEngine()); + if (acceleratedPaintEngine) { + QPaintDevice* targetPaintDevice = acceleratedPaintEngine->paintDevice(); + + QRect rect(QPoint(), m_paintDevice->size()); + + // drawTexture's rendering is flipped relative to QtWebKit's convention, so we need to compensate + FloatRect srcRectFlipped = m_paintDevice->paintFlipped() + ? FloatRect(srcRect.x(), srcRect.maxY(), srcRect.width(), -srcRect.height()) + : FloatRect(srcRect.x(), rect.height() - srcRect.maxY(), srcRect.width(), srcRect.height()); + + // Using the same texture as source and target of a rendering operation is undefined in OpenGL, + // so if that's the case we need to use a temporary intermediate buffer. + if (m_paintDevice == targetPaintDevice) { + m_context->makeCurrentIfNeeded(); + + QFramebufferPaintDevice device(rect.size(), QOpenGLFramebufferObject::NoAttachment, false); + + // We disable flipping in order to do a pure blit into the intermediate buffer + device.setPaintFlipped(false); + + QPainter painter(&device); + QOpenGL2PaintEngineEx* pe = static_cast<QOpenGL2PaintEngineEx*>(painter.paintEngine()); + pe->drawTexture(rect, m_paintDevice->texture(), rect.size(), rect); + painter.end(); + + acceleratedPaintEngine->drawTexture(destRect, device.texture(), rect.size(), srcRectFlipped); + } else { + acceleratedPaintEngine->drawTexture(destRect, m_paintDevice->texture(), rect.size(), srcRectFlipped); + } + + return; + } + } + RefPtr<Image> image = StillImage::create(QPixmap::fromImage(toQImage())); + destContext.drawImage(*image, destRect, srcRect, ImagePaintingOptions(op, blendMode, DoNotRespectImageOrientation)); +} + + +void ImageBufferDataPrivateAccelerated::drawPattern(GraphicsContext& destContext, const FloatRect& srcRect, const AffineTransform& patternTransform, + const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, const FloatRect& destRect, BlendMode blendMode, bool /*ownContext*/) +{ + RefPtr<Image> image = StillImage::create(QPixmap::fromImage(toQImage())); + image->drawPattern(destContext, srcRect, patternTransform, phase, spacing, op, destRect, blendMode); +} + +void ImageBufferDataPrivateAccelerated::clip(GraphicsContext& context, const IntRect& rect) const +{ + QPixmap alphaMask = QPixmap::fromImage(toQImage()); + context.pushTransparencyLayerInternal(rect, 1.0, alphaMask); +} + +void ImageBufferDataPrivateAccelerated::platformTransformColorSpace(const Vector<int>& lookUpTable) +{ + QPainter* painter = paintDevice()->paintEngine()->painter(); + + QImage image = toQImage().convertToFormat(QImage::Format_ARGB32); + ASSERT(!image.isNull()); + + uchar* bits = image.bits(); + const int bytesPerLine = image.bytesPerLine(); + + for (int y = 0; y < image.height(); ++y) { + quint32* scanLine = reinterpret_cast_ptr<quint32*>(bits + y * bytesPerLine); + for (int x = 0; x < image.width(); ++x) { + QRgb& pixel = scanLine[x]; + pixel = qRgba(lookUpTable[qRed(pixel)], + lookUpTable[qGreen(pixel)], + lookUpTable[qBlue(pixel)], + qAlpha(pixel)); + } + } + + painter->save(); + painter->resetTransform(); + painter->setOpacity(1.0); + painter->setClipping(false); + painter->setCompositionMode(QPainter::CompositionMode_Source); + painter->drawImage(QPoint(0, 0), image); + painter->restore(); +} + +void ImageBufferDataPrivateAccelerated::paintToTextureMapper(TextureMapper& textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity) +{ + bool canRenderDirectly = false; + if (textureMapper.accelerationMode() == TextureMapper::OpenGLMode) { + if (QOpenGLContext::areSharing(m_context->context(), + static_cast<TextureMapperGL&>(textureMapper).graphicsContext3D()->platformGraphicsContext3D())) + { + canRenderDirectly = true; + } + } + + if (!canRenderDirectly) { + QImage image = toQImage(); + TransformationMatrix oldTransform = textureMapper.graphicsContext()->get3DTransform(); + textureMapper.graphicsContext()->concat3DTransform(matrix); + textureMapper.graphicsContext()->platformContext()->drawImage(targetRect, image); + textureMapper.graphicsContext()->set3DTransform(oldTransform); + return; + } + + invalidateState(); +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + static_cast<TextureMapperGL&>(textureMapper).drawTexture(m_paintDevice->texture(), TextureMapperGL::ShouldBlend, m_paintDevice->size(), targetRect, matrix, opacity); +#else + static_cast<TextureMapperGL&>(textureMapper).drawTexture(m_paintDevice->texture(), TextureMapperGL::ShouldBlend | TextureMapperGL::ShouldFlipTexture, m_paintDevice->size(), targetRect, matrix, opacity); +#endif +} + +#if USE(GRAPHICS_SURFACE) +IntSize ImageBufferDataPrivateAccelerated::platformLayerSize() const +{ + return m_paintDevice->size(); +} + +uint32_t ImageBufferDataPrivateAccelerated::copyToGraphicsSurface() +{ + if (!m_graphicsSurface) { + GraphicsSurface::Flags flags = GraphicsSurface::SupportsAlpha | GraphicsSurface::SupportsTextureTarget | GraphicsSurface::SupportsSharing; + m_graphicsSurface = GraphicsSurface::create(m_paintDevice->size(), flags); + } + + invalidateState(); + + m_graphicsSurface->copyFromTexture(m_paintDevice->texture(), IntRect(IntPoint(), m_paintDevice->size())); + return m_graphicsSurface->swapBuffers(); +} + +GraphicsSurfaceToken ImageBufferDataPrivateAccelerated::graphicsSurfaceToken() const +{ + return m_graphicsSurface->exportToken(); +} +#endif // USE(GRAPHICS_SURFACE) + +#endif // ENABLE(ACCELERATED_2D_CANVAS) + +// ---------------------- ImageBufferDataPrivateUnaccelerated + +struct ImageBufferDataPrivateUnaccelerated final : public ImageBufferDataPrivate { + ImageBufferDataPrivateUnaccelerated(const IntSize&); + QPaintDevice* paintDevice() final { return m_pixmap.isNull() ? 0 : &m_pixmap; } + QImage toQImage() const final; + RefPtr<Image> image() const final; + RefPtr<Image> copyImage() const final; + RefPtr<Image> takeImage() final; + bool isAccelerated() const final { return false; } + PlatformLayer* platformLayer() final { return 0; } + void draw(GraphicsContext& destContext, const FloatRect& destRect, + const FloatRect& srcRect, CompositeOperator, BlendMode, bool ownContext) final; + void drawPattern(GraphicsContext& destContext, const FloatRect& srcRect, const AffineTransform& patternTransform, + const FloatPoint& phase, const FloatSize& spacing, CompositeOperator, + const FloatRect& destRect, BlendMode, bool ownContext) final; + void clip(GraphicsContext&, const IntRect& floatRect) const final; + void platformTransformColorSpace(const Vector<int>& lookUpTable) final; + + QPixmap m_pixmap; + RefPtr<Image> m_image; +}; + +ImageBufferDataPrivateUnaccelerated::ImageBufferDataPrivateUnaccelerated(const IntSize& size) + : m_pixmap(size) + , m_image(StillImage::createForRendering(&m_pixmap)) +{ + m_pixmap.fill(QColor(Qt::transparent)); +} + +QImage ImageBufferDataPrivateUnaccelerated::toQImage() const +{ + QPaintEngine* paintEngine = m_pixmap.paintEngine(); + if (!paintEngine || paintEngine->type() != QPaintEngine::Raster) + return m_pixmap.toImage(); + + // QRasterPixmapData::toImage() will deep-copy the backing QImage if there's an active QPainter on it. + // For performance reasons, we don't want that here, so we temporarily redirect the paint engine. + QPaintDevice* currentPaintDevice = paintEngine->paintDevice(); + paintEngine->setPaintDevice(0); + QImage image = m_pixmap.toImage(); + paintEngine->setPaintDevice(currentPaintDevice); + return image; +} + +RefPtr<Image> ImageBufferDataPrivateUnaccelerated::image() const +{ + return StillImage::createForRendering(&m_pixmap); +} + +RefPtr<Image> ImageBufferDataPrivateUnaccelerated::copyImage() const +{ + return StillImage::create(m_pixmap); +} + +RefPtr<Image> ImageBufferDataPrivateUnaccelerated::takeImage() +{ + return StillImage::create(WTFMove(m_pixmap)); +} + +void ImageBufferDataPrivateUnaccelerated::draw(GraphicsContext& destContext, const FloatRect& destRect, + const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode, bool ownContext) +{ + if (ownContext) { + // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first. + RefPtr<Image> copy = copyImage(); + destContext.drawImage(*copy, destRect, srcRect, ImagePaintingOptions(op, blendMode, ImageOrientationDescription())); + } else + destContext.drawImage(*m_image, destRect, srcRect, ImagePaintingOptions(op, blendMode, ImageOrientationDescription())); +} + +void ImageBufferDataPrivateUnaccelerated::drawPattern(GraphicsContext& destContext, const FloatRect& srcRect, const AffineTransform& patternTransform, + const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, + const FloatRect& destRect, BlendMode blendMode, bool ownContext) +{ + if (ownContext) { + // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first. + RefPtr<Image> copy = copyImage(); + copy->drawPattern(destContext, srcRect, patternTransform, phase, spacing, op, destRect, blendMode); + } else + m_image->drawPattern(destContext, srcRect, patternTransform, phase, spacing, op, destRect, blendMode); +} + +void ImageBufferDataPrivateUnaccelerated::clip(GraphicsContext& context, const IntRect& rect) const +{ + QPixmap* nativeImage = m_image->nativeImageForCurrentFrame(); + if (!nativeImage) + return; + + QPixmap alphaMask = *nativeImage; + context.pushTransparencyLayerInternal(rect, 1.0, alphaMask); +} + +void ImageBufferDataPrivateUnaccelerated::platformTransformColorSpace(const Vector<int>& lookUpTable) +{ + QPainter* painter = paintDevice()->paintEngine()->painter(); + + bool isPainting = painter->isActive(); + if (isPainting) + painter->end(); + + QImage image = toQImage().convertToFormat(QImage::Format_ARGB32); + ASSERT(!image.isNull()); + + uchar* bits = image.bits(); + const int bytesPerLine = image.bytesPerLine(); + + for (int y = 0; y < m_pixmap.height(); ++y) { + quint32* scanLine = reinterpret_cast_ptr<quint32*>(bits + y * bytesPerLine); + for (int x = 0; x < m_pixmap.width(); ++x) { + QRgb& pixel = scanLine[x]; + pixel = qRgba(lookUpTable[qRed(pixel)], + lookUpTable[qGreen(pixel)], + lookUpTable[qBlue(pixel)], + qAlpha(pixel)); + } + } + + m_pixmap = QPixmap::fromImage(image); + + if (isPainting) + painter->begin(&m_pixmap); +} + +// ---------------------- ImageBufferData + +ImageBufferData::ImageBufferData(const IntSize& size) +{ + m_painter = new QPainter; + + m_impl = new ImageBufferDataPrivateUnaccelerated(size); + + if (!m_impl->paintDevice()) + return; + if (!m_painter->begin(m_impl->paintDevice())) + return; + + initPainter(); +} + +#if ENABLE(ACCELERATED_2D_CANVAS) +ImageBufferData::ImageBufferData(const IntSize& size, QOpenGLContext* compatibleContext) +{ + m_painter = new QPainter; + + m_impl = new ImageBufferDataPrivateAccelerated(size, compatibleContext); + + if (!m_impl->paintDevice()) + return; + if (!m_painter->begin(m_impl->paintDevice())) + return; + + initPainter(); +} +#endif + +ImageBufferData::~ImageBufferData() +{ +#if ENABLE(ACCELERATED_2D_CANVAS) + if (m_impl->isAccelerated()) + static_cast<QFramebufferPaintDevice*>(m_impl->paintDevice())->ensureActiveTarget(); +#endif + m_painter->end(); + delete m_painter; + delete m_impl; +} + +void ImageBufferData::initPainter() +{ + m_painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); + + // Since ImageBuffer is used mainly for Canvas, explicitly initialize + // its painter's pen and brush with the corresponding canvas defaults + // NOTE: keep in sync with CanvasRenderingContext2D::State + QPen pen = m_painter->pen(); + pen.setColor(Qt::black); + pen.setWidth(1); + pen.setCapStyle(Qt::FlatCap); + pen.setJoinStyle(Qt::SvgMiterJoin); + pen.setMiterLimit(10); + m_painter->setPen(pen); + QBrush brush = m_painter->brush(); + brush.setColor(Qt::black); + m_painter->setBrush(brush); + m_painter->setCompositionMode(QPainter::CompositionMode_SourceOver); +} + +} diff --git a/Source/WebCore/platform/graphics/qt/ImageBufferDataQt.h b/Source/WebCore/platform/graphics/qt/ImageBufferDataQt.h index abd51a584..2ead943ca 100644 --- a/Source/WebCore/platform/graphics/qt/ImageBufferDataQt.h +++ b/Source/WebCore/platform/graphics/qt/ImageBufferDataQt.h @@ -23,10 +23,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef ImageBufferDataQt_h +#define ImageBufferDataQt_h + #include "Image.h" +#include "PlatformLayer.h" + +#include <QImage> +#include <QPaintDevice> #include <QPainter> -#include <QPixmap> + +#if ENABLE(ACCELERATED_2D_CANVAS) +#include <QOpenGLContext> +#endif #include <wtf/RefPtr.h> @@ -34,16 +44,39 @@ namespace WebCore { class IntSize; +struct ImageBufferDataPrivate { + virtual ~ImageBufferDataPrivate() { } + virtual QPaintDevice* paintDevice() = 0; + virtual QImage toQImage() const = 0; + virtual RefPtr<Image> image() const = 0; + virtual RefPtr<Image> copyImage() const = 0; + virtual RefPtr<Image> takeImage() = 0; + virtual bool isAccelerated() const = 0; + virtual PlatformLayer* platformLayer() = 0; + virtual void draw(GraphicsContext& destContext, const FloatRect& destRect, + const FloatRect& srcRect, CompositeOperator, BlendMode, + bool ownContext) = 0; + virtual void drawPattern(GraphicsContext& destContext, const FloatRect& srcRect, const AffineTransform& patternTransform, + const FloatPoint& phase, const FloatSize& spacing, CompositeOperator, + const FloatRect& destRect, BlendMode, bool ownContext) = 0; + virtual void clip(GraphicsContext&, const IntRect& floatRect) const = 0; + virtual void platformTransformColorSpace(const Vector<int>& lookUpTable) = 0; +}; + class ImageBufferData { public: ImageBufferData(const IntSize&); - - QImage toQImage() const; - - QPixmap m_pixmap; - std::unique_ptr<QPainter> m_painter; - RefPtr<Image> m_image; +#if ENABLE(ACCELERATED_2D_CANVAS) + ImageBufferData(const IntSize&, QOpenGLContext*); +#endif + ~ImageBufferData(); + QPainter* m_painter; std::unique_ptr<GraphicsContext> m_context; + ImageBufferDataPrivate* m_impl; +protected: + void initPainter(); }; } // namespace WebCore + +#endif diff --git a/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp index b0990b3ee..885c43f92 100644 --- a/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp +++ b/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -3,6 +3,7 @@ * Copyright (C) 2008 Holger Hans Peter Freyther * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. + * Copyright (C) 2014 Digia Plc. and/or its subsidiary(-ies) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -41,7 +42,6 @@ #include <wtf/text/WTFString.h> #include <QBuffer> -#include <QColor> #include <QImage> #include <QImageWriter> #include <QPainter> @@ -50,53 +50,21 @@ namespace WebCore { -ImageBufferData::ImageBufferData(const IntSize& size) - : m_pixmap(size) +#if ENABLE(ACCELERATED_2D_CANVAS) +ImageBuffer::ImageBuffer(const IntSize& size, float /* resolutionScale */, ColorSpace, QOpenGLContext* compatibleContext, bool& success) + : m_data(size, compatibleContext) + , m_size(size) + , m_logicalSize(size) { - if (m_pixmap.isNull()) - return; - - m_pixmap.fill(QColor(Qt::transparent)); - - m_painter = std::make_unique<QPainter>(); - - if (!m_painter->begin(&m_pixmap)) + success = m_data.m_painter && m_data.m_painter->isActive(); + if (!success) return; - // Since ImageBuffer is used mainly for Canvas, explicitly initialize - // its painter's pen and brush with the corresponding canvas defaults - // NOTE: keep in sync with CanvasRenderingContext2D::State - QPen pen = m_painter->pen(); - pen.setColor(Qt::black); - pen.setWidth(1); - pen.setCapStyle(Qt::FlatCap); - pen.setJoinStyle(Qt::SvgMiterJoin); - pen.setMiterLimit(10); - m_painter->setPen(pen); - QBrush brush = m_painter->brush(); - brush.setColor(Qt::black); - m_painter->setBrush(brush); - m_painter->setCompositionMode(QPainter::CompositionMode_SourceOver); - - m_image = StillImage::createForRendering(&m_pixmap); -} - -QImage ImageBufferData::toQImage() const -{ - QPaintEngine* paintEngine = m_pixmap.paintEngine(); - if (!paintEngine || paintEngine->type() != QPaintEngine::Raster) - return m_pixmap.toImage(); - - // QRasterPixmapData::toImage() will deep-copy the backing QImage if there's an active QPainter on it. - // For performance reasons, we don't want that here, so we temporarily redirect the paint engine. - QPaintDevice* currentPaintDevice = paintEngine->paintDevice(); - paintEngine->setPaintDevice(0); - QImage image = m_pixmap.toImage(); - paintEngine->setPaintDevice(currentPaintDevice); - return image; + m_data.m_context = std::make_unique<GraphicsContext>(m_data.m_painter); } +#endif -ImageBuffer::ImageBuffer(const FloatSize& size, float /* resolutionScale */, ColorSpace, RenderingMode, bool& success) +ImageBuffer::ImageBuffer(const FloatSize& size, float /* resolutionScale */, ColorSpace, RenderingMode /*renderingMode*/, bool& success) : m_data(IntSize(size)) , m_size(size) , m_logicalSize(size) @@ -105,13 +73,24 @@ ImageBuffer::ImageBuffer(const FloatSize& size, float /* resolutionScale */, Col if (!success) return; - m_data.m_context = std::make_unique<GraphicsContext>(m_data.m_painter.get()); + m_data.m_context = std::make_unique<GraphicsContext>(m_data.m_painter); } ImageBuffer::~ImageBuffer() { } +#if ENABLE(ACCELERATED_2D_CANVAS) +std::unique_ptr<ImageBuffer> ImageBuffer::createCompatibleBuffer(const IntSize& size, float resolutionScale, ColorSpace colorSpace, QOpenGLContext* context) +{ + bool success = false; + std::unique_ptr<ImageBuffer> buf(new ImageBuffer(size, resolutionScale, colorSpace, context, success)); + if (!success) + return nullptr; + return buf; +} +#endif + GraphicsContext& ImageBuffer::context() const { ASSERT(m_data.m_painter->isActive()); @@ -122,14 +101,14 @@ GraphicsContext& ImageBuffer::context() const RefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, ScaleBehavior) const { if (copyBehavior == CopyBackingStore) - return StillImage::create(m_data.m_pixmap); + return m_data.m_impl->copyImage(); - return StillImage::createForRendering(&m_data.m_pixmap); + return m_data.m_impl->image(); } -RefPtr<Image> ImageBuffer::sinkIntoImage(std::unique_ptr<ImageBuffer> imageBuffer, ScaleBehavior scaleBehavior) +RefPtr<Image> ImageBuffer::sinkIntoImage(std::unique_ptr<ImageBuffer> imageBuffer, ScaleBehavior) { - return StillImage::create(WTFMove(imageBuffer->m_data.m_pixmap)); + return imageBuffer->m_data.m_impl->takeImage(); } BackingStoreCopy ImageBuffer::fastCopyImageMode() @@ -145,52 +124,18 @@ void ImageBuffer::drawConsuming(std::unique_ptr<ImageBuffer> imageBuffer, Graphi void ImageBuffer::draw(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode) { - if (&destContext == &context()) { - // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first. - RefPtr<Image> copy = copyImage(CopyBackingStore); - destContext.drawImage(*copy, destRect, srcRect, ImagePaintingOptions(op, blendMode, ImageOrientationDescription())); - } else - destContext.drawImage(*m_data.m_image, destRect, srcRect, ImagePaintingOptions(op, blendMode, ImageOrientationDescription())); + m_data.m_impl->draw(destContext, destRect, srcRect, op, blendMode, &destContext == &context()); } void ImageBuffer::drawPattern(GraphicsContext& destContext, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, const FloatRect& destRect, BlendMode blendMode) { - if (&destContext == &context()) { - // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first. - RefPtr<Image> copy = copyImage(CopyBackingStore); - copy->drawPattern(destContext, srcRect, patternTransform, phase, spacing, op, destRect, blendMode); - } else - m_data.m_image->drawPattern(destContext, srcRect, patternTransform, phase, spacing, op, destRect, blendMode); + m_data.m_impl->drawPattern(destContext, srcRect, patternTransform, phase, spacing, op, destRect, blendMode, &destContext == &context()); } void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) { - bool isPainting = m_data.m_painter->isActive(); - if (isPainting) - m_data.m_painter->end(); - - QImage image = m_data.toQImage().convertToFormat(QImage::Format_ARGB32); - ASSERT(!image.isNull()); - - uchar* bits = image.bits(); - const int bytesPerLine = image.bytesPerLine(); - - for (int y = 0; y < m_size.height(); ++y) { - quint32* scanLine = reinterpret_cast_ptr<quint32*>(bits + y * bytesPerLine); - for (int x = 0; x < m_size.width(); ++x) { - QRgb& pixel = scanLine[x]; - pixel = qRgba(lookUpTable[qRed(pixel)], - lookUpTable[qGreen(pixel)], - lookUpTable[qBlue(pixel)], - qAlpha(pixel)); - } - } - - m_data.m_pixmap = QPixmap::fromImage(image); - - if (isPainting) - m_data.m_painter->begin(&m_data.m_pixmap); + m_data.m_impl->platformTransformColorSpace(lookUpTable); } template <Multiply multiplied> @@ -207,10 +152,11 @@ PassRefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, const ImageBuffe if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > size.width() || rect.maxY() > size.height()) image.fill(0); - // Let drawPixmap deal with the conversion. + // Let drawImage deal with the conversion. + // FIXME: This is inefficient for accelerated ImageBuffers when only part of the imageData is read. QPainter painter(&image); painter.setCompositionMode(QPainter::CompositionMode_Source); - painter.drawPixmap(QPoint(0, 0), imageData.m_pixmap, rect); + painter.drawImage(QPoint(0, 0), imageData.m_impl->toQImage(), rect); painter.end(); return result.release(); @@ -233,7 +179,7 @@ void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, c bool isPainting = m_data.m_painter->isActive(); if (!isPainting) - m_data.m_painter->begin(&m_data.m_pixmap); + m_data.m_painter->begin(m_data.m_impl->paintDevice()); else { m_data.m_painter->save(); @@ -281,11 +227,17 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality, Coo // gif, jpeg..., xpm) so skip the image/ to get the Qt image format used to encode // the m_pixmap image. + RefPtr<Image> image = copyImage(DontCopyBackingStore); QByteArray data; - if (!encodeImage(m_data.m_pixmap, mimeType.substring(sizeof "image"), quality, data)) + if (!encodeImage(*image->nativeImageForCurrentFrame(), mimeType.substring(sizeof "image"), quality, data)) return "data:,"; return "data:" + mimeType + ";base64," + data.toBase64().data(); } +PlatformLayer* ImageBuffer::platformLayer() const +{ + return m_data.m_impl->platformLayer(); +} + } diff --git a/Source/WebCore/platform/graphics/qt/OpenGLShimsQt.h b/Source/WebCore/platform/graphics/qt/OpenGLShimsQt.h new file mode 100644 index 000000000..827d8f6b2 --- /dev/null +++ b/Source/WebCore/platform/graphics/qt/OpenGLShimsQt.h @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2017 Konstantin Tokarev <annulen@yandex.ru> + * + * 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. ``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 + * 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. + */ + +#pragma once + +#include <private/qopenglextensions_p.h> + +#ifndef FUNCTIONS +#error You must define FUNCTIONS macro before including this header +#endif + +namespace OpenGLShimsQt { +ALWAYS_INLINE static void doNothing() { } +} + +#define LOOKUP_GL_FUNCTION(f, ...) OpenGLShimsQt::doNothing(), FUNCTIONS->f(__VA_ARGS__) + +// Extra items +#define glBindTexture(...) LOOKUP_GL_FUNCTION(glBindTexture, __VA_ARGS__) +#define glBlendFunc(...) LOOKUP_GL_FUNCTION(glBlendFunc, __VA_ARGS__) +#define glClear(...) LOOKUP_GL_FUNCTION(glClear, __VA_ARGS__) +#define glClearColor(...) LOOKUP_GL_FUNCTION(glClearColor, __VA_ARGS__) +#define glClearDepth(...) LOOKUP_GL_FUNCTION(glClearDepthf, __VA_ARGS__) +#define glClearStencil(...) LOOKUP_GL_FUNCTION(glClearStencil, __VA_ARGS__) +#define glColorMask(...) LOOKUP_GL_FUNCTION(glColorMask, __VA_ARGS__) +#define glCopyTexImage2D(...) LOOKUP_GL_FUNCTION(glCopyTexImage2D, __VA_ARGS__) +#define glCopyTexSubImage2D(...) LOOKUP_GL_FUNCTION(glCopyTexSubImage2D, __VA_ARGS__) +#define glCullFace(...) LOOKUP_GL_FUNCTION(glCullFace, __VA_ARGS__) +#define glDeleteTextures(...) LOOKUP_GL_FUNCTION(glDeleteTextures, __VA_ARGS__) +#define glDepthFunc(...) LOOKUP_GL_FUNCTION(glDepthFunc, __VA_ARGS__) +#define glDepthMask(...) LOOKUP_GL_FUNCTION(glDepthMask, __VA_ARGS__) +#define glDepthRange(...) LOOKUP_GL_FUNCTION(glDepthRangef, __VA_ARGS__) +#define glDisable(...) LOOKUP_GL_FUNCTION(glDisable, __VA_ARGS__) +#define glDrawArrays(...) LOOKUP_GL_FUNCTION(glDrawArrays, __VA_ARGS__) +#define glDrawElements(...) LOOKUP_GL_FUNCTION(glDrawElements, __VA_ARGS__) +#define glEnable(...) LOOKUP_GL_FUNCTION(glEnable, __VA_ARGS__) +#define glFinish(...) LOOKUP_GL_FUNCTION(glFinish, __VA_ARGS__) +#define glFlush(...) LOOKUP_GL_FUNCTION(glFlush, __VA_ARGS__) +#define glFrontFace(...) LOOKUP_GL_FUNCTION(glFrontFace, __VA_ARGS__) +#define glGenTextures(...) LOOKUP_GL_FUNCTION(glGenTextures, __VA_ARGS__) +#define glGetBooleanv(...) LOOKUP_GL_FUNCTION(glGetBooleanv, __VA_ARGS__) +#define glGetFloatv(...) LOOKUP_GL_FUNCTION(glGetFloatv, __VA_ARGS__) +#define glGetIntegerv(...) LOOKUP_GL_FUNCTION(glGetIntegerv, __VA_ARGS__) +#define glGetString(...) LOOKUP_GL_FUNCTION(glGetString, __VA_ARGS__) +#define glGetTexParameterfv(...) LOOKUP_GL_FUNCTION(glGetTexParameterfv, __VA_ARGS__) +#define glGetTexParameteriv(...) LOOKUP_GL_FUNCTION(glGetTexParameteriv, __VA_ARGS__) +#define glHint(...) LOOKUP_GL_FUNCTION(glHint, __VA_ARGS__) +#define glIsTexture(...) LOOKUP_GL_FUNCTION(glIsTexture, __VA_ARGS__) +#define glLineWidth(...) LOOKUP_GL_FUNCTION(glLineWidth, __VA_ARGS__) +#define glPixelStorei(...) LOOKUP_GL_FUNCTION(glPixelStorei, __VA_ARGS__) +#define glPolygonOffset(...) LOOKUP_GL_FUNCTION(glPolygonOffset, __VA_ARGS__) +#define glReadPixels(...) LOOKUP_GL_FUNCTION(glReadPixels, __VA_ARGS__) +#define glScissor(...) LOOKUP_GL_FUNCTION(glScissor, __VA_ARGS__) +#define glStencilFunc(...) LOOKUP_GL_FUNCTION(glStencilFunc, __VA_ARGS__) +#define glStencilMask(...) LOOKUP_GL_FUNCTION(glStencilMask, __VA_ARGS__) +#define glStencilOp(...) LOOKUP_GL_FUNCTION(glStencilOp, __VA_ARGS__) +#define glTexImage2D(...) LOOKUP_GL_FUNCTION(glTexImage2D, __VA_ARGS__) +#define glTexParameterf(...) LOOKUP_GL_FUNCTION(glTexParameterf, __VA_ARGS__) +#define glTexParameteri(...) LOOKUP_GL_FUNCTION(glTexParameteri, __VA_ARGS__) +#define glTexSubImage2D(...) LOOKUP_GL_FUNCTION(glTexSubImage2D, __VA_ARGS__) +#define glViewport(...) LOOKUP_GL_FUNCTION(glViewport, __VA_ARGS__) + +// Keep in sync with OpenGLShims.h + +#define glActiveTexture(...) LOOKUP_GL_FUNCTION(glActiveTexture, __VA_ARGS__) +#define glAttachShader(...) LOOKUP_GL_FUNCTION(glAttachShader, __VA_ARGS__) +#define glBindAttribLocation(...) LOOKUP_GL_FUNCTION(glBindAttribLocation, __VA_ARGS__) +#define glBindBuffer(...) LOOKUP_GL_FUNCTION(glBindBuffer, __VA_ARGS__) +#define glBindFramebufferEXT glBindFramebuffer +#define glBindFramebuffer(...) LOOKUP_GL_FUNCTION(glBindFramebuffer, __VA_ARGS__) +#define glBindRenderbufferEXT glBindRenderbuffer +#define glBindRenderbuffer(...) LOOKUP_GL_FUNCTION(glBindRenderbuffer, __VA_ARGS__) +#define glBlendColor(...) LOOKUP_GL_FUNCTION(glBlendColor, __VA_ARGS__) +#define glBlendEquation(...) LOOKUP_GL_FUNCTION(glBlendEquation, __VA_ARGS__) +#define glBlendEquationSeparate(...) LOOKUP_GL_FUNCTION(glBlendEquationSeparate, __VA_ARGS__) +#define glBlendFuncSeparate(...) LOOKUP_GL_FUNCTION(glBlendFuncSeparate, __VA_ARGS__) +#define glBlitFramebufferEXT glBlitFramebuffer +#define glBlitFramebuffer(...) LOOKUP_GL_FUNCTION(glBlitFramebuffer, __VA_ARGS__) +#define glBufferData(...) LOOKUP_GL_FUNCTION(glBufferData, __VA_ARGS__) +#define glBufferSubData(...) LOOKUP_GL_FUNCTION(glBufferSubData, __VA_ARGS__) +#define glCheckFramebufferStatusEXT glCheckFramebufferStatus +#define glCheckFramebufferStatus(...) LOOKUP_GL_FUNCTION(glCheckFramebufferStatus, __VA_ARGS__) +#define glCompileShader(...) LOOKUP_GL_FUNCTION(glCompileShader, __VA_ARGS__) +#define glCompressedTexImage2D(...) LOOKUP_GL_FUNCTION(glCompressedTexImage2D, __VA_ARGS__) +#define glCompressedTexSubImage2D(...) LOOKUP_GL_FUNCTION(glCompressedTexSubImage2D, __VA_ARGS__) +#define glCreateProgram(...) LOOKUP_GL_FUNCTION(glCreateProgram, __VA_ARGS__) +#define glCreateShader(...) LOOKUP_GL_FUNCTION(glCreateShader, __VA_ARGS__) +#define glDeleteBuffers(...) LOOKUP_GL_FUNCTION(glDeleteBuffers, __VA_ARGS__) +#define glDeleteFramebuffersEXT glDeleteFramebuffers +#define glDeleteFramebuffers(...) LOOKUP_GL_FUNCTION(glDeleteFramebuffers, __VA_ARGS__) +#define glDeleteProgram(...) LOOKUP_GL_FUNCTION(glDeleteProgram, __VA_ARGS__) +#define glDeleteRenderbuffersEXT glDeleteRenderbuffers +#define glDeleteRenderbuffers(...) LOOKUP_GL_FUNCTION(glDeleteRenderbuffers, __VA_ARGS__) +#define glDeleteShader(...) LOOKUP_GL_FUNCTION(glDeleteShader, __VA_ARGS__) +#define glDetachShader(...) LOOKUP_GL_FUNCTION(glDetachShader, __VA_ARGS__) +#define glDisableVertexAttribArray(...) LOOKUP_GL_FUNCTION(glDisableVertexAttribArray, __VA_ARGS__) +#define glDrawArraysInstancedEXT glDrawArraysInstanced +#define glDrawArraysInstanced(...) LOOKUP_GL_FUNCTION(glDrawArraysInstanced, __VA_ARGS__) +#define glDrawBuffersEXT glDrawBuffers +#define glDrawBuffers(...) LOOKUP_GL_FUNCTION(glDrawBuffers, __VA_ARGS__) +#define glDrawElementsInstancedEXT glDrawElementsInstanced +#define glDrawElementsInstanced(...) LOOKUP_GL_FUNCTION(glDrawElementsInstanced, __VA_ARGS__) +#define glEnableVertexAttribArray(...) LOOKUP_GL_FUNCTION(glEnableVertexAttribArray, __VA_ARGS__) +#define glFramebufferRenderbufferEXT glFramebufferRenderbuffer +#define glFramebufferRenderbuffer(...) LOOKUP_GL_FUNCTION(glFramebufferRenderbuffer, __VA_ARGS__) +#define glFramebufferTexture2DEXT glFramebufferTexture2D +#define glFramebufferTexture2D(...) LOOKUP_GL_FUNCTION(glFramebufferTexture2D, __VA_ARGS__) +#define glGenBuffers(...) LOOKUP_GL_FUNCTION(glGenBuffers, __VA_ARGS__) +#define glGenerateMipmapEXT glGenerateMipmap +#define glGenerateMipmap(...) LOOKUP_GL_FUNCTION(glGenerateMipmap, __VA_ARGS__) +#define glGenFramebuffersEXT glGenFramebuffers +#define glGenFramebuffers(...) LOOKUP_GL_FUNCTION(glGenFramebuffers, __VA_ARGS__) +#define glGenRenderbuffersEXT glGenRenderbuffers +#define glGenRenderbuffers(...) LOOKUP_GL_FUNCTION(glGenRenderbuffers, __VA_ARGS__) +#define glGetActiveAttrib(...) LOOKUP_GL_FUNCTION(glGetActiveAttrib, __VA_ARGS__) +#define glGetActiveUniform(...) LOOKUP_GL_FUNCTION(glGetActiveUniform, __VA_ARGS__) +#define glGetAttachedShaders(...) LOOKUP_GL_FUNCTION(glGetAttachedShaders, __VA_ARGS__) +#define glGetAttribLocation(...) LOOKUP_GL_FUNCTION(glGetAttribLocation, __VA_ARGS__) +#define glGetBufferParameterivEXT glGetBufferParameteriv +#define glGetBufferParameteriv(...) LOOKUP_GL_FUNCTION(glGetBufferParameteriv, __VA_ARGS__) +#define glGetFramebufferAttachmentParameterivEXT glGetFramebufferAttachmentParameteriv +#define glGetFramebufferAttachmentParameteriv(...) LOOKUP_GL_FUNCTION(glGetFramebufferAttachmentParameteriv, __VA_ARGS__) +#define glGetProgramInfoLog(...) LOOKUP_GL_FUNCTION(glGetProgramInfoLog, __VA_ARGS__) +#define glGetProgramiv(...) LOOKUP_GL_FUNCTION(glGetProgramiv, __VA_ARGS__) +#define glGetRenderbufferParameterivEXT glGetRenderbufferParameteriv +#define glGetRenderbufferParameteriv(...) LOOKUP_GL_FUNCTION(glGetRenderbufferParameteriv, __VA_ARGS__) +#define glGetShaderInfoLog(...) LOOKUP_GL_FUNCTION(glGetShaderInfoLog, __VA_ARGS__) +#define glGetShaderiv(...) LOOKUP_GL_FUNCTION(glGetShaderiv, __VA_ARGS__) +#define glGetShaderSource(...) LOOKUP_GL_FUNCTION(glGetShaderSource, __VA_ARGS__) +#define glGetUniformfv(...) LOOKUP_GL_FUNCTION(glGetUniformfv, __VA_ARGS__) +#define glGetUniformiv(...) LOOKUP_GL_FUNCTION(glGetUniformiv, __VA_ARGS__) +#define glGetUniformLocation(...) LOOKUP_GL_FUNCTION(glGetUniformLocation, __VA_ARGS__) +#define glGetVertexAttribfv(...) LOOKUP_GL_FUNCTION(glGetVertexAttribfv, __VA_ARGS__) +#define glGetVertexAttribiv(...) LOOKUP_GL_FUNCTION(glGetVertexAttribiv, __VA_ARGS__) +#define glGetVertexAttribPointerv(...) LOOKUP_GL_FUNCTION(glGetVertexAttribPointerv, __VA_ARGS__) +#define glIsBuffer(...) LOOKUP_GL_FUNCTION(glIsBuffer, __VA_ARGS__) +#define glIsFramebufferEXT glIsFramebuffer +#define glIsFramebuffer(...) LOOKUP_GL_FUNCTION(glIsFramebuffer, __VA_ARGS__) +#define glIsProgram(...) LOOKUP_GL_FUNCTION(glIsProgram, __VA_ARGS__) +#define glIsRenderbufferEXT glIsRenderbuffer +#define glIsRenderbuffer(...) LOOKUP_GL_FUNCTION(glIsRenderbuffer, __VA_ARGS__) +#define glIsShader(...) LOOKUP_GL_FUNCTION(glIsShader, __VA_ARGS__) +#define glLinkProgram(...) LOOKUP_GL_FUNCTION(glLinkProgram, __VA_ARGS__) +#define glRenderbufferStorageEXT glRenderbufferStorage +#define glRenderbufferStorage(...) LOOKUP_GL_FUNCTION(glRenderbufferStorage, __VA_ARGS__) +#define glRenderbufferStorageMultisampleEXT glRenderbufferStorageMultisample +#define glRenderbufferStorageMultisample(...) LOOKUP_GL_FUNCTION(glRenderbufferStorageMultisample, __VA_ARGS__) +#define glSampleCoverage(...) LOOKUP_GL_FUNCTION(glSampleCoverage, __VA_ARGS__) +#define glShaderSource(...) LOOKUP_GL_FUNCTION(glShaderSource, __VA_ARGS__) +#define glStencilFuncSeparate(...) LOOKUP_GL_FUNCTION(glStencilFuncSeparate, __VA_ARGS__) +#define glStencilMaskSeparate(...) LOOKUP_GL_FUNCTION(glStencilMaskSeparate, __VA_ARGS__) +#define glStencilOpSeparate(...) LOOKUP_GL_FUNCTION(glStencilOpSeparate, __VA_ARGS__) +#define glUniform1f(...) LOOKUP_GL_FUNCTION(glUniform1f, __VA_ARGS__) +#define glUniform1fv(...) LOOKUP_GL_FUNCTION(glUniform1fv, __VA_ARGS__) +#define glUniform1i(...) LOOKUP_GL_FUNCTION(glUniform1i, __VA_ARGS__) +#define glUniform1iv(...) LOOKUP_GL_FUNCTION(glUniform1iv, __VA_ARGS__) +#define glUniform2f(...) LOOKUP_GL_FUNCTION(glUniform2f, __VA_ARGS__) +#define glUniform2fv(...) LOOKUP_GL_FUNCTION(glUniform2fv, __VA_ARGS__) +#define glUniform2i(...) LOOKUP_GL_FUNCTION(glUniform2i, __VA_ARGS__) +#define glUniform2iv(...) LOOKUP_GL_FUNCTION(glUniform2iv, __VA_ARGS__) +#define glUniform3f(...) LOOKUP_GL_FUNCTION(glUniform3f, __VA_ARGS__) +#define glUniform3fv(...) LOOKUP_GL_FUNCTION(glUniform3fv, __VA_ARGS__) +#define glUniform3i(...) LOOKUP_GL_FUNCTION(glUniform3i, __VA_ARGS__) +#define glUniform3iv(...) LOOKUP_GL_FUNCTION(glUniform3iv, __VA_ARGS__) +#define glUniform4f(...) LOOKUP_GL_FUNCTION(glUniform4f, __VA_ARGS__) +#define glUniform4fv(...) LOOKUP_GL_FUNCTION(glUniform4fv, __VA_ARGS__) +#define glUniform4i(...) LOOKUP_GL_FUNCTION(glUniform4i, __VA_ARGS__) +#define glUniform4iv(...) LOOKUP_GL_FUNCTION(glUniform4iv, __VA_ARGS__) +#define glUniformMatrix2fv(...) LOOKUP_GL_FUNCTION(glUniformMatrix2fv, __VA_ARGS__) +#define glUniformMatrix3fv(...) LOOKUP_GL_FUNCTION(glUniformMatrix3fv, __VA_ARGS__) +#define glUniformMatrix4fv(...) LOOKUP_GL_FUNCTION(glUniformMatrix4fv, __VA_ARGS__) +#define glUseProgram(...) LOOKUP_GL_FUNCTION(glUseProgram, __VA_ARGS__) +#define glValidateProgram(...) LOOKUP_GL_FUNCTION(glValidateProgram, __VA_ARGS__) +#define glVertexAttrib1f(...) LOOKUP_GL_FUNCTION(glVertexAttrib1f, __VA_ARGS__) +#define glVertexAttrib1fv(...) LOOKUP_GL_FUNCTION(glVertexAttrib1fv, __VA_ARGS__) +#define glVertexAttrib2f(...) LOOKUP_GL_FUNCTION(glVertexAttrib2f, __VA_ARGS__) +#define glVertexAttrib2fv(...) LOOKUP_GL_FUNCTION(glVertexAttrib2fv, __VA_ARGS__) +#define glVertexAttrib3f(...) LOOKUP_GL_FUNCTION(glVertexAttrib3f, __VA_ARGS__) +#define glVertexAttrib3fv(...) LOOKUP_GL_FUNCTION(glVertexAttrib3fv, __VA_ARGS__) +#define glVertexAttrib4f(...) LOOKUP_GL_FUNCTION(glVertexAttrib4f, __VA_ARGS__) +#define glVertexAttrib4fv(...) LOOKUP_GL_FUNCTION(glVertexAttrib4fv, __VA_ARGS__) +#define glVertexAttribDivisorEXT glVertexAttribDivisor +#define glVertexAttribDivisor(...) LOOKUP_GL_FUNCTION(glVertexAttribDivisor, __VA_ARGS__) +#define glVertexAttribPointer(...) LOOKUP_GL_FUNCTION(glVertexAttribPointer, __VA_ARGS__) diff --git a/Source/WebCore/platform/graphics/gpu/qt/DrawingBufferQt.cpp b/Source/WebCore/platform/graphics/qt/OpenGLShimsQtVAO.h index 47cb4b95b..36b3aec69 100644 --- a/Source/WebCore/platform/graphics/gpu/qt/DrawingBufferQt.cpp +++ b/Source/WebCore/platform/graphics/qt/OpenGLShimsQtVAO.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andrew Wason (rectalogic@rectalogic.com) + * Copyright (C) 2017 Konstantin Tokarev <annulen@yandex.ru> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -13,40 +13,31 @@ * THIS SOFTWARE IS PROVIDED BY APPLE 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 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" +#pragma once -#if USE(3D_GRAPHICS) +#include <private/qopenglvertexarrayobject_p.h> -#include "DrawingBuffer.h" - -namespace WebCore { - -#if USE(ACCELERATED_COMPOSITING) -PlatformLayer* DrawingBuffer::platformLayer() -{ - return 0; -} - -unsigned DrawingBuffer::frontColorBuffer() const -{ - return colorBuffer(); -} - -void DrawingBuffer::paintCompositedResultsToCanvas(ImageBuffer*) -{ -} +#ifndef VAO_FUNCTIONS +#error You must define VAO_FUNCTIONS macro before including this header #endif -} - +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) +#define LOOKUP_VAO_FUNCTION(f, ...) VAO_FUNCTIONS->f(__VA_ARGS__) +#else +#define LOOKUP_VAO_FUNCTION(f, ...) #endif + +#define glGenVertexArrays(...) LOOKUP_VAO_FUNCTION(glGenVertexArrays, __VA_ARGS__) +#define glDeleteVertexArrays(...) LOOKUP_VAO_FUNCTION(glDeleteVertexArrays, __VA_ARGS__) +#define glIsVertexArray(...) LOOKUP_VAO_FUNCTION(glIsVertexArray, __VA_ARGS__) +#define glBindVertexArray(...) LOOKUP_VAO_FUNCTION(glBindVertexArray, __VA_ARGS__) diff --git a/Source/WebCore/platform/graphics/qt/QFramebufferPaintDevice.cpp b/Source/WebCore/platform/graphics/qt/QFramebufferPaintDevice.cpp new file mode 100644 index 000000000..7c29d95e6 --- /dev/null +++ b/Source/WebCore/platform/graphics/qt/QFramebufferPaintDevice.cpp @@ -0,0 +1,69 @@ +/* + Copyright (C) 2014 Digia Plc. and/or its subsidiary(-ies) + + 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 "QFramebufferPaintDevice.h" + +#include <QOpenGLFunctions> + +QFramebufferPaintDevice::QFramebufferPaintDevice(const QSize& size, + QOpenGLFramebufferObject::Attachment attachment, bool clearOnInit) + : QOpenGLPaintDevice(size) + , m_framebufferObject(size, attachment) +{ + m_surface = QOpenGLContext::currentContext()->surface(); +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + setPaintFlipped(true); +#endif + if (clearOnInit) { + m_framebufferObject.bind(); + + context()->functions()->glClearColor(0, 0, 0, 0); + context()->functions()->glClear(GL_COLOR_BUFFER_BIT); + } +} + +void QFramebufferPaintDevice::ensureActiveTarget() +{ + if (QOpenGLContext::currentContext() != context()) + context()->makeCurrent(m_surface); + + m_framebufferObject.bind(); +} + +QImage QFramebufferPaintDevice::toImage() const +{ + QOpenGLContext* currentContext = QOpenGLContext::currentContext(); + QSurface* currentSurface = currentContext ? currentContext->surface() : 0; + + context()->makeCurrent(m_surface); + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + QImage image = m_framebufferObject.toImage(false); +#else + QImage image = m_framebufferObject.toImage(); +#endif + + if (currentContext) + currentContext->makeCurrent(currentSurface); + else + context()->doneCurrent(); + + return image; +} diff --git a/Source/WebCore/platform/graphics/qt/QFramebufferPaintDevice.h b/Source/WebCore/platform/graphics/qt/QFramebufferPaintDevice.h new file mode 100644 index 000000000..14562acb2 --- /dev/null +++ b/Source/WebCore/platform/graphics/qt/QFramebufferPaintDevice.h @@ -0,0 +1,56 @@ +/* + Copyright (C) 2014 Digia Plc. and/or its subsidiary(-ies) + + 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. +*/ + +#ifndef QFramebufferPaintDevice_h +#define QFramebufferPaintDevice_h + +#include <QImage> +#include <QOpenGLFramebufferObject> +#include <QOpenGLPaintDevice> +#include <QSurface> + +class QFramebufferPaintDevice : public QOpenGLPaintDevice { +public: + QFramebufferPaintDevice(const QSize&, + QOpenGLFramebufferObject::Attachment = QOpenGLFramebufferObject::CombinedDepthStencil, + bool clearOnInit = true); + + // QOpenGLPaintDevice: + virtual void ensureActiveTarget() Q_DECL_OVERRIDE; + + bool isValid() const { return m_framebufferObject.isValid(); } + GLuint handle() const { return m_framebufferObject.handle(); } + GLuint texture() const { return m_framebufferObject.texture(); } + QImage toImage() const; + + bool bind() { return m_framebufferObject.bind(); } + bool release() { return m_framebufferObject.release(); } + QSize size() const { return m_framebufferObject.size(); } + + QOpenGLFramebufferObject* framebufferObject() { return &m_framebufferObject; } + const QOpenGLFramebufferObject* framebufferObject() const { return &m_framebufferObject; } + + static bool isSupported() { return QOpenGLFramebufferObject::hasOpenGLFramebufferObjects(); } + +private: + QOpenGLFramebufferObject m_framebufferObject; + QSurface* m_surface; +}; + +#endif diff --git a/Source/WebCore/platform/graphics/qt/StillImageQt.h b/Source/WebCore/platform/graphics/qt/StillImageQt.h index e35e56609..b9079727e 100644 --- a/Source/WebCore/platform/graphics/qt/StillImageQt.h +++ b/Source/WebCore/platform/graphics/qt/StillImageQt.h @@ -34,17 +34,17 @@ namespace WebCore { class StillImage final : public Image { public: - static PassRefPtr<StillImage> create(const QPixmap& pixmap) + static RefPtr<StillImage> create(const QPixmap& pixmap) { return adoptRef(new StillImage(pixmap)); } - static PassRefPtr<StillImage> createForRendering(const QPixmap* pixmap) + static RefPtr<StillImage> createForRendering(const QPixmap* pixmap) { return adoptRef(new StillImage(pixmap)); } - static PassRefPtr<StillImage> create(QPixmap&& pixmap) + static RefPtr<StillImage> create(QPixmap&& pixmap) { return adoptRef(new StillImage(WTFMove(pixmap))); } diff --git a/Source/WebCore/platform/graphics/texmap/BitmapTextureGL.cpp b/Source/WebCore/platform/graphics/texmap/BitmapTextureGL.cpp index 3d7037c2f..59c763b51 100644 --- a/Source/WebCore/platform/graphics/texmap/BitmapTextureGL.cpp +++ b/Source/WebCore/platform/graphics/texmap/BitmapTextureGL.cpp @@ -37,6 +37,10 @@ #include <wtf/RefCounted.h> #include <wtf/TemporaryChange.h> +#if PLATFORM(QT) +#include <QPaintEngine> +#endif + #if USE(CAIRO) #include "CairoUtilities.h" #include "RefPtrCairo.h" @@ -200,7 +204,17 @@ void BitmapTextureGL::updateContents(Image* image, const IntRect& targetRect, co imageData = reinterpret_cast<const char*>(cairo_image_surface_get_data(surface)); bytesPerLine = cairo_image_surface_get_stride(surface); #elif PLATFORM(QT) - QImage qImage = frameImage->toImage(); + QImage qImage; + QPaintEngine* paintEngine = frameImage->paintEngine(); + if (paintEngine && paintEngine->type() == QPaintEngine::Raster) { + // QRasterPixmapData::toImage() will deep-copy the backing QImage if there's an active QPainter on it. + // For performance reasons, we don't want that here, so we temporarily redirect the paint engine. + QPaintDevice* currentPaintDevice = paintEngine->paintDevice(); + paintEngine->setPaintDevice(0); + qImage = frameImage->toImage(); + paintEngine->setPaintDevice(currentPaintDevice); + } else + qImage = frameImage->toImage(); imageData = reinterpret_cast<const char*>(qImage.constBits()); bytesPerLine = qImage.bytesPerLine(); #endif diff --git a/Source/WebCore/platform/graphics/texmap/BitmapTextureImageBuffer.cpp b/Source/WebCore/platform/graphics/texmap/BitmapTextureImageBuffer.cpp new file mode 100644 index 000000000..ee677c2a2 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/BitmapTextureImageBuffer.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2014 Igalia S.L. + * + * 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 "BitmapTextureImageBuffer.h" + +#include "GraphicsLayer.h" + +#if PLATFORM(QT) +#include "GraphicsContext.h" +#include "NativeImageQt.h" +#endif + +namespace WebCore { + +void BitmapTextureImageBuffer::updateContents(const void* data, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, UpdateContentsFlag) +{ +#if PLATFORM(QT) + QImage image(reinterpret_cast<const uchar*>(data), targetRect.width(), targetRect.height(), bytesPerLine, NativeImageQt::defaultFormatForAlphaEnabledImages()); + + QPainter* painter = m_image->context().platformContext(); + painter->save(); + painter->setCompositionMode(QPainter::CompositionMode_Source); + painter->drawImage(targetRect, image, IntRect(sourceOffset, targetRect.size())); + painter->restore(); +#elif PLATFORM(CAIRO) + RefPtr<cairo_surface_t> surface = adoptRef(cairo_image_surface_create_for_data(static_cast<unsigned char*>(data()), + CAIRO_FORMAT_ARGB32, targetRect.width(), targetRect.height(), bytesPerLine)); + m_image->context()->platformContext()->drawSurfaceToContext(surface.get(), targetRect, + IntRect(sourceOffset, targetRect.size()), m_image->context()); +#else + UNUSED_PARAM(data); + UNUSED_PARAM(targetRect); + UNUSED_PARAM(sourceOffset); + UNUSED_PARAM(bytesPerLine); +#endif +} + +void BitmapTextureImageBuffer::updateContents(TextureMapper&, GraphicsLayer* sourceLayer, const IntRect& targetRect, const IntPoint& sourceOffset, UpdateContentsFlag, float scale) +{ + // QTFIXME: Handle scale, like BitmapTexture::updateContents + GraphicsContext& context = m_image->context(); + + context.clearRect(targetRect); + + IntRect sourceRect(targetRect); + sourceRect.setLocation(sourceOffset); + context.save(); + context.clip(targetRect); + context.translate(targetRect.x() - sourceOffset.x(), targetRect.y() - sourceOffset.y()); + sourceLayer->paintGraphicsLayerContents(context, sourceRect); + context.restore(); +} + +void BitmapTextureImageBuffer::didReset() +{ + m_image = ImageBuffer::create(contentSize(), Unaccelerated); +} + +void BitmapTextureImageBuffer::updateContents(Image* image, const IntRect& targetRect, const IntPoint& offset, UpdateContentsFlag) +{ + m_image->context().drawImage(*image, targetRect, IntRect(offset, targetRect.size()), CompositeCopy); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/texmap/BitmapTextureImageBuffer.h b/Source/WebCore/platform/graphics/texmap/BitmapTextureImageBuffer.h new file mode 100644 index 000000000..6443ba737 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/BitmapTextureImageBuffer.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2014 Igalia S.L. + * + * 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. + */ + +#ifndef BitmapTextureImageBuffer_h +#define BitmapTextureImageBuffer_h + +#include "BitmapTexture.h" +#include "ImageBuffer.h" +#include "IntRect.h" +#include "IntSize.h" + +namespace WebCore { + +class GraphicsContext; + +class BitmapTextureImageBuffer final : public BitmapTexture { +public: + static PassRefPtr<BitmapTexture> create() { return adoptRef(new BitmapTextureImageBuffer); } + IntSize size() const final { return m_image->internalSize(); } + void didReset() final; + bool isValid() const final { return m_image.get(); } + void updateContents(Image*, const IntRect&, const IntPoint&, UpdateContentsFlag) final; + void updateContents(TextureMapper&, GraphicsLayer*, const IntRect& target, const IntPoint& offset, UpdateContentsFlag, float scale) final; + void updateContents(const void*, const IntRect& target, const IntPoint& sourceOffset, int bytesPerLine, UpdateContentsFlag) final; + PassRefPtr<BitmapTexture> applyFilters(TextureMapper&, const FilterOperations&) final; + + inline GraphicsContext* graphicsContext() { return m_image ? &m_image->context() : nullptr; } + ImageBuffer* image() const { return m_image.get(); } + +private: + BitmapTextureImageBuffer() { } + std::unique_ptr<ImageBuffer> m_image; +}; + +} + +#endif // BitmapTextureImageBuffer_h diff --git a/Source/WebCore/platform/graphics/texmap/BitmapTexturePool.cpp b/Source/WebCore/platform/graphics/texmap/BitmapTexturePool.cpp index 1b46f3752..f0e7f23e7 100644 --- a/Source/WebCore/platform/graphics/texmap/BitmapTexturePool.cpp +++ b/Source/WebCore/platform/graphics/texmap/BitmapTexturePool.cpp @@ -31,11 +31,23 @@ #include "BitmapTextureGL.h" #endif +#if PLATFORM(QT) +#include "BitmapTextureImageBuffer.h" +#endif + namespace WebCore { static const double s_releaseUnusedSecondsTolerance = 3; static const double s_releaseUnusedTexturesTimerInterval = 0.5; + +#if PLATFORM(QT) +BitmapTexturePool::BitmapTexturePool() + : m_releaseUnusedTexturesTimer(*this, &BitmapTexturePool::releaseUnusedTexturesTimerFired) +{ +} +#endif + #if USE(TEXTURE_MAPPER_GL) BitmapTexturePool::BitmapTexturePool(RefPtr<GraphicsContext3D>&& context3D) : m_context3D(WTFMove(context3D)) @@ -104,10 +116,14 @@ void BitmapTexturePool::releaseUnusedTexturesTimerFired() RefPtr<BitmapTexture> BitmapTexturePool::createTexture(const BitmapTexture::Flags flags) { +#if PLATFORM(QT) + if (!m_context3D) + return BitmapTextureImageBuffer::create(); +#endif #if USE(TEXTURE_MAPPER_GL) return adoptRef(new BitmapTextureGL(m_context3D, flags)); #else - return nullptr; + return BitmapTextureImageBuffer::create(); #endif } diff --git a/Source/WebCore/platform/graphics/texmap/BitmapTexturePool.h b/Source/WebCore/platform/graphics/texmap/BitmapTexturePool.h index 95ba249aa..bf577344b 100644 --- a/Source/WebCore/platform/graphics/texmap/BitmapTexturePool.h +++ b/Source/WebCore/platform/graphics/texmap/BitmapTexturePool.h @@ -44,6 +44,9 @@ class BitmapTexturePool { WTF_MAKE_NONCOPYABLE(BitmapTexturePool); WTF_MAKE_FAST_ALLOCATED; public: +#if PLATFORM(QT) + BitmapTexturePool(); +#endif #if USE(TEXTURE_MAPPER_GL) explicit BitmapTexturePool(RefPtr<GraphicsContext3D>&&); #endif diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp index 636be8751..812980a28 100644 --- a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp +++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp @@ -608,7 +608,8 @@ void GraphicsLayerTextureMapper::removeAnimation(const String& animationName) bool GraphicsLayerTextureMapper::setFilters(const FilterOperations& filters) { TextureMapper* textureMapper = m_layer.textureMapper(); - if (!textureMapper) + // TextureMapperImageBuffer does not support CSS filters. + if (!textureMapper || textureMapper->accelerationMode() == TextureMapper::SoftwareMode) return false; notifyChange(FilterChange); return GraphicsLayer::setFilters(filters); diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp index b985c7b90..a458f8177 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp @@ -23,6 +23,7 @@ #include "BitmapTexturePool.h" #include "FilterOperations.h" #include "GraphicsLayer.h" +#include "TextureMapperImageBuffer.h" #include "Timer.h" #include <wtf/CurrentTime.h> @@ -35,15 +36,18 @@ PassRefPtr<BitmapTexture> TextureMapper::acquireTextureFromPool(const IntSize& s return selectedTexture.release(); } -std::unique_ptr<TextureMapper> TextureMapper::create() +std::unique_ptr<TextureMapper> TextureMapper::create(AccelerationMode mode) { + if (mode == SoftwareMode) + return std::make_unique<TextureMapperImageBuffer>(); return platformCreateAccelerated(); } -TextureMapper::TextureMapper() +TextureMapper::TextureMapper(AccelerationMode accelerationMode) : m_context(0) , m_interpolationQuality(InterpolationDefault) , m_textDrawingMode(TextModeFill) + , m_accelerationMode(accelerationMode) , m_isMaskMode(false) , m_wrapMode(StretchWrap) { } diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapper.h b/Source/WebCore/platform/graphics/texmap/TextureMapper.h index bfe718e28..43d1db7a1 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapper.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapper.h @@ -48,6 +48,7 @@ class FilterOperations; class TextureMapper { WTF_MAKE_FAST_ALLOCATED; public: + enum AccelerationMode { SoftwareMode, OpenGLMode }; enum PaintFlag { PaintingMirrored = 1 << 0, }; @@ -59,9 +60,9 @@ public: typedef unsigned PaintFlags; - static std::unique_ptr<TextureMapper> create(); + static std::unique_ptr<TextureMapper> create(AccelerationMode newMode = SoftwareMode); - explicit TextureMapper(); + explicit TextureMapper(AccelerationMode); virtual ~TextureMapper(); enum ExposedEdges { @@ -93,6 +94,7 @@ public: InterpolationQuality imageInterpolationQuality() const { return m_interpolationQuality; } TextDrawingModeFlags textDrawingMode() const { return m_textDrawingMode; } + AccelerationMode accelerationMode() const { return m_accelerationMode; } virtual void beginPainting(PaintFlags = 0) { } virtual void endPainting() { } @@ -125,6 +127,7 @@ private: #endif InterpolationQuality m_interpolationQuality; TextDrawingModeFlags m_textDrawingMode; + AccelerationMode m_accelerationMode; bool m_isMaskMode; TransformationMatrix m_patternTransform; WrapMode m_wrapMode; diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp index 86f100262..25ed9dd7f 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp @@ -176,7 +176,8 @@ void TextureMapperGLData::initializeStencil() } TextureMapperGL::TextureMapperGL() - : m_enableEdgeDistanceAntialiasing(false) + : TextureMapper(OpenGLMode) + , m_enableEdgeDistanceAntialiasing(false) { m_context3D = GraphicsContext3D::createForCurrentGLContext(); m_data = new TextureMapperGLData(m_context3D.get()); diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp new file mode 100644 index 000000000..0812b585d --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp @@ -0,0 +1,125 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + + 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 "TextureMapperImageBuffer.h" + +#include "BitmapTexturePool.h" +#include "GraphicsLayer.h" +#include "NotImplemented.h" + +#if USE(TEXTURE_MAPPER) +namespace WebCore { + +static const int s_maximumAllowedImageBufferDimension = 4096; + +TextureMapperImageBuffer::TextureMapperImageBuffer() + : TextureMapper(SoftwareMode) +{ + m_texturePool = std::make_unique<BitmapTexturePool>(); +} + +IntSize TextureMapperImageBuffer::maxTextureSize() const +{ + return IntSize(s_maximumAllowedImageBufferDimension, s_maximumAllowedImageBufferDimension); +} + +void TextureMapperImageBuffer::beginClip(const TransformationMatrix& matrix, const FloatRect& rect) +{ + GraphicsContext* context = currentContext(); + if (!context) + return; +#if ENABLE(3D_TRANSFORMS) + TransformationMatrix previousTransform = context->get3DTransform(); +#else + AffineTransform previousTransform = context->getCTM(); +#endif + context->save(); + +#if ENABLE(3D_TRANSFORMS) + context->concat3DTransform(matrix); +#else + context->concatCTM(matrix.toAffineTransform()); +#endif + + context->clip(rect); + +#if ENABLE(3D_TRANSFORMS) + context->set3DTransform(previousTransform); +#else + context->setCTM(previousTransform); +#endif +} + +void TextureMapperImageBuffer::drawTexture(const BitmapTexture& texture, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, unsigned /* exposedEdges */) +{ + GraphicsContext* context = currentContext(); + if (!context) + return; + + const BitmapTextureImageBuffer& textureImageBuffer = static_cast<const BitmapTextureImageBuffer&>(texture); + ImageBuffer* image = textureImageBuffer.image(); + context->save(); + context->setCompositeOperation(isInMaskMode() ? CompositeDestinationIn : CompositeSourceOver); + context->setAlpha(opacity); +#if ENABLE(3D_TRANSFORMS) + context->concat3DTransform(matrix); +#else + context->concatCTM(matrix.toAffineTransform()); +#endif + context->drawImageBuffer(*image, targetRect); + context->restore(); +} + +void TextureMapperImageBuffer::drawSolidColor(const FloatRect& rect, const TransformationMatrix& matrix, const Color& color) +{ + GraphicsContext* context = currentContext(); + if (!context) + return; + + context->save(); + context->setCompositeOperation(isInMaskMode() ? CompositeDestinationIn : CompositeSourceOver); +#if ENABLE(3D_TRANSFORMS) + context->concat3DTransform(matrix); +#else + context->concatCTM(matrix.toAffineTransform()); +#endif + + context->fillRect(rect, color); + context->restore(); +} + +void TextureMapperImageBuffer::drawBorder(const Color&, float /* borderWidth */, const FloatRect&, const TransformationMatrix&) +{ + notImplemented(); +} + +void TextureMapperImageBuffer::drawNumber(int /* number */, const Color&, const FloatPoint&, const TransformationMatrix&) +{ + notImplemented(); +} + +PassRefPtr<BitmapTexture> BitmapTextureImageBuffer::applyFilters(TextureMapper&, const FilterOperations&) +{ + ASSERT_NOT_REACHED(); + return this; +} + +} +#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h new file mode 100644 index 000000000..234b8eeec --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + + 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. + */ + +#ifndef TextureMapperImageBuffer_h +#define TextureMapperImageBuffer_h + +#include "BitmapTextureImageBuffer.h" +#include "ImageBuffer.h" +#include "TextureMapper.h" + +#if USE(TEXTURE_MAPPER) +namespace WebCore { + +class TextureMapperImageBuffer final : public TextureMapper { + WTF_MAKE_FAST_ALLOCATED; +public: + TextureMapperImageBuffer(); + + // TextureMapper implementation + void drawBorder(const Color&, float borderWidth, const FloatRect&, const TransformationMatrix&) final; + void drawNumber(int number, const Color&, const FloatPoint&, const TransformationMatrix&) final; + void drawTexture(const BitmapTexture&, const FloatRect& targetRect, const TransformationMatrix&, float opacity, unsigned exposedEdges) final; + void drawSolidColor(const FloatRect&, const TransformationMatrix&, const Color&) final; + void beginClip(const TransformationMatrix&, const FloatRect&) final; + void bindSurface(BitmapTexture* surface) final { m_currentSurface = surface;} + void endClip() final { graphicsContext()->restore(); } + IntRect clipBounds() final { return currentContext()->clipBounds(); } + IntSize maxTextureSize() const final; + PassRefPtr<BitmapTexture> createTexture() final { return BitmapTextureImageBuffer::create(); } + + inline GraphicsContext* currentContext() + { + return m_currentSurface ? static_cast<BitmapTextureImageBuffer*>(m_currentSurface.get())->graphicsContext() : graphicsContext(); + } + +private: + RefPtr<BitmapTexture> m_currentSurface; +}; + +} +#endif // USE(TEXTURE_MAPPER) + +#endif // TextureMapperImageBuffer_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CompositingCoordinator.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/CompositingCoordinator.cpp index 4bfddfd6c..e2f15b3b8 100644 --- a/Source/WebCore/platform/graphics/texmap/coordinated/CompositingCoordinator.cpp +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CompositingCoordinator.cpp @@ -58,6 +58,9 @@ CompositingCoordinator::CompositingCoordinator(Page* page, CompositingCoordinato , m_lastAnimationServiceTime(0) #endif { + // This is a temporary way to enable this only in the GL case, until TextureMapperImageBuffer is removed. + // See https://bugs.webkit.org/show_bug.cgi?id=114869 + CoordinatedGraphicsLayer::setShouldSupportContentsTiling(true); } CompositingCoordinator::~CompositingCoordinator() diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp index cb94a9652..7de531692 100644 --- a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp @@ -376,9 +376,16 @@ void CoordinatedGraphicsLayer::setContentsTilePhase(const FloatSize& p) didChangeLayerState(); } +static bool s_shouldSupportContentsTiling = false; + +void CoordinatedGraphicsLayer::setShouldSupportContentsTiling(bool s) +{ + s_shouldSupportContentsTiling = s; +} + bool GraphicsLayer::supportsContentsTiling() { - return true; + return s_shouldSupportContentsTiling; } void CoordinatedGraphicsLayer::setContentsNeedsDisplay() diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h index 8a45c3565..1664cffe7 100644 --- a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h @@ -146,6 +146,7 @@ public: void setNeedsVisibleRectAdjustment(); void purgeBackingStores(); + static void setShouldSupportContentsTiling(bool); CoordinatedGraphicsLayer* findFirstDescendantWithContentsRecursively(); private: diff --git a/Source/WebCore/platform/qt/FileSystemQt.cpp b/Source/WebCore/platform/qt/FileSystemQt.cpp index 363029406..167ff8354 100644 --- a/Source/WebCore/platform/qt/FileSystemQt.cpp +++ b/Source/WebCore/platform/qt/FileSystemQt.cpp @@ -147,6 +147,12 @@ CString fileSystemRepresentation(const String& path) return path.utf8(); } +String stringFromFileSystemRepresentation(const char* fileSystemRepresentation) +{ + // This needs to do the opposite of fileSystemRepresentation. + return String::fromUTF8(fileSystemRepresentation); +} + String openTemporaryFile(const String& prefix, PlatformFileHandle& handle) { #ifndef QT_NO_TEMPORARYFILE diff --git a/Source/WebCore/platform/qt/QWebPageClient.h b/Source/WebCore/platform/qt/QWebPageClient.h index c9211044c..c37abff62 100644 --- a/Source/WebCore/platform/qt/QWebPageClient.h +++ b/Source/WebCore/platform/qt/QWebPageClient.h @@ -34,6 +34,7 @@ #include <QRect> QT_BEGIN_NAMESPACE +class QOpenGLContext; class QStyle; class QWindow; QT_END_NAMESPACE @@ -54,6 +55,7 @@ public: virtual void setInputMethodEnabled(bool) = 0; virtual bool inputMethodEnabled() const = 0; virtual bool makeOpenGLContextCurrentIfAvailable() { return false; } + virtual QOpenGLContext* openGLContextIfAvailable() { return 0; } virtual void setInputMethodHints(Qt::InputMethodHints) = 0; virtual bool isViewVisible() = 0; diff --git a/Source/WebCore/platform/text/hyphen/HyphenationLibHyphen.cpp b/Source/WebCore/platform/text/hyphen/HyphenationLibHyphen.cpp index 16a540c91..92ce4685a 100644 --- a/Source/WebCore/platform/text/hyphen/HyphenationLibHyphen.cpp +++ b/Source/WebCore/platform/text/hyphen/HyphenationLibHyphen.cpp @@ -31,6 +31,8 @@ #include "FileSystem.h" #include <hyphen.h> +#include <limits> +#include <stdlib.h> #include <wtf/HashMap.h> #include <wtf/NeverDestroyed.h> #include <wtf/TinyLRUCache.h> @@ -62,8 +64,14 @@ static String extractLocaleFromDictionaryFilePath(const String& filePath) static void scanDirectoryForDicionaries(const char* directoryPath, HashMap<AtomicString, Vector<String>>& availableLocales) { - for (const auto& filePath : listDirectory(directoryPath, "hyph_*.dic")) { + for (auto& filePath : listDirectory(directoryPath, "hyph_*.dic")) { String locale = extractLocaleFromDictionaryFilePath(filePath).convertToASCIILowercase(); + + char normalizedPath[PATH_MAX]; + if (!realpath(fileSystemRepresentation(filePath).data(), normalizedPath)) + continue; + + filePath = stringFromFileSystemRepresentation(normalizedPath); availableLocales.add(locale, Vector<String>()).iterator->value.append(filePath); String localeReplacingUnderscores = String(locale); @@ -170,9 +178,9 @@ template<> class TinyLRUCachePolicy<AtomicString, RefPtr<HyphenationDictionary>> { public: - static TinyLRUCache<AtomicString, RefPtr<HyphenationDictionary>>& cache() + static TinyLRUCache<AtomicString, RefPtr<WebCore::HyphenationDictionary>, 32>& cache() { - static NeverDestroyed<TinyLRUCache<AtomicString, RefPtr<HyphenationDictionary>>> cache; + static NeverDestroyed<TinyLRUCache<AtomicString, RefPtr<WebCore::HyphenationDictionary>, 32>> cache; return cache; } |