diff options
author | Steve Block <steveblock@google.com> | 2009-11-05 09:23:40 +0000 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2009-11-10 22:41:12 +0000 |
commit | cac0f67c402d107cdb10971b95719e2ff9c7c76b (patch) | |
tree | d182c7f87211c6f201a5f038e332336493ebdbe7 /WebCore/platform | |
parent | 4b2ef0f288e7c6c4602f621b7a0e9feed304b70e (diff) | |
download | external_webkit-cac0f67c402d107cdb10971b95719e2ff9c7c76b.zip external_webkit-cac0f67c402d107cdb10971b95719e2ff9c7c76b.tar.gz external_webkit-cac0f67c402d107cdb10971b95719e2ff9c7c76b.tar.bz2 |
Merge webkit.org at r50258 : Initial merge by git.
Change-Id: I1a9e1dc4ed654b69174ad52a4f031a07240f37b0
Diffstat (limited to 'WebCore/platform')
97 files changed, 1747 insertions, 1074 deletions
diff --git a/WebCore/platform/FileSystem.h b/WebCore/platform/FileSystem.h index 958eb73..9952b39 100644 --- a/WebCore/platform/FileSystem.h +++ b/WebCore/platform/FileSystem.h @@ -65,15 +65,23 @@ namespace WebCore { class CString; -#if PLATFORM(QT) - -typedef QFile* PlatformFileHandle; -const PlatformFileHandle invalidPlatformFileHandle = 0; +// PlatformModule +#if PLATFORM(WIN_OS) +typedef HMODULE PlatformModule; +#elif PLATFORM(QT) #if defined(Q_WS_MAC) typedef CFBundleRef PlatformModule; -typedef unsigned PlatformModuleVersion; -#elif defined(Q_OS_WIN) -typedef HMODULE PlatformModule; +#else +typedef QLibrary* PlatformModule; +#endif // defined(Q_WS_MAC) +#elif PLATFORM(GTK) +typedef GModule* PlatformModule; +#else +typedef void* PlatformModule; +#endif + +// PlatformModuleVersion +#if PLATFORM(WIN_OS) struct PlatformModuleVersion { unsigned leastSig; unsigned mostSig; @@ -92,44 +100,21 @@ struct PlatformModuleVersion { }; #else -typedef QLibrary* PlatformModule; typedef unsigned PlatformModuleVersion; #endif +// PlatformFileHandle +#if PLATFORM(QT) +typedef QFile* PlatformFileHandle; +const PlatformFileHandle invalidPlatformFileHandle = 0; #elif PLATFORM(WIN_OS) typedef HANDLE PlatformFileHandle; -typedef HMODULE PlatformModule; // FIXME: -1 is INVALID_HANDLE_VALUE, defined in <winbase.h>. Chromium tries to // avoid using Windows headers in headers. We'd rather move this into the .cpp. const PlatformFileHandle invalidPlatformFileHandle = reinterpret_cast<HANDLE>(-1); - -struct PlatformModuleVersion { - unsigned leastSig; - unsigned mostSig; - - PlatformModuleVersion(unsigned) - : leastSig(0) - , mostSig(0) - { - } - - PlatformModuleVersion(unsigned lsb, unsigned msb) - : leastSig(lsb) - , mostSig(msb) - { - } - -}; #else typedef int PlatformFileHandle; -#if PLATFORM(GTK) -typedef GModule* PlatformModule; -#else -typedef void* PlatformModule; -#endif const PlatformFileHandle invalidPlatformFileHandle = -1; - -typedef unsigned PlatformModuleVersion; #endif bool fileExists(const String&); diff --git a/WebCore/platform/KURLGoogle.cpp b/WebCore/platform/KURLGoogle.cpp index b323332..d0aae0c 100644 --- a/WebCore/platform/KURLGoogle.cpp +++ b/WebCore/platform/KURLGoogle.cpp @@ -106,7 +106,7 @@ static inline bool isUnicodeEncoding(const TextEncoding* encoding) static bool lowerCaseEqualsASCII(const char* begin, const char* end, const char* str) { while (begin != end && *str) { - ASSERT(isASCIILower(*str)); + ASSERT(toASCIILower(*str) == *str); if (toASCIILower(*begin++) != *str++) return false; } diff --git a/WebCore/platform/SSLKeyGenerator.h b/WebCore/platform/SSLKeyGenerator.h index 398a009..f81f0a5 100644 --- a/WebCore/platform/SSLKeyGenerator.h +++ b/WebCore/platform/SSLKeyGenerator.h @@ -33,7 +33,14 @@ namespace WebCore { class KURL; - void getSupportedKeySizes(Vector<String>&); + // Returns strings representing key sizes that may be used + // for the <keygen> tag. The first string is displayed as the default + // key size in the <keygen> menu. + void getSupportedKeySizes(Vector<String>& sizes); + + // This function handles the <keygen> tag in form elements. + // Returns a signed copy of the combined challenge string and public + // key (from a newly generated key pair). String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String& challengeString, const KURL&); } // namespace WebCore diff --git a/WebCore/platform/ScrollView.cpp b/WebCore/platform/ScrollView.cpp index d59d10a..1c9b5ce 100644 --- a/WebCore/platform/ScrollView.cpp +++ b/WebCore/platform/ScrollView.cpp @@ -762,6 +762,22 @@ void ScrollView::paintScrollCorner(GraphicsContext* context, const IntRect& corn ScrollbarTheme::nativeTheme()->paintScrollCorner(this, context, cornerRect); } +void ScrollView::paintScrollbars(GraphicsContext* context, const IntRect& rect) +{ + if (m_horizontalScrollbar) + m_horizontalScrollbar->paint(context, rect); + if (m_verticalScrollbar) + m_verticalScrollbar->paint(context, rect); + + paintScrollCorner(context, scrollCornerRect()); +} + +void ScrollView::paintPanScrollIcon(GraphicsContext* context) +{ + DEFINE_STATIC_LOCAL(Image*, panScrollIcon, (Image::loadPlatformResource("panIcon").releaseRef())); + context->drawImage(panScrollIcon, m_panScrollIconPoint); +} + void ScrollView::paint(GraphicsContext* context, const IntRect& rect) { if (platformWidget()) { @@ -796,20 +812,15 @@ void ScrollView::paint(GraphicsContext* context, const IntRect& rect) scrollViewDirtyRect.intersect(frameRect()); context->translate(x(), y()); scrollViewDirtyRect.move(-x(), -y()); - if (m_horizontalScrollbar) - m_horizontalScrollbar->paint(context, scrollViewDirtyRect); - if (m_verticalScrollbar) - m_verticalScrollbar->paint(context, scrollViewDirtyRect); - paintScrollCorner(context, scrollCornerRect()); + paintScrollbars(context, scrollViewDirtyRect); + context->restore(); } // Paint the panScroll Icon - if (m_drawPanScrollIcon) { - DEFINE_STATIC_LOCAL(RefPtr<Image>, panScrollIcon, (Image::loadPlatformResource("panIcon"))); - context->drawImage(panScrollIcon.get(), m_panScrollIconPoint); - } + if (m_drawPanScrollIcon) + paintPanScrollIcon(context); } bool ScrollView::isPointInScrollbarCorner(const IntPoint& windowPoint) diff --git a/WebCore/platform/ScrollView.h b/WebCore/platform/ScrollView.h index 2da6829..2844ace 100644 --- a/WebCore/platform/ScrollView.h +++ b/WebCore/platform/ScrollView.h @@ -207,6 +207,7 @@ public: // Widget override. Handles painting of the contents of the view as well as the scrollbars. virtual void paint(GraphicsContext*, const IntRect&); + void paintScrollbars(GraphicsContext*, const IntRect&); // Widget overrides to ensure that our children's visibility status is kept up to date when we get shown and hidden. virtual void show(); @@ -217,6 +218,7 @@ public: static const int noPanScrollRadius = 15; void addPanScrollIcon(const IntPoint&); void removePanScrollIcon(); + void paintPanScrollIcon(GraphicsContext*); virtual bool isPointInScrollbarCorner(const IntPoint&); virtual bool scrollbarCornerPresent() const; @@ -234,7 +236,7 @@ protected: virtual void contentsResized() = 0; virtual void visibleContentsResized() = 0; - + // These methods are used to create/destroy scrollbars. void setHasHorizontalScrollbar(bool); void setHasVerticalScrollbar(bool); diff --git a/WebCore/platform/SuddenTermination.h b/WebCore/platform/SuddenTermination.h index 7171102..3fc5b0f 100644 --- a/WebCore/platform/SuddenTermination.h +++ b/WebCore/platform/SuddenTermination.h @@ -30,6 +30,9 @@ namespace WebCore { + // Once disabled via one or more more calls to disableSuddenTermination(), fast shutdown + // is not valid until enableSuddenTermination() has been called an equal number of times. + // On Mac, these are thin wrappers around Mac OS X functions of the same name. void disableSuddenTermination(); void enableSuddenTermination(); diff --git a/WebCore/platform/android/ClipboardAndroid.h b/WebCore/platform/android/ClipboardAndroid.h index f11798d..e30ea7d 100644 --- a/WebCore/platform/android/ClipboardAndroid.h +++ b/WebCore/platform/android/ClipboardAndroid.h @@ -33,8 +33,9 @@ namespace WebCore { - class CachedImage; +class CachedImage; +<<<<<<< HEAD:WebCore/platform/android/ClipboardAndroid.h class ClipboardAndroid : public Clipboard, public CachedResourceClient { public: ClipboardAndroid(ClipboardAccessPolicy policy, bool isForDragging); @@ -48,17 +49,31 @@ namespace WebCore { // extensions beyond IE's API HashSet<String> types() const; PassRefPtr<FileList> files() const; +======= +class ClipboardAndroid : public Clipboard, public CachedResourceClient { +public: + ClipboardAndroid(ClipboardAccessPolicy policy, bool isForDragging); + ~ClipboardAndroid(); + + void clearData(const String&); + void clearAllData(); + String getData(const String&, bool& success) const; + bool setData(const String&, const String&); + + // extensions beyond IE's API + HashSet<String> types() const; + + void setDragImage(CachedImage*, const IntPoint&); + void setDragImageElement(Node*, const IntPoint&); +>>>>>>> webkit.org at r50258.:WebCore/platform/android/ClipboardAndroid.h - void setDragImage(CachedImage*, const IntPoint&); - void setDragImageElement(Node*, const IntPoint&); - - virtual DragImageRef createDragImage(IntPoint&) const; - virtual void declareAndWriteDragImage(Element*, const KURL&, const String&, Frame*); - virtual void writeURL(const KURL&, const String&, Frame*); - virtual void writeRange(Range*, Frame*); + virtual DragImageRef createDragImage(IntPoint&) const; + virtual void declareAndWriteDragImage(Element*, const KURL&, const String&, Frame*); + virtual void writeURL(const KURL&, const String&, Frame*); + virtual void writeRange(Range*, Frame*); - virtual bool hasData(); - }; + virtual bool hasData(); +}; } // namespace WebCore diff --git a/WebCore/platform/android/CursorAndroid.cpp b/WebCore/platform/android/CursorAndroid.cpp index 5c6e473..beef3b2 100644 --- a/WebCore/platform/android/CursorAndroid.cpp +++ b/WebCore/platform/android/CursorAndroid.cpp @@ -23,6 +23,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #define LOG_TAG "WebCore" #include "config.h" @@ -282,12 +283,14 @@ const Cursor& westPanningCursor() return c; } -const Cursor& grabCursor() { +const Cursor& grabCursor() +{ notImplemented(); return c; } -const Cursor& grabbingCursor() { +const Cursor& grabbingCursor() +{ notImplemented(); return c; } diff --git a/WebCore/platform/android/FileChooserAndroid.cpp b/WebCore/platform/android/FileChooserAndroid.cpp index c293e66..c8e1999 100644 --- a/WebCore/platform/android/FileChooserAndroid.cpp +++ b/WebCore/platform/android/FileChooserAndroid.cpp @@ -36,12 +36,20 @@ String FileChooser::basenameForWidth(const Font& font, int width) const return String(); // FIXME: This could be a lot faster, but assuming the data will not // often be much longer than the provided width, this may be fast enough. +<<<<<<< HEAD:WebCore/platform/android/FileChooserAndroid.cpp // If this does not need to be threadsafe, we can use crossThreadString(). // See http://trac.webkit.org/changeset/49160. +======= +>>>>>>> webkit.org at r50258.:WebCore/platform/android/FileChooserAndroid.cpp String output = m_filenames[0].threadsafeCopy(); +<<<<<<< HEAD:WebCore/platform/android/FileChooserAndroid.cpp while (font.width(TextRun(output.impl())) > width && output.length() > 4) { output = output.replace(0, 4, String("...")); } +======= + while (font.width(TextRun(output.impl())) > width && output.length() > 4) + output = output.replace(output.length() - 4, 4, String("...")); +>>>>>>> webkit.org at r50258.:WebCore/platform/android/FileChooserAndroid.cpp return output; } diff --git a/WebCore/platform/android/FileSystemAndroid.cpp b/WebCore/platform/android/FileSystemAndroid.cpp index f2665a2..46c1297 100644 --- a/WebCore/platform/android/FileSystemAndroid.cpp +++ b/WebCore/platform/android/FileSystemAndroid.cpp @@ -30,12 +30,12 @@ #include "CString.h" #include "StringBuilder.h" -#include <fnmatch.h> -#include <dlfcn.h> +#include "cutils/log.h" #include <dirent.h> +#include <dlfcn.h> #include <errno.h> +#include <fnmatch.h> #include <sys/stat.h> -#include "cutils/log.h" namespace WebCore { @@ -72,7 +72,7 @@ CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) bool unloadModule(PlatformModule module) { - return dlclose(module) == 0; + return !dlclose(module); } void closeFile(PlatformFileHandle& handle) @@ -90,7 +90,7 @@ int writeToFile(PlatformFileHandle handle, const char* data, int length) int bytesWritten = write(handle, data, (size_t)(length - totalBytesWritten)); if (bytesWritten < 0 && errno != EINTR) return -1; - else if (bytesWritten > 0) + if (bytesWritten > 0) totalBytesWritten += bytesWritten; } diff --git a/WebCore/platform/android/KeyEventAndroid.cpp b/WebCore/platform/android/KeyEventAndroid.cpp index 998c781..af29598 100644 --- a/WebCore/platform/android/KeyEventAndroid.cpp +++ b/WebCore/platform/android/KeyEventAndroid.cpp @@ -41,128 +41,128 @@ namespace WebCore { static int windowsKeyCodeForKeyEvent(unsigned int keyCode) { // Does not provide all key codes, and does not handle all keys. - switch(keyCode) { - case kKeyCodeDel: - return VK_BACK; - case kKeyCodeTab: - return VK_TAB; - case kKeyCodeClear: - return VK_CLEAR; - case kKeyCodeDpadCenter: - case kKeyCodeNewline: - return VK_RETURN; - case kKeyCodeShiftLeft: - case kKeyCodeShiftRight: - return VK_SHIFT; - // back will serve as escape, although we probably do not have access to it - case kKeyCodeBack: - return VK_ESCAPE; - case kKeyCodeSpace: - return VK_SPACE; - case kKeyCodeHome: - return VK_HOME; - case kKeyCodeDpadLeft: - return VK_LEFT; - case kKeyCodeDpadUp: - return VK_UP; - case kKeyCodeDpadRight: - return VK_RIGHT; - case kKeyCodeDpadDown: - return VK_DOWN; - case kKeyCode0: - return VK_0; - case kKeyCode1: - return VK_1; - case kKeyCode2: - return VK_2; - case kKeyCode3: - return VK_3; - case kKeyCode4: - return VK_4; - case kKeyCode5: - return VK_5; - case kKeyCode6: - return VK_6; - case kKeyCode7: - return VK_7; - case kKeyCode8: - return VK_8; - case kKeyCode9: - return VK_9; - case kKeyCodeA: - return VK_A; - case kKeyCodeB: - return VK_B; - case kKeyCodeC: - return VK_C; - case kKeyCodeD: - return VK_D; - case kKeyCodeE: - return VK_E; - case kKeyCodeF: - return VK_F; - case kKeyCodeG: - return VK_G; - case kKeyCodeH: - return VK_H; - case kKeyCodeI: - return VK_I; - case kKeyCodeJ: - return VK_J; - case kKeyCodeK: - return VK_K; - case kKeyCodeL: - return VK_L; - case kKeyCodeM: - return VK_M; - case kKeyCodeN: - return VK_N; - case kKeyCodeO: - return VK_O; - case kKeyCodeP: - return VK_P; - case kKeyCodeQ: - return VK_Q; - case kKeyCodeR: - return VK_R; - case kKeyCodeS: - return VK_S; - case kKeyCodeT: - return VK_T; - case kKeyCodeU: - return VK_U; - case kKeyCodeV: - return VK_V; - case kKeyCodeW: - return VK_W; - case kKeyCodeX: - return VK_X; - case kKeyCodeY: - return VK_Y; - case kKeyCodeZ: - return VK_Z; - // colon - case kKeyCodeSemicolon: - return VK_OEM_1; - case kKeyCodeComma: - return VK_OEM_COMMA; - case kKeyCodeMinus: - return VK_OEM_MINUS; - case kKeyCodeEquals: - return VK_OEM_PLUS; - case kKeyCodePeriod: - return VK_OEM_PERIOD; - case kKeyCodeSlash: - return VK_OEM_2; - // maybe not the right choice - case kKeyCodeLeftBracket: - return VK_OEM_4; - case kKeyCodeBackslash: - return VK_OEM_5; - case kKeyCodeRightBracket: - return VK_OEM_6; - default: - return 0; + switch (keyCode) { + case kKeyCodeDel: + return VK_BACK; + case kKeyCodeTab: + return VK_TAB; + case kKeyCodeClear: + return VK_CLEAR; + case kKeyCodeDpadCenter: + case kKeyCodeNewline: + return VK_RETURN; + case kKeyCodeShiftLeft: + case kKeyCodeShiftRight: + return VK_SHIFT; + // back will serve as escape, although we probably do not have access to it + case kKeyCodeBack: + return VK_ESCAPE; + case kKeyCodeSpace: + return VK_SPACE; + case kKeyCodeHome: + return VK_HOME; + case kKeyCodeDpadLeft: + return VK_LEFT; + case kKeyCodeDpadUp: + return VK_UP; + case kKeyCodeDpadRight: + return VK_RIGHT; + case kKeyCodeDpadDown: + return VK_DOWN; + case kKeyCode0: + return VK_0; + case kKeyCode1: + return VK_1; + case kKeyCode2: + return VK_2; + case kKeyCode3: + return VK_3; + case kKeyCode4: + return VK_4; + case kKeyCode5: + return VK_5; + case kKeyCode6: + return VK_6; + case kKeyCode7: + return VK_7; + case kKeyCode8: + return VK_8; + case kKeyCode9: + return VK_9; + case kKeyCodeA: + return VK_A; + case kKeyCodeB: + return VK_B; + case kKeyCodeC: + return VK_C; + case kKeyCodeD: + return VK_D; + case kKeyCodeE: + return VK_E; + case kKeyCodeF: + return VK_F; + case kKeyCodeG: + return VK_G; + case kKeyCodeH: + return VK_H; + case kKeyCodeI: + return VK_I; + case kKeyCodeJ: + return VK_J; + case kKeyCodeK: + return VK_K; + case kKeyCodeL: + return VK_L; + case kKeyCodeM: + return VK_M; + case kKeyCodeN: + return VK_N; + case kKeyCodeO: + return VK_O; + case kKeyCodeP: + return VK_P; + case kKeyCodeQ: + return VK_Q; + case kKeyCodeR: + return VK_R; + case kKeyCodeS: + return VK_S; + case kKeyCodeT: + return VK_T; + case kKeyCodeU: + return VK_U; + case kKeyCodeV: + return VK_V; + case kKeyCodeW: + return VK_W; + case kKeyCodeX: + return VK_X; + case kKeyCodeY: + return VK_Y; + case kKeyCodeZ: + return VK_Z; + // colon + case kKeyCodeSemicolon: + return VK_OEM_1; + case kKeyCodeComma: + return VK_OEM_COMMA; + case kKeyCodeMinus: + return VK_OEM_MINUS; + case kKeyCodeEquals: + return VK_OEM_PLUS; + case kKeyCodePeriod: + return VK_OEM_PERIOD; + case kKeyCodeSlash: + return VK_OEM_2; + // maybe not the right choice + case kKeyCodeLeftBracket: + return VK_OEM_4; + case kKeyCodeBackslash: + return VK_OEM_5; + case kKeyCodeRightBracket: + return VK_OEM_6; + default: + return 0; } } @@ -171,28 +171,28 @@ static String keyIdentifierForAndroidKeyCode(int keyCode) // Does not return all of the same key identifiers, and // does not handle all the keys. switch (keyCode) { - case kKeyCodeClear: - return "Clear"; - case kKeyCodeNewline: - case kKeyCodeDpadCenter: - return "Enter"; - case kKeyCodeHome: - return "Home"; - case kKeyCodeDpadDown: - return "Down"; - case kKeyCodeDpadLeft: - return "Left"; - case kKeyCodeDpadRight: - return "Right"; - case kKeyCodeDpadUp: - return "Up"; - // Standard says that DEL becomes U+00007F. - case kKeyCodeDel: - return "U+00007F"; - default: - char upper[16]; - sprintf(upper, "U+%06X", windowsKeyCodeForKeyEvent(keyCode)); - return String(upper); + case kKeyCodeClear: + return "Clear"; + case kKeyCodeNewline: + case kKeyCodeDpadCenter: + return "Enter"; + case kKeyCodeHome: + return "Home"; + case kKeyCodeDpadDown: + return "Down"; + case kKeyCodeDpadLeft: + return "Left"; + case kKeyCodeDpadRight: + return "Right"; + case kKeyCodeDpadUp: + return "Up"; + // Standard says that DEL becomes U+00007F. + case kKeyCodeDel: + return "U+00007F"; + default: + char upper[16]; + sprintf(upper, "U+%06X", windowsKeyCodeForKeyEvent(keyCode)); + return String(upper); } } diff --git a/WebCore/platform/android/ScreenAndroid.cpp b/WebCore/platform/android/ScreenAndroid.cpp index 2439c1f..dcd2d10 100644 --- a/WebCore/platform/android/ScreenAndroid.cpp +++ b/WebCore/platform/android/ScreenAndroid.cpp @@ -31,14 +31,12 @@ #include "FloatRect.h" #include "Widget.h" - +#include "ui/DisplayInfo.h" +#include "ui/PixelFormat.h" +#include "ui/SurfaceComposerClient.h" #undef LOG // FIXME: Still have to do this to get the log to show up #include "utils/Log.h" -#include "ui/SurfaceComposerClient.h" -#include "ui/PixelFormat.h" -#include "ui/DisplayInfo.h" - namespace WebCore { int screenDepth(Widget* page) @@ -70,18 +68,18 @@ int Screen::orientation() const // to the values described here // (http://developer.apple.com/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/chapter_8_section_6.html) switch (info.orientation) { - case android::ISurfaceComposer::eOrientationDefault: - return 0; - case android::ISurfaceComposer::eOrientation90: - return 90; - case android::ISurfaceComposer::eOrientation180: - return 180; - case android::ISurfaceComposer::eOrientation270: - return -90; - default: - LOGE("Bad orientation returned from getDisplayIndo %d", - info.orientation); - return 0; + case android::ISurfaceComposer::eOrientationDefault: + return 0; + case android::ISurfaceComposer::eOrientation90: + return 90; + case android::ISurfaceComposer::eOrientation180: + return 180; + case android::ISurfaceComposer::eOrientation270: + return -90; + default: + LOGE("Bad orientation returned from getDisplayIndo %d", + info.orientation); + return 0; } } #endif diff --git a/WebCore/platform/android/TemporaryLinkStubs.cpp b/WebCore/platform/android/TemporaryLinkStubs.cpp index 215c7f5..e1889f0 100644 --- a/WebCore/platform/android/TemporaryLinkStubs.cpp +++ b/WebCore/platform/android/TemporaryLinkStubs.cpp @@ -28,17 +28,15 @@ #define ANDROID_COMPILE_HACK -#include <stdio.h> -#include <stdlib.h> #include "AXObjectCache.h" +#include "CString.h" #include "CachedPage.h" #include "CachedResource.h" -#include "CookieJar.h" +#include "Clipboard.h" #include "Console.h" #include "ContextMenu.h" #include "ContextMenuItem.h" -#include "Clipboard.h" -#include "CString.h" +#include "CookieJar.h" #include "Cursor.h" #include "Database.h" #include "DocumentFragment.h" @@ -48,8 +46,8 @@ #include "File.h" #include "Font.h" #include "Frame.h" -#include "FrameLoader.h" #include "FrameLoadRequest.h" +#include "FrameLoader.h" #include "FrameView.h" #include "GraphicsContext.h" #include "HTMLFrameOwnerElement.h" @@ -59,21 +57,11 @@ #include "IconDatabase.h" #include "IconLoader.h" #include "IntPoint.h" - -#if USE(JSC) -#include "JavaScriptCallFrame.h" -#include "JavaScriptDebugServer.h" -#include "API/JSClassRef.h" -#include "JavaScriptProfile.h" -#include "jni_utility.h" -#endif - #include "KURL.h" #include "Language.h" -#include "loader.h" #include "LocalizedStrings.h" -#include "MainResourceLoader.h" #include "MIMETypeRegistry.h" +#include "MainResourceLoader.h" #include "Node.h" #include "NotImplemented.h" #include "PageCache.h" @@ -88,6 +76,17 @@ #include "ScrollbarTheme.h" #include "SmartReplace.h" #include "Widget.h" +#include "loader.h" +#include <stdio.h> +#include <stdlib.h> + +#if USE(JSC) +#include "API/JSClassRef.h" +#include "JavaScriptCallFrame.h" +#include "JavaScriptDebugServer.h" +#include "JavaScriptProfile.h" +#include "jni_utility.h" +#endif using namespace WebCore; diff --git a/WebCore/platform/chromium/ChromiumBridge.h b/WebCore/platform/chromium/ChromiumBridge.h index 1afcc23..0c80636 100644 --- a/WebCore/platform/chromium/ChromiumBridge.h +++ b/WebCore/platform/chromium/ChromiumBridge.h @@ -32,12 +32,11 @@ #define ChromiumBridge_h #include "FileSystem.h" +#include "ImageSource.h" #include "LinkHash.h" #include "PassRefPtr.h" #include "PasteboardPrivate.h" -class NativeImageSkia; - typedef struct NPObject NPObject; typedef struct _NPP NPP_t; typedef NPP_t* NPP; @@ -78,7 +77,7 @@ namespace WebCore { static void clipboardWriteSelection(const String&, const KURL&, const String&, bool); static void clipboardWritePlainText(const String&); static void clipboardWriteURL(const KURL&, const String&); - static void clipboardWriteImage(const NativeImageSkia*, const KURL&, const String&); + static void clipboardWriteImage(NativeImagePtr, const KURL&, const String&); // Cookies ------------------------------------------------------------ static void setCookies(const KURL& url, const KURL& firstPartyForCookies, const String& value); @@ -127,6 +126,9 @@ namespace WebCore { static void notifyJSOutOfMemory(Frame*); static bool allowScriptDespiteSettings(const KURL& documentURL); + // Keygen ------------------------------------------------------------- + static String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String& challenge, const KURL& url); + // Language ----------------------------------------------------------- static String computedDefaultLanguage(); diff --git a/WebCore/platform/chromium/ChromiumDataObject.h b/WebCore/platform/chromium/ChromiumDataObject.h index a227001..3e8675e 100644 --- a/WebCore/platform/chromium/ChromiumDataObject.h +++ b/WebCore/platform/chromium/ChromiumDataObject.h @@ -55,38 +55,7 @@ namespace WebCore { void clear(); bool hasData() const; - - KURL mainURL() const { return url; } - void setMainURL(const KURL& newURL) { url = newURL; } - String mainURLTitle() const { return urlTitle; } - void setMainURLTitle(const String& newURLTitle) { urlTitle = newURLTitle; } - - String textPlain() const { return plainText; } - void setTextPlain(const String& newText) { plainText = newText; } - - String textHTML() const { return textHtml; } - void setTextHTML(const String& newText) { textHtml = newText; } - - KURL htmlBaseURL() const { return htmlBaseUrl; } - void setHTMLBaseURL(const KURL& newURL) { htmlBaseUrl = newURL; } - - SharedBuffer* content() const { return fileContent.get(); } - PassRefPtr<SharedBuffer> releaseContent() { return fileContent.release(); } - void setContent(PassRefPtr<SharedBuffer> newContent) { fileContent = newContent; } - - String contentFileExtension() const { return fileExtension; } - void setContentFileExtension(const String& newFileExtension) { fileExtension = newFileExtension; } - - String contentFileName() const { return fileContentFilename; } - void setContentFileName(const String& newFilename) { fileContentFilename = newFilename; } - - const Vector<String>& fileNames() const { return filenames; } - void setFileNames(const Vector<String>& newFilenames) { filenames = newFilenames; } - void takeFileNames(Vector<String>& newFilenames) { filenames.swap(newFilenames); } - - // Interim state: All members will become private, do NOT access them directly! - // Rather use the above accessor methods (or devise new ones if necessary). KURL url; String urlTitle; diff --git a/WebCore/platform/chromium/FramelessScrollViewClient.h b/WebCore/platform/chromium/FramelessScrollViewClient.h index 4b32a43..35bae10 100644 --- a/WebCore/platform/chromium/FramelessScrollViewClient.h +++ b/WebCore/platform/chromium/FramelessScrollViewClient.h @@ -34,6 +34,7 @@ #include "HostWindow.h" namespace WebCore { + class FramelessScrollView; class FramelessScrollViewClient : public HostWindow { public: diff --git a/WebCore/platform/chromium/KeyCodeConversionGtk.cpp b/WebCore/platform/chromium/KeyCodeConversionGtk.cpp index 5950de1..e3d5f61 100644 --- a/WebCore/platform/chromium/KeyCodeConversionGtk.cpp +++ b/WebCore/platform/chromium/KeyCodeConversionGtk.cpp @@ -91,6 +91,7 @@ int windowsKeyCodeForKeyEvent(unsigned keycode) case GDK_Control_R: return VKEY_CONTROL; // (11) CTRL key case GDK_Menu: + return VKEY_APPS; // (5D) Applications key (Natural keyboard) case GDK_Alt_L: case GDK_Alt_R: return VKEY_MENU; // (12) ALT key @@ -261,7 +262,6 @@ int windowsKeyCodeForKeyEvent(unsigned keycode) return VKEY_LWIN; // (5B) Left Windows key (Microsoft Natural keyboard) case GDK_Meta_R: return VKEY_RWIN; // (5C) Right Windows key (Natural keyboard) - // VKEY_APPS (5D) Applications key (Natural keyboard) // VKEY_SLEEP (5F) Computer Sleep key // VKEY_SEPARATOR (6C) Separator key // VKEY_SUBTRACT (6D) Subtract key diff --git a/WebCore/platform/chromium/MimeTypeRegistryChromium.cpp b/WebCore/platform/chromium/MIMETypeRegistryChromium.cpp index 0f371b1..51bff80 100644 --- a/WebCore/platform/chromium/MimeTypeRegistryChromium.cpp +++ b/WebCore/platform/chromium/MIMETypeRegistryChromium.cpp @@ -78,6 +78,8 @@ String MIMETypeRegistry::getMIMETypeForPath(const String& path) // if a plugin can handle the extension. mimeType = getPluginMimeTypeFromExtension(extension); } + if (mimeType.isEmpty()) + return "application/octet-stream"; return mimeType; } diff --git a/WebCore/platform/chromium/PasteboardChromium.cpp b/WebCore/platform/chromium/PasteboardChromium.cpp index 7702730..4929eb8 100644 --- a/WebCore/platform/chromium/PasteboardChromium.cpp +++ b/WebCore/platform/chromium/PasteboardChromium.cpp @@ -147,10 +147,7 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String& title) } KURL url = urlString.isEmpty() ? KURL() : node->document()->completeURL(deprecatedParseURL(urlString)); - NativeImageSkia* bitmap = 0; -#if !PLATFORM(CG) - bitmap = image->nativeImageForCurrentFrame(); -#endif + NativeImagePtr bitmap = image->nativeImageForCurrentFrame(); ChromiumBridge::clipboardWriteImage(bitmap, url, title); } diff --git a/WebCore/platform/chromium/SSLKeyGeneratorChromium.cpp b/WebCore/platform/chromium/SSLKeyGeneratorChromium.cpp index fdedf2b..49d9517 100644 --- a/WebCore/platform/chromium/SSLKeyGeneratorChromium.cpp +++ b/WebCore/platform/chromium/SSLKeyGeneratorChromium.cpp @@ -1,10 +1,10 @@ /* * Copyright (c) 2008, 2009, Google Inc. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above @@ -14,7 +14,7 @@ * * 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 @@ -31,22 +31,29 @@ #include "config.h" #include "SSLKeyGenerator.h" +#include "ChromiumBridge.h" +#include "PlatformString.h" + namespace WebCore { -// These are defined in webkit/glue/localized_strings.cpp. +// These are defined in webkit/api/src/LocalizedStrings.cpp. String keygenMenuHighGradeKeySize(); String keygenMenuMediumGradeKeySize(); -// Returns the key sizes supported by the HTML keygen tag. The first string -// is displayed as the default key size in the keygen menu. -Vector<String> supportedKeySizes() +void getSupportedKeySizes(Vector<String>& sizes) { - Vector<String> sizes(2); + sizes.resize(2); sizes[0] = keygenMenuHighGradeKeySize(); sizes[1] = keygenMenuMediumGradeKeySize(); - return sizes; } -// FIXME: implement signedPublicKeyAndChallengeString here. +String signedPublicKeyAndChallengeString(unsigned keySizeIndex, + const String& challengeString, + const KURL& url) +{ + return ChromiumBridge::signedPublicKeyAndChallengeString(keySizeIndex, + challengeString, + url); +} } // namespace WebCore diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp index ed8bf36..64f58c4 100644 --- a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp +++ b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp @@ -140,9 +140,17 @@ void ScrollbarThemeChromiumLinux::paintThumb(GraphicsContext* gc, Scrollbar* scr if (rect.height() > 10 && rect.width() > 10) { paint.setARGB(0xff, 0x9d, 0x96, 0x8e); - drawHorizLine(canvas, midx - 1, midx + 3, midy, paint); - drawHorizLine(canvas, midx - 1, midx + 3, midy - 3, paint); - drawHorizLine(canvas, midx - 1, midx + 3, midy + 3, paint); + const int grippyHalfWidth = 2; + const int interGrippyOffset = 3; + if (vertical) { + drawHorizLine(canvas, midx - grippyHalfWidth, midx + grippyHalfWidth, midy - interGrippyOffset, paint); + drawHorizLine(canvas, midx - grippyHalfWidth, midx + grippyHalfWidth, midy, paint); + drawHorizLine(canvas, midx - grippyHalfWidth, midx + grippyHalfWidth, midy + interGrippyOffset, paint); + } else { + drawVertLine(canvas, midx - interGrippyOffset, midy - grippyHalfWidth, midy + grippyHalfWidth, paint); + drawVertLine(canvas, midx, midy - grippyHalfWidth, midy + grippyHalfWidth, paint); + drawVertLine(canvas, midx + interGrippyOffset, midy - grippyHalfWidth, midy + grippyHalfWidth, paint); + } } } diff --git a/WebCore/platform/chromium/TemporaryLinkStubs.cpp b/WebCore/platform/chromium/TemporaryLinkStubs.cpp index f6e77d4..1f60d95 100644 --- a/WebCore/platform/chromium/TemporaryLinkStubs.cpp +++ b/WebCore/platform/chromium/TemporaryLinkStubs.cpp @@ -1,10 +1,10 @@ /* * Copyright (c) 2008, 2009, Google Inc. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above @@ -14,7 +14,7 @@ * * 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 @@ -36,11 +36,16 @@ namespace WebCore { -String signedPublicKeyAndChallengeString(unsigned, const String&, const KURL&) { notImplemented(); return String(); } -void getSupportedKeySizes(Vector<String>&) { notImplemented(); } +String KURL::fileSystemPath() const +{ + notImplemented(); + return String(); +} -String KURL::fileSystemPath() const { notImplemented(); return String(); } - -PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String&) { notImplemented(); return 0; } +PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String&) +{ + notImplemented(); + return 0; +} } // namespace WebCore diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h index b1d1ef9..5b62b2c 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -334,6 +334,11 @@ namespace WebCore { void addPath(const Path&); void clip(const Path&); + + // This clip function is used only by <canvas> code. It allows + // implementations to handle clipping on the canvas differently since + // the disipline is different. + void canvasClip(const Path&); void clipOut(const Path&); void scale(const FloatSize&); diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h index 5223e05..07ec04d 100644 --- a/WebCore/platform/graphics/GraphicsContext3D.h +++ b/WebCore/platform/graphics/GraphicsContext3D.h @@ -29,6 +29,7 @@ #include "PlatformString.h" #include <wtf/Noncopyable.h> +#include <wtf/PassOwnPtr.h> #if PLATFORM(MAC) #include <OpenGL/OpenGL.h> @@ -45,6 +46,7 @@ const Platform3DObject NullPlatform3DObject = 0; #endif namespace WebCore { + class CanvasActiveInfo; class CanvasArray; class CanvasBuffer; class CanvasUnsignedByteArray; @@ -61,17 +63,23 @@ namespace WebCore { class HTMLVideoElement; class ImageData; class WebKitCSSMatrix; - + + struct ActiveInfo { + String name; + unsigned type; + int size; + }; + // FIXME: ideally this would be used on all platforms. #if PLATFORM(CHROMIUM) class GraphicsContext3DInternal; #endif - class GraphicsContext3D : Noncopyable { + class GraphicsContext3D : public Noncopyable { public: enum ShaderType { FRAGMENT_SHADER, VERTEX_SHADER }; - GraphicsContext3D(); + static PassOwnPtr<GraphicsContext3D> create(); virtual ~GraphicsContext3D(); #if PLATFORM(MAC) @@ -85,7 +93,6 @@ namespace WebCore { Platform3DObject platformTexture() const { return NullPlatform3DObject; } #endif void checkError() const; - void makeContextCurrent(); // Helper to return the size in bytes of OpenGL data types @@ -141,6 +148,9 @@ namespace WebCore { void frontFace(unsigned long mode); void generateMipmap(unsigned long target); + bool getActiveAttrib(CanvasProgram* program, unsigned long index, ActiveInfo&); + bool getActiveUniform(CanvasProgram* program, unsigned long index, ActiveInfo&); + int getAttribLocation(CanvasProgram*, const String& name); bool getBoolean(unsigned long pname); @@ -204,8 +214,7 @@ namespace WebCore { void pixelStorei(unsigned long pname, long param); void polygonOffset(double factor, double units); - // TBD - //void readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type, void* pixels); + PassRefPtr<CanvasArray> readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type); void releaseShaderCompiler(); void renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height); @@ -311,6 +320,8 @@ namespace WebCore { void deleteTexture(unsigned); private: + GraphicsContext3D(); + int m_currentWidth, m_currentHeight; #if PLATFORM(MAC) diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp index b375bd3..c8582bb 100644 --- a/WebCore/platform/graphics/GraphicsLayer.cpp +++ b/WebCore/platform/graphics/GraphicsLayer.cpp @@ -59,9 +59,7 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client) : m_client(client) , m_anchorPoint(0.5f, 0.5f, 0) , m_opacity(1) -#ifndef NDEBUG , m_zPosition(0) -#endif , m_backgroundColorSet(false) , m_contentsOpaque(false) , m_preserves3D(false) @@ -74,9 +72,7 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client) , m_contentsOrientation(CompositingCoordinatesTopDown) , m_parent(0) , m_maskLayer(0) -#ifndef NDEBUG , m_repaintCount(0) -#endif { } @@ -86,6 +82,16 @@ GraphicsLayer::~GraphicsLayer() removeFromParent(); } +bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const +{ + for (GraphicsLayer* curr = parent(); curr; curr = curr->parent()) { + if (curr == ancestor) + return true; + } + + return false; +} + void GraphicsLayer::addChild(GraphicsLayer* childLayer) { ASSERT(childLayer != this); @@ -219,7 +225,6 @@ void GraphicsLayer::resumeAnimations() { } -#ifndef NDEBUG void GraphicsLayer::updateDebugIndicators() { if (GraphicsLayer::showDebugBorders()) { @@ -241,7 +246,6 @@ void GraphicsLayer::setZPosition(float position) { m_zPosition = position; } -#endif float GraphicsLayer::accumulatedOpacity() const { diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h index 2924073..85eace0 100644 --- a/WebCore/platform/graphics/GraphicsLayer.h +++ b/WebCore/platform/graphics/GraphicsLayer.h @@ -172,6 +172,9 @@ public: GraphicsLayer* parent() const { return m_parent; }; void setParent(GraphicsLayer* layer) { m_parent = layer; } // Internal use only. + // Returns true if the layer has the given layer as an ancestor (excluding self). + bool hasAncestor(GraphicsLayer*) const; + const Vector<GraphicsLayer*>& children() const { return m_children; } // Add child layers. If the child is already parented, it will be removed from its old parent. @@ -273,10 +276,8 @@ public: void dumpLayer(TextStream&, int indent = 0) const; -#ifndef NDEBUG int repaintCount() const { return m_repaintCount; } int incrementRepaintCount() { return ++m_repaintCount; } -#endif // Report whether the underlying compositing system uses a top-down // or a bottom-up coordinate system. @@ -291,7 +292,6 @@ public: virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation) { m_contentsOrientation = orientation; } CompositingCoordinatesOrientation contentsOrientation() const { return m_contentsOrientation; } -#ifndef NDEBUG static bool showDebugBorders(); static bool showRepaintCounter(); @@ -302,7 +302,6 @@ public: // z-position is the z-equivalent of position(). It's only used for debugging purposes. virtual float zPosition() const { return m_zPosition; } virtual void setZPosition(float); -#endif virtual void distributeOpacity(float); virtual float accumulatedOpacity() const; @@ -339,9 +338,7 @@ protected: Color m_backgroundColor; float m_opacity; -#ifndef NDEBUG float m_zPosition; -#endif bool m_backgroundColorSet : 1; bool m_contentsOpaque : 1; @@ -362,9 +359,7 @@ protected: IntRect m_contentsRect; -#ifndef NDEBUG int m_repaintCount; -#endif }; diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index de8afb3..8741c5e 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -931,6 +931,11 @@ void GraphicsContext::clip(const Path& path) m_data->clip(path); } +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + void GraphicsContext::clipOut(const Path& path) { if (paintingDisabled()) diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index 1b843e4..1350bd3 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -849,6 +849,11 @@ void GraphicsContext::clip(const Path& path) m_data->clip(path); } +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + void GraphicsContext::clipOut(const Path& path) { if (paintingDisabled()) diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp index dca0efb..a4526a8 100644 --- a/WebCore/platform/graphics/chromium/FontLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontLinux.cpp @@ -57,6 +57,23 @@ bool Font::canReturnFallbackFontsForComplexText() return false; } +static bool isCanvasMultiLayered(SkCanvas* canvas) +{ + SkCanvas::LayerIter layerIterator(canvas, false); + layerIterator.next(); + return !layerIterator.done(); +} + +static bool adjustTextRenderMode(SkPaint* paint, bool isCanvasMultiLayered) +{ + // Our layers only have a single alpha channel. This means that subpixel + // rendered text cannot be compositied correctly when the layer is + // collapsed. Therefore, subpixel text is disabled when we are drawing + // onto a layer. + if (isCanvasMultiLayered) + paint->setLCDRenderText(false); +} + void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { @@ -84,12 +101,14 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, SkCanvas* canvas = gc->platformContext()->canvas(); int textMode = gc->platformContext()->getTextDrawingMode(); + bool haveMultipleLayers = isCanvasMultiLayered(canvas); // We draw text up to two times (once for fill, once for stroke). if (textMode & cTextFill) { SkPaint paint; gc->platformContext()->setupPaintForFilling(&paint); font->platformData().setupPaint(&paint); + adjustTextRenderMode(&paint, haveMultipleLayers); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); paint.setColor(gc->fillColor().rgb()); canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint); @@ -102,6 +121,7 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, SkPaint paint; gc->platformContext()->setupPaintForStroking(&paint, 0, 0); font->platformData().setupPaint(&paint); + adjustTextRenderMode(&paint, haveMultipleLayers); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); paint.setColor(gc->strokeColor().rgb()); @@ -472,15 +492,18 @@ void Font::drawComplexText(GraphicsContext* gc, const TextRun& run, } TextRunWalker walker(run, point.x(), this); + bool haveMultipleLayers = isCanvasMultiLayered(canvas); while (walker.nextScriptRun()) { if (fill) { walker.fontPlatformDataForScriptRun()->setupPaint(&fillPaint); + adjustTextRenderMode(&fillPaint, haveMultipleLayers); canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), fillPaint); } if (stroke) { walker.fontPlatformDataForScriptRun()->setupPaint(&strokePaint); + adjustTextRenderMode(&strokePaint, haveMultipleLayers); canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), strokePaint); } } @@ -645,8 +668,6 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, if (toX == -1 && !to) toX = rightEdge; - else if (!walker.rtl()) - toX += truncateFixedPointToInteger(toAdvance); ASSERT(fromX != -1 && toX != -1); diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp index 1e2e552..a2ed9bd 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp +++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp @@ -30,6 +30,7 @@ #include "GraphicsContext.h" #include "ImageData.h" #include <math.h> +#include <wtf/MathExtras.h> namespace WebCore { @@ -92,8 +93,8 @@ inline void saturate(double& red, double& green, double& blue, const float& s) inline void huerotate(double& red, double& green, double& blue, const float& hue) { - double cosHue = cos(hue * M_PI / 180); - double sinHue = sin(hue * M_PI / 180); + double cosHue = cos(hue * piDouble / 180); + double sinHue = sin(hue * piDouble / 180); double r = red * (0.213 + cosHue * 0.787 - sinHue * 0.213) + green * (0.715 - cosHue * 0.715 - sinHue * 0.715) + blue * (0.072 - cosHue * 0.072 + sinHue * 0.928); diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp index 43e5edd..0d76d8d 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp @@ -92,11 +92,11 @@ void FEComponentTransfer::setAlphaFunction(const ComponentTransferFunction& func m_alphaFunc = func; } -void identity(unsigned char*, const ComponentTransferFunction&) +static void identity(unsigned char*, const ComponentTransferFunction&) { } -void table(unsigned char* values, const ComponentTransferFunction& transferFunction) +static void table(unsigned char* values, const ComponentTransferFunction& transferFunction) { const Vector<float>& tableValues = transferFunction.tableValues; unsigned n = tableValues.size(); @@ -113,7 +113,7 @@ void table(unsigned char* values, const ComponentTransferFunction& transferFunct } } -void discrete(unsigned char* values, const ComponentTransferFunction& transferFunction) +static void discrete(unsigned char* values, const ComponentTransferFunction& transferFunction) { const Vector<float>& tableValues = transferFunction.tableValues; unsigned n = tableValues.size(); @@ -128,7 +128,7 @@ void discrete(unsigned char* values, const ComponentTransferFunction& transferFu } } -void linear(unsigned char* values, const ComponentTransferFunction& transferFunction) +static void linear(unsigned char* values, const ComponentTransferFunction& transferFunction) { for (unsigned i = 0; i < 256; ++i) { double val = transferFunction.slope * i + 255 * transferFunction.intercept; @@ -137,7 +137,7 @@ void linear(unsigned char* values, const ComponentTransferFunction& transferFunc } } -void gamma(unsigned char* values, const ComponentTransferFunction& transferFunction) +static void gamma(unsigned char* values, const ComponentTransferFunction& transferFunction) { for (unsigned i = 0; i < 256; ++i) { double val = 255.0 * (transferFunction.amplitude * pow((i / 255.0), transferFunction.exponent) + transferFunction.offset); diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp new file mode 100644 index 0000000..f480f10 --- /dev/null +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp @@ -0,0 +1,140 @@ +/* + Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + 2004, 2005 Rob Buis <buis@kde.org> + 2005 Eric Seidel <eric@webkit.org> + 2009 Dirk Schulze <krit@webkit.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEGaussianBlur.h" + +#include "CanvasPixelArray.h" +#include "Filter.h" +#include "GraphicsContext.h" +#include "ImageData.h" +#include <math.h> +#include <wtf/MathExtras.h> + +namespace WebCore { + +FEGaussianBlur::FEGaussianBlur(FilterEffect* in, const float& x, const float& y) + : FilterEffect() + , m_in(in) + , m_x(x) + , m_y(y) +{ +} + +PassRefPtr<FEGaussianBlur> FEGaussianBlur::create(FilterEffect* in, const float& x, const float& y) +{ + return adoptRef(new FEGaussianBlur(in, x, y)); +} + +float FEGaussianBlur::stdDeviationX() const +{ + return m_x; +} + +void FEGaussianBlur::setStdDeviationX(float x) +{ + m_x = x; +} + +float FEGaussianBlur::stdDeviationY() const +{ + return m_y; +} + +void FEGaussianBlur::setStdDeviationY(float y) +{ + m_y = y; +} + +static void boxBlur(CanvasPixelArray*& srcPixelArray, CanvasPixelArray*& dstPixelArray, + unsigned dx, int stride, int strideLine, int effectWidth, int effectHeight, bool alphaImage) +{ + int dxLeft = dx / 2; + int dxRight = dx - dxLeft; + + for (int y = 0; y < effectHeight; ++y) { + int line = y * strideLine; + for (int channel = 3; channel >= 0; --channel) { + int sum = 0; + // Fill the kernel + int maxKernelSize = std::min(dxRight, effectWidth); + for (int i = 0; i < maxKernelSize; ++i) + sum += srcPixelArray->get(line + i * stride + channel); + + // Blurring + for (int x = 0; x < effectWidth; ++x) { + int pixelByteOffset = line + x * stride + channel; + dstPixelArray->set(pixelByteOffset, static_cast<unsigned char>(sum / dx)); + if (x >= dxLeft) + sum -= srcPixelArray->get(pixelByteOffset - dxLeft * stride); + if (x + dxRight < effectWidth) + sum += srcPixelArray->get(pixelByteOffset + dxRight * stride); + } + if (alphaImage) // Source image is black, it just has different alpha values + break; + } + } +} + +void FEGaussianBlur::apply(Filter* filter) +{ + m_in->apply(filter); + if (!m_in->resultImage()) + return; + + if (!getEffectContext()) + return; + + setIsAlphaImage(m_in->isAlphaImage()); + + if (m_x == 0 || m_y == 0) + return; + + unsigned sdx = static_cast<unsigned>(floor(m_x * 3 * sqrt(2 * piDouble) / 4.f + 0.5f)); + unsigned sdy = static_cast<unsigned>(floor(m_y * 3 * sqrt(2 * piDouble) / 4.f + 0.5f)); + + IntRect effectDrawingRect = calculateDrawingIntRect(m_in->subRegion()); + RefPtr<ImageData> srcImageData(m_in->resultImage()->getPremultipliedImageData(effectDrawingRect)); + CanvasPixelArray* srcPixelArray(srcImageData->data()); + + IntRect imageRect(IntPoint(), resultImage()->size()); + RefPtr<ImageData> tmpImageData = ImageData::create(imageRect.width(), imageRect.height()); + CanvasPixelArray* tmpPixelArray(tmpImageData->data()); + + int stride = 4 * imageRect.width(); + for (int i = 0; i < 3; ++i) { + boxBlur(srcPixelArray, tmpPixelArray, sdx, 4, stride, imageRect.width(), imageRect.height(), isAlphaImage()); + boxBlur(tmpPixelArray, srcPixelArray, sdy, stride, 4, imageRect.height(), imageRect.width(), isAlphaImage()); + } + + resultImage()->putPremultipliedImageData(srcImageData.get(), imageRect, IntPoint()); +} + +void FEGaussianBlur::dump() +{ +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.h b/WebCore/platform/graphics/filters/FEGaussianBlur.h new file mode 100644 index 0000000..ecdb9e3 --- /dev/null +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + 2004, 2005 Rob Buis <buis@kde.org> + 2005 Eric Seidel <eric@webkit.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef FEGaussianBlur_h +#define FEGaussianBlur_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "Filter.h" + +namespace WebCore { + + class FEGaussianBlur : public FilterEffect { + public: + static PassRefPtr<FEGaussianBlur> create(FilterEffect*, const float&, const float&); + + float stdDeviationX() const; + void setStdDeviationX(float); + + float stdDeviationY() const; + void setStdDeviationY(float); + + virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return calculateUnionOfChildEffectSubregions(filter, m_in.get()); } + void apply(Filter*); + void dump(); + + private: + FEGaussianBlur(FilterEffect*, const float&, const float&); + + RefPtr<FilterEffect> m_in; + float m_x; + float m_y; + }; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEGaussianBlur_h diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp index 5818e50..68900b5 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.cpp +++ b/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -25,14 +25,11 @@ namespace WebCore { FilterEffect::FilterEffect() - : m_xBBoxMode(false) - , m_yBBoxMode(false) - , m_widthBBoxMode(false) - , m_heightBBoxMode(false) - , m_hasX(false) + : m_hasX(false) , m_hasY(false) , m_hasWidth(false) , m_hasHeight(false) + , m_alphaImage(false) { } diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h index e2b8a0e..b30e513 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.h +++ b/WebCore/platform/graphics/filters/FilterEffect.h @@ -38,18 +38,6 @@ namespace WebCore { public: virtual ~FilterEffect(); - bool xBoundingBoxMode() const { return m_xBBoxMode; } - void setXBoundingBoxMode(bool bboxMode) { m_xBBoxMode = bboxMode; } - - bool yBoundingBoxMode() const { return m_yBBoxMode; } - void setYBoundingBoxMode(bool bboxMode) { m_yBBoxMode = bboxMode; } - - bool widthBoundingBoxMode() const { return m_widthBBoxMode; } - void setWidthBoundingBoxMode(bool bboxMode) { m_widthBBoxMode = bboxMode; } - - bool heightBoundingBoxMode() const { return m_heightBBoxMode; } - void setHeightBoundingBoxMode(bool bboxMode) { m_heightBBoxMode = bboxMode; } - void setUnionOfChildEffectSubregions(const FloatRect& uniteRect) { m_unionOfChildEffectSubregions = uniteRect; } FloatRect unionOfChildEffectSubregions() const { return m_unionOfChildEffectSubregions; } @@ -79,6 +67,10 @@ namespace WebCore { FloatRect calculateDrawingRect(const FloatRect&); IntRect calculateDrawingIntRect(const FloatRect&); + // black image with different alpha values + bool isAlphaImage() { return m_alphaImage; } + void setIsAlphaImage(bool alphaImage) { m_alphaImage = alphaImage; } + virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return filter->filterRegion(); } virtual FloatRect calculateEffectRect(Filter*); virtual void apply(Filter*) = 0; @@ -102,6 +94,8 @@ namespace WebCore { bool m_hasWidth : 1; bool m_hasHeight : 1; + bool m_alphaImage; + FloatRect m_subRegion; FloatRect m_unionOfChildEffectSubregions; diff --git a/WebCore/platform/graphics/filters/SourceAlpha.cpp b/WebCore/platform/graphics/filters/SourceAlpha.cpp index 57436be..1b6309b 100644 --- a/WebCore/platform/graphics/filters/SourceAlpha.cpp +++ b/WebCore/platform/graphics/filters/SourceAlpha.cpp @@ -59,6 +59,8 @@ void SourceAlpha::apply(Filter* filter) if (!filterContext) return; + setIsAlphaImage(true); + FloatRect imageRect(FloatPoint(), filter->sourceImage()->image()->size()); filterContext->save(); filterContext->clipToImageBuffer(imageRect, filter->sourceImage()); diff --git a/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp b/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp index a6c2dfb..567da74 100644 --- a/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp +++ b/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp @@ -214,7 +214,7 @@ static gboolean webkit_data_src_uri_set_uri(GstURIHandler* handler, const gchar* GInputStream* stream = g_memory_input_stream_new_from_data(decoded_data, decoded_size, g_free); - g_object_set(src->kid, "stream", stream, 0); + g_object_set(src->kid, "stream", stream, NULL); g_object_unref(stream); if (src->uri) { diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp index 65c64b4..8d1d261 100644 --- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp @@ -25,9 +25,10 @@ #if ENABLE(VIDEO) #include "MediaPlayerPrivateGStreamer.h" -#include "DataSourceGStreamer.h" + #include "CString.h" +#include "DataSourceGStreamer.h" #include "GraphicsContext.h" #include "IntRect.h" #include "KURL.h" @@ -35,11 +36,10 @@ #include "MediaPlayer.h" #include "NotImplemented.h" #include "ScrollView.h" +#include "TimeRanges.h" #include "VideoSinkGStreamer.h" #include "Widget.h" -#include "TimeRanges.h" -#include <gst/base/gstbasesrc.h> #include <gst/gst.h> #include <gst/interfaces/mixer.h> #include <gst/interfaces/xoverlay.h> @@ -52,16 +52,20 @@ using namespace std; namespace WebCore { -gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data) +gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data) { - if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) { - GOwnPtr<GError> err; - GOwnPtr<gchar> debug; + GOwnPtr<GError> err; + GOwnPtr<gchar> debug; + MediaPlayer::NetworkState error; + MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + gint percent = 0; + switch (GST_MESSAGE_TYPE(message)) { + case GST_MESSAGE_ERROR: gst_message_parse_error(message, &err.outPtr(), &debug.outPtr()); LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); - MediaPlayer::NetworkState error = MediaPlayer::Empty; + error = MediaPlayer::Empty; if (err->domain == GST_CORE_ERROR || err->domain == GST_LIBRARY_ERROR) error = MediaPlayer::DecodeError; else if (err->domain == GST_RESOURCE_ERROR) @@ -69,44 +73,32 @@ gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpoin else if (err->domain == GST_STREAM_ERROR) error = MediaPlayer::NetworkError; - MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); if (mp) mp->loadingFailed(error); - } - return true; -} - -gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data) -{ - if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_EOS) { + break; + case GST_MESSAGE_EOS: LOG_VERBOSE(Media, "End of Stream"); - MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); mp->didEnd(); - } - return true; -} - -gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data) -{ - if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STATE_CHANGED) { - MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + break; + case GST_MESSAGE_STATE_CHANGED: mp->updateStates(); - } - return true; -} - -gboolean mediaPlayerPrivateBufferingCallback(GstBus* bus, GstMessage* message, gpointer data) -{ - if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_BUFFERING) { - gint percent = 0; + break; + case GST_MESSAGE_BUFFERING: gst_message_parse_buffering(message, &percent); LOG_VERBOSE(Media, "Buffering %d", percent); + break; + default: + LOG_VERBOSE(Media, "Unhandled GStreamer message type: %s", + GST_MESSAGE_TYPE_NAME(message)); + break; } return true; } -static void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, MediaPlayerPrivate* playerPrivate) +void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivate* playerPrivate) { + g_return_if_fail(GST_IS_BUFFER(buffer)); + gst_buffer_replace(&playerPrivate->m_buffer, buffer); playerPrivate->repaint(); } @@ -123,7 +115,8 @@ void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) static bool gstInitialized = false; -static void do_gst_init() { +static void do_gst_init() +{ // FIXME: We should pass the arguments from the command line if (!gstInitialized) { gst_init(0, 0); @@ -139,50 +132,33 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_playBin(0) , m_videoSink(0) , m_source(0) - , m_rate(1.0f) , m_endTime(numeric_limits<float>::infinity()) - , m_volume(0.5f) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::HaveNothing) , m_startedPlaying(false) , m_isStreaming(false) , m_size(IntSize()) - , m_visible(true) + , m_buffer(0) , m_paused(true) , m_seeking(false) , m_errorOccured(false) { do_gst_init(); - - // FIXME: The size shouldn't be fixed here, this is just a quick hack. - m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 640, 480); -} - -static gboolean idleUnref(gpointer data) -{ - g_object_unref(reinterpret_cast<GObject*>(data)); - return FALSE; } MediaPlayerPrivate::~MediaPlayerPrivate() { - if (m_surface) - cairo_surface_destroy(m_surface); + if (m_buffer) + gst_buffer_unref(m_buffer); + m_buffer = 0; if (m_playBin) { gst_element_set_state(m_playBin, GST_STATE_NULL); gst_object_unref(GST_OBJECT(m_playBin)); } - // FIXME: We should find a better way to handle the lifetime of this object; this is - // needed because the object is sometimes being destroyed inbetween a call to - // webkit_video_sink_render, and the idle it schedules. Adding a ref in - // webkit_video_sink_render that would be balanced by the idle is not an option, - // because in some cases the destruction of the sink may happen in time for the idle - // to be removed from the queue, so it may not run. It would also cause lots of ref - // counting churn (render/idle are called many times). This is an ugly race. if (m_videoSink) { - g_idle_add(idleUnref, m_videoSink); + g_object_unref(m_videoSink); m_videoSink = 0; } } @@ -226,24 +202,14 @@ float MediaPlayerPrivate::duration() const GstFormat timeFormat = GST_FORMAT_TIME; gint64 timeLength = 0; -#if !GST_CHECK_VERSION(0, 10, 23) - // We try to get the duration, but we do not trust the - // return value of the query function only; the problem we are - // trying to work-around here is that pipelines in stream mode may - // not be able to figure out the duration, but still return true! - // See https://bugs.webkit.org/show_bug.cgi?id=24639 which has been - // fixed in gst-plugins-base 0.10.23 - if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeLength <= 0) { -#else - if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength)) { -#endif + if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeFormat != GST_FORMAT_TIME || timeLength == GST_CLOCK_TIME_NONE) { LOG_VERBOSE(Media, "Time duration query failed."); return numeric_limits<float>::infinity(); } LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(timeLength)); - return (float) (timeLength / 1000000000.0); + return (float) ((guint64) timeLength / 1000000000.0); // FIXME: handle 3.14.9.5 properly } @@ -288,7 +254,7 @@ void MediaPlayerPrivate::seek(float time) return; LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec)); - if (!gst_element_seek( m_playBin, m_rate, + if (!gst_element_seek(m_playBin, m_player->rate(), GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, sec, @@ -340,14 +306,17 @@ IntSize MediaPlayerPrivate::naturalSize() const // 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")) { - gst_video_get_size(GST_PAD(pad), &width, &height); GstCaps* caps = GST_PAD_CAPS(pad); gfloat pixelAspectRatio; gint pixelAspectRatioNumerator, pixelAspectRatioDenominator; - if (!gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, - &pixelAspectRatioDenominator)) - pixelAspectRatioNumerator = pixelAspectRatioDenominator = 1; + if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps) || + !gst_video_format_parse_caps(caps, NULL, &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; @@ -376,21 +345,10 @@ bool MediaPlayerPrivate::hasAudio() const void MediaPlayerPrivate::setVolume(float volume) { - m_volume = volume; - LOG_VERBOSE(Media, "Volume to %f", volume); - if (!m_playBin) return; - g_object_set(G_OBJECT(m_playBin), "volume", m_volume, NULL); -} - -void MediaPlayerPrivate::setMuted(bool mute) -{ - if (!m_playBin) - return; - - g_object_set(G_OBJECT(m_playBin), "mute", mute, NULL); + g_object_set(G_OBJECT(m_playBin), "volume", static_cast<double>(volume), NULL); } void MediaPlayerPrivate::setRate(float rate) @@ -403,7 +361,6 @@ void MediaPlayerPrivate::setRate(float rate) if (m_isStreaming) return; - m_rate = rate; LOG_VERBOSE(Media, "Set Rate to %f", rate); seek(currentTime()); } @@ -495,7 +452,11 @@ unsigned MediaPlayerPrivate::totalBytes() const void MediaPlayerPrivate::cancelLoad() { - notImplemented(); + if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded) + return; + + if (m_playBin) + gst_element_set_state(m_playBin, GST_STATE_NULL); } void MediaPlayerPrivate::updateStates() @@ -525,14 +486,15 @@ void MediaPlayerPrivate::updateStates() gst_element_state_get_name(state), gst_element_state_get_name(pending)); - if (state == GST_STATE_READY) { - m_readyState = MediaPlayer::HaveEnoughData; - } else if (state == GST_STATE_PAUSED) + if (state == GST_STATE_READY) + m_readyState = MediaPlayer::HaveNothing; + else if (state == GST_STATE_PAUSED) m_readyState = MediaPlayer::HaveEnoughData; - if (state == GST_STATE_PLAYING) + if (state == GST_STATE_PLAYING) { + m_readyState = MediaPlayer::HaveEnoughData; m_paused = false; - else + } else m_paused = true; if (m_seeking) { @@ -563,9 +525,9 @@ void MediaPlayerPrivate::updateStates() gst_element_state_get_name(state), gst_element_state_get_name(pending)); - if (state == GST_STATE_READY) { - m_readyState = MediaPlayer::HaveFutureData; - } else if (state == GST_STATE_PAUSED) + if (state == GST_STATE_READY) + m_readyState = MediaPlayer::HaveNothing; + else if (state == GST_STATE_PAUSED) m_readyState = MediaPlayer::HaveCurrentData; m_networkState = MediaPlayer::Loading; @@ -639,23 +601,11 @@ void MediaPlayerPrivate::loadingFailed(MediaPlayer::NetworkState error) void MediaPlayerPrivate::setSize(const IntSize& size) { - // Destroy and re-create the cairo surface only if the size - // changed. - if (size != m_size) { - if (m_surface) - cairo_surface_destroy(m_surface); - m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size.width(), - size.height()); - g_object_set(m_videoSink, "surface", m_surface, 0); - } - m_size = size; - } void MediaPlayerPrivate::setVisible(bool visible) { - m_visible = visible; } void MediaPlayerPrivate::repaint() @@ -668,20 +618,65 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) if (context->paintingDisabled()) return; - if (!m_visible) + if (!m_player->visible()) return; + if (!m_buffer) + return; + + int width = 0, height = 0; + int pixelAspectRatioNumerator = 0; + int pixelAspectRatioDenominator = 0; + double doublePixelAspectRatioNumerator = 0; + double doublePixelAspectRatioDenominator = 0; + double displayWidth; + double displayHeight; + double scale, gapHeight, gapWidth; + + GstCaps *caps = gst_buffer_get_caps(m_buffer); + + if (!gst_video_format_parse_caps(caps, NULL, &width, &height) || + !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, &pixelAspectRatioDenominator)) { + gst_caps_unref(caps); + return; + } + + displayWidth = width; + displayHeight = height; + doublePixelAspectRatioNumerator = pixelAspectRatioNumerator; + doublePixelAspectRatioDenominator = pixelAspectRatioDenominator; cairo_t* cr = context->platformContext(); + cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(m_buffer), + CAIRO_FORMAT_RGB24, + width, height, + 4 * width); cairo_save(cr); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + displayWidth *= doublePixelAspectRatioNumerator / doublePixelAspectRatioDenominator; + displayHeight *= doublePixelAspectRatioDenominator / doublePixelAspectRatioNumerator; + + scale = MIN (rect.width () / displayWidth, rect.height () / displayHeight); + displayWidth *= scale; + displayHeight *= scale; + + // Calculate gap between border an picture + gapWidth = (rect.width() - displayWidth) / 2.0; + gapHeight = (rect.height() - displayHeight) / 2.0; + // paint the rectangle on the context and draw the surface inside. - cairo_translate(cr, rect.x(), rect.y()); + cairo_translate(cr, rect.x() + gapWidth, rect.y() + gapHeight); cairo_rectangle(cr, 0, 0, rect.width(), rect.height()); - cairo_set_source_surface(cr, m_surface, 0, 0); + cairo_scale(cr, doublePixelAspectRatioNumerator / doublePixelAspectRatioDenominator, + doublePixelAspectRatioDenominator / doublePixelAspectRatioNumerator); + cairo_scale(cr, scale, scale); + cairo_set_source_surface(cr, src, 0, 0); cairo_fill(cr); cairo_restore(cr); + + cairo_surface_destroy(src); + gst_caps_unref(caps); } static HashSet<String> mimeTypeCache() @@ -805,25 +800,18 @@ void MediaPlayerPrivate::createGSTPlayBin(String url) GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin)); gst_bus_add_signal_watch(bus); - g_signal_connect(bus, "message::error", G_CALLBACK(mediaPlayerPrivateErrorCallback), this); - g_signal_connect(bus, "message::eos", G_CALLBACK(mediaPlayerPrivateEOSCallback), this); - g_signal_connect(bus, "message::state-changed", G_CALLBACK(mediaPlayerPrivateStateCallback), this); - g_signal_connect(bus, "message::buffering", G_CALLBACK(mediaPlayerPrivateBufferingCallback), this); + g_signal_connect(bus, "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this); gst_object_unref(bus); - g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(), NULL); - - m_videoSink = webkit_video_sink_new(m_surface); + g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(), + "volume", static_cast<double>(m_player->volume()), NULL); - // This ref is to protect the sink from being destroyed before we stop the idle it - // creates internally. See the comment in ~MediaPlayerPrivate. - g_object_ref(m_videoSink); + m_videoSink = webkit_video_sink_new(); + g_object_ref_sink(m_videoSink); g_object_set(m_playBin, "video-sink", m_videoSink, NULL); g_signal_connect(m_videoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this); - - setVolume(m_volume); } } diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h index d305759..54da420 100644 --- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h @@ -30,8 +30,10 @@ #include <cairo.h> #include <glib.h> -typedef struct _GstElement GstElement; +typedef struct _WebKitVideoSink WebKitVideoSink; +typedef struct _GstBuffer GstBuffer; typedef struct _GstMessage GstMessage; +typedef struct _GstElement GstElement; typedef struct _GstBus GstBus; namespace WebCore { @@ -41,14 +43,11 @@ namespace WebCore { class IntRect; class String; - gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data); - gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data); - gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data); + gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data); class MediaPlayerPrivate : public MediaPlayerPrivateInterface { - friend gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data); - friend gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data); - friend gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data); + friend gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data); + friend void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivate* playerPrivate); public: static void registerMediaEngine(MediaEngineRegistrar); @@ -74,7 +73,6 @@ namespace WebCore { void setRate(float); void setVolume(float); - void setMuted(bool); int dataRate() const; @@ -126,17 +124,14 @@ namespace WebCore { GstElement* m_playBin; GstElement* m_videoSink; GstElement* m_source; - float m_rate; float m_endTime; bool m_isEndReached; - double m_volume; MediaPlayer::NetworkState m_networkState; MediaPlayer::ReadyState m_readyState; bool m_startedPlaying; mutable bool m_isStreaming; IntSize m_size; - bool m_visible; - cairo_surface_t* m_surface; + GstBuffer* m_buffer; bool m_paused; bool m_seeking; diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp index fb86fe9..b5e1a8b 100644 --- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp +++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp @@ -21,8 +21,9 @@ * SECTION:webkit-video-sink * @short_description: GStreamer video sink * - * #WebKitVideoSink is a GStreamer sink element that sends - * data to a #cairo_surface_t. + * #WebKitVideoSink is a GStreamer sink element that triggers + * repaints in the WebKit GStreamer media player for the + * current video buffer. */ #include "config.h" @@ -57,22 +58,26 @@ enum { }; enum { - PROP_0, - PROP_SURFACE + PROP_0 }; static guint webkit_video_sink_signals[LAST_SIGNAL] = { 0, }; struct _WebKitVideoSinkPrivate { - cairo_surface_t* surface; - GAsyncQueue* async_queue; - gboolean rgb_ordering; - int width; - int height; - int fps_n; - int fps_d; - int par_n; - int par_d; + GstBuffer* buffer; + guint timeout_id; + GMutex* buffer_mutex; + GCond* data_cond; + + // If this is TRUE all processing should finish ASAP + // This is necessary because there could be a race between + // unlock() and render(), where unlock() wins, signals the + // GCond, then render() tries to render a frame although + // everything else isn't running anymore. This will lead + // to deadlocks because render() holds the stream lock. + // + // Protected by the buffer mutex + gboolean unlocked; }; #define _do_init(bla) \ @@ -83,8 +88,8 @@ struct _WebKitVideoSinkPrivate { GST_BOILERPLATE_FULL(WebKitVideoSink, webkit_video_sink, - GstBaseSink, - GST_TYPE_BASE_SINK, + GstVideoSink, + GST_TYPE_VIDEO_SINK, _do_init); static void @@ -102,59 +107,37 @@ webkit_video_sink_init(WebKitVideoSink* sink, WebKitVideoSinkClass* klass) WebKitVideoSinkPrivate* priv; sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate); - priv->async_queue = g_async_queue_new(); + priv->data_cond = g_cond_new(); + priv->buffer_mutex = g_mutex_new(); } static gboolean -webkit_video_sink_idle_func(gpointer data) +webkit_video_sink_timeout_func(gpointer data) { WebKitVideoSink* sink = reinterpret_cast<WebKitVideoSink*>(data); WebKitVideoSinkPrivate* priv = sink->priv; GstBuffer* buffer; - GstCaps* caps; - GstVideoFormat format; - gint par_n, par_d; - gfloat par; - gint bwidth, bheight; - if (!priv->async_queue) - return FALSE; + g_mutex_lock(priv->buffer_mutex); + buffer = priv->buffer; + priv->buffer = 0; + priv->timeout_id = 0; - buffer = (GstBuffer*)g_async_queue_try_pop(priv->async_queue); - if (!buffer || G_UNLIKELY(!GST_IS_BUFFER(buffer))) + if (!buffer || priv->unlocked || G_UNLIKELY(!GST_IS_BUFFER(buffer))) { + g_cond_signal(priv->data_cond); + g_mutex_unlock(priv->buffer_mutex); return FALSE; + } - caps = GST_BUFFER_CAPS(buffer); - if (!gst_video_format_parse_caps(caps, &format, &bwidth, &bheight)) { - GST_ERROR_OBJECT(sink, "Unknown video format in buffer caps '%s'", - gst_caps_to_string(caps)); - return FALSE; + if (G_UNLIKELY(!GST_BUFFER_CAPS(buffer))) { + buffer = gst_buffer_make_metadata_writable(buffer); + gst_buffer_set_caps(buffer, GST_PAD_CAPS(GST_BASE_SINK_PAD(sink))); } - if (!gst_video_parse_caps_pixel_aspect_ratio(caps, &par_n, &par_d)) - par_n = par_d = 1; - - par = (gfloat) par_n / (gfloat) par_d; - - // TODO: consider priv->rgb_ordering? - cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer), - CAIRO_FORMAT_RGB24, - bwidth, bheight, - 4 * bwidth); - - // TODO: We copy the data twice right now. This could be easily improved. - cairo_t* cr = cairo_create(priv->surface); - cairo_scale(cr, par, 1.0 / par); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_surface(cr, src, 0, 0); - cairo_surface_destroy(src); - cairo_rectangle(cr, 0, 0, priv->width, priv->height); - cairo_fill(cr); - cairo_destroy(cr); + g_signal_emit(sink, webkit_video_sink_signals[REPAINT_REQUESTED], 0, buffer); gst_buffer_unref(buffer); - g_async_queue_unref(priv->async_queue); - - g_signal_emit(sink, webkit_video_sink_signals[REPAINT_REQUESTED], 0); + g_cond_signal(priv->data_cond); + g_mutex_unlock(priv->buffer_mutex); return FALSE; } @@ -165,53 +148,24 @@ webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer) WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink); WebKitVideoSinkPrivate* priv = sink->priv; - g_async_queue_ref(priv->async_queue); - g_async_queue_push(priv->async_queue, gst_buffer_ref(buffer)); - g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, sink, 0); - - return GST_FLOW_OK; -} - -static gboolean -webkit_video_sink_set_caps(GstBaseSink* bsink, GstCaps* caps) -{ - WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink); - WebKitVideoSinkPrivate* priv = sink->priv; - GstStructure* structure; - gboolean ret; - gint width, height, fps_n, fps_d; - int red_mask; - - GstCaps* intersection = gst_caps_intersect(gst_static_pad_template_get_caps(&sinktemplate), caps); + g_mutex_lock(priv->buffer_mutex); - if (gst_caps_is_empty(intersection)) - return FALSE; - - gst_caps_unref(intersection); - - structure = gst_caps_get_structure(caps, 0); - - ret = gst_structure_get_int(structure, "width", &width); - ret &= gst_structure_get_int(structure, "height", &height); - - /* We dont yet use fps but handy to have */ - ret &= gst_structure_get_fraction(structure, "framerate", - &fps_n, &fps_d); - g_return_val_if_fail(ret, FALSE); - - priv->width = width; - priv->height = height; - priv->fps_n = fps_n; - priv->fps_d = fps_d; + if (priv->unlocked) { + g_mutex_unlock(priv->buffer_mutex); + return GST_FLOW_OK; + } - if (!gst_structure_get_fraction(structure, "pixel-aspect-ratio", - &priv->par_n, &priv->par_d)) - priv->par_n = priv->par_d = 1; + priv->buffer = gst_buffer_ref(buffer); - gst_structure_get_int(structure, "red_mask", &red_mask); - priv->rgb_ordering = (red_mask == static_cast<int>(0xff000000)); + // Use HIGH_IDLE+20 priority, like Gtk+ for redrawing operations. + priv->timeout_id = g_timeout_add_full(G_PRIORITY_HIGH_IDLE + 20, 0, + webkit_video_sink_timeout_func, + gst_object_ref(sink), + (GDestroyNotify)gst_object_unref); - return TRUE; + g_cond_wait(priv->data_cond, priv->buffer_mutex); + g_mutex_unlock(priv->buffer_mutex); + return GST_FLOW_OK; } static void @@ -220,56 +174,58 @@ webkit_video_sink_dispose(GObject* object) WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object); WebKitVideoSinkPrivate* priv = sink->priv; - if (priv->surface) { - cairo_surface_destroy(priv->surface); - priv->surface = 0; + if (priv->data_cond) { + g_cond_free(priv->data_cond); + priv->data_cond = 0; } - if (priv->async_queue) { - g_async_queue_unref(priv->async_queue); - priv->async_queue = 0; + if (priv->buffer_mutex) { + g_mutex_free(priv->buffer_mutex); + priv->buffer_mutex = 0; } G_OBJECT_CLASS(parent_class)->dispose(object); } static void -webkit_video_sink_finalize(GObject* object) +unlock_buffer_mutex(WebKitVideoSinkPrivate* priv) { - G_OBJECT_CLASS(parent_class)->finalize(object); + g_mutex_lock(priv->buffer_mutex); + + if (priv->buffer) { + gst_buffer_unref(priv->buffer); + priv->buffer = 0; + } + + priv->unlocked = TRUE; + + g_cond_signal(priv->data_cond); + g_mutex_unlock(priv->buffer_mutex); } -static void -webkit_video_sink_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) +static gboolean +webkit_video_sink_unlock(GstBaseSink* object) { WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object); - WebKitVideoSinkPrivate* priv = sink->priv; - switch (prop_id) { - case PROP_SURFACE: - if (priv->surface) - cairo_surface_destroy(priv->surface); - priv->surface = cairo_surface_reference((cairo_surface_t*)g_value_get_pointer(value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } + unlock_buffer_mutex(sink->priv); + + return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock, + (object), TRUE); } -static void -webkit_video_sink_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec) +static gboolean +webkit_video_sink_unlock_stop(GstBaseSink* object) { WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object); + WebKitVideoSinkPrivate* priv = sink->priv; - switch (prop_id) { - case PROP_SURFACE: - g_value_set_pointer(value, sink->priv->surface); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } + g_mutex_lock(priv->buffer_mutex); + priv->unlocked = FALSE; + g_mutex_unlock(priv->buffer_mutex); + + return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock_stop, + (object), TRUE); } static gboolean @@ -277,20 +233,46 @@ webkit_video_sink_stop(GstBaseSink* base_sink) { WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(base_sink)->priv; - g_async_queue_lock(priv->async_queue); - - /* Remove all remaining objects from the queue */ - while (GstBuffer* buffer = (GstBuffer*)g_async_queue_try_pop_unlocked(priv->async_queue)) - gst_buffer_unref(buffer); - - g_async_queue_unlock(priv->async_queue); + unlock_buffer_mutex(priv); + return TRUE; +} - g_idle_remove_by_data(base_sink); +static gboolean +webkit_video_sink_start(GstBaseSink* base_sink) +{ + WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(base_sink)->priv; + g_mutex_lock(priv->buffer_mutex); + priv->unlocked = FALSE; + g_mutex_unlock(priv->buffer_mutex); return TRUE; } static void +marshal_VOID__MINIOBJECT(GClosure * closure, GValue * return_value, + guint n_param_values, const GValue * param_values, + gpointer invocation_hint, gpointer marshal_data) +{ + typedef void (*marshalfunc_VOID__MINIOBJECT) (gpointer obj, gpointer arg1, gpointer data2); + marshalfunc_VOID__MINIOBJECT callback; + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + + g_return_if_fail(n_param_values == 2); + + if (G_CCLOSURE_SWAP_DATA(closure)) { + data1 = closure->data; + data2 = g_value_peek_pointer(param_values + 0); + } else { + data1 = g_value_peek_pointer(param_values + 0); + data2 = closure->data; + } + callback = (marshalfunc_VOID__MINIOBJECT) (marshal_data ? marshal_data : cc->callback); + + callback(data1, gst_value_get_mini_object(param_values + 1), data2); +} + +static void webkit_video_sink_class_init(WebKitVideoSinkClass* klass) { GObjectClass* gobject_class = G_OBJECT_CLASS(klass); @@ -298,16 +280,14 @@ webkit_video_sink_class_init(WebKitVideoSinkClass* klass) g_type_class_add_private(klass, sizeof(WebKitVideoSinkPrivate)); - gobject_class->set_property = webkit_video_sink_set_property; - gobject_class->get_property = webkit_video_sink_get_property; - gobject_class->dispose = webkit_video_sink_dispose; - gobject_class->finalize = webkit_video_sink_finalize; + gstbase_sink_class->unlock = webkit_video_sink_unlock; + gstbase_sink_class->unlock_stop = webkit_video_sink_unlock_stop; gstbase_sink_class->render = webkit_video_sink_render; gstbase_sink_class->preroll = webkit_video_sink_render; gstbase_sink_class->stop = webkit_video_sink_stop; - gstbase_sink_class->set_caps = webkit_video_sink_set_caps; + gstbase_sink_class->start = webkit_video_sink_start; webkit_video_sink_signals[REPAINT_REQUESTED] = g_signal_new("repaint-requested", G_TYPE_FROM_CLASS(klass), @@ -315,37 +295,20 @@ webkit_video_sink_class_init(WebKitVideoSinkClass* klass) 0, 0, 0, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - g_object_class_install_property( - gobject_class, PROP_SURFACE, - g_param_spec_pointer("surface", "surface", "Target cairo_surface_t*", - (GParamFlags)(G_PARAM_READWRITE))); + marshal_VOID__MINIOBJECT, + G_TYPE_NONE, 1, GST_TYPE_BUFFER); } /** * webkit_video_sink_new: - * @surface: a #cairo_surface_t * - * Creates a new GStreamer video sink which uses @surface as the target - * for sinking a video stream from GStreamer. + * Creates a new GStreamer video sink. * * Return value: a #GstElement for the newly created video sink */ GstElement* -webkit_video_sink_new(cairo_surface_t* surface) +webkit_video_sink_new(void) { - return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, "surface", surface, 0); + return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, 0); } -void -webkit_video_sink_set_surface(WebKitVideoSink* sink, cairo_surface_t* surface) -{ - WebKitVideoSinkPrivate* priv; - - sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate); - if (priv->surface) - cairo_surface_destroy(priv->surface); - priv->surface = cairo_surface_reference(surface); -} diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h index be2c94c..7ea7d91 100644 --- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h +++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h @@ -22,7 +22,7 @@ #include <cairo.h> #include <glib-object.h> -#include <gst/base/gstbasesink.h> +#include <gst/video/gstvideosink.h> G_BEGIN_DECLS @@ -54,13 +54,13 @@ typedef struct _WebKitVideoSinkPrivate WebKitVideoSinkPrivate; struct _WebKitVideoSink { /*< private >*/ - GstBaseSink parent; + GstVideoSink parent; WebKitVideoSinkPrivate *priv; }; struct _WebKitVideoSinkClass { /*< private >*/ - GstBaseSinkClass parent_class; + GstVideoSinkClass parent_class; /* Future padding */ void (* _webkit_reserved1)(void); @@ -72,9 +72,7 @@ struct _WebKitVideoSinkClass { }; GType webkit_video_sink_get_type(void) G_GNUC_CONST; -GstElement *webkit_video_sink_new(cairo_surface_t *surface); - -void webkit_video_sink_set_surface(WebKitVideoSink *sink, cairo_surface_t *surface); +GstElement *webkit_video_sink_new(void); G_END_DECLS diff --git a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp index d785ef4..c23b8a9 100644 --- a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp +++ b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp @@ -369,6 +369,11 @@ void GraphicsContext::clip(const Path& path) m_data->m_view->ConstrainClippingRegion(path.platformPath()); } +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + void GraphicsContext::clipOut(const Path& path) { if (paintingDisabled()) diff --git a/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp b/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp index 34941c0..adb7573 100644 --- a/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp +++ b/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp @@ -39,6 +39,8 @@ #include <unicode/unorm.h> +extern int charUnicodeToUTF8HACK(unsigned short, char*); + namespace WebCore { void SimpleFontData::platformInit() @@ -93,15 +95,15 @@ void SimpleFontData::determinePitch() float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { - const char charArray[1] = { glyph }; - float escapements[1]; + if (!m_platformData.font()) + return 0; - if (m_platformData.font()) { - m_platformData.font()->GetEscapements(charArray, 1, escapements); - return escapements[0] * m_platformData.font()->Size(); - } + char charArray[4]; + float escapements[1]; - return 0; + charUnicodeToUTF8HACK(glyph, charArray); + m_platformData.font()->GetEscapements(charArray, 1, escapements); + return escapements[0] * m_platformData.font()->Size(); } } // namespace WebCore diff --git a/WebCore/platform/graphics/mac/Canvas3DLayer.h b/WebCore/platform/graphics/mac/Canvas3DLayer.h index 6c65676..122ef39 100644 --- a/WebCore/platform/graphics/mac/Canvas3DLayer.h +++ b/WebCore/platform/graphics/mac/Canvas3DLayer.h @@ -41,7 +41,9 @@ namespace WebCore { GLuint m_texture; } --(id)initWithContext:(CGLContextObj)context texture:(GLuint)texture; +- (id)initWithContext:(CGLContextObj)context texture:(GLuint)texture; + +- (CGImageRef)copyImageSnapshotWithColorSpace:(CGColorSpaceRef)colorSpace; @end diff --git a/WebCore/platform/graphics/mac/Canvas3DLayer.mm b/WebCore/platform/graphics/mac/Canvas3DLayer.mm index 545c58b..94819d4 100644 --- a/WebCore/platform/graphics/mac/Canvas3DLayer.mm +++ b/WebCore/platform/graphics/mac/Canvas3DLayer.mm @@ -33,6 +33,8 @@ #import "GraphicsLayer.h" #import <QuartzCore/QuartzCore.h> #import <OpenGL/OpenGL.h> +#import <wtf/RetainPtr.h> +#include <wtf/FastMalloc.h> using namespace WebCore; @@ -48,19 +50,14 @@ using namespace WebCore; -(CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { - CGLPixelFormatAttribute attribs[] = - { - (CGLPixelFormatAttribute) kCGLPFAAccelerated, - (CGLPixelFormatAttribute) kCGLPFAColorSize, (CGLPixelFormatAttribute) 32, - (CGLPixelFormatAttribute) kCGLPFADisplayMask, (CGLPixelFormatAttribute) mask, - (CGLPixelFormatAttribute) 0 - }; - - CGLPixelFormatObj pixelFormatObj; - GLint numPixelFormats; - - CGLChoosePixelFormat(attribs, &pixelFormatObj, &numPixelFormats); - return pixelFormatObj; + // FIXME: The mask param tells you which display (on a multi-display system) + // is to be used. But since we are now getting the pixel format from the + // Canvas CGL context, we don't use it. This seems to do the right thing on + // one multi-display system. But there may be cases where this is not the case. + // If needed we will have to set the display mask in the Canvas CGLContext and + // make sure it matches. + UNUSED_PARAM(mask); + return CGLRetainPixelFormat(CGLGetPixelFormat(m_contextObj)); } -(CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat @@ -72,6 +69,10 @@ using namespace WebCore; -(void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp { + CGLSetCurrentContext(m_contextObj); + glFinish(); + CGLSetCurrentContext(glContext); + CGRect frame = [self frame]; // draw the FBO into the layer @@ -103,6 +104,42 @@ using namespace WebCore; [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp]; } +static void freeData(void *, const void *data, size_t /* size */) +{ + fastFree(const_cast<void *>(data)); +} + +-(CGImageRef)copyImageSnapshotWithColorSpace:(CGColorSpaceRef)colorSpace +{ + CGLSetCurrentContext(m_contextObj); + + RetainPtr<CGColorSpaceRef> imageColorSpace = colorSpace; + if (!imageColorSpace) + imageColorSpace.adoptCF(CGColorSpaceCreateDeviceRGB()); + + CGRect layerBounds = CGRectIntegral([self bounds]); + + size_t width = layerBounds.size.width; + size_t height = layerBounds.size.height; + + size_t rowBytes = (width * 4 + 15) & ~15; + size_t dataSize = rowBytes * height; + void* data = fastMalloc(dataSize); + if (!data) + return 0; + + glPixelStorei(GL_PACK_ROW_LENGTH, rowBytes / 4); + glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data); + + CGDataProviderRef provider = CGDataProviderCreateWithData(0, data, dataSize, freeData); + CGImageRef image = CGImageCreate(width, height, 8, 32, rowBytes, imageColorSpace.get(), + kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, + provider, 0, true, + kCGRenderingIntentDefault); + CGDataProviderRelease(provider); + return image; +} + @end @implementation Canvas3DLayer(WebLayerAdditions) diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp index cd66445..47617d8 100644 --- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp +++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp @@ -30,9 +30,10 @@ #include "GraphicsContext3D.h" #include "CachedImage.h" +#include "CanvasActiveInfo.h" +#include "CanvasArray.h" #include "CanvasBuffer.h" #include "CanvasFramebuffer.h" -#include "CanvasArray.h" #include "CanvasFloatArray.h" #include "CanvasIntArray.h" #include "CanvasObject.h" @@ -49,29 +50,91 @@ #include "WebKitCSSMatrix.h" #include <CoreGraphics/CGBitmapContext.h> +#include <OpenGL/CGLRenderers.h> namespace WebCore { -GraphicsContext3D::GraphicsContext3D() +static void setPixelFormat(Vector<CGLPixelFormatAttribute>& attribs, int colorBits, int depthBits, bool accelerated, bool supersample, bool closest) { - CGLPixelFormatAttribute attribs[] = - { - (CGLPixelFormatAttribute) kCGLPFAAccelerated, - (CGLPixelFormatAttribute) kCGLPFAColorSize, (CGLPixelFormatAttribute) 32, - (CGLPixelFormatAttribute) kCGLPFADepthSize, (CGLPixelFormatAttribute) 32, - (CGLPixelFormatAttribute) kCGLPFASupersample, - (CGLPixelFormatAttribute) 0 - }; + attribs.clear(); - CGLPixelFormatObj pixelFormatObj; - GLint numPixelFormats; + attribs.append(kCGLPFAColorSize); + attribs.append(static_cast<CGLPixelFormatAttribute>(colorBits)); + attribs.append(kCGLPFADepthSize); + attribs.append(static_cast<CGLPixelFormatAttribute>(depthBits)); - CGLChoosePixelFormat(attribs, &pixelFormatObj, &numPixelFormats); - - CGLCreateContext(pixelFormatObj, 0, &m_contextObj); + if (accelerated) + attribs.append(kCGLPFAAccelerated); + else { + attribs.append(kCGLPFARendererID); + attribs.append(static_cast<CGLPixelFormatAttribute>(kCGLRendererGenericFloatID)); + } + + if (supersample) + attribs.append(kCGLPFASupersample); + + if (closest) + attribs.append(kCGLPFAClosestPolicy); + + attribs.append(static_cast<CGLPixelFormatAttribute>(0)); +} + +PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create() +{ + OwnPtr<GraphicsContext3D> context(new GraphicsContext3D()); + return context->m_contextObj ? context.release() : 0; +} + +GraphicsContext3D::GraphicsContext3D() + : m_contextObj(0) + , m_texture(0) + , m_fbo(0) + , m_depthBuffer(0) +{ + Vector<CGLPixelFormatAttribute> attribs; + CGLPixelFormatObj pixelFormatObj = 0; + GLint numPixelFormats = 0; + + // We will try: + // + // 1) 32 bit RGBA/32 bit depth/accelerated/supersampled + // 2) 32 bit RGBA/32 bit depth/accelerated + // 3) 32 bit RGBA/16 bit depth/accelerated + // 4) closest to 32 bit RGBA/16 bit depth/software renderer + // + // If none of that works, we simply fail and set m_contextObj to 0. + + setPixelFormat(attribs, 32, 32, true, true, false); + CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats); + if (numPixelFormats == 0) { + setPixelFormat(attribs, 32, 32, true, false, false); + CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats); + + if (numPixelFormats == 0) { + setPixelFormat(attribs, 32, 16, true, false, false); + CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats); + + if (numPixelFormats == 0) { + setPixelFormat(attribs, 32, 16, false, false, true); + CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats); + + if (numPixelFormats == 0) { + // Could not find an acceptable renderer - fail + return; + } + } + } + } + CGLError err = CGLCreateContext(pixelFormatObj, 0, &m_contextObj); CGLDestroyPixelFormat(pixelFormatObj); + if (err != kCGLNoError || !m_contextObj) { + // Could not create the context - fail + m_contextObj = 0; + return; + } + // Set the current context to the one given to us. CGLSetCurrentContext(m_contextObj); @@ -102,12 +165,14 @@ GraphicsContext3D::GraphicsContext3D() GraphicsContext3D::~GraphicsContext3D() { - CGLSetCurrentContext(m_contextObj); - ::glDeleteRenderbuffersEXT(1, & m_depthBuffer); - ::glDeleteTextures(1, &m_texture); - ::glDeleteFramebuffersEXT(1, &m_fbo); - CGLSetCurrentContext(0); - CGLDestroyContext(m_contextObj); + if (m_contextObj) { + CGLSetCurrentContext(m_contextObj); + ::glDeleteRenderbuffersEXT(1, & m_depthBuffer); + ::glDeleteTextures(1, &m_texture); + ::glDeleteFramebuffersEXT(1, &m_fbo); + CGLSetCurrentContext(0); + CGLDestroyContext(m_contextObj); + } } void GraphicsContext3D::checkError() const @@ -135,7 +200,7 @@ void GraphicsContext3D::endPaint() void GraphicsContext3D::reshape(int width, int height) { - if (width == m_currentWidth && height == m_currentHeight) + if (width == m_currentWidth && height == m_currentHeight || !m_contextObj) return; m_currentWidth = width; @@ -167,6 +232,9 @@ void GraphicsContext3D::reshape(int width, int height) static inline void ensureContext(CGLContextObj context) { + if (!context) + return; + CGLContextObj currentContext = CGLGetCurrentContext(); if (currentContext != context) CGLSetCurrentContext(context); @@ -442,6 +510,46 @@ void GraphicsContext3D::generateMipmap(unsigned long target) ::glGenerateMipmapEXT(target); } +bool GraphicsContext3D::getActiveAttrib(CanvasProgram* program, unsigned long index, ActiveInfo& info) +{ + if (!program->object()) + return false; + ensureContext(m_contextObj); + GLint maxAttributeSize = 0; + ::glGetProgramiv(static_cast<GLuint>(program->object()), GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttributeSize); + GLchar name[maxAttributeSize]; // GL_ACTIVE_ATTRIBUTE_MAX_LENGTH includes null termination + GLsizei nameLength = 0; + GLint size = 0; + GLenum type = 0; + ::glGetActiveAttrib(static_cast<GLuint>(program->object()), index, maxAttributeSize, &nameLength, &size, &type, name); + if (!nameLength) + return false; + info.name = String(name, nameLength); + info.type = type; + info.size = size; + return true; +} + +bool GraphicsContext3D::getActiveUniform(CanvasProgram* program, unsigned long index, ActiveInfo& info) +{ + if (!program->object()) + return false; + ensureContext(m_contextObj); + GLint maxUniformSize = 0; + ::glGetProgramiv(static_cast<GLuint>(program->object()), GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformSize); + GLchar name[maxUniformSize]; // GL_ACTIVE_UNIFORM_MAX_LENGTH includes null termination + GLsizei nameLength = 0; + GLint size = 0; + GLenum type = 0; + ::glGetActiveUniform(static_cast<GLuint>(program->object()), index, maxUniformSize, &nameLength, &size, &type, name); + if (!nameLength) + return false; + info.name = String(name, nameLength); + info.type = type; + info.size = size; + return true; +} + int GraphicsContext3D::getAttribLocation(CanvasProgram* program, const String& name) { if (!program) @@ -556,6 +664,22 @@ void GraphicsContext3D::polygonOffset(double factor, double units) ::glPolygonOffset(static_cast<float>(factor), static_cast<float>(units)); } +PassRefPtr<CanvasArray> GraphicsContext3D::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type) +{ + ensureContext(m_contextObj); + + // FIXME: For now we only accept GL_UNSIGNED_BYTE/GL_RGBA. In reality OpenGL ES 2.0 accepts that pair and one other + // as specified by GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE. But for now we will + // not accept those. + // FIXME: Also, we should throw when an unacceptable value is passed + if (type != GL_UNSIGNED_BYTE || format != GL_RGBA) + return 0; + + RefPtr<CanvasUnsignedByteArray> array = CanvasUnsignedByteArray::create(width * height * 4); + ::glReadPixels(x, y, width, height, format, type, (GLvoid*) array->data()); + return array; +} + void GraphicsContext3D::releaseShaderCompiler() { // FIXME: This is not implemented on desktop OpenGL. We need to have ifdefs for the different GL variants diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h index d0e1108..8cf51b4 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h @@ -110,10 +110,8 @@ public: virtual PlatformLayer* platformLayer() const; -#ifndef NDEBUG virtual void setDebugBackgroundColor(const Color&); virtual void setDebugBorder(const Color&, float borderWidth); -#endif virtual void setGeometryOrientation(CompositingCoordinatesOrientation); diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm index e9960f1..b351956 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -274,7 +274,6 @@ static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction& tim return 0; } -#ifndef NDEBUG static void setLayerBorderColor(PlatformLayer* layer, const Color& color) { CGColorRef borderColor = createCGColor(color); @@ -286,7 +285,6 @@ static void clearBorderColor(PlatformLayer* layer) { [layer setBorderColor:nil]; } -#endif static void setLayerBackgroundColor(PlatformLayer* layer, const Color& color) { @@ -317,7 +315,6 @@ GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoord return CompositingCoordinatesBottomUp; } -#ifndef NDEBUG bool GraphicsLayer::showDebugBorders() { static bool showDebugBorders = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerBorders"]; @@ -329,7 +326,6 @@ bool GraphicsLayer::showRepaintCounter() static bool showRepaintCounter = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerRepaintCounter"]; return showRepaintCounter; } -#endif static NSDictionary* nullActionsDictionary() { @@ -373,9 +369,7 @@ GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client) setContentsOrientation(defaultContentsOrientation()); #endif -#ifndef NDEBUG updateDebugIndicators(); -#endif m_animationDelegate.adoptNS([[WebAnimationDelegate alloc] init]); [m_animationDelegate.get() setLayer:this]; @@ -964,9 +958,7 @@ void GraphicsLayerCA::updateChildrenTransform() void GraphicsLayerCA::updateMasksToBounds() { [m_layer.get() setMasksToBounds:m_masksToBounds]; -#ifndef NDEBUG updateDebugIndicators(); -#endif } void GraphicsLayerCA::updateContentsOpaque() @@ -1051,9 +1043,7 @@ void GraphicsLayerCA::updateLayerDrawsContent() else [m_layer.get() setContents:nil]; -#ifndef NDEBUG updateDebugIndicators(); -#endif } void GraphicsLayerCA::updateLayerBackgroundColor() @@ -1245,6 +1235,21 @@ void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedP [layer addAnimation:caAnim forKey:animationName]; } +// Workaround for <rdar://problem/7311367> +static void bug7311367Workaround(CALayer* transformLayer, const TransformationMatrix& transform) +{ + if (!transformLayer) + return; + + CATransform3D caTransform; + copyTransform(caTransform, transform); + caTransform.m41 += 1; + [transformLayer setTransform:caTransform]; + + caTransform.m41 -= 1; + [transformLayer setTransform:caTransform]; +} + bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, int index) { PlatformLayer* layer = animatedLayer(property); @@ -1255,10 +1260,11 @@ bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, int return false; [layer removeAnimationForKey:animationName]; + + bug7311367Workaround(m_transformLayer.get(), m_transform); return true; } - static void copyAnimationProperties(CAPropertyAnimation* from, CAPropertyAnimation* to) { [to setBeginTime:[from beginTime]]; @@ -1679,7 +1685,6 @@ PlatformLayer* GraphicsLayerCA::platformLayer() const return primaryLayer(); } -#ifndef NDEBUG void GraphicsLayerCA::setDebugBackgroundColor(const Color& color) { BEGIN_BLOCK_OBJC_EXCEPTIONS @@ -1706,7 +1711,6 @@ void GraphicsLayerCA::setDebugBorder(const Color& color, float borderWidth) END_BLOCK_OBJC_EXCEPTIONS } -#endif // NDEBUG bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const { @@ -1784,9 +1788,7 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer) // need to tell new layer to draw itself setNeedsDisplay(); -#ifndef NDEBUG updateDebugIndicators(); -#endif } GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerCA::defaultContentsOrientation() const @@ -1830,12 +1832,10 @@ void GraphicsLayerCA::setupContentsLayer(CALayer* contentsLayer) } else [contentsLayer setAnchorPoint:CGPointZero]; -#ifndef NDEBUG if (showDebugBorders()) { setLayerBorderColor(contentsLayer, Color(0, 0, 128, 180)); [contentsLayer setBorderWidth:1.0f]; } -#endif } void GraphicsLayerCA::setOpacityInternal(float accumulatedOpacity) diff --git a/WebCore/platform/graphics/mac/WebLayer.mm b/WebCore/platform/graphics/mac/WebLayer.mm index 2647466..56b28e6 100644 --- a/WebCore/platform/graphics/mac/WebLayer.mm +++ b/WebCore/platform/graphics/mac/WebLayer.mm @@ -80,7 +80,6 @@ using namespace WebCore; } #endif -#ifndef NDEBUG if (layerContents->showRepaintCounter()) { bool isTiledLayer = [layer isKindOfClass:[CATiledLayer class]]; @@ -107,7 +106,6 @@ using namespace WebCore; CGContextRestoreGState(context); } -#endif CGContextRestoreGState(context); } diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index fa7b070..57a481a 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -1053,6 +1053,11 @@ void GraphicsContext::clip(const Path& path) m_data->p()->setClipPath(*path.platformPath(), Qt::IntersectClip); } +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + void GraphicsContext::clipOut(const Path& path) { if (paintingDisabled()) diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index 3a27fe3..f8403b7 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -43,22 +43,13 @@ ImageDecoder* ImageDecoder::create(const SharedBuffer& data) if (data.size() < 4) return 0; - QByteArray bytes = QByteArray::fromRawData(data.data(), data.size()); - QBuffer buffer(&bytes); - if (!buffer.open(QBuffer::ReadOnly)) - return 0; - - QByteArray imageFormat = QImageReader::imageFormat(&buffer); - if (imageFormat.isEmpty()) - return 0; // Image format not supported - - return new ImageDecoderQt(imageFormat); + return new ImageDecoderQt; } -ImageDecoderQt::ImageDecoderQt(const QByteArray& imageFormat) - : m_buffer(0) +ImageDecoderQt::ImageDecoderQt() + : m_buffer(0) , m_reader(0) - , m_repetitionCount(-1) + , m_repetitionCount(cAnimationNone) { } @@ -73,13 +64,13 @@ void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived) if (m_failed) return; - // Cache our own new data. - ImageDecoder::setData(data, allDataReceived); - // No progressive loading possible if (!allDataReceived) return; + // Cache our own new data. + ImageDecoder::setData(data, allDataReceived); + // We expect to be only called once with allDataReceived ASSERT(!m_buffer); ASSERT(!m_reader); @@ -89,15 +80,12 @@ void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived) m_buffer = new QBuffer; m_buffer->setData(imageData); m_buffer->open(QBuffer::ReadOnly); - m_reader = new QImageReader(m_buffer); - - if (!m_reader->canRead()) - failRead(); + m_reader = new QImageReader(m_buffer, m_format); } bool ImageDecoderQt::isSizeAvailable() { - if (!m_failed && !ImageDecoder::isSizeAvailable() && m_reader) + if (!ImageDecoder::isSizeAvailable() && m_reader) internalDecodeSize(); return ImageDecoder::isSizeAvailable(); @@ -134,14 +122,16 @@ int ImageDecoderQt::repetitionCount() const String ImageDecoderQt::filenameExtension() const { - return m_format; + return String(m_format.constData(), m_format.length()); }; RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index) { - // this information might not have been set + // 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 (count == 0) { + if (!m_failed && count == 0) { internalDecodeSize(); count = frameCount(); } @@ -171,7 +161,12 @@ void ImageDecoderQt::internalDecodeSize() { ASSERT(m_reader); + // If we have a QSize() something failed QSize size = m_reader->size(); + if (size.isEmpty()) + return failRead(); + + m_format = m_reader->format(); setSize(size.width(), size.height()); } @@ -213,9 +208,15 @@ void ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex) buffer->setDecodedImage(img); } -// We will parse everything and we have no idea how -// many images we have... We will have to find out the -// hard way. +// The QImageIOHandler is not able to tell us how many frames +// we have and we need to parse every image. We do this by +// increasing the m_frameBufferCache by one and try to parse +// the image. We stop when QImage::read fails and then need +// to resize the m_frameBufferCache to the final size and update +// the m_failed. In case we failed to decode the first image +// we want to keep m_failed set to true. + +// TODO: Do not increment the m_frameBufferCache.size() by one but more than one void ImageDecoderQt::forceLoadEverything() { int imageCount = 0; @@ -225,9 +226,12 @@ void ImageDecoderQt::forceLoadEverything() internalHandleCurrentImage(imageCount - 1); } while(!m_failed); - // reset the failed state and resize the vector... + // If we failed decoding the first image we actually + // have no images and need to keep m_failed set to + // true otherwise we want to reset it and forget about + // the last attempt to decode a image. m_frameBufferCache.resize(imageCount - 1); - m_failed = false; + m_failed = imageCount == 1; } void ImageDecoderQt::failRead() diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h index 7b3b686..d11b938 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.h +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h @@ -40,7 +40,7 @@ namespace WebCore { class ImageDecoderQt : public ImageDecoder { public: - ImageDecoderQt(const QByteArray& imageFormat); + ImageDecoderQt(); ~ImageDecoderQt(); virtual void setData(SharedBuffer* data, bool allDataReceived); @@ -65,7 +65,7 @@ private: void failRead(); private: - String m_format; + QByteArray m_format; QBuffer* m_buffer; QImageReader* m_reader; mutable int m_repetitionCount; diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index c9f1349..889c41b 100644 --- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -296,7 +296,7 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness r.inset(SkIntToScalar(thickness), SkIntToScalar(thickness)); path.addOval(r, SkPath::kCCW_Direction); } - platformContext()->canvas()->clipPath(path); + platformContext()->clipPathAntiAliased(path); } void GraphicsContext::addPath(const Path& path) @@ -356,6 +356,18 @@ void GraphicsContext::clip(const Path& path) if (!isPathSkiaSafe(getCTM(), p)) return; + platformContext()->clipPathAntiAliased(p); +} + +void GraphicsContext::canvasClip(const Path& path) +{ + if (paintingDisabled()) + return; + + const SkPath& p = *path.platformPath(); + if (!isPathSkiaSafe(getCTM(), p)) + return; + platformContext()->canvas()->clipPath(p); } @@ -407,7 +419,7 @@ void GraphicsContext::clipPath(WindRule clipRule) return; path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); - platformContext()->canvas()->clipPath(path); + platformContext()->clipPathAntiAliased(path); } void GraphicsContext::clipToImageBuffer(const FloatRect& rect, diff --git a/WebCore/platform/graphics/skia/PathSkia.cpp b/WebCore/platform/graphics/skia/PathSkia.cpp index 5ac14b9..2cbb759 100644 --- a/WebCore/platform/graphics/skia/PathSkia.cpp +++ b/WebCore/platform/graphics/skia/PathSkia.cpp @@ -123,26 +123,31 @@ void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlo SkScalar cx = WebCoreFloatToSkScalar(p.x()); SkScalar cy = WebCoreFloatToSkScalar(p.y()); SkScalar radius = WebCoreFloatToSkScalar(r); + SkScalar s360 = SkIntToScalar(360); SkRect oval; oval.set(cx - radius, cy - radius, cx + radius, cy + radius); float sweep = ea - sa; - // check for a circle - if (sweep >= 2 * piFloat || sweep <= -2 * piFloat) + SkScalar startDegrees = WebCoreFloatToSkScalar(sa * 180 / piFloat); + SkScalar sweepDegrees = WebCoreFloatToSkScalar(sweep * 180 / piFloat); + // Check for a circle. + if (sweepDegrees >= s360 || sweepDegrees <= -s360) { + // Move to the start position (0 sweep means we add a single point). + m_path->arcTo(oval, startDegrees, 0, false); + // Draw the circle. m_path->addOval(oval); - else { - SkScalar startDegrees = WebCoreFloatToSkScalar(sa * 180 / piFloat); - SkScalar sweepDegrees = WebCoreFloatToSkScalar(sweep * 180 / piFloat); - + // Force a moveTo the end position. + m_path->arcTo(oval, startDegrees + sweepDegrees, 0, true); + } else { // Counterclockwise arcs should be drawn with negative sweeps, while // clockwise arcs should be drawn with positive sweeps. Check to see // if the situation is reversed and correct it by adding or subtracting // a full circle if (anticlockwise && sweepDegrees > 0) { - sweepDegrees -= SkIntToScalar(360); + sweepDegrees -= s360; } else if (!anticlockwise && sweepDegrees < 0) { - sweepDegrees += SkIntToScalar(360); + sweepDegrees += s360; } m_path->arcTo(oval, startDegrees, sweepDegrees, false); diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index 1fb62fc..a079da0 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -45,6 +45,7 @@ #include "SkDashPathEffect.h" #include <wtf/MathExtras.h> +#include <wtf/Vector.h> namespace WebCore { @@ -95,6 +96,10 @@ struct PlatformContextSkia::State { WebCore::FloatRect m_clip; #endif + // This is a list of clipping paths which are currently active, in the + // order in which they were pushed. + WTF::Vector<SkPath> m_antiAliasClipPaths; + private: // Not supported. void operator=(const State&); @@ -110,8 +115,8 @@ PlatformContextSkia::State::State() , m_fillShader(0) , m_strokeStyle(WebCore::SolidStroke) , m_strokeColor(WebCore::Color::black) - , m_strokeThickness(0) , m_strokeShader(0) + , m_strokeThickness(0) , m_dashRatio(3) , m_miterLimit(4) , m_lineCap(SkPaint::kDefault_Cap) @@ -130,8 +135,8 @@ PlatformContextSkia::State::State(const State& other) , m_fillShader(other.m_fillShader) , m_strokeStyle(other.m_strokeStyle) , m_strokeColor(other.m_strokeColor) - , m_strokeThickness(other.m_strokeThickness) , m_strokeShader(other.m_strokeShader) + , m_strokeThickness(other.m_strokeThickness) , m_dashRatio(other.m_dashRatio) , m_miterLimit(other.m_miterLimit) , m_lineCap(other.m_lineCap) @@ -249,6 +254,21 @@ void PlatformContextSkia::beginLayerClippedToImage(const WebCore::FloatRect& rec } #endif +void PlatformContextSkia::clipPathAntiAliased(const SkPath& clipPath) +{ + // If we are currently tracking any anti-alias clip paths, then we already + // have a layer in place and don't need to add another. + bool haveLayerOutstanding = m_state->m_antiAliasClipPaths.size(); + + // See comments in applyAntiAliasedClipPaths about how this works. + m_state->m_antiAliasClipPaths.append(clipPath); + + if (!haveLayerOutstanding) { + SkRect bounds = clipPath.getBounds(); + canvas()->saveLayerAlpha(&bounds, 255, static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag)); + } +} + void PlatformContextSkia::restore() { #if defined(__linux__) || PLATFORM(WIN_OS) @@ -258,6 +278,9 @@ void PlatformContextSkia::restore() } #endif + if (!m_state->m_antiAliasClipPaths.isEmpty()) + applyAntiAliasedClipPaths(m_state->m_antiAliasClipPaths); + m_stateStack.removeLast(); m_state = &m_stateStack.last(); @@ -549,3 +572,40 @@ void PlatformContextSkia::applyClipFromImage(const WebCore::FloatRect& rect, con m_canvas->drawBitmap(imageBuffer, SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()), &paint); } #endif + +void PlatformContextSkia::applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths) +{ + // Anti-aliased clipping: + // + // Skia's clipping is 1-bit only. Consider what would happen if it were 8-bit: + // We have a square canvas, filled with white and we declare a circular + // clipping path. Then we fill twice with a black rectangle. The fractional + // pixels would first get the correct color (white * alpha + black * (1 - + // alpha)), but the second fill would apply the alpha to the already + // modified color and the result would be too dark. + // + // This, anti-aliased clipping needs to be performed after the drawing has + // been done. In order to do this, we create a new layer of the canvas in + // clipPathAntiAliased and store the clipping path. All drawing is done to + // the layer's bitmap while it's in effect. When WebKit calls restore() to + // undo the clipping, this function is called. + // + // Here, we walk the list of clipping paths backwards and, for each, we + // clear outside of the clipping path. We only need a single extra layer + // for any number of clipping paths. + // + // When we call restore on the SkCanvas, the layer's bitmap is composed + // into the layer below and we end up with correct, anti-aliased clipping. + + SkPaint paint; + paint.setXfermodeMode(SkXfermode::kClear_Mode); + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kFill_Style); + + for (size_t i = paths.size() - 1; i < paths.size(); --i) { + paths[i].setFillType(SkPath::kInverseWinding_FillType); + m_canvas->drawPath(paths[i], paint); + } + + m_canvas->restore(); +} diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h index 0c87fc2..53590bf 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.h +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h @@ -92,6 +92,7 @@ public: void beginLayerClippedToImage(const WebCore::FloatRect&, const WebCore::ImageBuffer*); #endif + void clipPathAntiAliased(const SkPath&); // Sets up the common flags on a paint for antialiasing, effects, etc. // This is implicitly called by setupPaintFill and setupPaintStroke, but @@ -172,6 +173,7 @@ private: // m_canvas that are also in imageBuffer. void applyClipFromImage(const WebCore::FloatRect&, const SkBitmap&); #endif + void applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths); // Defines drawing style. struct State; diff --git a/WebCore/platform/graphics/skia/SkiaUtils.cpp b/WebCore/platform/graphics/skia/SkiaUtils.cpp index bb15aa2..377ca06 100644 --- a/WebCore/platform/graphics/skia/SkiaUtils.cpp +++ b/WebCore/platform/graphics/skia/SkiaUtils.cpp @@ -200,8 +200,13 @@ bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath:: SkRect bounds = originalPath->getBounds(); - // We can immediately return false if the point is outside the bounding rect - if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y()))) + // We can immediately return false if the point is outside the bounding + // rect. We don't use bounds.contains() here, since it would exclude + // points on the right and bottom edges of the bounding rect, and we want + // to include them. + SkScalar fX = SkFloatToScalar(point.x()); + SkScalar fY = SkFloatToScalar(point.y()); + if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom) return false; originalPath->setFillType(ft); @@ -225,7 +230,7 @@ bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath:: int x = static_cast<int>(floorf(point.x() / scale)); int y = static_cast<int>(floorf(point.y() / scale)); - clip.setRect(x, y, x + 1, y + 1); + clip.setRect(x - 1, y - 1, x + 1, y + 1); bool contains = rgn.setPath(*path, clip); diff --git a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp index 26b22af..e845d85 100644 --- a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp +++ b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp @@ -34,11 +34,11 @@ #include "Font.h" #include "FontCache.h" #include "FontDescription.h" -#include "MathExtras.h" #include <cairo.h> #include <cairo-win32.h> #include <mlang.h> #include <tchar.h> +#include <wtf/MathExtras.h> namespace WebCore { diff --git a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp index c114c0e..f308840 100644 --- a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp +++ b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp @@ -1219,6 +1219,11 @@ void GraphicsContext::clip(const Path& path) notImplemented(); } +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + void GraphicsContext::clipOut(const Path&) { notImplemented(); diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp index 686fb07..39f14f4 100644 --- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp +++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp @@ -344,6 +344,11 @@ void GraphicsContext::clip(const Path&) notImplemented(); } +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) { notImplemented(); diff --git a/WebCore/platform/gtk/KeyEventGtk.cpp b/WebCore/platform/gtk/KeyEventGtk.cpp index 4186c2f..3931eff 100644 --- a/WebCore/platform/gtk/KeyEventGtk.cpp +++ b/WebCore/platform/gtk/KeyEventGtk.cpp @@ -200,6 +200,7 @@ static int windowsKeyCodeForKeyEvent(unsigned int keycode) case GDK_Control_R: return VK_CONTROL; // (11) CTRL key case GDK_Menu: + return VK_APPS; // (5D) Applications key (Natural keyboard) case GDK_Alt_L: case GDK_Alt_R: return VK_MENU; // (12) ALT key @@ -370,7 +371,6 @@ static int windowsKeyCodeForKeyEvent(unsigned int keycode) return VK_LWIN; // (5B) Left Windows key (Microsoft Natural keyboard) case GDK_Meta_R: return VK_RWIN; // (5C) Right Windows key (Natural keyboard) - // VK_APPS (5D) Applications key (Natural keyboard) // VK_SLEEP (5F) Computer Sleep key // VK_SEPARATOR (6C) Separator key // VK_SUBTRACT (6D) Subtract key diff --git a/WebCore/platform/gtk/Language.cpp b/WebCore/platform/gtk/Language.cpp index 171cd84..fea2df6 100644 --- a/WebCore/platform/gtk/Language.cpp +++ b/WebCore/platform/gtk/Language.cpp @@ -21,16 +21,37 @@ #include "Language.h" #include "CString.h" +#include "GOwnPtr.h" #include "PlatformString.h" #include <gtk/gtk.h> +#include <locale.h> #include <pango/pango.h> namespace WebCore { +// Using pango_language_get_default() here is not an option, because +// it doesn't support changing the locale in runtime, so it returns +// always the same value. String defaultLanguage() { - return pango_language_to_string(gtk_get_default_language()); + char* localeDefault = setlocale(LC_CTYPE, NULL); + + if (!localeDefault) + return String("c"); + + GOwnPtr<gchar> normalizedDefault(g_ascii_strdown(localeDefault, -1)); + char* ptr = strchr(normalizedDefault.get(), '_'); + + if(ptr) + *ptr = '-'; + + ptr = strchr(normalizedDefault.get(), '.'); + + if(ptr) + *ptr = '\0'; + + return String(normalizedDefault.get()); } } diff --git a/WebCore/platform/mac/ClipboardMac.mm b/WebCore/platform/mac/ClipboardMac.mm index 78fb659..f4321ad 100644 --- a/WebCore/platform/mac/ClipboardMac.mm +++ b/WebCore/platform/mac/ClipboardMac.mm @@ -107,11 +107,15 @@ static String utiTypeFromCocoaType(NSString *type) static void addHTMLClipboardTypesForCocoaType(HashSet<String>& resultTypes, NSString *cocoaType, NSPasteboard *pasteboard) { // UTI may not do these right, so make sure we get the right, predictable result - if ([cocoaType isEqualToString:NSStringPboardType]) + if ([cocoaType isEqualToString:NSStringPboardType]) { resultTypes.add("text/plain"); - else if ([cocoaType isEqualToString:NSURLPboardType]) + return; + } + if ([cocoaType isEqualToString:NSURLPboardType]) { resultTypes.add("text/uri-list"); - else if ([cocoaType isEqualToString:NSFilenamesPboardType]) { + return; + } + if ([cocoaType isEqualToString:NSFilenamesPboardType]) { // If file list is empty, add nothing. // Note that there is a chance that the file list count could have changed since we grabbed the types array. // However, this is not really an issue for us doing a sanity check here. @@ -122,12 +126,15 @@ static void addHTMLClipboardTypesForCocoaType(HashSet<String>& resultTypes, NSSt resultTypes.add("text/uri-list"); resultTypes.add("Files"); } - } else if (String utiType = utiTypeFromCocoaType(cocoaType)) + return; + } + String utiType = utiTypeFromCocoaType(cocoaType); + if (!utiType.isEmpty()) { resultTypes.add(utiType); - else { - // No mapping, just pass the whole string though - resultTypes.add(cocoaType); + return; } + // No mapping, just pass the whole string though + resultTypes.add(cocoaType); } void ClipboardMac::clearData(const String& type) diff --git a/WebCore/platform/network/Credential.cpp b/WebCore/platform/network/Credential.cpp index caca785..f905743 100644 --- a/WebCore/platform/network/Credential.cpp +++ b/WebCore/platform/network/Credential.cpp @@ -32,6 +32,7 @@ namespace WebCore { Credential::Credential() : m_user("") , m_password("") + , m_persistence(CredentialPersistenceNone) { } @@ -44,7 +45,7 @@ Credential::Credential(const String& user, const String& password, CredentialPer { } -bool Credential::isEmpty() +bool Credential::isEmpty() const { return m_user.isEmpty() && m_password.isEmpty(); } diff --git a/WebCore/platform/network/Credential.h b/WebCore/platform/network/Credential.h index ca4a45a..0471fbc 100644 --- a/WebCore/platform/network/Credential.h +++ b/WebCore/platform/network/Credential.h @@ -41,7 +41,7 @@ public: Credential(); Credential(const String& user, const String& password, CredentialPersistence); - bool isEmpty(); + bool isEmpty() const; const String& user() const; const String& password() const; diff --git a/WebCore/platform/network/CredentialStorage.cpp b/WebCore/platform/network/CredentialStorage.cpp index 407ed5b..ec78372 100644 --- a/WebCore/platform/network/CredentialStorage.cpp +++ b/WebCore/platform/network/CredentialStorage.cpp @@ -43,13 +43,19 @@ static ProtectionSpaceToCredentialMap& protectionSpaceToCredentialMap() return map; } -typedef HashMap<String, HashMap<String, Credential> > OriginToDefaultBasicCredentialMap; -static OriginToDefaultBasicCredentialMap& originToDefaultBasicCredentialMap() +static HashSet<String>& originsWithCredentials() { - DEFINE_STATIC_LOCAL(OriginToDefaultBasicCredentialMap, map, ()); + DEFINE_STATIC_LOCAL(HashSet<String>, set, ()); + return set; +} + +typedef HashMap<String, ProtectionSpace> PathToDefaultProtectionSpaceMap; +static PathToDefaultProtectionSpaceMap& pathToDefaultProtectionSpaceMap() +{ + DEFINE_STATIC_LOCAL(PathToDefaultProtectionSpaceMap, map, ()); return map; } - + static String originStringFromURL(const KURL& url) { if (url.port()) @@ -58,32 +64,37 @@ static String originStringFromURL(const KURL& url) return url.protocol() + "://" + url.host() + "/"; } +static String protectionSpaceMapKeyFromURL(const KURL& url) +{ + ASSERT(url.isValid()); + + // Remove the last path component that is not a directory to determine the subtree for which credentials will apply. + // We keep a leading slash, but remove a trailing one. + String directoryURL = url.string().substring(0, url.pathEnd()); + unsigned directoryURLPathStart = url.pathStart(); + ASSERT(directoryURL[directoryURLPathStart] == '/'); + if (directoryURL.length() > directoryURLPathStart + 1) { + int index = directoryURL.reverseFind('/'); + ASSERT(index > 0); + directoryURL = directoryURL.substring(0, (static_cast<unsigned>(index) != directoryURLPathStart) ? index : directoryURLPathStart + 1); + } + ASSERT(directoryURL.length() == directoryURLPathStart + 1 || directoryURL[directoryURL.length() - 1] != '/'); + + return directoryURL; +} + void CredentialStorage::set(const Credential& credential, const ProtectionSpace& protectionSpace, const KURL& url) { ASSERT(url.protocolInHTTPFamily()); ASSERT(url.isValid()); protectionSpaceToCredentialMap().set(protectionSpace, credential); - + originsWithCredentials().add(originStringFromURL(url)); + ProtectionSpaceAuthenticationScheme scheme = protectionSpace.authenticationScheme(); - if (url.protocolInHTTPFamily() && (scheme == ProtectionSpaceAuthenticationSchemeHTTPBasic || scheme == ProtectionSpaceAuthenticationSchemeDefault)) { - String origin = originStringFromURL(url); - - HashMap<String, Credential> pathToCredentialMap; - pair<HashMap<String, HashMap<String, Credential> >::iterator, bool> result = originToDefaultBasicCredentialMap().add(origin, pathToCredentialMap); - - // Remove the last path component that is not a directory to determine the subpath for which this credential applies. - // We keep a leading slash, but remove a trailing one. - String path = url.path(); - ASSERT(path.length() > 0); - ASSERT(path[0] == '/'); - if (path.length() > 1) { - int index = path.reverseFind('/'); - path = path.substring(0, index ? index : 1); - } - ASSERT(path.length() == 1 || path[path.length() - 1] != '/'); - - result.first->second.set(path, credential); + if (scheme == ProtectionSpaceAuthenticationSchemeHTTPBasic || scheme == ProtectionSpaceAuthenticationSchemeDefault) { + // The map can contain both a path and its subpath - while redundant, this makes lookups faster. + pathToDefaultProtectionSpaceMap().set(protectionSpaceMapKeyFromURL(url), protectionSpace); } } @@ -92,33 +103,53 @@ Credential CredentialStorage::get(const ProtectionSpace& protectionSpace) return protectionSpaceToCredentialMap().get(protectionSpace); } -Credential CredentialStorage::getDefaultAuthenticationCredential(const KURL& url) +static PathToDefaultProtectionSpaceMap::iterator findDefaultProtectionSpaceForURL(const KURL& url) { ASSERT(url.protocolInHTTPFamily()); - String origin = originStringFromURL(url); - const HashMap<String, Credential>& pathToCredentialMap(originToDefaultBasicCredentialMap().get(origin)); - if (pathToCredentialMap.isEmpty()) - return Credential(); - - // Check to see if there is a stored credential for the subpath ancestry of this url. - String path = url.path(); - Credential credential = pathToCredentialMap.get(path); - while (credential.isEmpty() && !path.isNull()) { - int index = path.reverseFind('/'); - if (index == 0) { - credential = pathToCredentialMap.get("/"); - break; - } else if (index == -1) { - // This case should never happen, as all HTTP URL paths should start with a leading / - ASSERT_NOT_REACHED(); - credential = pathToCredentialMap.get(path); - break; - } else { - path = path.substring(0, index); - credential = pathToCredentialMap.get(path); - } + ASSERT(url.isValid()); + + PathToDefaultProtectionSpaceMap& map = pathToDefaultProtectionSpaceMap(); + + // Don't spend time iterating the path for origins that don't have any credentials. + if (!originsWithCredentials().contains(originStringFromURL(url))) + return map.end(); + + String directoryURL = protectionSpaceMapKeyFromURL(url); + unsigned directoryURLPathStart = url.pathStart(); + while (true) { + PathToDefaultProtectionSpaceMap::iterator iter = map.find(directoryURL); + if (iter != map.end()) + return iter; + + if (directoryURL.length() == directoryURLPathStart + 1) // path is "/" already, cannot shorten it any more + return map.end(); + + int index = directoryURL.reverseFind('/', -2); + ASSERT(index > 0); + directoryURL = directoryURL.substring(0, (static_cast<unsigned>(index) == directoryURLPathStart) ? index + 1 : index); + ASSERT(directoryURL.length() > directoryURLPathStart); + ASSERT(directoryURL.length() == directoryURLPathStart + 1 || directoryURL[directoryURL.length() - 1] != '/'); } - return credential; +} + +bool CredentialStorage::set(const Credential& credential, const KURL& url) +{ + ASSERT(url.protocolInHTTPFamily()); + ASSERT(url.isValid()); + PathToDefaultProtectionSpaceMap::iterator iter = findDefaultProtectionSpaceForURL(url); + if (iter == pathToDefaultProtectionSpaceMap().end()) + return false; + ASSERT(originsWithCredentials().contains(originStringFromURL(url))); + protectionSpaceToCredentialMap().set(iter->second, credential); + return true; +} + +Credential CredentialStorage::get(const KURL& url) +{ + PathToDefaultProtectionSpaceMap::iterator iter = findDefaultProtectionSpaceForURL(url); + if (iter == pathToDefaultProtectionSpaceMap().end()) + return Credential(); + return protectionSpaceToCredentialMap().get(iter->second); } } // namespace WebCore diff --git a/WebCore/platform/network/CredentialStorage.h b/WebCore/platform/network/CredentialStorage.h index 737efa6..5086f69 100644 --- a/WebCore/platform/network/CredentialStorage.h +++ b/WebCore/platform/network/CredentialStorage.h @@ -36,7 +36,11 @@ class CredentialStorage { public: static void set(const Credential&, const ProtectionSpace&, const KURL&); static Credential get(const ProtectionSpace&); - static Credential getDefaultAuthenticationCredential(const KURL&); + + // These methods work for authentication schemes that support sending credentials without waiting for a request. E.g., for HTTP Basic authentication scheme + // a client should assume that all paths at or deeper than the depth of a known protected resource share are within the same protection space. + static bool set(const Credential&, const KURL&); // Returns true if the URL corresponds to a known protection space, so credentials could be updated. + static Credential get(const KURL&); }; } // namespace WebCore diff --git a/WebCore/platform/network/FormDataBuilder.cpp b/WebCore/platform/network/FormDataBuilder.cpp index 27bdee3..04c7527 100644 --- a/WebCore/platform/network/FormDataBuilder.cpp +++ b/WebCore/platform/network/FormDataBuilder.cpp @@ -108,6 +108,34 @@ static inline void append(Vector<char>& buffer, const CString& string) buffer.append(string.data(), string.length()); } +static void appendQuotedString(Vector<char>& buffer, const CString& string) +{ + // Append a string as a quoted value, escaping quotes and line breaks. + // FIXME: Is it correct to use percent escaping here? Other browsers do not encode these characters yet, + // so we should test popular servers to find out if there is an encoding form they can handle. + unsigned length = string.length(); + for (unsigned i = 0; i < length; ++i) { + unsigned char c = string.data()[i]; + + switch (c) { + case 0x0a: + append(buffer, "%0A"); + break; + case 0x0d: + append(buffer, "%0D"); + break; + case '"': + append(buffer, "%22"); + break; + case '%': + append(buffer, "%25"); + break; + default: + append(buffer, c); + } + } +} + Vector<char> FormDataBuilder::generateUniqueBoundaryString() { Vector<char> boundary; @@ -161,8 +189,10 @@ void FormDataBuilder::beginMultiPartHeader(Vector<char>& buffer, const CString& { addBoundaryToMultiPartHeader(buffer, boundary); + // FIXME: This loses data irreversibly if the input name includes characters you can't encode + // in the website's character set. append(buffer, "Content-Disposition: form-data; name=\""); - append(buffer, name); + appendQuotedString(buffer, name); append(buffer, '"'); } @@ -179,12 +209,10 @@ void FormDataBuilder::addBoundaryToMultiPartHeader(Vector<char>& buffer, const C void FormDataBuilder::addFilenameToMultiPartHeader(Vector<char>& buffer, const TextEncoding& encoding, const String& filename) { - // FIXME: This won't work if the filename includes a " mark, - // or control characters like CR or LF. This also does strange - // things if the filename includes characters you can't encode + // FIXME: This loses data irreversibly if the filename includes characters you can't encode // in the website's character set. append(buffer, "; filename=\""); - append(buffer, encoding.encode(filename.characters(), filename.length(), QuestionMarksForUnencodables)); + appendQuotedString(buffer, encoding.encode(filename.characters(), filename.length(), QuestionMarksForUnencodables)); append(buffer, '"'); } diff --git a/WebCore/platform/network/ResourceRequestBase.cpp b/WebCore/platform/network/ResourceRequestBase.cpp index ee11bcb..8ab72c1 100644 --- a/WebCore/platform/network/ResourceRequestBase.cpp +++ b/WebCore/platform/network/ResourceRequestBase.cpp @@ -218,6 +218,26 @@ void ResourceRequestBase::setHTTPHeaderField(const AtomicString& name, const Str m_platformRequestUpdated = false; } +void ResourceRequestBase::clearHTTPReferrer() +{ + updateResourceRequest(); + + m_httpHeaderFields.remove("Referer"); + + if (url().protocolInHTTPFamily()) + m_platformRequestUpdated = false; +} + +void ResourceRequestBase::clearHTTPOrigin() +{ + updateResourceRequest(); + + m_httpHeaderFields.remove("Origin"); + + if (url().protocolInHTTPFamily()) + m_platformRequestUpdated = false; +} + void ResourceRequestBase::setResponseContentDispositionEncodingFallbackArray(const String& encoding1, const String& encoding2, const String& encoding3) { updateResourceRequest(); @@ -358,7 +378,11 @@ void ResourceRequestBase::updateResourceRequest() const m_resourceRequestUpdated = true; } +<<<<<<< HEAD:WebCore/platform/network/ResourceRequestBase.cpp #if !PLATFORM(MAC) && !USE(CFNETWORK) && !USE(SOUP) && !PLATFORM(ANDROID) +======= +#if !PLATFORM(MAC) && !USE(CFNETWORK) && !USE(SOUP) && !PLATFORM(CHROMIUM) +>>>>>>> webkit.org at r50258.:WebCore/platform/network/ResourceRequestBase.cpp unsigned initializeMaximumHTTPConnectionCountPerHost() { // This is used by the loader to control the number of issued parallel load requests. diff --git a/WebCore/platform/network/ResourceRequestBase.h b/WebCore/platform/network/ResourceRequestBase.h index 348e6b3..84a7bd0 100644 --- a/WebCore/platform/network/ResourceRequestBase.h +++ b/WebCore/platform/network/ResourceRequestBase.h @@ -88,11 +88,11 @@ namespace WebCore { String httpReferrer() const { return httpHeaderField("Referer"); } void setHTTPReferrer(const String& httpReferrer) { setHTTPHeaderField("Referer", httpReferrer); } - void clearHTTPReferrer() { m_httpHeaderFields.remove("Referer"); } + void clearHTTPReferrer(); String httpOrigin() const { return httpHeaderField("Origin"); } void setHTTPOrigin(const String& httpOrigin) { setHTTPHeaderField("Origin", httpOrigin); } - void clearHTTPOrigin() { m_httpHeaderFields.remove("Origin"); } + void clearHTTPOrigin(); String httpUserAgent() const { return httpHeaderField("User-Agent"); } void setHTTPUserAgent(const String& httpUserAgent) { setHTTPHeaderField("User-Agent", httpUserAgent); } diff --git a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp index ea5fcc6..38a9705 100644 --- a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp @@ -156,7 +156,11 @@ CFURLRequestRef willSendRequest(CFURLConnectionRef conn, CFURLRequestRef cfReque } if (request.isNull()) request = cfRequest; - + + // Should not set Referer after a redirect from a secure resource to non-secure one. + if (!request.url().protocolIs("https") && protocolIs(request.httpReferrer(), "https")) + request.clearHTTPReferrer(); + handle->willSendRequest(request, cfRedirectResponse); if (request.isNull()) @@ -401,8 +405,18 @@ bool ResourceHandle::start(Frame* frame) // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, // try and reuse the credential preemptively, as allowed by RFC 2617. - if (!client() || client()->shouldUseCredentialStorage(this) && d->m_request.url().protocolInHTTPFamily()) - d->m_initialCredential = CredentialStorage::getDefaultAuthenticationCredential(d->m_request.url()); + if (!client() || client()->shouldUseCredentialStorage(this) && d->m_request.url().protocolInHTTPFamily()) { + if (d->m_user.isEmpty() && d->m_pass.isEmpty()) { + // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, + // try and reuse the credential preemptively, as allowed by RFC 2617. + d->m_initialCredential = CredentialStorage::get(d->m_request.url()); + } else { + // If there is already a protection space known for the URL, update stored credentials before sending a request. + // This makes it possible to implement logout by sending an XMLHttpRequest with known incorrect credentials, and aborting it immediately + // (so that an authentication dialog doesn't pop up). + CredentialStorage::set(Credential(d->m_user, d->m_pass, CredentialPersistenceNone), d->m_request.url()); + } + } if (!d->m_initialCredential.isEmpty()) { String authHeader = "Basic " + encodeBasicAuthorization(d->m_initialCredential.user(), d->m_initialCredential.password()); @@ -769,7 +783,7 @@ RetainPtr<CFDataRef> WebCoreSynchronousLoader::load(const ResourceRequest& reque // try and reuse the credential preemptively, as allowed by RFC 2617. ResourceRequest requestWithInitialCredential(request); if (loader.m_allowStoredCredentials && url.protocolInHTTPFamily()) - loader.m_initialCredential = CredentialStorage::getDefaultAuthenticationCredential(url); + loader.m_initialCredential = CredentialStorage::get(url); if (!loader.m_initialCredential.isEmpty()) { String authHeader = "Basic " + encodeBasicAuthorization(loader.m_initialCredential.user(), loader.m_initialCredential.password()); diff --git a/WebCore/platform/network/cf/ResourceRequestCFNet.cpp b/WebCore/platform/network/cf/ResourceRequestCFNet.cpp index bba3d3e..cc0220e 100644 --- a/WebCore/platform/network/cf/ResourceRequestCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceRequestCFNet.cpp @@ -39,9 +39,11 @@ typedef CFArrayRef (*CFURLRequestCopyContentDispositionEncodingFallbackArrayFunc static HMODULE findCFNetworkModule() { - if (HMODULE module = GetModuleHandleA("CFNetwork")) - return module; +#ifndef DEBUG_ALL + return GetModuleHandleA("CFNetwork"); +#else return GetModuleHandleA("CFNetwork_debug"); +#endif } static CFURLRequestSetContentDispositionEncodingFallbackArrayFunction findCFURLRequestSetContentDispositionEncodingFallbackArrayFunction() @@ -76,11 +78,18 @@ CFURLRequestRef ResourceRequest::cfURLRequest() const return m_cfRequest.get(); } -static inline void addHeadersFromHashMap(CFMutableURLRequestRef request, const HTTPHeaderMap& requestHeaders) +static inline void setHeaderFields(CFMutableURLRequestRef request, const HTTPHeaderMap& requestHeaders) { - if (!requestHeaders.size()) - return; - + // Remove existing headers first, as some of them may no longer be present in the map. + RetainPtr<CFDictionaryRef> oldHeaderFields(AdoptCF, CFURLRequestCopyAllHTTPHeaderFields(request)); + CFIndex oldHeaderFieldCount = CFDictionaryGetCount(oldHeaderFields.get()); + if (oldHeaderFieldCount) { + Vector<CFStringRef> oldHeaderFieldNames(oldHeaderFieldCount); + CFDictionaryGetKeysAndValues(oldHeaderFields.get(), reinterpret_cast<const void**>(&oldHeaderFieldNames[0]), 0); + for (CFIndex i = 0; i < oldHeaderFieldCount; ++i) + CFURLRequestSetHTTPHeaderFieldValue(request, oldHeaderFieldNames[i], 0); + } + HTTPHeaderMap::const_iterator end = requestHeaders.end(); for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) { CFStringRef key = it->first.createCFString(); @@ -110,7 +119,7 @@ void ResourceRequest::doUpdatePlatformRequest() RetainPtr<CFStringRef> requestMethod(AdoptCF, httpMethod().createCFString()); CFURLRequestSetHTTPRequestMethod(cfRequest, requestMethod.get()); - addHeadersFromHashMap(cfRequest, httpHeaderFields()); + setHeaderFields(cfRequest, httpHeaderFields()); WebCore::setHTTPBody(cfRequest, httpBody()); CFURLRequestSetShouldHandleHTTPCookies(cfRequest, allowCookies()); @@ -148,6 +157,7 @@ void ResourceRequest::doUpdateResourceRequest() } m_allowCookies = CFURLRequestShouldHandleHTTPCookies(m_cfRequest.get()); + m_httpHeaderFields.clear(); if (CFDictionaryRef headers = CFURLRequestCopyAllHTTPHeaderFields(m_cfRequest.get())) { CFIndex headerCount = CFDictionaryGetCount(headers); Vector<const void*, 128> keys(headerCount); diff --git a/WebCore/platform/network/chromium/ResourceRequest.cpp b/WebCore/platform/network/chromium/ResourceRequest.cpp new file mode 100644 index 0000000..76d1288 --- /dev/null +++ b/WebCore/platform/network/chromium/ResourceRequest.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009 Google, 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. + */ + +namespace WebCore { + +// This is used by the loader to control the number of issued parallel load requests. +unsigned initializeMaximumHTTPConnectionCountPerHost() +{ + return 6; +} + +} // namespace WebCore diff --git a/WebCore/platform/network/curl/ResourceHandleCurl.cpp b/WebCore/platform/network/curl/ResourceHandleCurl.cpp index 5469ec9..5464e07 100644 --- a/WebCore/platform/network/curl/ResourceHandleCurl.cpp +++ b/WebCore/platform/network/curl/ResourceHandleCurl.cpp @@ -156,7 +156,7 @@ void ResourceHandle::setDefersLoading(bool defers) if (d->m_defersLoading == defers) return; -#if LIBCURL_VERSION_NUM > 0x071200 +#if LIBCURL_VERSION_NUM > 0x071800 if (!d->m_handle) d->m_defersLoading = defers; else if (defers) { diff --git a/WebCore/platform/network/curl/ResourceHandleManager.cpp b/WebCore/platform/network/curl/ResourceHandleManager.cpp index 14c6f31..d8a812f 100644 --- a/WebCore/platform/network/curl/ResourceHandleManager.cpp +++ b/WebCore/platform/network/curl/ResourceHandleManager.cpp @@ -409,6 +409,25 @@ void ResourceHandleManager::downloadTimerCallback(Timer<ResourceHandleManager>* m_downloadTimer.startOneShot(pollTimeSeconds); } +void ResourceHandleManager::setProxyInfo(const String& host, + unsigned long port, + ProxyType type, + const String& username, + const String& password) +{ + m_proxyType = type; + + if (!host.length()) { + m_proxy = String(""); + } else { + String userPass; + if (username.length() || password.length()) + userPass = username + ":" + password + "@"; + + m_proxy = String("http://") + userPass + host + ":" + String::number(port); + } +} + void ResourceHandleManager::removeFromCurl(ResourceHandle* job) { ResourceHandleInternal* d = job->getInternal(); @@ -678,7 +697,7 @@ void ResourceHandleManager::initializeHandle(ResourceHandle* job) d->m_handle = curl_easy_init(); -#if LIBCURL_VERSION_NUM > 0x071200 +#if LIBCURL_VERSION_NUM > 0x071800 if (d->m_defersLoading) { CURLcode error = curl_easy_pause(d->m_handle, CURLPAUSE_ALL); // If we did not pause the handle, we would ASSERT in the @@ -753,6 +772,17 @@ void ResourceHandleManager::initializeHandle(ResourceHandle* job) curl_easy_setopt(d->m_handle, CURLOPT_HTTPHEADER, headers); d->m_customHeaders = headers; } + // curl CURLOPT_USERPWD expects username:password + if (d->m_user.length() || d->m_pass.length()) { + String userpass = d->m_user + ":" + d->m_pass; + curl_easy_setopt(d->m_handle, CURLOPT_USERPWD, userpass.utf8().data()); + } + + // Set proxy options if we have them. + if (m_proxy.length()) { + curl_easy_setopt(d->m_handle, CURLOPT_PROXY, m_proxy.utf8().data()); + curl_easy_setopt(d->m_handle, CURLOPT_PROXYTYPE, m_proxyType); + } } void ResourceHandleManager::cancel(ResourceHandle* job) diff --git a/WebCore/platform/network/curl/ResourceHandleManager.h b/WebCore/platform/network/curl/ResourceHandleManager.h index 89b27d7..4d73d87 100644 --- a/WebCore/platform/network/curl/ResourceHandleManager.h +++ b/WebCore/platform/network/curl/ResourceHandleManager.h @@ -28,8 +28,9 @@ #ifndef ResourceHandleManager_h #define ResourceHandleManager_h -#include "Frame.h" #include "CString.h" +#include "Frame.h" +#include "PlatformString.h" #include "Timer.h" #include "ResourceHandleClient.h" @@ -45,6 +46,13 @@ namespace WebCore { class ResourceHandleManager { public: + enum ProxyType { + HTTP = CURLPROXY_HTTP, + Socks4 = CURLPROXY_SOCKS4, + Socks4A = CURLPROXY_SOCKS4A, + Socks5 = CURLPROXY_SOCKS5, + Socks5Hostname = CURLPROXY_SOCKS5_HOSTNAME + }; static ResourceHandleManager* sharedInstance(); void add(ResourceHandle*); void cancel(ResourceHandle*); @@ -55,6 +63,12 @@ public: void setupPOST(ResourceHandle*, struct curl_slist**); void setupPUT(ResourceHandle*, struct curl_slist**); + void setProxyInfo(const String& host = "", + unsigned long port = 0, + ProxyType type = HTTP, + const String& username = "", + const String& password = ""); + private: ResourceHandleManager(); ~ResourceHandleManager(); @@ -74,6 +88,9 @@ private: Vector<ResourceHandle*> m_resourceHandleList; const CString m_certificatePath; int m_runningJobs; + + String m_proxy; + ProxyType m_proxyType; }; } diff --git a/WebCore/platform/network/mac/AuthenticationMac.mm b/WebCore/platform/network/mac/AuthenticationMac.mm index 355931d..93725d5 100644 --- a/WebCore/platform/network/mac/AuthenticationMac.mm +++ b/WebCore/platform/network/mac/AuthenticationMac.mm @@ -150,6 +150,9 @@ NSURLProtectionSpace *mac(const ProtectionSpace& coreSpace) NSURLCredential *mac(const Credential& coreCredential) { + if (coreCredential.isEmpty()) + return nil; + NSURLCredentialPersistence persistence = NSURLCredentialPersistenceNone; switch (coreCredential.persistence()) { case CredentialPersistenceNone: diff --git a/WebCore/platform/network/mac/ResourceHandleMac.mm b/WebCore/platform/network/mac/ResourceHandleMac.mm index ec60079..3630b30 100644 --- a/WebCore/platform/network/mac/ResourceHandleMac.mm +++ b/WebCore/platform/network/mac/ResourceHandleMac.mm @@ -119,6 +119,7 @@ public: } }; +#ifndef BUILDING_ON_TIGER static String encodeBasicAuthorization(const String& user, const String& password) { CString unencodedString = (user + ":" + password).utf8(); @@ -128,6 +129,7 @@ static String encodeBasicAuthorization(const String& user, const String& passwor base64Encode(unencoded, encoded); return String(encoded.data(), encoded.size()); } +#endif ResourceHandleInternal::~ResourceHandleInternal() { @@ -175,23 +177,38 @@ bool ResourceHandle::start(Frame* frame) } else delegate = ResourceHandle::delegate(); - if ((!d->m_user.isEmpty() || !d->m_pass.isEmpty()) && !d->m_request.url().protocolInHTTPFamily()) { + if ((!d->m_user.isEmpty() || !d->m_pass.isEmpty()) +#ifndef BUILDING_ON_TIGER + && !d->m_request.url().protocolInHTTPFamily() // On Tiger, always pass credentials in URL, so that they get stored even if the request gets cancelled right away. +#endif + ) { // Credentials for ftp can only be passed in URL, the connection:didReceiveAuthenticationChallenge: delegate call won't be made. KURL urlWithCredentials(d->m_request.url()); urlWithCredentials.setUser(d->m_user); urlWithCredentials.setPass(d->m_pass); d->m_request.setURL(urlWithCredentials); } - - // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, - // try and reuse the credential preemptively, as allowed by RFC 2617. - if (!client() || client()->shouldUseCredentialStorage(this) && d->m_request.url().protocolInHTTPFamily()) - d->m_initialCredential = CredentialStorage::getDefaultAuthenticationCredential(d->m_request.url()); + +#ifndef BUILDING_ON_TIGER + if ((!client() || client()->shouldUseCredentialStorage(this)) && d->m_request.url().protocolInHTTPFamily()) { + if (d->m_user.isEmpty() && d->m_pass.isEmpty()) { + // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, + // try and reuse the credential preemptively, as allowed by RFC 2617. + d->m_initialCredential = CredentialStorage::get(d->m_request.url()); + } else { + // If there is already a protection space known for the URL, update stored credentials before sending a request. + // This makes it possible to implement logout by sending an XMLHttpRequest with known incorrect credentials, and aborting it immediately + // (so that an authentication dialog doesn't pop up). + CredentialStorage::set(Credential(d->m_user, d->m_pass, CredentialPersistenceNone), d->m_request.url()); + } + } if (!d->m_initialCredential.isEmpty()) { + // FIXME: Support Digest authentication, and Proxy-Authorization. String authHeader = "Basic " + encodeBasicAuthorization(d->m_initialCredential.user(), d->m_initialCredential.password()); d->m_request.addHTTPHeaderField("Authorization", authHeader); } +#endif if (!ResourceHandle::didSendBodyDataDelegateExists()) associateStreamWithResourceHandle([d->m_request.nsURLRequest() HTTPBodyStream], this); @@ -471,7 +488,7 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall if (!d->m_user.isNull() && !d->m_pass.isNull()) { NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:d->m_user password:d->m_pass - persistence:NSURLCredentialPersistenceNone]; + persistence:NSURLCredentialPersistenceForSession]; d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge(); d->m_currentWebChallenge = challenge; receivedCredential(challenge, core(credential)); @@ -482,6 +499,7 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall return; } +#ifndef BUILDING_ON_TIGER if (!challenge.previousFailureCount() && (!client() || client()->shouldUseCredentialStorage(this))) { Credential credential = CredentialStorage::get(challenge.protectionSpace()); if (!credential.isEmpty() && credential != d->m_initialCredential) { @@ -490,6 +508,7 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall return; } } +#endif d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge(); NSURLAuthenticationChallenge *webChallenge = [[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:d->m_currentMacChallenge @@ -521,11 +540,6 @@ void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge if (credential.persistence() == CredentialPersistenceNone) { // NSURLCredentialPersistenceNone doesn't work on Tiger, so we have to use session persistence. Credential webCredential(credential.user(), credential.password(), CredentialPersistenceForSession); - KURL urlToStore; - if (challenge.failureResponse().httpStatusCode() == 401) - urlToStore = d->m_request.url(); - CredentialStorage::set(webCredential, core([d->m_currentMacChallenge protectionSpace]), urlToStore); - [[d->m_currentMacChallenge sender] useCredential:mac(webCredential) forAuthenticationChallenge:d->m_currentMacChallenge]; } else #else @@ -620,6 +634,11 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen CallbackGuard guard; ResourceRequest request = newRequest; + + // Should not set Referer after a redirect from a secure resource to non-secure one. + if (!request.url().protocolIs("https") && protocolIs(request.httpReferrer(), "https")) + request.clearHTTPReferrer(); + m_handle->willSendRequest(request, redirectResponse); if (!ResourceHandle::didSendBodyDataDelegateExists()) { @@ -1055,7 +1074,7 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen // try and reuse the credential preemptively, as allowed by RFC 2617. ResourceRequest requestWithInitialCredentials = request; if (allowStoredCredentials && url.protocolInHTTPFamily()) - delegate->m_initialCredential = CredentialStorage::getDefaultAuthenticationCredential(url); + delegate->m_initialCredential = CredentialStorage::get(url); if (!delegate->m_initialCredential.isEmpty()) { String authHeader = "Basic " + encodeBasicAuthorization(delegate->m_initialCredential.user(), delegate->m_initialCredential.password()); diff --git a/WebCore/platform/network/mac/ResourceRequestMac.mm b/WebCore/platform/network/mac/ResourceRequestMac.mm index c4355b2..c2ad7d1 100644 --- a/WebCore/platform/network/mac/ResourceRequestMac.mm +++ b/WebCore/platform/network/mac/ResourceRequestMac.mm @@ -66,6 +66,7 @@ void ResourceRequest::doUpdateResourceRequest() NSDictionary *headers = [m_nsRequest.get() allHTTPHeaderFields]; NSEnumerator *e = [headers keyEnumerator]; NSString *name; + m_httpHeaderFields.clear(); while ((name = [e nextObject])) m_httpHeaderFields.set(name, [headers objectForKey:name]); @@ -114,7 +115,11 @@ void ResourceRequest::doUpdatePlatformRequest() if (!httpMethod().isEmpty()) [nsRequest setHTTPMethod:httpMethod()]; [nsRequest setHTTPShouldHandleCookies:allowCookies()]; - + + // Cannot just use setAllHTTPHeaderFields here, because it does not remove headers. + NSArray *oldHeaderFieldNames = [[nsRequest allHTTPHeaderFields] allKeys]; + for (unsigned i = [oldHeaderFieldNames count]; i != 0; --i) + [nsRequest setValue:nil forHTTPHeaderField:[oldHeaderFieldNames objectAtIndex:i - 1]]; HTTPHeaderMap::const_iterator end = httpHeaderFields().end(); for (HTTPHeaderMap::const_iterator it = httpHeaderFields().begin(); it != end; ++it) [nsRequest setValue:it->second forHTTPHeaderField:it->first]; diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index 7a3703d..ed5e024 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -112,23 +112,11 @@ qint64 FormDataIODevice::writeData(const char*, qint64) return -1; } -void FormDataIODevice::setParent(QNetworkReply* reply) -{ - QIODevice::setParent(reply); - - connect(reply, SIGNAL(finished()), SLOT(slotFinished()), Qt::QueuedConnection); -} - bool FormDataIODevice::isSequential() const { return true; } -void FormDataIODevice::slotFinished() -{ - deleteLater(); -} - QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode loadMode) : QObject(0) , m_reply(0) @@ -187,8 +175,8 @@ void QNetworkReplyHandler::abort() QNetworkReply* reply = release(); reply->abort(); reply->deleteLater(); - deleteLater(); } + deleteLater(); } QNetworkReply* QNetworkReplyHandler::release() @@ -200,6 +188,7 @@ QNetworkReply* QNetworkReplyHandler::release() // posted meta call events that were the result of a signal emission // don't reach the slots in our instance. QCoreApplication::removePostedEvents(this, QEvent::MetaCall); + m_reply->setParent(0); m_reply = 0; } return reply; diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.h b/WebCore/platform/network/qt/QNetworkReplyHandler.h index 545119e..fccc4a6 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.h +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.h @@ -96,16 +96,12 @@ public: FormDataIODevice(FormData*); ~FormDataIODevice(); - void setParent(QNetworkReply*); bool isSequential() const; protected: qint64 readData(char*, qint64); qint64 writeData(const char*, qint64); -private Q_SLOTS: - void slotFinished(); - private: void moveToNextElement(); diff --git a/WebCore/platform/qt/CursorQt.cpp b/WebCore/platform/qt/CursorQt.cpp index aad84be..3fc83f9 100644 --- a/WebCore/platform/qt/CursorQt.cpp +++ b/WebCore/platform/qt/CursorQt.cpp @@ -2,7 +2,7 @@ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> * Copyright (C) 2006 George Staikos <staikos@kde.org> * Copyright (C) 2006 Charles Samuels <charles@kde.org> - * Copyright (C) 2008 Holger Hans Peter Freyther + * Copyright (C) 2008, 2009 Holger Hans Peter Freyther * * All rights reserved. * @@ -92,14 +92,14 @@ protected: , SplitVCursor(Qt::SplitVCursor) , NoDropCursor(Qt::ForbiddenCursor) , BlankCursor(Qt::BlankCursor) - , ZoomInCursor(QPixmap(QLatin1String(":/webkit/resources/zoomInCursor.png"))) - , ZoomOutCursor(QPixmap(QLatin1String(":/webkit/resources/zoomOutCursor.png"))) - , VerticalTextCursor(QPixmap(QLatin1String(":/webkit/resources/verticalTextCursor.png"))) - , CellCursor(QPixmap(QLatin1String(":/webkit/resources/cellCursor.png"))) - , ContextMenuCursor(QPixmap(QLatin1String(":/webkit/resources/contextMenuCursor.png"))) - , CopyCursor(QPixmap(QLatin1String(":/webkit/resources/copyCursor.png"))) - , ProgressCursor(QPixmap(QLatin1String(":/webkit/resources/progressCursor.png"))) - , AliasCursor(QPixmap(QLatin1String(":/webkit/resources/aliasCursor.png"))) + , ZoomInCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/zoomInCursor.png")), 7, 7)) + , ZoomOutCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/zoomOutCursor.png")), 7, 7)) + , VerticalTextCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/verticalTextCursor.png")), 7, 7)) + , CellCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/cellCursor.png")), 7, 7)) + , ContextMenuCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/contextMenuCursor.png")), 3, 2)) + , CopyCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/copyCursor.png")), 3, 2)) + , ProgressCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/progressCursor.png")), 3, 2)) + , AliasCursor(QCursor(QPixmap(QLatin1String(":/webkit/resources/aliasCursor.png")), 11, 3)) #endif { diff --git a/WebCore/platform/qt/Localizations.cpp b/WebCore/platform/qt/Localizations.cpp index 77cac57..ca3ca9d 100644 --- a/WebCore/platform/qt/Localizations.cpp +++ b/WebCore/platform/qt/Localizations.cpp @@ -33,6 +33,7 @@ #include "PlatformString.h" #include <QCoreApplication> +#include <QLocale> namespace WebCore { @@ -53,7 +54,8 @@ String resetButtonDefaultLabel() String defaultLanguage() { - return "en"; + QLocale locale; + return locale.name().replace("_", "-"); } String searchableIndexIntroduction() diff --git a/WebCore/platform/qt/PlatformScreenQt.cpp b/WebCore/platform/qt/PlatformScreenQt.cpp index 7ba8350..8221760 100644 --- a/WebCore/platform/qt/PlatformScreenQt.cpp +++ b/WebCore/platform/qt/PlatformScreenQt.cpp @@ -62,7 +62,7 @@ int screenDepthPerComponent(Widget* w) QWebPageClient* client = w->root()->hostWindow()->platformPageClient(); if (client) { - QWidget* view = QWidget::find(client->winId()); + QWidget* view = client->ownerWidget(); if (view) return view->depth(); } diff --git a/WebCore/platform/qt/PopupMenuQt.cpp b/WebCore/platform/qt/PopupMenuQt.cpp index b44f2ec..f6ec4f7 100644 --- a/WebCore/platform/qt/PopupMenuQt.cpp +++ b/WebCore/platform/qt/PopupMenuQt.cpp @@ -92,7 +92,7 @@ void PopupMenu::show(const IntRect& r, FrameView* v, int index) rect.moveTopLeft(v->contentsToWindow(r.topLeft())); rect.setHeight(m_popup->sizeHint().height()); - m_popup->setParent(QWidget::find(client->winId())); + m_popup->setParent(client->ownerWidget()); m_popup->setGeometry(rect); m_popup->setCurrentIndex(index); m_popup->exec(); diff --git a/WebCore/platform/qt/QWebPageClient.h b/WebCore/platform/qt/QWebPageClient.h index 09f7886..28ef724 100644 --- a/WebCore/platform/qt/QWebPageClient.h +++ b/WebCore/platform/qt/QWebPageClient.h @@ -32,7 +32,10 @@ class QWebPageClient { public: virtual void scroll(int dx, int dy, const QRect&) = 0; virtual void update(const QRect&) = 0; - + virtual void setInputMethodEnabled(bool enable) = 0; +#if QT_VERSION >= 0x040600 + virtual void setInputMethodHint(Qt::InputMethodHint hint, bool enable) = 0; +#endif inline void resetCursor() { #ifndef QT_NO_CURSOR @@ -52,8 +55,9 @@ public: #endif } + virtual QPalette palette() const = 0; virtual int screenNumber() const = 0; - virtual WId winId() const = 0; + virtual QWidget* ownerWidget() const = 0; virtual QObject* pluginParent() const = 0; diff --git a/WebCore/platform/qt/WheelEventQt.cpp b/WebCore/platform/qt/WheelEventQt.cpp index 66118e1..9cc27ab 100644 --- a/WebCore/platform/qt/WheelEventQt.cpp +++ b/WebCore/platform/qt/WheelEventQt.cpp @@ -32,11 +32,11 @@ namespace WebCore { void PlatformWheelEvent::applyDelta(int delta, Qt::Orientation orientation) { if (orientation == Qt::Horizontal) { - m_deltaX = (delta / 120); + m_deltaX = (delta / 120.0f); m_deltaY = 0; } else { m_deltaX = 0; - m_deltaY = (delta / 120); + m_deltaY = (delta / 120.0f); } m_wheelTicksX = m_deltaX; diff --git a/WebCore/platform/sql/SQLiteDatabase.h b/WebCore/platform/sql/SQLiteDatabase.h index d313435..9982254 100644 --- a/WebCore/platform/sql/SQLiteDatabase.h +++ b/WebCore/platform/sql/SQLiteDatabase.h @@ -24,8 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLDatabase_h -#define SQLDatabase_h +#ifndef SQLiteDatabase_h +#define SQLiteDatabase_h #include "PlatformString.h" #include <wtf/Threading.h> diff --git a/WebCore/platform/text/AtomicString.cpp b/WebCore/platform/text/AtomicString.cpp index 409439e..17d7832 100644 --- a/WebCore/platform/text/AtomicString.cpp +++ b/WebCore/platform/text/AtomicString.cpp @@ -65,7 +65,9 @@ struct CStringTranslator { static void translate(StringImpl*& location, const char* const& c, unsigned hash) { - location = new StringImpl(c, strlen(c), hash); + location = StringImpl::create(c).releaseRef(); + location->setHash(hash); + location->setInTable(); } }; @@ -140,7 +142,9 @@ struct UCharBufferTranslator { static void translate(StringImpl*& location, const UCharBuffer& buf, unsigned hash) { - location = new StringImpl(buf.s, buf.length, hash); + location = StringImpl::create(buf.s, buf.length).releaseRef(); + location->setHash(hash); + location->setInTable(); } }; @@ -164,7 +168,9 @@ struct HashAndCharactersTranslator { static void translate(StringImpl*& location, const HashAndCharacters& buffer, unsigned hash) { - location = new StringImpl(buffer.characters, buffer.length, hash); + location = StringImpl::create(buffer.characters, buffer.length).releaseRef(); + location->setHash(hash); + location->setInTable(); } }; @@ -222,6 +228,16 @@ void AtomicString::remove(StringImpl* r) { stringTable().remove(r); } + +AtomicString AtomicString::lower() const +{ + // Note: This is a hot function in the Dromaeo benchmark. + StringImpl* impl = this->impl(); + RefPtr<StringImpl> newImpl = impl->lower(); + if (LIKELY(newImpl == impl)) + return *this; + return AtomicString(newImpl); +} #if USE(JSC) PassRefPtr<StringImpl> AtomicString::add(const JSC::Identifier& identifier) diff --git a/WebCore/platform/text/AtomicString.h b/WebCore/platform/text/AtomicString.h index 3307a2d..8805f4c 100644 --- a/WebCore/platform/text/AtomicString.h +++ b/WebCore/platform/text/AtomicString.h @@ -83,6 +83,9 @@ public: bool endsWith(const String& s, bool caseSensitive = true) const { return m_string.endsWith(s, caseSensitive); } + AtomicString lower() const; + AtomicString upper() const { return AtomicString(impl()->upper()); } + int toInt(bool* ok = 0) const { return m_string.toInt(ok); } double toDouble(bool* ok = 0) const { return m_string.toDouble(ok); } float toFloat(bool* ok = 0) const { return m_string.toFloat(ok); } diff --git a/WebCore/platform/text/String.cpp b/WebCore/platform/text/String.cpp index bef2674..44582a9 100644 --- a/WebCore/platform/text/String.cpp +++ b/WebCore/platform/text/String.cpp @@ -441,7 +441,7 @@ String String::number(unsigned long n) String String::number(long long n) { -#if PLATFORM(WIN_OS) +#if PLATFORM(WIN_OS) && !PLATFORM(QT) return String::format("%I64i", n); #else return String::format("%lli", n); @@ -450,7 +450,7 @@ String String::number(long long n) String String::number(unsigned long long n) { -#if PLATFORM(WIN_OS) +#if PLATFORM(WIN_OS) && !PLATFORM(QT) return String::format("%I64u", n); #else return String::format("%llu", n); diff --git a/WebCore/platform/text/StringImpl.cpp b/WebCore/platform/text/StringImpl.cpp index c3ab4be..5cf4ced 100644 --- a/WebCore/platform/text/StringImpl.cpp +++ b/WebCore/platform/text/StringImpl.cpp @@ -89,7 +89,7 @@ StringImpl::StringImpl() hash(); } -inline StringImpl::StringImpl(UChar* characters, unsigned length, AdoptBuffer) +inline StringImpl::StringImpl(const UChar* characters, unsigned length) : m_data(characters) , m_length(length) , m_hash(0) @@ -98,41 +98,6 @@ inline StringImpl::StringImpl(UChar* characters, unsigned length, AdoptBuffer) ASSERT(length); } -// This constructor is only for use by AtomicString. -StringImpl::StringImpl(const UChar* characters, unsigned length, unsigned hash) - : m_data(0) - , m_length(length) - , m_hash(hash) -{ - ASSERT(hash); - ASSERT(characters); - ASSERT(length); - - setInTable(); - UChar* data = newUCharVector(length); - memcpy(data, characters, length * sizeof(UChar)); - m_data = data; -} - -// This constructor is only for use by AtomicString. -StringImpl::StringImpl(const char* characters, unsigned length, unsigned hash) - : m_data(0) - , m_length(length) - , m_hash(hash) -{ - ASSERT(hash); - ASSERT(characters); - ASSERT(length); - - setInTable(); - UChar* data = newUCharVector(length); - for (unsigned i = 0; i != length; ++i) { - unsigned char c = characters[i]; - data[i] = c; - } - m_data = data; -} - StringImpl::~StringImpl() { if (inTable()) @@ -184,46 +149,38 @@ UChar32 StringImpl::characterStartingAt(unsigned i) return 0; } -bool StringImpl::isLower() +PassRefPtr<StringImpl> StringImpl::lower() { - // Do a faster loop for the case where all the characters are ASCII. - bool allLower = true; + // Note: This is a hot function in the Dromaeo benchmark, specifically the + // no-op code path up through the first 'return' statement. + + // First scan the string for uppercase and non-ASCII characters: UChar ored = 0; - for (unsigned i = 0; i < m_length; i++) { - UChar c = m_data[i]; - allLower = allLower && isASCIILower(c); - ored |= c; + bool noUpper = true; + const UChar *end = m_data + m_length; + for (const UChar* chp = m_data; chp != end; chp++) { + if (UNLIKELY(isASCIIUpper(*chp))) + noUpper = false; + ored |= *chp; } - if (!(ored & ~0x7F)) - return allLower; - - // Do a slower check for cases that include non-ASCII characters. - allLower = true; - unsigned i = 0; - while (i < m_length) { - UChar32 character; - U16_NEXT(m_data, i, m_length, character) - allLower = allLower && Unicode::isLower(character); - } - return allLower; -} + + // Nothing to do if the string is all ASCII with no uppercase. + if (noUpper && !(ored & ~0x7F)) + return this; -PassRefPtr<StringImpl> StringImpl::lower() -{ - UChar* data; - PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); int32_t length = m_length; + UChar* data; + RefPtr<StringImpl> newImpl = createUninitialized(m_length, data); - // Do a faster loop for the case where all the characters are ASCII. - UChar ored = 0; - for (int i = 0; i < length; i++) { - UChar c = m_data[i]; - ored |= c; - data[i] = toASCIILower(c); - } - if (!(ored & ~0x7F)) + if (!(ored & ~0x7F)) { + // Do a faster loop for the case where all the characters are ASCII. + for (int i = 0; i < length; i++) { + UChar c = m_data[i]; + data[i] = toASCIILower(c); + } return newImpl; - + } + // Do a slower implementation for cases that include non-ASCII characters. bool error; int32_t realLength = Unicode::toLower(data, length, m_data, m_length, &error); @@ -238,6 +195,9 @@ PassRefPtr<StringImpl> StringImpl::lower() PassRefPtr<StringImpl> StringImpl::upper() { + // This function could be optimized for no-op cases the way lower() is, + // but in empirical testing, few actual calls to upper() are no-ops, so + // it wouldn't be worth the extra time for pre-scanning. UChar* data; PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); int32_t length = m_length; @@ -322,6 +282,8 @@ PassRefPtr<StringImpl> StringImpl::stripWhiteSpace() while (end && isSpaceOrNewline(m_data[end])) end--; + if (!start && end == m_length - 1) + return this; return create(m_data + start, end + 1 - start); } @@ -364,12 +326,16 @@ PassRefPtr<StringImpl> StringImpl::simplifyWhiteSpace() const UChar* from = m_data; const UChar* fromend = from + m_length; int outc = 0; + bool changedToSpace = false; UChar* to = data.characters(); while (true) { - while (from != fromend && isSpaceOrNewline(*from)) + while (from != fromend && isSpaceOrNewline(*from)) { + if (*from != ' ') + changedToSpace = true; from++; + } while (from != fromend && !isSpaceOrNewline(*from)) to[outc++] = *from++; if (from != fromend) @@ -381,6 +347,9 @@ PassRefPtr<StringImpl> StringImpl::simplifyWhiteSpace() if (outc > 0 && to[outc - 1] == ' ') outc--; + if (static_cast<unsigned>(outc) == m_length && !changedToSpace) + return this; + data.shrink(outc); return adopt(data); @@ -933,7 +902,7 @@ PassRefPtr<StringImpl> StringImpl::adopt(StringBuffer& buffer) unsigned length = buffer.length(); if (length == 0) return empty(); - return adoptRef(new StringImpl(buffer.release(), length, AdoptBuffer())); + return adoptRef(new StringImpl(buffer.release(), length)); } PassRefPtr<StringImpl> StringImpl::adopt(Vector<UChar>& vector) @@ -941,7 +910,7 @@ PassRefPtr<StringImpl> StringImpl::adopt(Vector<UChar>& vector) size_t size = vector.size(); if (size == 0) return empty(); - return adoptRef(new StringImpl(vector.releaseBuffer(), size, AdoptBuffer())); + return adoptRef(new StringImpl(vector.releaseBuffer(), size)); } PassRefPtr<StringImpl> StringImpl::createUninitialized(unsigned length, UChar*& data) @@ -957,7 +926,7 @@ PassRefPtr<StringImpl> StringImpl::createUninitialized(unsigned length, UChar*& size_t size = sizeof(StringImpl) + length * sizeof(UChar); StringImpl* string = static_cast<StringImpl*>(fastMalloc(size)); data = reinterpret_cast<UChar*>(string + 1); - string = new (string) StringImpl(data, length, AdoptBuffer()); + string = new (string) StringImpl(data, length); return adoptRef(string); } @@ -998,7 +967,7 @@ 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(const_cast<UChar*>(str.data()), str.size(), AdoptBuffer())); + PassRefPtr<StringImpl> impl = adoptRef(new StringImpl(str.data(), str.size())); sharedBuffer->ref(); impl->m_sharedBufferAndFlags.set(sharedBuffer); return impl; @@ -1043,7 +1012,7 @@ PassRefPtr<StringImpl> StringImpl::crossThreadString() { SharedUChar* shared = sharedBuffer(); if (shared) { - RefPtr<StringImpl> impl = adoptRef(new StringImpl(const_cast<UChar*>(m_data), m_length, AdoptBuffer())); + RefPtr<StringImpl> impl = adoptRef(new StringImpl(m_data, m_length)); impl->m_sharedBufferAndFlags.set(shared->crossThreadCopy().releaseRef()); return impl.release(); } diff --git a/WebCore/platform/text/StringImpl.h b/WebCore/platform/text/StringImpl.h index f3256cc..dac25b2 100644 --- a/WebCore/platform/text/StringImpl.h +++ b/WebCore/platform/text/StringImpl.h @@ -47,7 +47,6 @@ typedef const struct __CFString * CFStringRef; namespace WebCore { -class AtomicString; class StringBuffer; struct CStringTranslator; @@ -60,21 +59,19 @@ enum TextCaseSensitivity { TextCaseSensitive, TextCaseInsensitive }; typedef bool (*CharacterMatchFunctionPtr)(UChar); class StringImpl : public RefCounted<StringImpl> { - friend class AtomicString; friend struct CStringTranslator; friend struct HashAndCharactersTranslator; friend struct UCharBufferTranslator; private: friend class ThreadGlobalData; StringImpl(); + + // This adopts the UChar* without copying the buffer. + StringImpl(const UChar*, unsigned length); - struct AdoptBuffer { }; - StringImpl(UChar*, unsigned length, AdoptBuffer); - - // For AtomicString. - StringImpl(const UChar*, unsigned length, unsigned hash); - StringImpl(const char*, unsigned length, unsigned hash); - + // For use only by AtomicString's XXXTranslator helpers. + void setHash(unsigned hash) { ASSERT(!m_hash); m_hash = hash; } + typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar; public: @@ -138,7 +135,6 @@ public: double toDouble(bool* ok = 0); float toFloat(bool* ok = 0); - bool isLower(); PassRefPtr<StringImpl> lower(); PassRefPtr<StringImpl> upper(); PassRefPtr<StringImpl> secure(UChar aChar); diff --git a/WebCore/platform/text/TextEncodingRegistry.cpp b/WebCore/platform/text/TextEncodingRegistry.cpp index 5d82511..d3e2965 100644 --- a/WebCore/platform/text/TextEncodingRegistry.cpp +++ b/WebCore/platform/text/TextEncodingRegistry.cpp @@ -129,6 +129,10 @@ static TextEncodingNameMap* textEncodingNameMap; static TextCodecMap* textCodecMap; static bool didExtendTextCodecMaps; +static const char* const textEncodingNameBlacklist[] = { + "UTF-7" +}; + #if ERROR_DISABLED static inline void checkExistingName(const char*, const char*) { } @@ -171,6 +175,30 @@ static void addToTextCodecMap(const char* name, NewTextCodecFunction function, c textCodecMap->add(atomicName, TextCodecFactory(function, additionalData)); } +static void pruneBlacklistedCodecs() +{ + size_t blacklistedCodecListLength = sizeof(textEncodingNameBlacklist) / sizeof(textEncodingNameBlacklist[0]); + for (size_t i = 0; i < blacklistedCodecListLength; ++i) { + const char* atomicName = textEncodingNameMap->get(textEncodingNameBlacklist[i]); + if (!atomicName) + continue; + + Vector<const char*> names; + TextEncodingNameMap::const_iterator it = textEncodingNameMap->begin(); + TextEncodingNameMap::const_iterator end = textEncodingNameMap->end(); + for (; it != end; ++it) { + if (it->second == atomicName) + names.append(it->first); + } + + size_t length = names.size(); + for (size_t j = 0; j < length; ++j) + textEncodingNameMap->remove(names[j]); + + textCodecMap->remove(atomicName); + } +} + static void buildBaseTextCodecMaps() { ASSERT(isMainThread()); @@ -221,6 +249,8 @@ static void extendTextCodecMaps() TextCodecWince::registerExtendedEncodingNames(addToTextEncodingNameMap); TextCodecWince::registerExtendedCodecs(addToTextCodecMap); #endif + + pruneBlacklistedCodecs(); } PassOwnPtr<TextCodec> newTextCodec(const TextEncoding& encoding) diff --git a/WebCore/platform/win/ClipboardWin.cpp b/WebCore/platform/win/ClipboardWin.cpp index b2e8e3e..b75ce46 100644 --- a/WebCore/platform/win/ClipboardWin.cpp +++ b/WebCore/platform/win/ClipboardWin.cpp @@ -577,8 +577,32 @@ HashSet<String> ClipboardWin::types() const PassRefPtr<FileList> ClipboardWin::files() const { - notImplemented(); - return 0; + RefPtr<FileList> files = FileList::create(); + if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable) + return files.release(); + + if (!m_dataObject) + return files.release(); + + STGMEDIUM medium; + if (FAILED(m_dataObject->GetData(cfHDropFormat(), &medium))) + return files.release(); + + HDROP hdrop = reinterpret_cast<HDROP>(GlobalLock(medium.hGlobal)); + if (!hdrop) + return files.release(); + + WCHAR filename[MAX_PATH]; + UINT fileCount = DragQueryFileW(hdrop, 0xFFFFFFFF, 0, 0); + for (UINT i = 0; i < fileCount; i++) { + if (!DragQueryFileW(hdrop, i, filename, ARRAYSIZE(filename))) + continue; + files->append(File::create(reinterpret_cast<UChar*>(filename))); + } + + GlobalUnlock(medium.hGlobal); + ReleaseStgMedium(&medium); + return files.release(); } void ClipboardWin::setDragImage(CachedImage* image, Node *node, const IntPoint &loc) diff --git a/WebCore/platform/win/ScrollbarThemeSafari.cpp b/WebCore/platform/win/ScrollbarThemeSafari.cpp index 06a6533..4e979f2 100644 --- a/WebCore/platform/win/ScrollbarThemeSafari.cpp +++ b/WebCore/platform/win/ScrollbarThemeSafari.cpp @@ -73,7 +73,7 @@ static int cButtonHitInset[] = { 3, 2 }; static int cButtonLength[] = { 14, 10 }; static int cThumbMinLength[] = { 26, 20 }; -#if !defined(NDEBUG) && defined(USE_DEBUG_SAFARI_THEME) +#ifdef DEBUG_ALL SOFT_LINK_DEBUG_LIBRARY(SafariTheme) #else SOFT_LINK_LIBRARY(SafariTheme) diff --git a/WebCore/platform/wx/wxcode/mac/carbon/fontprops.cpp b/WebCore/platform/wx/wxcode/mac/carbon/fontprops.cpp index 653f142..23dea6b 100644 --- a/WebCore/platform/wx/wxcode/mac/carbon/fontprops.cpp +++ b/WebCore/platform/wx/wxcode/mac/carbon/fontprops.cpp @@ -30,6 +30,7 @@ #include <wx/defs.h> #include <wx/gdicmn.h> +#include <wx/graphics.h> #ifdef BUILDING_ON_TIGER void (*wkGetFontMetrics)(CGFontRef, int* ascent, int* descent, int* lineGap, unsigned* unitsPerEm); @@ -91,98 +92,21 @@ m_ascent(0), m_descent(0), m_lineGap(0), m_lineSpacing(0), m_xHeight(0) void GetTextExtent( const wxFont& font, const wxString& str, wxCoord *width, wxCoord *height, wxCoord *descent, wxCoord *externalLeading ) { - ATSUStyle* ATSUIStyle; - - if ( font.Ok() ) + wxGraphicsContext * const gc = wxGraphicsContext::Create(); + gc->SetFont(font, *wxBLACK); // colour doesn't matter but must be specified + struct GCTextExtent { - OSStatus status ; - - status = ATSUCreateAndCopyStyle( (ATSUStyle) font.MacGetATSUStyle() , (ATSUStyle*) &ATSUIStyle ) ; - - wxASSERT_MSG( status == noErr, wxT("couldn't create ATSU style") ) ; - - // we need the scale here ... - - Fixed atsuSize = IntToFixed( int( /*m_scaleY*/ 1 * font.GetPointSize()) ) ; - //RGBColor atsuColor = MAC_WXCOLORREF( m_textForegroundColor.GetPixel() ) ; - ATSUAttributeTag atsuTags[] = - { - kATSUSizeTag //, - // kATSUColorTag , - } ; - ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] = - { - sizeof( Fixed ) //, - // sizeof( RGBColor ) , - } ; - ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] = - { - &atsuSize //, - // &atsuColor , - } ; - - status = ::ATSUSetAttributes( - (ATSUStyle)ATSUIStyle, sizeof(atsuTags) / sizeof(ATSUAttributeTag) , - atsuTags, atsuSizes, atsuValues); - - wxASSERT_MSG( status == noErr , wxT("couldn't modify ATSU style") ) ; - } - - wxCHECK_RET( ATSUIStyle != NULL, wxT("GetTextExtent - no valid font set") ) ; - - OSStatus status = noErr ; - - ATSUTextLayout atsuLayout ; - UniCharCount chars = str.length() ; - UniChar* ubuf = NULL ; - -#if SIZEOF_WCHAR_T == 4 - wxMBConvUTF16 converter ; -#if wxUSE_UNICODE - size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 ) ; - ubuf = (UniChar*) malloc( unicharlen + 2 ) ; - converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 ) ; -#else - const wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ; - size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ; - ubuf = (UniChar*) malloc( unicharlen + 2 ) ; - converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ; -#endif - chars = unicharlen / 2 ; -#else -#if wxUSE_UNICODE - ubuf = (UniChar*) str.wc_str() ; -#else - wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ; - chars = wxWcslen( wchar.data() ) ; - ubuf = (UniChar*) wchar.data() ; -#endif -#endif - - status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 , - &chars , (ATSUStyle*) &ATSUIStyle , &atsuLayout ) ; - - wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") ); - - ATSUTextMeasurement textBefore, textAfter ; - ATSUTextMeasurement textAscent, textDescent ; - - status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd, - &textBefore , &textAfter, &textAscent , &textDescent ); - + wxDouble width, height, descent, externalLeading; + } e; + gc->GetTextExtent(str, &e.width, &e.height, &e.descent, &e.externalLeading); + if ( width ) + *width = wxCoord(e.width + .5); if ( height ) - *height = FixedToInt(textAscent + textDescent) ; + *height = wxCoord(e.height + .5); if ( descent ) - *descent = FixedToInt(textDescent) ; + *descent = wxCoord(e.descent + .5); if ( externalLeading ) - *externalLeading = 0 ; - if ( width ) - *width = FixedToInt(textAfter - textBefore) ; - -#if SIZEOF_WCHAR_T == 4 - free( ubuf ) ; -#endif + *externalLeading = wxCoord(e.externalLeading + .5); - ::ATSUDisposeTextLayout(atsuLayout); - ::ATSUDisposeStyle((ATSUStyle)ATSUIStyle); + delete gc; } |