summaryrefslogtreecommitdiffstats
path: root/WebCore/platform
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2010-04-29 02:02:09 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2010-04-29 02:02:09 -0700
commitfbcad591f3f2962b92aa61c017c360ddaef5ebba (patch)
treea1e6f4d2b649801f5455f51739d75f4f34a7d190 /WebCore/platform
parent5a0626b52e267a829822dd9fc9f2863ebc3259c0 (diff)
parentec79cd2f7baa7ba941c8343f6d79f0dbfdd5be2a (diff)
downloadexternal_webkit-fbcad591f3f2962b92aa61c017c360ddaef5ebba.zip
external_webkit-fbcad591f3f2962b92aa61c017c360ddaef5ebba.tar.gz
external_webkit-fbcad591f3f2962b92aa61c017c360ddaef5ebba.tar.bz2
Merge changes Ie9ba4c69,I35363367,I18aaae5f,I2c315360,I4f163c97,Ib640e64c,I98a4af82
* changes: Merge webkit.org at r55033 : Update WebKit revision Merge webkit.org at r55033 : Update Android-specific LayoutTest expected result Merge webkit.org at r55033 : Implement FrameLoaderClient::didTransferChildFrameToNewDocument for Android Merge webkit.org at r55033 : Implement PluginPackage::NPVersion for Android Merge webkit.org at r55033 : Implement new ChromeClient::iconForFiles method for Android Merge webkit.org at r55033 : Fix merge conflicts Merge webkit.org at r55033 : Initial merge by git
Diffstat (limited to 'WebCore/platform')
-rw-r--r--WebCore/platform/FileChooser.cpp19
-rw-r--r--WebCore/platform/FileChooser.h7
-rw-r--r--WebCore/platform/GeolocationService.cpp5
-rw-r--r--WebCore/platform/GeolocationService.h7
-rw-r--r--WebCore/platform/Logging.cpp4
-rw-r--r--WebCore/platform/Logging.h1
-rw-r--r--WebCore/platform/PlatformKeyboardEvent.h10
-rw-r--r--WebCore/platform/brew/PlatformKeyboardEventBrew.cpp174
-rw-r--r--WebCore/platform/brew/SystemTimeBrew.cpp40
-rw-r--r--WebCore/platform/chromium/ChromiumBridge.h19
-rw-r--r--WebCore/platform/chromium/ChromiumDataObject.cpp3
-rw-r--r--WebCore/platform/chromium/ChromiumDataObject.h1
-rw-r--r--WebCore/platform/chromium/ClipboardChromium.cpp3
-rw-r--r--WebCore/platform/chromium/GeolocationServiceChromium.cpp82
-rw-r--r--WebCore/platform/chromium/GeolocationServiceChromium.h85
-rw-r--r--WebCore/platform/chromium/PasteboardChromium.cpp3
-rw-r--r--WebCore/platform/graphics/BitmapImage.cpp24
-rw-r--r--WebCore/platform/graphics/FloatRect.h2
-rw-r--r--WebCore/platform/graphics/Gradient.h4
-rw-r--r--WebCore/platform/graphics/GraphicsContext3D.cpp130
-rw-r--r--WebCore/platform/graphics/GraphicsContext3D.h65
-rw-r--r--WebCore/platform/graphics/GraphicsLayer.h2
-rw-r--r--WebCore/platform/graphics/Icon.h2
-rw-r--r--WebCore/platform/graphics/MediaPlayer.cpp10
-rw-r--r--WebCore/platform/graphics/MediaPlayer.h16
-rw-r--r--WebCore/platform/graphics/MediaPlayerPrivate.h3
-rw-r--r--WebCore/platform/graphics/cg/GradientCG.cpp6
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp101
-rw-r--r--WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp3
-rw-r--r--WebCore/platform/graphics/gtk/IconGtk.cpp1
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp295
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h12
-rw-r--r--WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.cpp51
-rw-r--r--WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.h2
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp57
-rw-r--r--WebCore/platform/graphics/mac/IconMac.mm1
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h3
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm25
-rw-r--r--WebCore/platform/graphics/mac/SimpleFontDataMac.mm69
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContextQt.cpp31
-rw-r--r--WebCore/platform/graphics/qt/GraphicsLayerQt.cpp92
-rw-r--r--WebCore/platform/graphics/qt/IconQt.cpp1
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.cpp10
-rw-r--r--WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp74
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.cpp16
-rw-r--r--WebCore/platform/graphics/win/IconWin.cpp1
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp23
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h3
-rw-r--r--WebCore/platform/gtk/PasteboardGtk.cpp3
-rw-r--r--WebCore/platform/gtk/RenderThemeGtk.cpp45
-rw-r--r--WebCore/platform/gtk/WidgetGtk.cpp14
-rw-r--r--WebCore/platform/haiku/FileSystemHaiku.cpp20
-rw-r--r--WebCore/platform/image-decoders/ImageDecoder.cpp63
-rw-r--r--WebCore/platform/image-decoders/ImageDecoder.h110
-rw-r--r--WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp24
-rw-r--r--WebCore/platform/image-decoders/bmp/BMPImageDecoder.h12
-rw-r--r--WebCore/platform/image-decoders/bmp/BMPImageReader.cpp142
-rw-r--r--WebCore/platform/image-decoders/bmp/BMPImageReader.h30
-rw-r--r--WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp235
-rw-r--r--WebCore/platform/image-decoders/gif/GIFImageDecoder.h38
-rw-r--r--WebCore/platform/image-decoders/gif/GIFImageReader.cpp19
-rw-r--r--WebCore/platform/image-decoders/gif/GIFImageReader.h4
-rw-r--r--WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp122
-rw-r--r--WebCore/platform/image-decoders/ico/ICOImageDecoder.h20
-rw-r--r--WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp368
-rw-r--r--WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h16
-rw-r--r--WebCore/platform/image-decoders/png/PNGImageDecoder.cpp191
-rw-r--r--WebCore/platform/image-decoders/png/PNGImageDecoder.h14
-rw-r--r--WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp30
-rw-r--r--WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp32
-rw-r--r--WebCore/platform/mac/PasteboardMac.mm4
-rw-r--r--WebCore/platform/network/brew/DNSBrew.cpp40
-rw-r--r--WebCore/platform/network/chromium/CookieJarChromium.cpp30
-rw-r--r--WebCore/platform/network/chromium/ResourceRequest.cpp5
-rw-r--r--WebCore/platform/network/soup/ResourceHandleSoup.cpp19
-rw-r--r--WebCore/platform/qt/PasteboardQt.cpp3
-rw-r--r--WebCore/platform/text/AtomicString.cpp6
-rw-r--r--WebCore/platform/text/StringImpl.cpp113
-rw-r--r--WebCore/platform/text/StringImpl.h62
-rw-r--r--WebCore/platform/win/PasteboardWin.cpp3
80 files changed, 2185 insertions, 1250 deletions
diff --git a/WebCore/platform/FileChooser.cpp b/WebCore/platform/FileChooser.cpp
index 9fad392..a2d4770 100644
--- a/WebCore/platform/FileChooser.cpp
+++ b/WebCore/platform/FileChooser.cpp
@@ -39,9 +39,9 @@ FileChooserClient::~FileChooserClient()
inline FileChooser::FileChooser(FileChooserClient* client, const Vector<String>& initialFilenames)
: m_client(client)
- , m_icon(Icon::createIconForFiles(initialFilenames))
{
m_filenames = initialFilenames;
+ loadIcon();
}
PassRefPtr<FileChooser> FileChooser::create(FileChooserClient* client, const Vector<String>& initialFilenames)
@@ -71,9 +71,24 @@ void FileChooser::chooseFiles(const Vector<String>& filenames)
if (m_filenames == filenames)
return;
m_filenames = filenames;
- m_icon = Icon::createIconForFiles(filenames);
+ loadIcon();
if (m_client)
m_client->valueChanged();
}
+void FileChooser::loadIcon()
+{
+ m_icon = Icon::createIconForFiles(m_filenames);
+ // If synchronous icon loading failed, try asynchronous loading.
+ if (!m_icon && m_filenames.size() && m_client)
+ m_client->iconForFiles(m_filenames);
+}
+
+void FileChooser::iconLoaded(PassRefPtr<Icon> icon)
+{
+ m_icon = icon;
+ if (m_icon && m_client)
+ m_client->repaint();
+}
+
}
diff --git a/WebCore/platform/FileChooser.h b/WebCore/platform/FileChooser.h
index 0764a6a..e7feb3e 100644
--- a/WebCore/platform/FileChooser.h
+++ b/WebCore/platform/FileChooser.h
@@ -41,8 +41,10 @@ class Icon;
class FileChooserClient {
public:
virtual void valueChanged() = 0;
+ virtual void repaint() = 0;
virtual bool allowsMultipleFiles() = 0;
virtual String acceptTypes() = 0;
+ virtual void iconForFiles(const Vector<String>&) = 0;
virtual ~FileChooserClient();
};
@@ -63,13 +65,16 @@ public:
void chooseFile(const String& path);
void chooseFiles(const Vector<String>& paths);
-
+ // Called when FileChooserClient finishes to load an icon requested by iconForFiles().
+ void iconLoaded(PassRefPtr<Icon>);
+
bool allowsMultipleFiles() const { return m_client ? m_client->allowsMultipleFiles() : false; }
// Acceptable MIME types. It's an 'accept' attribute value of the corresponding INPUT element.
String acceptTypes() const { return m_client ? m_client->acceptTypes() : String(); }
private:
FileChooser(FileChooserClient*, const Vector<String>& initialFilenames);
+ void loadIcon();
FileChooserClient* m_client;
Vector<String> m_filenames;
diff --git a/WebCore/platform/GeolocationService.cpp b/WebCore/platform/GeolocationService.cpp
index be9553b..7e1f755 100644
--- a/WebCore/platform/GeolocationService.cpp
+++ b/WebCore/platform/GeolocationService.cpp
@@ -25,12 +25,13 @@
#include "config.h"
#include "GeolocationService.h"
-#include "Geoposition.h"
+
#include "GeolocationServiceMock.h"
+#include "Geoposition.h"
#include "PositionError.h"
-#include <wtf/CurrentTime.h>
#include <wtf/Assertions.h>
+#include <wtf/CurrentTime.h>
namespace WebCore {
diff --git a/WebCore/platform/GeolocationService.h b/WebCore/platform/GeolocationService.h
index f991f67..363865d 100644
--- a/WebCore/platform/GeolocationService.h
+++ b/WebCore/platform/GeolocationService.h
@@ -20,7 +20,7 @@
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GeolocationService_h
@@ -46,7 +46,7 @@ class GeolocationService : public Noncopyable {
public:
static GeolocationService* create(GeolocationServiceClient*);
virtual ~GeolocationService() { }
-
+
#if PLATFORM(ANDROID)
// TODO: Upstream to webkit.org. See https://bugs.webkit.org/show_bug.cgi?id=34082
virtual bool startUpdating(PositionOptions*, bool suspend) { return false; }
@@ -54,7 +54,7 @@ public:
virtual bool startUpdating(PositionOptions*) { return false; }
#endif
virtual void stopUpdating() { }
-
+
virtual void suspend() { }
virtual void resume() { }
@@ -68,6 +68,7 @@ public:
protected:
GeolocationService(GeolocationServiceClient*);
+ GeolocationServiceClient* geolocationServiceClient() const { return m_geolocationServiceClient; }
private:
GeolocationServiceClient* m_geolocationServiceClient;
diff --git a/WebCore/platform/Logging.cpp b/WebCore/platform/Logging.cpp
index f3c6f1c..2358d41 100644
--- a/WebCore/platform/Logging.cpp
+++ b/WebCore/platform/Logging.cpp
@@ -59,6 +59,7 @@ WTFLogChannel LogMedia = { 0x01000000, "WebCoreLogLevel", WTFLogChan
WTFLogChannel LogPlugins = { 0x02000000, "WebCoreLogLevel", WTFLogChannelOff };
WTFLogChannel LogArchives = { 0x04000000, "WebCoreLogLevel", WTFLogChannelOff };
+WTFLogChannel LogProgress = { 0x08000000, "WebCoreLogLevel", WTFLogChannelOff };
WTFLogChannel* getChannelFromName(const String& channelName)
{
@@ -110,6 +111,9 @@ WTFLogChannel* getChannelFromName(const String& channelName)
if (equalIgnoringCase(channelName, String("PopupBlocking")))
return &LogPopupBlocking;
+ if (equalIgnoringCase(channelName, String("Progress")))
+ return &LogProgress;
+
if (equalIgnoringCase(channelName, String("SpellingAndGrammar")))
return &LogSpellingAndGrammar;
diff --git a/WebCore/platform/Logging.h b/WebCore/platform/Logging.h
index 5c958fe..a3dfe62 100644
--- a/WebCore/platform/Logging.h
+++ b/WebCore/platform/Logging.h
@@ -57,6 +57,7 @@ namespace WebCore {
extern WTFLogChannel LogMedia;
extern WTFLogChannel LogPlugins;
extern WTFLogChannel LogArchives;
+ extern WTFLogChannel LogProgress;
void InitializeLoggingChannelsIfNecessary();
WTFLogChannel* getChannelFromName(const String& channelName);
diff --git a/WebCore/platform/PlatformKeyboardEvent.h b/WebCore/platform/PlatformKeyboardEvent.h
index 2b94cce..b2dfe03 100644
--- a/WebCore/platform/PlatformKeyboardEvent.h
+++ b/WebCore/platform/PlatformKeyboardEvent.h
@@ -63,6 +63,12 @@ class wxKeyEvent;
class BMessage;
#endif
+#if PLATFORM(BREWMP)
+typedef unsigned short uint16;
+typedef unsigned long int uint32;
+#define AEEEvent uint16
+#endif
+
namespace WebCore {
class PlatformKeyboardEvent : public FastAllocBase {
@@ -164,6 +170,10 @@ namespace WebCore {
PlatformKeyboardEvent(BMessage*);
#endif
+#if PLATFORM(BREWMP)
+ PlatformKeyboardEvent(AEEEvent, uint16, uint32, Type);
+#endif
+
#if PLATFORM(WIN) || PLATFORM(CHROMIUM)
bool isSystemKey() const { return m_isSystemKey; }
#endif
diff --git a/WebCore/platform/brew/PlatformKeyboardEventBrew.cpp b/WebCore/platform/brew/PlatformKeyboardEventBrew.cpp
new file mode 100644
index 0000000..758d15c
--- /dev/null
+++ b/WebCore/platform/brew/PlatformKeyboardEventBrew.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2010 Company 100, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PlatformKeyboardEvent.h"
+
+#include "KeyboardCodes.h"
+#include "NotImplemented.h"
+
+#include <AEEEvent.h>
+#include <AEEStdDef.h>
+#include <AEEVCodes.h>
+
+namespace WebCore {
+
+static String keyIdentifierForBrewKeyCode(int16 keyCode)
+{
+ switch (keyCode) {
+ case AVK_LALT:
+ case AVK_RALT:
+ return "Alt";
+ case AVK_LCTRL:
+ case AVK_RCTRL:
+ return "Control";
+ case AVK_LSHIFT:
+ case AVK_RSHIFT:
+ return "Shift";
+ case AVK_CAPLK:
+ return "CapsLock";
+ case AVK_FUNCTION1:
+ return "F1";
+ case AVK_FUNCTION2:
+ return "F2";
+ case AVK_FUNCTION3:
+ return "F3";
+ case AVK_FUNCTION4:
+ return "F4";
+ case AVK_FUNCTION5:
+ return "F5";
+ case AVK_FUNCTION6:
+ return "F6";
+ case AVK_FUNCTION7:
+ return "F7";
+ case AVK_FUNCTION8:
+ return "F8";
+ case AVK_FUNCTION9:
+ return "F9";
+ case AVK_FUNCTION10:
+ return "F10";
+ case AVK_FUNCTION11:
+ return "F11";
+ case AVK_FUNCTION12:
+ return "F12";
+ case AVK_PRSCRN:
+ return "PrintScreen";
+ case AVK_LEFT:
+ return "Left";
+ case AVK_RIGHT:
+ return "Right";
+ case AVK_UP:
+ return "Up";
+ case AVK_DOWN:
+ return "Down";
+ case AVK_TXINSERT:
+ return "Insert";
+ case AVK_ENTER:
+ return "Enter";
+ case AVK_TXHOME:
+ return "Home";
+ case AVK_TXDELETE:
+ // Standard says that DEL becomes U+007F.
+ return "U+007F";
+ case AVK_TXEND:
+ return "End";
+ case AVK_TXPGUP:
+ return "PageUp";
+ case AVK_TXPGDOWN:
+ return "PageDown";
+ default:
+ return String::format("U+%04X", toASCIIUpper(keyCode));
+ }
+}
+
+static int windowsKeyCodeForKeyEvent(uint16 code)
+{
+ switch (code) {
+ case AVK_A:
+ return VK_BACK; // (08) BACKSPACE key
+ case AVK_ENTER:
+ return VK_RETURN; // (0D) Return key
+ case AVK_SPACE:
+ return VK_SPACE; // (20) SPACEBAR
+ case AVK_TXPGUP:
+ return VK_PRIOR; // (21) PAGE UP key
+ case AVK_TXPGDOWN:
+ return VK_NEXT; // (22) PAGE DOWN key
+ case AVK_TXEND:
+ return VK_END; // (23) END key
+ case AVK_TXHOME:
+ return VK_HOME; // (24) HOME key
+ case AVK_LEFT:
+ return VK_LEFT; // (25) LEFT ARROW key
+ case AVK_UP:
+ return VK_UP; // (26) UP ARROW key
+ case AVK_RIGHT:
+ return VK_RIGHT; // (27) RIGHT ARROW key
+ case AVK_DOWN:
+ return VK_DOWN; // (28) DOWN ARROW key
+ case AVK_TXINSERT:
+ return VK_INSERT; // (2D) INS key
+ case AVK_TXDELETE:
+ return VK_DELETE; // (2E) DEL key
+ default:
+ return 0;
+ }
+}
+
+static inline String singleCharacterString(UChar c)
+{
+ return String(&c, 1);
+}
+
+PlatformKeyboardEvent::PlatformKeyboardEvent(AEEEvent event, uint16 code, uint32 modifiers, Type type)
+ : m_type(type)
+ , m_text((type == Char) ? singleCharacterString(code) : String())
+ , m_unmodifiedText((type == Char) ? singleCharacterString(code) : String())
+ , m_keyIdentifier((type == Char) ? String() : keyIdentifierForBrewKeyCode(code))
+ , m_autoRepeat(modifiers & KB_AUTOREPEAT)
+ , m_windowsVirtualKeyCode((type == RawKeyDown || type == KeyUp) ? windowsKeyCodeForKeyEvent(code) : 0)
+ , m_nativeVirtualKeyCode(code)
+ , m_isKeypad(false)
+ , m_shiftKey(modifiers & (KB_LSHIFT | KB_RSHIFT))
+ , m_ctrlKey(modifiers & (KB_LCTRL | KB_RCTRL))
+ , m_altKey(modifiers & (KB_LALT | KB_RALT))
+ , m_metaKey(false)
+{
+}
+
+void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool)
+{
+ // No KeyDown events on BREW to disambiguate.
+ ASSERT_NOT_REACHED();
+}
+
+bool PlatformKeyboardEvent::currentCapsLockState()
+{
+ notImplemented();
+ return false;
+}
+
+} // namespace WebCore
+
diff --git a/WebCore/platform/brew/SystemTimeBrew.cpp b/WebCore/platform/brew/SystemTimeBrew.cpp
new file mode 100644
index 0000000..c1e39fb
--- /dev/null
+++ b/WebCore/platform/brew/SystemTimeBrew.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 Company 100.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SystemTime.h"
+
+#include <float.h>
+
+namespace WebCore {
+
+float userIdleTime()
+{
+ // return an arbitrarily high userIdleTime so that releasing pages from the page cache isn't postponed
+ return FLT_MAX;
+}
+
+}
+
diff --git a/WebCore/platform/chromium/ChromiumBridge.h b/WebCore/platform/chromium/ChromiumBridge.h
index 83f9c81..5a085be 100644
--- a/WebCore/platform/chromium/ChromiumBridge.h
+++ b/WebCore/platform/chromium/ChromiumBridge.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, 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
@@ -53,6 +53,8 @@ namespace WebCore {
class Cursor;
class Document;
class Frame;
+ class GeolocationServiceBridge;
+ class GeolocationServiceChromium;
class GraphicsContext;
class Image;
class IntRect;
@@ -83,12 +85,12 @@ namespace WebCore {
static void clipboardWriteImage(NativeImagePtr, const KURL&, const String&);
// Cookies ------------------------------------------------------------
- static void setCookies(const KURL& url, const KURL& firstPartyForCookies, const String& value);
- static String cookies(const KURL& url, const KURL& firstPartyForCookies);
- static String cookieRequestHeaderFieldValue(const KURL& url, const KURL& firstPartyForCookies);
- static bool rawCookies(const KURL& url, const KURL& firstPartyForCookies, Vector<Cookie>*);
- static void deleteCookie(const KURL& url, const String& cookieName);
- static bool cookiesEnabled(const KURL& url, const KURL& firstPartyForCookies);
+ static void setCookies(const Document*, const KURL&, const String& value);
+ static String cookies(const Document*, const KURL&);
+ static String cookieRequestHeaderFieldValue(const Document*, const KURL&);
+ static bool rawCookies(const Document*, const KURL& url, Vector<Cookie>&);
+ static void deleteCookie(const Document*, const KURL& url, const String& cookieName);
+ static bool cookiesEnabled(const Document*);
// DNS ----------------------------------------------------------------
static void prefetchDNS(const String& hostname);
@@ -117,6 +119,9 @@ namespace WebCore {
// Forms --------------------------------------------------------------
static void notifyFormStateChanged(const Document*);
+ // Geolocation --------------------------------------------------------
+ static GeolocationServiceBridge* createGeolocationServiceBridge(GeolocationServiceChromium*);
+
// HTML5 DB -----------------------------------------------------------
#if ENABLE(DATABASE)
// Returns a handle to the DB file and ooptionally a handle to its containing directory
diff --git a/WebCore/platform/chromium/ChromiumDataObject.cpp b/WebCore/platform/chromium/ChromiumDataObject.cpp
index 695da9f..77a5f0f 100644
--- a/WebCore/platform/chromium/ChromiumDataObject.cpp
+++ b/WebCore/platform/chromium/ChromiumDataObject.cpp
@@ -37,7 +37,6 @@ void ChromiumDataObject::clear()
{
url = KURL();
urlTitle = "";
- downloadURL = KURL();
downloadMetadata = "";
fileExtension = "";
filenames.clear();
@@ -52,7 +51,6 @@ void ChromiumDataObject::clear()
bool ChromiumDataObject::hasData() const
{
return !url.isEmpty()
- || !downloadURL.isEmpty()
|| !downloadMetadata.isEmpty()
|| !fileExtension.isEmpty()
|| !filenames.isEmpty()
@@ -64,7 +62,6 @@ bool ChromiumDataObject::hasData() const
ChromiumDataObject::ChromiumDataObject(const ChromiumDataObject& other)
: url(other.url)
, urlTitle(other.urlTitle)
- , downloadURL(other.downloadURL)
, downloadMetadata(other.downloadMetadata)
, fileExtension(other.fileExtension)
, filenames(other.filenames)
diff --git a/WebCore/platform/chromium/ChromiumDataObject.h b/WebCore/platform/chromium/ChromiumDataObject.h
index 186a1a0..5fae3e3 100644
--- a/WebCore/platform/chromium/ChromiumDataObject.h
+++ b/WebCore/platform/chromium/ChromiumDataObject.h
@@ -59,7 +59,6 @@ namespace WebCore {
KURL url;
String urlTitle;
- KURL downloadURL;
String downloadMetadata;
String fileExtension;
diff --git a/WebCore/platform/chromium/ClipboardChromium.cpp b/WebCore/platform/chromium/ClipboardChromium.cpp
index 933d839..a1f60a6 100644
--- a/WebCore/platform/chromium/ClipboardChromium.cpp
+++ b/WebCore/platform/chromium/ClipboardChromium.cpp
@@ -161,9 +161,6 @@ bool ClipboardChromium::setData(const String& type, const String& data)
if (winType == ClipboardDataTypeDownloadURL) {
m_dataObject->downloadMetadata = data;
- KURL url = KURL(ParsedURLString, data);
- if (url.isValid())
- m_dataObject->downloadURL = url;
return true;
}
diff --git a/WebCore/platform/chromium/GeolocationServiceChromium.cpp b/WebCore/platform/chromium/GeolocationServiceChromium.cpp
index 65886b0..4e00908 100644
--- a/WebCore/platform/chromium/GeolocationServiceChromium.cpp
+++ b/WebCore/platform/chromium/GeolocationServiceChromium.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 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
@@ -29,27 +29,79 @@
*/
#include "config.h"
-#include "GeolocationService.h"
+#include "GeolocationServiceChromium.h"
+
+#include "ChromiumBridge.h"
namespace WebCore {
-class GeolocationServiceChromium : public GeolocationService {
-public:
- GeolocationServiceChromium(GeolocationServiceClient* c)
- : GeolocationService(c)
- {
- }
- // FIXME: Implement. https://bugs.webkit.org/show_bug.cgi?id=32068
-};
+GeolocationServiceChromium::GeolocationServiceChromium(GeolocationServiceClient* c)
+ : GeolocationService(c),
+ m_geolocation(reinterpret_cast<Geolocation*>(c)),
+ m_geolocationServiceBridge(ChromiumBridge::createGeolocationServiceBridge(this)),
+ m_lastPosition(Geoposition::create(Coordinates::create(0.0, 0.0, false, 0.0, 0.0, false, 0.0, false, 0.0, false, 0.0), 0)),
+ m_lastError(PositionError::create(PositionError::POSITION_UNAVAILABLE, ""))
+{
+}
+
+void GeolocationServiceChromium::setIsAllowed(bool allowed)
+{
+ m_geolocation->setIsAllowed(allowed);
+}
+
+void GeolocationServiceChromium::setLastPosition(double latitude, double longitude, bool providesAltitude, double altitude, double accuracy, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed, long long timestamp)
+{
+ m_lastPosition = Geoposition::create(Coordinates::create(latitude, longitude, providesAltitude, altitude, accuracy, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed), timestamp);
+ positionChanged();
+}
+
+void GeolocationServiceChromium::setLastError(int errorCode, const String& message)
+{
+ m_lastError = PositionError::create(static_cast<PositionError::ErrorCode>(errorCode), message);
+ errorOccurred();
+}
+
+Frame* GeolocationServiceChromium::frame()
+{
+ return m_geolocation->frame();
+}
+
+bool GeolocationServiceChromium::startUpdating(PositionOptions* options)
+{
+ return m_geolocationServiceBridge->startUpdating(options);
+}
+
+void GeolocationServiceChromium::stopUpdating()
+{
+ return m_geolocationServiceBridge->stopUpdating();
+}
+
+void GeolocationServiceChromium::suspend()
+{
+ return m_geolocationServiceBridge->suspend();
+}
+
+void GeolocationServiceChromium::resume()
+{
+ return m_geolocationServiceBridge->resume();
+}
+
+Geoposition* GeolocationServiceChromium::lastPosition() const
+{
+ return m_lastPosition.get();
+}
+
+PositionError* GeolocationServiceChromium::lastError() const
+{
+ return m_lastError.get();
+}
-// This guard is the counterpart of the one in WebCore/platform/GeolocationService.cpp
-#if ENABLE(GEOLOCATION)
-static GeolocationService* createGeolocationService(GeolocationServiceClient* c)
+static GeolocationService* createGeolocationServiceChromium(GeolocationServiceClient* c)
{
return new GeolocationServiceChromium(c);
}
-GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &createGeolocationService;
-#endif
+// Sets up the factory function for GeolocationService.
+GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &createGeolocationServiceChromium;
} // namespace WebCore
diff --git a/WebCore/platform/chromium/GeolocationServiceChromium.h b/WebCore/platform/chromium/GeolocationServiceChromium.h
new file mode 100644
index 0000000..e32de8b
--- /dev/null
+++ b/WebCore/platform/chromium/GeolocationServiceChromium.h
@@ -0,0 +1,85 @@
+/*
+ * 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 GeolocationServiceChromium_h
+#define GeolocationServiceChromium_h
+
+#include "Geolocation.h"
+#include "GeolocationService.h"
+#include "Geoposition.h"
+#include "PlatformString.h"
+#include "PositionError.h"
+
+namespace WebCore {
+
+// Provides an interface for GeolocationServiceChromium to call into the embedder.
+class GeolocationServiceBridge {
+public:
+ // Called by GeolocationServiceChromium.
+ virtual bool startUpdating(PositionOptions*) = 0;
+ virtual void stopUpdating() = 0;
+ virtual void suspend() = 0;
+ virtual void resume() = 0;
+
+ // Called by the embedder, to identify this bridge.
+ virtual int getBridgeId() const = 0;
+};
+
+// This class extends GeolocationService, and uses GeolocationServiceBridge to
+// call into the embedder, as well as provides a few extra methods so that the
+// embedder can notify permission, position, error, etc.
+class GeolocationServiceChromium : public GeolocationService {
+public:
+ explicit GeolocationServiceChromium(GeolocationServiceClient*);
+
+ GeolocationServiceBridge* geolocationServiceBridge() const { return m_geolocationServiceBridge.get(); }
+ void setIsAllowed(bool allowed);
+ void setLastPosition(double latitude, double longitude, bool providesAltitude, double altitude, double accuracy, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed, long long timestamp);
+ void setLastError(int errorCode, const String& message);
+ Frame* frame();
+
+ // From GeolocationService.
+ virtual bool startUpdating(PositionOptions*);
+ virtual void stopUpdating();
+ virtual void suspend();
+ virtual void resume();
+ virtual Geoposition* lastPosition() const;
+ virtual PositionError* lastError() const;
+
+private:
+ Geolocation* m_geolocation;
+ OwnPtr<GeolocationServiceBridge> m_geolocationServiceBridge;
+ RefPtr<Geoposition> m_lastPosition;
+ RefPtr<PositionError> m_lastError;
+};
+
+} // namespace WebCore
+
+#endif // GeolocationServiceChromium_h
diff --git a/WebCore/platform/chromium/PasteboardChromium.cpp b/WebCore/platform/chromium/PasteboardChromium.cpp
index d4f9a27..6904050 100644
--- a/WebCore/platform/chromium/PasteboardChromium.cpp
+++ b/WebCore/platform/chromium/PasteboardChromium.cpp
@@ -125,7 +125,8 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String& title)
ASSERT(node->renderer()->isImage());
RenderImage* renderer = toRenderImage(node->renderer());
CachedImage* cachedImage = renderer->cachedImage();
- ASSERT(cachedImage);
+ if (!cachedImage || cachedImage->errorOccurred())
+ return;
Image* image = cachedImage->image();
ASSERT(image);
diff --git a/WebCore/platform/graphics/BitmapImage.cpp b/WebCore/platform/graphics/BitmapImage.cpp
index 0b94efb..0cd3907 100644
--- a/WebCore/platform/graphics/BitmapImage.cpp
+++ b/WebCore/platform/graphics/BitmapImage.cpp
@@ -270,6 +270,18 @@ void BitmapImage::startAnimation(bool catchUpIfNecessary)
if (m_frameTimer || !shouldAnimate() || frameCount() <= 1)
return;
+ // Don't advance the animation to an incomplete frame.
+ size_t nextFrame = (m_currentFrame + 1) % frameCount();
+ if (!m_allDataReceived && !frameIsCompleteAtIndex(nextFrame))
+ return;
+
+ // Don't advance past the last frame if we haven't decoded the whole image
+ // yet and our repetition count is potentially unset. The repetition count
+ // in a GIF can potentially come after all the rest of the image data, so
+ // wait on it.
+ if (!m_allDataReceived && repetitionCount(false) == cAnimationLoopOnce && m_currentFrame >= (frameCount() - 1))
+ return;
+
// Determine time for next frame to start. By ignoring paint and timer lag
// in this calculation, we make the animation appear to run at its desired
// rate regardless of how fast it's being repainted.
@@ -288,18 +300,6 @@ void BitmapImage::startAnimation(bool catchUpIfNecessary)
m_desiredFrameStartTime = time + currentDuration;
}
- // Don't advance the animation to an incomplete frame.
- size_t nextFrame = (m_currentFrame + 1) % frameCount();
- if (!m_allDataReceived && !frameIsCompleteAtIndex(nextFrame))
- return;
-
- // Don't advance past the last frame if we haven't decoded the whole image
- // yet and our repetition count is potentially unset. The repetition count
- // in a GIF can potentially come after all the rest of the image data, so
- // wait on it.
- if (!m_allDataReceived && repetitionCount(false) == cAnimationLoopOnce && m_currentFrame >= (frameCount() - 1))
- return;
-
// The image may load more slowly than it's supposed to animate, so that by
// the time we reach the end of the first repetition, we're well behind.
// Clamp the desired frame start time in this case, so that we don't skip
diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h
index 74a6293..b265121 100644
--- a/WebCore/platform/graphics/FloatRect.h
+++ b/WebCore/platform/graphics/FloatRect.h
@@ -99,6 +99,8 @@ public:
float right() const { return x() + width(); }
float bottom() const { return y() + height(); }
+ FloatPoint center() const { return FloatPoint(x() + width() / 2, y() + height() / 2); }
+
void move(const FloatSize& delta) { m_location += delta; }
void move(float dx, float dy) { m_location.move(dx, dy); }
diff --git a/WebCore/platform/graphics/Gradient.h b/WebCore/platform/graphics/Gradient.h
index e1be1fe..0efd3bf 100644
--- a/WebCore/platform/graphics/Gradient.h
+++ b/WebCore/platform/graphics/Gradient.h
@@ -37,7 +37,9 @@
#if PLATFORM(CG)
-#ifdef BUILDING_ON_TIGER
+#define USE_CG_SHADING defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
+
+#if USE_CG_SHADING
typedef struct CGShading* CGShadingRef;
typedef CGShadingRef PlatformGradient;
#else
diff --git a/WebCore/platform/graphics/GraphicsContext3D.cpp b/WebCore/platform/graphics/GraphicsContext3D.cpp
new file mode 100644
index 0000000..3eb9818
--- /dev/null
+++ b/WebCore/platform/graphics/GraphicsContext3D.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010 Apple 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 met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "GraphicsContext3D.h"
+
+#include "Image.h"
+
+namespace WebCore {
+
+bool GraphicsContext3D::extractImageData(Image* image,
+ bool flipY,
+ bool premultiplyAlpha,
+ Vector<uint8_t>& imageData,
+ unsigned int* format,
+ unsigned int* internalFormat)
+{
+ if (!image)
+ return false;
+ AlphaOp alphaOp = kAlphaDoNothing;
+ bool hasAlphaChannel = true;
+ if (!getImageData(image, imageData, premultiplyAlpha,
+ &hasAlphaChannel, &alphaOp, format))
+ return false;
+ processImageData(imageData.data(),
+ image->width(),
+ image->height(),
+ flipY,
+ alphaOp);
+ *internalFormat = (hasAlphaChannel ? RGBA : RGB);
+ return true;
+}
+
+void GraphicsContext3D::processImageData(uint8_t* imageData,
+ unsigned width,
+ unsigned height,
+ bool flipVertically,
+ AlphaOp alphaOp)
+{
+ switch (alphaOp) {
+ case kAlphaDoPremultiply:
+ premultiplyAlpha(imageData, width * height);
+ break;
+ case kAlphaDoUnmultiply:
+ unmultiplyAlpha(imageData, width * height);
+ break;
+ default:
+ break;
+ }
+
+ if (flipVertically && width && height) {
+ int rowBytes = width * 4;
+ uint8_t* tempRow = new uint8_t[rowBytes];
+ for (unsigned i = 0; i < height / 2; i++) {
+ uint8_t* lowRow = imageData + (rowBytes * i);
+ uint8_t* highRow = imageData + (rowBytes * (height - i - 1));
+ memcpy(tempRow, lowRow, rowBytes);
+ memcpy(lowRow, highRow, rowBytes);
+ memcpy(highRow, tempRow, rowBytes);
+ }
+ delete[] tempRow;
+ }
+}
+
+// Premultiply alpha into color channels.
+void GraphicsContext3D::premultiplyAlpha(unsigned char* rgbaData, int numPixels)
+{
+ for (int j = 0; j < numPixels; j++) {
+ float r = rgbaData[4*j+0] / 255.0f;
+ float g = rgbaData[4*j+1] / 255.0f;
+ float b = rgbaData[4*j+2] / 255.0f;
+ float a = rgbaData[4*j+3] / 255.0f;
+ rgbaData[4*j+0] = (unsigned char) (r * a * 255.0f);
+ rgbaData[4*j+1] = (unsigned char) (g * a * 255.0f);
+ rgbaData[4*j+2] = (unsigned char) (b * a * 255.0f);
+ }
+}
+
+// Remove premultiplied alpha from color channels.
+// FIXME: this is lossy. Must retrieve original values from HTMLImageElement.
+void GraphicsContext3D::unmultiplyAlpha(unsigned char* rgbaData, int numPixels)
+{
+ for (int j = 0; j < numPixels; j++) {
+ float r = rgbaData[4*j+0] / 255.0f;
+ float g = rgbaData[4*j+1] / 255.0f;
+ float b = rgbaData[4*j+2] / 255.0f;
+ float a = rgbaData[4*j+3] / 255.0f;
+ if (a > 0.0f) {
+ r /= a;
+ g /= a;
+ b /= a;
+ r = (r > 1.0f) ? 1.0f : r;
+ g = (g > 1.0f) ? 1.0f : g;
+ b = (b > 1.0f) ? 1.0f : b;
+ rgbaData[4*j+0] = (unsigned char) (r * 255.0f);
+ rgbaData[4*j+1] = (unsigned char) (g * 255.0f);
+ rgbaData[4*j+2] = (unsigned char) (b * 255.0f);
+ }
+ }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h
index b7be8fc..0a41dc6 100644
--- a/WebCore/platform/graphics/GraphicsContext3D.h
+++ b/WebCore/platform/graphics/GraphicsContext3D.h
@@ -419,6 +419,43 @@ namespace WebCore {
// like GL_FLOAT, GL_INT, etc.
int sizeInBytes(int type);
+ //----------------------------------------------------------------------
+ // Helpers for texture uploading.
+ //
+
+ // Extracts the contents of the given Image into the passed
+ // Vector, obeying the flipY and premultiplyAlpha flags.
+ // Returns the applicable OpenGL format and internalFormat for
+ // the subsequent glTexImage2D or glTexSubImage2D call.
+ // Returns true upon success.
+ bool extractImageData(Image* image,
+ bool flipY,
+ bool premultiplyAlpha,
+ Vector<uint8_t>& imageData,
+ unsigned int* format,
+ unsigned int* internalFormat);
+
+ // Processes the given image data in preparation for uploading
+ // via texImage2D or texSubImage2D. The input data must be in
+ // 4-component format with the alpha channel last (i.e., RGBA
+ // or BGRA), tightly packed, with no space between rows.
+
+ enum AlphaOp {
+ kAlphaDoNothing = 0,
+ kAlphaDoPremultiply = 1,
+ kAlphaDoUnmultiply = 2
+ };
+
+ void processImageData(uint8_t* imageData,
+ unsigned width,
+ unsigned height,
+ bool flipVertically,
+ AlphaOp alphaOp);
+
+ //----------------------------------------------------------------------
+ // Entry points for WebGL.
+ //
+
void activeTexture(unsigned long texture);
void attachShader(WebGLProgram* program, WebGLShader* shader);
void bindAttribLocation(WebGLProgram*, unsigned long index, const String& name);
@@ -624,6 +661,34 @@ namespace WebCore {
private:
GraphicsContext3D(Attributes attrs);
+ // Helpers for texture uploading.
+ void premultiplyAlpha(unsigned char* rgbaData, int numPixels);
+ void unmultiplyAlpha(uint8_t* imageData, int numPixels);
+
+ // Each platform must provide an implementation of this method.
+ //
+ // Gets the data for the given Image into outputVector,
+ // without doing any processing of the data (vertical flip or
+ // otherwise).
+ //
+ // premultiplyAlpha indicates whether the user will eventually
+ // want the alpha channel multiplied into the color channels.
+ //
+ // The out parameter hasAlphaChannel indicates whether the
+ // image actually had an alpha channel.
+ //
+ // The out parameter neededAlphaOp should be passed to a
+ // subsequent call of processImageData.
+ //
+ // The out parameter format should be passed to subsequent
+ // invocations of texImage2D and texSubImage2D.
+ bool getImageData(Image* image,
+ Vector<uint8_t>& outputVector,
+ bool premultiplyAlpha,
+ bool* hasAlphaChannel,
+ AlphaOp* neededAlphaOp,
+ unsigned int* format);
+
int m_currentWidth, m_currentHeight;
#if PLATFORM(MAC)
diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h
index 844301e..a097620 100644
--- a/WebCore/platform/graphics/GraphicsLayer.h
+++ b/WebCore/platform/graphics/GraphicsLayer.h
@@ -74,7 +74,7 @@ class FloatPoint3D;
class GraphicsContext;
class Image;
class TextStream;
-class TimingFunction;
+struct TimingFunction;
// Base class for animation values (also used for transitions). Here to
// represent values for properties being animated via the GraphicsLayer,
diff --git a/WebCore/platform/graphics/Icon.h b/WebCore/platform/graphics/Icon.h
index d7d694a..e9f2dc7 100644
--- a/WebCore/platform/graphics/Icon.h
+++ b/WebCore/platform/graphics/Icon.h
@@ -51,6 +51,8 @@ class String;
class Icon : public RefCounted<Icon> {
public:
+ // Deprecated. This function will be removed.
+ // FIXME: Remove it when all implementations are moved to ChromeClient::iconForFiles().
static PassRefPtr<Icon> createIconForFiles(const Vector<String>& filenames);
~Icon();
diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp
index 2b09885..8a9a264 100644
--- a/WebCore/platform/graphics/MediaPlayer.cpp
+++ b/WebCore/platform/graphics/MediaPlayer.cpp
@@ -69,6 +69,9 @@ public:
virtual void pause() { }
virtual PlatformMedia platformMedia() const { return NoPlatformMedia; }
+#if USE(ACCELERATED_COMPOSITING)
+ virtual PlatformLayer* platformLayer() const { return 0; }
+#endif
virtual IntSize naturalSize() const { return IntSize(0, 0); }
@@ -364,6 +367,13 @@ PlatformMedia MediaPlayer::platformMedia() const
return m_private->platformMedia();
}
+#if USE(ACCELERATED_COMPOSITING)
+PlatformLayer* MediaPlayer::platformLayer() const
+{
+ return m_private->platformLayer();
+}
+#endif
+
MediaPlayer::NetworkState MediaPlayer::networkState()
{
return m_private->networkState();
diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h
index 40ed8ae..1ca4576 100644
--- a/WebCore/platform/graphics/MediaPlayer.h
+++ b/WebCore/platform/graphics/MediaPlayer.h
@@ -39,6 +39,10 @@
#include <wtf/Noncopyable.h>
#include <wtf/PassOwnPtr.h>
+#if USE(ACCELERATED_COMPOSITING)
+#include "GraphicsLayer.h"
+#endif
+
#ifdef __OBJC__
@class QTMovie;
#else
@@ -67,10 +71,6 @@ class MediaPlayerPrivateInterface;
class String;
class TimeRanges;
-#if USE(ACCELERATED_COMPOSITING)
-class GraphicsLayer;
-#endif
-
class MediaPlayerClient {
public:
virtual ~MediaPlayerClient() { }
@@ -112,8 +112,9 @@ public:
// whether the rendering system can accelerate the display of this MediaPlayer.
virtual bool mediaPlayerRenderingCanBeAccelerated(MediaPlayer*) { return false; }
- // return the GraphicsLayer that will host the presentation for this MediaPlayer.
- virtual GraphicsLayer* mediaPlayerGraphicsLayer(MediaPlayer*) { return 0; }
+ // called when the media player's rendering mode changed, which indicates a change in the
+ // availability of the platformLayer().
+ virtual void mediaPlayerRenderingModeChanged(MediaPlayer*) { }
#endif
};
@@ -135,6 +136,9 @@ public:
bool supportsFullscreen() const;
bool supportsSave() const;
PlatformMedia platformMedia() const;
+#if USE(ACCELERATED_COMPOSITING)
+ PlatformLayer* platformLayer() const;
+#endif
IntSize naturalSize();
bool hasVideo() const;
diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h
index 3b7c4d4..3bb8475 100644
--- a/WebCore/platform/graphics/MediaPlayerPrivate.h
+++ b/WebCore/platform/graphics/MediaPlayerPrivate.h
@@ -45,6 +45,9 @@ public:
virtual void prepareToPlay() { }
virtual PlatformMedia platformMedia() const { return NoPlatformMedia; }
+#if USE(ACCELERATED_COMPOSITING)
+ virtual PlatformLayer* platformLayer() const { return 0; }
+#endif
virtual void play() = 0;
virtual void pause() = 0;
diff --git a/WebCore/platform/graphics/cg/GradientCG.cpp b/WebCore/platform/graphics/cg/GradientCG.cpp
index e9b5de7..9c91700 100644
--- a/WebCore/platform/graphics/cg/GradientCG.cpp
+++ b/WebCore/platform/graphics/cg/GradientCG.cpp
@@ -36,7 +36,7 @@ namespace WebCore {
void Gradient::platformDestroy()
{
-#ifdef BUILDING_ON_TIGER
+#if USE_CG_SHADING
CGShadingRelease(m_gradient);
#else
CGGradientRelease(m_gradient);
@@ -44,7 +44,7 @@ void Gradient::platformDestroy()
m_gradient = 0;
}
-#ifdef BUILDING_ON_TIGER
+#if USE_CG_SHADING
static void gradientCallback(void* info, const CGFloat* in, CGFloat* out)
{
float r, g, b, a;
@@ -114,7 +114,7 @@ void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
void Gradient::paint(GraphicsContext* context)
{
-#ifdef BUILDING_ON_TIGER
+#if USE_CG_SHADING
CGContextDrawShading(context->platformContext(), platformGradient());
#else
CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
diff --git a/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp
new file mode 100644
index 0000000..c6a8f83
--- /dev/null
+++ b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2010 Apple 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 met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "GraphicsContext3D.h"
+
+#include "Image.h"
+
+#include <CoreGraphics/CGBitmapContext.h>
+#include <CoreGraphics/CGContext.h>
+#include <CoreGraphics/CGImage.h>
+
+namespace WebCore {
+
+bool GraphicsContext3D::getImageData(Image* image,
+ Vector<uint8_t>& outputVector,
+ bool premultiplyAlpha,
+ bool* hasAlphaChannel,
+ AlphaOp* neededAlphaOp,
+ unsigned int* format)
+{
+ if (!image)
+ return false;
+ CGImageRef cgImage = image->nativeImageForCurrentFrame();
+ if (!cgImage)
+ return false;
+ int width = CGImageGetWidth(cgImage);
+ int height = CGImageGetHeight(cgImage);
+ int rowBytes = width * 4;
+ CGImageAlphaInfo info = CGImageGetAlphaInfo(cgImage);
+ *hasAlphaChannel = (info != kCGImageAlphaNone
+ && info != kCGImageAlphaNoneSkipLast
+ && info != kCGImageAlphaNoneSkipFirst);
+ if (!premultiplyAlpha && *hasAlphaChannel)
+ // FIXME: must fetch the image data before the premultiplication step
+ *neededAlphaOp = kAlphaDoUnmultiply;
+ *format = RGBA;
+ outputVector.resize(height * rowBytes);
+ // Try to reuse the color space from the image to preserve its colors.
+ // Some images use a color space (such as indexed) unsupported by the bitmap context.
+ CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgImage);
+ bool releaseColorSpace = false;
+ CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);
+ switch (colorSpaceModel) {
+ case kCGColorSpaceModelMonochrome:
+ case kCGColorSpaceModelRGB:
+ case kCGColorSpaceModelCMYK:
+ case kCGColorSpaceModelLab:
+ case kCGColorSpaceModelDeviceN:
+ break;
+ default:
+ colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear);
+ releaseColorSpace = true;
+ break;
+ }
+ CGContextRef tmpContext = CGBitmapContextCreate(outputVector.data(),
+ width, height, 8, rowBytes,
+ colorSpace,
+ kCGImageAlphaPremultipliedLast);
+ if (releaseColorSpace)
+ CGColorSpaceRelease(colorSpace);
+ if (!tmpContext)
+ return false;
+ CGContextSetBlendMode(tmpContext, kCGBlendModeCopy);
+ CGContextDrawImage(tmpContext,
+ CGRectMake(0, 0, static_cast<CGFloat>(width), static_cast<CGFloat>(height)),
+ cgImage);
+ CGContextRelease(tmpContext);
+ return true;
+}
+
+
+} // namespace WebCore
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
index e2c47c1..e71f66a 100644
--- a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
@@ -134,7 +134,8 @@ static bool fillBMPGlyphs(unsigned offset,
// Copy the output to the GlyphPage
bool haveGlyphs = false;
int invalidGlyph = 0xFFFF;
- if (!isVistaOrNewer() && !(tm.tmPitchAndFamily & TMPF_TRUETYPE))
+ const DWORD cffTableTag = 0x20464643; // 4-byte identifier for OpenType CFF table ('CFF ').
+ if (!isVistaOrNewer() && !(tm.tmPitchAndFamily & TMPF_TRUETYPE) && (GetFontData(dc, cffTableTag, 0, 0, 0) == GDI_ERROR))
invalidGlyph = 0x1F;
Glyph spaceGlyph = 0; // Glyph for a space. Lazily filled.
diff --git a/WebCore/platform/graphics/gtk/IconGtk.cpp b/WebCore/platform/graphics/gtk/IconGtk.cpp
index 3563a59..71b897e 100644
--- a/WebCore/platform/graphics/gtk/IconGtk.cpp
+++ b/WebCore/platform/graphics/gtk/IconGtk.cpp
@@ -87,6 +87,7 @@ static String lookupIconName(String MIMEType)
return GTK_STOCK_FILE;
}
+// FIXME: Move the code to ChromeClient::iconForFiles().
PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
{
if (filenames.isEmpty())
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
index 1866c36..e1c9fd2 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
@@ -3,6 +3,7 @@
* Copyright (C) 2007 Collabora Ltd. All rights reserved.
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
* Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org>
+ * Copyright (C) 2009, 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
@@ -52,20 +53,44 @@
#include <gst/video/video.h>
#include <limits>
#include <math.h>
-#include <webkit/webkitwebview.h>
#include <wtf/gtk/GOwnPtr.h>
+// GstPlayFlags flags from playbin2. It is the policy of GStreamer to
+// not publicly expose element-specific enums. That's why this
+// GstPlayFlags enum has been copied here.
+typedef enum {
+ GST_PLAY_FLAG_VIDEO = 0x00000001,
+ GST_PLAY_FLAG_AUDIO = 0x00000002,
+ GST_PLAY_FLAG_TEXT = 0x00000004,
+ GST_PLAY_FLAG_VIS = 0x00000008,
+ GST_PLAY_FLAG_SOFT_VOLUME = 0x00000010,
+ GST_PLAY_FLAG_NATIVE_AUDIO = 0x00000020,
+ GST_PLAY_FLAG_NATIVE_VIDEO = 0x00000040,
+ GST_PLAY_FLAG_DOWNLOAD = 0x00000080,
+ GST_PLAY_FLAG_BUFFERING = 0x000000100
+} GstPlayFlags;
+
using namespace std;
namespace WebCore {
+static int greatestCommonDivisor(int a, int b)
+{
+ while (b) {
+ int temp = a;
+ a = b;
+ b = temp % b;
+ }
+
+ return ABS(a);
+}
+
gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data)
{
GOwnPtr<GError> err;
GOwnPtr<gchar> debug;
MediaPlayer::NetworkState error;
MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
- gint percent = 0;
bool issueError = true;
bool attemptNextLocation = false;
@@ -115,8 +140,7 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo
mp->updateStates();
break;
case GST_MESSAGE_BUFFERING:
- gst_message_parse_buffering(message, &percent);
- LOG_VERBOSE(Media, "Buffering %d", percent);
+ mp->processBufferingStats(message);
break;
case GST_MESSAGE_DURATION:
LOG_VERBOSE(Media, "Duration changed");
@@ -174,6 +198,12 @@ gboolean notifyMuteIdleCallback(gpointer data)
return FALSE;
}
+gboolean bufferingTimeoutCallback(gpointer data)
+{
+ MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
+ return mp->queryBufferingStats();
+}
+
static float playbackPosition(GstElement* playbin)
{
@@ -278,14 +308,24 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
, m_playbackRate(1)
, m_errorOccured(false)
, m_volumeIdleId(0)
- , m_mediaDuration(0.0)
+ , m_mediaDuration(0)
, m_muteIdleId(0)
+ , m_startedBuffering(false)
+ , m_fillTimeoutId(0)
+ , m_maxTimeLoaded(0)
+ , m_fillStatus(0)
{
- doGstInit();
+ if (doGstInit())
+ createGSTPlayBin();
}
MediaPlayerPrivate::~MediaPlayerPrivate()
{
+ if (m_fillTimeoutId) {
+ g_source_remove(m_fillTimeoutId);
+ m_fillTimeoutId = 0;
+ }
+
if (m_volumeIdleId) {
g_source_remove(m_volumeIdleId);
m_volumeIdleId = 0;
@@ -338,7 +378,7 @@ void MediaPlayerPrivate::load(const String& url)
m_player->readyStateChanged();
}
- createGSTPlayBin(url);
+ g_object_set(m_playBin, "uri", url.utf8().data(), NULL);
pause();
}
@@ -422,9 +462,6 @@ void MediaPlayerPrivate::seek(float time)
if (!m_playBin)
return;
- if (m_isStreaming)
- return;
-
if (m_errorOccured)
return;
@@ -473,30 +510,60 @@ IntSize MediaPlayerPrivate::naturalSize() const
if (!hasVideo())
return IntSize();
+ GstPad* pad = gst_element_get_static_pad(m_videoSink, "sink");
+ if (!pad)
+ return IntSize();
+
+ int width = 0, height = 0;
+ GstCaps* caps = GST_PAD_CAPS(pad);
+ int pixelAspectRatioNumerator, pixelAspectRatioDenominator;
+ int displayWidth, displayHeight, displayAspectRatioGCD;
+ int originalWidth = 0, originalHeight = 0;
+
// TODO: handle possible clean aperture data. See
// https://bugzilla.gnome.org/show_bug.cgi?id=596571
// TODO: handle possible transformation matrix. See
// https://bugzilla.gnome.org/show_bug.cgi?id=596326
- int width = 0, height = 0;
- if (GstPad* pad = gst_element_get_static_pad(m_videoSink, "sink")) {
- GstCaps* caps = GST_PAD_CAPS(pad);
- gfloat pixelAspectRatio;
- gint pixelAspectRatioNumerator, pixelAspectRatioDenominator;
-
- if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps)
- || !gst_video_format_parse_caps(caps, 0, &width, &height)
- || !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator,
- &pixelAspectRatioDenominator)) {
- gst_object_unref(GST_OBJECT(pad));
- return IntSize();
- }
- pixelAspectRatio = (gfloat) pixelAspectRatioNumerator / (gfloat) pixelAspectRatioDenominator;
- width *= pixelAspectRatio;
- height /= pixelAspectRatio;
+ // Get the video PAR and original size.
+ if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps)
+ || !gst_video_format_parse_caps(caps, 0, &originalWidth, &originalHeight)
+ || !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator,
+ &pixelAspectRatioDenominator)) {
gst_object_unref(GST_OBJECT(pad));
+ return IntSize();
}
+ gst_object_unref(GST_OBJECT(pad));
+
+ LOG_VERBOSE(Media, "Original video size: %dx%d", originalWidth, originalHeight);
+ LOG_VERBOSE(Media, "Pixel aspect ratio: %d/%d", pixelAspectRatioNumerator, pixelAspectRatioDenominator);
+
+ // Calculate DAR based on PAR and video size.
+ displayWidth = originalWidth * pixelAspectRatioNumerator;
+ displayHeight = originalHeight * pixelAspectRatioDenominator;
+
+ // Divide display width and height by their GCD to avoid possible overflows.
+ displayAspectRatioGCD = greatestCommonDivisor(displayWidth, displayHeight);
+ displayWidth /= displayAspectRatioGCD;
+ displayHeight /= displayAspectRatioGCD;
+
+ // Apply DAR to original video size. This is the same behavior as in xvimagesink's setcaps function.
+ if (!(originalHeight % displayHeight)) {
+ LOG_VERBOSE(Media, "Keeping video original height");
+ width = gst_util_uint64_scale_int(originalHeight, displayWidth, displayHeight);
+ height = originalHeight;
+ } else if (!(originalWidth % displayWidth)) {
+ LOG_VERBOSE(Media, "Keeping video original width");
+ height = gst_util_uint64_scale_int(originalWidth, displayHeight, displayWidth);
+ width = originalWidth;
+ } else {
+ LOG_VERBOSE(Media, "Approximating while keeping original video height");
+ width = gst_util_uint64_scale_int(originalHeight, displayWidth, displayHeight);
+ height = originalHeight;
+ }
+
+ LOG_VERBOSE(Media, "Natural size: %dx%d", width, height);
return IntSize(width, height);
}
@@ -610,16 +677,79 @@ PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
return timeRanges.release();
}
+void MediaPlayerPrivate::processBufferingStats(GstMessage* message)
+{
+ GstBufferingMode mode;
+
+ gst_message_parse_buffering_stats(message, &mode, 0, 0, 0);
+ if (mode != GST_BUFFERING_DOWNLOAD)
+ return;
+
+ if (!m_startedBuffering) {
+ m_startedBuffering = true;
+
+ if (m_fillTimeoutId > 0)
+ g_source_remove(m_fillTimeoutId);
+
+ m_fillTimeoutId = g_timeout_add(200, (GSourceFunc) bufferingTimeoutCallback, this);
+ }
+}
+
+bool MediaPlayerPrivate::queryBufferingStats()
+{
+ GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
+
+ if (!gst_element_query(m_playBin, query)) {
+ gst_query_unref(query);
+ return TRUE;
+ }
+
+ gint64 start, stop;
+
+ gst_query_parse_buffering_range(query, 0, &start, &stop, 0);
+ gst_query_unref(query);
+
+ if (stop != -1)
+ m_fillStatus = 100.0 * stop / GST_FORMAT_PERCENT_MAX;
+ else
+ m_fillStatus = 100.0;
+
+ LOG_VERBOSE(Media, "Download buffer filled up to %f%%", m_fillStatus);
+
+ if (!m_mediaDuration)
+ durationChanged();
+
+ // Update maxTimeLoaded only if the media duration is
+ // available. Otherwise we can't compute it.
+ if (m_mediaDuration) {
+ m_maxTimeLoaded = static_cast<float>((m_fillStatus * m_mediaDuration) / 100.0);
+ LOG_VERBOSE(Media, "Updated maxTimeLoaded: %f", m_maxTimeLoaded);
+ }
+
+ if (m_fillStatus != 100.0) {
+ updateStates();
+ return TRUE;
+ }
+
+ // Media is now fully loaded. It will play even if network
+ // connection is cut. Buffering is done, remove the fill source
+ // from the main loop.
+ m_fillTimeoutId = 0;
+ m_startedBuffering = false;
+ updateStates();
+ return FALSE;
+}
+
float MediaPlayerPrivate::maxTimeSeekable() const
{
if (m_errorOccured)
return 0.0;
- // TODO
LOG_VERBOSE(Media, "maxTimeSeekable");
- if (m_isStreaming)
- return numeric_limits<float>::infinity();
// infinite duration means live stream
+ if (isinf(duration()))
+ return 0.0;
+
return maxTimeLoaded();
}
@@ -628,29 +758,28 @@ float MediaPlayerPrivate::maxTimeLoaded() const
if (m_errorOccured)
return 0.0;
- // TODO
- LOG_VERBOSE(Media, "maxTimeLoaded");
- notImplemented();
- return duration();
+ float loaded = m_maxTimeLoaded;
+ if (!loaded && !m_fillTimeoutId)
+ loaded = duration();
+ LOG_VERBOSE(Media, "maxTimeLoaded: %f", loaded);
+ return loaded;
}
unsigned MediaPlayerPrivate::bytesLoaded() const
{
- notImplemented();
- LOG_VERBOSE(Media, "bytesLoaded");
- /*if (!m_playBin)
+ if (!m_playBin)
return 0;
- float dur = duration();
- float maxTime = maxTimeLoaded();
- if (!dur)
- return 0;*/
- return 1; // totalBytes() * maxTime / dur;
+ if (!m_mediaDuration)
+ return 0;
+
+ unsigned loaded = totalBytes() * maxTimeLoaded() / m_mediaDuration;
+ LOG_VERBOSE(Media, "bytesLoaded: %d", loaded);
+ return loaded;
}
unsigned MediaPlayerPrivate::totalBytes() const
{
- LOG_VERBOSE(Media, "totalBytes");
if (!m_source)
return 0;
@@ -660,6 +789,7 @@ unsigned MediaPlayerPrivate::totalBytes() const
GstFormat fmt = GST_FORMAT_BYTES;
gint64 length = 0;
gst_element_query_duration(m_source, &fmt, &length);
+ LOG_VERBOSE(Media, "totalBytes %" G_GINT64_FORMAT, length);
return length;
}
@@ -710,6 +840,7 @@ void MediaPlayerPrivate::updateStates()
if (state == GST_STATE_PLAYING) {
m_readyState = MediaPlayer::HaveEnoughData;
m_paused = false;
+ m_startedPlaying = true;
if (!m_mediaDuration) {
float newDuration = duration();
if (!isinf(newDuration))
@@ -718,6 +849,28 @@ void MediaPlayerPrivate::updateStates()
} else
m_paused = true;
+ // Is on-disk buffering in progress?
+ if (m_fillTimeoutId) {
+ m_networkState = MediaPlayer::Loading;
+ // Buffering has just started, we should now have enough
+ // data to restart playback if it was internally paused by
+ // GStreamer.
+ if (m_paused && !m_startedPlaying)
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+ }
+
+ if (maxTimeLoaded() == duration()) {
+ m_networkState = MediaPlayer::Loaded;
+ if (state == GST_STATE_READY)
+ m_readyState = MediaPlayer::HaveNothing;
+ else if (state == GST_STATE_PAUSED)
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else
+ if (state == GST_STATE_READY)
+ m_readyState = MediaPlayer::HaveNothing;
+ else if (m_paused)
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
+
if (m_changingRate) {
m_player->rateChanged();
m_changingRate = false;
@@ -728,14 +881,24 @@ void MediaPlayerPrivate::updateStates()
m_seeking = false;
}
- m_networkState = MediaPlayer::Loaded;
break;
case GST_STATE_CHANGE_ASYNC:
LOG_VERBOSE(Media, "Async: State: %s, pending: %s",
gst_element_state_get_name(state),
gst_element_state_get_name(pending));
// Change in progress
- return;
+
+ if (!m_isStreaming)
+ return;
+
+ // Resume playback if a seek was performed in a live pipeline.
+ if (m_seeking) {
+ shouldUpdateAfterSeek = true;
+ m_seeking = false;
+ if (m_paused)
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+ }
+ break;
case GST_STATE_CHANGE_FAILURE:
LOG_VERBOSE(Media, "Failure: State: %s, pending: %s",
gst_element_state_get_name(state),
@@ -749,8 +912,25 @@ void MediaPlayerPrivate::updateStates()
if (state == GST_STATE_READY)
m_readyState = MediaPlayer::HaveNothing;
- else if (state == GST_STATE_PAUSED)
- m_readyState = MediaPlayer::HaveCurrentData;
+ else if (state == GST_STATE_PAUSED) {
+ m_readyState = MediaPlayer::HaveEnoughData;
+ m_paused = true;
+ // Live pipelines go in PAUSED without prerolling.
+ m_isStreaming = true;
+ } else if (state == GST_STATE_PLAYING) {
+ m_startedPlaying = true;
+ m_paused = false;
+ }
+
+ if (m_paused && !m_startedPlaying)
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+
+ if (m_seeking) {
+ shouldUpdateAfterSeek = true;
+ m_seeking = false;
+ if (m_paused)
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+ }
m_networkState = MediaPlayer::Loading;
break;
@@ -898,8 +1078,11 @@ void MediaPlayerPrivate::didEnd()
// not always 0. So to not confuse the HTMLMediaElement we
// synchronize position and duration values.
float now = currentTime();
- if (now > 0)
+ if (now > 0) {
m_mediaDuration = now;
+ m_player->durationChanged();
+ }
+
gst_element_set_state(m_playBin, GST_STATE_PAUSED);
timeChanged();
@@ -1150,7 +1333,19 @@ bool MediaPlayerPrivate::supportsFullscreen() const
return true;
}
-void MediaPlayerPrivate::createGSTPlayBin(String url)
+void MediaPlayerPrivate::setAutobuffer(bool autoBuffer)
+{
+ ASSERT(m_playBin);
+
+ GstPlayFlags flags;
+ g_object_get(m_playBin, "flags", &flags, NULL);
+ if (autoBuffer)
+ g_object_set(m_playBin, "flags", flags | GST_PLAY_FLAG_DOWNLOAD, NULL);
+ else
+ g_object_set(m_playBin, "flags", flags & ~GST_PLAY_FLAG_DOWNLOAD, NULL);
+}
+
+void MediaPlayerPrivate::createGSTPlayBin()
{
ASSERT(!m_playBin);
m_playBin = gst_element_factory_make("playbin2", "play");
@@ -1160,8 +1355,6 @@ void MediaPlayerPrivate::createGSTPlayBin(String url)
g_signal_connect(bus, "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this);
gst_object_unref(bus);
- g_object_set(m_playBin, "uri", url.utf8().data(), NULL);
-
g_signal_connect(m_playBin, "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this);
g_signal_connect(m_playBin, "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
g_signal_connect(m_playBin, "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this);
@@ -1180,7 +1373,7 @@ void MediaPlayerPrivate::createGSTPlayBin(String url)
} else {
m_fpsSink = 0;
g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
- LOG(Media, "Can't display FPS statistics, you need gst-plugins-bad >= 0.10.18");
+ LOG_VERBOSE(Media, "Can't display FPS statistics, you need gst-plugins-bad >= 0.10.18");
}
} else
g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
index 34257ca..e19b686 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
@@ -2,6 +2,7 @@
* Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2007 Collabora Ltd. All rights reserved.
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2009, 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
@@ -86,6 +87,9 @@ class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
void muteChanged();
void muteChangedCallback();
+ void setAutobuffer(bool);
+ bool queryBufferingStats();
+
MediaPlayer::NetworkState networkState() const;
MediaPlayer::ReadyState readyState() const;
@@ -128,9 +132,11 @@ class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
float maxTimeLoaded() const;
void startEndPointTimerIfNeeded();
- void createGSTPlayBin(String url);
+ void createGSTPlayBin();
bool changePipelineState(GstState state);
+ void processBufferingStats(GstMessage* message);
+
private:
MediaPlayer* m_player;
GstElement* m_playBin;
@@ -157,6 +163,10 @@ class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
guint m_volumeIdleId;
gfloat m_mediaDuration;
guint m_muteIdleId;
+ bool m_startedBuffering;
+ guint m_fillTimeoutId;
+ float m_maxTimeLoaded;
+ gdouble m_fillStatus;
};
}
diff --git a/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.cpp b/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.cpp
index 390c0ec..74a7852 100644
--- a/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ * Copyright (C) 2009, 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -79,6 +79,10 @@ struct _WebKitWebSrcPrivate {
gchar* iradioGenre;
gchar* iradioUrl;
gchar* iradioTitle;
+
+ // TRUE if appsrc's version is >= 0.10.27, see
+ // https://bugzilla.gnome.org/show_bug.cgi?id=609423
+ gboolean haveAppSrc27;
};
enum {
@@ -109,7 +113,7 @@ static void webKitWebSrcNeedDataCb(GstAppSrc* appsrc, guint length, gpointer use
static void webKitWebSrcEnoughDataCb(GstAppSrc* appsrc, gpointer userData);
static gboolean webKitWebSrcSeekDataCb(GstAppSrc* appsrc, guint64 offset, gpointer userData);
-static void webKitWebSrcStop(WebKitWebSrc* src, bool resetRequestedOffset);
+static void webKitWebSrcStop(WebKitWebSrc* src, bool seeking);
static GstAppSrcCallbacks appsrcCallbacks = {
webKitWebSrcNeedDataCb,
@@ -222,6 +226,9 @@ static void webkit_web_src_init(WebKitWebSrc* src,
return;
}
+ GstElementFactory* factory = GST_ELEMENT_FACTORY(GST_ELEMENT_GET_CLASS(priv->appsrc)->elementfactory);
+ priv->haveAppSrc27 = gst_plugin_feature_check_version(GST_PLUGIN_FEATURE(factory), 0, 10, 27);
+
gst_bin_add(GST_BIN(src), GST_ELEMENT(priv->appsrc));
targetpad = gst_element_get_static_pad(GST_ELEMENT(priv->appsrc), "src");
@@ -238,7 +245,20 @@ static void webkit_web_src_init(WebKitWebSrc* src,
// GStreamer to handle.
gst_app_src_set_max_bytes(priv->appsrc, 512 * 1024);
- webKitWebSrcStop(src, true);
+ // Emit the need-data signal if the queue contains less
+ // than 20% of data. Without this the need-data signal
+ // is emitted when the queue is empty, we then dispatch
+ // the soup message unpausing to the main loop and from
+ // there unpause the soup message. This already takes
+ // quite some time and libsoup even needs some more time
+ // to actually provide data again. If we do all this
+ // already if the queue is 20% empty, it's much more
+ // likely that libsoup already provides new data before
+ // the queue is really empty.
+ if (priv->haveAppSrc27)
+ g_object_set(priv->appsrc, "min-percent", 20, NULL);
+
+ webKitWebSrcStop(src, false);
}
static void webKitWebSrcFinalize(GObject* object)
@@ -296,7 +316,7 @@ static void webKitWebSrcGetProperty(GObject* object, guint propID, GValue* value
}
-static void webKitWebSrcStop(WebKitWebSrc* src, bool resetRequestedOffset)
+static void webKitWebSrcStop(WebKitWebSrc* src, bool seeking)
{
WebKitWebSrcPrivate* priv = src->priv;
@@ -335,15 +355,19 @@ static void webKitWebSrcStop(WebKitWebSrc* src, bool resetRequestedOffset)
g_free(priv->iradioTitle);
priv->iradioTitle = 0;
- if (priv->appsrc)
+ if (priv->appsrc) {
gst_app_src_set_caps(priv->appsrc, 0);
+ if (!seeking)
+ gst_app_src_set_size(priv->appsrc, -1);
+ }
priv->offset = 0;
- priv->size = 0;
priv->seekable = FALSE;
- if (resetRequestedOffset)
+ if (!seeking) {
+ priv->size = 0;
priv->requestedOffset = 0;
+ }
GST_DEBUG_OBJECT(src, "Stopped request");
}
@@ -434,7 +458,7 @@ static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStat
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_DEBUG_OBJECT(src, "PAUSED->READY");
- webKitWebSrcStop(src, true);
+ webKitWebSrcStop(src, false);
break;
default:
break;
@@ -558,7 +582,7 @@ static void webKitWebSrcEnoughDataCb(GstAppSrc* appsrc, gpointer userData)
static gboolean webKitWebSrcSeekMainCb(WebKitWebSrc* src)
{
- webKitWebSrcStop(src, false);
+ webKitWebSrcStop(src, true);
webKitWebSrcStart(src);
return FALSE;
@@ -617,7 +641,8 @@ void StreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse
// If we seeked we need 206 == PARTIAL_CONTENT
if (priv->requestedOffset && response.httpStatusCode() != 206) {
GST_ELEMENT_ERROR(m_src, RESOURCE, READ, (0), (0));
- webKitWebSrcStop(m_src, true);
+ gst_app_src_end_of_stream(priv->appsrc);
+ webKitWebSrcStop(m_src, false);
return;
}
@@ -625,6 +650,12 @@ void StreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse
if (length > 0) {
length += priv->requestedOffset;
gst_app_src_set_size(priv->appsrc, length);
+ if (!priv->haveAppSrc27) {
+ gst_segment_set_duration(&GST_BASE_SRC(priv->appsrc)->segment, GST_FORMAT_BYTES, length);
+ gst_element_post_message(GST_ELEMENT(priv->appsrc),
+ gst_message_new_duration(GST_OBJECT(priv->appsrc),
+ GST_FORMAT_BYTES, length));
+ }
}
priv->size = length >= 0 ? length : 0;
diff --git a/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.h b/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.h
index 045e7d7..ae19640 100644
--- a/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.h
+++ b/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ * Copyright (C) 2009,2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
index 99ad130..096cdbd 100644
--- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
+++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
@@ -1126,31 +1126,6 @@ long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long
return reinterpret_cast<long>(pointer);
}
-// Returned pointer must be freed by fastFree()
-static bool imageToTexture(Image* image, GLubyte*& buffer, size_t& width, size_t& height)
-{
- if (!image)
- return false;
-
- CGImageRef textureImage = image->getCGImageRef();
- if (!textureImage)
- return false;
-
- width = CGImageGetWidth(textureImage);
- height = CGImageGetHeight(textureImage);
-
- buffer = (GLubyte*) fastMalloc(width * height * 4);
- if (!buffer)
- return false;
-
- CGContextRef textureContext = CGBitmapContextCreate(buffer, width, height, 8, width * 4,
- CGImageGetColorSpace(textureImage), kCGImageAlphaPremultipliedLast);
- CGContextSetBlendMode(textureContext, kCGBlendModeCopy);
- CGContextDrawImage(textureContext, CGRectMake(0, 0, (CGFloat)width, (CGFloat)height), textureImage);
- CGContextRelease(textureContext);
- return true;
-}
-
int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, void* pixels)
{
// FIXME: Need to do bounds checking on the buffer here.
@@ -1160,20 +1135,12 @@ int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned inte
int GraphicsContext3D::texImage2D(unsigned target, unsigned level, Image* image, bool flipY, bool premultiplyAlpha)
{
- // FIXME: need to support flipY and premultiplyAlpha
- UNUSED_PARAM(flipY);
- UNUSED_PARAM(premultiplyAlpha);
- ASSERT(image);
-
ensureContext(m_contextObj);
- GLubyte* buffer;
- size_t width;
- size_t height;
- if (!imageToTexture(image, buffer, width, height))
+ Vector<uint8_t> imageData;
+ unsigned int format, internalFormat;
+ if (!extractImageData(image, flipY, premultiplyAlpha, imageData, &format, &internalFormat))
return -1;
-
- ::glTexImage2D(target, level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
- fastFree(buffer);
+ ::glTexImage2D(target, level, internalFormat, image->width(), image->height(), 0, format, GL_UNSIGNED_BYTE, imageData.data());
return 0;
}
@@ -1188,20 +1155,12 @@ int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned x
int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, Image* image, bool flipY, bool premultiplyAlpha)
{
// FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size
- // FIXME: need to support flipY and premultiplyAlpha
- UNUSED_PARAM(flipY);
- UNUSED_PARAM(premultiplyAlpha);
- ASSERT(image);
-
ensureContext(m_contextObj);
- GLubyte* buffer;
- size_t width;
- size_t height;
- if (!imageToTexture(image, buffer, width, height))
+ Vector<uint8_t> imageData;
+ unsigned int format, internalFormat;
+ if (!extractImageData(image, flipY, premultiplyAlpha, imageData, &format, &internalFormat))
return -1;
-
- ::glTexSubImage2D(target, level, xoff, yoff, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
- fastFree(buffer);
+ ::glTexSubImage2D(target, level, xoff, yoff, image->width(), image->height(), format, GL_UNSIGNED_BYTE, imageData.data());
return 0;
}
diff --git a/WebCore/platform/graphics/mac/IconMac.mm b/WebCore/platform/graphics/mac/IconMac.mm
index aee7234..bc8c312 100644
--- a/WebCore/platform/graphics/mac/IconMac.mm
+++ b/WebCore/platform/graphics/mac/IconMac.mm
@@ -39,6 +39,7 @@ Icon::~Icon()
{
}
+// FIXME: Move the code to ChromeClient::iconForFiles().
PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
{
if (filenames.isEmpty())
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
index e9f64be..355aa68 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
@@ -78,6 +78,9 @@ private:
static bool isAvailable();
PlatformMedia platformMedia() const;
+#if USE(ACCELERATED_COMPOSITING)
+ PlatformLayer* platformLayer() const;
+#endif
IntSize naturalSize() const;
bool hasVideo() const;
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
index dd87bb5..2b90f7a 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
@@ -445,12 +445,7 @@ void MediaPlayerPrivate::createQTMovieLayer()
#ifndef NDEBUG
[(CALayer *)m_qtVideoLayer.get() setName:@"Video layer"];
#endif
-
- // Hang the video layer from the render layer, if we have one yet. If not, we'll do this
- // later via acceleratedRenderingStateChanged().
- GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player);
- if (videoGraphicsLayer)
- videoGraphicsLayer->setContentsToMedia(m_qtVideoLayer.get());
+ // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration().
}
#endif
}
@@ -522,6 +517,11 @@ void MediaPlayerPrivate::setUpVideoRendering()
createQTMovieLayer();
break;
}
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (currentMode == MediaRenderingMovieLayer || preferredMode == MediaRenderingMovieLayer)
+ m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
+#endif
}
void MediaPlayerPrivate::tearDownVideoRendering()
@@ -576,6 +576,13 @@ PlatformMedia MediaPlayerPrivate::platformMedia() const
return plaftformMedia;
}
+#if USE(ACCELERATED_COMPOSITING)
+PlatformLayer* MediaPlayerPrivate::platformLayer() const
+{
+ return m_qtVideoLayer.get();
+}
+#endif
+
void MediaPlayerPrivate::play()
{
if (!metaDataAvailable())
@@ -1406,12 +1413,6 @@ void MediaPlayerPrivate::acceleratedRenderingStateChanged()
{
// Set up or change the rendering path if necessary.
setUpVideoRendering();
-
- if (currentRenderingMode() == MediaRenderingMovieLayer) {
- GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player);
- if (videoGraphicsLayer)
- videoGraphicsLayer->setContentsToMedia(m_qtVideoLayer.get());
- }
}
#endif
diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
index ef7c58f..09947d8 100644
--- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
+++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
@@ -273,37 +273,54 @@ void SimpleFontData::platformInit()
} else
m_xHeight = [m_platformData.font() xHeight];
}
+
+static CFDataRef copyFontTableForTag(FontPlatformData platformData, FourCharCode tableName)
+{
+#ifdef BUILDING_ON_TIGER
+ ATSFontRef atsFont = FMGetATSFontRefFromFont(platformData.m_atsuFontID);
+
+ ByteCount tableSize;
+ if (ATSFontGetTable(atsFont, tableName, 0, 0, NULL, &tableSize) != noErr)
+ return 0;
+
+ CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, tableSize);
+ if (!data)
+ return 0;
+
+ CFDataIncreaseLength(data, tableSize);
+ if (ATSFontGetTable(atsFont, tableName, 0, tableSize, CFDataGetMutableBytePtr(data), &tableSize) != noErr) {
+ CFRelease(data);
+ return 0;
+ }
+
+ return data;
+#else
+ return CGFontCopyTableForTag(platformData.cgFont(), tableName);
+#endif
+}
void SimpleFontData::platformCharWidthInit()
{
- m_avgCharWidth = 0.f;
-
- // Calculate avgCharWidth according to http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6OS2.html
- // We can try grabbing it out of the OS/2 table or via ATSFontGetHorizontalMetrics, but
- // ATSFontGetHorizontalMetrics never seems to return a non-zero value and the OS/2 table
- // contains zero for a large number of fonts.
- GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
- if (glyphPageZero) {
- static int weights[] = { 64, 14, 27, 35, 100, 20, 14, 42, 63, 3, 6, 35, 20, 56, 56, 17, 4, 49, 56, 71, 31, 10, 18, 3, 18, 2, 166 };
- int numGlyphs = 27;
- ASSERT(numGlyphs == sizeof(weights) / sizeof(int));
- // Compute the weighted sum of the space character and the lowercase letters in the Latin alphabet.
- float sum = 0.f;
- int totalWeight = 0;
- for (int i = 0; i < numGlyphs; i++) {
- Glyph glyph = glyphPageZero->glyphDataForCharacter((i < 26 ? i + 'a' : ' ')).glyph;
- if (glyph) {
- totalWeight += weights[i];
- sum += widthForGlyph(glyph) * weights[i];
- }
- }
- if (sum > 0.f && totalWeight > 0)
- m_avgCharWidth = sum / totalWeight;
+ m_avgCharWidth = 0;
+ m_maxCharWidth = 0;
+
+ RetainPtr<CFDataRef> os2Table(AdoptCF, copyFontTableForTag(m_platformData, 'OS/2'));
+ if (os2Table && CFDataGetLength(os2Table.get()) >= 4) {
+ const UInt8* os2 = CFDataGetBytePtr(os2Table.get());
+ SInt16 os2AvgCharWidth = os2[2] * 256 + os2[3];
+ m_avgCharWidth = scaleEmToUnits(os2AvgCharWidth, m_unitsPerEm) * m_platformData.m_size;
}
- m_maxCharWidth = 0.f;
- if (m_platformData.font())
- m_maxCharWidth = [m_platformData.font() maximumAdvancement].width;
+ RetainPtr<CFDataRef> headTable(AdoptCF, copyFontTableForTag(m_platformData, 'head'));
+ if (headTable && CFDataGetLength(headTable.get()) >= 42) {
+ const UInt8* head = CFDataGetBytePtr(headTable.get());
+ ushort uxMin = head[36] * 256 + head[37];
+ ushort uxMax = head[40] * 256 + head[41];
+ SInt16 xMin = static_cast<SInt16>(uxMin);
+ SInt16 xMax = static_cast<SInt16>(uxMax);
+ float diff = static_cast<float>(xMax - xMin);
+ m_maxCharWidth = scaleEmToUnits(diff, m_unitsPerEm) * m_platformData.m_size;
+ }
// Fallback to a cross-platform estimate, which will populate these values if they are non-positive.
initCharWidths();
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index 105d866..8bcda2e 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -219,6 +219,7 @@ public:
QStack<TransparencyLayer*> layers;
QPainter* redirect;
+ // reuse this brush for solid color (to prevent expensive QBrush construction)
QBrush solidColor;
InterpolationQuality imageInterpolationQuality;
@@ -760,11 +761,30 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int, b
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
{
- QRectF rect(frect);
- rect = m_data->p()->deviceMatrix().mapRect(rect);
+ // It is not enough just to round to pixels in device space. The rotation part of the
+ // affine transform matrix to device space can mess with this conversion if we have a
+ // rotating image like the hands of the world clock widget. We just need the scale, so
+ // we get the affine transform matrix and extract the scale.
+ QPainter* painter = platformContext();
+ QTransform deviceTransform = painter->deviceTransform();
+ if (deviceTransform.isIdentity())
+ return frect;
- QRect result = rect.toRect(); //round it
- return FloatRect(QRectF(result));
+ qreal deviceScaleX = sqrtf(deviceTransform.m11() * deviceTransform.m11() + deviceTransform.m12() * deviceTransform.m12());
+ qreal deviceScaleY = sqrtf(deviceTransform.m21() * deviceTransform.m21() + deviceTransform.m22() * deviceTransform.m22());
+
+ QPoint deviceOrigin(frect.x() * deviceScaleX, frect.y() * deviceScaleY);
+ QPoint deviceLowerRight(frect.right() * deviceScaleX, frect.bottom() * deviceScaleY);
+
+ // Don't let the height or width round to 0 unless either was originally 0
+ if (deviceOrigin.y() == deviceLowerRight.y() && frect.height())
+ deviceLowerRight.setY(deviceLowerRight.y() + 1);
+ if (deviceOrigin.x() == deviceLowerRight.x() && frect.width())
+ deviceLowerRight.setX(deviceLowerRight.x() + 1);
+
+ FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x() / deviceScaleX, deviceOrigin.y() / deviceScaleY);
+ FloatPoint roundedLowerRight = FloatPoint(deviceLowerRight.x() / deviceScaleX, deviceLowerRight.y() / deviceScaleY);
+ return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin);
}
void GraphicsContext::setPlatformShadow(const IntSize& size, int, const Color&, ColorSpace)
@@ -1112,7 +1132,8 @@ void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colo
return;
QPainter* p = m_data->p();
QPen newPen(p->pen());
- newPen.setColor(color);
+ m_data->solidColor.setColor(color);
+ newPen.setBrush(m_data->solidColor);
p->setPen(newPen);
}
diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
index 11f7384..0fd0f1a 100644
--- a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
@@ -136,7 +136,9 @@ public:
virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*);
// we manage transforms ourselves because transform-origin acts differently in webkit and in Qt
- void setBaseTransform(const QTransform&);
+ void setBaseTransform(const TransformationMatrix&);
+ QTransform computeTransform(const TransformationMatrix& baseTransform) const;
+ void updateTransform();
// let the compositor-API tell us which properties were changed
void notifyChange(ChangeMask);
@@ -145,7 +147,7 @@ public:
// this is called indirectly from ChromeClientQt::setNeedsOneShotDrawingSynchronization
// (meaning the sync would happen together with the next draw)
// or ChromeClientQt::scheduleCompositingLayerSync (meaning the sync will happen ASAP)
- void flushChanges(bool recursive = true);
+ void flushChanges(bool recursive = true, bool forceTransformUpdate = false);
// optimization: when we have an animation running on an element with no contents, that has child-elements with contents,
// ALL of them have to have ItemCoordinateCache and not DeviceCoordinateCache
@@ -166,7 +168,7 @@ signals:
public:
GraphicsLayerQt* m_layer;
- QTransform m_baseTransform;
+ TransformationMatrix m_baseTransform;
bool m_transformAnimationRunning;
bool m_opacityAnimationRunning;
QWeakPointer<MaskEffectQt> m_maskEffect;
@@ -237,7 +239,10 @@ GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer)
{
// we use graphics-view for compositing, not for interactivity
setAcceptedMouseButtons(Qt::NoButton);
- setEnabled(false);
+ // we need to have the item enabled, or else wheel events are not
+ // passed to the parent class implementation of wheelEvent, where
+ // they are ignored and passed to the item below.
+ setEnabled(true);
// we'll set the cache when we know what's going on
setCacheMode(NoCache);
@@ -280,18 +285,54 @@ void GraphicsLayerQtImpl::adjustCachingRecursively(bool animationIsRunning)
}
}
-void GraphicsLayerQtImpl::setBaseTransform(const QTransform& transform)
+void GraphicsLayerQtImpl::updateTransform()
+{
+ setBaseTransform(isTransformAnimationRunning() ? m_baseTransform : m_layer->transform());
+}
+
+void GraphicsLayerQtImpl::setBaseTransform(const TransformationMatrix& baseTransform)
+{
+ m_baseTransform = baseTransform;
+ setTransform(computeTransform(baseTransform));
+}
+
+QTransform GraphicsLayerQtImpl::computeTransform(const TransformationMatrix& baseTransform) const
{
if (!m_layer)
- return;
+ return baseTransform;
+
+ TransformationMatrix computedTransform;
+
+ // The origin for childrenTransform is always the center of the ancestor which contains the childrenTransform.
+ // this has to do with how WebCore implements -webkit-perspective and -webkit-perspective-origin, which are the CSS
+ // attribute that call setChildrenTransform
+ QPointF offset = -pos() - boundingRect().bottomRight() / 2;
+ const GraphicsLayerQtImpl* ancestor = this;
+ while ((ancestor = qobject_cast<GraphicsLayerQtImpl*>(ancestor->parentObject()))) {
+ if (!ancestor->m_state.childrenTransform.isIdentity()) {
+ offset += ancestor->boundingRect().bottomRight() / 2;
+ computedTransform
+ .translate(offset.x(), offset.y())
+ .multLeft(ancestor->m_state.childrenTransform)
+ .translate(-offset.x(), -offset.y());
+ break;
+ }
+ offset -= ancestor->pos();
+ }
+
+ computedTransform.multLeft(baseTransform);
+
// webkit has relative-to-size originPoint, graphics-view has a pixel originPoint, here we convert
// we have to manage this ourselves because QGraphicsView's transformOrigin is incompatible
- const qreal x = m_layer->anchorPoint().x() * m_layer->size().width();
- const qreal y = m_layer->anchorPoint().y() * m_layer->size().height();
- setTransform(QTransform::fromTranslate(x, y));
- setTransform(transform, true);
- translate(-x, -y);
- m_baseTransform = transform;
+ const qreal originX = m_state.anchorPoint.x() * m_size.width();
+ const qreal originY = m_state.anchorPoint.y() * m_size.height();
+ computedTransform = TransformationMatrix()
+ .translate(originX, originY)
+ .multiply(computedTransform)
+ .translate(-originX, -originY);
+
+ // now we project to 2D
+ return QTransform(computedTransform);
}
bool GraphicsLayerQtImpl::isTransformAnimationRunning() const
@@ -357,7 +398,7 @@ void GraphicsLayerQtImpl::notifyChange(ChangeMask changeMask)
m_layer->client()->notifySyncRequired(m_layer);
}
-void GraphicsLayerQtImpl::flushChanges(bool recursive)
+void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform)
{
// this is the bulk of the work. understanding what the compositor is trying to achieve,
// what graphics-view can do, and trying to find a sane common-grounds
@@ -425,12 +466,15 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive)
}
}
- if (m_changeMask & (TransformChange | AnchorPointChange | SizeChange)) {
- // since we convert a percentage-based origin-point to a pixel-based one,
- // the anchor-point, transform and size from WebCore all affect the one
- // that we give Qt
- if (m_state.transform != m_layer->transform() || m_state.anchorPoint != m_layer->anchorPoint() || m_state.size != m_layer->size())
- setBaseTransform(m_layer->transform());
+ // FIXME: this is a hack, due to a probable QGraphicsScene bug when rapidly modifying the perspective
+ // but without this line we get graphic artifacts
+ if ((m_changeMask & ChildrenTransformChange) && m_state.childrenTransform != m_layer->childrenTransform())
+ scene()->update();
+
+ if (m_changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange)) {
+ // due to the differences between the way WebCore handles transforms and the way Qt handles transforms,
+ // all these elements affect the transforms of all the descendants.
+ forceUpdateTransform = true;
}
if (m_changeMask & (ContentChange | DrawsContentChange | MaskLayerChange)) {
@@ -439,8 +483,6 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive)
update();
setFlag(ItemHasNoContents, false);
- // we only use ItemUsesExtendedStyleOption for HTML content - pixmap can be handled better with regular clipping
- setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, false);
break;
case ColorContentType:
@@ -524,6 +566,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive)
m_state.drawsContent = m_layer->drawsContent();
m_state.contentsOpaque = m_layer->contentsOpaque();
m_state.backfaceVisibility = m_layer->backfaceVisibility();
+ m_state.childrenTransform = m_layer->childrenTransform();
m_currentContent.pixmap = m_pendingContent.pixmap;
m_currentContent.contentType = m_pendingContent.contentType;
m_currentContent.backgroundColor = m_pendingContent.backgroundColor;
@@ -534,6 +577,9 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive)
afterLayerChanges:
+ if (forceUpdateTransform)
+ updateTransform();
+
if (!recursive)
return;
@@ -544,7 +590,7 @@ afterLayerChanges:
for (QList<QGraphicsItem*>::const_iterator it = children.begin(); it != children.end(); ++it) {
if (QGraphicsItem* item = *it)
if (GraphicsLayerQtImpl* layer = qobject_cast<GraphicsLayerQtImpl*>(item->toGraphicsObject()))
- layer->flushChanges(true);
+ layer->flushChanges(true, forceUpdateTransform);
}
}
@@ -1013,7 +1059,7 @@ public:
// this came up during the compositing/animation LayoutTests
// when the animation dies, the transform has to go back to default
if (m_layer)
- m_layer.data()->setBaseTransform(m_layer.data()->m_layer->transform());
+ m_layer.data()->updateTransform();
}
// the idea is that we let WebCore manage the transform-operations
diff --git a/WebCore/platform/graphics/qt/IconQt.cpp b/WebCore/platform/graphics/qt/IconQt.cpp
index a9870fc..eb09eda 100644
--- a/WebCore/platform/graphics/qt/IconQt.cpp
+++ b/WebCore/platform/graphics/qt/IconQt.cpp
@@ -40,6 +40,7 @@ Icon::~Icon()
{
}
+// FIXME: Move the code to ChromeClient::iconForFiles().
PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
{
if (filenames.isEmpty())
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
index 234f78b..18e7f08 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
@@ -102,7 +102,7 @@ size_t ImageDecoderQt::frameCount()
// Fixup for Qt decoders... imageCount() is wrong
// and jumpToNextImage does not work either... so
// we will have to parse everything...
- if (imageCount == 0)
+ if (!imageCount)
forceLoadEverything();
else
m_frameBufferCache.resize(imageCount);
@@ -132,13 +132,13 @@ RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index)
// In case the ImageDecoderQt got recreated we don't know
// yet how many images we are going to have and need to
// find that out now.
- int count = m_frameBufferCache.size();
- if (!m_failed && count == 0) {
+ size_t count = m_frameBufferCache.size();
+ if (!m_failed && !count) {
internalDecodeSize();
count = frameCount();
}
- if (index >= static_cast<size_t>(count))
+ if (index >= count)
return 0;
RGBA32Buffer& frame = m_frameBufferCache[index];
@@ -215,7 +215,7 @@ void ImageDecoderQt::forceLoadEverything()
do {
m_frameBufferCache.resize(++imageCount);
internalHandleCurrentImage(imageCount - 1);
- } while(!m_failed);
+ } while (!m_failed);
// If we failed decoding the first image we actually
// have no images and need to keep m_failed set to
diff --git a/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp
new file mode 100644
index 0000000..cd86e6d
--- /dev/null
+++ b/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 Apple 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 met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "GraphicsContext3D.h"
+
+#include "Image.h"
+#include "NativeImageSkia.h"
+
+namespace WebCore {
+
+bool GraphicsContext3D::getImageData(Image* image,
+ Vector<uint8_t>& outputVector,
+ bool premultiplyAlpha,
+ bool* hasAlphaChannel,
+ AlphaOp* neededAlphaOp,
+ unsigned int* format)
+{
+ if (!image)
+ return false;
+ NativeImageSkia* skiaImage = image->nativeImageForCurrentFrame();
+ if (!skiaImage)
+ return false;
+ SkBitmap::Config skiaConfig = skiaImage->config();
+ // FIXME: must support more image configurations.
+ if (skiaConfig != SkBitmap::kARGB_8888_Config)
+ return false;
+ SkBitmap& skiaImageRef = *skiaImage;
+ SkAutoLockPixels lock(skiaImageRef);
+ int width = skiaImage->width();
+ int height = skiaImage->height();
+ int rowBytes = skiaImage->rowBytes();
+ ASSERT(rowBytes == width * 4);
+ uint8_t* pixels = reinterpret_cast<uint8_t*>(skiaImage->getPixels());
+ outputVector.resize(rowBytes * height);
+ memcpy(outputVector.data(), pixels, rowBytes * height);
+ *hasAlphaChannel = true;
+ if (!premultiplyAlpha)
+ // FIXME: must fetch the image data before the premultiplication step
+ *neededAlphaOp = kAlphaDoUnmultiply;
+ // FIXME: remove this dependency on desktop OpenGL
+ *format = 0x80E1; // GL_BGRA
+ return true;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
index 92a1870..e0f6f5d 100644
--- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
@@ -344,15 +344,6 @@ void PlatformContextSkia::setupPaintForFilling(SkPaint* paint) const
paint->setShader(m_state->m_fillShader);
}
-static SkScalar scalarBound(SkScalar v, SkScalar min, SkScalar max)
-{
- if (v < min)
- return min;
- if (v > max)
- return max;
- return v;
-}
-
float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const
{
setupPaintCommon(paint);
@@ -361,13 +352,10 @@ float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, i
paint->setColor(m_state->applyAlpha(m_state->m_strokeColor));
paint->setShader(m_state->m_strokeShader);
paint->setStyle(SkPaint::kStroke_Style);
- // The limits here (512 and 256) were made up but are hopefully large
- // enough to be reasonable. They are, empirically, small enough not to
- // cause overflows in Skia.
- paint->setStrokeWidth(scalarBound(SkFloatToScalar(width), 0, 512));
+ paint->setStrokeWidth(SkFloatToScalar(width));
paint->setStrokeCap(m_state->m_lineCap);
paint->setStrokeJoin(m_state->m_lineJoin);
- paint->setStrokeMiter(scalarBound(SkFloatToScalar(m_state->m_miterLimit), 0, 256));
+ paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit));
if (m_state->m_dash)
paint->setPathEffect(m_state->m_dash);
diff --git a/WebCore/platform/graphics/win/IconWin.cpp b/WebCore/platform/graphics/win/IconWin.cpp
index 56b46de..cc9343a 100644
--- a/WebCore/platform/graphics/win/IconWin.cpp
+++ b/WebCore/platform/graphics/win/IconWin.cpp
@@ -47,6 +47,7 @@ Icon::~Icon()
DestroyIcon(m_hIcon);
}
+// FIXME: Move the code to ChromeClient::iconForFiles().
PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
{
if (filenames.isEmpty())
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
index b2fe069..1df73a7 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -108,6 +108,13 @@ PlatformMedia MediaPlayerPrivate::platformMedia() const
return p;
}
+#if USE(ACCELERATED_COMPOSITING)
+PlatformLayer* MediaPlayerPrivate::platformLayer() const
+{
+ return m_qtVideoLayer->platformLayer();
+}
+#endif
+
class TaskTimer : TimerBase {
public:
static void initialize();
@@ -745,6 +752,11 @@ void MediaPlayerPrivate::setUpVideoRendering()
if (preferredMode == MediaRenderingMovieLayer)
createLayerForMovie();
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (currentMode == MediaRenderingMovieLayer || preferredMode == MediaRenderingMovieLayer)
+ m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
+#endif
}
void MediaPlayerPrivate::tearDownVideoRendering()
@@ -810,11 +822,6 @@ void MediaPlayerPrivate::createLayerForMovie()
if (!m_qtMovie || m_qtVideoLayer)
return;
- // Do nothing if the parent layer hasn't been set up yet.
- GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player);
- if (!videoGraphicsLayer)
- return;
-
// Create a GraphicsLayer that won't be inserted directly into the render tree, but will used
// as a wrapper for a WKCACFLayer which gets inserted as the content layer of the video
// renderer's GraphicsLayer.
@@ -829,9 +836,7 @@ void MediaPlayerPrivate::createLayerForMovie()
#ifndef NDEBUG
m_qtVideoLayer->setName("Video layer");
#endif
-
- // Hang the video layer from the render layer.
- videoGraphicsLayer->setContentsToMedia(m_qtVideoLayer->platformLayer());
+ // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration().
#endif
}
@@ -858,7 +863,7 @@ void MediaPlayerPrivate::acceleratedRenderingStateChanged()
void MediaPlayerPrivate::notifySyncRequired(const GraphicsLayer*)
{
- GraphicsLayerCACF* videoGraphicsLayer = static_cast<GraphicsLayerCACF*>(m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player));
+ GraphicsLayerCACF* videoGraphicsLayer = static_cast<GraphicsLayerCACF*>(m_qtVideoLayer.get());
if (videoGraphicsLayer)
videoGraphicsLayer->notifySyncRequired();
}
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
index d58f44f..029a520 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
@@ -76,6 +76,9 @@ private:
virtual bool supportsFullscreen() const;
virtual PlatformMedia platformMedia() const;
+#if USE(ACCELERATED_COMPOSITING)
+ PlatformLayer* platformLayer() const;
+#endif
IntSize naturalSize() const;
bool hasVideo() const;
diff --git a/WebCore/platform/gtk/PasteboardGtk.cpp b/WebCore/platform/gtk/PasteboardGtk.cpp
index 0b4d356..5c7d9a7 100644
--- a/WebCore/platform/gtk/PasteboardGtk.cpp
+++ b/WebCore/platform/gtk/PasteboardGtk.cpp
@@ -134,7 +134,8 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String&)
ASSERT(node && node->renderer() && node->renderer()->isImage());
RenderImage* renderer = toRenderImage(node->renderer());
CachedImage* cachedImage = renderer->cachedImage();
- ASSERT(cachedImage);
+ if (!cachedImage || cachedImage->errorOccurred())
+ return;
Image* image = cachedImage->image();
ASSERT(image);
diff --git a/WebCore/platform/gtk/RenderThemeGtk.cpp b/WebCore/platform/gtk/RenderThemeGtk.cpp
index 727788a..e19e2fa 100644
--- a/WebCore/platform/gtk/RenderThemeGtk.cpp
+++ b/WebCore/platform/gtk/RenderThemeGtk.cpp
@@ -27,9 +27,11 @@
#include "AffineTransform.h"
#include "CString.h"
#include "GOwnPtr.h"
+#include "Gradient.h"
#include "GraphicsContext.h"
#include "HTMLMediaElement.h"
#include "HTMLNames.h"
+#include "MediaControlElements.h"
#include "NotImplemented.h"
#include "RenderBox.h"
#include "RenderObject.h"
@@ -686,9 +688,46 @@ bool RenderThemeGtk::paintMediaSeekForwardButton(RenderObject* o, const RenderOb
bool RenderThemeGtk::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- paintInfo.context->fillRect(FloatRect(r), m_panelColor, DeviceColorSpace);
- paintInfo.context->fillRect(FloatRect(IntRect(r.x(), r.y() + (r.height() - m_mediaSliderHeight) / 2,
- r.width(), m_mediaSliderHeight)), m_sliderColor, DeviceColorSpace);
+ GraphicsContext* context = paintInfo.context;
+
+ context->fillRect(FloatRect(r), m_panelColor, DeviceColorSpace);
+ context->fillRect(FloatRect(IntRect(r.x(), r.y() + (r.height() - m_mediaSliderHeight) / 2,
+ r.width(), m_mediaSliderHeight)), m_sliderColor, DeviceColorSpace);
+
+ RenderStyle* style = o->style();
+ HTMLMediaElement* mediaElement = toParentMediaElement(o);
+
+ if (!mediaElement)
+ return false;
+
+ // Draw the buffered ranges. This code is highly inspired from
+ // Chrome.
+ // FIXME: Draw multiple ranges if there are multiple buffered
+ // ranges. The current implementation of the player is always
+ // buffering a single range anyway.
+ IntRect bufferedRect = r;
+ bufferedRect.inflate(-style->borderLeftWidth());
+ bufferedRect.setWidth((bufferedRect.width() * mediaElement->percentLoaded()));
+
+ // Don't bother drawing an empty area.
+ if (bufferedRect.isEmpty())
+ return false;
+
+ IntPoint sliderTopLeft = bufferedRect.location();
+ IntPoint sliderTopRight = sliderTopLeft;
+ sliderTopRight.move(0, bufferedRect.height());
+
+ RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderTopRight);
+ Color startColor = m_panelColor;
+ gradient->addColorStop(0.0, startColor);
+ gradient->addColorStop(1.0, Color(startColor.red() / 2, startColor.green() / 2, startColor.blue() / 2, startColor.alpha()));
+
+ context->save();
+ context->setStrokeStyle(NoStroke);
+ context->setFillGradient(gradient);
+ context->fillRect(bufferedRect);
+ context->restore();
+
return false;
}
diff --git a/WebCore/platform/gtk/WidgetGtk.cpp b/WebCore/platform/gtk/WidgetGtk.cpp
index 53c10f1..834c21a 100644
--- a/WebCore/platform/gtk/WidgetGtk.cpp
+++ b/WebCore/platform/gtk/WidgetGtk.cpp
@@ -82,16 +82,18 @@ void Widget::setCursor(const Cursor& cursor)
void Widget::show()
{
- if (!platformWidget())
- return;
- gtk_widget_show(platformWidget());
+ setSelfVisible(true);
+
+ if (isParentVisible() && platformWidget())
+ gtk_widget_show(platformWidget());
}
void Widget::hide()
{
- if (!platformWidget())
- return;
- gtk_widget_hide(platformWidget());
+ setSelfVisible(false);
+
+ if (isParentVisible() && platformWidget())
+ gtk_widget_hide(platformWidget());
}
void Widget::paint(GraphicsContext* context, const IntRect& rect)
diff --git a/WebCore/platform/haiku/FileSystemHaiku.cpp b/WebCore/platform/haiku/FileSystemHaiku.cpp
index 7400cd1..3d9161a 100644
--- a/WebCore/platform/haiku/FileSystemHaiku.cpp
+++ b/WebCore/platform/haiku/FileSystemHaiku.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
*
* All rights reserved.
*
@@ -29,9 +30,14 @@
#include "FileSystem.h"
#include "CString.h"
+#include "NotImplemented.h"
#include "PlatformString.h"
-#include "NotImplemented.h"
+#include <Directory.h>
+#include <Entry.h>
+#include <File.h>
+#include <FindDirectory.h>
+#include <Path.h>
namespace WebCore {
@@ -43,8 +49,11 @@ CString fileSystemRepresentation(const String& string)
String homeDirectoryPath()
{
- notImplemented();
- return String();
+ BPath path;
+ if (find_directory(B_USER_DIRECTORY, &path) != B_OK)
+ return String();
+
+ return String(path.Path());
}
CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle)
@@ -74,7 +83,10 @@ bool unloadModule(PlatformModule)
Vector<String> listDirectory(const String& path, const String& filter)
{
Vector<String> entries;
- notImplemented();
+ BDirectory directory(path.utf8().data());
+ entry_ref ref;
+ while (directory.GetNextRef(&ref) == B_OK)
+ entries.append(ref.name);
return entries;
}
diff --git a/WebCore/platform/image-decoders/ImageDecoder.cpp b/WebCore/platform/image-decoders/ImageDecoder.cpp
index ed13048..86bcb45 100644
--- a/WebCore/platform/image-decoders/ImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/ImageDecoder.cpp
@@ -58,30 +58,24 @@ static unsigned copyFromSharedBuffer(char* buffer, unsigned bufferLength, const
// TODO: Find a better fix.
ImageDecoder* ImageDecoder::create(const SharedBuffer& data)
{
- // We need at least 4 bytes to figure out what kind of image we're dealing with.
+ // We need at least 4 bytes to figure out what kind of image we're dealing
+ // with.
static const unsigned maxMarkerLength = 4;
char contents[maxMarkerLength];
unsigned length = copyFromSharedBuffer(contents, maxMarkerLength, data, 0);
if (length < maxMarkerLength)
return 0;
- const unsigned char* uContents = reinterpret_cast<const unsigned char*>(contents);
-
// GIFs begin with GIF8(7 or 9).
if (strncmp(contents, "GIF8", 4) == 0)
return new GIFImageDecoder();
// Test for PNG.
- if (uContents[0]==0x89 &&
- uContents[1]==0x50 &&
- uContents[2]==0x4E &&
- uContents[3]==0x47)
+ if (!memcmp(contents, "\x89\x50\x4E\x47", 4))
return new PNGImageDecoder();
// JPEG
- if (uContents[0]==0xFF &&
- uContents[1]==0xD8 &&
- uContents[2]==0xFF)
+ if (!memcmp(contents, "\xFF\xD8\xFF", 3))
return new JPEGImageDecoder();
// BMP
@@ -90,8 +84,7 @@ ImageDecoder* ImageDecoder::create(const SharedBuffer& data)
// 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, "\000\000\001\000", 4) ||
- !memcmp(contents, "\000\000\002\000", 4))
+ if (!memcmp(contents, "\x00\x00\x01\x00", 4) || !memcmp(contents, "\x00\x00\x02\x00", 4))
return new ICOImageDecoder();
// Give up. We don't know what the heck this is.
@@ -109,14 +102,27 @@ RGBA32Buffer::RGBA32Buffer()
{
}
+RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other)
+{
+ if (this == &other)
+ return *this;
+
+ copyBitmapData(other);
+ setRect(other.rect());
+ setStatus(other.status());
+ setDuration(other.duration());
+ setDisposalMethod(other.disposalMethod());
+ return *this;
+}
+
void RGBA32Buffer::clear()
{
m_bytes.clear();
m_status = FrameEmpty;
- // NOTE: Do not reset other members here; clearFrameBufferCache()
- // calls this to free the bitmap data, but other functions like
- // initFrameBuffer() and frameComplete() may still need to read
- // other metadata out of this frame later.
+ // NOTE: Do not reset other members here; clearFrameBufferCache() calls this
+ // to free the bitmap data, but other functions like initFrameBuffer() and
+ // frameComplete() may still need to read other metadata out of this frame
+ // later.
}
void RGBA32Buffer::zeroFill()
@@ -137,8 +143,8 @@ void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other)
bool RGBA32Buffer::setSize(int newWidth, int newHeight)
{
- // NOTE: This has no way to check for allocation failure if the
- // requested size was too big...
+ // NOTE: This has no way to check for allocation failure if the requested
+ // size was too big...
m_bytes.resize(newWidth * newHeight);
m_size = IntSize(newWidth, newHeight);
@@ -163,19 +169,6 @@ void RGBA32Buffer::setStatus(FrameStatus status)
m_status = status;
}
-RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other)
-{
- if (this == &other)
- return *this;
-
- copyBitmapData(other);
- setRect(other.rect());
- setStatus(other.status());
- setDuration(other.duration());
- setDisposalMethod(other.disposalMethod());
- return *this;
-}
-
int RGBA32Buffer::width() const
{
return m_size.width();
@@ -200,13 +193,11 @@ inline void fillScaledValues(Vector<int>& scaledValues, double scaleRate, int le
{
double inflateRate = 1. / scaleRate;
scaledValues.reserveCapacity(static_cast<int>(length * scaleRate + 0.5));
- for (int scaledIndex = 0;;) {
+ for (int scaledIndex = 0; ; ++scaledIndex) {
int index = static_cast<int>(scaledIndex * inflateRate + 0.5);
- if (index < length) {
- scaledValues.append(index);
- ++scaledIndex;
- } else
+ if (index >= length)
break;
+ scaledValues.append(index);
}
}
diff --git a/WebCore/platform/image-decoders/ImageDecoder.h b/WebCore/platform/image-decoders/ImageDecoder.h
index 8d27072..002395b 100644
--- a/WebCore/platform/image-decoders/ImageDecoder.h
+++ b/WebCore/platform/image-decoders/ImageDecoder.h
@@ -46,18 +46,21 @@
namespace WebCore {
- // The RGBA32Buffer object represents the decoded image data in RGBA32 format. This buffer is what all
- // decoders write a single frame into. Frames are then instantiated for drawing by being handed this buffer.
+ // The RGBA32Buffer object represents the decoded image data in RGBA32
+ // format. This buffer is what all decoders write a single frame into.
+ // Frames are then instantiated for drawing by being handed this buffer.
class RGBA32Buffer {
public:
enum FrameStatus { FrameEmpty, FramePartial, FrameComplete };
enum FrameDisposalMethod {
- // If you change the numeric values of these, make sure you audit all
- // users, as some users may cast raw values to/from these constants.
- DisposeNotSpecified, // Leave frame in framebuffer
- DisposeKeep, // Leave frame in framebuffer
- DisposeOverwriteBgcolor, // Clear frame to transparent
- DisposeOverwritePrevious, // Clear frame to previous framebuffer contents
+ // If you change the numeric values of these, make sure you audit
+ // all users, as some users may cast raw values to/from these
+ // constants.
+ DisposeNotSpecified, // Leave frame in framebuffer
+ DisposeKeep, // Leave frame in framebuffer
+ DisposeOverwriteBgcolor, // Clear frame to transparent
+ DisposeOverwritePrevious, // Clear frame to previous framebuffer
+ // contents
};
#if PLATFORM(SKIA) || PLATFORM(QT)
typedef uint32_t PixelData;
@@ -67,15 +70,11 @@ namespace WebCore {
RGBA32Buffer();
- // For backends which refcount their data, this constructor doesn't need
- // to create a new copy of the image data, only increase the ref count.
- //
- // This exists because ImageDecoder keeps a Vector<RGBA32Buffer>, and
- // Vector requires this constructor.
- RGBA32Buffer(const RGBA32Buffer& other)
- {
- operator=(other);
- }
+ RGBA32Buffer(const RGBA32Buffer& other) { operator=(other); }
+
+ // For backends which refcount their data, this operator doesn't need to
+ // create a new copy of the image data, only increase the ref count.
+ RGBA32Buffer& operator=(const RGBA32Buffer& other);
// Deletes the pixel data entirely; used by ImageDecoder to save memory
// when we no longer need to display a frame and only need its metadata.
@@ -142,8 +141,6 @@ namespace WebCore {
#endif
private:
- RGBA32Buffer& operator=(const RGBA32Buffer& other);
-
int width() const;
int height() const;
@@ -188,26 +185,33 @@ namespace WebCore {
Vector<PixelData> m_bytes;
IntSize m_size; // The size of the buffer. This should be the
// same as ImageDecoder::m_size.
- bool m_hasAlpha; // Whether or not any of the pixels in the buffer have transparency.
+ bool m_hasAlpha; // Whether or not any of the pixels in the buffer
+ // have transparency.
#endif
- IntRect m_rect; // The rect of the original specified frame within the overall buffer.
- // This will always just be the entire buffer except for GIF frames
- // whose original rect was smaller than the overall image size.
- FrameStatus m_status; // Whether or not this frame is completely finished decoding.
+ IntRect m_rect; // The rect of the original specified frame within
+ // the overall buffer. This will always just be
+ // the entire buffer except for GIF frames whose
+ // original rect was smaller than the overall
+ // image size.
+ FrameStatus m_status; // Whether or not this frame is completely
+ // finished decoding.
unsigned m_duration; // The animation delay.
FrameDisposalMethod m_disposalMethod;
- // What to do with this frame's data when initializing the next frame.
+ // What to do with this frame's data when
+ // initializing the next frame.
};
- // The ImageDecoder class represents a base class for specific image format decoders
- // (e.g., GIF, JPG, PNG, ICO) to derive from. All decoders decode into RGBA32 format
- // and the base class manages the RGBA32 frame cache.
+ // The ImageDecoder class represents a base class for specific image format
+ // decoders (e.g., GIF, JPG, PNG, ICO) to derive from. All decoders decode
+ // into RGBA32 format and the base class manages the RGBA32 frame cache.
+ //
+ // ENABLE(IMAGE_DECODER_DOWN_SAMPLING) allows image decoders to write
+ // directly to scaled output buffers by down sampling. Call
+ // setMaxNumPixels() to specify the biggest size that decoded images can
+ // have. Image decoders will deflate those images that are bigger than
+ // m_maxNumPixels. (Not supported by all image decoders yet)
class ImageDecoder : public Noncopyable {
public:
- // ENABLE(IMAGE_DECODER_DOWN_SAMPLING) allows image decoders to write directly to
- // scaled output buffers by down sampling. Call setMaxNumPixels() to specify the
- // biggest size that decoded images can have. Image decoders will deflate those
- // images that are bigger than m_maxNumPixels. (Not supported by all image decoders yet)
ImageDecoder()
: m_scaled(false)
, m_failed(false)
@@ -224,21 +228,22 @@ namespace WebCore {
// needing to write a dedicated setData() implementation.
static ImageDecoder* create(const SharedBuffer& data);
- // The the filename extension usually associated with an undecoded image of this type.
+ // The the filename extension usually associated with an undecoded image
+ // of this type.
virtual String filenameExtension() const = 0;
- // All specific decoder plugins must do something with the data they are given.
bool isAllDataReceived() const { return m_isAllDataReceived; }
+
virtual void setData(SharedBuffer* data, bool allDataReceived)
{
m_data = data;
m_isAllDataReceived = allDataReceived;
}
- // Whether or not the size information has been decoded yet. This default
- // implementation just returns true if the size has been set and we have not
- // seen a failure. Decoders may want to override this to lazily decode
- // enough of the image to get the size.
+ // Whether or not the size information has been decoded yet. This
+ // default implementation just returns true if the size has been set and
+ // we have not seen a failure. Decoders may want to override this to
+ // lazily decode enough of the image to get the size.
virtual bool isSizeAvailable()
{
return !m_failed && m_sizeAvailable;
@@ -266,10 +271,10 @@ namespace WebCore {
return size();
}
- // Called by the image decoders to set their decoded size, this also check
- // the size for validity. It will return true if the size was set, or false
- // if there is an error. On error, the m_failed flag will be set and the
- // caller should immediately stop decoding.
+ // Called by the image decoders to set their decoded size, this also
+ // checks the size for validity. It will return true if the size was
+ // set, or false if there is an error. On error, the m_failed flag will
+ // be set and the caller should immediately stop decoding.
virtual bool setSize(unsigned width, unsigned height)
{
if (isOverSize(width, height)) {
@@ -281,29 +286,30 @@ namespace WebCore {
return true;
}
- // The total number of frames for the image. Classes that support multiple frames
- // will scan the image data for the answer if they need to (without necessarily
- // decoding all of the individual frames).
+ // The total number of frames for the image. Classes that support
+ // multiple frames will scan the image data for the answer if they need
+ // to (without necessarily decoding all of the individual frames).
virtual size_t frameCount() { return 1; }
// The number of repetitions to perform for an animation loop.
virtual int repetitionCount() const { return cAnimationNone; }
- // Called to obtain the RGBA32Buffer full of decoded data for rendering. The
- // decoder plugin will decode as much of the frame as it can before handing
- // back the buffer.
+ // Called to obtain the RGBA32Buffer full of decoded data for rendering.
+ // The decoder plugin will decode as much of the frame as it can before
+ // handing back the buffer.
virtual RGBA32Buffer* frameBufferAtIndex(size_t) = 0;
- // Whether or not the underlying image format even supports alpha transparency.
+ // Whether or not the underlying image format even supports alpha
+ // transparency.
virtual bool supportsAlpha() const { return true; }
bool failed() const { return m_failed; }
void setFailed() { m_failed = true; }
// Wipe out frames in the frame buffer cache before |clearBeforeFrame|,
- // assuming this can be done without breaking decoding. Different decoders
- // place different restrictions on what frames are safe to destroy, so this
- // is left to them to implement.
+ // assuming this can be done without breaking decoding. Different
+ // decoders place different restrictions on what frames are safe to
+ // destroy, so this is left to them to implement.
// For convenience's sake, we provide a default (empty) implementation,
// since in practice only GIFs will ever use this.
virtual void clearFrameBufferCache(size_t clearBeforeFrame) { }
diff --git a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp
index de0690f..fb9f9f2 100644
--- a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp
@@ -41,9 +41,7 @@ namespace WebCore {
static const size_t sizeOfFileHeader = 14;
BMPImageDecoder::BMPImageDecoder()
- : ImageDecoder()
- , m_allDataReceived(false)
- , m_decodedOffset(0)
+ : m_decodedOffset(0)
{
}
@@ -53,7 +51,6 @@ void BMPImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
return;
ImageDecoder::setData(data, allDataReceived);
- m_allDataReceived = allDataReceived;
if (m_reader)
m_reader->setData(data);
}
@@ -61,7 +58,7 @@ void BMPImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
bool BMPImageDecoder::isSizeAvailable()
{
if (!ImageDecoder::isSizeAvailable() && !failed())
- decodeWithCheckForDataEnded(true);
+ decode(true);
return ImageDecoder::isSizeAvailable();
}
@@ -76,31 +73,29 @@ RGBA32Buffer* BMPImageDecoder::frameBufferAtIndex(size_t index)
RGBA32Buffer* buffer = &m_frameBufferCache.first();
if (buffer->status() != RGBA32Buffer::FrameComplete && !failed())
- decodeWithCheckForDataEnded(false);
+ decode(false);
return buffer;
}
-void BMPImageDecoder::decodeWithCheckForDataEnded(bool onlySize)
+void BMPImageDecoder::decode(bool onlySize)
{
if (failed())
return;
// If we couldn't decode the image but we've received all the data, decoding
// has failed.
- if (!decode(onlySize) && m_allDataReceived)
+ if (!decodeHelper(onlySize) && isAllDataReceived())
setFailed();
}
-bool BMPImageDecoder::decode(bool onlySize)
+bool BMPImageDecoder::decodeHelper(bool onlySize)
{
size_t imgDataOffset = 0;
- if ((m_decodedOffset < sizeOfFileHeader)
- && !processFileHeader(&imgDataOffset))
+ if ((m_decodedOffset < sizeOfFileHeader) && !processFileHeader(&imgDataOffset))
return false;
if (!m_reader) {
- m_reader.set(new BMPImageReader(this, m_decodedOffset, imgDataOffset,
- false));
+ m_reader.set(new BMPImageReader(this, m_decodedOffset, imgDataOffset, false));
m_reader->setData(m_data.get());
}
@@ -118,8 +113,7 @@ bool BMPImageDecoder::processFileHeader(size_t* imgDataOffset)
ASSERT(!m_decodedOffset);
if (m_data->size() < sizeOfFileHeader)
return false;
- const uint16_t fileType =
- (m_data->data()[0] << 8) | static_cast<uint8_t>(m_data->data()[1]);
+ const uint16_t fileType = (m_data->data()[0] << 8) | static_cast<uint8_t>(m_data->data()[1]);
*imgDataOffset = readUint32(10);
m_decodedOffset = sizeOfFileHeader;
diff --git a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h
index c793585..15be0a2 100644
--- a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h
+++ b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h
@@ -50,29 +50,23 @@ namespace WebCore {
private:
inline uint32_t readUint32(int offset) const
{
- return BMPImageReader::readUint32(m_data.get(),
- m_decodedOffset + offset);
+ return BMPImageReader::readUint32(m_data.get(), m_decodedOffset + offset);
}
// Decodes the image. If |onlySize| is true, stops decoding after
// calculating the image size. If decoding fails but there is no more
// data coming, sets the "decode failure" flag.
- void decodeWithCheckForDataEnded(bool onlySize);
+ void decode(bool onlySize);
// Decodes the image. If |onlySize| is true, stops decoding after
// calculating the image size. Returns whether decoding succeeded.
- // NOTE: Used internally by decodeWithCheckForDataEnded(). Other people
- // should not call this.
- bool decode(bool onlySize);
+ bool decodeHelper(bool onlySize);
// Processes the file header at the beginning of the data. Sets
// |*imgDataOffset| based on the header contents. Returns true if the
// file header could be decoded.
bool processFileHeader(size_t* imgDataOffset);
- // True if we've seen all the data.
- bool m_allDataReceived;
-
// An index into |m_data| representing how much we've already decoded.
// Note that this only tracks data _this_ class decodes; once the
// BMPImageReader takes over this will not be updated further.
diff --git a/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp b/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp
index 1936d81..2f3bffa 100644
--- a/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp
+++ b/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp
@@ -33,10 +33,7 @@
namespace WebCore {
-BMPImageReader::BMPImageReader(ImageDecoder* parent,
- size_t decodedAndHeaderOffset,
- size_t imgDataOffset,
- bool usesAndMask)
+BMPImageReader::BMPImageReader(ImageDecoder* parent, size_t decodedAndHeaderOffset, size_t imgDataOffset, bool usesAndMask)
: m_parent(parent)
, m_buffer(0)
, m_decodedOffset(decodedAndHeaderOffset)
@@ -63,8 +60,7 @@ bool BMPImageReader::decodeBMP(bool onlySize)
return false;
// Read and process info header.
- if ((m_decodedOffset < (m_headerOffset + m_infoHeader.biSize))
- && !processInfoHeader())
+ if ((m_decodedOffset < (m_headerOffset + m_infoHeader.biSize)) && !processInfoHeader())
return false;
// processInfoHeader() set the size, so if that's all we needed, we're done.
@@ -82,8 +78,7 @@ bool BMPImageReader::decodeBMP(bool onlySize)
// Initialize the framebuffer if needed.
ASSERT(m_buffer); // Parent should set this before asking us to decode!
if (m_buffer->status() == RGBA32Buffer::FrameEmpty) {
- if (!m_buffer->setSize(m_parent->size().width(),
- m_parent->size().height()))
+ if (!m_buffer->setSize(m_parent->size().width(), m_parent->size().height()))
return setFailed(); // Unable to allocate.
m_buffer->setStatus(RGBA32Buffer::FramePartial);
// setSize() calls eraseARGB(), which resets the alpha flag, so we force
@@ -100,9 +95,7 @@ bool BMPImageReader::decodeBMP(bool onlySize)
// Decode the data.
if ((m_andMaskState != Decoding) && !pastEndOfImage(0)) {
- if ((m_infoHeader.biCompression == RLE4)
- || (m_infoHeader.biCompression == RLE8)
- || (m_infoHeader.biCompression == RLE24)) {
+ if ((m_infoHeader.biCompression == RLE4) || (m_infoHeader.biCompression == RLE8) || (m_infoHeader.biCompression == RLE24)) {
if (!processRLEData())
return false;
} else if (!processNonRLEData(false, 0))
@@ -133,8 +126,7 @@ bool BMPImageReader::readInfoHeaderSize()
{
// Get size of info header.
ASSERT(m_decodedOffset == m_headerOffset);
- if ((m_decodedOffset > m_data->size())
- || ((m_data->size() - m_decodedOffset) < 4))
+ if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset) < 4))
return false;
m_infoHeader.biSize = readUint32(0);
// Don't increment m_decodedOffset here, it just makes the code in
@@ -143,9 +135,7 @@ bool BMPImageReader::readInfoHeaderSize()
// Don't allow the header to overflow (which would be harmless here, but
// problematic or at least confusing in other places), or to overrun the
// image data.
- if (((m_headerOffset + m_infoHeader.biSize) < m_headerOffset)
- || (m_imgDataOffset
- && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize))))
+ if (((m_headerOffset + m_infoHeader.biSize) < m_headerOffset) || (m_imgDataOffset && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize))))
return setFailed();
// See if this is a header size we understand:
@@ -156,9 +146,7 @@ bool BMPImageReader::readInfoHeaderSize()
else if ((m_infoHeader.biSize == 40) || isWindowsV4Plus())
;
// OS/2 2.x: any multiple of 4 between 16 and 64, inclusive, or 42 or 46
- else if ((m_infoHeader.biSize >= 16) && (m_infoHeader.biSize <= 64)
- && (((m_infoHeader.biSize & 3) == 0) || (m_infoHeader.biSize == 42)
- || (m_infoHeader.biSize == 46)))
+ else if ((m_infoHeader.biSize >= 16) && (m_infoHeader.biSize <= 64) && (!(m_infoHeader.biSize & 3) || (m_infoHeader.biSize == 42) || (m_infoHeader.biSize == 46)))
m_isOS22x = true;
else
return setFailed();
@@ -170,9 +158,7 @@ bool BMPImageReader::processInfoHeader()
{
// Read info header.
ASSERT(m_decodedOffset == m_headerOffset);
- if ((m_decodedOffset > m_data->size())
- || ((m_data->size() - m_decodedOffset) < m_infoHeader.biSize)
- || !readInfoHeader())
+ if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset) < m_infoHeader.biSize) || !readInfoHeader())
return false;
m_decodedOffset += m_infoHeader.biSize;
@@ -188,11 +174,9 @@ bool BMPImageReader::processInfoHeader()
// colors", so set it to the maximum number of colors for this bit depth.
// Also do this for bitmaps that put too large a value here.
if (m_infoHeader.biBitCount < 16) {
- const uint32_t maxColors =
- static_cast<uint32_t>(1) << m_infoHeader.biBitCount;
- if ((m_infoHeader.biClrUsed == 0)
- || (m_infoHeader.biClrUsed > maxColors))
- m_infoHeader.biClrUsed = maxColors;
+ const uint32_t maxColors = static_cast<uint32_t>(1) << m_infoHeader.biBitCount;
+ if (!m_infoHeader.biClrUsed || (m_infoHeader.biClrUsed > maxColors))
+ m_infoHeader.biClrUsed = maxColors;
}
// For any bitmaps that set their BitCount to the wrong value, reset the
@@ -206,7 +190,7 @@ bool BMPImageReader::processInfoHeader()
// Tell caller what still needs to be processed.
if (m_infoHeader.biBitCount >= 16)
m_needToProcessBitmasks = true;
- else if (m_infoHeader.biBitCount > 0)
+ else if (m_infoHeader.biBitCount)
m_needToProcessColorTable = true;
return true;
@@ -246,8 +230,7 @@ bool BMPImageReader::readInfoHeader()
} else if (biCompression > 5)
return setFailed(); // Some type we don't understand.
else
- m_infoHeader.biCompression =
- static_cast<CompressionType>(biCompression);
+ m_infoHeader.biCompression = static_cast<CompressionType>(biCompression);
}
// Read colors used, if present.
@@ -288,7 +271,7 @@ bool BMPImageReader::isInfoHeaderValid() const
{
// Non-positive widths/heights are invalid. (We've already flipped the
// sign of the height for top-down bitmaps.)
- if ((m_infoHeader.biWidth <= 0) || (m_infoHeader.biHeight == 0))
+ if ((m_infoHeader.biWidth <= 0) || !m_infoHeader.biHeight)
return false;
// Only Windows V3+ has top-down bitmaps.
@@ -296,16 +279,10 @@ bool BMPImageReader::isInfoHeaderValid() const
return false;
// Only bit depths of 1, 4, 8, or 24 are universally supported.
- if ((m_infoHeader.biBitCount != 1) && (m_infoHeader.biBitCount != 4)
- && (m_infoHeader.biBitCount != 8)
- && (m_infoHeader.biBitCount != 24)) {
+ if ((m_infoHeader.biBitCount != 1) && (m_infoHeader.biBitCount != 4) && (m_infoHeader.biBitCount != 8) && (m_infoHeader.biBitCount != 24)) {
// Windows V3+ additionally supports bit depths of 0 (for embedded
// JPEG/PNG images), 16, and 32.
- if (m_isOS21x || m_isOS22x)
- return false;
- if ((m_infoHeader.biBitCount != 0)
- && (m_infoHeader.biBitCount != 16)
- && (m_infoHeader.biBitCount != 32))
+ if (m_isOS21x || m_isOS22x || (m_infoHeader.biBitCount && (m_infoHeader.biBitCount != 16) && (m_infoHeader.biBitCount != 32)))
return false;
}
@@ -314,7 +291,7 @@ bool BMPImageReader::isInfoHeaderValid() const
// some compression types.
switch (m_infoHeader.biCompression) {
case RGB:
- if (m_infoHeader.biBitCount == 0)
+ if (!m_infoHeader.biBitCount)
return false;
break;
@@ -323,46 +300,38 @@ bool BMPImageReader::isInfoHeaderValid() const
// Compression = RLE4" (which means "4 bit, but with a 2-color table"),
// so also allow the paletted RLE compression types to have too low a
// bit count; we'll correct this later.
- if (m_infoHeader.biBitCount == 0 || m_infoHeader.biBitCount > 8)
+ if (!m_infoHeader.biBitCount || (m_infoHeader.biBitCount > 8))
return false;
break;
case RLE4:
// See comments in RLE8.
- if (m_infoHeader.biBitCount == 0 || m_infoHeader.biBitCount > 4)
+ if (!m_infoHeader.biBitCount || (m_infoHeader.biBitCount > 4))
return false;
break;
case BITFIELDS:
// Only valid for Windows V3+.
- if (m_isOS21x || m_isOS22x)
- return false;
- if ((m_infoHeader.biBitCount != 16) && (m_infoHeader.biBitCount != 32))
+ if (m_isOS21x || m_isOS22x || ((m_infoHeader.biBitCount != 16) && (m_infoHeader.biBitCount != 32)))
return false;
break;
case JPEG:
case PNG:
// Only valid for Windows V3+.
- if (m_isOS21x || m_isOS22x)
- return false;
- if (m_infoHeader.biBitCount != 0)
+ if (m_isOS21x || m_isOS22x || m_infoHeader.biBitCount)
return false;
break;
case HUFFMAN1D:
// Only valid for OS/2 2.x.
- if (!m_isOS22x)
- return false;
- if (m_infoHeader.biBitCount != 1)
+ if (!m_isOS22x || (m_infoHeader.biBitCount != 1))
return false;
break;
case RLE24:
// Only valid for OS/2 2.x.
- if (!m_isOS22x)
- return false;
- if (m_infoHeader.biBitCount != 24)
+ if (!m_isOS22x || (m_infoHeader.biBitCount != 24))
return false;
break;
@@ -374,8 +343,7 @@ bool BMPImageReader::isInfoHeaderValid() const
}
// Top-down bitmaps cannot be compressed; they must be RGB or BITFIELDS.
- if (m_isTopDown && (m_infoHeader.biCompression != RGB)
- && (m_infoHeader.biCompression != BITFIELDS))
+ if (m_isTopDown && (m_infoHeader.biCompression != RGB) && (m_infoHeader.biCompression != BITFIELDS))
return false;
// Reject the following valid bitmap types that we don't currently bother
@@ -385,13 +353,11 @@ bool BMPImageReader::isInfoHeaderValid() const
// * Bitmaps larger than 2^16 pixels in either dimension (Windows
// probably doesn't draw these well anyway, and the decoded data would
// take a lot of memory).
- if ((m_infoHeader.biWidth >= (1 << 16))
- || (m_infoHeader.biHeight >= (1 << 16)))
+ if ((m_infoHeader.biWidth >= (1 << 16)) || (m_infoHeader.biHeight >= (1 << 16)))
return false;
// * Windows V3+ JPEG-in-BMP and PNG-in-BMP bitmaps (supposedly not found
// in the wild, only used to send data to printers?).
- if ((m_infoHeader.biCompression == JPEG)
- || (m_infoHeader.biCompression == PNG))
+ if ((m_infoHeader.biCompression == JPEG) || (m_infoHeader.biCompression == PNG))
return false;
// * OS/2 2.x Huffman-encoded monochrome bitmaps (see
// http://www.fileformat.info/mirror/egff/ch09_05.htm , re: "G31D"
@@ -413,11 +379,8 @@ bool BMPImageReader::processBitmasks()
// 16 bits: MSB <- xRRRRRGG GGGBBBBB -> LSB
// 24/32 bits: MSB <- [AAAAAAAA] RRRRRRRR GGGGGGGG BBBBBBBB -> LSB
const int numBits = (m_infoHeader.biBitCount == 16) ? 5 : 8;
- for (int i = 0; i <= 2; ++i) {
- m_bitMasks[i] =
- ((static_cast<uint32_t>(1) << (numBits * (3 - i))) - 1) ^
- ((static_cast<uint32_t>(1) << (numBits * (2 - i))) - 1);
- }
+ for (int i = 0; i <= 2; ++i)
+ m_bitMasks[i] = ((static_cast<uint32_t>(1) << (numBits * (3 - i))) - 1) ^ ((static_cast<uint32_t>(1) << (numBits * (2 - i))) - 1);
// For Windows V4+ 32-bit RGB, don't overwrite the alpha mask from the
// header (see note in readInfoHeader()).
@@ -431,10 +394,7 @@ bool BMPImageReader::processBitmasks()
// Fail if we don't have enough file space for the bitmasks.
static const size_t SIZEOF_BITMASKS = 12;
- if (((m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS) <
- (m_headerOffset + m_infoHeader.biSize))
- || (m_imgDataOffset && (m_imgDataOffset <
- (m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS))))
+ if (((m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS) < (m_headerOffset + m_infoHeader.biSize)) || (m_imgDataOffset && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS))))
return setFailed();
// Read bitmasks.
@@ -461,8 +421,7 @@ bool BMPImageReader::processBitmasks()
// specify a bogus alpha channel in bits that don't exist in the pixel
// data (for example, bits 25-31 in a 24-bit RGB format).
if (m_infoHeader.biBitCount < 32)
- m_bitMasks[i] &=
- ((static_cast<uint32_t>(1) << m_infoHeader.biBitCount) - 1);
+ m_bitMasks[i] &= ((static_cast<uint32_t>(1) << m_infoHeader.biBitCount) - 1);
// For empty masks (common on the alpha channel, especially after the
// trimming above), quickly clear the shifts and continue, to avoid an
@@ -507,15 +466,11 @@ bool BMPImageReader::processColorTable()
m_tableSizeInBytes = m_infoHeader.biClrUsed * (m_isOS21x ? 3 : 4);
// Fail if we don't have enough file space for the color table.
- if (((m_headerOffset + m_infoHeader.biSize + m_tableSizeInBytes) <
- (m_headerOffset + m_infoHeader.biSize))
- || (m_imgDataOffset && (m_imgDataOffset <
- (m_headerOffset + m_infoHeader.biSize + m_tableSizeInBytes))))
+ if (((m_headerOffset + m_infoHeader.biSize + m_tableSizeInBytes) < (m_headerOffset + m_infoHeader.biSize)) || (m_imgDataOffset && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize + m_tableSizeInBytes))))
return setFailed();
// Read color table.
- if ((m_decodedOffset > m_data->size())
- || ((m_data->size() - m_decodedOffset) < m_tableSizeInBytes))
+ if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset) < m_tableSizeInBytes))
return false;
m_colorTable.resize(m_infoHeader.biClrUsed);
for (size_t i = 0; i < m_infoHeader.biClrUsed; ++i) {
@@ -573,7 +528,7 @@ bool BMPImageReader::processRLEData()
// the image.
const uint8_t count = m_data->data()[m_decodedOffset];
const uint8_t code = m_data->data()[m_decodedOffset + 1];
- if (((count != 0) || (code != 1)) && pastEndOfImage(0))
+ if ((count || (code != 1)) && pastEndOfImage(0))
return setFailed();
// Decode.
@@ -590,10 +545,7 @@ bool BMPImageReader::processRLEData()
case 1: // Magic token: EOF
// Skip any remaining pixels in the image.
- if ((m_coord.x() < m_parent->size().width())
- || (m_isTopDown
- ? (m_coord.y() < (m_parent->size().height() - 1))
- : (m_coord.y() > 0)))
+ if ((m_coord.x() < m_parent->size().width()) || (m_isTopDown ? (m_coord.y() < (m_parent->size().height() - 1)) : (m_coord.y() > 0)))
m_buffer->setHasAlpha(true);
return true;
@@ -607,10 +559,9 @@ bool BMPImageReader::processRLEData()
// past the end of the image.
const uint8_t dx = m_data->data()[m_decodedOffset + 2];
const uint8_t dy = m_data->data()[m_decodedOffset + 3];
- if ((dx != 0) || (dy != 0))
+ if (dx || dy)
m_buffer->setHasAlpha(true);
- if (((m_coord.x() + dx) > m_parent->size().width()) ||
- pastEndOfImage(dy))
+ if (((m_coord.x() + dx) > m_parent->size().width()) || pastEndOfImage(dy))
return setFailed();
// Skip intervening pixels.
@@ -637,8 +588,7 @@ bool BMPImageReader::processRLEData()
// The following color data is repeated for |count| total pixels.
// Strangely, some BMPs seem to specify excessively large counts
// here; ignore pixels past the end of the row.
- const int endX =
- std::min(m_coord.x() + count, m_parent->size().width());
+ const int endX = std::min(m_coord.x() + count, m_parent->size().width());
if (m_infoHeader.biCompression == RLE24) {
// Bail if there isn't enough data.
@@ -646,8 +596,7 @@ bool BMPImageReader::processRLEData()
return false;
// One BGR triple that we copy |count| times.
- fillRGBA(endX, m_data->data()[m_decodedOffset + 3],
- m_data->data()[m_decodedOffset + 2], code, 0xff);
+ fillRGBA(endX, m_data->data()[m_decodedOffset + 3], m_data->data()[m_decodedOffset + 2], code, 0xff);
m_decodedOffset += 4;
} else {
// RLE8 has one color index that gets repeated; RLE4 has two
@@ -658,8 +607,7 @@ bool BMPImageReader::processRLEData()
colorIndexes[0] = (colorIndexes[0] >> 4) & 0xf;
colorIndexes[1] &= 0xf;
}
- if ((colorIndexes[0] >= m_infoHeader.biClrUsed)
- || (colorIndexes[1] >= m_infoHeader.biClrUsed))
+ if ((colorIndexes[0] >= m_infoHeader.biClrUsed) || (colorIndexes[1] >= m_infoHeader.biClrUsed))
return setFailed();
for (int which = 0; m_coord.x() < endX; ) {
setI(colorIndexes[which]);
@@ -689,9 +637,7 @@ bool BMPImageReader::processNonRLEData(bool inRLE, int numPixels)
// requires.
const size_t pixelsPerByte = 8 / m_infoHeader.biBitCount;
const size_t bytesPerPixel = m_infoHeader.biBitCount / 8;
- const size_t unpaddedNumBytes = (m_infoHeader.biBitCount < 16)
- ? ((numPixels + pixelsPerByte - 1) / pixelsPerByte)
- : (numPixels * bytesPerPixel);
+ const size_t unpaddedNumBytes = (m_infoHeader.biBitCount < 16) ? ((numPixels + pixelsPerByte - 1) / pixelsPerByte) : (numPixels * bytesPerPixel);
// RLE runs are zero-padded at the end to a multiple of 16 bits. Non-RLE
// data is in rows and is zero-padded to a multiple of 32 bits.
const size_t alignBits = inRLE ? 1 : 3;
@@ -711,10 +657,8 @@ bool BMPImageReader::processNonRLEData(bool inRLE, int numPixels)
const uint8_t mask = (1 << m_infoHeader.biBitCount) - 1;
for (size_t byte = 0; byte < unpaddedNumBytes; ++byte) {
uint8_t pixelData = m_data->data()[m_decodedOffset + byte];
- for (size_t pixel = 0;
- (pixel < pixelsPerByte) && (m_coord.x() < endX); ++pixel) {
- const size_t colorIndex =
- (pixelData >> (8 - m_infoHeader.biBitCount)) & mask;
+ for (size_t pixel = 0; (pixel < pixelsPerByte) && (m_coord.x() < endX); ++pixel) {
+ const size_t colorIndex = (pixelData >> (8 - m_infoHeader.biBitCount)) & mask;
if (m_andMaskState == Decoding) {
// There's no way to accurately represent an AND + XOR
// operation as an RGBA image, so where the AND values
@@ -749,7 +693,7 @@ bool BMPImageReader::processNonRLEData(bool inRLE, int numPixels)
// images where all alpha values are 255; opaque images are
// faster to draw.
int alpha = getAlpha(pixel);
- if (!m_seenNonZeroAlphaPixel && (alpha == 0)) {
+ if (!m_seenNonZeroAlphaPixel && !alpha) {
m_seenZeroAlphaPixel = true;
alpha = 255;
} else {
diff --git a/WebCore/platform/image-decoders/bmp/BMPImageReader.h b/WebCore/platform/image-decoders/bmp/BMPImageReader.h
index 3536e3b..a30a721 100644
--- a/WebCore/platform/image-decoders/bmp/BMPImageReader.h
+++ b/WebCore/platform/image-decoders/bmp/BMPImageReader.h
@@ -57,8 +57,7 @@ namespace WebCore {
uint32_t result;
memcpy(&result, &data->data()[offset], 4);
#if CPU(BIG_ENDIAN)
- result = ((result & 0xff) << 24) | ((result & 0xff00) << 8) |
- ((result & 0xff0000) >> 8) | ((result & 0xff000000) >> 24);
+ result = ((result & 0xff) << 24) | ((result & 0xff00) << 8) | ((result & 0xff0000) >> 8) | ((result & 0xff000000) >> 24);
#endif
return result;
}
@@ -67,10 +66,7 @@ namespace WebCore {
// |startOffset| points to the start of the BMP within the file.
// |buffer| points at an empty RGBA32Buffer that we'll initialize and
// fill with decoded data.
- BMPImageReader(ImageDecoder* parent,
- size_t decodedAndHeaderOffset,
- size_t imgDataOffset,
- bool usesAndMask);
+ BMPImageReader(ImageDecoder* parent, size_t decodedAndHeaderOffset, size_t imgDataOffset, bool usesAndMask);
void setBuffer(RGBA32Buffer* buffer) { m_buffer = buffer; }
void setData(SharedBuffer* data) { m_data = data; }
@@ -179,9 +175,7 @@ namespace WebCore {
// image", so downwards for m_isTopDown images and upwards otherwise.
inline bool pastEndOfImage(int numRows)
{
- return m_isTopDown
- ? ((m_coord.y() + numRows) >= m_parent->size().height())
- : ((m_coord.y() - numRows) < 0);
+ return m_isTopDown ? ((m_coord.y() + numRows) >= m_parent->size().height()) : ((m_coord.y() - numRows) < 0);
}
// Returns the pixel data for the current X coordinate in a uint32_t.
@@ -203,8 +197,7 @@ namespace WebCore {
uint32_t pixel;
memcpy(&pixel, &m_data->data()[m_decodedOffset + offset], 3);
#if CPU(BIG_ENDIAN)
- pixel = ((pixel & 0xff00) << 8) | ((pixel & 0xff0000) >> 8) |
- ((pixel & 0xff000000) >> 24);
+ pixel = ((pixel & 0xff00) << 8) | ((pixel & 0xff0000) >> 8) | ((pixel & 0xff000000) >> 24);
#endif
return pixel;
}
@@ -222,17 +215,13 @@ namespace WebCore {
// in the given pixel data.
inline unsigned getComponent(uint32_t pixel, int component) const
{
- return ((pixel & m_bitMasks[component]) >>
- m_bitShiftsRight[component]) << m_bitShiftsLeft[component];
+ return ((pixel & m_bitMasks[component]) >> m_bitShiftsRight[component]) << m_bitShiftsLeft[component];
}
inline unsigned getAlpha(uint32_t pixel) const
{
// For images without alpha, return alpha of 0xff.
- if (m_bitMasks[3] == 0)
- return 0xff;
-
- return getComponent(pixel, 3);
+ return m_bitMasks[3] ? getComponent(pixel, 3) : 0xff;
}
// Sets the current pixel to the color given by |colorIndex|. This also
@@ -240,9 +229,7 @@ namespace WebCore {
// right by one.
inline void setI(size_t colorIndex)
{
- setRGBA(m_colorTable[colorIndex].rgbRed,
- m_colorTable[colorIndex].rgbGreen,
- m_colorTable[colorIndex].rgbBlue, 0xff);
+ setRGBA(m_colorTable[colorIndex].rgbRed, m_colorTable[colorIndex].rgbGreen, m_colorTable[colorIndex].rgbBlue, 0xff);
}
// Like setI(), but with the individual component values specified.
@@ -251,8 +238,7 @@ namespace WebCore {
unsigned blue,
unsigned alpha)
{
- m_buffer->setRGBA(m_coord.x(), m_coord.y(), red, green, blue,
- alpha);
+ m_buffer->setRGBA(m_coord.x(), m_coord.y(), red, green, blue, alpha);
m_coord.move(1, 0);
}
diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
index 1124bd2..807d57c 100644
--- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
@@ -30,7 +30,7 @@
namespace WebCore {
GIFImageDecoder::GIFImageDecoder()
- : m_frameCountValid(true)
+ : m_alreadyScannedThisDataForFrameCount(true)
, m_repetitionCount(cAnimationLoopOnce)
, m_readOffset(0)
{
@@ -40,56 +40,45 @@ GIFImageDecoder::~GIFImageDecoder()
{
}
-// Take the data and store it.
void GIFImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
{
if (m_failed)
return;
- // Cache our new data.
ImageDecoder::setData(data, allDataReceived);
- // Our frame count is now unknown.
- m_frameCountValid = false;
+ // We need to rescan the frame count, as the new data may have changed it.
+ m_alreadyScannedThisDataForFrameCount = false;
- // Create the GIF reader.
if (!m_reader && !m_failed)
m_reader.set(new GIFImageReader(this));
}
-// Whether or not the size information has been decoded yet.
bool GIFImageDecoder::isSizeAvailable()
{
if (!ImageDecoder::isSizeAvailable() && !failed() && m_reader)
- decode(GIFSizeQuery, 0);
+ decode(0, GIFSizeQuery);
return ImageDecoder::isSizeAvailable();
}
-// The total number of frames for the image. Will scan the image data for the answer
-// (without necessarily decoding all of the individual frames).
size_t GIFImageDecoder::frameCount()
{
- // If the decoder had an earlier error, we will just return what we had decoded
- // so far.
- if (!m_frameCountValid) {
- // FIXME: Scanning all the data has O(n^2) behavior if the data were to come in really
- // slowly. Might be interesting to try to clone our existing read session to preserve
- // state, but for now we just crawl all the data. Note that this is no worse than what
- // ImageIO does on Mac right now (it also crawls all the data again).
+ if (!m_alreadyScannedThisDataForFrameCount) {
+ // FIXME: Scanning all the data has O(n^2) behavior if the data were to
+ // come in really slowly. Might be interesting to try to clone our
+ // existing read session to preserve state, but for now we just crawl
+ // all the data. Note that this is no worse than what ImageIO does on
+ // Mac right now (it also crawls all the data again).
GIFImageReader reader(0);
- // This function may fail, but we want to keep any partial data it may
- // have decoded, so don't mark it is invalid. If there is an overflow
- // or some serious error, m_failed will have gotten set for us.
reader.read((const unsigned char*)m_data->data(), m_data->size(), GIFFrameCountQuery, static_cast<unsigned>(-1));
- m_frameCountValid = true;
+ m_alreadyScannedThisDataForFrameCount = true;
m_frameBufferCache.resize(reader.images_count);
}
return m_frameBufferCache.size();
}
-// The number of repetitions to perform for an animation loop.
int GIFImageDecoder::repetitionCount() const
{
// This value can arrive at any point in the image data stream. Most GIFs
@@ -120,7 +109,7 @@ RGBA32Buffer* GIFImageDecoder::frameBufferAtIndex(size_t index)
RGBA32Buffer& frame = m_frameBufferCache[index];
if (frame.status() != RGBA32Buffer::FrameComplete && m_reader)
- decode(GIFFullQuery, index + 1); // Decode this frame.
+ decode(index + 1, GIFFullQuery); // Decode this frame.
return &frame;
}
@@ -174,23 +163,11 @@ void GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame)
}
}
-// Feed data to the GIF reader.
-void GIFImageDecoder::decode(GIFQuery query, unsigned haltAtFrame)
-{
- if (m_failed)
- return;
-
- m_failed = !m_reader->read((const unsigned char*)m_data->data() + m_readOffset, m_data->size() - m_readOffset, query, haltAtFrame);
-
- if (m_failed)
- m_reader.clear();
-}
-
-// Callbacks from the GIF reader.
bool GIFImageDecoder::sizeNowAvailable(unsigned width, unsigned height)
{
if (!setSize(width, height))
return false;
+
prepareScaleDataIfNecessary();
return true;
}
@@ -200,94 +177,7 @@ void GIFImageDecoder::decodingHalted(unsigned bytesLeft)
m_readOffset = m_data->size() - bytesLeft;
}
-bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
-{
- // Initialize the frame rect in our buffer.
- const GIFFrameReader* frameReader = m_reader->frame_reader;
- IntRect frameRect(frameReader->x_offset, frameReader->y_offset, frameReader->width, frameReader->height);
-
- // Make sure the frameRect doesn't extend past the bottom-right of the buffer.
- if (frameRect.right() > size().width())
- frameRect.setWidth(size().width() - frameReader->x_offset);
- if (frameRect.bottom() > size().height())
- frameRect.setHeight(size().height() - frameReader->y_offset);
-
- RGBA32Buffer* const buffer = &m_frameBufferCache[frameIndex];
- int left = upperBoundScaledX(frameRect.x());
- int right = lowerBoundScaledX(frameRect.right(), left);
- int top = upperBoundScaledY(frameRect.y());
- int bottom = lowerBoundScaledY(frameRect.bottom(), top);
- buffer->setRect(IntRect(left, top, right - left, bottom - top));
-
- if (frameIndex == 0) {
- // This is the first frame, so we're not relying on any previous data.
- if (!buffer->setSize(scaledSize().width(), scaledSize().height())) {
- m_failed = true;
- return false;
- }
- } else {
- // The starting state for this frame depends on the previous frame's
- // disposal method.
- //
- // Frames that use the DisposeOverwritePrevious method are effectively
- // no-ops in terms of changing the starting state of a frame compared to
- // the starting state of the previous frame, so skip over them. (If the
- // first frame specifies this method, it will get treated like
- // DisposeOverwriteBgcolor below and reset to a completely empty image.)
- const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex];
- RGBA32Buffer::FrameDisposalMethod prevMethod =
- prevBuffer->disposalMethod();
- while ((frameIndex > 0)
- && (prevMethod == RGBA32Buffer::DisposeOverwritePrevious)) {
- prevBuffer = &m_frameBufferCache[--frameIndex];
- prevMethod = prevBuffer->disposalMethod();
- }
- ASSERT(prevBuffer->status() == RGBA32Buffer::FrameComplete);
-
- if ((prevMethod == RGBA32Buffer::DisposeNotSpecified) ||
- (prevMethod == RGBA32Buffer::DisposeKeep)) {
- // Preserve the last frame as the starting state for this frame.
- buffer->copyBitmapData(*prevBuffer);
- } else {
- // We want to clear the previous frame to transparent, without
- // affecting pixels in the image outside of the frame.
- const IntRect& prevRect = prevBuffer->rect();
- const IntSize& bufferSize = scaledSize();
- if ((frameIndex == 0)
- || prevRect.contains(IntRect(IntPoint(), bufferSize))) {
- // Clearing the first frame, or a frame the size of the whole
- // image, results in a completely empty image.
- if (!buffer->setSize(bufferSize.width(), bufferSize.height())) {
- m_failed = true;
- return false;
- }
- } else {
- // Copy the whole previous buffer, then clear just its frame.
- buffer->copyBitmapData(*prevBuffer);
- for (int y = prevRect.y(); y < prevRect.bottom(); ++y) {
- for (int x = prevRect.x(); x < prevRect.right(); ++x)
- buffer->setRGBA(x, y, 0, 0, 0, 0);
- }
- if ((prevRect.width() > 0) && (prevRect.height() > 0))
- buffer->setHasAlpha(true);
- }
- }
- }
-
- // Update our status to be partially complete.
- buffer->setStatus(RGBA32Buffer::FramePartial);
-
- // Reset the alpha pixel tracker for this frame.
- m_currentBufferSawAlpha = false;
- return true;
-}
-
-bool GIFImageDecoder::haveDecodedRow(unsigned frameIndex,
- unsigned char* rowBuffer,
- unsigned char* rowEnd,
- unsigned rowNumber,
- unsigned repeatCount,
- bool writeTransparentPixels)
+bool GIFImageDecoder::haveDecodedRow(unsigned frameIndex, unsigned char* rowBuffer, unsigned char* rowEnd, unsigned rowNumber, unsigned repeatCount, bool writeTransparentPixels)
{
const GIFFrameReader* frameReader = m_reader->frame_reader;
// The pixel data and coordinates supplied to us are relative to the frame's
@@ -365,7 +255,7 @@ void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration,
// resulting buffer was non-transparent, and we can setHasAlpha(false).
if (buffer.rect().contains(IntRect(IntPoint(), scaledSize())))
buffer.setHasAlpha(false);
- else if (frameIndex > 0) {
+ else if (frameIndex) {
// Tricky case. This frame does not have alpha only if everywhere
// outside its rect doesn't have alpha. To know whether this is
// true, we check the start state of the frame -- if it doesn't have
@@ -375,8 +265,7 @@ void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration,
// don't affect the start state of this frame) the same way we do in
// initFrameBuffer().
const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex];
- while ((frameIndex > 0)
- && (prevBuffer->disposalMethod() == RGBA32Buffer::DisposeOverwritePrevious))
+ while (frameIndex && (prevBuffer->disposalMethod() == RGBA32Buffer::DisposeOverwritePrevious))
prevBuffer = &m_frameBufferCache[--frameIndex];
// Now, if we're at a DisposeNotSpecified or DisposeKeep frame, then
@@ -387,8 +276,7 @@ void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration,
// The only remaining case is a DisposeOverwriteBgcolor frame. If
// it had no alpha, and its rect is contained in the current frame's
// rect, we know the current frame has no alpha.
- if ((prevBuffer->disposalMethod() == RGBA32Buffer::DisposeOverwriteBgcolor)
- && !prevBuffer->hasAlpha() && buffer.rect().contains(prevBuffer->rect()))
+ if ((prevBuffer->disposalMethod() == RGBA32Buffer::DisposeOverwriteBgcolor) && !prevBuffer->hasAlpha() && buffer.rect().contains(prevBuffer->rect()))
buffer.setHasAlpha(false);
}
}
@@ -401,4 +289,93 @@ void GIFImageDecoder::gifComplete()
m_reader.clear();
}
+void GIFImageDecoder::decode(unsigned haltAtFrame, GIFQuery query)
+{
+ if (m_failed)
+ return;
+
+ m_failed = !m_reader->read((const unsigned char*)m_data->data() + m_readOffset, m_data->size() - m_readOffset, query, haltAtFrame);
+
+ if (m_failed)
+ m_reader.clear();
+}
+
+bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
+{
+ // Initialize the frame rect in our buffer.
+ const GIFFrameReader* frameReader = m_reader->frame_reader;
+ IntRect frameRect(frameReader->x_offset, frameReader->y_offset, frameReader->width, frameReader->height);
+
+ // Make sure the frameRect doesn't extend outside the buffer.
+ if (frameRect.right() > size().width())
+ frameRect.setWidth(size().width() - frameReader->x_offset);
+ if (frameRect.bottom() > size().height())
+ frameRect.setHeight(size().height() - frameReader->y_offset);
+
+ RGBA32Buffer* const buffer = &m_frameBufferCache[frameIndex];
+ int left = upperBoundScaledX(frameRect.x());
+ int right = lowerBoundScaledX(frameRect.right(), left);
+ int top = upperBoundScaledY(frameRect.y());
+ int bottom = lowerBoundScaledY(frameRect.bottom(), top);
+ buffer->setRect(IntRect(left, top, right - left, bottom - top));
+
+ if (!frameIndex) {
+ // This is the first frame, so we're not relying on any previous data.
+ if (!buffer->setSize(scaledSize().width(), scaledSize().height())) {
+ m_failed = true;
+ return false;
+ }
+ } else {
+ // The starting state for this frame depends on the previous frame's
+ // disposal method.
+ //
+ // Frames that use the DisposeOverwritePrevious method are effectively
+ // no-ops in terms of changing the starting state of a frame compared to
+ // the starting state of the previous frame, so skip over them. (If the
+ // first frame specifies this method, it will get treated like
+ // DisposeOverwriteBgcolor below and reset to a completely empty image.)
+ const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex];
+ RGBA32Buffer::FrameDisposalMethod prevMethod = prevBuffer->disposalMethod();
+ while (frameIndex && (prevMethod == RGBA32Buffer::DisposeOverwritePrevious)) {
+ prevBuffer = &m_frameBufferCache[--frameIndex];
+ prevMethod = prevBuffer->disposalMethod();
+ }
+ ASSERT(prevBuffer->status() == RGBA32Buffer::FrameComplete);
+
+ if ((prevMethod == RGBA32Buffer::DisposeNotSpecified) || (prevMethod == RGBA32Buffer::DisposeKeep)) {
+ // Preserve the last frame as the starting state for this frame.
+ buffer->copyBitmapData(*prevBuffer);
+ } else {
+ // We want to clear the previous frame to transparent, without
+ // affecting pixels in the image outside of the frame.
+ const IntRect& prevRect = prevBuffer->rect();
+ const IntSize& bufferSize = scaledSize();
+ if (!frameIndex || prevRect.contains(IntRect(IntPoint(), scaledSize()))) {
+ // Clearing the first frame, or a frame the size of the whole
+ // image, results in a completely empty image.
+ if (!buffer->setSize(bufferSize.width(), bufferSize.height())) {
+ m_failed = true;
+ return false;
+ }
+ } else {
+ // Copy the whole previous buffer, then clear just its frame.
+ buffer->copyBitmapData(*prevBuffer);
+ for (int y = prevRect.y(); y < prevRect.bottom(); ++y) {
+ for (int x = prevRect.x(); x < prevRect.right(); ++x)
+ buffer->setRGBA(x, y, 0, 0, 0, 0);
+ }
+ if ((prevRect.width() > 0) && (prevRect.height() > 0))
+ buffer->setHasAlpha(true);
+ }
+ }
+ }
+
+ // Update our status to be partially complete.
+ buffer->setStatus(RGBA32Buffer::FramePartial);
+
+ // Reset the alpha pixel tracker for this frame.
+ m_currentBufferSawAlpha = false;
+ return true;
+}
+
} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.h b/WebCore/platform/image-decoders/gif/GIFImageDecoder.h
index 011ca96..0aa5387 100644
--- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.h
+++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.h
@@ -37,48 +37,38 @@ namespace WebCore {
class GIFImageDecoder : public ImageDecoder {
public:
GIFImageDecoder();
- ~GIFImageDecoder();
+ virtual ~GIFImageDecoder();
- virtual String filenameExtension() const { return "gif"; }
+ enum GIFQuery { GIFFullQuery, GIFSizeQuery, GIFFrameCountQuery };
- // Take the data and store it.
+ // ImageDecoder
+ virtual String filenameExtension() const { return "gif"; }
virtual void setData(SharedBuffer* data, bool allDataReceived);
-
- // Whether or not the size information has been decoded yet.
virtual bool isSizeAvailable();
-
- // The total number of frames for the image. Will scan the image data for the answer
- // (without necessarily decoding all of the individual frames).
virtual size_t frameCount();
-
- // The number of repetitions to perform for an animation loop.
virtual int repetitionCount() const;
-
virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
-
virtual void clearFrameBufferCache(size_t clearBeforeFrame);
- virtual unsigned frameDurationAtIndex(size_t index) { return 0; }
-
- enum GIFQuery { GIFFullQuery, GIFSizeQuery, GIFFrameCountQuery };
-
- void decode(GIFQuery, unsigned haltAtFrame);
-
// Callbacks from the GIF reader.
bool sizeNowAvailable(unsigned width, unsigned height);
void decodingHalted(unsigned bytesLeft);
- bool haveDecodedRow(unsigned frameIndex, unsigned char* rowBuffer, unsigned char* rowEnd, unsigned rowNumber,
- unsigned repeatCount, bool writeTransparentPixels);
+ bool haveDecodedRow(unsigned frameIndex, unsigned char* rowBuffer, unsigned char* rowEnd, unsigned rowNumber, unsigned repeatCount, bool writeTransparentPixels);
void frameComplete(unsigned frameIndex, unsigned frameDuration, RGBA32Buffer::FrameDisposalMethod disposalMethod);
void gifComplete();
private:
- // Called to initialize the frame buffer with the given index, based on the
- // previous frame's disposal method. Returns true on success. On failure,
- // this will mark the image as failed.
+ // If the query is GIFFullQuery, decodes the image up to (but not
+ // including) |haltAtFrame|. Otherwise, decodes as much as is needed to
+ // answer the query, ignoring bitmap data.
+ void decode(unsigned haltAtFrame, GIFQuery);
+
+ // Called to initialize the frame buffer with the given index, based on
+ // the previous frame's disposal method. Returns true on success. On
+ // failure, this will mark the image as failed.
bool initFrameBuffer(unsigned frameIndex);
- bool m_frameCountValid;
+ bool m_alreadyScannedThisDataForFrameCount;
bool m_currentBufferSawAlpha;
mutable int m_repetitionCount;
OwnPtr<GIFImageReader> m_reader;
diff --git a/WebCore/platform/image-decoders/gif/GIFImageReader.cpp b/WebCore/platform/image-decoders/gif/GIFImageReader.cpp
index ffb1310..755a48d 100644
--- a/WebCore/platform/image-decoders/gif/GIFImageReader.cpp
+++ b/WebCore/platform/image-decoders/gif/GIFImageReader.cpp
@@ -290,7 +290,7 @@ bool GIFImageReader::do_lzw(const unsigned char *q)
/* Check for explicit end-of-stream code */
if (code == (clear_code + 1)) {
/* end-of-stream should only appear after all image data */
- return rows_remaining == 0;
+ return !rows_remaining;
}
if (oldcode == -1) {
@@ -494,11 +494,11 @@ bool GIFImageReader::read(const unsigned char *buf, unsigned len,
/* All GIF files begin with "GIF87a" or "GIF89a" */
case gif_type:
{
- if (!strncmp((char*)q, "GIF89a", 6)) {
+ if (!strncmp((char*)q, "GIF89a", 6))
version = 89;
- } else if (!strncmp((char*)q, "GIF87a", 6)) {
+ else if (!strncmp((char*)q, "GIF87a", 6))
version = 87;
- } else {
+ else {
state = gif_error;
break;
}
@@ -712,9 +712,10 @@ bool GIFImageReader::read(const unsigned char *buf, unsigned len,
// and doesn't do anything, as our streaming/buffering takes care of it all...
// See: http://semmix.pl/color/exgraf/eeg24.htm
GETN(1, gif_netscape_extension_block);
- } else
- state = gif_error; // 0,3-7 are yet to be defined netscape
- // extension codes
+ } else {
+ // 0,3-7 are yet to be defined netscape extension codes
+ state = gif_error;
+ }
break;
}
@@ -893,8 +894,7 @@ bool GIFImageReader::read(const unsigned char *buf, unsigned len,
// CALLBACK: The frame is now complete.
if (clientptr && frame_reader)
- clientptr->frameComplete(images_decoded - 1, frame_reader->delay_time,
- frame_reader->disposal_method);
+ clientptr->frameComplete(images_decoded - 1, frame_reader->delay_time, frame_reader->disposal_method);
/* Clear state from this image */
if (frame_reader) {
@@ -919,7 +919,6 @@ bool GIFImageReader::read(const unsigned char *buf, unsigned len,
// Handle general errors
case gif_error:
- // nsGIFDecoder2::EndGIF(gs->clientptr, gs->loop_count);
return false;
// We shouldn't ever get here.
diff --git a/WebCore/platform/image-decoders/gif/GIFImageReader.h b/WebCore/platform/image-decoders/gif/GIFImageReader.h
index 14c2fb4..5982827 100644
--- a/WebCore/platform/image-decoders/gif/GIFImageReader.h
+++ b/WebCore/platform/image-decoders/gif/GIFImageReader.h
@@ -194,10 +194,6 @@ struct GIFImageReader {
}
~GIFImageReader() {
- close();
- }
-
- void close() {
delete []global_colormap;
global_colormap = 0;
delete frame_reader;
diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp b/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp
index a0ec4f7..1a202bc 100644
--- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp
@@ -45,9 +45,11 @@ static const size_t sizeOfDirectory = 6;
static const size_t sizeOfDirEntry = 16;
ICOImageDecoder::ICOImageDecoder()
- : ImageDecoder()
- , m_allDataReceived(false)
- , m_decodedOffset(0)
+ : m_decodedOffset(0)
+{
+}
+
+ICOImageDecoder::~ICOImageDecoder()
{
}
@@ -57,10 +59,8 @@ void ICOImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
return;
ImageDecoder::setData(data, allDataReceived);
- m_allDataReceived = allDataReceived;
- for (BMPReaders::iterator i(m_bmpReaders.begin());
- i != m_bmpReaders.end(); ++i) {
+ for (BMPReaders::iterator i(m_bmpReaders.begin()); i != m_bmpReaders.end(); ++i) {
if (*i)
(*i)->setData(data);
}
@@ -71,7 +71,7 @@ void ICOImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
bool ICOImageDecoder::isSizeAvailable()
{
if (!ImageDecoder::isSizeAvailable())
- decodeWithCheckForDataEnded(0, true);
+ decode(0, true);
return ImageDecoder::isSizeAvailable();
}
@@ -83,8 +83,7 @@ IntSize ICOImageDecoder::size() const
IntSize ICOImageDecoder::frameSizeAtIndex(size_t index) const
{
- return (index && (index < m_dirEntries.size())) ?
- m_dirEntries[index].m_size : size();
+ return (index && (index < m_dirEntries.size())) ? m_dirEntries[index].m_size : size();
}
bool ICOImageDecoder::setSize(unsigned width, unsigned height)
@@ -101,7 +100,7 @@ bool ICOImageDecoder::setSize(unsigned width, unsigned height)
size_t ICOImageDecoder::frameCount()
{
- decodeWithCheckForDataEnded(0, true);
+ decode(0, true);
if (m_frameBufferCache.isEmpty())
m_frameBufferCache.resize(m_dirEntries.size());
// CAUTION: We must not resize m_frameBufferCache again after this, as
@@ -116,40 +115,19 @@ RGBA32Buffer* ICOImageDecoder::frameBufferAtIndex(size_t index)
if (index >= frameCount())
return 0;
- // Determine the image type, and if this is a BMP, decode.
- decodeWithCheckForDataEnded(index, false);
-
- // PNGs decode into their own framebuffers, so only use our internal cache
- // for non-PNGs (BMP or unknown).
- if (!m_pngDecoders[index])
- return &m_frameBufferCache[index];
-
- // Fail if the size the PNGImageDecoder calculated does not match the size
- // in the directory.
- if (m_pngDecoders[index]->isSizeAvailable()) {
- const IntSize pngSize(m_pngDecoders[index]->size());
- const IconDirectoryEntry& dirEntry = m_dirEntries[index];
- if (pngSize != dirEntry.m_size) {
- setFailed();
- m_pngDecoders[index]->setFailed();
- }
- }
-
- return m_pngDecoders[index]->frameBufferAtIndex(0);
+ RGBA32Buffer* buffer = &m_frameBufferCache[index];
+ if (buffer->status() != RGBA32Buffer::FrameComplete)
+ decode(index, false);
+ return buffer;
}
// static
-bool ICOImageDecoder::compareEntries(const IconDirectoryEntry& a,
- const IconDirectoryEntry& b)
+bool ICOImageDecoder::compareEntries(const IconDirectoryEntry& a, const IconDirectoryEntry& b)
{
- // Larger icons are better.
+ // Larger icons are better. After that, higher bit-depth icons are better.
const int aEntryArea = a.m_size.width() * a.m_size.height();
const int bEntryArea = b.m_size.width() * b.m_size.height();
- if (aEntryArea != bEntryArea)
- return (aEntryArea > bEntryArea);
-
- // Higher bit-depth icons are better.
- return (a.m_bitCount > b.m_bitCount);
+ return (aEntryArea == bEntryArea) ? (a.m_bitCount > b.m_bitCount) : (aEntryArea > bEntryArea);
}
void ICOImageDecoder::setDataForPNGDecoderAtIndex(size_t index)
@@ -161,21 +139,18 @@ void ICOImageDecoder::setDataForPNGDecoderAtIndex(size_t index)
// Copy out PNG data to a separate vector and send to the PNG decoder.
// FIXME: Save this copy by making the PNG decoder able to take an
// optional offset.
- RefPtr<SharedBuffer> pngData(
- SharedBuffer::create(&m_data->data()[dirEntry.m_imageOffset],
- m_data->size() - dirEntry.m_imageOffset));
- m_pngDecoders[index]->setData(pngData.get(), m_allDataReceived);
+ RefPtr<SharedBuffer> pngData(SharedBuffer::create(&m_data->data()[dirEntry.m_imageOffset], m_data->size() - dirEntry.m_imageOffset));
+ m_pngDecoders[index]->setData(pngData.get(), isAllDataReceived());
}
-void ICOImageDecoder::decodeWithCheckForDataEnded(size_t index, bool onlySize)
+void ICOImageDecoder::decode(size_t index, bool onlySize)
{
if (failed())
return;
// If we couldn't decode the image but we've received all the data, decoding
// has failed.
- if ((!decodeDirectory() || (!onlySize && !decodeAtIndex(index)))
- && m_allDataReceived)
+ if ((!decodeDirectory() || (!onlySize && !decodeAtIndex(index))) && isAllDataReceived())
setFailed();
}
@@ -186,45 +161,47 @@ bool ICOImageDecoder::decodeDirectory()
return false;
// Read and process directory entries.
- return (m_decodedOffset >=
- (sizeOfDirectory + (m_dirEntries.size() * sizeOfDirEntry)))
- || processDirectoryEntries();
+ return (m_decodedOffset >= (sizeOfDirectory + (m_dirEntries.size() * sizeOfDirEntry))) || processDirectoryEntries();
}
bool ICOImageDecoder::decodeAtIndex(size_t index)
{
ASSERT(index < m_dirEntries.size());
const IconDirectoryEntry& dirEntry = m_dirEntries[index];
- if (!m_bmpReaders[index] && !m_pngDecoders[index]) {
- // Image type unknown.
- const ImageType imageType = imageTypeAtIndex(index);
- if (imageType == BMP) {
+ const ImageType imageType = imageTypeAtIndex(index);
+ if (imageType == Unknown)
+ return false; // Not enough data to determine image type yet.
+
+ if (imageType == BMP) {
+ if (!m_bmpReaders[index]) {
// We need to have already sized m_frameBufferCache before this, and
// we must not resize it again later (see caution in frameCount()).
ASSERT(m_frameBufferCache.size() == m_dirEntries.size());
- m_bmpReaders[index].set(
- new BMPImageReader(this, dirEntry.m_imageOffset, 0, true));
+ m_bmpReaders[index].set(new BMPImageReader(this, dirEntry.m_imageOffset, 0, true));
m_bmpReaders[index]->setData(m_data.get());
m_bmpReaders[index]->setBuffer(&m_frameBufferCache[index]);
- } else if (imageType == PNG) {
- m_pngDecoders[index].set(new PNGImageDecoder());
- setDataForPNGDecoderAtIndex(index);
- } else {
- // Not enough data to determine image type yet.
- return false;
}
- }
-
- if (m_bmpReaders[index]) {
m_frameSize = dirEntry.m_size;
bool result = m_bmpReaders[index]->decodeBMP(false);
m_frameSize = IntSize();
return result;
}
- // For PNGs, we're now done; further decoding will happen when calling
- // frameBufferAtIndex() on the PNG decoder.
- return true;
+ if (!m_pngDecoders[index]) {
+ m_pngDecoders[index].set(new PNGImageDecoder());
+ setDataForPNGDecoderAtIndex(index);
+ }
+ // Fail if the size the PNGImageDecoder calculated does not match the size
+ // in the directory.
+ if (m_pngDecoders[index]->isSizeAvailable() && (m_pngDecoders[index]->size() != dirEntry.m_size)) {
+ setFailed();
+ return false;
+ }
+ m_frameBufferCache[index] = *m_pngDecoders[index]->frameBufferAtIndex(0);
+ if (!m_pngDecoders[index]->failed())
+ return true;
+ setFailed();
+ return false;
}
bool ICOImageDecoder::processDirectory()
@@ -259,18 +236,14 @@ bool ICOImageDecoder::processDirectoryEntries()
{
// Read directory entries.
ASSERT(m_decodedOffset == sizeOfDirectory);
- if ((m_decodedOffset > m_data->size())
- || ((m_data->size() - m_decodedOffset) <
- (m_dirEntries.size() * sizeOfDirEntry)))
+ if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset) < (m_dirEntries.size() * sizeOfDirEntry)))
return false;
- for (IconDirectoryEntries::iterator i(m_dirEntries.begin());
- i != m_dirEntries.end(); ++i)
+ for (IconDirectoryEntries::iterator i(m_dirEntries.begin()); i != m_dirEntries.end(); ++i)
*i = readDirectoryEntry(); // Updates m_decodedOffset.
// Make sure the specified image offsets are past the end of the directory
// entries.
- for (IconDirectoryEntries::iterator i(m_dirEntries.begin());
- i != m_dirEntries.end(); ++i) {
+ for (IconDirectoryEntries::iterator i(m_dirEntries.begin()); i != m_dirEntries.end(); ++i) {
if (i->m_imageOffset < m_decodedOffset) {
setFailed();
return false;
@@ -309,8 +282,7 @@ ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry()
// this isn't quite what the bitmap info header says later, as we only use
// this value to determine which icon entry is best.
if (!entry.m_bitCount) {
- int colorCount =
- static_cast<uint8_t>(m_data->data()[m_decodedOffset + 2]);
+ int colorCount = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 2]);
if (!colorCount)
colorCount = 256; // Vague in the spec, needed by real-world icons.
for (--colorCount; colorCount; colorCount >>= 1)
diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h
index 6117e06..c1f29c9 100644
--- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h
+++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h
@@ -41,6 +41,7 @@ namespace WebCore {
class ICOImageDecoder : public ImageDecoder {
public:
ICOImageDecoder();
+ virtual ~ICOImageDecoder();
// ImageDecoder
virtual String filenameExtension() const { return "ico"; }
@@ -67,19 +68,16 @@ namespace WebCore {
// Returns true if |a| is a preferable icon entry to |b|.
// Larger sizes, or greater bitdepths at the same size, are preferable.
- static bool compareEntries(const IconDirectoryEntry& a,
- const IconDirectoryEntry& b);
+ static bool compareEntries(const IconDirectoryEntry& a, const IconDirectoryEntry& b);
inline uint16_t readUint16(int offset) const
{
- return BMPImageReader::readUint16(m_data.get(),
- m_decodedOffset + offset);
+ return BMPImageReader::readUint16(m_data.get(), m_decodedOffset + offset);
}
inline uint32_t readUint32(int offset) const
{
- return BMPImageReader::readUint32(m_data.get(),
- m_decodedOffset + offset);
+ return BMPImageReader::readUint32(m_data.get(), m_decodedOffset + offset);
}
// If the desired PNGImageDecoder exists, gives it the appropriate data.
@@ -88,12 +86,7 @@ namespace WebCore {
// Decodes the entry at |index|. If |onlySize| is true, stops decoding
// after calculating the image size. If decoding fails but there is no
// more data coming, sets the "decode failure" flag.
- //
- // NOTE: If the desired entry is a PNG, this doesn't actually trigger
- // decoding, it merely ensures the decoder is created and ready to
- // decode. The caller will then call a function on the PNGImageDecoder
- // that actually triggers decoding.
- void decodeWithCheckForDataEnded(size_t index, bool onlySize);
+ void decode(size_t index, bool onlySize);
// Decodes the directory and directory entries at the beginning of the
// data, and initializes members. Returns true if all decoding
@@ -120,9 +113,6 @@ namespace WebCore {
// if the type could be determined.
ImageType imageTypeAtIndex(size_t);
- // True if we've seen all the data.
- bool m_allDataReceived;
-
// An index into |m_data| representing how much we've already decoded.
// Note that this only tracks data _this_ class decodes; once the
// BMPImageReader takes over this will not be updated further.
diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
index aaa9047..9ed20b6 100644
--- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
@@ -59,18 +59,17 @@ extern "C" {
namespace WebCore {
struct decoder_error_mgr {
- struct jpeg_error_mgr pub; /* "public" fields for IJG library*/
- jmp_buf setjmp_buffer; /* For handling catastropic errors */
+ struct jpeg_error_mgr pub; // "public" fields for IJG library
+ jmp_buf setjmp_buffer; // For handling catastropic errors
};
enum jstate {
- JPEG_HEADER, /* Reading JFIF headers */
+ JPEG_HEADER, // Reading JFIF headers
JPEG_START_DECOMPRESS,
- JPEG_DECOMPRESS_PROGRESSIVE, /* Output progressive pixels */
- JPEG_DECOMPRESS_SEQUENTIAL, /* Output sequential pixels */
+ JPEG_DECOMPRESS_PROGRESSIVE, // Output progressive pixels
+ JPEG_DECOMPRESS_SEQUENTIAL, // Output sequential pixels
JPEG_DONE,
- JPEG_SINK_NON_JPEG_TRAILER, /* Some image files have a */
- /* non-JPEG trailer */
+ JPEG_SINK_NON_JPEG_TRAILER, // Some image files have a non-JPEG trailer
JPEG_ERROR
};
@@ -80,14 +79,12 @@ void skip_input_data(j_decompress_ptr jd, long num_bytes);
void term_source(j_decompress_ptr jd);
void error_exit(j_common_ptr cinfo);
-/*
- * Implementation of a JPEG src object that understands our state machine
- */
+// Implementation of a JPEG src object that understands our state machine
struct decoder_source_mgr {
- /* public fields; must be first in this struct! */
- struct jpeg_source_mgr pub;
+ // public fields; must be first in this struct!
+ struct jpeg_source_mgr pub;
- JPEGImageReader *decoder;
+ JPEGImageReader* decoder;
};
class JPEGImageReader
@@ -102,11 +99,11 @@ public:
{
memset(&m_info, 0, sizeof(jpeg_decompress_struct));
- /* We set up the normal JPEG error routines, then override error_exit. */
+ // We set up the normal JPEG error routines, then override error_exit.
m_info.err = jpeg_std_error(&m_err.pub);
m_err.pub.error_exit = error_exit;
- /* Allocate and initialize JPEG decompression object */
+ // Allocate and initialize JPEG decompression object.
jpeg_create_decompress(&m_info);
decoder_source_mgr* src = 0;
@@ -120,7 +117,7 @@ public:
m_info.src = (jpeg_source_mgr*)src;
- /* Set up callback functions. */
+ // Set up callback functions.
src->pub.init_source = init_source;
src->pub.fill_input_buffer = fill_input_buffer;
src->pub.skip_input_data = skip_input_data;
@@ -148,22 +145,20 @@ public:
long bytesToSkip = std::min(num_bytes, (long)src->pub.bytes_in_buffer);
src->pub.bytes_in_buffer -= (size_t)bytesToSkip;
src->pub.next_input_byte += bytesToSkip;
-
- if (num_bytes > bytesToSkip)
- m_bytesToSkip = (size_t)(num_bytes - bytesToSkip);
- else
- m_bytesToSkip = 0;
+
+ m_bytesToSkip = std::max(num_bytes - bytesToSkip, static_cast<long>(0));
}
- bool decode(const Vector<char>& data, bool sizeOnly) {
- m_decodingSizeOnly = sizeOnly;
-
+ bool decode(const Vector<char>& data, bool onlySize)
+ {
+ m_decodingSizeOnly = onlySize;
+
unsigned newByteCount = data.size() - m_bufferLength;
unsigned readOffset = m_bufferLength - m_info.src->bytes_in_buffer;
m_info.src->bytes_in_buffer += newByteCount;
m_info.src->next_input_byte = (JOCTET*)(data.data()) + readOffset;
-
+
// If we still have bytes to skip, try to skip those now.
if (m_bytesToSkip)
skipBytes(m_bytesToSkip);
@@ -178,172 +173,150 @@ public:
}
switch (m_state) {
- case JPEG_HEADER:
- {
- /* Read file parameters with jpeg_read_header() */
- if (jpeg_read_header(&m_info, true) == JPEG_SUSPENDED)
- return true; /* I/O suspension */
-
- /* let libjpeg take care of gray->RGB and YCbCr->RGB conversions */
- switch (m_info.jpeg_color_space) {
- case JCS_GRAYSCALE:
- case JCS_RGB:
- case JCS_YCbCr:
- m_info.out_color_space = JCS_RGB;
- break;
- case JCS_CMYK:
- case JCS_YCCK:
- // jpeglib cannot convert these to rgb, but it can
- // convert ycck to cmyk
- m_info.out_color_space = JCS_CMYK;
- break;
- default:
- m_state = JPEG_ERROR;
- return false;
- }
-
- /*
- * Don't allocate a giant and superfluous memory buffer
- * when the image is a sequential JPEG.
- */
- m_info.buffered_image = jpeg_has_multiple_scans(&m_info);
-
- /* Used to set up image size so arrays can be allocated */
- jpeg_calc_output_dimensions(&m_info);
-
- /*
- * Make a one-row-high sample array that will go away
- * when done with image. Always make it big enough to
- * hold an RGB row. Since this uses the IJG memory
- * manager, it must be allocated before the call to
- * jpeg_start_compress().
- */
- int row_stride = m_info.output_width * 4; // RGBA buffer
+ case JPEG_HEADER:
+ // Read file parameters with jpeg_read_header().
+ if (jpeg_read_header(&m_info, true) == JPEG_SUSPENDED)
+ return true; // I/O suspension.
+
+ // Let libjpeg take care of gray->RGB and YCbCr->RGB conversions.
+ switch (m_info.jpeg_color_space) {
+ case JCS_GRAYSCALE:
+ case JCS_RGB:
+ case JCS_YCbCr:
+ m_info.out_color_space = JCS_RGB;
+ break;
+ case JCS_CMYK:
+ case JCS_YCCK:
+ // jpeglib cannot convert these to rgb, but it can convert ycck
+ // to cmyk.
+ m_info.out_color_space = JCS_CMYK;
+ break;
+ default:
+ m_state = JPEG_ERROR;
+ return false;
+ }
+ // Don't allocate a giant and superfluous memory buffer when the
+ // image is a sequential JPEG.
+ m_info.buffered_image = jpeg_has_multiple_scans(&m_info);
- m_samples = (*m_info.mem->alloc_sarray)((j_common_ptr) &m_info,
- JPOOL_IMAGE,
- row_stride, 1);
+ // Used to set up image size so arrays can be allocated.
+ jpeg_calc_output_dimensions(&m_info);
- m_state = JPEG_START_DECOMPRESS;
+ // Make a one-row-high sample array that will go away when done with
+ // image. Always make it big enough to hold an RGB row. Since this
+ // uses the IJG memory manager, it must be allocated before the call
+ // to jpeg_start_compress().
+ m_samples = (*m_info.mem->alloc_sarray)((j_common_ptr) &m_info, JPOOL_IMAGE, m_info.output_width * 4, 1);
- // We can fill in the size now that the header is available.
- if (!m_decoder->setSize(m_info.image_width, m_info.image_height)) {
- m_state = JPEG_ERROR;
- return false;
- }
+ m_state = JPEG_START_DECOMPRESS;
- if (m_decodingSizeOnly) {
- // We can stop here.
- // Reduce our buffer length and available data.
- m_bufferLength -= m_info.src->bytes_in_buffer;
- m_info.src->bytes_in_buffer = 0;
- return true;
- }
+ // We can fill in the size now that the header is available.
+ if (!m_decoder->setSize(m_info.image_width, m_info.image_height)) {
+ m_state = JPEG_ERROR;
+ return false;
}
- case JPEG_START_DECOMPRESS:
- {
- /* Set parameters for decompression */
- /* FIXME -- Should reset dct_method and dither mode
- * for final pass of progressive JPEG
- */
- m_info.dct_method = JDCT_ISLOW;
- m_info.dither_mode = JDITHER_FS;
- m_info.do_fancy_upsampling = true;
- m_info.enable_2pass_quant = false;
- m_info.do_block_smoothing = true;
-
- /* Start decompressor */
- if (!jpeg_start_decompress(&m_info))
- return true; /* I/O suspension */
-
- /* If this is a progressive JPEG ... */
- m_state = (m_info.buffered_image) ? JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL;
+ if (m_decodingSizeOnly) {
+ // We can stop here. Reduce our buffer length and available
+ // data.
+ m_bufferLength -= m_info.src->bytes_in_buffer;
+ m_info.src->bytes_in_buffer = 0;
+ return true;
}
-
- case JPEG_DECOMPRESS_SEQUENTIAL:
- {
- if (m_state == JPEG_DECOMPRESS_SEQUENTIAL) {
-
- if (!m_decoder->outputScanlines())
- return true; /* I/O suspension */
-
- /* If we've completed image output ... */
- ASSERT(m_info.output_scanline == m_info.output_height);
- m_state = JPEG_DONE;
- }
+ // FALL THROUGH
+
+ case JPEG_START_DECOMPRESS:
+ // Set parameters for decompression.
+ // FIXME -- Should reset dct_method and dither mode for final pass
+ // of progressive JPEG.
+ m_info.dct_method = JDCT_ISLOW;
+ m_info.dither_mode = JDITHER_FS;
+ m_info.do_fancy_upsampling = true;
+ m_info.enable_2pass_quant = false;
+ m_info.do_block_smoothing = true;
+
+ // Start decompressor.
+ if (!jpeg_start_decompress(&m_info))
+ return true; // I/O suspension.
+
+ // If this is a progressive JPEG ...
+ m_state = (m_info.buffered_image) ? JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL;
+ // FALL THROUGH
+
+ case JPEG_DECOMPRESS_SEQUENTIAL:
+ if (m_state == JPEG_DECOMPRESS_SEQUENTIAL) {
+
+ if (!m_decoder->outputScanlines())
+ return true; // I/O suspension.
+
+ // If we've completed image output...
+ ASSERT(m_info.output_scanline == m_info.output_height);
+ m_state = JPEG_DONE;
}
+ // FALL THROUGH
+
+ case JPEG_DECOMPRESS_PROGRESSIVE:
+ if (m_state == JPEG_DECOMPRESS_PROGRESSIVE) {
+ int status;
+ do {
+ status = jpeg_consume_input(&m_info);
+ } while ((status != JPEG_SUSPENDED) && (status != JPEG_REACHED_EOI));
+
+ for (;;) {
+ if (!m_info.output_scanline) {
+ int scan = m_info.input_scan_number;
+
+ // If we haven't displayed anything yet
+ // (output_scan_number == 0) and we have enough data for
+ // a complete scan, force output of the last full scan.
+ if (!m_info.output_scan_number && (scan > 1) && (status != JPEG_REACHED_EOI))
+ --scan;
+
+ if (!jpeg_start_output(&m_info, scan))
+ return true; // I/O suspension.
+ }
+
+ if (m_info.output_scanline == 0xffffff)
+ m_info.output_scanline = 0;
- case JPEG_DECOMPRESS_PROGRESSIVE:
- {
- if (m_state == JPEG_DECOMPRESS_PROGRESSIVE) {
- int status;
- do {
- status = jpeg_consume_input(&m_info);
- } while ((status != JPEG_SUSPENDED) &&
- (status != JPEG_REACHED_EOI));
-
- for (;;) {
- if (m_info.output_scanline == 0) {
- int scan = m_info.input_scan_number;
-
- /* if we haven't displayed anything yet (output_scan_number==0)
- and we have enough data for a complete scan, force output
- of the last full scan */
- if ((m_info.output_scan_number == 0) &&
- (scan > 1) &&
- (status != JPEG_REACHED_EOI))
- scan--;
-
- if (!jpeg_start_output(&m_info, scan))
- return true; /* I/O suspension */
- }
-
- if (m_info.output_scanline == 0xffffff)
- m_info.output_scanline = 0;
-
- if (!m_decoder->outputScanlines()) {
- if (m_info.output_scanline == 0)
- /* didn't manage to read any lines - flag so we don't call
- jpeg_start_output() multiple times for the same scan */
- m_info.output_scanline = 0xffffff;
- return true; /* I/O suspension */
- }
-
- if (m_info.output_scanline == m_info.output_height) {
- if (!jpeg_finish_output(&m_info))
- return true; /* I/O suspension */
-
- if (jpeg_input_complete(&m_info) &&
- (m_info.input_scan_number == m_info.output_scan_number))
- break;
-
- m_info.output_scanline = 0;
- }
+ if (!m_decoder->outputScanlines()) {
+ if (!m_info.output_scanline)
+ // Didn't manage to read any lines - flag so we
+ // don't call jpeg_start_output() multiple times for
+ // the same scan.
+ m_info.output_scanline = 0xffffff;
+ return true; // I/O suspension.
}
- m_state = JPEG_DONE;
- }
- }
+ if (m_info.output_scanline == m_info.output_height) {
+ if (!jpeg_finish_output(&m_info))
+ return true; // I/O suspension.
- case JPEG_DONE:
- {
- /* Finish decompression */
- if (!jpeg_finish_decompress(&m_info))
- return true; /* I/O suspension */
+ if (jpeg_input_complete(&m_info) && (m_info.input_scan_number == m_info.output_scan_number))
+ break;
- m_state = JPEG_SINK_NON_JPEG_TRAILER;
+ m_info.output_scanline = 0;
+ }
+ }
- /* we're done */
- break;
+ m_state = JPEG_DONE;
}
-
- case JPEG_SINK_NON_JPEG_TRAILER:
- break;
+ // FALL THROUGH
- case JPEG_ERROR:
- break;
+ case JPEG_DONE:
+ // Finish decompression.
+ if (!jpeg_finish_decompress(&m_info))
+ return true; // I/O suspension.
+
+ m_state = JPEG_SINK_NON_JPEG_TRAILER;
+ break;
+
+ case JPEG_SINK_NON_JPEG_TRAILER:
+ break;
+
+ case JPEG_ERROR:
+ break;
}
return true;
@@ -367,10 +340,10 @@ private:
JSAMPARRAY m_samples;
};
-/* Override the standard error method in the IJG JPEG decoder code. */
+// Override the standard error method in the IJG JPEG decoder code.
void error_exit(j_common_ptr cinfo)
{
- /* Return control to the setjmp point. */
+ // Return control to the setjmp point.
decoder_error_mgr *err = (decoder_error_mgr *) cinfo->err;
longjmp(err->setjmp_buffer, -1);
}
@@ -388,12 +361,12 @@ void skip_input_data(j_decompress_ptr jd, long num_bytes)
boolean fill_input_buffer(j_decompress_ptr jd)
{
// Our decode step always sets things up properly, so if this method is ever
- // called, then we have hit the end of the buffer. A return value of FALSE indicates
- // that we have no data to supply yet.
+ // called, then we have hit the end of the buffer. A return value of false
+ // indicates that we have no data to supply yet.
return false;
}
-void term_source (j_decompress_ptr jd)
+void term_source(j_decompress_ptr jd)
{
decoder_source_mgr *src = (decoder_source_mgr *)jd->src;
src->decoder->decoder()->jpegComplete();
@@ -407,21 +380,17 @@ JPEGImageDecoder::~JPEGImageDecoder()
{
}
-// Take the data and store it.
void JPEGImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
{
if (m_failed)
return;
- // Cache our new data.
ImageDecoder::setData(data, allDataReceived);
- // Create the JPEG reader.
if (!m_reader && !m_failed)
m_reader.set(new JPEGImageReader(this));
}
-// Whether or not the size information has been decoded yet.
bool JPEGImageDecoder::isSizeAvailable()
{
if (!ImageDecoder::isSizeAvailable() && !failed() && m_reader)
@@ -434,6 +403,7 @@ bool JPEGImageDecoder::setSize(unsigned width, unsigned height)
{
if (!ImageDecoder::setSize(width, height))
return false;
+
prepareScaleDataIfNecessary();
return true;
}
@@ -448,23 +418,10 @@ RGBA32Buffer* JPEGImageDecoder::frameBufferAtIndex(size_t index)
RGBA32Buffer& frame = m_frameBufferCache[0];
if (frame.status() != RGBA32Buffer::FrameComplete && m_reader)
- // Decode this frame.
- decode();
+ decode(false);
return &frame;
}
-// Feed data to the JPEG reader.
-void JPEGImageDecoder::decode(bool sizeOnly)
-{
- if (m_failed)
- return;
-
- m_failed = !m_reader->decode(m_data->buffer(), sizeOnly);
-
- if (m_failed || (!m_frameBufferCache.isEmpty() && m_frameBufferCache[0].status() == RGBA32Buffer::FrameComplete))
- m_reader.clear();
-}
-
bool JPEGImageDecoder::outputScanlines()
{
if (m_frameBufferCache.isEmpty())
@@ -531,9 +488,20 @@ void JPEGImageDecoder::jpegComplete()
if (m_frameBufferCache.isEmpty())
return;
- // Hand back an appropriately sized buffer, even if the image ended up being empty.
- RGBA32Buffer& buffer = m_frameBufferCache[0];
- buffer.setStatus(RGBA32Buffer::FrameComplete);
+ // Hand back an appropriately sized buffer, even if the image ended up being
+ // empty.
+ m_frameBufferCache[0].setStatus(RGBA32Buffer::FrameComplete);
+}
+
+void JPEGImageDecoder::decode(bool onlySize)
+{
+ if (m_failed)
+ return;
+
+ m_failed = !m_reader->decode(m_data->buffer(), onlySize);
+
+ if (m_failed || (!m_frameBufferCache.isEmpty() && m_frameBufferCache[0].status() == RGBA32Buffer::FrameComplete))
+ m_reader.clear();
}
}
diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h
index d8bfd70..2a95dbe 100644
--- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h
+++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h
@@ -38,28 +38,24 @@ namespace WebCore {
class JPEGImageDecoder : public ImageDecoder {
public:
JPEGImageDecoder();
- ~JPEGImageDecoder();
+ virtual ~JPEGImageDecoder();
+ // ImageDecoder
virtual String filenameExtension() const { return "jpg"; }
-
- // Take the data and store it.
virtual void setData(SharedBuffer* data, bool allDataReceived);
-
- // Whether or not the size information has been decoded yet.
virtual bool isSizeAvailable();
-
virtual bool setSize(unsigned width, unsigned height);
-
virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
-
virtual bool supportsAlpha() const { return false; }
- void decode(bool sizeOnly = false);
-
bool outputScanlines();
void jpegComplete();
private:
+ // Decodes the image. If |onlySize| is true, stops decoding after
+ // calculating the image size.
+ void decode(bool onlySize);
+
OwnPtr<JPEGImageReader> m_reader;
};
diff --git a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp
index 35c8af0..36f818f 100644
--- a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp
@@ -52,21 +52,41 @@ const double cInverseGamma = 0.45455;
const unsigned long cMaxPNGSize = 1000000UL;
// Called if the decoding of the image fails.
-static void PNGAPI decodingFailed(png_structp png_ptr, png_const_charp error_msg);
+static void PNGAPI decodingFailed(png_structp png, png_const_charp)
+{
+ static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->decodingFailed();
+ longjmp(png->jmpbuf, 1);
+}
-// Callbacks given to the read struct. The first is for warnings (we want to treat a particular warning
-// as an error, which is why we have to register this callback.
-static void PNGAPI decodingWarning(png_structp png_ptr, png_const_charp warning_msg);
+// Callbacks given to the read struct. The first is for warnings (we want to
+// treat a particular warning as an error, which is why we have to register this
+// callback).
+static void PNGAPI decodingWarning(png_structp png, png_const_charp warningMsg)
+{
+ // Mozilla did this, so we will too.
+ // Convert a tRNS warning to be an error (see
+ // http://bugzilla.mozilla.org/show_bug.cgi?id=251381 )
+ if (!strncmp(warningMsg, "Missing PLTE before tRNS", 24))
+ png_error(png, warningMsg);
+}
// Called when we have obtained the header information (including the size).
-static void PNGAPI headerAvailable(png_structp png_ptr, png_infop info_ptr);
+static void PNGAPI headerAvailable(png_structp png, png_infop)
+{
+ static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->headerAvailable();
+}
// Called when a row is ready.
-static void PNGAPI rowAvailable(png_structp png_ptr, png_bytep new_row,
- png_uint_32 row_num, int pass);
+static void PNGAPI rowAvailable(png_structp png, png_bytep rowBuffer, png_uint_32 rowIndex, int interlacePass)
+{
+ static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->rowAvailable(rowBuffer, rowIndex, interlacePass);
+}
// Called when we have completely finished decoding the image.
-static void PNGAPI pngComplete(png_structp png_ptr, png_infop info_ptr);
+static void PNGAPI pngComplete(png_structp png, png_infop)
+{
+ static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->pngComplete();
+}
class PNGImageReader
{
@@ -75,7 +95,7 @@ public:
: m_readOffset(0)
, m_decodingSizeOnly(false)
, m_interlaceBuffer(0)
- , m_hasAlpha(0)
+ , m_hasAlpha(false)
, m_hasFinishedDecoding(false)
, m_currentBufferSize(0)
{
@@ -89,10 +109,12 @@ public:
close();
}
- void close() {
+ void close()
+ {
if (m_png && m_info)
- png_destroy_read_struct(&m_png, &m_info, 0); // Will zero the pointers.
- delete []m_interlaceBuffer;
+ // This will zero the pointers.
+ png_destroy_read_struct(&m_png, &m_info, 0);
+ delete[] m_interlaceBuffer;
m_interlaceBuffer = 0;
m_readOffset = 0;
m_hasFinishedDecoding = false;
@@ -106,7 +128,7 @@ public:
{
m_decodingSizeOnly = sizeOnly;
- // We need to do the setjmp here. Otherwise bad things will happen
+ // We need to do the setjmp here. Otherwise bad things will happen.
if (setjmp(m_png->jmpbuf)) {
close();
return;
@@ -134,9 +156,7 @@ public:
void setReadOffset(unsigned offset) { m_readOffset = offset; }
void setHasAlpha(bool b) { m_hasAlpha = b; }
- void createInterlaceBuffer(int size) {
- m_interlaceBuffer = new png_byte[size];
- }
+ void createInterlaceBuffer(int size) { m_interlaceBuffer = new png_byte[size]; }
private:
unsigned m_readOffset;
@@ -157,21 +177,16 @@ PNGImageDecoder::~PNGImageDecoder()
{
}
-// Take the data and store it.
void PNGImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
{
if (m_failed)
return;
- // Cache our new data.
ImageDecoder::setData(data, allDataReceived);
- // Create the PNG reader.
if (!m_reader && !m_failed)
m_reader.set(new PNGImageReader(this));
}
-
-// Whether or not the size information has been decoded yet.
bool PNGImageDecoder::isSizeAvailable()
{
if (!ImageDecoder::isSizeAvailable() && !failed() && m_reader)
@@ -191,41 +206,10 @@ RGBA32Buffer* PNGImageDecoder::frameBufferAtIndex(size_t index)
RGBA32Buffer& frame = m_frameBufferCache[0];
if (frame.status() != RGBA32Buffer::FrameComplete && m_reader)
// Decode this frame.
- decode();
+ decode(false);
return &frame;
}
-// Feed data to the PNG reader.
-void PNGImageDecoder::decode(bool sizeOnly)
-{
- if (m_failed)
- return;
-
- m_reader->decode(*m_data, sizeOnly);
-
- if (m_failed || (!m_frameBufferCache.isEmpty() && m_frameBufferCache[0].status() == RGBA32Buffer::FrameComplete))
- m_reader.clear();
-}
-
-void decodingFailed(png_structp png, png_const_charp errorMsg)
-{
- static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->decodingFailed();
- longjmp(png->jmpbuf, 1);
-}
-
-void decodingWarning(png_structp png, png_const_charp warningMsg)
-{
- // Mozilla did this, so we will too.
- // Convert a tRNS warning to be an error (documented in bugzilla.mozilla.org bug #251381)
- if (!strncmp(warningMsg, "Missing PLTE before tRNS", 24))
- png_error(png, warningMsg);
-}
-
-void headerAvailable(png_structp png, png_infop info)
-{
- static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->headerAvailable();
-}
-
void PNGImageDecoder::decodingFailed()
{
m_failed = true;
@@ -256,14 +240,12 @@ void PNGImageDecoder::headerAvailable()
}
int bitDepth, colorType, interlaceType, compressionType, filterType, channels;
- png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType,
- &interlaceType, &compressionType, &filterType);
+ png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterType);
// The options we set here match what Mozilla does.
// Expand to ensure we use 24-bit for RGB and 32-bit for RGBA.
- if (colorType == PNG_COLOR_TYPE_PALETTE ||
- (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8))
+ if (colorType == PNG_COLOR_TYPE_PALETTE || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8))
png_set_expand(png);
png_bytep trns = 0;
@@ -276,8 +258,7 @@ void PNGImageDecoder::headerAvailable()
if (bitDepth == 16)
png_set_strip_16(png);
- if (colorType == PNG_COLOR_TYPE_GRAY ||
- colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
+ if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png);
// Deal with gamma and keep it under our control.
@@ -288,15 +269,14 @@ void PNGImageDecoder::headerAvailable()
png_set_gAMA(png, info, gamma);
}
png_set_gamma(png, cDefaultGamma, gamma);
- }
- else
+ } else
png_set_gamma(png, cDefaultGamma, cInverseGamma);
// Tell libpng to send us rows for interlaced pngs.
if (interlaceType == PNG_INTERLACE_ADAM7)
png_set_interlace_handling(png);
- // Update our info now
+ // Update our info now.
png_read_update_info(png, info);
channels = png_get_channels(png, info);
ASSERT(channels == 3 || channels == 4);
@@ -310,12 +290,6 @@ void PNGImageDecoder::headerAvailable()
}
}
-void rowAvailable(png_structp png, png_bytep rowBuffer,
- png_uint_32 rowIndex, int interlacePass)
-{
- static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->rowAvailable(rowBuffer, rowIndex, interlacePass);
-}
-
void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, int interlacePass)
{
if (m_frameBufferCache.isEmpty())
@@ -339,36 +313,36 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex,
m_reader->createInterlaceBuffer((m_reader->hasAlpha() ? 4 : 3) * size().width() * size().height());
}
- if (rowBuffer == 0)
+ if (!rowBuffer)
return;
- /* libpng comments (pasted in here to explain what follows)
- *
- * this function is called for every row in the image. If the
- * image is interlacing, and you turned on the interlace handler,
- * this function will be called for every row in every pass.
- * Some of these rows will not be changed from the previous pass.
- * When the row is not changed, the new_row variable will be NULL.
- * The rows and passes are called in order, so you don't really
- * need the row_num and pass, but I'm supplying them because it
- * may make your life easier.
- *
- * For the non-NULL rows of interlaced images, you must call
- * png_progressive_combine_row() passing in the row and the
- * old row. You can call this function for NULL rows (it will
- * just return) and for non-interlaced images (it just does the
- * memcpy for you) if it will make the code easier. Thus, you
- * can just do this for all cases:
- *
- * png_progressive_combine_row(png_ptr, old_row, new_row);
- *
- * where old_row is what was displayed for previous rows. Note
- * that the first pass (pass == 0 really) will completely cover
- * the old row, so the rows do not have to be initialized. After
- * the first pass (and only for interlaced images), you will have
- * to pass the current row, and the function will combine the
- * old row and the new row.
- */
+ // libpng comments (pasted in here to explain what follows)
+ /*
+ * this function is called for every row in the image. If the
+ * image is interlacing, and you turned on the interlace handler,
+ * this function will be called for every row in every pass.
+ * Some of these rows will not be changed from the previous pass.
+ * When the row is not changed, the new_row variable will be NULL.
+ * The rows and passes are called in order, so you don't really
+ * need the row_num and pass, but I'm supplying them because it
+ * may make your life easier.
+ *
+ * For the non-NULL rows of interlaced images, you must call
+ * png_progressive_combine_row() passing in the row and the
+ * old row. You can call this function for NULL rows (it will
+ * just return) and for non-interlaced images (it just does the
+ * memcpy for you) if it will make the code easier. Thus, you
+ * can just do this for all cases:
+ *
+ * png_progressive_combine_row(png_ptr, old_row, new_row);
+ *
+ * where old_row is what was displayed for previous rows. Note
+ * that the first pass (pass == 0 really) will completely cover
+ * the old row, so the rows do not have to be initialized. After
+ * the first pass (and only for interlaced images), you will have
+ * to pass the current row, and the function will combine the
+ * old row and the new row.
+ */
png_structp png = m_reader->pngPtr();
bool hasAlpha = m_reader->hasAlpha();
@@ -378,8 +352,7 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex,
if (interlaceBuffer) {
row = interlaceBuffer + (rowIndex * colorChannels * size().width());
png_progressive_combine_row(png, row, rowBuffer);
- }
- else
+ } else
row = rowBuffer;
// Copy the data into our buffer.
@@ -388,7 +361,7 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex,
if (destY < 0)
return;
bool sawAlpha = buffer.hasAlpha();
- for (int x = 0; x < width; x++) {
+ for (int x = 0; x < width; ++x) {
png_bytep pixel = row + (m_scaled ? m_scaledColumns[x] : x) * colorChannels;
unsigned alpha = hasAlpha ? pixel[3] : 255;
buffer.setRGBA(x, destY, pixel[0], pixel[1], pixel[2], alpha);
@@ -399,21 +372,23 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex,
}
}
-void pngComplete(png_structp png, png_infop info)
-{
- static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->pngComplete();
-}
-
void PNGImageDecoder::pngComplete()
{
m_reader->setComplete();
- if (m_frameBufferCache.isEmpty())
+ if (!m_frameBufferCache.isEmpty())
+ m_frameBufferCache.first().setStatus(RGBA32Buffer::FrameComplete);
+}
+
+void PNGImageDecoder::decode(bool onlySize)
+{
+ if (m_failed)
return;
- // Hand back an appropriately sized buffer, even if the image ended up being empty.
- RGBA32Buffer& buffer = m_frameBufferCache[0];
- buffer.setStatus(RGBA32Buffer::FrameComplete);
+ m_reader->decode(*m_data, onlySize);
+
+ if (m_failed || (!m_frameBufferCache.isEmpty() && m_frameBufferCache[0].status() == RGBA32Buffer::FrameComplete))
+ m_reader.clear();
}
} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/png/PNGImageDecoder.h b/WebCore/platform/image-decoders/png/PNGImageDecoder.h
index 07a0b3a..ba0e19a 100644
--- a/WebCore/platform/image-decoders/png/PNGImageDecoder.h
+++ b/WebCore/platform/image-decoders/png/PNGImageDecoder.h
@@ -37,20 +37,14 @@ namespace WebCore {
class PNGImageDecoder : public ImageDecoder {
public:
PNGImageDecoder();
- ~PNGImageDecoder();
+ virtual ~PNGImageDecoder();
+ // ImageDecoder
virtual String filenameExtension() const { return "png"; }
-
- // Take the data and store it.
virtual void setData(SharedBuffer* data, bool allDataReceived);
-
- // Whether or not the size information has been decoded yet.
virtual bool isSizeAvailable();
-
virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
- void decode(bool sizeOnly = false);
-
// Callbacks from libpng
void decodingFailed();
void headerAvailable();
@@ -58,6 +52,10 @@ namespace WebCore {
void pngComplete();
private:
+ // Decodes the image. If |onlySize| is true, stops decoding after
+ // calculating the image size.
+ void decode(bool onlySize);
+
OwnPtr<PNGImageReader> m_reader;
};
diff --git a/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp b/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp
index d3218cd..b2e5e17 100644
--- a/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp
+++ b/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp
@@ -42,12 +42,17 @@ RGBA32Buffer::RGBA32Buffer()
{
}
-// The image must not have format 8888 pre multiplied...
-void RGBA32Buffer::setDecodedImage(const QImage& image)
+RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other)
{
- m_image = image;
- m_size = image.size();
- m_hasAlpha = image.hasAlphaChannel();
+ if (this == &other)
+ return *this;
+
+ copyBitmapData(other);
+ setRect(other.rect());
+ setStatus(other.status());
+ setDuration(other.duration());
+ setDisposalMethod(other.disposalMethod());
+ return *this;
}
void RGBA32Buffer::clear()
@@ -115,17 +120,12 @@ void RGBA32Buffer::setStatus(FrameStatus status)
m_status = status;
}
-RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other)
+// The image must not have format 8888 pre multiplied...
+void RGBA32Buffer::setDecodedImage(const QImage& image)
{
- if (this == &other)
- return *this;
-
- copyBitmapData(other);
- setRect(other.rect());
- setStatus(other.status());
- setDuration(other.duration());
- setDisposalMethod(other.disposalMethod());
- return *this;
+ m_image = image;
+ m_size = image.size();
+ m_hasAlpha = image.hasAlphaChannel();
}
int RGBA32Buffer::width() const
diff --git a/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp b/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp
index 543eca8..928524a 100644
--- a/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp
+++ b/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp
@@ -39,6 +39,22 @@ RGBA32Buffer::RGBA32Buffer()
{
}
+RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other)
+{
+ if (this == &other)
+ return *this;
+
+ m_bitmap = other.m_bitmap;
+ // Keep the pixels locked since we will be writing directly into the
+ // bitmap throughout this object's lifetime.
+ m_bitmap.lockPixels();
+ setRect(other.rect());
+ setStatus(other.status());
+ setDuration(other.duration());
+ setDisposalMethod(other.disposalMethod());
+ return *this;
+}
+
void RGBA32Buffer::clear()
{
m_bitmap.reset();
@@ -105,22 +121,6 @@ void RGBA32Buffer::setStatus(FrameStatus status)
m_bitmap.setDataComplete(); // Tell the bitmap it's done.
}
-RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other)
-{
- if (this == &other)
- return *this;
-
- m_bitmap = other.m_bitmap;
- // Keep the pixels locked since we will be writing directly into the
- // bitmap throughout this object's lifetime.
- m_bitmap.lockPixels();
- setRect(other.rect());
- setStatus(other.status());
- setDuration(other.duration());
- setDisposalMethod(other.disposalMethod());
- return *this;
-}
-
int RGBA32Buffer::width() const
{
return m_bitmap.width();
diff --git a/WebCore/platform/mac/PasteboardMac.mm b/WebCore/platform/mac/PasteboardMac.mm
index 690637a..086b272 100644
--- a/WebCore/platform/mac/PasteboardMac.mm
+++ b/WebCore/platform/mac/PasteboardMac.mm
@@ -300,9 +300,7 @@ void Pasteboard::writeImage(Node* node, const KURL& url, const String& title)
ASSERT(node->renderer() && node->renderer()->isImage());
RenderImage* renderer = toRenderImage(node->renderer());
CachedImage* cachedImage = renderer->cachedImage();
- ASSERT(cachedImage);
-
- if (cachedImage->errorOccurred())
+ if (!cachedImage || cachedImage->errorOccurred())
return;
NSArray* types = writableTypesForImage();
diff --git a/WebCore/platform/network/brew/DNSBrew.cpp b/WebCore/platform/network/brew/DNSBrew.cpp
new file mode 100644
index 0000000..ed1767a
--- /dev/null
+++ b/WebCore/platform/network/brew/DNSBrew.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 Company 100, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DNS.h"
+
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+void prefetchDNS(const String& hostname)
+{
+ // DNS prefetching is not implemented because the maximum number of UDP
+ // sockets is quite small in most BREW devices.
+ notImplemented();
+}
+
+}
diff --git a/WebCore/platform/network/chromium/CookieJarChromium.cpp b/WebCore/platform/network/chromium/CookieJarChromium.cpp
index 41cf331..e17816a 100644
--- a/WebCore/platform/network/chromium/CookieJarChromium.cpp
+++ b/WebCore/platform/network/chromium/CookieJarChromium.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 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
@@ -39,46 +39,32 @@ namespace WebCore {
void setCookies(Document* document, const KURL& url, const String& value)
{
- ChromiumBridge::setCookies(url, document->firstPartyForCookies(), value);
+ ChromiumBridge::setCookies(document, url, value);
}
String cookies(const Document* document, const KURL& url)
{
- return ChromiumBridge::cookies(url, document->firstPartyForCookies());
+ return ChromiumBridge::cookies(document, url);
}
String cookieRequestHeaderFieldValue(const Document* document, const KURL& url)
{
- // FIXME: move in ChromiumBridge?
- Vector<Cookie> cookies;
- getRawCookies(document, url, cookies);
- String cookieLine;
- // FIXME: Set $Version=v;
- for (size_t i = 0; i < cookies.size(); i++) {
- Cookie cookie = cookies[i];
- if (i > 0)
- cookieLine += "; ";
- if (!cookie.name.isEmpty())
- cookieLine += cookie.name + "=";
- cookieLine += cookie.value;
- // FIXME: set $Path, $Domain, ...
- }
- return cookieLine;
+ return ChromiumBridge::cookieRequestHeaderFieldValue(document, url);
}
bool cookiesEnabled(const Document* document)
{
- return ChromiumBridge::cookiesEnabled(document->cookieURL(), document->firstPartyForCookies());
+ return ChromiumBridge::cookiesEnabled(document);
}
bool getRawCookies(const Document* document, const KURL& url, Vector<Cookie>& rawCookies)
{
- return ChromiumBridge::rawCookies(url, document->firstPartyForCookies(), &rawCookies);
+ return ChromiumBridge::rawCookies(document, url, rawCookies);
}
-void deleteCookie(const Document*, const KURL& url, const String& cookieName)
+void deleteCookie(const Document* document, const KURL& url, const String& cookieName)
{
- return ChromiumBridge::deleteCookie(url, cookieName);
+ return ChromiumBridge::deleteCookie(document, url, cookieName);
}
} // namespace WebCore
diff --git a/WebCore/platform/network/chromium/ResourceRequest.cpp b/WebCore/platform/network/chromium/ResourceRequest.cpp
index 5b27c1b..016bd34 100644
--- a/WebCore/platform/network/chromium/ResourceRequest.cpp
+++ b/WebCore/platform/network/chromium/ResourceRequest.cpp
@@ -31,7 +31,10 @@ namespace WebCore {
// This is used by the loader to control the number of issued parallel load requests.
unsigned initializeMaximumHTTPConnectionCountPerHost()
{
- return 6;
+ // The chromium network stack already handles limiting the number of
+ // parallel requests per host, so there's no need to do it here. Therefore,
+ // this is set to a high value that should never be hit in practice.
+ return 10000;
}
} // namespace WebCore
diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp
index ee8e7aa..4c59d34 100644
--- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp
+++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp
@@ -380,6 +380,7 @@ static gboolean parseDataUrl(gpointer callback_data)
String charset = extractCharsetFromMediaType(mediaType);
ResourceResponse response;
+ response.setURL(handle->request().url());
response.setMimeType(mimeType);
if (isBase64) {
@@ -387,7 +388,10 @@ static gboolean parseDataUrl(gpointer callback_data)
response.setTextEncodingName(charset);
client->didReceiveResponse(handle, response);
- if (d->m_cancelled)
+ // The load may be cancelled, and the client may be destroyed
+ // by any of the client reporting calls, so we check, and bail
+ // out in either of those cases.
+ if (!handle->client() || d->m_cancelled)
return false;
// Use the GLib Base64, since WebCore's decoder isn't
@@ -404,16 +408,16 @@ static gboolean parseDataUrl(gpointer callback_data)
response.setTextEncodingName("UTF-16");
client->didReceiveResponse(handle, response);
- if (d->m_cancelled)
+ if (!handle->client() || d->m_cancelled)
return false;
if (data.length() > 0)
client->didReceiveData(handle, reinterpret_cast<const char*>(data.characters()), data.length() * sizeof(UChar), 0);
-
- if (d->m_cancelled)
- return false;
}
+ if (!handle->client() || d->m_cancelled)
+ return false;
+
client->didFinishLoading(handle);
return false;
@@ -565,6 +569,11 @@ static bool startHttp(ResourceHandle* handle)
// balanced by a deref() in finishedCallback, which should always run
handle->ref();
+ // Make sure we have an Accept header for subresources; some sites
+ // want this to serve some of their subresources
+ if (!soup_message_headers_get_one(d->m_msg->request_headers, "Accept"))
+ soup_message_headers_append(d->m_msg->request_headers, "Accept", "*/*");
+
// Balanced in ResourceHandleInternal's destructor; we need to
// keep our own ref, because after queueing the message, the
// session owns the initial reference.
diff --git a/WebCore/platform/qt/PasteboardQt.cpp b/WebCore/platform/qt/PasteboardQt.cpp
index 44c9eec..70ec546 100644
--- a/WebCore/platform/qt/PasteboardQt.cpp
+++ b/WebCore/platform/qt/PasteboardQt.cpp
@@ -151,7 +151,8 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String&)
#ifndef QT_NO_CLIPBOARD
CachedImage* cachedImage = toRenderImage(node->renderer())->cachedImage();
- ASSERT(cachedImage);
+ if (!cachedImage || cachedImage->errorOccurred())
+ return;
Image* image = cachedImage->image();
ASSERT(image);
diff --git a/WebCore/platform/text/AtomicString.cpp b/WebCore/platform/text/AtomicString.cpp
index 64c03cb..19821c0 100644
--- a/WebCore/platform/text/AtomicString.cpp
+++ b/WebCore/platform/text/AtomicString.cpp
@@ -248,7 +248,7 @@ PassRefPtr<StringImpl> AtomicString::add(const JSC::Identifier& identifier)
return 0;
UString::Rep* string = identifier.ustring().rep();
- unsigned length = string->size();
+ unsigned length = string->length();
if (!length)
return StringImpl::empty();
@@ -265,7 +265,7 @@ PassRefPtr<StringImpl> AtomicString::add(const JSC::UString& ustring)
return 0;
UString::Rep* string = ustring.rep();
- unsigned length = string->size();
+ unsigned length = string->length();
if (!length)
return StringImpl::empty();
@@ -282,7 +282,7 @@ AtomicStringImpl* AtomicString::find(const JSC::Identifier& identifier)
return 0;
UString::Rep* string = identifier.ustring().rep();
- unsigned length = string->size();
+ unsigned length = string->length();
if (!length)
return static_cast<AtomicStringImpl*>(StringImpl::empty());
diff --git a/WebCore/platform/text/StringImpl.cpp b/WebCore/platform/text/StringImpl.cpp
index db6152d..3704c4e 100644
--- a/WebCore/platform/text/StringImpl.cpp
+++ b/WebCore/platform/text/StringImpl.cpp
@@ -52,36 +52,12 @@ static inline UChar* newUCharVector(unsigned n)
return static_cast<UChar*>(fastMalloc(sizeof(UChar) * n));
}
-static inline void deleteUCharVector(const UChar* p)
-{
- fastFree(const_cast<UChar*>(p));
-}
-
-// Some of the factory methods create buffers using fastMalloc.
-// We must ensure that all allocations of StringImpl are allocated using
-// fastMalloc so that we don't have mis-matched frees. We accomplish
-// this by overriding the new and delete operators.
-void* StringImpl::operator new(size_t size, void* address)
-{
- if (address)
- return address; // Allocating using an internal buffer
- return fastMalloc(size);
-}
-
-void* StringImpl::operator new(size_t size)
-{
- return fastMalloc(size);
-}
-
-void StringImpl::operator delete(void* address)
-{
- fastFree(address);
-}
-
// This constructor is used only to create the empty string.
StringImpl::StringImpl()
: m_data(0)
+ , m_sharedBuffer(0)
, m_length(0)
+ , m_refCountAndFlags(s_refCountIncrement | BufferInternal)
, m_hash(0)
{
// Ensure that the hash is computed so that AtomicStringHash can call existingHash()
@@ -90,35 +66,55 @@ StringImpl::StringImpl()
hash();
}
+inline StringImpl::StringImpl(unsigned length)
+ : m_data(reinterpret_cast<const UChar*>(this + 1))
+ , m_sharedBuffer(0)
+ , m_length(length)
+ , m_refCountAndFlags(s_refCountIncrement | BufferInternal)
+ , m_hash(0)
+{
+ ASSERT(m_data);
+ ASSERT(m_length);
+}
+
inline StringImpl::StringImpl(const UChar* characters, unsigned length)
: m_data(characters)
+ , m_sharedBuffer(0)
, m_length(length)
+ , m_refCountAndFlags(s_refCountIncrement | BufferOwned)
, m_hash(0)
{
- ASSERT(characters);
- ASSERT(length);
- ASSERT(!bufferIsInternal());
+ ASSERT(m_data);
+ ASSERT(m_length);
}
-inline StringImpl::StringImpl(unsigned length)
- : m_data(reinterpret_cast<const UChar*>(this + 1))
+inline StringImpl::StringImpl(const UChar* characters, unsigned length, PassRefPtr<SharedUChar> sharedBuffer)
+ : m_data(characters)
+ , m_sharedBuffer(sharedBuffer.releaseRef())
, m_length(length)
+ , m_refCountAndFlags(s_refCountIncrement | BufferShared)
, m_hash(0)
{
- ASSERT(length);
- ASSERT(bufferIsInternal());
+ ASSERT(m_data);
+ ASSERT(m_length);
}
StringImpl::~StringImpl()
{
if (inTable())
AtomicString::remove(this);
- if (!bufferIsInternal()) {
- SharedUChar* sharedBuffer = m_sharedBufferAndFlags.get();
- if (sharedBuffer)
- sharedBuffer->deref();
- else
- deleteUCharVector(m_data);
+
+ BufferOwnership ownership = bufferOwnership();
+ if (ownership != BufferInternal) {
+ if (ownership == BufferOwned) {
+ ASSERT(!m_sharedBuffer);
+ ASSERT(m_data);
+ fastFree(const_cast<UChar*>(m_data));
+ } else {
+ ASSERT(ownership == BufferShared);
+ ASSERT(m_sharedBuffer);
+ m_sharedBuffer->deref();
+ }
}
}
@@ -976,13 +972,8 @@ PassRefPtr<StringImpl> StringImpl::create(const char* string)
#if USE(JSC)
PassRefPtr<StringImpl> StringImpl::create(const JSC::UString& str)
{
- SharedUChar* sharedBuffer = const_cast<JSC::UString*>(&str)->rep()->sharedBuffer();
- if (sharedBuffer) {
- PassRefPtr<StringImpl> impl = adoptRef(new StringImpl(str.data(), str.size()));
- sharedBuffer->ref();
- impl->m_sharedBufferAndFlags.set(sharedBuffer);
- return impl;
- }
+ if (SharedUChar* sharedBuffer = const_cast<JSC::UString*>(&str)->rep()->sharedBuffer())
+ return adoptRef(new StringImpl(str.data(), str.size(), sharedBuffer));
return StringImpl::create(str.data(), str.size());
}
@@ -1007,7 +998,7 @@ PassRefPtr<StringImpl> StringImpl::createWithTerminatingNullCharacter(const Stri
data[length] = 0;
terminatedString->m_length--;
terminatedString->m_hash = string.m_hash;
- terminatedString->m_sharedBufferAndFlags.setFlag(HasTerminatingNullCharacter);
+ terminatedString->m_refCountAndFlags |= s_refCountFlagHasTerminatingNullCharacter;
return terminatedString.release();
}
@@ -1021,12 +1012,8 @@ PassRefPtr<StringImpl> StringImpl::threadsafeCopy() const
PassRefPtr<StringImpl> StringImpl::crossThreadString()
{
- SharedUChar* shared = sharedBuffer();
- if (shared) {
- RefPtr<StringImpl> impl = adoptRef(new StringImpl(m_data, m_length));
- impl->m_sharedBufferAndFlags.set(shared->crossThreadCopy().releaseRef());
- return impl.release();
- }
+ if (SharedUChar* sharedBuffer = this->sharedBuffer())
+ return adoptRef(new StringImpl(m_data, m_length, sharedBuffer->crossThreadCopy()));
// If no shared buffer is available, create a copy.
return threadsafeCopy();
@@ -1034,13 +1021,23 @@ PassRefPtr<StringImpl> StringImpl::crossThreadString()
StringImpl::SharedUChar* StringImpl::sharedBuffer()
{
- if (m_length < minLengthToShare || bufferIsInternal())
+ if (m_length < minLengthToShare)
return 0;
- if (!m_sharedBufferAndFlags.get())
- m_sharedBufferAndFlags.set(SharedUChar::create(new OwnFastMallocPtr<UChar>(const_cast<UChar*>(m_data))).releaseRef());
- return m_sharedBufferAndFlags.get();
-}
+ BufferOwnership ownership = bufferOwnership();
+ if (ownership == BufferInternal)
+ return 0;
+
+ if (ownership == BufferOwned) {
+ ASSERT(!m_sharedBuffer);
+ m_sharedBuffer = SharedUChar::create(new OwnFastMallocPtr<UChar>(const_cast<UChar*>(m_data))).releaseRef();
+ m_refCountAndFlags = (m_refCountAndFlags & ~s_refCountMaskBufferOwnership) | BufferShared;
+ }
+
+ ASSERT(bufferOwnership() == BufferShared);
+ ASSERT(m_sharedBuffer);
+ return m_sharedBuffer;
+}
} // namespace WebCore
diff --git a/WebCore/platform/text/StringImpl.h b/WebCore/platform/text/StringImpl.h
index 21f936d..65848bb 100644
--- a/WebCore/platform/text/StringImpl.h
+++ b/WebCore/platform/text/StringImpl.h
@@ -26,8 +26,8 @@
#include <limits.h>
#include <wtf/ASCIICType.h>
#include <wtf/CrossThreadRefCounted.h>
+#include <wtf/Noncopyable.h>
#include <wtf/OwnFastMallocPtr.h>
-#include <wtf/PtrAndFlags.h>
#include <wtf/RefCounted.h>
#include <wtf/StringHashFunctions.h>
#include <wtf/Vector.h>
@@ -58,25 +58,33 @@ enum TextCaseSensitivity { TextCaseSensitive, TextCaseInsensitive };
typedef bool (*CharacterMatchFunctionPtr)(UChar);
-class StringImpl : public RefCounted<StringImpl> {
+class StringImpl : public Noncopyable {
friend struct CStringTranslator;
friend struct HashAndCharactersTranslator;
friend struct UCharBufferTranslator;
private:
friend class ThreadGlobalData;
- StringImpl();
-
- // This constructor adopts the UChar* without copying the buffer.
- StringImpl(const UChar*, unsigned length);
- // This constructor assumes that 'this' was allocated with a UChar buffer of size 'length' at the end.
+ enum BufferOwnership {
+ BufferInternal,
+ BufferOwned,
+ BufferShared,
+ };
+
+ typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar;
+
+ // Used to create the empty string (""), automatically hashes.
+ StringImpl();
+ // Create a StringImpl with internal storage (BufferInternal)
StringImpl(unsigned length);
+ // Create a StringImpl adopting ownership of the provided buffer (BufferOwned)
+ StringImpl(const UChar*, unsigned length);
+ // Create a StringImpl using a shared buffer (BufferShared)
+ StringImpl(const UChar*, unsigned length, PassRefPtr<SharedUChar>);
// For use only by AtomicString's XXXTranslator helpers.
void setHash(unsigned hash) { ASSERT(!m_hash); m_hash = hash; }
- typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar;
-
public:
~StringImpl();
@@ -99,16 +107,20 @@ public:
const UChar* characters() { return m_data; }
unsigned length() { return m_length; }
- bool hasTerminatingNullCharacter() const { return m_sharedBufferAndFlags.isFlagSet(HasTerminatingNullCharacter); }
+ bool hasTerminatingNullCharacter() const { return m_refCountAndFlags & s_refCountFlagHasTerminatingNullCharacter; }
- bool inTable() const { return m_sharedBufferAndFlags.isFlagSet(InTable); }
- void setInTable() { return m_sharedBufferAndFlags.setFlag(InTable); }
+ bool inTable() const { return m_refCountAndFlags & s_refCountFlagInTable; }
+ void setInTable() { m_refCountAndFlags |= s_refCountFlagInTable; }
unsigned hash() { if (m_hash == 0) m_hash = computeHash(m_data, m_length); return m_hash; }
unsigned existingHash() const { ASSERT(m_hash); return m_hash; }
inline static unsigned computeHash(const UChar* data, unsigned length) { return WTF::stringHash(data, length); }
inline static unsigned computeHash(const char* data) { return WTF::stringHash(data); }
-
+
+ StringImpl* ref() { m_refCountAndFlags += s_refCountIncrement; return this; }
+ ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & s_refCountMask)) delete this; }
+ ALWAYS_INLINE bool hasOneRef() const { return (m_refCountAndFlags & s_refCountMask) == s_refCountIncrement; }
+
// Returns a StringImpl suitable for use on another thread.
PassRefPtr<StringImpl> crossThreadString();
// Makes a deep copy. Helpful only if you need to use a String on another thread
@@ -178,31 +190,27 @@ public:
operator NSString*();
#endif
- void operator delete(void*);
-
private:
- // Allocation from a custom buffer is only allowed internally to avoid
- // mismatched allocators. Callers should use create().
- void* operator new(size_t size);
- void* operator new(size_t size, void* address);
+ using Noncopyable::operator new;
+ void* operator new(size_t, void* inPlace) { ASSERT(inPlace); return inPlace; }
static PassRefPtr<StringImpl> createStrippingNullCharactersSlowCase(const UChar*, unsigned length);
// The StringImpl struct and its data may be allocated within a single heap block.
// In this case, the m_data pointer is an "internal buffer", and does not need to be deallocated.
- bool bufferIsInternal() { return m_data == reinterpret_cast<const UChar*>(this + 1); }
+ BufferOwnership bufferOwnership() const { return static_cast<BufferOwnership>(m_refCountAndFlags & s_refCountMaskBufferOwnership); }
- enum StringImplFlags {
- HasTerminatingNullCharacter,
- InTable,
- };
+ static const unsigned s_refCountMask = 0xFFFFFFF0;
+ static const unsigned s_refCountIncrement = 0x10;
+ static const unsigned s_refCountFlagHasTerminatingNullCharacter = 0x8;
+ static const unsigned s_refCountFlagInTable = 0x4;
+ static const unsigned s_refCountMaskBufferOwnership = 0x3;
const UChar* m_data;
+ SharedUChar* m_sharedBuffer;
unsigned m_length;
+ unsigned m_refCountAndFlags;
mutable unsigned m_hash;
- PtrAndFlags<SharedUChar, StringImplFlags> m_sharedBufferAndFlags;
- // There is a fictitious variable-length UChar array at the end, which is used
- // as the internal buffer by the createUninitialized and create methods.
};
bool equal(StringImpl*, StringImpl*);
diff --git a/WebCore/platform/win/PasteboardWin.cpp b/WebCore/platform/win/PasteboardWin.cpp
index d09769a..ffafd02 100644
--- a/WebCore/platform/win/PasteboardWin.cpp
+++ b/WebCore/platform/win/PasteboardWin.cpp
@@ -205,7 +205,8 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String&)
ASSERT(node && node->renderer() && node->renderer()->isImage());
RenderImage* renderer = toRenderImage(node->renderer());
CachedImage* cachedImage = renderer->cachedImage();
- ASSERT(cachedImage);
+ if (!cachedImage || cachedImage->errorOccurred())
+ return;
Image* image = cachedImage->image();
ASSERT(image);