diff options
Diffstat (limited to 'WebCore/platform')
142 files changed, 4029 insertions, 1768 deletions
diff --git a/WebCore/platform/AsyncFileStream.h b/WebCore/platform/AsyncFileStream.h new file mode 100644 index 0000000..3abda01 --- /dev/null +++ b/WebCore/platform/AsyncFileStream.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AsyncFileStream_h +#define AsyncFileStream_h + +#if ENABLE(BLOB) || ENABLE(FILE_WRITER) + +#include "FileStreamClient.h" +#include <wtf/Forward.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class KURL; + +class AsyncFileStream : public RefCounted<AsyncFileStream> { +public: + virtual ~AsyncFileStream() { } + + virtual void getSize(const String& path, double expectedModificationTime) = 0; + virtual void openForRead(const String& path, long long offset, long long length) = 0; + virtual void openForWrite(const String& path) = 0; + virtual void close() = 0; + virtual void read(char* buffer, int length) = 0; + virtual void write(const KURL& blobURL, long long position, int length) = 0; + virtual void truncate(long long position) = 0; + virtual void stop() = 0; + + FileStreamClient* client() const { return m_client; } + void setClient(FileStreamClient* client) { m_client = client; } + +protected: + AsyncFileStream(FileStreamClient* client) + : m_client(client) + { + } + +private: + FileStreamClient* m_client; +}; + +} // namespace WebCore + +#endif // ENABLE(BLOB) || ENABLE(FILE_WRITER) + +#endif // AsyncFileStream_h diff --git a/WebCore/platform/ContextMenu.cpp b/WebCore/platform/ContextMenu.cpp index 84a2ffc..37d4c2b 100644 --- a/WebCore/platform/ContextMenu.cpp +++ b/WebCore/platform/ContextMenu.cpp @@ -584,6 +584,10 @@ void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const if (!frame) return; + // Custom items already have proper checked and enabled values. + if (ContextMenuItemBaseCustomTag <= item.action() && item.action() <= ContextMenuItemLastCustomTag) + return; + bool shouldEnable = true; bool shouldCheck = false; diff --git a/WebCore/platform/Cursor.h b/WebCore/platform/Cursor.h index 5e547ef..92d3596 100644 --- a/WebCore/platform/Cursor.h +++ b/WebCore/platform/Cursor.h @@ -62,7 +62,7 @@ typedef struct HICON__ *HICON; typedef HICON HCURSOR; #endif -#if PLATFORM(WIN) || PLATFORM(MAC) || PLATFORM(GTK) +#if PLATFORM(WIN) || PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(QT) #define WTF_USE_LAZY_NATIVE_CURSOR 1 #endif @@ -84,11 +84,12 @@ namespace WebCore { #elif PLATFORM(MAC) typedef NSCursor* PlatformCursor; #elif PLATFORM(GTK) - typedef GRefPtr<GdkCursor> PlatformCursor; + typedef PlatformRefPtr<GdkCursor> PlatformCursor; #elif PLATFORM(EFL) typedef const char* PlatformCursor; #elif PLATFORM(QT) && !defined(QT_NO_CURSOR) - typedef QCursor PlatformCursor; + // Do not need to be shared but need to be created dynamically via ensurePlatformCursor. + typedef QCursor* PlatformCursor; #elif PLATFORM(WX) typedef wxCursor* PlatformCursor; #elif PLATFORM(CHROMIUM) @@ -151,7 +152,7 @@ namespace WebCore { static const Cursor& fromType(Cursor::Type); Cursor() -#if !PLATFORM(QT) && !PLATFORM(EFL) +#if !PLATFORM(EFL) : m_platformCursor(0) #endif { diff --git a/WebCore/platform/FileStream.cpp b/WebCore/platform/FileStream.cpp new file mode 100644 index 0000000..45f435e --- /dev/null +++ b/WebCore/platform/FileStream.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(BLOB) || ENABLE(FILE_WRITER) + +#include "FileStream.h" + +#include "PlatformString.h" + +namespace WebCore { + +FileStream::FileStream() + : m_handle(invalidPlatformFileHandle) + , m_bytesProcessed(0) + , m_totalBytesToRead(0) +{ +} + +FileStream::~FileStream() +{ + ASSERT(!isHandleValid(m_handle)); +} + +// FIXME: To be removed when we switch to using BlobData. +void FileStream::start() +{ +} + +void FileStream::stop() +{ + close(); +} + +long long FileStream::getSize(const String& path, double expectedModificationTime) +{ + // Check the modification time for the possible file change. + time_t modificationTime; + if (!getFileModificationTime(path, modificationTime)) + return -1; + if (expectedModificationTime) { + if (static_cast<time_t>(expectedModificationTime) != modificationTime) + return -1; + } + + // Now get the file size. + long long length; + if (!getFileSize(path, length)) + return -1; + + return length; +} + +bool FileStream::openForRead(const String& path, long long offset, long long length) +{ + if (isHandleValid(m_handle)) + return true; + + // Open the file. + m_handle = openFile(path, OpenForRead); + if (!isHandleValid(m_handle)) + return false; + + // Jump to the beginning position if the file has been sliced. + if (offset > 0) { + if (seekFile(m_handle, offset, SeekFromBeginning) < 0) + return false; + } + + m_totalBytesToRead = length; + m_bytesProcessed = 0; + + return true; +} + +bool FileStream::openForWrite(const String&) +{ + // FIXME: to be implemented. + return false; +} + +void FileStream::close() +{ + if (isHandleValid(m_handle)) { + closeFile(m_handle); + m_handle = invalidPlatformFileHandle; + } +} + +int FileStream::read(char* buffer, int bufferSize) +{ + if (!isHandleValid(m_handle)) + return -1; + + long long remaining = m_totalBytesToRead - m_bytesProcessed; + int bytesToRead = (remaining < bufferSize) ? static_cast<int>(remaining) : bufferSize; + int bytesRead = 0; + if (bytesToRead > 0) + bytesRead = readFromFile(m_handle, buffer, bytesToRead); + if (bytesRead < 0) + return -1; + if (bytesRead > 0) + m_bytesProcessed += bytesRead; + + return bytesRead; +} + +int FileStream::write(const KURL&, long long, int) +{ + // FIXME: to be implemented. + return -1; +} + +bool FileStream::truncate(long long) +{ + // FIXME: to be implemented. + return false; +} + +} // namespace WebCore + +#endif // ENABLE(BLOB) || ENABLE(FILE_WRITER) diff --git a/WebCore/platform/FileStream.h b/WebCore/platform/FileStream.h new file mode 100644 index 0000000..6c3a221 --- /dev/null +++ b/WebCore/platform/FileStream.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FileStream_h +#define FileStream_h + +#if ENABLE(BLOB) || ENABLE(FILE_WRITER) + +#include "FileSystem.h" +#include <wtf/Forward.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class KURL; + +// All methods are synchronous. +class FileStream : public RefCounted<FileStream> { +public: + static PassRefPtr<FileStream> create() + { + return adoptRef(new FileStream()); + } + ~FileStream(); + + // FIXME: To be removed when we switch to using BlobData. + void start(); + + // Aborts the operation. + void stop(); + + // Gets the size of a file. Also validates if the file has been changed or not if the expected modification time is provided, i.e. non-zero. + // Returns total number of bytes if successful. -1 otherwise. + long long getSize(const String& path, double expectedModificationTime); + + // Opens a file for reading. The reading starts at the specified offset and lasts till the specified length. + // Returns true on success. False otherwise. + bool openForRead(const String& path, long long offset, long long length); + + // Opens a file for writing. + // Returns true on success. False otherwise. + bool openForWrite(const String& path); + + // Closes the file. + void close(); + + // Reads a file into the provided data buffer. + // Returns number of bytes being read on success. -1 otherwise. + // If 0 is returned, it means that the reading is completed. + int read(char* buffer, int length); + + // Writes a blob to the file. + // Returns number of bytes being written on success. -1 otherwise. + int write(const KURL& blobURL, long long position, int length); + + // Truncates the file to the specified position. + // Returns true on success. False otherwise. + bool truncate(long long position); + +private: + FileStream(); + + PlatformFileHandle m_handle; + long long m_bytesProcessed; + long long m_totalBytesToRead; +}; + +} // namespace WebCore + +#endif // ENABLE(BLOB) || ENABLE(FILE_WRITER) + +#endif // FileStream_h diff --git a/WebCore/platform/graphics/chromium/TransformLayerChromium.h b/WebCore/platform/FileStreamClient.h index 3d5ce94..b3d1fff 100644 --- a/WebCore/platform/graphics/chromium/TransformLayerChromium.h +++ b/WebCore/platform/FileStreamClient.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -28,28 +28,36 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef FileStreamClient_h +#define FileStreamClient_h -#ifndef TransformLayerChromium_h -#define TransformLayerChromium_h - -#if USE(ACCELERATED_COMPOSITING) - -#include "LayerChromium.h" +#if ENABLE(BLOB) || ENABLE(FILE_WRITER) namespace WebCore { -// A Layer that doesn't draw any content but simply exists to group and -// transform its descendants. -class TransformLayerChromium : public LayerChromium { +class FileStreamClient { public: - static PassRefPtr<TransformLayerChromium> create(GraphicsLayerChromium* owner = 0); - virtual bool drawsContent() { return false; } + // For reading. + virtual void didRead(int) { } + + // For writing. + virtual void didWrite(int) { } + virtual void didTruncate(bool) { } -private: - TransformLayerChromium(GraphicsLayerChromium* owner); + // FIXME: To be removed when we switch to using BlobData. + virtual void didStart() { } + + // For both reading and writing. + virtual void didOpen(bool) { } + virtual void didStop() { } + virtual void didGetSize(long long) { } + +protected: + virtual ~FileStreamClient() { } }; -} -#endif // USE(ACCELERATED_COMPOSITING) +} // namespace WebCore + +#endif // ENABLE(BLOB) || ENABLE(FILE_WRITER) -#endif +#endif // FileStreamClient_h diff --git a/WebCore/platform/PlatformTouchPoint.h b/WebCore/platform/PlatformTouchPoint.h index 4a667a0..3a25736 100644 --- a/WebCore/platform/PlatformTouchPoint.h +++ b/WebCore/platform/PlatformTouchPoint.h @@ -45,6 +45,7 @@ public: #if PLATFORM(QT) PlatformTouchPoint(const QTouchEvent::TouchPoint&); + PlatformTouchPoint() {}; #elif PLATFORM(ANDROID) PlatformTouchPoint(const IntPoint& windowPos, State); #endif diff --git a/WebCore/platform/chromium/ChromiumBridge.h b/WebCore/platform/chromium/ChromiumBridge.h index fc1345e..35ace89 100644 --- a/WebCore/platform/chromium/ChromiumBridge.h +++ b/WebCore/platform/chromium/ChromiumBridge.h @@ -72,8 +72,10 @@ namespace WebCore { class GraphicsContext; class Image; class IDBFactoryBackendInterface; + class IDBKey; class IntRect; class KURL; + class SerializedScriptValue; class Widget; struct Cookie; @@ -167,6 +169,8 @@ namespace WebCore { // IndexedDB ---------------------------------------------------------- static PassRefPtr<IDBFactoryBackendInterface> idbFactory(); + // Extracts keyPath from values and returns the corresponding keys. + static void createIDBKeysFromSerializedValuesAndKeyPath(const Vector<RefPtr<SerializedScriptValue> >& values, const String& keyPath, Vector<RefPtr<IDBKey> >& keys); // JavaScript --------------------------------------------------------- static void notifyJSOutOfMemory(Frame*); diff --git a/WebCore/platform/chromium/ClipboardChromium.cpp b/WebCore/platform/chromium/ClipboardChromium.cpp index 06244a2..23508a6 100644 --- a/WebCore/platform/chromium/ClipboardChromium.cpp +++ b/WebCore/platform/chromium/ClipboardChromium.cpp @@ -400,7 +400,12 @@ void ClipboardChromium::setDragImageElement(Node* node, const IntPoint& loc) DragImageRef ClipboardChromium::createDragImage(IntPoint& loc) const { DragImageRef result = 0; - if (m_dragImage) { + if (m_dragImageElement) { + if (m_frame) { + result = m_frame->nodeImage(m_dragImageElement.get()); + loc = m_dragLoc; + } + } else if (m_dragImage) { result = createDragImageFromImage(m_dragImage->image()); loc = m_dragLoc; } diff --git a/WebCore/platform/efl/PopupMenuEfl.cpp b/WebCore/platform/efl/PopupMenuEfl.cpp index 401f24f..a6f7a53 100644 --- a/WebCore/platform/efl/PopupMenuEfl.cpp +++ b/WebCore/platform/efl/PopupMenuEfl.cpp @@ -43,7 +43,8 @@ PopupMenuEfl::~PopupMenuEfl() { // Tell client to destroy data related to this popup since this object is // going away. - hide(); + if (m_view) + hide(); } void PopupMenuEfl::show(const IntRect& rect, FrameView* view, int index) diff --git a/WebCore/platform/efl/RenderThemeEfl.cpp b/WebCore/platform/efl/RenderThemeEfl.cpp index 36600a9..102f754 100644 --- a/WebCore/platform/efl/RenderThemeEfl.cpp +++ b/WebCore/platform/efl/RenderThemeEfl.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "RenderThemeEfl.h" +#include "CSSValueKeywords.h" #include "FileSystem.h" #include "Frame.h" #include "FrameView.h" @@ -631,6 +632,8 @@ void RenderThemeEfl::themeChanged() applyPartDescriptions(); } +float RenderThemeEfl::defaultFontSize = 16.0f; + RenderThemeEfl::RenderThemeEfl(Page* page) : RenderTheme() , m_page(page) @@ -985,10 +988,24 @@ bool RenderThemeEfl::paintSearchField(RenderObject* o, const PaintInfo& i, const return paintThemePart(o, SearchField, i, rect); } -void RenderThemeEfl::systemFont(int, FontDescription&) const +void RenderThemeEfl::setDefaultFontSize(int size) { - // If you remove this notImplemented(), replace it with an comment that explains why. - notImplemented(); + defaultFontSize = size; +} + +void RenderThemeEfl::systemFont(int propId, FontDescription& fontDescription) const +{ + // It was called by RenderEmbeddedObject::paintReplaced to render alternative string. + // To avoid cairo_error while rendering, fontDescription should be passed. + DEFINE_STATIC_LOCAL(String, fontFace, ("Sans")); + float fontSize = defaultFontSize; + + fontDescription.firstFamily().setFamily(fontFace); + fontDescription.setSpecifiedSize(fontSize); + fontDescription.setIsAbsoluteSize(true); + fontDescription.setGenericFamily(FontDescription::NoFamily); + fontDescription.setWeight(FontWeightNormal); + fontDescription.setItalic(false); } } diff --git a/WebCore/platform/efl/RenderThemeEfl.h b/WebCore/platform/efl/RenderThemeEfl.h index 8e5650d..478dfc5 100644 --- a/WebCore/platform/efl/RenderThemeEfl.h +++ b/WebCore/platform/efl/RenderThemeEfl.h @@ -142,6 +142,12 @@ public: virtual void adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); + + static void setDefaultFontSize(int size); + +protected: + static float defaultFontSize; + private: void createCanvas(); void createEdje(); diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h index c48f91a..1056d81 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -48,6 +48,9 @@ class SurfaceOpenVG; typedef class WebCore::SurfaceOpenVG PlatformGraphicsContext; #elif PLATFORM(QT) #include <QPainter> +namespace WebCore { +class ContextShadow; +} typedef QPainter PlatformGraphicsContext; #elif PLATFORM(WX) class wxGCDC; @@ -329,8 +332,8 @@ namespace WebCore { void setAlpha(float); #if PLATFORM(CAIRO) float getAlpha(); - void createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float kernelSize); - static void calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& kernelSize, const FloatRect& sourceRect, const FloatSize& shadowSize, float shadowBlur); + void createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float radius); + static void calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& radius, const FloatRect& sourceRect, const FloatSize& shadowSize, float shadowBlur); #endif void setCompositeOperation(CompositeOperator); @@ -431,6 +434,7 @@ namespace WebCore { void pushTransparencyLayerInternal(const QRect &rect, qreal opacity, QPixmap& alphaMask); QPen pen(); static QPainter::CompositionMode toQtCompositionMode(CompositeOperator op); + ContextShadow* contextShadow(); #endif #if PLATFORM(GTK) diff --git a/WebCore/platform/graphics/GraphicsContext3D.cpp b/WebCore/platform/graphics/GraphicsContext3D.cpp index 51c4cd5..170bb84 100644 --- a/WebCore/platform/graphics/GraphicsContext3D.cpp +++ b/WebCore/platform/graphics/GraphicsContext3D.cpp @@ -144,7 +144,7 @@ bool GraphicsContext3D::extractTextureData(unsigned int width, unsigned int heig unsigned int format, unsigned int type, unsigned int unpackAlignment, bool flipY, bool premultiplyAlpha, - ArrayBufferView* pixels, + const void* pixels, Vector<uint8_t>& data) { // Assumes format, type, etc. have already been validated. @@ -193,7 +193,7 @@ bool GraphicsContext3D::extractTextureData(unsigned int width, unsigned int heig unsigned long bytesPerPixel = componentsPerPixel * bytesPerComponent; data.resize(width * height * bytesPerPixel); - if (!packPixels(static_cast<uint8_t*>(pixels->baseAddress()), + if (!packPixels(static_cast<const uint8_t*>(pixels), sourceDataFormat, width, height, unpackAlignment, format, type, @@ -424,6 +424,7 @@ void packRGBA8ToRGBA8Premultiply(const uint8_t* source, uint8_t* destination) destination[0] = sourceR; destination[1] = sourceG; destination[2] = sourceB; + destination[3] = source[3]; } // FIXME: this routine is lossy and must be removed. diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h index 25d1d06..b583813 100644 --- a/WebCore/platform/graphics/GraphicsContext3D.h +++ b/WebCore/platform/graphics/GraphicsContext3D.h @@ -77,15 +77,10 @@ const Platform3DObject NullPlatform3DObject = 0; #endif namespace WebCore { -class ArrayBuffer; -class ArrayBufferView; class CanvasRenderingContext; -class Float32Array; class HostWindow; class Image; class ImageData; -class Int32Array; -class Uint8Array; class WebGLActiveInfo; struct ActiveInfo { @@ -468,6 +463,8 @@ public: int sizeInBytes(int type); bool isGLES2Compliant() const; + bool isGLES2NPOTStrict() const; + bool isErrorGeneratedOnOutOfBoundsAccesses() const; //---------------------------------------------------------------------- // Helpers for texture uploading and pixel readback. @@ -512,7 +509,7 @@ public: unsigned int format, unsigned int type, unsigned int unpackAlignment, bool flipY, bool premultiplyAlpha, - ArrayBufferView* pixels, + const void* pixels, Vector<uint8_t>& data); // Flips the given image data vertically, in-place. @@ -556,10 +553,8 @@ public: void blendFuncSeparate(unsigned long srcRGB, unsigned long dstRGB, unsigned long srcAlpha, unsigned long dstAlpha); void bufferData(unsigned long target, int size, unsigned long usage); - void bufferData(unsigned long target, ArrayBuffer* data, unsigned long usage); - void bufferData(unsigned long target, ArrayBufferView* data, unsigned long usage); - void bufferSubData(unsigned long target, long offset, ArrayBuffer* data); - void bufferSubData(unsigned long target, long offset, ArrayBufferView* data); + void bufferData(unsigned long target, int size, const void* data, unsigned long usage); + void bufferSubData(unsigned long target, long offset, int size, const void* data); unsigned long checkFramebufferStatus(unsigned long target); void clear(unsigned long mask); diff --git a/WebCore/platform/graphics/ImageSource.cpp b/WebCore/platform/graphics/ImageSource.cpp index 7f6d323..c6d97fe 100644 --- a/WebCore/platform/graphics/ImageSource.cpp +++ b/WebCore/platform/graphics/ImageSource.cpp @@ -41,8 +41,9 @@ namespace WebCore { unsigned ImageSource::s_maxPixelsPerDecodedImage = 1024 * 1024; #endif -ImageSource::ImageSource() +ImageSource::ImageSource(bool premultiplyAlpha) : m_decoder(0) + , m_premultiplyAlpha(premultiplyAlpha) { } @@ -77,7 +78,7 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived) // If insufficient bytes are available to determine the image type, no decoder plugin will be // made. if (!m_decoder) { - m_decoder = static_cast<NativeImageSourcePtr>(ImageDecoder::create(*data)); + m_decoder = static_cast<NativeImageSourcePtr>(ImageDecoder::create(*data, m_premultiplyAlpha)); #if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) if (m_decoder && s_maxPixelsPerDecodedImage) m_decoder->setMaxNumPixels(s_maxPixelsPerDecodedImage); diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h index 014c136..189f0f5 100644 --- a/WebCore/platform/graphics/ImageSource.h +++ b/WebCore/platform/graphics/ImageSource.h @@ -133,7 +133,7 @@ const int cAnimationNone = -2; class ImageSource : public Noncopyable { public: - ImageSource(); + ImageSource(bool premultiplyAlpha = true); ~ImageSource(); // Tells the ImageSource that the Image no longer cares about decoded frame @@ -201,6 +201,7 @@ private: protected: #endif NativeImageSourcePtr m_decoder; + bool m_premultiplyAlpha; #if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) static unsigned s_maxPixelsPerDecodedImage; #endif diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp index e72987a..87060a4 100644 --- a/WebCore/platform/graphics/MediaPlayer.cpp +++ b/WebCore/platform/graphics/MediaPlayer.cpp @@ -194,6 +194,24 @@ static void addMediaEngine(CreateMediaEnginePlayer constructor, MediaEngineSuppo installedMediaEngines().append(new MediaPlayerFactory(constructor, getSupportedTypes, supportsType)); } +static const AtomicString& applicationOctetStream() +{ + DEFINE_STATIC_LOCAL(const AtomicString, applicationOctetStream, ("application/octet-stream")); + return applicationOctetStream; +} + +static const AtomicString& textPlain() +{ + DEFINE_STATIC_LOCAL(const AtomicString, textPlain, ("text/plain")); + return textPlain; +} + +static const AtomicString& codecs() +{ + DEFINE_STATIC_LOCAL(const AtomicString, codecs, ("codecs")); + return codecs; +} + static MediaPlayerFactory* chooseBestEngineForTypeAndCodecs(const String& type, const String& codecs) { Vector<MediaPlayerFactory*>& engines = installedMediaEngines(); @@ -201,6 +219,14 @@ static MediaPlayerFactory* chooseBestEngineForTypeAndCodecs(const String& type, if (engines.isEmpty()) return 0; + // 4.8.10.3 MIME types - In the absence of a specification to the contrary, the MIME type "application/octet-stream" + // when used with parameters, e.g. "application/octet-stream;codecs=theora", is a type that the user agent knows + // it cannot render. + if (type == applicationOctetStream()) { + if (!codecs.isEmpty()) + return 0; + } + MediaPlayerFactory* engine = 0; MediaPlayer::SupportsType supported = MediaPlayer::IsNotSupported; @@ -252,11 +278,11 @@ MediaPlayer::~MediaPlayer() void MediaPlayer::load(const String& url, const ContentType& contentType) { - String type = contentType.type(); - String codecs = contentType.parameter("codecs"); + String type = contentType.type().lower(); + String typeCodecs = contentType.parameter(codecs()); - // if we don't know the MIME type, see if the extension can help - if (type.isEmpty() || type == "application/octet-stream" || type == "text/plain") { + // If the MIME type is unhelpful, see if the type registry has a match for the file extension. + if (type.isEmpty() || type == applicationOctetStream() || type == textPlain()) { size_t pos = url.reverseFind('.'); if (pos != notFound) { String extension = url.substring(pos + 1); @@ -268,14 +294,17 @@ void MediaPlayer::load(const String& url, const ContentType& contentType) MediaPlayerFactory* engine = 0; if (!type.isEmpty()) - engine = chooseBestEngineForTypeAndCodecs(type, codecs); + engine = chooseBestEngineForTypeAndCodecs(type, typeCodecs); - // if we didn't find an engine that claims the MIME type, just use the first engine - if (!engine && !installedMediaEngines().isEmpty()) + // If we didn't find an engine and no MIME type is specified, just use the first engine. + if (!engine && type.isEmpty() && !installedMediaEngines().isEmpty()) engine = installedMediaEngines()[0]; - // don't delete and recreate the player unless it comes from a different engine - if (engine && m_currentMediaEngine != engine) { + // Don't delete and recreate the player unless it comes from a different engine + if (!engine) { + m_currentMediaEngine = engine; + m_private.clear(); + } else if (m_currentMediaEngine != engine) { m_currentMediaEngine = engine; m_private.clear(); m_private.set(engine->constructor(this)); @@ -532,14 +561,26 @@ void MediaPlayer::paintCurrentFrameInContext(GraphicsContext* p, const IntRect& MediaPlayer::SupportsType MediaPlayer::supportsType(ContentType contentType) { - String type = contentType.type(); - String codecs = contentType.parameter("codecs"); - MediaPlayerFactory* engine = chooseBestEngineForTypeAndCodecs(type, codecs); + String type = contentType.type().lower(); + String typeCodecs = contentType.parameter(codecs()); + + // 4.8.10.3 MIME types - In the absence of a specification to the contrary, the MIME type "application/octet-stream" + // when used with parameters, e.g. "application/octet-stream;codecs=theora", is a type that the user agent knows + // it cannot render. + if (type == applicationOctetStream()) { + if (!typeCodecs.isEmpty()) + return IsNotSupported; + + // The MIME type "application/octet-stream" with no parameters is never a type that the user agent knows it + // cannot render. + return MayBeSupported; + } + MediaPlayerFactory* engine = chooseBestEngineForTypeAndCodecs(type, typeCodecs); if (!engine) return IsNotSupported; - return engine->supportsTypeAndCodecs(type, codecs); + return engine->supportsTypeAndCodecs(type, typeCodecs); } void MediaPlayer::getSupportedTypes(HashSet<String>& types) diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp index 9217a81..f6d8f3d 100644 --- a/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -94,15 +94,15 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons FloatRect rect(FloatPoint(), FloatSize(extents.width, extents.height)); IntSize shadowBufferSize; FloatRect shadowRect; - float kernelSize = 0.f; - GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur); + float radius = 0; + context->calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowSize, shadowBlur); // Draw shadow into a new ImageBuffer OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); GraphicsContext* shadowContext = shadowBuffer->context(); cairo_t* shadowCr = shadowContext->platformContext(); - cairo_translate(shadowCr, kernelSize, extents.height + kernelSize); + cairo_translate(shadowCr, radius, extents.height + radius); cairo_set_scaled_font(shadowCr, font->platformData().scaledFont()); cairo_show_glyphs(shadowCr, glyphs, numGlyphs); @@ -113,7 +113,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons cairo_restore(shadowCr); } cairo_translate(cr, 0.0, -extents.height); - context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius); #else cairo_translate(cr, shadowSize.width(), shadowSize.height()); cairo_show_glyphs(cr, glyphs, numGlyphs); diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 9b3096e..3a667ac 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -61,6 +61,8 @@ #include "GraphicsContextPlatformPrivateCairo.h" #include "GraphicsContextPrivate.h" +using namespace std; + #ifndef M_PI #define M_PI 3.14159265358979323846 #endif @@ -173,18 +175,17 @@ static void addConvexPolygonToContext(cairo_t* context, size_t numPoints, const cairo_close_path(context); } -void GraphicsContext::calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& kernelSize, const FloatRect& sourceRect, const FloatSize& shadowSize, float shadowBlur) +void GraphicsContext::calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& radius, const FloatRect& sourceRect, const FloatSize& shadowSize, float shadowBlur) { #if ENABLE(FILTERS) - // calculate the kernel size according to the HTML5 canvas shadow specification - kernelSize = (shadowBlur < 8 ? shadowBlur / 2.f : sqrt(shadowBlur * 2.f)); - int blurRadius = ceil(kernelSize); + // limit radius to 128 + radius = min(128.f, max(shadowBlur, 0.f)); - shadowBufferSize = IntSize(sourceRect.width() + blurRadius * 2, sourceRect.height() + blurRadius * 2); + shadowBufferSize = IntSize(sourceRect.width() + radius * 2, sourceRect.height() + radius * 2); // determine dimensions of shadow rect shadowRect = FloatRect(sourceRect.location(), shadowBufferSize); - shadowRect.move(shadowSize.width() - kernelSize, shadowSize.height() - kernelSize); + shadowRect.move(shadowSize.width() - radius, shadowSize.height() - radius); #endif } @@ -209,8 +210,8 @@ static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPriva IntSize shadowBufferSize; FloatRect shadowRect; - float kernelSize = 0; - GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur); + float radius = 0; + GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowSize, shadowBlur); // Create suitably-sized ImageBuffer to hold the shadow. OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); @@ -218,7 +219,7 @@ static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPriva // Draw shadow into a new ImageBuffer. cairo_t* shadowContext = shadowBuffer->context()->platformContext(); copyContextProperties(cr, shadowContext); - cairo_translate(shadowContext, -rect.x() + kernelSize, -rect.y() + kernelSize); + cairo_translate(shadowContext, -rect.x() + radius, -rect.y() + radius); cairo_new_path(shadowContext); cairo_append_path(shadowContext, path); @@ -227,7 +228,7 @@ static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPriva if (strokeShadow) setPlatformStroke(context, shadowContext, gcp); - context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius); #endif } @@ -631,15 +632,15 @@ static void drawBorderlessRectShadow(GraphicsContext* context, const FloatRect& IntSize shadowBufferSize; FloatRect shadowRect; - float kernelSize = 0; - GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur); + float radius = 0; + GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowSize, shadowBlur); // Draw shadow into a new ImageBuffer OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); GraphicsContext* shadowContext = shadowBuffer->context(); - shadowContext->fillRect(FloatRect(FloatPoint(kernelSize, kernelSize), rect.size()), rectColor, DeviceColorSpace); + shadowContext->fillRect(FloatRect(FloatPoint(radius, radius), rect.size()), rectColor, DeviceColorSpace); - context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius); #endif } @@ -920,28 +921,28 @@ void GraphicsContext::setPlatformShadow(FloatSize const& size, float, Color cons } } -void GraphicsContext::createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float kernelSize) +void GraphicsContext::createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float radius) { #if ENABLE(FILTERS) cairo_t* cr = m_data->cr; - // draw the shadow without blurring, if kernelSize is zero - if (!kernelSize) { + // calculate the standard deviation + float sd = FEGaussianBlur::calculateStdDeviation(radius); + + // draw the shadow without blurring, if radius is zero + if (!radius || !sd) { setColor(cr, shadowColor); cairo_mask_surface(cr, buffer->m_data.m_surface, shadowRect.x(), shadowRect.y()); return; } - // limit kernel size to 1000, this is what CG is doing. - kernelSize = std::min(1000.f, kernelSize); - // create filter RefPtr<Filter> filter = ImageBufferFilter::create(); filter->setSourceImage(buffer); RefPtr<FilterEffect> source = SourceGraphic::create(); source->setScaledSubRegion(FloatRect(FloatPoint(), shadowRect.size())); source->setIsAlphaImage(true); - RefPtr<FilterEffect> blur = FEGaussianBlur::create(source.get(), kernelSize, kernelSize); + RefPtr<FilterEffect> blur = FEGaussianBlur::create(source.get(), sd, sd); blur->setScaledSubRegion(FloatRect(FloatPoint(), shadowRect.size())); blur->apply(filter.get()); diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h index 97e7e07..81987ef 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h +++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h @@ -27,6 +27,7 @@ #include "GraphicsContext.h" +#include "CairoPath.h" #include <cairo.h> #include <math.h> #include <stdio.h> diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index db66276..976dcb4 100644 --- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -38,10 +38,8 @@ #include "NotImplemented.h" #include "Pattern.h" #include "PlatformString.h" - #include <cairo.h> #include <wtf/Vector.h> -#include <math.h> using namespace std; @@ -100,7 +98,7 @@ GraphicsContext* ImageBuffer::context() const bool ImageBuffer::drawsUsingCopy() const { - return true; + return false; } PassRefPtr<Image> ImageBuffer::copyImage() const @@ -112,20 +110,23 @@ PassRefPtr<Image> ImageBuffer::copyImage() const void ImageBuffer::clip(GraphicsContext*, const FloatRect&) const { notImplemented(); + // See https://bugs.webkit.org/show_bug.cgi?id=23526 for why this is unimplemented. } void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op , bool useLowQualityScale) { - RefPtr<Image> imageCopy = copyImage(); - context->drawImage(imageCopy.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale); + // BitmapImage will release the passed in surface on destruction + RefPtr<Image> image = BitmapImage::create(cairo_surface_reference(m_data.m_surface)); + context->drawImage(image.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale); } void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) { - RefPtr<Image> imageCopy = copyImage(); - imageCopy->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect); + // BitmapImage will release the passed in surface on destruction + RefPtr<Image> image = BitmapImage::create(cairo_surface_reference(m_data.m_surface)); + image->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect); } void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp index 1582671..d9eb5e6 100644 --- a/WebCore/platform/graphics/cairo/ImageCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp @@ -33,7 +33,7 @@ #include "AffineTransform.h" #include "Color.h" #include "FloatRect.h" -#include "GRefPtrCairo.h" +#include "PlatformRefPtrCairo.h" #include "GraphicsContext.h" #include "ImageBuffer.h" #include "ImageObserver.h" @@ -141,8 +141,8 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo if (context->getShadow(shadowSize, shadowBlur, shadowColor)) { IntSize shadowBufferSize; FloatRect shadowRect; - float kernelSize (0.0); - GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, dstRect, shadowSize, shadowBlur); + float radius = 0; + context->calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, dstRect, shadowSize, shadowBlur); shadowColor = colorWithOverrideAlpha(shadowColor.rgb(), (shadowColor.alpha() * context->getAlpha()) / 255.f); //draw shadow into a new ImageBuffer @@ -153,7 +153,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo cairo_rectangle(shadowContext, 0, 0, dstRect.width(), dstRect.height()); cairo_fill(shadowContext); - context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius); } #endif @@ -185,11 +185,11 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, con cairo_t* cr = context->platformContext(); context->save(); - GRefPtr<cairo_surface_t> clippedImageSurface = 0; + PlatformRefPtr<cairo_surface_t> clippedImageSurface = 0; if (tileRect.size() != size()) { IntRect imageSize = enclosingIntRect(tileRect); - clippedImageSurface = adoptGRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, imageSize.width(), imageSize.height())); - GRefPtr<cairo_t> clippedImageContext(cairo_create(clippedImageSurface.get())); + clippedImageSurface = adoptPlatformRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, imageSize.width(), imageSize.height())); + PlatformRefPtr<cairo_t> clippedImageContext(cairo_create(clippedImageSurface.get())); cairo_set_source_surface(clippedImageContext.get(), image, -tileRect.x(), -tileRect.y()); cairo_paint(clippedImageContext.get()); image = clippedImageSurface.get(); diff --git a/WebCore/platform/graphics/cairo/GRefPtrCairo.cpp b/WebCore/platform/graphics/cairo/PlatformRefPtrCairo.cpp index d244954..6870560 100644 --- a/WebCore/platform/graphics/cairo/GRefPtrCairo.cpp +++ b/WebCore/platform/graphics/cairo/PlatformRefPtrCairo.cpp @@ -17,33 +17,33 @@ */ #include "config.h" -#include "GRefPtrCairo.h" +#include "PlatformRefPtrCairo.h" #include <cairo.h> namespace WTF { -template <> cairo_t* refGPtr(cairo_t* ptr) +template <> cairo_t* refPlatformPtr(cairo_t* ptr) { if (ptr) cairo_reference(ptr); return ptr; } -template <> void derefGPtr(cairo_t* ptr) +template <> void derefPlatformPtr(cairo_t* ptr) { if (ptr) cairo_destroy(ptr); } -template <> cairo_surface_t* refGPtr(cairo_surface_t* ptr) +template <> cairo_surface_t* refPlatformPtr(cairo_surface_t* ptr) { if (ptr) cairo_surface_reference(ptr); return ptr; } -template <> void derefGPtr(cairo_surface_t* ptr) +template <> void derefPlatformPtr(cairo_surface_t* ptr) { if (ptr) cairo_surface_destroy(ptr); diff --git a/WebCore/platform/graphics/cairo/GRefPtrCairo.h b/WebCore/platform/graphics/cairo/PlatformRefPtrCairo.h index aef51fe..51d8fa9 100644 --- a/WebCore/platform/graphics/cairo/GRefPtrCairo.h +++ b/WebCore/platform/graphics/cairo/PlatformRefPtrCairo.h @@ -17,21 +17,21 @@ * Boston, MA 02110-1301, USA. */ -#ifndef GRefPtrCairo_h -#define GRefPtrCairo_h +#ifndef PlatformRefPtrCairo_h +#define PlatformRefPtrCairo_h -#include "GRefPtr.h" +#include "PlatformRefPtr.h" typedef struct _cairo cairo_t; typedef struct _cairo_surface cairo_surface_t; namespace WTF { -template <> cairo_t* refGPtr(cairo_t* ptr); -template <> void derefGPtr(cairo_t* ptr); +template <> cairo_t* refPlatformPtr(cairo_t* ptr); +template <> void derefPlatformPtr(cairo_t* ptr); -template <> cairo_surface_t* refGPtr(cairo_surface_t* ptr); -template <> void derefGPtr(cairo_surface_t* ptr); +template <> cairo_surface_t* refPlatformPtr(cairo_surface_t* ptr); +template <> void derefPlatformPtr(cairo_surface_t* ptr); } diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp index 4a7aecc..5fa4896 100644 --- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp +++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -63,8 +63,10 @@ void sharedBufferRelease(void* info) } #endif -ImageSource::ImageSource() +ImageSource::ImageSource(bool premultiplyAlpha) : m_decoder(0) + // FIXME: m_premultiplyAlpha is ignored in cg at the moment. + , m_premultiplyAlpha(premultiplyAlpha) { } diff --git a/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp b/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp index 7e732d1..bbf091c 100644 --- a/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp @@ -35,11 +35,63 @@ #include "CanvasLayerChromium.h" #include "GraphicsContext3D.h" +#include "LayerRendererChromium.h" #include <GLES2/gl2.h> namespace WebCore { -unsigned CanvasLayerChromium::m_shaderProgramId = 0; +CanvasLayerChromium::SharedValues::SharedValues() + : m_canvasShaderProgram(0) + , m_shaderSamplerLocation(-1) + , m_shaderMatrixLocation(-1) + , m_shaderAlphaLocation(-1) + , m_initialized(false) +{ + char vertexShaderString[] = + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "uniform mat4 matrix; \n" + "varying vec2 v_texCoord; \n" + "void main() \n" + "{ \n" + " gl_Position = matrix * a_position; \n" + " v_texCoord = a_texCoord; \n" + "} \n"; + + // Canvas layers need to be flipped vertically and their colors shouldn't be + // swizzled. + char fragmentShaderString[] = + "precision mediump float; \n" + "varying vec2 v_texCoord; \n" + "uniform sampler2D s_texture; \n" + "uniform float alpha; \n" + "void main() \n" + "{ \n" + " vec4 texColor = texture2D(s_texture, vec2(v_texCoord.x, 1.0 - v_texCoord.y)); \n" + " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n" + "} \n"; + + m_canvasShaderProgram = createShaderProgram(vertexShaderString, fragmentShaderString); + if (!m_canvasShaderProgram) { + LOG_ERROR("CanvasLayerChromium: Failed to create shader program"); + return; + } + + m_shaderSamplerLocation = glGetUniformLocation(m_canvasShaderProgram, "s_texture"); + m_shaderMatrixLocation = glGetUniformLocation(m_canvasShaderProgram, "matrix"); + m_shaderAlphaLocation = glGetUniformLocation(m_canvasShaderProgram, "alpha"); + ASSERT(m_shaderSamplerLocation != -1); + ASSERT(m_shaderMatrixLocation != -1); + ASSERT(m_shaderAlphaLocation != -1); + + m_initialized = true; +} + +CanvasLayerChromium::SharedValues::~SharedValues() +{ + if (m_canvasShaderProgram) + GLC(glDeleteProgram(m_canvasShaderProgram)); +} PassRefPtr<CanvasLayerChromium> CanvasLayerChromium::create(GraphicsLayerChromium* owner) { @@ -54,14 +106,8 @@ CanvasLayerChromium::CanvasLayerChromium(GraphicsLayerChromium* owner) { } -unsigned CanvasLayerChromium::textureId() -{ - return m_textureId; -} - -void CanvasLayerChromium::updateTextureContents(unsigned textureId) +void CanvasLayerChromium::updateContents() { - ASSERT(textureId == m_textureId); ASSERT(m_context); if (m_textureChanged) { glBindTexture(GL_TEXTURE_2D, m_textureId); @@ -92,5 +138,19 @@ void CanvasLayerChromium::setContext(const GraphicsContext3D* context) m_textureId = textureId; } +void CanvasLayerChromium::draw() +{ + ASSERT(layerRenderer()); + const CanvasLayerChromium::SharedValues* sv = layerRenderer()->canvasLayerSharedValues(); + ASSERT(sv && sv->initialized()); + GLC(glActiveTexture(GL_TEXTURE0)); + GLC(glBindTexture(GL_TEXTURE_2D, m_textureId)); + layerRenderer()->useShader(sv->canvasShaderProgram()); + GLC(glUniform1i(sv->shaderSamplerLocation(), 0)); + drawTexturedQuad(layerRenderer()->projectionMatrix(), drawTransform(), + bounds().width(), bounds().height(), drawOpacity(), + sv->shaderMatrixLocation(), sv->shaderAlphaLocation()); +} + } #endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/chromium/CanvasLayerChromium.h b/WebCore/platform/graphics/chromium/CanvasLayerChromium.h index 98be270..053efff 100644 --- a/WebCore/platform/graphics/chromium/CanvasLayerChromium.h +++ b/WebCore/platform/graphics/chromium/CanvasLayerChromium.h @@ -45,14 +45,29 @@ class CanvasLayerChromium : public LayerChromium { public: static PassRefPtr<CanvasLayerChromium> create(GraphicsLayerChromium* owner = 0); virtual bool drawsContent() { return m_context; } - virtual bool ownsTexture() { return true; } - virtual void updateTextureContents(unsigned); - virtual unsigned textureId(); - virtual unsigned shaderProgramId() { return m_shaderProgramId; } + virtual void updateContents(); + virtual void draw(); void setContext(const GraphicsContext3D* context); - static void setShaderProgramId(unsigned shaderProgramId) { m_shaderProgramId = shaderProgramId; } + class SharedValues { + public: + SharedValues(); + ~SharedValues(); + + unsigned canvasShaderProgram() const { return m_canvasShaderProgram; } + int shaderSamplerLocation() const { return m_shaderSamplerLocation; } + int shaderMatrixLocation() const { return m_shaderMatrixLocation; } + int shaderAlphaLocation() const { return m_shaderAlphaLocation; } + bool initialized() const { return m_initialized; } + + private: + unsigned m_canvasShaderProgram; + int m_shaderSamplerLocation; + int m_shaderMatrixLocation; + int m_shaderAlphaLocation; + bool m_initialized; + }; class PrepareTextureCallback : public Noncopyable { public: @@ -66,8 +81,6 @@ private: unsigned m_textureId; bool m_textureChanged; OwnPtr<PrepareTextureCallback> m_prepareTextureCallback; - - static unsigned m_shaderProgramId; }; } diff --git a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp new file mode 100644 index 0000000..974933d --- /dev/null +++ b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "ContentLayerChromium.h" + +#include "LayerRendererChromium.h" +#include "RenderLayerBacking.h" + +#if PLATFORM(SKIA) +#include "NativeImageSkia.h" +#include "PlatformContextSkia.h" +#include "skia/ext/platform_canvas.h" +#elif PLATFORM(CG) +#include <CoreGraphics/CGBitmapContext.h> +#endif + +#include <GLES2/gl2.h> + +namespace WebCore { + +ContentLayerChromium::SharedValues::SharedValues() + : m_contentShaderProgram(0) + , m_shaderSamplerLocation(-1) + , m_shaderMatrixLocation(-1) + , m_shaderAlphaLocation(-1) + , m_initialized(false) +{ + // Shaders for drawing the layer contents. + char vertexShaderString[] = + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "uniform mat4 matrix; \n" + "varying vec2 v_texCoord; \n" + "void main() \n" + "{ \n" + " gl_Position = matrix * a_position; \n" + " v_texCoord = a_texCoord; \n" + "} \n"; + + // Note differences between Skia and Core Graphics versions: + // - Skia uses BGRA and origin is upper left + // - Core Graphics uses RGBA and origin is lower left + char fragmentShaderString[] = + "precision mediump float; \n" + "varying vec2 v_texCoord; \n" + "uniform sampler2D s_texture; \n" + "uniform float alpha; \n" + "void main() \n" + "{ \n" +#if PLATFORM(SKIA) + " vec4 texColor = texture2D(s_texture, v_texCoord); \n" + " gl_FragColor = vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha; \n" +#elif PLATFORM(CG) + " vec4 texColor = texture2D(s_texture, vec2(v_texCoord.x, 1.0 - v_texCoord.y)); \n" + " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n" +#else +#error "Need to implement for your platform." +#endif + "} \n"; + + m_contentShaderProgram = createShaderProgram(vertexShaderString, fragmentShaderString); + if (!m_contentShaderProgram) { + LOG_ERROR("ContentLayerChromium: Failed to create shader program"); + return; + } + + m_shaderSamplerLocation = glGetUniformLocation(m_contentShaderProgram, "s_texture"); + m_shaderMatrixLocation = glGetUniformLocation(m_contentShaderProgram, "matrix"); + m_shaderAlphaLocation = glGetUniformLocation(m_contentShaderProgram, "alpha"); + ASSERT(m_shaderSamplerLocation != -1); + ASSERT(m_shaderMatrixLocation != -1); + ASSERT(m_shaderAlphaLocation != -1); + + m_initialized = true; +} + +ContentLayerChromium::SharedValues::~SharedValues() +{ + if (m_contentShaderProgram) + GLC(glDeleteProgram(m_contentShaderProgram)); +} + + +PassRefPtr<ContentLayerChromium> ContentLayerChromium::create(GraphicsLayerChromium* owner) +{ + return adoptRef(new ContentLayerChromium(owner)); +} + +ContentLayerChromium::ContentLayerChromium(GraphicsLayerChromium* owner) + : LayerChromium(owner) + , m_contentsTexture(0) +{ +} + +ContentLayerChromium::~ContentLayerChromium() +{ + if (m_contentsTexture) + GLC(glDeleteTextures(1, &m_contentsTexture)); +} + + +void ContentLayerChromium::updateContents() +{ + RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); + if (!backing || backing->paintingGoesToWindow()) + return; + + ASSERT(drawsContent()); + + ASSERT(layerRenderer()); + + // FIXME: Remove this test when tiled layers are implemented. + m_skipsDraw = false; + if (!layerRenderer()->checkTextureSize(m_bounds)) { + m_skipsDraw = true; + return; + } + + void* pixels = 0; + IntRect dirtyRect(m_dirtyRect); + IntSize requiredTextureSize; + IntSize bitmapSize; + +#if PLATFORM(SKIA) + const SkBitmap* skiaBitmap = 0; + OwnPtr<skia::PlatformCanvas> canvas; + OwnPtr<PlatformContextSkia> skiaContext; + OwnPtr<GraphicsContext> graphicsContext; + + requiredTextureSize = m_bounds; + IntRect boundsRect(IntPoint(0, 0), m_bounds); + + // If the texture needs to be reallocated then we must redraw the entire + // contents of the layer. + if (requiredTextureSize != m_allocatedTextureSize) + dirtyRect = boundsRect; + else { + // Clip the dirtyRect to the size of the layer to avoid drawing outside + // the bounds of the backing texture. + dirtyRect.intersect(boundsRect); + } + + canvas.set(new skia::PlatformCanvas(dirtyRect.width(), dirtyRect.height(), false)); + skiaContext.set(new PlatformContextSkia(canvas.get())); + +#if OS(WINDOWS) + // This is needed to get text to show up correctly. Without it, + // GDI renders with zero alpha and the text becomes invisible. + // Unfortunately, setting this to true disables cleartype. + // FIXME: Does this take us down a very slow text rendering path? + // FIXME: why is this is a windows-only call ? + skiaContext->setDrawingToImageBuffer(true); +#endif + + graphicsContext.set(new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(skiaContext.get()))); + + // Bring the canvas into the coordinate system of the paint rect. + canvas->translate(static_cast<SkScalar>(-dirtyRect.x()), static_cast<SkScalar>(-dirtyRect.y())); + + m_owner->paintGraphicsLayerContents(*graphicsContext, dirtyRect); + const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); + skiaBitmap = &bitmap; + ASSERT(skiaBitmap); + + SkAutoLockPixels lock(*skiaBitmap); + SkBitmap::Config skiaConfig = skiaBitmap->config(); + // FIXME: do we need to support more image configurations? + if (skiaConfig == SkBitmap::kARGB_8888_Config) { + pixels = skiaBitmap->getPixels(); + bitmapSize = IntSize(skiaBitmap->width(), skiaBitmap->height()); + } +#elif PLATFORM(CG) + requiredTextureSize = m_bounds; + IntRect boundsRect(IntPoint(0, 0), m_bounds); + + // If the texture needs to be reallocated then we must redraw the entire + // contents of the layer. + if (requiredTextureSize != m_allocatedTextureSize) + dirtyRect = boundsRect; + else { + // Clip the dirtyRect to the size of the layer to avoid drawing outside + // the bounds of the backing texture. + dirtyRect.intersect(boundsRect); + } + + Vector<uint8_t> tempVector; + int rowBytes = 4 * dirtyRect.width(); + tempVector.resize(rowBytes * dirtyRect.height()); + memset(tempVector.data(), 0, tempVector.size()); + RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); + RetainPtr<CGContextRef> contextCG(AdoptCF, CGBitmapContextCreate(tempVector.data(), + dirtyRect.width(), dirtyRect.height(), 8, rowBytes, + colorSpace.get(), + kCGImageAlphaPremultipliedLast)); + + GraphicsContext graphicsContext(contextCG.get()); + + // Translate the graphics contxt into the coordinate system of the dirty rect. + graphicsContext.translate(-dirtyRect.x(), -dirtyRect.y()); + + m_owner->paintGraphicsLayerContents(graphicsContext, dirtyRect); + + pixels = tempVector.data(); + bitmapSize = dirtyRect.size(); +#else +#error "Need to implement for your platform." +#endif + + unsigned textureId = m_contentsTexture; + if (!textureId) + textureId = layerRenderer()->createLayerTexture(); + + if (pixels) + updateTextureRect(pixels, bitmapSize, requiredTextureSize, dirtyRect, textureId); +} + +void ContentLayerChromium::updateTextureRect(void* pixels, const IntSize& bitmapSize, const IntSize& requiredTextureSize, const IntRect& updateRect, unsigned textureId) +{ + if (!pixels) + return; + + glBindTexture(GL_TEXTURE_2D, textureId); + + // If the texture id or size changed since last time then we need to tell GL + // to re-allocate a texture. + if (m_contentsTexture != textureId || requiredTextureSize != m_allocatedTextureSize) { + ASSERT(bitmapSize == requiredTextureSize); + GLC(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, requiredTextureSize.width(), requiredTextureSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); + + m_contentsTexture = textureId; + m_allocatedTextureSize = requiredTextureSize; + } else { + ASSERT(updateRect.width() <= m_allocatedTextureSize.width() && updateRect.height() <= m_allocatedTextureSize.height()); + ASSERT(updateRect.width() == bitmapSize.width() && updateRect.height() == bitmapSize.height()); +#if PLATFORM(CG) + // The origin is at the lower left in Core Graphics' coordinate system. We need to correct for this here. + GLC(glTexSubImage2D(GL_TEXTURE_2D, 0, + updateRect.x(), m_allocatedTextureSize.height() - updateRect.height() - updateRect.y(), + updateRect.width(), updateRect.height(), + GL_RGBA, GL_UNSIGNED_BYTE, pixels)); +#elif PLATFORM(SKIA) + GLC(glTexSubImage2D(GL_TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GL_RGBA, GL_UNSIGNED_BYTE, pixels)); +#else +#error "Need to implement for your platform." +#endif + } + + m_dirtyRect.setSize(FloatSize()); + m_contentsDirty = false; +} + +void ContentLayerChromium::draw() +{ + if (m_skipsDraw) + return; + + ASSERT(layerRenderer()); + const ContentLayerChromium::SharedValues* sv = layerRenderer()->contentLayerSharedValues(); + ASSERT(sv && sv->initialized()); + GLC(glActiveTexture(GL_TEXTURE0)); + GLC(glBindTexture(GL_TEXTURE_2D, m_contentsTexture)); + layerRenderer()->useShader(sv->contentShaderProgram()); + GLC(glUniform1i(sv->shaderSamplerLocation(), 0)); + drawTexturedQuad(layerRenderer()->projectionMatrix(), drawTransform(), + bounds().width(), bounds().height(), drawOpacity(), + sv->shaderMatrixLocation(), sv->shaderAlphaLocation()); +} + +} +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/chromium/ContentLayerChromium.h b/WebCore/platform/graphics/chromium/ContentLayerChromium.h new file mode 100644 index 0000000..3e15372 --- /dev/null +++ b/WebCore/platform/graphics/chromium/ContentLayerChromium.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef ContentLayerChromium_h +#define ContentLayerChromium_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "LayerChromium.h" + +namespace WebCore { + +// A Layer that requires a GraphicsContext to render its contents. +class ContentLayerChromium : public LayerChromium { + friend class LayerRendererChromium; +public: + static PassRefPtr<ContentLayerChromium> create(GraphicsLayerChromium* owner = 0); + + ~ContentLayerChromium(); + + virtual void updateContents(); + virtual void draw(); + virtual bool drawsContent() { return m_owner && m_owner->drawsContent(); } + + // Stores values that are shared between instances of this class that are + // associated with the same LayerRendererChromium (and hence the same GL + // context). + class SharedValues { + public: + SharedValues(); + ~SharedValues(); + + unsigned contentShaderProgram() const { return m_contentShaderProgram; } + int shaderSamplerLocation() const { return m_shaderSamplerLocation; } + int shaderMatrixLocation() const { return m_shaderMatrixLocation; } + int shaderAlphaLocation() const { return m_shaderAlphaLocation; } + int initialized() const { return m_initialized; } + + private: + unsigned m_contentShaderProgram; + int m_shaderSamplerLocation; + int m_shaderMatrixLocation; + int m_shaderAlphaLocation; + int m_initialized; + }; + +protected: + ContentLayerChromium(GraphicsLayerChromium* owner); + + void updateTextureRect(void* pixels, const IntSize& bitmapSize, const IntSize& requiredTextureSize, + const IntRect& updateRect, unsigned textureId); + + unsigned m_contentsTexture; + IntSize m_allocatedTextureSize; + bool m_skipsDraw; + +}; + +} +#endif // USE(ACCELERATED_COMPOSITING) + +#endif diff --git a/WebCore/platform/graphics/chromium/GLES2Canvas.cpp b/WebCore/platform/graphics/chromium/GLES2Canvas.cpp index 534de7b..c0cb87c 100644 --- a/WebCore/platform/graphics/chromium/GLES2Canvas.cpp +++ b/WebCore/platform/graphics/chromium/GLES2Canvas.cpp @@ -34,13 +34,11 @@ #include "GLES2Canvas.h" -#include "Float32Array.h" #include "FloatRect.h" #include "GLES2Texture.h" #include "GraphicsContext3D.h" #include "IntRect.h" #include "PlatformString.h" -#include "Uint16Array.h" #define _USE_MATH_DEFINES #include <math.h> @@ -79,7 +77,6 @@ struct GLES2Canvas::State { GLES2Canvas::GLES2Canvas(GraphicsContext3D* context, const IntSize& size) : m_context(context) , m_quadVertices(0) - , m_quadIndices(0) , m_simpleProgram(0) , m_texProgram(0) , m_simpleMatrixLocation(-1) @@ -111,40 +108,33 @@ GLES2Canvas::~GLES2Canvas() m_context->deleteProgram(m_simpleProgram); m_context->deleteProgram(m_texProgram); m_context->deleteBuffer(m_quadVertices); - m_context->deleteBuffer(m_quadIndices); } void GLES2Canvas::clearRect(const FloatRect& rect) { - m_context->scissor(rect.x(), rect.y(), rect.width(), rect.height()); - m_context->enable(GraphicsContext3D::SCISSOR_TEST); - m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT); - m_context->disable(GraphicsContext3D::SCISSOR_TEST); + if (m_state->m_ctm.isIdentity()) { + m_context->scissor(rect.x(), rect.y(), rect.width(), rect.height()); + m_context->enable(GraphicsContext3D::SCISSOR_TEST); + m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT); + m_context->disable(GraphicsContext3D::SCISSOR_TEST); + } else { + save(); + setCompositeOperation(CompositeClear); + fillRect(rect, Color(RGBA32(0)), DeviceColorSpace); + restore(); + } } void GLES2Canvas::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { - m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, getQuadVertices()); - m_context->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, getQuadIndices()); - - float rgba[4]; - color.getRGBA(rgba[0], rgba[1], rgba[2], rgba[3]); - m_context->uniform4f(m_simpleColorLocation, rgba[0] * rgba[3], rgba[1] * rgba[3], rgba[2] * rgba[3], rgba[3]); - - m_context->drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0); -} - -void GLES2Canvas::fillRect(const FloatRect& rect) -{ applyCompositeOperator(m_state->m_compositeOp); m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, getQuadVertices()); - m_context->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, getQuadIndices()); m_context->useProgram(getSimpleProgram()); float rgba[4]; - m_state->m_fillColor.getRGBA(rgba[0], rgba[1], rgba[2], rgba[3]); + color.getRGBA(rgba[0], rgba[1], rgba[2], rgba[3]); m_context->uniform4f(m_simpleColorLocation, rgba[0] * rgba[3], rgba[1] * rgba[3], rgba[2] * rgba[3], rgba[3]); AffineTransform matrix(m_flipMatrix); @@ -159,7 +149,12 @@ void GLES2Canvas::fillRect(const FloatRect& rect) m_context->enableVertexAttribArray(m_simplePositionLocation); - m_context->drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0); + m_context->drawArrays(GraphicsContext3D::TRIANGLE_STRIP, 0, 4); +} + +void GLES2Canvas::fillRect(const FloatRect& rect) +{ + fillRect(rect, m_state->m_fillColor, DeviceColorSpace); } void GLES2Canvas::setFillColor(const Color& color, ColorSpace colorSpace) @@ -215,7 +210,6 @@ void GLES2Canvas::drawTexturedRect(GLES2Texture* texture, const FloatRect& srcRe applyCompositeOperator(compositeOp); m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, getQuadVertices()); - m_context->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, getQuadIndices()); checkGLError("glBindBuffer"); m_context->useProgram(getTexProgram()); @@ -275,8 +269,8 @@ void GLES2Canvas::drawTexturedRectTile(GLES2Texture* texture, int tile, const Fl m_context->uniformMatrix3fv(m_texTexMatrixLocation, false /*transpose*/, texMat, 1 /*count*/); checkGLError("glUniformMatrix3fv"); - m_context->drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0); - checkGLError("glDrawElements"); + m_context->drawArrays(GraphicsContext3D::TRIANGLE_STRIP, 0, 4); + checkGLError("glDrawArrays"); } void GLES2Canvas::setCompositeOperation(CompositeOperator op) @@ -351,30 +345,16 @@ unsigned GLES2Canvas::getQuadVertices() if (!m_quadVertices) { float vertices[] = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - 0.0f, 1.0f, 1.0f }; + 0.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f }; m_quadVertices = m_context->createBuffer(); - RefPtr<Float32Array> vertexArray = Float32Array::create(vertices, sizeof(vertices) / sizeof(float)); m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_quadVertices); - m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, vertexArray.get(), GraphicsContext3D::STATIC_DRAW); + m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, sizeof(vertices), vertices, GraphicsContext3D::STATIC_DRAW); } return m_quadVertices; } -unsigned GLES2Canvas::getQuadIndices() -{ - if (!m_quadIndices) { - unsigned short indices[] = { 0, 1, 2, 0, 2, 3}; - - m_quadIndices = m_context->createBuffer(); - RefPtr<Uint16Array> indexArray = Uint16Array::create(indices, sizeof(indices) / sizeof(unsigned short)); - m_context->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, m_quadIndices); - m_context->bufferData(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, indexArray.get(), GraphicsContext3D::STATIC_DRAW); - } - return m_quadIndices; -} - static unsigned loadShader(GraphicsContext3D* context, unsigned type, const char* shaderSource) { unsigned shader = context->createShader(type); diff --git a/WebCore/platform/graphics/chromium/GLES2Canvas.h b/WebCore/platform/graphics/chromium/GLES2Canvas.h index 0ad07fc..d00510a 100644 --- a/WebCore/platform/graphics/chromium/GLES2Canvas.h +++ b/WebCore/platform/graphics/chromium/GLES2Canvas.h @@ -85,7 +85,6 @@ private: void applyCompositeOperator(CompositeOperator); void checkGLError(const char* header); unsigned getQuadVertices(); - unsigned getQuadIndices(); unsigned getSimpleProgram(); unsigned getTexProgram(); @@ -94,7 +93,6 @@ private: WTF::Vector<State> m_stateStack; State* m_state; unsigned m_quadVertices; - unsigned m_quadIndices; unsigned m_simpleProgram; unsigned m_texProgram; int m_simpleMatrixLocation; diff --git a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp index 1d67857..648e35f 100644 --- a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp @@ -45,6 +45,7 @@ #include "GraphicsLayerChromium.h" +#include "ContentLayerChromium.h" #include "FloatConversion.h" #include "FloatRect.h" #include "Image.h" @@ -52,7 +53,6 @@ #include "LayerChromium.h" #include "PlatformString.h" #include "SystemTime.h" -#include "TransformLayerChromium.h" #include <wtf/CurrentTime.h> #include <wtf/StringExtras.h> @@ -97,7 +97,7 @@ GraphicsLayerChromium::GraphicsLayerChromium(GraphicsLayerClient* client) , m_contentsLayerPurpose(NoContentsLayer) , m_contentsLayerHasBackgroundColor(false) { - m_layer = LayerChromium::create(this); + m_layer = ContentLayerChromium::create(this); updateDebugIndicators(); } @@ -538,7 +538,7 @@ void GraphicsLayerChromium::updateLayerPreserves3D() { if (m_preserves3D && !m_transformLayer) { // Create the transform layer. - m_transformLayer = TransformLayerChromium::create(this); + m_transformLayer = LayerChromium::create(this); // Copy the position from this layer. updateLayerPosition(); diff --git a/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp b/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp index 3cc7cad..09b388d 100644 --- a/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp @@ -34,6 +34,8 @@ #include "ImageLayerChromium.h" +#include "LayerRendererChromium.h" + #if PLATFORM(SKIA) #include "NativeImageSkia.h" #include "PlatformContextSkia.h" @@ -54,7 +56,7 @@ PassRefPtr<ImageLayerChromium> ImageLayerChromium::create(GraphicsLayerChromium* } ImageLayerChromium::ImageLayerChromium(GraphicsLayerChromium* owner) - : LayerChromium(owner) + : ContentLayerChromium(owner) , m_contents(0) { } @@ -68,8 +70,10 @@ void ImageLayerChromium::setContents(NativeImagePtr contents) setNeedsDisplay(); } -void ImageLayerChromium::updateTextureContents(unsigned textureId) +void ImageLayerChromium::updateContents() { + ASSERT(layerRenderer()); + void* pixels = 0; IntRect dirtyRect(m_dirtyRect); IntSize requiredTextureSize; @@ -129,6 +133,17 @@ void ImageLayerChromium::updateTextureContents(unsigned textureId) #else #error "Need to implement for your platform." #endif + // FIXME: Remove this test when tiled layers are implemented. + m_skipsDraw = false; + if (!layerRenderer()->checkTextureSize(requiredTextureSize)) { + m_skipsDraw = true; + return; + } + + unsigned textureId = m_contentsTexture; + if (!textureId) + textureId = layerRenderer()->createLayerTexture(); + if (pixels) updateTextureRect(pixels, bitmapSize, requiredTextureSize, dirtyRect, textureId); } diff --git a/WebCore/platform/graphics/chromium/ImageLayerChromium.h b/WebCore/platform/graphics/chromium/ImageLayerChromium.h index 9355b2d..e95284c 100644 --- a/WebCore/platform/graphics/chromium/ImageLayerChromium.h +++ b/WebCore/platform/graphics/chromium/ImageLayerChromium.h @@ -34,16 +34,18 @@ #if USE(ACCELERATED_COMPOSITING) -#include "LayerChromium.h" +#include "ContentLayerChromium.h" namespace WebCore { // A Layer that contains only an Image element. -class ImageLayerChromium : public LayerChromium { +class ImageLayerChromium : public ContentLayerChromium { public: static PassRefPtr<ImageLayerChromium> create(GraphicsLayerChromium* owner = 0); + + virtual void updateContents(); virtual bool drawsContent() { return m_contents; } - virtual void updateTextureContents(unsigned textureId); + void setContents(NativeImagePtr); private: diff --git a/WebCore/platform/graphics/chromium/LayerChromium.cpp b/WebCore/platform/graphics/chromium/LayerChromium.cpp index 21d8d12..3553878 100644 --- a/WebCore/platform/graphics/chromium/LayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/LayerChromium.cpp @@ -48,7 +48,93 @@ namespace WebCore { using namespace std; -unsigned LayerChromium::m_shaderProgramId = 0; +const unsigned LayerChromium::s_positionAttribLocation = 0; +const unsigned LayerChromium::s_texCoordAttribLocation = 1; + +static GLuint loadShader(GLenum type, const char* shaderSource) +{ + GLuint shader = glCreateShader(type); + if (!shader) + return 0; + GLC(glShaderSource(shader, 1, &shaderSource, 0)); + GLC(glCompileShader(shader)); + GLint compiled; + GLC(glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled)); + if (!compiled) { + GLC(glDeleteShader(shader)); + return 0; + } + return shader; +} + +LayerChromium::SharedValues::SharedValues() + : m_quadVerticesVbo(0) + , m_quadElementsVbo(0) + , m_maxTextureSize(0) + , m_borderShaderProgram(0) + , m_borderShaderMatrixLocation(-1) + , m_borderShaderColorLocation(-1) + , m_initialized(false) +{ + // Vertex positions and texture coordinates for the 4 corners of a 1x1 quad. + GLfloat vertices[] = { -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, + 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.0f, 1.0f, 1.0f }; + GLushort indices[] = { 0, 1, 2, 0, 2, 3, // The two triangles that make up the layer quad. + 0, 1, 2, 3}; // A line path for drawing the layer border. + + GLuint vboIds[2]; + GLC(glGenBuffers(2, vboIds)); + m_quadVerticesVbo = vboIds[0]; + m_quadElementsVbo = vboIds[1]; + GLC(glBindBuffer(GL_ARRAY_BUFFER, m_quadVerticesVbo)); + GLC(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW)); + GLC(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_quadElementsVbo)); + GLC(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW)); + + // Get the max texture size supported by the system. + GLC(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize)); + + // Shaders for drawing the debug borders around the layers. + char borderVertexShaderString[] = + "attribute vec4 a_position; \n" + "uniform mat4 matrix; \n" + "void main() \n" + "{ \n" + " gl_Position = matrix * a_position; \n" + "} \n"; + char borderFragmentShaderString[] = + "precision mediump float; \n" + "uniform vec4 color; \n" + "void main() \n" + "{ \n" + " gl_FragColor = color; \n" + "} \n"; + + m_borderShaderProgram = createShaderProgram(borderVertexShaderString, borderFragmentShaderString); + if (!m_borderShaderProgram) { + LOG_ERROR("ContentLayerChromium: Failed to create shader program"); + return; + } + + m_borderShaderMatrixLocation = glGetUniformLocation(m_borderShaderProgram, "matrix"); + m_borderShaderColorLocation = glGetUniformLocation(m_borderShaderProgram, "color"); + ASSERT(m_borderShaderMatrixLocation != -1); + ASSERT(m_borderShaderColorLocation != -1); + + m_initialized = true; +} + +LayerChromium::SharedValues::~SharedValues() +{ + GLuint vboIds[2] = { m_quadVerticesVbo, m_quadElementsVbo }; + GLC(glDeleteBuffers(2, vboIds)); + + if (m_borderShaderProgram) + GLC(glDeleteProgram(m_borderShaderProgram)); +} + PassRefPtr<LayerChromium> LayerChromium::create(GraphicsLayerChromium* owner) { @@ -62,13 +148,10 @@ LayerChromium::LayerChromium(GraphicsLayerChromium* owner) , m_anchorPoint(0.5, 0.5) , m_backgroundColor(0, 0, 0, 0) , m_borderColor(0, 0, 0, 0) - , m_layerRenderer(0) - , m_edgeAntialiasingMask(0) , m_opacity(1.0) , m_zPosition(0.0) , m_anchorPointZ(0) , m_borderWidth(0) - , m_allocatedTextureId(0) , m_clearsContext(false) , m_doubleSided(true) , m_hidden(false) @@ -76,6 +159,7 @@ LayerChromium::LayerChromium(GraphicsLayerChromium* owner) , m_opaque(true) , m_geometryFlipped(false) , m_needsDisplayOnBoundsChange(false) + , m_layerRenderer(0) { } @@ -87,10 +171,6 @@ LayerChromium::~LayerChromium() // Remove the superlayer reference from all sublayers. removeAllSublayers(); - - // Notify the renderer to clean up the texture associated with the layer. - if (m_layerRenderer) - m_layerRenderer->freeLayerTexture(this); } void LayerChromium::setLayerRenderer(LayerRendererChromium* renderer) @@ -101,140 +181,46 @@ void LayerChromium::setLayerRenderer(LayerRendererChromium* renderer) m_layerRenderer = renderer; } -void LayerChromium::updateTextureContents(unsigned textureId) +unsigned LayerChromium::createShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource) { - RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); - if (!backing || backing->paintingGoesToWindow()) - return; - - ASSERT(drawsContent()); - - void* pixels = 0; - IntRect dirtyRect(m_dirtyRect); - IntSize requiredTextureSize; - IntSize bitmapSize; - -#if PLATFORM(SKIA) - const SkBitmap* skiaBitmap = 0; - OwnPtr<skia::PlatformCanvas> canvas; - OwnPtr<PlatformContextSkia> skiaContext; - OwnPtr<GraphicsContext> graphicsContext; - - requiredTextureSize = m_bounds; - IntRect boundsRect(IntPoint(0, 0), m_bounds); - - // If the texture needs to be reallocated then we must redraw the entire - // contents of the layer. - if (requiredTextureSize != m_allocatedTextureSize) - dirtyRect = boundsRect; - else { - // Clip the dirtyRect to the size of the layer to avoid drawing outside - // the bounds of the backing texture. - dirtyRect.intersect(boundsRect); + GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vertexShaderSource); + if (!vertexShader) { + LOG_ERROR("Failed to create vertex shader"); + return 0; } - canvas.set(new skia::PlatformCanvas(dirtyRect.width(), dirtyRect.height(), false)); - skiaContext.set(new PlatformContextSkia(canvas.get())); - -#if OS(WINDOWS) - // This is needed to get text to show up correctly. Without it, - // GDI renders with zero alpha and the text becomes invisible. - // Unfortunately, setting this to true disables cleartype. - // FIXME: Does this take us down a very slow text rendering path? - // FIXME: why is this is a windows-only call ? - skiaContext->setDrawingToImageBuffer(true); -#endif - - graphicsContext.set(new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(skiaContext.get()))); - - // Bring the canvas into the coordinate system of the paint rect. - canvas->translate(static_cast<SkScalar>(-dirtyRect.x()), static_cast<SkScalar>(-dirtyRect.y())); - - m_owner->paintGraphicsLayerContents(*graphicsContext, dirtyRect); - const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); - skiaBitmap = &bitmap; - ASSERT(skiaBitmap); - - SkAutoLockPixels lock(*skiaBitmap); - SkBitmap::Config skiaConfig = skiaBitmap->config(); - // FIXME: do we need to support more image configurations? - if (skiaConfig == SkBitmap::kARGB_8888_Config) { - pixels = skiaBitmap->getPixels(); - bitmapSize = IntSize(skiaBitmap->width(), skiaBitmap->height()); - } -#elif PLATFORM(CG) - requiredTextureSize = m_bounds; - IntRect boundsRect(IntPoint(0, 0), m_bounds); - - // If the texture needs to be reallocated then we must redraw the entire - // contents of the layer. - if (requiredTextureSize != m_allocatedTextureSize) - dirtyRect = boundsRect; - else { - // Clip the dirtyRect to the size of the layer to avoid drawing outside - // the bounds of the backing texture. - dirtyRect.intersect(boundsRect); + GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentShaderSource); + if (!fragmentShader) { + GLC(glDeleteShader(vertexShader)); + LOG_ERROR("Failed to create fragment shader"); + return 0; } - Vector<uint8_t> tempVector; - int rowBytes = 4 * dirtyRect.width(); - tempVector.resize(rowBytes * dirtyRect.height()); - memset(tempVector.data(), 0, tempVector.size()); - RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); - RetainPtr<CGContextRef> contextCG(AdoptCF, CGBitmapContextCreate(tempVector.data(), - dirtyRect.width(), dirtyRect.height(), 8, rowBytes, - colorSpace.get(), - kCGImageAlphaPremultipliedLast)); - - GraphicsContext graphicsContext(contextCG.get()); - - // Translate the graphics contxt into the coordinate system of the dirty rect. - graphicsContext.translate(-dirtyRect.x(), -dirtyRect.y()); - - m_owner->paintGraphicsLayerContents(graphicsContext, dirtyRect); - - pixels = tempVector.data(); - bitmapSize = dirtyRect.size(); -#else -#error "Need to implement for your platform." -#endif + GLuint programObject = glCreateProgram(); + if (!programObject) { + LOG_ERROR("Failed to create shader program"); + return 0; + } - if (pixels) - updateTextureRect(pixels, bitmapSize, requiredTextureSize, dirtyRect, textureId); -} + GLC(glAttachShader(programObject, vertexShader)); + GLC(glAttachShader(programObject, fragmentShader)); -void LayerChromium::updateTextureRect(void* pixels, const IntSize& bitmapSize, const IntSize& requiredTextureSize, const IntRect& updateRect, unsigned textureId) -{ - if (!pixels) - return; + // Bind the common attrib locations. + GLC(glBindAttribLocation(programObject, s_positionAttribLocation, "a_position")); + GLC(glBindAttribLocation(programObject, s_texCoordAttribLocation, "a_texCoord")); - glBindTexture(GL_TEXTURE_2D, textureId); - // If the texture id or size changed since last time then we need to tell GL - // to re-allocate a texture. - if (m_allocatedTextureId != textureId || requiredTextureSize != m_allocatedTextureSize) { - ASSERT(bitmapSize == requiredTextureSize); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, requiredTextureSize.width(), requiredTextureSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - - m_allocatedTextureId = textureId; - m_allocatedTextureSize = requiredTextureSize; - } else { - ASSERT(updateRect.width() <= m_allocatedTextureSize.width() && updateRect.height() <= m_allocatedTextureSize.height()); - ASSERT(updateRect.width() == bitmapSize.width() && updateRect.height() == bitmapSize.height()); -#if PLATFORM(CG) - // The origin is at the lower left in Core Graphics' coordinate system. We need to correct for this here. - glTexSubImage2D(GL_TEXTURE_2D, 0, - updateRect.x(), m_allocatedTextureSize.height() - updateRect.height() - updateRect.y(), - updateRect.width(), updateRect.height(), - GL_RGBA, GL_UNSIGNED_BYTE, pixels); -#elif PLATFORM(SKIA) - glTexSubImage2D(GL_TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GL_RGBA, GL_UNSIGNED_BYTE, pixels); -#else -#error "Need to implement for your platform." -#endif + GLC(glLinkProgram(programObject)); + GLint linked; + GLC(glGetProgramiv(programObject, GL_LINK_STATUS, &linked)); + if (!linked) { + LOG_ERROR("Failed to link shader program"); + GLC(glDeleteProgram(programObject)); + return 0; } - m_dirtyRect.setSize(FloatSize()); - m_contentsDirty = false; + GLC(glDeleteShader(vertexShader)); + GLC(glDeleteShader(fragmentShader)); + return programObject; } void LayerChromium::setNeedsCommit() @@ -377,5 +363,86 @@ void LayerChromium::setNeedsDisplay() m_contentsDirty = true; } +void LayerChromium::toGLMatrix(float* flattened, const TransformationMatrix& m) +{ + flattened[0] = m.m11(); + flattened[1] = m.m12(); + flattened[2] = m.m13(); + flattened[3] = m.m14(); + flattened[4] = m.m21(); + flattened[5] = m.m22(); + flattened[6] = m.m23(); + flattened[7] = m.m24(); + flattened[8] = m.m31(); + flattened[9] = m.m32(); + flattened[10] = m.m33(); + flattened[11] = m.m34(); + flattened[12] = m.m41(); + flattened[13] = m.m42(); + flattened[14] = m.m43(); + flattened[15] = m.m44(); +} + +void LayerChromium::drawTexturedQuad(const TransformationMatrix& projectionMatrix, const TransformationMatrix& drawMatrix, + float width, float height, float opacity, + int matrixLocation, int alphaLocation) +{ + static GLfloat glMatrix[16]; + + TransformationMatrix renderMatrix = drawMatrix; + + // Apply a scaling factor to size the quad from 1x1 to its intended size. + renderMatrix.scale3d(width, height, 1); + + // Apply the projection matrix before sending the transform over to the shader. + renderMatrix.multiply(projectionMatrix); + + toGLMatrix(&glMatrix[0], renderMatrix); + + GLC(glUniformMatrix4fv(matrixLocation, 1, false, &glMatrix[0])); + + if (alphaLocation != -1) + GLC(glUniform1f(alphaLocation, opacity)); + + GLC(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0)); +} + +void LayerChromium::drawDebugBorder() +{ + static GLfloat glMatrix[16]; + if (!borderColor().alpha()) + return; + + ASSERT(layerRenderer()); + const SharedValues* sv = layerRenderer()->layerSharedValues(); + ASSERT(sv && sv->initialized()); + layerRenderer()->useShader(sv->borderShaderProgram()); + TransformationMatrix renderMatrix = drawTransform(); + renderMatrix.scale3d(bounds().width(), bounds().height(), 1); + renderMatrix.multiply(layerRenderer()->projectionMatrix()); + toGLMatrix(&glMatrix[0], renderMatrix); + GLC(glUniformMatrix4fv(sv->borderShaderMatrixLocation(), 1, false, &glMatrix[0])); + + GLC(glUniform4f(sv->borderShaderColorLocation(), borderColor().red() / 255.0, borderColor().green() / 255.0, borderColor().blue() / 255.0, 1)); + + GLC(glLineWidth(borderWidth())); + + // The indices for the line are stored in the same array as the triangle indices. + GLC(glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, (void*)(6 * sizeof(unsigned short)))); +} + +// static +void LayerChromium::prepareForDraw(const SharedValues* sv) +{ + GLC(glBindBuffer(GL_ARRAY_BUFFER, sv->quadVerticesVbo())); + GLC(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sv->quadElementsVbo())); + GLuint offset = 0; + GLC(glVertexAttribPointer(s_positionAttribLocation, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)offset)); + offset += 3 * sizeof(GLfloat); + GLC(glVertexAttribPointer(s_texCoordAttribLocation, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)offset)); + GLC(glEnableVertexAttribArray(s_positionAttribLocation)); + GLC(glEnableVertexAttribArray(s_texCoordAttribLocation)); +} + } #endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/chromium/LayerChromium.h b/WebCore/platform/graphics/chromium/LayerChromium.h index 9fba415..0d0d362 100644 --- a/WebCore/platform/graphics/chromium/LayerChromium.h +++ b/WebCore/platform/graphics/chromium/LayerChromium.h @@ -55,19 +55,24 @@ namespace WebCore { class GraphicsContext3D; class LayerRendererChromium; -// Base class for composited layers. The implementation covers layers that require -// a GraphicsContext to render their contents. Special layer types are derived from +// Base class for composited layers. Special layer types are derived from // this class. class LayerChromium : public RefCounted<LayerChromium> { + friend class LayerRendererChromium; public: static PassRefPtr<LayerChromium> create(GraphicsLayerChromium* owner = 0); ~LayerChromium(); + const LayerChromium* rootLayer() const; + LayerChromium* superlayer() const; void addSublayer(PassRefPtr<LayerChromium>); void insertSublayer(PassRefPtr<LayerChromium>, size_t index); void replaceSublayer(LayerChromium* reference, PassRefPtr<LayerChromium> newLayer); void removeFromSuperlayer(); + void removeAllSublayers(); + void setSublayers(const Vector<RefPtr<LayerChromium> >&); + const Vector<RefPtr<LayerChromium> >& getSublayers() const { return m_sublayers; } void setAnchorPoint(const FloatPoint& anchorPoint) { m_anchorPoint = anchorPoint; setNeedsCommit(); } FloatPoint anchorPoint() const { return m_anchorPoint; } @@ -93,9 +98,6 @@ public: void setDoubleSided(bool doubleSided) { m_doubleSided = doubleSided; setNeedsCommit(); } bool doubleSided() const { return m_doubleSided; } - void setEdgeAntialiasingMask(uint32_t mask) { m_edgeAntialiasingMask = mask; setNeedsCommit(); } - uint32_t edgeAntialiasingMask() const { return m_edgeAntialiasingMask; } - void setFrame(const FloatRect&); FloatRect frame() const { return m_frame; } @@ -120,76 +122,99 @@ public: bool opaque() const { return m_opaque; } void setPosition(const FloatPoint& position) { m_position = position; setNeedsCommit(); } - FloatPoint position() const { return m_position; } void setZPosition(float zPosition) { m_zPosition = zPosition; setNeedsCommit(); } float zPosition() const { return m_zPosition; } - const LayerChromium* rootLayer() const; - - void removeAllSublayers(); - - void setSublayers(const Vector<RefPtr<LayerChromium> >&); - - const Vector<RefPtr<LayerChromium> >& getSublayers() const { return m_sublayers; } - void setSublayerTransform(const TransformationMatrix& transform) { m_sublayerTransform = transform; setNeedsCommit(); } const TransformationMatrix& sublayerTransform() const { return m_sublayerTransform; } - LayerChromium* superlayer() const; - - void setTransform(const TransformationMatrix& transform) { m_transform = transform; setNeedsCommit(); } const TransformationMatrix& transform() const { return m_transform; } + // FIXME: This setting is currently ignored. void setGeometryFlipped(bool flipped) { m_geometryFlipped = flipped; setNeedsCommit(); } bool geometryFlipped() const { return m_geometryFlipped; } - virtual void updateTextureContents(unsigned textureId); - bool contentsDirty() { return m_contentsDirty; } - void setDrawTransform(const TransformationMatrix& transform) { m_drawTransform = transform; } const TransformationMatrix& drawTransform() const { return m_drawTransform; } void setDrawOpacity(float opacity) { m_drawOpacity = opacity; } float drawOpacity() const { return m_drawOpacity; } - virtual bool drawsContent() { return m_owner && m_owner->drawsContent(); } - - // Return true if the layer has its own GL texture and false if the texture - // needs to be allocated by the compositor. - virtual bool ownsTexture() { return false; } - - // Returns the id of the GL texture that stores the contents of this layer. - // Derived layer classes that own their own textures should overwrite this method. - virtual unsigned textureId() { return m_allocatedTextureId; } - bool preserves3D() { return m_owner && m_owner->preserves3D(); } void setLayerRenderer(LayerRendererChromium*); - static void setShaderProgramId(unsigned shaderProgramId) { m_shaderProgramId = shaderProgramId; } - virtual unsigned shaderProgramId() { return m_shaderProgramId; } - void setOwner(GraphicsLayerChromium* owner) { m_owner = owner; } + bool contentsDirty() { return m_contentsDirty; } + + // These methods typically need to be overwritten by derived classes. + virtual bool drawsContent() { return false; } + virtual void updateContents() { }; + virtual void draw() { }; + + void drawDebugBorder(); + + // Stores values that are shared between instances of this class that are + // associated with the same LayerRendererChromium (and hence the same GL + // context). + class SharedValues { + public: + SharedValues(); + ~SharedValues(); + + unsigned quadVerticesVbo() const { return m_quadVerticesVbo; } + unsigned quadElementsVbo() const { return m_quadElementsVbo; } + int maxTextureSize() const { return m_maxTextureSize; } + unsigned borderShaderProgram() const { return m_borderShaderProgram; } + int borderShaderMatrixLocation() const { return m_borderShaderMatrixLocation; } + int borderShaderColorLocation() const { return m_borderShaderColorLocation; } + bool initialized() const { return m_initialized; } + + private: + unsigned m_quadVerticesVbo; + unsigned m_quadElementsVbo; + int m_maxTextureSize; + unsigned m_borderShaderProgram; + int m_borderShaderMatrixLocation; + int m_borderShaderColorLocation; + bool m_initialized; + }; + + static void prepareForDraw(const SharedValues*); + protected: GraphicsLayerChromium* m_owner; LayerChromium(GraphicsLayerChromium* owner); - void updateTextureRect(void* pixels, const IntSize& bitmapSize, const IntSize& requiredTextureSize, const IntRect& dirtyRect, unsigned textureId); + + LayerRendererChromium* layerRenderer() const { return m_layerRenderer; } + + static void drawTexturedQuad(const TransformationMatrix& projectionMatrix, const TransformationMatrix& layerMatrix, + float width, float height, float opacity, + int matrixLocation, int alphaLocation); + + static void toGLMatrix(float*, const TransformationMatrix&); + + static unsigned createShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource); IntSize m_bounds; FloatRect m_dirtyRect; bool m_contentsDirty; + // All layer shaders share the same attribute locations for the vertex positions + // and texture coordinates. This allows switching shaders without rebinding attribute + // arrays. + static const unsigned s_positionAttribLocation; + static const unsigned s_texCoordAttribLocation; + private: void setNeedsCommit(); void setSuperlayer(LayerChromium* superlayer) { m_superlayer = superlayer; } - void paintMe(); - size_t numSublayers() const { return m_sublayers.size(); @@ -204,35 +229,17 @@ private: Vector<RefPtr<LayerChromium> > m_sublayers; LayerChromium* m_superlayer; + // Layer properties. IntSize m_backingStoreSize; FloatPoint m_position; FloatPoint m_anchorPoint; Color m_backgroundColor; Color m_borderColor; - - LayerRendererChromium* m_layerRenderer; - - FloatRect m_frame; - TransformationMatrix m_transform; - TransformationMatrix m_sublayerTransform; - - TransformationMatrix m_drawTransform; - - uint32_t m_edgeAntialiasingMask; float m_opacity; float m_zPosition; float m_anchorPointZ; float m_borderWidth; - float m_drawOpacity; - - unsigned m_allocatedTextureId; - IntSize m_allocatedTextureSize; - - // The shader program used by all layers of this type is the same. - // This static can be shadowed by derived classes to use a special shader. - static unsigned m_shaderProgramId; - bool m_clearsContext; bool m_doubleSided; bool m_hidden; @@ -241,6 +248,14 @@ private: bool m_geometryFlipped; bool m_needsDisplayOnBoundsChange; + // Points to the layer renderer that updates and draws this layer. + LayerRendererChromium* m_layerRenderer; + + FloatRect m_frame; + TransformationMatrix m_transform; + TransformationMatrix m_sublayerTransform; + TransformationMatrix m_drawTransform; + String m_name; }; diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp index 2f70efa..cf23871 100644 --- a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp +++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp @@ -35,10 +35,10 @@ #include "LayerRendererChromium.h" #include "CanvasLayerChromium.h" +#include "ContentLayerChromium.h" #include "GLES2Context.h" #include "LayerChromium.h" #include "NotImplemented.h" -#include "TransformLayerChromium.h" #if PLATFORM(SKIA) #include "NativeImageSkia.h" #include "PlatformContextSkia.h" @@ -50,101 +50,6 @@ namespace WebCore { -#ifndef NDEBUG -static WTFLogChannel LogLayerRenderer = { 0x00000000, "LayerRenderer", WTFLogChannelOn }; -#endif - -static void checkGLError() -{ -#ifndef NDEBUG - GLenum error = glGetError(); - if (error) - LOG_ERROR("GL Error: %d " , error); -#endif -} - -static GLuint loadShader(GLenum type, const char* shaderSource) -{ - GLuint shader = glCreateShader(type); - if (!shader) - return 0; - glShaderSource(shader, 1, &shaderSource, 0); - glCompileShader(shader); - GLint compiled; - glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); - if (!compiled) { - glDeleteShader(shader); - return 0; - } - return shader; -} - -static GLuint loadShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource) -{ - GLuint vertexShader; - GLuint fragmentShader; - GLuint programObject; - GLint linked; - vertexShader = loadShader(GL_VERTEX_SHADER, vertexShaderSource); - if (!vertexShader) - return 0; - fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentShaderSource); - if (!fragmentShader) { - glDeleteShader(vertexShader); - return 0; - } - programObject = glCreateProgram(); - if (!programObject) - return 0; - glAttachShader(programObject, vertexShader); - glAttachShader(programObject, fragmentShader); - glLinkProgram(programObject); - glGetProgramiv(programObject, GL_LINK_STATUS, &linked); - if (!linked) { - glDeleteProgram(programObject); - return 0; - } - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - return programObject; -} - -bool LayerRendererChromium::createLayerShader(ShaderProgramType type, const char* vertexShaderSource, const char* fragmentShaderSource) -{ - unsigned programId = loadShaderProgram(vertexShaderSource, fragmentShaderSource); - ASSERT(programId); - - ShaderProgram* program = &m_shaderPrograms[type]; - - program->m_shaderProgramId = programId; - program->m_samplerLocation = glGetUniformLocation(programId, "s_texture"); - program->m_matrixLocation = glGetUniformLocation(programId, "matrix"); - program->m_alphaLocation = glGetUniformLocation(programId, "alpha"); - - return programId; -} - - -static void toGLMatrix(float* flattened, const TransformationMatrix& m) -{ - flattened[0] = m.m11(); - flattened[1] = m.m12(); - flattened[2] = m.m13(); - flattened[3] = m.m14(); - flattened[4] = m.m21(); - flattened[5] = m.m22(); - flattened[6] = m.m23(); - flattened[7] = m.m24(); - flattened[8] = m.m31(); - flattened[9] = m.m32(); - flattened[10] = m.m33(); - flattened[11] = m.m34(); - flattened[12] = m.m41(); - flattened[13] = m.m42(); - flattened[14] = m.m43(); - flattened[15] = m.m44(); -} - static TransformationMatrix orthoMatrix(float left, float right, float bottom, float top, float nearZ, float farZ) { float deltaX = right - left; @@ -162,21 +67,6 @@ static TransformationMatrix orthoMatrix(float left, float right, float bottom, f return ortho; } -// Creates a GL texture object to be used for transfering the layer's bitmap into. -static GLuint createLayerTexture() -{ - GLuint textureId = 0; - glGenTextures(1, &textureId); - glBindTexture(GL_TEXTURE_2D, textureId); - // Do basic linear filtering on resize. - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // NPOT textures in GL ES only work when the wrap mode is set to GL_CLAMP_TO_EDGE. - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - return textureId; -} - static inline bool compareLayerZ(const LayerChromium* a, const LayerChromium* b) { const TransformationMatrix& transformA = a->drawTransform(); @@ -185,51 +75,35 @@ static inline bool compareLayerZ(const LayerChromium* a, const LayerChromium* b) return transformA.m43() < transformB.m43(); } -ShaderProgram::ShaderProgram() - : m_shaderProgramId(0) - , m_samplerLocation(-1) - , m_matrixLocation(-1) - , m_alphaLocation(-1) -{ -} - PassOwnPtr<LayerRendererChromium> LayerRendererChromium::create(PassOwnPtr<GLES2Context> gles2Context) { return new LayerRendererChromium(gles2Context); } LayerRendererChromium::LayerRendererChromium(PassOwnPtr<GLES2Context> gles2Context) - : m_rootLayerTextureWidth(0) + : m_rootLayerTextureId(0) + , m_rootLayerTextureWidth(0) , m_rootLayerTextureHeight(0) - , m_positionLocation(0) - , m_texCoordLocation(1) + , m_scrollShaderProgram(0) , m_rootLayer(0) , m_needsDisplay(false) , m_scrollPosition(IntPoint(-1, -1)) - , m_currentShaderProgramType(NumShaderProgramTypes) + , m_currentShader(0) , m_gles2Context(gles2Context) { - m_quadVboIds[Vertices] = m_quadVboIds[LayerElements] = 0; - m_hardwareCompositing = (m_gles2Context && initializeSharedGLObjects()); + m_hardwareCompositing = (m_gles2Context && initializeSharedObjects()); } LayerRendererChromium::~LayerRendererChromium() { - if (m_hardwareCompositing) { - makeContextCurrent(); - glDeleteBuffers(3, m_quadVboIds); - - for (int i = 0; i < NumShaderProgramTypes; i++) { - if (m_shaderPrograms[i].m_shaderProgramId) - glDeleteProgram(m_shaderPrograms[i].m_shaderProgramId); - } - } + cleanupSharedObjects(); +} - // Free up all GL textures. - for (TextureIdMap::iterator iter = m_textureIdMap.begin(); iter != m_textureIdMap.end(); ++iter) { - glDeleteTextures(1, &(iter->second)); - iter->first->setLayerRenderer(0); - } +void LayerRendererChromium::debugGLCall(const char* command, const char* file, int line) +{ + GLenum error = glGetError(); + if (error != GL_NO_ERROR) + LOG_ERROR("GL command failed: File: %s\n\tLine %d\n\tcommand: %s, error %x\n", file, line, command, error); } // Creates a canvas and an associated graphics context that the root layer will @@ -268,43 +142,14 @@ void LayerRendererChromium::setRootLayerCanvasSize(const IntSize& size) m_rootLayerCanvasSize = size; } -void LayerRendererChromium::useShaderProgram(ShaderProgramType programType) +void LayerRendererChromium::useShader(unsigned programId) { - if (programType != m_currentShaderProgramType) { - ShaderProgram* program = &m_shaderPrograms[programType]; - glUseProgram(program->m_shaderProgramId); - m_currentShaderProgramType = programType; - - // Set the uniform locations matching the program. - m_samplerLocation = program->m_samplerLocation; - m_matrixLocation = program->m_matrixLocation; - m_alphaLocation = program->m_alphaLocation; + if (programId != m_currentShader) { + GLC(glUseProgram(programId)); + m_currentShader = programId; } } -void LayerRendererChromium::drawTexturedQuad(const TransformationMatrix& matrix, float width, float height, float opacity) -{ - static GLfloat glMatrix[16]; - - TransformationMatrix renderMatrix = matrix; - - // Apply a scaling factor to size the quad from 1x1 to its intended size. - renderMatrix.scale3d(width, height, 1); - - // Apply the projection matrix before sending the transform over to the shader. - renderMatrix.multiply(m_projectionMatrix); - - toGLMatrix(&glMatrix[0], renderMatrix); - - glUniformMatrix4fv(m_matrixLocation, 1, false, &glMatrix[0]); - - if (m_alphaLocation != -1) - glUniform1f(m_alphaLocation, opacity); - - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); -} - - // Updates the contents of the root layer texture that fall inside the updateRect // and re-composits all sublayers. void LayerRendererChromium::drawLayers(const IntRect& updateRect, const IntRect& visibleRect, @@ -315,17 +160,13 @@ void LayerRendererChromium::drawLayers(const IntRect& updateRect, const IntRect& if (!m_rootLayer) return; - // If the size of the visible area has changed then allocate a new texture - // to store the contents of the root layer and adjust the projection matrix - // and viewport. makeContextCurrent(); - checkGLError(); - - glBindTexture(GL_TEXTURE_2D, m_rootLayerTextureId); - - checkGLError(); + GLC(glBindTexture(GL_TEXTURE_2D, m_rootLayerTextureId)); + // If the size of the visible area has changed then allocate a new texture + // to store the contents of the root layer and adjust the projection matrix + // and viewport. int visibleRectWidth = visibleRect.width(); int visibleRectHeight = visibleRect.height(); if (visibleRectWidth != m_rootLayerTextureWidth || visibleRectHeight != m_rootLayerTextureHeight) { @@ -333,38 +174,18 @@ void LayerRendererChromium::drawLayers(const IntRect& updateRect, const IntRect& m_rootLayerTextureHeight = visibleRect.height(); m_projectionMatrix = orthoMatrix(0, visibleRectWidth, visibleRectHeight, 0, -1000, 1000); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_rootLayerTextureWidth, m_rootLayerTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - - checkGLError(); + GLC(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_rootLayerTextureWidth, m_rootLayerTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); } // The GL viewport covers the entire visible area, including the scrollbars. - glViewport(0, 0, visibleRectWidth, visibleRectHeight); - - checkGLError(); - - // The layer, scroll and debug border shaders all use the same vertex attributes - // so we can bind them only once. - glBindBuffer(GL_ARRAY_BUFFER, m_quadVboIds[Vertices]); - checkGLError(); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_quadVboIds[LayerElements]); - checkGLError(); - GLuint offset = 0; - glVertexAttribPointer(m_positionLocation, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(offset)); - checkGLError(); - offset += 3 * sizeof(GLfloat); - glVertexAttribPointer(m_texCoordLocation, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(offset)); - checkGLError(); - glEnableVertexAttribArray(m_positionLocation); - checkGLError(); - glEnableVertexAttribArray(m_texCoordLocation); - checkGLError(); - glActiveTexture(GL_TEXTURE0); - checkGLError(); - glDisable(GL_DEPTH_TEST); - checkGLError(); - glDisable(GL_CULL_FACE); - checkGLError(); + GLC(glViewport(0, 0, visibleRectWidth, visibleRectHeight)); + + // Bind the common vertex attributes used for drawing all the layers. + LayerChromium::prepareForDraw(layerSharedValues()); + + GLC(glDisable(GL_DEPTH_TEST)); + GLC(glDisable(GL_CULL_FACE)); + GLC(glDepthFunc(GL_LEQUAL)); if (m_scrollPosition == IntPoint(-1, -1)) m_scrollPosition = scrollPosition; @@ -390,21 +211,21 @@ void LayerRendererChromium::drawLayers(const IntRect& updateRect, const IntRect& #error "Need to implement for your platform." #endif - scrolledLayerMatrix.translate3d((int)floorf(0.5 * visibleRect.width()) - scrollDelta.x(), - (int)floorf(0.5 * visibleRect.height()) + scaleFactor * scrollDelta.y(), 0); + scrolledLayerMatrix.translate3d(0.5 * visibleRect.width() - scrollDelta.x(), + 0.5 * visibleRect.height() + scaleFactor * scrollDelta.y(), 0); scrolledLayerMatrix.scale3d(1, -1, 1); - // Switch shaders to avoid RGB swizzling. - useShaderProgram(ScrollLayerProgram); - glUniform1i(m_shaderPrograms[ScrollLayerProgram].m_samplerLocation, 0); - checkGLError(); - - drawTexturedQuad(scrolledLayerMatrix, visibleRect.width(), visibleRect.height(), 1); - checkGLError(); + useShader(m_scrollShaderProgram); + GLC(glUniform1i(m_scrollShaderSamplerLocation, 0)); + LayerChromium::drawTexturedQuad(m_projectionMatrix, scrolledLayerMatrix, + visibleRect.width(), visibleRect.height(), 1, + m_scrollShaderMatrixLocation, -1); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, contentRect.width(), contentRect.height()); - - checkGLError(); + GLC(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, contentRect.width(), contentRect.height())); + m_scrollPosition = scrollPosition; + } else if (abs(scrollDelta.y()) > contentRect.height() || abs(scrollDelta.x()) > contentRect.width()) { + // Scrolling larger than the contentRect size does not preserve any of the pixels, so there is + // no need to copy framebuffer pixels back into the texture. m_scrollPosition = scrollPosition; } @@ -423,154 +244,92 @@ void LayerRendererChromium::drawLayers(const IntRect& updateRect, const IntRect& ASSERT(rootLayerWidth == updateRect.width() && rootLayerHeight == updateRect.height()); void* pixels = bitmap.getPixels(); - checkGLError(); // Copy the contents of the updated rect to the root layer texture. - glTexSubImage2D(GL_TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GL_RGBA, GL_UNSIGNED_BYTE, pixels); - checkGLError(); + GLC(glTexSubImage2D(GL_TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GL_RGBA, GL_UNSIGNED_BYTE, pixels)); #elif PLATFORM(CG) // Get the contents of the updated rect. ASSERT(static_cast<int>(CGBitmapContextGetWidth(m_rootLayerCGContext.get())) == updateRect.width() && static_cast<int>(CGBitmapContextGetHeight(m_rootLayerCGContext.get())) == updateRect.height()); void* pixels = m_rootLayerBackingStore.data(); - checkGLError(); // Copy the contents of the updated rect to the root layer texture. // The origin is at the lower left in Core Graphics' coordinate system. We need to correct for this here. - glTexSubImage2D(GL_TEXTURE_2D, 0, - updateRect.x(), m_rootLayerTextureHeight - updateRect.y() - updateRect.height(), - updateRect.width(), updateRect.height(), - GL_RGBA, GL_UNSIGNED_BYTE, pixels); - checkGLError(); + GLC(glTexSubImage2D(GL_TEXTURE_2D, 0, + updateRect.x(), m_rootLayerTextureHeight - updateRect.y() - updateRect.height(), + updateRect.width(), updateRect.height(), + GL_RGBA, GL_UNSIGNED_BYTE, pixels)); #else #error "Need to implement for your platform." #endif } glClearColor(0, 0, 1, 1); - checkGLError(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - checkGLError(); // Render the root layer using a quad that takes up the entire visible area of the window. - useShaderProgram(ContentLayerProgram); - checkGLError(); - glUniform1i(m_samplerLocation, 0); - checkGLError(); + // We reuse the shader program used by ContentLayerChromium. + const ContentLayerChromium::SharedValues* contentLayerValues = contentLayerSharedValues(); + useShader(contentLayerValues->contentShaderProgram()); + GLC(glUniform1i(contentLayerValues->shaderSamplerLocation(), 0)); TransformationMatrix layerMatrix; layerMatrix.translate3d(visibleRect.width() * 0.5f, visibleRect.height() * 0.5f, 0); - drawTexturedQuad(layerMatrix, visibleRect.width(), visibleRect.height(), 1); - checkGLError(); + LayerChromium::drawTexturedQuad(m_projectionMatrix, layerMatrix, + visibleRect.width(), visibleRect.height(), 1, + contentLayerValues->shaderMatrixLocation(), contentLayerValues->shaderAlphaLocation()); // If culling is enabled then we will cull the backface. - glCullFace(GL_BACK); - checkGLError(); + GLC(glCullFace(GL_BACK)); // The orthographic projection is setup such that Y starts at zero and // increases going down the page so we need to adjust the winding order of // front facing triangles. - glFrontFace(GL_CW); - checkGLError(); + GLC(glFrontFace(GL_CW)); // The shader used to render layers returns pre-multiplied alpha colors // so we need to send the blending mode appropriately. - glEnable(GL_BLEND); - checkGLError(); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - checkGLError(); + GLC(glEnable(GL_BLEND)); + GLC(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); // Translate all the composited layers by the scroll position. TransformationMatrix matrix; matrix.translate3d(-m_scrollPosition.x(), -m_scrollPosition.y(), 0); + // Traverse the layer tree and update the layer transforms. float opacity = 1; - m_layerList.shrink(0); const Vector<RefPtr<LayerChromium> >& sublayers = m_rootLayer->getSublayers(); - for (size_t i = 0; i < sublayers.size(); i++) - updateLayersRecursive(sublayers[i].get(), matrix, opacity, visibleRect); - - // Sort layers by the z coordinate of their center so that layers further - // away get drawn first. - std::stable_sort(m_layerList.begin(), m_layerList.end(), compareLayerZ); + size_t i; + for (i = 0; i < sublayers.size(); i++) + updateLayersRecursive(sublayers[i].get(), matrix, opacity); // Enable scissoring to avoid rendering composited layers over the scrollbars. - glEnable(GL_SCISSOR_TEST); - glScissor(0, visibleRect.height() - contentRect.height(), contentRect.width(), contentRect.height()); + GLC(glEnable(GL_SCISSOR_TEST)); + GLC(glScissor(0, visibleRect.height() - contentRect.height(), contentRect.width(), contentRect.height())); - for (size_t j = 0; j < m_layerList.size(); j++) - drawLayer(m_layerList[j]); + // Traverse the layer tree one more time to draw the layers. + m_visibleRect = visibleRect; + for (i = 0; i < sublayers.size(); i++) + drawLayersRecursive(sublayers[i].get()); - glDisable(GL_SCISSOR_TEST); + GLC(glDisable(GL_SCISSOR_TEST)); - glFlush(); m_gles2Context->swapBuffers(); m_needsDisplay = false; } -// Returns the id of the texture currently associated with the layer or -// -1 if the id hasn't been registered yet. -int LayerRendererChromium::getTextureId(LayerChromium* layer) +// FIXME: This method should eventually be replaced by a proper texture manager. +unsigned LayerRendererChromium::createLayerTexture() { - TextureIdMap::iterator textureId = m_textureIdMap.find(layer); - if (textureId != m_textureIdMap.end()) - return textureId->second; - - return -1; -} - -// Allocates a new texture for the layer and registers it in the textureId map. -// FIXME: We will need to come up with a more sophisticated allocation strategy here. -int LayerRendererChromium::assignTextureForLayer(LayerChromium* layer) -{ - GLuint textureId = createLayerTexture(); - - // FIXME: Check that textureId is valid - m_textureIdMap.set(layer, textureId); - - layer->setLayerRenderer(this); - + GLuint textureId = 0; + GLC(glGenTextures(1, &textureId)); + GLC(glBindTexture(GL_TEXTURE_2D, textureId)); + // Do basic linear filtering on resize. + GLC(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GLC(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + // NPOT textures in GL ES only work when the wrap mode is set to GL_CLAMP_TO_EDGE. + GLC(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GLC(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); return textureId; } -bool LayerRendererChromium::freeLayerTexture(LayerChromium* layer) -{ - TextureIdMap::iterator textureId = m_textureIdMap.find(layer); - if (textureId == m_textureIdMap.end()) - return false; - // Free up the texture. - glDeleteTextures(1, &(textureId->second)); - m_textureIdMap.remove(textureId); - return true; -} - -// Draws a debug border around the layer's bounds. -void LayerRendererChromium::drawDebugBorder(LayerChromium* layer, const TransformationMatrix& matrix) -{ - static GLfloat glMatrix[16]; - Color borderColor = layer->borderColor(); - if (!borderColor.alpha()) - return; - - useShaderProgram(DebugBorderProgram); - TransformationMatrix renderMatrix = matrix; - IntSize bounds = layer->bounds(); - renderMatrix.scale3d(bounds.width(), bounds.height(), 1); - renderMatrix.multiply(m_projectionMatrix); - toGLMatrix(&glMatrix[0], renderMatrix); - unsigned borderMatrixLocation = m_shaderPrograms[DebugBorderProgram].m_matrixLocation; - glUniformMatrix4fv(borderMatrixLocation, 1, false, &glMatrix[0]); - - glUniform4f(m_borderColorLocation, borderColor.red() / 255.0, - borderColor.green() / 255.0, - borderColor.blue() / 255.0, - 1); - - glLineWidth(layer->borderWidth()); - - // The indices for the line are stored in the same array as the triangle indices. - glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, (void*)(6 * sizeof(unsigned short))); - checkGLError(); -} - // Returns true if any part of the layer falls within the visibleRect bool LayerRendererChromium::isLayerVisible(LayerChromium* layer, const TransformationMatrix& matrix, const IntRect& visibleRect) { @@ -588,9 +347,9 @@ bool LayerRendererChromium::isLayerVisible(LayerChromium* layer, const Transform return mappedRect.intersects(FloatRect(-1, -1, 2, 2)); } -// Updates and caches the layer transforms and opacity values that will be used -// when rendering them. -void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, float opacity, const IntRect& visibleRect) +// Recursively walks the layer tree starting at the given node and updates the +// transform and opacity values. +void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, float opacity) { // Compute the new matrix transformation that will be applied to this layer and // all its sublayers. It's important to remember that the layer's position @@ -627,23 +386,11 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr // M = M[p] * Tr[l] * M[l] * Tr[c] localMatrix.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ()); - // Check if the layer falls within the visible bounds of the page. - bool layerVisible = isLayerVisible(layer, localMatrix, visibleRect); - - bool skipLayer = false; - if (bounds.width() > 2048 || bounds.height() > 2048) { - if (layer->drawsContent()) - LOG(LayerRenderer, "Skipping layer with size %d %d", bounds.width(), bounds.height()); - skipLayer = true; - } - // Calculate the layer's opacity. opacity *= layer->opacity(); layer->setDrawTransform(localMatrix); layer->setDrawOpacity(opacity); - if (layerVisible && !skipLayer) - m_layerList.append(layer); // Flatten to 2D if the layer doesn't preserve 3D. if (!layer->preserves3D()) { @@ -667,29 +414,71 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers(); for (size_t i = 0; i < sublayers.size(); i++) - updateLayersRecursive(sublayers[i].get(), localMatrix, opacity, visibleRect); + updateLayersRecursive(sublayers[i].get(), localMatrix, opacity); + + layer->setLayerRenderer(this); +} + +// Recursively walk the layer tree and draw the layers. +void LayerRendererChromium::drawLayersRecursive(LayerChromium* layer) +{ + static bool depthTestEnabledForSubtree = false; + + // Check if the layer falls within the visible bounds of the page. + bool layerVisible = isLayerVisible(layer, layer->drawTransform(), m_visibleRect); + + // Enable depth testing for this layer and all its descendants if preserves3D is set. + bool mustClearDepth = false; + if (layer->preserves3D()) { + if (!depthTestEnabledForSubtree) { + GLC(glEnable(GL_DEPTH_TEST)); + depthTestEnabledForSubtree = true; + + // Need to clear the depth buffer when we're done rendering this subtree. + mustClearDepth = true; + } + } + + if (layerVisible) + drawLayer(layer); + + // If we're using depth testing then we need to sort the children in Z to + // get the transparency to work properly. + if (depthTestEnabledForSubtree) { + const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers(); + Vector<LayerChromium*> sublayerList; + size_t i; + for (i = 0; i < sublayers.size(); i++) + sublayerList.append(sublayers[i].get()); + + // Sort by the z coordinate of the layer center so that layers further away + // are drawn first. + std::stable_sort(sublayerList.begin(), sublayerList.end(), compareLayerZ); + + for (i = 0; i < sublayerList.size(); i++) + drawLayersRecursive(sublayerList[i]); + } else { + const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers(); + for (size_t i = 0; i < sublayers.size(); i++) + drawLayersRecursive(sublayers[i].get()); + } + + if (mustClearDepth) { + GLC(glDisable(GL_DEPTH_TEST)); + GLC(glClear(GL_DEPTH_BUFFER_BIT)); + depthTestEnabledForSubtree = false; + } } void LayerRendererChromium::drawLayer(LayerChromium* layer) { - const TransformationMatrix& localMatrix = layer->drawTransform(); IntSize bounds = layer->bounds(); if (layer->drawsContent()) { - int textureId; - if (layer->ownsTexture()) - textureId = layer->textureId(); - else { - textureId = getTextureId(layer); - // If no texture has been created for the layer yet then create one now. - if (textureId == -1) - textureId = assignTextureForLayer(layer); - } - - // Redraw the contents of the layer if necessary. + // Update the contents of the layer if necessary. if (layer->contentsDirty()) { // Update the backing texture contents for any dirty portion of the layer. - layer->updateTextureContents(textureId); + layer->updateContents(); m_gles2Context->makeCurrent(); } @@ -698,13 +487,11 @@ void LayerRendererChromium::drawLayer(LayerChromium* layer) else glEnable(GL_CULL_FACE); - glBindTexture(GL_TEXTURE_2D, textureId); - useShaderProgram(static_cast<ShaderProgramType>(layer->shaderProgramId())); - drawTexturedQuad(localMatrix, bounds.width(), bounds.height(), layer->drawOpacity()); + layer->draw(); } // Draw the debug border if there is one. - drawDebugBorder(layer, localMatrix); + layer->drawDebugBorder(); } bool LayerRendererChromium::makeContextCurrent() @@ -712,21 +499,22 @@ bool LayerRendererChromium::makeContextCurrent() return m_gles2Context->makeCurrent(); } -void LayerRendererChromium::bindCommonAttribLocations(ShaderProgramType program) +// Checks whether a given size is within the maximum allowed texture size range. +bool LayerRendererChromium::checkTextureSize(const IntSize& textureSize) { - unsigned programId = m_shaderPrograms[program].m_shaderProgramId; - glBindAttribLocation(programId, m_positionLocation, "a_position"); - glBindAttribLocation(programId, m_texCoordLocation, "a_texCoord"); - - // Re-link the program for the new attribute locations to take effect. - glLinkProgram(programId); - checkGLError(); + if (textureSize.width() > m_maxTextureSize || textureSize.height() > m_maxTextureSize) + return false; + return true; } -bool LayerRendererChromium::initializeSharedGLObjects() +bool LayerRendererChromium::initializeSharedObjects() { - // Shaders for drawing the layer contents. - char vertexShaderString[] = + makeContextCurrent(); + + // Vertex and fragment shaders for rendering the scrolled root layer quad. + // They differ from a regular content layer shader in that they don't swizzle + // the colors or take an alpha value. + char scrollVertexShaderString[] = "attribute vec4 a_position; \n" "attribute vec2 a_texCoord; \n" "uniform mat4 matrix; \n" @@ -736,30 +524,6 @@ bool LayerRendererChromium::initializeSharedGLObjects() " gl_Position = matrix * a_position; \n" " v_texCoord = a_texCoord; \n" "} \n"; - // Note differences between Skia and Core Graphics versions: - // - Skia uses BGRA and origin is upper left - // - Core Graphics uses RGBA and origin is lower left - char fragmentShaderString[] = - "precision mediump float; \n" - "varying vec2 v_texCoord; \n" - "uniform sampler2D s_texture; \n" - "uniform float alpha; \n" - "void main() \n" - "{ \n" -#if PLATFORM(SKIA) - " vec4 texColor = texture2D(s_texture, v_texCoord); \n" - " gl_FragColor = vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha; \n" -#elif PLATFORM(CG) - " vec4 texColor = texture2D(s_texture, vec2(v_texCoord.x, 1.0 - v_texCoord.y)); \n" - " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n" -#else -#error "Need to implement for your platform." -#endif - "} \n"; - - // Fragment shader used for rendering the scrolled root layer quad. It differs - // from fragmentShaderString in that it doesn't swizzle the colors and doesn't - // take an alpha value. char scrollFragmentShaderString[] = "precision mediump float; \n" "varying vec2 v_texCoord; \n" @@ -770,101 +534,67 @@ bool LayerRendererChromium::initializeSharedGLObjects() " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w); \n" "} \n"; - // Canvas layers need to be flipped vertically and their colors shouldn't be - // swizzled. - char canvasFragmentShaderString[] = - "precision mediump float; \n" - "varying vec2 v_texCoord; \n" - "uniform sampler2D s_texture; \n" - "uniform float alpha; \n" - "void main() \n" - "{ \n" - " vec4 texColor = texture2D(s_texture, vec2(v_texCoord.x, 1.0 - v_texCoord.y)); \n" - " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n" - "} \n"; - - // Shaders for drawing the debug borders around the layers. - char borderVertexShaderString[] = - "attribute vec4 a_position; \n" - "uniform mat4 matrix; \n" - "void main() \n" - "{ \n" - " gl_Position = matrix * a_position; \n" - "} \n"; - char borderFragmentShaderString[] = - "precision mediump float; \n" - "uniform vec4 color; \n" - "void main() \n" - "{ \n" - " gl_FragColor = color; \n" - "} \n"; - - GLfloat vertices[] = { -0.5f, 0.5f, 0.0f, // Position 0 - 0.0f, 1.0f, // TexCoord 0 - -0.5f, -0.5f, 0.0f, // Position 1 - 0.0f, 0.0f, // TexCoord 1 - 0.5f, -0.5f, 0.0f, // Position 2 - 1.0f, 0.0f, // TexCoord 2 - 0.5f, 0.5f, 0.0f, // Position 3 - 1.0f, 1.0f // TexCoord 3 - }; - GLushort indices[] = { 0, 1, 2, 0, 2, 3, // The two triangles that make up the layer quad. - 0, 1, 2, 3}; // A line path for drawing the layer border. - - makeContextCurrent(); - - if (!createLayerShader(ContentLayerProgram, vertexShaderString, fragmentShaderString)) { - LOG_ERROR("Failed to create shader program for content layers"); - return false; - } - LayerChromium::setShaderProgramId(ContentLayerProgram); - - if (!createLayerShader(CanvasLayerProgram, vertexShaderString, canvasFragmentShaderString)) { - LOG_ERROR("Failed to create shader program for Canvas layers"); + m_scrollShaderProgram = LayerChromium::createShaderProgram(scrollVertexShaderString, scrollFragmentShaderString); + if (!m_scrollShaderProgram) { + LOG_ERROR("LayerRendererChromium: Failed to create scroll shader program"); + cleanupSharedObjects(); return false; } - CanvasLayerChromium::setShaderProgramId(CanvasLayerProgram); - if (!createLayerShader(ScrollLayerProgram, vertexShaderString, scrollFragmentShaderString)) { - LOG_ERROR("Failed to create shader program for scrolling layer"); + GLC(m_scrollShaderSamplerLocation = glGetUniformLocation(m_scrollShaderProgram, "s_texture")); + GLC(m_scrollShaderMatrixLocation = glGetUniformLocation(m_scrollShaderProgram, "matrix")); + if (m_scrollShaderSamplerLocation == -1 || m_scrollShaderMatrixLocation == -1) { + LOG_ERROR("Failed to initialize scroll shader."); + cleanupSharedObjects(); return false; } - if (!createLayerShader(DebugBorderProgram, borderVertexShaderString, borderFragmentShaderString)) { - LOG_ERROR("Failed to create shader program for debug borders"); - return false; - } - - // Specify the attrib location for the position and texCoord and make it the same for all programs to - // avoid binding re-binding the vertex attributes. - bindCommonAttribLocations(ContentLayerProgram); - bindCommonAttribLocations(CanvasLayerProgram); - bindCommonAttribLocations(DebugBorderProgram); - bindCommonAttribLocations(ScrollLayerProgram); - - // Get the location of the color uniform for the debug border shader program. - m_borderColorLocation = glGetUniformLocation(m_shaderPrograms[DebugBorderProgram].m_shaderProgramId, "color"); - - glGenBuffers(3, m_quadVboIds); - glBindBuffer(GL_ARRAY_BUFFER, m_quadVboIds[Vertices]); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_quadVboIds[LayerElements]); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); - // Create a texture object to hold the contents of the root layer. m_rootLayerTextureId = createLayerTexture(); if (!m_rootLayerTextureId) { LOG_ERROR("Failed to create texture for root layer"); + cleanupSharedObjects(); return false; } // Turn off filtering for the root layer to avoid blurring from the repeated // writes and reads to the framebuffer that happen while scrolling. - glBindTexture(GL_TEXTURE_2D, m_rootLayerTextureId); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + GLC(glBindTexture(GL_TEXTURE_2D, m_rootLayerTextureId)); + GLC(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); + GLC(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); + + // Get the max texture size supported by the system. + GLC(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize)); + + m_layerSharedValues = adoptPtr(new LayerChromium::SharedValues()); + m_contentLayerSharedValues = adoptPtr(new ContentLayerChromium::SharedValues()); + m_canvasLayerSharedValues = adoptPtr(new CanvasLayerChromium::SharedValues()); + if (!m_layerSharedValues->initialized() || !m_contentLayerSharedValues->initialized() || !m_canvasLayerSharedValues->initialized()) { + cleanupSharedObjects(); + return false; + } return true; } + +void LayerRendererChromium::cleanupSharedObjects() +{ + makeContextCurrent(); + + m_layerSharedValues.clear(); + m_contentLayerSharedValues.clear(); + m_canvasLayerSharedValues.clear(); + + if (m_scrollShaderProgram) { + GLC(glDeleteProgram(m_scrollShaderProgram)); + m_scrollShaderProgram = 0; + } + + if (m_rootLayerTextureId) { + GLC(glDeleteTextures(1, &m_rootLayerTextureId)); + m_rootLayerTextureId = 0; + } +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.h b/WebCore/platform/graphics/chromium/LayerRendererChromium.h index e4474b5..24bbe65 100644 --- a/WebCore/platform/graphics/chromium/LayerRendererChromium.h +++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.h @@ -34,6 +34,8 @@ #if USE(ACCELERATED_COMPOSITING) +#include "CanvasLayerChromium.h" +#include "ContentLayerChromium.h" #include "IntRect.h" #include "LayerChromium.h" #include "SkBitmap.h" @@ -51,16 +53,6 @@ namespace WebCore { class GLES2Context; -class ShaderProgram { -public: - ShaderProgram(); - - unsigned m_shaderProgramId; - int m_samplerLocation; - int m_matrixLocation; - int m_alphaLocation; -}; - // Class that handles drawing of composited render layers using GL. class LayerRendererChromium : public Noncopyable { public: @@ -78,73 +70,58 @@ public: void setNeedsDisplay() { m_needsDisplay = true; } - // Frees the texture associated with the given layer. - bool freeLayerTexture(LayerChromium*); - bool hardwareCompositing() const { return m_hardwareCompositing; } void setRootLayerCanvasSize(const IntSize&); GraphicsContext* rootLayerGraphicsContext() const { return m_rootLayerGraphicsContext.get(); } -private: - enum ShaderProgramType { DebugBorderProgram, ScrollLayerProgram, ContentLayerProgram, CanvasLayerProgram, NumShaderProgramTypes }; + unsigned createLayerTexture(); - void updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, float opacity, const IntRect& visibleRect); + static void debugGLCall(const char* command, const char* file, int line); - void drawLayer(LayerChromium*); + const TransformationMatrix& projectionMatrix() const { return m_projectionMatrix; } - void drawDebugBorder(LayerChromium*, const TransformationMatrix&); + void useShader(unsigned); - void drawTexturedQuad(const TransformationMatrix& matrix, float width, float height, float opacity); + bool checkTextureSize(const IntSize&); - bool isLayerVisible(LayerChromium*, const TransformationMatrix&, const IntRect& visibleRect); + const LayerChromium::SharedValues* layerSharedValues() const { return m_layerSharedValues.get(); } + const ContentLayerChromium::SharedValues* contentLayerSharedValues() const { return m_contentLayerSharedValues.get(); } + const CanvasLayerChromium::SharedValues* canvasLayerSharedValues() const { return m_canvasLayerSharedValues.get(); } - bool createLayerShader(ShaderProgramType, const char* vertexShaderSource, const char* fragmentShaderSource); +private: + void updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, float opacity); - void useShaderProgram(ShaderProgramType); + void drawLayersRecursive(LayerChromium*); - void bindCommonAttribLocations(ShaderProgramType); + void drawLayer(LayerChromium*); - enum VboIds { Vertices, LayerElements }; + bool isLayerVisible(LayerChromium*, const TransformationMatrix&, const IntRect& visibleRect); - // These are here only temporarily and should be removed once we switch over to GGL bool makeContextCurrent(); - bool initializeSharedGLObjects(); - int getTextureId(LayerChromium*); - int assignTextureForLayer(LayerChromium*); - - ShaderProgram m_shaderPrograms[NumShaderProgramTypes]; + bool initializeSharedObjects(); + void cleanupSharedObjects(); unsigned m_rootLayerTextureId; int m_rootLayerTextureWidth; int m_rootLayerTextureHeight; - // Shader uniform and attribute locations. - const int m_positionLocation; - const int m_texCoordLocation; - int m_samplerLocation; - int m_matrixLocation; - int m_alphaLocation; - int m_borderColorLocation; + // Scroll shader uniform locations. + unsigned m_scrollShaderProgram; + int m_scrollShaderSamplerLocation; + int m_scrollShaderMatrixLocation; - unsigned m_quadVboIds[3]; TransformationMatrix m_projectionMatrix; RefPtr<LayerChromium> m_rootLayer; - Vector<LayerChromium*> m_layerList; - bool m_needsDisplay; IntPoint m_scrollPosition; bool m_hardwareCompositing; - ShaderProgramType m_currentShaderProgramType; - - // Map associating layers with textures ids used by the GL compositor. - typedef HashMap<LayerChromium*, unsigned> TextureIdMap; - TextureIdMap m_textureIdMap; + unsigned int m_currentShader; #if PLATFORM(SKIA) OwnPtr<skia::PlatformCanvas> m_rootLayerCanvas; @@ -158,9 +135,33 @@ private: IntSize m_rootLayerCanvasSize; + IntRect m_visibleRect; + + int m_maxTextureSize; + + // Store values that are shared between instances of each layer type + // associated with this instance of the compositor. Since there can be + // multiple instances of the compositor running in the same renderer process + // we cannot store these values in static variables. + OwnPtr<LayerChromium::SharedValues> m_layerSharedValues; + OwnPtr<ContentLayerChromium::SharedValues> m_contentLayerSharedValues; + OwnPtr<CanvasLayerChromium::SharedValues> m_canvasLayerSharedValues; + OwnPtr<GLES2Context> m_gles2Context; }; +// Setting DEBUG_GL_CALLS to 1 will call glGetError() after almost every GL +// call made by the compositor. Useful for debugging rendering issues but +// will significantly degrade performance. +#define DEBUG_GL_CALLS 0 + +#if DEBUG_GL_CALLS && !defined ( NDEBUG ) +#define GLC(x) { (x), LayerRendererChromium::debugGLCall(#x, __FILE__, __LINE__); } +#else +#define GLC(x) (x) +#endif + + } #endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/chromium/TilingData.cpp b/WebCore/platform/graphics/chromium/TilingData.cpp index c52288d..4da242b 100755 --- a/WebCore/platform/graphics/chromium/TilingData.cpp +++ b/WebCore/platform/graphics/chromium/TilingData.cpp @@ -117,18 +117,22 @@ int TilingData::tilePositionX(int xIndex) const { ASSERT(xIndex >= 0 && xIndex < numTilesX()); - if (!xIndex) - return 0; - return tilePositionX(xIndex - 1) + tileSizeX(xIndex - 1); + int pos = 0; + for (int i = 0; i < xIndex; i++) + pos += tileSizeX(i); + + return pos; } int TilingData::tilePositionY(int yIndex) const { ASSERT(yIndex >= 0 && yIndex < numTilesY()); - if (!yIndex) - return 0; - return tilePositionX(yIndex - 1) + tileSizeY(yIndex - 1); + int pos = 0; + for (int i = 0; i < yIndex; i++) + pos += tileSizeY(i); + + return pos; } int TilingData::tileSizeX(int xIndex) const diff --git a/WebCore/platform/graphics/chromium/VideoFrameChromium.h b/WebCore/platform/graphics/chromium/VideoFrameChromium.h new file mode 100644 index 0000000..bbd677e --- /dev/null +++ b/WebCore/platform/graphics/chromium/VideoFrameChromium.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef VideoFrameChromium_h +#define VideoFrameChromium_h + +namespace WebCore { + +// A class that represents a video frame in chromium. +class VideoFrameChromium { +public: + static const unsigned cMaxPlanes; + static const unsigned cNumRGBPlanes; + static const unsigned cRGBPlane; + static const unsigned cNumYUVPlanes; + static const unsigned cYPlane; + static const unsigned cUPlane; + static const unsigned cVPlane; + + // These enums must be kept in sync with WebKit::WebVideoFrame. + enum Format { + Invalid, + RGB555, + RGB565, + RGB24, + RGB32, + RGBA, + YV12, + YV16, + NV12, + Empty, + ASCII, + }; + + enum SurfaceType { + TypeSystemMemory, + TypeOMXBufferHead, + TypeEGLImage, + TypeMFBuffer, + TypeDirect3DSurface + }; + + virtual SurfaceType surfaceType() const = 0; + virtual Format format() const = 0; + virtual unsigned width() const = 0; + virtual unsigned height() const = 0; + virtual unsigned planes() const = 0; + virtual int stride(unsigned plane) const = 0; + virtual const void* data(unsigned plane) const = 0; +}; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/graphics/chromium/TransformLayerChromium.cpp b/WebCore/platform/graphics/chromium/VideoFrameProvider.h index 6427eeb..f0bad08 100644 --- a/WebCore/platform/graphics/chromium/TransformLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/VideoFrameProvider.h @@ -28,23 +28,28 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" +#ifndef VideoFrameProvider_h +#define VideoFrameProvider_h -#if USE(ACCELERATED_COMPOSITING) - -#include "TransformLayerChromium.h" +#include "VideoFrameChromium.h" namespace WebCore { -PassRefPtr<TransformLayerChromium> TransformLayerChromium::create(GraphicsLayerChromium* owner) -{ - return adoptRef(new TransformLayerChromium(owner)); -} +class VideoFrameProvider { +public: + // This function returns a pointer to a VideoFrameChromium, which is + // the WebCore wrapper for a video frame in Chromium. getCurrentFrame() + // places a lock on the frame in Chromium. Calls to this method should + // always be followed with a call to putCurrentFrame(). + // The ownership of the object is not transferred to the caller and + // the caller should not free the returned object. + virtual VideoFrameChromium* getCurrentFrame() = 0; + // This function releases the lock on the video frame in chromium. It should + // always be called after getCurrentFrame(). Frames passed into this method + // should no longer be referenced after the call is made. + virtual void putCurrentFrame(VideoFrameChromium*) = 0; +}; -TransformLayerChromium::TransformLayerChromium(GraphicsLayerChromium* owner) - : LayerChromium(owner) -{ -} +} // namespace WebCore -} -#endif // USE(ACCELERATED_COMPOSITING) +#endif diff --git a/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp b/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp index 89b6ec1..7ff98b9 100644 --- a/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp @@ -48,23 +48,24 @@ namespace WebCore { -PassRefPtr<VideoLayerChromium> VideoLayerChromium::create(GraphicsLayerChromium* owner) +PassRefPtr<VideoLayerChromium> VideoLayerChromium::create(GraphicsLayerChromium* owner, + VideoFrameProvider* provider) { - return adoptRef(new VideoLayerChromium(owner)); + return adoptRef(new VideoLayerChromium(owner, provider)); } -VideoLayerChromium::VideoLayerChromium(GraphicsLayerChromium* owner) - : LayerChromium(owner) - , m_allocatedTextureId(0) +VideoLayerChromium::VideoLayerChromium(GraphicsLayerChromium* owner, VideoFrameProvider* provider) + : ContentLayerChromium(owner) #if PLATFORM(SKIA) , m_canvas(0) , m_skiaContext(0) #endif , m_graphicsContext(0) + , m_provider(provider) { } -void VideoLayerChromium::updateTextureContents(unsigned textureId) +void VideoLayerChromium::updateContents() { RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); if (!backing || backing->paintingGoesToWindow()) @@ -109,9 +110,20 @@ void VideoLayerChromium::updateTextureContents(unsigned textureId) // Bring the canvas into the coordinate system of the paint rect. m_canvas->translate(static_cast<SkScalar>(-dirtyRect.x()), static_cast<SkScalar>(-dirtyRect.y())); + // FIXME: Remove this test when tiled layers are implemented. + m_skipsDraw = false; + if (!layerRenderer()->checkTextureSize(requiredTextureSize)) { + m_skipsDraw = true; + return; + } + + unsigned textureId = m_contentsTexture; + if (!textureId) + textureId = layerRenderer()->createLayerTexture(); + // If the texture id or size changed since last time, then we need to tell GL // to re-allocate a texture. - if (m_allocatedTextureId != textureId || requiredTextureSize != m_allocatedTextureSize) + if (m_contentsTexture != textureId || requiredTextureSize != m_allocatedTextureSize) createTextureRect(requiredTextureSize, dirtyRect, textureId); else updateTextureRect(dirtyRect, textureId); @@ -150,7 +162,7 @@ void VideoLayerChromium::createTextureRect(const IntSize& requiredTextureSize, c ASSERT(bitmapSize == requiredTextureSize); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, requiredTextureSize.width(), requiredTextureSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - m_allocatedTextureId = textureId; + m_contentsTexture = textureId; m_allocatedTextureSize = requiredTextureSize; updateCompleted(); diff --git a/WebCore/platform/graphics/chromium/VideoLayerChromium.h b/WebCore/platform/graphics/chromium/VideoLayerChromium.h index 746299f..3507cb2 100644 --- a/WebCore/platform/graphics/chromium/VideoLayerChromium.h +++ b/WebCore/platform/graphics/chromium/VideoLayerChromium.h @@ -34,30 +34,31 @@ #if USE(ACCELERATED_COMPOSITING) -#include "LayerChromium.h" +#include "ContentLayerChromium.h" +#include "VideoFrameProvider.h" namespace WebCore { // A Layer that contains a Video element. -class VideoLayerChromium : public LayerChromium { +class VideoLayerChromium : public ContentLayerChromium { public: - static PassRefPtr<VideoLayerChromium> create(GraphicsLayerChromium* owner = 0); + static PassRefPtr<VideoLayerChromium> create(GraphicsLayerChromium* owner = 0, + VideoFrameProvider* = 0); virtual bool drawsContent() { return true; } - virtual void updateTextureContents(unsigned textureId); + virtual void updateContents(); private: - VideoLayerChromium(GraphicsLayerChromium* owner); + VideoLayerChromium(GraphicsLayerChromium* owner, VideoFrameProvider*); void createTextureRect(const IntSize& requiredTextureSize, const IntRect& updateRect, unsigned textureId); void updateTextureRect(const IntRect& updateRect, unsigned textureId); void updateCompleted(); - unsigned m_allocatedTextureId; - IntSize m_allocatedTextureSize; #if PLATFORM(SKIA) OwnPtr<skia::PlatformCanvas> m_canvas; OwnPtr<PlatformContextSkia> m_skiaContext; #endif OwnPtr<GraphicsContext> m_graphicsContext; + OwnPtr<VideoFrameProvider> m_provider; }; } diff --git a/WebCore/platform/graphics/filters/FEComposite.cpp b/WebCore/platform/graphics/filters/FEComposite.cpp index 0bafc48..d9f00ce 100644 --- a/WebCore/platform/graphics/filters/FEComposite.cpp +++ b/WebCore/platform/graphics/filters/FEComposite.cpp @@ -136,7 +136,7 @@ void FEComposite::apply(Filter* filter) break; case FECOMPOSITE_OPERATOR_IN: filterContext->save(); - filterContext->clipToImageBuffer(m_in->resultImage(), calculateDrawingRect(m_in2->scaledSubRegion())); + filterContext->clipToImageBuffer(m_in2->resultImage(), calculateDrawingRect(m_in2->scaledSubRegion())); filterContext->drawImageBuffer(m_in->resultImage(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion())); filterContext->restore(); break; diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp index 70465a0..44bb65a 100644 --- a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp @@ -200,6 +200,12 @@ TextStream& FEGaussianBlur::externalRepresentation(TextStream& ts, int indent) c return ts; } +float FEGaussianBlur::calculateStdDeviation(float radius) +{ + // Blur radius represents 2/3 times the kernel size, the dest pixel is half of the radius applied 3 times + return max((radius * 2 / 3.f - 0.5f) / gGaussianKernelFactor, 0.f); +} + } // namespace WebCore #endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.h b/WebCore/platform/graphics/filters/FEGaussianBlur.h index 4c7c43c..ad5c5a3 100644 --- a/WebCore/platform/graphics/filters/FEGaussianBlur.h +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.h @@ -43,6 +43,8 @@ public: void dump(); TextStream& externalRepresentation(TextStream&, int indent) const; + static float calculateStdDeviation(float); + private: FEGaussianBlur(FilterEffect*, const float&, const float&); static void kernelPosition(int boxBlur, unsigned& std, int& dLeft, int& dRight); diff --git a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp index c5022f9..96a639b 100644 --- a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp +++ b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp @@ -21,24 +21,178 @@ #include "GStreamerGWorld.h" -#include "MediaPlayerPrivateGStreamer.h" +#include "GOwnPtrGStreamer.h" + +#include <gst/gst.h> +#include <gst/interfaces/xoverlay.h> + +#if PLATFORM(GTK) +#include <gtk/gtk.h> +#ifdef GDK_WINDOWING_X11 +#include <gdk/gdkx.h> // for GDK_WINDOW_XID +#endif +#endif using namespace std; namespace WebCore { -PassRefPtr<GStreamerGWorld> GStreamerGWorld::createGWorld(MediaPlayerPrivateGStreamer* player) +gboolean gstGWorldSyncMessageCallback(GstBus* bus, GstMessage* message, gpointer data) +{ + ASSERT(GST_MESSAGE_TYPE(message) == GST_MESSAGE_ELEMENT); + + GStreamerGWorld* gstGWorld = static_cast<GStreamerGWorld*>(data); + + if (gst_structure_has_name(message->structure, "prepare-xwindow-id")) + gstGWorld->setWindowOverlay(message); + return TRUE; +} + +PassRefPtr<GStreamerGWorld> GStreamerGWorld::createGWorld(GstElement* pipeline) { - return adoptRef(new GStreamerGWorld(player)); + return adoptRef(new GStreamerGWorld(pipeline)); } -GStreamerGWorld::GStreamerGWorld(MediaPlayerPrivateGStreamer* player) - : m_player(player) +GStreamerGWorld::GStreamerGWorld(GstElement* pipeline) + : m_pipeline(pipeline) + , m_dynamicPadName(0) { + // XOverlay messages need to be handled synchronously. + GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_pipeline)); + gst_bus_set_sync_handler(bus, gst_bus_sync_signal_handler, this); + g_signal_connect(bus, "sync-message::element", G_CALLBACK(gstGWorldSyncMessageCallback), this); + gst_object_unref(bus); } GStreamerGWorld::~GStreamerGWorld() { + exitFullscreen(); + + m_pipeline = 0; +} + +bool GStreamerGWorld::enterFullscreen() +{ + if (m_dynamicPadName) + return false; + + if (!m_videoWindow) + m_videoWindow = PlatformVideoWindow::createWindow(); + + GstElement* platformVideoSink = gst_element_factory_make("autovideosink", "platformVideoSink"); + GstElement* colorspace = gst_element_factory_make("ffmpegcolorspace", "colorspace"); + GstElement* queue = gst_element_factory_make("queue", "queue"); + GstElement* videoScale = gst_element_factory_make("videoscale", "videoScale"); + + // Get video sink bin and the tee inside. + GOwnPtr<GstElement> videoSink; + g_object_get(m_pipeline, "video-sink", &videoSink.outPtr(), NULL); + GstElement* tee = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoTee"); + + // Add and link a queue, ffmpegcolorspace and sink in the bin. + gst_bin_add_many(GST_BIN(videoSink.get()), platformVideoSink, videoScale, colorspace, queue, NULL); + gst_element_link_many(queue, colorspace, videoScale, platformVideoSink, NULL); + + // Link a new src pad from tee to queue. + GstPad* srcPad = gst_element_get_request_pad(tee, "src%d"); + GstPad* sinkPad = gst_element_get_static_pad(queue, "sink"); + gst_pad_link(srcPad, sinkPad); + gst_object_unref(GST_OBJECT(sinkPad)); + + m_dynamicPadName = gst_pad_get_name(srcPad); + + // Roll new elements to pipeline state. + gst_element_sync_state_with_parent(queue); + gst_element_sync_state_with_parent(colorspace); + gst_element_sync_state_with_parent(videoScale); + gst_element_sync_state_with_parent(platformVideoSink); + + gst_object_unref(tee); + + // Query the current media segment informations and send them towards + // the new tee branch downstream. + + GstQuery* query = gst_query_new_segment(GST_FORMAT_TIME); + gboolean queryResult = gst_element_query(m_pipeline, query); + + // See https://bugzilla.gnome.org/show_bug.cgi?id=620490. +#if GST_CHECK_VERSION(0, 10, 30) + if (!queryResult) { + gst_query_unref(query); + gst_object_unref(GST_OBJECT(srcPad)); + return true; + } +#endif + + GstFormat format; + gint64 position; + if (!gst_element_query_position(m_pipeline, &format, &position)) + position = 0; + + gdouble rate; + gint64 startValue, stopValue; + gst_query_parse_segment(query, &rate, &format, &startValue, &stopValue); + + GstEvent* event = gst_event_new_new_segment(FALSE, rate, format, startValue, stopValue, position); + gst_pad_push_event(srcPad, event); + + gst_query_unref(query); + gst_object_unref(GST_OBJECT(srcPad)); + return true; +} + +void GStreamerGWorld::exitFullscreen() +{ + if (!m_dynamicPadName) + return; + + // Get video sink bin and the elements to remove. + GOwnPtr<GstElement> videoSink; + g_object_get(m_pipeline, "video-sink", &videoSink.outPtr(), NULL); + GstElement* tee = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoTee"); + GstElement* platformVideoSink = gst_bin_get_by_name(GST_BIN(videoSink.get()), "platformVideoSink"); + GstElement* queue = gst_bin_get_by_name(GST_BIN(videoSink.get()), "queue"); + GstElement* colorspace = gst_bin_get_by_name(GST_BIN(videoSink.get()), "colorspace"); + GstElement* videoScale = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoScale"); + + // Get pads to unlink and remove. + GstPad* srcPad = gst_element_get_static_pad(tee, m_dynamicPadName); + GstPad* sinkPad = gst_element_get_static_pad(queue, "sink"); + + // Unlink and release request pad. + gst_pad_unlink(srcPad, sinkPad); + gst_element_release_request_pad(tee, srcPad); + gst_object_unref(GST_OBJECT(srcPad)); + gst_object_unref(GST_OBJECT(sinkPad)); + + // Unlink, remove and cleanup queue, ffmpegcolorspace, videoScale and sink. + gst_element_unlink_many(queue, colorspace, videoScale, platformVideoSink, NULL); + gst_bin_remove_many(GST_BIN(videoSink.get()), queue, colorspace, videoScale, platformVideoSink, NULL); + gst_element_set_state(queue, GST_STATE_NULL); + gst_element_set_state(colorspace, GST_STATE_NULL); + gst_element_set_state(videoScale, GST_STATE_NULL); + gst_element_set_state(platformVideoSink, GST_STATE_NULL); + gst_object_unref(queue); + gst_object_unref(colorspace); + gst_object_unref(videoScale); + gst_object_unref(platformVideoSink); + + gst_object_unref(tee); + m_dynamicPadName = 0; +} + +void GStreamerGWorld::setWindowOverlay(GstMessage* message) +{ + GstObject* sink = GST_MESSAGE_SRC(message); + + if (!GST_IS_X_OVERLAY(sink)) + return; + + if (g_object_class_find_property(G_OBJECT_GET_CLASS(sink), "force-aspect-ratio")) + g_object_set(sink, "force-aspect-ratio", TRUE, NULL); + + if (m_videoWindow) + gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(sink), m_videoWindow->videoWindowId()); } } diff --git a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h index b626298..659052a 100644 --- a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h +++ b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h @@ -23,25 +23,43 @@ #if ENABLE(VIDEO) +#include "PlatformVideoWindow.h" #include "RefCounted.h" #include "RefPtr.h" #include <glib.h> +typedef struct _GstElement GstElement; +typedef struct _GstMessage GstMessage; +typedef struct _GstBus GstBus; +typedef struct _GstBin GstBin; namespace WebCore { class MediaPlayerPrivateGStreamer; +gboolean gstGWorldSyncMessageCallback(GstBus* bus, GstMessage* message, gpointer data); class GStreamerGWorld : public RefCounted<GStreamerGWorld> { + friend gboolean gstGWorldSyncMessageCallback(GstBus* bus, GstMessage* message, gpointer data); public: - static PassRefPtr<GStreamerGWorld> createGWorld(MediaPlayerPrivateGStreamer*); + static PassRefPtr<GStreamerGWorld> createGWorld(GstElement*); ~GStreamerGWorld(); + GstElement* pipeline() const { return m_pipeline; } + + // Returns the full-screen window created + bool enterFullscreen(); + void exitFullscreen(); + + void setWindowOverlay(GstMessage* message); + PlatformVideoWindow* platformVideoWindow() const { return m_videoWindow.get(); } + private: - GStreamerGWorld(MediaPlayerPrivateGStreamer*); - MediaPlayerPrivateGStreamer* m_player; + GStreamerGWorld(GstElement*); + GstElement* m_pipeline; + RefPtr<PlatformVideoWindow> m_videoWindow; + gchar* m_dynamicPadName; }; } diff --git a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp index 7184439..d9d2d97 100644 --- a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp @@ -54,7 +54,6 @@ #include <GOwnPtr.h> #include <gst/gst.h> #include <gst/interfaces/mixer.h> -#include <gst/interfaces/xoverlay.h> #include <gst/video/video.h> #include <limits> #include <math.h> @@ -1385,7 +1384,7 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin() ASSERT(!m_playBin); m_playBin = gst_element_factory_make("playbin2", "play"); - m_gstGWorld = GStreamerGWorld::createGWorld(this); + m_gstGWorld = GStreamerGWorld::createGWorld(m_playBin); GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin)); gst_bus_add_signal_watch(bus); diff --git a/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h b/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h new file mode 100644 index 0000000..83dc5dd --- /dev/null +++ b/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2010 Igalia S.L + * + * 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 PlatformVideoWindow_h +#define PlatformVideoWindow_h + +#if ENABLE(VIDEO) + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +#if PLATFORM(GTK) +#include <gtk/gtk.h> +typedef GtkWidget PlatformWindowType; +#endif + +namespace WebCore { + +class PlatformVideoWindow : public RefCounted<PlatformVideoWindow> { + public: + static PassRefPtr<PlatformVideoWindow> createWindow() { return adoptRef(new PlatformVideoWindow()); } + + PlatformVideoWindow(); + ~PlatformVideoWindow(); + + PlatformWindowType* window() const { return m_window; } + gulong videoWindowId() const { return m_videoWindowId; } + + private: + gulong m_videoWindowId; + PlatformWindowType* m_videoWindow; + PlatformWindowType* m_window; + }; +} + +#endif + +#endif diff --git a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp new file mode 100644 index 0000000..185f535 --- /dev/null +++ b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 Igalia S.L + * + * 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 "PlatformVideoWindow.h" + +#ifdef GDK_WINDOWING_X11 +#include <gdk/gdkx.h> // for GDK_WINDOW_XID +#endif + +using namespace WebCore; + +PlatformVideoWindow::PlatformVideoWindow() +{ + m_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_set_events(m_window, GDK_POINTER_MOTION_MASK | GDK_KEY_PRESS_MASK | GDK_FOCUS_CHANGE_MASK); + + m_videoWindow = gtk_drawing_area_new(); + gtk_widget_set_double_buffered(m_videoWindow, FALSE); + gtk_container_add(GTK_CONTAINER(m_window), m_videoWindow); + + gtk_widget_realize(m_window); + +#ifdef GDK_WINDOWING_X11 + m_videoWindowId = GDK_WINDOW_XID(gtk_widget_get_window(m_window)); +#endif + +} + +PlatformVideoWindow::~PlatformVideoWindow() +{ + if (m_videoWindow && m_window) { + gtk_container_remove(GTK_CONTAINER(m_window), m_videoWindow); + gtk_widget_destroy(m_videoWindow); + m_videoWindow = 0; + } + + if (m_window) { + gtk_widget_destroy(m_window); + m_window = 0; + } + + m_videoWindowId = 0; +} diff --git a/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp b/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp index d0b0274..821cc12 100644 --- a/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp +++ b/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp @@ -44,7 +44,7 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con if (type != "jpeg" && type != "png" && type != "tiff" && type != "ico" && type != "bmp") return "data:,"; - GRefPtr<GdkPixbuf> pixbuf = cairoImageSurfaceToGdkPixbuf(m_data.m_surface); + PlatformRefPtr<GdkPixbuf> pixbuf = cairoImageSurfaceToGdkPixbuf(m_data.m_surface); if (!pixbuf) return "data:,"; diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp index c591ddc..a600d73 100644 --- a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp @@ -31,8 +31,10 @@ namespace WebCore { FontCustomPlatformData::~FontCustomPlatformData() { +#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) if (m_atsContainer) ATSFontDeactivate(m_atsContainer, NULL, kATSOptionFlagsDefault); +#endif CGFontRelease(m_cgFont); } diff --git a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm index 33de3c3..d905b62 100644 --- a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm +++ b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm @@ -39,9 +39,10 @@ FontPlatformData::FontPlatformData(NSFont *nsFont, bool syntheticBold, bool synt , m_isColorBitmapFont(false) #endif { - if (nsFont) - CFRetain(nsFont); - m_size = nsFont ? [nsFont pointSize] : 0.0f; + ASSERT_ARG(nsFont, nsFont); + + CFRetain(nsFont); + m_size = [nsFont pointSize]; #ifndef BUILDING_ON_TIGER m_cgFont.adoptCF(CTFontCopyGraphicsFont(toCTFontRef(nsFont), 0)); m_atsuFontID = CTFontGetPlatformFont(toCTFontRef(nsFont), 0); @@ -95,14 +96,17 @@ const FontPlatformData& FontPlatformData::operator=(const FontPlatformData& f) void FontPlatformData::setFont(NSFont *font) { + ASSERT_ARG(font, font); + ASSERT(m_font != reinterpret_cast<NSFont *>(-1)); + if (m_font == font) return; - if (font) - CFRetain(font); - if (m_font && m_font != reinterpret_cast<NSFont *>(-1)) + + CFRetain(font); + if (m_font) CFRelease(m_font); m_font = font; - m_size = font ? [font pointSize] : 0.0f; + m_size = [font pointSize]; #ifndef BUILDING_ON_TIGER m_cgFont.adoptCF(CTFontCopyGraphicsFont(toCTFontRef(font), 0)); m_atsuFontID = CTFontGetPlatformFont(toCTFontRef(font), 0); diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm b/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm index be1d278..ab4ef4b 100644 --- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm +++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm @@ -312,6 +312,16 @@ bool GraphicsContext3D::isGLES2Compliant() const return false; } +bool GraphicsContext3D::isGLES2NPOTStrict() const +{ + return false; +} + +bool GraphicsContext3D::isErrorGeneratedOnOutOfBoundsAccesses() const +{ + return false; +} + void GraphicsContext3D::reshape(int width, int height) { if (width == m_currentWidth && height == m_currentHeight || !m_contextObj) @@ -557,40 +567,16 @@ void GraphicsContext3D::bufferData(unsigned long target, int size, unsigned long ::glBufferData(target, size, 0, usage); } -void GraphicsContext3D::bufferData(unsigned long target, ArrayBuffer* array, unsigned long usage) -{ - if (!array || !array->byteLength()) - return; - - ensureContext(m_contextObj); - ::glBufferData(target, array->byteLength(), array->data(), usage); -} - -void GraphicsContext3D::bufferData(unsigned long target, ArrayBufferView* array, unsigned long usage) -{ - if (!array || !array->length()) - return; - - ensureContext(m_contextObj); - ::glBufferData(target, array->byteLength(), array->baseAddress(), usage); -} - -void GraphicsContext3D::bufferSubData(unsigned long target, long offset, ArrayBuffer* array) +void GraphicsContext3D::bufferData(unsigned long target, int size, const void* data, unsigned long usage) { - if (!array || !array->byteLength()) - return; - ensureContext(m_contextObj); - ::glBufferSubData(target, offset, array->byteLength(), array->data()); + ::glBufferData(target, size, data, usage); } -void GraphicsContext3D::bufferSubData(unsigned long target, long offset, ArrayBufferView* array) +void GraphicsContext3D::bufferSubData(unsigned long target, long offset, int size, const void* data) { - if (!array || !array->length()) - return; - ensureContext(m_contextObj); - ::glBufferSubData(target, offset, array->byteLength(), array->baseAddress()); + ::glBufferSubData(target, offset, size, data); } unsigned long GraphicsContext3D::checkFramebufferStatus(unsigned long target) diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm index cb4ca58..315cc00 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -1213,6 +1213,18 @@ void GraphicsLayerCA::updateContentsOpaque() void GraphicsLayerCA::updateBackfaceVisibility() { + if (m_structuralLayer && structuralLayerPurpose() == StructuralLayerForReplicaFlattening) { + [m_structuralLayer.get() setDoubleSided:m_backfaceVisibility]; + + if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + CALayer *currLayer = it->second.get(); + [currLayer setDoubleSided:m_backfaceVisibility]; + } + } + } + [m_layer.get() setDoubleSided:m_backfaceVisibility]; if (LayerMap* layerCloneMap = m_layerClones.get()) { @@ -1243,7 +1255,7 @@ void GraphicsLayerCA::ensureStructuralLayer(StructuralLayerPurpose purpose) // Release the structural layer. m_structuralLayer = 0; - // Update the properties of m_layer now that we no loner have a structural layer. + // Update the properties of m_layer now that we no longer have a structural layer. updateLayerPosition(); updateLayerSize(); updateAnchorPoint(); @@ -1294,6 +1306,7 @@ void GraphicsLayerCA::ensureStructuralLayer(StructuralLayerPurpose purpose) updateAnchorPoint(); updateTransform(); updateChildrenTransform(); + updateBackfaceVisibility(); // Set properties of m_layer to their default values, since these are expressed on on the structural layer. CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); diff --git a/WebCore/platform/graphics/qt/ContextShadow.cpp b/WebCore/platform/graphics/qt/ContextShadow.cpp index 0511218..829ca82 100644 --- a/WebCore/platform/graphics/qt/ContextShadow.cpp +++ b/WebCore/platform/graphics/qt/ContextShadow.cpp @@ -28,8 +28,80 @@ #include "config.h" #include "ContextShadow.h" +#include <QTimerEvent> +#include <wtf/Noncopyable.h> + namespace WebCore { +// ContextShadow needs a scratch image as the buffer for the blur filter. +// Instead of creating and destroying the buffer for every operation, +// we create a buffer which will be automatically purged via a timer. + +class ShadowBuffer: public QObject { +public: + ShadowBuffer(QObject* parent = 0); + + QImage* scratchImage(const QSize& size); + + void schedulePurge(); + +protected: + void timerEvent(QTimerEvent* event); + +private: + QImage image; + int timerId; +}; + +ShadowBuffer::ShadowBuffer(QObject* parent) + : QObject(parent) + , timerId(0) +{ +} + +QImage* ShadowBuffer::scratchImage(const QSize& size) +{ + int width = size.width(); + int height = size.height(); + + // We do not need to recreate the buffer if the buffer is reasonably + // larger than the requested size. However, if the requested size is + // much smaller than our buffer, reduce our buffer so that we will not + // keep too many allocated pixels for too long. + if (!image.isNull() && (image.width() > width) && (image.height() > height)) + if (((2 * width) > image.width()) && ((2 * height) > image.height())) { + image.fill(Qt::transparent); + return ℑ + } + + // Round to the nearest 32 pixels so we do not grow the buffer everytime + // there is larger request by 1 pixel. + width = (1 + (width >> 5)) << 5; + height = (1 + (height >> 5)) << 5; + + image = QImage(width, height, QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::transparent); + return ℑ +} + +void ShadowBuffer::schedulePurge() +{ + static const double BufferPurgeDelay = 2; // seconds + killTimer(timerId); + timerId = startTimer(BufferPurgeDelay * 1000); +} + +void ShadowBuffer::timerEvent(QTimerEvent* event) +{ + if (event->timerId() == timerId) { + killTimer(timerId); + image = QImage(); + } + QObject::timerEvent(event); +} + +Q_GLOBAL_STATIC(ShadowBuffer, scratchShadowBuffer) + ContextShadow::ContextShadow() : type(NoShadow) , blurRadius(0) @@ -203,54 +275,66 @@ static void shadowBlur(QImage& image, int radius, const QColor& shadowColor) p.end(); } -void ContextShadow::drawShadowRect(QPainter* p, const QRectF& rect) +QPainter* ContextShadow::beginShadowLayer(QPainter* p, const QRectF &rect) { - if (type == NoShadow) - return; - - if (type == BlurShadow) { - QRectF shadowRect = rect.translated(offset); - - // We expand the area by the blur radius * 2 to give extra space - // for the blur transition. - int extra = blurRadius * 2; - QRectF bufferRect = shadowRect.adjusted(-extra, -extra, extra, extra); - QRect alignedBufferRect = bufferRect.toAlignedRect(); - - QRect clipRect; - if (p->hasClipping()) - clipRect = p->clipRegion().boundingRect(); - else - clipRect = p->transform().inverted().mapRect(p->window()); - - if (!clipRect.contains(alignedBufferRect)) { + // We expand the area by the blur radius * 2 to give extra space + // for the blur transition. + int extra = (type == BlurShadow) ? blurRadius * 2 : 0; + + QRectF shadowRect = rect.translated(offset); + QRectF bufferRect = shadowRect.adjusted(-extra, -extra, extra, extra); + m_layerRect = bufferRect.toAlignedRect(); + + QRect clipRect; + if (p->hasClipping()) +#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0) + clipRect = p->clipBoundingRect(); +#else + clipRect = p->clipRegion().boundingRect(); +#endif + else + clipRect = p->transform().inverted().mapRect(p->window()); + + if (!clipRect.contains(m_layerRect)) { + + // No need to have the buffer larger than the clip. + m_layerRect = m_layerRect.intersected(clipRect); + if (m_layerRect.isEmpty()) + return 0; + + // We adjust again because the pixels at the borders are still + // potentially affected by the pixels outside the buffer. + if (type == BlurShadow) + m_layerRect.adjust(-extra, -extra, extra, extra); + } - // No need to have the buffer larger that the clip. - alignedBufferRect = alignedBufferRect.intersected(clipRect); - if (alignedBufferRect.isEmpty()) - return; + ShadowBuffer* shadowBuffer = scratchShadowBuffer(); + QImage* shadowImage = shadowBuffer->scratchImage(m_layerRect.size()); + m_layerImage = QImage(*shadowImage); - // We adjust again because the pixels at the borders are still - // potentially affected by the pixels outside the buffer. - alignedBufferRect.adjust(-extra, -extra, extra, extra); - } + m_layerPainter = new QPainter; + m_layerPainter->begin(&m_layerImage); + m_layerPainter->setFont(p->font()); + m_layerPainter->translate(offset); - QImage shadowImage(alignedBufferRect.size(), QImage::Format_ARGB32_Premultiplied); - shadowImage.fill(Qt::transparent); - QPainter shadowPainter(&shadowImage); + // The origin is now the top left corner of the scratch image. + m_layerPainter->translate(-m_layerRect.topLeft()); - shadowPainter.fillRect(shadowRect.translated(-alignedBufferRect.topLeft()), color); - shadowPainter.end(); + return m_layerPainter; +} - shadowBlur(shadowImage, blurRadius, color); +void ContextShadow::endShadowLayer(QPainter* p) +{ + m_layerPainter->end(); + delete m_layerPainter; + m_layerPainter = 0; - p->drawImage(alignedBufferRect.topLeft(), shadowImage); + if (type == BlurShadow) + shadowBlur(m_layerImage, blurRadius, color); - return; - } + p->drawImage(m_layerRect.topLeft(), m_layerImage); - p->fillRect(rect.translated(offset), color); + scratchShadowBuffer()->schedulePurge(); } - } diff --git a/WebCore/platform/graphics/qt/ContextShadow.h b/WebCore/platform/graphics/qt/ContextShadow.h index e114ebc..7140340 100644 --- a/WebCore/platform/graphics/qt/ContextShadow.h +++ b/WebCore/platform/graphics/qt/ContextShadow.h @@ -58,12 +58,35 @@ public: void clear(); - // Draws the shadow for colored rectangle (can't be filled with pattern - // or gradient) according to the shadow parameters. - // Note: 'rect' specifies the rectangle which casts the shadow, - // NOT the bounding box of the shadow. - void drawShadowRect(QPainter* p, const QRectF& rect); + // The pair beginShadowLayer and endShadowLayer creates a temporary image + // where the caller can draw onto, using the returned QPainter. This + // QPainter instance must be used only to draw between the call to + // beginShadowLayer and endShadowLayer. + // + // Note: multiple/nested shadow layer is NOT allowed. + // + // The current clip region will be used to optimize the size of the + // temporary image. Thus, the original painter should not change any + // clipping until endShadowLayer. + // If the shadow will be completely outside the clipping region, + // beginShadowLayer will return 0. + // + // The returned QPainter will have the transformation matrix and clipping + // properly initialized to start doing the painting (no need to account + // for the shadow offset), however it will not have the same render hints, + // pen, brush, etc as the passed QPainter. This is intentional, usually + // shadow has different properties than the shape which casts the shadow. + // + // Once endShadowLayer is called, the temporary image will be drawn + // with the original painter. If blur radius is specified, the shadow + // will be filtered first. + QPainter* beginShadowLayer(QPainter* p, const QRectF& rect); + void endShadowLayer(QPainter* p); +private: + QRect m_layerRect; + QImage m_layerImage; + QPainter* m_layerPainter; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp index 59320cb..2b246de 100644 --- a/WebCore/platform/graphics/qt/FontQt.cpp +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -23,6 +23,7 @@ #include "Font.h" #include "AffineTransform.h" +#include "ContextShadow.h" #include "FontDescription.h" #include "FontFallbackList.h" #include "FontSelector.h" @@ -108,12 +109,6 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float QString string = fromRawDataWithoutRef(sanitized); QPointF pt(point.x(), point.y()); - // text shadow - FloatSize shadowSize; - float shadowBlur; - Color shadowColor; - bool hasShadow = ctx->textDrawingMode() == cTextFill && ctx->getShadow(shadowSize, shadowBlur, shadowColor); - if (from > 0 || to < run.length()) { if (isComplexText) { QTextLayout layout(string, font); @@ -125,32 +120,46 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float QFontMetrics fm(font); int ascent = fm.ascent(); - QRectF clip(point.x() + x1, point.y() - ascent, x2 - x1, fm.height()); + QRectF boundingRect(point.x() + x1, point.y() - ascent, x2 - x1, fm.height()); + QRectF clip = boundingRect; + + ContextShadow* ctxShadow = ctx->contextShadow(); - if (hasShadow) { - // TODO: when blur support is added, the clip will need to account - // for the blur radius + if (ctxShadow->type != ContextShadow::NoShadow) { qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0; - if (shadowSize.width() > 0) - dx2 = shadowSize.width(); + if (ctxShadow->offset.x() > 0) + dx2 = ctxShadow->offset.x(); else - dx1 = -shadowSize.width(); - if (shadowSize.height() > 0) - dy2 = shadowSize.height(); + dx1 = -ctxShadow->offset.x(); + if (ctxShadow->offset.y() > 0) + dy2 = ctxShadow->offset.y(); else - dy1 = -shadowSize.height(); + dy1 = -ctxShadow->offset.y(); // expand the clip rect to include the text shadow as well clip.adjust(dx1, dx2, dy1, dy2); + clip.adjust(-ctxShadow->blurRadius, -ctxShadow->blurRadius, ctxShadow->blurRadius, ctxShadow->blurRadius); } p->save(); p->setClipRect(clip.toRect(), Qt::IntersectClip); pt.setY(pt.y() - ascent); - if (hasShadow) { - p->save(); - p->setPen(QColor(shadowColor)); - p->translate(shadowSize.width(), shadowSize.height()); - line.draw(p, pt); - p->restore(); + + if (ctxShadow->type != ContextShadow::NoShadow) { + ContextShadow* ctxShadow = ctx->contextShadow(); + if (ctxShadow->type != ContextShadow::BlurShadow) { + p->save(); + p->setPen(ctxShadow->color); + p->translate(ctxShadow->offset); + line.draw(p, pt); + p->restore(); + } else { + QPainter* shadowPainter = ctxShadow->beginShadowLayer(p, boundingRect); + if (shadowPainter) { + // Since it will be blurred anyway, we don't care about render hints. + shadowPainter->setPen(ctxShadow->color); + line.draw(shadowPainter, pt); + ctxShadow->endShadowLayer(p); + } + } } p->setPen(textFillPen); line.draw(p, pt); @@ -169,16 +178,29 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) // See QWebPagePrivate::QWebPagePrivate() where the default path is set to Complex for Qt 4.6 and earlier. - if (!isComplexText) + if (!isComplexText && !(ctx->textDrawingMode() & cTextStroke)) flags |= Qt::TextBypassShaping; #endif - if (hasShadow) { - // TODO: text shadow blur support - p->save(); - p->setPen(QColor(shadowColor)); - p->translate(shadowSize.width(), shadowSize.height()); - p->drawText(pt, string, flags, run.padding()); - p->restore(); + if (ctx->contextShadow()->type != ContextShadow::NoShadow) { + ContextShadow* ctxShadow = ctx->contextShadow(); + if (ctxShadow->type != ContextShadow::BlurShadow) { + p->save(); + p->setPen(ctxShadow->color); + p->translate(ctxShadow->offset); + p->drawText(pt, string, flags, run.padding()); + p->restore(); + } else { + QFontMetrics fm(font); + QRectF boundingRect(point.x(), point.y() - fm.ascent(), fm.width(string), fm.height()); + QPainter* shadowPainter = ctxShadow->beginShadowLayer(p, boundingRect); + if (shadowPainter) { + // Since it will be blurred anyway, we don't care about render hints. + shadowPainter->setFont(p->font()); + shadowPainter->setPen(ctxShadow->color); + shadowPainter->drawText(pt, string, flags, run.padding()); + ctxShadow->endShadowLayer(p); + } + } } if (ctx->textDrawingMode() & cTextStroke) { QPainterPath path; diff --git a/WebCore/platform/graphics/qt/GradientQt.cpp b/WebCore/platform/graphics/qt/GradientQt.cpp index 1f05a15..72bb009 100644 --- a/WebCore/platform/graphics/qt/GradientQt.cpp +++ b/WebCore/platform/graphics/qt/GradientQt.cpp @@ -46,8 +46,15 @@ QGradient* Gradient::platformGradient() if (m_gradient) return m_gradient; + bool reversed = m_r0 > m_r1; + + qreal innerRadius = reversed ? m_r1 : m_r0; + qreal outerRadius = reversed ? m_r0 : m_r1; + QPointF center = reversed ? m_p0 : m_p1; + QPointF focalPoint = reversed ? m_p1 : m_p0; + if (m_radial) - m_gradient = new QRadialGradient(m_p1.x(), m_p1.y(), m_r1, m_p0.x(), m_p0.y()); + m_gradient = new QRadialGradient(center, outerRadius, focalPoint); else m_gradient = new QLinearGradient(m_p0.x(), m_p0.y(), m_p1.x(), m_p1.y()); @@ -65,9 +72,19 @@ QGradient* Gradient::platformGradient() lastStop = stopIterator->stop + lastStopDiff; else lastStop = stopIterator->stop; - if (m_radial && m_r0) - lastStop = m_r0 / m_r1 + lastStop * (1.0f - m_r0 / m_r1); - m_gradient->setColorAt(qMin(lastStop, qreal(1.0f)), stopColor); + + if (m_radial && !qFuzzyCompare(1 + outerRadius, qreal(1))) { + lastStop = lastStop * (1.0f - innerRadius / outerRadius); + if (!reversed) + lastStop += innerRadius / outerRadius; + } + + qreal stopPosition = qMin(lastStop, qreal(1.0f)); + + if (m_radial && reversed) + stopPosition = 1 - stopPosition; + + m_gradient->setColorAt(stopPosition, stopColor); // Keep the lastStop as orginal value, since the following stopColor depend it lastStop = stopIterator->stop; ++stopIterator; diff --git a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp index d5e7b3f..7918378 100644 --- a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp @@ -20,18 +20,14 @@ #include "GraphicsContext3D.h" -#include "ArrayBufferView.h" #include "WebGLObject.h" #include "CanvasRenderingContext.h" -#include "Float32Array.h" #include "GraphicsContext.h" #include "HTMLCanvasElement.h" #include "HostWindow.h" #include "ImageBuffer.h" -#include "Int32Array.h" #include "NotImplemented.h" #include "QWebPageClient.h" -#include "Uint8Array.h" #include <QAbstractScrollArea> #include <QGLContext> #include <wtf/UnusedParam.h> @@ -89,6 +85,7 @@ typedef void (APIENTRY* glGenFramebuffersType) (GLsizei, GLuint*); typedef void (APIENTRY* glGenRenderbuffersType) (GLsizei, GLuint*); typedef void (APIENTRY* glGetActiveAttribType) (GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*); typedef void (APIENTRY* glGetActiveUniformType) (GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*); +typedef void (APIENTRY* glGetAttachedShadersType) (GLuint, GLsizei, GLsizei*, GLuint*); typedef GLint (APIENTRY* glGetAttribLocationType) (GLuint, const char*); typedef void (APIENTRY* glGetBufferParameterivType) (GLenum, GLenum, GLint*); typedef void (APIENTRY* glGetFramebufferAttachmentParameterivType) (GLenum, GLenum, GLenum, GLint* params); @@ -187,6 +184,7 @@ public: glGenRenderbuffersType genRenderbuffers; glGetActiveAttribType getActiveAttrib; glGetActiveUniformType getActiveUniform; + glGetAttachedShadersType getAttachedShaders; glGetAttribLocationType getAttribLocation; glGetBufferParameterivType getBufferParameteriv; glGetFramebufferAttachmentParameterivType getFramebufferAttachmentParameteriv; @@ -276,6 +274,18 @@ bool GraphicsContext3D::isGLES2Compliant() const #endif } +// Even with underlying GLES2 driver, the below flags should still be set to +// false if extentions exist (and they almost always do). +bool GraphicsContext3D::isGLES2NPOTStrict() const +{ + return false; +} + +bool GraphicsContext3D::isErrorGeneratedOnOutOfBoundsAccesses() const +{ + return false; +} + GraphicsContext3DInternal::GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow) : m_attrs(attrs) @@ -349,6 +359,7 @@ GraphicsContext3DInternal::GraphicsContext3DInternal(GraphicsContext3D::Attribut genRenderbuffers = GET_PROC_ADDRESS(glGenRenderbuffers); getActiveAttrib = GET_PROC_ADDRESS(glGetActiveAttrib); getActiveUniform = GET_PROC_ADDRESS(glGetActiveUniform); + getAttachedShaders = GET_PROC_ADDRESS(glGetAttachedShaders); getAttribLocation = GET_PROC_ADDRESS(glGetAttribLocation); getBufferParameteriv = GET_PROC_ADDRESS(glGetBufferParameteriv); getFramebufferAttachmentParameteriv = GET_PROC_ADDRESS(glGetFramebufferAttachmentParameteriv); @@ -582,7 +593,7 @@ void GraphicsContext3D::activeTexture(unsigned long texture) m_internal->activeTexture(texture); } -void GraphicsContext3D::attachShader(PlatformGLObject program, PlatformGLObject shader) +void GraphicsContext3D::attachShader(Platform3DObject program, Platform3DObject shader) { ASSERT(program); ASSERT(shader); @@ -590,33 +601,44 @@ void GraphicsContext3D::attachShader(PlatformGLObject program, PlatformGLObject m_internal->attachShader((GLuint) program, (GLuint) shader); } -void GraphicsContext3D::bindAttribLocation(PlatformGLObject program, unsigned long index, const String& name) +void GraphicsContext3D::getAttachedShaders(Platform3DObject program, int maxCount, int* count, unsigned int* shaders) +{ + if (!program) { + synthesizeGLError(INVALID_VALUE); + return; + } + + m_internal->m_glWidget->makeCurrent(); + getAttachedShaders((GLuint) program, maxCount, count, shaders); +} + +void GraphicsContext3D::bindAttribLocation(Platform3DObject program, unsigned long index, const String& name) { ASSERT(program); m_internal->m_glWidget->makeCurrent(); m_internal->bindAttribLocation((GLuint) program, index, name.utf8().data()); } -void GraphicsContext3D::bindBuffer(unsigned long target, PlatformGLObject buffer) +void GraphicsContext3D::bindBuffer(unsigned long target, Platform3DObject buffer) { m_internal->m_glWidget->makeCurrent(); - m_internal->bindBuffer(target, (GLuint) buffer->object()); + m_internal->bindBuffer(target, (GLuint) buffer); } -void GraphicsContext3D::bindFramebuffer(unsigned long target, PlatformGLObject buffer) +void GraphicsContext3D::bindFramebuffer(unsigned long target, Platform3DObject buffer) { m_internal->m_glWidget->makeCurrent(); m_internal->m_currentFbo = buffer ? (GLuint) buffer : m_internal->m_mainFbo; m_internal->bindFramebuffer(target, m_internal->m_currentFbo); } -void GraphicsContext3D::bindRenderbuffer(unsigned long target, PlatformGLObject renderbuffer) +void GraphicsContext3D::bindRenderbuffer(unsigned long target, Platform3DObject renderbuffer) { m_internal->m_glWidget->makeCurrent(); m_internal->bindRenderbuffer(target, (GLuint) renderbuffer); } -void GraphicsContext3D::bindTexture(unsigned long target, PlatformGLObject texture) +void GraphicsContext3D::bindTexture(unsigned long target, Platform3DObject texture) { m_internal->m_glWidget->makeCurrent(); glBindTexture(target, (GLuint) texture); @@ -658,22 +680,16 @@ void GraphicsContext3D::bufferData(unsigned long target, int size, unsigned long m_internal->bufferData(target, size, /* data */ 0, usage); } -void GraphicsContext3D::bufferData(unsigned long target, ArrayBufferView* array, unsigned long usage) +void GraphicsContext3D::bufferData(unsigned long target, int size, const void* data, unsigned long usage) { - if (!array || !array->length()) - return; - m_internal->m_glWidget->makeCurrent(); - m_internal->bufferData(target, array->byteLength(), array->baseAddress(), usage); + m_internal->bufferData(target, size, data, usage); } -void GraphicsContext3D::bufferSubData(unsigned long target, long offset, ArrayBufferView* array) +void GraphicsContext3D::bufferSubData(unsigned long target, long offset, int size, const void* data) { - if (!array || !array->length()) - return; - m_internal->m_glWidget->makeCurrent(); - m_internal->bufferSubData(target, offset, array->byteLength(), array->baseAddress()); + m_internal->bufferSubData(target, offset, size, data); } unsigned long GraphicsContext3D::checkFramebufferStatus(unsigned long target) @@ -716,7 +732,7 @@ void GraphicsContext3D::colorMask(bool red, bool green, bool blue, bool alpha) glColorMask(red, green, blue, alpha); } -void GraphicsContext3D::compileShader(PlatformGLObject shader) +void GraphicsContext3D::compileShader(Platform3DObject shader) { ASSERT(shader); m_internal->m_glWidget->makeCurrent(); @@ -763,7 +779,7 @@ void GraphicsContext3D::depthRange(double zNear, double zFar) #endif } -void GraphicsContext3D::detachShader(PlatformGLObject program, PlatformGLObject shader) +void GraphicsContext3D::detachShader(Platform3DObject program, Platform3DObject shader) { ASSERT(program); ASSERT(shader); @@ -819,13 +835,13 @@ void GraphicsContext3D::flush() glFlush(); } -void GraphicsContext3D::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, PlatformGLObject buffer) +void GraphicsContext3D::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, Platform3DObject buffer) { m_internal->m_glWidget->makeCurrent(); m_internal->framebufferRenderbuffer(target, attachment, renderbuffertarget, (GLuint) buffer); } -void GraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, PlatformGLObject texture, long level) +void GraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, Platform3DObject texture, long level) { m_internal->m_glWidget->makeCurrent(); m_internal->framebufferTexture2D(target, attachment, textarget, (GLuint) texture, level); @@ -843,7 +859,7 @@ void GraphicsContext3D::generateMipmap(unsigned long target) m_internal->generateMipmap(target); } -bool GraphicsContext3D::getActiveAttrib(PlatformGLObject program, unsigned long index, ActiveInfo& info) +bool GraphicsContext3D::getActiveAttrib(Platform3DObject program, unsigned long index, ActiveInfo& info) { if (!program) { synthesizeGLError(INVALID_VALUE); @@ -875,7 +891,7 @@ bool GraphicsContext3D::getActiveAttrib(PlatformGLObject program, unsigned long return true; } -bool GraphicsContext3D::getActiveUniform(PlatformGLObject program, unsigned long index, ActiveInfo& info) +bool GraphicsContext3D::getActiveUniform(Platform3DObject program, unsigned long index, ActiveInfo& info) { if (!program) { synthesizeGLError(INVALID_VALUE); @@ -907,7 +923,7 @@ bool GraphicsContext3D::getActiveUniform(PlatformGLObject program, unsigned long return true; } -int GraphicsContext3D::getAttribLocation(PlatformGLObject program, const String& name) +int GraphicsContext3D::getAttribLocation(Platform3DObject program, const String& name) { if (!program) return -1; @@ -946,7 +962,7 @@ void GraphicsContext3D::hint(unsigned long target, unsigned long mode) glHint(target, mode); } -bool GraphicsContext3D::isBuffer(PlatformGLObject buffer) +bool GraphicsContext3D::isBuffer(Platform3DObject buffer) { if (!buffer) return false; @@ -961,7 +977,7 @@ bool GraphicsContext3D::isEnabled(unsigned long cap) return glIsEnabled(cap); } -bool GraphicsContext3D::isFramebuffer(PlatformGLObject framebuffer) +bool GraphicsContext3D::isFramebuffer(Platform3DObject framebuffer) { if (!framebuffer) return false; @@ -970,7 +986,7 @@ bool GraphicsContext3D::isFramebuffer(PlatformGLObject framebuffer) return m_internal->isFramebuffer((GLuint) framebuffer); } -bool GraphicsContext3D::isProgram(PlatformGLObject program) +bool GraphicsContext3D::isProgram(Platform3DObject program) { if (!program) return false; @@ -979,7 +995,7 @@ bool GraphicsContext3D::isProgram(PlatformGLObject program) return m_internal->isProgram((GLuint) program); } -bool GraphicsContext3D::isRenderbuffer(PlatformGLObject renderbuffer) +bool GraphicsContext3D::isRenderbuffer(Platform3DObject renderbuffer) { if (!renderbuffer) return false; @@ -988,7 +1004,7 @@ bool GraphicsContext3D::isRenderbuffer(PlatformGLObject renderbuffer) return m_internal->isRenderbuffer((GLuint) renderbuffer); } -bool GraphicsContext3D::isShader(PlatformGLObject shader) +bool GraphicsContext3D::isShader(Platform3DObject shader) { if (!shader) return false; @@ -997,7 +1013,7 @@ bool GraphicsContext3D::isShader(PlatformGLObject shader) return m_internal->isShader((GLuint) shader); } -bool GraphicsContext3D::isTexture(PlatformGLObject texture) +bool GraphicsContext3D::isTexture(Platform3DObject texture) { if (!texture) return false; @@ -1012,7 +1028,7 @@ void GraphicsContext3D::lineWidth(double width) glLineWidth(static_cast<float>(width)); } -void GraphicsContext3D::linkProgram(PlatformGLObject program) +void GraphicsContext3D::linkProgram(Platform3DObject program) { ASSERT(program); m_internal->m_glWidget->makeCurrent(); @@ -1065,7 +1081,7 @@ void GraphicsContext3D::scissor(long x, long y, unsigned long width, unsigned lo glScissor(x, y, width, height); } -void GraphicsContext3D::shaderSource(PlatformGLObject shader, const String& source) +void GraphicsContext3D::shaderSource(Platform3DObject shader, const String& source) { ASSERT(shader); @@ -1247,7 +1263,7 @@ void GraphicsContext3D::uniformMatrix4fv(long location, bool transpose, float* a m_internal->uniformMatrix4fv(location, size, transpose, array); } -void GraphicsContext3D::useProgram(PlatformGLObject program) +void GraphicsContext3D::useProgram(Platform3DObject program) { ASSERT(program); @@ -1255,7 +1271,7 @@ void GraphicsContext3D::useProgram(PlatformGLObject program) m_internal->useProgram((GLuint) program); } -void GraphicsContext3D::validateProgram(PlatformGLObject program) +void GraphicsContext3D::validateProgram(Platform3DObject program) { ASSERT(program); @@ -1353,13 +1369,13 @@ void GraphicsContext3D::getIntegerv(unsigned long paramName, int* value) glGetIntegerv(paramName, value); } -void GraphicsContext3D::getProgramiv(PlatformGLObject program, unsigned long paramName, int* value) +void GraphicsContext3D::getProgramiv(Platform3DObject program, unsigned long paramName, int* value) { m_internal->m_glWidget->makeCurrent(); m_internal->getProgramiv((GLuint) program, paramName, value); } -String GraphicsContext3D::getProgramInfoLog(PlatformGLObject program) +String GraphicsContext3D::getProgramInfoLog(Platform3DObject program) { m_internal->m_glWidget->makeCurrent(); @@ -1386,14 +1402,14 @@ void GraphicsContext3D::getRenderbufferParameteriv(unsigned long target, unsigne m_internal->getRenderbufferParameteriv(target, paramName, value); } -void GraphicsContext3D::getShaderiv(PlatformGLObject shader, unsigned long paramName, int* value) +void GraphicsContext3D::getShaderiv(Platform3DObject shader, unsigned long paramName, int* value) { ASSERT(shader); m_internal->m_glWidget->makeCurrent(); m_internal->getShaderiv((GLuint) shader, paramName, value); } -String GraphicsContext3D::getShaderInfoLog(PlatformGLObject shader) +String GraphicsContext3D::getShaderInfoLog(Platform3DObject shader) { m_internal->m_glWidget->makeCurrent(); @@ -1413,7 +1429,7 @@ String GraphicsContext3D::getShaderInfoLog(PlatformGLObject shader) return result; } -String GraphicsContext3D::getShaderSource(PlatformGLObject shader) +String GraphicsContext3D::getShaderSource(Platform3DObject shader) { m_internal->m_glWidget->makeCurrent(); @@ -1445,19 +1461,19 @@ void GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long pa glGetTexParameteriv(target, paramName, value); } -void GraphicsContext3D::getUniformfv(PlatformGLObject program, long location, float* value) +void GraphicsContext3D::getUniformfv(Platform3DObject program, long location, float* value) { m_internal->m_glWidget->makeCurrent(); m_internal->getUniformfv((GLuint) program, location, value); } -void GraphicsContext3D::getUniformiv(PlatformGLObject program, long location, int* value) +void GraphicsContext3D::getUniformiv(Platform3DObject program, long location, int* value) { m_internal->m_glWidget->makeCurrent(); m_internal->getUniformiv((GLuint) program, location, value); } -long GraphicsContext3D::getUniformLocation(PlatformGLObject program, const String& name) +long GraphicsContext3D::getUniformLocation(Platform3DObject program, const String& name) { ASSERT(program); @@ -1621,7 +1637,7 @@ bool GraphicsContext3D::getImageData(Image* image, return false; AlphaOp neededAlphaOp = kAlphaDoNothing; - if (!premultiplyAlpha && *hasAlphaChannel) + if (!premultiplyAlpha) // FIXME: must fetch the image data before the premultiplication step neededAlphaOp = kAlphaDoUnmultiply; QImage nativeImage = nativePixmap->toImage().convertToFormat(QImage::Format_ARGB32); diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index 1632804..41c9759 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -209,6 +209,15 @@ public: return shadow.type != ContextShadow::NoShadow; } + QRectF clipBoundingRect() const + { +#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0) + return painter->clipBoundingRect(); +#else + return painter->clipRegion().boundingRect(); +#endif + } + private: QPainter* painter; }; @@ -247,6 +256,9 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) // Make sure the context starts in sync with our state. setPlatformFillColor(fillColor(), DeviceColorSpace); setPlatformStrokeColor(strokeColor(), DeviceColorSpace); + + // Make sure we start with the correct join mode. + setLineJoin(MiterJoin); } } @@ -636,56 +648,50 @@ void GraphicsContext::fillRect(const FloatRect& rect) return; QPainter* p = m_data->p(); - FloatRect normalizedRect = rect.normalized(); - - QRectF shadowDestRect; - QImage* shadowImage = 0; - QPainter* pShadow = 0; - - if (m_data->hasShadow()) { - shadowImage = new QImage(roundedIntSize(normalizedRect.size()), QImage::Format_ARGB32_Premultiplied); - pShadow = new QPainter(shadowImage); - shadowDestRect = normalizedRect; - shadowDestRect.translate(m_data->shadow.offset); - - pShadow->setCompositionMode(QPainter::CompositionMode_Source); - pShadow->fillRect(shadowImage->rect(), m_data->shadow.color); - pShadow->setCompositionMode(QPainter::CompositionMode_DestinationIn); - } + QRectF normalizedRect = rect.normalized(); + ContextShadow* shadow = contextShadow(); if (m_common->state.fillPattern) { AffineTransform affine; - FloatRect rectM(rect); QBrush brush(m_common->state.fillPattern->createPlatformPattern(affine)); QPixmap* image = m_common->state.fillPattern->tileImage()->nativeImageForCurrentFrame(); - - if (m_data->hasShadow()) { - drawRepeatPattern(pShadow, image, FloatRect(static_cast<QRectF>(shadowImage->rect())), m_common->state.fillPattern->repeatX(), m_common->state.fillPattern->repeatY()); - pShadow->end(); - p->drawImage(shadowDestRect, *shadowImage, shadowImage->rect()); + QPainter* shadowPainter = m_data->hasShadow() ? shadow->beginShadowLayer(p, normalizedRect) : 0; + if (shadowPainter) { + drawRepeatPattern(shadowPainter, image, normalizedRect, m_common->state.fillPattern->repeatX(), m_common->state.fillPattern->repeatY()); + shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn); + shadowPainter->fillRect(normalizedRect, shadow->color); + shadow->endShadowLayer(p); } drawRepeatPattern(p, image, normalizedRect, m_common->state.fillPattern->repeatX(), m_common->state.fillPattern->repeatY()); } else if (m_common->state.fillGradient) { QBrush brush(*m_common->state.fillGradient->platformGradient()); brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); - - if (m_data->hasShadow()) { - pShadow->fillRect(shadowImage->rect(), brush); - pShadow->end(); - p->drawImage(shadowDestRect, *shadowImage, shadowImage->rect()); + QPainter* shadowPainter = m_data->hasShadow() ? shadow->beginShadowLayer(p, normalizedRect) : 0; + if (shadowPainter) { + shadowPainter->fillRect(normalizedRect, brush); + shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn); + shadowPainter->fillRect(normalizedRect, shadow->color); + shadow->endShadowLayer(p); } p->fillRect(normalizedRect, brush); } else { if (m_data->hasShadow()) { - pShadow->fillRect(shadowImage->rect(), p->brush()); - pShadow->end(); - p->drawImage(shadowDestRect, *shadowImage, shadowImage->rect()); + if (shadow->type == ContextShadow::BlurShadow) { + QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect); + if (shadowPainter) { + shadowPainter->fillRect(normalizedRect, p->brush()); + shadow->endShadowLayer(p); + } + } else { + // Solid rectangle fill with no blur shadow can be done faster + // without using the shadow layer at all. + QColor shadowColor = shadow->color; + shadowColor.setAlphaF(shadowColor.alphaF() * p->brush().color().alphaF()); + p->fillRect(normalizedRect.translated(shadow->offset), shadowColor); + } } p->fillRect(normalizedRect, p->brush()); } - - delete shadowImage; - delete pShadow; } @@ -696,11 +702,25 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS m_data->solidColor.setColor(color); QPainter* p = m_data->p(); + QRectF normalizedRect = rect.normalized(); - if (m_data->hasShadow()) - m_data->shadow.drawShadowRect(p, rect); + if (m_data->hasShadow()) { + ContextShadow* shadow = contextShadow(); - p->fillRect(rect, m_data->solidColor); + if (shadow->type != ContextShadow::BlurShadow) { + // We do not need any layer for simple shadow. + p->fillRect(normalizedRect.translated(shadow->offset), shadow->color); + } else { + QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect); + if (shadowPainter) { + shadowPainter->setCompositionMode(QPainter::CompositionMode_Source); + shadowPainter->fillRect(normalizedRect, shadow->color); + shadow->endShadowLayer(p); + } + } + } + + p->fillRect(normalizedRect, m_data->solidColor); } void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) @@ -742,6 +762,11 @@ PlatformPath* GraphicsContext::currentPath() return &m_data->currentPath; } +ContextShadow* GraphicsContext::contextShadow() +{ + return &m_data->shadow; +} + void GraphicsContext::clip(const FloatRect& rect) { if (paintingDisabled()) @@ -893,7 +918,7 @@ void GraphicsContext::beginTransparencyLayer(float opacity) w = device->width(); h = device->height(); - QRectF clip = p->clipPath().boundingRect(); + QRectF clip = m_data->clipBoundingRect(); QRectF deviceClip = p->transform().mapRect(clip); x = int(qBound(qreal(0), deviceClip.x(), (qreal)w)); y = int(qBound(qreal(0), deviceClip.y(), (qreal)h)); @@ -1056,7 +1081,7 @@ void GraphicsContext::clipOut(const Path& path) QPainterPath newClip; newClip.setFillRule(Qt::OddEvenFill); if (p->hasClipping()) { - newClip.addRect(p->clipRegion().boundingRect()); + newClip.addRect(m_data->clipBoundingRect()); newClip.addPath(clippedOut); p->setClipPath(newClip, Qt::IntersectClip); } else { @@ -1126,7 +1151,7 @@ void GraphicsContext::clipOut(const IntRect& rect) QPainterPath newClip; newClip.setFillRule(Qt::OddEvenFill); if (p->hasClipping()) { - newClip.addRect(p->clipRegion().boundingRect()); + newClip.addRect(m_data->clipBoundingRect()); newClip.addRect(QRect(rect)); p->setClipPath(newClip, Qt::IntersectClip); } else { @@ -1148,7 +1173,7 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) QPainterPath newClip; newClip.setFillRule(Qt::OddEvenFill); if (p->hasClipping()) { - newClip.addRect(p->clipRegion().boundingRect()); + newClip.addRect(m_data->clipBoundingRect()); newClip.addEllipse(QRect(rect)); p->setClipPath(newClip, Qt::IntersectClip); } else { diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.h b/WebCore/platform/graphics/qt/GraphicsLayerQt.h index f81bd3d..4282e64 100644 --- a/WebCore/platform/graphics/qt/GraphicsLayerQt.h +++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.h @@ -20,6 +20,9 @@ #ifndef GraphicsLayerQt_h #define GraphicsLayerQt_h +#if ENABLE(3D_CANVAS) +#include "GraphicsContext3D.h" +#endif #include "GraphicsLayer.h" #include "GraphicsLayerClient.h" diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp index 11ca377..ee01222 100644 --- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp +++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -216,11 +216,11 @@ PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& i const uchar* bits = image.bits(); #endif - quint32* destRows = reinterpret_cast<quint32*>(&data[desty * rect.width() + destx]); + quint32* destRows = reinterpret_cast_ptr<quint32*>(&data[desty * rect.width() + destx]); if (multiplied == Unmultiplied) { for (int y = 0; y < numRows; ++y) { - const quint32* scanLine = reinterpret_cast<const quint32*>(bits + (y + originy) * bytesPerLine); + const quint32* scanLine = reinterpret_cast_ptr<const quint32*>(bits + (y + originy) * bytesPerLine); for (int x = 0; x < numColumns; x++) { QRgb pixel = scanLine[x + originx]; int alpha = qAlpha(pixel); @@ -242,7 +242,7 @@ PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& i } } else { for (int y = 0; y < numRows; ++y) { - const quint32* scanLine = reinterpret_cast<const quint32*>(bits + (y + originy) * bytesPerLine); + const quint32* scanLine = reinterpret_cast_ptr<const quint32*>(bits + (y + originy) * bytesPerLine); for (int x = 0; x < numColumns; x++) { QRgb pixel = scanLine[x + originx]; // Convert RGB to BGR. @@ -318,11 +318,11 @@ void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& uchar* bits = image.bits(); const int bytesPerLine = image.bytesPerLine(); - const quint32* srcScanLine = reinterpret_cast<const quint32*>(source->data()->data()->data() + originy * srcBytesPerRow + originx * 4); + const quint32* srcScanLine = reinterpret_cast_ptr<const quint32*>(source->data()->data()->data() + originy * srcBytesPerRow + originx * 4); if (multiplied == Unmultiplied) { for (int y = 0; y < numRows; ++y) { - quint32* destScanLine = reinterpret_cast<quint32*>(bits + y * bytesPerLine); + quint32* destScanLine = reinterpret_cast_ptr<quint32*>(bits + y * bytesPerLine); for (int x = 0; x < numColumns; x++) { // Premultiply and convert BGR to RGB. quint32 pixel = srcScanLine[x]; @@ -332,7 +332,7 @@ void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& } } else { for (int y = 0; y < numRows; ++y) { - quint32* destScanLine = reinterpret_cast<quint32*>(bits + y * bytesPerLine); + quint32* destScanLine = reinterpret_cast_ptr<quint32*>(bits + y * bytesPerLine); for (int x = 0; x < numColumns; x++) { // Convert BGR to RGB. quint32 pixel = srcScanLine[x]; diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index 858cc44..02bb110 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -37,17 +37,18 @@ namespace WebCore { -ImageDecoder* ImageDecoder::create(const SharedBuffer& data) +ImageDecoder* ImageDecoder::create(const SharedBuffer& data, bool premultiplyAlpha) { // We need at least 4 bytes to figure out what kind of image we're dealing with. if (data.size() < 4) return 0; - return new ImageDecoderQt; + return new ImageDecoderQt(premultiplyAlpha); } -ImageDecoderQt::ImageDecoderQt() - : m_repetitionCount(cAnimationNone) +ImageDecoderQt::ImageDecoderQt(bool premultiplyAlpha) + : ImageDecoder(premultiplyAlpha) + , m_repetitionCount(cAnimationNone) { } @@ -104,10 +105,15 @@ size_t ImageDecoderQt::frameCount() // we will have to parse everything... if (!imageCount) forceLoadEverything(); - else + else { m_frameBufferCache.resize(imageCount); - } else + for (size_t i = 0; i < m_frameBufferCache.size(); ++i) + m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha); + } + } else { m_frameBufferCache.resize(1); + m_frameBufferCache[0].setPremultiplyAlpha(m_premultiplyAlpha); + } } return m_frameBufferCache.size(); @@ -236,6 +242,8 @@ void ImageDecoderQt::forceLoadEverything() // Otherwise, we want to forget about // the last attempt to decode a image. m_frameBufferCache.resize(imageCount - 1); + for (size_t i = 0; i < m_frameBufferCache.size(); ++i) + m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha); if (imageCount == 1) setFailed(); } diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h index ceef884..5014d53 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.h +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h @@ -41,7 +41,7 @@ namespace WebCore { class ImageDecoderQt : public ImageDecoder { public: - ImageDecoderQt(); + ImageDecoderQt(bool premultiplyAlpha); ~ImageDecoderQt(); virtual void setData(SharedBuffer* data, bool allDataReceived); diff --git a/WebCore/platform/graphics/qt/TransparencyLayer.h b/WebCore/platform/graphics/qt/TransparencyLayer.h index 0d9c121..1a614ac 100644 --- a/WebCore/platform/graphics/qt/TransparencyLayer.h +++ b/WebCore/platform/graphics/qt/TransparencyLayer.h @@ -52,7 +52,7 @@ struct TransparencyLayer : FastAllocBase { offset = rect.topLeft(); pixmap.fill(Qt::transparent); painter.begin(&pixmap); - painter.setRenderHint(QPainter::Antialiasing, p->testRenderHint(QPainter::Antialiasing)); + painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); painter.translate(-offset); painter.setPen(p->pen()); painter.setBrush(p->brush()); diff --git a/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h b/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h index 9fb6a8b..553f203 100644 --- a/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h +++ b/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h @@ -46,9 +46,10 @@ namespace WebCore { // is that NativeImagePtr = NativeImageSkia, yet callers have SkBitmap. class BitmapImageSingleFrameSkia : public Image { public: - // Creates a new Image, by copying the pixel values out of |bitmap|. - // If creation failed, returns null. - static PassRefPtr<BitmapImageSingleFrameSkia> create(const SkBitmap&); + // Creates a new Image from the given SkBitmap. If "copyPixels" is true, a + // deep copy is done. Otherwise, a shallow copy is done (pixel data is + // ref'ed). + static PassRefPtr<BitmapImageSingleFrameSkia> create(const SkBitmap&, bool copyPixels); virtual bool isBitmapImage() const { return true; } @@ -77,8 +78,8 @@ protected: private: NativeImageSkia m_nativeImage; - // Use create(). - BitmapImageSingleFrameSkia() { } + // Creates a new Image from the given SkBitmap, using a shallow copy. + explicit BitmapImageSingleFrameSkia(const SkBitmap&); }; } // namespace WebCore diff --git a/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp index ee0a874..61039f2 100644 --- a/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp +++ b/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp @@ -31,6 +31,7 @@ #include "GraphicsContext3D.h" #include "Image.h" +#include "ImageSource.h" #include "NativeImageSkia.h" #include <algorithm> @@ -43,27 +44,28 @@ bool GraphicsContext3D::getImageData(Image* image, bool premultiplyAlpha, Vector<uint8_t>& outputVector) { - if (!image) + if (!image || !image->data()) return false; - NativeImageSkia* skiaImage = image->nativeImageForCurrentFrame(); - if (!skiaImage) + ImageSource decoder(false); + decoder.setData(image->data(), true); + if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0)) return false; - SkBitmap::Config skiaConfig = skiaImage->config(); - // FIXME: must support more image configurations. + bool hasAlpha = decoder.frameHasAlphaAtIndex(0); + OwnPtr<NativeImageSkia> pixels(decoder.createFrameAtIndex(0)); + if (!pixels.get() || !pixels->isDataComplete() || !pixels->width() || !pixels->height()) + return false; + SkBitmap::Config skiaConfig = pixels->config(); if (skiaConfig != SkBitmap::kARGB_8888_Config) return false; - SkBitmap& skiaImageRef = *skiaImage; + SkBitmap& skiaImageRef = *pixels; SkAutoLockPixels lock(skiaImageRef); - int height = skiaImage->height(); - int rowBytes = skiaImage->rowBytes(); - ASSERT(rowBytes == skiaImage->width() * 4); - uint8_t* pixels = reinterpret_cast<uint8_t*>(skiaImage->getPixels()); - outputVector.resize(rowBytes * height); + ASSERT(pixels->rowBytes() == pixels->width() * 4); + outputVector.resize(pixels->rowBytes() * pixels->height()); AlphaOp neededAlphaOp = kAlphaDoNothing; - if (!premultiplyAlpha) - // FIXME: must fetch the image data before the premultiplication step - neededAlphaOp = kAlphaDoUnmultiply; - return packPixels(pixels, kSourceFormatBGRA8, skiaImage->width(), height, 0, + if (hasAlpha && premultiplyAlpha) + neededAlphaOp = kAlphaDoPremultiply; + return packPixels(reinterpret_cast<const uint8_t*>(pixels->getPixels()), + kSourceFormatBGRA8, pixels->width(), pixels->height(), 0, format, type, neededAlphaOp, outputVector.data()); } diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index fe7f6ce..1b20e26 100644 --- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -323,7 +323,6 @@ void GraphicsContext::addPath(const Path& path) { if (paintingDisabled()) return; - platformContext()->prepareForSoftwareDraw(); platformContext()->addPath(*path.platformPath()); } @@ -331,7 +330,6 @@ void GraphicsContext::beginPath() { if (paintingDisabled()) return; - platformContext()->prepareForSoftwareDraw(); platformContext()->beginPath(); } @@ -783,7 +781,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) } #if USE(GLES2_RENDERING) - if (platformContext()->useGPU() && !m_common->state.fillPattern && !m_common->state.fillGradient) { + if (platformContext()->useGPU() && !m_common->state.fillPattern && !m_common->state.fillGradient && !platformContext()->getDrawLooper()) { platformContext()->prepareForHardwareDraw(); platformContext()->gpuCanvas()->fillRect(rect); return; diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index a63eec5..9403406 100644 --- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -89,12 +89,13 @@ GraphicsContext* ImageBuffer::context() const bool ImageBuffer::drawsUsingCopy() const { - return true; + return false; } PassRefPtr<Image> ImageBuffer::copyImage() const { - return BitmapImageSingleFrameSkia::create(*m_data.m_platformContext.bitmap()); + m_context->platformContext()->syncSoftwareCanvas(); + return BitmapImageSingleFrameSkia::create(*m_data.m_platformContext.bitmap(), true); } void ImageBuffer::clip(GraphicsContext* context, const FloatRect& rect) const @@ -107,15 +108,15 @@ void ImageBuffer::clip(GraphicsContext* context, const FloatRect& rect) const void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, bool useLowQualityScale) { - RefPtr<Image> imageCopy = copyImage(); - context->drawImage(imageCopy.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale); + RefPtr<Image> image = BitmapImageSingleFrameSkia::create(*m_data.m_platformContext.bitmap(), context == m_context); + context->drawImage(image.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale); } void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) { - RefPtr<Image> imageCopy = copyImage(); - imageCopy->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect); + RefPtr<Image> image = BitmapImageSingleFrameSkia::create(*m_data.m_platformContext.bitmap(), context == m_context); + image->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect); } void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp index b514b1a..1ff87cc 100644 --- a/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -419,8 +419,9 @@ static void drawBitmapGLES2(GraphicsContext* ctxt, NativeImageSkia* bitmap, cons ASSERT(bitmap->config() == SkBitmap::kARGB_8888_Config); ASSERT(bitmap->rowBytes() == bitmap->width() * 4); texture = gpuCanvas->createTexture(bitmap, GLES2Texture::BGRA8, bitmap->width(), bitmap->height()); - ASSERT(bitmap->pixelRef()); - texture->load(bitmap->pixelRef()->pixels()); + SkAutoLockPixels lock(*bitmap); + ASSERT(bitmap->getPixels()); + texture->load(bitmap->getPixels()); } gpuCanvas->drawTexturedRect(texture, srcRect, dstRect, styleColorSpace, compositeOp); } @@ -516,11 +517,19 @@ void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt, WebCoreCompositeToSkiaComposite(compositeOp)); } -PassRefPtr<BitmapImageSingleFrameSkia> BitmapImageSingleFrameSkia::create(const SkBitmap& bitmap) +BitmapImageSingleFrameSkia::BitmapImageSingleFrameSkia(const SkBitmap& bitmap) + : m_nativeImage(bitmap) { - RefPtr<BitmapImageSingleFrameSkia> image(adoptRef(new BitmapImageSingleFrameSkia())); - bitmap.copyTo(&image->m_nativeImage, bitmap.config()); - return image.release(); +} + +PassRefPtr<BitmapImageSingleFrameSkia> BitmapImageSingleFrameSkia::create(const SkBitmap& bitmap, bool copyPixels) +{ + if (copyPixels) { + SkBitmap temp; + bitmap.copyTo(&temp, bitmap.config()); + return adoptRef(new BitmapImageSingleFrameSkia(temp)); + } + return adoptRef(new BitmapImageSingleFrameSkia(bitmap)); } } // namespace WebCore diff --git a/WebCore/platform/graphics/skia/NativeImageSkia.cpp b/WebCore/platform/graphics/skia/NativeImageSkia.cpp index 007a32c..28e0758 100644 --- a/WebCore/platform/graphics/skia/NativeImageSkia.cpp +++ b/WebCore/platform/graphics/skia/NativeImageSkia.cpp @@ -46,6 +46,14 @@ NativeImageSkia::NativeImageSkia() { } +NativeImageSkia::NativeImageSkia(const SkBitmap& other) + : SkBitmap(other), + m_isDataComplete(false), + m_lastRequestSize(0, 0), + m_resizeRequests(0) +{ +} + int NativeImageSkia::decodedSize() const { return getSize() + m_resizedImage.getSize(); diff --git a/WebCore/platform/graphics/skia/NativeImageSkia.h b/WebCore/platform/graphics/skia/NativeImageSkia.h index 0718836..e26a5ea 100644 --- a/WebCore/platform/graphics/skia/NativeImageSkia.h +++ b/WebCore/platform/graphics/skia/NativeImageSkia.h @@ -43,6 +43,11 @@ class NativeImageSkia : public SkBitmap { public: NativeImageSkia(); + // This constructor does a shallow copy of the passed-in SkBitmap (ie., it + // references the same pixel data and bumps the refcount). Use only when + // you want sharing semantics. + explicit NativeImageSkia(const SkBitmap&); + // Returns the number of bytes of image data. This includes the cached // resized version if there is one. int decodedSize() const; diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index 1161224..b9de0a2 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -733,11 +733,7 @@ void PlatformContextSkia::prepareForSoftwareDraw() const if (m_state->m_xferMode == SkXfermode::kSrcOver_Mode) { // Last drawn on hardware; clear out the canvas. - m_canvas->save(); - SkRect bounds = {0, 0, m_canvas->getDevice()->width(), m_canvas->getDevice()->height()}; - m_canvas->clipRect(bounds, SkRegion::kReplace_Op); - m_canvas->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode); - m_canvas->restore(); + m_canvas->getDevice()->eraseColor(0); // Start compositing into the empty canvas. m_backingStoreState = Mixed; } else { @@ -753,6 +749,8 @@ void PlatformContextSkia::prepareForSoftwareDraw() const readbackHardwareToSoftware(); m_backingStoreState = Software; } + } else if (m_backingStoreState == None) { + m_backingStoreState = Software; } } diff --git a/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp index 35839f5..02c5b99 100644 --- a/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp +++ b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp @@ -27,12 +27,12 @@ namespace WebCore { -FontCustomPlatformDataCairo::~FontCustomPlatformDataCairo() +FontCustomPlatformData::~FontCustomPlatformData() { cairo_font_face_destroy(m_fontFace); } -FontPlatformData FontCustomPlatformDataCairo::fontPlatformData(int size, bool bold, bool italic) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic) { return FontPlatformData(m_fontFace, size, bold, italic); } @@ -42,7 +42,7 @@ static void releaseData(void* data) static_cast<SharedBuffer*>(data)->deref(); } -FontCustomPlatformDataCairo* createFontCustomPlatformData(SharedBuffer* buffer) +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) { ASSERT_ARG(buffer, buffer); @@ -55,7 +55,7 @@ FontCustomPlatformDataCairo* createFontCustomPlatformData(SharedBuffer* buffer) static cairo_user_data_key_t bufferKey; cairo_font_face_set_user_data(fontFace, &bufferKey, buffer, releaseData); - return new FontCustomPlatformDataCairo(fontFace); + return new FontCustomPlatformData(fontFace); } bool FontCustomPlatformData::supportsFormat(const String& format) diff --git a/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h index 2dbea51..525957f 100644 --- a/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h +++ b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 Apple Computer, Inc. + * Copyright (C) 2010 Brent Fulgham <bfulgham@webkit.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -31,12 +32,12 @@ namespace WebCore { class FontPlatformData; class SharedBuffer; -struct FontCustomPlatformDataCairo : Noncopyable { - FontCustomPlatformDataCairo(cairo_font_face_t* fontFace) +struct FontCustomPlatformData : Noncopyable { + FontCustomPlatformData(cairo_font_face_t* fontFace) : m_fontFace(fontFace) { } - ~FontCustomPlatformDataCairo(); + ~FontCustomPlatformData(); FontPlatformData fontPlatformData(int size, bool bold, bool italic); @@ -45,7 +46,7 @@ struct FontCustomPlatformDataCairo : Noncopyable { cairo_font_face_t* m_fontFace; }; -FontCustomPlatformDataCairo* createFontCustomPlatformData(SharedBuffer*); +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*); } diff --git a/WebCore/platform/graphics/win/WKCACFLayer.cpp b/WebCore/platform/graphics/win/WKCACFLayer.cpp index b5f3427..bbe5883 100644 --- a/WebCore/platform/graphics/win/WKCACFLayer.cpp +++ b/WebCore/platform/graphics/win/WKCACFLayer.cpp @@ -44,6 +44,24 @@ namespace WebCore { using namespace std; +#ifndef NDEBUG +void WKCACFLayer::internalCheckLayerConsistency() +{ + ASSERT(layer()); + size_t n = sublayerCount(); + for (size_t i = 0; i < n; ++i) { + // This will ASSERT in internalSublayerAtIndex if this entry doesn't have proper user data + WKCACFLayer* sublayer = internalSublayerAtIndex(i); + + // Make sure we don't have any null entries in the list + ASSERT(sublayer); + + // Make sure the each layer has a corresponding CACFLayer + ASSERT(sublayer->layer()); + } +} +#endif + static void displayCallback(CACFLayerRef layer, CGContextRef context) { ASSERT_ARG(layer, WKCACFLayer::layer(layer)); @@ -161,7 +179,14 @@ WKCACFLayer::~WKCACFLayer() // Our superlayer should be holding a reference to us, so there should be no way for us to be destroyed while we still have a superlayer. ASSERT(!superlayer()); + // Get rid of the children so we don't have any dangling references around + removeAllSublayers(); + +#ifndef NDEBUG + CACFLayerSetUserData(layer(), reinterpret_cast<void*>(0xDEADBEEF)); +#else CACFLayerSetUserData(layer(), 0); +#endif CACFLayerSetDisplayCallback(layer(), 0); } @@ -192,10 +217,11 @@ void WKCACFLayer::addSublayer(PassRefPtr<WKCACFLayer> sublayer) void WKCACFLayer::internalInsertSublayer(PassRefPtr<WKCACFLayer> sublayer, size_t index) { - index = min(index, sublayerCount()); + index = min(index, sublayerCount() + 1); sublayer->removeFromSuperlayer(); CACFLayerInsertSublayer(layer(), sublayer->layer(), index); setNeedsCommit(); + checkLayerConsistency(); } void WKCACFLayer::insertSublayerAboveLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference) @@ -268,12 +294,14 @@ void WKCACFLayer::adoptSublayers(WKCACFLayer* source) sublayers.append(source->internalSublayerAtIndex(i)); setSublayers(sublayers); + source->checkLayerConsistency(); } void WKCACFLayer::removeFromSuperlayer() { WKCACFLayer* superlayer = this->superlayer(); CACFLayerRemoveFromSuperlayer(layer()); + checkLayerConsistency(); if (superlayer) superlayer->setNeedsCommit(); diff --git a/WebCore/platform/graphics/win/WKCACFLayer.h b/WebCore/platform/graphics/win/WKCACFLayer.h index abc04c8..7243508 100644 --- a/WebCore/platform/graphics/win/WKCACFLayer.h +++ b/WebCore/platform/graphics/win/WKCACFLayer.h @@ -60,7 +60,11 @@ public: BottomLeft, BottomRight, Resize, ResizeAspect, ResizeAspectFill }; static PassRefPtr<WKCACFLayer> create(LayerType); - static WKCACFLayer* layer(CACFLayerRef layer) { return static_cast<WKCACFLayer*>(CACFLayerGetUserData(layer)); } + static WKCACFLayer* layer(CACFLayerRef layer) + { + ASSERT(CACFLayerGetUserData(layer) != reinterpret_cast<void*>(0xDEADBEEF)); + return static_cast<WKCACFLayer*>(CACFLayerGetUserData(layer)); + } virtual ~WKCACFLayer(); @@ -133,7 +137,11 @@ public: void adoptSublayers(WKCACFLayer* source); void removeAllSublayers() { internalRemoveAllSublayers(); } - void setSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers) { internalSetSublayers(sublayers); } + void setSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers) + { + internalSetSublayers(sublayers); + checkLayerConsistency(); + } void insertSublayer(PassRefPtr<WKCACFLayer> layer, size_t index) { internalInsertSublayer(layer, index); } @@ -244,6 +252,13 @@ protected: // This should only be called from removeFromSuperlayer. void removeSublayer(const WKCACFLayer*); + void checkLayerConsistency() + { +#ifndef NDEBUG + internalCheckLayerConsistency(); +#endif + } + // Methods to be overridden for sublayer and rendering management virtual WKCACFLayer* internalSublayerAtIndex(int) const; @@ -259,6 +274,10 @@ protected: virtual void internalSetNeedsDisplay(const CGRect* dirtyRect); #ifndef NDEBUG + virtual void internalCheckLayerConsistency(); +#endif + +#ifndef NDEBUG // Print this layer and its children to the console void printLayer(int indent) const; #endif diff --git a/WebCore/platform/graphics/win/WebTiledLayer.cpp b/WebCore/platform/graphics/win/WebTiledLayer.cpp index d8c02d2..01dd6ae 100755 --- a/WebCore/platform/graphics/win/WebTiledLayer.cpp +++ b/WebCore/platform/graphics/win/WebTiledLayer.cpp @@ -36,6 +36,26 @@ namespace WebCore { using namespace std; +#ifndef NDEBUG +void WebTiledLayer::internalCheckLayerConsistency() +{ + WKCACFLayer::internalCheckLayerConsistency(); + + // Additionally make sure the tiled parent is valid + CFArrayRef sublayers = CACFLayerGetSublayers(layer()); + + // Make sure there is a tile parent and it is the same as we remember + size_t n = CFArrayGetCount(sublayers); + ASSERT(n > 0); + const void* element = CFArrayGetValueAtIndex(sublayers, 0); + ASSERT(m_tileParent.get() == element); + + // Make sure the tile parent doesn't have user data. If it does, it is probably + // a WKCACFLayer in the wrong place. + ASSERT(!layer(m_tileParent.get())); +} +#endif + void WebTiledLayer::tileDisplayCallback(CACFLayerRef layer, CGContextRef context) { static_cast<WebTiledLayer*>(CACFLayerGetUserData(layer))->drawTile(layer, context); diff --git a/WebCore/platform/graphics/win/WebTiledLayer.h b/WebCore/platform/graphics/win/WebTiledLayer.h index fdf0205..b8ae320 100644 --- a/WebCore/platform/graphics/win/WebTiledLayer.h +++ b/WebCore/platform/graphics/win/WebTiledLayer.h @@ -56,6 +56,10 @@ protected: virtual void internalSetNeedsDisplay(const CGRect* dirtyRect); +#ifndef NDEBUG + virtual void internalCheckLayerConsistency(); +#endif + private: static void tileDisplayCallback(CACFLayerRef, CGContextRef); void drawTile(CACFLayerRef, CGContextRef); diff --git a/WebCore/platform/gtk/ClipboardGtk.cpp b/WebCore/platform/gtk/ClipboardGtk.cpp index 21ebe4c..b2c32a4 100644 --- a/WebCore/platform/gtk/ClipboardGtk.cpp +++ b/WebCore/platform/gtk/ClipboardGtk.cpp @@ -330,7 +330,7 @@ void ClipboardGtk::declareAndWriteDragImage(Element* element, const KURL& url, c if (!image || !image->isLoaded()) return; - GRefPtr<GdkPixbuf> pixbuf = adoptGRef(image->image()->getGdkPixbuf()); + PlatformRefPtr<GdkPixbuf> pixbuf = adoptPlatformRef(image->image()->getGdkPixbuf()); if (!pixbuf) return; diff --git a/WebCore/platform/gtk/CursorGtk.cpp b/WebCore/platform/gtk/CursorGtk.cpp index 41b0800..d1f1293 100644 --- a/WebCore/platform/gtk/CursorGtk.cpp +++ b/WebCore/platform/gtk/CursorGtk.cpp @@ -37,25 +37,39 @@ namespace WebCore { -static GRefPtr<GdkCursor> createNamedCursor(CustomCursorType cursorType) +static GdkPixmap* createPixmapFromBits(const unsigned char* bits, const IntSize& size) +{ + cairo_surface_t* dataSurface = cairo_image_surface_create_for_data(const_cast<unsigned char*>(bits), CAIRO_FORMAT_A1, size.width(), size.height(), size.width() / 8); + GdkPixmap* pixmap = gdk_pixmap_new(0, size.width(), size.height(), 1); + cairo_t* cr = gdk_cairo_create(pixmap); + cairo_set_source_surface(cr, dataSurface, 0, 0); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_paint(cr); + cairo_destroy(cr); + cairo_surface_destroy(dataSurface); + return pixmap; +} + +static PlatformRefPtr<GdkCursor> createNamedCursor(CustomCursorType cursorType) { CustomCursor cursor = CustomCursors[cursorType]; - GRefPtr<GdkCursor> c = adoptGRef(gdk_cursor_new_from_name(gdk_display_get_default(), cursor.name)); + PlatformRefPtr<GdkCursor> c = adoptPlatformRef(gdk_cursor_new_from_name(gdk_display_get_default(), cursor.name)); if (c) return c; const GdkColor fg = { 0, 0, 0, 0 }; const GdkColor bg = { 65535, 65535, 65535, 65535 }; - GRefPtr<GdkPixmap> source = adoptGRef(gdk_bitmap_create_from_data(0, cursor.bits, 32, 32)); - GRefPtr<GdkPixmap> mask = adoptGRef(gdk_bitmap_create_from_data(0, cursor.mask_bits, 32, 32)); - return adoptGRef(gdk_cursor_new_from_pixmap(source.get(), mask.get(), &fg, &bg, cursor.hot_x, cursor.hot_y)); + IntSize cursorSize = IntSize(32, 32); + PlatformRefPtr<GdkPixmap> source = adoptPlatformRef(createPixmapFromBits(cursor.bits, cursorSize)); + PlatformRefPtr<GdkPixmap> mask = adoptPlatformRef(createPixmapFromBits(cursor.mask_bits, cursorSize)); + return adoptPlatformRef(gdk_cursor_new_from_pixmap(source.get(), mask.get(), &fg, &bg, cursor.hot_x, cursor.hot_y)); } -static GRefPtr<GdkCursor> createCustomCursor(Image* image, const IntPoint& hotSpot) +static PlatformRefPtr<GdkCursor> createCustomCursor(Image* image, const IntPoint& hotSpot) { IntPoint effectiveHotSpot = determineHotSpot(image, hotSpot); - GRefPtr<GdkPixbuf> pixbuf = adoptGRef(image->getGdkPixbuf()); - return adoptGRef(gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf.get(), effectiveHotSpot.x(), effectiveHotSpot.y())); + PlatformRefPtr<GdkPixbuf> pixbuf = adoptPlatformRef(image->getGdkPixbuf()); + return adoptPlatformRef(gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf.get(), effectiveHotSpot.x(), effectiveHotSpot.y())); } void Cursor::ensurePlatformCursor() const @@ -69,77 +83,77 @@ void Cursor::ensurePlatformCursor() const m_platformCursor = 0; break; case Cursor::Cross: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_CROSS)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_CROSS)); break; case Cursor::Hand: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_HAND2)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_HAND2)); break; case Cursor::IBeam: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_XTERM)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_XTERM)); break; case Cursor::Wait: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_WATCH)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_WATCH)); break; case Cursor::Help: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_QUESTION_ARROW)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_QUESTION_ARROW)); break; case Cursor::Move: case Cursor::MiddlePanning: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_FLEUR)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_FLEUR)); break; case Cursor::EastResize: case Cursor::EastPanning: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_RIGHT_SIDE)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_RIGHT_SIDE)); break; case Cursor::NorthResize: case Cursor::NorthPanning: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_TOP_SIDE)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_TOP_SIDE)); break; case Cursor::NorthEastResize: case Cursor::NorthEastPanning: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_LEFT_SIDE)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_LEFT_SIDE)); break; case Cursor::NorthWestResize: case Cursor::NorthWestPanning: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_TOP_LEFT_CORNER)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_TOP_LEFT_CORNER)); break; case Cursor::SouthResize: case Cursor::SouthPanning: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_BOTTOM_SIDE)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_BOTTOM_SIDE)); break; case Cursor::SouthEastResize: case Cursor::SouthEastPanning: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER)); break; case Cursor::SouthWestResize: case Cursor::SouthWestPanning: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER)); break; case Cursor::WestResize: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_LEFT_SIDE)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_LEFT_SIDE)); break; case Cursor::NorthSouthResize: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_TOP_TEE)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_TOP_TEE)); break; case Cursor::EastWestResize: case Cursor::WestPanning: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_LEFT_SIDE)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_LEFT_SIDE)); break; case Cursor::NorthEastSouthWestResize: case Cursor::NorthWestSouthEastResize: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_SIZING)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_SIZING)); break; case Cursor::ColumnResize: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW)); break; case Cursor::RowResize: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW)); break; case Cursor::VerticalText: m_platformCursor = createNamedCursor(CustomCursorVerticalText); break; case Cursor::Cell: - m_platformCursor = adoptGRef(gdk_cursor_new(GDK_PLUS)); + m_platformCursor = adoptPlatformRef(gdk_cursor_new(GDK_PLUS)); break; case Cursor::ContextMenu: m_platformCursor = createNamedCursor(CustomCursorContextMenu); diff --git a/WebCore/platform/gtk/CursorGtk.h b/WebCore/platform/gtk/CursorGtk.h index 85aaefa..568919b 100644 --- a/WebCore/platform/gtk/CursorGtk.h +++ b/WebCore/platform/gtk/CursorGtk.h @@ -47,7 +47,7 @@ */ /* MOZ_CURSOR_VERTICAL_TEXT */ -static const char moz_vertical_text_bits[] = { +static const unsigned char moz_vertical_text_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -60,7 +60,7 @@ static const char moz_vertical_text_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const char moz_vertical_text_mask_bits[] = { +static const unsigned char moz_vertical_text_mask_bits[] = { 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, @@ -74,7 +74,7 @@ static const char moz_vertical_text_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* MOZ_CURSOR_CONTEXT_MENU */ -static const char moz_menu_bits[] = { +static const unsigned char moz_menu_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0xfd, 0x00, 0x00, @@ -87,7 +87,7 @@ static const char moz_menu_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const char moz_menu_mask_bits[] = { +static const unsigned char moz_menu_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0xfd, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, @@ -101,7 +101,7 @@ static const char moz_menu_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* MOZ_CURSOR_COPY */ -static const char moz_copy_bits[] = { +static const unsigned char moz_copy_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, @@ -114,7 +114,7 @@ static const char moz_copy_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const char moz_copy_mask_bits[] = { +static const unsigned char moz_copy_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, @@ -128,7 +128,7 @@ static const char moz_copy_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* MOZ_CURSOR_ALIAS */ -static const char moz_alias_bits[] = { +static const unsigned char moz_alias_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, @@ -141,7 +141,7 @@ static const char moz_alias_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const char moz_alias_mask_bits[] = { +static const unsigned char moz_alias_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, @@ -155,7 +155,7 @@ static const char moz_alias_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* MOZ_CURSOR_ZOOM_IN */ -static const char moz_zoom_in_bits[] = { +static const unsigned char moz_zoom_in_bits[] = { 0xf0, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x62, 0x04, 0x00, 0x00, 0x61, 0x08, 0x00, 0x00, 0xf9, 0x09, 0x00, 0x00, 0xf9, 0x09, 0x00, 0x00, 0x61, 0x08, 0x00, 0x00, 0x62, 0x04, 0x00, 0x00, @@ -168,7 +168,7 @@ static const char moz_zoom_in_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const char moz_zoom_in_mask_bits[] = { +static const unsigned char moz_zoom_in_mask_bits[] = { 0xf0, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, @@ -182,7 +182,7 @@ static const char moz_zoom_in_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* MOZ_CURSOR_ZOOM_OUT */ -static const char moz_zoom_out_bits[] = { +static const unsigned char moz_zoom_out_bits[] = { 0xf0, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xf9, 0x09, 0x00, 0x00, 0xf9, 0x09, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, @@ -195,7 +195,7 @@ static const char moz_zoom_out_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const char moz_zoom_out_mask_bits[] = { +static const unsigned char moz_zoom_out_mask_bits[] = { 0xf0, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, @@ -209,7 +209,7 @@ static const char moz_zoom_out_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* MOZ_CURSOR_NOT_ALLOWED */ -static const char moz_not_allowed_bits[] = { +static const unsigned char moz_not_allowed_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0x38, 0xc0, 0x01, 0x00, 0x7c, 0x80, 0x03, 0x00, 0xec, 0x00, 0x03, 0x00, 0xce, 0x01, 0x07, 0x00, 0x86, 0x03, 0x06, 0x00, @@ -222,7 +222,7 @@ static const char moz_not_allowed_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const char moz_not_allowed_mask_bits[] = { +static const unsigned char moz_not_allowed_mask_bits[] = { 0x80, 0x1f, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xfc, 0xf0, 0x03, 0x00, 0xfe, 0xc0, 0x07, 0x00, 0xfe, 0x81, 0x07, 0x00, 0xff, 0x83, 0x0f, 0x00, 0xcf, 0x07, 0x0f, 0x00, @@ -236,7 +236,7 @@ static const char moz_not_allowed_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* MOZ_CURSOR_SPINNING */ -static const char moz_spinning_bits[] = { +static const unsigned char moz_spinning_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, @@ -249,7 +249,7 @@ static const char moz_spinning_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const char moz_spinning_mask_bits[] = { +static const unsigned char moz_spinning_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x3b, 0x00, 0x00, @@ -263,7 +263,7 @@ static const char moz_spinning_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* MOZ_CURSOR_NONE */ -static const char moz_none_bits[] = { +static const unsigned char moz_none_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -276,7 +276,7 @@ static const char moz_none_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const char moz_none_mask_bits[] = { +static const unsigned char moz_none_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -290,7 +290,7 @@ static const char moz_none_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* MOZ_CURSOR_HAND_GRAB */ -static const char moz_hand_grab_bits[] = { +static const unsigned char moz_hand_grab_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x60, 0x39, 0x00, 0x00, 0x90, 0x49, 0x00, 0x00, 0x90, 0x49, 0x01, 0x00, 0x20, 0xc9, 0x02, 0x00, 0x20, 0x49, 0x02, 0x00, 0x58, 0x40, 0x02, 0x00, @@ -303,7 +303,7 @@ static const char moz_hand_grab_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const char moz_hand_grab_mask_bits[] = { +static const unsigned char moz_hand_grab_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x60, 0x3f, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, @@ -317,7 +317,7 @@ static const char moz_hand_grab_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* MOZ_CURSOR_HAND_GRABBING */ -static const char moz_hand_grabbing_bits[] = { +static const unsigned char moz_hand_grabbing_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x36, 0x00, 0x00, 0x20, 0xc9, 0x00, 0x00, 0x20, 0x40, 0x01, 0x00, @@ -330,7 +330,7 @@ static const char moz_hand_grabbing_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const char moz_hand_grabbing_mask_bits[] = { +static const unsigned char moz_hand_grabbing_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x36, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x03, 0x00, @@ -359,8 +359,8 @@ enum CustomCursorType { typedef struct { const char* name; - const char* bits; - const char* mask_bits; + const unsigned char* bits; + const unsigned char* mask_bits; int hot_x; int hot_y; } CustomCursor; @@ -374,7 +374,7 @@ static const CustomCursor CustomCursors[] = { { "zoom-out", moz_zoom_out_bits, moz_zoom_out_mask_bits, 6, 6 }, { "vertical-text", moz_vertical_text_bits, moz_vertical_text_mask_bits, 8, 4 }, { "dnd-no-drop", moz_not_allowed_bits, moz_not_allowed_mask_bits, 9, 9 }, - { "progress", moz_spinning_bits, moz_spinning_mask_bits, 2, 2}, + { "left_ptr_watch", moz_spinning_bits, moz_spinning_mask_bits, 2, 2}, { "none", moz_none_bits, moz_none_mask_bits, 0, 0 }, { "grab", moz_hand_grab_bits, moz_hand_grab_mask_bits, 10, 10 }, { "grabbing", moz_hand_grabbing_bits, moz_hand_grabbing_mask_bits, 10, 10 } diff --git a/WebCore/platform/gtk/DataObjectGtk.h b/WebCore/platform/gtk/DataObjectGtk.h index a7d8baf..6f7149c 100644 --- a/WebCore/platform/gtk/DataObjectGtk.h +++ b/WebCore/platform/gtk/DataObjectGtk.h @@ -73,8 +73,8 @@ private: String m_text; String m_markup; Vector<KURL> m_uriList; - GRefPtr<GdkPixbuf> m_image; - GRefPtr<GdkDragContext> m_dragContext; + PlatformRefPtr<GdkPixbuf> m_image; + PlatformRefPtr<GdkDragContext> m_dragContext; RefPtr<Range> m_range; }; diff --git a/WebCore/platform/gtk/GRefPtrGtk.cpp b/WebCore/platform/gtk/GRefPtrGtk.cpp index 6647b99..83129cc 100644 --- a/WebCore/platform/gtk/GRefPtrGtk.cpp +++ b/WebCore/platform/gtk/GRefPtrGtk.cpp @@ -25,27 +25,27 @@ namespace WTF { -template <> GtkTargetList* refGPtr(GtkTargetList* ptr) +template <> GtkTargetList* refPlatformPtr(GtkTargetList* ptr) { if (ptr) gtk_target_list_ref(ptr); return ptr; } -template <> void derefGPtr(GtkTargetList* ptr) +template <> void derefPlatformPtr(GtkTargetList* ptr) { if (ptr) gtk_target_list_unref(ptr); } -template <> GdkCursor* refGPtr(GdkCursor* ptr) +template <> GdkCursor* refPlatformPtr(GdkCursor* ptr) { if (ptr) gdk_cursor_ref(ptr); return ptr; } -template <> void derefGPtr(GdkCursor* ptr) +template <> void derefPlatformPtr(GdkCursor* ptr) { if (ptr) gdk_cursor_unref(ptr); diff --git a/WebCore/platform/gtk/GRefPtrGtk.h b/WebCore/platform/gtk/GRefPtrGtk.h index 77941f5..ea1b089 100644 --- a/WebCore/platform/gtk/GRefPtrGtk.h +++ b/WebCore/platform/gtk/GRefPtrGtk.h @@ -28,11 +28,11 @@ typedef struct _GdkCursor GdkCursor; namespace WTF { -template <> GtkTargetList* refGPtr(GtkTargetList* ptr); -template <> void derefGPtr(GtkTargetList* ptr); +template <> GtkTargetList* refPlatformPtr(GtkTargetList* ptr); +template <> void derefPlatformPtr(GtkTargetList* ptr); -template <> GdkCursor* refGPtr(GdkCursor* ptr); -template <> void derefGPtr(GdkCursor* ptr); +template <> GdkCursor* refPlatformPtr(GdkCursor* ptr); +template <> void derefPlatformPtr(GdkCursor* ptr); } diff --git a/WebCore/platform/gtk/GtkVersioning.h b/WebCore/platform/gtk/GtkVersioning.h index 6b45228..34e6081 100644 --- a/WebCore/platform/gtk/GtkVersioning.h +++ b/WebCore/platform/gtk/GtkVersioning.h @@ -47,6 +47,8 @@ #define gtk_widget_set_visible(widget, FALSE) GTK_WIDGET_UNSET_FLAGS((widget), GTK_VISIBLE) #define gtk_widget_set_window(widget, new_window) (widget)->window = (new_window) #define gtk_widget_set_can_focus(widget, TRUE) GTK_WIDGET_SET_FLAGS((widget), GTK_CAN_FOCUS) +#define gtk_widget_get_allocation(widget, alloc) (*(alloc) = (widget)->allocation) +#define gtk_widget_set_allocation(widget, alloc) ((widget)->allocation = *(alloc)) #endif // GTK_CHECK_VERSION(2, 18, 0) #if !GTK_CHECK_VERSION(2, 14, 0) diff --git a/WebCore/platform/gtk/PasteboardGtk.cpp b/WebCore/platform/gtk/PasteboardGtk.cpp index a0069cf..ddb9768 100644 --- a/WebCore/platform/gtk/PasteboardGtk.cpp +++ b/WebCore/platform/gtk/PasteboardGtk.cpp @@ -103,7 +103,7 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String&) Image* image = cachedImage->image(); ASSERT(image); - GRefPtr<GdkPixbuf> pixbuf = adoptGRef(image->getGdkPixbuf()); + PlatformRefPtr<GdkPixbuf> pixbuf = adoptPlatformRef(image->getGdkPixbuf()); DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard); dataObject->setImage(pixbuf.get()); m_helper->writeClipboardContents(clipboard); diff --git a/WebCore/platform/gtk/PasteboardHelper.cpp b/WebCore/platform/gtk/PasteboardHelper.cpp index 2babe91..95df25f 100644 --- a/WebCore/platform/gtk/PasteboardHelper.cpp +++ b/WebCore/platform/gtk/PasteboardHelper.cpp @@ -245,7 +245,7 @@ Vector<GdkAtom> PasteboardHelper::dropAtomsForContext(GtkWidget* widget, GdkDrag dropAtoms.append(netscapeURLAtom); // For images, try to find the most applicable image type. - GRefPtr<GtkTargetList> list(gtk_target_list_new(0, 0)); + PlatformRefPtr<GtkTargetList> list(gtk_target_list_new(0, 0)); gtk_target_list_add_image_targets(list.get(), getIdForTargetType(TargetTypeImage), TRUE); GdkAtom atom = gtk_drag_dest_find_target(widget, context, list.get()); if (atom != GDK_NONE) diff --git a/WebCore/platform/gtk/PopupMenuGtk.h b/WebCore/platform/gtk/PopupMenuGtk.h index fb4e7dd..d63e6d9 100644 --- a/WebCore/platform/gtk/PopupMenuGtk.h +++ b/WebCore/platform/gtk/PopupMenuGtk.h @@ -58,7 +58,7 @@ private: PopupMenuClient* m_popupClient; IntPoint m_menuPosition; - GRefPtr<GtkMenu> m_popup; + PlatformRefPtr<GtkMenu> m_popup; HashMap<GtkWidget*, int> m_indexMap; }; diff --git a/WebCore/platform/gtk/RenderThemeGtk.cpp b/WebCore/platform/gtk/RenderThemeGtk.cpp index 36fccf0..5019f35 100644 --- a/WebCore/platform/gtk/RenderThemeGtk.cpp +++ b/WebCore/platform/gtk/RenderThemeGtk.cpp @@ -148,7 +148,7 @@ RenderThemeGtk::RenderThemeGtk() , m_pauseButton(0) , m_seekBackButton(0) , m_seekForwardButton(0) - , m_partsTable(adoptGRef(g_hash_table_new_full(0, 0, 0, g_free))) + , m_partsTable(adoptPlatformRef(g_hash_table_new_full(0, 0, 0, g_free))) { if (!mozGtkRefCount) { moz_gtk_init(); @@ -317,7 +317,7 @@ static bool paintMozillaGtkWidget(const RenderThemeGtk* theme, GtkThemeWidgetTyp else if (type == MOZ_GTK_CHECKBUTTON || type == MOZ_GTK_RADIOBUTTON) flags = theme->isChecked(o); - GRefPtr<GdkDrawable> drawable(i.context->gdkDrawable()); + PlatformRefPtr<GdkDrawable> drawable(i.context->gdkDrawable()); GdkRectangle paintRect, clipRect; if (drawable) { AffineTransform ctm = i.context->getCTM(); @@ -342,7 +342,7 @@ static bool paintMozillaGtkWidget(const RenderThemeGtk* theme, GtkThemeWidgetTyp // In some situations, like during print previews, this GraphicsContext is not // backed by a GdkDrawable. In those situations, we render onto a pixmap and then // copy the rendered data back to the GraphicsContext via Cairo. - drawable = adoptGRef(gdk_pixmap_new(0, rect.width(), rect.height(), gdk_visual_get_depth(gdk_visual_get_system()))); + drawable = adoptPlatformRef(gdk_pixmap_new(0, rect.width(), rect.height(), gdk_visual_get_depth(gdk_visual_get_system()))); paintRect = clipRect = IntRect(0, 0, rect.width(), rect.height()); } diff --git a/WebCore/platform/gtk/RenderThemeGtk.h b/WebCore/platform/gtk/RenderThemeGtk.h index 71338d4..b9c076d 100644 --- a/WebCore/platform/gtk/RenderThemeGtk.h +++ b/WebCore/platform/gtk/RenderThemeGtk.h @@ -190,7 +190,7 @@ private: RefPtr<Image> m_seekBackButton; RefPtr<Image> m_seekForwardButton; Page* m_page; - GRefPtr<GHashTable> m_partsTable; + PlatformRefPtr<GHashTable> m_partsTable; }; diff --git a/WebCore/platform/gtk/ScrollViewGtk.cpp b/WebCore/platform/gtk/ScrollViewGtk.cpp index 871a0bf..565123c 100644 --- a/WebCore/platform/gtk/ScrollViewGtk.cpp +++ b/WebCore/platform/gtk/ScrollViewGtk.cpp @@ -65,12 +65,20 @@ void ScrollView::platformDestroy() PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation) { - if (orientation == HorizontalScrollbar && m_horizontalAdjustment) - return ScrollbarGtk::createScrollbar(this, orientation, m_horizontalAdjustment); - else if (orientation == VerticalScrollbar && m_verticalAdjustment) - return ScrollbarGtk::createScrollbar(this, orientation, m_verticalAdjustment); - else + // If this is an interior frame scrollbar, we want to create a scrollbar without + // passing a GtkAdjustment. This will cause the Scrollbar to create a native GTK+ + // scrollbar. + if (parent()) return Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar); + + // If this is the main frame, we want to create a Scrollbar that does no painting + // and defers to our GtkAdjustment for all of its state. Note that the GtkAdjustment + // may be null here. + if (orientation == HorizontalScrollbar) + return ScrollbarGtk::createScrollbar(this, orientation, m_horizontalAdjustment); + + // VerticalScrollbar + return ScrollbarGtk::createScrollbar(this, orientation, m_verticalAdjustment); } /* diff --git a/WebCore/platform/gtk/ScrollbarGtk.cpp b/WebCore/platform/gtk/ScrollbarGtk.cpp index 3b86ec9..8a1c4fa 100644 --- a/WebCore/platform/gtk/ScrollbarGtk.cpp +++ b/WebCore/platform/gtk/ScrollbarGtk.cpp @@ -81,8 +81,10 @@ ScrollbarGtk::ScrollbarGtk(ScrollbarClient* client, ScrollbarOrientation orienta : Scrollbar(client, orientation, RegularScrollbar) , m_adjustment(adjustment) { - g_object_ref(m_adjustment); - g_signal_connect(m_adjustment, "value-changed", G_CALLBACK(ScrollbarGtk::gtkValueChanged), this); + if (m_adjustment) { + g_object_ref(m_adjustment); + g_signal_connect(m_adjustment, "value-changed", G_CALLBACK(ScrollbarGtk::gtkValueChanged), this); + } // We have nothing to show as we are solely operating on the GtkAdjustment resize(0, 0); @@ -104,8 +106,10 @@ void ScrollbarGtk::attachAdjustment(GtkAdjustment* adjustment) m_adjustment = adjustment; - g_object_ref(m_adjustment); - g_signal_connect(m_adjustment, "value-changed", G_CALLBACK(ScrollbarGtk::gtkValueChanged), this); + if (m_adjustment) { + g_object_ref(m_adjustment); + g_signal_connect(m_adjustment, "value-changed", G_CALLBACK(ScrollbarGtk::gtkValueChanged), this); + } updateThumbProportion(); updateThumbPosition(); @@ -156,12 +160,18 @@ void ScrollbarGtk::frameRectsChanged() void ScrollbarGtk::updateThumbPosition() { + if (!m_adjustment) + return; + if (gtk_adjustment_get_value(m_adjustment) != m_currentPos) gtk_adjustment_set_value(m_adjustment, m_currentPos); } void ScrollbarGtk::updateThumbProportion() { + if (!m_adjustment) + return; + gtk_adjustment_configure(m_adjustment, gtk_adjustment_get_value(m_adjustment), gtk_adjustment_get_lower(m_adjustment), diff --git a/WebCore/platform/gtk/gtk2drawing.c b/WebCore/platform/gtk/gtk2drawing.c index 80e2c2a..349bde0 100644 --- a/WebCore/platform/gtk/gtk2drawing.c +++ b/WebCore/platform/gtk/gtk2drawing.c @@ -732,6 +732,7 @@ ConvertGtkState(GtkWidgetState* state) return GTK_STATE_NORMAL; } +#ifdef GTK_API_VERSION_2 static gint TSOffsetStyleGCArray(GdkGC** gcs, gint xorigin, gint yorigin) { @@ -741,10 +742,12 @@ TSOffsetStyleGCArray(GdkGC** gcs, gint xorigin, gint yorigin) gdk_gc_set_ts_origin(gcs[i], xorigin, yorigin); return MOZ_GTK_SUCCESS; } +#endif static gint TSOffsetStyleGCs(GtkStyle* style, gint xorigin, gint yorigin) { +#ifdef GTK_API_VERSION_2 TSOffsetStyleGCArray(style->fg_gc, xorigin, yorigin); TSOffsetStyleGCArray(style->bg_gc, xorigin, yorigin); TSOffsetStyleGCArray(style->light_gc, xorigin, yorigin); @@ -754,6 +757,7 @@ TSOffsetStyleGCs(GtkStyle* style, gint xorigin, gint yorigin) TSOffsetStyleGCArray(style->base_gc, xorigin, yorigin); gdk_gc_set_ts_origin(style->black_gc, xorigin, yorigin); gdk_gc_set_ts_origin(style->white_gc, xorigin, yorigin); +#endif return MOZ_GTK_SUCCESS; } @@ -1094,6 +1098,34 @@ calculate_arrow_rect(GtkWidget* arrow, GdkRectangle* rect, } static gint +moz_gtk_scrolled_window_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state) +{ + GtkStateType state_type = ConvertGtkState(state); + GtkShadowType shadow_type = (state->active) ? GTK_SHADOW_IN : GTK_SHADOW_OUT; + GtkStyle* style; + GtkAllocation allocation; + GtkWidget* widget; + + ensure_scrolled_window_widget(); + widget = gParts->scrolledWindowWidget; + + gtk_widget_get_allocation(widget, &allocation); + allocation.x = rect->x; + allocation.y = rect->y; + allocation.width = rect->width; + allocation.height = rect->height; + gtk_widget_set_allocation(widget, &allocation); + + style = gtk_widget_get_style(widget); + TSOffsetStyleGCs(style, rect->x - 1, rect->y - 1); + gtk_paint_box(style, drawable, state_type, shadow_type, cliprect, + widget, "scrolled_window", rect->x - 1, rect->y - 1, + rect->width + 2, rect->height + 2); + return MOZ_GTK_SUCCESS; +} + +static gint moz_gtk_scrollbar_button_paint(GdkDrawable* drawable, GdkRectangle* rect, GdkRectangle* cliprect, GtkWidgetState* state, GtkScrollbarButtonFlags flags, @@ -1124,11 +1156,7 @@ moz_gtk_scrollbar_button_paint(GdkDrawable* drawable, GdkRectangle* rect, to determine where it should paint rounded corners on the buttons. We need to trick them into drawing the buttons the way we want them. */ -#if GTK_CHECK_VERSION(2, 18, 0) gtk_widget_get_allocation(scrollbar, &allocation); -#else - allocation = scrollbar->allocation; -#endif allocation.x = rect->x; allocation.y = rect->y; allocation.width = rect->width; @@ -1163,6 +1191,7 @@ moz_gtk_scrollbar_button_paint(GdkDrawable* drawable, GdkRectangle* rect, } } + gtk_widget_set_allocation(scrollbar, &allocation); style = gtk_widget_get_style(scrollbar); TSOffsetStyleGCs(style, rect->x, rect->y); @@ -1214,10 +1243,6 @@ moz_gtk_scrollbar_trough_paint(GtkThemeWidgetType widget, style = gtk_widget_get_style(GTK_WIDGET(scrollbar)); TSOffsetStyleGCs(style, rect->x, rect->y); - gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_ACTIVE, - cliprect, rect->x, rect->y, - rect->width, rect->height); - gtk_paint_box(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN, cliprect, GTK_WIDGET(scrollbar), "trough", rect->x, rect->y, rect->width, rect->height); @@ -1557,8 +1582,17 @@ moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect, if (theme_honors_transparency) { g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } else { +#ifndef GTK_API_VERSION_2 + cairo_t* cr = gdk_cairo_create(drawable); + gdk_cairo_set_source_color(cr, (const GdkColor*)&style->base[bg_state]); + cairo_pattern_set_extend (cairo_get_source(cr), CAIRO_EXTEND_REPEAT); + gdk_cairo_rectangle(cr, cliprect); + cairo_fill(cr); + cairo_destroy(cr); +#else gdk_draw_rectangle(drawable, style->base_gc[bg_state], TRUE, cliprect->x, cliprect->y, cliprect->width, cliprect->height); +#endif g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(FALSE)); } @@ -3047,6 +3081,7 @@ moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics) "trough_border", &metrics->trough_border, "stepper_size", &metrics->stepper_size, "stepper_spacing", &metrics->stepper_spacing, + "trough_under_steppers", &metrics->trough_under_steppers, NULL); metrics->min_slider_size = gtk_range_get_min_slider_size(GTK_RANGE(gParts->horizScrollbarWidget)); @@ -3109,6 +3144,9 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable, return moz_gtk_scrollbar_thumb_paint(widget, drawable, rect, cliprect, state, direction); break; + case MOZ_GTK_SCROLLED_WINDOW: + return moz_gtk_scrolled_window_paint(drawable, rect, cliprect, state); + break; case MOZ_GTK_SCALE_HORIZONTAL: case MOZ_GTK_SCALE_VERTICAL: return moz_gtk_scale_paint(drawable, rect, cliprect, state, diff --git a/WebCore/platform/gtk/gtkdrawing.h b/WebCore/platform/gtk/gtkdrawing.h index b5a7feb..9d06d5d 100644 --- a/WebCore/platform/gtk/gtkdrawing.h +++ b/WebCore/platform/gtk/gtkdrawing.h @@ -75,6 +75,7 @@ typedef struct { gint stepper_size; gint stepper_spacing; gint min_slider_size; + gboolean trough_under_steppers; } MozGtkScrollbarMetrics; typedef struct _GtkThemeParts { @@ -180,6 +181,8 @@ typedef enum { /* Paints the slider (thumb) of a GtkScrollbar. */ MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL, MOZ_GTK_SCROLLBAR_THUMB_VERTICAL, + /* Paints the background of a scrolled window */ + MOZ_GTK_SCROLLED_WINDOW, /* Paints a GtkScale. */ MOZ_GTK_SCALE_HORIZONTAL, MOZ_GTK_SCALE_VERTICAL, diff --git a/WebCore/platform/image-decoders/ImageDecoder.cpp b/WebCore/platform/image-decoders/ImageDecoder.cpp index 1946596..d4518fe 100644 --- a/WebCore/platform/image-decoders/ImageDecoder.cpp +++ b/WebCore/platform/image-decoders/ImageDecoder.cpp @@ -52,11 +52,15 @@ static unsigned copyFromSharedBuffer(char* buffer, unsigned bufferLength, const return bytesExtracted; } +<<<<<<< HEAD #if !OS(ANDROID) // This method requires BMPImageDecoder, PNGImageDecoder, ICOImageDecoder and // JPEGDecoder, which aren't used on Android, and which don't all compile. // TODO: Find a better fix. ImageDecoder* ImageDecoder::create(const SharedBuffer& data) +======= +ImageDecoder* ImageDecoder::create(const SharedBuffer& data, bool premultiplyAlpha) +>>>>>>> webkit.org at r66079 { // We need at least 4 bytes to figure out what kind of image we're dealing // with. @@ -68,24 +72,24 @@ ImageDecoder* ImageDecoder::create(const SharedBuffer& data) // GIFs begin with GIF8(7 or 9). if (strncmp(contents, "GIF8", 4) == 0) - return new GIFImageDecoder(); + return new GIFImageDecoder(premultiplyAlpha); // Test for PNG. if (!memcmp(contents, "\x89\x50\x4E\x47", 4)) - return new PNGImageDecoder(); + return new PNGImageDecoder(premultiplyAlpha); // JPEG if (!memcmp(contents, "\xFF\xD8\xFF", 3)) - return new JPEGImageDecoder(); + return new JPEGImageDecoder(premultiplyAlpha); // BMP if (strncmp(contents, "BM", 2) == 0) - return new BMPImageDecoder(); + return new BMPImageDecoder(premultiplyAlpha); // ICOs always begin with a 2-byte 0 followed by a 2-byte 1. // CURs begin with 2-byte 0 followed by 2-byte 2. if (!memcmp(contents, "\x00\x00\x01\x00", 4) || !memcmp(contents, "\x00\x00\x02\x00", 4)) - return new ICOImageDecoder(); + return new ICOImageDecoder(premultiplyAlpha); // Give up. We don't know what the heck this is. return 0; @@ -99,6 +103,7 @@ RGBA32Buffer::RGBA32Buffer() , m_status(FrameEmpty) , m_duration(0) , m_disposalMethod(DisposeNotSpecified) + , m_premultiplyAlpha(true) { } @@ -112,6 +117,7 @@ RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other) setStatus(other.status()); setDuration(other.duration()); setDisposalMethod(other.disposalMethod()); + setPremultiplyAlpha(other.premultiplyAlpha()); return *this; } diff --git a/WebCore/platform/image-decoders/ImageDecoder.h b/WebCore/platform/image-decoders/ImageDecoder.h index f32536c..4012168 100644 --- a/WebCore/platform/image-decoders/ImageDecoder.h +++ b/WebCore/platform/image-decoders/ImageDecoder.h @@ -124,12 +124,14 @@ namespace WebCore { FrameStatus status() const { return m_status; } unsigned duration() const { return m_duration; } FrameDisposalMethod disposalMethod() const { return m_disposalMethod; } + bool premultiplyAlpha() const { return m_premultiplyAlpha; } void setHasAlpha(bool alpha); void setRect(const IntRect& r) { m_rect = r; } void setStatus(FrameStatus status); void setDuration(unsigned duration) { m_duration = duration; } void setDisposalMethod(FrameDisposalMethod method) { m_disposalMethod = method; } + void setPremultiplyAlpha(bool premultiplyAlpha) { m_premultiplyAlpha = premultiplyAlpha; } inline void setRGBA(int x, int y, unsigned r, unsigned g, unsigned b, unsigned a) { @@ -151,7 +153,7 @@ namespace WebCore { #elif PLATFORM(QT) m_image = m_pixmap.toImage(); m_pixmap = QPixmap(); - return reinterpret_cast<QRgb*>(m_image.scanLine(y)) + x; + return reinterpret_cast_ptr<QRgb*>(m_image.scanLine(y)) + x; #else return m_bytes.data() + (y * width()) + x; #endif @@ -159,11 +161,10 @@ namespace WebCore { inline void setRGBA(PixelData* dest, unsigned r, unsigned g, unsigned b, unsigned a) { - // We store this data pre-multiplied. - if (a == 0) + if (m_premultiplyAlpha && !a) *dest = 0; else { - if (a < 255) { + if (m_premultiplyAlpha && a < 255) { float alphaPercent = a / 255.0f; r = static_cast<unsigned>(r * alphaPercent); g = static_cast<unsigned>(g * alphaPercent); @@ -202,6 +203,9 @@ namespace WebCore { FrameDisposalMethod m_disposalMethod; // What to do with this frame's data when // initializing the next frame. + bool m_premultiplyAlpha; + // Whether to premultiply alpha into R, G, B + // channels; by default it's true. }; // The ImageDecoder class represents a base class for specific image format @@ -215,8 +219,9 @@ namespace WebCore { // m_maxNumPixels. (Not supported by all image decoders yet) class ImageDecoder : public Noncopyable { public: - ImageDecoder() + ImageDecoder(bool premultiplyAlpha) : m_scaled(false) + , m_premultiplyAlpha(premultiplyAlpha) , m_sizeAvailable(false) , m_maxNumPixels(-1) , m_isAllDataReceived(false) @@ -229,7 +234,7 @@ namespace WebCore { // Factory function to create an ImageDecoder. Ports that subclass // ImageDecoder can provide their own implementation of this to avoid // needing to write a dedicated setData() implementation. - static ImageDecoder* create(const SharedBuffer& data); + static ImageDecoder* create(const SharedBuffer& data, bool premultiplyAlpha); // The the filename extension usually associated with an undecoded image // of this type. @@ -343,6 +348,7 @@ namespace WebCore { bool m_scaled; Vector<int> m_scaledColumns; Vector<int> m_scaledRows; + bool m_premultiplyAlpha; private: // Some code paths compute the size of the image as "width * height * 4" diff --git a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp index 901f60d..1c117a8 100644 --- a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp +++ b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp @@ -40,8 +40,9 @@ namespace WebCore { // don't pack). static const size_t sizeOfFileHeader = 14; -BMPImageDecoder::BMPImageDecoder() - : m_decodedOffset(0) +BMPImageDecoder::BMPImageDecoder(bool premultiplyAlpha) + : ImageDecoder(premultiplyAlpha) + , m_decodedOffset(0) { } @@ -68,8 +69,10 @@ RGBA32Buffer* BMPImageDecoder::frameBufferAtIndex(size_t index) if (index) return 0; - if (m_frameBufferCache.isEmpty()) + if (m_frameBufferCache.isEmpty()) { m_frameBufferCache.resize(1); + m_frameBufferCache.first().setPremultiplyAlpha(m_premultiplyAlpha); + } RGBA32Buffer* buffer = &m_frameBufferCache.first(); if (buffer->status() != RGBA32Buffer::FrameComplete) diff --git a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h index b08b32b..3996bf9 100644 --- a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h +++ b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h @@ -39,7 +39,7 @@ namespace WebCore { // This class decodes the BMP image format. class BMPImageDecoder : public ImageDecoder { public: - BMPImageDecoder(); + BMPImageDecoder(bool premultiplyAlpha); // ImageDecoder virtual String filenameExtension() const { return "bmp"; } diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp index ec16da7..a2397ee 100644 --- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp +++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp @@ -29,8 +29,9 @@ namespace WebCore { -GIFImageDecoder::GIFImageDecoder() - : m_alreadyScannedThisDataForFrameCount(true) +GIFImageDecoder::GIFImageDecoder(bool premultiplyAlpha) + : ImageDecoder(premultiplyAlpha) + , m_alreadyScannedThisDataForFrameCount(true) , m_repetitionCount(cAnimationLoopOnce) , m_readOffset(0) { @@ -83,6 +84,8 @@ size_t GIFImageDecoder::frameCount() reader.read((const unsigned char*)m_data->data(), m_data->size(), GIFFrameCountQuery, static_cast<unsigned>(-1)); m_alreadyScannedThisDataForFrameCount = true; m_frameBufferCache.resize(reader.images_count); + for (int i = 0; i < reader.images_count; ++i) + m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha); } return m_frameBufferCache.size(); diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.h b/WebCore/platform/image-decoders/gif/GIFImageDecoder.h index e0f8173..21c1c57 100644 --- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.h +++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.h @@ -36,7 +36,7 @@ namespace WebCore { // This class decodes the GIF image format. class GIFImageDecoder : public ImageDecoder { public: - GIFImageDecoder(); + GIFImageDecoder(bool premultiplyAlpha); virtual ~GIFImageDecoder(); enum GIFQuery { GIFFullQuery, GIFSizeQuery, GIFFrameCountQuery }; diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp b/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp index d667795..453efd2 100644 --- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp +++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp @@ -44,8 +44,9 @@ namespace WebCore { static const size_t sizeOfDirectory = 6; static const size_t sizeOfDirEntry = 16; -ICOImageDecoder::ICOImageDecoder() - : m_decodedOffset(0) +ICOImageDecoder::ICOImageDecoder(bool premultiplyAlpha) + : ImageDecoder(premultiplyAlpha) + , m_decodedOffset(0) { } @@ -96,8 +97,11 @@ bool ICOImageDecoder::setSize(unsigned width, unsigned height) size_t ICOImageDecoder::frameCount() { decode(0, true); - if (m_frameBufferCache.isEmpty()) + if (m_frameBufferCache.isEmpty()) { m_frameBufferCache.resize(m_dirEntries.size()); + for (size_t i = 0; i < m_dirEntries.size(); ++i) + m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha); + } // CAUTION: We must not resize m_frameBufferCache again after this, as // decodeAtIndex() may give a BMPImageReader a pointer to one of the // entries. @@ -197,7 +201,7 @@ bool ICOImageDecoder::decodeAtIndex(size_t index) } if (!m_pngDecoders[index]) { - m_pngDecoders[index].set(new PNGImageDecoder()); + m_pngDecoders[index].set(new PNGImageDecoder(m_premultiplyAlpha)); setDataForPNGDecoderAtIndex(index); } // Fail if the size the PNGImageDecoder calculated does not match the size diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h index 48024a2..e2ee9e3 100644 --- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h +++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h @@ -40,7 +40,7 @@ namespace WebCore { // This class decodes the ICO and CUR image formats. class ICOImageDecoder : public ImageDecoder { public: - ICOImageDecoder(); + ICOImageDecoder(bool premultiplyAlpha); virtual ~ICOImageDecoder(); // ImageDecoder diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp index 4911bc9..6c6c782 100644 --- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp +++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp @@ -361,7 +361,8 @@ void term_source(j_decompress_ptr jd) src->decoder->decoder()->jpegComplete(); } -JPEGImageDecoder::JPEGImageDecoder() +JPEGImageDecoder::JPEGImageDecoder(bool premultiplyAlpha) + : ImageDecoder(premultiplyAlpha) { } @@ -391,8 +392,10 @@ RGBA32Buffer* JPEGImageDecoder::frameBufferAtIndex(size_t index) if (index) return 0; - if (m_frameBufferCache.isEmpty()) + if (m_frameBufferCache.isEmpty()) { m_frameBufferCache.resize(1); + m_frameBufferCache[0].setPremultiplyAlpha(m_premultiplyAlpha); + } RGBA32Buffer& frame = m_frameBufferCache[0]; if (frame.status() != RGBA32Buffer::FrameComplete) diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h index 43b35fd..5047019 100644 --- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h +++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h @@ -37,7 +37,7 @@ namespace WebCore { // This class decodes the JPEG image format. class JPEGImageDecoder : public ImageDecoder { public: - JPEGImageDecoder(); + JPEGImageDecoder(bool premultiplyAlpha); virtual ~JPEGImageDecoder(); // ImageDecoder diff --git a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp index 8186f33..940e4c4 100644 --- a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp +++ b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp @@ -169,8 +169,9 @@ private: unsigned m_currentBufferSize; }; -PNGImageDecoder::PNGImageDecoder() - : m_doNothingOnFailure(false) +PNGImageDecoder::PNGImageDecoder(bool premultiplyAlpha) + : ImageDecoder(premultiplyAlpha) + , m_doNothingOnFailure(false) { } @@ -200,8 +201,10 @@ RGBA32Buffer* PNGImageDecoder::frameBufferAtIndex(size_t index) if (index) return 0; - if (m_frameBufferCache.isEmpty()) + if (m_frameBufferCache.isEmpty()) { m_frameBufferCache.resize(1); + m_frameBufferCache[0].setPremultiplyAlpha(m_premultiplyAlpha); + } RGBA32Buffer& frame = m_frameBufferCache[0]; if (frame.status() != RGBA32Buffer::FrameComplete) diff --git a/WebCore/platform/image-decoders/png/PNGImageDecoder.h b/WebCore/platform/image-decoders/png/PNGImageDecoder.h index 145fc4d..763b88f 100644 --- a/WebCore/platform/image-decoders/png/PNGImageDecoder.h +++ b/WebCore/platform/image-decoders/png/PNGImageDecoder.h @@ -36,7 +36,7 @@ namespace WebCore { // This class decodes the PNG image format. class PNGImageDecoder : public ImageDecoder { public: - PNGImageDecoder(); + PNGImageDecoder(bool premultiplyAlpha); virtual ~PNGImageDecoder(); // ImageDecoder diff --git a/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp b/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp index 928524a..c7e2114 100644 --- a/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp +++ b/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp @@ -36,6 +36,7 @@ RGBA32Buffer::RGBA32Buffer() : m_status(FrameEmpty) , m_duration(0) , m_disposalMethod(DisposeNotSpecified) + , m_premultiplyAlpha(true) { } @@ -52,6 +53,7 @@ RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other) setStatus(other.status()); setDuration(other.duration()); setDisposalMethod(other.disposalMethod()); + setPremultiplyAlpha(other.premultiplyAlpha()); return *this; } diff --git a/WebCore/platform/mock/SpeechInputClientMock.cpp b/WebCore/platform/mock/SpeechInputClientMock.cpp index c3d74d1..6b64942 100644 --- a/WebCore/platform/mock/SpeechInputClientMock.cpp +++ b/WebCore/platform/mock/SpeechInputClientMock.cpp @@ -50,7 +50,7 @@ void SpeechInputClientMock::setListener(SpeechInputListener* listener) m_listener = listener; } -bool SpeechInputClientMock::startRecognition(int requestId) +bool SpeechInputClientMock::startRecognition(int requestId, const IntRect&) { if (m_timer.isActive()) return false; diff --git a/WebCore/platform/mock/SpeechInputClientMock.h b/WebCore/platform/mock/SpeechInputClientMock.h index 7d5fda2..ce83d3b 100644 --- a/WebCore/platform/mock/SpeechInputClientMock.h +++ b/WebCore/platform/mock/SpeechInputClientMock.h @@ -50,7 +50,7 @@ public: // SpeechInputClient methods. void setListener(SpeechInputListener*); - bool startRecognition(int); + bool startRecognition(int, const IntRect&); void stopRecording(int); void cancelRecognition(int); diff --git a/WebCore/platform/network/BlobData.cpp b/WebCore/platform/network/BlobData.cpp index bb256d0..21e8917 100644 --- a/WebCore/platform/network/BlobData.cpp +++ b/WebCore/platform/network/BlobData.cpp @@ -64,6 +64,11 @@ void BlobData::appendData(const CString& data) m_items.append(BlobDataItem(data)); } +void BlobData::appendData(const CString& data, long long offset, long long length) +{ + m_items.append(BlobDataItem(data, offset, length)); +} + void BlobData::appendFile(const String& path) { m_items.append(BlobDataItem(path)); diff --git a/WebCore/platform/network/BlobData.h b/WebCore/platform/network/BlobData.h index 17cdfdd..13e3b9c 100644 --- a/WebCore/platform/network/BlobData.h +++ b/WebCore/platform/network/BlobData.h @@ -45,14 +45,15 @@ struct BlobDataItem { // Default constructor. BlobDataItem() - : offset(0) + : type(Data) + , offset(0) , length(toEndOfFile) , expectedModificationTime(doNotCheckFileChange) { } - // Constructor for String type. - BlobDataItem(const CString& data) + // Constructor for String type (complete string). + explicit BlobDataItem(const CString& data) : type(Data) , data(data) , offset(0) @@ -61,8 +62,18 @@ struct BlobDataItem { { } + // Constructor for String type (partial string). + BlobDataItem(const CString& data, long long offset, long long length) + : type(Data) + , data(data) + , offset(offset) + , length(length) + , expectedModificationTime(doNotCheckFileChange) + { + } + // Constructor for File type (complete file). - BlobDataItem(const String& path) + explicit BlobDataItem(const String& path) : type(File) , path(path) , offset(0) @@ -105,11 +116,8 @@ struct BlobDataItem { // For Blob type. KURL url; - // For File and Blob type. long long offset; long long length; - - // For File type only. double expectedModificationTime; }; @@ -140,8 +148,14 @@ public: void appendBlob(const KURL&, long long offset, long long length); private: + friend class BlobRegistryImpl; + friend class BlobStorageData; + BlobData() { } + // This is only exposed to BlobStorageData. + void appendData(const CString&, long long offset, long long length); + String m_contentType; String m_contentDisposition; BlobDataItemList m_items; diff --git a/WebCore/platform/network/BlobRegistry.h b/WebCore/platform/network/BlobRegistry.h index fcd7b1c..7e64233 100644 --- a/WebCore/platform/network/BlobRegistry.h +++ b/WebCore/platform/network/BlobRegistry.h @@ -38,6 +38,7 @@ namespace WebCore { class BlobData; +class BlobRegistry; class KURL; class ResourceError; class ResourceHandle; @@ -45,17 +46,23 @@ class ResourceHandleClient; class ResourceRequest; class ResourceResponse; +// Returns a single instance of BlobRegistry. +BlobRegistry& blobRegistry(); + // BlobRegistry is not thread-safe. It should only be called from main thread. class BlobRegistry { public: - static BlobRegistry& instance(); - + // Registers a blob URL referring to the specified blob data. virtual void registerBlobURL(const KURL&, PassOwnPtr<BlobData>) = 0; + + // Registers a blob URL referring to the blob data identified by the specified srcURL. virtual void registerBlobURL(const KURL&, const KURL& srcURL) = 0; + virtual void unregisterBlobURL(const KURL&) = 0; virtual PassRefPtr<ResourceHandle> createResourceHandle(const ResourceRequest&, ResourceHandleClient*) = 0; virtual bool loadResourceSynchronously(const ResourceRequest&, ResourceError&, ResourceResponse&, Vector<char>& data) = 0; +protected: virtual ~BlobRegistry() { } }; diff --git a/WebCore/platform/network/BlobRegistryImpl.cpp b/WebCore/platform/network/BlobRegistryImpl.cpp index bbbb8f0..ee872e6 100644 --- a/WebCore/platform/network/BlobRegistryImpl.cpp +++ b/WebCore/platform/network/BlobRegistryImpl.cpp @@ -32,9 +32,6 @@ #include "BlobRegistryImpl.h" -#include "FileStream.h" -#include "FileStreamProxy.h" -#include "FileSystem.h" #include "ResourceError.h" #include "ResourceHandle.h" #include "ResourceLoader.h" @@ -45,6 +42,15 @@ namespace WebCore { +#if !PLATFORM(CHROMIUM) +BlobRegistry& blobRegistry() +{ + ASSERT(isMainThread()); + DEFINE_STATIC_LOCAL(BlobRegistryImpl, instance, ()); + return instance; +} +#endif + bool BlobRegistryImpl::shouldLoadResource(const ResourceRequest& request) const { // If the resource is not fetched using the GET method, bail out. @@ -72,30 +78,23 @@ bool BlobRegistryImpl::loadResourceSynchronously(const ResourceRequest& request, return false; } -BlobRegistry& BlobRegistry::instance() -{ - ASSERT(isMainThread()); - DEFINE_STATIC_LOCAL(BlobRegistryImpl, instance, ()); - return instance; -} - -void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobStorageDataItemList& items) +void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobDataItemList& items) { - for (BlobStorageDataItemList::const_iterator iter = items.begin(); iter != items.end(); ++iter) { - if (iter->type == BlobStorageDataItem::Data) - blobStorageData->appendData(iter->data, iter->offset, iter->length); + for (BlobDataItemList::const_iterator iter = items.begin(); iter != items.end(); ++iter) { + if (iter->type == BlobDataItem::Data) + blobStorageData->m_data.appendData(iter->data, iter->offset, iter->length); else { - ASSERT(iter->type == BlobStorageDataItem::File); - blobStorageData->appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime); + ASSERT(iter->type == BlobDataItem::File); + blobStorageData->m_data.appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime); } } } -void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobStorageDataItemList& items, long long offset, long long length) +void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobDataItemList& items, long long offset, long long length) { ASSERT(length != BlobDataItem::toEndOfFile); - BlobStorageDataItemList::const_iterator iter = items.begin(); + BlobDataItemList::const_iterator iter = items.begin(); if (offset) { for (; iter != items.end(); ++iter) { if (offset >= iter->length) @@ -108,12 +107,13 @@ void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, cons for (; iter != items.end() && length > 0; ++iter) { long long currentLength = iter->length - offset; long long newLength = currentLength > length ? length : currentLength; - if (iter->type == BlobStorageDataItem::Data) - blobStorageData->appendData(iter->data, iter->offset + offset, newLength); + if (iter->type == BlobDataItem::Data) + blobStorageData->m_data.appendData(iter->data, iter->offset + offset, newLength); else { - ASSERT(iter->type == BlobStorageDataItem::File); - blobStorageData->appendFile(iter->path, iter->offset + offset, newLength, iter->expectedModificationTime); + ASSERT(iter->type == BlobDataItem::File); + blobStorageData->m_data.appendFile(iter->path, iter->offset + offset, newLength, iter->expectedModificationTime); } + length -= newLength; offset = 0; } } @@ -122,17 +122,20 @@ void BlobRegistryImpl::registerBlobURL(const KURL& url, PassOwnPtr<BlobData> blo { ASSERT(isMainThread()); - RefPtr<BlobStorageData> blobStorageData = BlobStorageData::create(); - blobStorageData->setContentType(blobData->contentType()); - blobStorageData->setContentDisposition(blobData->contentDisposition()); + RefPtr<BlobStorageData> blobStorageData = BlobStorageData::create(blobData->contentType(), blobData->contentDisposition()); + + // The blob data is stored in the "canonical" way. That is, it only contains a list of Data and File items. + // 1) The Data item is denoted by the raw data and the range. + // 2) The File item is denoted by the file path, the range and the expected modification time. + // All the Blob items in the passing blob data are resolved and expanded into a set of Data and File items. for (BlobDataItemList::const_iterator iter = blobData->items().begin(); iter != blobData->items().end(); ++iter) { switch (iter->type) { case BlobDataItem::Data: - blobStorageData->appendData(iter->data, 0, iter->data.length()); + blobStorageData->m_data.appendData(iter->data, 0, iter->data.length()); break; case BlobDataItem::File: - blobStorageData->appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime); + blobStorageData->m_data.appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime); break; case BlobDataItem::Blob: if (m_blobs.contains(iter->url.string())) @@ -141,7 +144,6 @@ void BlobRegistryImpl::registerBlobURL(const KURL& url, PassOwnPtr<BlobData> blo } } - m_blobs.set(url.string(), blobStorageData); } @@ -154,9 +156,7 @@ void BlobRegistryImpl::registerBlobURL(const KURL& url, const KURL& srcURL) if (!src) return; - RefPtr<BlobStorageData> blobStorageData = BlobStorageData::create(); - blobStorageData->setContentType(src->contentType()); - blobStorageData->setContentDisposition(src->contentDisposition()); + RefPtr<BlobStorageData> blobStorageData = BlobStorageData::create(src->contentType(), src->contentDisposition()); appendStorageItems(blobStorageData.get(), src->items()); m_blobs.set(url.string(), blobStorageData); diff --git a/WebCore/platform/network/BlobRegistryImpl.h b/WebCore/platform/network/BlobRegistryImpl.h index 42693bc..f616664 100644 --- a/WebCore/platform/network/BlobRegistryImpl.h +++ b/WebCore/platform/network/BlobRegistryImpl.h @@ -63,8 +63,8 @@ public: private: bool shouldLoadResource(const ResourceRequest& request) const; - void appendStorageItems(BlobStorageData*, const BlobStorageDataItemList&); - void appendStorageItems(BlobStorageData*, const BlobStorageDataItemList&, long long offset, long long length); + void appendStorageItems(BlobStorageData*, const BlobDataItemList&); + void appendStorageItems(BlobStorageData*, const BlobDataItemList&, long long offset, long long length); HashMap<String, RefPtr<BlobStorageData> > m_blobs; }; diff --git a/WebCore/platform/network/BlobResourceHandle.cpp b/WebCore/platform/network/BlobResourceHandle.cpp new file mode 100644 index 0000000..63335f6 --- /dev/null +++ b/WebCore/platform/network/BlobResourceHandle.cpp @@ -0,0 +1,589 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(BLOB) + +#include "BlobResourceHandle.h" + +#include "AsyncFileStream.h" +#include "BlobRegistryImpl.h" +#include "FileStream.h" +#include "FileSystem.h" +#include "HTTPParsers.h" +#include "KURL.h" +#include "ResourceError.h" +#include "ResourceLoader.h" +#include "ResourceRequest.h" +#include "ResourceResponse.h" + +namespace WebCore { + +static const unsigned bufferSize = 1024; +static const int maxVectorLength = 0x7fffffff; +static const long long positionNotSpecified = -1; + +static const int httpOK = 200; +static const int httpPartialContent = 206; +static const int httpNotAllowed = 403; +static const int httpNotFound = 404; +static const int httpRequestedRangeNotSatisfiable = 416; +static const int httpInternalError = 500; +static const char* httpOKText = "OK"; +static const char* httpPartialContentText = "Partial Content"; +static const char* httpNotAllowedText = "Not Allowed"; +static const char* httpNotFoundText = "Not Found"; +static const char* httpRequestedRangeNotSatisfiableText = "Requested Range Not Satisfiable"; +static const char* httpInternalErrorText = "Internal Server Error"; + +static const int notFoundError = 1; +static const int securityError = 2; +static const int rangeError = 3; +static const int notReadableError = 4; + +/////////////////////////////////////////////////////////////////////////////// +// BlobResourceSynchronousLoader + +namespace { + +class BlobResourceSynchronousLoader : public ResourceHandleClient { +public: + BlobResourceSynchronousLoader(ResourceError&, ResourceResponse&, Vector<char>&); + + virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); + virtual void didReceiveData(ResourceHandle*, const char*, int, int /*lengthReceived*/); + virtual void didFinishLoading(ResourceHandle*); + virtual void didFail(ResourceHandle*, const ResourceError&); + +private: + ResourceError& m_error; + ResourceResponse& m_response; + Vector<char>& m_data; +}; + +BlobResourceSynchronousLoader::BlobResourceSynchronousLoader(ResourceError& error, ResourceResponse& response, Vector<char>& data) + : m_error(error) + , m_response(response) + , m_data(data) +{ +} + +void BlobResourceSynchronousLoader::didReceiveResponse(ResourceHandle* handle, const ResourceResponse& response) +{ + // We cannot handle the size that is more than maximum integer. + const int intMaxForLength = 0x7fffffff; + if (response.expectedContentLength() > intMaxForLength) { + m_error = ResourceError(String(), notReadableError, response.url(), String()); + return; + } + + m_response = response; + + // Read all the data. + m_data.resize(static_cast<size_t>(response.expectedContentLength())); + static_cast<BlobResourceHandle*>(handle)->readSync(m_data.data(), static_cast<int>(m_data.size())); +} + +void BlobResourceSynchronousLoader::didReceiveData(ResourceHandle*, const char*, int, int) +{ +} + +void BlobResourceSynchronousLoader::didFinishLoading(ResourceHandle*) +{ +} + +void BlobResourceSynchronousLoader::didFail(ResourceHandle*, const ResourceError& error) +{ + m_error = error; +} + +} + +/////////////////////////////////////////////////////////////////////////////// +// BlobResourceHandle + +// static +void BlobResourceHandle::loadResourceSynchronously(PassRefPtr<BlobStorageData> blobData, const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data) +{ + BlobResourceSynchronousLoader loader(error, response, data); + RefPtr<BlobResourceHandle> handle = BlobResourceHandle::create(blobData, request, &loader, false); + handle->start(); +} + +static void delayedStart(void* context) +{ + static_cast<BlobResourceHandle*>(context)->start(); +} + +BlobResourceHandle::BlobResourceHandle(PassRefPtr<BlobStorageData> blobData, const ResourceRequest& request, ResourceHandleClient* client, bool async) + : ResourceHandle(request, client, false, false) + , m_blobData(blobData) + , m_async(async) + , m_errorCode(0) + , m_aborted(false) + , m_rangeOffset(positionNotSpecified) + , m_rangeEnd(positionNotSpecified) + , m_rangeSuffixLength(positionNotSpecified) + , m_totalRemainingSize(0) + , m_currentItemReadSize(0) + , m_sizeItemCount(0) + , m_readItemCount(0) + , m_fileOpened(false) +{ + if (m_async) { + m_asyncStream = adoptRef(client->createAsyncFileStream(this)); + callOnMainThread(delayedStart, this); + } else + m_stream = FileStream::create(); +} + +BlobResourceHandle::~BlobResourceHandle() +{ + if (m_async) { + if (m_asyncStream) + m_asyncStream->stop(); + } else { + if (m_stream) + m_stream->stop(); + } +} + +void BlobResourceHandle::cancel() +{ + if (m_async) { + if (m_asyncStream) { + m_asyncStream->stop(); + m_asyncStream = 0; + } + } + + m_aborted = true; +} + +void BlobResourceHandle::start() +{ + // Do not continue if the request is aborted or an error occurs. + if (m_aborted || m_errorCode) + return; + + // If the blob data is not found, fail now. + if (!m_blobData) { + m_errorCode = notFoundError; + notifyResponse(); + return; + } + + // Parse the "Range" header we care about. + String range = firstRequest().httpHeaderField("Range"); + if (!range.isEmpty() && !parseRange(range, m_rangeOffset, m_rangeEnd, m_rangeSuffixLength)) { + m_errorCode = rangeError; + notifyResponse(); + return; + } + + if (m_async) + getSizeForNext(); + else { + for (size_t i = 0; i < m_blobData->items().size() && !m_aborted && !m_errorCode; ++i) + getSizeForNext(); + notifyResponse(); + } +} + +void BlobResourceHandle::getSizeForNext() +{ + // Do we finish validating and counting size for all items? + if (m_sizeItemCount >= m_blobData->items().size()) { + seek(); + + // Start reading if in asynchronous mode. + if (m_async) { + notifyResponse(); + m_buffer.resize(bufferSize); + readAsync(); + } + return; + } + + const BlobDataItem& item = m_blobData->items().at(m_sizeItemCount); + switch (item.type) { + case BlobDataItem::Data: + didGetSize(item.length); + break; + case BlobDataItem::File: + if (m_async) + m_asyncStream->getSize(item.path, item.expectedModificationTime); + else + didGetSize(m_stream->getSize(item.path, item.expectedModificationTime)); + break; + default: + ASSERT_NOT_REACHED(); + } +} + +void BlobResourceHandle::didGetSize(long long size) +{ + // Do not continue if the request is aborted or an error occurs. + if (m_aborted || m_errorCode) + return; + + // If the size is -1, it means the file has been moved or changed. Fail now. + if (size == -1) { + m_errorCode = notFoundError; + notifyResponse(); + return; + } + + // The size passed back is the size of the whole file. If the underlying item is a sliced file, we need to use the slice length. + const BlobDataItem& item = m_blobData->items().at(m_sizeItemCount); + if (item.type == BlobDataItem::File && item.length != BlobDataItem::toEndOfFile) + size = item.length; + + // Cache the size. + m_itemLengthList.append(size); + + // Count the size. + m_totalRemainingSize += size; + m_sizeItemCount++; + + // Continue with the next item. + getSizeForNext(); +} + +void BlobResourceHandle::seek() +{ + // Convert from the suffix length to the range. + if (m_rangeSuffixLength != positionNotSpecified) { + m_rangeOffset = m_totalRemainingSize - m_rangeSuffixLength; + m_rangeEnd = m_rangeOffset + m_rangeSuffixLength - 1; + } + + // Bail out if the range is not provided. + if (m_rangeOffset == positionNotSpecified) + return; + + // Skip the initial items that are not in the range. + long long offset = m_rangeOffset; + for (m_readItemCount = 0; m_readItemCount < m_blobData->items().size() && offset >= m_itemLengthList[m_readItemCount]; ++m_readItemCount) + offset -= m_itemLengthList[m_readItemCount]; + + // Set the offset that need to jump to for the first item in the range. + m_currentItemReadSize = offset; + + // Adjust the total remaining size in order not to go beyond the range. + if (m_rangeEnd != positionNotSpecified) { + long long rangeSize = m_rangeEnd - m_rangeOffset + 1; + if (m_totalRemainingSize > rangeSize) + m_totalRemainingSize = rangeSize; + } else + m_totalRemainingSize -= m_rangeOffset; +} + +int BlobResourceHandle::readSync(char* buf, int length) +{ + ASSERT(!m_async); + + int offset = 0; + int remaining = length; + while (remaining) { + // Do not continue if the request is aborted or an error occurs. + if (m_aborted || m_errorCode) + break; + + // If there is no more remaining data to read, we are done. + if (!m_totalRemainingSize || m_readItemCount >= m_blobData->items().size()) + break; + + const BlobDataItem& item = m_blobData->items().at(m_readItemCount); + int bytesRead = 0; + if (item.type == BlobDataItem::Data) + bytesRead = readDataSync(item, buf + offset, remaining); + else if (item.type == BlobDataItem::File) + bytesRead = readFileSync(item, buf + offset, remaining); + else + ASSERT_NOT_REACHED(); + + if (bytesRead > 0) { + offset += bytesRead; + remaining -= bytesRead; + } + } + + int result; + if (m_aborted || m_errorCode) + result = -1; + else + result = length - remaining; + + notifyReceiveData(buf, result); + if (!result) + notifyFinish(); + + return result; +} + +int BlobResourceHandle::readDataSync(const BlobDataItem& item, char* buf, int length) +{ + ASSERT(!m_async); + + long long remaining = item.length - m_currentItemReadSize; + int bytesToRead = (length > remaining) ? static_cast<int>(remaining) : length; + if (bytesToRead > m_totalRemainingSize) + bytesToRead = static_cast<int>(m_totalRemainingSize); + memcpy(buf, item.data.data() + item.offset + m_currentItemReadSize, bytesToRead); + m_totalRemainingSize -= bytesToRead; + + m_currentItemReadSize += bytesToRead; + if (m_currentItemReadSize == item.length) { + m_readItemCount++; + m_currentItemReadSize = 0; + } + + return bytesToRead; +} + +int BlobResourceHandle::readFileSync(const BlobDataItem& item, char* buf, int length) +{ + ASSERT(!m_async); + + if (!m_fileOpened) { + long long bytesToRead = m_itemLengthList[m_readItemCount] - m_currentItemReadSize; + if (bytesToRead > m_totalRemainingSize) + bytesToRead = m_totalRemainingSize; + bool success = m_stream->openForRead(item.path, item.offset + m_currentItemReadSize, bytesToRead); + m_currentItemReadSize = 0; + if (!success) { + m_errorCode = notReadableError; + return 0; + } + + m_fileOpened = true; + } + + int bytesRead = m_stream->read(buf, length); + if (bytesRead < 0) { + m_errorCode = notReadableError; + return 0; + } + if (!bytesRead) { + m_stream->close(); + m_fileOpened = false; + m_readItemCount++; + } else + m_totalRemainingSize -= bytesRead; + + return bytesRead; +} + +void BlobResourceHandle::readAsync() +{ + ASSERT(m_async); + + // Do not continue if the request is aborted or an error occurs. + if (m_aborted || m_errorCode) + return; + + // If there is no more remaining data to read, we are done. + if (!m_totalRemainingSize || m_readItemCount >= m_blobData->items().size()) { + notifyFinish(); + return; + } + + const BlobDataItem& item = m_blobData->items().at(m_readItemCount); + if (item.type == BlobDataItem::Data) + readDataAsync(item); + else if (item.type == BlobDataItem::File) + readFileAsync(item); + else + ASSERT_NOT_REACHED(); +} + +void BlobResourceHandle::readDataAsync(const BlobDataItem& item) +{ + ASSERT(m_async); + + long long bytesToRead = item.length - m_currentItemReadSize; + if (bytesToRead > m_totalRemainingSize) + bytesToRead = m_totalRemainingSize; + consumeData(item.data.data() + item.offset + m_currentItemReadSize, static_cast<int>(bytesToRead)); + m_currentItemReadSize = 0; +} + +void BlobResourceHandle::readFileAsync(const BlobDataItem& item) +{ + ASSERT(m_async); + + if (m_fileOpened) { + m_asyncStream->read(m_buffer.data(), m_buffer.size()); + return; + } + + long long bytesToRead = m_itemLengthList[m_readItemCount] - m_currentItemReadSize; + if (bytesToRead > m_totalRemainingSize) + bytesToRead = static_cast<int>(m_totalRemainingSize); + m_asyncStream->openForRead(item.path, item.offset + m_currentItemReadSize, bytesToRead); + m_fileOpened = true; + m_currentItemReadSize = 0; +} + +void BlobResourceHandle::didOpen(bool success) +{ + ASSERT(m_async); + + if (!success) { + failed(notReadableError); + return; + } + + // Continue the reading. + readAsync(); +} + +void BlobResourceHandle::didRead(int bytesRead) +{ + consumeData(m_buffer.data(), bytesRead); +} + +void BlobResourceHandle::consumeData(const char* data, int bytesRead) +{ + ASSERT(m_async); + + m_totalRemainingSize -= bytesRead; + + // Notify the client. + if (bytesRead) + notifyReceiveData(data, bytesRead); + + if (m_fileOpened) { + // When the current item is a file item, the reading is completed only if bytesRead is 0. + if (!bytesRead) { + // Close the file. + m_fileOpened = false; + m_asyncStream->close(); + + // Move to the next item. + m_readItemCount++; + } + } else { + // Otherwise, we read the current text item as a whole and move to the next item. + m_readItemCount++; + } + + // Continue the reading. + readAsync(); +} + +void BlobResourceHandle::failed(int errorCode) +{ + ASSERT(m_async); + + // Notify the client. + notifyFail(errorCode); + + // Close the file if needed. + if (m_fileOpened) { + m_fileOpened = false; + m_asyncStream->close(); + } +} + +void BlobResourceHandle::notifyResponse() +{ + if (!client()) + return; + + if (m_errorCode) { + notifyResponseOnError(); + notifyFinish(); + } else + notifyResponseOnSuccess(); +} + +void BlobResourceHandle::notifyResponseOnSuccess() +{ + bool isRangeRequest = m_rangeOffset != positionNotSpecified; + ResourceResponse response(firstRequest().url(), m_blobData->contentType(), m_totalRemainingSize, String(), String()); + response.setExpectedContentLength(m_totalRemainingSize); + response.setHTTPStatusCode(isRangeRequest ? httpPartialContent : httpOK); + response.setHTTPStatusText(isRangeRequest ? httpPartialContentText : httpOKText); + if (!m_blobData->contentDisposition().isEmpty()) + response.setHTTPHeaderField("Content-Disposition", m_blobData->contentDisposition()); + client()->didReceiveResponse(this, response); +} + +void BlobResourceHandle::notifyResponseOnError() +{ + ASSERT(m_errorCode); + + ResourceResponse response(firstRequest().url(), String(), 0, String(), String()); + switch (m_errorCode) { + case rangeError: + response.setHTTPStatusCode(httpRequestedRangeNotSatisfiable); + response.setHTTPStatusText(httpRequestedRangeNotSatisfiableText); + break; + case notFoundError: + response.setHTTPStatusCode(httpNotFound); + response.setHTTPStatusText(httpNotFoundText); + break; + case securityError: + response.setHTTPStatusCode(httpNotAllowed); + response.setHTTPStatusText(httpNotAllowedText); + break; + default: + response.setHTTPStatusCode(httpInternalError); + response.setHTTPStatusText(httpInternalErrorText); + break; + } + client()->didReceiveResponse(this, response); +} + +void BlobResourceHandle::notifyReceiveData(const char* data, int bytesRead) +{ + if (client()) + client()->didReceiveData(this, data, bytesRead, bytesRead); +} + +void BlobResourceHandle::notifyFail(int errorCode) +{ + if (client()) + client()->didFail(this, ResourceError(String(), errorCode, firstRequest().url(), String())); +} + +void BlobResourceHandle::notifyFinish() +{ + if (client()) + client()->didFinishLoading(this); +} + +} // namespace WebCore + +#endif // ENABLE(BLOB) + diff --git a/WebCore/platform/network/BlobResourceHandle.h b/WebCore/platform/network/BlobResourceHandle.h new file mode 100644 index 0000000..b2a0854 --- /dev/null +++ b/WebCore/platform/network/BlobResourceHandle.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BlobResourceHandle_h +#define BlobResourceHandle_h + +#if ENABLE(BLOB) + +#include "FileStreamClient.h" +#include "PlatformString.h" +#include "ResourceHandle.h" +#include <wtf/PassRefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class AsyncFileStream; +class BlobDataItem; +class BlobStorageData; +class FileStream; +class ResourceHandleClient; +class ResourceRequest; + +class BlobResourceHandle : public FileStreamClient, public ResourceHandle { +public: + static PassRefPtr<BlobResourceHandle> create(PassRefPtr<BlobStorageData> blobData, const ResourceRequest& request, ResourceHandleClient* client, bool async = true) + { + return adoptRef(new BlobResourceHandle(blobData, request, client, async)); + } + + static void loadResourceSynchronously(PassRefPtr<BlobStorageData> blobData, const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data); + + // FileStreamClient methods. + virtual void didGetSize(long long); + virtual void didOpen(bool); + virtual void didRead(int); + + // ResourceHandle methods. + virtual void cancel(); + + void start(); + int readSync(char*, int); + +private: + BlobResourceHandle(PassRefPtr<BlobStorageData>, const ResourceRequest&, ResourceHandleClient*, bool async); + virtual ~BlobResourceHandle(); + + void getSizeForNext(); + void seek(); + void consumeData(const char* data, int bytesRead); + void failed(int errorCode); + + void readAsync(); + void readDataAsync(const BlobDataItem&); + void readFileAsync(const BlobDataItem&); + + int readDataSync(const BlobDataItem&, char*, int); + int readFileSync(const BlobDataItem&, char*, int); + + void notifyResponse(); + void notifyResponseOnSuccess(); + void notifyResponseOnError(); + void notifyReceiveData(const char*, int); + void notifyFail(int errorCode); + void notifyFinish(); + + RefPtr<BlobStorageData> m_blobData; + bool m_async; + RefPtr<AsyncFileStream> m_asyncStream; // For asynchronous loading. + RefPtr<FileStream> m_stream; // For synchronous loading. + Vector<char> m_buffer; + Vector<long long> m_itemLengthList; + int m_errorCode; + bool m_aborted; + long long m_rangeOffset; + long long m_rangeEnd; + long long m_rangeSuffixLength; + long long m_totalRemainingSize; + long long m_currentItemReadSize; + unsigned m_sizeItemCount; + unsigned m_readItemCount; + bool m_fileOpened; +}; + +} // namespace WebCore + +#endif // ENABLE(BLOB) + +#endif // BlobResourceHandle_h diff --git a/WebCore/platform/network/BlobStorageData.h b/WebCore/platform/network/BlobStorageData.h index f4125a4..6535e62 100644 --- a/WebCore/platform/network/BlobStorageData.h +++ b/WebCore/platform/network/BlobStorageData.h @@ -31,76 +31,33 @@ #ifndef BlobStorageData_h #define BlobStorageData_h -#include "PlatformString.h" +#include "BlobData.h" #include <wtf/PassRefPtr.h> -#include <wtf/Vector.h> -#include <wtf/text/CString.h> +#include <wtf/RefCounted.h> namespace WebCore { -struct BlobStorageDataItem { - enum BlobStoreDataItemType { Data, File }; - BlobStoreDataItemType type; - long long offset; - long long length; - - // For string data. - CString data; - - // For file data. - String path; - double expectedModificationTime; - - BlobStorageDataItem(const CString& data, long long offset, long long length) - : type(Data) - , offset(offset) - , length(length) - , data(data) - , expectedModificationTime(0) - { - } - - BlobStorageDataItem(const String& path, long long offset, long long length, double expectedModificationTime) - : type(File) - , offset(offset) - , length(length) - , path(path) - , expectedModificationTime(expectedModificationTime) - { - } -}; - -typedef Vector<BlobStorageDataItem> BlobStorageDataItemList; - class BlobStorageData : public RefCounted<BlobStorageData> { public: - static PassRefPtr<BlobStorageData> create() + static PassRefPtr<BlobStorageData> create(const String& contentType, const String& contentDisposition) { - return adoptRef(new BlobStorageData()); + return adoptRef(new BlobStorageData(contentType, contentDisposition)); } - const String& contentType() const { return m_contentType; } - void setContentType(const String& contentType) { m_contentType = contentType; } - - const String& contentDisposition() const { return m_contentDisposition; } - void setContentDisposition(const String& contentDisposition) { m_contentDisposition = contentDisposition; } - - const BlobStorageDataItemList& items() const { return m_items; } + const String& contentType() const { return m_data.contentType(); } + const String& contentDisposition() const { return m_data.contentDisposition(); } + const BlobDataItemList& items() const { return m_data.items(); } - void appendData(const CString& data, long long offset, long long length) - { - m_items.append(BlobStorageDataItem(data, offset, length)); - } +private: + friend class BlobRegistryImpl; - void appendFile(const String& path, long long offset, long long length, double expectedModificationTime) + BlobStorageData(const String& contentType, const String& contentDisposition) { - m_items.append(BlobStorageDataItem(path, offset, length, expectedModificationTime)); + m_data.setContentType(contentType); + m_data.setContentDisposition(contentDisposition); } -private: - String m_contentType; - String m_contentDisposition; - BlobStorageDataItemList m_items; + BlobData m_data; }; } // namespace WebCore diff --git a/WebCore/platform/network/CredentialStorage.cpp b/WebCore/platform/network/CredentialStorage.cpp index 4fb7799..38f71a4 100644 --- a/WebCore/platform/network/CredentialStorage.cpp +++ b/WebCore/platform/network/CredentialStorage.cpp @@ -79,7 +79,6 @@ static String protectionSpaceMapKeyFromURL(const KURL& url) ASSERT(index != notFound); directoryURL = directoryURL.substring(0, (index != directoryURLPathStart) ? index : directoryURLPathStart + 1); } - ASSERT(directoryURL.length() == directoryURLPathStart + 1 || directoryURL[directoryURL.length() - 1] != '/'); return directoryURL; } diff --git a/WebCore/platform/network/FormData.cpp b/WebCore/platform/network/FormData.cpp index 31506ea..4f2b365 100644 --- a/WebCore/platform/network/FormData.cpp +++ b/WebCore/platform/network/FormData.cpp @@ -139,6 +139,11 @@ PassRefPtr<FormData> FormData::deepCopy() const formData->m_elements.append(FormDataElement(e.m_filename, e.m_shouldGenerateFile)); #endif break; +#if ENABLE(BLOB) + case FormDataElement::encodedBlob: + formData->m_elements.append(FormDataElement(e.m_blobURL)); + break; +#endif } } return formData.release(); @@ -200,6 +205,11 @@ void FormData::appendFileRange(const String& filename, long long start, long lon { m_elements.append(FormDataElement(filename, start, length, expectedModificationTime, shouldGenerateFile)); } + +void FormData::appendBlob(const KURL& blobURL) +{ + m_elements.append(FormDataElement(blobURL)); +} #endif void FormData::appendKeyValuePairItems(const BlobItemList& items, const TextEncoding& encoding, bool isMultiPartForm, Document* document) diff --git a/WebCore/platform/network/FormData.h b/WebCore/platform/network/FormData.h index a1964e3..d7faa89 100644 --- a/WebCore/platform/network/FormData.h +++ b/WebCore/platform/network/FormData.h @@ -20,6 +20,7 @@ #ifndef FormData_h #define FormData_h +#include "KURL.h" #include "PlatformString.h" #include <wtf/Forward.h> #include <wtf/RefCounted.h> @@ -39,17 +40,25 @@ public: #if ENABLE(BLOB) FormDataElement(const String& filename, long long fileStart, long long fileLength, double expectedFileModificationTime, bool shouldGenerateFile) : m_type(encodedFile), m_filename(filename), m_fileStart(fileStart), m_fileLength(fileLength), m_expectedFileModificationTime(expectedFileModificationTime), m_shouldGenerateFile(shouldGenerateFile) { } + FormDataElement(const KURL& blobURL) : m_type(encodedBlob), m_blobURL(blobURL) { } #else FormDataElement(const String& filename, bool shouldGenerateFile) : m_type(encodedFile), m_filename(filename), m_shouldGenerateFile(shouldGenerateFile) { } #endif - enum { data, encodedFile } m_type; + enum { + data, + encodedFile +#if ENABLE(BLOB) + , encodedBlob +#endif + } m_type; Vector<char> m_data; String m_filename; #if ENABLE(BLOB) long long m_fileStart; long long m_fileLength; double m_expectedFileModificationTime; + KURL m_blobURL; #endif String m_generatedFilename; bool m_shouldGenerateFile; @@ -67,14 +76,16 @@ inline bool operator==(const FormDataElement& a, const FormDataElement& b) if (a.m_type != b.m_type) return false; - if (a.m_data != b.m_data) - return false; + if (a.m_type == FormDataElement::data) + return a.m_data == b.m_data; + if (a.m_type == FormDataElement::encodedFile) #if ENABLE(BLOB) - if (a.m_filename != b.m_filename || a.m_fileStart != b.m_fileStart || a.m_fileLength != b.m_fileLength || a.m_expectedFileModificationTime != b.m_expectedFileModificationTime) + return a.m_filename == b.m_filename && a.m_fileStart == b.m_fileStart && a.m_fileLength == b.m_fileLength && a.m_expectedFileModificationTime == b.m_expectedFileModificationTime; + if (a.m_type == FormDataElement::encodedBlob) + return a.m_blobURL == b.m_blobURL; #else - if (a.m_filename != b.m_filename) + return a.m_filename == b.m_filename; #endif - return false; return true; } @@ -101,6 +112,7 @@ public: void appendFile(const String& filename, bool shouldGenerateFile = false); #if ENABLE(BLOB) void appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime, bool shouldGenerateFile = false); + void appendBlob(const KURL& blobURL); #endif void flatten(Vector<char>&) const; // omits files diff --git a/WebCore/platform/network/HTTPParsers.cpp b/WebCore/platform/network/HTTPParsers.cpp index b3f3d45..a1ba9d3 100644 --- a/WebCore/platform/network/HTTPParsers.cpp +++ b/WebCore/platform/network/HTTPParsers.cpp @@ -315,4 +315,61 @@ String extractReasonPhraseFromHTTPStatusLine(const String& statusLine) return statusLine.substring(spacePos + 1); } +bool parseRange(const String& range, long long& rangeOffset, long long& rangeEnd, long long& rangeSuffixLength) +{ + // The format of "Range" header is defined in RFC 2616 Section 14.35.1. + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.1 + // We don't support multiple range requests. + + rangeOffset = rangeEnd = rangeSuffixLength = -1; + + // The "bytes" unit identifier should be present. + static const char bytesStart[] = "bytes="; + if (!range.startsWith(bytesStart, false)) + return false; + String byteRange = range.substring(sizeof(bytesStart) - 1); + + // The '-' character needs to be present. + int index = byteRange.find('-'); + if (index == -1) + return false; + + // If the '-' character is at the beginning, the suffix length, which specifies the last N bytes, is provided. + // Example: + // -500 + if (!index) { + String suffixLengthString = byteRange.substring(index + 1).stripWhiteSpace(); + bool ok; + long long value = suffixLengthString.toInt64Strict(&ok); + if (ok) + rangeSuffixLength = value; + return true; + } + + // Otherwise, the first-byte-position and the last-byte-position are provied. + // Examples: + // 0-499 + // 500- + String firstBytePosStr = byteRange.left(index).stripWhiteSpace(); + bool ok; + long long firstBytePos = firstBytePosStr.toInt64Strict(&ok); + if (!ok) + return false; + + String lastBytePosStr = byteRange.substring(index + 1).stripWhiteSpace(); + long long lastBytePos = -1; + if (!lastBytePosStr.isEmpty()) { + lastBytePos = lastBytePosStr.toInt64Strict(&ok); + if (!ok) + return false; + } + + if (firstBytePos < 0 || !(lastBytePos == -1 || lastBytePos >= firstBytePos)) + return false; + + rangeOffset = firstBytePos; + rangeEnd = lastBytePos; + return true; +} + } diff --git a/WebCore/platform/network/HTTPParsers.h b/WebCore/platform/network/HTTPParsers.h index 9d6971b..55b8c7b 100644 --- a/WebCore/platform/network/HTTPParsers.h +++ b/WebCore/platform/network/HTTPParsers.h @@ -59,6 +59,9 @@ void findCharsetInMediaType(const String& mediaType, unsigned int& charsetPos, u XSSProtectionDisposition parseXSSProtectionHeader(const String&); String extractReasonPhraseFromHTTPStatusLine(const String&); +// -1 could be set to one of the return parameters to indicate the value is not specified. +bool parseRange(const String&, long long& rangeOffset, long long& rangeEnd, long long& rangeSuffixLength); + } #endif diff --git a/WebCore/platform/network/ResourceHandle.cpp b/WebCore/platform/network/ResourceHandle.cpp index 0575523..2da1d77 100644 --- a/WebCore/platform/network/ResourceHandle.cpp +++ b/WebCore/platform/network/ResourceHandle.cpp @@ -27,6 +27,7 @@ #include "ResourceHandle.h" #include "ResourceHandleInternal.h" +#include "BlobRegistry.h" #include "DNS.h" #include "Logging.h" #include "ResourceHandleClient.h" @@ -54,6 +55,14 @@ ResourceHandle::ResourceHandle(const ResourceRequest& request, ResourceHandleCli PassRefPtr<ResourceHandle> ResourceHandle::create(const ResourceRequest& request, ResourceHandleClient* client, Frame* frame, bool defersLoading, bool shouldContentSniff) { +#if ENABLE(BLOB) + if (request.url().protocolIs("blob")) { + PassRefPtr<ResourceHandle> handle = blobRegistry().createResourceHandle(request, client); + if (handle) + return handle; + } +#endif + RefPtr<ResourceHandle> newHandle(adoptRef(new ResourceHandle(request, client, defersLoading, shouldContentSniff))); if (newHandle->d->m_scheduledFailureType != NoFailure) diff --git a/WebCore/platform/network/ResourceHandle.h b/WebCore/platform/network/ResourceHandle.h index 3dc38f8..1167715 100644 --- a/WebCore/platform/network/ResourceHandle.h +++ b/WebCore/platform/network/ResourceHandle.h @@ -98,9 +98,10 @@ class ResourceHandle : public RefCounted<ResourceHandle> , public AuthenticationClient #endif { -private: +protected: ResourceHandle(const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff); +private: enum FailureType { NoFailure, BlockedFailure, diff --git a/WebCore/platform/network/ResourceHandleClient.h b/WebCore/platform/network/ResourceHandleClient.h index 0098010..97c0f54 100644 --- a/WebCore/platform/network/ResourceHandleClient.h +++ b/WebCore/platform/network/ResourceHandleClient.h @@ -44,8 +44,10 @@ class NSCachedURLResponse; #endif namespace WebCore { + class AsyncFileStream; class AuthenticationChallenge; class Credential; + class FileStreamClient; class KURL; class ProtectionSpace; class ResourceHandle; @@ -92,6 +94,9 @@ namespace WebCore { #if USE(CFNETWORK) virtual bool shouldCacheResponse(ResourceHandle*, CFCachedURLResponseRef response) { return true; } #endif +#if ENABLE(BLOB) + virtual AsyncFileStream* createAsyncFileStream(FileStreamClient*) { return 0; } +#endif }; } diff --git a/WebCore/platform/network/ResourceHandleInternal.h b/WebCore/platform/network/ResourceHandleInternal.h index 7b6e960..24b00bf 100644 --- a/WebCore/platform/network/ResourceHandleInternal.h +++ b/WebCore/platform/network/ResourceHandleInternal.h @@ -92,7 +92,6 @@ namespace WebCore { , m_connection(0) #endif #if USE(WININET) - , m_fileHandle(INVALID_HANDLE_VALUE) , m_fileLoadTimer(loader, &ResourceHandle::fileLoadTimer) , m_resourceHandle(0) , m_secondaryHandle(0) @@ -170,7 +169,6 @@ namespace WebCore { bool m_needsSiteSpecificQuirks; #endif #if USE(WININET) - HANDLE m_fileHandle; Timer<ResourceHandle> m_fileLoadTimer; HINTERNET m_resourceHandle; HINTERNET m_secondaryHandle; diff --git a/WebCore/platform/network/mac/ResourceHandleMac.mm b/WebCore/platform/network/mac/ResourceHandleMac.mm index f7161ec..d014bb3 100644 --- a/WebCore/platform/network/mac/ResourceHandleMac.mm +++ b/WebCore/platform/network/mac/ResourceHandleMac.mm @@ -29,6 +29,7 @@ #import "AuthenticationChallenge.h" #import "AuthenticationMac.h" #import "Base64.h" +#import "BlobRegistry.h" #import "BlockExceptions.h" #import "CredentialStorage.h" #import "DocLoader.h" @@ -464,6 +465,12 @@ void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, S { LOG(Network, "ResourceHandle::loadResourceSynchronously:%@ allowStoredCredentials:%u", request.nsURLRequest(), storedCredentials); +#if ENABLE(BLOB) + if (request.url().protocolIs("blob")) + if (blobRegistry().loadResourceSynchronously(request, error, response, data)) + return; +#endif + NSError *nsError = nil; NSURLResponse *nsURLResponse = nil; NSData *result = nil; diff --git a/WebCore/platform/network/win/ResourceHandleWin.cpp b/WebCore/platform/network/win/ResourceHandleWin.cpp index 63c84a9..3dabd91 100644 --- a/WebCore/platform/network/win/ResourceHandleWin.cpp +++ b/WebCore/platform/network/win/ResourceHandleWin.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -63,6 +64,20 @@ static const ResourceHandleEventHandler messageHandlers[] = { &ResourceHandle::onRequestComplete }; +static String queryHTTPHeader(HINTERNET requestHandle, DWORD infoLevel) +{ + DWORD bufferSize = 0; + HttpQueryInfoW(requestHandle, infoLevel, 0, &bufferSize, 0); + + Vector<UChar> characters(bufferSize / sizeof(UChar)); + + if (!HttpQueryInfoW(requestHandle, infoLevel, characters.data(), &bufferSize, 0)) + return String(); + + characters.removeLast(); // Remove NullTermination. + return String::adopt(characters); +} + static int addToOutstandingJobs(ResourceHandle* job) { if (!jobIdMap) @@ -122,6 +137,49 @@ static void initializeOffScreenResourceHandleWindow() HWND_MESSAGE, 0, WebCore::instanceHandle(), 0); } + +class WebCoreSynchronousLoader : public ResourceHandleClient, public Noncopyable { +public: + WebCoreSynchronousLoader(ResourceError&, ResourceResponse&, Vector<char>&, const String& userAgent); + + virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); + virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived); + virtual void didFinishLoading(ResourceHandle*); + virtual void didFail(ResourceHandle*, const ResourceError&); + +private: + ResourceError& m_error; + ResourceResponse& m_response; + Vector<char>& m_data; +}; + +WebCoreSynchronousLoader::WebCoreSynchronousLoader(ResourceError& error, ResourceResponse& response, Vector<char>& data, const String& userAgent) + : m_error(error) + , m_response(response) + , m_data(data) +{ +} + +void WebCoreSynchronousLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response) +{ + m_response = response; +} + +void WebCoreSynchronousLoader::didReceiveData(ResourceHandle*, const char* data, int length, int) +{ + m_data.append(data, length); +} + +void WebCoreSynchronousLoader::didFinishLoading(ResourceHandle*) +{ +} + +void WebCoreSynchronousLoader::didFail(ResourceHandle*, const ResourceError& error) +{ + m_error = error; +} + + ResourceHandleInternal::~ResourceHandleInternal() { if (m_fileHandle != INVALID_HANDLE_VALUE) @@ -225,7 +283,6 @@ void ResourceHandle::onRequestComplete(LPARAM lParam) } HINTERNET handle = (request().httpMethod() == "POST") ? d->m_secondaryHandle : d->m_resourceHandle; - BOOL ok = FALSE; static const int bufferSize = 32768; char buffer[bufferSize]; @@ -234,11 +291,31 @@ void ResourceHandle::onRequestComplete(LPARAM lParam) buffers.lpvBuffer = buffer; buffers.dwBufferLength = bufferSize; - bool receivedAnyData = false; + BOOL ok = FALSE; while ((ok = InternetReadFileExA(handle, &buffers, IRF_NO_WAIT, (DWORD_PTR)this)) && buffers.dwBufferLength) { if (!hasReceivedResponse()) { setHasReceivedResponse(); ResourceResponse response; + response.setURL(firstRequest().url()); + + String httpStatusText = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_STATUS_TEXT); + if (!httpStatusText.isNull()) + response.setHTTPStatusText(httpStatusText); + + String httpStatusCode = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_STATUS_CODE); + if (!httpStatusCode.isNull()) + response.setHTTPStatusCode(httpStatusCode.toInt()); + + String httpContentLength = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_CONTENT_LENGTH); + if (!httpContentLength.isNull()) + response.setExpectedContentLength(httpContentLength.toInt()); + + String httpContentType = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_CONTENT_TYPE); + if (!httpContentType.isNull()) { + response.setMimeType(extractMIMETypeFromMediaType(httpContentType)); + response.setTextEncodingName(extractCharsetFromMediaType(httpContentType)); + } + client()->didReceiveResponse(this, response); } client()->didReceiveData(this, buffer, buffers.dwBufferLength, 0); @@ -333,20 +410,6 @@ bool ResourceHandle::start(Frame* frame) { ref(); if (request().url().isLocalFile()) { - String path = request().url().path(); - // windows does not enjoy a leading slash on paths - if (path[0] == '/') - path = path.substring(1); - // FIXME: This is wrong. Need to use wide version of this call. - d->m_fileHandle = CreateFileA(path.utf8().data(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - // FIXME: perhaps this error should be reported asynchronously for - // consistency. - if (d->m_fileHandle == INVALID_HANDLE_VALUE) { - delete this; - return false; - } - d->m_fileLoadTimer.startOneShot(0.0); return true; } else { @@ -409,9 +472,29 @@ bool ResourceHandle::start(Frame* frame) } } -void ResourceHandle::fileLoadTimer(Timer<ResourceHandle>* timer) +void ResourceHandle::fileLoadTimer(Timer<ResourceHandle>*) { + RefPtr<ResourceHandle> protector(this); + deref(); // balances ref in start + + String fileName = firstRequest().url().fileSystemPath(); + HANDLE fileHandle = CreateFileW(fileName.charactersWithNullTermination(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + + if (fileHandle == INVALID_HANDLE_VALUE) { + client()->didFail(this, ResourceError()); + return; + } + ResourceResponse response; + + int dotPos = fileName.reverseFind('.'); + int slashPos = fileName.reverseFind('/'); + + if (slashPos < dotPos && dotPos != -1) { + String ext = fileName.substring(dotPos + 1); + response.setMimeType(MIMETypeRegistry::getMIMETypeForExtension(ext)); + } + client()->didReceiveResponse(this, response); bool result = false; @@ -420,16 +503,13 @@ void ResourceHandle::fileLoadTimer(Timer<ResourceHandle>* timer) do { const int bufferSize = 8192; char buffer[bufferSize]; - result = ReadFile(d->m_fileHandle, &buffer, bufferSize, &bytesRead, NULL); + result = ReadFile(fileHandle, &buffer, bufferSize, &bytesRead, 0); if (result && bytesRead) client()->didReceiveData(this, buffer, bytesRead, 0); - // Check for end of file. + // Check for end of file. } while (result && bytesRead); - // FIXME: handle errors better - - CloseHandle(d->m_fileHandle); - d->m_fileHandle = INVALID_HANDLE_VALUE; + CloseHandle(fileHandle); client()->didFinishLoading(this); } @@ -449,6 +529,16 @@ void ResourceHandle::cancel() client()->didFail(this, ResourceError()); } +void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame* frame) +{ + UNUSED_PARAM(storedCredentials); + + WebCoreSynchronousLoader syncLoader(error, response, data, request.httpUserAgent()); + ResourceHandle handle(request, &syncLoader, true, false); + + handle.start(frame); +} + void ResourceHandle::setHasReceivedResponse(bool b) { d->m_hasReceivedResponse = b; @@ -459,4 +549,36 @@ bool ResourceHandle::hasReceivedResponse() const return d->m_hasReceivedResponse; } +bool ResourceHandle::willLoadFromCache(ResourceRequest&, Frame*) +{ + notImplemented(); + return false; +} + +void prefetchDNS(const String&) +{ + notImplemented(); +} + +PassRefPtr<SharedBuffer> ResourceHandle::bufferedData() +{ + ASSERT_NOT_REACHED(); + return 0; +} + +bool ResourceHandle::supportsBufferedData() +{ + return false; +} + +bool ResourceHandle::loadsBlocked() +{ + return false; +} + +void ResourceHandle::platformSetDefersLoading(bool) +{ + notImplemented(); +} + } // namespace WebCore diff --git a/WebCore/platform/qt/CursorQt.cpp b/WebCore/platform/qt/CursorQt.cpp index 6017daa..227b80c 100644 --- a/WebCore/platform/qt/CursorQt.cpp +++ b/WebCore/platform/qt/CursorQt.cpp @@ -3,6 +3,7 @@ * Copyright (C) 2006 George Staikos <staikos@kde.org> * Copyright (C) 2006 Charles Samuels <charles@kde.org> * Copyright (C) 2008, 2009 Holger Hans Peter Freyther + * Copyright (C) 2010 University of Szeged * * All rights reserved. * @@ -43,329 +44,166 @@ namespace WebCore { -Cursor::Cursor(PlatformCursor p) - : m_platformCursor(p) -{ -} - Cursor::Cursor(const Cursor& other) - : m_platformCursor(other.m_platformCursor) + : m_type(other.m_type) + , m_image(other.m_image) + , m_hotSpot(other.m_hotSpot) +#ifndef QT_NO_CURSOR + , m_platformCursor(other.m_platformCursor ? new QCursor(*other.m_platformCursor) : 0) +#endif { } Cursor::~Cursor() { -} - -Cursor::Cursor(Image* image, const IntPoint& hotSpot) -{ #ifndef QT_NO_CURSOR - IntPoint effectiveHotSpot = determineHotSpot(image, hotSpot); - m_platformCursor = QCursor(*(image->nativeImageForCurrentFrame()), effectiveHotSpot.x(), effectiveHotSpot.y()); + delete m_platformCursor; #endif } Cursor& Cursor::operator=(const Cursor& other) { - m_platformCursor = other.m_platformCursor; - return *this; -} - -namespace { - -// FIXME: static deleter -class Cursors : public Noncopyable { -protected: - Cursors() + m_type = other.m_type; + m_image = other.m_image; + m_hotSpot = other.m_hotSpot; #ifndef QT_NO_CURSOR - : CrossCursor(Qt::CrossCursor) - , MoveCursor(Qt::SizeAllCursor) - , PointerCursor(Qt::ArrowCursor) - , PointingHandCursor(Qt::PointingHandCursor) - , IBeamCursor(Qt::IBeamCursor) - , WaitCursor(Qt::WaitCursor) - , WhatsThisCursor(Qt::WhatsThisCursor) - , SizeHorCursor(Qt::SizeHorCursor) - , SizeVerCursor(Qt::SizeVerCursor) - , SizeFDiagCursor(Qt::SizeFDiagCursor) - , SizeBDiagCursor(Qt::SizeBDiagCursor) - , SplitHCursor(Qt::SplitHCursor) - , SplitVCursor(Qt::SplitVCursor) - , NoDropCursor(Qt::ForbiddenCursor) - , BlankCursor(Qt::BlankCursor) - , ZoomInCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/zoomInCursor.png")), 7, 7)) - , ZoomOutCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/zoomOutCursor.png")), 7, 7)) - , VerticalTextCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/verticalTextCursor.png")), 7, 7)) - , CellCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/cellCursor.png")), 7, 7)) - , ContextMenuCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/contextMenuCursor.png")), 3, 2)) - , CopyCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/copyCursor.png")), 3, 2)) - , ProgressCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/progressCursor.png")), 3, 2)) - , AliasCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/aliasCursor.png")), 11, 3)) - + m_platformCursor = other.m_platformCursor ? new QCursor(*other.m_platformCursor) : 0; #endif - { - } - - ~Cursors() - { - } - -public: - static Cursors* self(); - static Cursors* s_self; - - Cursor CrossCursor; - Cursor MoveCursor; - Cursor PointerCursor; - Cursor PointingHandCursor; - Cursor IBeamCursor; - Cursor WaitCursor; - Cursor WhatsThisCursor; - Cursor SizeHorCursor; - Cursor SizeVerCursor; - Cursor SizeFDiagCursor; - Cursor SizeBDiagCursor; - Cursor SplitHCursor; - Cursor SplitVCursor; - Cursor NoDropCursor; - Cursor BlankCursor; - Cursor ZoomInCursor; - Cursor ZoomOutCursor; - Cursor VerticalTextCursor; - Cursor CellCursor; - Cursor ContextMenuCursor; - Cursor CopyCursor; - Cursor ProgressCursor; - Cursor AliasCursor; -}; - -Cursors* Cursors::s_self = 0; - -Cursors* Cursors::self() -{ - if (!s_self) - s_self = new Cursors(); - - return s_self; -} - -} - -const Cursor& pointerCursor() -{ - return Cursors::self()->PointerCursor; -} - -const Cursor& moveCursor() -{ - return Cursors::self()->MoveCursor; -} - -const Cursor& crossCursor() -{ - return Cursors::self()->CrossCursor; -} - -const Cursor& handCursor() -{ - return Cursors::self()->PointingHandCursor; -} - -const Cursor& iBeamCursor() -{ - return Cursors::self()->IBeamCursor; -} - -const Cursor& waitCursor() -{ - return Cursors::self()->WaitCursor; -} - -const Cursor& helpCursor() -{ - return Cursors::self()->WhatsThisCursor; -} - -const Cursor& eastResizeCursor() -{ - return Cursors::self()->SizeHorCursor; -} - -const Cursor& northResizeCursor() -{ - return Cursors::self()->SizeVerCursor; -} - -const Cursor& northEastResizeCursor() -{ - return Cursors::self()->SizeBDiagCursor; -} - -const Cursor& northWestResizeCursor() -{ - return Cursors::self()->SizeFDiagCursor; -} - -const Cursor& southResizeCursor() -{ - return Cursors::self()->SizeVerCursor; -} - -const Cursor& southEastResizeCursor() -{ - return Cursors::self()->SizeFDiagCursor; -} - -const Cursor& southWestResizeCursor() -{ - return Cursors::self()->SizeBDiagCursor; -} - -const Cursor& westResizeCursor() -{ - return Cursors::self()->SizeHorCursor; -} - -const Cursor& northSouthResizeCursor() -{ - return Cursors::self()->SizeVerCursor; -} - -const Cursor& eastWestResizeCursor() -{ - return Cursors::self()->SizeHorCursor; -} - -const Cursor& northEastSouthWestResizeCursor() -{ - return Cursors::self()->SizeBDiagCursor; -} - -const Cursor& northWestSouthEastResizeCursor() -{ - return Cursors::self()->SizeFDiagCursor; -} - -const Cursor& columnResizeCursor() -{ - return Cursors::self()->SplitHCursor; -} - -const Cursor& rowResizeCursor() -{ - return Cursors::self()->SplitVCursor; -} - -const Cursor& middlePanningCursor() -{ - return moveCursor(); -} - -const Cursor& eastPanningCursor() -{ - return eastResizeCursor(); -} - -const Cursor& northPanningCursor() -{ - return northResizeCursor(); -} - -const Cursor& northEastPanningCursor() -{ - return northEastResizeCursor(); -} - -const Cursor& northWestPanningCursor() -{ - return northWestResizeCursor(); -} - -const Cursor& southPanningCursor() -{ - return southResizeCursor(); -} - -const Cursor& southEastPanningCursor() -{ - return southEastResizeCursor(); -} - -const Cursor& southWestPanningCursor() -{ - return southWestResizeCursor(); -} - -const Cursor& westPanningCursor() -{ - return westResizeCursor(); -} - -const Cursor& verticalTextCursor() -{ - return Cursors::self()->VerticalTextCursor; -} - -const Cursor& cellCursor() -{ - return Cursors::self()->CellCursor; -} - -const Cursor& contextMenuCursor() -{ - return Cursors::self()->ContextMenuCursor; -} - -const Cursor& noDropCursor() -{ - return Cursors::self()->NoDropCursor; -} - -const Cursor& copyCursor() -{ - return Cursors::self()->CopyCursor; -} - -const Cursor& progressCursor() -{ - return Cursors::self()->ProgressCursor; -} - -const Cursor& aliasCursor() -{ - return Cursors::self()->AliasCursor; -} - -const Cursor& noneCursor() -{ - return Cursors::self()->BlankCursor; -} - -const Cursor& notAllowedCursor() -{ - return Cursors::self()->NoDropCursor; -} - -const Cursor& zoomInCursor() -{ - return Cursors::self()->ZoomInCursor; -} - -const Cursor& zoomOutCursor() -{ - return Cursors::self()->ZoomOutCursor; + return *this; } -const Cursor& grabCursor() +static QCursor* createCustomCursor(Image* image, const IntPoint& hotSpot) { - notImplemented(); - return Cursors::self()->PointerCursor; +#ifndef QT_NO_CURSOR + IntPoint effectiveHotSpot = determineHotSpot(image, hotSpot); + return new QCursor(*(image->nativeImageForCurrentFrame()), effectiveHotSpot.x(), effectiveHotSpot.y()); +#else + return 0; +#endif } -const Cursor& grabbingCursor() +void Cursor::ensurePlatformCursor() const { - notImplemented(); - return Cursors::self()->PointerCursor; +#ifndef QT_NO_CURSOR + if (m_platformCursor) + return; + + switch (m_type) { + case Pointer: + m_platformCursor = new QCursor(Qt::ArrowCursor); + break; + case Cross: + m_platformCursor = new QCursor(Qt::CrossCursor); + break; + case Hand: + m_platformCursor = new QCursor(Qt::PointingHandCursor); + break; + case IBeam: + m_platformCursor = new QCursor(Qt::IBeamCursor); + break; + case Wait: + m_platformCursor = new QCursor(Qt::WaitCursor); + break; + case Help: + m_platformCursor = new QCursor(Qt::WhatsThisCursor); + break; + case EastResize: + case EastPanning: + m_platformCursor = new QCursor(Qt::SizeHorCursor); + break; + case NorthResize: + case NorthPanning: + m_platformCursor = new QCursor(Qt::SizeVerCursor); + break; + case NorthEastResize: + case NorthEastPanning: + m_platformCursor = new QCursor(Qt::SizeBDiagCursor); + break; + case NorthWestResize: + case NorthWestPanning: + m_platformCursor = new QCursor(Qt::SizeFDiagCursor); + break; + case SouthResize: + case SouthPanning: + m_platformCursor = new QCursor(Qt::SizeVerCursor); + break; + case SouthEastResize: + case SouthEastPanning: + m_platformCursor = new QCursor(Qt::SizeFDiagCursor); + break; + case SouthWestResize: + case SouthWestPanning: + m_platformCursor = new QCursor(Qt::SizeBDiagCursor); + break; + case WestResize: + case WestPanning: + m_platformCursor = new QCursor(Qt::SizeHorCursor); + break; + case NorthSouthResize: + m_platformCursor = new QCursor(Qt::SizeVerCursor); + break; + case EastWestResize: + m_platformCursor = new QCursor(Qt::SizeHorCursor); + break; + case NorthEastSouthWestResize: + m_platformCursor = new QCursor(Qt::SizeBDiagCursor); + break; + case NorthWestSouthEastResize: + m_platformCursor = new QCursor(Qt::SizeFDiagCursor); + break; + case ColumnResize: + m_platformCursor = new QCursor(Qt::SplitHCursor); + break; + case RowResize: + m_platformCursor = new QCursor(Qt::SplitVCursor); + break; + case MiddlePanning: + case Move: + m_platformCursor = new QCursor(Qt::SizeAllCursor); + break; + case None: + m_platformCursor = new QCursor(Qt::BlankCursor); + break; + case NoDrop: + case NotAllowed: + m_platformCursor = new QCursor(Qt::ForbiddenCursor); + break; + case Grab: + case Grabbing: + notImplemented(); + m_platformCursor = new QCursor(Qt::ArrowCursor); + break; + case VerticalText: + m_platformCursor = new QCursor(QPixmap(QLatin1String(":/webkit/resources/verticalTextCursor.png")), 7, 7); + break; + case Cell: + m_platformCursor = new QCursor(QPixmap(QLatin1String(":/webkit/resources/cellCursor.png")), 7, 7); + break; + case ContextMenu: + m_platformCursor = new QCursor(QPixmap(QLatin1String(":/webkit/resources/contextMenuCursor.png")), 3, 2); + break; + case Alias: + m_platformCursor = new QCursor(QPixmap(QLatin1String(":/webkit/resources/aliasCursor.png")), 11, 3); + break; + case Progress: + m_platformCursor = new QCursor(QPixmap(QLatin1String(":/webkit/resources/progressCursor.png")), 3, 2); + break; + case Copy: + m_platformCursor = new QCursor(QPixmap(QLatin1String(":/webkit/resources/copyCursor.png")), 3, 2); + break; + case ZoomIn: + m_platformCursor = new QCursor(QPixmap(QLatin1String(":/webkit/resources/zoomInCursor.png")), 7, 7); + break; + case ZoomOut: + m_platformCursor = new QCursor(QPixmap(QLatin1String(":/webkit/resources/zoomOutCursor.png")), 7, 7); + break; + case Custom: + m_platformCursor = createCustomCursor(m_image.get(), m_hotSpot); + break; + default: + ASSERT_NOT_REACHED(); + } +#endif } } diff --git a/WebCore/platform/qt/PasteboardQt.cpp b/WebCore/platform/qt/PasteboardQt.cpp index e1e6d84..fc53124 100644 --- a/WebCore/platform/qt/PasteboardQt.cpp +++ b/WebCore/platform/qt/PasteboardQt.cpp @@ -65,10 +65,7 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, text.replace(QChar(0xa0), QLatin1Char(' ')); md->setText(text); - QString html = QLatin1String("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /></head><body>"); - html += createMarkup(selectedRange, 0, AnnotateForInterchange, false, AbsoluteURLs); - html += QLatin1String("</body></html>"); - md->setHtml(html); + md->setHtml(createMarkup(selectedRange, 0, AnnotateForInterchange, false, AbsoluteURLs)); #ifndef QT_NO_CLIPBOARD QApplication::clipboard()->setMimeData(md, m_selectionMode ? diff --git a/WebCore/platform/qt/WidgetQt.cpp b/WebCore/platform/qt/WidgetQt.cpp index 0903b6e..e64d655 100644 --- a/WebCore/platform/qt/WidgetQt.cpp +++ b/WebCore/platform/qt/WidgetQt.cpp @@ -78,10 +78,10 @@ void Widget::setFocus(bool focused) void Widget::setCursor(const Cursor& cursor) { #ifndef QT_NO_CURSOR - QWebPageClient* pageClient = root()->hostWindow()->platformPageClient(); - - if (pageClient) - pageClient->setCursor(cursor.impl()); + ScrollView* view = root(); + if (!view) + return; + view->hostWindow()->setCursor(cursor); #endif } diff --git a/WebCore/platform/sql/SQLiteStatement.cpp b/WebCore/platform/sql/SQLiteStatement.cpp index 4dc80fb..037ec79 100644 --- a/WebCore/platform/sql/SQLiteStatement.cpp +++ b/WebCore/platform/sql/SQLiteStatement.cpp @@ -192,6 +192,14 @@ int SQLiteStatement::bindText(int index, const String& text) return sqlite3_bind_text16(m_statement, index, characters, sizeof(UChar) * text.length(), SQLITE_TRANSIENT); } +int SQLiteStatement::bindInt(int index, int integer) +{ + ASSERT(m_isPrepared); + ASSERT(index > 0); + ASSERT(static_cast<unsigned>(index) <= bindParameterCount()); + + return sqlite3_bind_int(m_statement, index, integer); +} int SQLiteStatement::bindInt64(int index, int64_t integer) { @@ -251,6 +259,18 @@ int SQLiteStatement::columnCount() return sqlite3_data_count(m_statement); } +bool SQLiteStatement::isColumnNull(int col) +{ + ASSERT(col >= 0); + if (!m_statement) + if (prepareAndStep() != SQLITE_ROW) + return false; + if (columnCount() <= col) + return false; + + return sqlite3_column_type(m_statement, col) == SQLITE_NULL; +} + String SQLiteStatement::getColumnName(int col) { ASSERT(col >= 0); diff --git a/WebCore/platform/sql/SQLiteStatement.h b/WebCore/platform/sql/SQLiteStatement.h index e62b4f0..1444f0e 100644 --- a/WebCore/platform/sql/SQLiteStatement.h +++ b/WebCore/platform/sql/SQLiteStatement.h @@ -42,6 +42,7 @@ public: int prepare(); int bindBlob(int index, const void* blob, int size); int bindText(int index, const String&); + int bindInt(int index, int); int bindInt64(int index, int64_t); int bindDouble(int index, double); int bindNull(int index); @@ -70,6 +71,7 @@ public: // returned in the last step() int columnCount(); + bool isColumnNull(int col); String getColumnName(int col); SQLValue getColumnValue(int col); String getColumnText(int col); diff --git a/WebCore/platform/text/TextCodecLatin1.cpp b/WebCore/platform/text/TextCodecLatin1.cpp index 4f9cbe0..2a217c5 100644 --- a/WebCore/platform/text/TextCodecLatin1.cpp +++ b/WebCore/platform/text/TextCodecLatin1.cpp @@ -164,7 +164,7 @@ String TextCodecLatin1::decode(const char* bytes, size_t length, bool, bool, boo // Wait until we're at a properly aligned address, then read full CPU words. if (!(reinterpret_cast<ptrdiff_t>(src) & (sizeof(uintptr_t) - 1))) { while (src < alignedEnd) { - uintptr_t chunk = *reinterpret_cast<const uintptr_t*>(src); + uintptr_t chunk = *reinterpret_cast_ptr<const uintptr_t*>(src); if (chunk & NonASCIIMask<sizeof(uintptr_t)>::value()) goto useLookupTable; diff --git a/WebCore/platform/text/qt/TextCodecQt.cpp b/WebCore/platform/text/qt/TextCodecQt.cpp index 735d773..94a2b7b 100644 --- a/WebCore/platform/text/qt/TextCodecQt.cpp +++ b/WebCore/platform/text/qt/TextCodecQt.cpp @@ -110,7 +110,7 @@ String TextCodecQt::decode(const char* bytes, size_t length, bool flush, bool /* int size = end - buf; size = qMin(size, MaxInputChunkSize); QString decoded = m_codec->toUnicode(buf, size, &m_state); - unicode.append(decoded); + unicode.append(reinterpret_cast_ptr<const UChar*>(decoded.unicode()), decoded.length()); buf += size; } diff --git a/WebCore/platform/win/BitmapInfo.cpp b/WebCore/platform/win/BitmapInfo.cpp index 514f722..610a27e 100644 --- a/WebCore/platform/win/BitmapInfo.cpp +++ b/WebCore/platform/win/BitmapInfo.cpp @@ -33,21 +33,14 @@ namespace WebCore { -BitmapInfo bitmapInfoForSize(int width, int height, WORD bitCount) +BitmapInfo bitmapInfoForSize(int width, int height, BitmapInfo::BitCount bitCount) { - ASSERT_ARG(bitCount, bitCount == 16 || bitCount == 32); - BitmapInfo bitmapInfo; bitmapInfo.bmiHeader.biWidth = width; bitmapInfo.bmiHeader.biHeight = height; bitmapInfo.bmiHeader.biPlanes = 1; bitmapInfo.bmiHeader.biBitCount = bitCount; bitmapInfo.bmiHeader.biCompression = BI_RGB; - bitmapInfo.bmiHeader.biSizeImage = 0; - bitmapInfo.bmiHeader.biXPelsPerMeter = 0; - bitmapInfo.bmiHeader.biYPelsPerMeter = 0; - bitmapInfo.bmiHeader.biClrUsed = 0; - bitmapInfo.bmiHeader.biClrImportant = 0; return bitmapInfo; } @@ -58,12 +51,12 @@ BitmapInfo::BitmapInfo() bmiHeader.biSize = sizeof(BITMAPINFOHEADER); } -BitmapInfo BitmapInfo::create(const IntSize& size, WORD bitCount) +BitmapInfo BitmapInfo::create(const IntSize& size, BitCount bitCount) { return bitmapInfoForSize(size.width(), size.height(), bitCount); } -BitmapInfo BitmapInfo::createBottomUp(const IntSize& size, WORD bitCount) +BitmapInfo BitmapInfo::createBottomUp(const IntSize& size, BitCount bitCount) { return bitmapInfoForSize(size.width(), -size.height(), bitCount); } diff --git a/WebCore/platform/win/BitmapInfo.h b/WebCore/platform/win/BitmapInfo.h index d1c3319..caf1b31 100644 --- a/WebCore/platform/win/BitmapInfo.h +++ b/WebCore/platform/win/BitmapInfo.h @@ -35,19 +35,30 @@ namespace WebCore { struct BitmapInfo : public BITMAPINFO { + enum BitCount { + BitCount1 = 1, + BitCount4 = 4, + BitCount8 = 8, + BitCount16 = 16, + BitCount24 = 24, + BitCount32 = 32 + }; + BitmapInfo(); - static BitmapInfo create(const IntSize&, WORD bitCount = 32); - static BitmapInfo createBottomUp(const IntSize&, WORD bitCount = 32); + static BitmapInfo create(const IntSize&, BitCount bitCount = BitCount32); + static BitmapInfo createBottomUp(const IntSize&, BitCount bitCount = BitCount32); bool is16bit() const { return bmiHeader.biBitCount == 16; } bool is32bit() const { return bmiHeader.biBitCount == 32; } unsigned width() const { return abs(bmiHeader.biWidth); } unsigned height() const { return abs(bmiHeader.biHeight); } IntSize size() const { return IntSize(width(), height()); } - unsigned paddedWidth() const { return is16bit() ? (width() + 1) & ~0x1 : width(); } + unsigned bytesPerLine() const { return (width() * bmiHeader.biBitCount + 7) / 8; } + unsigned paddedBytesPerLine() const { return (bytesPerLine() + 3) & ~0x3; } + unsigned paddedWidth() const { return paddedBytesPerLine() * 8 / bmiHeader.biBitCount; } unsigned numPixels() const { return paddedWidth() * height(); } - unsigned paddedBytesPerLine() const { return is16bit() ? paddedWidth() * 2 : width() * 4; } - unsigned bytesPerLine() const { return width() * bmiHeader.biBitCount / 8; }}; +}; + } // namespace WebCore #endif // BitmapInfo_h diff --git a/WebCore/platform/win/PopupMenuWin.cpp b/WebCore/platform/win/PopupMenuWin.cpp index aaadc53..6e22024 100644 --- a/WebCore/platform/win/PopupMenuWin.cpp +++ b/WebCore/platform/win/PopupMenuWin.cpp @@ -581,7 +581,7 @@ void PopupMenuWin::paint(const IntRect& damageRect, HDC hdc) } if (!m_bmp) { #if OS(WINCE) - BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(clientRect().size(), 16); + BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(clientRect().size(), BitmapInfo::BitCount16); #else BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(clientRect().size()); #endif |