diff options
author | Kristian Monsen <kristianm@google.com> | 2010-09-30 15:42:16 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2010-10-07 10:59:29 +0100 |
commit | bec39347bb3bb5bf1187ccaf471d26247f28b585 (patch) | |
tree | 56bdc4c2978fbfd3d79d0d36d5d6c640ecc09cc8 /WebCore/platform | |
parent | 90b7966e7815b262cd19ac25f03aaad9b21fdc06 (diff) | |
download | external_webkit-bec39347bb3bb5bf1187ccaf471d26247f28b585.zip external_webkit-bec39347bb3bb5bf1187ccaf471d26247f28b585.tar.gz external_webkit-bec39347bb3bb5bf1187ccaf471d26247f28b585.tar.bz2 |
Merge WebKit at r68651 : Initial merge by git.
Change-Id: I3d6bff59f17eedd6722723354f386fec9be8ad12
Diffstat (limited to 'WebCore/platform')
234 files changed, 9964 insertions, 2336 deletions
diff --git a/WebCore/platform/AsyncFileSystem.cpp b/WebCore/platform/AsyncFileSystem.cpp index b4fcd0d..57305ff 100644 --- a/WebCore/platform/AsyncFileSystem.cpp +++ b/WebCore/platform/AsyncFileSystem.cpp @@ -35,12 +35,20 @@ #include "AsyncFileSystemCallbacks.h" #include "FileSystem.h" +#include "NotImplemented.h" namespace WebCore { +#if !PLATFORM(CHROMIUM) +bool AsyncFileSystem::isAvailable() +{ + notImplemented(); + return false; +} + PassOwnPtr<AsyncFileSystem> AsyncFileSystem::create(const String&) { - // FIXME: return default AsyncFileSystem implementation. + notImplemented(); return 0; } @@ -62,6 +70,7 @@ void AsyncFileSystem::openFileSystem(const String& basePath, const String& stora callbacks->didOpenFileSystem(name, AsyncFileSystem::create(rootPath)); } +#endif // Default implementation. String AsyncFileSystem::virtualToPlatformPath(const String& path) const diff --git a/WebCore/platform/AsyncFileSystem.h b/WebCore/platform/AsyncFileSystem.h index 601f0ea..1bf7580 100644 --- a/WebCore/platform/AsyncFileSystem.h +++ b/WebCore/platform/AsyncFileSystem.h @@ -41,6 +41,7 @@ namespace WebCore { class AsyncFileSystem; class AsyncFileSystemCallbacks; +class AsyncFileWriterClient; // This class provides async interface for platform-specific file system implementation. Note that all the methods take platform paths. class AsyncFileSystem : public Noncopyable { @@ -56,6 +57,8 @@ public: virtual void stop() { } virtual bool hasPendingActivity() { return false; } + static bool isAvailable(); + // Creates and returns a new platform-specific AsyncFileSystem instance if the platform has its own implementation. static PassOwnPtr<AsyncFileSystem> create(const String& rootPath); @@ -107,6 +110,11 @@ public: // AsyncFileSystemCallbacks::didFail() is when there is an error. virtual void readDirectory(const String& path, PassOwnPtr<AsyncFileSystemCallbacks>) = 0; + // Creates an AsyncFileWriter for a given file path. + // AsyncFileSystemCallbacks::didCreateFileWriter() is called when an AsyncFileWriter is created successfully. + // AsyncFileSystemCallbacks::didFail() is called otherwise. + virtual void createWriter(AsyncFileWriterClient* client, const String& path, PassOwnPtr<AsyncFileSystemCallbacks>) = 0; + // Converts a given absolute virtual path to a platform path that starts with the platform root path of this file system. virtual String virtualToPlatformPath(const String& path) const; diff --git a/WebCore/platform/AsyncFileSystemCallbacks.h b/WebCore/platform/AsyncFileSystemCallbacks.h index 0547fad..451aead 100644 --- a/WebCore/platform/AsyncFileSystemCallbacks.h +++ b/WebCore/platform/AsyncFileSystemCallbacks.h @@ -38,6 +38,7 @@ namespace WebCore { class AsyncFileSystem; +class AsyncFileWriter; class AsyncFileSystemCallbacks : public Noncopyable { public: @@ -56,6 +57,9 @@ public: // Called after a chunk of directory entries have been read (i.e. indicates it's good time to call back to the application). If hasMore is true there can be more chunks. virtual void didReadDirectoryEntries(bool hasMore) = 0; + // Called when an AsyncFileWrter has been created successfully. + virtual void didCreateFileWriter(PassOwnPtr<AsyncFileWriter> writer, long long length) = 0; + // Called when there was an error. virtual void didFail(int code) = 0; diff --git a/WebCore/platform/ColorData.gperf b/WebCore/platform/ColorData.gperf index 11ef798..dd726cc 100644 --- a/WebCore/platform/ColorData.gperf +++ b/WebCore/platform/ColorData.gperf @@ -1,15 +1,13 @@ %struct-type -struct NamedColor { - const char *name; - int RGBValue; -}; -%language=ANSI-C +struct NamedColor; +%omit-struct-type +%language=C++ %readonly-tables %global-table %compare-strncmp -%define lookup-function-name findColor +%define class-name ColorDataHash +%define lookup-function-name findColorImpl %define hash-function-name colordata_hash_function -%includes %enum %% aliceblue, 0xf0f8ff diff --git a/WebCore/platform/ContextMenu.cpp b/WebCore/platform/ContextMenu.cpp index 37d4c2b..ca1f719 100644 --- a/WebCore/platform/ContextMenu.cpp +++ b/WebCore/platform/ContextMenu.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * Copyright (C) 2008 Christian Dywan <christian@imendio.com> + * Copyright (C) 2010 Igalia S.L * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -282,6 +283,19 @@ void ContextMenu::populate() contextMenuItemTagDownloadImageToDisk()); ContextMenuItem CopyImageItem(ActionType, ContextMenuItemTagCopyImageToClipboard, contextMenuItemTagCopyImageToClipboard()); + ContextMenuItem OpenMediaInNewWindowItem(ActionType, ContextMenuItemTagOpenMediaInNewWindow, String()); + ContextMenuItem CopyMediaLinkItem(ActionType, ContextMenuItemTagCopyMediaLinkToClipboard, + String()); + ContextMenuItem MediaPlayPause(ActionType, ContextMenuItemTagMediaPlayPause, + contextMenuItemTagMediaPlay()); + ContextMenuItem MediaMute(ActionType, ContextMenuItemTagMediaMute, + contextMenuItemTagMediaMute()); + ContextMenuItem ToggleMediaControls(CheckableActionType, ContextMenuItemTagToggleMediaControls, + contextMenuItemTagToggleMediaControls()); + ContextMenuItem ToggleMediaLoop(CheckableActionType, ContextMenuItemTagToggleMediaLoop, + contextMenuItemTagToggleMediaLoop()); + ContextMenuItem EnterVideoFullscreen(ActionType, ContextMenuItemTagEnterVideoFullscreen, + contextMenuItemTagEnterVideoFullscreen()); #if PLATFORM(MAC) ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight, contextMenuItemTagSearchInSpotlight()); @@ -349,7 +363,23 @@ void ContextMenu::populate() appendItem(CopyImageItem); } - if (imageURL.isEmpty() && linkURL.isEmpty()) { + KURL mediaURL = result.absoluteMediaURL(); + if (!mediaURL.isEmpty()) { + if (!linkURL.isEmpty() || !imageURL.isEmpty()) + appendItem(*separatorItem()); + + appendItem(MediaPlayPause); + appendItem(MediaMute); + appendItem(ToggleMediaControls); + appendItem(ToggleMediaLoop); + appendItem(EnterVideoFullscreen); + + appendItem(*separatorItem()); + appendItem(CopyMediaLinkItem); + appendItem(OpenMediaInNewWindowItem); + } + + if (imageURL.isEmpty() && linkURL.isEmpty() && mediaURL.isEmpty()) { if (result.isSelected()) { if (selectionContainsPossibleWord(frame)) { #if PLATFORM(MAC) @@ -375,12 +405,6 @@ void ContextMenu::populate() #if ENABLE(INSPECTOR) if (!(frame->page() && frame->page()->inspectorController()->hasInspectorFrontendClient())) { #endif -#if PLATFORM(GTK) - appendItem(BackItem); - appendItem(ForwardItem); - appendItem(StopItem); - appendItem(ReloadItem); -#else if (frame->page() && frame->page()->canGoBackOrForward(-1)) appendItem(BackItem); @@ -393,7 +417,6 @@ void ContextMenu::populate() appendItem(StopItem); else appendItem(ReloadItem); -#endif #if ENABLE(INSPECTOR) } #endif @@ -788,6 +811,28 @@ void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const case ContextMenuItemTagOpenImageInNewWindow: case ContextMenuItemTagDownloadImageToDisk: case ContextMenuItemTagCopyImageToClipboard: + break; + case ContextMenuItemTagOpenMediaInNewWindow: + if (m_hitTestResult.mediaIsVideo()) + item.setTitle(contextMenuItemTagOpenVideoInNewWindow()); + else + item.setTitle(contextMenuItemTagOpenAudioInNewWindow()); + break; + case ContextMenuItemTagCopyMediaLinkToClipboard: + if (m_hitTestResult.mediaIsVideo()) + item.setTitle(contextMenuItemTagCopyVideoLinkToClipboard()); + else + item.setTitle(contextMenuItemTagCopyAudioLinkToClipboard()); + break; + case ContextMenuItemTagToggleMediaControls: + shouldCheck = m_hitTestResult.mediaControlsEnabled(); + break; + case ContextMenuItemTagToggleMediaLoop: + shouldCheck = m_hitTestResult.mediaLoopEnabled(); + break; + case ContextMenuItemTagEnterVideoFullscreen: + shouldEnable = m_hitTestResult.mediaSupportsFullscreen(); + break; case ContextMenuItemTagOpenFrameInNewWindow: case ContextMenuItemTagSpellingGuess: case ContextMenuItemTagOther: @@ -823,6 +868,16 @@ void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const case ContextMenuItemLastCustomTag: case ContextMenuItemBaseApplicationTag: break; + case ContextMenuItemTagMediaPlayPause: + if (m_hitTestResult.mediaPlaying()) + item.setTitle(contextMenuItemTagMediaPause()); + else + item.setTitle(contextMenuItemTagMediaPlay()); + break; + case ContextMenuItemTagMediaMute: + shouldEnable = m_hitTestResult.mediaHasAudio(); + shouldCheck = shouldEnable && m_hitTestResult.mediaMuted(); + break; } item.setChecked(shouldCheck); diff --git a/WebCore/platform/ContextMenuItem.h b/WebCore/platform/ContextMenuItem.h index 3731e24..ee9d2a3 100644 --- a/WebCore/platform/ContextMenuItem.h +++ b/WebCore/platform/ContextMenuItem.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2010 Igalia S.L * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -143,6 +144,13 @@ namespace WebCore { ContextMenuItemTagCapitalize, ContextMenuItemTagChangeBack, #endif + ContextMenuItemTagOpenMediaInNewWindow, + ContextMenuItemTagCopyMediaLinkToClipboard, + ContextMenuItemTagToggleMediaControls, + ContextMenuItemTagToggleMediaLoop, + ContextMenuItemTagEnterVideoFullscreen, + ContextMenuItemTagMediaPlayPause, + ContextMenuItemTagMediaMute, ContextMenuItemBaseCustomTag = 5000, ContextMenuItemCustomTagNoAction = 5998, ContextMenuItemLastCustomTag = 5999, diff --git a/WebCore/platform/Cursor.cpp b/WebCore/platform/Cursor.cpp index 3f17ad9..dac5c24 100644 --- a/WebCore/platform/Cursor.cpp +++ b/WebCore/platform/Cursor.cpp @@ -253,12 +253,16 @@ Cursor::Cursor(Type type) { } +#if !PLATFORM(MAC) + PlatformCursor Cursor::platformCursor() const { ensurePlatformCursor(); return m_platformCursor; } +#endif + const Cursor& pointerCursor() { DEFINE_STATIC_LOCAL(Cursor, c, (Cursor::Pointer)); diff --git a/WebCore/platform/Cursor.h b/WebCore/platform/Cursor.h index 92d3596..a962bbb 100644 --- a/WebCore/platform/Cursor.h +++ b/WebCore/platform/Cursor.h @@ -35,6 +35,8 @@ typedef struct HICON__* HICON; typedef HICON HCURSOR; #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> +#elif PLATFORM(MAC) +#include <wtf/RetainPtr.h> #elif PLATFORM(GTK) #include "GRefPtrGtk.h" #elif PLATFORM(QT) @@ -82,7 +84,7 @@ namespace WebCore { }; typedef RefPtr<SharedCursor> PlatformCursor; #elif PLATFORM(MAC) - typedef NSCursor* PlatformCursor; + typedef NSCursor *PlatformCursor; #elif PLATFORM(GTK) typedef PlatformRefPtr<GdkCursor> PlatformCursor; #elif PLATFORM(EFL) @@ -183,7 +185,11 @@ namespace WebCore { IntPoint m_hotSpot; #endif +#if !PLATFORM(MAC) mutable PlatformCursor m_platformCursor; +#else + mutable RetainPtr<NSCursor> m_platformCursor; +#endif }; IntPoint determineHotSpot(Image*, const IntPoint& specifiedHotSpot); diff --git a/WebCore/platform/LocalizationStrategy.h b/WebCore/platform/LocalizationStrategy.h index 178cfa2..1fe138a 100644 --- a/WebCore/platform/LocalizationStrategy.h +++ b/WebCore/platform/LocalizationStrategy.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Igalia S.L * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -112,6 +113,16 @@ public: virtual String contextMenuItemTagCapitalize() = 0; virtual String contextMenuItemTagChangeBack(const String& replacedString) = 0; #endif + virtual String contextMenuItemTagOpenVideoInNewWindow() = 0; + virtual String contextMenuItemTagOpenAudioInNewWindow() = 0; + virtual String contextMenuItemTagCopyVideoLinkToClipboard() = 0; + virtual String contextMenuItemTagCopyAudioLinkToClipboard() = 0; + virtual String contextMenuItemTagToggleMediaControls() = 0; + virtual String contextMenuItemTagToggleMediaLoop() = 0; + virtual String contextMenuItemTagEnterVideoFullscreen() = 0; + virtual String contextMenuItemTagMediaPlay() = 0; + virtual String contextMenuItemTagMediaPause() = 0; + virtual String contextMenuItemTagMediaMute() = 0; virtual String contextMenuItemTagInspectElement() = 0; #endif // ENABLE(CONTEXT_MENUS) diff --git a/WebCore/platform/LocalizedStrings.cpp b/WebCore/platform/LocalizedStrings.cpp index a69e0fb..012d90e 100644 --- a/WebCore/platform/LocalizedStrings.cpp +++ b/WebCore/platform/LocalizedStrings.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2003, 2006, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Igalia S.L * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -362,6 +363,56 @@ String contextMenuItemTagChangeBack(const String& replacedString) } #endif // PLATFORM(MAC) + +String contextMenuItemTagOpenVideoInNewWindow() +{ + return platformStrategies()->localizationStrategy()->contextMenuItemTagOpenVideoInNewWindow(); +} + +String contextMenuItemTagOpenAudioInNewWindow() +{ + return platformStrategies()->localizationStrategy()->contextMenuItemTagOpenAudioInNewWindow(); +} + +String contextMenuItemTagCopyVideoLinkToClipboard() +{ + return platformStrategies()->localizationStrategy()->contextMenuItemTagCopyVideoLinkToClipboard(); +} + +String contextMenuItemTagCopyAudioLinkToClipboard() +{ + return platformStrategies()->localizationStrategy()->contextMenuItemTagCopyAudioLinkToClipboard(); +} + +String contextMenuItemTagToggleMediaControls() +{ + return platformStrategies()->localizationStrategy()->contextMenuItemTagToggleMediaControls(); +} + +String contextMenuItemTagToggleMediaLoop() +{ + return platformStrategies()->localizationStrategy()->contextMenuItemTagToggleMediaLoop(); +} + +String contextMenuItemTagEnterVideoFullscreen() +{ + return platformStrategies()->localizationStrategy()->contextMenuItemTagEnterVideoFullscreen(); +} + +String contextMenuItemTagMediaPlay() +{ + return platformStrategies()->localizationStrategy()->contextMenuItemTagMediaPlay(); +} + +String contextMenuItemTagMediaPause() +{ + return platformStrategies()->localizationStrategy()->contextMenuItemTagMediaPause(); +} + +String contextMenuItemTagMediaMute() +{ + return platformStrategies()->localizationStrategy()->contextMenuItemTagMediaMute(); +} String contextMenuItemTagInspectElement() { diff --git a/WebCore/platform/LocalizedStrings.h b/WebCore/platform/LocalizedStrings.h index 04042b6..a72eb8a 100644 --- a/WebCore/platform/LocalizedStrings.h +++ b/WebCore/platform/LocalizedStrings.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2003, 2006, 2009 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2010 Igalia S.L * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -108,6 +109,16 @@ namespace WebCore { String contextMenuItemTagCapitalize(); String contextMenuItemTagChangeBack(const String& replacedString); #endif + String contextMenuItemTagOpenVideoInNewWindow(); + String contextMenuItemTagOpenAudioInNewWindow(); + String contextMenuItemTagCopyVideoLinkToClipboard(); + String contextMenuItemTagCopyAudioLinkToClipboard(); + String contextMenuItemTagToggleMediaControls(); + String contextMenuItemTagToggleMediaLoop(); + String contextMenuItemTagEnterVideoFullscreen(); + String contextMenuItemTagMediaPlay(); + String contextMenuItemTagMediaPause(); + String contextMenuItemTagMediaMute(); String contextMenuItemTagInspectElement(); #endif // ENABLE(CONTEXT_MENUS) diff --git a/WebCore/platform/PlatformTouchEvent.h b/WebCore/platform/PlatformTouchEvent.h index 19cb8e9..f8d503d 100644 --- a/WebCore/platform/PlatformTouchEvent.h +++ b/WebCore/platform/PlatformTouchEvent.h @@ -35,6 +35,12 @@ QT_END_NAMESPACE #include "IntPoint.h" #endif +#if PLATFORM(BREWMP) +typedef unsigned short uint16; +typedef unsigned long int uint32; +#define AEEEvent uint16 +#endif + namespace WebCore { enum TouchEventType { @@ -61,6 +67,11 @@ public: PlatformTouchEvent(QTouchEvent*); #elif PLATFORM(ANDROID) PlatformTouchEvent(const Vector<IntPoint>&, TouchEventType, PlatformTouchPoint::State, int metaState); +<<<<<<< HEAD +======= +#elif PLATFORM(BREWMP) + PlatformTouchEvent(AEEEvent, uint16 wParam, uint32 dwParam); +>>>>>>> webkit.org at r68651 #endif TouchEventType type() const { return m_type; } diff --git a/WebCore/platform/PlatformTouchPoint.h b/WebCore/platform/PlatformTouchPoint.h index 4b8ebae..f330eb6 100644 --- a/WebCore/platform/PlatformTouchPoint.h +++ b/WebCore/platform/PlatformTouchPoint.h @@ -48,6 +48,11 @@ public: PlatformTouchPoint() {}; #elif PLATFORM(ANDROID) PlatformTouchPoint(unsigned id, const IntPoint& windowPos, State); +<<<<<<< HEAD +======= +#elif PLATFORM(BREWMP) + PlatformTouchPoint(int id, const IntPoint& windowPos, State); +>>>>>>> webkit.org at r68651 #endif unsigned id() const { return m_id; } diff --git a/WebCore/platform/ScrollView.cpp b/WebCore/platform/ScrollView.cpp index 0273807..0e95e22 100644 --- a/WebCore/platform/ScrollView.cpp +++ b/WebCore/platform/ScrollView.cpp @@ -383,6 +383,14 @@ bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity return false; } +void ScrollView::windowResizerRectChanged() +{ + if (platformWidget()) + return; + + updateScrollbars(scrollOffset()); +} + static const unsigned cMaxUpdateScrollbarsPass = 2; void ScrollView::updateScrollbars(const IntSize& desiredOffset) diff --git a/WebCore/platform/ScrollView.h b/WebCore/platform/ScrollView.h index 751b276..1744963 100644 --- a/WebCore/platform/ScrollView.h +++ b/WebCore/platform/ScrollView.h @@ -195,6 +195,8 @@ public: virtual IntRect windowResizerRect() const { return IntRect(); } bool containsScrollbarsAvoidingResizer() const; void adjustScrollbarsAvoidingResizerCount(int overlapDelta); + void windowResizerRectChanged(); + virtual void setParent(ScrollView*); // Overridden to update the overlapping scrollbar count. // Called when our frame rect changes (or the rect/scroll position of an ancestor changes). diff --git a/WebCore/platform/Scrollbar.cpp b/WebCore/platform/Scrollbar.cpp index 398584a..72f0639 100644 --- a/WebCore/platform/Scrollbar.cpp +++ b/WebCore/platform/Scrollbar.cpp @@ -40,7 +40,7 @@ using namespace std; -#if PLATFORM(CHROMIUM) && OS(LINUX) || PLATFORM(GTK) +#if (PLATFORM(CHROMIUM) && (OS(LINUX) || OS(FREEBSD))) || PLATFORM(GTK) // The position of the scrollbar thumb affects the appearance of the steppers, so // when the thumb moves, we have to invalidate them for painting. #define THUMB_POSITION_AFFECTS_BUTTONS diff --git a/WebCore/platform/Widget.cpp b/WebCore/platform/Widget.cpp index 1370863..05a5237 100644 --- a/WebCore/platform/Widget.cpp +++ b/WebCore/platform/Widget.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -127,6 +127,7 @@ IntPoint Widget::convertFromContainingWindowToRoot(const Widget*, const IntPoint } #endif +<<<<<<< HEAD #if !PLATFORM(MAC) && !PLATFORM(GTK) && !OS(ANDROID) void Widget::releasePlatformWidget() { @@ -137,6 +138,8 @@ void Widget::retainPlatformWidget() } #endif +======= +>>>>>>> webkit.org at r68651 IntRect Widget::convertToContainingView(const IntRect& localRect) const { if (const ScrollView* parentScrollView = parent()) { diff --git a/WebCore/platform/Widget.h b/WebCore/platform/Widget.h index 58d4e57..90d38a9 100644 --- a/WebCore/platform/Widget.h +++ b/WebCore/platform/Widget.h @@ -27,6 +27,22 @@ #ifndef Widget_h #define Widget_h +#include "IntRect.h" +#include <wtf/Forward.h> +#include <wtf/RefCounted.h> + +#if PLATFORM(CHROMIUM) +#include "PlatformWidget.h" +#endif + +#if PLATFORM(MAC) +#include <wtf/RetainPtr.h> +#endif + +#if PLATFORM(QT) +#include <qglobal.h> +#endif + #if PLATFORM(MAC) #ifdef __OBJC__ @class NSView; @@ -35,7 +51,7 @@ class NSView; class NSWindow; #endif -typedef NSView* PlatformWidget; +typedef NSView *PlatformWidget; #endif #if PLATFORM(ANDROID) @@ -56,7 +72,6 @@ typedef GtkWidget* PlatformWidget; #endif #if PLATFORM(QT) -#include <qglobal.h> QT_BEGIN_NAMESPACE class QWidget; QT_END_NAMESPACE @@ -77,10 +92,6 @@ typedef BView* PlatformWidget; typedef void* PlatformWidget; #endif -#if PLATFORM(CHROMIUM) -#include "PlatformWidget.h" -#endif - #if PLATFORM(EFL) typedef struct _Evas_Object Evas_Object; typedef struct _Evas Evas; @@ -95,13 +106,6 @@ typedef QWebPageClient* PlatformPageClient; typedef PlatformWidget PlatformPageClient; #endif -#include "IntPoint.h" -#include "IntRect.h" -#include "IntSize.h" - -#include <wtf/Forward.h> -#include <wtf/RefCounted.h> - namespace WebCore { class Cursor; @@ -132,15 +136,9 @@ public: Widget(PlatformWidget = 0); virtual ~Widget(); - PlatformWidget platformWidget() const { return m_widget; } - void setPlatformWidget(PlatformWidget widget) - { - if (widget != m_widget) { - releasePlatformWidget(); - m_widget = widget; - retainPlatformWidget(); - } - } + PlatformWidget platformWidget() const; + void setPlatformWidget(PlatformWidget); + #if PLATFORM(HAIKU) PlatformWidget topLevelPlatformWidget() const { return m_topLevelPlatformWidget; } void setTopLevelPlatformWidget(PlatformWidget widget) @@ -256,7 +254,11 @@ private: private: ScrollView* m_parent; +#if !PLATFORM(MAC) PlatformWidget m_widget; +#else + RetainPtr<NSView> m_widget; +#endif bool m_selfVisible; bool m_parentVisible; @@ -283,6 +285,36 @@ public: #endif }; +#if !PLATFORM(MAC) + +inline PlatformWidget Widget::platformWidget() const +{ + return m_widget; +} + +inline void Widget::setPlatformWidget(PlatformWidget widget) +{ + if (widget != m_widget) { + releasePlatformWidget(); + m_widget = widget; + retainPlatformWidget(); + } +} + +#endif + +#if !PLATFORM(GTK) + +inline void Widget::releasePlatformWidget() +{ +} + +inline void Widget::retainPlatformWidget() +{ +} + +#endif + } // namespace WebCore #endif // Widget_h diff --git a/WebCore/platform/android/ClipboardAndroid.cpp b/WebCore/platform/android/ClipboardAndroid.cpp index d9b2d68..a91fd21 100644 --- a/WebCore/platform/android/ClipboardAndroid.cpp +++ b/WebCore/platform/android/ClipboardAndroid.cpp @@ -40,8 +40,8 @@ PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy, DragData*, Frame* return 0; } -ClipboardAndroid::ClipboardAndroid(ClipboardAccessPolicy policy, bool isForDragging) - : Clipboard(policy, isForDragging) +ClipboardAndroid::ClipboardAndroid(ClipboardAccessPolicy policy, ClipboardType clipboardType) + : Clipboard(policy, clipboardType) { } @@ -51,12 +51,12 @@ ClipboardAndroid::~ClipboardAndroid() void ClipboardAndroid::clearData(const String&) { - ASSERT(isForDragging()); + ASSERT(isForDragAndDrop()); } void ClipboardAndroid::clearAllData() { - ASSERT(isForDragging()); + ASSERT(isForDragAndDrop()); } String ClipboardAndroid::getData(const String&, bool& success) const @@ -67,7 +67,7 @@ String ClipboardAndroid::getData(const String&, bool& success) const bool ClipboardAndroid::setData(const String&, const String&) { - ASSERT(isForDragging()); + ASSERT(isForDragAndDrop()); return false; } diff --git a/WebCore/platform/android/ClipboardAndroid.h b/WebCore/platform/android/ClipboardAndroid.h index 23bfdf6..807653b 100644 --- a/WebCore/platform/android/ClipboardAndroid.h +++ b/WebCore/platform/android/ClipboardAndroid.h @@ -37,7 +37,7 @@ class CachedImage; class ClipboardAndroid : public Clipboard, public CachedResourceClient { public: - ClipboardAndroid(ClipboardAccessPolicy policy, bool isForDragging); + ClipboardAndroid(ClipboardAccessPolicy policy, ClipboardType); ~ClipboardAndroid(); void clearData(const String&); diff --git a/WebCore/platform/android/LocalizedStringsAndroid.cpp b/WebCore/platform/android/LocalizedStringsAndroid.cpp index 5ca7fa2..635f741 100644 --- a/WebCore/platform/android/LocalizedStringsAndroid.cpp +++ b/WebCore/platform/android/LocalizedStringsAndroid.cpp @@ -98,6 +98,66 @@ String contextMenuItemTagCopyImageToClipboard() return String(); } +String contextMenuItemTagOpenVideoInNewWindow() +{ + notImplemented(); + return String(); +} + +String contextMenuItemTagOpenAudioInNewWindow() +{ + notImplemented(); + return String(); +} + +String contextMenuItemTagCopyVideoLinkToClipboard() +{ + notImplemented(); + return String(); +} + +String contextMenuItemTagCopyAudioLinkToClipboard() +{ + notImplemented(); + return String(); +} + +String contextMenuItemTagToggleMediaControls() +{ + notImplemented(); + return String(); +} + +String contextMenuItemTagToggleMediaLoop() +{ + notImplemented(); + return String(); +} + +String contextMenuItemTagEnterVideoFullscreen() +{ + notImplemented(); + return String(); +} + +String contextMenuItemTagMediaPlay() +{ + notImplemented(); + return String(); +} + +String contextMenuItemTagMediaPause() +{ + notImplemented(); + return String(); +} + +String contextMenuItemTagMediaMute() +{ + notImplemented(); + return String(); +} + String contextMenuItemTagOpenFrameInNewWindow() { notImplemented(); diff --git a/WebCore/platform/android/PlatformTouchEventAndroid.cpp b/WebCore/platform/android/PlatformTouchEventAndroid.cpp index 8b3d285..eb23322 100644 --- a/WebCore/platform/android/PlatformTouchEventAndroid.cpp +++ b/WebCore/platform/android/PlatformTouchEventAndroid.cpp @@ -43,7 +43,11 @@ PlatformTouchEvent::PlatformTouchEvent(const Vector<IntPoint>& windowPoints, Tou { m_touchPoints.reserveCapacity(windowPoints.size()); for (unsigned c = 0; c < windowPoints.size(); c++) +<<<<<<< HEAD m_touchPoints.append(PlatformTouchPoint(c, windowPoints[c], state)); +======= + m_touchPoints.append(PlatformTouchPoint(windowPos, state)); +>>>>>>> webkit.org at r68651 m_altKey = metaState & META_ALT_ON; m_shiftKey = metaState & META_SHIFT_ON; diff --git a/WebCore/platform/audio/AudioDestination.h b/WebCore/platform/audio/AudioDestination.h new file mode 100644 index 0000000..9498110 --- /dev/null +++ b/WebCore/platform/audio/AudioDestination.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AudioDestination_h +#define AudioDestination_h + +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +class AudioSourceProvider; + +// Abstraction for an audio output to the audio hardware +// An AudioSourceProvider is called back periodically to provide the rendered audio stream. + +class AudioDestination { +public: + static PassOwnPtr<AudioDestination> create(AudioSourceProvider&, double sampleRate); + + virtual ~AudioDestination() { } + + virtual void start() = 0; + virtual void stop() = 0; + virtual bool isPlaying() = 0; + + // Sample-rate conversion may happen in AudioDestination to the hardware sample-rate + virtual double sampleRate() const = 0; + static double hardwareSampleRate(); +}; + +} // namespace WebCore + +#endif // AudioDestination_h diff --git a/WebCore/platform/audio/HRTFDatabase.cpp b/WebCore/platform/audio/HRTFDatabase.cpp new file mode 100644 index 0000000..ef1229f --- /dev/null +++ b/WebCore/platform/audio/HRTFDatabase.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEB_AUDIO) + +#include "HRTFDatabase.h" + +#include "HRTFElevation.h" + +using namespace std; + +namespace WebCore { + +const int HRTFDatabase::MinElevation = -45; +const int HRTFDatabase::MaxElevation = 90; +const unsigned HRTFDatabase::RawElevationAngleSpacing = 15; +const unsigned HRTFDatabase::NumberOfRawElevations = 10; // -45 -> +90 (each 15 degrees) +const unsigned HRTFDatabase::InterpolationFactor = 1; +const unsigned HRTFDatabase::NumberOfTotalElevations = NumberOfRawElevations * InterpolationFactor; + +PassOwnPtr<HRTFDatabase> HRTFDatabase::create(double sampleRate) +{ + OwnPtr<HRTFDatabase> hrtfDatabase = adoptPtr(new HRTFDatabase(sampleRate)); + return hrtfDatabase.release(); +} + +HRTFDatabase::HRTFDatabase(double sampleRate) + : m_elevations(NumberOfTotalElevations) + , m_sampleRate(sampleRate) +{ + unsigned elevationIndex = 0; + for (int elevation = MinElevation; elevation <= MaxElevation; elevation += RawElevationAngleSpacing) { + OwnPtr<HRTFElevation> hrtfElevation = HRTFElevation::createForSubject("Composite", elevation, sampleRate); + ASSERT(hrtfElevation.get()); + if (!hrtfElevation.get()) + return; + + m_elevations[elevationIndex] = hrtfElevation.release(); + elevationIndex += InterpolationFactor; + } + + // Now, go back and interpolate elevations. + if (InterpolationFactor > 1) { + for (unsigned i = 0; i < NumberOfTotalElevations; i += InterpolationFactor) { + unsigned j = (i + InterpolationFactor); + if (j >= NumberOfTotalElevations) + j = i; // for last elevation interpolate with itself + + // Create the interpolated convolution kernels and delays. + for (unsigned jj = 1; jj < InterpolationFactor; ++jj) { + double x = static_cast<double>(jj) / static_cast<double>(InterpolationFactor); + m_elevations[i + jj] = HRTFElevation::createByInterpolatingSlices(m_elevations[i].get(), m_elevations[j].get(), x, sampleRate); + ASSERT(m_elevations[i + jj].get()); + } + } + } +} + +void HRTFDatabase::getKernelsFromAzimuthElevation(double azimuthBlend, unsigned azimuthIndex, double elevationAngle, HRTFKernel* &kernelL, HRTFKernel* &kernelR, + double& frameDelayL, double& frameDelayR) +{ + unsigned elevationIndex = indexFromElevationAngle(elevationAngle); + ASSERT(elevationIndex < m_elevations.size() && m_elevations.size() > 0); + + if (!m_elevations.size()) { + kernelL = 0; + kernelR = 0; + return; + } + + if (elevationIndex > m_elevations.size() - 1) + elevationIndex = m_elevations.size() - 1; + + HRTFElevation* hrtfElevation = m_elevations[elevationIndex].get(); + ASSERT(hrtfElevation); + if (!hrtfElevation) { + kernelL = 0; + kernelR = 0; + return; + } + + hrtfElevation->getKernelsFromAzimuth(azimuthBlend, azimuthIndex, kernelL, kernelR, frameDelayL, frameDelayR); +} + +unsigned HRTFDatabase::indexFromElevationAngle(double elevationAngle) +{ + // Clamp to allowed range. + elevationAngle = max(static_cast<double>(MinElevation), elevationAngle); + elevationAngle = min(static_cast<double>(MaxElevation), elevationAngle); + + unsigned elevationIndex = static_cast<int>(InterpolationFactor * (elevationAngle - MinElevation) / RawElevationAngleSpacing); + return elevationIndex; +} + +} // namespace WebCore + +#endif // ENABLE(WEB_AUDIO) diff --git a/WebCore/platform/audio/HRTFDatabase.h b/WebCore/platform/audio/HRTFDatabase.h new file mode 100644 index 0000000..c33b38f --- /dev/null +++ b/WebCore/platform/audio/HRTFDatabase.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HRTFDatabase_h +#define HRTFDatabase_h + +#include "HRTFElevation.h" +#include <wtf/HashMap.h> +#include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/Vector.h> +#include <wtf/text/CString.h> +#include <wtf/text/StringHash.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class HRTFKernel; + +class HRTFDatabase : public Noncopyable { +public: + static PassOwnPtr<HRTFDatabase> create(double sampleRate); + + // getKernelsFromAzimuthElevation() returns a left and right ear kernel, and an interpolated left and right frame delay for the given azimuth and elevation. + // azimuthBlend must be in the range 0 -> 1. + // Valid values for azimuthIndex are 0 -> HRTFElevation::NumberOfTotalAzimuths - 1 (corresponding to angles of 0 -> 360). + // Valid values for elevationAngle are MinElevation -> MaxElevation. + void getKernelsFromAzimuthElevation(double azimuthBlend, unsigned azimuthIndex, double elevationAngle, HRTFKernel* &kernelL, HRTFKernel* &kernelR, double& frameDelayL, double& frameDelayR); + + // Returns the number of different azimuth angles. + static unsigned numberOfAzimuths() { return HRTFElevation::NumberOfTotalAzimuths; } + + double sampleRate() const { return m_sampleRate; } + +private: + explicit HRTFDatabase(double sampleRate); + + // Minimum and maximum elevation angles (inclusive) for a HRTFDatabase. + static const int MinElevation; + static const int MaxElevation; + static const unsigned RawElevationAngleSpacing; + + // Number of elevations loaded from resource. + static const unsigned NumberOfRawElevations; + + // Interpolates by this factor to get the total number of elevations from every elevation loaded from resource. + static const unsigned InterpolationFactor; + + // Total number of elevations after interpolation. + static const unsigned NumberOfTotalElevations; + + // Returns the index for the correct HRTFElevation given the elevation angle. + static unsigned indexFromElevationAngle(double); + + Vector<OwnPtr<HRTFElevation> > m_elevations; + double m_sampleRate; +}; + +} // namespace WebCore + +#endif // HRTFDatabase_h diff --git a/WebCore/platform/audio/HRTFDatabaseLoader.cpp b/WebCore/platform/audio/HRTFDatabaseLoader.cpp new file mode 100644 index 0000000..4368d22 --- /dev/null +++ b/WebCore/platform/audio/HRTFDatabaseLoader.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEB_AUDIO) + +#include "HRTFDatabaseLoader.h" + +#include "HRTFDatabase.h" + +namespace WebCore { + +// Singleton +HRTFDatabaseLoader* HRTFDatabaseLoader::s_loader = 0; + +PassRefPtr<HRTFDatabaseLoader> HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(double sampleRate) +{ + ASSERT(isMainThread()); + + RefPtr<HRTFDatabaseLoader> loader; + + if (!s_loader) { + // Lazily create and load. + loader = adoptRef(new HRTFDatabaseLoader(sampleRate)); + s_loader = loader.get(); + loader->loadAsynchronously(); + } else { + loader = s_loader; + ASSERT(sampleRate == loader->databaseSampleRate()); + } + + return loader; +} + +HRTFDatabaseLoader::HRTFDatabaseLoader(double sampleRate) + : m_hrtfDatabase(0) + , m_databaseLoaderThread(0) + , m_startedLoadingDatabase(false) + , m_databaseSampleRate(sampleRate) +{ + ASSERT(isMainThread()); +} + +HRTFDatabaseLoader::~HRTFDatabaseLoader() +{ + ASSERT(isMainThread()); + + if (m_startedLoadingDatabase) + waitForThreadCompletion(m_databaseLoaderThread, 0); + + m_startedLoadingDatabase = false; + m_databaseLoaderThread = 0; + + m_hrtfDatabase.clear(); + + // Clear out singleton. + ASSERT(this == s_loader); + s_loader = 0; +} + + +// Asynchronously load the database in this thread. +static void* databaseLoaderEntry(void* threadData) +{ + HRTFDatabaseLoader* loader = reinterpret_cast<HRTFDatabaseLoader*>(threadData); + ASSERT(loader); + loader->load(); + + return 0; +} + +void HRTFDatabaseLoader::load() +{ + ASSERT(!isMainThread()); + if (!m_hrtfDatabase.get()) { + // Load the default HRTF database. + m_hrtfDatabase = HRTFDatabase::create(m_databaseSampleRate); + } +} + +void HRTFDatabaseLoader::loadAsynchronously() +{ + ASSERT(isMainThread()); + + if (!m_hrtfDatabase.get() && !m_startedLoadingDatabase) { + // Start the asynchronous database loading process. + m_startedLoadingDatabase = true; + m_databaseLoaderThread = createThread(databaseLoaderEntry, this, "HRTF database loader"); + } +} + +bool HRTFDatabaseLoader::isLoaded() const +{ + return m_hrtfDatabase.get(); +} + +HRTFDatabase* HRTFDatabaseLoader::defaultHRTFDatabase() +{ + if (!s_loader) + return 0; + + return s_loader->database(); +} + +} // namespace WebCore + +#endif // ENABLE(WEB_AUDIO) diff --git a/WebCore/platform/audio/HRTFDatabaseLoader.h b/WebCore/platform/audio/HRTFDatabaseLoader.h new file mode 100644 index 0000000..72002c5 --- /dev/null +++ b/WebCore/platform/audio/HRTFDatabaseLoader.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HRTFDatabaseLoader_h +#define HRTFDatabaseLoader_h + +#include "HRTFDatabase.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/Threading.h> + +namespace WebCore { + +// HRTFDatabaseLoader will asynchronously load the default HRTFDatabase in a new thread. + +class HRTFDatabaseLoader : public RefCounted<HRTFDatabaseLoader> { +public: + // Lazily creates the singleton HRTFDatabaseLoader (if not already created) and starts loading asynchronously (when created the first time). + // Returns the singleton HRTFDatabaseLoader. + // Must be called from the main thread. + static PassRefPtr<HRTFDatabaseLoader> createAndLoadAsynchronouslyIfNecessary(double sampleRate); + + // Both constructor and destructor must be called from the main thread. + ~HRTFDatabaseLoader(); + + // Returns true once the default database has been completely loaded. + bool isLoaded() const; + + HRTFDatabase* database() { return m_hrtfDatabase.get(); } + + // Called in asynchronous loading thread. + void load(); + + // defaultHRTFDatabase() gives access to the loaded database. + // This can be called from any thread, but it is the callers responsibilty to call this while the context (and thus HRTFDatabaseLoader) + // is still alive. Otherwise this will return 0. + static HRTFDatabase* defaultHRTFDatabase(); + +private: + // Both constructor and destructor must be called from the main thread. + explicit HRTFDatabaseLoader(double sampleRate); + + // If it hasn't already been loaded, creates a new thread and initiates asynchronous loading of the default database. + // This must be called from the main thread. + void loadAsynchronously(); + + double databaseSampleRate() const { return m_databaseSampleRate; } + + static HRTFDatabaseLoader* s_loader; // singleton + OwnPtr<HRTFDatabase> m_hrtfDatabase; + ThreadIdentifier m_databaseLoaderThread; + bool m_startedLoadingDatabase; + double m_databaseSampleRate; +}; + + +} // namespace WebCore + +#endif // HRTFDatabaseLoader_h diff --git a/WebCore/platform/audio/HRTFElevation.cpp b/WebCore/platform/audio/HRTFElevation.cpp new file mode 100644 index 0000000..ac1eb4d --- /dev/null +++ b/WebCore/platform/audio/HRTFElevation.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEB_AUDIO) + +#include "HRTFElevation.h" + +#include "AudioBus.h" +#include "AudioFileReader.h" +#include "AudioResources.h" +#include "Biquad.h" +#include "FFTFrame.h" +#include "HRTFPanner.h" +#include <algorithm> +#include <math.h> +#include <wtf/OwnPtr.h> + +using namespace std; + +namespace WebCore { + +const unsigned HRTFElevation::AzimuthSpacing = 15; +const unsigned HRTFElevation::NumberOfRawAzimuths = 360 / AzimuthSpacing; +const unsigned HRTFElevation::InterpolationFactor = 8; +const unsigned HRTFElevation::NumberOfTotalAzimuths = NumberOfRawAzimuths * InterpolationFactor; + +// Takes advantage of the symmetry and creates a composite version of the two measured versions. For example, we have both azimuth 30 and -30 degrees +// where the roles of left and right ears are reversed with respect to each other. +bool HRTFElevation::calculateSymmetricKernelsForAzimuthElevation(int azimuth, int elevation, double sampleRate, const String& subjectName, + RefPtr<HRTFKernel>& kernelL, RefPtr<HRTFKernel>& kernelR) +{ + RefPtr<HRTFKernel> kernelL1; + RefPtr<HRTFKernel> kernelR1; + bool success = calculateKernelsForAzimuthElevation(azimuth, elevation, sampleRate, subjectName, kernelL1, kernelR1); + if (!success) + return false; + + // And symmetric version + int symmetricAzimuth = !azimuth ? 0 : 360 - azimuth; + + RefPtr<HRTFKernel> kernelL2; + RefPtr<HRTFKernel> kernelR2; + success = calculateKernelsForAzimuthElevation(symmetricAzimuth, elevation, sampleRate, subjectName, kernelL2, kernelR2); + if (!success) + return false; + + // Notice L/R reversal in symmetric version. + kernelL = HRTFKernel::createInterpolatedKernel(kernelL1.get(), kernelR2.get(), 0.5); + kernelR = HRTFKernel::createInterpolatedKernel(kernelR1.get(), kernelL2.get(), 0.5); + + return true; +} + +bool HRTFElevation::calculateKernelsForAzimuthElevation(int azimuth, int elevation, double sampleRate, const String& subjectName, + RefPtr<HRTFKernel>& kernelL, RefPtr<HRTFKernel>& kernelR) +{ + // Valid values for azimuth are 0 -> 345 in 15 degree increments. + // Valid values for elevation are -45 -> +90 in 15 degree increments. + + bool isAzimuthGood = azimuth >= 0 && azimuth <= 345 && (azimuth / 15) * 15 == azimuth; + ASSERT(isAzimuthGood); + if (!isAzimuthGood) + return false; + + bool isElevationGood = elevation >= -45 && elevation <= 90 && (elevation / 15) * 15 == elevation; + ASSERT(isElevationGood); + if (!isElevationGood) + return false; + + // Construct the resource name from the subject name, azimuth, and elevation, for example: + // "IRC_Composite_C_R0195_T015_P000" + // Note: the passed in subjectName is not a string passed in via JavaScript or the web. + // It's passed in as an internal ASCII identifier and is an implementation detail. + int positiveElevation = elevation < 0 ? elevation + 360 : elevation; + String resourceName = String::format("IRC_%s_C_R0195_T%03d_P%03d", subjectName.utf8().data(), azimuth, positiveElevation); + + OwnPtr<AudioBus> impulseResponse(createBusFromAudioFileResource(resourceName, sampleRate)); + + ASSERT(impulseResponse.get()); + if (!impulseResponse.get()) + return false; + + size_t responseLength = impulseResponse->length(); + + // Check number of channels and length. For now these are fixed and known. + bool isBusGood = responseLength == 512 && impulseResponse->numberOfChannels() == 2; + ASSERT(isBusGood); + if (!isBusGood) + return false; + + AudioChannel* leftEarImpulseResponse = impulseResponse->channelByType(AudioBus::ChannelLeft); + AudioChannel* rightEarImpulseResponse = impulseResponse->channelByType(AudioBus::ChannelRight); + + // Note that depending on the fftSize returned by the panner, we may be truncating the impulse response we just loaded in. + const size_t fftSize = HRTFPanner::fftSizeForSampleRate(sampleRate); + kernelL = HRTFKernel::create(leftEarImpulseResponse, fftSize, sampleRate, true); + kernelR = HRTFKernel::create(rightEarImpulseResponse, fftSize, sampleRate, true); + + return true; +} + +// The range of elevations for the IRCAM impulse responses varies depending on azimuth, but the minimum elevation appears to always be -45. +// +// Here's how it goes: +static int maxElevations[] = { + // Azimuth + // + 90, // 0 + 45, // 15 + 60, // 30 + 45, // 45 + 75, // 60 + 45, // 75 + 60, // 90 + 45, // 105 + 75, // 120 + 45, // 135 + 60, // 150 + 45, // 165 + 75, // 180 + 45, // 195 + 60, // 210 + 45, // 225 + 75, // 240 + 45, // 255 + 60, // 270 + 45, // 285 + 75, // 300 + 45, // 315 + 60, // 330 + 45 // 345 +}; + +PassOwnPtr<HRTFElevation> HRTFElevation::createForSubject(const String& subjectName, int elevation, double sampleRate) +{ + bool isElevationGood = elevation >= -45 && elevation <= 90 && (elevation / 15) * 15 == elevation; + ASSERT(isElevationGood); + if (!isElevationGood) + return 0; + + OwnPtr<HRTFKernelList> kernelListL = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths)); + OwnPtr<HRTFKernelList> kernelListR = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths)); + + // Load convolution kernels from HRTF files. + int interpolatedIndex = 0; + for (unsigned rawIndex = 0; rawIndex < NumberOfRawAzimuths; ++rawIndex) { + // Don't let elevation exceed maximum for this azimuth. + int maxElevation = maxElevations[rawIndex]; + int actualElevation = min(elevation, maxElevation); + + bool success = calculateKernelsForAzimuthElevation(rawIndex * AzimuthSpacing, actualElevation, sampleRate, subjectName, kernelListL->at(interpolatedIndex), kernelListR->at(interpolatedIndex)); + if (!success) + return 0; + + interpolatedIndex += InterpolationFactor; + } + + // Now go back and interpolate intermediate azimuth values. + for (unsigned i = 0; i < NumberOfTotalAzimuths; i += InterpolationFactor) { + int j = (i + InterpolationFactor) % NumberOfTotalAzimuths; + + // Create the interpolated convolution kernels and delays. + for (unsigned jj = 1; jj < InterpolationFactor; ++jj) { + double x = double(jj) / double(InterpolationFactor); // interpolate from 0 -> 1 + + (*kernelListL)[i + jj] = HRTFKernel::createInterpolatedKernel(kernelListL->at(i).get(), kernelListL->at(j).get(), x); + (*kernelListR)[i + jj] = HRTFKernel::createInterpolatedKernel(kernelListR->at(i).get(), kernelListR->at(j).get(), x); + } + } + + OwnPtr<HRTFElevation> hrtfElevation = adoptPtr(new HRTFElevation(kernelListL.release(), kernelListR.release(), elevation, sampleRate)); + return hrtfElevation.release(); +} + +PassOwnPtr<HRTFElevation> HRTFElevation::createByInterpolatingSlices(HRTFElevation* hrtfElevation1, HRTFElevation* hrtfElevation2, double x, double sampleRate) +{ + ASSERT(hrtfElevation1 && hrtfElevation2); + if (!hrtfElevation1 || !hrtfElevation2) + return 0; + + ASSERT(x >= 0.0 && x < 1.0); + + OwnPtr<HRTFKernelList> kernelListL = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths)); + OwnPtr<HRTFKernelList> kernelListR = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths)); + + HRTFKernelList* kernelListL1 = hrtfElevation1->kernelListL(); + HRTFKernelList* kernelListR1 = hrtfElevation1->kernelListR(); + HRTFKernelList* kernelListL2 = hrtfElevation2->kernelListL(); + HRTFKernelList* kernelListR2 = hrtfElevation2->kernelListR(); + + // Interpolate kernels of corresponding azimuths of the two elevations. + for (unsigned i = 0; i < NumberOfTotalAzimuths; ++i) { + (*kernelListL)[i] = HRTFKernel::createInterpolatedKernel(kernelListL1->at(i).get(), kernelListL2->at(i).get(), x); + (*kernelListR)[i] = HRTFKernel::createInterpolatedKernel(kernelListR1->at(i).get(), kernelListR2->at(i).get(), x); + } + + // Interpolate elevation angle. + double angle = (1.0 - x) * hrtfElevation1->elevationAngle() + x * hrtfElevation2->elevationAngle(); + + OwnPtr<HRTFElevation> hrtfElevation = adoptPtr(new HRTFElevation(kernelListL.release(), kernelListR.release(), angle, sampleRate)); + return hrtfElevation.release(); +} + +void HRTFElevation::getKernelsFromAzimuth(double azimuthBlend, unsigned azimuthIndex, HRTFKernel* &kernelL, HRTFKernel* &kernelR, double& frameDelayL, double& frameDelayR) +{ + bool checkAzimuthBlend = azimuthBlend >= 0.0 && azimuthBlend < 1.0; + ASSERT(checkAzimuthBlend); + if (!checkAzimuthBlend) + azimuthBlend = 0.0; + + unsigned numKernels = m_kernelListL->size(); + + bool isIndexGood = azimuthIndex < numKernels; + ASSERT(isIndexGood); + if (!isIndexGood) { + kernelL = 0; + kernelR = 0; + return; + } + + // Return the left and right kernels. + kernelL = m_kernelListL->at(azimuthIndex).get(); + kernelR = m_kernelListR->at(azimuthIndex).get(); + + frameDelayL = m_kernelListL->at(azimuthIndex)->frameDelay(); + frameDelayR = m_kernelListR->at(azimuthIndex)->frameDelay(); + + int azimuthIndex2 = (azimuthIndex + 1) % numKernels; + double frameDelay2L = m_kernelListL->at(azimuthIndex2)->frameDelay(); + double frameDelay2R = m_kernelListR->at(azimuthIndex2)->frameDelay(); + + // Linearly interpolate delays. + frameDelayL = (1.0 - azimuthBlend) * frameDelayL + azimuthBlend * frameDelay2L; + frameDelayR = (1.0 - azimuthBlend) * frameDelayR + azimuthBlend * frameDelay2R; +} + +} // namespace WebCore + +#endif // ENABLE(WEB_AUDIO) diff --git a/WebCore/platform/audio/HRTFElevation.h b/WebCore/platform/audio/HRTFElevation.h new file mode 100644 index 0000000..b388b34 --- /dev/null +++ b/WebCore/platform/audio/HRTFElevation.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HRTFElevation_h +#define HRTFElevation_h + +#include "HRTFKernel.h" +#include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +// HRTFElevation contains all of the HRTFKernels (one left ear and one right ear per azimuth angle) for a particular elevation. + +class HRTFElevation : public Noncopyable { +public: + // Loads and returns an HRTFElevation with the given HRTF database subject name and elevation from browser (or WebKit.framework) resources. + // Normally, there will only be a single HRTF database set, but this API supports the possibility of multiple ones with different names. + // Interpolated azimuths will be generated based on InterpolationFactor. + // Valid values for elevation are -45 -> +90 in 15 degree increments. + static PassOwnPtr<HRTFElevation> createForSubject(const String& subjectName, int elevation, double sampleRate); + + // Given two HRTFElevations, and an interpolation factor x: 0 -> 1, returns an interpolated HRTFElevation. + static PassOwnPtr<HRTFElevation> createByInterpolatingSlices(HRTFElevation* hrtfElevation1, HRTFElevation* hrtfElevation2, double x, double sampleRate); + + // Returns the list of left or right ear HRTFKernels for all the azimuths going from 0 to 360 degrees. + HRTFKernelList* kernelListL() { return m_kernelListL.get(); } + HRTFKernelList* kernelListR() { return m_kernelListR.get(); } + + double elevationAngle() const { return m_elevationAngle; } + unsigned numberOfAzimuths() { return NumberOfTotalAzimuths; } + double sampleRate() const { return m_sampleRate; } + + // Returns the left and right kernels for the given azimuth index. + // The interpolated delays based on azimuthBlend: 0 -> 1 are returned in frameDelayL and frameDelayR. + void getKernelsFromAzimuth(double azimuthBlend, unsigned azimuthIndex, HRTFKernel* &kernelL, HRTFKernel* &kernelR, double& frameDelayL, double& frameDelayR); + + // Spacing, in degrees, between every azimuth loaded from resource. + static const unsigned AzimuthSpacing; + + // Number of azimuths loaded from resource. + static const unsigned NumberOfRawAzimuths; + + // Interpolates by this factor to get the total number of azimuths from every azimuth loaded from resource. + static const unsigned InterpolationFactor; + + // Total number of azimuths after interpolation. + static const unsigned NumberOfTotalAzimuths; + + // Given a specific azimuth and elevation angle, returns the left and right HRTFKernel. + // Valid values for azimuth are 0 -> 345 in 15 degree increments. + // Valid values for elevation are -45 -> +90 in 15 degree increments. + // Returns true on success. + static bool calculateKernelsForAzimuthElevation(int azimuth, int elevation, double sampleRate, const String& subjectName, + RefPtr<HRTFKernel>& kernelL, RefPtr<HRTFKernel>& kernelR); + + // Given a specific azimuth and elevation angle, returns the left and right HRTFKernel in kernelL and kernelR. + // This method averages the measured response using symmetry of azimuth (for example by averaging the -30.0 and +30.0 azimuth responses). + // Returns true on success. + static bool calculateSymmetricKernelsForAzimuthElevation(int azimuth, int elevation, double sampleRate, const String& subjectName, + RefPtr<HRTFKernel>& kernelL, RefPtr<HRTFKernel>& kernelR); +private: + HRTFElevation(PassOwnPtr<HRTFKernelList> kernelListL, PassOwnPtr<HRTFKernelList> kernelListR, int elevation, double sampleRate) + : m_kernelListL(kernelListL) + , m_kernelListR(kernelListR) + , m_elevationAngle(elevation) + , m_sampleRate(sampleRate) + { + } + + OwnPtr<HRTFKernelList> m_kernelListL; + OwnPtr<HRTFKernelList> m_kernelListR; + double m_elevationAngle; + double m_sampleRate; +}; + +} // namespace WebCore + +#endif // HRTFElevation_h diff --git a/WebCore/platform/audio/HRTFKernel.cpp b/WebCore/platform/audio/HRTFKernel.cpp new file mode 100644 index 0000000..852cdbf --- /dev/null +++ b/WebCore/platform/audio/HRTFKernel.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEB_AUDIO) + +#include "HRTFKernel.h" + +#include "AudioChannel.h" +#include "Biquad.h" +#include "FFTFrame.h" + +using namespace std; + +namespace WebCore { + +// Takes the input AudioChannel as an input impulse response and calculates the average group delay. +// This represents the initial delay before the most energetic part of the impulse response. +// The sample-frame delay is removed from the impulseP impulse response, and this value is returned. +// the length of the passed in AudioChannel must be a power of 2. +static double extractAverageGroupDelay(AudioChannel* channel) +{ + ASSERT(channel); + + float* impulseP = channel->data(); + size_t length = channel->length(); + + // Check that length is power-of-2; + ASSERT(1UL << static_cast<unsigned>(log2(length)) == length); + + FFTFrame estimationFrame(length); + estimationFrame.doFFT(impulseP); + + double frameDelay = estimationFrame.extractAverageGroupDelay(); + estimationFrame.doInverseFFT(impulseP); + + return frameDelay; +} + +HRTFKernel::HRTFKernel(AudioChannel* channel, size_t fftSize, double sampleRate, bool bassBoost) + : m_frameDelay(0.0) + , m_sampleRate(sampleRate) +{ + ASSERT(channel); + + // Determine the leading delay (average group delay) for the response. + m_frameDelay = extractAverageGroupDelay(channel); + + float* impulseResponse = channel->data(); + size_t responseLength = channel->length(); + + if (bassBoost) { + // Run through some post-processing to boost the bass a little -- the HRTF's seem to be a little bass-deficient. + // FIXME: this post-processing should have already been applied to the HRTF file resources. Once the files are put into this form, + // then this code path can be removed along with the bassBoost parameter. + Biquad filter; + filter.setLowShelfParams(700.0 / nyquist(), 6.0); // boost 6dB at 700Hz + filter.process(impulseResponse, impulseResponse, responseLength); + } + + // We need to truncate to fit into 1/2 the FFT size (with zero padding) in order to do proper convolution. + size_t truncatedResponseLength = min(responseLength, fftSize / 2); // truncate if necessary to max impulse response length allowed by FFT + + // Quick fade-out (apply window) at truncation point + unsigned numberOfFadeOutFrames = static_cast<unsigned>(sampleRate / 4410); // 10 sample-frames @44.1KHz sample-rate + ASSERT(numberOfFadeOutFrames < truncatedResponseLength); + if (numberOfFadeOutFrames < truncatedResponseLength) { + for (unsigned i = truncatedResponseLength - numberOfFadeOutFrames; i < truncatedResponseLength; ++i) { + float x = 1.0f - static_cast<float>(i - (truncatedResponseLength - numberOfFadeOutFrames)) / numberOfFadeOutFrames; + impulseResponse[i] *= x; + } + } + + m_fftFrame = adoptPtr(new FFTFrame(fftSize)); + m_fftFrame->doPaddedFFT(impulseResponse, truncatedResponseLength); +} + +PassOwnPtr<AudioChannel> HRTFKernel::createImpulseResponse() +{ + OwnPtr<AudioChannel> channel = adoptPtr(new AudioChannel(fftSize())); + FFTFrame fftFrame(*m_fftFrame); + + // Add leading delay back in. + fftFrame.addConstantGroupDelay(m_frameDelay); + fftFrame.doInverseFFT(channel->data()); + + return channel.release(); +} + +// Interpolates two kernels with x: 0 -> 1 and returns the result. +PassRefPtr<HRTFKernel> HRTFKernel::createInterpolatedKernel(HRTFKernel* kernel1, HRTFKernel* kernel2, double x) +{ + ASSERT(kernel1 && kernel2); + if (!kernel1 || !kernel2) + return 0; + + ASSERT(x >= 0.0 && x < 1.0); + x = min(1.0, max(0.0, x)); + + double sampleRate1 = kernel1->sampleRate(); + double sampleRate2 = kernel2->sampleRate(); + ASSERT(sampleRate1 == sampleRate2); + if (sampleRate1 != sampleRate2) + return 0; + + double frameDelay = (1.0 - x) * kernel1->frameDelay() + x * kernel2->frameDelay(); + + OwnPtr<FFTFrame> interpolatedFrame = FFTFrame::createInterpolatedFrame(*kernel1->fftFrame(), *kernel2->fftFrame(), x); + return HRTFKernel::create(interpolatedFrame.release(), frameDelay, sampleRate1); +} + +} // namespace WebCore + +#endif // ENABLE(WEB_AUDIO) diff --git a/WebCore/platform/audio/HRTFKernel.h b/WebCore/platform/audio/HRTFKernel.h new file mode 100644 index 0000000..572a085 --- /dev/null +++ b/WebCore/platform/audio/HRTFKernel.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HRTFKernel_h +#define HRTFKernel_h + +#include "FFTFrame.h" +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class AudioChannel; + +// HRTF stands for Head-Related Transfer Function. +// HRTFKernel is a frequency-domain representation of an impulse-response used as part of the spatialized panning system. +// For a given azimuth / elevation angle there will be one HRTFKernel for the left ear transfer function, and one for the right ear. +// The leading delay (average group delay) for each impulse response is extracted: +// m_fftFrame is the frequency-domain representation of the impulse response with the delay removed +// m_frameDelay is the leading delay of the original impulse response. +class HRTFKernel : public RefCounted<HRTFKernel> { +public: + // Note: this is destructive on the passed in AudioChannel. + // The length of channel must be a power of two. + static PassRefPtr<HRTFKernel> create(AudioChannel* channel, size_t fftSize, double sampleRate, bool bassBoost) + { + return adoptRef(new HRTFKernel(channel, fftSize, sampleRate, bassBoost)); + } + + static PassRefPtr<HRTFKernel> create(PassOwnPtr<FFTFrame> fftFrame, double frameDelay, double sampleRate) + { + return adoptRef(new HRTFKernel(fftFrame, frameDelay, sampleRate)); + } + + // Given two HRTFKernels, and an interpolation factor x: 0 -> 1, returns an interpolated HRTFKernel. + static PassRefPtr<HRTFKernel> createInterpolatedKernel(HRTFKernel* kernel1, HRTFKernel* kernel2, double x); + + FFTFrame* fftFrame() { return m_fftFrame.get(); } + + size_t fftSize() const { return m_fftFrame->fftSize(); } + double frameDelay() const { return m_frameDelay; } + + double sampleRate() const { return m_sampleRate; } + double nyquist() const { return 0.5 * sampleRate(); } + + // Converts back into impulse-response form. + PassOwnPtr<AudioChannel> createImpulseResponse(); + +private: + // Note: this is destructive on the passed in AudioChannel. + HRTFKernel(AudioChannel* channel, size_t fftSize, double sampleRate, bool bassBoost); + + HRTFKernel(PassOwnPtr<FFTFrame> fftFrame, double frameDelay, double sampleRate) + : m_fftFrame(fftFrame) + , m_frameDelay(frameDelay) + , m_sampleRate(sampleRate) + { + } + + OwnPtr<FFTFrame> m_fftFrame; + double m_frameDelay; + double m_sampleRate; +}; + +typedef Vector<RefPtr<HRTFKernel> > HRTFKernelList; + +} // namespace WebCore + +#endif // HRTFKernel_h diff --git a/WebCore/platform/audio/mac/AudioDestinationMac.cpp b/WebCore/platform/audio/mac/AudioDestinationMac.cpp new file mode 100644 index 0000000..523729f --- /dev/null +++ b/WebCore/platform/audio/mac/AudioDestinationMac.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEB_AUDIO) + +#include "AudioDestinationMac.h" + +#include "AudioSourceProvider.h" +#include <CoreAudio/AudioHardware.h> + +namespace WebCore { + +const int kBufferSize = 128; + +// Factory method: Mac-implementation +PassOwnPtr<AudioDestination> AudioDestination::create(AudioSourceProvider& provider, double sampleRate) +{ + return adoptPtr(new AudioDestinationMac(provider, sampleRate)); +} + +double AudioDestination::hardwareSampleRate() +{ + // Determine the default output device's sample-rate. + AudioDeviceID deviceID = kAudioDeviceUnknown; + UInt32 infoSize = sizeof(deviceID); + + AudioObjectPropertyAddress defaultInputDeviceAddress = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; + OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultInputDeviceAddress, 0, 0, &infoSize, (void*)&deviceID); + if (result) + return 0.0; // error + + Float64 nominalSampleRate; + infoSize = sizeof(Float64); + + AudioObjectPropertyAddress nominalSampleRateAddress = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; + result = AudioObjectGetPropertyData(deviceID, &nominalSampleRateAddress, 0, 0, &infoSize, (void*)&nominalSampleRate); + if (result) + return 0.0; // error + + return nominalSampleRate; +} + +AudioDestinationMac::AudioDestinationMac(AudioSourceProvider& provider, double sampleRate) + : m_outputUnit(0) + , m_provider(provider) + , m_renderBus(2, kBufferSize, false) + , m_sampleRate(sampleRate) + , m_isPlaying(false) +{ + // Open and initialize DefaultOutputUnit + Component comp; + ComponentDescription desc; + + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_DefaultOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + comp = FindNextComponent(0, &desc); + + ASSERT(comp); + + OSStatus result = OpenAComponent(comp, &m_outputUnit); + ASSERT(!result); + + result = AudioUnitInitialize(m_outputUnit); + ASSERT(!result); + + configure(); +} + +AudioDestinationMac::~AudioDestinationMac() +{ + if (m_outputUnit) + CloseComponent(m_outputUnit); +} + +void AudioDestinationMac::configure() +{ + // Set render callback + AURenderCallbackStruct input; + input.inputProc = inputProc; + input.inputProcRefCon = this; + OSStatus result = AudioUnitSetProperty(m_outputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &input, sizeof(input)); + ASSERT(!result); + + // Set stream format + AudioStreamBasicDescription streamFormat; + streamFormat.mSampleRate = m_sampleRate; + streamFormat.mFormatID = kAudioFormatLinearPCM; + streamFormat.mFormatFlags = kAudioFormatFlagsCanonical | kAudioFormatFlagIsNonInterleaved; + streamFormat.mBitsPerChannel = 8 * sizeof(AudioSampleType); + streamFormat.mChannelsPerFrame = 2; + streamFormat.mFramesPerPacket = 1; + streamFormat.mBytesPerPacket = sizeof(AudioSampleType); + streamFormat.mBytesPerFrame = sizeof(AudioSampleType); + + result = AudioUnitSetProperty(m_outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, (void*)&streamFormat, sizeof(AudioStreamBasicDescription)); + ASSERT(!result); + + // Set the buffer frame size. + UInt32 bufferSize = kBufferSize; + result = AudioUnitSetProperty(m_outputUnit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Output, 0, (void*)&bufferSize, sizeof(bufferSize)); + ASSERT(!result); +} + +void AudioDestinationMac::start() +{ + OSStatus result = AudioOutputUnitStart(m_outputUnit); + + if (!result) + m_isPlaying = true; +} + +void AudioDestinationMac::stop() +{ + OSStatus result = AudioOutputUnitStop(m_outputUnit); + + if (!result) + m_isPlaying = false; +} + +// Pulls on our provider to get rendered audio stream. +OSStatus AudioDestinationMac::render(UInt32 numberOfFrames, AudioBufferList* ioData) +{ + AudioBuffer* buffers = ioData->mBuffers; + m_renderBus.setChannelMemory(0, (float*)buffers[0].mData, numberOfFrames); + m_renderBus.setChannelMemory(1, (float*)buffers[1].mData, numberOfFrames); + + m_provider.provideInput(&m_renderBus, numberOfFrames); + + return noErr; +} + +// DefaultOutputUnit callback +OSStatus AudioDestinationMac::inputProc(void* userData, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32 /*busNumber*/, UInt32 numberOfFrames, AudioBufferList* ioData) +{ + AudioDestinationMac* audioOutput = static_cast<AudioDestinationMac*>(userData); + return audioOutput->render(numberOfFrames, ioData); +} + +} // namespace WebCore + +#endif // ENABLE(WEB_AUDIO) diff --git a/WebCore/platform/audio/mac/AudioDestinationMac.h b/WebCore/platform/audio/mac/AudioDestinationMac.h new file mode 100644 index 0000000..197440c --- /dev/null +++ b/WebCore/platform/audio/mac/AudioDestinationMac.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AudioDestinationMac_h +#define AudioDestinationMac_h + +#include "AudioBus.h" +#include "AudioDestination.h" +#include <AudioUnit/AudioUnit.h> + +namespace WebCore { + +// An AudioDestination using CoreAudio's default output AudioUnit + +class AudioDestinationMac : public AudioDestination { +public: + AudioDestinationMac(AudioSourceProvider&, double sampleRate); + virtual ~AudioDestinationMac(); + + virtual void start(); + virtual void stop(); + bool isPlaying() { return m_isPlaying; } + + double sampleRate() const { return m_sampleRate; } + +private: + void configure(); + + // DefaultOutputUnit callback + static OSStatus inputProc(void* userData, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32 busNumber, UInt32 numberOfFrames, AudioBufferList* ioData); + + OSStatus render(UInt32 numberOfFrames, AudioBufferList* ioData); + + AudioUnit m_outputUnit; + AudioSourceProvider& m_provider; + AudioBus m_renderBus; + + double m_sampleRate; + bool m_isPlaying; +}; + +} // namespace WebCore + +#endif // AudioDestinationMac_h diff --git a/WebCore/platform/brew/ClipboardBrew.cpp b/WebCore/platform/brew/ClipboardBrew.cpp index 720d6a6..10025d6 100644 --- a/WebCore/platform/brew/ClipboardBrew.cpp +++ b/WebCore/platform/brew/ClipboardBrew.cpp @@ -41,8 +41,8 @@ PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy, DragData*, Frame* return 0; } -ClipboardBrew::ClipboardBrew(ClipboardAccessPolicy policy, bool isForDragging) - : Clipboard(policy, isForDragging) +ClipboardBrew::ClipboardBrew(ClipboardAccessPolicy policy, ClipboardType clipboardType) + : Clipboard(clipboardType, isForDragging) { } @@ -52,12 +52,12 @@ ClipboardBrew::~ClipboardBrew() void ClipboardBrew::clearData(const String&) { - ASSERT(isForDragging()); + ASSERT(isForDragAndDrop()); } void ClipboardBrew::clearAllData() { - ASSERT(isForDragging()); + ASSERT(isForDragAndDrop()); } String ClipboardBrew::getData(const String&, bool& success) const @@ -68,7 +68,7 @@ String ClipboardBrew::getData(const String&, bool& success) const bool ClipboardBrew::setData(const String&, const String&) { - ASSERT(isForDragging()); + ASSERT(isForDragAndDrop()); return false; } diff --git a/WebCore/platform/brew/ClipboardBrew.h b/WebCore/platform/brew/ClipboardBrew.h index a966db1..1faf031 100644 --- a/WebCore/platform/brew/ClipboardBrew.h +++ b/WebCore/platform/brew/ClipboardBrew.h @@ -36,7 +36,7 @@ class CachedImage; class ClipboardBrew : public Clipboard, public CachedResourceClient { public: - ClipboardBrew(ClipboardAccessPolicy policy, bool isForDragging); + ClipboardBrew(ClipboardAccessPolicy policy, ClipboardType); ~ClipboardBrew(); void clearData(const String&); diff --git a/WebCore/platform/brew/FileSystemBrew.cpp b/WebCore/platform/brew/FileSystemBrew.cpp index 88aa05b..a723e63 100644 --- a/WebCore/platform/brew/FileSystemBrew.cpp +++ b/WebCore/platform/brew/FileSystemBrew.cpp @@ -131,7 +131,7 @@ static String canonicalPath(const String& path) return canonPath; } -static bool makeAllDirectories(PassOwnPtr<IFileMgr> fileMgr, const String& path) +static bool makeAllDirectories(IFileMgr* fileManager, const String& path) { if (path == canonicalPath(AEEFS_HOME_DIR)) return true; @@ -144,7 +144,7 @@ static bool makeAllDirectories(PassOwnPtr<IFileMgr> fileMgr, const String& path) } if (lastDivPos > 0) { - if (!makeAllDirectories(fileMgr.release(), path.substring(0, lastDivPos))) + if (!makeAllDirectories(fileManager, path.substring(0, lastDivPos))) return false; } @@ -152,10 +152,10 @@ static bool makeAllDirectories(PassOwnPtr<IFileMgr> fileMgr, const String& path) // IFILEMGR_MkDir return SUCCESS when the file is successfully created or if file already exists. // So we need to check fileinfo.attrib. - IFILEMGR_MkDir(fileMgr.get(), folder.utf8().data()); + IFILEMGR_MkDir(fileManager, folder.utf8().data()); FileInfo fileInfo; - if (IFILEMGR_GetInfo(fileMgr.get(), folder.utf8().data(), &fileInfo) != SUCCESS) + if (IFILEMGR_GetInfo(fileManager, folder.utf8().data(), &fileInfo) != SUCCESS) return false; return fileInfo.attrib & _FA_DIR; @@ -165,12 +165,13 @@ bool makeAllDirectories(const String& path) { OwnPtr<IFileMgr> fileMgr = createInstance<IFileMgr>(AEECLSID_FILEMGR); - return makeAllDirectories(fileMgr.release(), canonicalPath(path)); + return makeAllDirectories(fileMgr.get(), canonicalPath(path)); } String homeDirectoryPath() { - return String(AEEFS_HOME_DIR); + const int webViewClassId = 0x010aa04c; + return String::format("fs:/~0X%08X/", webViewClassId); } String pathGetFileName(const String& path) diff --git a/WebCore/platform/brew/LocalizedStringsBrew.cpp b/WebCore/platform/brew/LocalizedStringsBrew.cpp index 1bc5985..2dfd12b 100644 --- a/WebCore/platform/brew/LocalizedStringsBrew.cpp +++ b/WebCore/platform/brew/LocalizedStringsBrew.cpp @@ -96,6 +96,56 @@ String contextMenuItemTagCopyImageToClipboard() return "Copy image to clipboard"; } +String contextMenuItemTagOpenVideoInNewWindow() +{ + return "Open video in new window"; +} + +String contextMenuItemTagOpenAudioInNewWindow() +{ + return "Open audio in new window"; +} + +String contextMenuItemTagCopyVideoLinkToClipboard() +{ + return "Copy Video link location"; +} + +String contextMenuItemTagCopyAudioLinkToClipboard() +{ + return "Copy audio link location"; +} + +String contextMenuItemTagToggleMediaControls() +{ + return "Toggle media controls"; +} + +String contextMenuItemTagToggleMediaLoop() +{ + return "Toggle media loop playback"; +} + +String contextMenuItemTagEnterVideoFullscreen() +{ + return "Switch video to fullscreen"; +} + +String contextMenuItemTagMediaPlay() +{ + return "Play"; +} + +String contextMenuItemTagMediaPause() +{ + return "Pause"; +} + +String contextMenuItemTagMediaMute() +{ + return "Mute"; +} + String contextMenuItemTagOpenFrameInNewWindow() { return "Open frame in new window"; diff --git a/WebCore/platform/brew/PasteboardBrew.cpp b/WebCore/platform/brew/PasteboardBrew.cpp new file mode 100644 index 0000000..e5049b4 --- /dev/null +++ b/WebCore/platform/brew/PasteboardBrew.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2009 Company 100, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "config.h" +#include "Pasteboard.h" + +#include "DocumentFragment.h" +#include "NotImplemented.h" +#include "Range.h" + +#include <wtf/text/CString.h> + +namespace WebCore { + +Pasteboard* Pasteboard::generalPasteboard() +{ + static Pasteboard* pasteboard = new Pasteboard; + return pasteboard; +} + +Pasteboard::Pasteboard() +{ + notImplemented(); +} + +void Pasteboard::clear() +{ + notImplemented(); +} + +void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame) +{ + notImplemented(); +} + +void Pasteboard::writePlainText(const String& text) +{ + notImplemented(); +} + +void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame) +{ + notImplemented(); +} + +void Pasteboard::writeImage(Node* node, const KURL&, const String&) +{ + notImplemented(); +} + +bool Pasteboard::canSmartReplace() +{ + notImplemented(); + return false; +} + +String Pasteboard::plainText(Frame* frame) +{ + notImplemented(); + return String(); +} + +PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText) +{ + notImplemented(); + return 0; +} + +} // namespace WebCore diff --git a/WebCore/platform/brew/PlatformKeyboardEventBrew.cpp b/WebCore/platform/brew/PlatformKeyboardEventBrew.cpp index d7a1279..3384a4f 100644 --- a/WebCore/platform/brew/PlatformKeyboardEventBrew.cpp +++ b/WebCore/platform/brew/PlatformKeyboardEventBrew.cpp @@ -98,6 +98,8 @@ static String keyIdentifierForBrewKeyCode(uint16 keyCode) return "PageUp"; case AVK_TXPGDOWN: return "PageDown"; + case AVK_FUNCTION: + return "U+0009"; default: return String::format("U+%04X", toASCIIUpper(keyCode)); } @@ -132,6 +134,8 @@ static int windowsKeyCodeForKeyEvent(uint16 code) return VK_INSERT; // (2D) INS key case AVK_TXDELETE: return VK_DELETE; // (2E) DEL key + case AVK_FUNCTION: + return VK_TAB; // (09) TAB key default: return 0; } diff --git a/WebCore/platform/brew/PlatformTouchEventBrew.cpp b/WebCore/platform/brew/PlatformTouchEventBrew.cpp new file mode 100644 index 0000000..9f31dae --- /dev/null +++ b/WebCore/platform/brew/PlatformTouchEventBrew.cpp @@ -0,0 +1,76 @@ +/* + * Copyright 2010, Company 100, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PlatformTouchEvent.h" + +#include <AEEEvent.h> +#include <AEEPointerHelpers.h> +#include <AEEVCodes.h> + +#if ENABLE(TOUCH_EVENTS) + +namespace WebCore { + +PlatformTouchEvent::PlatformTouchEvent(AEEEvent event, uint16 wParam, uint32 dwParam) + : m_metaKey(false) +{ + PlatformTouchPoint::State state; + + switch (event) { + case EVT_POINTER_DOWN: + m_type = TouchStart; + state = PlatformTouchPoint::TouchPressed; + break; + case EVT_POINTER_UP: + m_type = TouchEnd; + state = PlatformTouchPoint::TouchReleased; + break; + case EVT_POINTER_MOVE: + case EVT_POINTER_STALE_MOVE: + m_type = TouchMove; + state = PlatformTouchPoint::TouchMoved; + break; + default: + ASSERT_NOT_REACHED(); + } + + char* dwParamStr = reinterpret_cast<char*>(dwParam); + int x, y; + AEE_POINTER_GET_XY(dwParamStr, &x, &y); + IntPoint windowPos = IntPoint(x, y); + + int id = AEE_POINTER_GET_PTRID(dwParamStr); + m_touchPoints.append(PlatformTouchPoint(id, windowPos, state)); + + uint32 keyModifiers = AEE_POINTER_GET_KEY_MODIFIERS(dwParamStr); + m_altKey = keyModifiers & (KB_LALT | KB_RALT); + m_shiftKey = keyModifiers & (KB_LSHIFT | KB_RSHIFT); + m_ctrlKey = keyModifiers & (KB_LCTRL | KB_RCTRL); +} + +} + +#endif diff --git a/WebCore/platform/brew/PlatformTouchPointBrew.cpp b/WebCore/platform/brew/PlatformTouchPointBrew.cpp new file mode 100644 index 0000000..6943182 --- /dev/null +++ b/WebCore/platform/brew/PlatformTouchPointBrew.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2010, Company 100, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PlatformTouchPoint.h" + +#if ENABLE(TOUCH_EVENTS) + +namespace WebCore { + +PlatformTouchPoint::PlatformTouchPoint(int id, const IntPoint& windowPos, State state) + : m_id(id) + , m_state(state) + , m_screenPos(windowPos) + , m_pos(windowPos) { } + +} + +#endif diff --git a/WebCore/platform/chromium/ChromiumBridge.h b/WebCore/platform/chromium/ChromiumBridge.h index 894799c..121ec4b 100644 --- a/WebCore/platform/chromium/ChromiumBridge.h +++ b/WebCore/platform/chromium/ChromiumBridge.h @@ -143,7 +143,7 @@ namespace WebCore { #if OS(WINDOWS) static bool ensureFontLoaded(HFONT font); #endif -#if OS(LINUX) +#if OS(LINUX) || OS(FREEBSD) static void getRenderStyleForStrike(const char* family, int sizeAndStyle, FontRenderStyle* result); static String getFontFamilyForCharacters(const UChar*, size_t numCharacters); #endif diff --git a/WebCore/platform/chromium/ClipboardChromium.cpp b/WebCore/platform/chromium/ClipboardChromium.cpp index 3d82aea..c2ec80c 100644 --- a/WebCore/platform/chromium/ClipboardChromium.cpp +++ b/WebCore/platform/chromium/ClipboardChromium.cpp @@ -93,23 +93,23 @@ static ClipboardDataType clipboardTypeFromMIMEType(const String& type) PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* dragData, Frame* frame) { - return ClipboardChromium::create(true, dragData->platformData(), policy, frame); + return ClipboardChromium::create(DragAndDrop, dragData->platformData(), policy, frame); } -ClipboardChromium::ClipboardChromium(bool isForDragging, +ClipboardChromium::ClipboardChromium(ClipboardType clipboardType, PassRefPtr<ChromiumDataObject> dataObject, ClipboardAccessPolicy policy, Frame* frame) - : Clipboard(policy, isForDragging) + : Clipboard(policy, clipboardType) , m_dataObject(dataObject) , m_frame(frame) { } -PassRefPtr<ClipboardChromium> ClipboardChromium::create(bool isForDragging, +PassRefPtr<ClipboardChromium> ClipboardChromium::create(ClipboardType clipboardType, PassRefPtr<ChromiumDataObject> dataObject, ClipboardAccessPolicy policy, Frame* frame) { - return adoptRef(new ClipboardChromium(isForDragging, dataObject, policy, frame)); + return adoptRef(new ClipboardChromium(clipboardType, dataObject, policy, frame)); } void ClipboardChromium::clearData(const String& type) @@ -203,9 +203,7 @@ String ClipboardChromium::getData(const String& type, bool& success) const return m_dataObject->downloadMetadata; case ClipboardDataTypePlainText: - if (!isForDragging()) { - // If this isn't for a drag, it's for a cut/paste event handler. - // In this case, we need to check the clipboard. + if (isForCopyAndPaste()) { PasteboardPrivate::ClipboardBuffer buffer = Pasteboard::generalPasteboard()->isSelectionMode() ? PasteboardPrivate::SelectionBuffer : @@ -219,9 +217,7 @@ String ClipboardChromium::getData(const String& type, bool& success) const return m_dataObject->plainText; case ClipboardDataTypeHTML: - if (!isForDragging()) { - // If this isn't for a drag, it's for a cut/paste event handler. - // In this case, we need to check the clipboard. + if (isForCopyAndPaste()) { PasteboardPrivate::ClipboardBuffer buffer = Pasteboard::generalPasteboard()->isSelectionMode() ? PasteboardPrivate::SelectionBuffer : diff --git a/WebCore/platform/chromium/ClipboardChromium.h b/WebCore/platform/chromium/ClipboardChromium.h index a4150d0..14f59e9 100644 --- a/WebCore/platform/chromium/ClipboardChromium.h +++ b/WebCore/platform/chromium/ClipboardChromium.h @@ -46,7 +46,7 @@ namespace WebCore { ~ClipboardChromium() {} static PassRefPtr<ClipboardChromium> create( - bool isForDragging, PassRefPtr<ChromiumDataObject>, ClipboardAccessPolicy, Frame*); + ClipboardType, PassRefPtr<ChromiumDataObject>, ClipboardAccessPolicy, Frame*); // Returns the file name (not including the extension). This removes any // invalid file system characters as well as making sure the @@ -80,7 +80,7 @@ namespace WebCore { virtual bool hasData(); private: - ClipboardChromium(bool, PassRefPtr<ChromiumDataObject>, ClipboardAccessPolicy, Frame*); + ClipboardChromium(ClipboardType, PassRefPtr<ChromiumDataObject>, ClipboardAccessPolicy, Frame*); void resetFromClipboard(); void setDragImage(CachedImage*, Node*, const IntPoint&); diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp index 19b4a54..d8f2c79 100644 --- a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp +++ b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp @@ -115,7 +115,7 @@ void ScrollbarThemeChromiumLinux::paintButton(GraphicsContext* gc, Scrollbar* sc ControlStates states = 0; // Determine if the button can be pressed. if (((direction == PlatformThemeChromiumGtk::West || direction == PlatformThemeChromiumGtk::North) && scrollbar->currentPos()) - || (direction == PlatformThemeChromiumGtk::East || direction == PlatformThemeChromiumGtk::South) && scrollbar->currentPos() != scrollbar->maximum()) + || ((direction == PlatformThemeChromiumGtk::East || direction == PlatformThemeChromiumGtk::South) && scrollbar->currentPos() != scrollbar->maximum())) states |= EnabledState; if (states & EnabledState) { diff --git a/WebCore/platform/efl/ClipboardEfl.cpp b/WebCore/platform/efl/ClipboardEfl.cpp index 6fc80dc..a7c2a54 100644 --- a/WebCore/platform/efl/ClipboardEfl.cpp +++ b/WebCore/platform/efl/ClipboardEfl.cpp @@ -29,7 +29,7 @@ namespace WebCore { PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy, Frame*) { - return ClipboardEfl::create(policy, false); + return ClipboardEfl::create(policy, Clipboard::CopyAndPaste); } PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy, DragData*, Frame*) @@ -37,8 +37,8 @@ PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy, DragData*, Frame* return 0; } -ClipboardEfl::ClipboardEfl(ClipboardAccessPolicy policy, bool forDragging) - : Clipboard(policy, forDragging) +ClipboardEfl::ClipboardEfl(ClipboardAccessPolicy policy, ClipboardType clipboardType) + : Clipboard(policy, clipboardType) { notImplemented(); } diff --git a/WebCore/platform/efl/ClipboardEfl.h b/WebCore/platform/efl/ClipboardEfl.h index 5db2fed..06f4e58 100644 --- a/WebCore/platform/efl/ClipboardEfl.h +++ b/WebCore/platform/efl/ClipboardEfl.h @@ -28,9 +28,9 @@ class CachedImage; class ClipboardEfl : public Clipboard { public: - static PassRefPtr<ClipboardEfl> create(ClipboardAccessPolicy policy, bool forDragging = false) + static PassRefPtr<ClipboardEfl> create(ClipboardAccessPolicy policy, ClipboardType clipboardType = CopyAndPaste) { - return adoptRef(new ClipboardEfl(policy, forDragging)); + return adoptRef(new ClipboardEfl(policy, clipboardType)); } ~ClipboardEfl(); @@ -58,7 +58,7 @@ public: virtual void writePlainText(const WTF::String&); private: - ClipboardEfl(ClipboardAccessPolicy, bool); + ClipboardEfl(ClipboardAccessPolicy, ClipboardType); }; } diff --git a/WebCore/platform/efl/LocalizedStringsEfl.cpp b/WebCore/platform/efl/LocalizedStringsEfl.cpp index 6023205..a81434f 100644 --- a/WebCore/platform/efl/LocalizedStringsEfl.cpp +++ b/WebCore/platform/efl/LocalizedStringsEfl.cpp @@ -98,6 +98,56 @@ String contextMenuItemTagCopyImageToClipboard() return String::fromUTF8("Copy Image"); } +String contextMenuItemTagOpenVideoInNewWindow() +{ + return String::fromUTF8("Open Video in New Window"); +} + +String contextMenuItemTagOpenAudioInNewWindow() +{ + return String::fromUTF8("Open Audio in New Window"); +} + +String contextMenuItemTagCopyVideoLinkToClipboard() +{ + return String::fromUTF8("Copy Video Link Location"); +} + +String contextMenuItemTagCopyAudioLinkToClipboard() +{ + return String::fromUTF8("Copy Audio Link Location"); +} + +String contextMenuItemTagToggleMediaControls() +{ + return String::fromUTF8("Toggle Media Controls"); +} + +String contextMenuItemTagToggleMediaLoop() +{ + return String::fromUTF8("Toggle Media Loop Playback"); +} + +String contextMenuItemTagEnterVideoFullscreen() +{ + return String::fromUTF8("Switch Video to Fullscreen"); +} + +String contextMenuItemTagMediaPlay() +{ + return String::fromUTF8("Play"); +} + +String contextMenuItemTagMediaPause() +{ + return String::fromUTF8("Pause"); +} + +String contextMenuItemTagMediaMute() +{ + return String::fromUTF8("Mute"); +} + String contextMenuItemTagOpenFrameInNewWindow() { return String::fromUTF8("Open Frame in New Window"); diff --git a/WebCore/platform/efl/RenderThemeEfl.cpp b/WebCore/platform/efl/RenderThemeEfl.cpp index 102f754..53997be 100644 --- a/WebCore/platform/efl/RenderThemeEfl.cpp +++ b/WebCore/platform/efl/RenderThemeEfl.cpp @@ -78,7 +78,7 @@ bool RenderThemeEfl::themePartCacheEntryReset(struct ThemePartCacheEntry* ce, Fo ASSERT(group); if (!edje_object_file_set(ce->o, file, group)) { - int err = edje_object_load_error_get(ce->o); + Edje_Load_Error err = edje_object_load_error_get(ce->o); const char *errmsg = edje_load_error_str(err); EINA_LOG_ERR("Could not load '%s' from theme %s: %s", group, file, errmsg); @@ -421,7 +421,7 @@ void RenderThemeEfl::createEdje() if (!m_edje) EINA_LOG_ERR("Could not create base edje object."); else if (!edje_object_file_set(m_edje, theme.utf8().data(), "webkit/base")) { - int err = edje_object_load_error_get(m_edje); + Edje_Load_Error err = edje_object_load_error_get(m_edje); const char* errmsg = edje_load_error_str(err); EINA_LOG_ERR("Could not load 'webkit/base' from theme %s: %s", theme.utf8().data(), errmsg); @@ -600,7 +600,7 @@ void RenderThemeEfl::applyPartDescriptions() const char* group = edjeGroupFromFormType(type); m_partDescs[i].type = type; if (!edje_object_file_set(o, file, group)) { - int err = edje_object_load_error_get(o); + Edje_Load_Error err = edje_object_load_error_get(o); const char* errmsg = edje_load_error_str(err); EINA_LOG_ERR("Could not set theme group '%s' of file '%s': %s", group, file, errmsg); diff --git a/WebCore/platform/efl/ScrollbarEfl.cpp b/WebCore/platform/efl/ScrollbarEfl.cpp index 6b00a37..282ca7c 100644 --- a/WebCore/platform/efl/ScrollbarEfl.cpp +++ b/WebCore/platform/efl/ScrollbarEfl.cpp @@ -122,7 +122,7 @@ void ScrollbarEfl::setParent(ScrollView* view) } if (!edje_object_file_set(o, theme.utf8().data(), group)) { - int err = edje_object_load_error_get(o); + Edje_Load_Error err = edje_object_load_error_get(o); const char* errmsg = edje_load_error_str(err); EINA_LOG_ERR("Could not load theme '%s' from file '%s': #%d '%s'", group, theme.utf8().data(), err, errmsg); diff --git a/WebCore/platform/graphics/Color.cpp b/WebCore/platform/graphics/Color.cpp index 80c8286..f28d51c 100644 --- a/WebCore/platform/graphics/Color.cpp +++ b/WebCore/platform/graphics/Color.cpp @@ -26,13 +26,12 @@ #include "config.h" #include "Color.h" +#include "HashTools.h" #include "PlatformString.h" #include <math.h> #include <wtf/Assertions.h> #include <wtf/MathExtras.h> -#include "ColorData.cpp" - using namespace std; using namespace WTF; diff --git a/WebCore/platform/graphics/qt/ContextShadow.cpp b/WebCore/platform/graphics/ContextShadow.cpp index 4609923..1007962 100644 --- a/WebCore/platform/graphics/qt/ContextShadow.cpp +++ b/WebCore/platform/graphics/ContextShadow.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 Sencha, Inc. + * Copyright (C) 2010 Igalia S.L. * * All rights reserved. * @@ -28,115 +29,50 @@ #include "config.h" #include "ContextShadow.h" -#include <QTimerEvent> +#include <wtf/MathExtras.h> #include <wtf/Noncopyable.h> -namespace WebCore { - -// ContextShadow needs a scratch image as the buffer for the blur filter. -// Instead of creating and destroying the buffer for every operation, -// we create a buffer which will be automatically purged via a timer. - -class ShadowBuffer: public QObject { -public: - ShadowBuffer(QObject* parent = 0); - - QImage* scratchImage(const QSize& size); - - void schedulePurge(); - -protected: - void timerEvent(QTimerEvent* event); - -private: - QImage image; - int timerId; -}; - -ShadowBuffer::ShadowBuffer(QObject* parent) - : QObject(parent) - , timerId(0) -{ -} - -QImage* ShadowBuffer::scratchImage(const QSize& size) -{ - int width = size.width(); - int height = size.height(); - - // We do not need to recreate the buffer if the buffer is reasonably - // larger than the requested size. However, if the requested size is - // much smaller than our buffer, reduce our buffer so that we will not - // keep too many allocated pixels for too long. - if (!image.isNull() && (image.width() > width) && (image.height() > height)) - if (((2 * width) > image.width()) && ((2 * height) > image.height())) { - image.fill(Qt::transparent); - return ℑ - } - - // Round to the nearest 32 pixels so we do not grow the buffer everytime - // there is larger request by 1 pixel. - width = (1 + (width >> 5)) << 5; - height = (1 + (height >> 5)) << 5; - - image = QImage(width, height, QImage::Format_ARGB32_Premultiplied); - image.fill(Qt::transparent); - return ℑ -} - -void ShadowBuffer::schedulePurge() -{ - static const double BufferPurgeDelay = 2; // seconds - killTimer(timerId); - timerId = startTimer(BufferPurgeDelay * 1000); -} - -void ShadowBuffer::timerEvent(QTimerEvent* event) -{ - if (event->timerId() == timerId) { - killTimer(timerId); - image = QImage(); - } - QObject::timerEvent(event); -} +using WTF::min; +using WTF::max; -Q_GLOBAL_STATIC(ShadowBuffer, scratchShadowBuffer) +namespace WebCore { ContextShadow::ContextShadow() - : type(NoShadow) - , blurRadius(0) + : m_type(NoShadow) + , m_blurRadius(0) { } -ContextShadow::ContextShadow(const QColor& c, float r, qreal dx, qreal dy) - : color(c) - , blurRadius(qRound(r)) - , offset(dx, dy) +ContextShadow::ContextShadow(const Color& color, float radius, const FloatSize& offset) + : m_color(color) + , m_blurRadius(round(radius)) + , m_offset(offset) { + // See comments in http://webkit.org/b/40793, it seems sensible + // to follow Skia's limit of 128 pixels of blur radius + m_blurRadius = min(m_blurRadius, 128); + // The type of shadow is decided by the blur radius, shadow offset, and shadow color. - if (!color.isValid() || !color.alpha()) { + if (!m_color.isValid() || !color.alpha()) { // Can't paint the shadow with invalid or invisible color. - type = NoShadow; - } else if (r > 0) { + m_type = NoShadow; + } else if (radius > 0) { // Shadow is always blurred, even the offset is zero. - type = BlurShadow; - } else if (offset.isNull()) { + m_type = BlurShadow; + } else if (!m_offset.width() && !m_offset.height()) { // Without blur and zero offset means the shadow is fully hidden. - type = NoShadow; + m_type = NoShadow; } else { - if (color.alpha() > 0) - type = AlphaSolidShadow; - else - type = OpaqueSolidShadow; + m_type = SolidShadow; } } void ContextShadow::clear() { - type = NoShadow; - color = QColor(); - blurRadius = 0; - offset = QPointF(0, 0); + m_type = NoShadow; + m_color = Color(); + m_blurRadius = 0; + m_offset = FloatSize(); } // Instead of integer division, we use 17.15 for fixed-point division. @@ -146,27 +82,22 @@ static const int BlurSumShift = 15; // As noted in the SVG filter specification, running box blur 3x // approximates a real gaussian blur nicely. -void shadowBlur(QImage& image, int radius, const QColor& shadowColor) +void ContextShadow::blurLayerImage(unsigned char* imageData, const IntSize& size, int rowStride) { - // See comments in http://webkit.org/b/40793, it seems sensible - // to follow Skia's limit of 128 pixels for the blur radius. - if (radius > 128) - radius = 128; - int channels[4] = { 3, 0, 1, 3 }; - int dmax = radius >> 1; - int dmin = dmax - 1 + (radius & 1); + int dmax = m_blurRadius >> 1; + int dmin = dmax - 1 + (m_blurRadius & 1); if (dmin < 0) dmin = 0; // Two stages: horizontal and vertical for (int k = 0; k < 2; ++k) { - unsigned char* pixels = image.bits(); - int stride = (!k) ? 4 : image.bytesPerLine(); - int delta = (!k) ? image.bytesPerLine() : 4; - int jfinal = (!k) ? image.height() : image.width(); - int dim = (!k) ? image.width() : image.height(); + unsigned char* pixels = imageData; + int stride = (!k) ? 4 : rowStride; + int delta = (!k) ? rowStride : 4; + int jfinal = (!k) ? size.height() : size.width(); + int dim = (!k) ? size.width() : size.height(); for (int j = 0; j < jfinal; ++j, pixels += delta) { @@ -213,74 +144,31 @@ void shadowBlur(QImage& image, int radius, const QColor& shadowColor) } } } - - // "Colorize" with the right shadow color. - QPainter p(&image); - p.setCompositionMode(QPainter::CompositionMode_SourceIn); - p.fillRect(image.rect(), shadowColor.rgb()); - p.end(); } -QPainter* ContextShadow::beginShadowLayer(QPainter* p, const QRectF &rect) +void ContextShadow::calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect) { - // We expand the area by the blur radius * 2 to give extra space - // for the blur transition. - int extra = (type == BlurShadow) ? blurRadius * 2 : 0; - - QRectF shadowRect = rect.translated(offset); - QRectF bufferRect = shadowRect.adjusted(-extra, -extra, extra, extra); - m_layerRect = bufferRect.toAlignedRect(); + // Calculate the destination of the blurred layer. + FloatRect destinationRect(layerArea); + destinationRect.move(m_offset); + m_layerRect = enclosingIntRect(destinationRect); - QRect clipRect; - if (p->hasClipping()) -#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0) - clipRect = p->clipBoundingRect(); -#else - clipRect = p->clipRegion().boundingRect(); -#endif - else - clipRect = p->transform().inverted().mapRect(p->window()); + // We expand the area by the blur radius * 2 to give extra space for the blur transition. + m_layerRect.inflate((m_type == BlurShadow) ? ceil(m_blurRadius * 2) : 0); if (!clipRect.contains(m_layerRect)) { - // No need to have the buffer larger than the clip. - m_layerRect = m_layerRect.intersected(clipRect); + m_layerRect.intersect(clipRect); + + // If we are totally outside the clip region, we aren't painting at all. if (m_layerRect.isEmpty()) - return 0; + return; // We adjust again because the pixels at the borders are still // potentially affected by the pixels outside the buffer. - if (type == BlurShadow) - m_layerRect.adjust(-extra, -extra, extra, extra); + if (m_type == BlurShadow) + m_layerRect.inflate((m_type == BlurShadow) ? ceil(m_blurRadius * 2) : 0); } - - ShadowBuffer* shadowBuffer = scratchShadowBuffer(); - QImage* shadowImage = shadowBuffer->scratchImage(m_layerRect.size()); - m_layerImage = QImage(*shadowImage); - - m_layerPainter = new QPainter; - m_layerPainter->begin(&m_layerImage); - m_layerPainter->setFont(p->font()); - m_layerPainter->translate(offset); - - // The origin is now the top left corner of the scratch image. - m_layerPainter->translate(-m_layerRect.topLeft()); - - return m_layerPainter; } -void ContextShadow::endShadowLayer(QPainter* p) -{ - m_layerPainter->end(); - delete m_layerPainter; - m_layerPainter = 0; - - if (type == BlurShadow) - shadowBlur(m_layerImage, blurRadius, color); - - p->drawImage(m_layerRect.topLeft(), m_layerImage); - - scratchShadowBuffer()->schedulePurge(); -} - -} +} // namespace WebCore diff --git a/WebCore/platform/graphics/qt/ContextShadow.h b/WebCore/platform/graphics/ContextShadow.h index 7140340..ede9336 100644 --- a/WebCore/platform/graphics/qt/ContextShadow.h +++ b/WebCore/platform/graphics/ContextShadow.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 Sencha, Inc. + * Copyright (C) 2010 Igalia S.L. * * All rights reserved. * @@ -28,7 +29,22 @@ #ifndef ContextShadow_h #define ContextShadow_h -#include <QPainter> +#include "Color.h" +#include "FloatRect.h" +#include "IntRect.h" +#include "RefCounted.h" + +#if PLATFORM(CAIRO) +typedef struct _cairo cairo_t; +typedef struct _cairo_surface cairo_surface_t; +typedef cairo_surface_t* PlatformImage; +typedef cairo_t* PlatformContext; +#elif PLATFORM(QT) +#include <QImage> +class QPainter; +typedef QImage PlatformImage; +typedef QPainter* PlatformContext; +#endif namespace WebCore { @@ -44,49 +60,57 @@ class ContextShadow { public: enum { NoShadow, - OpaqueSolidShadow, - AlphaSolidShadow, + SolidShadow, BlurShadow - } type; + } m_type; - QColor color; - int blurRadius; - QPointF offset; + Color m_color; + int m_blurRadius; + FloatSize m_offset; ContextShadow(); - ContextShadow(const QColor& c, float r, qreal dx, qreal dy); + ContextShadow(const Color&, float radius, const FloatSize& offset); void clear(); // The pair beginShadowLayer and endShadowLayer creates a temporary image - // where the caller can draw onto, using the returned QPainter. This - // QPainter instance must be used only to draw between the call to - // beginShadowLayer and endShadowLayer. + // where the caller can draw onto, using the returned context. This context + // must be used only to draw between the call to beginShadowLayer and + // endShadowLayer. // - // Note: multiple/nested shadow layer is NOT allowed. + // Note: multiple/nested shadow layers are NOT allowed. // // The current clip region will be used to optimize the size of the - // temporary image. Thus, the original painter should not change any - // clipping until endShadowLayer. - // If the shadow will be completely outside the clipping region, - // beginShadowLayer will return 0. + // temporary image. Thus, the original context should not change any + // clipping until endShadowLayer. If the shadow will be completely outside + // the clipping region, beginShadowLayer will return 0. // - // The returned QPainter will have the transformation matrix and clipping - // properly initialized to start doing the painting (no need to account - // for the shadow offset), however it will not have the same render hints, - // pen, brush, etc as the passed QPainter. This is intentional, usually - // shadow has different properties than the shape which casts the shadow. + // The returned context will have the transformation matrix and clipping + // properly initialized to start doing the painting (no need to account for + // the shadow offset), however it will not have the same render hints, pen, + // brush, etc as the passed context. This is intentional, usually shadows + // have different properties than the shapes which cast them. // - // Once endShadowLayer is called, the temporary image will be drawn - // with the original painter. If blur radius is specified, the shadow - // will be filtered first. - QPainter* beginShadowLayer(QPainter* p, const QRectF& rect); - void endShadowLayer(QPainter* p); + // Once endShadowLayer is called, the temporary image will be drawn with the + // original context. If blur radius is specified, the shadow will be + // filtered first. + + PlatformContext beginShadowLayer(PlatformContext, const FloatRect& layerArea); + void endShadowLayer(PlatformContext); + static void purgeScratchBuffer(); + +#if PLATFORM(QT) + QPointF offset() { return QPointF(m_offset.width(), m_offset.height()); } +#endif + private: - QRect m_layerRect; - QImage m_layerImage; - QPainter* m_layerPainter; + IntRect m_layerRect; + PlatformImage m_layerImage; + PlatformContext m_layerContext; + + void blurLayerImage(unsigned char*, const IntSize& imageSize, int stride); + void calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect); }; } // namespace WebCore diff --git a/WebCore/platform/graphics/Font.h b/WebCore/platform/graphics/Font.h index d6cf140..1a321bd 100644 --- a/WebCore/platform/graphics/Font.h +++ b/WebCore/platform/graphics/Font.h @@ -191,8 +191,8 @@ public: } FontSelector* fontSelector() const; - static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0; } - static bool treatAsZeroWidthSpace(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || (c >= 0x200c && c <= 0x200f) || (c >= 0x202a && c <= 0x202e) || c == 0xFFFC; } + static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == noBreakSpace; } + static bool treatAsZeroWidthSpace(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == softHyphen || (c >= 0x200c && c <= 0x200f) || (c >= 0x202a && c <= 0x202e) || c == objectReplacementCharacter; } static inline UChar normalizeSpaces(UChar character) { diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/WebCore/platform/graphics/GlyphPageTreeNode.cpp index dac26b3..3df14b9 100644 --- a/WebCore/platform/graphics/GlyphPageTreeNode.cpp +++ b/WebCore/platform/graphics/GlyphPageTreeNode.cpp @@ -171,6 +171,7 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu buffer[i] = zeroWidthSpace; for (i = 0x7F; i < 0xA0; i++) buffer[i] = zeroWidthSpace; + buffer[softHyphen] = zeroWidthSpace; // \n, \t, and nonbreaking space must render as a space. buffer[(int)'\n'] = ' '; diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h index 7863b95..fd3bf2c 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -108,12 +108,6 @@ typedef unsigned char UInt8; #endif #endif -#if PLATFORM(CHROMIUM) -#define CanvasInterpolationQuality InterpolationMedium -#else -#define CanvasInterpolationQuality InterpolationDefault -#endif - #if PLATFORM(QT) && defined(Q_WS_WIN) #include <windows.h> #endif diff --git a/WebCore/platform/graphics/GraphicsContext3D.cpp b/WebCore/platform/graphics/GraphicsContext3D.cpp index 2da5862..86e9569 100644 --- a/WebCore/platform/graphics/GraphicsContext3D.cpp +++ b/WebCore/platform/graphics/GraphicsContext3D.cpp @@ -255,6 +255,14 @@ void unpackRGB8ToRGBA8(const uint8_t* source, uint8_t* destination) destination[3] = 0xFF; } +void unpackARGB8ToRGBA8(const uint8_t* source, uint8_t* destination) +{ + destination[0] = source[1]; + destination[1] = source[2]; + destination[2] = source[3]; + destination[3] = source[0]; +} + void unpackBGRA8ToRGBA8(const uint8_t* source, uint8_t* destination) { destination[0] = source[2]; @@ -316,6 +324,14 @@ void unpackRA8ToRGBA8(const uint8_t* source, uint8_t* destination) destination[3] = source[1]; } +void unpackAR8ToRGBA8(const uint8_t* source, uint8_t* destination) +{ + destination[0] = source[1]; + destination[1] = source[1]; + destination[2] = source[1]; + destination[3] = source[0]; +} + void unpackA8ToRGBA8(const uint8_t* source, uint8_t* destination) { destination[0] = 0x0; @@ -634,6 +650,12 @@ static void doPacking(const void* sourceData, doUnpackingAndPacking<uint8_t, DestType, unpackRGB8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } + case GraphicsContext3D::kSourceFormatARGB8: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint8_t, DestType, unpackARGB8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } case GraphicsContext3D::kSourceFormatBGRA8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); @@ -670,6 +692,12 @@ static void doPacking(const void* sourceData, doUnpackingAndPacking<uint8_t, DestType, unpackRA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } + case GraphicsContext3D::kSourceFormatAR8: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint8_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint8_t, DestType, unpackAR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } case GraphicsContext3D::kSourceFormatA8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h index bcb7997..a12b1c4 100644 --- a/WebCore/platform/graphics/GraphicsContext3D.h +++ b/WebCore/platform/graphics/GraphicsContext3D.h @@ -537,11 +537,13 @@ public: kSourceFormatRGBA8, kSourceFormatRGB8, kSourceFormatBGRA8, + kSourceFormatARGB8, kSourceFormatRGBA5551, kSourceFormatRGBA4444, kSourceFormatRGB565, kSourceFormatR8, kSourceFormatRA8, + kSourceFormatAR8, kSourceFormatA8 }; @@ -834,14 +836,14 @@ public: int m_currentWidth, m_currentHeight; - typedef struct { - String source; - String log; +#if PLATFORM(MAC) + typedef struct { + String source; + String log; bool isValid; } ShaderSourceEntry; HashMap<Platform3DObject, ShaderSourceEntry> m_shaderSourceMap; -#if PLATFORM(MAC) ANGLEWebKitBridge m_compiler; Attributes m_attrs; diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp index b0f529b..412f06d 100644 --- a/WebCore/platform/graphics/GraphicsLayer.cpp +++ b/WebCore/platform/graphics/GraphicsLayer.cpp @@ -246,6 +246,12 @@ void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const I m_client->paintContents(this, context, m_paintingPhase, clip); } +String GraphicsLayer::animationNameForTransition(AnimatedPropertyID property) +{ + // | is not a valid identifier character in CSS, so this can never conflict with a keyframe identifier. + return String::format("-|transition%c-", property); +} + void GraphicsLayer::suspendAnimations(double) { } diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h index 04899f2..ad4d056 100644 --- a/WebCore/platform/graphics/GraphicsLayer.h +++ b/WebCore/platform/graphics/GraphicsLayer.h @@ -284,13 +284,16 @@ public: IntRect contentsRect() const { return m_contentsRect; } virtual void setContentsRect(const IntRect& r) { m_contentsRect = r; } + // Transitions are identified by a special animation name that cannot clash with a keyframe identifier. + static String animationNameForTransition(AnimatedPropertyID); + // Return true if the animation is handled by the compositing system. If this returns // false, the animation will be run by AnimationController. - virtual bool addAnimation(const KeyframeValueList&, const IntSize& /*boxSize*/, const Animation*, const String& /*keyframesName*/, double /*timeOffset*/) { return false; } - virtual void removeAnimationsForProperty(AnimatedPropertyID) { } - virtual void removeAnimationsForKeyframes(const String& /* keyframesName */) { } - virtual void pauseAnimation(const String& /* keyframesName */, double /*timeOffset*/) { } - + // These methods handle both transitions and keyframe animations. + virtual bool addAnimation(const KeyframeValueList&, const IntSize& /*boxSize*/, const Animation*, const String& /*animationName*/, double /*timeOffset*/) { return false; } + virtual void pauseAnimation(const String& /*animationName*/, double /*timeOffset*/) { } + virtual void removeAnimation(const String& /*animationName*/) { } + virtual void suspendAnimations(double time); virtual void resumeAnimations(); diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp index b4a669c..79c33e0 100644 --- a/WebCore/platform/graphics/MediaPlayer.cpp +++ b/WebCore/platform/graphics/MediaPlayer.cpp @@ -173,6 +173,12 @@ static Vector<MediaPlayerFactory*>& installedMediaEngines() #if PLATFORM(WIN) MediaPlayerPrivateQuickTimeVisualContext::registerMediaEngine(addMediaEngine); +#elif PLATFORM(QT) +#if USE(QT_MULTIMEDIA) + MediaPlayerPrivateQt::registerMediaEngine(addMediaEngine); +#else + MediaPlayerPrivatePhonon::registerMediaEngine(addMediaEngine); +#endif #elif !PLATFORM(GTK) && !PLATFORM(EFL) // FIXME: currently all the MediaEngines are named // MediaPlayerPrivate. This code will need an update when bug diff --git a/WebCore/platform/graphics/WidthIterator.cpp b/WebCore/platform/graphics/WidthIterator.cpp index ef047e8..ae58918 100644 --- a/WebCore/platform/graphics/WidthIterator.cpp +++ b/WebCore/platform/graphics/WidthIterator.cpp @@ -212,20 +212,29 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) // Force characters that are used to determine word boundaries for the rounding hack // to be integer width, so following words will start on an integer boundary. - if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c)) + if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c)) { width = ceilf(width); - // Check to see if the next character is a "rounding hack character", if so, adjust - // width so that the total run width will be on an integer boundary. - if ((m_run.applyWordRounding() && currentCharacter < m_run.length() && Font::isRoundingHackCharacter(*cp)) - || (m_run.applyRunRounding() && currentCharacter >= m_end)) { - float totalWidth = widthSinceLastRounding + width; - widthSinceLastRounding = ceilf(totalWidth); - width += widthSinceLastRounding - totalWidth; - m_runWidthSoFar += widthSinceLastRounding; - widthSinceLastRounding = 0; - } else - widthSinceLastRounding += width; + // Since widthSinceLastRounding can lose precision if we include measurements for + // preceding whitespace, we bypass it here. + m_runWidthSoFar += width; + + // Since this is a rounding hack character, we should have reset this sum on the previous + // iteration. + ASSERT(!widthSinceLastRounding); + } else { + // Check to see if the next character is a "rounding hack character", if so, adjust + // width so that the total run width will be on an integer boundary. + if ((m_run.applyWordRounding() && currentCharacter < m_run.length() && Font::isRoundingHackCharacter(*cp)) + || (m_run.applyRunRounding() && currentCharacter >= m_end)) { + float totalWidth = widthSinceLastRounding + width; + widthSinceLastRounding = ceilf(totalWidth); + width += widthSinceLastRounding - totalWidth; + m_runWidthSoFar += widthSinceLastRounding; + widthSinceLastRounding = 0; + } else + widthSinceLastRounding += width; + } if (glyphBuffer) glyphBuffer->add(glyph, fontData, (rtl ? oldWidth + lastRoundingWidth : width)); diff --git a/WebCore/platform/graphics/brew/ImageBrew.cpp b/WebCore/platform/graphics/brew/ImageBrew.cpp new file mode 100644 index 0000000..f5c855d --- /dev/null +++ b/WebCore/platform/graphics/brew/ImageBrew.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010, Company 100, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Image.h" + +#include "BitmapImage.h" +#include "FileSystem.h" +#include "SharedBuffer.h" + +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +PassRefPtr<Image> Image::loadPlatformResource(const char *name) +{ + String resourcePath = homeDirectoryPath() + String::format("res/%s.png", name); + + RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(resourcePath.utf8().data()); + if (!buffer) + return Image::nullImage(); + + RefPtr<Image> image = BitmapImage::create(); + image->setData(buffer, true); + return image.release(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/cairo/CairoUtilities.cpp b/WebCore/platform/graphics/cairo/CairoUtilities.cpp new file mode 100644 index 0000000..8c2049f --- /dev/null +++ b/WebCore/platform/graphics/cairo/CairoUtilities.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2010 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CairoUtilities.h" + +#include "Color.h" +#include <cairo.h> +#include <wtf/Vector.h> + +namespace WebCore { + +void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr) +{ + cairo_set_antialias(dstCr, cairo_get_antialias(srcCr)); + + size_t dashCount = cairo_get_dash_count(srcCr); + Vector<double> dashes(dashCount); + + double offset; + cairo_get_dash(srcCr, dashes.data(), &offset); + cairo_set_dash(dstCr, dashes.data(), dashCount, offset); + cairo_set_line_cap(dstCr, cairo_get_line_cap(srcCr)); + cairo_set_line_join(dstCr, cairo_get_line_join(srcCr)); + cairo_set_line_width(dstCr, cairo_get_line_width(srcCr)); + cairo_set_miter_limit(dstCr, cairo_get_miter_limit(srcCr)); + cairo_set_fill_rule(dstCr, cairo_get_fill_rule(srcCr)); +} + +void setSourceRGBAFromColor(cairo_t* context, const Color& color) +{ + float red, green, blue, alpha; + color.getRGBA(red, green, blue, alpha); + cairo_set_source_rgba(context, red, green, blue, alpha); +} + +} // namespace WebCore diff --git a/WebCore/platform/network/win/ResourceHandleWin.h b/WebCore/platform/graphics/cairo/CairoUtilities.h index 2964bcb..0675b90 100644 --- a/WebCore/platform/network/win/ResourceHandleWin.h +++ b/WebCore/platform/graphics/cairo/CairoUtilities.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2010 Igalia S.L. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -20,27 +20,20 @@ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ResourceHandleWin_h -#define ResourceHandleWin_h +#ifndef CairoUtilities_h +#define CairoUtilities_h -#include <windows.h> +typedef struct _cairo cairo_t; namespace WebCore { +class Color; -struct PlatformDataStruct -{ - DWORD error; - BOOL loaded; - LPTSTR errorString; -}; +void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr); +void setSourceRGBAFromColor(cairo_t*, const Color&); -struct PlatformResponseStruct -{ -}; +} // namespace WebCore -} - -#endif +#endif // CairoUtilities_h diff --git a/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp b/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp new file mode 100644 index 0000000..4b94cb3 --- /dev/null +++ b/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2010 Sencha, Inc. + * Copyright (C) 2010 Igalia S.L. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ContextShadow.h" + +#include "CairoUtilities.h" +#include "Timer.h" +#include <cairo.h> + +namespace WebCore { + +static cairo_surface_t* scratchBuffer = 0; +static void purgeScratchBuffer() +{ + cairo_surface_destroy(scratchBuffer); + scratchBuffer = 0; +} + +// ContextShadow needs a scratch image as the buffer for the blur filter. +// Instead of creating and destroying the buffer for every operation, +// we create a buffer which will be automatically purged via a timer. +class PurgeScratchBufferTimer : public TimerBase { +private: + virtual void fired() { purgeScratchBuffer(); } +}; +static PurgeScratchBufferTimer purgeScratchBufferTimer; +static void scheduleScratchBufferPurge() +{ + if (purgeScratchBufferTimer.isActive()) + purgeScratchBufferTimer.stop(); + purgeScratchBufferTimer.startOneShot(2); +} + +static cairo_surface_t* getScratchBuffer(const IntSize& size) +{ + int width = size.width(); + int height = size.height(); + int scratchWidth = scratchBuffer ? cairo_image_surface_get_width(scratchBuffer) : 0; + int scratchHeight = scratchBuffer ? cairo_image_surface_get_height(scratchBuffer) : 0; + + // We do not need to recreate the buffer if the current buffer is large enough. + if (scratchBuffer && scratchWidth >= width && scratchHeight >= height) + return scratchBuffer; + + purgeScratchBuffer(); + + // Round to the nearest 32 pixels so we do not grow the buffer for similar sized requests. + width = (1 + (width >> 5)) << 5; + height = (1 + (height >> 5)) << 5; + scratchBuffer = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + return scratchBuffer; +} + +PlatformContext ContextShadow::beginShadowLayer(PlatformContext context, const FloatRect& layerArea) +{ + double x1, x2, y1, y2; + cairo_clip_extents(context, &x1, &y1, &x2, &y2); + calculateLayerBoundingRect(layerArea, IntRect(x1, y1, x2 - x1, y2 - y1)); + + // Don't paint if we are totally outside the clip region. + if (m_layerRect.isEmpty()) + return 0; + + m_layerImage = getScratchBuffer(m_layerRect.size()); + m_layerContext = cairo_create(m_layerImage); + + // Always clear the surface first. + cairo_set_operator(m_layerContext, CAIRO_OPERATOR_CLEAR); + cairo_paint(m_layerContext); + cairo_set_operator(m_layerContext, CAIRO_OPERATOR_OVER); + + cairo_translate(m_layerContext, m_offset.width(), m_offset.height()); + cairo_translate(m_layerContext, -m_layerRect.x(), -m_layerRect.y()); + return m_layerContext; +} + +void ContextShadow::endShadowLayer(cairo_t* cr) +{ + cairo_destroy(m_layerContext); + m_layerContext = 0; + + if (m_type == BlurShadow) + blurLayerImage(cairo_image_surface_get_data(m_layerImage), + IntSize(cairo_image_surface_get_width(m_layerImage), cairo_image_surface_get_height(m_layerImage)), + cairo_image_surface_get_stride(m_layerImage)); + + cairo_save(cr); + setSourceRGBAFromColor(cr, m_color); + cairo_mask_surface(cr, m_layerImage, m_layerRect.x(), m_layerRect.y()); + cairo_restore(cr); + + // Schedule a purge of the scratch buffer. We do not need to destroy the surface. + scheduleScratchBufferPurge(); +} + +} diff --git a/WebCore/platform/graphics/cairo/FontCacheFreeType.cpp b/WebCore/platform/graphics/cairo/FontCacheFreeType.cpp index c09dd49..febad12 100644 --- a/WebCore/platform/graphics/cairo/FontCacheFreeType.cpp +++ b/WebCore/platform/graphics/cairo/FontCacheFreeType.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 Alp Toker <alp@atoker.com> + * Copyright (C) 2010 Igalia S.L. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,13 +27,17 @@ #include "OwnPtrCairo.h" #include "PlatformRefPtrCairo.h" #include "SimpleFontData.h" +#include <cairo-ft.h> +#include <cairo.h> +#include <fontconfig/fcfreetype.h> #include <wtf/Assertions.h> namespace WebCore { void FontCache::platformInit() { - if (!FontPlatformData::init()) + // It's fine to call FcInit multiple times per the documentation. + if (!FcInit()) ASSERT_NOT_REACHED(); } @@ -72,9 +77,9 @@ SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font) SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription) { - // FIXME: Would be even better to somehow get the user's default font here. - // For now we'll pick the default that the user would get without changing any prefs. - static AtomicString timesStr("Times New Roman"); + // We want to return a fallback font here, otherwise the logic preventing FontConfig + // matches for non-fallback fonts might return 0. See isFallbackFontAllowed. + static AtomicString timesStr("serif"); return getCachedFontData(fontDescription, timesStr); } @@ -82,54 +87,106 @@ void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigne { } -static bool isWellKnownFontName(const AtomicString family) +static CString getFamilyNameStringFromFontDescriptionAndFamily(const FontDescription& fontDescription, const AtomicString& family) { - // Fonts that are used by layout tests included. The fact that - // they are used in Layout Tests indicate web compatibility issues - // if we do not handle them correctly. - if (equalIgnoringCase(family, "sans-serif") || equalIgnoringCase(family, "sans") - || equalIgnoringCase(family, "serif") || equalIgnoringCase(family, "mono") - || equalIgnoringCase(family, "monospace") || equalIgnoringCase(family, "cursive") - || equalIgnoringCase(family, "fantasy") || equalIgnoringCase(family, "Times") - || equalIgnoringCase(family, "Courier") || equalIgnoringCase(family, "Helvetica") - || equalIgnoringCase(family, "Arial") || equalIgnoringCase(family, "Lucida Grande") - || equalIgnoringCase(family, "Ahem") || equalIgnoringCase(family, "Georgia") - || equalIgnoringCase(family, "Times New Roman")) - return true; - - return false; + // If we're creating a fallback font (e.g. "-webkit-monospace"), convert the name into + // the fallback name (like "monospace") that fontconfig understands. + if (family.length() && !family.startsWith("-webkit-")) + return family.string().utf8(); + + switch (fontDescription.genericFamily()) { + case FontDescription::StandardFamily: + case FontDescription::SerifFamily: + return "serif"; + case FontDescription::SansSerifFamily: + return "sans-serif"; + case FontDescription::MonospaceFamily: + return "monospace"; + case FontDescription::CursiveFamily: + return "cursive"; + case FontDescription::FantasyFamily: + return "fantasy"; + case FontDescription::NoFamily: + default: + return ""; + } } -FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) -{ - // Handle generic family types specially, because fontconfig does not know them, but we have - // code to fallback correctly in our platform data implementation. - if (!family.length() || family.startsWith("-webkit-") - || (fontDescription.genericFamily() != FontDescription::NoFamily) - || isWellKnownFontName(family)) - return new FontPlatformData(fontDescription, family); - // First check the font exists. - CString familyNameString = family.string().utf8(); - const char* fcfamily = familyNameString.data(); +static bool isFallbackFontAllowed(const CString& familyName) +{ + return !strcasecmp(familyName.data(), "sans") + || !strcasecmp(familyName.data(), "sans-serif") + || !strcasecmp(familyName.data(), "serif") + || !strcasecmp(familyName.data(), "monospace"); +} +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) +{ + // The CSS font matching algorithm (http://www.w3.org/TR/css3-fonts/#font-matching-algorithm) + // says that we must find an exact match for font family, slant (italic or oblique can be used) + // and font weight (we only match bold/non-bold here). PlatformRefPtr<FcPattern> pattern = adoptPlatformRef(FcPatternCreate()); - if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily))) + CString familyNameString = getFamilyNameStringFromFontDescriptionAndFamily(fontDescription, family); + if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(familyNameString.data()))) return 0; - OwnPtr<FcObjectSet> objectSet(FcObjectSetCreate()); - if (!FcObjectSetAdd(objectSet.get(), FC_FAMILY)) + bool italic = fontDescription.italic(); + if (!FcPatternAddInteger(pattern.get(), FC_SLANT, italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN)) + return 0; + bool bold = fontDescription.weight() >= FontWeightBold; + if (!FcPatternAddInteger(pattern.get(), FC_WEIGHT, bold ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL)) + return 0; + if (!FcPatternAddDouble(pattern.get(), FC_PIXEL_SIZE, fontDescription.computedPixelSize())) return 0; - OwnPtr<FcFontSet> fontSet(FcFontList(0, pattern.get(), objectSet.get())); - - if (!fontSet) + // The following comment and strategy are originally from Skia (src/ports/SkFontHost_fontconfig.cpp): + // Font matching: + // CSS often specifies a fallback list of families: + // font-family: a, b, c, serif; + // However, fontconfig will always do its best to find *a* font when asked + // for something so we need a way to tell if the match which it has found is + // "good enough" for us. Otherwise, we can return null which gets piped up + // and lets WebKit know to try the next CSS family name. However, fontconfig + // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we + // wish to support that. + // + // Thus, if a specific family is requested we set @family_requested. Then we + // record two strings: the family name after config processing and the + // family name after resolving. If the two are equal, it's a good match. + // + // So consider the case where a user has mapped Arial to Helvetica in their + // config. + // requested family: "Arial" + // post_config_family: "Helvetica" + // post_match_family: "Helvetica" + // -> good match + // + // and for a missing font: + // requested family: "Monaco" + // post_config_family: "Monaco" + // post_match_family: "Times New Roman" + // -> BAD match + // + FcConfigSubstitute(0, pattern.get(), FcMatchPattern); + FcDefaultSubstitute(pattern.get()); + + FcChar8* familyNameAfterConfiguration; + FcPatternGetString(pattern.get(), FC_FAMILY, 0, &familyNameAfterConfiguration); + + FcResult fontConfigResult; + PlatformRefPtr<FcPattern> resultPattern = adoptPlatformRef(FcFontMatch(0, pattern.get(), &fontConfigResult)); + if (!resultPattern) // No match. return 0; - if (!fontSet->fonts) + // Properly handle the situation where Fontconfig gives us a font that has a different family than we requested. + FcChar8* familyNameAfterMatching; + FcPatternGetString(resultPattern.get(), FC_FAMILY, 0, &familyNameAfterMatching); + if (strcasecmp(reinterpret_cast<char*>(familyNameAfterConfiguration), + reinterpret_cast<char*>(familyNameAfterMatching)) && !isFallbackFontAllowed(familyNameString)) return 0; - return new FontPlatformData(fontDescription, family); + return new FontPlatformData(resultPattern.get(), fontDescription); } } diff --git a/WebCore/platform/graphics/cairo/FontCustomPlatformData.cpp b/WebCore/platform/graphics/cairo/FontCustomPlatformData.cpp index 6b76c2a..0d195cb 100644 --- a/WebCore/platform/graphics/cairo/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/cairo/FontCustomPlatformData.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 Alp Toker <alp@atoker.com> + * Copyright (C) 2010 Igalia S.L. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -23,11 +24,37 @@ #include "FontPlatformData.h" #include "SharedBuffer.h" +#include <cairo-ft.h> +#include <cairo.h> namespace WebCore { +static void releaseCustomFontData(void* data) +{ + static_cast<SharedBuffer*>(data)->deref(); +} + +FontCustomPlatformData::FontCustomPlatformData(FT_Face freeTypeFace, SharedBuffer* buffer) + : m_freeTypeFace(freeTypeFace) + , m_fontFace(cairo_ft_font_face_create_for_ft_face(freeTypeFace, 0)) +{ + // FIXME Should we be setting some hinting options here? + + buffer->ref(); // This is balanced by the buffer->deref() in releaseCustomFontData. + static cairo_user_data_key_t bufferKey; + cairo_font_face_set_user_data(m_fontFace, &bufferKey, buffer, + static_cast<cairo_destroy_func_t>(releaseCustomFontData)); + + // Cairo doesn't do FreeType reference counting, so we need to ensure that when + // this cairo_font_face_t is destroyed, it cleans up the FreeType face as well. + static cairo_user_data_key_t freeTypeFaceKey; + cairo_font_face_set_user_data(m_fontFace, &freeTypeFaceKey, freeTypeFace, + reinterpret_cast<cairo_destroy_func_t>(FT_Done_Face)); +} + FontCustomPlatformData::~FontCustomPlatformData() { + // m_freeTypeFace will be destroyed along with m_fontFace. See the constructor. cairo_font_face_destroy(m_fontFace); } @@ -36,38 +63,20 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b return FontPlatformData(m_fontFace, size, bold, italic); } -static void releaseData(void* data) -{ - static_cast<SharedBuffer*>(data)->deref(); -} - FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) { ASSERT_ARG(buffer, buffer); - int error; - static FT_Library library = 0; - if (!library) { - error = FT_Init_FreeType(&library); - if (error) { - library = 0; - return 0; - } + if (!library && FT_Init_FreeType(&library)) { + library = 0; + return 0; } - FT_Face face; - error = FT_New_Memory_Face(library, reinterpret_cast<const FT_Byte*>(buffer->data()), buffer->size(), 0, &face); - if (error) + FT_Face freeTypeFace; + if (FT_New_Memory_Face(library, reinterpret_cast<const FT_Byte*>(buffer->data()), buffer->size(), 0, &freeTypeFace)) return 0; - - buffer->ref(); - cairo_font_face_t* fontFace = cairo_ft_font_face_create_for_ft_face(face, 0); - - static cairo_user_data_key_t bufferKey; - cairo_font_face_set_user_data(fontFace, &bufferKey, buffer, releaseData); - - return new FontCustomPlatformData(fontFace); + return new FontCustomPlatformData(freeTypeFace, buffer); } bool FontCustomPlatformData::supportsFormat(const String& format) diff --git a/WebCore/platform/graphics/cairo/FontCustomPlatformData.h b/WebCore/platform/graphics/cairo/FontCustomPlatformData.h index a72a6a4..c48d110 100644 --- a/WebCore/platform/graphics/cairo/FontCustomPlatformData.h +++ b/WebCore/platform/graphics/cairo/FontCustomPlatformData.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 Alp Toker <alp@atoker.com> + * Copyright (C) 2010 Igalia S.L. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,6 +26,7 @@ #include <wtf/Forward.h> #include <wtf/Noncopyable.h> +typedef struct FT_FaceRec_* FT_Face; typedef struct _cairo_font_face cairo_font_face_t; namespace WebCore { @@ -33,16 +35,14 @@ class FontPlatformData; class SharedBuffer; struct FontCustomPlatformData : Noncopyable { - FontCustomPlatformData(cairo_font_face_t* fontFace) - : m_fontFace(fontFace) - {} - +public: + FontCustomPlatformData(FT_Face, SharedBuffer*); ~FontCustomPlatformData(); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode); - static bool supportsFormat(const String&); +private: + FT_Face m_freeTypeFace; cairo_font_face_t* m_fontFace; }; diff --git a/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.cpp b/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.cpp index 7968966..0617e6c 100644 --- a/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.cpp +++ b/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.cpp @@ -3,7 +3,7 @@ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com> * Copyright (C) 2007 Holger Hans Peter Freyther - * Copyright (C) 2009 Igalia S.L. + * Copyright (C) 2009, 2010 Igalia S.L. * All rights reserved. * * This library is free software; you can redistribute it and/or @@ -27,100 +27,88 @@ #include "PlatformString.h" #include "FontDescription.h" -#include <wtf/text/CString.h> - #include <cairo-ft.h> #include <cairo.h> #include <fontconfig/fcfreetype.h> + #if !PLATFORM(EFL) || ENABLE(GLIB_SUPPORT) #include <gdk/gdk.h> #endif namespace WebCore { -FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName) - : m_fallbacks(0) +cairo_subpixel_order_t convertFontConfigSubpixelOrder(int fontConfigOrder) +{ + switch (fontConfigOrder) { + case FC_RGBA_RGB: + return CAIRO_SUBPIXEL_ORDER_RGB; + case FC_RGBA_BGR: + return CAIRO_SUBPIXEL_ORDER_BGR; + case FC_RGBA_VRGB: + return CAIRO_SUBPIXEL_ORDER_VRGB; + case FC_RGBA_VBGR: + return CAIRO_SUBPIXEL_ORDER_VBGR; + case FC_RGBA_NONE: + case FC_RGBA_UNKNOWN: + return CAIRO_SUBPIXEL_ORDER_DEFAULT; + } + return CAIRO_SUBPIXEL_ORDER_DEFAULT; +} + +cairo_hint_style_t convertFontConfigHintStyle(int fontConfigStyle) +{ + switch (fontConfigStyle) { + case FC_HINT_NONE: + return CAIRO_HINT_STYLE_NONE; + case FC_HINT_SLIGHT: + return CAIRO_HINT_STYLE_SLIGHT; + case FC_HINT_MEDIUM: + return CAIRO_HINT_STYLE_MEDIUM; + case FC_HINT_FULL: + return CAIRO_HINT_STYLE_FULL; + } + return CAIRO_HINT_STYLE_NONE; +} + +void setCairoFontOptionsFromFontConfigPattern(cairo_font_options_t* options, FcPattern* pattern) +{ + FcBool booleanResult; + int integerResult; + + // We will determine if subpixel anti-aliasing is enabled via the FC_RGBA setting. + if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &booleanResult) == FcResultMatch && booleanResult) + cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY); + + if (FcPatternGetInteger(pattern, FC_RGBA, 0, &integerResult) == FcResultMatch) { + if (integerResult != FC_RGBA_NONE) + cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_SUBPIXEL); + cairo_font_options_set_subpixel_order(options, convertFontConfigSubpixelOrder(integerResult)); + } + + if (FcPatternGetInteger(pattern, FC_HINT_STYLE, 0, &integerResult) == FcResultMatch) + cairo_font_options_set_hint_style(options, convertFontConfigHintStyle(integerResult)); + + if (FcPatternGetBool(pattern, FC_HINTING, 0, &booleanResult) == FcResultMatch && !booleanResult) + cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE); +} + +FontPlatformData::FontPlatformData(FcPattern* pattern, const FontDescription& fontDescription) + : m_pattern(pattern) + , m_fallbacks(0) , m_size(fontDescription.computedPixelSize()) , m_syntheticBold(false) , m_syntheticOblique(false) { - FontPlatformData::init(); - - CString familyNameString = familyName.string().utf8(); - const char* fcfamily = familyNameString.data(); - int fcslant = FC_SLANT_ROMAN; - // FIXME: Map all FontWeight values to fontconfig weights. - int fcweight = FC_WEIGHT_NORMAL; - double fcsize = fontDescription.computedPixelSize(); - if (fontDescription.italic()) - fcslant = FC_SLANT_ITALIC; - if (fontDescription.weight() >= FontWeight600) - fcweight = FC_WEIGHT_BOLD; - - int type = fontDescription.genericFamily(); - - PlatformRefPtr<FcPattern> pattern = adoptPlatformRef(FcPatternCreate()); - cairo_font_face_t* fontFace; - static const cairo_font_options_t* defaultOptions = cairo_font_options_create(); - const cairo_font_options_t* options = NULL; - cairo_matrix_t fontMatrix; - - if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily))) - return; - - switch (type) { - case FontDescription::SerifFamily: - fcfamily = "serif"; - break; - case FontDescription::SansSerifFamily: - fcfamily = "sans-serif"; - break; - case FontDescription::MonospaceFamily: - fcfamily = "monospace"; - break; - case FontDescription::StandardFamily: - fcfamily = "sans-serif"; - break; - case FontDescription::NoFamily: - default: - fcfamily = NULL; - break; - } + cairo_font_options_t* options = cairo_font_options_create(); + setCairoFontOptionsFromFontConfigPattern(options, pattern); - if (fcfamily && !FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily))) - return; - if (!FcPatternAddInteger(pattern.get(), FC_WEIGHT, fcweight)) - return; - if (!FcPatternAddInteger(pattern.get(), FC_SLANT, fcslant)) - return; - if (!FcPatternAddDouble(pattern.get(), FC_PIXEL_SIZE, fcsize)) - return; - - FcConfigSubstitute(0, pattern.get(), FcMatchPattern); - FcDefaultSubstitute(pattern.get()); - - FcResult fcresult; - m_pattern = adoptPlatformRef(FcFontMatch(0, pattern.get(), &fcresult)); - // FIXME: should we set some default font? - if (!m_pattern) - return; - fontFace = cairo_ft_font_face_create_for_pattern(m_pattern.get()); + cairo_matrix_t fontMatrix; + cairo_matrix_init_scale(&fontMatrix, m_size, m_size); cairo_matrix_t ctm; - cairo_matrix_init_scale(&fontMatrix, fontDescription.computedPixelSize(), fontDescription.computedPixelSize()); cairo_matrix_init_identity(&ctm); -#if !PLATFORM(EFL) || ENABLE(GLIB_SUPPORT) - if (GdkScreen* screen = gdk_screen_get_default()) -gdk_screen_get_font_options(screen); -#endif - - // gdk_screen_get_font_options() returns NULL if no default options are - // set, so we always have to check. - if (!options) - options = defaultOptions; - - m_scaledFont = adoptPlatformRef(cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options)); - cairo_font_face_destroy(fontFace); + PlatformRefPtr<cairo_font_face_t> fontFace = adoptPlatformRef(cairo_ft_font_face_create_for_pattern(m_pattern.get())); + m_scaledFont = adoptPlatformRef(cairo_scaled_font_create(fontFace.get(), &fontMatrix, &ctm, options)); } FontPlatformData::FontPlatformData(float size, bool bold, bool italic) @@ -184,19 +172,6 @@ FontPlatformData::FontPlatformData(const FontPlatformData& other) *this = other; } -bool FontPlatformData::init() -{ - static bool initialized = false; - if (initialized) - return true; - if (!FcInit()) { - fprintf(stderr, "Can't init font config library\n"); - return false; - } - initialized = true; - return true; -} - FontPlatformData::~FontPlatformData() { if (m_fallbacks) { diff --git a/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.h b/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.h index 987a684..f3488ef 100644 --- a/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.h +++ b/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.h @@ -3,6 +3,7 @@ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com * Copyright (C) 2007 Holger Hans Peter Freyther * Copyright (C) 2007 Pioneer Research Center USA, Inc. + * Copyright (C) 2010 Igalia S.L. * All rights reserved. * * This library is free software; you can redistribute it and/or @@ -29,11 +30,10 @@ #include "GlyphBuffer.h" #include "HashFunctions.h" #include "PlatformRefPtrCairo.h" -#include <cairo-ft.h> -#include <cairo.h> -#include <fontconfig/fcfreetype.h> #include <wtf/Forward.h> +typedef struct _FcFontSet FcFontSet; + namespace WebCore { class FontPlatformData { @@ -53,14 +53,13 @@ public: , m_syntheticOblique(false) { } - FontPlatformData(const FontDescription&, const AtomicString& family); + FontPlatformData(FcPattern*, const FontDescription&); FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic); FontPlatformData(float size, bool bold, bool italic); FontPlatformData(const FontPlatformData&); ~FontPlatformData(); - static bool init(); bool isFixedPitch(); float size() const { return m_size; } void setSize(float size) { m_size = size; } diff --git a/WebCore/platform/graphics/cairo/GlyphPageTreeNodeCairo.cpp b/WebCore/platform/graphics/cairo/GlyphPageTreeNodeCairo.cpp index 26da68d..66e9c16 100644 --- a/WebCore/platform/graphics/cairo/GlyphPageTreeNodeCairo.cpp +++ b/WebCore/platform/graphics/cairo/GlyphPageTreeNodeCairo.cpp @@ -32,6 +32,9 @@ #include "GlyphPageTreeNode.h" #include "SimpleFontData.h" +#include <cairo-ft.h> +#include <cairo.h> +#include <fontconfig/fcfreetype.h> namespace WebCore { diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 5de7e1f..05096a9 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -35,6 +35,7 @@ #include "AffineTransform.h" #include "CairoPath.h" +#include "CairoUtilities.h" #include "FEGaussianBlur.h" #include "FloatRect.h" #include "Font.h" @@ -131,28 +132,10 @@ static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const cairo_fill(cr); } -static inline void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr) -{ - cairo_set_antialias(dstCr, cairo_get_antialias(srcCr)); - - size_t dashCount = cairo_get_dash_count(srcCr); - Vector<double> dashes(dashCount); - - double offset; - cairo_get_dash(srcCr, dashes.data(), &offset); - cairo_set_dash(dstCr, dashes.data(), dashCount, offset); - cairo_set_line_cap(dstCr, cairo_get_line_cap(srcCr)); - cairo_set_line_join(dstCr, cairo_get_line_join(srcCr)); - cairo_set_line_width(dstCr, cairo_get_line_width(srcCr)); - cairo_set_miter_limit(dstCr, cairo_get_miter_limit(srcCr)); - cairo_set_fill_rule(dstCr, cairo_get_fill_rule(srcCr)); -} - static void appendPathToCairoContext(cairo_t* to, cairo_t* from) { - cairo_path_t* cairoPath = cairo_copy_path(from); - cairo_append_path(to, cairoPath); - cairo_path_destroy(cairoPath); + OwnPtr<cairo_path_t> cairoPath(cairo_copy_path(from)); + cairo_append_path(to, cairoPath.get()); } // We apply the pending path built via addPath to the Cairo context @@ -1182,9 +1165,8 @@ void GraphicsContext::clip(const Path& path) return; cairo_t* cr = m_data->cr; - cairo_path_t* p = cairo_copy_path(path.platformPath()->context()); - cairo_append_path(cr, p); - cairo_path_destroy(p); + OwnPtr<cairo_path_t> p(cairo_copy_path(path.platformPath()->context())); + cairo_append_path(cr, p.get()); cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING); cairo_clip(cr); @@ -1341,9 +1323,8 @@ void GraphicsContext::drawTiledShadow(const IntRect& rect, const FloatSize& topL copyContextProperties(cr, shadowContext); cairo_translate(shadowContext, -rect.x() + blurRadius, -rect.y() + blurRadius); cairo_new_path(shadowContext); - cairo_path_t* path = cairo_copy_path(cr); - cairo_append_path(shadowContext, path); - cairo_path_destroy(path); + OwnPtr<cairo_path_t> path(cairo_copy_path(cr)); + cairo_append_path(shadowContext, path.get()); setPlatformFill(this, shadowContext, m_common); diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp index 05c6952..776bceb 100644 --- a/WebCore/platform/graphics/cairo/PathCairo.cpp +++ b/WebCore/platform/graphics/cairo/PathCairo.cpp @@ -29,9 +29,9 @@ #include "CairoPath.h" #include "FloatRect.h" #include "GraphicsContext.h" +#include "OwnPtrCairo.h" #include "PlatformString.h" #include "StrokeStyleApplier.h" - #include <cairo.h> #include <math.h> #include <wtf/MathExtras.h> @@ -52,9 +52,8 @@ Path::Path(const Path& other) : m_path(new CairoPath()) { cairo_t* cr = platformPath()->context(); - cairo_path_t* p = cairo_copy_path(other.platformPath()->context()); - cairo_append_path(cr, p); - cairo_path_destroy(p); + OwnPtr<cairo_path_t> p(cairo_copy_path(other.platformPath()->context())); + cairo_append_path(cr, p.get()); } Path& Path::operator=(const Path& other) @@ -64,9 +63,8 @@ Path& Path::operator=(const Path& other) clear(); cairo_t* cr = platformPath()->context(); - cairo_path_t* p = cairo_copy_path(other.platformPath()->context()); - cairo_append_path(cr, p); - cairo_path_destroy(p); + OwnPtr<cairo_path_t> p(cairo_copy_path(other.platformPath()->context())); + cairo_append_path(cr, p.get()); return *this; } @@ -297,7 +295,7 @@ bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) void Path::apply(void* info, PathApplierFunction function) const { cairo_t* cr = platformPath()->context(); - cairo_path_t* path = cairo_copy_path(cr); + OwnPtr<cairo_path_t> path(cairo_copy_path(cr)); cairo_path_data_t* data; PathElement pelement; FloatPoint points[3]; @@ -329,7 +327,6 @@ void Path::apply(void* info, PathApplierFunction function) const break; } } - cairo_path_destroy(path); } void Path::transform(const AffineTransform& trans) @@ -346,7 +343,7 @@ String Path::debugString() const return String(); String pathString; - cairo_path_t* path = cairo_copy_path(platformPath()->context()); + OwnPtr<cairo_path_t> path(cairo_copy_path(platformPath()->context())); cairo_path_data_t* data; for (int i = 0; i < path->num_data; i += path->data[i].header.length) { @@ -373,7 +370,6 @@ String Path::debugString() const } } - cairo_path_destroy(path); return pathString.simplifyWhiteSpace(); } diff --git a/WebCore/platform/graphics/cairo/PlatformRefPtrCairo.cpp b/WebCore/platform/graphics/cairo/PlatformRefPtrCairo.cpp index aa466f9..d289585 100644 --- a/WebCore/platform/graphics/cairo/PlatformRefPtrCairo.cpp +++ b/WebCore/platform/graphics/cairo/PlatformRefPtrCairo.cpp @@ -54,6 +54,19 @@ template <> void derefPlatformPtr(cairo_surface_t* ptr) cairo_surface_destroy(ptr); } +template <> cairo_font_face_t* refPlatformPtr(cairo_font_face_t* ptr) +{ + if (ptr) + cairo_font_face_reference(ptr); + return ptr; +} + +template <> void derefPlatformPtr(cairo_font_face_t* ptr) +{ + if (ptr) + cairo_font_face_destroy(ptr); +} + template <> cairo_scaled_font_t* refPlatformPtr(cairo_scaled_font_t* ptr) { if (ptr) diff --git a/WebCore/platform/graphics/cairo/PlatformRefPtrCairo.h b/WebCore/platform/graphics/cairo/PlatformRefPtrCairo.h index 4b45c1b..3b720c6 100644 --- a/WebCore/platform/graphics/cairo/PlatformRefPtrCairo.h +++ b/WebCore/platform/graphics/cairo/PlatformRefPtrCairo.h @@ -24,6 +24,7 @@ typedef struct _cairo cairo_t; typedef struct _cairo_surface cairo_surface_t; +typedef struct _cairo_font_face cairo_font_face_t; typedef struct _cairo_scaled_font cairo_scaled_font_t; #if defined(USE_FREETYPE) @@ -38,6 +39,9 @@ template <> void derefPlatformPtr(cairo_t* ptr); template <> cairo_surface_t* refPlatformPtr(cairo_surface_t* ptr); template <> void derefPlatformPtr(cairo_surface_t* ptr); +template <> cairo_font_face_t* refPlatformPtr(cairo_font_face_t*); +template <> void derefPlatformPtr(cairo_font_face_t*); + template <> cairo_scaled_font_t* refPlatformPtr(cairo_scaled_font_t*); template <> void derefPlatformPtr(cairo_scaled_font_t*); diff --git a/WebCore/platform/graphics/cairo/SimpleFontDataCairo.cpp b/WebCore/platform/graphics/cairo/SimpleFontDataCairo.cpp index fd85d6f..3d7c34b 100644 --- a/WebCore/platform/graphics/cairo/SimpleFontDataCairo.cpp +++ b/WebCore/platform/graphics/cairo/SimpleFontDataCairo.cpp @@ -38,7 +38,9 @@ #include "FontCache.h" #include "FontDescription.h" #include "GlyphBuffer.h" +#include <cairo-ft.h> #include <cairo.h> +#include <fontconfig/fcfreetype.h> #include <wtf/MathExtras.h> namespace WebCore { @@ -81,12 +83,12 @@ void SimpleFontData::platformDestroy() SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const { - if (!m_smallCapsFontData) { - FontDescription desc = FontDescription(fontDescription); - desc.setComputedSize(0.70f * fontDescription.computedSize()); - FontPlatformData platformData(desc, desc.family().family()); - m_smallCapsFontData = new SimpleFontData(platformData); - } + // FIXME: I think we want to ask FontConfig for the right font again. + if (!m_smallCapsFontData) + m_smallCapsFontData = new SimpleFontData( + FontPlatformData(cairo_scaled_font_get_font_face(m_platformData.scaledFont()), + 0.70f * fontDescription.computedSize(), m_platformData.syntheticBold(), m_platformData.syntheticOblique())); + return m_smallCapsFontData; } diff --git a/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp index fadc385..2a81fd2 100644 --- a/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp @@ -71,9 +71,54 @@ bool GraphicsContext3D::getImageData(Image* image, AlphaOp neededAlphaOp = kAlphaDoNothing; switch (CGImageGetAlphaInfo(cgImage)) { case kCGImageAlphaPremultipliedFirst: + // This path is only accessible for MacOS earlier than 10.6.4. + // This is a special case for texImage2D with HTMLCanvasElement input, + // in which case image->data() should be null. + ASSERT(!image->data()); + if (!premultiplyAlpha) + neededAlphaOp = kAlphaDoUnmultiply; + switch (componentsPerPixel) { + case 2: + srcDataFormat = kSourceFormatAR8; + break; + case 4: + srcDataFormat = kSourceFormatARGB8; + break; + default: + return false; + } + break; case kCGImageAlphaFirst: + // This path is only accessible for MacOS earlier than 10.6.4. + if (premultiplyAlpha) + neededAlphaOp = kAlphaDoPremultiply; + switch (componentsPerPixel) { + case 1: + srcDataFormat = kSourceFormatA8; + break; + case 2: + srcDataFormat = kSourceFormatAR8; + break; + case 4: + srcDataFormat = kSourceFormatARGB8; + break; + default: + return false; + } + break; case kCGImageAlphaNoneSkipFirst: - return false; + // This path is only accessible for MacOS earlier than 10.6.4. + switch (componentsPerPixel) { + case 2: + srcDataFormat = kSourceFormatAR8; + break; + case 4: + srcDataFormat = kSourceFormatARGB8; + break; + default: + return false; + } + break; case kCGImageAlphaPremultipliedLast: // This is a special case for texImage2D with HTMLCanvasElement input, // in which case image->data() should be null. diff --git a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp index 86be8da..8dda4d6 100644 --- a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp @@ -126,10 +126,28 @@ ContentLayerChromium::ContentLayerChromium(GraphicsLayerChromium* owner) ContentLayerChromium::~ContentLayerChromium() { - if (m_contentsTexture) - GLC(layerRendererContext(), layerRendererContext()->deleteTexture(m_contentsTexture)); + cleanupResources(); } +void ContentLayerChromium::setLayerRenderer(LayerRendererChromium* renderer) +{ + // If we're changing layer renderers then we need to free up any resources + // allocated by the old renderer. + if (layerRenderer() && layerRenderer() != renderer) + cleanupResources(); + + LayerChromium::setLayerRenderer(renderer); +} + +void ContentLayerChromium::cleanupResources() +{ + if (layerRenderer()) { + if (m_contentsTexture) { + layerRenderer()->deleteLayerTexture(m_contentsTexture); + m_contentsTexture = 0; + } + } +} void ContentLayerChromium::updateContents() { diff --git a/WebCore/platform/graphics/chromium/ContentLayerChromium.h b/WebCore/platform/graphics/chromium/ContentLayerChromium.h index 42a77c7..412ba06 100644 --- a/WebCore/platform/graphics/chromium/ContentLayerChromium.h +++ b/WebCore/platform/graphics/chromium/ContentLayerChromium.h @@ -49,6 +49,7 @@ public: virtual void updateContents(); virtual void draw(); virtual bool drawsContent() { return m_owner && m_owner->drawsContent(); } + virtual void setLayerRenderer(LayerRendererChromium*); // Stores values that are shared between instances of this class that are // associated with the same LayerRendererChromium (and hence the same GL @@ -79,6 +80,8 @@ protected: void updateTextureRect(void* pixels, const IntSize& bitmapSize, const IntSize& requiredTextureSize, const IntRect& updateRect, unsigned textureId); + void cleanupResources(); + unsigned m_contentsTexture; IntSize m_allocatedTextureSize; bool m_skipsDraw; diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp index 696cd9c..a242523 100644 --- a/WebCore/platform/graphics/chromium/FontLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontLinux.cpp @@ -130,7 +130,7 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, if (textMode & cTextFill) { // If we also filled, we don't want to draw shadows twice. // See comment in FontChromiumWin.cpp::paintSkiaText() for more details. - paint.setLooper(0)->safeUnref(); + SkSafeUnref(paint.setLooper(0)); } canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint); @@ -313,7 +313,7 @@ public: // So we allow that to run first, then do a second pass over the range it // found and take the largest subregion that stays within a single font. const FontData* glyphData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData; - int endOfRun; + unsigned endOfRun; for (endOfRun = 1; endOfRun < m_item.item.length; ++endOfRun) { const FontData* nextGlyphData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos + endOfRun], false, false).fontData; if (nextGlyphData != glyphData) @@ -406,7 +406,7 @@ private: // Harfbuzz will do the same thing for us using the GSUB table. // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs // for characters like '\n' otherwise. - for (unsigned i = 0; i < originalRun.length(); ++i) { + for (int i = 0; i < originalRun.length(); ++i) { UChar ch = originalRun[i]; UBlockCode block = ::ublock_getCode(ch); if (block == UBLOCK_COMBINING_DIACRITICAL_MARKS || (Font::treatAsSpace(ch) && ch != ' ')) { @@ -428,7 +428,7 @@ private: normalizedString.extract(m_normalizedBuffer.get(), normalizedString.length() + 1, error); ASSERT(U_SUCCESS(error)); - for (unsigned i = 0; i < normalizedString.length(); ++i) { + for (int i = 0; i < normalizedString.length(); ++i) { if (Font::treatAsSpace(m_normalizedBuffer[i])) m_normalizedBuffer[i] = ' '; } @@ -517,7 +517,7 @@ private: // glyph. unsigned logClustersIndex = isRTL ? m_item.num_glyphs - 1 : 0; - for (int iter = 0; iter < m_item.num_glyphs; ++iter) { + for (unsigned iter = 0; iter < m_item.num_glyphs; ++iter) { // Glyphs are stored in logical order, but for layout purposes we // always go left to right. int i = isRTL ? m_item.num_glyphs - iter - 1 : iter; @@ -683,7 +683,7 @@ static int glyphIndexForXPositionInScriptRun(const TextRunWalker& walker, int x) x -= truncateFixedPointToInteger(advances[glyphIndex]); } } else { - for (glyphIndex = 0; glyphIndex < walker.length(); ++glyphIndex) { + for (glyphIndex = 0; static_cast<unsigned>(glyphIndex) < walker.length(); ++glyphIndex) { if (x < truncateFixedPointToInteger(advances[glyphIndex])) break; x -= truncateFixedPointToInteger(advances[glyphIndex]); @@ -741,7 +741,7 @@ int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, if (walker.rtl()) basePosition -= walker.numCodePoints(); - if (x >= 0 && x < walker.width()) { + if (x >= 0 && static_cast<unsigned>(x) < walker.width()) { // The x value in question is within this script run. We consider // each glyph in presentation order and stop when we find the one // covering this position. @@ -803,7 +803,7 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, if (walker.rtl()) base -= walker.width(); - if (fromX == -1 && from < walker.numCodePoints()) { + if (fromX == -1 && from >= 0 && static_cast<unsigned>(from) < walker.numCodePoints()) { // |from| is within this script run. So we index the clusters log to // find which glyph this code-point contributed to and find its x // position. @@ -813,7 +813,7 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, } else from -= walker.numCodePoints(); - if (toX == -1 && to < walker.numCodePoints()) { + if (toX == -1 && to >= 0 && static_cast<unsigned>(to) < walker.numCodePoints()) { int glyph = walker.logClusters()[to]; toX = base + walker.xPositions()[glyph]; toAdvance = walker.advances()[glyph]; diff --git a/WebCore/platform/graphics/chromium/FontPlatformData.h b/WebCore/platform/graphics/chromium/FontPlatformData.h index 871fec8..d8ce3e2 100644 --- a/WebCore/platform/graphics/chromium/FontPlatformData.h +++ b/WebCore/platform/graphics/chromium/FontPlatformData.h @@ -33,7 +33,7 @@ #if OS(WINDOWS) #include "FontPlatformDataChromiumWin.h" -#elif OS(LINUX) +#elif OS(LINUX) || OS(FREEBSD) #include "FontPlatformDataLinux.h" #endif diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp index b51eb8c..0da873b 100644 --- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp @@ -76,7 +76,7 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src) , m_style(src.m_style) , m_harfbuzzFace(src.m_harfbuzzFace) { - m_typeface->safeRef(); + SkSafeRef(m_typeface); } FontPlatformData::FontPlatformData(SkTypeface* tf, const char* family, float textSize, bool fakeBold, bool fakeItalic) @@ -86,7 +86,7 @@ FontPlatformData::FontPlatformData(SkTypeface* tf, const char* family, float tex , m_fakeBold(fakeBold) , m_fakeItalic(fakeItalic) { - m_typeface->safeRef(); + SkSafeRef(m_typeface); querySystemForRenderStyle(); } @@ -98,13 +98,13 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize) , m_fakeItalic(src.m_fakeItalic) , m_harfbuzzFace(src.m_harfbuzzFace) { - m_typeface->safeRef(); + SkSafeRef(m_typeface); querySystemForRenderStyle(); } FontPlatformData::~FontPlatformData() { - m_typeface->safeUnref(); + SkSafeUnref(m_typeface); } FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src) diff --git a/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp b/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp index 59e8122..056d8eb 100644 --- a/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp +++ b/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp @@ -150,7 +150,7 @@ static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_ui SkPath path; paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path); int numPoints = path.getPoints(0, 0); - if (point >= numPoints) + if (point >= static_cast<unsigned>(numPoints)) return HB_Err_Invalid_SubTable; SkPoint* points = reinterpret_cast<SkPoint*>(fastMalloc(sizeof(SkPoint) * (point + 1))); if (!points) diff --git a/WebCore/platform/graphics/chromium/LayerChromium.cpp b/WebCore/platform/graphics/chromium/LayerChromium.cpp index e36c69d..5dba58d 100644 --- a/WebCore/platform/graphics/chromium/LayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/LayerChromium.cpp @@ -174,9 +174,6 @@ LayerChromium::~LayerChromium() void LayerChromium::setLayerRenderer(LayerRendererChromium* renderer) { - // It's not expected that layers will ever switch renderers. - ASSERT(!renderer || !m_layerRenderer || renderer == m_layerRenderer); - m_layerRenderer = renderer; } @@ -224,9 +221,10 @@ unsigned LayerChromium::createShaderProgram(GraphicsContext3D* context, const ch void LayerChromium::setNeedsCommit() { - // Call notifySyncRequired(), which in this implementation plumbs through to + // Call notifySyncRequired(), which for non-root layers plumbs through to // call setRootLayerNeedsDisplay() on the WebView, which will cause LayerRendererChromium // to render a frame. + // This function has no effect on root layers. if (m_owner) m_owner->notifySyncRequired(); } @@ -352,8 +350,9 @@ LayerChromium* LayerChromium::superlayer() const void LayerChromium::setNeedsDisplay(const FloatRect& dirtyRect) { - // Simply mark the contents as dirty. The actual redraw will - // happen when it's time to do the compositing. + // Simply mark the contents as dirty. For non-root layers, the call to + // setNeedsCommit will schedule a fresh compositing pass. + // For the root layer, setNeedsCommit has no effect. m_contentsDirty = true; m_dirtyRect.unite(dirtyRect); diff --git a/WebCore/platform/graphics/chromium/LayerChromium.h b/WebCore/platform/graphics/chromium/LayerChromium.h index 30d35d1..0a66318 100644 --- a/WebCore/platform/graphics/chromium/LayerChromium.h +++ b/WebCore/platform/graphics/chromium/LayerChromium.h @@ -147,7 +147,9 @@ public: bool preserves3D() { return m_owner && m_owner->preserves3D(); } - void setLayerRenderer(LayerRendererChromium*); + // Derived types must override this method if they need to react to a change + // in the LayerRendererChromium. + virtual void setLayerRenderer(LayerRendererChromium*); void setOwner(GraphicsLayerChromium* owner) { m_owner = owner; } @@ -200,7 +202,7 @@ protected: GraphicsLayerChromium* m_owner; LayerChromium(GraphicsLayerChromium* owner); - LayerRendererChromium* layerRenderer() const { return m_layerRenderer; } + LayerRendererChromium* layerRenderer() const { return m_layerRenderer.get(); } GraphicsContext3D* layerRendererContext() const; static void drawTexturedQuad(GraphicsContext3D*, const TransformationMatrix& projectionMatrix, const TransformationMatrix& layerMatrix, @@ -260,7 +262,7 @@ private: bool m_needsDisplayOnBoundsChange; // Points to the layer renderer that updates and draws this layer. - LayerRendererChromium* m_layerRenderer; + RefPtr<LayerRendererChromium> m_layerRenderer; FloatRect m_frame; TransformationMatrix m_transform; diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp index 116a15d..c4031e5 100644 --- a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp +++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp @@ -73,12 +73,12 @@ static inline bool compareLayerZ(const LayerChromium* a, const LayerChromium* b) return transformA.m43() < transformB.m43(); } -PassOwnPtr<LayerRendererChromium> LayerRendererChromium::create(PassOwnPtr<GraphicsContext3D> context) +PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassOwnPtr<GraphicsContext3D> context) { if (!context) return 0; - OwnPtr<LayerRendererChromium> layerRenderer(new LayerRendererChromium(context)); + RefPtr<LayerRendererChromium> layerRenderer(adoptRef(new LayerRendererChromium(context))); if (!layerRenderer->hardwareCompositing()) return 0; @@ -91,7 +91,6 @@ LayerRendererChromium::LayerRendererChromium(PassOwnPtr<GraphicsContext3D> conte , m_rootLayerTextureHeight(0) , m_scrollShaderProgram(0) , m_rootLayer(0) - , m_needsDisplay(false) , m_scrollPosition(IntPoint(-1, -1)) , m_currentShader(0) , m_context(context) @@ -159,8 +158,10 @@ void LayerRendererChromium::useShader(unsigned programId) } } -// Updates the contents of the root layer texture that fall inside the updateRect -// and re-composits all sublayers. +// This method must be called before any other updates are made to the +// root layer texture. It resizes the root layer texture and scrolls its +// contents as needed. It also sets up common GL state used by the rest +// of the layer drawing code. void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, const IntRect& contentRect, const IntPoint& scrollPosition) { @@ -172,6 +173,8 @@ void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, cons makeContextCurrent(); GLC(m_context, m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_rootLayerTextureId)); + + bool skipScroll = false; // If the size of the visible area has changed then allocate a new texture // to store the contents of the root layer and adjust the projection matrix @@ -184,6 +187,10 @@ void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, cons m_projectionMatrix = orthoMatrix(0, visibleRectWidth, visibleRectHeight, 0, -1000, 1000); GLC(m_context, m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, m_rootLayerTextureWidth, m_rootLayerTextureHeight, 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0)); + + // The root layer texture was just resized so its contents are not + // useful for scrolling. + skipScroll = true; } // The GL viewport covers the entire visible area, including the scrollbars. @@ -198,12 +205,20 @@ void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, cons GLC(m_context, m_context->depthFunc(GraphicsContext3D::LEQUAL)); GLC(m_context, m_context->clearStencil(0)); - if (m_scrollPosition == IntPoint(-1, -1)) + if (m_scrollPosition == IntPoint(-1, -1)) { m_scrollPosition = scrollPosition; + skipScroll = true; + } IntPoint scrollDelta = toPoint(scrollPosition - m_scrollPosition); + + // Scrolling larger than the contentRect size does not preserve any of the pixels, so there is + // no need to copy framebuffer pixels back into the texture. + if (abs(scrollDelta.y()) > contentRect.height() || abs(scrollDelta.x()) > contentRect.width()) + skipScroll = true; + // Scroll the backbuffer - if (scrollDelta.x() || scrollDelta.y()) { + if (!skipScroll && (scrollDelta.x() || scrollDelta.y())) { // Scrolling works as follows: We render a quad with the current root layer contents // translated by the amount the page has scrolled since the last update and then read the // pixels of the content area (visible area excluding the scroll bars) back into the @@ -221,23 +236,9 @@ void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, cons m_scrollShaderMatrixLocation, -1); GLC(m_context, m_context->copyTexSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, 0, 0, contentRect.width(), contentRect.height())); - m_scrollPosition = scrollPosition; - } else if (abs(scrollDelta.y()) > contentRect.height() || abs(scrollDelta.x()) > contentRect.width()) { - // Scrolling larger than the contentRect size does not preserve any of the pixels, so there is - // no need to copy framebuffer pixels back into the texture. - m_scrollPosition = scrollPosition; } - // Translate all the composited layers by the scroll position. - TransformationMatrix matrix; - matrix.translate3d(-m_scrollPosition.x(), -m_scrollPosition.y(), 0); - - // Traverse the layer tree and update the layer transforms. - float opacity = 1; - const Vector<RefPtr<LayerChromium> >& sublayers = m_rootLayer->getSublayers(); - size_t i; - for (i = 0; i < sublayers.size(); i++) - updateLayersRecursive(sublayers[i].get(), matrix, opacity); + m_scrollPosition = scrollPosition; } void LayerRendererChromium::updateRootLayerTextureRect(const IntRect& updateRect) @@ -256,9 +257,7 @@ void LayerRendererChromium::updateRootLayerTextureRect(const IntRect& updateRect #if PLATFORM(SKIA) // Get the contents of the updated rect. const SkBitmap bitmap = m_rootLayerCanvas->getDevice()->accessBitmap(false); - int bitmapWidth = bitmap.width(); - int bitmapHeight = bitmap.height(); - ASSERT(bitmapWidth == updateRect.width() && bitmapHeight == updateRect.height()); + ASSERT(bitmap.width() == updateRect.width() && bitmap.height() == updateRect.height()); void* pixels = bitmap.getPixels(); #elif PLATFORM(CG) // Get the contents of the updated rect. @@ -306,16 +305,13 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect // Set the rootVisibleRect --- used by subsequent drawLayers calls m_rootVisibleRect = visibleRect; - // Translate all the composited layers by the scroll position. - TransformationMatrix matrix; - matrix.translate3d(-m_scrollPosition.x(), -m_scrollPosition.y(), 0); - // Traverse the layer tree and update the layer transforms. float opacity = 1; const Vector<RefPtr<LayerChromium> >& sublayers = m_rootLayer->getSublayers(); size_t i; + TransformationMatrix identityMatrix; for (i = 0; i < sublayers.size(); i++) - updateLayersRecursive(sublayers[i].get(), matrix, opacity); + updateLayersRecursive(sublayers[i].get(), identityMatrix, opacity); // Enable scissoring to avoid rendering composited layers over the scrollbars. GLC(m_context, m_context->enable(GraphicsContext3D::SCISSOR_TEST)); @@ -349,7 +345,6 @@ void LayerRendererChromium::present() // Note that currently this has the same effect as swapBuffers; we should // consider exposing a different entry point on GraphicsContext3D. m_context->prepareTexture(); - m_needsDisplay = false; } void LayerRendererChromium::getFramebufferPixels(void *pixels, const IntRect& rect) @@ -381,6 +376,14 @@ unsigned LayerRendererChromium::createLayerTexture() return textureId; } +void LayerRendererChromium::deleteLayerTexture(unsigned textureId) +{ + if (!textureId) + return; + + GLC(m_context, m_context->deleteTexture(textureId)); +} + // Returns true if any part of the layer falls within the visibleRect bool LayerRendererChromium::isLayerVisible(LayerChromium* layer, const TransformationMatrix& matrix, const IntRect& visibleRect) { @@ -717,7 +720,8 @@ bool LayerRendererChromium::initializeSharedObjects() m_layerSharedValues = adoptPtr(new LayerChromium::SharedValues(m_context.get())); m_contentLayerSharedValues = adoptPtr(new ContentLayerChromium::SharedValues(m_context.get())); m_canvasLayerSharedValues = adoptPtr(new CanvasLayerChromium::SharedValues(m_context.get())); - if (!m_layerSharedValues->initialized() || !m_contentLayerSharedValues->initialized() || !m_canvasLayerSharedValues->initialized()) { + m_videoLayerSharedValues = adoptPtr(new VideoLayerChromium::SharedValues(m_context.get())); + if (!m_layerSharedValues->initialized() || !m_contentLayerSharedValues->initialized() || !m_canvasLayerSharedValues->initialized() || !m_videoLayerSharedValues->initialized()) { cleanupSharedObjects(); return false; } @@ -732,6 +736,7 @@ void LayerRendererChromium::cleanupSharedObjects() m_layerSharedValues.clear(); m_contentLayerSharedValues.clear(); m_canvasLayerSharedValues.clear(); + m_videoLayerSharedValues.clear(); if (m_scrollShaderProgram) { GLC(m_context, m_context->deleteProgram(m_scrollShaderProgram)); @@ -739,7 +744,7 @@ void LayerRendererChromium::cleanupSharedObjects() } if (m_rootLayerTextureId) { - GLC(m_context, m_context->deleteTexture(m_rootLayerTextureId)); + deleteLayerTexture(m_rootLayerTextureId); m_rootLayerTextureId = 0; } } diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.h b/WebCore/platform/graphics/chromium/LayerRendererChromium.h index c733228..b714584 100644 --- a/WebCore/platform/graphics/chromium/LayerRendererChromium.h +++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.h @@ -39,9 +39,12 @@ #include "IntRect.h" #include "LayerChromium.h" #include "SkBitmap.h" +#include "VideoLayerChromium.h" #include <wtf/HashMap.h> #include <wtf/Noncopyable.h> #include <wtf/PassOwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> #include <wtf/Vector.h> #if PLATFORM(CG) @@ -54,9 +57,9 @@ namespace WebCore { class GraphicsContext3D; // Class that handles drawing of composited render layers using GL. -class LayerRendererChromium : public Noncopyable { +class LayerRendererChromium : public RefCounted<LayerRendererChromium> { public: - static PassOwnPtr<LayerRendererChromium> create(PassOwnPtr<GraphicsContext3D> graphicsContext3D); + static PassRefPtr<LayerRendererChromium> create(PassOwnPtr<GraphicsContext3D> graphicsContext3D); LayerRendererChromium(PassOwnPtr<GraphicsContext3D> graphicsContext3D); ~LayerRendererChromium(); @@ -81,8 +84,6 @@ public: void setRootLayer(PassRefPtr<LayerChromium> layer) { m_rootLayer = layer; } LayerChromium* rootLayer() { return m_rootLayer.get(); } - void setNeedsDisplay() { m_needsDisplay = true; } - bool hardwareCompositing() const { return m_hardwareCompositing; } void setRootLayerCanvasSize(const IntSize&); @@ -90,6 +91,7 @@ public: GraphicsContext* rootLayerGraphicsContext() const { return m_rootLayerGraphicsContext.get(); } unsigned createLayerTexture(); + void deleteLayerTexture(unsigned); static void debugGLCall(GraphicsContext3D*, const char* command, const char* file, int line); @@ -102,6 +104,7 @@ public: const LayerChromium::SharedValues* layerSharedValues() const { return m_layerSharedValues.get(); } const ContentLayerChromium::SharedValues* contentLayerSharedValues() const { return m_contentLayerSharedValues.get(); } const CanvasLayerChromium::SharedValues* canvasLayerSharedValues() const { return m_canvasLayerSharedValues.get(); } + const VideoLayerChromium::SharedValues* videoLayerSharedValues() const { return m_videoLayerSharedValues.get(); } void resizeOnscreenContent(const IntSize&); @@ -139,7 +142,6 @@ private: RefPtr<LayerChromium> m_rootLayer; - bool m_needsDisplay; IntPoint m_scrollPosition; bool m_hardwareCompositing; @@ -170,6 +172,7 @@ private: OwnPtr<LayerChromium::SharedValues> m_layerSharedValues; OwnPtr<ContentLayerChromium::SharedValues> m_contentLayerSharedValues; OwnPtr<CanvasLayerChromium::SharedValues> m_canvasLayerSharedValues; + OwnPtr<VideoLayerChromium::SharedValues> m_videoLayerSharedValues; OwnPtr<GraphicsContext3D> m_context; }; diff --git a/WebCore/platform/graphics/chromium/VDMXParser.cpp b/WebCore/platform/graphics/chromium/VDMXParser.cpp index 3347226..bd30a97 100644 --- a/WebCore/platform/graphics/chromium/VDMXParser.cpp +++ b/WebCore/platform/graphics/chromium/VDMXParser.cpp @@ -31,7 +31,6 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> -#include <sys/types.h> // For htons/ntohs #include <arpa/inet.h> diff --git a/WebCore/platform/chromium/GLES2Context.h b/WebCore/platform/graphics/chromium/VideoFrameChromium.cpp index d37885a..43b40e2 100644 --- a/WebCore/platform/chromium/GLES2Context.h +++ b/WebCore/platform/graphics/chromium/VideoFrameChromium.cpp @@ -28,43 +28,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef GLES2Context_h -#define GLES2Context_h +#include "config.h" -#include <wtf/Noncopyable.h> -#include <wtf/OwnPtr.h> -#include <wtf/PassOwnPtr.h> +#include "VideoFrameChromium.h" namespace WebCore { -class GLES2ContextInternal; -class IntSize; -class Page; - -class GLES2Context : public Noncopyable { -public: - // Used by the implementation only - static PassOwnPtr<GLES2Context> create(PassOwnPtr<GLES2ContextInternal>); - ~GLES2Context(); - - bool makeCurrent(); - bool destroy(); - bool swapBuffers(); - - // Only valid for offscreen contexts. - void resizeOffscreenContent(const IntSize&); - - // Returns the ID of the texture used for offscreen rendering in the context of the parent. - // This texture is accessible by the GPU page compositor. - unsigned getOffscreenContentParentTextureId(); - -private: - GLES2Context(); - - friend class GLES2ContextInternal; - OwnPtr<GLES2ContextInternal> m_internal; -}; +const unsigned VideoFrameChromium::maxPlanes = 3; +const unsigned VideoFrameChromium::numRGBPlanes = 1; +const unsigned VideoFrameChromium::rgbPlane = 0; +const unsigned VideoFrameChromium::numYUVPlanes = 3; +const unsigned VideoFrameChromium::yPlane = 0; +const unsigned VideoFrameChromium::uPlane = 1; +const unsigned VideoFrameChromium::vPlane = 2; } // namespace WebCore -#endif + diff --git a/WebCore/platform/graphics/chromium/VideoFrameChromium.h b/WebCore/platform/graphics/chromium/VideoFrameChromium.h index bbd677e..34e922b 100644 --- a/WebCore/platform/graphics/chromium/VideoFrameChromium.h +++ b/WebCore/platform/graphics/chromium/VideoFrameChromium.h @@ -31,18 +31,20 @@ #ifndef VideoFrameChromium_h #define VideoFrameChromium_h +#include "IntSize.h" + namespace WebCore { // A class that represents a video frame in chromium. class VideoFrameChromium { public: - static const unsigned cMaxPlanes; - static const unsigned cNumRGBPlanes; - static const unsigned cRGBPlane; - static const unsigned cNumYUVPlanes; - static const unsigned cYPlane; - static const unsigned cUPlane; - static const unsigned cVPlane; + static const unsigned maxPlanes; + static const unsigned numRGBPlanes; + static const unsigned rgbPlane; + static const unsigned numYUVPlanes; + static const unsigned yPlane; + static const unsigned uPlane; + static const unsigned vPlane; // These enums must be kept in sync with WebKit::WebVideoFrame. enum Format { @@ -74,6 +76,7 @@ public: virtual unsigned planes() const = 0; virtual int stride(unsigned plane) const = 0; virtual const void* data(unsigned plane) const = 0; + virtual const IntSize requiredTextureSize(unsigned plane) const = 0; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp b/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp index 0fb1bb4..26641a9 100644 --- a/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp @@ -36,15 +36,134 @@ #include "GraphicsContext3D.h" #include "LayerRendererChromium.h" #include "RenderLayerBacking.h" -#include "skia/ext/platform_canvas.h" - -#if PLATFORM(SKIA) -#include "NativeImageSkia.h" -#include "PlatformContextSkia.h" -#endif +#include "VideoFrameChromium.h" +#include "VideoFrameProvider.h" namespace WebCore { +// These values are magic numbers that are used in the transformation +// from YUV to RGB color values. +const float VideoLayerChromium::yuv2RGB[9] = { + 1.f, 1.f, 1.f, + 0.f, -.344f, 1.772f, + 1.403f, -.714f, 0.f, +}; + +VideoLayerChromium::SharedValues::SharedValues(GraphicsContext3D* context) + : m_context(context) + , m_yuvShaderProgram(0) + , m_rgbaShaderProgram(0) + , m_yuvShaderMatrixLocation(0) + , m_yuvWidthScaleFactorLocation(0) + , m_rgbaShaderMatrixLocation(0) + , m_rgbaWidthScaleFactorLocation(0) + , m_ccMatrixLocation(0) + , m_yTextureLocation(0) + , m_uTextureLocation(0) + , m_vTextureLocation(0) + , m_rgbaTextureLocation(0) + , m_yuvAlphaLocation(0) + , m_rgbaAlphaLocation(0) + , m_initialized(false) +{ + // Frame textures are allocated based on stride width, not visible frame + // width, such that there is a guarantee that the frame rows line up + // properly and are not shifted by (stride - width) pixels. To hide the + // "padding" pixels between the edge of the visible frame width and the end + // of the stride, we give the shader a widthScaleFactor (<=1.0) of how much + // of the width of the texture should be shown when drawing the texture onto + // the vertices. + char vertexShaderString[] = + "precision mediump float; \n" + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "uniform mat4 matrix; \n" + "varying vec2 v_texCoord; \n" + "uniform float widthScaleFactor; \n" + "void main() \n" + "{ \n" + " gl_Position = matrix * a_position; \n" + " v_texCoord = vec2(widthScaleFactor * a_texCoord.x, a_texCoord.y); \n" + "} \n"; + + char yuvFragmentShaderString[] = + "precision mediump float; \n" + "precision mediump int; \n" + "varying vec2 v_texCoord; \n" + "uniform sampler2D y_texture; \n" + "uniform sampler2D u_texture; \n" + "uniform sampler2D v_texture; \n" + "uniform float alpha; \n" + "uniform mat3 cc_matrix; \n" + "void main() \n" + "{ \n" + " float y = texture2D(y_texture, v_texCoord).x; \n" + " float u = texture2D(u_texture, v_texCoord).r - .5; \n" + " float v = texture2D(v_texture, v_texCoord).r - .5; \n" + " vec3 rgb = cc_matrix * vec3(y, u, v); \n" + " gl_FragColor = vec4(rgb.x, rgb.y, rgb.z, 1.0) * alpha; \n" + "} \n"; + + char rgbaFragmentShaderString[] = + "precision mediump float; \n" + "varying vec2 v_texCoord; \n" + "uniform sampler2D rgba_texture; \n" + "uniform float alpha; \n" + "void main() \n" + "{ \n" + " vec4 texColor = texture2D(rgba_texture, vec2(v_texCoord.x, 1.0 - v_texCoord.y)); \n" + " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n" + "} \n"; + + m_rgbaShaderProgram = createShaderProgram(m_context, vertexShaderString, rgbaFragmentShaderString); + if (!m_rgbaShaderProgram) { + LOG_ERROR("VideoLayerChromium: Failed to create rgba shader program"); + return; + } + + m_yuvShaderProgram = createShaderProgram(m_context, vertexShaderString, yuvFragmentShaderString); + if (!m_yuvShaderProgram) { + LOG_ERROR("VideoLayerChromium: Failed to create yuv shader program"); + return; + } + + m_yuvShaderMatrixLocation = m_context->getUniformLocation(m_yuvShaderProgram, "matrix"); + m_yuvWidthScaleFactorLocation = m_context->getUniformLocation(m_yuvShaderProgram, "widthScaleFactor"); + m_yTextureLocation = m_context->getUniformLocation(m_yuvShaderProgram, "y_texture"); + m_uTextureLocation = m_context->getUniformLocation(m_yuvShaderProgram, "u_texture"); + m_vTextureLocation = m_context->getUniformLocation(m_yuvShaderProgram, "v_texture"); + m_ccMatrixLocation = m_context->getUniformLocation(m_yuvShaderProgram, "cc_matrix"); + m_yuvAlphaLocation = m_context->getUniformLocation(m_yuvShaderProgram, "alpha"); + + ASSERT(m_yuvShaderMatrixLocation != -1); + ASSERT(m_yuvWidthScaleFactorLocation != -1); + ASSERT(m_yTextureLocation != -1); + ASSERT(m_uTextureLocation != -1); + ASSERT(m_vTextureLocation != -1); + ASSERT(m_ccMatrixLocation != -1); + ASSERT(m_yuvAlphaLocation != -1); + + m_rgbaShaderMatrixLocation = m_context->getUniformLocation(m_rgbaShaderProgram, "matrix"); + m_rgbaTextureLocation = m_context->getUniformLocation(m_rgbaShaderProgram, "rgba_texture"); + m_rgbaWidthScaleFactorLocation = m_context->getUniformLocation(m_rgbaShaderProgram, "widthScaleFactor"); + m_rgbaAlphaLocation = m_context->getUniformLocation(m_rgbaShaderProgram, "alpha"); + + ASSERT(m_rgbaShaderMatrixLocation != -1); + ASSERT(m_rgbaTextureLocation != -1); + ASSERT(m_rgbaWidthScaleFactorLocation != -1); + ASSERT(m_rgbaAlphaLocation != -1); + + m_initialized = true; +} + +VideoLayerChromium::SharedValues::~SharedValues() +{ + if (m_yuvShaderProgram) + GLC(m_context, m_context->deleteProgram(m_yuvShaderProgram)); + if (m_rgbaShaderProgram) + GLC(m_context, m_context->deleteProgram(m_rgbaShaderProgram)); +} + PassRefPtr<VideoLayerChromium> VideoLayerChromium::create(GraphicsLayerChromium* owner, VideoFrameProvider* provider) { @@ -52,14 +171,25 @@ PassRefPtr<VideoLayerChromium> VideoLayerChromium::create(GraphicsLayerChromium* } VideoLayerChromium::VideoLayerChromium(GraphicsLayerChromium* owner, VideoFrameProvider* provider) - : ContentLayerChromium(owner) -#if PLATFORM(SKIA) - , m_canvas(0) - , m_skiaContext(0) -#endif - , m_graphicsContext(0) + : LayerChromium(owner) + , m_skipsDraw(true) + , m_frameFormat(VideoFrameChromium::Invalid) , m_provider(provider) { + for (unsigned plane = 0; plane < VideoFrameChromium::maxPlanes; plane++) { + m_textures[plane] = 0; + m_textureSizes[plane] = IntSize(); + m_frameSizes[plane] = IntSize(); + } +} + +VideoLayerChromium::~VideoLayerChromium() +{ + GraphicsContext3D* context = layerRendererContext(); + for (unsigned plane = 0; plane < VideoFrameChromium::maxPlanes; plane++) { + if (m_textures[plane]) + GLC(context, context->deleteTexture(m_textures[plane])); + } } void VideoLayerChromium::updateContents() @@ -70,129 +200,176 @@ void VideoLayerChromium::updateContents() ASSERT(drawsContent()); - IntRect dirtyRect(m_dirtyRect); - IntSize requiredTextureSize; - -#if PLATFORM(SKIA) - requiredTextureSize = m_bounds; - IntRect boundsRect(IntPoint(0, 0), m_bounds); - - // If the texture needs to be reallocated, then we must redraw the entire - // contents of the layer. - if (requiredTextureSize != m_allocatedTextureSize) - dirtyRect = boundsRect; - else { - // Clip the dirtyRect to the size of the layer to avoid drawing outside - // the bounds of the backing texture. - dirtyRect.intersect(boundsRect); + m_skipsDraw = false; + VideoFrameChromium* frame = m_provider->getCurrentFrame(); + if (!frame) { + m_skipsDraw = true; + m_provider->putCurrentFrame(frame); + return; } - if (!m_canvas.get() - || dirtyRect.width() != m_canvas->getDevice()->width() - || dirtyRect.height() != m_canvas->getDevice()->height()) { - m_canvas = new skia::PlatformCanvas(dirtyRect.width(), dirtyRect.height(), true); - m_skiaContext = new PlatformContextSkia(m_canvas.get()); - - // This is needed to get text to show up correctly. - // FIXME: Does this take us down a very slow text rendering path? - m_skiaContext->setDrawingToImageBuffer(true); - m_graphicsContext = new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(m_skiaContext.get())); + m_frameFormat = frame->format(); + unsigned textureFormat = determineTextureFormat(frame); + if (textureFormat == GraphicsContext3D::INVALID_VALUE) { + // FIXME: Implement other paths. + notImplemented(); + m_skipsDraw = true; + m_provider->putCurrentFrame(frame); + return; } - // Bring the canvas into the coordinate system of the paint rect. - m_canvas->translate(static_cast<SkScalar>(-dirtyRect.x()), static_cast<SkScalar>(-dirtyRect.y())); - - // FIXME: Remove this test when tiled layers are implemented. - m_skipsDraw = false; - if (!layerRenderer()->checkTextureSize(requiredTextureSize)) { + // Allocate textures for planes if they are not allocated already, or + // reallocate textures that are the wrong size for the frame. + GraphicsContext3D* context = layerRendererContext(); + bool texturesAllocated = allocateTexturesIfNeeded(context, frame, textureFormat); + if (!texturesAllocated) { m_skipsDraw = true; + m_provider->putCurrentFrame(frame); return; } - unsigned textureId = m_contentsTexture; - if (!textureId) - textureId = layerRenderer()->createLayerTexture(); - - // If the texture id or size changed since last time, then we need to tell GL - // to re-allocate a texture. - if (m_contentsTexture != textureId || requiredTextureSize != m_allocatedTextureSize) - createTextureRect(requiredTextureSize, dirtyRect, textureId); - else - updateTextureRect(dirtyRect, textureId); -#else - // FIXME: Implement non-skia path - notImplemented(); -#endif + // Update texture planes. + for (unsigned plane = 0; plane < frame->planes(); plane++) { + ASSERT(frame->requiredTextureSize(plane) == m_textureSizes[plane]); + updateTexture(context, m_textures[plane], frame->requiredTextureSize(plane), textureFormat, frame->data(plane)); + } + + m_dirtyRect.setSize(FloatSize()); + m_contentsDirty = false; + m_provider->putCurrentFrame(frame); } -void VideoLayerChromium::createTextureRect(const IntSize& requiredTextureSize, const IntRect& updateRect, unsigned textureId) +unsigned VideoLayerChromium::determineTextureFormat(VideoFrameChromium* frame) { - // Paint into graphics context and get bitmap. - m_owner->paintGraphicsLayerContents(*m_graphicsContext, updateRect); - void* pixels = 0; - IntSize bitmapSize = IntSize(); -#if PLATFORM(SKIA) - const SkBitmap& bitmap = m_canvas->getDevice()->accessBitmap(false); - const SkBitmap* skiaBitmap = &bitmap; - ASSERT(skiaBitmap); - - SkAutoLockPixels lock(*skiaBitmap); - SkBitmap::Config skiaConfig = skiaBitmap->config(); - // FIXME: Do we need to support more image configurations? - if (skiaConfig == SkBitmap::kARGB_8888_Config) { - pixels = skiaBitmap->getPixels(); - bitmapSize = IntSize(skiaBitmap->width(), skiaBitmap->height()); + switch (frame->format()) { + case VideoFrameChromium::YV12: + return GraphicsContext3D::LUMINANCE; + case VideoFrameChromium::RGBA: + return GraphicsContext3D::RGBA; + default: + break; } -#else - // FIXME: Implement non-skia path - notImplemented(); -#endif - if (!pixels) - return; + return GraphicsContext3D::INVALID_VALUE; +} - GraphicsContext3D* context = layerRendererContext(); - context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId); - ASSERT(bitmapSize == requiredTextureSize); - context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, requiredTextureSize.width(), requiredTextureSize.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels); +bool VideoLayerChromium::allocateTexturesIfNeeded(GraphicsContext3D* context, VideoFrameChromium* frame, unsigned textureFormat) +{ + ASSERT(context); + ASSERT(frame); + + for (unsigned plane = 0; plane < frame->planes(); plane++) { + IntSize planeTextureSize = frame->requiredTextureSize(plane); - m_contentsTexture = textureId; - m_allocatedTextureSize = requiredTextureSize; + // If the renderer cannot handle this large of a texture, return false. + // FIXME: Remove this test when tiled layers are implemented. + if (!layerRenderer()->checkTextureSize(planeTextureSize)) + return false; - updateCompleted(); + if (!m_textures[plane]) + m_textures[plane] = layerRenderer()->createLayerTexture(); + + if (!planeTextureSize.isZero() && planeTextureSize != m_textureSizes[plane]) { + allocateTexture(context, m_textures[plane], planeTextureSize, textureFormat); + m_textureSizes[plane] = planeTextureSize; + m_frameSizes[plane] = IntSize(frame->width(), frame->height()); + } + } + return true; +} + +void VideoLayerChromium::allocateTexture(GraphicsContext3D* context, unsigned textureId, const IntSize& dimensions, unsigned textureFormat) +{ + GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId)); + GLC(context, context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, textureFormat, dimensions.width(), dimensions.height(), 0, textureFormat, GraphicsContext3D::UNSIGNED_BYTE, 0)); } -void VideoLayerChromium::updateTextureRect(const IntRect& updateRect, unsigned textureId) +void VideoLayerChromium::updateTexture(GraphicsContext3D* context, unsigned textureId, const IntSize& dimensions, unsigned format, const void* data) { -#if PLATFORM(SKIA) - const SkBitmap& bitmap = m_canvas->getDevice()->accessBitmap(true); - SkBitmap* skiaBitmap = const_cast<SkBitmap*>(&bitmap); - ASSERT(skiaBitmap); - - SkAutoLockPixels lock(*skiaBitmap); - SkBitmap::Config skiaConfig = skiaBitmap->config(); - - if (skiaConfig == SkBitmap::kARGB_8888_Config) { - GraphicsContext3D* context = layerRendererContext(); - context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId); - ASSERT(context->supportsMapSubCHROMIUM()); - void* mem = context->mapTexSubImage2DCHROMIUM(GraphicsContext3D::TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, GraphicsContext3D::WRITE_ONLY); - skiaBitmap->setPixels(mem); - m_owner->paintGraphicsLayerContents(*m_graphicsContext, updateRect); - context->unmapTexSubImage2DCHROMIUM(mem); + ASSERT(context); + GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId)); + void* mem = context->mapTexSubImage2DCHROMIUM(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, dimensions.width(), dimensions.height(), format, GraphicsContext3D::UNSIGNED_BYTE, GraphicsContext3D::WRITE_ONLY); + if (mem) { + memcpy(mem, data, dimensions.width() * dimensions.height()); + GLC(context, context->unmapTexSubImage2DCHROMIUM(mem)); + } else { + // FIXME: We should have some sort of code to handle the case when + // mapTexSubImage2D fails. + m_skipsDraw = true; } +} + +void VideoLayerChromium::draw() +{ + if (m_skipsDraw) + return; + + ASSERT(layerRenderer()); + const VideoLayerChromium::SharedValues* sv = layerRenderer()->videoLayerSharedValues(); + ASSERT(sv && sv->initialized()); - updateCompleted(); -#else - // FIXME: Implement non-skia path - notImplemented(); -#endif + switch (m_frameFormat) { + case VideoFrameChromium::YV12: + drawYUV(sv); + break; + case VideoFrameChromium::RGBA: + drawRGBA(sv); + break; + default: + // FIXME: Implement other paths. + notImplemented(); + break; + } } -void VideoLayerChromium::updateCompleted() +void VideoLayerChromium::drawYUV(const SharedValues* sv) { - m_dirtyRect.setSize(FloatSize()); - m_contentsDirty = false; + GraphicsContext3D* context = layerRendererContext(); + GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE1)); + GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textures[VideoFrameChromium::yPlane])); + GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE2)); + GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textures[VideoFrameChromium::uPlane])); + GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE3)); + GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textures[VideoFrameChromium::vPlane])); + + layerRenderer()->useShader(sv->yuvShaderProgram()); + unsigned frameWidth = m_frameSizes[VideoFrameChromium::yPlane].width(); + unsigned textureWidth = m_textureSizes[VideoFrameChromium::yPlane].width(); + float widthScaleFactor = static_cast<float>(frameWidth) / textureWidth; + GLC(context, context->uniform1f(sv->yuvWidthScaleFactorLocation(), widthScaleFactor)); + + GLC(context, context->uniform1i(sv->yTextureLocation(), 1)); + GLC(context, context->uniform1i(sv->uTextureLocation(), 2)); + GLC(context, context->uniform1i(sv->vTextureLocation(), 3)); + + GLC(context, context->uniformMatrix3fv(sv->ccMatrixLocation(), 0, const_cast<float*>(yuv2RGB), 1)); + + drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(), + bounds().width(), bounds().height(), drawOpacity(), + sv->yuvShaderMatrixLocation(), sv->yuvAlphaLocation()); + + // Reset active texture back to texture 0. + GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); } +void VideoLayerChromium::drawRGBA(const SharedValues* sv) +{ + GraphicsContext3D* context = layerRendererContext(); + GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); + GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textures[VideoFrameChromium::rgbPlane])); + + layerRenderer()->useShader(sv->rgbaShaderProgram()); + unsigned frameWidth = m_frameSizes[VideoFrameChromium::rgbPlane].width(); + unsigned textureWidth = m_textureSizes[VideoFrameChromium::rgbPlane].width(); + float widthScaleFactor = static_cast<float>(frameWidth) / textureWidth; + GLC(context, context->uniform1f(sv->rgbaWidthScaleFactorLocation(), widthScaleFactor)); + + GLC(context, context->uniform1i(sv->rgbaTextureLocation(), 0)); + + drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(), + bounds().width(), bounds().height(), drawOpacity(), + sv->rgbaShaderMatrixLocation(), sv->rgbaAlphaLocation()); } + +} // namespace WebCore + #endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/chromium/VideoLayerChromium.h b/WebCore/platform/graphics/chromium/VideoLayerChromium.h index 3507cb2..620d1a7 100644 --- a/WebCore/platform/graphics/chromium/VideoLayerChromium.h +++ b/WebCore/platform/graphics/chromium/VideoLayerChromium.h @@ -34,31 +34,76 @@ #if USE(ACCELERATED_COMPOSITING) -#include "ContentLayerChromium.h" +#include "LayerChromium.h" #include "VideoFrameProvider.h" namespace WebCore { // A Layer that contains a Video element. -class VideoLayerChromium : public ContentLayerChromium { +class VideoLayerChromium : public LayerChromium { public: static PassRefPtr<VideoLayerChromium> create(GraphicsLayerChromium* owner = 0, VideoFrameProvider* = 0); - virtual bool drawsContent() { return true; } + virtual ~VideoLayerChromium(); virtual void updateContents(); + virtual bool drawsContent() { return true; } + virtual void draw(); + + class SharedValues { + public: + explicit SharedValues(GraphicsContext3D*); + ~SharedValues(); + unsigned yuvShaderProgram() const { return m_yuvShaderProgram; } + unsigned rgbaShaderProgram() const { return m_rgbaShaderProgram; } + int yuvShaderMatrixLocation() const { return m_yuvShaderMatrixLocation; } + int rgbaShaderMatrixLocation() const { return m_rgbaShaderMatrixLocation; } + int yuvWidthScaleFactorLocation() const { return m_yuvWidthScaleFactorLocation; } + int rgbaWidthScaleFactorLocation() const { return m_rgbaWidthScaleFactorLocation; } + int yTextureLocation() const { return m_yTextureLocation; } + int uTextureLocation() const { return m_uTextureLocation; } + int vTextureLocation() const { return m_vTextureLocation; } + int yuvAlphaLocation() const { return m_yuvAlphaLocation; } + int rgbaAlphaLocation() const { return m_rgbaAlphaLocation; } + int rgbaTextureLocation() const { return m_rgbaTextureLocation; } + int ccMatrixLocation() const { return m_ccMatrixLocation; } + bool initialized() const { return m_initialized; }; + private: + GraphicsContext3D* m_context; + unsigned m_yuvShaderProgram; + unsigned m_rgbaShaderProgram; + int m_yuvShaderMatrixLocation; + int m_yuvWidthScaleFactorLocation; + int m_rgbaShaderMatrixLocation; + int m_rgbaWidthScaleFactorLocation; + int m_ccMatrixLocation; + int m_yTextureLocation; + int m_uTextureLocation; + int m_vTextureLocation; + int m_rgbaTextureLocation; + int m_yuvAlphaLocation; + int m_rgbaAlphaLocation; + bool m_initialized; + }; private: VideoLayerChromium(GraphicsLayerChromium* owner, VideoFrameProvider*); - void createTextureRect(const IntSize& requiredTextureSize, const IntRect& updateRect, unsigned textureId); - void updateTextureRect(const IntRect& updateRect, unsigned textureId); - void updateCompleted(); + static unsigned determineTextureFormat(VideoFrameChromium*); + bool allocateTexturesIfNeeded(GraphicsContext3D*, VideoFrameChromium*, unsigned textureFormat); + void updateYUVContents(GraphicsContext3D*, const VideoFrameChromium*); + void updateRGBAContents(GraphicsContext3D*, const VideoFrameChromium*); + void allocateTexture(GraphicsContext3D*, unsigned textureId, const IntSize& dimensions, unsigned textureFormat); + void updateTexture(GraphicsContext3D*, unsigned textureId, const IntSize& dimensions, unsigned textureFormat, const void* data); + void drawYUV(const SharedValues*); + void drawRGBA(const SharedValues*); -#if PLATFORM(SKIA) - OwnPtr<skia::PlatformCanvas> m_canvas; - OwnPtr<PlatformContextSkia> m_skiaContext; -#endif - OwnPtr<GraphicsContext> m_graphicsContext; + static const float yuv2RGB[9]; + + bool m_skipsDraw; + VideoFrameChromium::Format m_frameFormat; OwnPtr<VideoFrameProvider> m_provider; + unsigned m_textures[3]; + IntSize m_textureSizes[3]; + IntSize m_frameSizes[3]; }; } diff --git a/WebCore/platform/graphics/filters/DistantLightSource.h b/WebCore/platform/graphics/filters/DistantLightSource.h new file mode 100644 index 0000000..d5d474f --- /dev/null +++ b/WebCore/platform/graphics/filters/DistantLightSource.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef DistantLightSource_h +#define DistantLightSource_h + +#if ENABLE(FILTERS) +#include "LightSource.h" + +namespace WebCore { + +class DistantLightSource : public LightSource { +public: + static PassRefPtr<DistantLightSource> create(float azimuth, float elevation) + { + return adoptRef(new DistantLightSource(azimuth, elevation)); + } + + float azimuth() const { return m_azimuth; } + float elevation() const { return m_elevation; } + + virtual void initPaintingData(PaintingData&); + virtual void updatePaintingData(PaintingData&, int x, int y, float z); + + virtual TextStream& externalRepresentation(TextStream&) const; + +private: + DistantLightSource(float azimuth, float elevation) + : LightSource(LS_DISTANT) + , m_azimuth(azimuth) + , m_elevation(elevation) + { + } + + float m_azimuth; + float m_elevation; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // DistantLightSource_h diff --git a/WebCore/platform/graphics/filters/FEBlend.cpp b/WebCore/platform/graphics/filters/FEBlend.cpp index acd6545..4185f61 100644 --- a/WebCore/platform/graphics/filters/FEBlend.cpp +++ b/WebCore/platform/graphics/filters/FEBlend.cpp @@ -1,24 +1,24 @@ /* - 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. -*/ + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ #include "config.h" @@ -98,13 +98,13 @@ void FEBlend::apply(Filter* filter) if (m_mode == FEBLEND_MODE_UNKNOWN) return; - if (!getEffectContext()) + if (!effectContext()) return; - IntRect effectADrawingRect = calculateDrawingIntRect(in->repaintRectInLocalCoordinates()); + IntRect effectADrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates()); RefPtr<CanvasPixelArray> srcPixelArrayA(in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); - IntRect effectBDrawingRect = calculateDrawingIntRect(in2->repaintRectInLocalCoordinates()); + IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->repaintRectInLocalCoordinates()); RefPtr<CanvasPixelArray> srcPixelArrayB(in2->resultImage()->getPremultipliedImageData(effectBDrawingRect)->data()); IntRect imageRect(IntPoint(), resultImage()->size()); diff --git a/WebCore/platform/graphics/filters/FEBlend.h b/WebCore/platform/graphics/filters/FEBlend.h index 2e67588..a6569e2 100644 --- a/WebCore/platform/graphics/filters/FEBlend.h +++ b/WebCore/platform/graphics/filters/FEBlend.h @@ -1,23 +1,23 @@ /* - 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. -*/ + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ #ifndef FEBlend_h #define FEBlend_h @@ -29,31 +29,32 @@ namespace WebCore { - enum BlendModeType { - FEBLEND_MODE_UNKNOWN = 0, - FEBLEND_MODE_NORMAL = 1, - FEBLEND_MODE_MULTIPLY = 2, - FEBLEND_MODE_SCREEN = 3, - FEBLEND_MODE_DARKEN = 4, - FEBLEND_MODE_LIGHTEN = 5 - }; +enum BlendModeType { + FEBLEND_MODE_UNKNOWN = 0, + FEBLEND_MODE_NORMAL = 1, + FEBLEND_MODE_MULTIPLY = 2, + FEBLEND_MODE_SCREEN = 3, + FEBLEND_MODE_DARKEN = 4, + FEBLEND_MODE_LIGHTEN = 5 +}; - class FEBlend : public FilterEffect { - public: - static PassRefPtr<FEBlend> create(BlendModeType); +class FEBlend : public FilterEffect { +public: + static PassRefPtr<FEBlend> create(BlendModeType); - BlendModeType blendMode() const; - void setBlendMode(BlendModeType); + BlendModeType blendMode() const; + void setBlendMode(BlendModeType); - void apply(Filter*); - void dump(); - TextStream& externalRepresentation(TextStream&, int indent) const; + virtual void apply(Filter*); + virtual void dump(); - private: - FEBlend(BlendModeType); + virtual TextStream& externalRepresentation(TextStream&, int indention) const; - BlendModeType m_mode; - }; +private: + FEBlend(BlendModeType); + + BlendModeType m_mode; +}; } // namespace WebCore diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp index 1d9c66b..86c37c2 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp +++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp @@ -1,24 +1,24 @@ /* - 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. -*/ + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ #include "config.h" @@ -160,11 +160,11 @@ void FEColorMatrix::apply(Filter* filter) if (!in->resultImage()) return; - GraphicsContext* filterContext = getEffectContext(); + GraphicsContext* filterContext = effectContext(); if (!filterContext) return; - filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, calculateDrawingRect(in->repaintRectInLocalCoordinates())); + filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates())); IntRect imageRect(IntPoint(), resultImage()->size()); PassRefPtr<ImageData> imageData(resultImage()->getUnmultipliedImageData(imageRect)); diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.h b/WebCore/platform/graphics/filters/FEColorMatrix.h index 9b9084c..b898b17 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.h +++ b/WebCore/platform/graphics/filters/FEColorMatrix.h @@ -1,23 +1,23 @@ /* - 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. -*/ + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ #ifndef FEColorMatrix_h #define FEColorMatrix_h @@ -30,34 +30,35 @@ namespace WebCore { - enum ColorMatrixType { - FECOLORMATRIX_TYPE_UNKNOWN = 0, - FECOLORMATRIX_TYPE_MATRIX = 1, - FECOLORMATRIX_TYPE_SATURATE = 2, - FECOLORMATRIX_TYPE_HUEROTATE = 3, - FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4 - }; +enum ColorMatrixType { + FECOLORMATRIX_TYPE_UNKNOWN = 0, + FECOLORMATRIX_TYPE_MATRIX = 1, + FECOLORMATRIX_TYPE_SATURATE = 2, + FECOLORMATRIX_TYPE_HUEROTATE = 3, + FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4 +}; + +class FEColorMatrix : public FilterEffect { +public: + static PassRefPtr<FEColorMatrix> create(ColorMatrixType, const Vector<float>&); - class FEColorMatrix : public FilterEffect { - public: - static PassRefPtr<FEColorMatrix> create(ColorMatrixType, const Vector<float>&); + ColorMatrixType type() const; + void setType(ColorMatrixType); - ColorMatrixType type() const; - void setType(ColorMatrixType); + const Vector<float>& values() const; + void setValues(const Vector<float>&); - const Vector<float>& values() const; - void setValues(const Vector<float>&); + virtual void apply(Filter*); + virtual void dump(); - void apply(Filter*); - void dump(); - TextStream& externalRepresentation(TextStream&, int indent) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const; - private: - FEColorMatrix(ColorMatrixType, const Vector<float>&); +private: + FEColorMatrix(ColorMatrixType, const Vector<float>&); - ColorMatrixType m_type; - Vector<float> m_values; - }; + ColorMatrixType m_type; + Vector<float> m_values; +}; } // namespace WebCore diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp index 471fec8..6fe38e4 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp @@ -1,25 +1,25 @@ /* - 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> - Copyright (C) Research In Motion Limited 2010. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - 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. -*/ + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ #include "config.h" @@ -36,8 +36,8 @@ namespace WebCore { typedef void (*TransferType)(unsigned char*, const ComponentTransferFunction&); -FEComponentTransfer::FEComponentTransfer(const ComponentTransferFunction& redFunc, - const ComponentTransferFunction& greenFunc, const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc) +FEComponentTransfer::FEComponentTransfer(const ComponentTransferFunction& redFunc, const ComponentTransferFunction& greenFunc, + const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc) : FilterEffect() , m_redFunc(redFunc) , m_greenFunc(greenFunc) @@ -154,7 +154,7 @@ void FEComponentTransfer::apply(Filter* filter) if (!in->resultImage()) return; - if (!getEffectContext()) + if (!effectContext()) return; unsigned char rValues[256], gValues[256], bValues[256], aValues[256]; @@ -167,7 +167,7 @@ void FEComponentTransfer::apply(Filter* filter) for (unsigned channel = 0; channel < 4; channel++) (*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]); - IntRect drawingRect = calculateDrawingIntRect(in->repaintRectInLocalCoordinates()); + IntRect drawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates()); RefPtr<ImageData> imageData(in->resultImage()->getUnmultipliedImageData(drawingRect)); CanvasPixelArray* srcPixelArray(imageData->data()); diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.h b/WebCore/platform/graphics/filters/FEComponentTransfer.h index 55724db..d3145d4 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.h +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.h @@ -1,23 +1,23 @@ /* - 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. -*/ + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ #ifndef FEComponentTransfer_h #define FEComponentTransfer_h @@ -30,67 +30,68 @@ namespace WebCore { - enum ComponentTransferType { - FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0, - FECOMPONENTTRANSFER_TYPE_IDENTITY = 1, - FECOMPONENTTRANSFER_TYPE_TABLE = 2, - FECOMPONENTTRANSFER_TYPE_DISCRETE = 3, - FECOMPONENTTRANSFER_TYPE_LINEAR = 4, - FECOMPONENTTRANSFER_TYPE_GAMMA = 5 - }; - - struct ComponentTransferFunction { - ComponentTransferFunction() - : type(FECOMPONENTTRANSFER_TYPE_UNKNOWN) - , slope(0.0f) - , intercept(0.0f) - , amplitude(0.0f) - , exponent(0.0f) - , offset(0.0f) - { - } - - ComponentTransferType type; - - float slope; - float intercept; - float amplitude; - float exponent; - float offset; - - Vector<float> tableValues; - }; - - class FEComponentTransfer : public FilterEffect { - public: - static PassRefPtr<FEComponentTransfer> create(const ComponentTransferFunction&, - const ComponentTransferFunction&, const ComponentTransferFunction&, const ComponentTransferFunction&); - - ComponentTransferFunction redFunction() const; - void setRedFunction(const ComponentTransferFunction&); - - ComponentTransferFunction greenFunction() const; - void setGreenFunction(const ComponentTransferFunction&); - - ComponentTransferFunction blueFunction() const; - void setBlueFunction(const ComponentTransferFunction&); - - ComponentTransferFunction alphaFunction() const; - void setAlphaFunction(const ComponentTransferFunction&); - - void apply(Filter*); - void dump(); - TextStream& externalRepresentation(TextStream&, int indent) const; - - private: - FEComponentTransfer(const ComponentTransferFunction&, const ComponentTransferFunction&, - const ComponentTransferFunction&, const ComponentTransferFunction&); - - ComponentTransferFunction m_redFunc; - ComponentTransferFunction m_greenFunc; - ComponentTransferFunction m_blueFunc; - ComponentTransferFunction m_alphaFunc; - }; +enum ComponentTransferType { + FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0, + FECOMPONENTTRANSFER_TYPE_IDENTITY = 1, + FECOMPONENTTRANSFER_TYPE_TABLE = 2, + FECOMPONENTTRANSFER_TYPE_DISCRETE = 3, + FECOMPONENTTRANSFER_TYPE_LINEAR = 4, + FECOMPONENTTRANSFER_TYPE_GAMMA = 5 +}; + +struct ComponentTransferFunction { + ComponentTransferFunction() + : type(FECOMPONENTTRANSFER_TYPE_UNKNOWN) + , slope(0) + , intercept(0) + , amplitude(0) + , exponent(0) + , offset(0) + { + } + + ComponentTransferType type; + + float slope; + float intercept; + float amplitude; + float exponent; + float offset; + + Vector<float> tableValues; +}; + +class FEComponentTransfer : public FilterEffect { +public: + static PassRefPtr<FEComponentTransfer> create(const ComponentTransferFunction& redFunc, const ComponentTransferFunction& greenFunc, + const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc); + + ComponentTransferFunction redFunction() const; + void setRedFunction(const ComponentTransferFunction&); + + ComponentTransferFunction greenFunction() const; + void setGreenFunction(const ComponentTransferFunction&); + + ComponentTransferFunction blueFunction() const; + void setBlueFunction(const ComponentTransferFunction&); + + ComponentTransferFunction alphaFunction() const; + void setAlphaFunction(const ComponentTransferFunction&); + + virtual void apply(Filter*); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEComponentTransfer(const ComponentTransferFunction& redFunc, const ComponentTransferFunction& greenFunc, + const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc); + + ComponentTransferFunction m_redFunc; + ComponentTransferFunction m_greenFunc; + ComponentTransferFunction m_blueFunc; + ComponentTransferFunction m_alphaFunc; +}; } // namespace WebCore diff --git a/WebCore/platform/graphics/filters/FEComposite.cpp b/WebCore/platform/graphics/filters/FEComposite.cpp index c10a0f2..94e2524 100644 --- a/WebCore/platform/graphics/filters/FEComposite.cpp +++ b/WebCore/platform/graphics/filters/FEComposite.cpp @@ -1,24 +1,24 @@ /* - 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. -*/ + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ #include "config.h" @@ -122,39 +122,39 @@ void FEComposite::apply(Filter* filter) if (!in->resultImage() || !in2->resultImage()) return; - GraphicsContext* filterContext = getEffectContext(); + GraphicsContext* filterContext = effectContext(); if (!filterContext) return; - FloatRect srcRect = FloatRect(0.f, 0.f, -1.f, -1.f); + FloatRect srcRect = FloatRect(0, 0, -1, -1); switch (m_type) { case FECOMPOSITE_OPERATOR_OVER: - filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, calculateDrawingRect(in2->repaintRectInLocalCoordinates())); - filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, calculateDrawingRect(in->repaintRectInLocalCoordinates())); + filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates())); + filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates())); break; case FECOMPOSITE_OPERATOR_IN: filterContext->save(); - filterContext->clipToImageBuffer(in2->resultImage(), calculateDrawingRect(in2->repaintRectInLocalCoordinates())); - filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, calculateDrawingRect(in->repaintRectInLocalCoordinates())); + filterContext->clipToImageBuffer(in2->resultImage(), drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates())); + filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates())); filterContext->restore(); break; case FECOMPOSITE_OPERATOR_OUT: - filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, calculateDrawingRect(in->repaintRectInLocalCoordinates())); - filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, calculateDrawingRect(in2->repaintRectInLocalCoordinates()), srcRect, CompositeDestinationOut); + filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates())); + filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates()), srcRect, CompositeDestinationOut); break; case FECOMPOSITE_OPERATOR_ATOP: - filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, calculateDrawingRect(in2->repaintRectInLocalCoordinates())); - filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, calculateDrawingRect(in->repaintRectInLocalCoordinates()), srcRect, CompositeSourceAtop); + filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates())); + filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates()), srcRect, CompositeSourceAtop); break; case FECOMPOSITE_OPERATOR_XOR: - filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, calculateDrawingRect(in2->repaintRectInLocalCoordinates())); - filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, calculateDrawingRect(in->repaintRectInLocalCoordinates()), srcRect, CompositeXOR); + filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates())); + filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates()), srcRect, CompositeXOR); break; case FECOMPOSITE_OPERATOR_ARITHMETIC: { - IntRect effectADrawingRect = calculateDrawingIntRect(in->repaintRectInLocalCoordinates()); + IntRect effectADrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates()); RefPtr<CanvasPixelArray> srcPixelArrayA(in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); - IntRect effectBDrawingRect = calculateDrawingIntRect(in2->repaintRectInLocalCoordinates()); + IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->repaintRectInLocalCoordinates()); RefPtr<ImageData> imageData(in2->resultImage()->getPremultipliedImageData(effectBDrawingRect)); CanvasPixelArray* srcPixelArrayB(imageData->data()); diff --git a/WebCore/platform/graphics/filters/FEComposite.h b/WebCore/platform/graphics/filters/FEComposite.h index 448d036..82a3b06 100644 --- a/WebCore/platform/graphics/filters/FEComposite.h +++ b/WebCore/platform/graphics/filters/FEComposite.h @@ -1,23 +1,23 @@ /* - 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. -*/ + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ #ifndef FEComposite_h #define FEComposite_h @@ -59,9 +59,10 @@ public: float k4() const; void setK4(float); - void apply(Filter*); - void dump(); - TextStream& externalRepresentation(TextStream&, int indent) const; + virtual void apply(Filter*); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; private: FEComposite(const CompositeOperationType&, float, float, float, float); diff --git a/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp b/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp new file mode 100644 index 0000000..dd66c6a --- /dev/null +++ b/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp @@ -0,0 +1,471 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2010 Zoltan Herczeg <zherczeg@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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEConvolveMatrix.h" + +#include "CanvasPixelArray.h" +#include "Filter.h" +#include "ImageData.h" + +namespace WebCore { + +FEConvolveMatrix::FEConvolveMatrix(const IntSize& kernelSize, + float divisor, float bias, const IntPoint& targetOffset, EdgeModeType edgeMode, + const FloatPoint& kernelUnitLength, bool preserveAlpha, const Vector<float>& kernelMatrix) + : FilterEffect() + , m_kernelSize(kernelSize) + , m_divisor(divisor) + , m_bias(bias) + , m_targetOffset(targetOffset) + , m_edgeMode(edgeMode) + , m_kernelUnitLength(kernelUnitLength) + , m_preserveAlpha(preserveAlpha) + , m_kernelMatrix(kernelMatrix) +{ +} + +PassRefPtr<FEConvolveMatrix> FEConvolveMatrix::create(const IntSize& kernelSize, + float divisor, float bias, const IntPoint& targetOffset, EdgeModeType edgeMode, + const FloatPoint& kernelUnitLength, bool preserveAlpha, const Vector<float>& kernelMatrix) +{ + return adoptRef(new FEConvolveMatrix(kernelSize, divisor, bias, targetOffset, edgeMode, kernelUnitLength, + preserveAlpha, kernelMatrix)); +} + + +IntSize FEConvolveMatrix::kernelSize() const +{ + return m_kernelSize; +} + +void FEConvolveMatrix::setKernelSize(IntSize kernelSize) +{ + m_kernelSize = kernelSize; +} + +const Vector<float>& FEConvolveMatrix::kernel() const +{ + return m_kernelMatrix; +} + +void FEConvolveMatrix::setKernel(const Vector<float>& kernel) +{ + m_kernelMatrix = kernel; +} + +float FEConvolveMatrix::divisor() const +{ + return m_divisor; +} + +void FEConvolveMatrix::setDivisor(float divisor) +{ + m_divisor = divisor; +} + +float FEConvolveMatrix::bias() const +{ + return m_bias; +} + +void FEConvolveMatrix::setBias(float bias) +{ + m_bias = bias; +} + +IntPoint FEConvolveMatrix::targetOffset() const +{ + return m_targetOffset; +} + +void FEConvolveMatrix::setTargetOffset(IntPoint targetOffset) +{ + m_targetOffset = targetOffset; +} + +EdgeModeType FEConvolveMatrix::edgeMode() const +{ + return m_edgeMode; +} + +void FEConvolveMatrix::setEdgeMode(EdgeModeType edgeMode) +{ + m_edgeMode = edgeMode; +} + +FloatPoint FEConvolveMatrix::kernelUnitLength() const +{ + return m_kernelUnitLength; +} + +void FEConvolveMatrix::setKernelUnitLength(FloatPoint kernelUnitLength) +{ + m_kernelUnitLength = kernelUnitLength; +} + +bool FEConvolveMatrix::preserveAlpha() const +{ + return m_preserveAlpha; +} + +void FEConvolveMatrix::setPreserveAlpha(bool preserveAlpha) +{ + m_preserveAlpha = preserveAlpha; +} + +/* + ----------------------------------- + ConvolveMatrix implementation + ----------------------------------- + + The image rectangle is split in the following way: + + +---------------------+ + | A | + +---------------------+ + | | | | + | B | C | D | + | | | | + +---------------------+ + | E | + +---------------------+ + + Where region C contains those pixels, whose values + can be calculated without crossing the edge of the rectangle. + + Example: + Image size: width: 10, height: 10 + + Order (kernel matrix size): width: 3, height 4 + Target: x:1, y:3 + + The following figure shows the target inside the kernel matrix: + + ... + ... + ... + .X. + + The regions in this case are the following: + Note: (x1, y1) top-left and (x2, y2) is the bottom-right corner + Note: row x2 and column y2 is not part of the region + only those (x, y) pixels, where x1 <= x < x2 and y1 <= y < y2 + + Region A: x1: 0, y1: 0, x2: 10, y2: 3 + Region B: x1: 0, y1: 3, x2: 1, y2: 10 + Region C: x1: 1, y1: 3, x2: 9, y2: 10 + Region D: x1: 9, y1: 3, x2: 10, y2: 10 + Region E: x1: 0, y1: 10, x2: 10, y2: 10 (empty region) + + Since region C (often) contains most of the pixels, we implemented + a fast algoritm to calculate these values, called fastSetInteriorPixels. + For other regions, fastSetOuterPixels is used, which calls getPixelValue, + to handle pixels outside of the image. In a rare situations, when + kernel matrix is bigger than the image, all pixels are calculated by this + function. + + Although these two functions have lot in common, I decided not to make + common a template for them, since there are key differences as well, + and would make it really hard to understand. +*/ + +static ALWAYS_INLINE unsigned char clampRGBAValue(float channel, unsigned char max = 255) +{ + if (channel <= 0) + return 0; + if (channel >= max) + return max; + return channel; +} + +template<bool preserveAlphaValues> +ALWAYS_INLINE void setDestinationPixels(CanvasPixelArray* image, int& pixel, float* totals, float divisor, float bias, CanvasPixelArray* src) +{ + unsigned char maxAlpha = preserveAlphaValues ? 255 : clampRGBAValue(totals[3] / divisor + bias); + for (int i = 0; i < 3; ++i) + image->set(pixel++, clampRGBAValue(totals[i] / divisor + bias, maxAlpha)); + + if (preserveAlphaValues) { + image->set(pixel, src->get(pixel)); + ++pixel; + } else + image->set(pixel++, maxAlpha); +} + +// Only for region C +template<bool preserveAlphaValues> +ALWAYS_INLINE void FEConvolveMatrix::fastSetInteriorPixels(PaintingData& paintingData, int clipRight, int clipBottom) +{ + // edge mode does not affect these pixels + int pixel = (m_targetOffset.y() * paintingData.width + m_targetOffset.x()) * 4; + int startKernelPixel = 0; + int kernelIncrease = clipRight * 4; + int xIncrease = (m_kernelSize.width() - 1) * 4; + // Contains the sum of rgb(a) components + float totals[3 + (preserveAlphaValues ? 0 : 1)]; + + // m_divisor cannot be 0, SVGFEConvolveMatrixElement ensures this + ASSERT(m_divisor); + + for (int y = clipBottom + 1; y > 0; --y) { + for (int x = clipRight + 1; x > 0; --x) { + int kernelValue = m_kernelMatrix.size() - 1; + int kernelPixel = startKernelPixel; + int width = m_kernelSize.width(); + + totals[0] = 0; + totals[1] = 0; + totals[2] = 0; + if (!preserveAlphaValues) + totals[3] = 0; + + while (kernelValue >= 0) { + totals[0] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(kernelPixel++)); + totals[1] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(kernelPixel++)); + totals[2] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(kernelPixel++)); + if (!preserveAlphaValues) + totals[3] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(kernelPixel)); + ++kernelPixel; + --kernelValue; + if (!--width) { + kernelPixel += kernelIncrease; + width = m_kernelSize.width(); + } + } + + setDestinationPixels<preserveAlphaValues>(paintingData.dstPixelArray, pixel, totals, m_divisor, paintingData.bias, paintingData.srcPixelArray); + startKernelPixel += 4; + } + pixel += xIncrease; + startKernelPixel += xIncrease; + } +} + +ALWAYS_INLINE int FEConvolveMatrix::getPixelValue(PaintingData& paintingData, int x, int y) +{ + if (x >= 0 && x < paintingData.width && x >= 0 && y < paintingData.height) + return (y * paintingData.width + x) << 2; + + switch (m_edgeMode) { + default: // EDGEMODE_NONE + return -1; + case EDGEMODE_DUPLICATE: + if (x < 0) + x = 0; + else if (x >= paintingData.width) + x = paintingData.width - 1; + if (y < 0) + y = 0; + else if (y >= paintingData.height) + y = paintingData.height - 1; + return (y * paintingData.width + x) << 2; + case EDGEMODE_WRAP: + while (x < 0) + x += paintingData.width; + x %= paintingData.width; + while (y < 0) + y += paintingData.height; + y %= paintingData.height; + return (y * paintingData.width + x) << 2; + } +} + +// For other regions than C +template<bool preserveAlphaValues> +void FEConvolveMatrix::fastSetOuterPixels(PaintingData& paintingData, int x1, int y1, int x2, int y2) +{ + int pixel = (y1 * paintingData.width + x1) * 4; + int height = y2 - y1; + int width = x2 - x1; + int beginKernelPixelX = x1 - m_targetOffset.x(); + int startKernelPixelX = beginKernelPixelX; + int startKernelPixelY = y1 - m_targetOffset.y(); + int xIncrease = (paintingData.width - width) * 4; + // Contains the sum of rgb(a) components + float totals[3 + (preserveAlphaValues ? 0 : 1)]; + + // m_divisor cannot be 0, SVGFEConvolveMatrixElement ensures this + ASSERT(m_divisor); + + for (int y = height; y > 0; --y) { + for (int x = width; x > 0; --x) { + int kernelValue = m_kernelMatrix.size() - 1; + int kernelPixelX = startKernelPixelX; + int kernelPixelY = startKernelPixelY; + int width = m_kernelSize.width(); + + totals[0] = 0; + totals[1] = 0; + totals[2] = 0; + if (!preserveAlphaValues) + totals[3] = 0; + + while (kernelValue >= 0) { + int pixelIndex = getPixelValue(paintingData, kernelPixelX, kernelPixelY); + if (pixelIndex >= 0) { + totals[0] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(pixelIndex)); + totals[1] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(pixelIndex + 1)); + totals[2] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(pixelIndex + 2)); + } + if (!preserveAlphaValues && pixelIndex >= 0) + totals[3] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(pixelIndex + 3)); + ++kernelPixelX; + --kernelValue; + if (!--width) { + kernelPixelX = startKernelPixelX; + ++kernelPixelY; + width = m_kernelSize.width(); + } + } + + setDestinationPixels<preserveAlphaValues>(paintingData.dstPixelArray, pixel, totals, m_divisor, paintingData.bias, paintingData.srcPixelArray); + ++startKernelPixelX; + } + pixel += xIncrease; + startKernelPixelX = beginKernelPixelX; + ++startKernelPixelY; + } +} + +ALWAYS_INLINE void FEConvolveMatrix::setInteriorPixels(PaintingData& paintingData, int clipRight, int clipBottom) +{ + // Must be implemented here, since it refers another ALWAYS_INLINE + // function, which defined in this C++ source file as well + if (m_preserveAlpha) + fastSetInteriorPixels<true>(paintingData, clipRight, clipBottom); + else + fastSetInteriorPixels<false>(paintingData, clipRight, clipBottom); +} + +ALWAYS_INLINE void FEConvolveMatrix::setOuterPixels(PaintingData& paintingData, int x1, int y1, int x2, int y2) +{ + // Although this function can be moved to the header, it is implemented here + // because setInteriorPixels is also implemented here + if (m_preserveAlpha) + fastSetOuterPixels<true>(paintingData, x1, y1, x2, y2); + else + fastSetOuterPixels<false>(paintingData, x1, y1, x2, y2); +} + +void FEConvolveMatrix::apply(Filter* filter) +{ + FilterEffect* in = inputEffect(0); + in->apply(filter); + if (!in->resultImage()) + return; + + if (!effectContext()) + return; + + IntRect imageRect(IntPoint(), resultImage()->size()); + IntRect effectDrawingRect = requestedRegionOfInputImageData(in->filterPrimitiveSubregion()); + + RefPtr<CanvasPixelArray> srcPixelArray; + if (m_preserveAlpha) + srcPixelArray = in->resultImage()->getUnmultipliedImageData(effectDrawingRect)->data(); + else + srcPixelArray = in->resultImage()->getPremultipliedImageData(effectDrawingRect)->data(); + + RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); + + PaintingData paintingData; + paintingData.srcPixelArray = srcPixelArray.get(); + paintingData.dstPixelArray = imageData->data(); + paintingData.width = imageRect.width(); + paintingData.height = imageRect.height(); + paintingData.bias = m_bias * 255; + + // Drawing fully covered pixels + int clipRight = imageRect.width() - m_kernelSize.width(); + int clipBottom = imageRect.height() - m_kernelSize.height(); + + if (clipRight >= 0 && clipBottom >= 0) { + setInteriorPixels(paintingData, clipRight, clipBottom); + + clipRight += m_targetOffset.x() + 1; + clipBottom += m_targetOffset.y() + 1; + if (m_targetOffset.y() > 0) + setOuterPixels(paintingData, 0, 0, imageRect.width(), m_targetOffset.y()); + if (clipBottom < imageRect.height()) + setOuterPixels(paintingData, 0, clipBottom, imageRect.width(), imageRect.height()); + if (m_targetOffset.x() > 0) + setOuterPixels(paintingData, 0, m_targetOffset.y(), m_targetOffset.x(), clipBottom); + if (clipRight < imageRect.width()) + setOuterPixels(paintingData, clipRight, m_targetOffset.y(), imageRect.width(), clipBottom); + } else { + // Rare situation, not optimizied for speed + setOuterPixels(paintingData, 0, 0, imageRect.width(), imageRect.height()); + } + + if (m_preserveAlpha) + resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint()); + else + resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint()); +} + +void FEConvolveMatrix::dump() +{ +} + +static TextStream& operator<<(TextStream& ts, const EdgeModeType& type) +{ + switch (type) { + case EDGEMODE_UNKNOWN: + ts << "UNKNOWN"; + break; + case EDGEMODE_DUPLICATE: + ts << "DUPLICATE"; + break; + case EDGEMODE_WRAP: + ts << "WRAP"; + break; + case EDGEMODE_NONE: + ts << "NONE"; + break; + } + return ts; +} + +TextStream& FEConvolveMatrix::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feConvolveMatrix"; + FilterEffect::externalRepresentation(ts); + ts << " order=\"" << m_kernelSize << "\" " + << "kernelMatrix=\"" << m_kernelMatrix << "\" " + << "divisor=\"" << m_divisor << "\" " + << "bias=\"" << m_bias << "\" " + << "target=\"" << m_targetOffset << "\" " + << "edgeMode=\"" << m_edgeMode << "\" " + << "kernelUnitLength=\"" << m_kernelUnitLength << "\" " + << "preserveAlpha=\"" << m_preserveAlpha << "\"]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +}; // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEConvolveMatrix.h b/WebCore/platform/graphics/filters/FEConvolveMatrix.h new file mode 100644 index 0000000..2fe634f --- /dev/null +++ b/WebCore/platform/graphics/filters/FEConvolveMatrix.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2010 Zoltan Herczeg <zherczeg@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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEConvolveMatrix_h +#define FEConvolveMatrix_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "FloatPoint.h" +#include "FloatSize.h" +#include "Filter.h" +#include <wtf/AlwaysInline.h> +#include <wtf/Vector.h> + +namespace WebCore { + +enum EdgeModeType { + EDGEMODE_UNKNOWN = 0, + EDGEMODE_DUPLICATE = 1, + EDGEMODE_WRAP = 2, + EDGEMODE_NONE = 3 +}; + +class CanvasPixelArray; + +class FEConvolveMatrix : public FilterEffect { +public: + static PassRefPtr<FEConvolveMatrix> create(const IntSize&, + float, float, const IntPoint&, EdgeModeType, const FloatPoint&, + bool, const Vector<float>&); + + IntSize kernelSize() const; + void setKernelSize(IntSize); + + const Vector<float>& kernel() const; + void setKernel(const Vector<float>&); + + float divisor() const; + void setDivisor(float); + + float bias() const; + void setBias(float); + + IntPoint targetOffset() const; + void setTargetOffset(IntPoint); + + EdgeModeType edgeMode() const; + void setEdgeMode(EdgeModeType); + + FloatPoint kernelUnitLength() const; + void setKernelUnitLength(FloatPoint); + + bool preserveAlpha() const; + void setPreserveAlpha(bool); + + virtual void apply(Filter*); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEConvolveMatrix(const IntSize&, float, float, + const IntPoint&, EdgeModeType, const FloatPoint&, bool, const Vector<float>&); + + struct PaintingData { + CanvasPixelArray* srcPixelArray; + CanvasPixelArray* dstPixelArray; + int width; + int height; + float bias; + }; + + template<bool preserveAlphaValues> + ALWAYS_INLINE void fastSetInteriorPixels(PaintingData&, int clipRight, int clipBottom); + + ALWAYS_INLINE int getPixelValue(PaintingData&, int x, int y); + + template<bool preserveAlphaValues> + void fastSetOuterPixels(PaintingData&, int x1, int y1, int x2, int y2); + + // Wrapper functions + ALWAYS_INLINE void setInteriorPixels(PaintingData& paintingData, int clipRight, int clipBottom); + ALWAYS_INLINE void setOuterPixels(PaintingData& paintingData, int x1, int y1, int x2, int y2); + + IntSize m_kernelSize; + float m_divisor; + float m_bias; + IntPoint m_targetOffset; + EdgeModeType m_edgeMode; + FloatPoint m_kernelUnitLength; + bool m_preserveAlpha; + Vector<float> m_kernelMatrix; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEConvolveMatrix_h diff --git a/WebCore/platform/graphics/filters/FEDiffuseLighting.cpp b/WebCore/platform/graphics/filters/FEDiffuseLighting.cpp new file mode 100644 index 0000000..98b5adf --- /dev/null +++ b/WebCore/platform/graphics/filters/FEDiffuseLighting.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEDiffuseLighting.h" + +#include "LightSource.h" + +namespace WebCore { + +FEDiffuseLighting::FEDiffuseLighting(const Color& lightingColor, float surfaceScale, + float diffuseConstant, float kernelUnitLengthX, float kernelUnitLengthY, PassRefPtr<LightSource> lightSource) + : FELighting(DiffuseLighting, lightingColor, surfaceScale, diffuseConstant, 0, 0, kernelUnitLengthX, kernelUnitLengthY, lightSource) +{ +} + +PassRefPtr<FEDiffuseLighting> FEDiffuseLighting::create(const Color& lightingColor, + float surfaceScale, float diffuseConstant, float kernelUnitLengthX, + float kernelUnitLengthY, PassRefPtr<LightSource> lightSource) +{ + return adoptRef(new FEDiffuseLighting(lightingColor, surfaceScale, diffuseConstant, kernelUnitLengthX, kernelUnitLengthY, lightSource)); +} + +FEDiffuseLighting::~FEDiffuseLighting() +{ +} + +Color FEDiffuseLighting::lightingColor() const +{ + return m_lightingColor; +} + +void FEDiffuseLighting::setLightingColor(const Color& lightingColor) +{ + m_lightingColor = lightingColor; +} + +float FEDiffuseLighting::surfaceScale() const +{ + return m_surfaceScale; +} + +void FEDiffuseLighting::setSurfaceScale(float surfaceScale) +{ + m_surfaceScale = surfaceScale; +} + +float FEDiffuseLighting::diffuseConstant() const +{ + return m_diffuseConstant; +} + +void FEDiffuseLighting::setDiffuseConstant(float diffuseConstant) +{ + m_diffuseConstant = diffuseConstant; +} + +float FEDiffuseLighting::kernelUnitLengthX() const +{ + return m_kernelUnitLengthX; +} + +void FEDiffuseLighting::setKernelUnitLengthX(float kernelUnitLengthX) +{ + m_kernelUnitLengthX = kernelUnitLengthX; +} + +float FEDiffuseLighting::kernelUnitLengthY() const +{ + return m_kernelUnitLengthY; +} + +void FEDiffuseLighting::setKernelUnitLengthY(float kernelUnitLengthY) +{ + m_kernelUnitLengthY = kernelUnitLengthY; +} + +const LightSource* FEDiffuseLighting::lightSource() const +{ + return m_lightSource.get(); +} + +void FEDiffuseLighting::setLightSource(PassRefPtr<LightSource> lightSource) +{ + m_lightSource = lightSource; +} + +void FEDiffuseLighting::dump() +{ +} + +TextStream& FEDiffuseLighting::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feDiffuseLighting"; + FilterEffect::externalRepresentation(ts); + ts << " surfaceScale=\"" << m_surfaceScale << "\" " + << "diffuseConstant=\"" << m_diffuseConstant << "\" " + << "kernelUnitLength=\"" << m_kernelUnitLengthX << ", " << m_kernelUnitLengthY << "\"]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEDiffuseLighting.h b/WebCore/platform/graphics/filters/FEDiffuseLighting.h new file mode 100644 index 0000000..5273144 --- /dev/null +++ b/WebCore/platform/graphics/filters/FEDiffuseLighting.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEDiffuseLighting_h +#define FEDiffuseLighting_h + +#if ENABLE(FILTERS) +#include "FELighting.h" + +namespace WebCore { + +class LightSource; + +class FEDiffuseLighting : public FELighting { +public: + static PassRefPtr<FEDiffuseLighting> create(const Color&, float, float, + float, float, PassRefPtr<LightSource>); + virtual ~FEDiffuseLighting(); + + Color lightingColor() const; + void setLightingColor(const Color&); + + float surfaceScale() const; + void setSurfaceScale(float); + + float diffuseConstant() const; + void setDiffuseConstant(float); + + float kernelUnitLengthX() const; + void setKernelUnitLengthX(float); + + float kernelUnitLengthY() const; + void setKernelUnitLengthY(float); + + const LightSource* lightSource() const; + void setLightSource(PassRefPtr<LightSource>); + + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEDiffuseLighting(const Color&, float, float, float, float, PassRefPtr<LightSource>); +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEDiffuseLighting_h diff --git a/WebCore/platform/graphics/filters/FEDisplacementMap.cpp b/WebCore/platform/graphics/filters/FEDisplacementMap.cpp new file mode 100644 index 0000000..6b5dbaa --- /dev/null +++ b/WebCore/platform/graphics/filters/FEDisplacementMap.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEDisplacementMap.h" + +#include "CanvasPixelArray.h" +#include "Filter.h" +#include "GraphicsContext.h" +#include "ImageData.h" + +namespace WebCore { + +FEDisplacementMap::FEDisplacementMap(ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, float scale) + : FilterEffect() + , m_xChannelSelector(xChannelSelector) + , m_yChannelSelector(yChannelSelector) + , m_scale(scale) +{ +} + +PassRefPtr<FEDisplacementMap> FEDisplacementMap::create(ChannelSelectorType xChannelSelector, + ChannelSelectorType yChannelSelector, float scale) +{ + return adoptRef(new FEDisplacementMap(xChannelSelector, yChannelSelector, scale)); +} + +ChannelSelectorType FEDisplacementMap::xChannelSelector() const +{ + return m_xChannelSelector; +} + +void FEDisplacementMap::setXChannelSelector(const ChannelSelectorType xChannelSelector) +{ + m_xChannelSelector = xChannelSelector; +} + +ChannelSelectorType FEDisplacementMap::yChannelSelector() const +{ + return m_yChannelSelector; +} + +void FEDisplacementMap::setYChannelSelector(const ChannelSelectorType yChannelSelector) +{ + m_yChannelSelector = yChannelSelector; +} + +float FEDisplacementMap::scale() const +{ + return m_scale; +} + +void FEDisplacementMap::setScale(float scale) +{ + m_scale = scale; +} + +void FEDisplacementMap::apply(Filter* filter) +{ + FilterEffect* in = inputEffect(0); + FilterEffect* in2 = inputEffect(1); + in->apply(filter); + in2->apply(filter); + if (!in->resultImage() || !in2->resultImage()) + return; + + if (m_xChannelSelector == CHANNEL_UNKNOWN || m_yChannelSelector == CHANNEL_UNKNOWN) + return; + + if (!effectContext()) + return; + + IntRect effectADrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates()); + RefPtr<CanvasPixelArray> srcPixelArrayA(in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); + + IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->repaintRectInLocalCoordinates()); + RefPtr<CanvasPixelArray> srcPixelArrayB(in2->resultImage()->getUnmultipliedImageData(effectBDrawingRect)->data()); + + IntRect imageRect(IntPoint(), resultImage()->size()); + RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); + + ASSERT(srcPixelArrayA->length() == srcPixelArrayB->length()); + + float scaleX = m_scale / 255.f * filter->filterResolution().width(); + float scaleY = m_scale / 255.f * filter->filterResolution().height(); + float scaleAdjustmentX = (0.5f - 0.5f * m_scale) * filter->filterResolution().width(); + float scaleAdjustmentY = (0.5f - 0.5f * m_scale) * filter->filterResolution().height(); + int stride = imageRect.width() * 4; + for (int y = 0; y < imageRect.height(); ++y) { + int line = y * stride; + for (int x = 0; x < imageRect.width(); ++x) { + int dstIndex = line + x * 4; + int srcX = x + static_cast<int>(scaleX * srcPixelArrayB->get(dstIndex + m_xChannelSelector - 1) + scaleAdjustmentX); + int srcY = y + static_cast<int>(scaleY * srcPixelArrayB->get(dstIndex + m_yChannelSelector - 1) + scaleAdjustmentY); + for (unsigned channel = 0; channel < 4; ++channel) { + if (srcX < 0 || srcX >= imageRect.width() || srcY < 0 || srcY >= imageRect.height()) + imageData->data()->set(dstIndex + channel, static_cast<unsigned char>(0)); + else { + unsigned char pixelValue = srcPixelArrayA->get(srcY * stride + srcX * 4 + channel); + imageData->data()->set(dstIndex + channel, pixelValue); + } + } + + } + } + resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint()); +} + +void FEDisplacementMap::dump() +{ +} + +static TextStream& operator<<(TextStream& ts, const ChannelSelectorType& type) +{ + switch (type) { + case CHANNEL_UNKNOWN: + ts << "UNKNOWN"; + break; + case CHANNEL_R: + ts << "RED"; + break; + case CHANNEL_G: + ts << "GREEN"; + break; + case CHANNEL_B: + ts << "BLUE"; + break; + case CHANNEL_A: + ts << "ALPHA"; + break; + } + return ts; +} + +TextStream& FEDisplacementMap::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feDisplacementMap"; + FilterEffect::externalRepresentation(ts); + ts << " scale=\"" << m_scale << "\" " + << "xChannelSelector=\"" << m_xChannelSelector << "\" " + << "yChannelSelector=\"" << m_yChannelSelector << "\"]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + inputEffect(1)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEDisplacementMap.h b/WebCore/platform/graphics/filters/FEDisplacementMap.h new file mode 100644 index 0000000..dc87b90 --- /dev/null +++ b/WebCore/platform/graphics/filters/FEDisplacementMap.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEDisplacementMap_h +#define FEDisplacementMap_h + +#if ENABLE(FILTERS) +#include "PlatformString.h" +#include "FilterEffect.h" +#include "Filter.h" + +namespace WebCore { + +enum ChannelSelectorType { + CHANNEL_UNKNOWN = 0, + CHANNEL_R = 1, + CHANNEL_G = 2, + CHANNEL_B = 3, + CHANNEL_A = 4 +}; + +class FEDisplacementMap : public FilterEffect { +public: + static PassRefPtr<FEDisplacementMap> create(ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, float); + + ChannelSelectorType xChannelSelector() const; + void setXChannelSelector(const ChannelSelectorType); + + ChannelSelectorType yChannelSelector() const; + void setYChannelSelector(const ChannelSelectorType); + + float scale() const; + void setScale(float scale); + + virtual void apply(Filter*); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEDisplacementMap(ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, float); + + ChannelSelectorType m_xChannelSelector; + ChannelSelectorType m_yChannelSelector; + float m_scale; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEDisplacementMap_h diff --git a/WebCore/platform/graphics/filters/FEFlood.cpp b/WebCore/platform/graphics/filters/FEFlood.cpp new file mode 100644 index 0000000..7804d89 --- /dev/null +++ b/WebCore/platform/graphics/filters/FEFlood.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEFlood.h" + +#include "Filter.h" +#include "GraphicsContext.h" + +namespace WebCore { + +FEFlood::FEFlood(const Color& floodColor, float floodOpacity) + : FilterEffect() + , m_floodColor(floodColor) + , m_floodOpacity(floodOpacity) +{ +} + +PassRefPtr<FEFlood> FEFlood::create(const Color& floodColor, float floodOpacity) +{ + return adoptRef(new FEFlood(floodColor, floodOpacity)); +} + +Color FEFlood::floodColor() const +{ + return m_floodColor; +} + +void FEFlood::setFloodColor(const Color& color) +{ + m_floodColor = color; +} + +float FEFlood::floodOpacity() const +{ + return m_floodOpacity; +} + +void FEFlood::setFloodOpacity(float floodOpacity) +{ + m_floodOpacity = floodOpacity; +} + +void FEFlood::apply(Filter*) +{ + GraphicsContext* filterContext = effectContext(); + if (!filterContext) + return; + + Color color = colorWithOverrideAlpha(floodColor().rgb(), floodOpacity()); + filterContext->fillRect(FloatRect(FloatPoint(), repaintRectInLocalCoordinates().size()), color, DeviceColorSpace); +} + +void FEFlood::dump() +{ +} + +TextStream& FEFlood::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feFlood"; + FilterEffect::externalRepresentation(ts); + ts << " flood-color=\"" << floodColor().name() << "\" " + << "flood-opacity=\"" << floodOpacity() << "\"]\n"; + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEFlood.h b/WebCore/platform/graphics/filters/FEFlood.h new file mode 100644 index 0000000..b615531 --- /dev/null +++ b/WebCore/platform/graphics/filters/FEFlood.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEFlood_h +#define FEFlood_h + +#if ENABLE(FILTERS) +#include "Color.h" +#include "Filter.h" +#include "FilterEffect.h" + +namespace WebCore { + +class FEFlood : public FilterEffect { +public: + static PassRefPtr<FEFlood> create(const Color&, float); + + Color floodColor() const; + void setFloodColor(const Color &); + + float floodOpacity() const; + void setFloodOpacity(float); + + virtual void apply(Filter*); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEFlood(const Color&, float); + + Color m_floodColor; + float m_floodOpacity; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEFlood_h diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp index 72a5a04..fd9a3d8 100644 --- a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp @@ -1,25 +1,25 @@ /* - 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> - 2010 Igalia, S.L. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - 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. -*/ + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2010 Igalia, S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ #include "config.h" @@ -132,12 +132,12 @@ void FEGaussianBlur::apply(Filter* filter) if (!in->resultImage()) return; - if (!getEffectContext()) + if (!effectContext()) return; setIsAlphaImage(in->isAlphaImage()); - IntRect effectDrawingRect = calculateDrawingIntRect(in->repaintRectInLocalCoordinates()); + IntRect effectDrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates()); RefPtr<ImageData> srcImageData(in->resultImage()->getPremultipliedImageData(effectDrawingRect)); IntRect imageRect(IntPoint(), resultImage()->size()); diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.h b/WebCore/platform/graphics/filters/FEGaussianBlur.h index 63d763e..745bcc8 100644 --- a/WebCore/platform/graphics/filters/FEGaussianBlur.h +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.h @@ -1,23 +1,23 @@ /* - 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. -*/ + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ #ifndef FEGaussianBlur_h #define FEGaussianBlur_h @@ -38,12 +38,13 @@ public: float stdDeviationY() const; void setStdDeviationY(float); - void apply(Filter*); - void dump(); - TextStream& externalRepresentation(TextStream&, int indent) const; - static float calculateStdDeviation(float); + virtual void apply(Filter*); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + private: FEGaussianBlur(float, float); static void kernelPosition(int boxBlur, unsigned& std, int& dLeft, int& dRight); diff --git a/WebCore/platform/graphics/filters/FELighting.cpp b/WebCore/platform/graphics/filters/FELighting.cpp new file mode 100644 index 0000000..f49b67d --- /dev/null +++ b/WebCore/platform/graphics/filters/FELighting.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2010 University of Szeged + * Copyright (C) 2010 Zoltan Herczeg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FELighting.h" + +#include "CanvasPixelArray.h" +#include "ImageData.h" +#include "LightSource.h" + +namespace WebCore { + +FELighting::FELighting(LightingType lightingType, const Color& lightingColor, float surfaceScale, + float diffuseConstant, float specularConstant, float specularExponent, + float kernelUnitLengthX, float kernelUnitLengthY, PassRefPtr<LightSource> lightSource) + : FilterEffect() + , m_lightingType(lightingType) + , m_lightSource(lightSource) + , m_lightingColor(lightingColor) + , m_surfaceScale(surfaceScale) + , m_diffuseConstant(diffuseConstant) + , m_specularConstant(specularConstant) + , m_specularExponent(specularExponent) + , m_kernelUnitLengthX(kernelUnitLengthX) + , m_kernelUnitLengthY(kernelUnitLengthY) +{ +} + +const static int cPixelSize = 4; +const static int cAlphaChannelOffset = 3; +const static unsigned char cOpaqueAlpha = static_cast<unsigned char>(0xff); + +ALWAYS_INLINE int FELighting::LightingData::upLeftPixelValue() +{ + return static_cast<int>(pixels->get(offset - widthMultipliedByPixelSize - cPixelSize + cAlphaChannelOffset)); +} + +ALWAYS_INLINE int FELighting::LightingData::upPixelValue() +{ + return static_cast<int>(pixels->get(offset - widthMultipliedByPixelSize + cAlphaChannelOffset)); +} + +ALWAYS_INLINE int FELighting::LightingData::upRightPixelValue() +{ + return static_cast<int>(pixels->get(offset - widthMultipliedByPixelSize + cPixelSize + cAlphaChannelOffset)); +} + +ALWAYS_INLINE int FELighting::LightingData::leftPixelValue() +{ + return static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); +} + +ALWAYS_INLINE int FELighting::LightingData::centerPixelValue() +{ + return static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); +} + +ALWAYS_INLINE int FELighting::LightingData::rightPixelValue() +{ + return static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); +} + +ALWAYS_INLINE int FELighting::LightingData::downLeftPixelValue() +{ + return static_cast<int>(pixels->get(offset + widthMultipliedByPixelSize - cPixelSize + cAlphaChannelOffset)); +} + +ALWAYS_INLINE int FELighting::LightingData::downPixelValue() +{ + return static_cast<int>(pixels->get(offset + widthMultipliedByPixelSize + cAlphaChannelOffset)); +} + +ALWAYS_INLINE int FELighting::LightingData::downRightPixelValue() +{ + return static_cast<int>(pixels->get(offset + widthMultipliedByPixelSize + cPixelSize + cAlphaChannelOffset)); +} + +ALWAYS_INLINE void FELighting::setPixel(LightingData& data, LightSource::PaintingData& paintingData, + int lightX, int lightY, float factorX, int normalX, float factorY, int normalY) +{ + m_lightSource->updatePaintingData(paintingData, lightX, lightY, static_cast<float>(data.pixels->get(data.offset + 3)) * data.surfaceScale); + + data.normalVector.setX(factorX * static_cast<float>(normalX) * data.surfaceScale); + data.normalVector.setY(factorY * static_cast<float>(normalY) * data.surfaceScale); + data.normalVector.setZ(1.0f); + data.normalVector.normalize(); + + if (m_lightingType == FELighting::DiffuseLighting) + data.lightStrength = m_diffuseConstant * (data.normalVector * paintingData.lightVector); + else { + FloatPoint3D halfwayVector = paintingData.lightVector; + halfwayVector.setZ(halfwayVector.z() + 1.0f); + halfwayVector.normalize(); + if (m_specularExponent == 1.0f) + data.lightStrength = m_specularConstant * (data.normalVector * halfwayVector); + else + data.lightStrength = m_specularConstant * powf(data.normalVector * halfwayVector, m_specularExponent); + } + + if (data.lightStrength > 1.0f) + data.lightStrength = 1.0f; + if (data.lightStrength < 0.0f) + data.lightStrength = 0.0f; + + data.pixels->set(data.offset, static_cast<unsigned char>(data.lightStrength * paintingData.colorVector.x())); + data.pixels->set(data.offset + 1, static_cast<unsigned char>(data.lightStrength * paintingData.colorVector.y())); + data.pixels->set(data.offset + 2, static_cast<unsigned char>(data.lightStrength * paintingData.colorVector.z())); +} + +bool FELighting::drawLighting(CanvasPixelArray* pixels, int width, int height) +{ + LightSource::PaintingData paintingData; + LightingData data; + + if (!m_lightSource) + return false; + + // FIXME: do something if width or height (or both) is 1 pixel. + // The W3 spec does not define this case. Now the filter just returns. + if (width <= 2 || height <= 2) + return false; + + data.pixels = pixels; + data.surfaceScale = m_surfaceScale / 255.0f; + data.widthMultipliedByPixelSize = width * cPixelSize; + data.widthDecreasedByOne = width - 1; + data.heightDecreasedByOne = height - 1; + paintingData.colorVector = FloatPoint3D(m_lightingColor.red(), m_lightingColor.green(), m_lightingColor.blue()); + m_lightSource->initPaintingData(paintingData); + + // Top/Left corner + data.offset = 0; + setPixel(data, paintingData, 0, 0, + -2.0f / 3.0f, -2 * data.centerPixelValue() + 2 * data.rightPixelValue() - data.downPixelValue() + data.downRightPixelValue(), + -2.0f / 3.0f, -2 * data.centerPixelValue() - data.rightPixelValue() + 2 * data.downPixelValue() + data.downRightPixelValue()); + + // Top/Right pixel + data.offset = data.widthMultipliedByPixelSize - cPixelSize; + setPixel(data, paintingData, data.widthDecreasedByOne, 0, + -2.0f / 3.0f, -2 * data.leftPixelValue() + 2 * data.centerPixelValue() - data.downLeftPixelValue() + data.downPixelValue(), + -2.0f / 3.0f, -data.leftPixelValue() - 2 * data.centerPixelValue() + data.downLeftPixelValue() + 2 * data.downPixelValue()); + + // Bottom/Left pixel + data.offset = data.heightDecreasedByOne * data.widthMultipliedByPixelSize; + setPixel(data, paintingData, 0, data.heightDecreasedByOne, + -2.0f / 3.0f, -data.upPixelValue() + data.upRightPixelValue() - 2 * data.centerPixelValue() + 2 * data.rightPixelValue(), + -2.0f / 3.0f, -2 * data.upPixelValue() - data.upRightPixelValue() + 2 * data.centerPixelValue() + data.rightPixelValue()); + + // Bottom/Right pixel + data.offset = height * data.widthMultipliedByPixelSize - cPixelSize; + setPixel(data, paintingData, data.widthDecreasedByOne, data.heightDecreasedByOne, + -2.0f / 3.0f, -data.upLeftPixelValue() + data.upPixelValue() - 2 * data.leftPixelValue() + 2 * data.centerPixelValue(), + -2.0f / 3.0f, -data.upLeftPixelValue() - 2 * data.upPixelValue() + data.leftPixelValue() + 2 * data.centerPixelValue()); + + if (width >= 3) { + // Top line + data.offset = cPixelSize; + for (int x = 1; x < data.widthDecreasedByOne; ++x, data.offset += cPixelSize) { + setPixel(data, paintingData, x, 0, + -1.0f / 3.0f, -2 * data.leftPixelValue() + 2 * data.rightPixelValue() - data.downLeftPixelValue() + data.downRightPixelValue(), + -1.0f / 2.0f, -data.leftPixelValue() - 2 * data.centerPixelValue() - data.rightPixelValue() + data.downLeftPixelValue() + 2 * data.downPixelValue() + data.downRightPixelValue()); + } + // Bottom line + data.offset = data.heightDecreasedByOne * data.widthMultipliedByPixelSize + cPixelSize; + for (int x = 1; x < data.widthDecreasedByOne; ++x, data.offset += cPixelSize) { + setPixel(data, paintingData, x, data.heightDecreasedByOne, + -1.0f / 3.0f, -data.upLeftPixelValue() + data.upRightPixelValue() - 2 * data.leftPixelValue() + 2 * data.rightPixelValue(), + -1.0f / 2.0f, -data.upLeftPixelValue() - 2 * data.upPixelValue() - data.upRightPixelValue() + data.leftPixelValue() + 2 * data.centerPixelValue() + data.rightPixelValue()); + } + } + + if (height >= 3) { + // Left line + data.offset = data.widthMultipliedByPixelSize; + for (int y = 1; y < data.heightDecreasedByOne; ++y, data.offset += data.widthMultipliedByPixelSize) { + setPixel(data, paintingData, 0, y, + -1.0f / 2.0f, -data.upPixelValue() + data.upRightPixelValue() - 2 * data.centerPixelValue() + 2 * data.rightPixelValue() - data.downPixelValue() + data.downRightPixelValue(), + -1.0f / 3.0f, -2 * data.upPixelValue() - data.upRightPixelValue() + 2 * data.downPixelValue() + data.downRightPixelValue()); + } + // Right line + data.offset = data.widthMultipliedByPixelSize + data.widthMultipliedByPixelSize - cPixelSize; + for (int y = 1; y < data.heightDecreasedByOne; ++y, data.offset += data.widthMultipliedByPixelSize) { + setPixel(data, paintingData, data.widthDecreasedByOne, y, + -1.0f / 2.0f, -data.upLeftPixelValue() + data.upPixelValue() -2 * data.leftPixelValue() + 2 * data.centerPixelValue() - data.downLeftPixelValue() + data.downPixelValue(), + -1.0f / 3.0f, -data.upLeftPixelValue() - 2 * data.upPixelValue() + data.downLeftPixelValue() + 2 * data.downPixelValue()); + } + } + + if (width >= 3 && height >= 3) { + // Interior pixels + for (int y = 1; y < data.heightDecreasedByOne; ++y) { + data.offset = y * data.widthMultipliedByPixelSize + cPixelSize; + for (int x = 1; x < data.widthDecreasedByOne; ++x, data.offset += cPixelSize) { + setPixel(data, paintingData, x, y, + -1.0f / 4.0f, -data.upLeftPixelValue() + data.upRightPixelValue() - 2 * data.leftPixelValue() + 2 * data.rightPixelValue() - data.downLeftPixelValue() + data.downRightPixelValue(), + -1.0f / 4.0f, -data.upLeftPixelValue() - 2 * data.upPixelValue() - data.upRightPixelValue() + data.downLeftPixelValue() + 2 * data.downPixelValue() + data.downRightPixelValue()); + } + } + } + + int totalSize = data.widthMultipliedByPixelSize * height; + if (m_lightingType == DiffuseLighting) { + for (int i = 3; i < totalSize; i += 4) + data.pixels->set(i, cOpaqueAlpha); + } else { + for (int i = 0; i < totalSize; i += 4) { + unsigned char a1 = data.pixels->get(i); + unsigned char a2 = data.pixels->get(i + 1); + unsigned char a3 = data.pixels->get(i + 2); + // alpha set to set to max(a1, a2, a3) + data.pixels->set(i + 3, a1 >= a2 ? (a1 >= a3 ? a1 : a3) : (a2 >= a3 ? a2 : a3)); + } + } + + return true; +} + +void FELighting::apply(Filter* filter) +{ + FilterEffect* in = inputEffect(0); + in->apply(filter); + if (!in->resultImage()) + return; + + if (!effectContext()) + return; + + setIsAlphaImage(false); + + IntRect effectDrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates()); + RefPtr<ImageData> srcImageData(in->resultImage()->getUnmultipliedImageData(effectDrawingRect)); + CanvasPixelArray* srcPixelArray(srcImageData->data()); + + // FIXME: support kernelUnitLengths other than (1,1). The issue here is that the W3 + // standard has no test case for them, and other browsers (like Firefox) has strange + // output for various kernelUnitLengths, and I am not sure they are reliable. + // Anyway, feConvolveMatrix should also use the implementation + + if (drawLighting(srcPixelArray, effectDrawingRect.width(), effectDrawingRect.height())) + resultImage()->putUnmultipliedImageData(srcImageData.get(), IntRect(IntPoint(), resultImage()->size()), IntPoint()); +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FELighting.h b/WebCore/platform/graphics/filters/FELighting.h new file mode 100644 index 0000000..28c00c4 --- /dev/null +++ b/WebCore/platform/graphics/filters/FELighting.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2010 University of Szeged + * Copyright (C) 2010 Zoltan Herczeg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FELighting_h +#define FELighting_h + +#if ENABLE(FILTERS) +#include "Color.h" +#include "Filter.h" +#include "FilterEffect.h" +#include "LightSource.h" +#include <wtf/AlwaysInline.h> + +// Common base class for FEDiffuseLighting and FESpecularLighting + +namespace WebCore { + +class CanvasPixelArray; + +class FELighting : public FilterEffect { +public: + virtual void apply(Filter*); + +protected: + enum LightingType { + DiffuseLighting, + SpecularLighting + }; + + struct LightingData { + FloatPoint3D normalVector; + CanvasPixelArray* pixels; + float lightStrength; + float surfaceScale; + int offset; + int widthMultipliedByPixelSize; + int widthDecreasedByOne; + int heightDecreasedByOne; + + ALWAYS_INLINE int upLeftPixelValue(); + ALWAYS_INLINE int upPixelValue(); + ALWAYS_INLINE int upRightPixelValue(); + ALWAYS_INLINE int leftPixelValue(); + ALWAYS_INLINE int centerPixelValue(); + ALWAYS_INLINE int rightPixelValue(); + ALWAYS_INLINE int downLeftPixelValue(); + ALWAYS_INLINE int downPixelValue(); + ALWAYS_INLINE int downRightPixelValue(); + }; + + FELighting(LightingType, const Color&, float, float, float, float, float, float, PassRefPtr<LightSource>); + + bool drawLighting(CanvasPixelArray*, int, int); + ALWAYS_INLINE void setPixel(LightingData&, LightSource::PaintingData&, + int lightX, int lightY, float factorX, int normalX, float factorY, int normalY); + + LightingType m_lightingType; + RefPtr<LightSource> m_lightSource; + + Color m_lightingColor; + float m_surfaceScale; + float m_diffuseConstant; + float m_specularConstant; + float m_specularExponent; + float m_kernelUnitLengthX; + float m_kernelUnitLengthY; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FELighting_h diff --git a/WebCore/platform/graphics/filters/FEMerge.cpp b/WebCore/platform/graphics/filters/FEMerge.cpp new file mode 100644 index 0000000..19c832a --- /dev/null +++ b/WebCore/platform/graphics/filters/FEMerge.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEMerge.h" + +#include "Filter.h" +#include "GraphicsContext.h" + +namespace WebCore { + +FEMerge::FEMerge() + : FilterEffect() +{ +} + +PassRefPtr<FEMerge> FEMerge::create() +{ + return adoptRef(new FEMerge); +} + +void FEMerge::apply(Filter* filter) +{ + unsigned size = numberOfEffectInputs(); + ASSERT(size > 0); + for (unsigned i = 0; i < size; ++i) { + FilterEffect* in = inputEffect(i); + in->apply(filter); + if (!in->resultImage()) + return; + } + + GraphicsContext* filterContext = effectContext(); + if (!filterContext) + return; + + for (unsigned i = 0; i < size; ++i) { + FilterEffect* in = inputEffect(i); + filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates())); + } +} + +void FEMerge::dump() +{ +} + +TextStream& FEMerge::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feMerge"; + FilterEffect::externalRepresentation(ts); + unsigned size = numberOfEffectInputs(); + ASSERT(size > 0); + ts << " mergeNodes=\"" << size << "\"]\n"; + for (unsigned i = 0; i < size; ++i) + inputEffect(i)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEMerge.h b/WebCore/platform/graphics/filters/FEMerge.h new file mode 100644 index 0000000..46b882f --- /dev/null +++ b/WebCore/platform/graphics/filters/FEMerge.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEMerge_h +#define EMerge_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "Filter.h" +#include <wtf/Vector.h> + +namespace WebCore { + +class FEMerge : public FilterEffect { +public: + static PassRefPtr<FEMerge> create(); + + virtual void apply(Filter*); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEMerge(); +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEMerge_h diff --git a/WebCore/platform/graphics/filters/FEMorphology.cpp b/WebCore/platform/graphics/filters/FEMorphology.cpp new file mode 100644 index 0000000..7329e1e --- /dev/null +++ b/WebCore/platform/graphics/filters/FEMorphology.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEMorphology.h" + +#include "CanvasPixelArray.h" +#include "Filter.h" +#include "ImageData.h" + +#include <wtf/Vector.h> + +using std::min; +using std::max; + +namespace WebCore { + +FEMorphology::FEMorphology(MorphologyOperatorType type, float radiusX, float radiusY) + : FilterEffect() + , m_type(type) + , m_radiusX(radiusX) + , m_radiusY(radiusY) +{ +} + +PassRefPtr<FEMorphology> FEMorphology::create(MorphologyOperatorType type, float radiusX, float radiusY) +{ + return adoptRef(new FEMorphology(type, radiusX, radiusY)); +} + +MorphologyOperatorType FEMorphology::morphologyOperator() const +{ + return m_type; +} + +void FEMorphology::setMorphologyOperator(MorphologyOperatorType type) +{ + m_type = type; +} + +float FEMorphology::radiusX() const +{ + return m_radiusX; +} + +void FEMorphology::setRadiusX(float radiusX) +{ + m_radiusX = radiusX; +} + +float FEMorphology::radiusY() const +{ + return m_radiusY; +} + +void FEMorphology::setRadiusY(float radiusY) +{ + m_radiusY = radiusY; +} + +void FEMorphology::apply(Filter* filter) +{ + FilterEffect* in = inputEffect(0); + in->apply(filter); + if (!in->resultImage()) + return; + + if (!effectContext()) + return; + + setIsAlphaImage(in->isAlphaImage()); + + int radiusX = static_cast<int>(m_radiusX * filter->filterResolution().width()); + int radiusY = static_cast<int>(m_radiusY * filter->filterResolution().height()); + if (radiusX <= 0 || radiusY <= 0) + return; + + IntRect imageRect(IntPoint(), resultImage()->size()); + IntRect effectDrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates()); + RefPtr<CanvasPixelArray> srcPixelArray(in->resultImage()->getPremultipliedImageData(effectDrawingRect)->data()); + RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); + + int effectWidth = effectDrawingRect.width() * 4; + + // Limit the radius size to effect dimensions + radiusX = min(effectDrawingRect.width() - 1, radiusX); + radiusY = min(effectDrawingRect.height() - 1, radiusY); + + Vector<unsigned char> extrema; + for (int y = 0; y < effectDrawingRect.height(); ++y) { + int startY = max(0, y - radiusY); + int endY = min(effectDrawingRect.height() - 1, y + radiusY); + for (unsigned channel = 0; channel < 4; ++channel) { + // Fill the kernel + extrema.clear(); + for (int j = 0; j <= radiusX; ++j) { + unsigned char columnExtrema = srcPixelArray->get(startY * effectWidth + 4 * j + channel); + for (int i = startY; i <= endY; ++i) { + unsigned char pixel = srcPixelArray->get(i * effectWidth + 4 * j + channel); + if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) || + (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema)) + columnExtrema = pixel; + } + extrema.append(columnExtrema); + } + + // Kernel is filled, get extrema of next column + for (int x = 0; x < effectDrawingRect.width(); ++x) { + unsigned endX = min(x + radiusX, effectDrawingRect.width() - 1); + unsigned char columnExtrema = srcPixelArray->get(startY * effectWidth + endX * 4 + channel); + for (int i = startY; i <= endY; ++i) { + unsigned char pixel = srcPixelArray->get(i * effectWidth + endX * 4 + channel); + if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) || + (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema)) + columnExtrema = pixel; + } + if (x - radiusX >= 0) + extrema.remove(0); + if (x + radiusX <= effectDrawingRect.width()) + extrema.append(columnExtrema); + unsigned char entireExtrema = extrema[0]; + for (unsigned kernelIndex = 0; kernelIndex < extrema.size(); ++kernelIndex) { + if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && extrema[kernelIndex] <= entireExtrema) || + (m_type == FEMORPHOLOGY_OPERATOR_DILATE && extrema[kernelIndex] >= entireExtrema)) + entireExtrema = extrema[kernelIndex]; + } + imageData->data()->set(y * effectWidth + 4 * x + channel, entireExtrema); + } + } + } + resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint()); +} + +void FEMorphology::dump() +{ +} + +static TextStream& operator<<(TextStream& ts, const MorphologyOperatorType& type) +{ + switch (type) { + case FEMORPHOLOGY_OPERATOR_UNKNOWN: + ts << "UNKNOWN"; + break; + case FEMORPHOLOGY_OPERATOR_ERODE: + ts << "ERODE"; + break; + case FEMORPHOLOGY_OPERATOR_DILATE: + ts << "DILATE"; + break; + } + return ts; +} + +TextStream& FEMorphology::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feMorphology"; + FilterEffect::externalRepresentation(ts); + ts << " operator=\"" << morphologyOperator() << "\" " + << "radius=\"" << radiusX() << ", " << radiusY() << "\"]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEMorphology.h b/WebCore/platform/graphics/filters/FEMorphology.h new file mode 100644 index 0000000..c8ce058 --- /dev/null +++ b/WebCore/platform/graphics/filters/FEMorphology.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEMorphology_h +#define FEMorphology_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "Filter.h" + +namespace WebCore { + +enum MorphologyOperatorType { + FEMORPHOLOGY_OPERATOR_UNKNOWN = 0, + FEMORPHOLOGY_OPERATOR_ERODE = 1, + FEMORPHOLOGY_OPERATOR_DILATE = 2 +}; + +class FEMorphology : public FilterEffect { +public: + static PassRefPtr<FEMorphology> create(MorphologyOperatorType, float radiusX, float radiusY); + MorphologyOperatorType morphologyOperator() const; + void setMorphologyOperator(MorphologyOperatorType); + + float radiusX() const; + void setRadiusX(float); + + float radiusY() const; + void setRadiusY(float); + + virtual void apply(Filter*); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEMorphology(MorphologyOperatorType, float radiusX, float radiusY); + + MorphologyOperatorType m_type; + float m_radiusX; + float m_radiusY; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEMorphology_h diff --git a/WebCore/platform/graphics/filters/FEOffset.cpp b/WebCore/platform/graphics/filters/FEOffset.cpp new file mode 100644 index 0000000..ea84cf0 --- /dev/null +++ b/WebCore/platform/graphics/filters/FEOffset.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEOffset.h" + +#include "Filter.h" +#include "GraphicsContext.h" + +namespace WebCore { + +FEOffset::FEOffset(float dx, float dy) + : FilterEffect() + , m_dx(dx) + , m_dy(dy) +{ +} + +PassRefPtr<FEOffset> FEOffset::create(float dx, float dy) +{ + return adoptRef(new FEOffset(dx, dy)); +} + +float FEOffset::dx() const +{ + return m_dx; +} + +void FEOffset::setDx(float dx) +{ + m_dx = dx; +} + +float FEOffset::dy() const +{ + return m_dy; +} + +void FEOffset::setDy(float dy) +{ + m_dy = dy; +} + +void FEOffset::apply(Filter* filter) +{ + FilterEffect* in = inputEffect(0); + in->apply(filter); + if (!in->resultImage()) + return; + + GraphicsContext* filterContext = effectContext(); + if (!filterContext) + return; + + setIsAlphaImage(in->isAlphaImage()); + + FloatRect sourceImageRect = filter->sourceImageRect(); + sourceImageRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); + + if (filter->effectBoundingBoxMode()) { + m_dx *= sourceImageRect.width(); + m_dy *= sourceImageRect.height(); + } + m_dx *= filter->filterResolution().width(); + m_dy *= filter->filterResolution().height(); + + FloatRect dstRect = FloatRect(m_dx + in->repaintRectInLocalCoordinates().x() - repaintRectInLocalCoordinates().x(), + m_dy + in->repaintRectInLocalCoordinates().y() - repaintRectInLocalCoordinates().y(), + in->repaintRectInLocalCoordinates().width(), + in->repaintRectInLocalCoordinates().height()); + + filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, dstRect); +} + +void FEOffset::dump() +{ +} + +TextStream& FEOffset::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feOffset"; + FilterEffect::externalRepresentation(ts); + ts << " dx=\"" << dx() << "\" dy=\"" << dy() << "\"]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEOffset.h b/WebCore/platform/graphics/filters/FEOffset.h new file mode 100644 index 0000000..052ba74 --- /dev/null +++ b/WebCore/platform/graphics/filters/FEOffset.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEOffset_h +#define FEOffset_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "Filter.h" + +namespace WebCore { + +class FEOffset : public FilterEffect { +public: + static PassRefPtr<FEOffset> create(float dx, float dy); + + float dx() const; + void setDx(float); + + float dy() const; + void setDy(float); + + virtual void apply(Filter*); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEOffset(float dx, float dy); + + float m_dx; + float m_dy; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEOffset_h diff --git a/WebCore/platform/graphics/filters/FESpecularLighting.cpp b/WebCore/platform/graphics/filters/FESpecularLighting.cpp new file mode 100644 index 0000000..2606600 --- /dev/null +++ b/WebCore/platform/graphics/filters/FESpecularLighting.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FESpecularLighting.h" + +#include "LightSource.h" + +namespace WebCore { + +FESpecularLighting::FESpecularLighting(const Color& lightingColor, float surfaceScale, + float specularConstant, float specularExponent, float kernelUnitLengthX, + float kernelUnitLengthY, PassRefPtr<LightSource> lightSource) + : FELighting(SpecularLighting, lightingColor, surfaceScale, 0, specularConstant, specularExponent, kernelUnitLengthX, kernelUnitLengthY, lightSource) +{ +} + +PassRefPtr<FESpecularLighting> FESpecularLighting::create(const Color& lightingColor, + float surfaceScale, float specularConstant, float specularExponent, + float kernelUnitLengthX, float kernelUnitLengthY, PassRefPtr<LightSource> lightSource) +{ + return adoptRef(new FESpecularLighting(lightingColor, surfaceScale, specularConstant, specularExponent, + kernelUnitLengthX, kernelUnitLengthY, lightSource)); +} + +FESpecularLighting::~FESpecularLighting() +{ +} + +Color FESpecularLighting::lightingColor() const +{ + return m_lightingColor; +} + +void FESpecularLighting::setLightingColor(const Color& lightingColor) +{ + m_lightingColor = lightingColor; +} + +float FESpecularLighting::surfaceScale() const +{ + return m_surfaceScale; +} + +void FESpecularLighting::setSurfaceScale(float surfaceScale) +{ + m_surfaceScale = surfaceScale; +} + +float FESpecularLighting::specularConstant() const +{ + return m_specularConstant; +} + +void FESpecularLighting::setSpecularConstant(float specularConstant) +{ + m_specularConstant = specularConstant; +} + +float FESpecularLighting::specularExponent() const +{ + return m_specularExponent; +} + +void FESpecularLighting::setSpecularExponent(float specularExponent) +{ + m_specularExponent = specularExponent; +} + +float FESpecularLighting::kernelUnitLengthX() const +{ + return m_kernelUnitLengthX; +} + +void FESpecularLighting::setKernelUnitLengthX(float kernelUnitLengthX) +{ + m_kernelUnitLengthX = kernelUnitLengthX; +} + +float FESpecularLighting::kernelUnitLengthY() const +{ + return m_kernelUnitLengthY; +} + +void FESpecularLighting::setKernelUnitLengthY(float kernelUnitLengthY) +{ + m_kernelUnitLengthY = kernelUnitLengthY; +} + +const LightSource* FESpecularLighting::lightSource() const +{ + return m_lightSource.get(); +} + +void FESpecularLighting::setLightSource(PassRefPtr<LightSource> lightSource) +{ + m_lightSource = lightSource; +} + +void FESpecularLighting::dump() +{ +} + +TextStream& FESpecularLighting::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feSpecularLighting"; + FilterEffect::externalRepresentation(ts); + ts << " surfaceScale=\"" << m_surfaceScale << "\" " + << "specualConstant=\"" << m_specularConstant << "\" " + << "specularExponent=\"" << m_specularExponent << "\"]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FESpecularLighting.h b/WebCore/platform/graphics/filters/FESpecularLighting.h new file mode 100644 index 0000000..f6e7b66 --- /dev/null +++ b/WebCore/platform/graphics/filters/FESpecularLighting.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FESpecularLighting_h +#define FESpecularLighting_h + +#if ENABLE(FILTERS) +#include "FELighting.h" + +namespace WebCore { + +class FESpecularLighting : public FELighting { +public: + static PassRefPtr<FESpecularLighting> create(const Color&, float, float, + float, float, float, PassRefPtr<LightSource>); + virtual ~FESpecularLighting(); + + Color lightingColor() const; + void setLightingColor(const Color&); + + float surfaceScale() const; + void setSurfaceScale(float); + + float specularConstant() const; + void setSpecularConstant(float); + + float specularExponent() const; + void setSpecularExponent(float); + + float kernelUnitLengthX() const; + void setKernelUnitLengthX(float); + + float kernelUnitLengthY() const; + void setKernelUnitLengthY(float); + + const LightSource* lightSource() const; + void setLightSource(PassRefPtr<LightSource>); + + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FESpecularLighting(const Color&, float, float, float, float, float, PassRefPtr<LightSource>); +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FESpecularLighting_h diff --git a/WebCore/platform/graphics/filters/FETile.cpp b/WebCore/platform/graphics/filters/FETile.cpp new file mode 100644 index 0000000..41abd34 --- /dev/null +++ b/WebCore/platform/graphics/filters/FETile.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FETile.h" + +#include "AffineTransform.h" +#include "Filter.h" +#include "GraphicsContext.h" +#include "Pattern.h" + +namespace WebCore { + +FETile::FETile() + : FilterEffect() +{ +} + +PassRefPtr<FETile> FETile::create() +{ + return adoptRef(new FETile); +} + +FloatRect FETile::determineFilterPrimitiveSubregion(Filter* filter) +{ + inputEffect(0)->determineFilterPrimitiveSubregion(filter); + + filter->determineFilterPrimitiveSubregion(this, filter->filterRegion()); + return filterPrimitiveSubregion(); +} + +void FETile::apply(Filter* filter) +{ + FilterEffect* in = inputEffect(0); + in->apply(filter); + if (!in->resultImage()) + return; + + GraphicsContext* filterContext = effectContext(); + if (!filterContext) + return; + + setIsAlphaImage(in->isAlphaImage()); + + IntRect tileRect = enclosingIntRect(in->repaintRectInLocalCoordinates()); + + // Source input needs more attention. It has the size of the filterRegion but gives the + // size of the cutted sourceImage back. This is part of the specification and optimization. + if (in->isSourceInput()) { + FloatRect filterRegion = filter->filterRegion(); + filterRegion.scale(filter->filterResolution().width(), filter->filterResolution().height()); + tileRect = enclosingIntRect(filterRegion); + } + + OwnPtr<ImageBuffer> tileImage = ImageBuffer::create(tileRect.size()); + GraphicsContext* tileImageContext = tileImage->context(); + tileImageContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, IntPoint()); + RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(), true, true); + + AffineTransform matrix; + matrix.translate(in->repaintRectInLocalCoordinates().x() - repaintRectInLocalCoordinates().x(), + in->repaintRectInLocalCoordinates().y() - repaintRectInLocalCoordinates().y()); + pattern.get()->setPatternSpaceTransform(matrix); + + filterContext->setFillPattern(pattern); + filterContext->fillRect(FloatRect(FloatPoint(), repaintRectInLocalCoordinates().size())); +} + +void FETile::dump() +{ +} + +TextStream& FETile::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feTile"; + FilterEffect::externalRepresentation(ts); + ts << "]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + diff --git a/WebCore/platform/graphics/filters/FETile.h b/WebCore/platform/graphics/filters/FETile.h new file mode 100644 index 0000000..20efbcd --- /dev/null +++ b/WebCore/platform/graphics/filters/FETile.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FETile_h +#define FETile_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "Filter.h" + +namespace WebCore { + +class FETile : public FilterEffect { +public: + static PassRefPtr<FETile> create(); + + virtual void apply(Filter*); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + + virtual FloatRect determineFilterPrimitiveSubregion(Filter*); + +private: + FETile(); +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FETile_h diff --git a/WebCore/platform/graphics/filters/FETurbulence.cpp b/WebCore/platform/graphics/filters/FETurbulence.cpp new file mode 100644 index 0000000..bb24362 --- /dev/null +++ b/WebCore/platform/graphics/filters/FETurbulence.cpp @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2010 Renata Hodovan <reni@inf.u-szeged.hu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FETurbulence.h" + +#include "CanvasPixelArray.h" +#include "Filter.h" +#include "ImageData.h" + +#include <wtf/MathExtras.h> + +namespace WebCore { + +/* + Produces results in the range [1, 2**31 - 2]. Algorithm is: + r = (a * r) mod m where a = randAmplitude = 16807 and + m = randMaximum = 2**31 - 1 = 2147483647, r = seed. + See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988 + To test: the algorithm should produce the result 1043618065 + as the 10,000th generated number if the original seed is 1. +*/ +static const int s_perlinNoise = 4096; +static const long s_randMaximum = 2147483647; // 2**31 - 1 +static const int s_randAmplitude = 16807; // 7**5; primitive root of m +static const int s_randQ = 127773; // m / a +static const int s_randR = 2836; // m % a + +FETurbulence::FETurbulence(TurbulanceType type, float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, bool stitchTiles) + : FilterEffect() + , m_type(type) + , m_baseFrequencyX(baseFrequencyX) + , m_baseFrequencyY(baseFrequencyY) + , m_numOctaves(numOctaves) + , m_seed(seed) + , m_stitchTiles(stitchTiles) +{ +} + +PassRefPtr<FETurbulence> FETurbulence::create(TurbulanceType type, float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, bool stitchTiles) +{ + return adoptRef(new FETurbulence(type, baseFrequencyX, baseFrequencyY, numOctaves, seed, stitchTiles)); +} + +TurbulanceType FETurbulence::type() const +{ + return m_type; +} + +void FETurbulence::setType(TurbulanceType type) +{ + m_type = type; +} + +float FETurbulence::baseFrequencyY() const +{ + return m_baseFrequencyY; +} + +void FETurbulence::setBaseFrequencyY(float baseFrequencyY) +{ + m_baseFrequencyY = baseFrequencyY; +} + +float FETurbulence::baseFrequencyX() const +{ + return m_baseFrequencyX; +} + +void FETurbulence::setBaseFrequencyX(float baseFrequencyX) +{ + m_baseFrequencyX = baseFrequencyX; +} + +float FETurbulence::seed() const +{ + return m_seed; +} + +void FETurbulence::setSeed(float seed) +{ + m_seed = seed; +} + +int FETurbulence::numOctaves() const +{ + return m_numOctaves; +} + +void FETurbulence::setNumOctaves(bool numOctaves) +{ + m_numOctaves = numOctaves; +} + +bool FETurbulence::stitchTiles() const +{ + return m_stitchTiles; +} + +void FETurbulence::setStitchTiles(bool stitch) +{ + m_stitchTiles = stitch; +} + +// The turbulence calculation code is an adapted version of what appears in the SVG 1.1 specification: +// http://www.w3.org/TR/SVG11/filters.html#feTurbulence + +FETurbulence::PaintingData::PaintingData(long paintingSeed, const IntSize& paintingSize) + : seed(paintingSeed) + , width(0) + , height(0) + , wrapX(0) + , wrapY(0) + , channel(0) + , filterSize(paintingSize) +{ +} + +// Compute pseudo random number. +inline long FETurbulence::PaintingData::random() +{ + long result = s_randAmplitude * (seed % s_randQ) - s_randR * (seed / s_randQ); + if (result <= 0) + result += s_randMaximum; + seed = result; + return result; +} + +inline float smoothCurve(float t) +{ + return t * t * (3 - 2 * t); +} + +inline float linearInterpolation(float t, float a, float b) +{ + return a + t * (b - a); +} + +inline void FETurbulence::initPaint(PaintingData& paintingData) +{ + float normalizationFactor; + + // The seed value clamp to the range [1, s_randMaximum - 1]. + if (paintingData.seed <= 0) + paintingData.seed = -(paintingData.seed % (s_randMaximum - 1)) + 1; + if (paintingData.seed > s_randMaximum - 1) + paintingData.seed = s_randMaximum - 1; + + float* gradient; + for (int channel = 0; channel < 4; ++channel) { + for (int i = 0; i < s_blockSize; ++i) { + paintingData.latticeSelector[i] = i; + gradient = paintingData.gradient[channel][i]; + gradient[0] = static_cast<float>((paintingData.random() % (2 * s_blockSize)) - s_blockSize) / s_blockSize; + gradient[1] = static_cast<float>((paintingData.random() % (2 * s_blockSize)) - s_blockSize) / s_blockSize; + normalizationFactor = sqrtf(gradient[0] * gradient[0] + gradient[1] * gradient[1]); + gradient[0] /= normalizationFactor; + gradient[1] /= normalizationFactor; + } + } + for (int i = s_blockSize - 1; i > 0; --i) { + int k = paintingData.latticeSelector[i]; + int j = paintingData.random() % s_blockSize; + ASSERT(j >= 0); + ASSERT(j < 2 * s_blockSize + 2); + paintingData.latticeSelector[i] = paintingData.latticeSelector[j]; + paintingData.latticeSelector[j] = k; + } + for (int i = 0; i < s_blockSize + 2; ++i) { + paintingData.latticeSelector[s_blockSize + i] = paintingData.latticeSelector[i]; + for (int channel = 0; channel < 4; ++channel) { + paintingData.gradient[channel][s_blockSize + i][0] = paintingData.gradient[channel][i][0]; + paintingData.gradient[channel][s_blockSize + i][1] = paintingData.gradient[channel][i][1]; + } + } +} + +inline void checkNoise(int& noiseValue, int limitValue, int newValue) +{ + if (noiseValue >= limitValue) + noiseValue -= newValue; + if (noiseValue >= limitValue - 1) + noiseValue -= newValue - 1; +} + +float FETurbulence::noise2D(PaintingData& paintingData, const FloatPoint& noiseVector) +{ + struct Noise { + int noisePositionIntegerValue; + float noisePositionFractionValue; + + Noise(float component) + { + float position = component + s_perlinNoise; + noisePositionIntegerValue = static_cast<int>(position); + noisePositionFractionValue = position - noisePositionIntegerValue; + } + }; + + Noise noiseX(noiseVector.x()); + Noise noiseY(noiseVector.y()); + float* q; + float sx, sy, a, b, u, v; + + // If stitching, adjust lattice points accordingly. + if (m_stitchTiles) { + checkNoise(noiseX.noisePositionIntegerValue, paintingData.wrapX, paintingData.width); + checkNoise(noiseY.noisePositionIntegerValue, paintingData.wrapY, paintingData.height); + } + + noiseX.noisePositionIntegerValue &= s_blockMask; + noiseY.noisePositionIntegerValue &= s_blockMask; + int latticeIndex = paintingData.latticeSelector[noiseX.noisePositionIntegerValue]; + int nextLatticeIndex = paintingData.latticeSelector[(noiseX.noisePositionIntegerValue + 1) & s_blockMask]; + + sx = smoothCurve(noiseX.noisePositionFractionValue); + sy = smoothCurve(noiseY.noisePositionFractionValue); + + // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement. + int temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue]; + q = paintingData.gradient[paintingData.channel][temp]; + u = noiseX.noisePositionFractionValue * q[0] + noiseY.noisePositionFractionValue * q[1]; + temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue]; + q = paintingData.gradient[paintingData.channel][temp]; + v = (noiseX.noisePositionFractionValue - 1) * q[0] + noiseY.noisePositionFractionValue * q[1]; + a = linearInterpolation(sx, u, v); + temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue + 1]; + q = paintingData.gradient[paintingData.channel][temp]; + u = noiseX.noisePositionFractionValue * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1]; + temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue + 1]; + q = paintingData.gradient[paintingData.channel][temp]; + v = (noiseX.noisePositionFractionValue - 1) * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1]; + b = linearInterpolation(sx, u, v); + return linearInterpolation(sy, a, b); +} + +unsigned char FETurbulence::calculateTurbulenceValueForPoint(PaintingData& paintingData, const FloatPoint& point) +{ + float tileWidth = paintingData.filterSize.width(); + ASSERT(tileWidth > 0); + float tileHeight = paintingData.filterSize.height(); + ASSERT(tileHeight > 0); + // Adjust the base frequencies if necessary for stitching. + if (m_stitchTiles) { + // When stitching tiled turbulence, the frequencies must be adjusted + // so that the tile borders will be continuous. + if (m_baseFrequencyX) { + float lowFrequency = floorf(tileWidth * m_baseFrequencyX) / tileWidth; + float highFrequency = ceilf(tileWidth * m_baseFrequencyX) / tileWidth; + // BaseFrequency should be non-negative according to the standard. + if (m_baseFrequencyX / lowFrequency < highFrequency / m_baseFrequencyX) + m_baseFrequencyX = lowFrequency; + else + m_baseFrequencyX = highFrequency; + } + if (m_baseFrequencyY) { + float lowFrequency = floorf(tileHeight * m_baseFrequencyY) / tileHeight; + float highFrequency = ceilf(tileHeight * m_baseFrequencyY) / tileHeight; + if (m_baseFrequencyY / lowFrequency < highFrequency / m_baseFrequencyY) + m_baseFrequencyY = lowFrequency; + else + m_baseFrequencyY = highFrequency; + } + // Set up TurbulenceInitial stitch values. + paintingData.width = roundf(tileWidth * m_baseFrequencyX); + paintingData.wrapX = s_perlinNoise + paintingData.width; + paintingData.height = roundf(tileHeight * m_baseFrequencyY); + paintingData.wrapY = s_perlinNoise + paintingData.height; + } + float turbulenceFunctionResult = 0; + FloatPoint noiseVector(point.x() * m_baseFrequencyX, point.y() * m_baseFrequencyY); + float ratio = 1; + for (int octave = 0; octave < m_numOctaves; ++octave) { + if (m_type == FETURBULENCE_TYPE_FRACTALNOISE) + turbulenceFunctionResult += noise2D(paintingData, noiseVector) / ratio; + else + turbulenceFunctionResult += fabsf(noise2D(paintingData, noiseVector)) / ratio; + noiseVector.setX(noiseVector.x() * 2); + noiseVector.setY(noiseVector.y() * 2); + ratio *= 2; + if (m_stitchTiles) { + // Update stitch values. Subtracting s_perlinNoiseoise before the multiplication and + // adding it afterward simplifies to subtracting it once. + paintingData.width *= 2; + paintingData.wrapX = 2 * paintingData.wrapX - s_perlinNoise; + paintingData.height *= 2; + paintingData.wrapY = 2 * paintingData.wrapY - s_perlinNoise; + } + } + + // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult * 255) + 255) / 2 by fractalNoise + // and (turbulenceFunctionResult * 255) by turbulence. + if (m_type == FETURBULENCE_TYPE_FRACTALNOISE) + turbulenceFunctionResult = turbulenceFunctionResult * 0.5f + 0.5f; + // Clamp result + turbulenceFunctionResult = std::max(std::min(turbulenceFunctionResult, 1.f), 0.f); + return static_cast<unsigned char>(turbulenceFunctionResult * 255); +} + +void FETurbulence::apply(Filter* filter) +{ + if (!effectContext()) + return; + + IntRect imageRect(IntPoint(), resultImage()->size()); + if (!imageRect.size().width() || !imageRect.size().height()) + return; + + RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); + PaintingData paintingData(m_seed, imageRect.size()); + initPaint(paintingData); + + FloatRect filterRegion = filter->filterRegion(); + FloatPoint point; + point.setY(filterRegion.y()); + int indexOfPixelChannel = 0; + for (int y = 0; y < imageRect.height(); ++y) { + point.setY(point.y() + 1); + point.setX(filterRegion.x()); + for (int x = 0; x < imageRect.width(); ++x) { + point.setX(point.x() + 1); + for (paintingData.channel = 0; paintingData.channel < 4; ++paintingData.channel, ++indexOfPixelChannel) + imageData->data()->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(paintingData, point)); + } + } + resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint()); +} + +void FETurbulence::dump() +{ +} + +static TextStream& operator<<(TextStream& ts, const TurbulanceType& type) +{ + switch (type) { + case FETURBULENCE_TYPE_UNKNOWN: + ts << "UNKNOWN"; + break; + case FETURBULENCE_TYPE_TURBULENCE: + ts << "TURBULANCE"; + break; + case FETURBULENCE_TYPE_FRACTALNOISE: + ts << "NOISE"; + break; + } + return ts; +} + +TextStream& FETurbulence::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feTurbulence"; + FilterEffect::externalRepresentation(ts); + ts << " type=\"" << type() << "\" " + << "baseFrequency=\"" << baseFrequencyX() << ", " << baseFrequencyY() << "\" " + << "seed=\"" << seed() << "\" " + << "numOctaves=\"" << numOctaves() << "\" " + << "stitchTiles=\"" << stitchTiles() << "\"]\n"; + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FETurbulence.h b/WebCore/platform/graphics/filters/FETurbulence.h new file mode 100644 index 0000000..1a5a28a --- /dev/null +++ b/WebCore/platform/graphics/filters/FETurbulence.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2010 Renata Hodovan <reni@inf.u-szeged.hu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FETurbulence_h +#define FETurbulence_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "Filter.h" + +namespace WebCore { + +enum TurbulanceType { + FETURBULENCE_TYPE_UNKNOWN = 0, + FETURBULENCE_TYPE_FRACTALNOISE = 1, + FETURBULENCE_TYPE_TURBULENCE = 2 +}; + +class FETurbulence : public FilterEffect { +public: + static PassRefPtr<FETurbulence> create(TurbulanceType, float, float, int, float, bool); + + TurbulanceType type() const; + void setType(TurbulanceType); + + float baseFrequencyY() const; + void setBaseFrequencyY(float); + + float baseFrequencyX() const; + void setBaseFrequencyX(float); + + float seed() const; + void setSeed(float); + + int numOctaves() const; + void setNumOctaves(bool); + + bool stitchTiles() const; + void setStitchTiles(bool); + + virtual void apply(Filter*); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + static const int s_blockSize = 256; + static const int s_blockMask = s_blockSize - 1; + + struct PaintingData { + long seed; + int latticeSelector[2 * s_blockSize + 2]; + float gradient[4][2 * s_blockSize + 2][2]; + int width; // How much to subtract to wrap for stitching. + int height; + int wrapX; // Minimum value to wrap. + int wrapY; + int channel; + IntSize filterSize; + + PaintingData(long paintingSeed, const IntSize& paintingSize); + inline long random(); + }; + + FETurbulence(TurbulanceType, float, float, int, float, bool); + + inline void initPaint(PaintingData&); + float noise2D(PaintingData&, const FloatPoint&); + unsigned char calculateTurbulenceValueForPoint(PaintingData&, const FloatPoint&); + + TurbulanceType m_type; + float m_baseFrequencyX; + float m_baseFrequencyY; + int m_numOctaves; + float m_seed; + bool m_stitchTiles; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FETurbulence_h diff --git a/WebCore/platform/graphics/filters/Filter.h b/WebCore/platform/graphics/filters/Filter.h index 7ad25aa..bce4be3 100644 --- a/WebCore/platform/graphics/filters/Filter.h +++ b/WebCore/platform/graphics/filters/Filter.h @@ -1,20 +1,20 @@ /* - * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 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 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. + * 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. + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #ifndef Filter_h diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp index b6278b2..461b22a 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.cpp +++ b/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -56,7 +56,7 @@ FloatRect FilterEffect::determineFilterPrimitiveSubregion(Filter* filter) return m_filterPrimitiveSubregion; } -IntRect FilterEffect::calculateDrawingIntRect(const FloatRect& effectRect) const +IntRect FilterEffect::requestedRegionOfInputImageData(const FloatRect& effectRect) const { ASSERT(m_effectBuffer); FloatPoint location = m_repaintRectInLocalCoordinates.location(); @@ -64,7 +64,7 @@ IntRect FilterEffect::calculateDrawingIntRect(const FloatRect& effectRect) const return IntRect(roundedIntPoint(location), m_effectBuffer->size()); } -FloatRect FilterEffect::calculateDrawingRect(const FloatRect& srcRect) const +FloatRect FilterEffect::drawingRegionOfInputImage(const FloatRect& srcRect) const { return FloatRect(FloatPoint(srcRect.x() - m_repaintRectInLocalCoordinates.x(), srcRect.y() - m_repaintRectInLocalCoordinates.y()), srcRect.size()); @@ -76,7 +76,7 @@ FilterEffect* FilterEffect::inputEffect(unsigned number) const return m_inputEffects.at(number).get(); } -GraphicsContext* FilterEffect::getEffectContext() +GraphicsContext* FilterEffect::effectContext() { IntRect bufferRect = enclosingIntRect(m_repaintRectInLocalCoordinates); m_effectBuffer = ImageBuffer::create(bufferRect.size(), LinearRGB); diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h index 91c52f3..ebe1880 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.h +++ b/WebCore/platform/graphics/filters/FilterEffect.h @@ -49,14 +49,14 @@ public: // Creates the ImageBuffer for the current filter primitive result in the size of the // repaintRect. Gives back the GraphicsContext of the own ImageBuffer. - GraphicsContext* getEffectContext(); + GraphicsContext* effectContext(); FilterEffectVector& inputEffects() { return m_inputEffects; } FilterEffect* inputEffect(unsigned) const; unsigned numberOfEffectInputs() const { return m_inputEffects.size(); } - FloatRect calculateDrawingRect(const FloatRect&) const; - IntRect calculateDrawingIntRect(const FloatRect&) const; + FloatRect drawingRegionOfInputImage(const FloatRect&) const; + IntRect requestedRegionOfInputImageData(const FloatRect&) const; // Solid black image with different alpha values. bool isAlphaImage() const { return m_alphaImage; } diff --git a/WebCore/platform/graphics/filters/ImageBufferFilter.cpp b/WebCore/platform/graphics/filters/ImageBufferFilter.cpp index 33953d6..12407f8 100644 --- a/WebCore/platform/graphics/filters/ImageBufferFilter.cpp +++ b/WebCore/platform/graphics/filters/ImageBufferFilter.cpp @@ -1,21 +1,21 @@ /* - * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> - * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * 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. + * 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. + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include "config.h" diff --git a/WebCore/platform/graphics/filters/ImageBufferFilter.h b/WebCore/platform/graphics/filters/ImageBufferFilter.h index a2775ea..cd4bc2f 100644 --- a/WebCore/platform/graphics/filters/ImageBufferFilter.h +++ b/WebCore/platform/graphics/filters/ImageBufferFilter.h @@ -1,21 +1,21 @@ /* - * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> - * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * 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. + * 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. + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #ifndef ImageBufferFilter_h diff --git a/WebCore/platform/graphics/filters/LightSource.cpp b/WebCore/platform/graphics/filters/LightSource.cpp new file mode 100644 index 0000000..a80b14b --- /dev/null +++ b/WebCore/platform/graphics/filters/LightSource.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2010 Zoltan Herczeg <zherczeg@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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "LightSource.h" + +#include "DistantLightSource.h" +#include "PointLightSource.h" +#include "RenderTreeAsText.h" +#include "SpotLightSource.h" +#include <wtf/MathExtras.h> + +namespace WebCore { + +void PointLightSource::initPaintingData(PaintingData&) +{ +} + +void PointLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z) +{ + paintingData.lightVector.setX(m_position.x() - x); + paintingData.lightVector.setY(m_position.y() - y); + paintingData.lightVector.setZ(m_position.z() - z); + paintingData.lightVector.normalize(); +} + +// spot-light edge darkening depends on an absolute treshold +// according to the SVG 1.1 SE light regression tests +static const float antiAliasTreshold = 0.016f; + +void SpotLightSource::initPaintingData(PaintingData& paintingData) +{ + paintingData.privateColorVector = paintingData.colorVector; + paintingData.directionVector.setX(m_direction.x() - m_position.x()); + paintingData.directionVector.setY(m_direction.y() - m_position.y()); + paintingData.directionVector.setZ(m_direction.z() - m_position.z()); + paintingData.directionVector.normalize(); + + if (!m_limitingConeAngle) { + paintingData.coneCutOffLimit = 0.0f; + paintingData.coneFullLight = -antiAliasTreshold; + } else { + float limitingConeAngle = m_limitingConeAngle; + if (limitingConeAngle < 0.0f) + limitingConeAngle = -limitingConeAngle; + if (limitingConeAngle > 90.0f) + limitingConeAngle = 90.0f; + paintingData.coneCutOffLimit = cosf(deg2rad(180.0f - limitingConeAngle)); + paintingData.coneFullLight = paintingData.coneCutOffLimit - antiAliasTreshold; + } + + // Optimization for common specularExponent values + if (!m_specularExponent) + paintingData.specularExponent = 0; + else if (m_specularExponent == 1.0f) + paintingData.specularExponent = 1; + else // It is neither 0.0f nor 1.0f + paintingData.specularExponent = 2; +} + +void SpotLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z) +{ + paintingData.lightVector.setX(m_position.x() - x); + paintingData.lightVector.setY(m_position.y() - y); + paintingData.lightVector.setZ(m_position.z() - z); + paintingData.lightVector.normalize(); + + float cosineOfAngle = paintingData.lightVector * paintingData.directionVector; + if (cosineOfAngle > paintingData.coneCutOffLimit) { + // No light is produced, scanlines are not updated + paintingData.colorVector.setX(0.0f); + paintingData.colorVector.setY(0.0f); + paintingData.colorVector.setZ(0.0f); + return; + } + + // Set the color of the pixel + float lightStrength; + switch (paintingData.specularExponent) { + case 0: + lightStrength = 1.0f; // -cosineOfAngle ^ 0 == 1 + break; + case 1: + lightStrength = -cosineOfAngle; // -cosineOfAngle ^ 1 == -cosineOfAngle + break; + default: + lightStrength = powf(-cosineOfAngle, m_specularExponent); + break; + } + + if (cosineOfAngle > paintingData.coneFullLight) + lightStrength *= (paintingData.coneCutOffLimit - cosineOfAngle) / (paintingData.coneCutOffLimit - paintingData.coneFullLight); + + if (lightStrength > 1.0f) + lightStrength = 1.0f; + + paintingData.colorVector.setX(paintingData.privateColorVector.x() * lightStrength); + paintingData.colorVector.setY(paintingData.privateColorVector.y() * lightStrength); + paintingData.colorVector.setZ(paintingData.privateColorVector.z() * lightStrength); +} + +void DistantLightSource::initPaintingData(PaintingData& paintingData) +{ + float azimuth = deg2rad(m_azimuth); + float elevation = deg2rad(m_elevation); + paintingData.lightVector.setX(cosf(azimuth) * cosf(elevation)); + paintingData.lightVector.setY(sinf(azimuth) * cosf(elevation)); + paintingData.lightVector.setZ(sinf(elevation)); +} + +void DistantLightSource::updatePaintingData(PaintingData&, int, int, float) +{ +} + +static TextStream& operator<<(TextStream& ts, const FloatPoint3D& p) +{ + ts << "x=" << p.x() << " y=" << p.y() << " z=" << p.z(); + return ts; +} + +TextStream& PointLightSource::externalRepresentation(TextStream& ts) const +{ + ts << "[type=POINT-LIGHT] "; + ts << "[position=\"" << position() << "\"]"; + return ts; +} + +TextStream& SpotLightSource::externalRepresentation(TextStream& ts) const +{ + ts << "[type=SPOT-LIGHT] "; + ts << "[position=\"" << position() << "\"]"; + ts << "[direction=\"" << direction() << "\"]"; + ts << "[specularExponent=\"" << specularExponent() << "\"]"; + ts << "[limitingConeAngle=\"" << limitingConeAngle() << "\"]"; + return ts; +} + +TextStream& DistantLightSource::externalRepresentation(TextStream& ts) const +{ + ts << "[type=DISTANT-LIGHT] "; + ts << "[azimuth=\"" << azimuth() << "\"]"; + ts << "[elevation=\"" << elevation() << "\"]"; + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/LightSource.h b/WebCore/platform/graphics/filters/LightSource.h new file mode 100644 index 0000000..2e4c579 --- /dev/null +++ b/WebCore/platform/graphics/filters/LightSource.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2010 Zoltan Herczeg <zherczeg@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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef LightSource_h +#define LightSource_h + +#if ENABLE(FILTERS) +#include "FloatPoint3D.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +enum LightType { + LS_DISTANT, + LS_POINT, + LS_SPOT +}; + +class TextStream; + +class LightSource : public RefCounted<LightSource> { +public: + + // Light vectors must be calculated for every pixel during + // painting. It is expensive to pass all these arguments to + // a frequently called function, especially because not all + // light sources require all of them. Instead, we just pass + // a reference to the following structure + struct PaintingData { + // SVGFELighting also use them + FloatPoint3D lightVector; + FloatPoint3D colorVector; + // Private members + FloatPoint3D directionVector; + FloatPoint3D privateColorVector; + float coneCutOffLimit; + float coneFullLight; + int specularExponent; + }; + + LightSource(LightType type) + : m_type(type) + { } + + virtual ~LightSource() { } + + LightType type() const { return m_type; } + virtual TextStream& externalRepresentation(TextStream&) const = 0; + + virtual void initPaintingData(PaintingData&) = 0; + // z is a float number, since it is the alpha value scaled by a user + // specified "surfaceScale" constant, which type is <number> in the SVG standard + virtual void updatePaintingData(PaintingData&, int x, int y, float z) = 0; + +private: + LightType m_type; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // LightSource_h diff --git a/WebCore/platform/graphics/filters/PointLightSource.h b/WebCore/platform/graphics/filters/PointLightSource.h new file mode 100644 index 0000000..163c829 --- /dev/null +++ b/WebCore/platform/graphics/filters/PointLightSource.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef PointLightSource_h +#define PointLightSource_h + +#if ENABLE(FILTERS) +#include "LightSource.h" + +namespace WebCore { + +class PointLightSource : public LightSource { +public: + static PassRefPtr<PointLightSource> create(const FloatPoint3D& position) + { + return adoptRef(new PointLightSource(position)); + } + + const FloatPoint3D& position() const { return m_position; } + + virtual void initPaintingData(PaintingData&); + virtual void updatePaintingData(PaintingData&, int x, int y, float z); + + virtual TextStream& externalRepresentation(TextStream&) const; + +private: + PointLightSource(const FloatPoint3D& position) + : LightSource(LS_POINT) + , m_position(position) + { + } + + FloatPoint3D m_position; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // PointLightSource_h diff --git a/WebCore/platform/graphics/filters/SourceAlpha.cpp b/WebCore/platform/graphics/filters/SourceAlpha.cpp index 9c6a953..beaf2e7 100644 --- a/WebCore/platform/graphics/filters/SourceAlpha.cpp +++ b/WebCore/platform/graphics/filters/SourceAlpha.cpp @@ -1,20 +1,20 @@ /* - * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 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 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. + * 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. + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include "config.h" @@ -57,7 +57,7 @@ FloatRect SourceAlpha::determineFilterPrimitiveSubregion(Filter* filter) void SourceAlpha::apply(Filter* filter) { - GraphicsContext* filterContext = getEffectContext(); + GraphicsContext* filterContext = effectContext(); if (!filterContext) return; diff --git a/WebCore/platform/graphics/filters/SourceAlpha.h b/WebCore/platform/graphics/filters/SourceAlpha.h index 25a17b2..f0fa319 100644 --- a/WebCore/platform/graphics/filters/SourceAlpha.h +++ b/WebCore/platform/graphics/filters/SourceAlpha.h @@ -1,21 +1,21 @@ /* - Copyright (C) 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. -*/ + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ #ifndef SourceAlpha_h #define SourceAlpha_h @@ -28,22 +28,25 @@ namespace WebCore { - class SourceAlpha : public FilterEffect { - public: - static PassRefPtr<SourceAlpha> create(); +class SourceAlpha : public FilterEffect { +public: + static PassRefPtr<SourceAlpha> create(); + + static const AtomicString& effectName(); + + virtual FloatRect determineFilterPrimitiveSubregion(Filter*); + + virtual void apply(Filter*); + virtual void dump(); + + virtual bool isSourceInput() const { return true; } - static const AtomicString& effectName(); + virtual TextStream& externalRepresentation(TextStream&, int indention) const; - void apply(Filter*); - void dump(); - TextStream& externalRepresentation(TextStream&, int indent) const; +private: + SourceAlpha() { } +}; - virtual bool isSourceInput() const { return true; } - virtual FloatRect determineFilterPrimitiveSubregion(Filter*); - - private: - SourceAlpha() { } - }; } //namespace WebCore #endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/SourceGraphic.cpp b/WebCore/platform/graphics/filters/SourceGraphic.cpp index 6a32e36..c014e68 100644 --- a/WebCore/platform/graphics/filters/SourceGraphic.cpp +++ b/WebCore/platform/graphics/filters/SourceGraphic.cpp @@ -1,20 +1,20 @@ /* - * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 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 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. + * 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. + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include "config.h" @@ -56,7 +56,7 @@ FloatRect SourceGraphic::determineFilterPrimitiveSubregion(Filter* filter) void SourceGraphic::apply(Filter* filter) { - GraphicsContext* filterContext = getEffectContext(); + GraphicsContext* filterContext = effectContext(); if (!filterContext) return; diff --git a/WebCore/platform/graphics/filters/SourceGraphic.h b/WebCore/platform/graphics/filters/SourceGraphic.h index 911648c..2378798 100644 --- a/WebCore/platform/graphics/filters/SourceGraphic.h +++ b/WebCore/platform/graphics/filters/SourceGraphic.h @@ -1,22 +1,22 @@ /* - Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> - 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. -*/ + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ #ifndef SourceGraphic_h #define SourceGrahpic_h @@ -29,22 +29,25 @@ namespace WebCore { - class SourceGraphic : public FilterEffect { - public: - static PassRefPtr<SourceGraphic> create(); +class SourceGraphic : public FilterEffect { +public: + static PassRefPtr<SourceGraphic> create(); + + static const AtomicString& effectName(); + + virtual FloatRect determineFilterPrimitiveSubregion(Filter*); + + virtual void apply(Filter*); + virtual void dump(); - static const AtomicString& effectName(); + virtual bool isSourceInput() const { return true; } - void apply(Filter*); - void dump(); - TextStream& externalRepresentation(TextStream&, int indent) const; + virtual TextStream& externalRepresentation(TextStream&, int indention) const; - virtual bool isSourceInput() const { return true; } - virtual FloatRect determineFilterPrimitiveSubregion(Filter*); +private: + SourceGraphic() { } +}; - private: - SourceGraphic() { } - }; } //namespace WebCore #endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/SpotLightSource.h b/WebCore/platform/graphics/filters/SpotLightSource.h new file mode 100644 index 0000000..cd6a614 --- /dev/null +++ b/WebCore/platform/graphics/filters/SpotLightSource.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 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 + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef SpotLightSource_h +#define SpotLightSource_h + +#if ENABLE(FILTERS) +#include "LightSource.h" + +namespace WebCore { + +class SpotLightSource : public LightSource { +public: + static PassRefPtr<SpotLightSource> create(const FloatPoint3D& position, + const FloatPoint3D& direction, float specularExponent, float limitingConeAngle) + { + return adoptRef(new SpotLightSource(position, direction, specularExponent, limitingConeAngle)); + } + + const FloatPoint3D& position() const { return m_position; } + const FloatPoint3D& direction() const { return m_direction; } + + float specularExponent() const { return m_specularExponent; } + float limitingConeAngle() const { return m_limitingConeAngle; } + + virtual void initPaintingData(PaintingData&); + virtual void updatePaintingData(PaintingData&, int x, int y, float z); + + virtual TextStream& externalRepresentation(TextStream&) const; + +private: + SpotLightSource(const FloatPoint3D& position, const FloatPoint3D& direction, + float specularExponent, float limitingConeAngle) + : LightSource(LS_SPOT) + , m_position(position) + , m_direction(direction) + , m_specularExponent(specularExponent) + , m_limitingConeAngle(limitingConeAngle) + { + } + + FloatPoint3D m_position; + FloatPoint3D m_direction; + + float m_specularExponent; + float m_limitingConeAngle; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // SpotLightSource_h diff --git a/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp b/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp new file mode 100644 index 0000000..3b73ff6 --- /dev/null +++ b/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "LoopBlinnLocalTriangulator.h" + +#include "LoopBlinnMathUtils.h" +#include <algorithm> + +namespace WebCore { + +using LoopBlinnMathUtils::approxEqual; +using LoopBlinnMathUtils::linesIntersect; +using LoopBlinnMathUtils::pointInTriangle; + +bool LoopBlinnLocalTriangulator::Triangle::contains(LoopBlinnLocalTriangulator::Vertex* v) +{ + return indexForVertex(v) >= 0; +} + +LoopBlinnLocalTriangulator::Vertex* LoopBlinnLocalTriangulator::Triangle::nextVertex(LoopBlinnLocalTriangulator::Vertex* current, bool traverseCounterClockwise) +{ + int index = indexForVertex(current); + ASSERT(index >= 0); + if (traverseCounterClockwise) + ++index; + else + --index; + if (index < 0) + index += 3; + else + index = index % 3; + return m_vertices[index]; +} + +int LoopBlinnLocalTriangulator::Triangle::indexForVertex(LoopBlinnLocalTriangulator::Vertex* vertex) +{ + for (int i = 0; i < 3; ++i) + if (m_vertices[i] == vertex) + return i; + return -1; +} + +void LoopBlinnLocalTriangulator::Triangle::makeCounterClockwise() +{ + // Possibly swaps two vertices so that the triangle's vertices are + // always specified in counterclockwise order. This orders the + // vertices canonically when walking the interior edges from the + // start to the end vertex. + FloatPoint3D point0(m_vertices[0]->xyCoordinates()); + FloatPoint3D point1(m_vertices[1]->xyCoordinates()); + FloatPoint3D point2(m_vertices[2]->xyCoordinates()); + FloatPoint3D crossProduct = (point1 - point0).cross(point2 - point0); + if (crossProduct.z() < 0) + std::swap(m_vertices[1], m_vertices[2]); +} + +LoopBlinnLocalTriangulator::LoopBlinnLocalTriangulator() +{ + reset(); +} + +void LoopBlinnLocalTriangulator::reset() +{ + m_numberOfTriangles = 0; + m_numberOfInteriorVertices = 0; + for (int i = 0; i < 4; ++i) { + m_interiorVertices[i] = 0; + m_vertices[i].resetFlags(); + } +} + +void LoopBlinnLocalTriangulator::triangulate(InsideEdgeComputation computeInsideEdges, LoopBlinnConstants::FillSide sideToFill) +{ + triangulateHelper(sideToFill); + + if (computeInsideEdges == ComputeInsideEdges) { + // We need to compute which vertices describe the path along the + // interior portion of the shape, to feed these vertices to the + // more general tessellation algorithm. It is possible that we + // could determine this directly while producing triangles above. + // Here we try to do it generally just by examining the triangles + // that have already been produced. We walk around them in a + // specific direction determined by which side of the curve is + // being filled. We ignore the interior vertex unless it is also + // the ending vertex, and skip the edges shared between two + // triangles. + Vertex* v = &m_vertices[0]; + addInteriorVertex(v); + int numSteps = 0; + while (!v->end() && numSteps < 4) { + // Find the next vertex according to the above rules + bool gotNext = false; + for (int i = 0; i < numberOfTriangles() && !gotNext; ++i) { + Triangle* tri = getTriangle(i); + if (tri->contains(v)) { + Vertex* next = tri->nextVertex(v, sideToFill == LoopBlinnConstants::RightSide); + if (!next->marked() && !isSharedEdge(v, next) && (!next->interior() || next->end())) { + addInteriorVertex(next); + v = next; + // Break out of for loop + gotNext = true; + } + } + } + ++numSteps; + } + if (!v->end()) { + // Something went wrong with the above algorithm; add the last + // vertex to the interior vertices anyway. (FIXME: should we + // add an assert here and do more extensive testing?) + addInteriorVertex(&m_vertices[3]); + } + } +} + +void LoopBlinnLocalTriangulator::triangulateHelper(LoopBlinnConstants::FillSide sideToFill) +{ + reset(); + + m_vertices[3].setEnd(true); + + // First test for degenerate cases. + for (int i = 0; i < 4; ++i) { + for (int j = i + 1; j < 4; ++j) { + if (approxEqual(m_vertices[i].xyCoordinates(), m_vertices[j].xyCoordinates())) { + // Two of the vertices are coincident, so we can eliminate at + // least one triangle. We might be able to eliminate the other + // as well, but this seems sufficient to avoid degenerate + // triangulations. + int indices[3] = { 0 }; + int index = 0; + for (int k = 0; k < 4; ++k) + if (k != j) + indices[index++] = k; + addTriangle(&m_vertices[indices[0]], + &m_vertices[indices[1]], + &m_vertices[indices[2]]); + return; + } + } + } + + // See whether any of the points are fully contained in the + // triangle defined by the other three. + for (int i = 0; i < 4; ++i) { + int indices[3] = { 0 }; + int index = 0; + for (int j = 0; j < 4; ++j) + if (i != j) + indices[index++] = j; + if (pointInTriangle(m_vertices[i].xyCoordinates(), + m_vertices[indices[0]].xyCoordinates(), + m_vertices[indices[1]].xyCoordinates(), + m_vertices[indices[2]].xyCoordinates())) { + // Produce three triangles surrounding this interior vertex. + for (int j = 0; j < 3; ++j) + addTriangle(&m_vertices[indices[j % 3]], + &m_vertices[indices[(j + 1) % 3]], + &m_vertices[i]); + // Mark the interior vertex so we ignore it if trying to trace + // the interior edge. + m_vertices[i].setInterior(true); + return; + } + } + + // There are only a few permutations of the vertices, ignoring + // rotations, which are irrelevant: + // + // 0--3 0--2 0--3 0--1 0--2 0--1 + // | | | | | | | | | | | | + // | | | | | | | | | | | | + // 1--2 1--3 2--1 2--3 3--1 3--2 + // + // Note that three of these are reflections of each other. + // Therefore there are only three possible triangulations: + // + // 0--3 0--2 0--3 + // |\ | |\ | |\ | + // | \| | \| | \| + // 1--2 1--3 2--1 + // + // From which we can choose by seeing which of the potential + // diagonals intersect. Note that we choose the shortest diagonal + // to split the quad. + if (linesIntersect(m_vertices[0].xyCoordinates(), + m_vertices[2].xyCoordinates(), + m_vertices[1].xyCoordinates(), + m_vertices[3].xyCoordinates())) { + if ((m_vertices[2].xyCoordinates() - m_vertices[0].xyCoordinates()).diagonalLengthSquared() < + (m_vertices[3].xyCoordinates() - m_vertices[1].xyCoordinates()).diagonalLengthSquared()) { + addTriangle(&m_vertices[0], &m_vertices[1], &m_vertices[2]); + addTriangle(&m_vertices[0], &m_vertices[2], &m_vertices[3]); + } else { + addTriangle(&m_vertices[0], &m_vertices[1], &m_vertices[3]); + addTriangle(&m_vertices[1], &m_vertices[2], &m_vertices[3]); + } + } else if (linesIntersect(m_vertices[0].xyCoordinates(), + m_vertices[3].xyCoordinates(), + m_vertices[1].xyCoordinates(), + m_vertices[2].xyCoordinates())) { + if ((m_vertices[3].xyCoordinates() - m_vertices[0].xyCoordinates()).diagonalLengthSquared() < + (m_vertices[2].xyCoordinates() - m_vertices[1].xyCoordinates()).diagonalLengthSquared()) { + addTriangle(&m_vertices[0], &m_vertices[1], &m_vertices[3]); + addTriangle(&m_vertices[0], &m_vertices[3], &m_vertices[2]); + } else { + addTriangle(&m_vertices[0], &m_vertices[1], &m_vertices[2]); + addTriangle(&m_vertices[2], &m_vertices[1], &m_vertices[3]); + } + } else { + // Lines (0->1), (2->3) intersect -- or should, modulo numerical + // precision issues + if ((m_vertices[1].xyCoordinates() - m_vertices[0].xyCoordinates()).diagonalLengthSquared() < + (m_vertices[3].xyCoordinates() - m_vertices[2].xyCoordinates()).diagonalLengthSquared()) { + addTriangle(&m_vertices[0], &m_vertices[2], &m_vertices[1]); + addTriangle(&m_vertices[0], &m_vertices[1], &m_vertices[3]); + } else { + addTriangle(&m_vertices[0], &m_vertices[2], &m_vertices[3]); + addTriangle(&m_vertices[3], &m_vertices[2], &m_vertices[1]); + } + } +} + +void LoopBlinnLocalTriangulator::addTriangle(Vertex* v0, Vertex* v1, Vertex* v2) +{ + ASSERT(m_numberOfTriangles < 3); + m_triangles[m_numberOfTriangles++].setVertices(v0, v1, v2); +} + +void LoopBlinnLocalTriangulator::addInteriorVertex(Vertex* v) +{ + ASSERT(m_numberOfInteriorVertices < 4); + m_interiorVertices[m_numberOfInteriorVertices++] = v; + v->setMarked(true); +} + +bool LoopBlinnLocalTriangulator::isSharedEdge(Vertex* v0, Vertex* v1) +{ + bool haveEdge01 = false; + bool haveEdge10 = false; + for (int i = 0; i < numberOfTriangles(); ++i) { + Triangle* tri = getTriangle(i); + if (tri->contains(v0) && tri->nextVertex(v0, true) == v1) + haveEdge01 = true; + if (tri->contains(v1) && tri->nextVertex(v1, true) == v0) + haveEdge10 = true; + } + return haveEdge01 && haveEdge10; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.h b/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.h new file mode 100644 index 0000000..ea3d7e3 --- /dev/null +++ b/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.h @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LoopBlinnLocalTriangulator_h +#define LoopBlinnLocalTriangulator_h + +#include "FloatPoint.h" +#include "FloatPoint3D.h" +#include "LoopBlinnConstants.h" +#include <wtf/Assertions.h> +#include <wtf/Noncopyable.h> + +namespace WebCore { + +// Performs a localized triangulation of the triangle mesh +// corresponding to the four control point vertices of a cubic curve +// segment. +class LoopBlinnLocalTriangulator : public Noncopyable { +public: + // The vertices that the triangulator operates upon, containing both + // the position information as well as the cubic texture + // coordinates. + class Vertex : public Noncopyable { + public: + Vertex() + { + resetFlags(); + } + + const FloatPoint& xyCoordinates() const + { + return m_xyCoordinates; + } + + const FloatPoint3D& klmCoordinates() const + { + return m_klmCoordinates; + } + + // Sets the position and texture coordinates of the vertex. + void set(float x, float y, + float k, float l, float m) + { + m_xyCoordinates.set(x, y); + m_klmCoordinates.set(k, l, m); + } + + // Flags for walking from the start vertex to the end vertex. + bool end() + { + return m_end; + } + + void setEnd(bool end) + { + m_end = end; + } + + bool marked() + { + return m_marked; + } + + void setMarked(bool marked) + { + m_marked = marked; + } + + bool interior() + { + return m_interior; + } + + void setInterior(bool interior) + { + m_interior = interior; + } + + void resetFlags() + { + m_end = false; + m_marked = false; + m_interior = false; + } + + private: + // 2D coordinates of the vertex in the plane. + FloatPoint m_xyCoordinates; + // Cubic texture coordinates for rendering the curve. + FloatPoint3D m_klmCoordinates; + + // Flags for walking from the start vertex to the end vertex. + bool m_end; + bool m_marked; + bool m_interior; + }; + + // The triangles the Triangulator produces. + class Triangle { + public: + Triangle() + { + m_vertices[0] = 0; + m_vertices[1] = 0; + m_vertices[2] = 0; + } + + // Gets the vertex at the given index, 0 <= index < 3. + Vertex* getVertex(int index) + { + ASSERT(index >= 0 && index < 3); + return m_vertices[index]; + } + + // Returns true if this triangle contains the given vertex (by + // identity, not geometrically). + bool contains(Vertex* v); + + // Returns the vertex following the current one in the specified + // direction, counterclockwise or clockwise. + Vertex* nextVertex(Vertex* current, bool traverseCounterClockwise); + + // Sets the vertices of this triangle, potentially reordering them + // to produce a canonical orientation. + void setVertices(Vertex* v0, + Vertex* v1, + Vertex* v2) + { + m_vertices[0] = v0; + m_vertices[1] = v1; + m_vertices[2] = v2; + makeCounterClockwise(); + } + + private: + // Returns the index [0..2] associated with the given vertex, or + // -1 if not found. + int indexForVertex(Vertex* vertex); + + // Reorders the vertices in this triangle to make them + // counterclockwise when viewed in the 2D plane, in order to + // achieve a canonical ordering. + void makeCounterClockwise(); + + // Note: these are raw pointers because they point to the + // m_vertices contained in the surrounding triangulator. + Vertex* m_vertices[3]; + }; + + LoopBlinnLocalTriangulator(); + + // Resets the triangulator's state. After each triangulation and + // before the next, call this to re-initialize the internal + // vertices' state. + void reset(); + + // Returns a mutable vertex stored in the triangulator. Use this to + // set up the vertices before a triangulation. + Vertex* getVertex(int index) + { + ASSERT(index >= 0 && index < 4); + return &m_vertices[index]; + } + + enum InsideEdgeComputation { + ComputeInsideEdges, + DontComputeInsideEdges + }; + + // Once the vertices' contents have been set up, call triangulate() + // to recompute the triangles. + // + // If computeInsideEdges is ComputeInsideEdges, then sideToFill + // will be used to determine which side of the cubic curve defined + // by the four control points is to be filled. + // + // The triangulation obeys the following guarantees: + // - If the convex hull is a quadrilateral, then the shortest edge + // will be chosen for the cut into two triangles. + // - If one of the vertices is contained in the triangle spanned + // by the other three, three triangles will be produced. + void triangulate(InsideEdgeComputation computeInsideEdges, + LoopBlinnConstants::FillSide sideToFill); + + // Number of triangles computed by triangulate(). + int numberOfTriangles() const + { + return m_numberOfTriangles; + } + + // Returns the computed triangle at index, 0 <= index < numberOfTriangles(). + Triangle* getTriangle(int index) + { + ASSERT(index >= 0 && index < m_numberOfTriangles); + return &m_triangles[index]; + } + + // Number of vertices facing the inside of the shape, if + // ComputeInsideEdges was passed when triangulate() was called. + int numberOfInteriorVertices() const + { + return m_numberOfInteriorVertices; + } + + // Fetches the given interior vertex, 0 <= index < numberOfInteriorVertices(). + Vertex* getInteriorVertex(int index) + { + ASSERT(index >= 0 && index < m_numberOfInteriorVertices); + return m_interiorVertices[index]; + } + +private: + void triangulateHelper(LoopBlinnConstants::FillSide sideToFill); + + // Adds a triangle to the triangulation. + void addTriangle(Vertex* v0, Vertex* v1, Vertex* v2); + + // Adds a vertex to the list of interior vertices. + void addInteriorVertex(Vertex* v); + + // Indicates whether the edge between vertex v0 and v1 is shared + // between two or more triangles. + bool isSharedEdge(Vertex* v0, Vertex* v1); + + // The vertices being triangulated. + Vertex m_vertices[4]; + + // The vertices corresponding to the edges facing the inside of the + // shape, in order from the start vertex to the end vertex. The more + // general triangulation algorithm tessellates this interior region. + Vertex* m_interiorVertices[4]; + // The number of interior vertices that are valid for the current + // triangulation. + int m_numberOfInteriorVertices; + + // There can be at most three triangles computed by this local + // algorithm, which occurs when one of the vertices is contained in + // the triangle spanned by the other three. Most of the time the + // algorithm computes two triangles. + Triangle m_triangles[3]; + int m_numberOfTriangles; +}; + +} // namespace WebCore + +#endif // LoopBlinnLocalTriangulator_h diff --git a/WebCore/platform/graphics/gpu/Texture.cpp b/WebCore/platform/graphics/gpu/Texture.cpp index 95436ba..6023fe9 100644 --- a/WebCore/platform/graphics/gpu/Texture.cpp +++ b/WebCore/platform/graphics/gpu/Texture.cpp @@ -129,7 +129,7 @@ static uint32_t* copySubRect(uint32_t* src, int srcX, int srcY, uint32_t* dst, i for (int y = 0; y < height; ++y) { for (int x = 0; x < width ; ++x) { uint32_t pixel = srcOffset[x + y * srcStride]; - *dstPixel = pixel & 0xFF00FF00 | ((pixel & 0x00FF0000) >> 16) | ((pixel & 0x000000FF) << 16); + *dstPixel = (pixel & 0xFF00FF00) | ((pixel & 0x00FF0000) >> 16) | ((pixel & 0x000000FF) << 16); dstPixel++; } } diff --git a/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.cpp b/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.cpp index 63555bf..5a94fd4 100644 --- a/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.cpp @@ -18,7 +18,7 @@ #include "config.h" #include "DataSourceGStreamer.h" -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include <gio/gio.h> #include <glib.h> @@ -243,4 +243,4 @@ static void webkit_data_src_uri_handler_init(gpointer g_iface, gpointer iface_da iface->set_uri = webkit_data_src_uri_set_uri; } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) diff --git a/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.h b/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.h index 453685a..d462ccc4 100644 --- a/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.h @@ -19,7 +19,7 @@ #ifndef DataSourceGStreamer_h #define DataSourceGStreamer_h -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include <glib-object.h> #include <gst/base/gstbasesrc.h> @@ -53,5 +53,5 @@ GType webkit_data_src_get_type(void); G_END_DECLS -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) #endif diff --git a/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp b/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp index 6333437..06eec14 100644 --- a/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp @@ -20,7 +20,7 @@ #include "config.h" #include "GOwnPtrGStreamer.h" -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include <gst/gstelement.h> namespace WTF { @@ -32,4 +32,4 @@ template <> void freeOwnedGPtr<GstElement>(GstElement* ptr) } } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) diff --git a/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h b/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h index 84a3e30..672a23d 100644 --- a/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h @@ -19,7 +19,7 @@ #ifndef GOwnPtrGStreamer_h #define GOwnPtrGStreamer_h -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include "GOwnPtr.h" @@ -31,5 +31,5 @@ template<> void freeOwnedGPtr<GstElement>(GstElement* ptr); } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) #endif diff --git a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp index efccff0..539d92a 100644 --- a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp +++ b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp @@ -19,7 +19,7 @@ #include "config.h" #include "GStreamerGWorld.h" -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include "GOwnPtrGStreamer.h" #include <gst/gst.h> @@ -203,4 +203,4 @@ void GStreamerGWorld::setWindowOverlay(GstMessage* message) } } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) diff --git a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h index 282f13c..f519911 100644 --- a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h +++ b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h @@ -20,7 +20,7 @@ #ifndef GStreamerGWorld_h #define GStreamerGWorld_h -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include "PlatformVideoWindow.h" #include "RefCounted.h" @@ -62,5 +62,5 @@ private: }; } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) #endif diff --git a/WebCore/platform/graphics/gstreamer/ImageGStreamer.h b/WebCore/platform/graphics/gstreamer/ImageGStreamer.h index 4a4ff2b..cf2b9d6 100644 --- a/WebCore/platform/graphics/gstreamer/ImageGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/ImageGStreamer.h @@ -20,7 +20,7 @@ #ifndef ImageGStreamer_h #define ImageGStreamer_h -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include "BitmapImage.h" #include <gst/gst.h> @@ -59,5 +59,5 @@ class ImageGStreamer : public RefCounted<ImageGStreamer> { }; } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) #endif diff --git a/WebCore/platform/graphics/gstreamer/ImageGStreamerCG.mm b/WebCore/platform/graphics/gstreamer/ImageGStreamerCG.mm index 076df4a..c73adc0 100644 --- a/WebCore/platform/graphics/gstreamer/ImageGStreamerCG.mm +++ b/WebCore/platform/graphics/gstreamer/ImageGStreamerCG.mm @@ -19,7 +19,7 @@ #include "config.h" #include "ImageGStreamer.h" -#if ENABLE(VIDEO) +#if USE(GSTREAMER) using namespace WebCore; @@ -57,4 +57,4 @@ ImageGStreamer::~ImageGStreamer() m_image = 0; } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) diff --git a/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp b/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp index 2fed892..6a9d068 100644 --- a/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp +++ b/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp @@ -20,7 +20,7 @@ #include "config.h" #include "ImageGStreamer.h" -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include "GOwnPtr.h" @@ -65,4 +65,4 @@ ImageGStreamer::~ImageGStreamer() m_image = 0; } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) diff --git a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp index 0071d67..da9255b 100644 --- a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp @@ -24,7 +24,7 @@ #include "config.h" #include "MediaPlayerPrivateGStreamer.h" -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include "ColorSpace.h" #include "DataSourceGStreamer.h" @@ -1459,4 +1459,4 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin() } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) diff --git a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h index 6d1392d..800ca6d 100644 --- a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h @@ -22,7 +22,7 @@ #ifndef MediaPlayerPrivateGStreamer_h #define MediaPlayerPrivateGStreamer_h -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include <wtf/Forward.h> #include "MediaPlayerPrivate.h" @@ -179,5 +179,5 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { }; } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) #endif diff --git a/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h b/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h index 3c4904b..f3df207 100644 --- a/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h +++ b/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h @@ -19,7 +19,7 @@ #ifndef PlatformVideoWindow_h #define PlatformVideoWindow_h -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include "Widget.h" #include <wtf/PassRefPtr.h> @@ -44,5 +44,5 @@ class PlatformVideoWindow : public RefCounted<PlatformVideoWindow> { }; } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) #endif diff --git a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp index 68ab7ac..c55b9cc 100644 --- a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp +++ b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp @@ -19,7 +19,7 @@ #include "config.h" #include "PlatformVideoWindow.h" -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include "NotImplemented.h" @@ -35,4 +35,4 @@ PlatformVideoWindow::~PlatformVideoWindow() notImplemented(); } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) diff --git a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp index 88b6552..77343ae 100644 --- a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp +++ b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp @@ -19,7 +19,7 @@ #include "config.h" #include "PlatformVideoWindow.h" -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include <gtk/gtk.h> @@ -61,4 +61,4 @@ PlatformVideoWindow::~PlatformVideoWindow() m_videoWindowId = 0; } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) diff --git a/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp index 00fef4b..4319f6c 100644 --- a/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp @@ -28,7 +28,7 @@ #include "config.h" #include "VideoSinkGStreamer.h" -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include <glib.h> #include <gst/gst.h> @@ -371,4 +371,4 @@ webkit_video_sink_new(void) return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, 0); } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) diff --git a/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h b/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h index 767e83f..6cd86c2 100644 --- a/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h @@ -20,7 +20,7 @@ #ifndef VideoSinkGStreamer_h #define VideoSinkGStreamer_h -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include <glib-object.h> #include <gst/video/gstvideosink.h> @@ -77,5 +77,5 @@ GstElement *webkit_video_sink_new(void); G_END_DECLS -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) #endif diff --git a/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp b/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp index 4e57193..635feff 100644 --- a/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp @@ -18,7 +18,7 @@ #include "config.h" #include "WebKitWebSourceGStreamer.h" -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include "Document.h" #include "GOwnPtr.h" @@ -795,5 +795,5 @@ void StreamingClient::cannotShowURL(ResourceHandle*) GST_ELEMENT_ERROR(m_src, RESOURCE, OPEN_READ, ("Can't show \"%s\"", m_src->priv->uri), (0)); } -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) diff --git a/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h b/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h index 1594062..bdb0833 100644 --- a/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h @@ -18,7 +18,7 @@ #ifndef WebKitWebSourceGStreamer_h #define WebKitWebSourceGStreamer_h -#if ENABLE(VIDEO) +#if USE(GSTREAMER) #include "Frame.h" #include <gst/gst.h> @@ -50,5 +50,5 @@ void webKitWebSrcSetFrame(WebKitWebSrc* src, WebCore::Frame* frame); G_END_DECLS -#endif // ENABLE(VIDEO) +#endif // USE(GSTREAMER) #endif diff --git a/WebCore/platform/graphics/gtk/CairoUtilities.cpp b/WebCore/platform/graphics/gtk/GdkCairoUtilities.cpp index 81e00f0..d768ce2 100644 --- a/WebCore/platform/graphics/gtk/CairoUtilities.cpp +++ b/WebCore/platform/graphics/gtk/GdkCairoUtilities.cpp @@ -24,7 +24,7 @@ */ #include "config.h" -#include "CairoUtilities.h" +#include "GdkCairoUtilities.h" #include <cairo.h> #include <gtk/gtk.h> diff --git a/WebCore/platform/graphics/gtk/CairoUtilities.h b/WebCore/platform/graphics/gtk/GdkCairoUtilities.h index 594abc0..ff5b3ed 100644 --- a/WebCore/platform/graphics/gtk/CairoUtilities.h +++ b/WebCore/platform/graphics/gtk/GdkCairoUtilities.h @@ -23,9 +23,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CairoUtilities_h -#define CairoUtilities_h +#ifndef GdkCairoUtilities_h +#define GdkCairoUtilities_h GdkPixbuf* cairoImageSurfaceToGdkPixbuf(cairo_surface_t* surface); -#endif // CairoUtilities_h +#endif // GdkCairoUtilities_h diff --git a/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp b/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp index 821cc12..edb26f0 100644 --- a/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp +++ b/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp @@ -21,7 +21,7 @@ #include "ImageBuffer.h" #include "Base64.h" -#include "CairoUtilities.h" +#include "GdkCairoUtilities.h" #include "GOwnPtr.h" #include "GRefPtrGtk.h" #include "MIMETypeRegistry.h" diff --git a/WebCore/platform/graphics/gtk/ImageGtk.cpp b/WebCore/platform/graphics/gtk/ImageGtk.cpp index 5272243..623ace6 100644 --- a/WebCore/platform/graphics/gtk/ImageGtk.cpp +++ b/WebCore/platform/graphics/gtk/ImageGtk.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "BitmapImage.h" -#include "CairoUtilities.h" +#include "GdkCairoUtilities.h" #include "GOwnPtrGtk.h" #include "SharedBuffer.h" #include <wtf/text/CString.h> diff --git a/WebCore/platform/graphics/mac/ComplexTextController.cpp b/WebCore/platform/graphics/mac/ComplexTextController.cpp index da381f2..a2733f8 100644 --- a/WebCore/platform/graphics/mac/ComplexTextController.cpp +++ b/WebCore/platform/graphics/mac/ComplexTextController.cpp @@ -185,25 +185,14 @@ void ComplexTextController::collectComplexTextRuns() // We break up glyph run generation for the string by FontData and (if needed) the use of small caps. const UChar* cp = m_run.characters(); - bool hasTrailingSoftHyphen = m_run[m_end - 1] == softHyphen; - if (m_font.isSmallCaps() || hasTrailingSoftHyphen) + if (m_font.isSmallCaps()) m_smallCapsBuffer.resize(m_end); unsigned indexOfFontTransition = m_run.rtl() ? m_end - 1 : 0; const UChar* curr = m_run.rtl() ? cp + m_end - 1 : cp; const UChar* end = m_run.rtl() ? cp - 1 : cp + m_end; - // FIXME: Using HYPHEN-MINUS rather than HYPHEN because Times has a HYPHEN-MINUS glyph that looks like its - // SOFT-HYPHEN glyph, and has no HYPHEN glyph. - static const UChar hyphen = '-'; - - if (hasTrailingSoftHyphen && m_run.rtl()) { - collectComplexTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); - indexOfFontTransition--; - curr--; - } - GlyphData glyphData; GlyphData nextGlyphData; @@ -267,14 +256,11 @@ void ComplexTextController::collectComplexTextRuns() } } - int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : m_end - indexOfFontTransition - (hasTrailingSoftHyphen ? 1 : 0); + int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : m_end - indexOfFontTransition; if (itemLength) { int itemStart = m_run.rtl() ? 0 : indexOfFontTransition; collectComplexTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, nextGlyphData.glyph ? nextGlyphData.fontData : 0); } - - if (hasTrailingSoftHyphen && m_run.ltr()) - collectComplexTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); } #if USE(CORE_TEXT) && USE(ATSUI) @@ -382,9 +368,9 @@ void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) unsigned glyphEndOffset; if (complexTextRun.isMonotonic()) { if (ltr) - glyphEndOffset = max<unsigned>(glyphStartOffset, g + 1 < glyphCount ? complexTextRun.indexAt(g + 1) : complexTextRun.stringLength()); + glyphEndOffset = max<unsigned>(glyphStartOffset, g + 1 < glyphCount ? static_cast<unsigned>(complexTextRun.indexAt(g + 1)) : complexTextRun.stringLength()); else - glyphEndOffset = max<unsigned>(glyphStartOffset, g > 0 ? complexTextRun.indexAt(g - 1) : complexTextRun.stringLength()); + glyphEndOffset = max<unsigned>(glyphStartOffset, g > 0 ? static_cast<unsigned>(complexTextRun.indexAt(g - 1)) : complexTextRun.stringLength()); } else glyphEndOffset = complexTextRun.endOffsetAt(g); diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h index 6ff3ff0..17a67ac 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h @@ -96,11 +96,10 @@ public: virtual void suspendAnimations(double time); virtual void resumeAnimations(); - virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, const String& keyframesName, double timeOffset); - virtual void removeAnimationsForProperty(AnimatedPropertyID); - virtual void removeAnimationsForKeyframes(const String& keyframesName); - virtual void pauseAnimation(const String& keyframesName, double timeOffset); - + virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, const String& animationName, double timeOffset); + virtual void pauseAnimation(const String& animationName, double timeOffset); + virtual void removeAnimation(const String& animationName); + virtual void setContentsToImage(Image*); virtual void setContentsToMedia(PlatformLayer*); virtual void setContentsToCanvas(PlatformLayer*); @@ -119,6 +118,9 @@ public: virtual void syncCompositingState(); virtual void syncCompositingStateForThisLayerOnly(); + // Should only be called by animationDidStart: callback + void animationDidStart(CAAnimation*); + protected: virtual void setOpacityInternal(float); @@ -128,17 +130,17 @@ private: CALayer* primaryLayer() const { return m_structuralLayer.get() ? m_structuralLayer.get() : m_layer.get(); } CALayer* hostLayerForSublayers() const; CALayer* layerForSuperlayer() const; - CALayer* animatedLayer(AnimatedPropertyID property) const; + CALayer* animatedLayer(AnimatedPropertyID) const; typedef String CloneID; // Identifier for a given clone, based on original/replica branching down the tree. static bool isReplicatedRootClone(const CloneID& cloneID) { return cloneID[0U] & 1; } typedef HashMap<CloneID, RetainPtr<CALayer> > LayerMap; LayerMap* primaryLayerClones() const { return m_structuralLayer.get() ? m_structuralLayerClones.get() : m_layerClones.get(); } - LayerMap* animatedLayerClones(AnimatedPropertyID property) const; + LayerMap* animatedLayerClones(AnimatedPropertyID) const; - bool createAnimationFromKeyframes(const KeyframeValueList&, const Animation*, const String& keyframesName, double timeOffset); - bool createTransformAnimationsFromKeyframes(const KeyframeValueList&, const Animation*, const String& keyframesName, double timeOffset, const IntSize& boxSize); + bool createAnimationFromKeyframes(const KeyframeValueList&, const Animation*, const String& animationName, double timeOffset); + bool createTransformAnimationsFromKeyframes(const KeyframeValueList&, const Animation*, const String& animationName, double timeOffset, const IntSize& boxSize); // Return autoreleased animation (use RetainPtr?) CABasicAnimation* createBasicAnimation(const Animation*, AnimatedPropertyID, bool additive); @@ -153,9 +155,9 @@ private: bool setTransformAnimationEndpoints(const KeyframeValueList&, const Animation*, CABasicAnimation*, int functionIndex, TransformOperation::OperationType, bool isMatrixAnimation, const IntSize& boxSize); bool setTransformAnimationKeyframes(const KeyframeValueList&, const Animation*, CAKeyframeAnimation*, int functionIndex, TransformOperation::OperationType, bool isMatrixAnimation, const IntSize& boxSize); - bool animationIsRunning(const String& keyframesName) const + bool animationIsRunning(const String& animationName) const { - return m_runningKeyframeAnimations.find(keyframesName) != m_runningKeyframeAnimations.end(); + return m_runningAnimations.find(animationName) != m_runningAnimations.end(); } void commitLayerChangesBeforeSublayers(); @@ -271,13 +273,13 @@ private: void ensureStructuralLayer(StructuralLayerPurpose); StructuralLayerPurpose structuralLayerPurpose() const; - void setAnimationOnLayer(CAPropertyAnimation*, AnimatedPropertyID, const String& keyframesName, int index, double timeOffset); - bool removeAnimationFromLayer(AnimatedPropertyID, const String& keyframesName, int index); - void pauseAnimationOnLayer(AnimatedPropertyID, const String& keyframesName, int index, double timeOffset); + void setCAAnimationOnLayer(CAPropertyAnimation*, AnimatedPropertyID, const String& animationName, int index, double timeOffset); + bool removeCAAnimationFromLayer(AnimatedPropertyID, const String& animationName, int index); + void pauseCAAnimationOnLayer(AnimatedPropertyID, const String& animationName, int index, double timeOffset); enum MoveOrCopy { Move, Copy }; - void moveOrCopyAnimationsForProperty(MoveOrCopy, AnimatedPropertyID property, CALayer * fromLayer, CALayer * toLayer); - static void moveOrCopyAllAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, const String& keyframesName, CALayer * fromLayer, CALayer * toLayer); + static void moveOrCopyLayerAnimation(MoveOrCopy, const String& animationIdentifier, CALayer *fromLayer, CALayer *toLayer); + void moveOrCopyAnimationsForProperty(MoveOrCopy, AnimatedPropertyID, CALayer * fromLayer, CALayer * toLayer); enum LayerChange { NoChange = 0, @@ -335,29 +337,26 @@ private: RetainPtr<CGImageRef> m_uncorrectedContentsImage; RetainPtr<CGImageRef> m_pendingContentsImage; - struct LayerAnimation { - LayerAnimation(CAPropertyAnimation* caAnim, const String& keyframesName, AnimatedPropertyID property, int index, double timeOffset) - : m_animation(caAnim) - , m_keyframesName(keyframesName) + // This represents the animation of a single property. There may be multiple transform animations for + // a single transition or keyframe animation, so index is used to distinguish these. + struct LayerPropertyAnimation { + LayerPropertyAnimation(CAPropertyAnimation* caAnimation, const String& animationName, AnimatedPropertyID property, int index, double timeOffset) + : m_animation(caAnimation) + , m_name(animationName) , m_property(property) , m_index(index) , m_timeOffset(timeOffset) { } RetainPtr<CAPropertyAnimation*> m_animation; - String m_keyframesName; + String m_name; AnimatedPropertyID m_property; int m_index; double m_timeOffset; }; - Vector<LayerAnimation> m_uncomittedAnimations; - - // Animations on the layer are identified by property + index. - typedef int AnimatedProperty; // std containers choke on the AnimatedPropertyID enum - typedef pair<AnimatedProperty, int> AnimationPair; - - HashSet<AnimatedProperty> m_transitionPropertiesToRemove; + // Uncommitted transitions and animations. + Vector<LayerPropertyAnimation> m_uncomittedAnimations; enum Action { Remove, Pause }; struct AnimationProcessingAction { @@ -367,15 +366,15 @@ private: { } Action action; - double timeOffset; // only used for pause + double timeOffset; // only used for pause }; typedef HashMap<String, AnimationProcessingAction> AnimationsToProcessMap; - AnimationsToProcessMap m_keyframeAnimationsToProcess; + AnimationsToProcessMap m_animationsToProcess; + + // Map of animation names to their associated lists of property animations, so we can remove/pause them. + typedef HashMap<String, Vector<LayerPropertyAnimation> > AnimationsMap; + AnimationsMap m_runningAnimations; - // Map of keyframe names to their associated lists of animations for running animations, so we can remove/pause them. - typedef HashMap<String, Vector<AnimationPair> > KeyframeAnimationsMap; - KeyframeAnimationsMap m_runningKeyframeAnimations; - Vector<FloatRect> m_dirtyRects; LayerChangeFlags m_uncommittedChanges; diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm index 395a691..d4cd851 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -55,6 +55,8 @@ using namespace std; namespace WebCore { +static NSString * const WebKitAnimationBeginTimeSetKey = @"WebKitAnimationBeginTimeSet"; + // The threshold width or height above which a tiled layer will be used. This should be // large enough to avoid tiled layers for most GraphicsLayers, but less than the OpenGL // texture size limit on all supported hardware. @@ -101,11 +103,8 @@ static double mediaTimeToCurrentTime(CFTimeInterval t) - (void)animationDidStart:(CAAnimation *)animation { - if (!m_graphicsLayer) - return; - - double startTime = WebCore::mediaTimeToCurrentTime([animation beginTime]); - m_graphicsLayer->client()->notifyAnimationStarted(m_graphicsLayer, startTime); + if (m_graphicsLayer) + m_graphicsLayer->animationDidStart(animation); } - (WebCore::GraphicsLayerCA*)graphicsLayer @@ -197,7 +196,7 @@ static NSValue* getTransformFunctionValue(const TransformOperation* transformOp, } #if HAVE_MODERN_QUARTZCORE -static NSString* getValueFunctionNameForTransformOperation(TransformOperation::OperationType transformType) +static NSString *getValueFunctionNameForTransformOperation(TransformOperation::OperationType transformType) { // Use literal strings to avoid link-time dependency on those symbols. switch (transformType) { @@ -247,20 +246,9 @@ static String propertyIdToString(AnimatedPropertyID property) return ""; } -static String animationIdentifier(AnimatedPropertyID property, const String& keyframesName, int index) +static String animationIdentifier(const String& animationName, AnimatedPropertyID property, int index) { - StringBuilder builder; - - builder.append(propertyIdToString(property)); - builder.append("_"); - - if (!keyframesName.isEmpty()) { - builder.append(keyframesName); - builder.append("_"); - } - builder.append("_"); - builder.append(String::number(index)); - return builder.toString(); + return animationName + String::format("_%d_%d", property, index); } static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction* timingFunction) @@ -550,39 +538,40 @@ void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t) noteLayerPropertyChanged(ChildrenTransformChanged); } -void GraphicsLayerCA::moveOrCopyAllAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, const String& keyframesName, CALayer *fromLayer, CALayer *toLayer) +void GraphicsLayerCA::moveOrCopyLayerAnimation(MoveOrCopy operation, const String& animationIdentifier, CALayer *fromLayer, CALayer *toLayer) { - for (int index = 0; ; ++index) { - String animName = animationIdentifier(property, keyframesName, index); + NSString *animationID = animationIdentifier; + CAAnimation *anim = [fromLayer animationForKey:animationID]; + if (!anim) + return; - CAAnimation* anim = [fromLayer animationForKey:animName]; - if (!anim) + switch (operation) { + case Move: + [anim retain]; + [fromLayer removeAnimationForKey:animationID]; + [toLayer addAnimation:anim forKey:animationID]; + [anim release]; break; - switch (operation) { - case Move: - [anim retain]; - [fromLayer removeAnimationForKey:animName]; - [toLayer addAnimation:anim forKey:animName]; - [anim release]; - break; - - case Copy: - [toLayer addAnimation:anim forKey:animName]; - break; - } + case Copy: + [toLayer addAnimation:anim forKey:animationID]; + break; } } void GraphicsLayerCA::moveOrCopyAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, CALayer *fromLayer, CALayer *toLayer) { - // Move transitions for this property. - moveOrCopyAllAnimationsForProperty(operation, property, "", fromLayer, toLayer); - // Look for running animations affecting this property. - KeyframeAnimationsMap::const_iterator end = m_runningKeyframeAnimations.end(); - for (KeyframeAnimationsMap::const_iterator it = m_runningKeyframeAnimations.begin(); it != end; ++it) - moveOrCopyAllAnimationsForProperty(operation, property, it->first, fromLayer, toLayer); + AnimationsMap::const_iterator end = m_runningAnimations.end(); + for (AnimationsMap::const_iterator it = m_runningAnimations.begin(); it != end; ++it) { + const Vector<LayerPropertyAnimation>& propertyAnimations = it->second; + size_t numAnimations = propertyAnimations.size(); + for (size_t i = 0; i < numAnimations; ++i) { + const LayerPropertyAnimation& currAnimation = propertyAnimations[i]; + if (currAnimation.m_property == property) + moveOrCopyLayerAnimation(operation, animationIdentifier(currAnimation.m_name, currAnimation.m_property, currAnimation.m_index), fromLayer, toLayer); + } + } } void GraphicsLayerCA::setPreserves3D(bool preserves3D) @@ -704,8 +693,10 @@ void GraphicsLayerCA::setContentsRect(const IntRect& rect) noteLayerPropertyChanged(ContentsRectChanged); } -bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset) +bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& animationName, double timeOffset) { + ASSERT(!animationName.isEmpty()); + if (forceSoftwareAnimation() || !anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2) return false; @@ -723,9 +714,9 @@ bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const Int bool createdAnimations = false; if (valueList.property() == AnimatedPropertyWebkitTransform) - createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, keyframesName, timeOffset, boxSize); + createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, animationName, timeOffset, boxSize); else - createdAnimations = createAnimationFromKeyframes(valueList, anim, keyframesName, timeOffset); + createdAnimations = createAnimationFromKeyframes(valueList, anim, animationName, timeOffset); if (createdAnimations) noteLayerPropertyChanged(AnimationChanged); @@ -733,39 +724,46 @@ bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const Int return createdAnimations; } -void GraphicsLayerCA::removeAnimationsForProperty(AnimatedPropertyID property) +void GraphicsLayerCA::pauseAnimation(const String& animationName, double timeOffset) { - if (m_transitionPropertiesToRemove.find(property) != m_transitionPropertiesToRemove.end()) + if (!animationIsRunning(animationName)) return; - m_transitionPropertiesToRemove.add(property); + AnimationsToProcessMap::iterator it = m_animationsToProcess.find(animationName); + if (it != m_animationsToProcess.end()) { + AnimationProcessingAction& processingInfo = it->second; + // If an animation is scheduled to be removed, don't change the remove to a pause. + if (processingInfo.action != Remove) + processingInfo.action = Pause; + } else + m_animationsToProcess.add(animationName, AnimationProcessingAction(Pause, timeOffset)); + noteLayerPropertyChanged(AnimationChanged); } -void GraphicsLayerCA::removeAnimationsForKeyframes(const String& animationName) +void GraphicsLayerCA::removeAnimation(const String& animationName) { if (!animationIsRunning(animationName)) return; - m_keyframeAnimationsToProcess.add(animationName, AnimationProcessingAction(Remove)); + m_animationsToProcess.add(animationName, AnimationProcessingAction(Remove)); noteLayerPropertyChanged(AnimationChanged); } -void GraphicsLayerCA::pauseAnimation(const String& keyframesName, double timeOffset) +void GraphicsLayerCA::animationDidStart(CAAnimation* caAnimation) { - if (!animationIsRunning(keyframesName)) - return; + bool hadNonZeroBeginTime = [[caAnimation valueForKey:WebKitAnimationBeginTimeSetKey] boolValue]; - AnimationsToProcessMap::iterator it = m_keyframeAnimationsToProcess.find(keyframesName); - if (it != m_keyframeAnimationsToProcess.end()) { - AnimationProcessingAction& processingInfo = it->second; - // If an animation is scheduled to be removed, don't change the remove to a pause. - if (processingInfo.action != Remove) - processingInfo.action = Pause; + double startTime; + if (hadNonZeroBeginTime) { + // We don't know what time CA used to commit the animation, so just use the current time + // (even though this will be slightly off). + startTime = WebCore::mediaTimeToCurrentTime(CACurrentMediaTime()); } else - m_keyframeAnimationsToProcess.add(keyframesName, AnimationProcessingAction(Pause, timeOffset)); + startTime = WebCore::mediaTimeToCurrentTime([caAnimation beginTime]); - noteLayerPropertyChanged(AnimationChanged); + if (m_client) + m_client->notifyAnimationStarted(this, startTime); } void GraphicsLayerCA::setContentsToImage(Image* image) @@ -1496,68 +1494,49 @@ CALayer *GraphicsLayerCA::replicatedLayerRoot(ReplicaState& replicaState) void GraphicsLayerCA::updateLayerAnimations() { - if (m_transitionPropertiesToRemove.size()) { - HashSet<int>::const_iterator end = m_transitionPropertiesToRemove.end(); - for (HashSet<AnimatedProperty>::const_iterator it = m_transitionPropertiesToRemove.begin(); it != end; ++it) { - AnimatedPropertyID currProperty = static_cast<AnimatedPropertyID>(*it); - // Remove all animations with this property in the key. - for (int index = 0; ; ++index) { - if (!removeAnimationFromLayer(currProperty, "", index)) - break; - } - } - - m_transitionPropertiesToRemove.clear(); - } - - if (m_keyframeAnimationsToProcess.size()) { - AnimationsToProcessMap::const_iterator end = m_keyframeAnimationsToProcess.end(); - for (AnimationsToProcessMap::const_iterator it = m_keyframeAnimationsToProcess.begin(); it != end; ++it) { - const String& currKeyframeName = it->first; - KeyframeAnimationsMap::iterator animationIt = m_runningKeyframeAnimations.find(currKeyframeName); - if (animationIt == m_runningKeyframeAnimations.end()) + if (m_animationsToProcess.size()) { + AnimationsToProcessMap::const_iterator end = m_animationsToProcess.end(); + for (AnimationsToProcessMap::const_iterator it = m_animationsToProcess.begin(); it != end; ++it) { + const String& currAnimationName = it->first; + AnimationsMap::iterator animationIt = m_runningAnimations.find(currAnimationName); + if (animationIt == m_runningAnimations.end()) continue; const AnimationProcessingAction& processingInfo = it->second; - const Vector<AnimationPair>& animations = animationIt->second; + const Vector<LayerPropertyAnimation>& animations = animationIt->second; for (size_t i = 0; i < animations.size(); ++i) { - const AnimationPair& currPair = animations[i]; + const LayerPropertyAnimation& currAnimation = animations[i]; switch (processingInfo.action) { case Remove: - removeAnimationFromLayer(static_cast<AnimatedPropertyID>(currPair.first), currKeyframeName, currPair.second); + removeCAAnimationFromLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index); break; case Pause: - pauseAnimationOnLayer(static_cast<AnimatedPropertyID>(currPair.first), currKeyframeName, currPair.second, processingInfo.timeOffset); + pauseCAAnimationOnLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index, processingInfo.timeOffset); break; } } if (processingInfo.action == Remove) - m_runningKeyframeAnimations.remove(currKeyframeName); + m_runningAnimations.remove(currAnimationName); } - m_keyframeAnimationsToProcess.clear(); + m_animationsToProcess.clear(); } size_t numAnimations; if ((numAnimations = m_uncomittedAnimations.size())) { for (size_t i = 0; i < numAnimations; ++i) { - const LayerAnimation& pendingAnimation = m_uncomittedAnimations[i]; - setAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_keyframesName, pendingAnimation.m_index, pendingAnimation.m_timeOffset); + const LayerPropertyAnimation& pendingAnimation = m_uncomittedAnimations[i]; + setCAAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_name, pendingAnimation.m_index, pendingAnimation.m_timeOffset); - if (!pendingAnimation.m_keyframesName.isEmpty()) { - // If this is a keyframe anim, we have to remember the association of keyframes name to property/index pairs, - // so we can remove the animations later if needed. - // For transitions, we can just generate animation names with property and index. - KeyframeAnimationsMap::iterator it = m_runningKeyframeAnimations.find(pendingAnimation.m_keyframesName); - if (it == m_runningKeyframeAnimations.end()) { - Vector<AnimationPair> firstPair; - firstPair.append(AnimationPair(pendingAnimation.m_property, pendingAnimation.m_index)); - m_runningKeyframeAnimations.add(pendingAnimation.m_keyframesName, firstPair); - } else { - Vector<AnimationPair>& animPairs = it->second; - animPairs.append(AnimationPair(pendingAnimation.m_property, pendingAnimation.m_index)); - } + AnimationsMap::iterator it = m_runningAnimations.find(pendingAnimation.m_name); + if (it == m_runningAnimations.end()) { + Vector<LayerPropertyAnimation> animations; + animations.append(pendingAnimation); + m_runningAnimations.add(pendingAnimation.m_name, animations); + } else { + Vector<LayerPropertyAnimation>& animations = it->second; + animations.append(pendingAnimation); } } @@ -1565,16 +1544,19 @@ void GraphicsLayerCA::updateLayerAnimations() } } -void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedPropertyID property, const String& keyframesName, int index, double timeOffset) +void GraphicsLayerCA::setCAAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedPropertyID property, const String& animationName, int index, double timeOffset) { PlatformLayer* layer = animatedLayer(property); - [caAnim setTimeOffset:timeOffset]; - - String animationName = animationIdentifier(property, keyframesName, index); - - [layer removeAnimationForKey:animationName]; - [layer addAnimation:caAnim forKey:animationName]; + if (timeOffset) { + [caAnim setBeginTime:CACurrentMediaTime() - timeOffset]; + [caAnim setValue:[NSNumber numberWithBool:YES] forKey:WebKitAnimationBeginTimeSetKey]; + } + + NSString *animationID = animationIdentifier(animationName, property, index); + + [layer removeAnimationForKey:animationID]; + [layer addAnimation:caAnim forKey:animationID]; if (LayerMap* layerCloneMap = animatedLayerClones(property)) { LayerMap::const_iterator end = layerCloneMap->end(); @@ -1583,8 +1565,8 @@ void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedP if (m_replicaLayer && isReplicatedRootClone(it->first)) continue; CALayer *currLayer = it->second.get(); - [currLayer removeAnimationForKey:animationName]; - [currLayer addAnimation:caAnim forKey:animationName]; + [currLayer removeAnimationForKey:animationID]; + [currLayer addAnimation:caAnim forKey:animationID]; } } } @@ -1604,16 +1586,16 @@ static void bug7311367Workaround(CALayer* transformLayer, const TransformationMa [transformLayer setTransform:caTransform]; } -bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, const String& keyframesName, int index) +bool GraphicsLayerCA::removeCAAnimationFromLayer(AnimatedPropertyID property, const String& animationName, int index) { PlatformLayer* layer = animatedLayer(property); - String animationName = animationIdentifier(property, keyframesName, index); + NSString *animationID = animationIdentifier(animationName, property, index); - if (![layer animationForKey:animationName]) + if (![layer animationForKey:animationID]) return false; - [layer removeAnimationForKey:animationName]; + [layer removeAnimationForKey:animationID]; bug7311367Workaround(m_structuralLayer.get(), m_transform); if (LayerMap* layerCloneMap = animatedLayerClones(property)) { @@ -1624,7 +1606,7 @@ bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, cons continue; CALayer *currLayer = it->second.get(); - [currLayer removeAnimationForKey:animationName]; + [currLayer removeAnimationForKey:animationID]; } } return true; @@ -1644,15 +1626,18 @@ static void copyAnimationProperties(CAPropertyAnimation* from, CAPropertyAnimati #if HAVE_MODERN_QUARTZCORE [to setValueFunction:[from valueFunction]]; #endif + + if (id object = [from valueForKey:WebKitAnimationBeginTimeSetKey]) + [to setValue:object forKey:WebKitAnimationBeginTimeSetKey]; } -void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, const String& keyframesName, int index, double timeOffset) +void GraphicsLayerCA::pauseCAAnimationOnLayer(AnimatedPropertyID property, const String& animationName, int index, double timeOffset) { PlatformLayer* layer = animatedLayer(property); - String animationName = animationIdentifier(property, keyframesName, index); + NSString *animationID = animationIdentifier(animationName, property, index); - CAAnimation* caAnim = [layer animationForKey:animationName]; + CAAnimation *caAnim = [layer animationForKey:animationID]; if (!caAnim) return; @@ -1679,7 +1664,7 @@ void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, const S [pausedAnim setSpeed:0]; [pausedAnim setTimeOffset:timeOffset]; - [layer addAnimation:pausedAnim forKey:animationName]; // This will replace the running animation. + [layer addAnimation:pausedAnim forKey:animationID]; // This will replace the running animation. // Pause the animations on the clones too. if (LayerMap* layerCloneMap = animatedLayerClones(property)) { @@ -1689,7 +1674,7 @@ void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, const S if (m_replicaLayer && isReplicatedRootClone(it->first)) continue; CALayer *currLayer = it->second.get(); - [currLayer addAnimation:pausedAnim forKey:animationName]; + [currLayer addAnimation:pausedAnim forKey:animationID]; } } } @@ -1726,7 +1711,7 @@ void GraphicsLayerCA::updateContentsNeedsDisplay() [m_contentsLayer.get() setNeedsDisplay]; } -bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double timeOffset) +bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset) { ASSERT(valueList.property() != AnimatedPropertyWebkitTransform); @@ -1752,14 +1737,14 @@ bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valu if (!valuesOK) return false; - m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, timeOffset)); + m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, timeOffset)); END_BLOCK_OBJC_EXCEPTIONS; return true; } -bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double timeOffset, const IntSize& boxSize) +bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset, const IntSize& boxSize) { ASSERT(valueList.property() == AnimatedPropertyWebkitTransform); @@ -1810,7 +1795,7 @@ bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValue if (!validMatrices) break; - m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, timeOffset)); + m_uncomittedAnimations.append(LayerPropertyAnimation(caAnimation, animationName, valueList.property(), animationIndex, timeOffset)); } END_BLOCK_OBJC_EXCEPTIONS; @@ -1844,7 +1829,7 @@ void GraphicsLayerCA::setupAnimation(CAPropertyAnimation* propertyAnim, const An else if (anim->direction() == Animation::AnimationDirectionAlternate) repeatCount /= 2; - NSString* fillMode = 0; + NSString *fillMode = 0; switch (anim->fillMode()) { case AnimationFillModeNone: fillMode = kCAFillModeForwards; // Use "forwards" rather than "removed" because the style system will remove the animation when it is finished. This avoids a flash. @@ -1983,7 +1968,7 @@ bool GraphicsLayerCA::setTransformAnimationEndpoints(const KeyframeValueList& va [basicAnim setToValue:toValue]; #if HAVE_MODERN_QUARTZCORE - if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(transformOp)) + if (NSString *valueFunctionName = getValueFunctionNameForTransformOperation(transformOp)) [basicAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]]; #endif @@ -2028,7 +2013,7 @@ bool GraphicsLayerCA::setTransformAnimationKeyframes(const KeyframeValueList& va [keyframeAnim setTimingFunctions:timingFunctions.get()]; #if HAVE_MODERN_QUARTZCORE - if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(transformOpType)) + if (NSString *valueFunctionName = getValueFunctionNameForTransformOperation(transformOpType)) [keyframeAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]]; #endif return true; @@ -2045,7 +2030,7 @@ void GraphicsLayerCA::suspendAnimations(double time) LayerMap::const_iterator end = layerCloneMap->end(); for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { CALayer *currLayer = it->second.get(); - [currLayer setSpeed:0 ]; + [currLayer setSpeed:0]; [currLayer setTimeOffset:t]; } } diff --git a/WebCore/platform/graphics/mac/ImageMac.mm b/WebCore/platform/graphics/mac/ImageMac.mm index 96b93be..6ad3080 100644 --- a/WebCore/platform/graphics/mac/ImageMac.mm +++ b/WebCore/platform/graphics/mac/ImageMac.mm @@ -27,7 +27,6 @@ #import "BitmapImage.h" #import "FloatRect.h" -#import "FoundationExtras.h" #import "GraphicsContext.h" #import "PlatformString.h" #import "SharedBuffer.h" diff --git a/WebCore/platform/graphics/qt/ContextShadowQt.cpp b/WebCore/platform/graphics/qt/ContextShadowQt.cpp new file mode 100644 index 0000000..342e027 --- /dev/null +++ b/WebCore/platform/graphics/qt/ContextShadowQt.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2010 Sencha, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ContextShadow.h" + +#include <QPainter> +#include <QTimerEvent> + +namespace WebCore { + +// ContextShadow needs a scratch image as the buffer for the blur filter. +// Instead of creating and destroying the buffer for every operation, +// we create a buffer which will be automatically purged via a timer. + +class ShadowBuffer: public QObject { +public: + ShadowBuffer(QObject* parent = 0); + + QImage* scratchImage(const QSize& size); + + void schedulePurge(); + +protected: + void timerEvent(QTimerEvent* event); + +private: + QImage image; + int timerId; +}; + +ShadowBuffer::ShadowBuffer(QObject* parent) + : QObject(parent) + , timerId(0) +{ +} + +QImage* ShadowBuffer::scratchImage(const QSize& size) +{ + int width = size.width(); + int height = size.height(); + + // We do not need to recreate the buffer if the buffer is reasonably + // larger than the requested size. However, if the requested size is + // much smaller than our buffer, reduce our buffer so that we will not + // keep too many allocated pixels for too long. + if (!image.isNull() && (image.width() > width) && (image.height() > height)) + if (((2 * width) > image.width()) && ((2 * height) > image.height())) { + image.fill(Qt::transparent); + return ℑ + } + + // Round to the nearest 32 pixels so we do not grow the buffer everytime + // there is larger request by 1 pixel. + width = (1 + (width >> 5)) << 5; + height = (1 + (height >> 5)) << 5; + + image = QImage(width, height, QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::transparent); + return ℑ +} + +void ShadowBuffer::schedulePurge() +{ + static const double BufferPurgeDelay = 2; // seconds + killTimer(timerId); + timerId = startTimer(BufferPurgeDelay * 1000); +} + +void ShadowBuffer::timerEvent(QTimerEvent* event) +{ + if (event->timerId() == timerId) { + killTimer(timerId); + image = QImage(); + } + QObject::timerEvent(event); +} + +Q_GLOBAL_STATIC(ShadowBuffer, scratchShadowBuffer) + +PlatformContext ContextShadow::beginShadowLayer(PlatformContext p, const FloatRect& layerArea) +{ + QRect clipRect; + if (p->hasClipping()) +#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0) + clipRect = p->clipBoundingRect().toAlignedRect(); +#else + clipRect = p->clipRegion().boundingRect(); +#endif + else + clipRect = p->transform().inverted().mapRect(p->window()); + + calculateLayerBoundingRect(layerArea, IntRect(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height())); + + // Don't paint if we are totally outside the clip region. + if (m_layerRect.isEmpty()) + return 0; + + ShadowBuffer* shadowBuffer = scratchShadowBuffer(); + QImage* shadowImage = shadowBuffer->scratchImage(m_layerRect.size()); + m_layerImage = QImage(*shadowImage); + + m_layerContext = new QPainter; + m_layerContext->begin(&m_layerImage); + m_layerContext->setFont(p->font()); + m_layerContext->translate(m_offset.width(), m_offset.height()); + + // The origin is now the top left corner of the scratch image. + m_layerContext->translate(-m_layerRect.x(), -m_layerRect.y()); + + return m_layerContext; +} + +void ContextShadow::endShadowLayer(PlatformContext p) +{ + m_layerContext->end(); + delete m_layerContext; + m_layerContext = 0; + + if (m_type == BlurShadow) { + blurLayerImage(m_layerImage.bits(), IntSize(m_layerImage.width(), m_layerImage.height()), + m_layerImage.bytesPerLine()); + + // "Colorize" with the right shadow color. + QPainter p(&m_layerImage); + p.setCompositionMode(QPainter::CompositionMode_SourceIn); + p.fillRect(m_layerImage.rect(), m_color.rgb()); + p.end(); + } + + p->drawImage(m_layerRect.topLeft(), m_layerImage); + scratchShadowBuffer()->schedulePurge(); +} + +} diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp index 2b246de..e7566eb 100644 --- a/WebCore/platform/graphics/qt/FontQt.cpp +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -125,37 +125,38 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float ContextShadow* ctxShadow = ctx->contextShadow(); - if (ctxShadow->type != ContextShadow::NoShadow) { + if (ctxShadow->m_type != ContextShadow::NoShadow) { qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0; - if (ctxShadow->offset.x() > 0) - dx2 = ctxShadow->offset.x(); + if (ctxShadow->offset().x() > 0) + dx2 = ctxShadow->offset().x(); else - dx1 = -ctxShadow->offset.x(); - if (ctxShadow->offset.y() > 0) - dy2 = ctxShadow->offset.y(); + dx1 = -ctxShadow->offset().x(); + if (ctxShadow->offset().y() > 0) + dy2 = ctxShadow->offset().y(); else - dy1 = -ctxShadow->offset.y(); + dy1 = -ctxShadow->offset().y(); // expand the clip rect to include the text shadow as well clip.adjust(dx1, dx2, dy1, dy2); - clip.adjust(-ctxShadow->blurRadius, -ctxShadow->blurRadius, ctxShadow->blurRadius, ctxShadow->blurRadius); + clip.adjust(-ctxShadow->m_blurRadius, -ctxShadow->m_blurRadius, ctxShadow->m_blurRadius, ctxShadow->m_blurRadius); } p->save(); p->setClipRect(clip.toRect(), Qt::IntersectClip); pt.setY(pt.y() - ascent); - if (ctxShadow->type != ContextShadow::NoShadow) { + if (ctxShadow->m_type != ContextShadow::NoShadow) { ContextShadow* ctxShadow = ctx->contextShadow(); - if (ctxShadow->type != ContextShadow::BlurShadow) { + if (ctxShadow->m_type != ContextShadow::BlurShadow) { p->save(); - p->setPen(ctxShadow->color); - p->translate(ctxShadow->offset); + p->setPen(ctxShadow->m_color); + p->translate(ctxShadow->offset()); line.draw(p, pt); p->restore(); } else { QPainter* shadowPainter = ctxShadow->beginShadowLayer(p, boundingRect); if (shadowPainter) { // Since it will be blurred anyway, we don't care about render hints. - shadowPainter->setPen(ctxShadow->color); + shadowPainter->setFont(p->font()); + shadowPainter->setPen(ctxShadow->m_color); line.draw(shadowPainter, pt); ctxShadow->endShadowLayer(p); } @@ -181,12 +182,12 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float if (!isComplexText && !(ctx->textDrawingMode() & cTextStroke)) flags |= Qt::TextBypassShaping; #endif - if (ctx->contextShadow()->type != ContextShadow::NoShadow) { + if (ctx->contextShadow()->m_type != ContextShadow::NoShadow) { ContextShadow* ctxShadow = ctx->contextShadow(); - if (ctxShadow->type != ContextShadow::BlurShadow) { + if (ctxShadow->m_type != ContextShadow::BlurShadow) { p->save(); - p->setPen(ctxShadow->color); - p->translate(ctxShadow->offset); + p->setPen(ctxShadow->m_color); + p->translate(ctxShadow->offset()); p->drawText(pt, string, flags, run.padding()); p->restore(); } else { @@ -196,7 +197,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float if (shadowPainter) { // Since it will be blurred anyway, we don't care about render hints. shadowPainter->setFont(p->font()); - shadowPainter->setPen(ctxShadow->color); + shadowPainter->setPen(ctxShadow->m_color); shadowPainter->drawText(pt, string, flags, run.padding()); ctxShadow->endShadowLayer(p); } @@ -205,12 +206,13 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float if (ctx->textDrawingMode() & cTextStroke) { QPainterPath path; path.addText(pt, font, string); - p->setPen(textStrokePen); - p->strokePath(path, p->pen()); + p->strokePath(path, textStrokePen); } if (ctx->textDrawingMode() & cTextFill) { + QPen previousPen = p->pen(); p->setPen(textFillPen); p->drawText(pt, string, flags, run.padding()); + p->setPen(previousPen); } } diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index 5a29ad4..7e4af40 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -201,7 +201,7 @@ public: bool hasShadow() const { - return shadow.type != ContextShadow::NoShadow; + return shadow.m_type != ContextShadow::NoShadow; } QRectF clipBoundingRect() const @@ -440,9 +440,9 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp if (m_data->hasShadow()) { p->save(); - p->translate(m_data->shadow.offset); + p->translate(m_data->shadow.offset()); QPen pen(p->pen()); - pen.setColor(m_data->shadow.color); + pen.setColor(m_data->shadow.m_color); p->setPen(pen); p->drawArc(rect, startAngle, angleSpan); p->restore(); @@ -470,12 +470,12 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points p->setRenderHint(QPainter::Antialiasing, shouldAntialias); if (m_data->hasShadow()) { p->save(); - p->translate(m_data->shadow.offset); + p->translate(m_data->shadow.offset()); if (p->brush().style() != Qt::NoBrush) - p->setBrush(QBrush(m_data->shadow.color)); + p->setBrush(QBrush(m_data->shadow.m_color)); QPen pen(p->pen()); if (pen.style() != Qt::NoPen) { - pen.setColor(m_data->shadow.color); + pen.setColor(m_data->shadow.m_color); p->setPen(pen); } p->drawConvexPolygon(polygon); @@ -519,9 +519,9 @@ void GraphicsContext::fillPath() path.setFillRule(toQtFillRule(fillRule())); if (m_data->hasShadow()) { - p->translate(m_data->shadow.offset); - p->fillPath(path, m_data->shadow.color); - p->translate(-m_data->shadow.offset); + p->translate(m_data->shadow.offset()); + p->fillPath(path, QColor(m_data->shadow.m_color)); + p->translate(-m_data->shadow.offset()); } if (m_common->state.fillPattern) { AffineTransform affine; @@ -547,11 +547,11 @@ void GraphicsContext::strokePath() path.setFillRule(toQtFillRule(fillRule())); if (m_data->hasShadow()) { - p->translate(m_data->shadow.offset); + p->translate(m_data->shadow.offset()); QPen shadowPen(pen); - shadowPen.setColor(m_data->shadow.color); + shadowPen.setColor(m_data->shadow.m_color); p->strokePath(path, shadowPen); - p->translate(-m_data->shadow.offset); + p->translate(-m_data->shadow.offset()); } if (m_common->state.strokePattern) { AffineTransform affine; @@ -653,7 +653,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) if (shadowPainter) { drawRepeatPattern(shadowPainter, image, normalizedRect, m_common->state.fillPattern->repeatX(), m_common->state.fillPattern->repeatY()); shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn); - shadowPainter->fillRect(normalizedRect, shadow->color); + shadowPainter->fillRect(normalizedRect, shadow->m_color); shadow->endShadowLayer(p); } drawRepeatPattern(p, image, normalizedRect, m_common->state.fillPattern->repeatX(), m_common->state.fillPattern->repeatY()); @@ -664,13 +664,13 @@ void GraphicsContext::fillRect(const FloatRect& rect) if (shadowPainter) { shadowPainter->fillRect(normalizedRect, brush); shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn); - shadowPainter->fillRect(normalizedRect, shadow->color); + shadowPainter->fillRect(normalizedRect, shadow->m_color); shadow->endShadowLayer(p); } p->fillRect(normalizedRect, brush); } else { if (m_data->hasShadow()) { - if (shadow->type == ContextShadow::BlurShadow) { + if (shadow->m_type == ContextShadow::BlurShadow) { QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect); if (shadowPainter) { shadowPainter->fillRect(normalizedRect, p->brush()); @@ -679,9 +679,9 @@ void GraphicsContext::fillRect(const FloatRect& rect) } else { // Solid rectangle fill with no blur shadow can be done faster // without using the shadow layer at all. - QColor shadowColor = shadow->color; + QColor shadowColor = shadow->m_color; shadowColor.setAlphaF(shadowColor.alphaF() * p->brush().color().alphaF()); - p->fillRect(normalizedRect.translated(shadow->offset), shadowColor); + p->fillRect(normalizedRect.translated(shadow->offset()), shadowColor); } } p->fillRect(normalizedRect, p->brush()); @@ -701,14 +701,14 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS if (m_data->hasShadow()) { ContextShadow* shadow = contextShadow(); - if (shadow->type != ContextShadow::BlurShadow) { + if (shadow->m_type != ContextShadow::BlurShadow) { // We do not need any layer for simple shadow. - p->fillRect(normalizedRect.translated(shadow->offset), shadow->color); + p->fillRect(normalizedRect.translated(shadow->offset()), shadow->m_color); } else { QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect); if (shadowPainter) { shadowPainter->setCompositionMode(QPainter::CompositionMode_Source); - shadowPainter->fillRect(normalizedRect, shadow->color); + shadowPainter->fillRect(normalizedRect, shadow->m_color); shadow->endShadowLayer(p); } } @@ -725,9 +725,9 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef Path path = Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight); QPainter* p = m_data->p(); if (m_data->hasShadow()) { - p->translate(m_data->shadow.offset); - p->fillPath(path.platformPath(), m_data->shadow.color); - p->translate(-m_data->shadow.offset); + p->translate(m_data->shadow.offset()); + p->fillPath(path.platformPath(), QColor(m_data->shadow.m_color)); + p->translate(-m_data->shadow.offset()); } p->fillPath(path.platformPath(), QColor(color)); } @@ -884,9 +884,9 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const // Meaning that this graphics context is associated with a CanvasRenderingContext // We flip the height since CG and HTML5 Canvas have opposite Y axis m_common->state.shadowOffset = FloatSize(size.width(), -size.height()); - m_data->shadow = ContextShadow(color, blur, size.width(), -size.height()); + m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height())); } else { - m_data->shadow = ContextShadow(color, blur, size.width(), size.height()); + m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height())); } } @@ -1002,7 +1002,7 @@ void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) pattern.append(dashes[i % dashLength] / penWidth); pen.setDashPattern(pattern); - pen.setDashOffset(dashOffset); + pen.setDashOffset(dashOffset / penWidth); } else pen.setStyle(Qt::SolidLine); p->setPen(pen); diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp index 08eb816..b881036 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp @@ -51,7 +51,7 @@ using namespace Phonon; #define LOG_MEDIAOBJECT() (LOG(Media, "%s", debugMediaObject(this, *m_mediaObject).constData())) #if !LOG_DISABLED -static QByteArray debugMediaObject(WebCore::MediaPlayerPrivate* mediaPlayer, const MediaObject& mediaObject) +static QByteArray debugMediaObject(WebCore::MediaPlayerPrivatePhonon* mediaPlayer, const MediaObject& mediaObject) { QByteArray byteArray; QTextStream stream(&byteArray); @@ -84,7 +84,7 @@ using namespace WTF; namespace WebCore { -MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) +MediaPlayerPrivatePhonon::MediaPlayerPrivatePhonon(MediaPlayer* player) : m_player(player) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::HaveNothing) @@ -118,19 +118,19 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) connect(m_mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64))); } -MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player) +MediaPlayerPrivateInterface* MediaPlayerPrivatePhonon::create(MediaPlayer* player) { - return new MediaPlayerPrivate(player); + return new MediaPlayerPrivatePhonon(player); } -void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) +void MediaPlayerPrivatePhonon::registerMediaEngine(MediaEngineRegistrar registrar) { if (isAvailable()) registrar(create, getSupportedTypes, supportsType); } -MediaPlayerPrivate::~MediaPlayerPrivate() +MediaPlayerPrivatePhonon::~MediaPlayerPrivatePhonon() { LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting videowidget"); m_videoWidget->close(); @@ -146,7 +146,7 @@ MediaPlayerPrivate::~MediaPlayerPrivate() m_mediaObject = 0; } -HashSet<String>& MediaPlayerPrivate::supportedTypesCache() +HashSet<String>& MediaPlayerPrivatePhonon::supportedTypesCache() { static HashSet<String> supportedTypes; if (!supportedTypes.isEmpty()) @@ -190,12 +190,12 @@ HashSet<String>& MediaPlayerPrivate::supportedTypesCache() return supportedTypes; } -void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types) +void MediaPlayerPrivatePhonon::getSupportedTypes(HashSet<String>& types) { types = supportedTypesCache(); } -MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs) +MediaPlayer::SupportsType MediaPlayerPrivatePhonon::supportsType(const String& type, const String& codecs) { if (type.isEmpty()) return MediaPlayer::IsNotSupported; @@ -205,14 +205,14 @@ MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, c return MediaPlayer::IsNotSupported; } -bool MediaPlayerPrivate::hasVideo() const +bool MediaPlayerPrivatePhonon::hasVideo() const { bool hasVideo = m_mediaObject->hasVideo(); LOG(Media, "MediaPlayerPrivatePhonon::hasVideo() -> %s", hasVideo ? "true" : "false"); return hasVideo; } -bool MediaPlayerPrivate::hasAudio() const +bool MediaPlayerPrivatePhonon::hasAudio() const { // FIXME: Phonon::MediaObject does not have such a hasAudio() function bool hasAudio = true; @@ -220,7 +220,7 @@ bool MediaPlayerPrivate::hasAudio() const return hasAudio; } -void MediaPlayerPrivate::load(const String& url) +void MediaPlayerPrivatePhonon::load(const String& url) { LOG(Media, "MediaPlayerPrivatePhonon::load(\"%s\")", url.utf8().data()); @@ -241,33 +241,33 @@ void MediaPlayerPrivate::load(const String& url) setVisible(m_player->visible()); } -void MediaPlayerPrivate::cancelLoad() +void MediaPlayerPrivatePhonon::cancelLoad() { notImplemented(); } -void MediaPlayerPrivate::play() +void MediaPlayerPrivatePhonon::play() { LOG(Media, "MediaPlayerPrivatePhonon::play()"); m_mediaObject->play(); } -void MediaPlayerPrivate::pause() +void MediaPlayerPrivatePhonon::pause() { LOG(Media, "MediaPlayerPrivatePhonon::pause()"); m_mediaObject->pause(); } -bool MediaPlayerPrivate::paused() const +bool MediaPlayerPrivatePhonon::paused() const { bool paused = m_mediaObject->state() == Phonon::PausedState; LOG(Media, "MediaPlayerPrivatePhonon::paused() --> %s", paused ? "true" : "false"); return paused; } -void MediaPlayerPrivate::seek(float position) +void MediaPlayerPrivatePhonon::seek(float position) { LOG(Media, "MediaPlayerPrivatePhonon::seek(%f)", position); @@ -280,12 +280,12 @@ void MediaPlayerPrivate::seek(float position) m_mediaObject->seek(position * 1000.0f); } -bool MediaPlayerPrivate::seeking() const +bool MediaPlayerPrivatePhonon::seeking() const { return false; } -float MediaPlayerPrivate::duration() const +float MediaPlayerPrivatePhonon::duration() const { if (m_readyState < MediaPlayer::HaveMetadata) return 0.0f; @@ -299,7 +299,7 @@ float MediaPlayerPrivate::duration() const return duration; } -float MediaPlayerPrivate::currentTime() const +float MediaPlayerPrivatePhonon::currentTime() const { float currentTime = m_mediaObject->currentTime() / 1000.0f; @@ -307,48 +307,48 @@ float MediaPlayerPrivate::currentTime() const return currentTime; } -PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const +PassRefPtr<TimeRanges> MediaPlayerPrivatePhonon::buffered() const { notImplemented(); return TimeRanges::create(); } -float MediaPlayerPrivate::maxTimeSeekable() const +float MediaPlayerPrivatePhonon::maxTimeSeekable() const { notImplemented(); return 0.0f; } -unsigned MediaPlayerPrivate::bytesLoaded() const +unsigned MediaPlayerPrivatePhonon::bytesLoaded() const { notImplemented(); return 0; } -unsigned MediaPlayerPrivate::totalBytes() const +unsigned MediaPlayerPrivatePhonon::totalBytes() const { //notImplemented(); return 0; } -void MediaPlayerPrivate::setRate(float) +void MediaPlayerPrivatePhonon::setRate(float) { notImplemented(); } -void MediaPlayerPrivate::setVolume(float volume) +void MediaPlayerPrivatePhonon::setVolume(float volume) { LOG(Media, "MediaPlayerPrivatePhonon::setVolume()"); m_audioOutput->setVolume(volume); } -void MediaPlayerPrivate::setMuted(bool muted) +void MediaPlayerPrivatePhonon::setMuted(bool muted) { LOG(Media, "MediaPlayerPrivatePhonon::setMuted()"); m_audioOutput->setMuted(muted); } -MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const +MediaPlayer::NetworkState MediaPlayerPrivatePhonon::networkState() const { const QMetaObject* metaObj = this->metaObject(); QMetaEnum networkStates = metaObj->enumerator(metaObj->indexOfEnumerator("NetworkState")); @@ -356,7 +356,7 @@ MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const return m_networkState; } -MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const +MediaPlayer::ReadyState MediaPlayerPrivatePhonon::readyState() const { const QMetaObject* metaObj = this->metaObject(); QMetaEnum readyStates = metaObj->enumerator(metaObj->indexOfEnumerator("ReadyState")); @@ -364,7 +364,7 @@ MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const return m_readyState; } -void MediaPlayerPrivate::updateStates() +void MediaPlayerPrivatePhonon::updateStates() { MediaPlayer::NetworkState oldNetworkState = m_networkState; MediaPlayer::ReadyState oldReadyState = m_readyState; @@ -412,7 +412,7 @@ void MediaPlayerPrivate::updateStates() } } -void MediaPlayerPrivate::setVisible(bool visible) +void MediaPlayerPrivatePhonon::setVisible(bool visible) { m_isVisible = visible; LOG(Media, "MediaPlayerPrivatePhonon::setVisible(%s)", visible ? "true" : "false"); @@ -420,7 +420,7 @@ void MediaPlayerPrivate::setVisible(bool visible) m_videoWidget->setVisible(m_isVisible); } -void MediaPlayerPrivate::setSize(const IntSize& newSize) +void MediaPlayerPrivatePhonon::setSize(const IntSize& newSize) { if (!m_videoWidget) return; @@ -434,7 +434,7 @@ void MediaPlayerPrivate::setSize(const IntSize& newSize) m_videoWidget->resize(newSize.width(), newSize.height()); } -IntSize MediaPlayerPrivate::naturalSize() const +IntSize MediaPlayerPrivatePhonon::naturalSize() const { if (!hasVideo()) { LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d", @@ -455,7 +455,7 @@ IntSize MediaPlayerPrivate::naturalSize() const return naturalSize; } -bool MediaPlayerPrivate::eventFilter(QObject* obj, QEvent* event) +bool MediaPlayerPrivatePhonon::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::UpdateRequest) m_player->repaint(); @@ -463,7 +463,7 @@ bool MediaPlayerPrivate::eventFilter(QObject* obj, QEvent* event) return QObject::eventFilter(obj, event); } -void MediaPlayerPrivate::paint(GraphicsContext* graphicsContect, const IntRect& rect) +void MediaPlayerPrivatePhonon::paint(GraphicsContext* graphicsContect, const IntRect& rect) { if (graphicsContect->paintingDisabled()) return; @@ -481,7 +481,7 @@ void MediaPlayerPrivate::paint(GraphicsContext* graphicsContect, const IntRect& // ====================== Phonon::MediaObject signals ====================== -void MediaPlayerPrivate::stateChanged(Phonon::State newState, Phonon::State oldState) +void MediaPlayerPrivatePhonon::stateChanged(Phonon::State newState, Phonon::State oldState) { const QMetaObject* metaObj = this->metaObject(); QMetaEnum phononStates = metaObj->enumerator(metaObj->indexOfEnumerator("PhononState")); @@ -491,48 +491,48 @@ void MediaPlayerPrivate::stateChanged(Phonon::State newState, Phonon::State oldS updateStates(); } -void MediaPlayerPrivate::metaDataChanged() +void MediaPlayerPrivatePhonon::metaDataChanged() { LOG(Media, "MediaPlayerPrivatePhonon::metaDataChanged()"); LOG_MEDIAOBJECT(); } -void MediaPlayerPrivate::seekableChanged(bool) +void MediaPlayerPrivatePhonon::seekableChanged(bool) { notImplemented(); LOG_MEDIAOBJECT(); } -void MediaPlayerPrivate::hasVideoChanged(bool hasVideo) +void MediaPlayerPrivatePhonon::hasVideoChanged(bool hasVideo) { LOG(Media, "MediaPlayerPrivatePhonon::hasVideoChanged(%s)", hasVideo ? "true" : "false"); } -void MediaPlayerPrivate::bufferStatus(int) +void MediaPlayerPrivatePhonon::bufferStatus(int) { notImplemented(); LOG_MEDIAOBJECT(); } -void MediaPlayerPrivate::finished() +void MediaPlayerPrivatePhonon::finished() { notImplemented(); LOG_MEDIAOBJECT(); } -void MediaPlayerPrivate::currentSourceChanged(const Phonon::MediaSource&) +void MediaPlayerPrivatePhonon::currentSourceChanged(const Phonon::MediaSource&) { notImplemented(); LOG_MEDIAOBJECT(); } -void MediaPlayerPrivate::aboutToFinish() +void MediaPlayerPrivatePhonon::aboutToFinish() { notImplemented(); LOG_MEDIAOBJECT(); } -void MediaPlayerPrivate::totalTimeChanged(qint64 totalTime) +void MediaPlayerPrivatePhonon::totalTimeChanged(qint64 totalTime) { #if OS(WINDOWS) LOG(Media, "MediaPlayerPrivatePhonon::totalTimeChanged(%I64d)", totalTime); diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h index ff6a01c..d793675 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h @@ -40,13 +40,13 @@ QT_END_NAMESPACE namespace WebCore { - class MediaPlayerPrivate : public QObject, public MediaPlayerPrivateInterface { + class MediaPlayerPrivatePhonon : public QObject, public MediaPlayerPrivateInterface { Q_OBJECT public: static void registerMediaEngine(MediaEngineRegistrar); - ~MediaPlayerPrivate(); + ~MediaPlayerPrivatePhonon(); // These enums are used for debugging Q_ENUMS(ReadyState NetworkState PhononState) @@ -127,7 +127,7 @@ namespace WebCore { void totalTimeChanged(qint64); private: - MediaPlayerPrivate(MediaPlayer*); + MediaPlayerPrivatePhonon(MediaPlayer*); static MediaPlayerPrivateInterface* create(MediaPlayer* player); static void getSupportedTypes(HashSet<String>&); diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp index 1bf1a3d..1a31d1e 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp @@ -53,17 +53,17 @@ using namespace WTF; namespace WebCore { -MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player) +MediaPlayerPrivateInterface* MediaPlayerPrivateQt::create(MediaPlayer* player) { - return new MediaPlayerPrivate(player); + return new MediaPlayerPrivateQt(player); } -void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) +void MediaPlayerPrivateQt::registerMediaEngine(MediaEngineRegistrar registrar) { registrar(create, getSupportedTypes, supportsType); } -void MediaPlayerPrivate::getSupportedTypes(HashSet<String> &supported) +void MediaPlayerPrivateQt::getSupportedTypes(HashSet<String> &supported) { QStringList types = QMediaPlayer::supportedMimeTypes(); @@ -74,7 +74,7 @@ void MediaPlayerPrivate::getSupportedTypes(HashSet<String> &supported) } } -MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& mime, const String& codec) +MediaPlayer::SupportsType MediaPlayerPrivateQt::supportsType(const String& mime, const String& codec) { if (!mime.startsWith("audio/") && !mime.startsWith("video/")) return MediaPlayer::IsNotSupported; @@ -85,8 +85,8 @@ MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& mime, c return MediaPlayer::MayBeSupported; } -MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) - : m_player(player) +MediaPlayerPrivateQt::MediaPlayerPrivateQt(MediaPlayer* player) + : m_webCorePlayer(player) , m_mediaPlayer(new QMediaPlayer) , m_mediaPlayerControl(0) , m_videoItem(new QGraphicsVideoItem) @@ -132,23 +132,23 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) } } -MediaPlayerPrivate::~MediaPlayerPrivate() +MediaPlayerPrivateQt::~MediaPlayerPrivateQt() { delete m_mediaPlayer; delete m_videoScene; } -bool MediaPlayerPrivate::hasVideo() const +bool MediaPlayerPrivateQt::hasVideo() const { return m_mediaPlayer->isVideoAvailable(); } -bool MediaPlayerPrivate::hasAudio() const +bool MediaPlayerPrivateQt::hasAudio() const { return true; } -void MediaPlayerPrivate::load(const String& url) +void MediaPlayerPrivateQt::load(const String& url) { m_mediaUrl = url; @@ -162,25 +162,25 @@ void MediaPlayerPrivate::load(const String& url) commitLoad(url); } -void MediaPlayerPrivate::commitLoad(const String& url) +void MediaPlayerPrivateQt::commitLoad(const String& url) { // We are now loading if (m_networkState != MediaPlayer::Loading) { m_networkState = MediaPlayer::Loading; - m_player->networkStateChanged(); + m_webCorePlayer->networkStateChanged(); } // And we don't have any data yet if (m_readyState != MediaPlayer::HaveNothing) { m_readyState = MediaPlayer::HaveNothing; - m_player->readyStateChanged(); + m_webCorePlayer->readyStateChanged(); } const QUrl rUrl = QUrl(QString(url)); const QString scheme = rUrl.scheme().toLower(); // Grab the client media element - HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_player->mediaPlayerClient()); + HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_webCorePlayer->mediaPlayerClient()); // Construct the media content with a network request if the resource is http[s] if (scheme == "http" || scheme == "https") { @@ -236,7 +236,7 @@ void MediaPlayerPrivate::commitLoad(const String& url) m_mediaPlayer->play(); } -void MediaPlayerPrivate::resumeLoad() +void MediaPlayerPrivateQt::resumeLoad() { m_delayingLoad = false; @@ -244,36 +244,36 @@ void MediaPlayerPrivate::resumeLoad() commitLoad(m_mediaUrl); } -void MediaPlayerPrivate::cancelLoad() +void MediaPlayerPrivateQt::cancelLoad() { m_mediaPlayer->setMedia(QMediaContent()); updateStates(); } -void MediaPlayerPrivate::prepareToPlay() +void MediaPlayerPrivateQt::prepareToPlay() { if (m_mediaPlayer->media().isNull() || m_delayingLoad) resumeLoad(); } -void MediaPlayerPrivate::play() +void MediaPlayerPrivateQt::play() { if (m_mediaPlayer->state() != QMediaPlayer::PlayingState) m_mediaPlayer->play(); } -void MediaPlayerPrivate::pause() +void MediaPlayerPrivateQt::pause() { if (m_mediaPlayer->state() == QMediaPlayer::PlayingState) m_mediaPlayer->pause(); } -bool MediaPlayerPrivate::paused() const +bool MediaPlayerPrivateQt::paused() const { return (m_mediaPlayer->state() != QMediaPlayer::PlayingState); } -void MediaPlayerPrivate::seek(float position) +void MediaPlayerPrivateQt::seek(float position) { if (!m_mediaPlayer->isSeekable()) return; @@ -309,12 +309,12 @@ void MediaPlayerPrivate::seek(float position) } } -bool MediaPlayerPrivate::seeking() const +bool MediaPlayerPrivateQt::seeking() const { return m_isSeeking; } -float MediaPlayerPrivate::duration() const +float MediaPlayerPrivateQt::duration() const { if (m_readyState < MediaPlayer::HaveMetadata) return 0.0f; @@ -328,13 +328,13 @@ float MediaPlayerPrivate::duration() const return duration; } -float MediaPlayerPrivate::currentTime() const +float MediaPlayerPrivateQt::currentTime() const { float currentTime = m_mediaPlayer->position() / 1000.0f; return currentTime; } -PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const +PassRefPtr<TimeRanges> MediaPlayerPrivateQt::buffered() const { RefPtr<TimeRanges> buffered = TimeRanges::create(); @@ -352,7 +352,7 @@ PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const return buffered.release(); } -float MediaPlayerPrivate::maxTimeSeekable() const +float MediaPlayerPrivateQt::maxTimeSeekable() const { if (!m_mediaPlayerControl) return 0; @@ -360,7 +360,7 @@ float MediaPlayerPrivate::maxTimeSeekable() const return static_cast<float>(m_mediaPlayerControl->availablePlaybackRanges().latestTime()) / 1000.0f; } -unsigned MediaPlayerPrivate::bytesLoaded() const +unsigned MediaPlayerPrivateQt::bytesLoaded() const { QLatin1String bytesLoadedKey("bytes-loaded"); if (m_mediaPlayer->availableExtendedMetaData().contains(bytesLoadedKey)) @@ -369,7 +369,7 @@ unsigned MediaPlayerPrivate::bytesLoaded() const return m_mediaPlayer->bufferStatus(); } -unsigned MediaPlayerPrivate::totalBytes() const +unsigned MediaPlayerPrivateQt::totalBytes() const { if (m_mediaPlayer->availableMetaData().contains(QtMultimediaKit::Size)) return m_mediaPlayer->metaData(QtMultimediaKit::Size).toInt(); @@ -377,59 +377,59 @@ unsigned MediaPlayerPrivate::totalBytes() const return 100; } -void MediaPlayerPrivate::setPreload(MediaPlayer::Preload preload) +void MediaPlayerPrivateQt::setPreload(MediaPlayer::Preload preload) { m_preload = preload; if (m_delayingLoad && m_preload != MediaPlayer::None) resumeLoad(); } -void MediaPlayerPrivate::setRate(float rate) +void MediaPlayerPrivateQt::setRate(float rate) { m_mediaPlayer->setPlaybackRate(rate); } -void MediaPlayerPrivate::setVolume(float volume) +void MediaPlayerPrivateQt::setVolume(float volume) { m_mediaPlayer->setVolume(static_cast<int>(volume * 100.0)); } -bool MediaPlayerPrivate::supportsMuting() const +bool MediaPlayerPrivateQt::supportsMuting() const { return true; } -void MediaPlayerPrivate::setMuted(bool muted) +void MediaPlayerPrivateQt::setMuted(bool muted) { m_mediaPlayer->setMuted(muted); } -MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const +MediaPlayer::NetworkState MediaPlayerPrivateQt::networkState() const { return m_networkState; } -MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const +MediaPlayer::ReadyState MediaPlayerPrivateQt::readyState() const { return m_readyState; } -void MediaPlayerPrivate::setVisible(bool visible) +void MediaPlayerPrivateQt::setVisible(bool visible) { m_isVisible = visible; } -void MediaPlayerPrivate::mediaStatusChanged(QMediaPlayer::MediaStatus) +void MediaPlayerPrivateQt::mediaStatusChanged(QMediaPlayer::MediaStatus) { updateStates(); } -void MediaPlayerPrivate::handleError(QMediaPlayer::Error) +void MediaPlayerPrivateQt::handleError(QMediaPlayer::Error) { updateStates(); } -void MediaPlayerPrivate::stateChanged(QMediaPlayer::State state) +void MediaPlayerPrivateQt::stateChanged(QMediaPlayer::State state) { if (state != QMediaPlayer::PlayingState && m_isSeeking && m_queuedSeek >= 0) { m_mediaPlayer->setPosition(m_queuedSeek); @@ -437,12 +437,12 @@ void MediaPlayerPrivate::stateChanged(QMediaPlayer::State state) } } -void MediaPlayerPrivate::nativeSizeChanged(const QSizeF&) +void MediaPlayerPrivateQt::nativeSizeChanged(const QSizeF&) { - m_player->sizeChanged(); + m_webCorePlayer->sizeChanged(); } -void MediaPlayerPrivate::queuedSeekTimeout() +void MediaPlayerPrivateQt::queuedSeekTimeout() { // If we haven't heard anything, assume the player is now paused // and we can attempt the seek @@ -455,45 +455,45 @@ void MediaPlayerPrivate::queuedSeekTimeout() } } -void MediaPlayerPrivate::seekTimeout() +void MediaPlayerPrivateQt::seekTimeout() { // If we haven't heard anything, assume the seek succeeded if (m_isSeeking) { - m_player->timeChanged(); + m_webCorePlayer->timeChanged(); m_isSeeking = false; } } -void MediaPlayerPrivate::positionChanged(qint64) +void MediaPlayerPrivateQt::positionChanged(qint64) { // Only propogate this event if we are seeking if (m_isSeeking && m_queuedSeek == -1) { - m_player->timeChanged(); + m_webCorePlayer->timeChanged(); m_isSeeking = false; } } -void MediaPlayerPrivate::bufferStatusChanged(int) +void MediaPlayerPrivateQt::bufferStatusChanged(int) { notImplemented(); } -void MediaPlayerPrivate::durationChanged(qint64) +void MediaPlayerPrivateQt::durationChanged(qint64) { - m_player->durationChanged(); + m_webCorePlayer->durationChanged(); } -void MediaPlayerPrivate::volumeChanged(int volume) +void MediaPlayerPrivateQt::volumeChanged(int volume) { - m_player->volumeChanged(static_cast<float>(volume) / 100.0); + m_webCorePlayer->volumeChanged(static_cast<float>(volume) / 100.0); } -void MediaPlayerPrivate::mutedChanged(bool muted) +void MediaPlayerPrivateQt::mutedChanged(bool muted) { - m_player->muteChanged(muted); + m_webCorePlayer->muteChanged(muted); } -void MediaPlayerPrivate::updateStates() +void MediaPlayerPrivateQt::updateStates() { // Store the old states so that we can detect a change and raise change events MediaPlayer::NetworkState oldNetworkState = m_networkState; @@ -538,13 +538,13 @@ void MediaPlayerPrivate::updateStates() // Breaking this invariant will cause the resource selection algorithm for multiple // sources to fail. if (m_readyState != oldReadyState) - m_player->readyStateChanged(); + m_webCorePlayer->readyStateChanged(); if (m_networkState != oldNetworkState) - m_player->networkStateChanged(); + m_webCorePlayer->networkStateChanged(); } -void MediaPlayerPrivate::setSize(const IntSize& size) +void MediaPlayerPrivateQt::setSize(const IntSize& size) { if (size == m_currentSize) return; @@ -553,7 +553,7 @@ void MediaPlayerPrivate::setSize(const IntSize& size) m_videoItem->setSize(QSizeF(QSize(size))); } -IntSize MediaPlayerPrivate::naturalSize() const +IntSize MediaPlayerPrivateQt::naturalSize() const { if (!hasVideo() || m_readyState < MediaPlayer::HaveMetadata) return IntSize(); @@ -561,7 +561,7 @@ IntSize MediaPlayerPrivate::naturalSize() const return IntSize(m_videoItem->nativeSize().toSize()); } -void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) +void MediaPlayerPrivateQt::paint(GraphicsContext* context, const IntRect& rect) { #if USE(ACCELERATED_COMPOSITING) if (m_composited) @@ -580,15 +580,16 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) m_videoScene->render(painter, QRectF(QRect(rect)), m_videoItem->sceneBoundingRect()); } -void MediaPlayerPrivate::repaint() +void MediaPlayerPrivateQt::repaint() { - m_player->repaint(); + m_webCorePlayer->repaint(); } #if USE(ACCELERATED_COMPOSITING) -void MediaPlayerPrivate::acceleratedRenderingStateChanged() +void MediaPlayerPrivateQt::acceleratedRenderingStateChanged() { - bool composited = m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player); + MediaPlayerClient* client = m_webCorePlayer->mediaPlayerClient(); + bool composited = client->mediaPlayerRenderingCanBeAccelerated(m_webCorePlayer); if (composited == m_composited) return; @@ -599,17 +600,17 @@ void MediaPlayerPrivate::acceleratedRenderingStateChanged() m_videoScene->addItem(m_videoItem); } -PlatformLayer* MediaPlayerPrivate::platformLayer() const +PlatformLayer* MediaPlayerPrivateQt::platformLayer() const { return m_composited ? m_videoItem : 0; } #endif -PlatformMedia MediaPlayerPrivate::platformMedia() const +PlatformMedia MediaPlayerPrivateQt::platformMedia() const { PlatformMedia pm; pm.type = PlatformMedia::QtMediaPlayerType; - pm.media.qtMediaPlayer = const_cast<MediaPlayerPrivate*>(this); + pm.media.qtMediaPlayer = const_cast<MediaPlayerPrivateQt*>(this); return pm; } diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h index 117187d..179bf2a 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h @@ -33,13 +33,13 @@ QT_END_NAMESPACE namespace WebCore { -class MediaPlayerPrivate : public QObject, public MediaPlayerPrivateInterface { +class MediaPlayerPrivateQt : public QObject, public MediaPlayerPrivateInterface { Q_OBJECT public: static MediaPlayerPrivateInterface* create(MediaPlayer* player); - ~MediaPlayerPrivate(); + ~MediaPlayerPrivateQt(); static void registerMediaEngine(MediaEngineRegistrar); static void getSupportedTypes(HashSet<String>&); @@ -118,9 +118,9 @@ private: void updateStates(); private: - MediaPlayerPrivate(MediaPlayer*); + MediaPlayerPrivateQt(MediaPlayer*); - MediaPlayer* m_player; + MediaPlayer* m_webCorePlayer; QMediaPlayer* m_mediaPlayer; QMediaPlayerControl* m_mediaPlayerControl; QGraphicsVideoItem* m_videoItem; diff --git a/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp b/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp index b6d6e65..8301871 100644 --- a/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp @@ -36,7 +36,7 @@ #include "Base64.h" #include "ChromiumBridge.h" #include "OpenTypeUtilities.h" -#elif OS(LINUX) +#elif OS(LINUX) || OS(FREEBSD) #include "SkStream.h" #endif @@ -47,7 +47,7 @@ #if OS(WINDOWS) #include <objbase.h> -#elif OS(LINUX) +#elif OS(LINUX) || OS(FREEBSD) #include <cstring> #endif @@ -58,7 +58,7 @@ FontCustomPlatformData::~FontCustomPlatformData() #if OS(WINDOWS) if (m_fontReference) RemoveFontMemResourceEx(m_fontReference); -#elif OS(LINUX) +#elif OS(LINUX) || OS(FREEBSD) if (m_fontReference) m_fontReference->unref(); #endif @@ -99,7 +99,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b HFONT hfont = CreateFontIndirect(&logFont); return FontPlatformData(hfont, size); -#elif OS(LINUX) +#elif OS(LINUX) || OS(FREEBSD) ASSERT(m_fontReference); return FontPlatformData(m_fontReference, "", size, bold && !m_fontReference->isBold(), italic && !m_fontReference->isItalic()); #else @@ -123,7 +123,7 @@ static String createUniqueFontName() } #endif -#if OS(LINUX) +#if OS(LINUX) || OS(FREEBSD) class RemoteFontStream : public SkStream { public: explicit RemoteFontStream(PassRefPtr<SharedBuffer> buffer) @@ -189,7 +189,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) if (!fontReference) return 0; return new FontCustomPlatformData(fontReference, fontName); -#elif OS(LINUX) +#elif OS(LINUX) || OS(FREEBSD) RemoteFontStream* stream = new RemoteFontStream(buffer); SkTypeface* typeface = SkTypeface::CreateFromStream(stream); if (!typeface) diff --git a/WebCore/platform/graphics/skia/FontCustomPlatformData.h b/WebCore/platform/graphics/skia/FontCustomPlatformData.h index d451c9c..94d7ec3 100644 --- a/WebCore/platform/graphics/skia/FontCustomPlatformData.h +++ b/WebCore/platform/graphics/skia/FontCustomPlatformData.h @@ -39,7 +39,7 @@ #if OS(WINDOWS) #include "PlatformString.h" #include <windows.h> -#elif OS(LINUX) +#elif OS(LINUX) || OS(FREEBSD) #include "SkTypeface.h" #endif @@ -54,7 +54,7 @@ struct FontCustomPlatformData : Noncopyable { : m_fontReference(fontReference) , m_name(name) {} -#elif OS(LINUX) +#elif OS(LINUX) || OS(FREEBSD) explicit FontCustomPlatformData(SkTypeface* typeface) : m_fontReference(typeface) {} @@ -70,7 +70,7 @@ struct FontCustomPlatformData : Noncopyable { #if OS(WINDOWS) HANDLE m_fontReference; String m_name; -#elif OS(LINUX) +#elif OS(LINUX) || OS(FREEBSD) SkTypeface* m_fontReference; #endif }; diff --git a/WebCore/platform/graphics/skia/GradientSkia.cpp b/WebCore/platform/graphics/skia/GradientSkia.cpp index 66a8976..a636d10 100644 --- a/WebCore/platform/graphics/skia/GradientSkia.cpp +++ b/WebCore/platform/graphics/skia/GradientSkia.cpp @@ -42,7 +42,7 @@ namespace WebCore { void Gradient::platformDestroy() { if (m_gradient) - m_gradient->safeUnref(); + SkSafeUnref(m_gradient); m_gradient = 0; } diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index d618c19..4bc98fb 100644 --- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -338,13 +338,15 @@ void GraphicsContext::clearRect(const FloatRect& rect) if (paintingDisabled()) return; - if (platformContext()->useGPU()) { + if (platformContext()->useGPU() && !platformContext()->canvasClipApplied()) { platformContext()->prepareForHardwareDraw(); platformContext()->gpuCanvas()->clearRect(rect); return; } - platformContext()->prepareForSoftwareDraw(); + // Force a readback here (if we're using the GPU), since clearRect() is + // incompatible with mixed-mode rendering. + platformContext()->syncSoftwareCanvas(); SkRect r = rect; if (!isRectSkiaSafe(getCTM(), r)) diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp index 0b96d80..e123256 100644 --- a/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -36,7 +36,6 @@ #include "FloatConversion.h" #include "FloatRect.h" #include "GLES2Canvas.h" -#include "GLES2Context.h" #include "GraphicsContext.h" #include "Logging.h" #include "NativeImageSkia.h" @@ -144,7 +143,9 @@ static ResamplingMode computeResamplingMode(PlatformContextSkia* platformContext // Everything else gets resampled. // If the platform context permits high quality interpolation, use it. - if (platformContext->interpolationQuality() == InterpolationHigh) + // High quality interpolation only enabled for scaling and translation. + if (platformContext->interpolationQuality() == InterpolationHigh + && !(platformContext->canvas()->getTotalMatrix().getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask))) return RESAMPLE_AWESOME; return RESAMPLE_LINEAR; @@ -174,8 +175,12 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm && srcIRect.height() == bitmap.height(); // We will always draw in integer sizes, so round the destination rect. + // First we need to apply canvas transformation matrix to get desired size of + // resampled image. + SkRect destRectTransformed; + canvas.getTotalMatrix().mapRect(&destRectTransformed, destRect); SkIRect destRectRounded; - destRect.round(&destRectRounded); + destRectTransformed.round(&destRectRounded); SkIRect resizedImageRect = // Represents the size of the resized image. { 0, 0, destRectRounded.width(), destRectRounded.height() }; @@ -189,7 +194,10 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm // Compute the visible portion of our rect. SkRect destBitmapSubsetSk; ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk); - destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop); + // Determine size of resampled image based on clipped destination rect. + SkRect destBitmapSubsetSkTransformed; + canvas.getTotalMatrix().mapRect(&destBitmapSubsetSkTransformed, destBitmapSubsetSk); + destBitmapSubsetSkTransformed.offset(-destBitmapSubsetSkTransformed.fLeft, -destBitmapSubsetSkTransformed.fTop); // The matrix inverting, etc. could have introduced rounding error which // causes the bounds to be outside of the resized bitmap. We round outward @@ -197,7 +205,7 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm // need, and then clamp to the bitmap bounds so we don't get any invalid // data. SkIRect destBitmapSubsetSkI; - destBitmapSubsetSk.roundOut(&destBitmapSubsetSkI); + destBitmapSubsetSkTransformed.roundOut(&destBitmapSubsetSkI); if (!destBitmapSubsetSkI.intersect(resizedImageRect)) return; // Resized image does not intersect. diff --git a/WebCore/platform/graphics/skia/PatternSkia.cpp b/WebCore/platform/graphics/skia/PatternSkia.cpp index bd27b6a..72fac77 100644 --- a/WebCore/platform/graphics/skia/PatternSkia.cpp +++ b/WebCore/platform/graphics/skia/PatternSkia.cpp @@ -42,7 +42,7 @@ namespace WebCore { void Pattern::platformDestroy() { - m_pattern->safeUnref(); + SkSafeUnref(m_pattern); m_pattern = 0; } diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index 88fbcdd..b469312 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -162,19 +162,19 @@ PlatformContextSkia::State::State(const State& other) , m_interpolationQuality(other.m_interpolationQuality) , m_canvasClipApplied(other.m_canvasClipApplied) { - // Up the ref count of these. saveRef does nothing if 'this' is NULL. - m_looper->safeRef(); - m_dash->safeRef(); - m_fillShader->safeRef(); - m_strokeShader->safeRef(); + // Up the ref count of these. SkSafeRef does nothing if its argument is 0. + SkSafeRef(m_looper); + SkSafeRef(m_dash); + SkSafeRef(m_fillShader); + SkSafeRef(m_strokeShader); } PlatformContextSkia::State::~State() { - m_looper->safeUnref(); - m_dash->safeUnref(); - m_fillShader->safeUnref(); - m_strokeShader->safeUnref(); + SkSafeUnref(m_looper); + SkSafeUnref(m_dash); + SkSafeUnref(m_fillShader); + SkSafeUnref(m_strokeShader); } // Returns a new State with all of this object's inherited properties copied. @@ -327,7 +327,7 @@ void PlatformContextSkia::drawRect(SkRect rect) // setFillColor() will set the shader to NULL, so save a ref to it now. SkShader* oldFillShader = m_state->m_fillShader; - oldFillShader->safeRef(); + SkSafeRef(oldFillShader); setFillColor(m_state->m_strokeColor); paint.reset(); setupPaintForFilling(&paint); @@ -341,7 +341,7 @@ void PlatformContextSkia::drawRect(SkRect rect) canvas()->drawRect(rightBorder, paint); setFillColor(oldFillColor); setFillShader(oldFillShader); - oldFillShader->safeUnref(); + SkSafeUnref(oldFillShader); } } @@ -487,9 +487,9 @@ void PlatformContextSkia::setStrokeThickness(float thickness) void PlatformContextSkia::setStrokeShader(SkShader* strokeShader) { if (strokeShader != m_state->m_strokeShader) { - m_state->m_strokeShader->safeUnref(); + SkSafeUnref(m_state->m_strokeShader); m_state->m_strokeShader = strokeShader; - m_state->m_strokeShader->safeRef(); + SkSafeRef(m_state->m_strokeShader); } } @@ -561,9 +561,9 @@ void PlatformContextSkia::setFillRule(SkPath::FillType fr) void PlatformContextSkia::setFillShader(SkShader* fillShader) { if (fillShader != m_state->m_fillShader) { - m_state->m_fillShader->safeUnref(); + SkSafeUnref(m_state->m_fillShader); m_state->m_fillShader = fillShader; - m_state->m_fillShader->safeRef(); + SkSafeRef(m_state->m_fillShader); } } @@ -580,7 +580,7 @@ void PlatformContextSkia::setInterpolationQuality(InterpolationQuality interpola void PlatformContextSkia::setDashPathEffect(SkDashPathEffect* dash) { if (dash != m_state->m_dash) { - m_state->m_dash->safeUnref(); + SkSafeUnref(m_state->m_dash); m_state->m_dash = dash; } } @@ -677,6 +677,11 @@ bool PlatformContextSkia::canAccelerate() const && !m_state->m_canvasClipApplied; // Can't accelerate with a clip to path applied. } +bool PlatformContextSkia::canvasClipApplied() const +{ + return m_state->m_canvasClipApplied; +} + class WillPublishCallbackImpl : public DrawingBuffer::WillPublishCallback { public: static PassOwnPtr<WillPublishCallback> create(PlatformContextSkia* pcs) @@ -840,7 +845,7 @@ void PlatformContextSkia::readbackHardwareToSoftware() const for (int i = 0; i < width; ++i) { uint32_t pixel = pixels[i]; // Swizzles from RGBA -> BGRA. - pixels[i] = pixel & 0xFF00FF00 | ((pixel & 0x00FF0000) >> 16) | ((pixel & 0x000000FF) << 16); + pixels[i] = (pixel & 0xFF00FF00) | ((pixel & 0x00FF0000) >> 16) | ((pixel & 0x000000FF) << 16); } } } diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h index 4ba85d1..eb03224 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.h +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h @@ -180,6 +180,7 @@ public: bool hasImageResamplingHint() const; bool canAccelerate() const; + bool canvasClipApplied() const; bool useGPU() { return m_useGPU; } void setSharedGraphicsContext3D(SharedGraphicsContext3D*, DrawingBuffer*, const IntSize&); GLES2Canvas* gpuCanvas() const { return m_gpuCanvas.get(); } diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.cpp b/WebCore/platform/graphics/skia/SkiaFontWin.cpp index 9edb775..6acfd35 100644 --- a/WebCore/platform/graphics/skia/SkiaFontWin.cpp +++ b/WebCore/platform/graphics/skia/SkiaFontWin.cpp @@ -340,7 +340,7 @@ bool paintSkiaText(GraphicsContext* context, // thing would be to draw to a new layer and then draw that layer // with a shadow. But this is a lot of extra work for something // that isn't normally an issue. - paint.setLooper(0)->safeUnref(); + SkSafeUnref(paint.setLooper(0)); } if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint, diff --git a/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp b/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp index 4072a18..80e01a9 100644 --- a/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp +++ b/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp @@ -234,7 +234,6 @@ static void addArcPoints(PathPolygon& poly, const PlatformPathElement::ArcTo& da static void drawPolygons(HDC dc, const Vector<PathPolygon>& polygons, bool fill, const AffineTransform* transformation) { - MemoryAllocationCanFail canFail; for (Vector<PathPolygon>::const_iterator i = polygons.begin(); i != polygons.end(); ++i) { int npoints = i->size(); if (!npoints) diff --git a/WebCore/platform/gtk/ClipboardGtk.cpp b/WebCore/platform/gtk/ClipboardGtk.cpp index 327f069..e7ee432 100644 --- a/WebCore/platform/gtk/ClipboardGtk.cpp +++ b/WebCore/platform/gtk/ClipboardGtk.cpp @@ -37,27 +37,27 @@ namespace WebCore { -enum ClipboardType { - ClipboardTypeText, - ClipboardTypeMarkup, - ClipboardTypeURIList, - ClipboardTypeURL, - ClipboardTypeImage, - ClipboardTypeUnknown +enum ClipboardDataType { + ClipboardDataTypeText, + ClipboardDataTypeMarkup, + ClipboardDataTypeURIList, + ClipboardDataTypeURL, + ClipboardDataTypeImage, + ClipboardDataTypeUnknown }; PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy, Frame* frame) { - return ClipboardGtk::create(policy, gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD), false, frame); + return ClipboardGtk::create(policy, gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD), frame); } PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* dragData, Frame* frame) { - return ClipboardGtk::create(policy, dragData->platformData(), true, frame); + return ClipboardGtk::create(policy, dragData->platformData(), DragAndDrop, frame); } ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, GtkClipboard* clipboard, Frame* frame) - : Clipboard(policy, false) + : Clipboard(policy, CopyAndPaste) , m_dataObject(DataObjectGtk::forClipboard(clipboard)) , m_clipboard(clipboard) , m_helper(Pasteboard::generalPasteboard()->helper()) @@ -65,8 +65,8 @@ ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, GtkClipboard* clipboard { } -ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, PassRefPtr<DataObjectGtk> dataObject, bool forDragging, Frame* frame) - : Clipboard(policy, forDragging) +ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, PassRefPtr<DataObjectGtk> dataObject, ClipboardType clipboardType, Frame* frame) + : Clipboard(policy, clipboardType) , m_dataObject(dataObject) , m_clipboard(0) , m_helper(Pasteboard::generalPasteboard()->helper()) @@ -78,27 +78,27 @@ ClipboardGtk::~ClipboardGtk() { } -static ClipboardType dataObjectTypeFromHTMLClipboardType(const String& rawType) +static ClipboardDataType dataObjectTypeFromHTMLClipboardType(const String& rawType) { String type(rawType.stripWhiteSpace()); // Two special cases for IE compatibility if (type == "Text") - return ClipboardTypeText; + return ClipboardDataTypeText; if (type == "URL") - return ClipboardTypeURL; + return ClipboardDataTypeURL; // From the Mac port: Ignore any trailing charset - JS strings are // Unicode, which encapsulates the charset issue. if (type == "text/plain" || type.startsWith("text/plain;")) - return ClipboardTypeText; + return ClipboardDataTypeText; if (type == "text/html" || type.startsWith("text/html;")) - return ClipboardTypeMarkup; + return ClipboardDataTypeMarkup; if (type == "Files" || type == "text/uri-list" || type.startsWith("text/uri-list;")) - return ClipboardTypeURIList; + return ClipboardDataTypeURIList; // Not a known type, so just default to using the text portion. - return ClipboardTypeUnknown; + return ClipboardDataTypeUnknown; } void ClipboardGtk::clearData(const String& typeString) @@ -106,19 +106,19 @@ void ClipboardGtk::clearData(const String& typeString) if (policy() != ClipboardWritable) return; - ClipboardType type = dataObjectTypeFromHTMLClipboardType(typeString); + ClipboardDataType type = dataObjectTypeFromHTMLClipboardType(typeString); switch (type) { - case ClipboardTypeURIList: - case ClipboardTypeURL: + case ClipboardDataTypeURIList: + case ClipboardDataTypeURL: m_dataObject->clearURIList(); break; - case ClipboardTypeMarkup: + case ClipboardDataTypeMarkup: m_dataObject->clearMarkup(); break; - case ClipboardTypeText: + case ClipboardDataTypeText: m_dataObject->clearText(); break; - case ClipboardTypeUnknown: + case ClipboardDataTypeUnknown: default: m_dataObject->clear(); } @@ -162,29 +162,29 @@ String ClipboardGtk::getData(const String& typeString, bool& success) const if (m_clipboard) m_helper->getClipboardContents(m_clipboard); - ClipboardType type = dataObjectTypeFromHTMLClipboardType(typeString); - if (type == ClipboardTypeURIList) { + ClipboardDataType type = dataObjectTypeFromHTMLClipboardType(typeString); + if (type == ClipboardDataTypeURIList) { if (!m_dataObject->hasURIList()) return String(); success = true; return joinURIList(m_dataObject->uriList()); } - if (type == ClipboardTypeURL) { + if (type == ClipboardDataTypeURL) { if (!m_dataObject->hasURL()) return String(); success = true; return m_dataObject->url(); } - if (type == ClipboardTypeMarkup) { + if (type == ClipboardDataTypeMarkup) { if (!m_dataObject->hasMarkup()) return String(); success = true; return m_dataObject->markup(); } - if (type == ClipboardTypeText) { + if (type == ClipboardDataTypeText) { if (!m_dataObject->hasText()) return String(); success = true; @@ -200,8 +200,8 @@ bool ClipboardGtk::setData(const String& typeString, const String& data) return false; bool success = false; - ClipboardType type = dataObjectTypeFromHTMLClipboardType(typeString); - if (type == ClipboardTypeURIList || type == ClipboardTypeURL) { + ClipboardDataType type = dataObjectTypeFromHTMLClipboardType(typeString); + if (type == ClipboardDataTypeURIList || type == ClipboardDataTypeURL) { Vector<KURL> uriList; gchar** uris = g_uri_list_extract_uris(data.utf8().data()); if (uris) { @@ -214,10 +214,10 @@ bool ClipboardGtk::setData(const String& typeString, const String& data) m_dataObject->setURIList(uriList); success = true; } - } else if (type == ClipboardTypeMarkup) { + } else if (type == ClipboardDataTypeMarkup) { m_dataObject->setMarkup(data); success = true; - } else if (type == ClipboardTypeText) { + } else if (type == ClipboardDataTypeText) { m_dataObject->setText(data); success = true; } diff --git a/WebCore/platform/gtk/ClipboardGtk.h b/WebCore/platform/gtk/ClipboardGtk.h index f0af318..e14a583 100644 --- a/WebCore/platform/gtk/ClipboardGtk.h +++ b/WebCore/platform/gtk/ClipboardGtk.h @@ -40,14 +40,14 @@ namespace WebCore { // Created from the EventHandlerGtk to be used by the dom class ClipboardGtk : public Clipboard, public CachedResourceClient { public: - static PassRefPtr<ClipboardGtk> create(ClipboardAccessPolicy policy, GtkClipboard* clipboard, bool isForDragging, Frame* frame) + static PassRefPtr<ClipboardGtk> create(ClipboardAccessPolicy policy, GtkClipboard* clipboard, Frame* frame) { return adoptRef(new ClipboardGtk(policy, clipboard, frame)); } - static PassRefPtr<ClipboardGtk> create(ClipboardAccessPolicy policy, PassRefPtr<DataObjectGtk> dataObject, bool isForDragging, Frame* frame) + static PassRefPtr<ClipboardGtk> create(ClipboardAccessPolicy policy, PassRefPtr<DataObjectGtk> dataObject, ClipboardType clipboardType, Frame* frame) { - return adoptRef(new ClipboardGtk(policy, dataObject, isForDragging, frame)); + return adoptRef(new ClipboardGtk(policy, dataObject, clipboardType, frame)); } virtual ~ClipboardGtk(); @@ -78,7 +78,7 @@ namespace WebCore { private: ClipboardGtk(ClipboardAccessPolicy, GtkClipboard*, Frame*); - ClipboardGtk(ClipboardAccessPolicy, PassRefPtr<DataObjectGtk>, bool, Frame*); + ClipboardGtk(ClipboardAccessPolicy, PassRefPtr<DataObjectGtk>, ClipboardType, Frame*); RefPtr<DataObjectGtk> m_dataObject; GtkClipboard* m_clipboard; diff --git a/WebCore/platform/gtk/ContextMenuItemGtk.cpp b/WebCore/platform/gtk/ContextMenuItemGtk.cpp index e2c5b84..68d0a9a 100644 --- a/WebCore/platform/gtk/ContextMenuItemGtk.cpp +++ b/WebCore/platform/gtk/ContextMenuItemGtk.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2010 Igalia S.L * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -33,11 +34,13 @@ static const char* gtkStockIDFromContextMenuAction(const ContextMenuAction& acti switch (action) { case ContextMenuItemTagCopyLinkToClipboard: case ContextMenuItemTagCopyImageToClipboard: + case ContextMenuItemTagCopyMediaLinkToClipboard: case ContextMenuItemTagCopy: return GTK_STOCK_COPY; case ContextMenuItemTagOpenLinkInNewWindow: case ContextMenuItemTagOpenImageInNewWindow: case ContextMenuItemTagOpenFrameInNewWindow: + case ContextMenuItemTagOpenMediaInNewWindow: return GTK_STOCK_OPEN; case ContextMenuItemTagDownloadLinkToDisk: case ContextMenuItemTagDownloadImageToDisk: @@ -59,7 +62,7 @@ static const char* gtkStockIDFromContextMenuAction(const ContextMenuAction& acti case ContextMenuItemTagSelectAll: return GTK_STOCK_SELECT_ALL; case ContextMenuItemTagSpellingGuess: - return NULL; + return 0; case ContextMenuItemTagIgnoreSpelling: return GTK_STOCK_NO; case ContextMenuItemTagLearnSpelling: @@ -99,8 +102,14 @@ static const char* gtkStockIDFromContextMenuAction(const ContextMenuAction& acti return GTK_STOCK_UNDERLINE; case ContextMenuItemTagShowColors: return GTK_STOCK_SELECT_COLOR; + case ContextMenuItemTagToggleMediaControls: + case ContextMenuItemTagToggleMediaLoop: + // No icon for this. + return 0; + case ContextMenuItemTagEnterVideoFullscreen: + return GTK_STOCK_FULLSCREEN; default: - return NULL; + return 0; } } diff --git a/WebCore/platform/gtk/GtkVersioning.c b/WebCore/platform/gtk/GtkVersioning.c index 7dd601e..f5466be 100644 --- a/WebCore/platform/gtk/GtkVersioning.c +++ b/WebCore/platform/gtk/GtkVersioning.c @@ -60,10 +60,41 @@ GdkDevice *getDefaultGDKPointerDevice(GdkWindow* window) } #if !GTK_CHECK_VERSION(2, 17, 3) -static void gdk_window_get_root_coords(GdkWindow* window, gint x, gint y, gint* rootX, gint* rootY) +void gdk_window_get_root_coords(GdkWindow* window, gint x, gint y, gint* rootX, gint* rootY) { gdk_window_get_root_origin(window, rootX, rootY); *rootX = *rootX + x; *rootY = *rootY + y; } #endif + +GdkCursor * blankCursor() +{ +#if GTK_CHECK_VERSION(2, 16, 0) + return gdk_cursor_new(GDK_BLANK_CURSOR); +#else + GdkCursor * cursor; + GdkPixmap * source; + GdkPixmap * mask; + GdkColor foreground = { 0, 65535, 0, 0 }; // Red. + GdkColor background = { 0, 0, 0, 65535 }; // Blue. + static gchar cursorBits[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + + source = gdk_bitmap_create_from_data(0, cursorBits, 8, 8); + mask = gdk_bitmap_create_from_data(0, cursorBits, 8, 8); + cursor = gdk_cursor_new_from_pixmap(source, mask, &foreground, &background, 8, 8); + gdk_pixmap_unref(source); + gdk_pixmap_unref(mask); + return cursor; +#endif // GTK_CHECK_VERSION(2, 16, 0) +} + +#if !GTK_CHECK_VERSION(2, 16, 0) +const gchar* gtk_menu_item_get_label(GtkMenuItem* menuItem) +{ + GtkWidget * label = gtk_bin_get_child(GTK_BIN(menuItem)); + if (GTK_IS_LABEL(label)) + return gtk_label_get_text(GTK_LABEL(label)); + return 0; +} +#endif // GTK_CHECK_VERSION(2, 16, 0) diff --git a/WebCore/platform/gtk/GtkVersioning.h b/WebCore/platform/gtk/GtkVersioning.h index 867e14f..a874e9e 100644 --- a/WebCore/platform/gtk/GtkVersioning.h +++ b/WebCore/platform/gtk/GtkVersioning.h @@ -57,6 +57,8 @@ G_BEGIN_DECLS #if !GTK_CHECK_VERSION(2, 18, 0) #define gtk_widget_set_visible(widget, FALSE) GTK_WIDGET_UNSET_FLAGS((widget), GTK_VISIBLE) +#define gtk_widget_get_visible(widget) (GTK_WIDGET_FLAGS(widget) & GTK_VISIBLE) + #define gtk_widget_set_window(widget, new_window) (widget)->window = (new_window) #define gtk_widget_set_can_focus(widget, TRUE) GTK_WIDGET_SET_FLAGS((widget), GTK_CAN_FOCUS) #define gtk_widget_get_allocation(widget, alloc) (*(alloc) = (widget)->allocation) @@ -64,8 +66,13 @@ G_BEGIN_DECLS #endif // GTK_CHECK_VERSION(2, 18, 0) #if !GTK_CHECK_VERSION(2, 17, 3) -static void gdk_window_get_root_coords(GdkWindow* window, gint x, gint y, gint* rootX, gint* rootY); -#endif //GTK_CHECK_VERSION(2, 17, 3) +void gdk_window_get_root_coords(GdkWindow* window, gint x, gint y, gint* rootX, gint* rootY); +#endif // GTK_CHECK_VERSION(2, 17, 3) + +#if !GTK_CHECK_VERSION(2, 16, 0) +const gchar* gtk_menu_item_get_label(GtkMenuItem*); +#endif // GTK_CHECK_VERSION(2, 16, 0) + #if !GTK_CHECK_VERSION(2, 14, 0) #define gtk_widget_get_window(widget) (widget)->window @@ -84,6 +91,7 @@ void gtk_adjustment_set_value(GtkAdjustment* adjusment, gdouble value); #endif // GTK_CHECK_VERSION(2, 14, 0) GdkDevice* getDefaultGDKPointerDevice(GdkWindow* window); +GdkCursor* blankCursor(); G_END_DECLS diff --git a/WebCore/platform/gtk/LocalizedStringsGtk.cpp b/WebCore/platform/gtk/LocalizedStringsGtk.cpp index 432c92f..7851326 100644 --- a/WebCore/platform/gtk/LocalizedStringsGtk.cpp +++ b/WebCore/platform/gtk/LocalizedStringsGtk.cpp @@ -4,6 +4,7 @@ * Copyright (C) 2007 Holger Hans Peter Freyther * Copyright (C) 2008 Christian Dywan <christian@imendio.com> * Copyright (C) 2008 Nuanti Ltd. + * Copyright (C) 2010 Igalia S.L * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -110,6 +111,56 @@ String contextMenuItemTagCopyImageToClipboard() return String::fromUTF8(_("Cop_y Image")); } +String contextMenuItemTagOpenVideoInNewWindow() +{ + return String::fromUTF8(_("Open _Video in New Window")); +} + +String contextMenuItemTagOpenAudioInNewWindow() +{ + return String::fromUTF8(_("Open _Audio in New Window")); +} + +String contextMenuItemTagCopyVideoLinkToClipboard() +{ + return String::fromUTF8(_("Cop_y Video Link Location")); +} + +String contextMenuItemTagCopyAudioLinkToClipboard() +{ + return String::fromUTF8(_("Cop_y Audio Link Location")); +} + +String contextMenuItemTagToggleMediaControls() +{ + return String::fromUTF8(_("_Toggle Media Controls")); +} + +String contextMenuItemTagToggleMediaLoop() +{ + return String::fromUTF8(_("Toggle Media _Loop Playback")); +} + +String contextMenuItemTagEnterVideoFullscreen() +{ + return String::fromUTF8(_("Switch Video to _Fullscreen")); +} + +String contextMenuItemTagMediaPlay() +{ + return String::fromUTF8(_("_Play")); +} + +String contextMenuItemTagMediaPause() +{ + return String::fromUTF8(_("_Pause")); +} + +String contextMenuItemTagMediaMute() +{ + return String::fromUTF8(_("_Mute")); +} + String contextMenuItemTagOpenFrameInNewWindow() { return String::fromUTF8(_("Open _Frame in New Window")); diff --git a/WebCore/platform/haiku/ClipboardHaiku.cpp b/WebCore/platform/haiku/ClipboardHaiku.cpp index da242c1..495f1d2 100644 --- a/WebCore/platform/haiku/ClipboardHaiku.cpp +++ b/WebCore/platform/haiku/ClipboardHaiku.cpp @@ -44,11 +44,11 @@ namespace WebCore { PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData*, Frame*) { - return ClipboardHaiku::create(policy, true); + return ClipboardHaiku::create(policy, DragAndDrop); } -ClipboardHaiku::ClipboardHaiku(ClipboardAccessPolicy policy, bool forDragging) - : Clipboard(policy, forDragging) +ClipboardHaiku::ClipboardHaiku(ClipboardAccessPolicy policy, ClipboardType clipboardType) + : Clipboard(policy, clipboardType) { } diff --git a/WebCore/platform/haiku/ClipboardHaiku.h b/WebCore/platform/haiku/ClipboardHaiku.h index 37ffe5c..89dc7bd 100644 --- a/WebCore/platform/haiku/ClipboardHaiku.h +++ b/WebCore/platform/haiku/ClipboardHaiku.h @@ -36,9 +36,9 @@ namespace WebCore { // State available during IE's events for drag and drop and copy/paste. class ClipboardHaiku : public Clipboard { public: - static PassRefPtr<ClipboardHaiku> create(ClipboardAccessPolicy policy, bool forDragging) + static PassRefPtr<ClipboardHaiku> create(ClipboardAccessPolicy policy, ClipboardType clipboardType) { - return adoptRef(new ClipboardHaiku(policy, forDragging)); + return adoptRef(new ClipboardHaiku(policy, clipboardType)); } ~ClipboardHaiku() { } @@ -66,7 +66,7 @@ namespace WebCore { virtual bool hasData(); private: - ClipboardHaiku(ClipboardAccessPolicy, bool forDragging); + ClipboardHaiku(ClipboardAccessPolicy, ClipboardType); }; } // namespace WebCore diff --git a/WebCore/platform/haiku/LocalizedStringsHaiku.cpp b/WebCore/platform/haiku/LocalizedStringsHaiku.cpp index 5321792..4c12cf3 100644 --- a/WebCore/platform/haiku/LocalizedStringsHaiku.cpp +++ b/WebCore/platform/haiku/LocalizedStringsHaiku.cpp @@ -98,6 +98,56 @@ String contextMenuItemTagCopyImageToClipboard() return "Copy image to clipboard"; } +String contextMenuItemTagOpenVideoInNewWindow() +{ + return "Open video in new window"; +} + +String contextMenuItemTagOpenAudioInNewWindow() +{ + return "Open audio in new window"; +} + +String contextMenuItemTagCopyVideoLinkToClipboard() +{ + return "Copy video link location"; +} + +String contextMenuItemTagCopyAudioLinkToClipboard() +{ + return "Copy audio link location"; +} + +String contextMenuItemTagToggleMediaControls() +{ + return "Toggle media controls"; +} + +String contextMenuItemTagToggleMediaLoop() +{ + return "Toggle media loop playback"; +} + +String contextMenuItemTagEnterVideoFullscreen() +{ + return "Switch video to fullscreen"; +} + +String contextMenuItemTagMediaPlay() +{ + return "Play"; +} + +String contextMenuItemTagMediaPause() +{ + return "Pause"; +} + +String contextMenuItemTagMediaMute() +{ + return "Mute"; +} + String contextMenuItemTagOpenFrameInNewWindow() { return "Open frame in new window"; diff --git a/WebCore/platform/image-decoders/ImageDecoder.cpp b/WebCore/platform/image-decoders/ImageDecoder.cpp index 475bd9f..1c3dcf8 100644 --- a/WebCore/platform/image-decoders/ImageDecoder.cpp +++ b/WebCore/platform/image-decoders/ImageDecoder.cpp @@ -133,14 +133,15 @@ void RGBA32Buffer::zeroFill() m_hasAlpha = true; } -void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) +bool RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) { if (this == &other) - return; + return true; m_bytes = other.m_bytes; m_size = other.m_size; setHasAlpha(other.m_hasAlpha); + return true; } bool RGBA32Buffer::setSize(int newWidth, int newHeight) diff --git a/WebCore/platform/image-decoders/ImageDecoder.h b/WebCore/platform/image-decoders/ImageDecoder.h index 4012168..90e8ae2 100644 --- a/WebCore/platform/image-decoders/ImageDecoder.h +++ b/WebCore/platform/image-decoders/ImageDecoder.h @@ -85,8 +85,8 @@ namespace WebCore { void zeroFill(); // Creates a new copy of the image data in |other|, so the two images - // can be modified independently. - void copyBitmapData(const RGBA32Buffer& other); + // can be modified independently. Returns whether the copy succeeded. + bool copyBitmapData(const RGBA32Buffer& other); // Copies the pixel data at [(startX, startY), (endX, startY)) to the // same X-coordinates on each subsequent row up to but not including diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp index 4d2a92d..4797495 100644 --- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp +++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp @@ -60,7 +60,7 @@ bool GIFImageDecoder::isSizeAvailable() return ImageDecoder::isSizeAvailable(); } -bool GIFImageDecoder::setSize(unsigned width, unsigned height) +bool GIFImageDecoder::setSize(int width, int height) { if (ImageDecoder::isSizeAvailable() && size().width() == width && size().height() == height) return true; @@ -356,7 +356,8 @@ bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex) if ((prevMethod == RGBA32Buffer::DisposeNotSpecified) || (prevMethod == RGBA32Buffer::DisposeKeep)) { // Preserve the last frame as the starting state for this frame. - buffer->copyBitmapData(*prevBuffer); + if (!buffer->copyBitmapData(*prevBuffer)) + return setFailed(); } else { // We want to clear the previous frame to transparent, without // affecting pixels in the image outside of the frame. @@ -369,7 +370,8 @@ bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex) return setFailed(); } else { // Copy the whole previous buffer, then clear just its frame. - buffer->copyBitmapData(*prevBuffer); + if (!buffer->copyBitmapData(*prevBuffer)) + return setFailed(); for (int y = prevRect.y(); y < prevRect.bottom(); ++y) { for (int x = prevRect.x(); x < prevRect.right(); ++x) buffer->setRGBA(x, y, 0, 0, 0, 0); diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.h b/WebCore/platform/image-decoders/gif/GIFImageDecoder.h index 21c1c57..0a88ffd 100644 --- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.h +++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.h @@ -45,7 +45,7 @@ namespace WebCore { virtual String filenameExtension() const { return "gif"; } virtual void setData(SharedBuffer* data, bool allDataReceived); virtual bool isSizeAvailable(); - virtual bool setSize(unsigned width, unsigned height); + virtual bool setSize(int width, int height); virtual size_t frameCount(); virtual int repetitionCount() const; virtual RGBA32Buffer* frameBufferAtIndex(size_t index); diff --git a/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp b/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp index 044515a..a782373 100644 --- a/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp +++ b/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp @@ -75,15 +75,16 @@ void RGBA32Buffer::zeroFill() m_pixmap.fill(QColor(0, 0, 0, 0)); } -void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) +bool RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) { if (this == &other) - return; + return true; m_image = other.m_image; m_pixmap = other.m_pixmap; m_size = other.m_size; m_hasAlpha = other.m_hasAlpha; + return true; } bool RGBA32Buffer::setSize(int newWidth, int newHeight) diff --git a/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp b/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp index c7e2114..7baca5f 100644 --- a/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp +++ b/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp @@ -72,14 +72,14 @@ void RGBA32Buffer::zeroFill() m_bitmap.eraseARGB(0, 0, 0, 0); } -void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) +bool RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) { if (this == &other) - return; + return true; m_bitmap.reset(); const NativeImageSkia& otherBitmap = other.m_bitmap; - otherBitmap.copyTo(&m_bitmap, otherBitmap.config()); + return otherBitmap.copyTo(&m_bitmap, otherBitmap.config()); } bool RGBA32Buffer::setSize(int newWidth, int newHeight) diff --git a/WebCore/platform/mac/ClipboardMac.h b/WebCore/platform/mac/ClipboardMac.h index adde09c..7187ecf 100644 --- a/WebCore/platform/mac/ClipboardMac.h +++ b/WebCore/platform/mac/ClipboardMac.h @@ -45,9 +45,9 @@ class FileList; class ClipboardMac : public Clipboard, public CachedResourceClient { public: - static PassRefPtr<ClipboardMac> create(bool forDragging, NSPasteboard *pasteboard, ClipboardAccessPolicy policy, Frame* frame) + static PassRefPtr<ClipboardMac> create(ClipboardType clipboardType, NSPasteboard *pasteboard, ClipboardAccessPolicy policy, Frame* frame) { - return adoptRef(new ClipboardMac(forDragging, pasteboard, policy, frame)); + return adoptRef(new ClipboardMac(clipboardType, pasteboard, policy, frame)); } virtual ~ClipboardMac(); @@ -79,7 +79,7 @@ public: NSPasteboard *pasteboard() { return m_pasteboard.get(); } private: - ClipboardMac(bool forDragging, NSPasteboard *, ClipboardAccessPolicy, Frame*); + ClipboardMac(ClipboardType, NSPasteboard *, ClipboardAccessPolicy, Frame*); void setDragImage(CachedImage*, Node*, const IntPoint&); diff --git a/WebCore/platform/mac/ClipboardMac.mm b/WebCore/platform/mac/ClipboardMac.mm index 74a93b6..10d196a 100644 --- a/WebCore/platform/mac/ClipboardMac.mm +++ b/WebCore/platform/mac/ClipboardMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2008, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,7 +31,6 @@ #import "DragController.h" #import "DragData.h" #import "Editor.h" -#import "FoundationExtras.h" #import "FileList.h" #import "Frame.h" #import "Image.h" @@ -50,11 +49,11 @@ namespace WebCore { PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* dragData, Frame* frame) { - return ClipboardMac::create(true, [dragData->platformData() draggingPasteboard], policy, frame); + return ClipboardMac::create(DragAndDrop, [dragData->platformData() draggingPasteboard], policy, frame); } -ClipboardMac::ClipboardMac(bool forDragging, NSPasteboard *pasteboard, ClipboardAccessPolicy policy, Frame *frame) - : Clipboard(policy, forDragging) +ClipboardMac::ClipboardMac(ClipboardType clipboardType, NSPasteboard *pasteboard, ClipboardAccessPolicy policy, Frame *frame) + : Clipboard(policy, clipboardType) , m_pasteboard(pasteboard) , m_frame(frame) { @@ -70,7 +69,7 @@ bool ClipboardMac::hasData() return m_pasteboard && [m_pasteboard.get() types] && [[m_pasteboard.get() types] count] > 0; } -static NSString *cocoaTypeFromHTMLClipboardType(const String& type) +static RetainPtr<NSString> cocoaTypeFromHTMLClipboardType(const String& type) { String qType = type.stripWhiteSpace(); @@ -93,11 +92,11 @@ static NSString *cocoaTypeFromHTMLClipboardType(const String& type) if (utiType) { CFStringRef pbType = UTTypeCopyPreferredTagWithClass(utiType.get(), kUTTagClassNSPboardType); if (pbType) - return HardAutorelease(pbType); + return (NSString *)pbType; } - // No mapping, just pass the whole string though - return qType; + // No mapping, just pass the whole string though + return (NSString *)qType; } static String utiTypeFromCocoaType(NSString *type) @@ -151,9 +150,8 @@ void ClipboardMac::clearData(const String& type) // note NSPasteboard enforces changeCount itself on writing - can't write if not the owner - NSString *cocoaType = cocoaTypeFromHTMLClipboardType(type); - if (cocoaType) - [m_pasteboard.get() setString:@"" forType:cocoaType]; + if (RetainPtr<NSString> cocoaType = cocoaTypeFromHTMLClipboardType(type)) + [m_pasteboard.get() setString:@"" forType:cocoaType.get()]; } void ClipboardMac::clearAllData() @@ -218,19 +216,19 @@ String ClipboardMac::getData(const String& type, bool& success) const if (policy() != ClipboardReadable) return String(); - NSString *cocoaType = cocoaTypeFromHTMLClipboardType(type); + RetainPtr<NSString> cocoaType = cocoaTypeFromHTMLClipboardType(type); NSString *cocoaValue = nil; // Grab the value off the pasteboard corresponding to the cocoaType - if ([cocoaType isEqualToString:NSURLPboardType]) { + if ([cocoaType.get() isEqualToString:NSURLPboardType]) { // "URL" and "text/url-list" both map to NSURLPboardType in cocoaTypeFromHTMLClipboardType(), "URL" only wants the first URL bool onlyFirstURL = (type == "URL"); NSArray *absoluteURLs = absoluteURLsFromPasteboard(m_pasteboard.get(), onlyFirstURL); cocoaValue = [absoluteURLs componentsJoinedByString:@"\n"]; - } else if ([cocoaType isEqualToString:NSStringPboardType]) { - cocoaValue = [[m_pasteboard.get() stringForType:cocoaType] precomposedStringWithCanonicalMapping]; + } else if ([cocoaType.get() isEqualToString:NSStringPboardType]) { + cocoaValue = [[m_pasteboard.get() stringForType:cocoaType.get()] precomposedStringWithCanonicalMapping]; } else if (cocoaType) - cocoaValue = [m_pasteboard.get() stringForType:cocoaType]; + cocoaValue = [m_pasteboard.get() stringForType:cocoaType.get()]; // Enforce changeCount ourselves for security. We check after reading instead of before to be // sure it doesn't change between our testing the change count and accessing the data. @@ -248,10 +246,10 @@ bool ClipboardMac::setData(const String &type, const String &data) return false; // note NSPasteboard enforces changeCount itself on writing - can't write if not the owner - NSString *cocoaType = cocoaTypeFromHTMLClipboardType(type); + RetainPtr<NSString> cocoaType = cocoaTypeFromHTMLClipboardType(type); NSString *cocoaData = data; - if ([cocoaType isEqualToString:NSURLPboardType]) { + if ([cocoaType.get() isEqualToString:NSURLPboardType]) { [m_pasteboard.get() addTypes:[NSArray arrayWithObject:NSURLPboardType] owner:nil]; NSURL *url = [[NSURL alloc] initWithString:cocoaData]; [url writeToPasteboard:m_pasteboard.get()]; @@ -268,8 +266,8 @@ bool ClipboardMac::setData(const String &type, const String &data) if (cocoaType) { // everything else we know of goes on the pboard as a string - [m_pasteboard.get() addTypes:[NSArray arrayWithObject:cocoaType] owner:nil]; - return [m_pasteboard.get() setString:cocoaData forType:cocoaType]; + [m_pasteboard.get() addTypes:[NSArray arrayWithObject:cocoaType.get()] owner:nil]; + return [m_pasteboard.get() setString:cocoaData forType:cocoaType.get()]; } return false; diff --git a/WebCore/platform/mac/CursorMac.mm b/WebCore/platform/mac/CursorMac.mm index 1b4c1b1..c006cbc 100644 --- a/WebCore/platform/mac/CursorMac.mm +++ b/WebCore/platform/mac/CursorMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2006 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2006, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,7 +27,6 @@ #import "Cursor.h" #import "BlockExceptions.h" -#import "FoundationExtras.h" #import <wtf/StdLibExtras.h> @interface WebCoreCursorBundle : NSObject { } @@ -41,14 +40,14 @@ namespace WebCore { // Simple NSCursor calls shouldn't need protection, // but creating a cursor with a bad image might throw. -static NSCursor* createCustomCursor(Image* image, const IntPoint& hotSpot) +static RetainPtr<NSCursor> createCustomCursor(Image* image, const IntPoint& hotSpot) { // FIXME: The cursor won't animate. Not sure if that's a big deal. - NSImage* img = image->getNSImage(); - if (!img) + NSImage* nsImage = image->getNSImage(); + if (!nsImage) return 0; BEGIN_BLOCK_OBJC_EXCEPTIONS; - return [[NSCursor alloc] initWithImage:img hotSpot:hotSpot]; + return RetainPtr<NSCursor>(AdoptNS, [[NSCursor alloc] initWithImage:nsImage hotSpot:hotSpot]); END_BLOCK_OBJC_EXCEPTIONS; return 0; } @@ -81,118 +80,118 @@ void Cursor::ensurePlatformCursor() const switch (m_type) { case Cursor::Pointer: - m_platformCursor = HardRetain([NSCursor arrowCursor]); + m_platformCursor = [NSCursor arrowCursor]; break; case Cursor::Cross: - m_platformCursor = HardRetain(leakNamedCursor("crossHairCursor", 11, 11)); + m_platformCursor = leakNamedCursor("crossHairCursor", 11, 11); break; case Cursor::Hand: - m_platformCursor = HardRetain(leakNamedCursor("linkCursor", 6, 1)); + m_platformCursor = leakNamedCursor("linkCursor", 6, 1); break; case Cursor::IBeam: - m_platformCursor = HardRetain([NSCursor IBeamCursor]); + m_platformCursor = [NSCursor IBeamCursor]; break; case Cursor::Wait: - m_platformCursor = HardRetain(leakNamedCursor("waitCursor", 7, 7)); + m_platformCursor = leakNamedCursor("waitCursor", 7, 7); break; case Cursor::Help: - m_platformCursor = HardRetain(leakNamedCursor("helpCursor", 8, 8)); + m_platformCursor = leakNamedCursor("helpCursor", 8, 8); break; case Cursor::Move: case Cursor::MiddlePanning: - m_platformCursor = HardRetain(leakNamedCursor("moveCursor", 7, 7)); + m_platformCursor = leakNamedCursor("moveCursor", 7, 7); break; case Cursor::EastResize: case Cursor::EastPanning: - m_platformCursor = HardRetain(leakNamedCursor("eastResizeCursor", 14, 7)); + m_platformCursor = leakNamedCursor("eastResizeCursor", 14, 7); break; case Cursor::NorthResize: case Cursor::NorthPanning: - m_platformCursor = HardRetain(leakNamedCursor("northResizeCursor", 7, 1)); + m_platformCursor = leakNamedCursor("northResizeCursor", 7, 1); break; case Cursor::NorthEastResize: case Cursor::NorthEastPanning: - m_platformCursor = HardRetain(leakNamedCursor("northEastResizeCursor", 14, 1)); + m_platformCursor = leakNamedCursor("northEastResizeCursor", 14, 1); break; case Cursor::NorthWestResize: case Cursor::NorthWestPanning: - m_platformCursor = HardRetain(leakNamedCursor("northWestResizeCursor", 0, 0)); + m_platformCursor = leakNamedCursor("northWestResizeCursor", 0, 0); break; case Cursor::SouthResize: case Cursor::SouthPanning: - m_platformCursor = HardRetain(leakNamedCursor("southResizeCursor", 7, 14)); + m_platformCursor = leakNamedCursor("southResizeCursor", 7, 14); break; case Cursor::SouthEastResize: case Cursor::SouthEastPanning: - m_platformCursor = HardRetain(leakNamedCursor("southEastResizeCursor", 14, 14)); + m_platformCursor = leakNamedCursor("southEastResizeCursor", 14, 14); break; case Cursor::SouthWestResize: case Cursor::SouthWestPanning: - m_platformCursor = HardRetain(leakNamedCursor("southWestResizeCursor", 1, 14)); + m_platformCursor = leakNamedCursor("southWestResizeCursor", 1, 14); break; case Cursor::WestResize: - m_platformCursor = HardRetain(leakNamedCursor("westResizeCursor", 1, 7)); + m_platformCursor = leakNamedCursor("westResizeCursor", 1, 7); break; case Cursor::NorthSouthResize: - m_platformCursor = HardRetain(leakNamedCursor("northSouthResizeCursor", 7, 7)); + m_platformCursor = leakNamedCursor("northSouthResizeCursor", 7, 7); break; case Cursor::EastWestResize: case Cursor::WestPanning: - m_platformCursor = HardRetain(leakNamedCursor("eastWestResizeCursor", 7, 7)); + m_platformCursor = leakNamedCursor("eastWestResizeCursor", 7, 7); break; case Cursor::NorthEastSouthWestResize: - m_platformCursor = HardRetain(leakNamedCursor("northEastSouthWestResizeCursor", 7, 7)); + m_platformCursor = leakNamedCursor("northEastSouthWestResizeCursor", 7, 7); break; case Cursor::NorthWestSouthEastResize: - m_platformCursor = HardRetain(leakNamedCursor("northWestSouthEastResizeCursor", 7, 7)); + m_platformCursor = leakNamedCursor("northWestSouthEastResizeCursor", 7, 7); break; case Cursor::ColumnResize: - m_platformCursor = HardRetain([NSCursor resizeLeftRightCursor]); + m_platformCursor = [NSCursor resizeLeftRightCursor]; break; case Cursor::RowResize: - m_platformCursor = HardRetain([NSCursor resizeUpDownCursor]); + m_platformCursor = [NSCursor resizeUpDownCursor]; break; case Cursor::VerticalText: - m_platformCursor = HardRetain(leakNamedCursor("verticalTextCursor", 7, 7)); + m_platformCursor = leakNamedCursor("verticalTextCursor", 7, 7); break; case Cursor::Cell: - m_platformCursor = HardRetain(leakNamedCursor("cellCursor", 7, 7)); + m_platformCursor = leakNamedCursor("cellCursor", 7, 7); break; case Cursor::ContextMenu: - m_platformCursor = HardRetain(leakNamedCursor("contextMenuCursor", 3, 2)); + m_platformCursor = leakNamedCursor("contextMenuCursor", 3, 2); break; case Cursor::Alias: - m_platformCursor = HardRetain(leakNamedCursor("aliasCursor", 11, 3)); + m_platformCursor = leakNamedCursor("aliasCursor", 11, 3); break; case Cursor::Progress: - m_platformCursor = HardRetain(leakNamedCursor("progressCursor", 3, 2)); + m_platformCursor = leakNamedCursor("progressCursor", 3, 2); break; case Cursor::NoDrop: - m_platformCursor = HardRetain(leakNamedCursor("noDropCursor", 3, 1)); + m_platformCursor = leakNamedCursor("noDropCursor", 3, 1); break; case Cursor::Copy: - m_platformCursor = HardRetain(leakNamedCursor("copyCursor", 3, 2)); + m_platformCursor = leakNamedCursor("copyCursor", 3, 2); break; case Cursor::None: - m_platformCursor = HardRetain(leakNamedCursor("noneCursor", 7, 7)); + m_platformCursor = leakNamedCursor("noneCursor", 7, 7); break; case Cursor::NotAllowed: - m_platformCursor = HardRetain(leakNamedCursor("notAllowedCursor", 11, 11)); + m_platformCursor = leakNamedCursor("notAllowedCursor", 11, 11); break; case Cursor::ZoomIn: - m_platformCursor = HardRetain(leakNamedCursor("zoomInCursor", 7, 7)); + m_platformCursor = leakNamedCursor("zoomInCursor", 7, 7); break; case Cursor::ZoomOut: - m_platformCursor = HardRetain(leakNamedCursor("zoomOutCursor", 7, 7)); + m_platformCursor = leakNamedCursor("zoomOutCursor", 7, 7); break; case Cursor::Grab: - m_platformCursor = HardRetain([NSCursor openHandCursor]); + m_platformCursor = [NSCursor openHandCursor]; break; case Cursor::Grabbing: - m_platformCursor = HardRetain([NSCursor closedHandCursor]); + m_platformCursor = [NSCursor closedHandCursor]; break; case Cursor::Custom: - m_platformCursor = HardRetainWithNSRelease(createCustomCursor(m_image.get(), m_hotSpot)); + m_platformCursor = createCustomCursor(m_image.get(), m_hotSpot); break; } } @@ -201,7 +200,7 @@ Cursor::Cursor(const Cursor& other) : m_type(other.m_type) , m_image(other.m_image) , m_hotSpot(other.m_hotSpot) - , m_platformCursor(HardRetain(other.m_platformCursor)) + , m_platformCursor(other.m_platformCursor) { } @@ -210,16 +209,18 @@ Cursor& Cursor::operator=(const Cursor& other) m_type = other.m_type; m_image = other.m_image; m_hotSpot = other.m_hotSpot; - - HardRetain(other.m_platformCursor); - HardRelease(m_platformCursor); m_platformCursor = other.m_platformCursor; return *this; } Cursor::~Cursor() { - HardRelease(m_platformCursor); +} + +NSCursor *Cursor::platformCursor() const +{ + ensurePlatformCursor(); + return m_platformCursor.get(); } } // namespace WebCore diff --git a/WebCore/platform/mac/FoundationExtras.h b/WebCore/platform/mac/FoundationExtras.h index 85ce8d7..39b12ea 100644 --- a/WebCore/platform/mac/FoundationExtras.h +++ b/WebCore/platform/mac/FoundationExtras.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2004 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,50 +26,15 @@ #import <CoreFoundation/CFBase.h> #import <Foundation/NSObject.h> -// nil-checked CFRetain/CFRelease covers for Objective-C ids - -// Use CFRetain, CFRelease, HardRetain, or HardRelease instead of -// -[NSObject retain] and -[NSObject release] if you want to store -// a pointer to an Objective-C object into memory that won't -// be scanned for GC, like a C++ object. - -static inline id HardRetain(id obj) -{ - if (obj) CFRetain(obj); - return obj; -} - -static inline void HardRelease(id obj) -{ - if (obj) CFRelease(obj); -} - -// As if CF and Foundation had logically separate reference counts, -// this function first increments the CF retain count, and then -// decrements the NS retain count. This is needed to handle cases where -// -retain/-release aren't equivalent to CFRetain/HardRelease, such as -// when GC is used. - -// Use HardRetainWithNSRelease after allocating and initializing a NSObject -// if you want to store a pointer to that object into memory that won't -// be scanned for GC, like a C++ object. - -static inline id HardRetainWithNSRelease(id obj) -{ - HardRetain(obj); - [obj release]; - return obj; -} - // Use HardAutorelease to return an object made by a CoreFoundation // "create" or "copy" function as an autoreleased and garbage collected // object. CF objects need to be "made collectable" for autorelease to work // properly under GC. -static inline id HardAutorelease(CFTypeRef obj) +static inline id HardAutorelease(CFTypeRef object) { - if (obj) - CFMakeCollectable(obj); - [(id)obj autorelease]; - return (id)obj; + if (object) + CFMakeCollectable(object); + [(id)object autorelease]; + return (id)object; } diff --git a/WebCore/platform/mac/RuntimeApplicationChecks.h b/WebCore/platform/mac/RuntimeApplicationChecks.h index 24b8ae1..f938048 100644 --- a/WebCore/platform/mac/RuntimeApplicationChecks.h +++ b/WebCore/platform/mac/RuntimeApplicationChecks.h @@ -32,6 +32,8 @@ bool applicationIsAppleMail(); bool applicationIsSafari(); bool applicationIsMicrosoftMessenger(); bool applicationIsAdobeInstaller(); +bool applicationIsAOLInstantMessenger(); +bool applicationIsMicrosoftMyDay(); } // namespace WebCore diff --git a/WebCore/platform/mac/RuntimeApplicationChecks.mm b/WebCore/platform/mac/RuntimeApplicationChecks.mm index bcc1dc9..7fe8378 100644 --- a/WebCore/platform/mac/RuntimeApplicationChecks.mm +++ b/WebCore/platform/mac/RuntimeApplicationChecks.mm @@ -52,5 +52,17 @@ bool applicationIsAdobeInstaller() static bool isAdobeInstaller = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.adobe.Installers.Setup"]; return isAdobeInstaller; } + +bool applicationIsAOLInstantMessenger() +{ + static bool isAOLInstantMessenger = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.aol.aim.desktop"]; + return isAOLInstantMessenger; +} + +bool applicationIsMicrosoftMyDay() +{ + static bool isMicrosoftMyDay = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.microsoft.myday"]; + return isMicrosoftMyDay; +} } // namespace WebCore diff --git a/WebCore/platform/mac/ThemeMac.mm b/WebCore/platform/mac/ThemeMac.mm index c57e8df..75cbd36 100644 --- a/WebCore/platform/mac/ThemeMac.mm +++ b/WebCore/platform/mac/ThemeMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2010 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -375,43 +375,53 @@ static const int* buttonMargins(NSControlSize controlSize) return margins[controlSize]; } -static void setupButtonCell(NSButtonCell *&buttonCell, ControlPart part, ControlStates states, const IntRect& zoomedRect, float zoomFactor) +enum ButtonCellType { NormalButtonCell, DefaultButtonCell }; + +static NSButtonCell *leakButtonCell(ButtonCellType type) { - if (!buttonCell) { - buttonCell = [[NSButtonCell alloc] init]; - [buttonCell setTitle:nil]; - [buttonCell setButtonType:NSMomentaryPushInButton]; - if (states & DefaultState) - [buttonCell setKeyEquivalent:@"\r"]; - } + NSButtonCell *cell = [[NSButtonCell alloc] init]; + [cell setTitle:nil]; + [cell setButtonType:NSMomentaryPushInButton]; + if (type == DefaultButtonCell) + [cell setKeyEquivalent:@"\r"]; + return cell; +} +static void setUpButtonCell(NSButtonCell *cell, ControlPart part, ControlStates states, const IntRect& zoomedRect, float zoomFactor) +{ // Set the control size based off the rectangle we're painting into. const IntSize* sizes = buttonSizes(); #if ENABLE(DATALIST) if (part == ListButtonPart) { - [buttonCell setBezelStyle:NSRoundedDisclosureBezelStyle]; + [cell setBezelStyle:NSRoundedDisclosureBezelStyle]; sizes = listButtonSizes(); } else #endif if (part == SquareButtonPart || zoomedRect.height() > buttonSizes()[NSRegularControlSize].height() * zoomFactor) { // Use the square button - if ([buttonCell bezelStyle] != NSShadowlessSquareBezelStyle) - [buttonCell setBezelStyle:NSShadowlessSquareBezelStyle]; - } else if ([buttonCell bezelStyle] != NSRoundedBezelStyle) - [buttonCell setBezelStyle:NSRoundedBezelStyle]; + if ([cell bezelStyle] != NSShadowlessSquareBezelStyle) + [cell setBezelStyle:NSShadowlessSquareBezelStyle]; + } else if ([cell bezelStyle] != NSRoundedBezelStyle) + [cell setBezelStyle:NSRoundedBezelStyle]; - setControlSize(buttonCell, sizes, zoomedRect.size(), zoomFactor); + setControlSize(cell, sizes, zoomedRect.size(), zoomFactor); // Update the various states we respond to. - updateStates(buttonCell, states); + updateStates(cell, states); } - + static NSButtonCell *button(ControlPart part, ControlStates states, const IntRect& zoomedRect, float zoomFactor) { - bool isDefault = states & DefaultState; - static NSButtonCell *cells[2]; - setupButtonCell(cells[isDefault], part, states, zoomedRect, zoomFactor); - return cells[isDefault]; + NSButtonCell *cell; + if (states & DefaultState) { + static NSButtonCell *defaultCell = leakButtonCell(DefaultButtonCell); + cell = defaultCell; + } else { + static NSButtonCell *normalCell = leakButtonCell(NormalButtonCell); + cell = normalCell; + } + setUpButtonCell(cell, part, states, zoomedRect, zoomFactor); + return cell; } static void paintButton(ControlPart part, ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView) diff --git a/WebCore/platform/mac/WidgetMac.mm b/WebCore/platform/mac/WidgetMac.mm index 2598591..e8bb81d 100644 --- a/WebCore/platform/mac/WidgetMac.mm +++ b/WebCore/platform/mac/WidgetMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2008, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,7 +35,6 @@ #import "Cursor.h" #import "Document.h" #import "Font.h" -#import "FoundationExtras.h" #import "Frame.h" #import "GraphicsContext.h" #import "NotImplemented.h" @@ -100,7 +99,6 @@ Widget::Widget(NSView *view) Widget::~Widget() { - releasePlatformWidget(); delete m_data; } @@ -354,16 +352,18 @@ IntPoint Widget::convertFromContainingWindowToRoot(const Widget* rootWidget, con return point; } -void Widget::releasePlatformWidget() +NSView *Widget::platformWidget() const { - HardRelease(m_widget); - m_data->previousVisibleRect = NSZeroRect; + return m_widget.get(); } -void Widget::retainPlatformWidget() +void Widget::setPlatformWidget(NSView *widget) { - HardRetain(m_widget); + if (widget == m_widget) + return; + + m_widget = widget; + m_data->previousVisibleRect = NSZeroRect; } } // namespace WebCore - diff --git a/WebCore/platform/mock/DeviceOrientationClientMock.h b/WebCore/platform/mock/DeviceOrientationClientMock.h index 6691130..baa4245 100644 --- a/WebCore/platform/mock/DeviceOrientationClientMock.h +++ b/WebCore/platform/mock/DeviceOrientationClientMock.h @@ -49,6 +49,7 @@ public: virtual void startUpdating(); virtual void stopUpdating(); virtual DeviceOrientation* lastOrientation() const { return m_orientation.get(); } + virtual void deviceOrientationControllerDestroyed() { } void setOrientation(PassRefPtr<DeviceOrientation>); diff --git a/WebCore/platform/network/ResourceHandle.h b/WebCore/platform/network/ResourceHandle.h index 1cb9ee0..2ea42b1 100644 --- a/WebCore/platform/network/ResourceHandle.h +++ b/WebCore/platform/network/ResourceHandle.h @@ -46,11 +46,6 @@ typedef unsigned long DWORD; typedef unsigned long DWORD_PTR; typedef void* LPVOID; typedef LPVOID HINTERNET; -typedef unsigned WPARAM; -typedef long LPARAM; -typedef struct HWND__* HWND; -typedef _W64 long LONG_PTR; -typedef LONG_PTR LRESULT; #endif @@ -168,14 +163,11 @@ public: static void forceContentSniffing(); #if USE(WININET) - void setHasReceivedResponse(bool = true); - bool hasReceivedResponse() const; + void setSynchronousInternetHandle(HINTERNET); void fileLoadTimer(Timer<ResourceHandle>*); - void onHandleCreated(LPARAM); - void onRequestRedirected(LPARAM); - void onRequestComplete(LPARAM); - friend void __stdcall transferJobStatusCallback(HINTERNET, DWORD_PTR, DWORD, LPVOID, DWORD); - friend LRESULT __stdcall ResourceHandleWndProc(HWND, unsigned message, WPARAM, LPARAM); + void onRedirect(); + bool onRequestComplete(); + static void CALLBACK internetStatusCallback(HINTERNET, DWORD_PTR, DWORD, LPVOID, DWORD); #endif #if PLATFORM(QT) || USE(CURL) || USE(SOUP) || PLATFORM(ANDROID) diff --git a/WebCore/platform/network/ResourceHandleInternal.h b/WebCore/platform/network/ResourceHandleInternal.h index 7b6db90..96fbf00 100644 --- a/WebCore/platform/network/ResourceHandleInternal.h +++ b/WebCore/platform/network/ResourceHandleInternal.h @@ -92,16 +92,13 @@ namespace WebCore { #endif #if USE(WININET) , m_fileLoadTimer(loader, &ResourceHandle::fileLoadTimer) - , m_resourceHandle(0) - , m_secondaryHandle(0) - , m_jobId(0) - , m_threadId(0) - , m_writing(false) - , m_formDataString(0) - , m_formDataLength(0) + , m_internetHandle(0) + , m_connectHandle(0) + , m_requestHandle(0) + , m_sentEndRequest(false) , m_bytesRemainingToWrite(0) + , m_loadSynchronously(false) , m_hasReceivedResponse(false) - , m_resend(false) #endif #if USE(CURL) , m_handle(0) @@ -167,17 +164,15 @@ namespace WebCore { #endif #if USE(WININET) Timer<ResourceHandle> m_fileLoadTimer; - HINTERNET m_resourceHandle; - HINTERNET m_secondaryHandle; - unsigned m_jobId; - DWORD m_threadId; - bool m_writing; - char* m_formDataString; - int m_formDataLength; - int m_bytesRemainingToWrite; - String m_postReferrer; + HINTERNET m_internetHandle; + HINTERNET m_connectHandle; + HINTERNET m_requestHandle; + bool m_sentEndRequest; + Vector<char> m_formData; + size_t m_bytesRemainingToWrite; + bool m_loadSynchronously; bool m_hasReceivedResponse; - bool m_resend; + String m_redirectUrl; #endif #if USE(CURL) CURL* m_handle; diff --git a/WebCore/platform/network/mac/WebCoreURLResponse.mm b/WebCore/platform/network/mac/WebCoreURLResponse.mm index 9be4714..e287e5f 100644 --- a/WebCore/platform/network/mac/WebCoreURLResponse.mm +++ b/WebCore/platform/network/mac/WebCoreURLResponse.mm @@ -29,7 +29,6 @@ #import "config.h" #import "WebCoreURLResponse.h" -#import "FoundationExtras.h" #import "MIMETypeRegistry.h" #import <objc/objc-class.h> #import <wtf/Assertions.h> @@ -327,12 +326,12 @@ static NSDictionary *createExtensionToMIMETypeMap() ]; } -static NSString *mimeTypeFromUTITree(CFStringRef uti) +static RetainPtr<NSString> mimeTypeFromUTITree(CFStringRef uti) { // Check if this UTI has a MIME type. RetainPtr<CFStringRef> mimeType(AdoptCF, UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)); if (mimeType) - return (NSString *)HardAutorelease(mimeType.releaseRef()); + return (NSString *)mimeType.get(); // If not, walk the ancestory of this UTI via its "ConformsTo" tags and return the first MIME type we find. RetainPtr<CFDictionaryRef> decl(AdoptCF, UTTypeCopyDeclaration(uti)); @@ -354,7 +353,7 @@ static NSString *mimeTypeFromUTITree(CFStringRef uti) if (CFGetTypeID(object) != CFStringGetTypeID()) continue; - if (NSString *mimeType = mimeTypeFromUTITree((CFStringRef)object)) + if (RetainPtr<NSString> mimeType = mimeTypeFromUTITree((CFStringRef)object)) return mimeType; } } @@ -366,13 +365,13 @@ static NSString *mimeTypeFromUTITree(CFStringRef uti) -(void)adjustMIMETypeIfNecessary { - NSString *result = [self MIMEType]; - NSString *originalResult = result; + RetainPtr<NSString> result = [self MIMEType]; + RetainPtr<NSString> originalResult = result; #ifdef BUILDING_ON_TIGER // When content sniffing is disabled, Tiger's CFNetwork automatically returns application/octet-stream for certain // extensions even when scouring the UTI maps would end up with a better result, so we'll give a chance for that to happen. - if ([[self URL] isFileURL] && [result caseInsensitiveCompare:@"application/octet-stream"] == NSOrderedSame) + if ([[self URL] isFileURL] && [result.get() caseInsensitiveCompare:@"application/octet-stream"] == NSOrderedSame) result = nil; #endif @@ -403,7 +402,7 @@ static NSString *mimeTypeFromUTITree(CFStringRef uti) #ifndef BUILDING_ON_TIGER // <rdar://problem/5321972> Plain text document from HTTP server detected as application/octet-stream // Make the best guess when deciding between "generic binary" and "generic text" using a table of known binary MIME types. - if ([result isEqualToString:@"application/octet-stream"] && [self respondsToSelector:@selector(allHeaderFields)] && [[[self performSelector:@selector(allHeaderFields)] objectForKey:@"Content-Type"] hasPrefix:@"text/plain"]) { + if ([result.get() isEqualToString:@"application/octet-stream"] && [self respondsToSelector:@selector(allHeaderFields)] && [[[self performSelector:@selector(allHeaderFields)] objectForKey:@"Content-Type"] hasPrefix:@"text/plain"]) { static NSSet *binaryExtensions = createBinaryExtensionsSet(); if (![binaryExtensions containsObject:[[[self suggestedFilename] pathExtension] lowercaseString]]) result = @"text/plain"; @@ -413,12 +412,12 @@ static NSString *mimeTypeFromUTITree(CFStringRef uti) #ifdef BUILDING_ON_LEOPARD // Workaround for <rdar://problem/5539824> - if ([result isEqualToString:@"text/xml"]) + if ([result.get() isEqualToString:@"text/xml"]) result = @"application/xml"; #endif if (result != originalResult) - [self _setMIMEType:result]; + [self _setMIMEType:result.get()]; } @end diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index 30f7011..ca3af75 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -161,10 +161,8 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load m_method = QNetworkAccessManager::PostOperation; else if (r.httpMethod() == "PUT") m_method = QNetworkAccessManager::PutOperation; -#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) else if (r.httpMethod() == "DELETE") m_method = QNetworkAccessManager::DeleteOperation; -#endif #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) else if (r.httpMethod() == "OPTIONS") m_method = QNetworkAccessManager::CustomOperation; @@ -246,6 +244,9 @@ void QNetworkReplyHandler::finish() if (m_shouldFinish) return; + if (!m_reply) + return; + sendResponseIfNeeded(); if (!m_resourceHandle) @@ -465,12 +466,10 @@ void QNetworkReplyHandler::start() putDevice->setParent(m_reply); break; } -#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) case QNetworkAccessManager::DeleteOperation: { m_reply = manager->deleteResource(m_request); break; } -#endif #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) case QNetworkAccessManager::CustomOperation: m_reply = manager->sendCustomRequest(m_request, m_resourceHandle->firstRequest().httpMethod().latin1().data()); diff --git a/WebCore/platform/network/qt/ResourceRequestQt.cpp b/WebCore/platform/network/qt/ResourceRequestQt.cpp index 4d576c7..7e162ed 100644 --- a/WebCore/platform/network/qt/ResourceRequestQt.cpp +++ b/WebCore/platform/network/qt/ResourceRequestQt.cpp @@ -47,9 +47,7 @@ QNetworkRequest ResourceRequest::toNetworkRequest(QObject* originatingFrame) con { QNetworkRequest request; request.setUrl(url()); -#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) request.setOriginatingObject(originatingFrame); -#endif const HTTPHeaderMap &headers = httpHeaderFields(); for (HTTPHeaderMap::const_iterator it = headers.begin(), end = headers.end(); diff --git a/WebCore/platform/network/qt/SocketStreamHandleQt.cpp b/WebCore/platform/network/qt/SocketStreamHandleQt.cpp index e666ff7..cc508b6 100644 --- a/WebCore/platform/network/qt/SocketStreamHandleQt.cpp +++ b/WebCore/platform/network/qt/SocketStreamHandleQt.cpp @@ -148,12 +148,9 @@ void SocketStreamHandlePrivate::socketErrorCallback(int error) } #ifndef QT_NO_OPENSSL -void SocketStreamHandlePrivate::socketSslErrors(const QList<QSslError>&) +void SocketStreamHandlePrivate::socketSslErrors(const QList<QSslError>& error) { - // FIXME: based on http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-68#page-15 - // we should abort on certificate errors. - // We don't abort while this is still work in progress. - static_cast<QSslSocket*>(m_socket)->ignoreSslErrors(); + QMetaObject::invokeMethod(this, "socketErrorCallback", Qt::QueuedConnection, Q_ARG(int, error[0].error())); } #endif diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp index 0009e36..0d84388 100644 --- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp +++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp @@ -866,7 +866,10 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) return; } - response.setMimeType(g_file_info_get_content_type(info)); + // According to http://library.gnome.org/devel/gio/stable/gio-GContentType.html + // GContentType on Unix is the mime type, but not on Win32. + GOwnPtr<gchar> mimeType(g_content_type_get_mime_type(g_file_info_get_content_type(info))); + response.setMimeType(mimeType.get()); response.setExpectedContentLength(g_file_info_get_size(info)); GTimeVal tv; diff --git a/WebCore/platform/network/win/ResourceHandleWin.cpp b/WebCore/platform/network/win/ResourceHandleWin.cpp index 832a8e2..5de2e1b 100644 --- a/WebCore/platform/network/win/ResourceHandleWin.cpp +++ b/WebCore/platform/network/win/ResourceHandleWin.cpp @@ -27,43 +27,38 @@ #include "config.h" #include "ResourceHandle.h" -#include "CachedResourceLoader.h" -#include "Document.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "Page.h" +#include "HTTPParsers.h" +#include "MIMETypeRegistry.h" +#include "MainThread.h" +#include "NotImplemented.h" #include "ResourceError.h" #include "ResourceHandleClient.h" #include "ResourceHandleInternal.h" -#include "ResourceHandleWin.h" +#include "SharedBuffer.h" #include "Timer.h" -#include "WebCoreInstanceHandle.h" - +#include "UnusedParam.h" #include <wtf/text/CString.h> #include <windows.h> #include <wininet.h> namespace WebCore { -static unsigned transferJobId = 0; -static HashMap<int, ResourceHandle*>* jobIdMap = 0; +static inline HINTERNET createInternetHandle(const String& userAgent, bool asynchronous) +{ + String userAgentString = userAgent; + HINTERNET internetHandle = InternetOpenW(userAgentString.charactersWithNullTermination(), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, asynchronous ? INTERNET_FLAG_ASYNC : 0); -static HWND transferJobWindowHandle = 0; -const LPCWSTR kResourceHandleWindowClassName = L"ResourceHandleWindowClass"; + if (asynchronous) + InternetSetStatusCallback(internetHandle, &ResourceHandle::internetStatusCallback); -// Message types for internal use (keep in sync with kMessageHandlers) -enum { - handleCreatedMessage = WM_USER, - requestRedirectedMessage, - requestCompleteMessage -}; + return internetHandle; +} -typedef void (ResourceHandle:: *ResourceHandleEventHandler)(LPARAM); -static const ResourceHandleEventHandler messageHandlers[] = { - &ResourceHandle::onHandleCreated, - &ResourceHandle::onRequestRedirected, - &ResourceHandle::onRequestComplete -}; +static HINTERNET asynchronousInternetHandle(const String& userAgent) +{ + static HINTERNET internetHandle = createInternetHandle(userAgent, true); + return internetHandle; +} static String queryHTTPHeader(HINTERNET requestHandle, DWORD infoLevel) { @@ -79,69 +74,13 @@ static String queryHTTPHeader(HINTERNET requestHandle, DWORD infoLevel) return String::adopt(characters); } -static int addToOutstandingJobs(ResourceHandle* job) -{ - if (!jobIdMap) - jobIdMap = new HashMap<int, ResourceHandle*>; - transferJobId++; - jobIdMap->set(transferJobId, job); - return transferJobId; -} - -static void removeFromOutstandingJobs(int jobId) -{ - if (!jobIdMap) - return; - jobIdMap->remove(jobId); -} - -static ResourceHandle* lookupResourceHandle(int jobId) -{ - if (!jobIdMap) - return 0; - return jobIdMap->get(jobId); -} - -static LRESULT CALLBACK ResourceHandleWndProc(HWND hWnd, UINT message, - WPARAM wParam, LPARAM lParam) -{ - if (message >= handleCreatedMessage) { - UINT index = message - handleCreatedMessage; - if (index < _countof(messageHandlers)) { - unsigned jobId = (unsigned) wParam; - ResourceHandle* job = lookupResourceHandle(jobId); - if (job) { - ASSERT(job->d->m_jobId == jobId); - ASSERT(job->d->m_threadId == GetCurrentThreadId()); - (job->*(messageHandlers[index]))(lParam); - } - return 0; - } - } - return DefWindowProc(hWnd, message, wParam, lParam); -} - -static void initializeOffScreenResourceHandleWindow() -{ - if (transferJobWindowHandle) - return; - - WNDCLASSEX wcex; - memset(&wcex, 0, sizeof(WNDCLASSEX)); - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.lpfnWndProc = ResourceHandleWndProc; - wcex.hInstance = WebCore::instanceHandle(); - wcex.lpszClassName = kResourceHandleWindowClassName; - RegisterClassEx(&wcex); - - transferJobWindowHandle = CreateWindow(kResourceHandleWindowClassName, 0, 0, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, - HWND_MESSAGE, 0, WebCore::instanceHandle(), 0); -} - class WebCoreSynchronousLoader : public ResourceHandleClient, public Noncopyable { public: WebCoreSynchronousLoader(ResourceError&, ResourceResponse&, Vector<char>&, const String& userAgent); + ~WebCoreSynchronousLoader(); + + HINTERNET internetHandle() const { return m_internetHandle; } virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived); @@ -152,13 +91,20 @@ private: ResourceError& m_error; ResourceResponse& m_response; Vector<char>& m_data; + HINTERNET m_internetHandle; }; WebCoreSynchronousLoader::WebCoreSynchronousLoader(ResourceError& error, ResourceResponse& response, Vector<char>& data, const String& userAgent) : m_error(error) , m_response(response) , m_data(data) + , m_internetHandle(createInternetHandle(userAgent, false)) +{ +} + +WebCoreSynchronousLoader::~WebCoreSynchronousLoader() { + InternetCloseHandle(m_internetHandle); } void WebCoreSynchronousLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response) @@ -183,107 +129,79 @@ void WebCoreSynchronousLoader::didFail(ResourceHandle*, const ResourceError& err ResourceHandleInternal::~ResourceHandleInternal() { - if (m_fileHandle != INVALID_HANDLE_VALUE) - CloseHandle(m_fileHandle); } ResourceHandle::~ResourceHandle() { - if (d->m_jobId) - removeFromOutstandingJobs(d->m_jobId); } -void ResourceHandle::onHandleCreated(LPARAM lParam) +static void callOnRedirect(void* context) { - if (!d->m_resourceHandle) { - d->m_resourceHandle = HINTERNET(lParam); - if (d->status != 0) { - // We were canceled before Windows actually created a handle for us, close and delete now. - InternetCloseHandle(d->m_resourceHandle); - delete this; - return; - } + ResourceHandle* handle = static_cast<ResourceHandle*>(context); + handle->onRedirect(); +} - if (request().httpMethod() == "POST") { - // FIXME: Too late to set referrer properly. - String urlStr = request().url().path(); - int fragmentIndex = urlStr.find('#'); - if (fragmentIndex != -1) - urlStr = urlStr.left(fragmentIndex); - static LPCSTR accept[2]={"*/*", NULL}; - HINTERNET urlHandle = HttpOpenRequestA(d->m_resourceHandle, - "POST", urlStr.latin1().data(), 0, 0, accept, - INTERNET_FLAG_KEEP_CONNECTION | - INTERNET_FLAG_FORMS_SUBMIT | - INTERNET_FLAG_RELOAD | - INTERNET_FLAG_NO_CACHE_WRITE | - INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS | - INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP, - (DWORD_PTR)d->m_jobId); - if (urlHandle == INVALID_HANDLE_VALUE) { - InternetCloseHandle(d->m_resourceHandle); - delete this; - } - } - } else if (!d->m_secondaryHandle) { - assert(request().httpMethod() == "POST"); - d->m_secondaryHandle = HINTERNET(lParam); - - // Need to actually send the request now. - String headers = "Content-Type: application/x-www-form-urlencoded\n"; - headers += "Referer: "; - headers += d->m_postReferrer; - headers += "\n"; - const CString& headersLatin1 = headers.latin1(); - String formData = request().httpBody()->flattenToString(); - INTERNET_BUFFERSA buffers; - memset(&buffers, 0, sizeof(buffers)); - buffers.dwStructSize = sizeof(INTERNET_BUFFERSA); - buffers.lpcszHeader = headersLatin1.data(); - buffers.dwHeadersLength = headers.length(); - buffers.dwBufferTotal = formData.length(); - - d->m_bytesRemainingToWrite = formData.length(); - d->m_formDataString = (char*)malloc(formData.length()); - d->m_formDataLength = formData.length(); - strncpy(d->m_formDataString, formData.latin1().data(), formData.length()); - d->m_writing = true; - HttpSendRequestExA(d->m_secondaryHandle, &buffers, 0, 0, (DWORD_PTR)d->m_jobId); - // FIXME: add proper error handling +static void callOnRequestComplete(void* context) +{ + ResourceHandle* handle = static_cast<ResourceHandle*>(context); + handle->onRequestComplete(); +} + +void ResourceHandle::internetStatusCallback(HINTERNET internetHandle, DWORD_PTR context, DWORD internetStatus, + LPVOID statusInformation, DWORD statusInformationLength) +{ + ResourceHandle* handle = reinterpret_cast<ResourceHandle*>(context); + + switch (internetStatus) { + case INTERNET_STATUS_REDIRECT: + handle->d->m_redirectUrl = String(static_cast<UChar*>(statusInformation), statusInformationLength); + callOnMainThread(callOnRedirect, handle); + break; + + case INTERNET_STATUS_REQUEST_COMPLETE: + callOnMainThread(callOnRequestComplete, handle); + break; + + default: + break; } } -void ResourceHandle::onRequestRedirected(LPARAM lParam) +void ResourceHandle::onRedirect() { - // If already canceled, then ignore this event. - if (d->status != 0) - return; + ResourceRequest newRequest = firstRequest(); + newRequest.setURL(KURL(ParsedURLString, d->m_redirectUrl)); + + ResourceResponse response(firstRequest().url(), String(), 0, String(), String()); - ResourceRequest request((StringImpl*) lParam); - ResourceResponse redirectResponse; - client()->willSendRequest(this, request, redirectResponse); + if (ResourceHandleClient* resourceHandleClient = client()) + resourceHandleClient->willSendRequest(this, newRequest, response); } -void ResourceHandle::onRequestComplete(LPARAM lParam) +bool ResourceHandle::onRequestComplete() { - if (d->m_writing) { + if (!d->m_internetHandle) { // 0 if canceled. + deref(); // balances ref in start + return false; + } + + if (d->m_bytesRemainingToWrite) { DWORD bytesWritten; - InternetWriteFile(d->m_secondaryHandle, - d->m_formDataString + (d->m_formDataLength - d->m_bytesRemainingToWrite), + InternetWriteFile(d->m_requestHandle, + d->m_formData.data() + (d->m_formData.size() - d->m_bytesRemainingToWrite), d->m_bytesRemainingToWrite, &bytesWritten); d->m_bytesRemainingToWrite -= bytesWritten; - if (!d->m_bytesRemainingToWrite) { - // End the request. - d->m_writing = false; - HttpEndRequest(d->m_secondaryHandle, 0, 0, (DWORD_PTR)d->m_jobId); - free(d->m_formDataString); - d->m_formDataString = 0; - } - return; + if (d->m_bytesRemainingToWrite) + return true; + d->m_formData.clear(); } - HINTERNET handle = (request().httpMethod() == "POST") ? d->m_secondaryHandle : d->m_resourceHandle; + if (!d->m_sentEndRequest) { + HttpEndRequestW(d->m_requestHandle, 0, 0, reinterpret_cast<DWORD_PTR>(this)); + d->m_sentEndRequest = true; + return true; + } static const int bufferSize = 32768; char buffer[bufferSize]; @@ -293,9 +211,10 @@ void ResourceHandle::onRequestComplete(LPARAM lParam) buffers.dwBufferLength = bufferSize; BOOL ok = FALSE; - while ((ok = InternetReadFileExA(handle, &buffers, IRF_NO_WAIT, (DWORD_PTR)this)) && buffers.dwBufferLength) { - if (!hasReceivedResponse()) { - setHasReceivedResponse(); + while ((ok = InternetReadFileExA(d->m_requestHandle, &buffers, d->m_loadSynchronously ? 0 : IRF_NO_WAIT, reinterpret_cast<DWORD_PTR>(this))) && buffers.dwBufferLength) { + if (!d->m_hasReceivedResponse) { + d->m_hasReceivedResponse = true; + ResourceResponse response; response.setURL(firstRequest().url()); @@ -317,160 +236,112 @@ void ResourceHandle::onRequestComplete(LPARAM lParam) response.setTextEncodingName(extractCharsetFromMediaType(httpContentType)); } - client()->didReceiveResponse(this, response); + if (ResourceHandleClient* resourceHandleClient = client()) + resourceHandleClient->didReceiveResponse(this, response); } - client()->didReceiveData(this, buffer, buffers.dwBufferLength, 0); + + if (ResourceHandleClient* resourceHandleClient = client()) + resourceHandleClient->didReceiveData(this, buffer, buffers.dwBufferLength, 0); buffers.dwBufferLength = bufferSize; } - PlatformDataStruct platformData; - platformData.errorString = 0; - platformData.error = 0; - platformData.loaded = ok; - - if (!ok) { - int error = GetLastError(); - if (error == ERROR_IO_PENDING) - return; - DWORD errorStringChars = 0; - if (!InternetGetLastResponseInfo(&platformData.error, 0, &errorStringChars)) { - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - platformData.errorString = new TCHAR[errorStringChars]; - InternetGetLastResponseInfo(&platformData.error, platformData.errorString, &errorStringChars); - } - } -#ifdef RESOURCE_LOADER_DEBUG - char buf[64]; - _snprintf(buf, sizeof(buf), "Load error: %i\n", error); - OutputDebugStringA(buf); -#endif - } - - if (d->m_secondaryHandle) - InternetCloseHandle(d->m_secondaryHandle); - InternetCloseHandle(d->m_resourceHandle); + if (!ok && GetLastError() == ERROR_IO_PENDING) + return true; - client()->didFinishLoading(this, 0); - delete this; + if (ResourceHandleClient* resourceHandleClient = client()) + resourceHandleClient->didFinishLoading(this, 0); + + InternetCloseHandle(d->m_requestHandle); + InternetCloseHandle(d->m_connectHandle); + deref(); // balances ref in start + return false; } -static void __stdcall transferJobStatusCallback(HINTERNET internetHandle, - DWORD_PTR jobId, - DWORD internetStatus, - LPVOID statusInformation, - DWORD statusInformationLength) +bool ResourceHandle::start(NetworkingContext* context) { -#ifdef RESOURCE_LOADER_DEBUG - char buf[64]; - _snprintf(buf, sizeof(buf), "status-callback: status=%u, job=%p\n", - internetStatus, jobId); - OutputDebugStringA(buf); -#endif + if (request().url().isLocalFile()) { + ref(); // balanced by deref in fileLoadTimer + if (d->m_loadSynchronously) + fileLoadTimer(0); + else + d->m_fileLoadTimer.startOneShot(0.0); + return true; + } - UINT msg; - LPARAM lParam; + if (!d->m_internetHandle) + d->m_internetHandle = asynchronousInternetHandle(context->userAgent()); - switch (internetStatus) { - case INTERNET_STATUS_HANDLE_CREATED: - // tell the main thread about the newly created handle - msg = handleCreatedMessage; - lParam = (LPARAM) LPINTERNET_ASYNC_RESULT(statusInformation)->dwResult; - break; - case INTERNET_STATUS_REQUEST_COMPLETE: -#ifdef RESOURCE_LOADER_DEBUG - _snprintf(buf, sizeof(buf), "request-complete: result=%p, error=%u\n", - LPINTERNET_ASYNC_RESULT(statusInformation)->dwResult, - LPINTERNET_ASYNC_RESULT(statusInformation)->dwError); - OutputDebugStringA(buf); -#endif - // tell the main thread that the request is done - msg = requestCompleteMessage; - lParam = 0; - break; - case INTERNET_STATUS_REDIRECT: - // tell the main thread to observe this redirect (FIXME: we probably - // need to block the redirect at this point so the application can - // decide whether or not to follow the redirect) - msg = requestRedirectedMessage; - lParam = (LPARAM) StringImpl::create((const UChar*) statusInformation, - statusInformationLength).releaseRef(); - break; - case INTERNET_STATUS_USER_INPUT_REQUIRED: - // FIXME: prompt the user if necessary - ResumeSuspendedDownload(internetHandle, 0); - case INTERNET_STATUS_STATE_CHANGE: - // may need to call ResumeSuspendedDownload here as well - default: - return; + if (!d->m_internetHandle) + return false; + + DWORD flags = INTERNET_FLAG_KEEP_CONNECTION + | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS + | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP; + + d->m_connectHandle = InternetConnectW(d->m_internetHandle, firstRequest().url().host().charactersWithNullTermination(), firstRequest().url().port(), + 0, 0, INTERNET_SERVICE_HTTP, flags, reinterpret_cast<DWORD_PTR>(this)); + + if (!d->m_connectHandle) + return false; + + String urlStr = firstRequest().url().path(); + String urlQuery = firstRequest().url().query(); + + if (!urlQuery.isEmpty()) { + urlStr.append('?'); + urlStr.append(urlQuery); } - PostMessage(transferJobWindowHandle, msg, (WPARAM) jobId, lParam); -} + String httpMethod = firstRequest().httpMethod(); + String httpReferrer = firstRequest().httpReferrer(); -bool ResourceHandle::start(NetworkingContext* context) -{ - ref(); - if (request().url().isLocalFile()) { - d->m_fileLoadTimer.startOneShot(0.0); - return true; - } else { - static HINTERNET internetHandle = 0; - if (!internetHandle) { - String userAgentStr = context->userAgent() + String("", 1); - LPCWSTR userAgent = reinterpret_cast<const WCHAR*>(userAgentStr.characters()); - // leak the Internet for now - internetHandle = InternetOpen(userAgent, INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, INTERNET_FLAG_ASYNC); - } - if (!internetHandle) { - delete this; - return false; - } - static INTERNET_STATUS_CALLBACK callbackHandle = - InternetSetStatusCallback(internetHandle, transferJobStatusCallback); - - initializeOffScreenResourceHandleWindow(); - d->m_jobId = addToOutstandingJobs(this); - - DWORD flags = - INTERNET_FLAG_KEEP_CONNECTION | - INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS | - INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP; - - // For form posting, we can't use InternetOpenURL. We have to use - // InternetConnect followed by HttpSendRequest. - HINTERNET urlHandle; - String referrer = context->referrer(); - if (request().httpMethod() == "POST") { - d->m_postReferrer = referrer; - String host = request().url().host(); - urlHandle = InternetConnectA(internetHandle, host.latin1().data(), - request().url().port(), - NULL, // no username - NULL, // no password - INTERNET_SERVICE_HTTP, - flags, (DWORD_PTR)d->m_jobId); - } else { - String urlStr = request().url().string(); - int fragmentIndex = urlStr.find('#'); - if (fragmentIndex != -1) - urlStr = urlStr.left(fragmentIndex); - String headers; - if (!referrer.isEmpty()) - headers += String("Referer: ") + referrer + "\r\n"; - - urlHandle = InternetOpenUrlA(internetHandle, urlStr.latin1().data(), - headers.latin1().data(), headers.length(), - flags, (DWORD_PTR)d->m_jobId); - } + LPCWSTR httpAccept[] = { L"*/*", 0 }; - if (urlHandle == INVALID_HANDLE_VALUE) { - delete this; - return false; - } - d->m_threadId = GetCurrentThreadId(); + d->m_requestHandle = HttpOpenRequestW(d->m_connectHandle, httpMethod.charactersWithNullTermination(), urlStr.charactersWithNullTermination(), + 0, httpReferrer.charactersWithNullTermination(), httpAccept, flags, reinterpret_cast<DWORD_PTR>(this)); - return true; + if (!d->m_requestHandle) { + InternetCloseHandle(d->m_connectHandle); + return false; + } + + if (firstRequest().httpBody()) { + firstRequest().httpBody()->flatten(d->m_formData); + d->m_bytesRemainingToWrite = d->m_formData.size(); + } + + Vector<UChar> httpHeaders; + const HTTPHeaderMap& httpHeaderFields = firstRequest().httpHeaderFields(); + + for (HTTPHeaderMap::const_iterator it = httpHeaderFields.begin(); it != httpHeaderFields.end(); ++it) { + if (equalIgnoringCase(it->first, "Accept") || equalIgnoringCase(it->first, "Referer") || equalIgnoringCase(it->first, "User-Agent")) + continue; + + if (!httpHeaders.isEmpty()) + httpHeaders.append('\n'); + + httpHeaders.append(it->first.characters(), it->first.length()); + httpHeaders.append(':'); + httpHeaders.append(it->second.characters(), it->second.length()); } + + INTERNET_BUFFERSW internetBuffers; + ZeroMemory(&internetBuffers, sizeof(internetBuffers)); + internetBuffers.dwStructSize = sizeof(internetBuffers); + internetBuffers.lpcszHeader = httpHeaders.data(); + internetBuffers.dwHeadersLength = httpHeaders.size(); + internetBuffers.dwBufferTotal = d->m_bytesRemainingToWrite; + + HttpSendRequestExW(d->m_requestHandle, &internetBuffers, 0, 0, reinterpret_cast<DWORD_PTR>(this)); + + ref(); // balanced by deref in onRequestComplete + + if (d->m_loadSynchronously) + while (onRequestComplete()) { + // Loop until finished. + } + + return true; } void ResourceHandle::fileLoadTimer(Timer<ResourceHandle>*) @@ -517,37 +388,29 @@ void ResourceHandle::fileLoadTimer(Timer<ResourceHandle>*) void ResourceHandle::cancel() { - if (d->m_resourceHandle) - InternetCloseHandle(d->m_resourceHandle); - else + if (d->m_requestHandle) { + d->m_internetHandle = 0; + InternetCloseHandle(d->m_requestHandle); + InternetCloseHandle(d->m_connectHandle); + } else d->m_fileLoadTimer.stop(); - - client()->didFinishLoading(this, 0); - - if (!d->m_resourceHandle) - // Async load canceled before we have a handle -- mark ourselves as in error, to be deleted later. - // FIXME: need real cancel error - client()->didFail(this, ResourceError()); } -void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame* frame) +void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data) { UNUSED_PARAM(storedCredentials); WebCoreSynchronousLoader syncLoader(error, response, data, request.httpUserAgent()); ResourceHandle handle(request, &syncLoader, true, false); - handle.start(frame); -} - -void ResourceHandle::setHasReceivedResponse(bool b) -{ - d->m_hasReceivedResponse = b; + handle.setSynchronousInternetHandle(syncLoader.internetHandle()); + handle.start(context); } -bool ResourceHandle::hasReceivedResponse() const +void ResourceHandle::setSynchronousInternetHandle(HINTERNET internetHandle) { - return d->m_hasReceivedResponse; + d->m_internetHandle = internetHandle; + d->m_loadSynchronously = true; } bool ResourceHandle::willLoadFromCache(ResourceRequest&, Frame*) diff --git a/WebCore/platform/qt/ClipboardQt.cpp b/WebCore/platform/qt/ClipboardQt.cpp index 6cbde0c..90e3bfe 100644 --- a/WebCore/platform/qt/ClipboardQt.cpp +++ b/WebCore/platform/qt/ClipboardQt.cpp @@ -75,15 +75,15 @@ PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* } ClipboardQt::ClipboardQt(ClipboardAccessPolicy policy, const QMimeData* readableClipboard) - : Clipboard(policy, true) + : Clipboard(policy, DragAndDrop) , m_readableData(readableClipboard) , m_writableData(0) { Q_ASSERT(policy == ClipboardReadable || policy == ClipboardTypesReadable); } -ClipboardQt::ClipboardQt(ClipboardAccessPolicy policy, bool forDragging) - : Clipboard(policy, forDragging) +ClipboardQt::ClipboardQt(ClipboardAccessPolicy policy, ClipboardType clipboardType) + : Clipboard(policy, clipboardType) , m_readableData(0) , m_writableData(0) { @@ -91,7 +91,7 @@ ClipboardQt::ClipboardQt(ClipboardAccessPolicy policy, bool forDragging) #ifndef QT_NO_CLIPBOARD if (policy != ClipboardWritable) { - Q_ASSERT(!forDragging); + Q_ASSERT(isForCopyAndPaste()); m_readableData = QApplication::clipboard()->mimeData(); } #endif @@ -99,7 +99,7 @@ ClipboardQt::ClipboardQt(ClipboardAccessPolicy policy, bool forDragging) ClipboardQt::~ClipboardQt() { - if (m_writableData && !isForDragging()) + if (m_writableData && isForCopyAndPaste()) m_writableData = 0; else delete m_writableData; @@ -114,13 +114,13 @@ void ClipboardQt::clearData(const String& type) if (m_writableData) { m_writableData->removeFormat(type); if (m_writableData->formats().isEmpty()) { - if (isForDragging()) + if (isForDragAndDrop()) delete m_writableData; m_writableData = 0; } } #ifndef QT_NO_CLIPBOARD - if (!isForDragging()) + if (isForCopyAndPaste()) QApplication::clipboard()->setMimeData(m_writableData); #endif } @@ -131,7 +131,7 @@ void ClipboardQt::clearAllData() return; #ifndef QT_NO_CLIPBOARD - if (!isForDragging()) + if (isForCopyAndPaste()) QApplication::clipboard()->setMimeData(0); else #endif @@ -182,7 +182,7 @@ bool ClipboardQt::setData(const String& type, const String& data) } #ifndef QT_NO_CLIPBOARD - if (!isForDragging()) + if (isForCopyAndPaste()) QApplication::clipboard()->setMimeData(m_writableData); #endif return true; @@ -287,7 +287,7 @@ void ClipboardQt::declareAndWriteDragImage(Element* element, const KURL& url, co m_writableData->setText(title); m_writableData->setUrls(urls); #ifndef QT_NO_CLIPBOARD - if (!isForDragging()) + if (isForCopyAndPaste()) QApplication::clipboard()->setMimeData(m_writableData); #endif } @@ -303,7 +303,7 @@ void ClipboardQt::writeURL(const KURL& url, const String& title, Frame* frame) m_writableData->setUrls(urls); m_writableData->setText(title); #ifndef QT_NO_CLIPBOARD - if (!isForDragging()) + if (isForCopyAndPaste()) QApplication::clipboard()->setMimeData(m_writableData); #endif } @@ -320,7 +320,7 @@ void ClipboardQt::writeRange(Range* range, Frame* frame) m_writableData->setText(text); m_writableData->setHtml(createMarkup(range, 0, AnnotateForInterchange, false, AbsoluteURLs)); #ifndef QT_NO_CLIPBOARD - if (!isForDragging()) + if (isForCopyAndPaste()) QApplication::clipboard()->setMimeData(m_writableData); #endif } @@ -333,7 +333,7 @@ void ClipboardQt::writePlainText(const String& str) text.replace(QChar(0xa0), QLatin1Char(' ')); m_writableData->setText(text); #ifndef QT_NO_CLIPBOARD - if (!isForDragging()) + if (isForCopyAndPaste()) QApplication::clipboard()->setMimeData(m_writableData); #endif } diff --git a/WebCore/platform/qt/ClipboardQt.h b/WebCore/platform/qt/ClipboardQt.h index 9b54d5f..5aca1a6 100644 --- a/WebCore/platform/qt/ClipboardQt.h +++ b/WebCore/platform/qt/ClipboardQt.h @@ -44,9 +44,9 @@ namespace WebCore { { return adoptRef(new ClipboardQt(policy, readableClipboard)); } - static PassRefPtr<ClipboardQt> create(ClipboardAccessPolicy policy, bool forDragging = false) + static PassRefPtr<ClipboardQt> create(ClipboardAccessPolicy policy, ClipboardType clipboardType = CopyAndPaste) { - return adoptRef(new ClipboardQt(policy, forDragging)); + return adoptRef(new ClipboardQt(policy, clipboardType)); } virtual ~ClipboardQt(); @@ -77,7 +77,7 @@ namespace WebCore { ClipboardQt(ClipboardAccessPolicy, const QMimeData* readableClipboard); // Clipboard is writable so it will create its own QMimeData object - ClipboardQt(ClipboardAccessPolicy, bool forDragging); + ClipboardQt(ClipboardAccessPolicy, ClipboardType); void setDragImage(CachedImage*, Node*, const IntPoint& loc); diff --git a/WebCore/platform/qt/QWebPageClient.h b/WebCore/platform/qt/QWebPageClient.h index a0a0218..9301cd5 100644 --- a/WebCore/platform/qt/QWebPageClient.h +++ b/WebCore/platform/qt/QWebPageClient.h @@ -58,9 +58,7 @@ public: virtual bool allowsAcceleratedCompositing() const { return false; } #endif -#if QT_VERSION >= 0x040600 virtual void setInputMethodHints(Qt::InputMethodHints hint) = 0; -#endif #ifndef QT_NO_CURSOR inline void resetCursor() diff --git a/WebCore/platform/qt/RenderThemeQt.cpp b/WebCore/platform/qt/RenderThemeQt.cpp index 4a461ac..7388b76 100644 --- a/WebCore/platform/qt/RenderThemeQt.cpp +++ b/WebCore/platform/qt/RenderThemeQt.cpp @@ -219,7 +219,7 @@ String RenderThemeQt::extraDefaultStyleSheet() result += String(themeQtNoListboxesUserAgentStyleSheet, sizeof(themeQtNoListboxesUserAgentStyleSheet)); #endif #if USE(QT_MOBILE_THEME) - result += String(themeQtMaemo5UserAgentStyleSheet, sizeof(themeQtMaemo5UserAgentStyleSheet)); + result += String(themeQtMobileUserAgentStyleSheet, sizeof(themeQtMobileUserAgentStyleSheet)); #endif return result; } diff --git a/WebCore/platform/qt/TemporaryLinkStubsQt.cpp b/WebCore/platform/qt/TemporaryLinkStubsQt.cpp index 51e25b8..15933e8 100644 --- a/WebCore/platform/qt/TemporaryLinkStubsQt.cpp +++ b/WebCore/platform/qt/TemporaryLinkStubsQt.cpp @@ -87,6 +87,19 @@ bool PluginDatabase::isPreferredPluginDirectory(const String& directory) notImplemented(); return false; } + +void PluginView::privateBrowsingStateChanged(bool) +{ +} + +PassRefPtr<JSC::Bindings::Instance> PluginView::bindingInstance() +{ + return 0; +} + +void PluginView::setJavaScriptPaused(bool) +{ +} #endif namespace WebCore { diff --git a/WebCore/platform/sql/SQLiteFileSystem.cpp b/WebCore/platform/sql/SQLiteFileSystem.cpp index c9583eb..d487b95 100644 --- a/WebCore/platform/sql/SQLiteFileSystem.cpp +++ b/WebCore/platform/sql/SQLiteFileSystem.cpp @@ -28,12 +28,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define __STDC_FORMAT_MACROS #include "config.h" #include "SQLiteFileSystem.h" #include "FileSystem.h" #include "SQLiteDatabase.h" #include "SQLiteStatement.h" +#include <inttypes.h> #include <sqlite3.h> namespace WebCore { @@ -73,10 +75,10 @@ String SQLiteFileSystem::getFileNameForNewDatabase(const String& dbDir, const St String fileName; do { ++seq; - fileName = pathByAppendingComponent(dbDir, String::format("%016llx.db", seq)); + fileName = pathByAppendingComponent(dbDir, String::format("%016"PRIx64".db", seq)); } while (fileExists(fileName)); - return String::format("%016llx.db", seq); + return String::format("%016"PRIx64".db", seq); } String SQLiteFileSystem::appendDatabaseFileNameToPath(const String& path, const String& fileName) diff --git a/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp b/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp index 6549936..1102df5 100644 --- a/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp +++ b/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp @@ -34,23 +34,938 @@ #include "ChromiumBridge.h" #include <sqlite3.h> +#include <errno.h> #include <fcntl.h> #include <string.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> #include <unistd.h> using namespace WebCore; -// Defined in Chromium's codebase in third_party/sqlite/src/os_unix.c -extern "C" { -void chromium_sqlite3_initialize_unix_sqlite3_file(sqlite3_file* file); -int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* vfs, int fd, int dirfd, sqlite3_file* file, const char* fileName, int noLock); -int chromium_sqlite3_get_reusable_file_handle(sqlite3_file* file, const char* fileName, int flags, int* fd); -void chromium_sqlite3_update_reusable_file_handle(sqlite3_file* file, int fd, int flags); -void chromium_sqlite3_destroy_reusable_file_handle(sqlite3_file* file); +// Chromium's Posix implementation of SQLite VFS. +// This is heavily based on SQLite's os_unix.c, +// without parts we don't need. + +// Identifies a file by its device number and inode. +struct ChromiumFileId { + dev_t dev; // Device number. + ino_t ino; // Inode number. +}; + +// Information about file locks (one per open inode). Note that many open +// file descriptors may refer to the same inode. +struct ChromiumLockInfo { + ChromiumFileId lockKey; // File identifier. + int cnt; // Number of shared locks held. + int locktype; // Type of the lock. + int nRef; // Reference count. + + // Double-linked list pointers. + ChromiumLockInfo* pNext; + ChromiumLockInfo* pPrev; +}; + +// Information about a file descriptor that cannot be closed immediately. +struct ChromiumUnusedFd { + int fd; // File descriptor. + int flags; // Flags this file descriptor was opened with. + ChromiumUnusedFd* pNext; // Next unused file descriptor on the same file. +}; + +// Information about an open inode. When we want to close an inode +// that still has locks, we defer the close until all locks are cleared. +struct ChromiumOpenInfo { + ChromiumFileId fileId; // The lookup key. + int nRef; // Reference count. + int nLock; // Number of outstanding locks. + ChromiumUnusedFd* pUnused; // List of file descriptors to close. + + // Double-linked list pointers. + ChromiumOpenInfo* pNext; + ChromiumOpenInfo* pPrev; +}; + +// Keep track of locks and inodes in double-linked lists. +static struct ChromiumLockInfo* lockList = 0; +static struct ChromiumOpenInfo* openList = 0; + +// Extension of sqlite3_file specific to the chromium VFS. +struct ChromiumFile { + sqlite3_io_methods const* pMethod; // Implementation of sqlite3_file. + ChromiumOpenInfo* pOpen; // Information about all open file descriptors for this file. + ChromiumLockInfo* pLock; // Information about all locks for this file. + int h; // File descriptor. + int dirfd; // File descriptor for the file directory. + unsigned char locktype; // Type of the lock used for this file. + int lastErrno; // Value of errno for last operation on this file. + ChromiumUnusedFd* pUnused; // Information about unused file descriptors for this file. +}; + +// The following constants specify the range of bytes used for locking. +// SQLiteSharedSize is the number of bytes available in the pool from which +// a random byte is selected for a shared lock. The pool of bytes for +// shared locks begins at SQLiteSharedFirstByte. +// The values are the same as used by SQLite for compatibility. +static const off_t SQLitePendingByte = 0x40000000; +static const off_t SQLiteReservedByte = SQLitePendingByte + 1; +static const off_t SQLiteSharedFirstByte = SQLitePendingByte + 2; +static const off_t SQLiteSharedSize = 510; + +// Maps a POSIX error code to an SQLite error code. +static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) +{ + switch (posixError) { + case 0: + return SQLITE_OK; + case EAGAIN: + case ETIMEDOUT: + case EBUSY: + case EINTR: + case ENOLCK: + return SQLITE_BUSY; + case EACCES: + // EACCES is like EAGAIN during locking operations. + if ((sqliteIOErr == SQLITE_IOERR_LOCK) || + (sqliteIOErr == SQLITE_IOERR_UNLOCK) || + (sqliteIOErr == SQLITE_IOERR_RDLOCK) || + (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK)) + return SQLITE_BUSY; + return SQLITE_PERM; + case EPERM: + return SQLITE_PERM; + case EDEADLK: + return SQLITE_IOERR_BLOCKED; + default: + return sqliteIOErr; + } +} + +// Releases a ChromiumLockInfo structure previously allocated by findLockInfo(). +static void releaseLockInfo(ChromiumLockInfo* pLock) +{ + if (!pLock) + return; + + pLock->nRef--; + if (pLock->nRef > 0) + return; + + if (pLock->pPrev) { + ASSERT(pLock->pPrev->pNext == pLock); + pLock->pPrev->pNext = pLock->pNext; + } else { + ASSERT(lockList == pLock); + lockList = pLock->pNext; + } + if (pLock->pNext) { + ASSERT(pLock->pNext->pPrev == pLock); + pLock->pNext->pPrev = pLock->pPrev; + } + + sqlite3_free(pLock); +} + +// Releases a ChromiumOpenInfo structure previously allocated by findLockInfo(). +static void releaseOpenInfo(ChromiumOpenInfo* pOpen) +{ + if (!pOpen) + return; + + pOpen->nRef--; + if (pOpen->nRef > 0) + return; + + if (pOpen->pPrev) { + ASSERT(pOpen->pPrev->pNext == pOpen); + pOpen->pPrev->pNext = pOpen->pNext; + } else { + ASSERT(openList == pOpen); + openList = pOpen->pNext; + } + if (pOpen->pNext) { + ASSERT(pOpen->pNext->pPrev == pOpen); + pOpen->pNext->pPrev = pOpen->pPrev; + } + + ASSERT(!pOpen->pUnused); // Make sure we're not leaking memory and file descriptors. + + sqlite3_free(pOpen); +} + +// Locates ChromiumLockInfo and ChromiumOpenInfo for given file descriptor (creating new ones if needed). +// Returns a SQLite error code. +static int findLockInfo(ChromiumFile* pFile, ChromiumLockInfo** ppLock, ChromiumOpenInfo** ppOpen) +{ + int fd = pFile->h; + struct stat statbuf; + int rc = fstat(fd, &statbuf); + if (rc) { + pFile->lastErrno = errno; +#ifdef EOVERFLOW + if (pFile->lastErrno == EOVERFLOW) + return SQLITE_NOLFS; +#endif + return SQLITE_IOERR; + } + +#if OS(DARWIN) + // On OS X on an msdos/fat filesystems, the inode number is reported + // incorrectly for zero-size files. See http://www.sqlite.org/cvstrac/tktview?tn=3260. + // To work around this problem we always increase the file size to 1 by writing a single byte + // prior to accessing the inode number. The one byte written is an ASCII 'S' character which + // also happens to be the first byte in the header of every SQLite database. In this way, + // if there is a race condition such that another thread has already populated the first page + // of the database, no damage is done. + if (!statbuf.st_size) { + rc = write(fd, "S", 1); + if (rc != 1) + return SQLITE_IOERR; + rc = fstat(fd, &statbuf); + if (rc) { + pFile->lastErrno = errno; + return SQLITE_IOERR; + } + } +#endif + + ChromiumFileId fileId; + memset(&fileId, 0, sizeof(fileId)); + fileId.dev = statbuf.st_dev; + fileId.ino = statbuf.st_ino; + + ChromiumLockInfo* pLock = 0; + + if (ppLock) { + pLock = lockList; + while (pLock && memcmp(&fileId, &pLock->lockKey, sizeof(fileId))) + pLock = pLock->pNext; + if (pLock) + pLock->nRef++; + else { + pLock = static_cast<ChromiumLockInfo*>(sqlite3_malloc(sizeof(*pLock))); + if (!pLock) + return SQLITE_NOMEM; + pLock->lockKey = fileId; + pLock->nRef = 1; + pLock->cnt = 0; + pLock->locktype = 0; + pLock->pNext = lockList; + pLock->pPrev = 0; + if (lockList) + lockList->pPrev = pLock; + lockList = pLock; + } + *ppLock = pLock; + } + + if (ppOpen) { + ChromiumOpenInfo* pOpen = openList; + while (pOpen && memcmp(&fileId, &pOpen->fileId, sizeof(fileId))) + pOpen = pOpen->pNext; + if (pOpen) + pOpen->nRef++; + else { + pOpen = static_cast<ChromiumOpenInfo*>(sqlite3_malloc(sizeof(*pOpen))); + if (!pOpen) { + releaseLockInfo(pLock); + return SQLITE_NOMEM; + } + memset(pOpen, 0, sizeof(*pOpen)); + pOpen->fileId = fileId; + pOpen->nRef = 1; + pOpen->pNext = openList; + if (openList) + openList->pPrev = pOpen; + openList = pOpen; + } + *ppOpen = pOpen; + } + + return rc; +} + +// Checks if there is a RESERVED lock held on the specified file by this or any other process. +// If the lock is held, sets pResOut to a non-zero value. Returns a SQLite error code. +static int chromiumCheckReservedLock(sqlite3_file* id, int* pResOut) +{ + ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id); + ASSERT(pFile); + + // Look for locks held by this process. + int reserved = 0; + if (pFile->pLock->locktype > SQLITE_LOCK_SHARED) + reserved = 1; + + // Look for locks held by other processes. + int rc = SQLITE_OK; + if (!reserved) { + struct flock lock; + lock.l_whence = SEEK_SET; + lock.l_start = SQLiteReservedByte; + lock.l_len = 1; + lock.l_type = F_WRLCK; + if (-1 == fcntl(pFile->h, F_GETLK, &lock)) { + int tErrno = errno; + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK); + pFile->lastErrno = tErrno; + } else if (lock.l_type != F_UNLCK) + reserved = 1; + } + + *pResOut = reserved; + return rc; +} + +// Performs a file locking operation on a range of bytes in a file. +// The |op| parameter should be one of F_RFLCK, F_WRLCK or F_UNLCK. +// Returns a Unix error code, and also writes it to pErrcode. +static int rangeLock(ChromiumFile* pFile, int op, int* pErrcode) +{ + struct flock lock; + lock.l_type = op; + lock.l_start = SQLiteSharedFirstByte; + lock.l_whence = SEEK_SET; + lock.l_len = SQLiteSharedSize; + int rc = fcntl(pFile->h, F_SETLK, &lock); + *pErrcode = errno; + return rc; +} + +// Locks the file with the lock specified by parameter locktype - one +// of the following: +// +// (1) SQLITE_LOCK_SHARED +// (2) SQLITE_LOCK_RESERVED +// (3) SQLITE_LOCK_PENDING +// (4) SQLITE_LOCK_EXCLUSIVE +// +// Sometimes when requesting one lock state, additional lock states +// are inserted in between. The locking might fail on one of the later +// transitions leaving the lock state different from what it started but +// still short of its goal. The following chart shows the allowed +// transitions and the inserted intermediate states: +// +// UNLOCKED -> SHARED +// SHARED -> RESERVED +// SHARED -> (PENDING) -> EXCLUSIVE +// RESERVED -> (PENDING) -> EXCLUSIVE +// PENDING -> EXCLUSIVE +static int chromiumLock(sqlite3_file* id, int locktype) +{ + // To obtain a SHARED lock, a read-lock is obtained on the 'pending + // byte'. If this is successful, a random byte from the 'shared byte + // range' is read-locked and the lock on the 'pending byte' released. + // + // A process may only obtain a RESERVED lock after it has a SHARED lock. + // A RESERVED lock is implemented by grabbing a write-lock on the + // 'reserved byte'. + // + // A process may only obtain a PENDING lock after it has obtained a + // SHARED lock. A PENDING lock is implemented by obtaining a write-lock + // on the 'pending byte'. This ensures that no new SHARED locks can be + // obtained, but existing SHARED locks are allowed to persist. A process + // does not have to obtain a RESERVED lock on the way to a PENDING lock. + // This property is used by the algorithm for rolling back a journal file + // after a crash. + // + // An EXCLUSIVE lock, obtained after a PENDING lock is held, is + // implemented by obtaining a write-lock on the entire 'shared byte + // range'. Since all other locks require a read-lock on one of the bytes + // within this range, this ensures that no other locks are held on the + // database. + + int rc = SQLITE_OK; + struct flock lock; + int s = 0; + int tErrno; + + ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id); + ASSERT(pFile); + + ChromiumLockInfo* pLock = pFile->pLock; + + // If there is already a lock of this type or more restrictive, do nothing. + if (pFile->locktype >= locktype) + return SQLITE_OK; + + // Make sure we never move from unlocked to anything higher than shared lock. + ASSERT(pFile->locktype != SQLITE_LOCK_NONE || locktype == SQLITE_LOCK_SHARED); + + // Make sure we never request a pending lock. + ASSERT(locktype != SQLITE_LOCK_PENDING); + + // Make sure a shared lock is always held when a RESERVED lock is requested. + ASSERT(locktype != SQLITE_LOCK_RESERVED || pFile->locktype == SQLITE_LOCK_SHARED); + + // If some thread using this PID has a lock via a different ChromiumFile + // handle that precludes the requested lock, return BUSY. + if (pFile->locktype != pLock->locktype && + (pLock->locktype >= SQLITE_LOCK_PENDING || locktype > SQLITE_LOCK_SHARED)) + return SQLITE_BUSY; + + // If a SHARED lock is requested, and some thread using this PID already + // has a SHARED or RESERVED lock, then just increment reference counts. + if (locktype == SQLITE_LOCK_SHARED && + (pLock->locktype == SQLITE_LOCK_SHARED || pLock->locktype == SQLITE_LOCK_RESERVED)) { + ASSERT(!pFile->locktype); + ASSERT(pLock->cnt > 0); + pFile->locktype = SQLITE_LOCK_SHARED; + pLock->cnt++; + pFile->pOpen->nLock++; + return SQLITE_OK; + } + + // A PENDING lock is needed before acquiring a SHARED lock and before + // acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will + // be released. + lock.l_len = 1; + lock.l_whence = SEEK_SET; + if (locktype == SQLITE_LOCK_SHARED || + (locktype == SQLITE_LOCK_EXCLUSIVE && pFile->locktype < SQLITE_LOCK_PENDING)) { + lock.l_type = (locktype == SQLITE_LOCK_SHARED ? F_RDLCK : F_WRLCK); + lock.l_start = SQLitePendingByte; + s = fcntl(pFile->h, F_SETLK, &lock); + if (s == -1) { + tErrno = errno; + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); + if ((rc != SQLITE_OK) && (rc != SQLITE_BUSY)) + pFile->lastErrno = tErrno; + return rc; + } + } + + if (locktype == SQLITE_LOCK_SHARED) { + ASSERT(!pLock->cnt); + ASSERT(!pLock->locktype); + + s = rangeLock(pFile, F_RDLCK, &tErrno); + + // Drop the temporary PENDING lock. + lock.l_start = SQLitePendingByte; + lock.l_len = 1; + lock.l_type = F_UNLCK; + if (fcntl(pFile->h, F_SETLK, &lock)) { + if (s != -1) { + tErrno = errno; + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); + if ((rc != SQLITE_OK) && (rc != SQLITE_BUSY)) + pFile->lastErrno = tErrno; + return rc; + } + } + if (s == -1) { + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); + if ((rc != SQLITE_OK) && (rc != SQLITE_BUSY)) + pFile->lastErrno = tErrno; + } else { + pFile->locktype = SQLITE_LOCK_SHARED; + pFile->pOpen->nLock++; + pLock->cnt = 1; + } + } else if (locktype == SQLITE_LOCK_EXCLUSIVE && pLock->cnt > 1) { + // We are trying for an exclusive lock but another thread in the + // same process is still holding a shared lock. + rc = SQLITE_BUSY; + } else { + // The request was for a RESERVED or EXCLUSIVE lock. It is + // assumed that there is a SHARED or greater lock on the file + // already. + ASSERT(pFile->locktype); + lock.l_type = F_WRLCK; + switch (locktype) { + case SQLITE_LOCK_RESERVED: + lock.l_start = SQLiteReservedByte; + s = fcntl(pFile->h, F_SETLK, &lock); + tErrno = errno; + break; + case SQLITE_LOCK_EXCLUSIVE: + s = rangeLock(pFile, F_WRLCK, &tErrno); + break; + default: + ASSERT_NOT_REACHED(); + } + if (s == -1) { + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); + if ((rc != SQLITE_OK) && (rc != SQLITE_BUSY)) + pFile->lastErrno = tErrno; + } + } + + if (rc == SQLITE_OK) { + pFile->locktype = locktype; + pLock->locktype = locktype; + } else if (locktype == SQLITE_LOCK_EXCLUSIVE) { + pFile->locktype = SQLITE_LOCK_PENDING; + pLock->locktype = SQLITE_LOCK_PENDING; + } + + return rc; +} + +// Closes all file descriptors for given ChromiumFile for which the close has been deferred. +// Returns a SQLite error code. +static int closePendingFds(ChromiumFile* pFile) +{ + int rc = SQLITE_OK; + ChromiumOpenInfo* pOpen = pFile->pOpen; + ChromiumUnusedFd* pError = 0; + ChromiumUnusedFd* pNext; + for (ChromiumUnusedFd* p = pOpen->pUnused; p; p = pNext) { + pNext = p->pNext; + if (close(p->fd)) { + pFile->lastErrno = errno; + rc = SQLITE_IOERR_CLOSE; + p->pNext = pError; + pError = p; + } else + sqlite3_free(p); + } + pOpen->pUnused = pError; + return rc; +} + +// Lowers the locking level on file descriptor. +// locktype must be either SQLITE_LOCK_NONE or SQLITE_LOCK_SHARED. +static int chromiumUnlock(sqlite3_file* id, int locktype) +{ + ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id); + ASSERT(pFile); + ASSERT(locktype <= SQLITE_LOCK_SHARED); + + if (pFile->locktype <= locktype) + return SQLITE_OK; + + ChromiumLockInfo* pLock = pFile->pLock; + ASSERT(pLock->cnt); + + struct flock lock; + int rc = SQLITE_OK; + int h = pFile->h; + int tErrno; + + if (pFile->locktype > SQLITE_LOCK_SHARED) { + ASSERT(pLock->locktype == pFile->locktype); + + if (locktype == SQLITE_LOCK_SHARED && rangeLock(pFile, F_RDLCK, &tErrno) == -1) { + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK); + if ((rc != SQLITE_OK) && (rc != SQLITE_BUSY)) + pFile->lastErrno = tErrno; + if (rc == SQLITE_OK) + pFile->locktype = locktype; + return rc; + } + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = SQLitePendingByte; + lock.l_len = 2; + if (fcntl(h, F_SETLK, &lock) != -1) + pLock->locktype = SQLITE_LOCK_SHARED; + else { + tErrno = errno; + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); + if ((rc != SQLITE_OK) && (rc != SQLITE_BUSY)) + pFile->lastErrno = tErrno; + if (rc == SQLITE_OK) + pFile->locktype = locktype; + return rc; + } + } + if (locktype == SQLITE_LOCK_NONE) { + struct ChromiumOpenInfo *pOpen; + + pLock->cnt--; + + // Release the lock using an OS call only when all threads in this same process have released the lock. + if (!pLock->cnt) { + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = lock.l_len = 0L; + if (fcntl(h, F_SETLK, &lock) != -1) + pLock->locktype = SQLITE_LOCK_NONE; + else { + tErrno = errno; + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); + if ((rc != SQLITE_OK) && (rc != SQLITE_BUSY)) + pFile->lastErrno = tErrno; + pLock->locktype = SQLITE_LOCK_NONE; + pFile->locktype = SQLITE_LOCK_NONE; + } + } + + pOpen = pFile->pOpen; + pOpen->nLock--; + ASSERT(pOpen->nLock >= 0); + if (!pOpen->nLock) { + int rc2 = closePendingFds(pFile); + if (rc == SQLITE_OK) + rc = rc2; + } + } + + if (rc == SQLITE_OK) + pFile->locktype = locktype; + return rc; } -// Chromium's Posix implementation of SQLite VFS -namespace { +// Closes all file handles for given ChromiumFile and sets all its fields to 0. +// Returns a SQLite error code. +static int chromiumCloseNoLock(sqlite3_file* id) +{ + ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id); + if (!pFile) + return SQLITE_OK; + if (pFile->dirfd >= 0) { + if (close(pFile->dirfd)) { + pFile->lastErrno = errno; + return SQLITE_IOERR_DIR_CLOSE; + } + pFile->dirfd = -1; + } + if (pFile->h >= 0 && close(pFile->h)) { + pFile->lastErrno = errno; + return SQLITE_IOERR_CLOSE; + } + sqlite3_free(pFile->pUnused); + memset(pFile, 0, sizeof(ChromiumFile)); + return SQLITE_OK; +} + +// Closes a ChromiumFile, including locking operations. Returns a SQLite error code. +static int chromiumClose(sqlite3_file* id) +{ + if (!id) + return SQLITE_OK; + + ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id); + chromiumUnlock(id, SQLITE_LOCK_NONE); + if (pFile->pOpen && pFile->pOpen->nLock) { + // If there are outstanding locks, do not actually close the file just + // yet because that would clear those locks. + ChromiumOpenInfo* pOpen = pFile->pOpen; + ChromiumUnusedFd* p = pFile->pUnused; + p->pNext = pOpen->pUnused; + pOpen->pUnused = p; + pFile->h = -1; + pFile->pUnused = 0; + } + releaseLockInfo(pFile->pLock); + releaseOpenInfo(pFile->pOpen); + return chromiumCloseNoLock(id); +} + +static int chromiumCheckReservedLockNoop(sqlite3_file*, int* pResOut) +{ + *pResOut = 0; + return SQLITE_OK; +} + +static int chromiumLockNoop(sqlite3_file*, int) +{ + return SQLITE_OK; +} + +static int chromiumUnlockNoop(sqlite3_file*, int) +{ + return SQLITE_OK; +} + +// Seeks to the requested offset and reads up to |cnt| bytes into |pBuf|. Returns number of bytes actually read. +static int seekAndRead(ChromiumFile* id, sqlite3_int64 offset, void* pBuf, int cnt) +{ + sqlite_int64 newOffset = lseek(id->h, offset, SEEK_SET); + if (newOffset != offset) { + id->lastErrno = (newOffset == -1) ? errno : 0; + return -1; + } + int got = read(id->h, pBuf, cnt); + if (got < 0) + id->lastErrno = errno; + return got; +} + +// Reads data from file into a buffer. Returns a SQLite error code. +static int chromiumRead(sqlite3_file* id, void* pBuf, int amt, sqlite3_int64 offset) +{ + ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id); + ASSERT(pFile); + + // The bytes in the locking range should never be read. + ASSERT(!pFile->pUnused || offset >= SQLitePendingByte + 512 || offset + amt <= SQLitePendingByte); + + int got = seekAndRead(pFile, offset, pBuf, amt); + if (got == amt) + return SQLITE_OK; + + if (got < 0) + return SQLITE_IOERR_READ; + + // Unread parts of the buffer must be zero-filled. + memset(&(reinterpret_cast<char*>(pBuf))[got], 0, amt - got); + pFile->lastErrno = 0; + return SQLITE_IOERR_SHORT_READ; +} + +// Seeks to the requested offset and writes up to |cnt| bytes. Returns number of bytes actually written. +static int seekAndWrite(ChromiumFile* id, sqlite_int64 offset, const void* pBuf, int cnt) +{ + sqlite_int64 newOffset = lseek(id->h, offset, SEEK_SET); + if (newOffset != offset) { + id->lastErrno = (newOffset == -1) ? errno : 0; + return -1; + } + int got = write(id->h, pBuf, cnt); + if (got < 0) + id->lastErrno = errno; + return got; +} + +// Writes data from buffer into a file. Returns a SQLite error code. +static int chromiumWrite(sqlite3_file* id, const void* pBuf, int amt, sqlite3_int64 offset) +{ + ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id); + ASSERT(pFile); + ASSERT(amt > 0); + + // The bytes in the locking range should never be written. + ASSERT(!pFile->pUnused || offset >= SQLitePendingByte + 512 || offset + amt <= SQLitePendingByte); + + int wrote = 0; + while (amt > 0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt)) > 0) { + amt -= wrote; + offset += wrote; + pBuf = &(reinterpret_cast<const char*>(pBuf))[wrote]; + } + if (amt > 0) { + if (wrote < 0) + return SQLITE_IOERR_WRITE; + pFile->lastErrno = 0; + return SQLITE_FULL; + } + return SQLITE_OK; +} + +static bool syncWrapper(int fd, bool fullSync) +{ +#if OS(DARWIN) + bool success = false; + if (fullSync) + success = !fcntl(fd, F_FULLFSYNC, 0); + if (!success) + success = !fsync(fd); + return success; +#else + return !fdatasync(fd); +#endif +} + +// Makes sure all writes to a particular file are committed to disk. Returns a SQLite error code. +static int chromiumSync(sqlite3_file* id, int flags) +{ + ASSERT((flags & 0x0F) == SQLITE_SYNC_NORMAL || (flags & 0x0F) == SQLITE_SYNC_FULL); + + ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id); + ASSERT(pFile); + + bool isFullSync = ((flags & 0x0F) == SQLITE_SYNC_FULL); + + if (!syncWrapper(pFile->h, isFullSync)) { + pFile->lastErrno = errno; + return SQLITE_IOERR_FSYNC; + } + + if (pFile->dirfd >= 0) { +#if !OS(DARWIN) + if (!isFullSync) { + // Ignore directory sync failures, see http://www.sqlite.org/cvstrac/tktview?tn=1657. + syncWrapper(pFile->dirfd, false); + } +#endif + if (!close(pFile->dirfd)) + pFile->dirfd = -1; + else { + pFile->lastErrno = errno; + return SQLITE_IOERR_DIR_CLOSE; + } + } + + return SQLITE_OK; +} + +// Truncates an open file to the specified size. Returns a SQLite error code. +static int chromiumTruncate(sqlite3_file* id, sqlite_int64 nByte) +{ + ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id); + ASSERT(pFile); + + if (ftruncate(pFile->h, nByte)) { + pFile->lastErrno = errno; + return SQLITE_IOERR_TRUNCATE; + } + + return SQLITE_OK; +} + +// Determines the size of a file in bytes. Returns a SQLite error code. +static int chromiumFileSize(sqlite3_file* id, sqlite_int64* pSize) +{ + ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id); + ASSERT(pFile); + + struct stat buf; + if (fstat(pFile->h, &buf)) { + pFile->lastErrno = errno; + return SQLITE_IOERR_FSTAT; + } + *pSize = buf.st_size; + + // When opening a zero-size database, findLockInfo writes a single byte into that file + // in order to work around a bug in the OS X msdos filesystem. In order to avoid problems + // with upper layers, we need to report this file size as zero even though it is really 1. + // See http://www.sqlite.org/cvstrac/tktview?tn=3260. + if (*pSize == 1) + *pSize = 0; + + return SQLITE_OK; +} + +static int chromiumFileControl(sqlite3_file* id, int op, void* pArg) +{ + ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id); + ASSERT(pFile); + + switch (op) { + case SQLITE_FCNTL_LOCKSTATE: + *reinterpret_cast<int*>(pArg) = pFile->locktype; + return SQLITE_OK; + case SQLITE_LAST_ERRNO: + *reinterpret_cast<int*>(pArg) = pFile->lastErrno; + return SQLITE_OK; + } + return SQLITE_ERROR; +} + +// Same as SQLITE_DEFAULT_SECTOR_SIZE from sqlite's os.h. +static const int SQLiteDefaultSectorSize = 512; + +static int chromiumSectorSize(sqlite3_file*) +{ + return SQLiteDefaultSectorSize; +} + +static int chromiumDeviceCharacteristics(sqlite3_file*) +{ + return 0; +} + +static const sqlite3_io_methods posixIoMethods = { + 1, + chromiumClose, + chromiumRead, + chromiumWrite, + chromiumTruncate, + chromiumSync, + chromiumFileSize, + chromiumLock, + chromiumUnlock, + chromiumCheckReservedLock, + chromiumFileControl, + chromiumSectorSize, + chromiumDeviceCharacteristics +}; + +static const sqlite3_io_methods nolockIoMethods = { + 1, + chromiumCloseNoLock, + chromiumRead, + chromiumWrite, + chromiumTruncate, + chromiumSync, + chromiumFileSize, + chromiumLockNoop, + chromiumUnlockNoop, + chromiumCheckReservedLockNoop, + chromiumFileControl, + chromiumSectorSize, + chromiumDeviceCharacteristics +}; + +// Initializes a ChromiumFile. Returns a SQLite error code. +static int fillInChromiumFile(sqlite3_vfs* pVfs, int h, int dirfd, sqlite3_file* pId, const char* zFilename, int noLock) +{ + ChromiumFile* pNew = reinterpret_cast<ChromiumFile*>(pId); + + ASSERT(!pNew->pLock); + ASSERT(!pNew->pOpen); + + pNew->h = h; + pNew->dirfd = dirfd; + + int rc = SQLITE_OK; + const sqlite3_io_methods* pLockingStyle; + if (noLock) + pLockingStyle = &nolockIoMethods; + else { + pLockingStyle = &posixIoMethods; + rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen); + if (rc != SQLITE_OK) { + // If an error occured in findLockInfo(), close the file descriptor + // immediately. This can happen in two scenarios: + // + // (a) A call to fstat() failed. + // (b) A malloc failed. + // + // Scenario (b) may only occur if the process is holding no other + // file descriptors open on the same file. If there were other file + // descriptors on this file, then no malloc would be required by + // findLockInfo(). If this is the case, it is quite safe to close + // handle h - as it is guaranteed that no posix locks will be released + // by doing so. + // + // If scenario (a) caused the error then things are not so safe. The + // implicit assumption here is that if fstat() fails, things are in + // such bad shape that dropping a lock or two doesn't matter much. + close(h); + h = -1; + } + } + + pNew->lastErrno = 0; + if (rc != SQLITE_OK) { + if (dirfd >= 0) + close(dirfd); + if (h >= 0) + close(h); + } else + pNew->pMethod = pLockingStyle; + return rc; +} + +// Searches for an unused file descriptor that was opened on the database +// file identified by zPath with matching flags. Returns 0 if not found. +static ChromiumUnusedFd* findReusableFd(const char* zPath, int flags) +{ + ChromiumUnusedFd* pUnused = 0; + + struct stat sStat; + if (!stat(zPath, &sStat)) { + ChromiumFileId id; + id.dev = sStat.st_dev; + id.ino = sStat.st_ino; + + ChromiumOpenInfo* pO = 0; + for (pO = openList; pO && memcmp(&id, &pO->fileId, sizeof(id)); pO = pO->pNext) { } + if (pO) { + ChromiumUnusedFd** pp; + for (pp = &pO->pUnused; *pp && (*pp)->flags != flags; pp = &((*pp)->pNext)) { } + pUnused = *pp; + if (pUnused) + *pp = pUnused->pNext; + } + } + return pUnused; +} // Opens a file. // @@ -59,14 +974,26 @@ namespace { // id - the structure that will manipulate the newly opened file. // desiredFlags - the desired open mode flags. // usedFlags - the actual open mode flags that were used. -int chromiumOpen(sqlite3_vfs* vfs, const char* fileName, - sqlite3_file* id, int desiredFlags, int* usedFlags) +static int chromiumOpen(sqlite3_vfs* vfs, const char* fileName, + sqlite3_file* id, int desiredFlags, int* usedFlags) { - chromium_sqlite3_initialize_unix_sqlite3_file(id); + // The mask 0x00007F00 gives us the 7 bits that determine the type of the file SQLite is trying to open. + int fileType = desiredFlags & 0x00007F00; + + memset(id, 0, sizeof(ChromiumFile)); + ChromiumFile* chromiumFile = reinterpret_cast<ChromiumFile*>(id); int fd = -1; - int result = chromium_sqlite3_get_reusable_file_handle(id, fileName, desiredFlags, &fd); - if (result != SQLITE_OK) - return result; + if (fileType == SQLITE_OPEN_MAIN_DB) { + ChromiumUnusedFd* unusedFd = findReusableFd(fileName, desiredFlags); + if (unusedFd) + fd = unusedFd->fd; + else { + unusedFd = static_cast<ChromiumUnusedFd*>(sqlite3_malloc(sizeof(*unusedFd))); + if (!unusedFd) + return SQLITE_NOMEM; + } + chromiumFile->pUnused = unusedFd; + } if (fd < 0) { fd = ChromiumBridge::databaseOpenFile(fileName, desiredFlags); @@ -76,23 +1003,24 @@ int chromiumOpen(sqlite3_vfs* vfs, const char* fileName, } } if (fd < 0) { - chromium_sqlite3_destroy_reusable_file_handle(id); + sqlite3_free(chromiumFile->pUnused); return SQLITE_CANTOPEN; } if (usedFlags) *usedFlags = desiredFlags; - chromium_sqlite3_update_reusable_file_handle(id, fd, desiredFlags); + if (chromiumFile->pUnused) { + chromiumFile->pUnused->fd = fd; + chromiumFile->pUnused->flags = desiredFlags; + } fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); - // The mask 0x00007F00 gives us the 7 bits that determine the type of the file SQLite is trying to open. - int fileType = desiredFlags & 0x00007F00; int noLock = (fileType != SQLITE_OPEN_MAIN_DB); - result = chromium_sqlite3_fill_in_unix_sqlite3_file(vfs, fd, -1, id, fileName, noLock); - if (result != SQLITE_OK) - chromium_sqlite3_destroy_reusable_file_handle(id); - return result; + int rc = fillInChromiumFile(vfs, fd, -1, id, fileName, noLock); + if (rc != SQLITE_OK) + sqlite3_free(chromiumFile->pUnused); + return rc; } // Deletes the given file. @@ -101,7 +1029,7 @@ int chromiumOpen(sqlite3_vfs* vfs, const char* fileName, // fileName - the name of the file. // syncDir - determines if the directory to which this file belongs // should be synched after the file is deleted. -int chromiumDelete(sqlite3_vfs*, const char* fileName, int syncDir) +static int chromiumDelete(sqlite3_vfs*, const char* fileName, int syncDir) { return ChromiumBridge::databaseDeleteFile(fileName, syncDir); } @@ -112,7 +1040,7 @@ int chromiumDelete(sqlite3_vfs*, const char* fileName, int syncDir) // fileName - the name of the file. // flag - the type of test to make on this file. // res - the result. -int chromiumAccess(sqlite3_vfs*, const char* fileName, int flag, int* res) +static int chromiumAccess(sqlite3_vfs*, const char* fileName, int flag, int* res) { int attr = static_cast<int>(ChromiumBridge::databaseGetFileAttributes(fileName)); if (attr < 0) { @@ -122,7 +1050,7 @@ int chromiumAccess(sqlite3_vfs*, const char* fileName, int flag, int* res) switch (flag) { case SQLITE_ACCESS_EXISTS: - *res = 1; // if the file doesn't exist, attr < 0 + *res = 1; // if the file doesn't exist, attr < 0 break; case SQLITE_ACCESS_READWRITE: *res = (attr & W_OK) && (attr & R_OK); @@ -143,8 +1071,8 @@ int chromiumAccess(sqlite3_vfs*, const char* fileName, int flag, int* res) // relativePath - the relative path. // bufSize - the size of the output buffer in bytes. // absolutePath - the output buffer where the absolute path will be stored. -int chromiumFullPathname(sqlite3_vfs* vfs, const char* relativePath, - int, char* absolutePath) +static int chromiumFullPathname(sqlite3_vfs* vfs, const char* relativePath, + int, char* absolutePath) { // The renderer process doesn't need to know the absolute path of the file sqlite3_snprintf(vfs->mxPathname, absolutePath, "%s", relativePath); @@ -152,44 +1080,107 @@ int chromiumFullPathname(sqlite3_vfs* vfs, const char* relativePath, } #ifndef SQLITE_OMIT_LOAD_EXTENSION -// Returns NULL, thus disallowing loading libraries in the renderer process. -// -// vfs - pointer to the sqlite3_vfs object. -// fileName - the name of the shared library file. -void* chromiumDlOpen(sqlite3_vfs*, const char*) +// We disallow loading DSOs inside the renderer process, so the following procedures are no-op. +static void* chromiumDlOpen(sqlite3_vfs*, const char*) +{ + return 0; +} + +static void chromiumDlError(sqlite3_vfs*, int, char*) +{ +} + +static void (*chromiumDlSym(sqlite3_vfs*, void*, const char*))() { return 0; } + +static void chromiumDlClose(sqlite3_vfs*, void*) +{ +} #else #define chromiumDlOpen 0 +#define chromiumDlError 0 +#define chromiumDlSym 0 +#define chromiumDlClose 0 #endif // SQLITE_OMIT_LOAD_EXTENSION -} // namespace +// Generates a seed for SQLite's PRNG. +static int chromiumRandomness(sqlite3_vfs*, int nBuf, char *zBuf) +{ + ASSERT(static_cast<size_t>(nBuf) >= (sizeof(time_t) + sizeof(int))); + + memset(zBuf, 0, nBuf); + int fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + time_t t; + time(&t); + memcpy(zBuf, &t, sizeof(t)); + int pid = getpid(); + memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid)); + return sizeof(t) + sizeof(pid); + } + nBuf = read(fd, zBuf, nBuf); + close(fd); + return nBuf; +} + +// Sleeps for at least |microseconds|, and returns the actual +// amount of time spent sleeping (in microseconds). +static int chromiumSleep(sqlite3_vfs*, int microseconds) +{ +#if OS(DARWIN) + usleep(microseconds); + return microseconds; +#else + // Round to the nearest second. + int seconds = (microseconds + 999999) / 1000000; + sleep(seconds); + return seconds * 1000000; +#endif +} + +// Retrieves the current system time (UTC). +static int chromiumCurrentTime(sqlite3_vfs*, double* now) +{ + struct timeval timeval; + gettimeofday(&timeval, 0); + *now = 2440587.5 + timeval.tv_sec / 86400.0 + timeval.tv_usec / 86400000000.0; + return 0; +} + +// This is not yet implemented in SQLite core. +static int chromiumGetLastError(sqlite3_vfs*, int, char*) +{ + return 0; +} + +// Same as MAX_PATHNAME from sqlite's os_unix.c. +static const int chromiumMaxPathname = 512; namespace WebCore { void SQLiteFileSystem::registerSQLiteVFS() { - sqlite3_vfs* unix_vfs = sqlite3_vfs_find("unix"); static sqlite3_vfs chromium_vfs = { 1, - unix_vfs->szOsFile, - unix_vfs->mxPathname, + sizeof(ChromiumFile), + chromiumMaxPathname, 0, "chromium_vfs", - unix_vfs->pAppData, + 0, chromiumOpen, chromiumDelete, chromiumAccess, chromiumFullPathname, chromiumDlOpen, - unix_vfs->xDlError, - unix_vfs->xDlSym, - unix_vfs->xDlClose, - unix_vfs->xRandomness, - unix_vfs->xSleep, - unix_vfs->xCurrentTime, - unix_vfs->xGetLastError + chromiumDlError, + chromiumDlSym, + chromiumDlClose, + chromiumRandomness, + chromiumSleep, + chromiumCurrentTime, + chromiumGetLastError }; sqlite3_vfs_register(&chromium_vfs, 0); } diff --git a/WebCore/platform/text/cf/HyphenationCF.cpp b/WebCore/platform/text/cf/HyphenationCF.cpp index 8be537d..b265c56 100644 --- a/WebCore/platform/text/cf/HyphenationCF.cpp +++ b/WebCore/platform/text/cf/HyphenationCF.cpp @@ -48,20 +48,27 @@ RetainPtr<CFLocaleRef> AtomicStringKeyedMRUCache<RetainPtr<CFLocaleRef> >::creat { RetainPtr<CFStringRef> cfLocaleIdentifier(AdoptCF, localeIdentifier.createCFString()); RetainPtr<CFLocaleRef> locale(AdoptCF, CFLocaleCreate(kCFAllocatorDefault, cfLocaleIdentifier.get())); - return locale; + + return CFStringIsHyphenationAvailableForLocale(locale.get()) ? locale : 0; +} + +static AtomicStringKeyedMRUCache<RetainPtr<CFLocaleRef> >& cfLocaleCache() +{ + DEFINE_STATIC_LOCAL(AtomicStringKeyedMRUCache<RetainPtr<CFLocaleRef> >, cache, ()); + return cache; } -bool canHyphenate(const AtomicString& /* localeIdentifer */) +bool canHyphenate(const AtomicString& localeIdentifier) { - return true; + return cfLocaleCache().get(localeIdentifier); } size_t lastHyphenLocation(const UChar* characters, size_t length, size_t beforeIndex, const AtomicString& localeIdentifier) { RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, characters, length, kCFAllocatorNull)); - DEFINE_STATIC_LOCAL(AtomicStringKeyedMRUCache<RetainPtr<CFLocaleRef> >, cfLocaleCache, ()); - RetainPtr<CFLocaleRef> locale = cfLocaleCache.get(localeIdentifier); + RetainPtr<CFLocaleRef> locale = cfLocaleCache().get(localeIdentifier); + ASSERT(locale); CFIndex result = CFStringGetHyphenationLocationBeforeIndex(string.get(), beforeIndex, CFRangeMake(0, length), 0, locale.get(), 0); return result == kCFNotFound ? 0 : result; diff --git a/WebCore/platform/text/qt/TextCodecQt.cpp b/WebCore/platform/text/qt/TextCodecQt.cpp index 94a2b7b..1e95d87 100644 --- a/WebCore/platform/text/qt/TextCodecQt.cpp +++ b/WebCore/platform/text/qt/TextCodecQt.cpp @@ -29,7 +29,6 @@ #include "PlatformString.h" #include <wtf/text/CString.h> #include <qset.h> -// #include <QDebug> namespace WebCore { @@ -125,14 +124,41 @@ String TextCodecQt::decode(const char* bytes, size_t length, bool flush, bool /* return unicode; } -CString TextCodecQt::encode(const UChar* characters, size_t length, UnencodableHandling) +CString TextCodecQt::encode(const UChar* characters, size_t length, UnencodableHandling handling) { + QTextCodec::ConverterState state; + state.flags = QTextCodec::ConversionFlags(QTextCodec::ConvertInvalidToNull | QTextCodec::IgnoreHeader); + if (!length) return ""; - // FIXME: do something sensible with UnencodableHandling + QByteArray ba = m_codec->fromUnicode(reinterpret_cast<const QChar*>(characters), length, &state); + + // If some <b> characters </b> are unencodable, escape them as specified by <b> handling </b> + // We append one valid encoded chunk to a QByteArray at a time. When we encounter an unencodable chunk we + // escape it with getUnencodableReplacement, append it, then move to the next chunk. + if (state.invalidChars) { + state.invalidChars = 0; + state.remainingChars = 0; + int len = 0; + ba.clear(); + for (size_t pos = 0; pos < length; ++pos) { + QByteArray tba = m_codec->fromUnicode(reinterpret_cast<const QChar*>(characters), ++len, &state); + if (state.remainingChars) + continue; + if (state.invalidChars) { + UnencodableReplacementArray replacement; + getUnencodableReplacement(characters[0], handling, replacement); + tba.replace('\0', replacement); + state.invalidChars = 0; + } + ba.append(tba); + characters += len; + len = 0; + state.remainingChars = 0; + } + } - QByteArray ba = m_codec->fromUnicode(reinterpret_cast<const QChar*>(characters), length, 0); return CString(ba.constData(), ba.length()); } diff --git a/WebCore/platform/win/ClipboardWin.cpp b/WebCore/platform/win/ClipboardWin.cpp index b13473a..529963f 100644 --- a/WebCore/platform/win/ClipboardWin.cpp +++ b/WebCore/platform/win/ClipboardWin.cpp @@ -397,19 +397,19 @@ exit: PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* dragData, Frame* frame) { - return ClipboardWin::create(true, dragData->platformData(), policy, frame); + return ClipboardWin::create(DragAndDrop, dragData->platformData(), policy, frame); } -ClipboardWin::ClipboardWin(bool isForDragging, IDataObject* dataObject, ClipboardAccessPolicy policy, Frame* frame) - : Clipboard(policy, isForDragging) +ClipboardWin::ClipboardWin(ClipboardType clipboardType, IDataObject* dataObject, ClipboardAccessPolicy policy, Frame* frame) + : Clipboard(policy, clipboardType) , m_dataObject(dataObject) , m_writableDataObject(0) , m_frame(frame) { } -ClipboardWin::ClipboardWin(bool isForDragging, WCDataObject* dataObject, ClipboardAccessPolicy policy, Frame* frame) - : Clipboard(policy, isForDragging) +ClipboardWin::ClipboardWin(ClipboardType clipboardType, WCDataObject* dataObject, ClipboardAccessPolicy policy, Frame* frame) + : Clipboard(policy, clipboardType) , m_dataObject(dataObject) , m_writableDataObject(dataObject) , m_frame(frame) @@ -467,7 +467,7 @@ static bool writeURL(WCDataObject *data, const KURL& url, String title, bool wit void ClipboardWin::clearData(const String& type) { // FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941> - ASSERT(isForDragging()); + ASSERT(isForDragAndDrop()); if (policy() != ClipboardWritable || !m_writableDataObject) return; @@ -487,7 +487,7 @@ void ClipboardWin::clearData(const String& type) void ClipboardWin::clearAllData() { // FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941> - ASSERT(isForDragging()); + ASSERT(isForDragAndDrop()); if (policy() != ClipboardWritable) return; @@ -520,7 +520,7 @@ String ClipboardWin::getData(const String& type, bool& success) const bool ClipboardWin::setData(const String& type, const String& data) { // FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941> - ASSERT(isForDragging()); + ASSERT(isForDragAndDrop()); if (policy() != ClipboardWritable || !m_writableDataObject) return false; @@ -831,7 +831,7 @@ bool ClipboardWin::hasData() void ClipboardWin::setExternalDataObject(IDataObject *dataObject) { - ASSERT(isForDragging()); + ASSERT(isForDragAndDrop()); m_writableDataObject = 0; m_dataObject = dataObject; diff --git a/WebCore/platform/win/ClipboardWin.h b/WebCore/platform/win/ClipboardWin.h index 6a08087..ce64b85 100644 --- a/WebCore/platform/win/ClipboardWin.h +++ b/WebCore/platform/win/ClipboardWin.h @@ -42,13 +42,13 @@ class WCDataObject; // State available during IE's events for drag and drop and copy/paste class ClipboardWin : public Clipboard, public CachedResourceClient { public: - static PassRefPtr<ClipboardWin> create(bool isForDragging, IDataObject* dataObject, ClipboardAccessPolicy policy, Frame* frame) + static PassRefPtr<ClipboardWin> create(ClipboardType clipboardType, IDataObject* dataObject, ClipboardAccessPolicy policy, Frame* frame) { - return adoptRef(new ClipboardWin(isForDragging, dataObject, policy, frame)); + return adoptRef(new ClipboardWin(clipboardType, dataObject, policy, frame)); } - static PassRefPtr<ClipboardWin> create(bool isForDragging, WCDataObject* dataObject, ClipboardAccessPolicy policy, Frame* frame) + static PassRefPtr<ClipboardWin> create(ClipboardType clipboardType, WCDataObject* dataObject, ClipboardAccessPolicy policy, Frame* frame) { - return adoptRef(new ClipboardWin(isForDragging, dataObject, policy, frame)); + return adoptRef(new ClipboardWin(clipboardType, dataObject, policy, frame)); } ~ClipboardWin(); @@ -77,8 +77,8 @@ public: void setExternalDataObject(IDataObject *dataObject); private: - ClipboardWin(bool isForDragging, IDataObject*, ClipboardAccessPolicy, Frame*); - ClipboardWin(bool isForDragging, WCDataObject*, ClipboardAccessPolicy, Frame*); + ClipboardWin(ClipboardType, IDataObject*, ClipboardAccessPolicy, Frame*); + ClipboardWin(ClipboardType, WCDataObject*, ClipboardAccessPolicy, Frame*); void resetFromClipboard(); void setDragImage(CachedImage*, Node*, const IntPoint&); diff --git a/WebCore/platform/win/EditorWin.cpp b/WebCore/platform/win/EditorWin.cpp index 075827d..4965c97 100644 --- a/WebCore/platform/win/EditorWin.cpp +++ b/WebCore/platform/win/EditorWin.cpp @@ -45,7 +45,7 @@ PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy, if (!SUCCEEDED(OleGetClipboard(&clipboardData))) clipboardData = 0; - return ClipboardWin::create(false, clipboardData.get(), policy, frame); + return ClipboardWin::create(Clipboard::CopyAndPaste, clipboardData.get(), policy, frame); } } // namespace WebCore diff --git a/WebCore/platform/wx/ClipboardWx.cpp b/WebCore/platform/wx/ClipboardWx.cpp index 2ef943f..32216a6 100644 --- a/WebCore/platform/wx/ClipboardWx.cpp +++ b/WebCore/platform/wx/ClipboardWx.cpp @@ -42,8 +42,8 @@ PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy, DragData*, Frame* return 0; } -ClipboardWx::ClipboardWx(ClipboardAccessPolicy policy, bool forDragging) - : Clipboard(policy, forDragging) +ClipboardWx::ClipboardWx(ClipboardAccessPolicy policy, ClipboardType clipboardType) + : Clipboard(policy, clipboardType) { } diff --git a/WebCore/platform/wx/ClipboardWx.h b/WebCore/platform/wx/ClipboardWx.h index 45d1cf3..138635a 100644 --- a/WebCore/platform/wx/ClipboardWx.h +++ b/WebCore/platform/wx/ClipboardWx.h @@ -35,9 +35,9 @@ namespace WebCore { // State available during IE's events for drag and drop and copy/paste class ClipboardWx : public Clipboard { public: - static PassRefPtr<ClipboardWx> create(ClipboardAccessPolicy policy, bool forDragging) + static PassRefPtr<ClipboardWx> create(ClipboardAccessPolicy policy, ClipboardType clipboardType) { - return adoptRef(new ClipboardWx(policy, forDragging)); + return adoptRef(new ClipboardWx(policy, clipboardType)); } void clearData(const String& type); @@ -65,7 +65,7 @@ namespace WebCore { virtual bool hasData(); private: - ClipboardWx(ClipboardAccessPolicy, bool forDragging); + ClipboardWx(ClipboardAccessPolicy, ClipboardType); }; } diff --git a/WebCore/platform/wx/LocalizedStringsWx.cpp b/WebCore/platform/wx/LocalizedStringsWx.cpp index 4112f64..10ea435 100644 --- a/WebCore/platform/wx/LocalizedStringsWx.cpp +++ b/WebCore/platform/wx/LocalizedStringsWx.cpp @@ -97,6 +97,56 @@ String contextMenuItemTagCopyImageToClipboard() return String("Copy Image to Clipboard"); } +String contextMenuItemTagOpenVideoInNewWindow() +{ + return String("Open Video in New Window"); +} + +String contextMenuItemTagOpenAudioInNewWindow() +{ + return String("Open Audio in New Window"); +} + +String contextMenuItemTagCopyVideoLinkToClipboard() +{ + return String("Copy Video Link Location"); +} + +String contextMenuItemTagCopyAudioLinkToClipboard() +{ + return String("Copy Audio Link Location"); +} + +String contextMenuItemTagToggleMediaControls() +{ + return String("Toggle Media Controls"); +} + +String contextMenuItemTagToggleMediaLoop() +{ + return String("Toggle Media Loop Playback"); +} + +String contextMenuItemTagEnterVideoFullscreen() +{ + return String("Switch Video to Fullscreen"); +} + +String contextMenuItemTagMediaPlay() +{ + return String("Play"); +} + +String contextMenuItemTagMediaPause() +{ + return String("Pause"); +} + +String contextMenuItemTagMediaMute() +{ + return String("Mute"); +} + String contextMenuItemTagOpenFrameInNewWindow() { return String("Open Frame in New Window"); diff --git a/WebCore/platform/wx/PopupMenuWx.cpp b/WebCore/platform/wx/PopupMenuWx.cpp index e88d1e5..b850ef5 100644 --- a/WebCore/platform/wx/PopupMenuWx.cpp +++ b/WebCore/platform/wx/PopupMenuWx.cpp @@ -38,14 +38,34 @@ static int s_menuStartId = wxNewId(); +namespace WebCore { + +class PopupMenuEventHandler : public wxEvtHandler +{ +public: + PopupMenuEventHandler(PopupMenuClient* client) : + m_client(client) + {} + + void OnMenuItemSelected(wxCommandEvent& event) + { + if (m_client) { + m_client->valueChanged(event.GetId() - s_menuStartId); + m_client->popupDidHide(); + } + // TODO: Do we need to call Disconnect here? Do we have a ref to the native window still? + } +private: + PopupMenuClient* m_client; -namespace WebCore { +}; PopupMenuWx::PopupMenuWx(PopupMenuClient* client) : m_popupClient(client) - , m_menu(NULL) + , m_menu(0) { + PopupMenuEventHandler m_popupHandler(client); } PopupMenuWx::~PopupMenuWx() @@ -69,6 +89,7 @@ void PopupMenuWx::show(const IntRect& r, FrameView* v, int index) if (nativeWin) { // construct the menu m_menu = new wxMenu(); + int size = client()->listSize(); for (int i = 0; i < size; i++) { int id = s_menuStartId + i; @@ -84,19 +105,10 @@ void PopupMenuWx::show(const IntRect& r, FrameView* v, int index) m_menu->Append(s_menuStartId + i, client()->itemText(i)); } } - nativeWin->Connect(s_menuStartId, s_menuStartId + (size-1), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(PopupMenuWx::OnMenuItemSelected), 0, this); + nativeWin->Connect(s_menuStartId, s_menuStartId + (size-1), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(PopupMenuEventHandler::OnMenuItemSelected), 0, m_popupHandler); nativeWin->PopupMenu(m_menu, r.x() - v->scrollX(), r.y() - v->scrollY()); - nativeWin->Disconnect(s_menuStartId, s_menuStartId + (size-1), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(PopupMenuWx::OnMenuItemSelected), 0, this); - } -} - -void PopupMenuWx::OnMenuItemSelected(wxCommandEvent& event) -{ - if (client()) { - client()->valueChanged(event.GetId() - s_menuStartId); - client()->popupDidHide(); + nativeWin->Disconnect(s_menuStartId, s_menuStartId + (size-1), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(PopupMenuEventHandler::OnMenuItemSelected), 0, m_popupHandler); } - // TODO: Do we need to call Disconnect here? Do we have a ref to the native window still? } void PopupMenuWx::hide() diff --git a/WebCore/platform/wx/PopupMenuWx.h b/WebCore/platform/wx/PopupMenuWx.h index c2573fc..ad947a7 100644 --- a/WebCore/platform/wx/PopupMenuWx.h +++ b/WebCore/platform/wx/PopupMenuWx.h @@ -37,9 +37,10 @@ class wxMenu; namespace WebCore { class FrameView; +class PopupMenuEventHandler; class Scrollbar; -class PopupMenuWx : public PopupMenu, public wxEvtHandler { +class PopupMenuWx : public PopupMenu { public: PopupMenuWx(PopupMenuClient*); ~PopupMenuWx(); @@ -55,6 +56,7 @@ private: PopupMenuClient* m_popupClient; wxMenu* m_menu; + PopupMenuEventHandler* m_popupHandler; }; } |