diff options
Diffstat (limited to 'Source/WebCore/platform')
407 files changed, 10139 insertions, 4436 deletions
diff --git a/Source/WebCore/platform/AsyncFileSystem.cpp b/Source/WebCore/platform/AsyncFileSystem.cpp index 404aab673..c3c241224 100644 --- a/Source/WebCore/platform/AsyncFileSystem.cpp +++ b/Source/WebCore/platform/AsyncFileSystem.cpp @@ -39,6 +39,11 @@ namespace WebCore { +const char AsyncFileSystem::persistentPathPrefix[] = "persistent"; +const size_t AsyncFileSystem::persistentPathPrefixLength = sizeof(AsyncFileSystem::persistentPathPrefix) - 1; +const char AsyncFileSystem::temporaryPathPrefix[] = "temporary"; +const size_t AsyncFileSystem::temporaryPathPrefixLength = sizeof(AsyncFileSystem::temporaryPathPrefix) - 1; + #if !PLATFORM(CHROMIUM) bool AsyncFileSystem::isAvailable() { @@ -46,6 +51,11 @@ bool AsyncFileSystem::isAvailable() return false; } +bool AsyncFileSystem::isValidType(Type type) +{ + return type == Temporary || type == Persistent; +} + PassOwnPtr<AsyncFileSystem> AsyncFileSystem::create(Type, const String&) { notImplemented(); diff --git a/Source/WebCore/platform/AsyncFileSystem.h b/Source/WebCore/platform/AsyncFileSystem.h index c2c68454f..bbef6a4e3 100644 --- a/Source/WebCore/platform/AsyncFileSystem.h +++ b/Source/WebCore/platform/AsyncFileSystem.h @@ -54,14 +54,26 @@ public: enum Type { Temporary, Persistent, - External, }; + // Path prefixes that are used in the filesystem URLs (that can be obtained by toURL()). + // http://www.w3.org/TR/file-system-api/#widl-Entry-toURL + static const char persistentPathPrefix[]; + static const size_t persistentPathPrefixLength; + static const char temporaryPathPrefix[]; + static const size_t temporaryPathPrefixLength; + virtual void stop() { } virtual bool hasPendingActivity() { return false; } static bool isAvailable(); + static bool isValidType(Type); + + static bool crackFileSystemURL(const KURL&, Type&, String& filePath); + + virtual String toURL(const String& originString, const String& fullPath) = 0; + // Subclass must implement this if it supports synchronous operations. // This should return false if there are no pending operations. virtual bool waitForOperationToComplete() { return false; } diff --git a/Source/WebCore/platform/AutodrainedPool.h b/Source/WebCore/platform/AutodrainedPool.h index f03ec812e..207aadcbe 100644 --- a/Source/WebCore/platform/AutodrainedPool.h +++ b/Source/WebCore/platform/AutodrainedPool.h @@ -31,11 +31,7 @@ #include <wtf/Noncopyable.h> -#ifdef __OBJC__ -@class NSAutoreleasePool; -#else -class NSAutoreleasePool; -#endif +OBJC_CLASS NSAutoreleasePool; namespace WebCore { diff --git a/Source/WebCore/platform/CalculationValue.cpp b/Source/WebCore/platform/CalculationValue.cpp new file mode 100755 index 000000000..b9e38581a --- /dev/null +++ b/Source/WebCore/platform/CalculationValue.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CalculationValue.h" + +namespace WebCore { + +} // namespace WebCore diff --git a/Source/WebCore/platform/mock/SpeechInputClientMock.h b/Source/WebCore/platform/CalculationValue.h index 4e13242ac..44a52d5ed 100644..100755 --- a/Source/WebCore/platform/mock/SpeechInputClientMock.h +++ b/Source/WebCore/platform/CalculationValue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2011 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -28,51 +28,25 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SpeechInputClientMock_h -#define SpeechInputClientMock_h +#ifndef CalculationValue_h +#define CalculationValue_h -#include "PlatformString.h" -#include "SpeechInputClient.h" -#include "SpeechInputResult.h" -#include "Timer.h" -#include <wtf/HashMap.h> -#include <wtf/text/StringHash.h> - -#if ENABLE(INPUT_SPEECH) +#include "Length.h" +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> namespace WebCore { -class SpeechInputListener; - -// Provides a mock object for the speech input embedder API called by WebCore. -class SpeechInputClientMock : public SpeechInputClient { -public: - SpeechInputClientMock(); - - void addRecognitionResult(const String& result, double confidence, const AtomicString& language); - void clearResults(); - - // SpeechInputClient methods. - void setListener(SpeechInputListener*); - bool startRecognition(int requestId, const IntRect& elementRect, const AtomicString& language, const String& grammar, SecurityOrigin*); - void stopRecording(int); - void cancelRecognition(int); - -private: - void timerFired(Timer<SpeechInputClientMock>*); - - bool m_recording; - Timer<SpeechInputClientMock> m_timer; - SpeechInputListener* m_listener; - int m_requestId; - - HashMap<String, SpeechInputResultArray> m_recognitionResults; - AtomicString m_language; - SpeechInputResultArray m_resultsForEmptyLanguage; +enum CalcOperator { + CalcAdd = '+', + CalcSubtract = '-', + CalcMultiply = '*', + CalcDivide = '/', + CalcMod = '%' }; } // namespace WebCore -#endif // ENABLE(INPUT_SPEECH) - -#endif // SpeechInputClientMock_h +#endif // CalculationValue_h diff --git a/Source/WebCore/platform/ContextMenuItem.h b/Source/WebCore/platform/ContextMenuItem.h index 98d4be245..2520c64e6 100644 --- a/Source/WebCore/platform/ContextMenuItem.h +++ b/Source/WebCore/platform/ContextMenuItem.h @@ -33,12 +33,7 @@ #if PLATFORM(MAC) #include <wtf/RetainPtr.h> - -#ifdef __OBJC__ -@class NSMenuItem; -#else -class NSMenuItem; -#endif +OBJC_CLASS NSMenuItem; #elif PLATFORM(WIN) typedef struct tagMENUITEMINFOW MENUITEMINFO; #elif PLATFORM(GTK) @@ -64,7 +59,7 @@ namespace WebCore { ContextMenuItemTagOpenImageInNewWindow, ContextMenuItemTagDownloadImageToDisk, ContextMenuItemTagCopyImageToClipboard, -#if PLATFORM(QT) || PLATFORM(GTK) +#if PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL) ContextMenuItemTagCopyImageUrlToClipboard, #endif ContextMenuItemTagOpenFrameInNewWindow, diff --git a/Source/WebCore/platform/Cursor.h b/Source/WebCore/platform/Cursor.h index c324ef00e..bc5184070 100644 --- a/Source/WebCore/platform/Cursor.h +++ b/Source/WebCore/platform/Cursor.h @@ -46,11 +46,7 @@ typedef HICON HCURSOR; #endif #if PLATFORM(MAC) && !PLATFORM(IOS) -#ifdef __OBJC__ -@class NSCursor; -#else -class NSCursor; -#endif +OBJC_CLASS NSCursor; #endif #if PLATFORM(WX) diff --git a/Source/WebCore/platform/DragData.h b/Source/WebCore/platform/DragData.h index bb242f9e9..17abd44fa 100644 --- a/Source/WebCore/platform/DragData.h +++ b/Source/WebCore/platform/DragData.h @@ -36,15 +36,17 @@ #if PLATFORM(MAC) #include <wtf/RetainPtr.h> + #ifdef __OBJC__ #import <Foundation/Foundation.h> #import <AppKit/NSDragging.h> typedef id <NSDraggingInfo> DragDataRef; -@class NSPasteboard; #else typedef void* DragDataRef; -class NSPasteboard; #endif + +OBJC_CLASS NSPasteboard; + #elif PLATFORM(QT) QT_BEGIN_NAMESPACE class QMimeData; diff --git a/Source/WebCore/platform/DragImage.h b/Source/WebCore/platform/DragImage.h index 811fa56d2..a22db6a76 100644 --- a/Source/WebCore/platform/DragImage.h +++ b/Source/WebCore/platform/DragImage.h @@ -32,11 +32,7 @@ #if PLATFORM(MAC) #include <wtf/RetainPtr.h> -#ifdef __OBJC__ -@class NSImage; -#else -class NSImage; -#endif +OBJC_CLASS NSImage; #elif PLATFORM(QT) QT_BEGIN_NAMESPACE class QPixmap; diff --git a/Source/WebCore/platform/KURL.cpp b/Source/WebCore/platform/KURL.cpp index 2408cc2b4..606280ab4 100644 --- a/Source/WebCore/platform/KURL.cpp +++ b/Source/WebCore/platform/KURL.cpp @@ -68,6 +68,18 @@ static inline bool isLetterMatchIgnoringCase(UChar character, char lowercaseLett #if !USE(GOOGLEURL) +static const char wsScheme[] = {'w', 's'}; +static const char ftpScheme[] = {'f', 't', 'p'}; +static const char ftpPort[] = {'2', '1'}; +static const char wssScheme[] = {'w', 's', 's'}; +static const char fileScheme[] = {'f', 'i', 'l', 'e'}; +static const char httpScheme[] = {'h', 't', 't', 'p'}; +static const char httpPort[] = {'8', '0'}; +static const char httpsScheme[] = {'h', 't', 't', 'p', 's'}; +static const char httpsPort[] = {'4', '4', '3'}; +static const char gopherScheme[] = {'g', 'o', 'p', 'h', 'e', 'r'}; +static const char gopherPort[] = {'7', '0'}; + static inline bool isLetterMatchIgnoringCase(char character, char lowercaseLetter) { ASSERT(isASCIILower(lowercaseLetter)); @@ -1050,13 +1062,20 @@ void KURL::parse(const String& string) parse(buffer.data(), &string); } -// FIXME: (lenA != lenB) is never true in the way this function is used. -// FIXME: This is only used for short string, we should replace equal() by a recursive template comparing the strings without loop. -static inline bool equal(const char* a, size_t lenA, const char* b, size_t lenB) +template<size_t length> +static inline bool equal(const char* a, const char (&b)[length]) { - if (lenA != lenB) - return false; - return !strncmp(a, b, lenA); + for (size_t i = 0; i < length; ++i) { + if (a[i] != b[i]) + return false; + } + return true; +} + +template<size_t lengthB> +static inline bool equal(const char* stringA, size_t lengthA, const char (&stringB)[lengthB]) +{ + return lengthA == lengthB && equal(stringA, stringB); } // List of default schemes is taken from google-url: @@ -1067,19 +1086,19 @@ static inline bool isDefaultPortForScheme(const char* port, size_t portLength, c // the code was moved from google-url, but may be removed later. switch (schemeLength) { case 2: - return equal("ws", 2, scheme, schemeLength) && equal("80", 2, port, portLength); + return equal(scheme, wsScheme) && equal(port, portLength, httpPort); case 3: - if (equal("ftp", 3, scheme, schemeLength)) - return equal("21", 2, port, portLength); - if (equal("wss", 3, scheme, schemeLength)) - return equal("443", 3, port, portLength); + if (equal(scheme, ftpScheme)) + return equal(port, portLength, ftpPort); + if (equal(scheme, wssScheme)) + return equal(port, portLength, httpsPort); break; case 4: - return equal("http", 4, scheme, schemeLength) && equal("80", 2, port, portLength); + return equal(scheme, httpScheme) && equal(port, portLength, httpPort); case 5: - return equal("https", 5, scheme, schemeLength) && equal("443", 3, port, portLength); + return equal(scheme, httpsScheme) && equal(port, portLength, httpsPort); case 6: - return equal("gopher", 6, scheme, schemeLength) && equal("70", 2, port, portLength); + return equal(scheme, gopherScheme) && equal(port, portLength, gopherPort); } return false; } @@ -1093,15 +1112,15 @@ static bool isNonFileHierarchicalScheme(const char* scheme, size_t schemeLength) { switch (schemeLength) { case 2: - return equal("ws", 2, scheme, schemeLength); + return equal(scheme, wsScheme); case 3: - return equal("ftp", 3, scheme, schemeLength) || equal("wss", 3, scheme, schemeLength); + return equal(scheme, ftpScheme) || equal(scheme, wssScheme); case 4: - return equal("http", 4, scheme, schemeLength); + return equal(scheme, httpScheme); case 5: - return equal("https", 5, scheme, schemeLength); + return equal(scheme, httpsScheme); case 6: - return equal("gopher", 6, scheme, schemeLength); + return equal(scheme, gopherScheme); } return false; } @@ -1110,15 +1129,15 @@ static bool isCanonicalHostnameLowercaseForScheme(const char* scheme, size_t sch { switch (schemeLength) { case 2: - return equal("ws", 2, scheme, schemeLength); + return equal(scheme, wsScheme); case 3: - return equal("ftp", 3, scheme, schemeLength) || equal("wss", 3, scheme, schemeLength); + return equal(scheme, ftpScheme) || equal(scheme, wssScheme); case 4: - return equal("http", 4, scheme, schemeLength) || equal("file", 4, scheme, schemeLength); + return equal(scheme, httpScheme) || equal(scheme, fileScheme); case 5: - return equal("https", 5, scheme, schemeLength); + return equal(scheme, httpsScheme); case 6: - return equal("gopher", 6, scheme, schemeLength); + return equal(scheme, gopherScheme); } return false; } @@ -1324,7 +1343,7 @@ void KURL::parse(const char* url, const String* originalString) && isLetterMatchIgnoringCase(url[userStart+8], 't'); // File URLs need a host part unless it is just file:// or file://localhost - bool degenFilePath = pathStart == pathEnd && (hostStart == hostEnd || hostIsLocalHost); + bool degenerateFilePath = pathStart == pathEnd && (hostStart == hostEnd || hostIsLocalHost); bool haveNonHostAuthorityPart = userStart != userEnd || passwordStart != passwordEnd || portStart != portEnd; @@ -1332,7 +1351,7 @@ void KURL::parse(const char* url, const String* originalString) *p++ = ':'; // if we have at least one authority part or a file URL - add "//" and authority - if (isFile ? !degenFilePath : (haveNonHostAuthorityPart || hostStart != hostEnd)) { + if (isFile ? !degenerateFilePath : (haveNonHostAuthorityPart || hostStart != hostEnd)) { *p++ = '/'; *p++ = '/'; @@ -1385,12 +1404,18 @@ void KURL::parse(const char* url, const String* originalString) } } m_portEnd = p - buffer.data(); - } else + } else { + if (isFile) { + ASSERT(degenerateFilePath); + *p++ = '/'; + *p++ = '/'; + } m_userStart = m_userEnd = m_passwordEnd = m_hostEnd = m_portEnd = p - buffer.data(); + } // For canonicalization, ensure we have a '/' for no path. - // Do this only for URL with protocol http or https. - if (m_protocolIsInHTTPFamily && pathEnd == pathStart) + // Do this only for URL with protocol file, http or https. + if ((m_protocolIsInHTTPFamily || isFile) && pathEnd == pathStart) *p++ = '/'; // add path, escaping bad characters diff --git a/Source/WebCore/platform/KURL.h b/Source/WebCore/platform/KURL.h index 49cd9514c..9afced50e 100644 --- a/Source/WebCore/platform/KURL.h +++ b/Source/WebCore/platform/KURL.h @@ -35,11 +35,7 @@ typedef const struct __CFURL* CFURLRef; #endif #if PLATFORM(MAC) || (PLATFORM(QT) && USE(QTKIT)) -#ifdef __OBJC__ -@class NSURL; -#else -class NSURL; -#endif +OBJC_CLASS NSURL; #endif #if PLATFORM(QT) @@ -222,6 +218,13 @@ public: const CString& utf8String() const { return m_url.utf8String(); } #endif + +#if USE(GOOGLEURL) + const KURL* innerURL() const { return m_url.innerURL(); } +#else + const KURL* innerURL() const { return 0; } +#endif + #ifndef NDEBUG void print() const; #endif diff --git a/Source/WebCore/platform/KURLGoogle.cpp b/Source/WebCore/platform/KURLGoogle.cpp index 6bf9fccb1..0507a2412 100644 --- a/Source/WebCore/platform/KURLGoogle.cpp +++ b/Source/WebCore/platform/KURLGoogle.cpp @@ -174,6 +174,35 @@ KURLGooglePrivate::KURLGooglePrivate(WTF::HashTableDeletedValueType) { } +KURLGooglePrivate::KURLGooglePrivate(const KURLGooglePrivate& o) + : m_isValid(o.m_isValid) + , m_protocolIsInHTTPFamily(o.m_protocolIsInHTTPFamily) + , m_parsed(o.m_parsed) + , m_utf8(o.m_utf8) + , m_utf8IsASCII(o.m_utf8IsASCII) + , m_stringIsValid(o.m_stringIsValid) + , m_string(o.m_string) +{ + if (o.m_innerURL.get()) + m_innerURL = adoptPtr(new KURL(o.m_innerURL->copy())); +} + +KURLGooglePrivate& KURLGooglePrivate::operator=(const KURLGooglePrivate& o) +{ + m_isValid = o.m_isValid; + m_protocolIsInHTTPFamily = o.m_protocolIsInHTTPFamily; + m_parsed = o.m_parsed; + m_utf8 = o.m_utf8; + m_utf8IsASCII = o.m_utf8IsASCII; + m_stringIsValid = o.m_stringIsValid; + m_string = o.m_string; + if (o.m_innerURL.get()) + m_innerURL = adoptPtr(new KURL(o.m_innerURL->copy())); + else + m_innerURL.clear(); + return *this; +} + // Setters for the data. Using the ASCII version when you know the // data is ASCII will be slightly more efficient. The UTF-8 version // will always be correct if the caller is unsure. @@ -197,6 +226,7 @@ void KURLGooglePrivate::setUtf8(const CString& str) m_utf8 = str; m_stringIsValid = false; initProtocolIsInHTTPFamily(); + initInnerURL(); } void KURLGooglePrivate::setAscii(const CString& str) @@ -205,6 +235,7 @@ void KURLGooglePrivate::setAscii(const CString& str) m_utf8IsASCII = true; m_stringIsValid = false; initProtocolIsInHTTPFamily(); + initInnerURL(); } void KURLGooglePrivate::init(const KURL& base, @@ -258,6 +289,21 @@ void KURLGooglePrivate::init(const KURL& base, const CHAR* rel, int relLength, } } +void KURLGooglePrivate::initInnerURL() +{ + if (!m_isValid) { + m_innerURL.clear(); + return; + } + url_parse::Parsed* innerParsed = m_parsed.inner_parsed(); + if (innerParsed) + m_innerURL = adoptPtr(new KURL( + ParsedURLString, + String(m_utf8.data() + innerParsed->scheme.begin, innerParsed->Length() - innerParsed->scheme.begin))); + else + m_innerURL.clear(); +} + void KURLGooglePrivate::initProtocolIsInHTTPFamily() { if (!m_isValid) { @@ -285,6 +331,10 @@ void KURLGooglePrivate::copyTo(KURLGooglePrivate* dest) const dest->m_utf8IsASCII = m_utf8IsASCII; dest->m_stringIsValid = false; dest->m_string = String(); // Clear the invalid string to avoid cross thread ref counting. + if (m_innerURL) + dest->m_innerURL = adoptPtr(new KURL(m_innerURL->copy())); + else + dest->m_innerURL.clear(); } String KURLGooglePrivate::componentString(const url_parse::Component& comp) const @@ -827,7 +877,10 @@ String encodeWithURLEscapeSequences(const String& notEncodedString) buffer.Resize(inputLength * 3); url_util::EncodeURIComponent(input, inputLength, &buffer); - return String(buffer.data(), buffer.length()); + String escaped(buffer.data(), buffer.length()); + // Unescape '/'; it's safe and much prettier. + escaped.replace("%2F", "/"); + return escaped; } bool KURL::isHierarchical() const diff --git a/Source/WebCore/platform/KURLGooglePrivate.h b/Source/WebCore/platform/KURLGooglePrivate.h index 31efd64ee..374d0d726 100644 --- a/Source/WebCore/platform/KURLGooglePrivate.h +++ b/Source/WebCore/platform/KURLGooglePrivate.h @@ -31,6 +31,7 @@ #ifndef KURLGooglePrivate_h #define KURLGooglePrivate_h +#include <wtf/OwnPtr.h> #include <wtf/text/CString.h> #include <googleurl/src/url_parse.h> @@ -49,6 +50,8 @@ namespace WebCore { KURLGooglePrivate(); KURLGooglePrivate(const url_parse::Parsed&, bool isValid); KURLGooglePrivate(WTF::HashTableDeletedValueType); + KURLGooglePrivate(const KURLGooglePrivate&); + KURLGooglePrivate& operator=(const KURLGooglePrivate&); // Initializes the object. This will call through the backend initializer // below. @@ -94,7 +97,10 @@ namespace WebCore { bool m_protocolIsInHTTPFamily; url_parse::Parsed m_parsed; // Indexes into the UTF-8 version of the string. + KURL* innerURL() const { return m_innerURL.get(); } + private: + void initInnerURL(); void initProtocolIsInHTTPFamily(); CString m_utf8; @@ -107,6 +113,8 @@ namespace WebCore { mutable bool m_stringIsValid; mutable String m_string; + + OwnPtr<KURL> m_innerURL; }; } // namespace WebCore diff --git a/Source/WebCore/platform/Language.cpp b/Source/WebCore/platform/Language.cpp index 6cf259724..47f09f609 100644 --- a/Source/WebCore/platform/Language.cpp +++ b/Source/WebCore/platform/Language.cpp @@ -56,24 +56,91 @@ void languageDidChange() iter->second(iter->first); } -static String& languageOverride() +String defaultLanguage() +{ + Vector<String> languages = userPreferredLanguages(); + if (languages.size()) + return languages[0]; + + return emptyString(); +} + +static Vector<String>& preferredLanguagesOverride() { - DEFINE_STATIC_LOCAL(String, override, ()); + DEFINE_STATIC_LOCAL(Vector<String>, override, ()); return override; } -String defaultLanguage() +void overrideUserPreferredLanguages(const Vector<String>& override) { - const String& override = languageOverride(); - if (!override.isNull()) + preferredLanguagesOverride() = override; +} + +Vector<String> userPreferredLanguages() +{ + Vector<String>& override = preferredLanguagesOverride(); + if (!override.isEmpty()) return override; + + return platformUserPreferredLanguages(); +} + +static String canonicalLanguageIdentifier(const String& languageCode) +{ + String lowercaseLanguageCode = languageCode.lower(); + + if (lowercaseLanguageCode.length() >= 3 && lowercaseLanguageCode[2] == '_') + lowercaseLanguageCode.replace(2, 1, "-"); - return platformDefaultLanguage(); + return lowercaseLanguageCode; } -void overrideDefaultLanguage(const String& override) +static String bestMatchingLanguage(const String& language, const Vector<String>& languageList) { - languageOverride() = override; + bool canMatchLanguageOnly = (language.length() == 2 || (language.length() >= 3 && language[2] == '-')); + String languageWithoutLocaleMatch; + String languageMatchButNotLocale; + + for (size_t i = 0; i < languageList.size(); ++i) { + String canonicalizedLanguageFromList = canonicalLanguageIdentifier(languageList[i]); + + if (language == canonicalizedLanguageFromList) + return languageList[i]; + + if (canMatchLanguageOnly && canonicalizedLanguageFromList.length() >= 2) { + if (language[0] == canonicalizedLanguageFromList[0] && language[1] == canonicalizedLanguageFromList[1]) { + if (!languageWithoutLocaleMatch.length() && canonicalizedLanguageFromList.length() == 2) + languageWithoutLocaleMatch = languageList[i]; + if (!languageMatchButNotLocale.length() && canonicalizedLanguageFromList.length() >= 3) + languageMatchButNotLocale = languageList[i]; + } + } + } + + // If we have both a language-only match and a languge-but-not-locale match, return the + // languge-only match as is considered a "better" match. For example, if the list + // provided has both "en-GB" and "en" and the user prefers "en-US" we will return "en". + if (languageWithoutLocaleMatch.length()) + return languageWithoutLocaleMatch; + + if (languageMatchButNotLocale.length()) + return languageMatchButNotLocale; + + return emptyString(); } +String preferredLanguageFromList(const Vector<String>& languageList) +{ + Vector<String> preferredLanguages = userPreferredLanguages(); + + for (size_t i = 0; i < preferredLanguages.size(); ++i) { + String bestMatch = bestMatchingLanguage(canonicalLanguageIdentifier(preferredLanguages[i]), languageList); + + if (bestMatch.length()) + return bestMatch; + } + + return emptyString(); +} + } diff --git a/Source/WebCore/platform/Language.h b/Source/WebCore/platform/Language.h index 656caee07..411615c9e 100644 --- a/Source/WebCore/platform/Language.h +++ b/Source/WebCore/platform/Language.h @@ -27,18 +27,23 @@ #define Language_h #include <wtf/Forward.h> +#include <wtf/Vector.h> namespace WebCore { String defaultLanguage(); -void overrideDefaultLanguage(const String&); +Vector<String> userPreferredLanguages(); +void overrideUserPreferredLanguages(const Vector<String>&); +String preferredLanguageFromList(const Vector<String>&); -// The observer function will be called when system language changes (unless it's overridden by overrideDefaultLanguage()). +// The observer function will be called when system language changes. typedef void (*LanguageChangeObserverFunction)(void* context); void addLanguageChangeObserver(void* context, LanguageChangeObserverFunction); void removeLanguageChangeObserver(void* context); -String platformDefaultLanguage(); +Vector<String> platformUserPreferredLanguages(); + +// Called from platform specific code when the user's preferred language(s) change. void languageDidChange(); } diff --git a/Source/WebCore/platform/LocalizationStrategy.h b/Source/WebCore/platform/LocalizationStrategy.h index b00ab13d0..8fab764b8 100644 --- a/Source/WebCore/platform/LocalizationStrategy.h +++ b/Source/WebCore/platform/LocalizationStrategy.h @@ -58,7 +58,7 @@ public: virtual String contextMenuItemTagOpenImageInNewWindow() = 0; virtual String contextMenuItemTagDownloadImageToDisk() = 0; virtual String contextMenuItemTagCopyImageToClipboard() = 0; -#if PLATFORM(QT) || PLATFORM(GTK) +#if PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL) virtual String contextMenuItemTagCopyImageUrlToClipboard() = 0; #endif virtual String contextMenuItemTagOpenFrameInNewWindow() = 0; diff --git a/Source/WebCore/platform/LocalizedStrings.cpp b/Source/WebCore/platform/LocalizedStrings.cpp index a6a41ac34..1409bbf31 100644 --- a/Source/WebCore/platform/LocalizedStrings.cpp +++ b/Source/WebCore/platform/LocalizedStrings.cpp @@ -127,7 +127,7 @@ String contextMenuItemTagCopyImageToClipboard() return localizationStrategy()->contextMenuItemTagCopyImageToClipboard(); } -#if PLATFORM(QT) || PLATFORM(GTK) +#if PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL) String contextMenuItemTagCopyImageUrlToClipboard() { return localizationStrategy()->contextMenuItemTagCopyImageUrlToClipboard(); diff --git a/Source/WebCore/platform/LocalizedStrings.h b/Source/WebCore/platform/LocalizedStrings.h index edceb6306..a73c991fe 100644 --- a/Source/WebCore/platform/LocalizedStrings.h +++ b/Source/WebCore/platform/LocalizedStrings.h @@ -54,7 +54,7 @@ namespace WebCore { String contextMenuItemTagOpenImageInNewWindow(); String contextMenuItemTagDownloadImageToDisk(); String contextMenuItemTagCopyImageToClipboard(); -#if PLATFORM(QT) || PLATFORM(GTK) +#if PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL) String contextMenuItemTagCopyImageUrlToClipboard(); #endif String contextMenuItemTagOpenFrameInNewWindow(); diff --git a/Source/WebCore/platform/Logging.cpp b/Source/WebCore/platform/Logging.cpp index 8f6428241..bd0196410 100644 --- a/Source/WebCore/platform/Logging.cpp +++ b/Source/WebCore/platform/Logging.cpp @@ -61,6 +61,8 @@ WTFLogChannel LogProgress = { 0x08000000, "WebCoreLogLevel", WTFLogChan WTFLogChannel LogFileAPI = { 0x10000000, "WebCoreLogLevel", WTFLogChannelOff }; +WTFLogChannel LogWebAudio = { 0x20000000, "WebCoreLogLevel", WTFLogChannelOff }; + WTFLogChannel* getChannelFromName(const String& channelName) { if (!(channelName.length() >= 2)) @@ -135,6 +137,9 @@ WTFLogChannel* getChannelFromName(const String& channelName) if (equalIgnoringCase(channelName, String("FileAPI"))) return &LogFileAPI; + if (equalIgnoringCase(channelName, String("WebAudio"))) + return &LogWebAudio; + return 0; } diff --git a/Source/WebCore/platform/Logging.h b/Source/WebCore/platform/Logging.h index 0092699d7..8201f16b3 100644 --- a/Source/WebCore/platform/Logging.h +++ b/Source/WebCore/platform/Logging.h @@ -59,6 +59,7 @@ namespace WebCore { extern WTFLogChannel LogArchives; extern WTFLogChannel LogProgress; extern WTFLogChannel LogFileAPI; + extern WTFLogChannel LogWebAudio; void initializeLoggingChannelsIfNecessary(); WTFLogChannel* getChannelFromName(const String& channelName); diff --git a/Source/WebCore/platform/MIMETypeRegistry.cpp b/Source/WebCore/platform/MIMETypeRegistry.cpp index d20986159..b5f2d4551 100644 --- a/Source/WebCore/platform/MIMETypeRegistry.cpp +++ b/Source/WebCore/platform/MIMETypeRegistry.cpp @@ -261,6 +261,10 @@ static void initializeSupportedImageMIMETypes() supportedImageMIMETypes->add(types[i]); supportedImageResourceMIMETypes->add(types[i]); } +#if PLATFORM(BLACKBERRY) + supportedImageMIMETypes->add("image/pjpeg"); + supportedImageResourceMIMETypes->add("image/pjpeg"); +#endif #endif } diff --git a/Source/WebCore/platform/MemoryPressureHandler.cpp b/Source/WebCore/platform/MemoryPressureHandler.cpp index bb0c64c97..982876d05 100644 --- a/Source/WebCore/platform/MemoryPressureHandler.cpp +++ b/Source/WebCore/platform/MemoryPressureHandler.cpp @@ -42,7 +42,7 @@ MemoryPressureHandler::MemoryPressureHandler() { } -#if !PLATFORM(MAC) || defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD) +#if !PLATFORM(MAC) || defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD) || PLATFORM(IOS) void MemoryPressureHandler::install() { } void MemoryPressureHandler::uninstall() { } diff --git a/Source/WebCore/platform/MemoryPressureHandler.h b/Source/WebCore/platform/MemoryPressureHandler.h index d9d2d90b2..9d6e95f8d 100644 --- a/Source/WebCore/platform/MemoryPressureHandler.h +++ b/Source/WebCore/platform/MemoryPressureHandler.h @@ -45,6 +45,7 @@ private: ~MemoryPressureHandler(); void respondToMemoryPressure(); + void releaseMemory(bool critical); bool m_installed; time_t m_lastRespondTime; diff --git a/Source/WebCore/platform/Pasteboard.h b/Source/WebCore/platform/Pasteboard.h index 866e7e532..fedfc8abd 100644 --- a/Source/WebCore/platform/Pasteboard.h +++ b/Source/WebCore/platform/Pasteboard.h @@ -43,15 +43,9 @@ // knowledge of the frame and editor or moved into the editing directory. #if PLATFORM(MAC) -#ifdef __OBJC__ -@class NSFileWrapper; -@class NSPasteboard; -@class NSArray; -#else -class NSFileWrapper; -class NSPasteboard; -class NSArray; -#endif +OBJC_CLASS NSFileWrapper; +OBJC_CLASS NSPasteboard; +OBJC_CLASS NSArray; #endif #if PLATFORM(WIN) @@ -86,12 +80,10 @@ class Pasteboard { WTF_MAKE_NONCOPYABLE(Pasteboard); WTF_MAKE_FAST_ALLOCATED; public: #if PLATFORM(MAC) - //Helper functions to allow Clipboard to share code - static void writeSelection(NSPasteboard*, NSArray* pasteboardTypes, Range* selectedRange, bool canSmartCopyOrDelete, Frame*); - static void writeURL(NSPasteboard* pasteboard, NSArray* types, const KURL& url, const String& titleStr, Frame* frame); - static void writePlainText(NSPasteboard* pasteboard, const String& text); + void writeSelectionForTypes(NSArray* pasteboardTypes, Range* selectedRange, bool canSmartCopyOrDelete, Frame*); + void writeURLForTypes(NSArray* types, const KURL&, const String& titleStr, Frame*); - Pasteboard(NSPasteboard *); + Pasteboard(const String& pasteboardName); #endif static Pasteboard* generalPasteboard(); diff --git a/Source/WebCore/platform/PlatformKeyboardEvent.h b/Source/WebCore/platform/PlatformKeyboardEvent.h index f15496673..5990098db 100644 --- a/Source/WebCore/platform/PlatformKeyboardEvent.h +++ b/Source/WebCore/platform/PlatformKeyboardEvent.h @@ -32,11 +32,7 @@ #if PLATFORM(MAC) #include <wtf/RetainPtr.h> -#ifdef __OBJC__ -@class NSEvent; -#else -class NSEvent; -#endif +OBJC_CLASS NSEvent; #endif #if PLATFORM(WIN) diff --git a/Source/WebCore/platform/PlatformMenuDescription.h b/Source/WebCore/platform/PlatformMenuDescription.h index 08845cb4a..459d0a5ea 100644 --- a/Source/WebCore/platform/PlatformMenuDescription.h +++ b/Source/WebCore/platform/PlatformMenuDescription.h @@ -27,11 +27,7 @@ #define PlatformMenuDescription_h #if PLATFORM(MAC) -#ifdef __OBJC__ -@class NSMutableArray; -#else -class NSMutableArray; -#endif +OBJC_CLASS NSMutableArray; #elif PLATFORM(QT) #include <qlist.h> #elif PLATFORM(GTK) diff --git a/Source/WebCore/platform/PlatformScreen.h b/Source/WebCore/platform/PlatformScreen.h index a9acb5dd0..827801b44 100644 --- a/Source/WebCore/platform/PlatformScreen.h +++ b/Source/WebCore/platform/PlatformScreen.h @@ -31,13 +31,8 @@ #include <wtf/RefPtr.h> #if PLATFORM(MAC) -#ifdef __OBJC__ - @class NSScreen; - @class NSWindow; -#else - class NSScreen; - class NSWindow; -#endif +OBJC_CLASS NSScreen; +OBJC_CLASS NSWindow; #endif typedef uint32_t PlatformDisplayID; @@ -45,6 +40,7 @@ typedef uint32_t PlatformDisplayID; namespace WebCore { class FloatRect; + class FrameView; class Widget; int screenHorizontalDPI(Widget*); @@ -53,19 +49,14 @@ namespace WebCore { int screenDepthPerComponent(Widget*); bool screenIsMonochrome(Widget*); - FloatRect screenRect(Widget*); - FloatRect screenAvailableRect(Widget*); - -#if PLATFORM(CHROMIUM) - // Measured in frames per second. 0 if the refresh rate is unknown, or not applicable. - double screenRefreshRate(Widget*); -#endif + FloatRect screenRect(FrameView*); + FloatRect screenAvailableRect(FrameView*); #if PLATFORM(MAC) NSScreen *screenForWindow(NSWindow *); - FloatRect toUserSpace(const NSRect&, NSWindow *destination); - NSRect toDeviceSpace(const FloatRect&, NSWindow *source); + FloatRect toUserSpace(const NSRect&, NSWindow *destination, float deviceScaleFactor); + NSRect toDeviceSpace(const FloatRect&, NSWindow *source, float deviceScaleFactor); NSPoint flipScreenPoint(const NSPoint&, NSScreen *); #endif diff --git a/Source/WebCore/platform/PlatformWheelEvent.h b/Source/WebCore/platform/PlatformWheelEvent.h index 8e99e4762..f76f4c958 100644 --- a/Source/WebCore/platform/PlatformWheelEvent.h +++ b/Source/WebCore/platform/PlatformWheelEvent.h @@ -77,11 +77,12 @@ namespace WebCore { #if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN)) enum PlatformWheelEventPhase { PlatformWheelEventPhaseNone = 0, - PlatformWheelEventPhaseBegan = 1 << 1, - PlatformWheelEventPhaseStationary = 1 << 2, - PlatformWheelEventPhaseChanged = 1 << 3, - PlatformWheelEventPhaseEnded = 1 << 4, - PlatformWheelEventPhaseCancelled = 1 << 5, + PlatformWheelEventPhaseBegan = 1 << 0, + PlatformWheelEventPhaseStationary = 1 << 1, + PlatformWheelEventPhaseChanged = 1 << 2, + PlatformWheelEventPhaseEnded = 1 << 3, + PlatformWheelEventPhaseCancelled = 1 << 4, + PlatformWheelEventPhaseMayBegin = 1 << 5, }; #endif diff --git a/Source/WebCore/platform/PopupMenuClient.h b/Source/WebCore/platform/PopupMenuClient.h index 7c2b4a9b4..4abe3379c 100644 --- a/Source/WebCore/platform/PopupMenuClient.h +++ b/Source/WebCore/platform/PopupMenuClient.h @@ -64,7 +64,7 @@ public: virtual void setTextFromItem(unsigned listIndex) = 0; virtual void listBoxSelectItem(int /*listIndex*/, bool /*allowMultiplySelections*/, bool /*shift*/, bool /*fireOnChangeNow*/ = true) { ASSERT_NOT_REACHED(); } - virtual bool multiple() + virtual bool multiple() const { ASSERT_NOT_REACHED(); return false; diff --git a/Source/WebCore/platform/RunLoop.cpp b/Source/WebCore/platform/RunLoop.cpp new file mode 100644 index 000000000..cbbca4c61 --- /dev/null +++ b/Source/WebCore/platform/RunLoop.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RunLoop.h" + +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +#if !PLATFORM(MAC) + +static RunLoop* s_mainRunLoop; + +void RunLoop::initializeMainRunLoop() +{ + if (s_mainRunLoop) + return; + s_mainRunLoop = RunLoop::current(); +} + +RunLoop* RunLoop::current() +{ + DEFINE_STATIC_LOCAL(WTF::ThreadSpecific<RunLoop>, runLoopData, ()); + return &*runLoopData; +} + +RunLoop* RunLoop::main() +{ + ASSERT(s_mainRunLoop); + return s_mainRunLoop; +} + +#endif + +void RunLoop::performWork() +{ + Vector<Function<void()> > functionQueue; + { + MutexLocker locker(m_functionQueueLock); + m_functionQueue.swap(functionQueue); + } + + for (size_t i = 0; i < functionQueue.size(); ++i) + functionQueue[i](); +} + +void RunLoop::dispatch(const Function<void()>& function) +{ + MutexLocker locker(m_functionQueueLock); + m_functionQueue.append(function); + + wakeUp(); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/RunLoop.h b/Source/WebCore/platform/RunLoop.h new file mode 100644 index 000000000..1f19c836d --- /dev/null +++ b/Source/WebCore/platform/RunLoop.h @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * Portions Copyright (c) 2010 Motorola Mobility, 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 INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RunLoop_h +#define RunLoop_h + +#include <wtf/Forward.h> +#include <wtf/Functional.h> +#include <wtf/HashMap.h> +#include <wtf/ThreadSpecific.h> +#include <wtf/Threading.h> +#include <wtf/Vector.h> + +#if PLATFORM(GTK) +#include <wtf/gobject/GRefPtr.h> +typedef struct _GSource GSource; +typedef struct _GMainLoop GMainLoop; +typedef struct _GMainContext GMainContext; +typedef int gboolean; +#endif + +namespace WebCore { + +class RunLoop { +public: + // Must be called from the main thread (except for the Mac platform, where it + // can be called from any thread). + static void initializeMainRunLoop(); + + static RunLoop* current(); + static RunLoop* main(); + + void dispatch(const Function<void()>&); + + static void run(); + void stop(); + +#if PLATFORM(MAC) + void runForDuration(double duration); +#endif + + class TimerBase { + friend class RunLoop; + public: + TimerBase(RunLoop*); + virtual ~TimerBase(); + + void startRepeating(double repeatInterval) { start(repeatInterval, true); } + void startOneShot(double interval) { start(interval, false); } + + void stop(); + bool isActive() const; + + virtual void fired() = 0; + + private: + void start(double nextFireInterval, bool repeat); + + RunLoop* m_runLoop; + +#if PLATFORM(WIN) + static void timerFired(RunLoop*, uint64_t ID); + uint64_t m_ID; + bool m_isRepeating; +#elif PLATFORM(MAC) + static void timerFired(CFRunLoopTimerRef, void*); + CFRunLoopTimerRef m_timer; +#elif PLATFORM(QT) + static void timerFired(RunLoop*, int ID); + int m_ID; + bool m_isRepeating; +#elif PLATFORM(GTK) + static gboolean timerFiredCallback(RunLoop::TimerBase*); + gboolean isRepeating() const { return m_isRepeating; } + void clearTimerSource(); + GRefPtr<GSource> m_timerSource; + gboolean m_isRepeating; +#endif + }; + + template <typename TimerFiredClass> + class Timer : public TimerBase { + public: + typedef void (TimerFiredClass::*TimerFiredFunction)(); + + Timer(RunLoop* runLoop, TimerFiredClass* o, TimerFiredFunction f) + : TimerBase(runLoop) + , m_object(o) + , m_function(f) + { + } + + private: + virtual void fired() { (m_object->*m_function)(); } + + TimerFiredClass* m_object; + TimerFiredFunction m_function; + }; + +private: + friend class WTF::ThreadSpecific<RunLoop>; + + RunLoop(); + ~RunLoop(); + + void performWork(); + void wakeUp(); + + Mutex m_functionQueueLock; + Vector<Function<void()> > m_functionQueue; + +#if PLATFORM(WIN) + static bool registerRunLoopMessageWindowClass(); + static LRESULT CALLBACK RunLoopWndProc(HWND, UINT, WPARAM, LPARAM); + LRESULT wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + HWND m_runLoopMessageWindow; + + typedef HashMap<uint64_t, TimerBase*> TimerMap; + TimerMap m_activeTimers; +#elif PLATFORM(MAC) + RunLoop(CFRunLoopRef); + static void performWork(void*); + CFRunLoopRef m_runLoop; + CFRunLoopSourceRef m_runLoopSource; + int m_nestingLevel; +#elif PLATFORM(QT) + typedef HashMap<int, TimerBase*> TimerMap; + TimerMap m_activeTimers; + class TimerObject; + TimerObject* m_timerObject; +#elif PLATFORM(GTK) +public: + static gboolean queueWork(RunLoop*); + GMainLoop* mainLoop(); +private: + GMainContext* m_runLoopContext; + GMainLoop* m_runLoopMain; +#endif +}; + +} // namespace WebCore + +#endif // RunLoop_h diff --git a/Source/WebCore/platform/SchemeRegistry.cpp b/Source/WebCore/platform/SchemeRegistry.cpp index 5cdeb3375..d5d36f151 100644 --- a/Source/WebCore/platform/SchemeRegistry.cpp +++ b/Source/WebCore/platform/SchemeRegistry.cpp @@ -25,6 +25,7 @@ */ #include "config.h" #include "SchemeRegistry.h" +#include <wtf/MainThread.h> namespace WebCore { @@ -152,6 +153,19 @@ static URLSchemesMap& schemesAllowingDatabaseAccessInPrivateBrowsing() return schemesAllowingDatabaseAccessInPrivateBrowsing; } +static URLSchemesMap& CORSEnabledSchemes() +{ + // FIXME: http://bugs.webkit.org/show_bug.cgi?id=77160 + DEFINE_STATIC_LOCAL(URLSchemesMap, CORSEnabledSchemes, ()); + + if (CORSEnabledSchemes.isEmpty()) { + CORSEnabledSchemes.add("http"); + CORSEnabledSchemes.add("https"); + } + + return CORSEnabledSchemes; +} + bool SchemeRegistry::shouldTreatURLSchemeAsLocal(const String& scheme) { if (scheme.isEmpty()) @@ -273,4 +287,16 @@ bool SchemeRegistry::allowsDatabaseAccessInPrivateBrowsing(const String& scheme) return schemesAllowingDatabaseAccessInPrivateBrowsing().contains(scheme); } +void SchemeRegistry::registerURLSchemeAsCORSEnabled(const String& scheme) +{ + CORSEnabledSchemes().add(scheme); +} + +bool SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(const String& scheme) +{ + if (scheme.isEmpty()) + return false; + return CORSEnabledSchemes().contains(scheme); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/SchemeRegistry.h b/Source/WebCore/platform/SchemeRegistry.h index 04f1bf864..9b08e0a41 100644 --- a/Source/WebCore/platform/SchemeRegistry.h +++ b/Source/WebCore/platform/SchemeRegistry.h @@ -78,6 +78,10 @@ public: static bool allowsLocalStorageAccessInPrivateBrowsing(const String& scheme); static void registerURLSchemeAsAllowingDatabaseAccessInPrivateBrowsing(const String& scheme); static bool allowsDatabaseAccessInPrivateBrowsing(const String& scheme); + + // Allow non-HTTP schemes to be registered to allow CORS requests. + static void registerURLSchemeAsCORSEnabled(const String& scheme); + static bool shouldTreatURLSchemeAsCORSEnabled(const String& scheme); }; } // namespace WebCore diff --git a/Source/WebCore/platform/ScrollAnimator.h b/Source/WebCore/platform/ScrollAnimator.h index 576743945..b33c45812 100644 --- a/Source/WebCore/platform/ScrollAnimator.h +++ b/Source/WebCore/platform/ScrollAnimator.h @@ -96,6 +96,8 @@ public: virtual void resetZoom(); virtual void setZoomParametersForTest(float, float, float); + virtual bool shouldScrollbarParticipateInHitTesting(Scrollbar*) { return true; } + protected: ScrollAnimator(ScrollableArea*); diff --git a/Source/WebCore/platform/ScrollView.cpp b/Source/WebCore/platform/ScrollView.cpp index d76a909e5..f2bb054a3 100644 --- a/Source/WebCore/platform/ScrollView.cpp +++ b/Source/WebCore/platform/ScrollView.cpp @@ -219,7 +219,11 @@ void ScrollView::setClipsRepaints(bool clipsRepaints) void ScrollView::setDelegatesScrolling(bool delegatesScrolling) { + if (m_delegatesScrolling == delegatesScrolling) + return; + m_delegatesScrolling = delegatesScrolling; + delegatesScrollingDidChange(); } #if !PLATFORM(GTK) @@ -828,9 +832,9 @@ Scrollbar* ScrollView::scrollbarAtPoint(const IntPoint& windowPoint) return 0; IntPoint viewPoint = convertFromContainingWindow(windowPoint); - if (m_horizontalScrollbar && m_horizontalScrollbar->frameRect().contains(viewPoint)) + if (m_horizontalScrollbar && m_horizontalScrollbar->shouldParticipateInHitTesting() && m_horizontalScrollbar->frameRect().contains(viewPoint)) return m_horizontalScrollbar.get(); - if (m_verticalScrollbar && m_verticalScrollbar->frameRect().contains(viewPoint)) + if (m_verticalScrollbar && m_verticalScrollbar->shouldParticipateInHitTesting() && m_verticalScrollbar->frameRect().contains(viewPoint)) return m_verticalScrollbar.get(); return 0; } @@ -991,6 +995,7 @@ void ScrollView::scrollbarStyleChanged(int, bool forceUpdate) contentsResized(); updateScrollbars(scrollOffset()); + positionScrollbarLayers(); } void ScrollView::updateScrollCorner() @@ -1075,7 +1080,7 @@ void ScrollView::paint(GraphicsContext* context, const IntRect& rect) paintContents(context, documentDirtyRect); } -#if USE(ACCELERATED_COMPOSITING) && PLATFORM(CHROMIUM) && ENABLE(RUBBER_BANDING) +#if USE(ACCELERATED_COMPOSITING) && ENABLE(RUBBER_BANDING) if (!layerForOverhangAreas()) calculateAndPaintOverhangAreas(context, rect); #else diff --git a/Source/WebCore/platform/ScrollView.h b/Source/WebCore/platform/ScrollView.h index 5d34a9288..ba586a4ab 100644 --- a/Source/WebCore/platform/ScrollView.h +++ b/Source/WebCore/platform/ScrollView.h @@ -301,6 +301,7 @@ protected: virtual void paintOverhangAreas(GraphicsContext*, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect); virtual void visibleContentsResized() = 0; + virtual void delegatesScrollingDidChange() { } IntRect fixedVisibleContentRect() const { return m_fixedVisibleContentRect; } diff --git a/Source/WebCore/platform/ScrollableArea.cpp b/Source/WebCore/platform/ScrollableArea.cpp index 374092eb2..99b9babc3 100644 --- a/Source/WebCore/platform/ScrollableArea.cpp +++ b/Source/WebCore/platform/ScrollableArea.cpp @@ -181,7 +181,7 @@ void ScrollableArea::setScrollOffsetFromAnimation(const IntPoint& offset) // Tell the scrollbars to update their thumb postions. if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { horizontalScrollbar->offsetDidChange(); - if (horizontalScrollbar->isOverlayScrollbar()) { + if (horizontalScrollbar->isOverlayScrollbar() && !hasLayerForHorizontalScrollbar()) { if (!verticalScrollbar) horizontalScrollbar->invalidate(); else { @@ -195,7 +195,7 @@ void ScrollableArea::setScrollOffsetFromAnimation(const IntPoint& offset) } if (verticalScrollbar) { verticalScrollbar->offsetDidChange(); - if (verticalScrollbar->isOverlayScrollbar()) + if (verticalScrollbar->isOverlayScrollbar() && !hasLayerForVerticalScrollbar()) verticalScrollbar->invalidate(); } } diff --git a/Source/WebCore/platform/ScrollableArea.h b/Source/WebCore/platform/ScrollableArea.h index 26a8cfe10..0b4583bbe 100644 --- a/Source/WebCore/platform/ScrollableArea.h +++ b/Source/WebCore/platform/ScrollableArea.h @@ -184,7 +184,7 @@ protected: virtual GraphicsLayer* layerForHorizontalScrollbar() const { return 0; } virtual GraphicsLayer* layerForVerticalScrollbar() const { return 0; } virtual GraphicsLayer* layerForScrollCorner() const { return 0; } -#if PLATFORM(CHROMIUM) && ENABLE(RUBBER_BANDING) +#if ENABLE(RUBBER_BANDING) virtual GraphicsLayer* layerForOverhangAreas() const { return 0; } #endif #endif diff --git a/Source/WebCore/platform/Scrollbar.cpp b/Source/WebCore/platform/Scrollbar.cpp index b952d49df..3b9c195cf 100644 --- a/Source/WebCore/platform/Scrollbar.cpp +++ b/Source/WebCore/platform/Scrollbar.cpp @@ -487,6 +487,14 @@ bool Scrollbar::isOverlayScrollbar() const return m_theme->usesOverlayScrollbars(); } +bool Scrollbar::shouldParticipateInHitTesting() +{ + // Non-overlay scrollbars should always participate in hit testing. + if (!isOverlayScrollbar()) + return true; + return m_scrollableArea->scrollAnimator()->shouldScrollbarParticipateInHitTesting(this); +} + bool Scrollbar::isWindowActive() const { return m_scrollableArea && m_scrollableArea->isActive(); diff --git a/Source/WebCore/platform/Scrollbar.h b/Source/WebCore/platform/Scrollbar.h index 09b247b54..e4e72465b 100644 --- a/Source/WebCore/platform/Scrollbar.h +++ b/Source/WebCore/platform/Scrollbar.h @@ -87,6 +87,7 @@ public: virtual void setEnabled(bool e); virtual bool isOverlayScrollbar() const; + bool shouldParticipateInHitTesting(); bool isWindowActive() const; diff --git a/Source/WebCore/platform/SharedBuffer.h b/Source/WebCore/platform/SharedBuffer.h index d85abba1b..57cfc2949 100644 --- a/Source/WebCore/platform/SharedBuffer.h +++ b/Source/WebCore/platform/SharedBuffer.h @@ -23,6 +23,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #ifndef SharedBuffer_h #define SharedBuffer_h @@ -37,12 +38,7 @@ #endif #if PLATFORM(MAC) || (PLATFORM(QT) && USE(QTKIT)) -#ifdef __OBJC__ -@class NSData; -#else -class NSData; -#endif - +OBJC_CLASS NSData; #endif namespace WebCore { diff --git a/Source/WebCore/platform/Widget.h b/Source/WebCore/platform/Widget.h index 9fddf7092..3f19b61e2 100644 --- a/Source/WebCore/platform/Widget.h +++ b/Source/WebCore/platform/Widget.h @@ -45,13 +45,8 @@ #endif #if PLATFORM(MAC) -#ifdef __OBJC__ -@class NSView; -@class NSWindow; -#else -class NSView; -class NSWindow; -#endif +OBJC_CLASS NSView; +OBJC_CLASS NSWindow; typedef NSView *PlatformWidget; #endif diff --git a/Source/WebCore/platform/animation/AnimationUtilities.h b/Source/WebCore/platform/animation/AnimationUtilities.h index 128f2ed0e..aebca46bb 100644 --- a/Source/WebCore/platform/animation/AnimationUtilities.h +++ b/Source/WebCore/platform/animation/AnimationUtilities.h @@ -35,6 +35,11 @@ inline int blend(int from, int to, double progress) return static_cast<int>(lround(static_cast<double>(from) + static_cast<double>(to - from) * progress)); } +inline unsigned blend(unsigned from, unsigned to, double progress) +{ + return static_cast<unsigned>(lround(static_cast<double>(from) + static_cast<double>(to - from) * progress)); +} + inline double blend(double from, double to, double progress) { return from + (to - from) * progress; diff --git a/Source/WebCore/platform/audio/AudioArray.h b/Source/WebCore/platform/audio/AudioArray.h index a14c950dd..7a2251b38 100644 --- a/Source/WebCore/platform/audio/AudioArray.h +++ b/Source/WebCore/platform/audio/AudioArray.h @@ -127,7 +127,7 @@ public: memset(this->data() + start, 0, sizeof(T) * (end - start)); } - void copyToRange(T* sourceData, unsigned start, unsigned end) + void copyToRange(const T* sourceData, unsigned start, unsigned end) { bool isSafe = (start <= end) && (end <= this->size()); ASSERT(isSafe); diff --git a/Source/WebCore/platform/audio/AudioBus.cpp b/Source/WebCore/platform/audio/AudioBus.cpp index 800197e2d..eea191961 100644 --- a/Source/WebCore/platform/audio/AudioBus.cpp +++ b/Source/WebCore/platform/audio/AudioBus.cpp @@ -34,9 +34,7 @@ #include "DenormalDisabler.h" -#if !PLATFORM(MAC) #include "SincResampler.h" -#endif #include "VectorMath.h" #include <algorithm> #include <assert.h> @@ -132,6 +130,11 @@ AudioChannel* AudioBus::channelByType(unsigned channelType) return 0; } +const AudioChannel* AudioBus::channelByType(unsigned type) const +{ + return const_cast<AudioBus*>(this)->channelByType(type); +} + // Returns true if the channel count and frame-size match. bool AudioBus::topologyMatches(const AudioBus& bus) const { @@ -145,7 +148,7 @@ bool AudioBus::topologyMatches(const AudioBus& bus) const return true; } -PassOwnPtr<AudioBus> AudioBus::createBufferFromRange(AudioBus* sourceBuffer, unsigned startFrame, unsigned endFrame) +PassOwnPtr<AudioBus> AudioBus::createBufferFromRange(const AudioBus* sourceBuffer, unsigned startFrame, unsigned endFrame) { size_t numberOfSourceFrames = sourceBuffer->length(); unsigned numberOfChannels = sourceBuffer->numberOfChannels(); @@ -185,7 +188,7 @@ void AudioBus::normalize() scale(1.0f / max); } -void AudioBus::scale(double scale) +void AudioBus::scale(float scale) { for (unsigned i = 0; i < numberOfChannels(); ++i) channel(i)->scale(scale); @@ -243,7 +246,8 @@ void AudioBus::sumFrom(const AudioBus &sourceBus) OP \ GAIN_DEZIPPER \ } \ - gain = totalDesiredGain; \ + if (!framesToDezipper) \ + gain = totalDesiredGain; \ OP##_V #define STEREO_SUM \ @@ -254,10 +258,11 @@ void AudioBus::sumFrom(const AudioBus &sourceBus) *destinationR++ = sumR; \ } -// FIXME: this can be optimized with additional VectorMath functions. #define STEREO_SUM_V \ - for (; k < framesToProcess; ++k) \ - STEREO_SUM + { \ + vsma(sourceL, 1, &gain, destinationL, 1, framesToProcess - k); \ + vsma(sourceR, 1, &gain, destinationR, 1, framesToProcess - k); \ + } // Mono -> stereo (mix equally into L and R) // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center... @@ -271,8 +276,10 @@ void AudioBus::sumFrom(const AudioBus &sourceBus) } #define MONO2STEREO_SUM_V \ - for (; k < framesToProcess; ++k) \ - MONO2STEREO_SUM + { \ + vsma(sourceL, 1, &gain, destinationL, 1, framesToProcess - k); \ + vsma(sourceL, 1, &gain, destinationR, 1, framesToProcess - k); \ + } #define MONO_SUM \ { \ @@ -281,8 +288,9 @@ void AudioBus::sumFrom(const AudioBus &sourceBus) } #define MONO_SUM_V \ - for (; k < framesToProcess; ++k) \ - MONO_SUM + { \ + vsma(sourceL, 1, &gain, destinationL, 1, framesToProcess - k); \ + } #define STEREO_NO_SUM \ { \ @@ -324,12 +332,10 @@ void AudioBus::sumFrom(const AudioBus &sourceBus) vsmul(sourceL, 1, &gain, destinationL, 1, framesToProcess - k); \ } -void AudioBus::processWithGainFromMonoStereo(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus) +void AudioBus::processWithGainFromMonoStereo(const AudioBus &sourceBus, float* lastMixGain, float targetGain, bool sumToBus) { // We don't want to suddenly change the gain from mixing one time slice to the next, // so we "de-zipper" by slowly changing the gain each sample-frame until we've achieved the target gain. - - // FIXME: targetGain and lastMixGain should be changed to floats instead of doubles. // Take master bus gain into account as well as the targetGain. float totalDesiredGain = static_cast<float>(m_busGain * targetGain); @@ -345,8 +351,8 @@ void AudioBus::processWithGainFromMonoStereo(const AudioBus &sourceBus, double* const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data(); const float* sourceR = numberOfSourceChannels > 1 ? sourceBusSafe.channelByType(ChannelRight)->data() : 0; - float* destinationL = channelByType(ChannelLeft)->data(); - float* destinationR = numberOfDestinationChannels > 1 ? channelByType(ChannelRight)->data() : 0; + float* destinationL = channelByType(ChannelLeft)->mutableData(); + float* destinationR = numberOfDestinationChannels > 1 ? channelByType(ChannelRight)->mutableData() : 0; const float DezipperRate = 0.005f; int framesToProcess = length(); @@ -392,10 +398,10 @@ void AudioBus::processWithGainFromMonoStereo(const AudioBus &sourceBus, double* } // Save the target gain as the starting point for next time around. - *lastMixGain = static_cast<double>(gain); + *lastMixGain = gain; } -void AudioBus::processWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus) +void AudioBus::processWithGainFrom(const AudioBus &sourceBus, float* lastMixGain, float targetGain, bool sumToBus) { // Make sure we're summing from same type of bus. // We *are* able to sum from mono -> stereo @@ -437,23 +443,22 @@ void AudioBus::copyWithSampleAccurateGainValuesFrom(const AudioBus &sourceBus, f for (unsigned channelIndex = 0; channelIndex < numberOfChannels(); ++channelIndex) { if (sourceBus.numberOfChannels() == numberOfChannels()) source = sourceBus.channel(channelIndex)->data(); - float* destination = channel(channelIndex)->data(); + float* destination = channel(channelIndex)->mutableData(); vmul(source, 1, gainValues, 1, destination, 1, numberOfGainValues); } } -void AudioBus::copyWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain) +void AudioBus::copyWithGainFrom(const AudioBus &sourceBus, float* lastMixGain, float targetGain) { processWithGainFrom(sourceBus, lastMixGain, targetGain, false); } -void AudioBus::sumWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain) +void AudioBus::sumWithGainFrom(const AudioBus &sourceBus, float* lastMixGain, float targetGain) { processWithGainFrom(sourceBus, lastMixGain, targetGain, true); } -#if !PLATFORM(MAC) -PassOwnPtr<AudioBus> AudioBus::createBySampleRateConverting(AudioBus* sourceBus, bool mixToMono, double newSampleRate) +PassOwnPtr<AudioBus> AudioBus::createBySampleRateConverting(const AudioBus* sourceBus, bool mixToMono, double newSampleRate) { // sourceBus's sample-rate must be known. ASSERT(sourceBus && sourceBus->sampleRate()); @@ -477,7 +482,7 @@ PassOwnPtr<AudioBus> AudioBus::createBySampleRateConverting(AudioBus* sourceBus, } // First, mix to mono (if necessary) then sample-rate convert. - AudioBus* resamplerSourceBus; + const AudioBus* resamplerSourceBus; OwnPtr<AudioBus> mixedMonoBus; if (mixToMono) { mixedMonoBus = AudioBus::createByMixingToMono(sourceBus); @@ -498,8 +503,8 @@ PassOwnPtr<AudioBus> AudioBus::createBySampleRateConverting(AudioBus* sourceBus, // Sample-rate convert each channel. for (unsigned i = 0; i < numberOfDestinationChannels; ++i) { - float* source = resamplerSourceBus->channel(i)->data(); - float* destination = destinationBus->channel(i)->data(); + const float* source = resamplerSourceBus->channel(i)->data(); + float* destination = destinationBus->channel(i)->mutableData(); SincResampler resampler(sampleRateRatio); resampler.process(source, destination, sourceLength); @@ -508,9 +513,8 @@ PassOwnPtr<AudioBus> AudioBus::createBySampleRateConverting(AudioBus* sourceBus, destinationBus->setSampleRate(newSampleRate); return destinationBus.release(); } -#endif // !PLATFORM(MAC) -PassOwnPtr<AudioBus> AudioBus::createByMixingToMono(AudioBus* sourceBus) +PassOwnPtr<AudioBus> AudioBus::createByMixingToMono(const AudioBus* sourceBus) { switch (sourceBus->numberOfChannels()) { case 1: @@ -521,9 +525,9 @@ PassOwnPtr<AudioBus> AudioBus::createByMixingToMono(AudioBus* sourceBus) unsigned n = sourceBus->length(); OwnPtr<AudioBus> destinationBus(adoptPtr(new AudioBus(1, n))); - float* sourceL = sourceBus->channel(0)->data(); - float* sourceR = sourceBus->channel(1)->data(); - float* destination = destinationBus->channel(0)->data(); + const float* sourceL = sourceBus->channel(0)->data(); + const float* sourceR = sourceBus->channel(1)->data(); + float* destination = destinationBus->channel(0)->mutableData(); // Do the mono mixdown. for (unsigned i = 0; i < n; ++i) diff --git a/Source/WebCore/platform/audio/AudioBus.h b/Source/WebCore/platform/audio/AudioBus.h index 53fb4b969..b3da0f451 100644 --- a/Source/WebCore/platform/audio/AudioBus.h +++ b/Source/WebCore/platform/audio/AudioBus.h @@ -71,6 +71,7 @@ public: AudioChannel* channel(unsigned channel) { return m_channels[channel].get(); } const AudioChannel* channel(unsigned channel) const { return const_cast<AudioBus*>(this)->m_channels[channel].get(); } AudioChannel* channelByType(unsigned type); + const AudioChannel* channelByType(unsigned type) const; // Number of sample-frames size_t length() const { return m_length; } @@ -87,26 +88,24 @@ public: // Creates a new buffer from a range in the source buffer. // 0 may be returned if the range does not fit in the sourceBuffer - static PassOwnPtr<AudioBus> createBufferFromRange(AudioBus* sourceBuffer, unsigned startFrame, unsigned endFrame); + static PassOwnPtr<AudioBus> createBufferFromRange(const AudioBus* sourceBuffer, unsigned startFrame, unsigned endFrame); -#if !PLATFORM(MAC) // Creates a new AudioBus by sample-rate converting sourceBus to the newSampleRate. // setSampleRate() must have been previously called on sourceBus. // Note: sample-rate conversion is already handled in the file-reading code for the mac port, so we don't need this. - static PassOwnPtr<AudioBus> createBySampleRateConverting(AudioBus* sourceBus, bool mixToMono, double newSampleRate); -#endif + static PassOwnPtr<AudioBus> createBySampleRateConverting(const AudioBus* sourceBus, bool mixToMono, double newSampleRate); // Creates a new AudioBus by mixing all the channels down to mono. // If sourceBus is already mono, then the returned AudioBus will simply be a copy. - static PassOwnPtr<AudioBus> createByMixingToMono(AudioBus* sourceBus); + static PassOwnPtr<AudioBus> createByMixingToMono(const AudioBus* sourceBus); // Scales all samples by the same amount. - void scale(double scale); + void scale(float scale); // Master gain for this bus - used with sumWithGainFrom() below - void setGain(double gain) { m_busGain = gain; } - double gain() { return m_busGain; } + void setGain(float gain) { m_busGain = gain; } + float gain() const { return m_busGain; } void reset() { m_isFirstTime = true; } // for de-zippering @@ -121,8 +120,8 @@ public: // We scale by targetGain (and our own internal gain m_busGain), performing "de-zippering" to smoothly change from *lastMixGain to (targetGain*m_busGain). // The caller is responsible for setting up lastMixGain to point to storage which is unique for every "stream" which will be summed to this bus. // This represents the dezippering memory. - void copyWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain); - void sumWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain); + void copyWithGainFrom(const AudioBus &sourceBus, float* lastMixGain, float targetGain); + void sumWithGainFrom(const AudioBus &sourceBus, float* lastMixGain, float targetGain); // Copies the sourceBus by scaling with sample-accurate gain values. void copyWithSampleAccurateGainValuesFrom(const AudioBus &sourceBus, float* gainValues, unsigned numberOfGainValues); @@ -138,8 +137,8 @@ public: protected: AudioBus() { }; - void processWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus); - void processWithGainFromMonoStereo(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus); + void processWithGainFrom(const AudioBus &sourceBus, float* lastMixGain, float targetGain, bool sumToBus); + void processWithGainFromMonoStereo(const AudioBus &sourceBus, float* lastMixGain, float targetGain, bool sumToBus); size_t m_length; @@ -147,7 +146,7 @@ protected: int m_layout; - double m_busGain; + float m_busGain; bool m_isFirstTime; float m_sampleRate; // 0.0 if unknown or N/A }; diff --git a/Source/WebCore/platform/audio/AudioChannel.cpp b/Source/WebCore/platform/audio/AudioChannel.cpp index a962debd5..3c748e633 100644 --- a/Source/WebCore/platform/audio/AudioChannel.cpp +++ b/Source/WebCore/platform/audio/AudioChannel.cpp @@ -41,10 +41,9 @@ namespace WebCore { using namespace VectorMath; -void AudioChannel::scale(double scale) +void AudioChannel::scale(float scale) { - float s = static_cast<float>(scale); - vsmul(data(), 1, &s, data(), 1, length()); + vsmul(data(), 1, &scale, mutableData(), 1, length()); } void AudioChannel::copyFrom(const AudioChannel* sourceChannel) @@ -54,7 +53,7 @@ void AudioChannel::copyFrom(const AudioChannel* sourceChannel) if (!isSafe) return; - memcpy(data(), sourceChannel->data(), sizeof(float) * length()); + memcpy(mutableData(), sourceChannel->data(), sizeof(float) * length()); } void AudioChannel::copyFromRange(const AudioChannel* sourceChannel, unsigned startFrame, unsigned endFrame) @@ -73,7 +72,7 @@ void AudioChannel::copyFromRange(const AudioChannel* sourceChannel, unsigned sta return; const float* source = sourceChannel->data(); - float* destination = data(); + float* destination = mutableData(); memcpy(destination, source + startFrame, sizeof(float) * rangeLength); } @@ -84,17 +83,14 @@ void AudioChannel::sumFrom(const AudioChannel* sourceChannel) if (!isSafe) return; - vadd(data(), 1, sourceChannel->data(), 1, data(), 1, length()); + vadd(data(), 1, sourceChannel->data(), 1, mutableData(), 1, length()); } float AudioChannel::maxAbsValue() const { - const float* p = data(); - int n = length(); - float max = 0.0f; - while (n--) - max = std::max(max, fabsf(*p++)); + + vmaxmgv(data(), 1, &max, length()); return max; } diff --git a/Source/WebCore/platform/audio/AudioChannel.h b/Source/WebCore/platform/audio/AudioChannel.h index 7325e9f38..24de3f9e8 100644 --- a/Source/WebCore/platform/audio/AudioChannel.h +++ b/Source/WebCore/platform/audio/AudioChannel.h @@ -73,7 +73,7 @@ public: size_t length() const { return m_length; } // Direct access to PCM sample data - float* data() { return m_rawPointer ? m_rawPointer : m_memBuffer->data(); } + float* mutableData() { return m_rawPointer ? m_rawPointer : m_memBuffer->data(); } const float* data() const { return m_rawPointer ? m_rawPointer : m_memBuffer->data(); } // Zeroes out all sample values in buffer. @@ -86,7 +86,7 @@ public: } // Scales all samples by the same amount. - void scale(double scale); + void scale(float scale); // A simple memcpy() from the source channel void copyFrom(const AudioChannel* sourceChannel); diff --git a/Source/WebCore/platform/audio/AudioDSPKernelProcessor.cpp b/Source/WebCore/platform/audio/AudioDSPKernelProcessor.cpp index cf4d2d351..5f9139f03 100644 --- a/Source/WebCore/platform/audio/AudioDSPKernelProcessor.cpp +++ b/Source/WebCore/platform/audio/AudioDSPKernelProcessor.cpp @@ -71,7 +71,7 @@ void AudioDSPKernelProcessor::uninitialize() m_initialized = false; } -void AudioDSPKernelProcessor::process(AudioBus* source, AudioBus* destination, size_t framesToProcess) +void AudioDSPKernelProcessor::process(const AudioBus* source, AudioBus* destination, size_t framesToProcess) { ASSERT(source && destination); if (!source || !destination) @@ -88,7 +88,7 @@ void AudioDSPKernelProcessor::process(AudioBus* source, AudioBus* destination, s return; for (unsigned i = 0; i < m_kernels.size(); ++i) - m_kernels[i]->process(source->channel(i)->data(), destination->channel(i)->data(), framesToProcess); + m_kernels[i]->process(source->channel(i)->data(), destination->channel(i)->mutableData(), framesToProcess); } // Resets filter state diff --git a/Source/WebCore/platform/audio/AudioDSPKernelProcessor.h b/Source/WebCore/platform/audio/AudioDSPKernelProcessor.h index 40b5ab8d6..7f8f81d2f 100644 --- a/Source/WebCore/platform/audio/AudioDSPKernelProcessor.h +++ b/Source/WebCore/platform/audio/AudioDSPKernelProcessor.h @@ -59,7 +59,7 @@ public: // AudioProcessor methods virtual void initialize(); virtual void uninitialize(); - virtual void process(AudioBus* source, AudioBus* destination, size_t framesToProcess); + virtual void process(const AudioBus* source, AudioBus* destination, size_t framesToProcess); virtual void reset(); virtual void setNumberOfChannels(unsigned numberOfChannels); diff --git a/Source/WebCore/platform/audio/AudioProcessor.h b/Source/WebCore/platform/audio/AudioProcessor.h index 2d7b60a7c..469f83322 100644 --- a/Source/WebCore/platform/audio/AudioProcessor.h +++ b/Source/WebCore/platform/audio/AudioProcessor.h @@ -54,7 +54,7 @@ public: virtual void uninitialize() = 0; // Processes the source to destination bus. The number of channels must match in source and destination. - virtual void process(AudioBus* source, AudioBus* destination, size_t framesToProcess) = 0; + virtual void process(const AudioBus* source, AudioBus* destination, size_t framesToProcess) = 0; // Resets filter state virtual void reset() = 0; diff --git a/Source/WebCore/platform/audio/AudioResampler.cpp b/Source/WebCore/platform/audio/AudioResampler.cpp index ba5b58e64..1a9f81e7a 100644 --- a/Source/WebCore/platform/audio/AudioResampler.cpp +++ b/Source/WebCore/platform/audio/AudioResampler.cpp @@ -103,7 +103,7 @@ void AudioResampler::process(AudioSourceProvider* provider, AudioBus* destinatio // Now that we have the source data, resample each channel into the destination bus. // FIXME: optimize for the common stereo case where it's faster to process both left/right channels in the same inner loop. for (unsigned i = 0; i < numberOfChannels; ++i) { - float* destination = destinationBus->channel(i)->data(); + float* destination = destinationBus->channel(i)->mutableData(); m_kernels[i]->process(destination, framesToProcess); } } diff --git a/Source/WebCore/platform/audio/AudioUtilities.cpp b/Source/WebCore/platform/audio/AudioUtilities.cpp index 1a02b7e10..ff19cee69 100644 --- a/Source/WebCore/platform/audio/AudioUtilities.cpp +++ b/Source/WebCore/platform/audio/AudioUtilities.cpp @@ -55,7 +55,39 @@ float discreteTimeConstantForSampleRate(float timeConstant, float sampleRate) // FIXME: replace hardcode 2.718282 with M_E until the correct MathExtras.h solution is determined. return 1 - powf(1 / 2.718282f, 1 / (sampleRate * timeConstant)); } - + +#if OS(WINDOWS) && COMPILER(MSVC) && !_M_IX86_FP +// When compiling with MSVC with x87 FPU instructions using 80-bit +// floats, we want very precise control over the arithmetic so that +// rounding is done according to the IEEE 754 specification for +// single- and double-precision floats. We want each operation to be +// done with specified arithmetic precision and rounding consistent +// with gcc, not extended to 80 bits automatically. +// +// These pragmas are equivalent to /fp:strict flag, but we only need +// it for the function here. (Using fp:strict everywhere can have +// severe impact on floating point performance.) +#pragma float_control(push) +#pragma float_control(precise, on) +#pragma fenv_access(on) +#pragma float_control(except, on) +#endif + +size_t timeToSampleFrame(double time, double sampleRate) +{ + // DO NOT CONSOLIDATE THESE ASSIGNMENTS INTO ONE! When compiling + // with Visual Studio, these assignments force the rounding of + // each operation according to IEEE 754, instead of leaving + // intermediate results in 80-bit precision which is not + // consistent with IEEE 754 double-precision rounding. + double r = time * sampleRate; + r += 0.5; + return static_cast<size_t>(r); +} +#if OS(WINDOWS) && COMPILER(MSVC) && !_M_IX86_FP +// Restore normal floating-point semantics. +#pragma float_control(pop) +#endif } // AudioUtilites } // WebCore diff --git a/Source/WebCore/platform/audio/AudioUtilities.h b/Source/WebCore/platform/audio/AudioUtilities.h index c98a4c8de..ed2945fb6 100644 --- a/Source/WebCore/platform/audio/AudioUtilities.h +++ b/Source/WebCore/platform/audio/AudioUtilities.h @@ -37,7 +37,9 @@ float decibelsToLinear(float); // to reach the value 1 - 1/e (around 63.2%) given a step input response. // discreteTimeConstantForSampleRate() will return the discrete time-constant for the specific sampleRate. float discreteTimeConstantForSampleRate(float timeConstant, float sampleRate); - + +// Convert the time to a sample frame at the given sample rate. +size_t timeToSampleFrame(double time, double sampleRate); } // AudioUtilites } // WebCore diff --git a/Source/WebCore/platform/audio/DynamicsCompressor.cpp b/Source/WebCore/platform/audio/DynamicsCompressor.cpp index c4795f4f8..a55205705 100644 --- a/Source/WebCore/platform/audio/DynamicsCompressor.cpp +++ b/Source/WebCore/platform/audio/DynamicsCompressor.cpp @@ -115,10 +115,10 @@ void DynamicsCompressor::setEmphasisParameters(float gain, float anchorFreq, flo setEmphasisStageParameters(3, gain, anchorFreq / (filterStageRatio * filterStageRatio * filterStageRatio)); } -void DynamicsCompressor::process(AudioBus* sourceBus, AudioBus* destinationBus, unsigned framesToProcess) +void DynamicsCompressor::process(const AudioBus* sourceBus, AudioBus* destinationBus, unsigned framesToProcess) { - float* sourceL = sourceBus->channel(0)->data(); - float* sourceR; + const float* sourceL = sourceBus->channel(0)->data(); + const float* sourceR; if (sourceBus->numberOfChannels() > 1) sourceR = sourceBus->channel(1)->data(); @@ -127,8 +127,8 @@ void DynamicsCompressor::process(AudioBus* sourceBus, AudioBus* destinationBus, ASSERT(destinationBus->numberOfChannels() == 2); - float* destinationL = destinationBus->channel(0)->data(); - float* destinationR = destinationBus->channel(1)->data(); + float* destinationL = destinationBus->channel(0)->mutableData(); + float* destinationR = destinationBus->channel(1)->mutableData(); float filterStageGain = parameterValue(ParamFilterStageGain); float filterStageRatio = parameterValue(ParamFilterStageRatio); diff --git a/Source/WebCore/platform/audio/DynamicsCompressor.h b/Source/WebCore/platform/audio/DynamicsCompressor.h index 21529512d..e0115ee27 100644 --- a/Source/WebCore/platform/audio/DynamicsCompressor.h +++ b/Source/WebCore/platform/audio/DynamicsCompressor.h @@ -64,7 +64,7 @@ public: DynamicsCompressor(bool isStereo, float sampleRate); - void process(AudioBus* sourceBus, AudioBus* destinationBus, unsigned framesToProcess); + void process(const AudioBus* sourceBus, AudioBus* destinationBus, unsigned framesToProcess); void reset(); float parameterValue(unsigned parameterID); diff --git a/Source/WebCore/platform/audio/DynamicsCompressorKernel.cpp b/Source/WebCore/platform/audio/DynamicsCompressorKernel.cpp index e9f496a5b..a7a4c1212 100644 --- a/Source/WebCore/platform/audio/DynamicsCompressorKernel.cpp +++ b/Source/WebCore/platform/audio/DynamicsCompressorKernel.cpp @@ -82,9 +82,9 @@ void DynamicsCompressorKernel::setPreDelayTime(float preDelayTime) } } -void DynamicsCompressorKernel::process(float* sourceL, +void DynamicsCompressorKernel::process(const float* sourceL, float* destinationL, - float* sourceR, /* stereo-linked */ + const float* sourceR, /* stereo-linked */ float* destinationR, unsigned framesToProcess, diff --git a/Source/WebCore/platform/audio/DynamicsCompressorKernel.h b/Source/WebCore/platform/audio/DynamicsCompressorKernel.h index 8e5f7099d..cf319b378 100644 --- a/Source/WebCore/platform/audio/DynamicsCompressorKernel.h +++ b/Source/WebCore/platform/audio/DynamicsCompressorKernel.h @@ -38,9 +38,9 @@ public: DynamicsCompressorKernel(float sampleRate); // Performs stereo-linked compression. - void process(float *sourceL, + void process(const float *sourceL, float *destinationL, - float *sourceR, + const float *sourceR, float *destinationR, unsigned framesToProcess, diff --git a/Source/WebCore/platform/audio/EqualPowerPanner.cpp b/Source/WebCore/platform/audio/EqualPowerPanner.cpp index 13a19d6cd..a2d2dff4c 100644 --- a/Source/WebCore/platform/audio/EqualPowerPanner.cpp +++ b/Source/WebCore/platform/audio/EqualPowerPanner.cpp @@ -49,7 +49,7 @@ EqualPowerPanner::EqualPowerPanner(float sampleRate) m_smoothingConstant = AudioUtilities::discreteTimeConstantForSampleRate(SmoothingTimeConstant, sampleRate); } -void EqualPowerPanner::pan(double azimuth, double /*elevation*/, AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess) +void EqualPowerPanner::pan(double azimuth, double /*elevation*/, const AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess) { // FIXME: implement stereo sources bool isInputSafe = inputBus && inputBus->numberOfChannels() == 1 && framesToProcess <= inputBus->length(); @@ -62,10 +62,10 @@ void EqualPowerPanner::pan(double azimuth, double /*elevation*/, AudioBus* input if (!isOutputSafe) return; - AudioChannel* channel = inputBus->channel(0); - float* sourceP = channel->data(); - float* destinationL = outputBus->channelByType(AudioBus::ChannelLeft)->data(); - float* destinationR = outputBus->channelByType(AudioBus::ChannelRight)->data(); + const AudioChannel* channel = inputBus->channel(0); + const float* sourceP = channel->data(); + float* destinationL = outputBus->channelByType(AudioBus::ChannelLeft)->mutableData(); + float* destinationR = outputBus->channelByType(AudioBus::ChannelRight)->mutableData(); if (!sourceP || !destinationL || !destinationR) return; @@ -84,8 +84,8 @@ void EqualPowerPanner::pan(double azimuth, double /*elevation*/, AudioBus* input // Pan smoothly from left to right with azimuth going from -90 -> +90 degrees. double desiredPanPosition = (azimuth + 90) / 180; - double desiredGainL = 0.5 * cos(piDouble * desiredPanPosition) + 0.5; - double desiredGainR = sqrt(1.0 - desiredGainL*desiredGainL); + double desiredGainL = cos(0.5 * piDouble * desiredPanPosition); + double desiredGainR = sin(0.5 * piDouble * desiredPanPosition); // Don't de-zipper on first render call. if (m_isFirstRender) { diff --git a/Source/WebCore/platform/audio/EqualPowerPanner.h b/Source/WebCore/platform/audio/EqualPowerPanner.h index 4f6001df9..016cd4aa1 100644 --- a/Source/WebCore/platform/audio/EqualPowerPanner.h +++ b/Source/WebCore/platform/audio/EqualPowerPanner.h @@ -35,7 +35,7 @@ class EqualPowerPanner : public Panner { public: EqualPowerPanner(float sampleRate); - virtual void pan(double azimuth, double elevation, AudioBus* inputBus, AudioBus* outputBuf, size_t framesToProcess); + virtual void pan(double azimuth, double elevation, const AudioBus* inputBus, AudioBus* outputBuf, size_t framesToProcess); virtual void reset() { m_isFirstRender = true; } diff --git a/Source/WebCore/platform/audio/FFTConvolver.cpp b/Source/WebCore/platform/audio/FFTConvolver.cpp index 909343380..2321de0cf 100644 --- a/Source/WebCore/platform/audio/FFTConvolver.cpp +++ b/Source/WebCore/platform/audio/FFTConvolver.cpp @@ -47,7 +47,7 @@ FFTConvolver::FFTConvolver(size_t fftSize) { } -void FFTConvolver::process(FFTFrame* fftKernel, float* sourceP, float* destP, size_t framesToProcess) +void FFTConvolver::process(FFTFrame* fftKernel, const float* sourceP, float* destP, size_t framesToProcess) { // FIXME: make so framesToProcess is not required to fit evenly into fftSize/2 diff --git a/Source/WebCore/platform/audio/FFTConvolver.h b/Source/WebCore/platform/audio/FFTConvolver.h index c1b500276..375bf2c65 100644 --- a/Source/WebCore/platform/audio/FFTConvolver.h +++ b/Source/WebCore/platform/audio/FFTConvolver.h @@ -46,7 +46,7 @@ public: // The input to output latency is equal to fftSize / 2 // // Processing in-place is allowed... - void process(FFTFrame* fftKernel, float* sourceP, float* destP, size_t framesToProcess); + void process(FFTFrame* fftKernel, const float* sourceP, float* destP, size_t framesToProcess); void reset(); diff --git a/Source/WebCore/platform/audio/FFTFrame.cpp b/Source/WebCore/platform/audio/FFTFrame.cpp index fbb5dfe24..a1a0a50da 100644 --- a/Source/WebCore/platform/audio/FFTFrame.cpp +++ b/Source/WebCore/platform/audio/FFTFrame.cpp @@ -36,13 +36,14 @@ #include <stdio.h> #endif +#include "Logging.h" #include <wtf/Complex.h> #include <wtf/MathExtras.h> #include <wtf/OwnPtr.h> namespace WebCore { -void FFTFrame::doPaddedFFT(float* data, size_t dataSize) +void FFTFrame::doPaddedFFT(const float* data, size_t dataSize) { // Zero-pad the impulse response AudioFloatArray paddedResponse(fftSize()); // zero-initialized @@ -253,8 +254,8 @@ void FFTFrame::print() FFTFrame& frame = *this; float* realP = frame.realData(); float* imagP = frame.imagData(); - printf("**** \n"); - printf("DC = %f : nyquist = %f\n", realP[0], imagP[0]); + LOG(WebAudio, "**** \n"); + LOG(WebAudio, "DC = %f : nyquist = %f\n", realP[0], imagP[0]); int n = m_FFTSize / 2; @@ -262,9 +263,9 @@ void FFTFrame::print() double mag = sqrt(realP[i] * realP[i] + imagP[i] * imagP[i]); double phase = atan2(realP[i], imagP[i]); - printf("[%d] (%f %f)\n", i, mag, phase); + LOG(WebAudio, "[%d] (%f %f)\n", i, mag, phase); } - printf("****\n"); + LOG(WebAudio, "****\n"); } #endif // NDEBUG diff --git a/Source/WebCore/platform/audio/FFTFrame.h b/Source/WebCore/platform/audio/FFTFrame.h index b25d27956..db1d042ee 100644 --- a/Source/WebCore/platform/audio/FFTFrame.h +++ b/Source/WebCore/platform/audio/FFTFrame.h @@ -47,6 +47,13 @@ #include "mkl_dfti.h" #endif // USE(WEBAUDIO_MKL) +#if USE(WEBAUDIO_GSTREAMER) +#include <glib.h> +G_BEGIN_DECLS +#include <gst/fft/gstfftf32.h> +G_END_DECLS +#endif // USE(WEBAUDIO_GSTREAMER) + #if USE(WEBAUDIO_FFMPEG) struct RDFTContext; #endif // USE(WEBAUDIO_FFMPEG) @@ -73,7 +80,7 @@ public: static void initialize(); static void cleanup(); - void doFFT(float* data); + void doFFT(const float* data); void doInverseFFT(float* data); void multiply(const FFTFrame& frame); // multiplies ourself with frame : effectively operator*=() @@ -88,7 +95,7 @@ public: // Interpolates from frame1 -> frame2 as x goes from 0.0 -> 1.0 static PassOwnPtr<FFTFrame> createInterpolatedFrame(const FFTFrame& frame1, const FFTFrame& frame2, double x); - void doPaddedFFT(float* data, size_t dataSize); // zero-padding with dataSize <= fftSize + void doPaddedFFT(const float* data, size_t dataSize); // zero-padding with dataSize <= fftSize double extractAverageGroupDelay(); void addConstantGroupDelay(double sampleFrameDelay); @@ -146,6 +153,14 @@ private: AudioFloatArray m_imagData; #endif // USE(WEBAUDIO_FFMPEG) +#if USE(WEBAUDIO_GSTREAMER) + GstFFTF32* m_fft; + GstFFTF32* m_inverseFft; + GstFFTF32Complex* m_complexData; + AudioFloatArray m_realData; + AudioFloatArray m_imagData; +#endif // USE(WEBAUDIO_GSTREAMER) + #endif // !USE_ACCELERATE_FFT }; diff --git a/Source/WebCore/platform/audio/FFTFrameStub.cpp b/Source/WebCore/platform/audio/FFTFrameStub.cpp index dfc52a2ad..aa26ec605 100644 --- a/Source/WebCore/platform/audio/FFTFrameStub.cpp +++ b/Source/WebCore/platform/audio/FFTFrameStub.cpp @@ -29,7 +29,7 @@ #if ENABLE(WEB_AUDIO) -#if !OS(DARWIN) && !USE(WEBAUDIO_MKL) && !USE(WEBAUDIO_FFMPEG) +#if !OS(DARWIN) && !USE(WEBAUDIO_MKL) && !USE(WEBAUDIO_FFMPEG) && !USE(WEBAUDIO_GSTREAMER) #include "FFTFrame.h" @@ -102,6 +102,6 @@ float* FFTFrame::imagData() const } // namespace WebCore -#endif // !OS(DARWIN) && !USE(WEBAUDIO_MKL) +#endif // !OS(DARWIN) && !USE(WEBAUDIO_MKL) && !USE(WEBAUDIO_GSTREAMER) #endif // ENABLE(WEB_AUDIO) diff --git a/Source/WebCore/platform/audio/HRTFElevation.cpp b/Source/WebCore/platform/audio/HRTFElevation.cpp index e7de83a05..eb07d4ec9 100644 --- a/Source/WebCore/platform/audio/HRTFElevation.cpp +++ b/Source/WebCore/platform/audio/HRTFElevation.cpp @@ -60,7 +60,7 @@ const size_t ResponseFrameSize = 256; // The impulse responses may be resampled to a different sample-rate (depending on the audio hardware) when they are loaded. const float ResponseSampleRate = 44100; -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(MAC) #define USE_CONCATENATED_IMPULSE_RESPONSES #endif diff --git a/Source/WebCore/platform/audio/HRTFElevation.h b/Source/WebCore/platform/audio/HRTFElevation.h index ccff097f8..446e66d0e 100644 --- a/Source/WebCore/platform/audio/HRTFElevation.h +++ b/Source/WebCore/platform/audio/HRTFElevation.h @@ -60,7 +60,7 @@ public: HRTFKernelList* kernelListR() { return m_kernelListR.get(); } double elevationAngle() const { return m_elevationAngle; } - unsigned numberOfAzimuths() { return NumberOfTotalAzimuths; } + unsigned numberOfAzimuths() const { return NumberOfTotalAzimuths; } float sampleRate() const { return m_sampleRate; } // Returns the left and right kernels for the given azimuth index. diff --git a/Source/WebCore/platform/audio/HRTFKernel.cpp b/Source/WebCore/platform/audio/HRTFKernel.cpp index c44de932d..391f90402 100644 --- a/Source/WebCore/platform/audio/HRTFKernel.cpp +++ b/Source/WebCore/platform/audio/HRTFKernel.cpp @@ -50,7 +50,7 @@ static float extractAverageGroupDelay(AudioChannel* channel, size_t analysisFFTS { ASSERT(channel); - float* impulseP = channel->data(); + float* impulseP = channel->mutableData(); bool isSizeGood = channel->length() >= analysisFFTSize; ASSERT(isSizeGood); @@ -78,7 +78,7 @@ HRTFKernel::HRTFKernel(AudioChannel* channel, size_t fftSize, float sampleRate, // Determine the leading delay (average group delay) for the response. m_frameDelay = extractAverageGroupDelay(channel, fftSize / 2); - float* impulseResponse = channel->data(); + float* impulseResponse = channel->mutableData(); size_t responseLength = channel->length(); if (bassBoost) { @@ -114,7 +114,7 @@ PassOwnPtr<AudioChannel> HRTFKernel::createImpulseResponse() // Add leading delay back in. fftFrame.addConstantGroupDelay(m_frameDelay); - fftFrame.doInverseFFT(channel->data()); + fftFrame.doInverseFFT(channel->mutableData()); return channel.release(); } diff --git a/Source/WebCore/platform/audio/HRTFPanner.cpp b/Source/WebCore/platform/audio/HRTFPanner.cpp index 978371cef..4c69932ed 100644 --- a/Source/WebCore/platform/audio/HRTFPanner.cpp +++ b/Source/WebCore/platform/audio/HRTFPanner.cpp @@ -37,23 +37,37 @@ #include <wtf/RefPtr.h> using namespace std; - + namespace WebCore { // The value of 2 milliseconds is larger than the largest delay which exists in any HRTFKernel from the default HRTFDatabase (0.0136 seconds). // We ASSERT the delay values used in process() with this value. const double MaxDelayTimeSeconds = 0.002; +const int UninitializedAzimuth = -1; +const unsigned RenderingQuantum = 128; + HRTFPanner::HRTFPanner(float sampleRate) : Panner(PanningModelHRTF) , m_sampleRate(sampleRate) - , m_isFirstRender(true) - , m_azimuthIndex(0) - , m_convolverL(fftSizeForSampleRate(sampleRate)) - , m_convolverR(fftSizeForSampleRate(sampleRate)) + , m_crossfadeSelection(CrossfadeSelection1) + , m_azimuthIndex1(UninitializedAzimuth) + , m_elevation1(0) + , m_azimuthIndex2(UninitializedAzimuth) + , m_elevation2(0) + , m_crossfadeX(0) + , m_crossfadeIncr(0) + , m_convolverL1(fftSizeForSampleRate(sampleRate)) + , m_convolverR1(fftSizeForSampleRate(sampleRate)) + , m_convolverL2(fftSizeForSampleRate(sampleRate)) + , m_convolverR2(fftSizeForSampleRate(sampleRate)) , m_delayLineL(MaxDelayTimeSeconds, sampleRate) , m_delayLineR(MaxDelayTimeSeconds, sampleRate) -{ + , m_tempL1(RenderingQuantum) + , m_tempR1(RenderingQuantum) + , m_tempL2(RenderingQuantum) + , m_tempR2(RenderingQuantum) +{ } HRTFPanner::~HRTFPanner() @@ -71,31 +85,24 @@ size_t HRTFPanner::fftSizeForSampleRate(float sampleRate) void HRTFPanner::reset() { - m_isFirstRender = true; - m_convolverL.reset(); - m_convolverR.reset(); + m_convolverL1.reset(); + m_convolverR1.reset(); + m_convolverL2.reset(); + m_convolverR2.reset(); m_delayLineL.reset(); m_delayLineR.reset(); } -static bool wrapDistance(int i, int j, int length) -{ - int directDistance = abs(i - j); - int indirectDistance = length - directDistance; - - return indirectDistance < directDistance; -} - int HRTFPanner::calculateDesiredAzimuthIndexAndBlend(double azimuth, double& azimuthBlend) { // Convert the azimuth angle from the range -180 -> +180 into the range 0 -> 360. // The azimuth index may then be calculated from this positive value. if (azimuth < 0) azimuth += 360.0; - - HRTFDatabase* database = HRTFDatabaseLoader::defaultHRTFDatabase(); + + HRTFDatabase* database = HRTFDatabaseLoader::defaultHRTFDatabase(); ASSERT(database); - + int numberOfAzimuths = database->numberOfAzimuths(); const double angleBetweenAzimuths = 360.0 / numberOfAzimuths; @@ -103,7 +110,7 @@ int HRTFPanner::calculateDesiredAzimuthIndexAndBlend(double azimuth, double& azi double desiredAzimuthIndexFloat = azimuth / angleBetweenAzimuths; int desiredAzimuthIndex = static_cast<int>(desiredAzimuthIndexFloat); azimuthBlend = desiredAzimuthIndexFloat - static_cast<double>(desiredAzimuthIndex); - + // We don't immediately start using this azimuth index, but instead approach this index from the last index we rendered at. // This minimizes the clicks and graininess for moving sources which occur otherwise. desiredAzimuthIndex = max(0, desiredAzimuthIndex); @@ -111,7 +118,7 @@ int HRTFPanner::calculateDesiredAzimuthIndexAndBlend(double azimuth, double& azi return desiredAzimuthIndex; } -void HRTFPanner::pan(double desiredAzimuth, double elevation, AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess) +void HRTFPanner::pan(double desiredAzimuth, double elevation, const AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess) { unsigned numInputChannels = inputBus ? inputBus->numberOfChannels() : 0; @@ -128,7 +135,7 @@ void HRTFPanner::pan(double desiredAzimuth, double elevation, AudioBus* inputBus } // This code only runs as long as the context is alive and after database has been loaded. - HRTFDatabase* database = HRTFDatabaseLoader::defaultHRTFDatabase(); + HRTFDatabase* database = HRTFDatabaseLoader::defaultHRTFDatabase(); ASSERT(database); if (!database) { outputBus->zero(); @@ -147,68 +154,89 @@ void HRTFPanner::pan(double desiredAzimuth, double elevation, AudioBus* inputBus // Normally, we'll just be dealing with mono sources. // If we have a stereo input, implement stereo panning with left source processed by left HRTF, and right source by right HRTF. - AudioChannel* inputChannelL = inputBus->channelByType(AudioBus::ChannelLeft); - AudioChannel* inputChannelR = numInputChannels > 1 ? inputBus->channelByType(AudioBus::ChannelRight) : 0; + const AudioChannel* inputChannelL = inputBus->channelByType(AudioBus::ChannelLeft); + const AudioChannel* inputChannelR = numInputChannels > 1 ? inputBus->channelByType(AudioBus::ChannelRight) : 0; // Get source and destination pointers. - float* sourceL = inputChannelL->data(); - float* sourceR = numInputChannels > 1 ? inputChannelR->data() : sourceL; - float* destinationL = outputBus->channelByType(AudioBus::ChannelLeft)->data(); - float* destinationR = outputBus->channelByType(AudioBus::ChannelRight)->data(); + const float* sourceL = inputChannelL->data(); + const float* sourceR = numInputChannels > 1 ? inputChannelR->data() : sourceL; + float* destinationL = outputBus->channelByType(AudioBus::ChannelLeft)->mutableData(); + float* destinationR = outputBus->channelByType(AudioBus::ChannelRight)->mutableData(); double azimuthBlend; int desiredAzimuthIndex = calculateDesiredAzimuthIndexAndBlend(azimuth, azimuthBlend); - // This algorithm currently requires that we process in power-of-two size chunks at least 128. + // Initially snap azimuth and elevation values to first values encountered. + if (m_azimuthIndex1 == UninitializedAzimuth) { + m_azimuthIndex1 = desiredAzimuthIndex; + m_elevation1 = elevation; + } + if (m_azimuthIndex2 == UninitializedAzimuth) { + m_azimuthIndex2 = desiredAzimuthIndex; + m_elevation2 = elevation; + } + + // Cross-fade / transition over a period of around 45 milliseconds. + // This is an empirical value tuned to be a reasonable trade-off between + // smoothness and speed. + const double fadeFrames = sampleRate() <= 48000 ? 2048 : 4096; + + // Check for azimuth and elevation changes, initiating a cross-fade if needed. + if (!m_crossfadeX && m_crossfadeSelection == CrossfadeSelection1) { + if (desiredAzimuthIndex != m_azimuthIndex1 || elevation != m_elevation1) { + // Cross-fade from 1 -> 2 + m_crossfadeIncr = 1 / fadeFrames; + m_azimuthIndex2 = desiredAzimuthIndex; + m_elevation2 = elevation; + } + } + if (m_crossfadeX == 1 && m_crossfadeSelection == CrossfadeSelection2) { + if (desiredAzimuthIndex != m_azimuthIndex2 || elevation != m_elevation2) { + // Cross-fade from 2 -> 1 + m_crossfadeIncr = -1 / fadeFrames; + m_azimuthIndex1 = desiredAzimuthIndex; + m_elevation1 = elevation; + } + } + + // This algorithm currently requires that we process in power-of-two size chunks at least RenderingQuantum. ASSERT(1UL << static_cast<int>(log2(framesToProcess)) == framesToProcess); - ASSERT(framesToProcess >= 128); - - const unsigned framesPerSegment = 128; + ASSERT(framesToProcess >= RenderingQuantum); + + const unsigned framesPerSegment = RenderingQuantum; const unsigned numberOfSegments = framesToProcess / framesPerSegment; for (unsigned segment = 0; segment < numberOfSegments; ++segment) { - if (m_isFirstRender) { - // Snap exactly to desired position (first time and after reset()). - m_azimuthIndex = desiredAzimuthIndex; - m_isFirstRender = false; - } else { - // Each segment renders with an azimuth index closer by one to the desired azimuth index. - // Because inter-aural time delay is mostly a factor of azimuth and the delay is where the clicks and graininess come from, - // we don't bother smoothing the elevations. - int numberOfAzimuths = database->numberOfAzimuths(); - bool wrap = wrapDistance(m_azimuthIndex, desiredAzimuthIndex, numberOfAzimuths); - if (wrap) { - if (m_azimuthIndex < desiredAzimuthIndex) - m_azimuthIndex = (m_azimuthIndex - 1 + numberOfAzimuths) % numberOfAzimuths; - else if (m_azimuthIndex > desiredAzimuthIndex) - m_azimuthIndex = (m_azimuthIndex + 1) % numberOfAzimuths; - } else { - if (m_azimuthIndex < desiredAzimuthIndex) - m_azimuthIndex = (m_azimuthIndex + 1) % numberOfAzimuths; - else if (m_azimuthIndex > desiredAzimuthIndex) - m_azimuthIndex = (m_azimuthIndex - 1 + numberOfAzimuths) % numberOfAzimuths; - } - } - - // Get the HRTFKernels and interpolated delays. - HRTFKernel* kernelL; - HRTFKernel* kernelR; - double frameDelayL; - double frameDelayR; - database->getKernelsFromAzimuthElevation(azimuthBlend, m_azimuthIndex, elevation, kernelL, kernelR, frameDelayL, frameDelayR); - - ASSERT(kernelL && kernelR); - if (!kernelL || !kernelR) { + // Get the HRTFKernels and interpolated delays. + HRTFKernel* kernelL1; + HRTFKernel* kernelR1; + HRTFKernel* kernelL2; + HRTFKernel* kernelR2; + double frameDelayL1; + double frameDelayR1; + double frameDelayL2; + double frameDelayR2; + database->getKernelsFromAzimuthElevation(azimuthBlend, m_azimuthIndex1, m_elevation1, kernelL1, kernelR1, frameDelayL1, frameDelayR1); + database->getKernelsFromAzimuthElevation(azimuthBlend, m_azimuthIndex2, m_elevation2, kernelL2, kernelR2, frameDelayL2, frameDelayR2); + + bool areKernelsGood = kernelL1 && kernelR1 && kernelL2 && kernelR2; + ASSERT(areKernelsGood); + if (!areKernelsGood) { outputBus->zero(); return; } - - ASSERT(frameDelayL / sampleRate() < MaxDelayTimeSeconds && frameDelayR / sampleRate() < MaxDelayTimeSeconds); - + + ASSERT(frameDelayL1 / sampleRate() < MaxDelayTimeSeconds && frameDelayR1 / sampleRate() < MaxDelayTimeSeconds); + ASSERT(frameDelayL2 / sampleRate() < MaxDelayTimeSeconds && frameDelayR2 / sampleRate() < MaxDelayTimeSeconds); + + // Crossfade inter-aural delays based on transitions. + double frameDelayL = (1 - m_crossfadeX) * frameDelayL1 + m_crossfadeX * frameDelayL2; + double frameDelayR = (1 - m_crossfadeX) * frameDelayR1 + m_crossfadeX * frameDelayR2; + // Calculate the source and destination pointers for the current segment. unsigned offset = segment * framesPerSegment; - float* segmentSourceL = sourceL + offset; - float* segmentSourceR = sourceR + offset; + const float* segmentSourceL = sourceL + offset; + const float* segmentSourceR = sourceR + offset; float* segmentDestinationL = destinationL + offset; float* segmentDestinationR = destinationR + offset; @@ -218,9 +246,51 @@ void HRTFPanner::pan(double desiredAzimuth, double elevation, AudioBus* inputBus m_delayLineL.process(segmentSourceL, segmentDestinationL, framesPerSegment); m_delayLineR.process(segmentSourceR, segmentDestinationR, framesPerSegment); - // Now do the convolutions in-place. - m_convolverL.process(kernelL->fftFrame(), segmentDestinationL, segmentDestinationL, framesPerSegment); - m_convolverR.process(kernelR->fftFrame(), segmentDestinationR, segmentDestinationR, framesPerSegment); + bool needsCrossfading = m_crossfadeIncr; + + // Have the convolvers render directly to the final destination if we're not cross-fading. + float* convolutionDestinationL1 = needsCrossfading ? m_tempL1.data() : segmentDestinationL; + float* convolutionDestinationR1 = needsCrossfading ? m_tempR1.data() : segmentDestinationR; + float* convolutionDestinationL2 = needsCrossfading ? m_tempL2.data() : segmentDestinationL; + float* convolutionDestinationR2 = needsCrossfading ? m_tempR2.data() : segmentDestinationR; + + // Now do the convolutions. + // Note that we avoid doing convolutions on both sets of convolvers if we're not currently cross-fading. + + if (m_crossfadeSelection == CrossfadeSelection1 || needsCrossfading) { + m_convolverL1.process(kernelL1->fftFrame(), segmentDestinationL, convolutionDestinationL1, framesPerSegment); + m_convolverR1.process(kernelR1->fftFrame(), segmentDestinationR, convolutionDestinationR1, framesPerSegment); + } + + if (m_crossfadeSelection == CrossfadeSelection2 || needsCrossfading) { + m_convolverL2.process(kernelL2->fftFrame(), segmentDestinationL, convolutionDestinationL2, framesPerSegment); + m_convolverR2.process(kernelR2->fftFrame(), segmentDestinationR, convolutionDestinationR2, framesPerSegment); + } + + if (needsCrossfading) { + // Apply linear cross-fade. + float x = m_crossfadeX; + float incr = m_crossfadeIncr; + for (unsigned i = 0; i < framesPerSegment; ++i) { + segmentDestinationL[i] = (1 - x) * convolutionDestinationL1[i] + x * convolutionDestinationL2[i]; + segmentDestinationR[i] = (1 - x) * convolutionDestinationR1[i] + x * convolutionDestinationR2[i]; + x += incr; + } + // Update cross-fade value from local. + m_crossfadeX = x; + + if (m_crossfadeIncr > 0 && fabs(m_crossfadeX - 1) < m_crossfadeIncr) { + // We've fully made the crossfade transition from 1 -> 2. + m_crossfadeSelection = CrossfadeSelection2; + m_crossfadeX = 1; + m_crossfadeIncr = 0; + } else if (m_crossfadeIncr < 0 && fabs(m_crossfadeX) < -m_crossfadeIncr) { + // We've fully made the crossfade transition from 2 -> 1. + m_crossfadeSelection = CrossfadeSelection1; + m_crossfadeX = 0; + m_crossfadeIncr = 0; + } + } } } diff --git a/Source/WebCore/platform/audio/HRTFPanner.h b/Source/WebCore/platform/audio/HRTFPanner.h index e771ba28b..f5af1d152 100644 --- a/Source/WebCore/platform/audio/HRTFPanner.h +++ b/Source/WebCore/platform/audio/HRTFPanner.h @@ -37,30 +37,65 @@ public: virtual ~HRTFPanner(); // Panner - virtual void pan(double azimuth, double elevation, AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess); + virtual void pan(double azimuth, double elevation, const AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess); virtual void reset(); size_t fftSize() { return fftSizeForSampleRate(m_sampleRate); } static size_t fftSizeForSampleRate(float sampleRate); float sampleRate() const { return m_sampleRate; } - + private: // Given an azimuth angle in the range -180 -> +180, returns the corresponding azimuth index for the database, // and azimuthBlend which is an interpolation value from 0 -> 1. int calculateDesiredAzimuthIndexAndBlend(double azimuth, double& azimuthBlend); float m_sampleRate; - - // m_isFirstRender and m_azimuthIndex are used to avoid harshly changing from rendering at one azimuth angle to another angle very far away. - // Changing the azimuth gradually produces a smoother sound. - bool m_isFirstRender; - int m_azimuthIndex; - - FFTConvolver m_convolverL; - FFTConvolver m_convolverR; + + // We maintain two sets of convolvers for smooth cross-faded interpolations when + // then azimuth and elevation are dynamically changing. + // When the azimuth and elevation are not changing, we simply process with one of the two sets. + // Initially we use CrossfadeSelection1 corresponding to m_convolverL1 and m_convolverR1. + // Whenever the azimuth or elevation changes, a crossfade is initiated to transition + // to the new position. So if we're currently processing with CrossfadeSelection1, then + // we transition to CrossfadeSelection2 (and vice versa). + // If we're in the middle of a transition, then we wait until it is complete before + // initiating a new transition. + + // Selects either the convolver set (m_convolverL1, m_convolverR1) or (m_convolverL2, m_convolverR2). + enum CrossfadeSelection { + CrossfadeSelection1, + CrossfadeSelection2 + }; + + CrossfadeSelection m_crossfadeSelection; + + // azimuth/elevation for CrossfadeSelection1. + int m_azimuthIndex1; + double m_elevation1; + + // azimuth/elevation for CrossfadeSelection2. + int m_azimuthIndex2; + double m_elevation2; + + // A crossfade value 0 <= m_crossfadeX <= 1. + float m_crossfadeX; + + // Per-sample-frame crossfade value increment. + float m_crossfadeIncr; + + FFTConvolver m_convolverL1; + FFTConvolver m_convolverR1; + FFTConvolver m_convolverL2; + FFTConvolver m_convolverR2; + DelayDSPKernel m_delayLineL; DelayDSPKernel m_delayLineR; + + AudioFloatArray m_tempL1; + AudioFloatArray m_tempR1; + AudioFloatArray m_tempL2; + AudioFloatArray m_tempR2; }; } // namespace WebCore diff --git a/Source/WebCore/platform/audio/MultiChannelResampler.cpp b/Source/WebCore/platform/audio/MultiChannelResampler.cpp index db51e90ed..f6c07e7c1 100644 --- a/Source/WebCore/platform/audio/MultiChannelResampler.cpp +++ b/Source/WebCore/platform/audio/MultiChannelResampler.cpp @@ -77,7 +77,7 @@ public: // Copy the channel data from what we received from m_multiChannelProvider. ASSERT(m_currentChannel <= m_numberOfChannels); if (m_currentChannel < m_numberOfChannels) { - memcpy(bus->channel(0)->data(), m_multiChannelBus->channel(m_currentChannel)->data(), sizeof(float) * framesToProcess); + memcpy(bus->channel(0)->mutableData(), m_multiChannelBus->channel(m_currentChannel)->data(), sizeof(float) * framesToProcess); ++m_currentChannel; } } @@ -113,7 +113,7 @@ void MultiChannelResampler::process(AudioSourceProvider* provider, AudioBus* des // However, if it calls provideInput() for the first channel, then it will call it for the remaining // channels, since they all buffer in the same way and are processing the same number of frames. m_kernels[channelIndex]->process(&channelProvider, - destination->channel(channelIndex)->data(), + destination->channel(channelIndex)->mutableData(), framesToProcess); } } diff --git a/Source/WebCore/platform/audio/Panner.h b/Source/WebCore/platform/audio/Panner.h index 4b728327d..d8b8dd0f1 100644 --- a/Source/WebCore/platform/audio/Panner.h +++ b/Source/WebCore/platform/audio/Panner.h @@ -53,7 +53,7 @@ public: PanningModel panningModel() const { return m_panningModel; } - virtual void pan(double azimuth, double elevation, AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess) = 0; + virtual void pan(double azimuth, double elevation, const AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess) = 0; virtual void reset() = 0; diff --git a/Source/WebCore/platform/audio/Reverb.cpp b/Source/WebCore/platform/audio/Reverb.cpp index 2b787ebf3..122e21b68 100644 --- a/Source/WebCore/platform/audio/Reverb.cpp +++ b/Source/WebCore/platform/audio/Reverb.cpp @@ -35,6 +35,7 @@ #include "AudioBus.h" #include "AudioFileReader.h" #include "ReverbConvolver.h" +#include "VectorMath.h" #include <math.h> #include <wtf/MathExtras.h> #include <wtf/OwnPtr.h> @@ -46,28 +47,26 @@ using namespace std; namespace WebCore { +using namespace VectorMath; + // Empirical gain calibration tested across many impulse responses to ensure perceived volume is same as dry (unprocessed) signal -const double GainCalibration = -58.0; +const float GainCalibration = -58; // A minimum power value to when normalizing a silent (or very quiet) impulse response -const double MinPower = 0.000125; +const float MinPower = 0.000125f; -static double calculateNormalizationScale(AudioBus* response) +static float calculateNormalizationScale(AudioBus* response) { // Normalize by RMS power size_t numberOfChannels = response->numberOfChannels(); size_t length = response->length(); - double power = 0.0; + float power = 0; for (size_t i = 0; i < numberOfChannels; ++i) { - int n = length; - float* p = response->channel(i)->data(); - - while (n--) { - float sample = *p++; - power += sample * sample; - } + float channelPower = 0; + vsvesq(response->channel(i)->data(), 1, &channelPower, length); + power += channelPower; } power = sqrt(power / (numberOfChannels * length)); @@ -76,20 +75,20 @@ static double calculateNormalizationScale(AudioBus* response) if (isinf(power) || isnan(power) || power < MinPower) power = MinPower; - double scale = 1.0 / power; + float scale = 1 / power; - scale *= pow(10.0, GainCalibration * 0.05); // calibrate to make perceived volume same as unprocessed + scale *= powf(10, GainCalibration * 0.05f); // calibrate to make perceived volume same as unprocessed // True-stereo compensation if (response->numberOfChannels() == 4) - scale *= 0.5; + scale *= 0.5f; return scale; } Reverb::Reverb(AudioBus* impulseResponse, size_t renderSliceSize, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads, bool normalize) { - double scale = 1; + float scale = 1; if (normalize) { scale = calculateNormalizationScale(impulseResponse); @@ -104,7 +103,7 @@ Reverb::Reverb(AudioBus* impulseResponse, size_t renderSliceSize, size_t maxFFTS // FIXME: What about roundoff? Perhaps consider making a temporary scaled copy // instead of scaling and unscaling in place. if (normalize && scale) - impulseResponse->scale(1.0 / scale); + impulseResponse->scale(1 / scale); } void Reverb::initialize(AudioBus* impulseResponseBuffer, size_t renderSliceSize, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads) @@ -131,7 +130,7 @@ void Reverb::initialize(AudioBus* impulseResponseBuffer, size_t renderSliceSize, m_tempBuffer = adoptPtr(new AudioBus(2, MaxFrameSize)); } -void Reverb::process(AudioBus* sourceBus, AudioBus* destinationBus, size_t framesToProcess) +void Reverb::process(const AudioBus* sourceBus, AudioBus* destinationBus, size_t framesToProcess) { // Do a fairly comprehensive sanity check. // If these conditions are satisfied, all of the source and destination pointers will be valid for the various matrixing cases. @@ -149,7 +148,7 @@ void Reverb::process(AudioBus* sourceBus, AudioBus* destinationBus, size_t frame } AudioChannel* destinationChannelL = destinationBus->channel(0); - AudioChannel* sourceChannelL = sourceBus->channel(0); + const AudioChannel* sourceChannelL = sourceBus->channel(0); // Handle input -> output matrixing... size_t numInputChannels = sourceBus->numberOfChannels(); @@ -158,7 +157,7 @@ void Reverb::process(AudioBus* sourceBus, AudioBus* destinationBus, size_t frame if (numInputChannels == 2 && numReverbChannels == 2 && numOutputChannels == 2) { // 2 -> 2 -> 2 - AudioChannel* sourceChannelR = sourceBus->channel(1); + const AudioChannel* sourceChannelR = sourceBus->channel(1); AudioChannel* destinationChannelR = destinationBus->channel(1); m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess); m_convolvers[1]->process(sourceChannelR, destinationChannelR, framesToProcess); @@ -178,13 +177,13 @@ void Reverb::process(AudioBus* sourceBus, AudioBus* destinationBus, size_t frame ASSERT(isCopySafe); if (!isCopySafe) return; - memcpy(destinationChannelR->data(), destinationChannelL->data(), sizeof(float) * framesToProcess); + memcpy(destinationChannelR->mutableData(), destinationChannelL->data(), sizeof(float) * framesToProcess); } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 1) { // 1 -> 1 -> 1 m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess); } else if (numInputChannels == 2 && numReverbChannels == 4 && numOutputChannels == 2) { // 2 -> 4 -> 2 ("True" stereo) - AudioChannel* sourceChannelR = sourceBus->channel(1); + const AudioChannel* sourceChannelR = sourceBus->channel(1); AudioChannel* destinationChannelR = destinationBus->channel(1); AudioChannel* tempChannelL = m_tempBuffer->channel(0); diff --git a/Source/WebCore/platform/audio/Reverb.h b/Source/WebCore/platform/audio/Reverb.h index f162e0b70..779e7bba4 100644 --- a/Source/WebCore/platform/audio/Reverb.h +++ b/Source/WebCore/platform/audio/Reverb.h @@ -45,7 +45,7 @@ public: // renderSliceSize is a rendering hint, so the FFTs can be optimized to not all occur at the same time (very bad when rendering on a real-time thread). Reverb(AudioBus* impulseResponseBuffer, size_t renderSliceSize, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads, bool normalize); - void process(AudioBus* sourceBus, AudioBus* destinationBus, size_t framesToProcess); + void process(const AudioBus* sourceBus, AudioBus* destinationBus, size_t framesToProcess); void reset(); unsigned impulseResponseLength() const { return m_impulseResponseLength; } diff --git a/Source/WebCore/platform/audio/ReverbConvolver.cpp b/Source/WebCore/platform/audio/ReverbConvolver.cpp index bbb55087f..c611414cb 100644 --- a/Source/WebCore/platform/audio/ReverbConvolver.cpp +++ b/Source/WebCore/platform/audio/ReverbConvolver.cpp @@ -82,7 +82,7 @@ ReverbConvolver::ReverbConvolver(AudioChannel* impulseResponse, size_t renderSli // Otherwise, assume we're being run from a command-line tool. bool hasRealtimeConstraint = useBackgroundThreads; - float* response = impulseResponse->data(); + const float* response = impulseResponse->data(); size_t totalResponseLength = impulseResponse->length(); // Because we're not using direct-convolution in the leading portion, the reverb has an overall latency of half the first-stage FFT size @@ -175,15 +175,15 @@ void ReverbConvolver::backgroundThreadEntry() } } -void ReverbConvolver::process(AudioChannel* sourceChannel, AudioChannel* destinationChannel, size_t framesToProcess) +void ReverbConvolver::process(const AudioChannel* sourceChannel, AudioChannel* destinationChannel, size_t framesToProcess) { bool isSafe = sourceChannel && destinationChannel && sourceChannel->length() >= framesToProcess && destinationChannel->length() >= framesToProcess; ASSERT(isSafe); if (!isSafe) return; - float* source = sourceChannel->data(); - float* destination = destinationChannel->data(); + const float* source = sourceChannel->data(); + float* destination = destinationChannel->mutableData(); bool isDataSafe = source && destination; ASSERT(isDataSafe); if (!isDataSafe) diff --git a/Source/WebCore/platform/audio/ReverbConvolver.h b/Source/WebCore/platform/audio/ReverbConvolver.h index 013b68497..370b87206 100644 --- a/Source/WebCore/platform/audio/ReverbConvolver.h +++ b/Source/WebCore/platform/audio/ReverbConvolver.h @@ -52,7 +52,7 @@ public: ReverbConvolver(AudioChannel* impulseResponse, size_t renderSliceSize, size_t maxFFTSize, size_t convolverRenderPhase, bool useBackgroundThreads); ~ReverbConvolver(); - void process(AudioChannel* sourceChannel, AudioChannel* destinationChannel, size_t framesToProcess); + void process(const AudioChannel* sourceChannel, AudioChannel* destinationChannel, size_t framesToProcess); void reset(); size_t impulseResponseLength() const { return m_impulseResponseLength; } diff --git a/Source/WebCore/platform/audio/ReverbConvolverStage.cpp b/Source/WebCore/platform/audio/ReverbConvolverStage.cpp index f207d19de..53bb65008 100644 --- a/Source/WebCore/platform/audio/ReverbConvolverStage.cpp +++ b/Source/WebCore/platform/audio/ReverbConvolverStage.cpp @@ -43,7 +43,7 @@ namespace WebCore { using namespace VectorMath; -ReverbConvolverStage::ReverbConvolverStage(float* impulseResponse, size_t responseLength, size_t reverbTotalLatency, size_t stageOffset, size_t stageLength, +ReverbConvolverStage::ReverbConvolverStage(const float* impulseResponse, size_t responseLength, size_t reverbTotalLatency, size_t stageOffset, size_t stageLength, size_t fftSize, size_t renderPhase, size_t renderSliceSize, ReverbAccumulationBuffer* accumulationBuffer) : m_fftKernel(fftSize) , m_accumulationBuffer(accumulationBuffer) @@ -88,7 +88,7 @@ void ReverbConvolverStage::processInBackground(ReverbConvolver* convolver, size_ process(source, framesToProcess); } -void ReverbConvolverStage::process(float* source, size_t framesToProcess) +void ReverbConvolverStage::process(const float* source, size_t framesToProcess) { ASSERT(source); if (!source) @@ -96,7 +96,8 @@ void ReverbConvolverStage::process(float* source, size_t framesToProcess) // Deal with pre-delay stream : note special handling of zero delay. - float* preDelayedSource; + const float* preDelayedSource; + float* preDelayedDestination; float* temporaryBuffer; bool isTemporaryBufferSafe = false; if (m_preDelayLength > 0) { @@ -108,10 +109,12 @@ void ReverbConvolverStage::process(float* source, size_t framesToProcess) isTemporaryBufferSafe = framesToProcess <= m_temporaryBuffer.size(); - preDelayedSource = m_preDelayBuffer.data() + m_preReadWriteIndex; + preDelayedDestination = m_preDelayBuffer.data() + m_preReadWriteIndex; + preDelayedSource = preDelayedDestination; temporaryBuffer = m_temporaryBuffer.data(); } else { // Zero delay + preDelayedDestination = 0; preDelayedSource = source; temporaryBuffer = m_preDelayBuffer.data(); @@ -138,7 +141,7 @@ void ReverbConvolverStage::process(float* source, size_t framesToProcess) // Finally copy input to pre-delay. if (m_preDelayLength > 0) { - memcpy(preDelayedSource, source, sizeof(float) * framesToProcess); + memcpy(preDelayedDestination, source, sizeof(float) * framesToProcess); m_preReadWriteIndex += framesToProcess; ASSERT(m_preReadWriteIndex <= m_preDelayLength); diff --git a/Source/WebCore/platform/audio/ReverbConvolverStage.h b/Source/WebCore/platform/audio/ReverbConvolverStage.h index fc05a0e08..9811bc603 100644 --- a/Source/WebCore/platform/audio/ReverbConvolverStage.h +++ b/Source/WebCore/platform/audio/ReverbConvolverStage.h @@ -45,11 +45,11 @@ class ReverbConvolverStage { public: // renderPhase is useful to know so that we can manipulate the pre versus post delay so that stages will perform // their heavy work (FFT processing) on different slices to balance the load in a real-time thread. - ReverbConvolverStage(float* impulseResponse, size_t responseLength, size_t reverbTotalLatency, size_t stageOffset, size_t stageLength, + ReverbConvolverStage(const float* impulseResponse, size_t responseLength, size_t reverbTotalLatency, size_t stageOffset, size_t stageLength, size_t fftSize, size_t renderPhase, size_t renderSliceSize, ReverbAccumulationBuffer* accumulationBuffer); // WARNING: framesToProcess must be such that it evenly divides the delay buffer size (stage_offset). - void process(float* source, size_t framesToProcess); + void process(const float* source, size_t framesToProcess); void processInBackground(ReverbConvolver* convolver, size_t framesToProcess); diff --git a/Source/WebCore/platform/audio/ReverbInputBuffer.cpp b/Source/WebCore/platform/audio/ReverbInputBuffer.cpp index f270f6faa..1be9af884 100644 --- a/Source/WebCore/platform/audio/ReverbInputBuffer.cpp +++ b/Source/WebCore/platform/audio/ReverbInputBuffer.cpp @@ -40,7 +40,7 @@ ReverbInputBuffer::ReverbInputBuffer(size_t length) { } -void ReverbInputBuffer::write(float* sourceP, size_t numberOfFrames) +void ReverbInputBuffer::write(const float* sourceP, size_t numberOfFrames) { size_t bufferLength = m_buffer.size(); bool isCopySafe = m_writeIndex + numberOfFrames <= bufferLength; diff --git a/Source/WebCore/platform/audio/ReverbInputBuffer.h b/Source/WebCore/platform/audio/ReverbInputBuffer.h index 15a281824..5036575b9 100644 --- a/Source/WebCore/platform/audio/ReverbInputBuffer.h +++ b/Source/WebCore/platform/audio/ReverbInputBuffer.h @@ -41,7 +41,7 @@ public: // The realtime audio thread keeps writing samples here. // The assumption is that the buffer's length is evenly divisible by numberOfFrames (for nearly all cases this will be fine). // FIXME: remove numberOfFrames restriction... - void write(float* sourceP, size_t numberOfFrames); + void write(const float* sourceP, size_t numberOfFrames); // Background threads can call this to check if there's anything to read... size_t writeIndex() const { return m_writeIndex; } diff --git a/Source/WebCore/platform/audio/SincResampler.cpp b/Source/WebCore/platform/audio/SincResampler.cpp index 0e4b84985..1ee692c7c 100644 --- a/Source/WebCore/platform/audio/SincResampler.cpp +++ b/Source/WebCore/platform/audio/SincResampler.cpp @@ -135,6 +135,8 @@ void SincResampler::consumeSource(float* buffer, unsigned numberOfSourceFrames) // Wrap the provided buffer by an AudioBus for use by the source provider. AudioBus bus(1, numberOfSourceFrames, false); + + // FIXME: Find a way to make the following const-correct: bus.setChannelMemory(0, buffer, numberOfSourceFrames); m_sourceProvider->provideInput(&bus, numberOfSourceFrames); @@ -146,7 +148,7 @@ namespace { class BufferSourceProvider : public AudioSourceProvider { public: - BufferSourceProvider(float* source, size_t numberOfSourceFrames) + BufferSourceProvider(const float* source, size_t numberOfSourceFrames) : m_source(source) , m_sourceFramesAvailable(numberOfSourceFrames) { @@ -159,7 +161,7 @@ public: if (!m_source || !bus) return; - float* buffer = bus->channel(0)->data(); + float* buffer = bus->channel(0)->mutableData(); // Clamp to number of frames available and zero-pad. size_t framesToCopy = min(m_sourceFramesAvailable, framesToProcess); @@ -174,13 +176,13 @@ public: } private: - float* m_source; + const float* m_source; size_t m_sourceFramesAvailable; }; } // namespace -void SincResampler::process(float* source, float* destination, unsigned numberOfSourceFrames) +void SincResampler::process(const float* source, float* destination, unsigned numberOfSourceFrames) { // Resample an in-memory buffer using an AudioSourceProvider. BufferSourceProvider sourceProvider(source, numberOfSourceFrames); diff --git a/Source/WebCore/platform/audio/SincResampler.h b/Source/WebCore/platform/audio/SincResampler.h index bbe0c558c..04dbf3fa1 100644 --- a/Source/WebCore/platform/audio/SincResampler.h +++ b/Source/WebCore/platform/audio/SincResampler.h @@ -44,7 +44,7 @@ public: SincResampler(double scaleFactor, unsigned kernelSize = 32, unsigned numberOfKernelOffsets = 32); // Processes numberOfSourceFrames from source to produce numberOfSourceFrames / scaleFactor frames in destination. - void process(float* source, float* destination, unsigned numberOfSourceFrames); + void process(const float* source, float* destination, unsigned numberOfSourceFrames); // Process with input source callback function for streaming applications. void process(AudioSourceProvider*, float* destination, size_t framesToProcess); @@ -71,7 +71,7 @@ protected: // Source is copied into this buffer for each processing pass. AudioFloatArray m_inputBuffer; - float* m_source; + const float* m_source; unsigned m_sourceFramesAvailable; // m_sourceProvider is used to provide the audio input stream to the resampler. diff --git a/Source/WebCore/platform/audio/VectorMath.cpp b/Source/WebCore/platform/audio/VectorMath.cpp index 71e101470..572dbf353 100644 --- a/Source/WebCore/platform/audio/VectorMath.cpp +++ b/Source/WebCore/platform/audio/VectorMath.cpp @@ -36,6 +36,9 @@ #include <emmintrin.h> #endif +#include <algorithm> +#include <math.h> + namespace WebCore { namespace VectorMath { @@ -90,8 +93,77 @@ void zvmul(const float* real1P, const float* imag1P, const float* real2P, const #endif } +void vsma(const float* sourceP, int sourceStride, const float* scale, float* destP, int destStride, size_t framesToProcess) +{ + vDSP_vsma(sourceP, sourceStride, scale, destP, destStride, destP, destStride, framesToProcess); +} + +void vmaxmgv(const float* sourceP, int sourceStride, float* maxP, size_t framesToProcess) +{ + vDSP_maxmgv(sourceP, sourceStride, maxP, framesToProcess); +} + +void vsvesq(const float* sourceP, int sourceStride, float* sumP, size_t framesToProcess) +{ + vDSP_svesq(const_cast<float*>(sourceP), sourceStride, sumP, framesToProcess); +} #else +void vsma(const float* sourceP, int sourceStride, const float* scale, float* destP, int destStride, size_t framesToProcess) +{ + int n = framesToProcess; + +#ifdef __SSE2__ + if ((sourceStride == 1) && (destStride == 1)) { + float k = *scale; + + // If the sourceP address is not 16-byte aligned, the first several frames (at most three) should be processed seperately. + while ((reinterpret_cast<uintptr_t>(sourceP) & 0x0F) && n) { + *destP += k * *sourceP; + sourceP++; + destP++; + n--; + } + + // Now the sourceP address aligned and start to apply SSE. + int tailFrames = n % 4; + float* endP = destP + n - tailFrames; + + __m128 pSource; + __m128 dest; + __m128 temp; + __m128 mScale = _mm_set_ps1(k); + + bool destAligned = !(reinterpret_cast<uintptr_t>(destP) & 0x0F); + +#define SSE2_MULT_ADD(loadInstr, storeInstr) \ + while (destP < endP) \ + { \ + pSource = _mm_load_ps(sourceP); \ + temp = _mm_mul_ps(pSource, mScale); \ + dest = _mm_##loadInstr##_ps(destP); \ + dest = _mm_add_ps(dest, temp); \ + _mm_##storeInstr##_ps(destP, dest); \ + sourceP += 4; \ + destP += 4; \ + } + + if (destAligned) + SSE2_MULT_ADD(load, store) + else + SSE2_MULT_ADD(loadu, storeu) + + n = tailFrames; + } +#endif + while (n) { + *destP += *sourceP * *scale; + sourceP += sourceStride; + destP += destStride; + n--; + } +} + void vsmul(const float* sourceP, int sourceStride, const float* scale, float* destP, int destStride, size_t framesToProcess) { #ifdef __SSE2__ @@ -351,6 +423,34 @@ void zvmul(const float* real1P, const float* imag1P, const float* real2P, const } } +void vsvesq(const float* sourceP, int sourceStride, float* sumP, size_t framesToProcess) +{ + // FIXME: optimize for SSE + int n = framesToProcess; + float sum = 0; + while (n--) { + float sample = *sourceP; + sum += sample * sample; + sourceP += sourceStride; + } + + ASSERT(sumP); + *sumP = sum; +} + +void vmaxmgv(const float* sourceP, int sourceStride, float* maxP, size_t framesToProcess) +{ + // FIXME: optimize for SSE + int n = framesToProcess; + float max = 0; + while (n--) { + max = std::max(max, fabsf(*sourceP)); + sourceP += sourceStride; + } + + ASSERT(maxP); + *maxP = max; +} #endif // OS(DARWIN) } // namespace VectorMath diff --git a/Source/WebCore/platform/audio/VectorMath.h b/Source/WebCore/platform/audio/VectorMath.h index 5ae80dab9..702251920 100644 --- a/Source/WebCore/platform/audio/VectorMath.h +++ b/Source/WebCore/platform/audio/VectorMath.h @@ -31,9 +31,18 @@ namespace WebCore { namespace VectorMath { +// Vector scalar multiply and then add. +void vsma(const float* sourceP, int sourceStride, const float* scale, float* destP, int destStride, size_t framesToProcess); + void vsmul(const float* sourceP, int sourceStride, const float* scale, float* destP, int destStride, size_t framesToProcess); void vadd(const float* source1P, int sourceStride1, const float* source2P, int sourceStride2, float* destP, int destStride, size_t framesToProcess); +// Finds the maximum magnitude of a float vector. +void vmaxmgv(const float* sourceP, int sourceStride, float* maxP, size_t framesToProcess); + +// Sums the squares of a float vector's elements. +void vsvesq(const float* sourceP, int sourceStride, float* sumP, size_t framesToProcess); + // For an element-by-element multiply of two float vectors. void vmul(const float* source1P, int sourceStride1, const float* source2P, int sourceStride2, float* destP, int destStride, size_t framesToProcess); diff --git a/Source/WebCore/platform/audio/ZeroPole.cpp b/Source/WebCore/platform/audio/ZeroPole.cpp index 2fa44003a..9e6f1b635 100644 --- a/Source/WebCore/platform/audio/ZeroPole.cpp +++ b/Source/WebCore/platform/audio/ZeroPole.cpp @@ -36,7 +36,7 @@ namespace WebCore { -void ZeroPole::process(float *source, float *destination, unsigned framesToProcess) +void ZeroPole::process(const float *source, float *destination, unsigned framesToProcess) { float zero = m_zero; float pole = m_pole; diff --git a/Source/WebCore/platform/audio/ZeroPole.h b/Source/WebCore/platform/audio/ZeroPole.h index 93fd0d6f9..4cb1d1745 100644 --- a/Source/WebCore/platform/audio/ZeroPole.h +++ b/Source/WebCore/platform/audio/ZeroPole.h @@ -43,7 +43,7 @@ public: { } - void process(float *source, float *destination, unsigned framesToProcess); + void process(const float *source, float *destination, unsigned framesToProcess); // Reset filter state. void reset() { m_lastX = 0; m_lastY = 0; } diff --git a/Source/WebCore/platform/audio/ffmpeg/FFTFrameFFMPEG.cpp b/Source/WebCore/platform/audio/ffmpeg/FFTFrameFFMPEG.cpp index 9f8932445..d4624a70b 100644 --- a/Source/WebCore/platform/audio/ffmpeg/FFTFrameFFMPEG.cpp +++ b/Source/WebCore/platform/audio/ffmpeg/FFTFrameFFMPEG.cpp @@ -135,7 +135,7 @@ void FFTFrame::multiply(const FFTFrame& frame) VectorMath::vsmul(imagP1, 1, &scale, imagP1, 1, halfSize); } -void FFTFrame::doFFT(float* data) +void FFTFrame::doFFT(const float* data) { // Copy since processing is in-place. float* p = m_complexData.data(); diff --git a/Source/WebCore/platform/audio/gstreamer/AudioFileReaderGStreamer.cpp b/Source/WebCore/platform/audio/gstreamer/AudioFileReaderGStreamer.cpp index 20e81b9c0..093f81fa8 100644 --- a/Source/WebCore/platform/audio/gstreamer/AudioFileReaderGStreamer.cpp +++ b/Source/WebCore/platform/audio/gstreamer/AudioFileReaderGStreamer.cpp @@ -80,7 +80,7 @@ static void copyGstreamerBuffersToAudioChannel(GstBufferList* buffers, AudioChan gst_buffer_list_iterator_next_group(iter); GstBuffer* buffer = gst_buffer_list_iterator_merge_group(iter); if (buffer) { - memcpy(audioChannel->data(), reinterpret_cast<float*>(GST_BUFFER_DATA(buffer)), GST_BUFFER_SIZE(buffer)); + memcpy(audioChannel->mutableData(), reinterpret_cast<float*>(GST_BUFFER_DATA(buffer)), GST_BUFFER_SIZE(buffer)); gst_buffer_unref(buffer); } diff --git a/Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp b/Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp index 5183e3403..2cae4acab 100644 --- a/Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp +++ b/Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp @@ -333,7 +333,7 @@ static void webKitWebAudioSrcLoop(WebKitWebAudioSrc* src) ASSERT(buffer); ASSERT(!GST_BUFFER_MALLOCDATA(buffer)); - GST_BUFFER_DATA(buffer) = reinterpret_cast<guint8*>(priv->bus->channel(index)->data()); + GST_BUFFER_DATA(buffer) = reinterpret_cast<guint8*>(const_cast<float*>(priv->bus->channel(index)->data())); GST_BUFFER_SIZE(buffer) = bufferSize; GST_BUFFER_OFFSET(buffer) = priv->currentBufferOffset; GST_BUFFER_OFFSET_END(buffer) = priv->currentBufferOffset + priv->framesToPull; diff --git a/Source/WebCore/platform/audio/mac/AudioBusMac.mm b/Source/WebCore/platform/audio/mac/AudioBusMac.mm index 42a718b21..f2d3676e5 100644 --- a/Source/WebCore/platform/audio/mac/AudioBusMac.mm +++ b/Source/WebCore/platform/audio/mac/AudioBusMac.mm @@ -47,8 +47,13 @@ PassOwnPtr<AudioBus> AudioBus::loadPlatformResource(const char* name, float samp NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSBundle *bundle = [NSBundle bundleForClass:[WebCoreAudioBundleClass class]]; - NSString *audioFilePath = [bundle pathForResource:[NSString stringWithUTF8String:name] ofType:@"wav" inDirectory:@"audio"]; - NSData *audioData = [NSData dataWithContentsOfFile:audioFilePath]; + NSURL *audioFileURL = [bundle URLForResource:[NSString stringWithUTF8String:name] withExtension:@"wav" subdirectory:@"audio"]; +#if defined(BUILDING_ON_SNOW_LEOPARD) + NSDataReadingOptions options = NSDataReadingMapped; +#else + NSDataReadingOptions options = NSDataReadingMappedIfSafe; +#endif + NSData *audioData = [NSData dataWithContentsOfURL:audioFileURL options:options error:nil]; if (audioData) { OwnPtr<AudioBus> bus(createBusFromInMemoryAudioFile([audioData bytes], [audioData length], false, sampleRate)); diff --git a/Source/WebCore/platform/audio/mac/AudioFileReaderMac.cpp b/Source/WebCore/platform/audio/mac/AudioFileReaderMac.cpp index 95502636b..d0ecf1a31 100644 --- a/Source/WebCore/platform/audio/mac/AudioFileReaderMac.cpp +++ b/Source/WebCore/platform/audio/mac/AudioFileReaderMac.cpp @@ -212,7 +212,7 @@ PassOwnPtr<AudioBus> AudioFileReader::createBus(float sampleRate, bool mixToMono for (size_t i = 0; i < numberOfChannels; ++i) { bufferList->mBuffers[i].mNumberChannels = 1; bufferList->mBuffers[i].mDataByteSize = numberOfFrames * sizeof(float); - bufferList->mBuffers[i].mData = audioBus->channel(i)->data(); + bufferList->mBuffers[i].mData = audioBus->channel(i)->mutableData(); } } @@ -224,7 +224,7 @@ PassOwnPtr<AudioBus> AudioFileReader::createBus(float sampleRate, bool mixToMono if (mixToMono && numberOfChannels == 2) { // Mix stereo down to mono - float* destL = audioBus->channel(0)->data(); + float* destL = audioBus->channel(0)->mutableData(); for (size_t i = 0; i < numberOfFrames; i++) destL[i] = 0.5f * (bufferL[i] + bufferR[i]); } diff --git a/Source/WebCore/platform/audio/mac/FFTFrameMac.cpp b/Source/WebCore/platform/audio/mac/FFTFrameMac.cpp index 6dfbbeccb..8cef928d4 100644 --- a/Source/WebCore/platform/audio/mac/FFTFrameMac.cpp +++ b/Source/WebCore/platform/audio/mac/FFTFrameMac.cpp @@ -127,7 +127,7 @@ void FFTFrame::multiply(const FFTFrame& frame) VectorMath::vsmul(imagP1, 1, &scale, imagP1, 1, halfSize); } -void FFTFrame::doFFT(float* data) +void FFTFrame::doFFT(const float* data) { vDSP_ctoz((DSPComplex*)data, 2, &m_frame, 1, m_FFTSize / 2); vDSP_fft_zrip(m_FFTSetup, &m_frame, 1, m_log2FFTSize, FFT_FORWARD); diff --git a/Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp b/Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp index 6bf2c1e20..0f3a2827f 100644 --- a/Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp +++ b/Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp @@ -170,7 +170,7 @@ void FFTFrame::multiply(const FFTFrame& frame) } } -void FFTFrame::doFFT(float* data) +void FFTFrame::doFFT(const float* data) { // Compute Forward transform. MKL_LONG status = DftiComputeForward(m_handle, data, m_complexData.data()); diff --git a/Source/WebCore/platform/audio/resources/Composite.wav b/Source/WebCore/platform/audio/resources/Composite.wav Binary files differindex 617dd2ae2..25fc82314 100644 --- a/Source/WebCore/platform/audio/resources/Composite.wav +++ b/Source/WebCore/platform/audio/resources/Composite.wav diff --git a/Source/WebCore/platform/blackberry/LocalizedStringsBlackBerry.cpp b/Source/WebCore/platform/blackberry/LocalizedStringsBlackBerry.cpp index b7f369ba4..a93e38109 100644 --- a/Source/WebCore/platform/blackberry/LocalizedStringsBlackBerry.cpp +++ b/Source/WebCore/platform/blackberry/LocalizedStringsBlackBerry.cpp @@ -23,6 +23,7 @@ #include "NotImplemented.h" #include <BlackBerryPlatformClient.h> #include <LocalizeResource.h> +#include <wtf/Vector.h> namespace WebCore { @@ -59,7 +60,7 @@ String inputElementAltText() return String(); } -String platformDefaultLanguage() +static String platformLanguage() { String lang = BlackBerry::Platform::Client::get()->getLocale().c_str(); // getLocale() returns a POSIX locale which uses '_' to separate language and country. @@ -71,6 +72,13 @@ String platformDefaultLanguage() return lang; } +Vector<String> platformUserPreferredLanguages() +{ + Vector<String> userPreferredLanguages; + userPreferredLanguages.append(platformLanguage()); + return userPreferredLanguages; +} + #if ENABLE(CONTEXT_MENUS) String contextMenuItemTagBold() { diff --git a/Source/WebCore/platform/blackberry/LoggingBlackBerry.cpp b/Source/WebCore/platform/blackberry/LoggingBlackBerry.cpp index ea535f897..994d78ec9 100644 --- a/Source/WebCore/platform/blackberry/LoggingBlackBerry.cpp +++ b/Source/WebCore/platform/blackberry/LoggingBlackBerry.cpp @@ -19,6 +19,8 @@ #include "config.h" #include "Logging.h" +#include <wtf/text/WTFString.h> + namespace WebCore { static inline void initializeWithUserDefault(WTFLogChannel& channel, bool enabled) @@ -36,30 +38,18 @@ void initializeLoggingChannelsIfNecessary() return; haveInitializedLoggingChannels = true; - initializeWithUserDefault(LogNotYetImplemented, true); - initializeWithUserDefault(LogFrames, true); - initializeWithUserDefault(LogLoading, true); - initializeWithUserDefault(LogPopupBlocking, true); - initializeWithUserDefault(LogEvents, true); - initializeWithUserDefault(LogEditing, true); - initializeWithUserDefault(LogLiveConnect, true); - initializeWithUserDefault(LogIconDatabase, false); - initializeWithUserDefault(LogSQLDatabase, false); - initializeWithUserDefault(LogSpellingAndGrammar, true); - initializeWithUserDefault(LogBackForward, true); - initializeWithUserDefault(LogHistory, true); - initializeWithUserDefault(LogPageCache, true); - initializeWithUserDefault(LogPlatformLeaks, true); - initializeWithUserDefault(LogNetwork, true); - initializeWithUserDefault(LogFTP, true); - initializeWithUserDefault(LogThreading, true); - initializeWithUserDefault(LogStorageAPI, true); - initializeWithUserDefault(LogMedia, true); - initializeWithUserDefault(LogPlugins, true); - initializeWithUserDefault(LogArchives, true); - initializeWithUserDefault(LogProgress, false); - initializeWithUserDefault(LogResourceLoading, false); - initializeWithUserDefault(LogFileAPI, true); + String logEnv = getenv("WEBKIT_DEBUG"); + if (logEnv.isEmpty()) + return; + + Vector<String> logv; + logEnv.split(" ", logv); + + Vector<String>::const_iterator it = logv.begin(); + for (; it != logv.end(); ++it) { + if (WTFLogChannel* channel = getChannelFromName(*it)) + channel->state = WTFLogChannelOn; + } } } // namespace WebCore diff --git a/Source/WebCore/platform/blackberry/PlatformKeyboardEventBlackBerry.cpp b/Source/WebCore/platform/blackberry/PlatformKeyboardEventBlackBerry.cpp index b8fc1ee65..607126b7d 100644 --- a/Source/WebCore/platform/blackberry/PlatformKeyboardEventBlackBerry.cpp +++ b/Source/WebCore/platform/blackberry/PlatformKeyboardEventBlackBerry.cpp @@ -73,10 +73,10 @@ static String keyIdentifierForBlackBerryCharacter(unsigned short character) return "Insert"; case KEYCODE_PG_UP: case KEYCODE_KP_PG_UP: - return "PageDown"; + return "PageUp"; case KEYCODE_PG_DOWN: case KEYCODE_KP_PG_DOWN: - return "PageUp"; + return "PageDown"; case KEYCODE_END: case KEYCODE_KP_END: return "End"; @@ -299,10 +299,10 @@ static int windowsKeyCodeForBlackBerryCharacter(unsigned short character) return VK_INSERT; case KEYCODE_PG_UP: case KEYCODE_KP_PG_UP: - return VK_NEXT; + return VK_PRIOR; case KEYCODE_PG_DOWN: case KEYCODE_KP_PG_DOWN: - return VK_PRIOR; + return VK_NEXT; case KEYCODE_END: case KEYCODE_KP_END: return VK_END; diff --git a/Source/WebCore/platform/blackberry/PlatformScreenBlackBerry.cpp b/Source/WebCore/platform/blackberry/PlatformScreenBlackBerry.cpp index d26e55664..b2829c4e9 100644 --- a/Source/WebCore/platform/blackberry/PlatformScreenBlackBerry.cpp +++ b/Source/WebCore/platform/blackberry/PlatformScreenBlackBerry.cpp @@ -20,6 +20,7 @@ #include "PlatformScreen.h" #include "FloatRect.h" +#include "FrameView.h" #include "Widget.h" #include <BlackBerryPlatformScreen.h> @@ -41,12 +42,12 @@ int screenDepth(Widget*) return 24; } -FloatRect screenAvailableRect(Widget* widget) +FloatRect screenAvailableRect(FrameView* frameView) { return FloatRect(FloatPoint(), FloatSize(IntSize(BlackBerry::Platform::Graphics::Screen::size()))); } -FloatRect screenRect(Widget* widget) +FloatRect screenRect(FrameView* frameView) { return FloatRect(FloatPoint(), FloatSize(IntSize(BlackBerry::Platform::Graphics::Screen::size()))); } diff --git a/Source/WebCore/platform/cf/KURLCFNet.cpp b/Source/WebCore/platform/cf/KURLCFNet.cpp index d79123720..b3a58652b 100644 --- a/Source/WebCore/platform/cf/KURLCFNet.cpp +++ b/Source/WebCore/platform/cf/KURLCFNet.cpp @@ -45,22 +45,11 @@ KURL::KURL(CFURLRef url) } CFIndex bytesLength = CFURLGetBytes(url, 0, 0); - Vector<char, 512> buffer(bytesLength + 6); // 5 for "file:", 1 for null character to end C string - char* bytes = &buffer[5]; + Vector<char, 512> buffer(bytesLength + 1); + char* bytes = &buffer[0]; CFURLGetBytes(url, reinterpret_cast<UInt8*>(bytes), bytesLength); bytes[bytesLength] = '\0'; - if (bytes[0] != '/') { - parse(bytes); - return; - } - - buffer[0] = 'f'; - buffer[1] = 'i'; - buffer[2] = 'l'; - buffer[3] = 'e'; - buffer[4] = ':'; - - parse(buffer.data()); + parse(bytes); } CFURLRef createCFURLFromBuffer(const CharBuffer& buffer) diff --git a/Source/WebCore/platform/cf/SchedulePair.h b/Source/WebCore/platform/cf/SchedulePair.h index 517243688..764c29fc4 100644 --- a/Source/WebCore/platform/cf/SchedulePair.h +++ b/Source/WebCore/platform/cf/SchedulePair.h @@ -35,11 +35,7 @@ #include <wtf/RetainPtr.h> #if PLATFORM(MAC) -#ifdef __OBJC__ -@class NSRunLoop; -#else -class NSRunLoop; -#endif +OBJC_CLASS NSRunLoop; #endif namespace WebCore { diff --git a/Source/WebCore/platform/chromium/ChromiumDataObject.cpp b/Source/WebCore/platform/chromium/ChromiumDataObject.cpp index 05c5e130c..6ad10c7da 100644 --- a/Source/WebCore/platform/chromium/ChromiumDataObject.cpp +++ b/Source/WebCore/platform/chromium/ChromiumDataObject.cpp @@ -33,6 +33,7 @@ #include "ClipboardMimeTypes.h" #include "ClipboardUtilitiesChromium.h" +#include "DataTransferItemListChromium.h" #include "Pasteboard.h" #include "PlatformSupport.h" @@ -115,9 +116,6 @@ HashSet<String> ChromiumDataObject::types() const results.add(mimeTypeTextPlain); } - if (m_url.isValid()) - results.add(mimeTypeURL); - if (!m_uriList.isEmpty()) results.add(mimeTypeTextURIList); @@ -145,7 +143,7 @@ String ChromiumDataObject::getData(const String& type, bool& success) const } if (type == mimeTypeURL) { - success = !m_url.isEmpty(); + success = !m_uriList.isEmpty(); return m_url.string(); } diff --git a/Source/WebCore/platform/chromium/ChromiumDataObject.h b/Source/WebCore/platform/chromium/ChromiumDataObject.h index 9ddfb0b93..7e675bf93 100644 --- a/Source/WebCore/platform/chromium/ChromiumDataObject.h +++ b/Source/WebCore/platform/chromium/ChromiumDataObject.h @@ -85,11 +85,14 @@ public: KURL htmlBaseUrl() const { return m_htmlBaseUrl; } void setHtmlBaseUrl(const KURL& url) { m_htmlBaseUrl = url; } - // Used to handle files being dragged in. + // Used to handle files being dragged in and out. bool containsFilenames() const; - Vector<String> filenames() const { return m_filenames; } + const Vector<String>& filenames() const { return m_filenames; } void setFilenames(const Vector<String>& filenames) { m_filenames = filenames; } + // Used to handle files being dragged out. + void addFilename(const String& filename) { m_filenames.append(filename); } + // Used to handle files (images) being dragged out. String fileExtension() const { return m_fileExtension; } void setFileExtension(const String& fileExtension) { m_fileExtension = fileExtension; } diff --git a/Source/WebCore/platform/chromium/ClipboardChromium.cpp b/Source/WebCore/platform/chromium/ClipboardChromium.cpp index cd0bf78cf..75f8f630c 100644 --- a/Source/WebCore/platform/chromium/ClipboardChromium.cpp +++ b/Source/WebCore/platform/chromium/ClipboardChromium.cpp @@ -31,10 +31,13 @@ #include "ChromiumDataObject.h" #include "ClipboardMimeTypes.h" #include "ClipboardUtilitiesChromium.h" +#include "DataTransferItemChromium.h" #include "DataTransferItemListChromium.h" #include "Document.h" #include "DragData.h" #include "Element.h" +#include "ExceptionCode.h" +#include "File.h" #include "FileList.h" #include "Frame.h" #include "HTMLNames.h" @@ -45,14 +48,160 @@ #include "PlatformSupport.h" #include "Range.h" #include "RenderImage.h" -#include "ScriptExecutionContext.h" +#include "StringCallback.h" #include "markup.h" -#include <wtf/text/StringBuilder.h> #include <wtf/text/WTFString.h> namespace WebCore { +namespace { + +// These wrapper classes invalidate a DataTransferItem/DataTransferItemList when the associated +// Clipboard object goes out of scope. +class DataTransferItemListPolicyWrapper : public DataTransferItemList { +public: + static PassRefPtr<DataTransferItemListPolicyWrapper> create( + PassRefPtr<ClipboardChromium>, PassRefPtr<DataTransferItemListChromium>); + + virtual size_t length() const; + virtual PassRefPtr<DataTransferItem> item(unsigned long index); + virtual void deleteItem(unsigned long index, ExceptionCode&); + virtual void clear(); + virtual void add(const String& data, const String& type, ExceptionCode&); + virtual void add(PassRefPtr<File>); + +private: + DataTransferItemListPolicyWrapper(PassRefPtr<ClipboardChromium>, PassRefPtr<DataTransferItemListChromium>); + + RefPtr<ClipboardChromium> m_clipboard; + RefPtr<DataTransferItemListChromium> m_list; +}; + +class DataTransferItemPolicyWrapper : public DataTransferItem { +public: + static PassRefPtr<DataTransferItemPolicyWrapper> create( + PassRefPtr<ClipboardChromium>, PassRefPtr<DataTransferItem>); + + virtual String kind() const; + virtual String type() const; + + virtual void getAsString(PassRefPtr<StringCallback>) const; + virtual PassRefPtr<Blob> getAsFile() const; + +private: + DataTransferItemPolicyWrapper(PassRefPtr<ClipboardChromium>, PassRefPtr<DataTransferItem>); + + RefPtr<ClipboardChromium> m_clipboard; + RefPtr<DataTransferItem> m_item; +}; + +PassRefPtr<DataTransferItemListPolicyWrapper> DataTransferItemListPolicyWrapper::create( + PassRefPtr<ClipboardChromium> clipboard, PassRefPtr<DataTransferItemListChromium> list) +{ + return adoptRef(new DataTransferItemListPolicyWrapper(clipboard, list)); +} + +size_t DataTransferItemListPolicyWrapper::length() const +{ + if (m_clipboard->policy() == ClipboardNumb) + return 0; + return m_list->length(); +} + +PassRefPtr<DataTransferItem> DataTransferItemListPolicyWrapper::item(unsigned long index) +{ + if (m_clipboard->policy() == ClipboardNumb) + return 0; + RefPtr<DataTransferItem> item = m_list->item(index); + if (!item) + return 0; + return DataTransferItemPolicyWrapper::create(m_clipboard, item); +} + +void DataTransferItemListPolicyWrapper::deleteItem(unsigned long index, ExceptionCode& ec) +{ + if (m_clipboard->policy() != ClipboardWritable) { + ec = INVALID_STATE_ERR; + return; + } + // FIXME: We handle all the exceptions here, so we don't need to propogate ec. + m_list->deleteItem(index, ec); +} + +void DataTransferItemListPolicyWrapper::clear() +{ + if (m_clipboard->policy() != ClipboardWritable) + return; + m_list->clear(); +} + +void DataTransferItemListPolicyWrapper::add(const String& data, const String& type, ExceptionCode& ec) +{ + if (m_clipboard->policy() != ClipboardWritable) + return; + m_list->add(data, type, ec); +} + +void DataTransferItemListPolicyWrapper::add(PassRefPtr<File> file) +{ + if (m_clipboard->policy() != ClipboardWritable) + return; + m_list->add(file); +} + +DataTransferItemListPolicyWrapper::DataTransferItemListPolicyWrapper( + PassRefPtr<ClipboardChromium> clipboard, PassRefPtr<DataTransferItemListChromium> list) + : m_clipboard(clipboard) + , m_list(list) +{ +} + +PassRefPtr<DataTransferItemPolicyWrapper> DataTransferItemPolicyWrapper::create( + PassRefPtr<ClipboardChromium> clipboard, PassRefPtr<DataTransferItem> item) +{ + return adoptRef(new DataTransferItemPolicyWrapper(clipboard, item)); +} + +String DataTransferItemPolicyWrapper::kind() const +{ + if (m_clipboard->policy() == ClipboardNumb) + return String(); + return m_item->kind(); +} + +String DataTransferItemPolicyWrapper::type() const +{ + if (m_clipboard->policy() == ClipboardNumb) + return String(); + return m_item->type(); +} + +void DataTransferItemPolicyWrapper::getAsString(PassRefPtr<StringCallback> callback) const +{ + if (m_clipboard->policy() != ClipboardReadable && m_clipboard->policy() != ClipboardWritable) + return; + + m_item->getAsString(callback); +} + +PassRefPtr<Blob> DataTransferItemPolicyWrapper::getAsFile() const +{ + if (m_clipboard->policy() != ClipboardReadable && m_clipboard->policy() != ClipboardWritable) + return 0; + + return m_item->getAsFile(); +} + +DataTransferItemPolicyWrapper::DataTransferItemPolicyWrapper( + PassRefPtr<ClipboardChromium> clipboard, PassRefPtr<DataTransferItem> item) + : m_clipboard(clipboard) + , m_item(item) +{ +} + +} // namespace + using namespace HTMLNames; // We provide the IE clipboard types (URL and Text), and the clipboard types specified in the WHATWG Web Applications 1.0 draft @@ -79,6 +228,11 @@ ClipboardChromium::ClipboardChromium(ClipboardType clipboardType, , m_dataObject(dataObject) , m_frame(frame) , m_originalSequenceNumber(PlatformSupport::clipboardSequenceNumber(currentPasteboardBuffer())) + , m_dragStorageUpdated(true) +{ +} + +ClipboardChromium::~ClipboardChromium() { } @@ -93,6 +247,7 @@ void ClipboardChromium::clearData(const String& type) if (policy() != ClipboardWritable || !m_dataObject) return; + m_dragStorageUpdated = true; m_dataObject->clearData(normalizeType(type)); ASSERT_NOT_REACHED(); @@ -103,6 +258,7 @@ void ClipboardChromium::clearAllData() if (policy() != ClipboardWritable) return; + m_dragStorageUpdated = true; m_dataObject->clearAll(); } @@ -123,6 +279,7 @@ bool ClipboardChromium::setData(const String& type, const String& data) if (policy() != ClipboardWritable) return false; + m_dragStorageUpdated = true; return m_dataObject->setData(normalizeType(type), data); } @@ -246,13 +403,15 @@ static void writeImageToDataObject(ChromiumDataObject* dataObject, Element* elem if (extensionIndex != -1) filename.truncate(extensionIndex); } - filename = ClipboardChromium::validateFileName(filename, dataObject); String extension = MIMETypeRegistry::getPreferredExtensionForMIMEType( cachedImage->response().mimeType()); - dataObject->setFileExtension(extension.isEmpty() ? emptyString() : "." + extension); + extension = extension.isEmpty() ? emptyString() : "." + extension; + + ClipboardChromium::validateFilename(filename, extension); - dataObject->setFileContentFilename(filename + dataObject->fileExtension()); + dataObject->setFileContentFilename(filename + extension); + dataObject->setFileExtension(extension); } void ClipboardChromium::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame) @@ -260,6 +419,7 @@ void ClipboardChromium::declareAndWriteDragImage(Element* element, const KURL& u if (!m_dataObject) return; + m_dragStorageUpdated = true; m_dataObject->setData(mimeTypeURL, url); m_dataObject->setUrlTitle(title); @@ -275,6 +435,8 @@ void ClipboardChromium::writeURL(const KURL& url, const String& title, Frame*) if (!m_dataObject) return; ASSERT(!url.isEmpty()); + + m_dragStorageUpdated = true; m_dataObject->setData(mimeTypeURL, url); m_dataObject->setUrlTitle(title); @@ -292,6 +454,7 @@ void ClipboardChromium::writeRange(Range* selectedRange, Frame* frame) if (!m_dataObject) return; + m_dragStorageUpdated = true; m_dataObject->setData(mimeTypeTextHTML, createMarkup(selectedRange, 0, AnnotateForInterchange, false, ResolveNonLocalURLs)); m_dataObject->setHtmlBaseUrl(frame->document()->url()); @@ -313,6 +476,8 @@ void ClipboardChromium::writePlainText(const String& text) replaceNewlinesWithWindowsStyleNewlines(str); #endif replaceNBSPWithSpace(str); + + m_dragStorageUpdated = true; m_dataObject->setData(mimeTypeTextPlain, str); } @@ -328,19 +493,60 @@ bool ClipboardChromium::hasData() #if ENABLE(DATA_TRANSFER_ITEMS) PassRefPtr<DataTransferItemList> ClipboardChromium::items() { - RefPtr<DataTransferItemListChromium> items = DataTransferItemListChromium::create(this, m_frame->document()->scriptExecutionContext()); - if (!m_dataObject) - return items; + // Return an unassociated empty list. + return DataTransferItemListChromium::create(this, m_frame->document()->scriptExecutionContext()); + + if (!m_itemList) + m_itemList = DataTransferItemListChromium::create(this, m_frame->document()->scriptExecutionContext()); + + // FIXME: According to the spec, we are supposed to return the same collection of items each + // time. We now return a wrapper that always wraps the *same* set of items, so JS shouldn't be + // able to tell, but we probably still want to fix this. + return DataTransferItemListPolicyWrapper::create(this, m_itemList); +} + +// FIXME: integrate ChromiumDataObject and DataTransferItemList rather than holding them separately and keeping them synced. +void ClipboardChromium::mayUpdateItems(Vector<RefPtr<DataTransferItem> >& items) +{ + if (!items.isEmpty() && !storageHasUpdated()) + return; + + items.clear(); + + ScriptExecutionContext* scriptExecutionContext = m_frame->document()->scriptExecutionContext(); if (isForCopyAndPaste() && policy() == ClipboardReadable) { // Iterate through the types and add them. HashSet<String> types = m_dataObject->types(); for (HashSet<String>::const_iterator it = types.begin(); it != types.end(); ++it) - items->addPasteboardItem(*it); + items.append(DataTransferItemChromium::createFromPasteboard(this, scriptExecutionContext, *it)); + return; } - return items; + + bool success = false; + String plainText = m_dataObject->getData(mimeTypeTextPlain, success); + if (success) + items.append(DataTransferItemChromium::create(this, scriptExecutionContext, plainText, mimeTypeTextPlain)); + + success = false; + String htmlText = m_dataObject->getData(mimeTypeTextHTML, success); + if (success) + items.append(DataTransferItemChromium::create(this, scriptExecutionContext, htmlText, mimeTypeTextHTML)); + + if (m_dataObject->containsFilenames()) { + const Vector<String>& filenames = m_dataObject->filenames(); + for (Vector<String>::const_iterator it = filenames.begin(); it != filenames.end(); ++it) + items.append(DataTransferItemChromium::create(this, scriptExecutionContext, File::create(*it))); + } + m_dragStorageUpdated = false; } + +bool ClipboardChromium::storageHasUpdated() const +{ + return (isForCopyAndPaste() && platformClipboardChanged()) || (isForDragAndDrop() && m_dragStorageUpdated); +} + #endif } // namespace WebCore diff --git a/Source/WebCore/platform/chromium/ClipboardChromium.h b/Source/WebCore/platform/chromium/ClipboardChromium.h index 8b174527a..924226df3 100644 --- a/Source/WebCore/platform/chromium/ClipboardChromium.h +++ b/Source/WebCore/platform/chromium/ClipboardChromium.h @@ -38,22 +38,23 @@ namespace WebCore { class CachedImage; class ChromiumDataObject; + class DataTransferItem; + class DataTransferItemListChromium; class Frame; class IntPoint; class ClipboardChromium : public Clipboard, public CachedImageClient { WTF_MAKE_FAST_ALLOCATED; public: - ~ClipboardChromium() {} + ~ClipboardChromium(); static PassRefPtr<ClipboardChromium> create( 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 - // path + extension is not bigger than allowed by the file system. - // This may change the file extension in dataObject. - static String validateFileName(const String& title, ChromiumDataObject* dataObject); + // Validates a filename (without the extension) and the extension. This removes any invalid + // file system characters as well as making sure the path + extension is not bigger than + // allowed by the file system. + static void validateFilename(String& name, String& extension); virtual void clearData(const String& type); void clearAllData(); @@ -83,6 +84,10 @@ namespace WebCore { #if ENABLE(DATA_TRANSFER_ITEMS) virtual PassRefPtr<DataTransferItemList> items(); + + // Internal routines to keep the list returned by items() (i.e. m_itemList) synchronized with the content of the clipboard data. + void mayUpdateItems(Vector<RefPtr<DataTransferItem> >& items); + bool storageHasUpdated() const; #endif private: @@ -93,7 +98,12 @@ namespace WebCore { RefPtr<ChromiumDataObject> m_dataObject; Frame* m_frame; +#if ENABLE(DATA_TRANSFER_ITEMS) + RefPtr<DataTransferItemListChromium> m_itemList; +#endif + uint64_t m_originalSequenceNumber; + bool m_dragStorageUpdated; }; } // namespace WebCore diff --git a/Source/WebCore/platform/chromium/ClipboardChromiumMac.cpp b/Source/WebCore/platform/chromium/ClipboardChromiumPosix.cpp index 38021402e..54cb99458 100644 --- a/Source/WebCore/platform/chromium/ClipboardChromiumMac.cpp +++ b/Source/WebCore/platform/chromium/ClipboardChromiumPosix.cpp @@ -27,43 +27,32 @@ #include "config.h" #include "ClipboardChromium.h" -#include "ChromiumDataObject.h" - namespace WebCore { - - -// Filename length and character-set limits vary by filesystem, and there's no -// real way to tell what filesystem is in use. Since HFS+ is by far the most -// common, we'll abide by its limits, which are 255 Unicode characters (slightly -// simplified; really it uses Normalization Form D, but the differences aren't -// really worth dealing with here.) -static const unsigned MaxHFSFilenameLength = 255; +// On POSIX systems, the typical filename length limit is 255 character units. HFS+'s limit is +// actually 255 Unicode characters using Apple's modification of Normzliation Form D, but the +// differences aren't really worth dealing with here. +static const unsigned maxFilenameLength = 255; static bool isInvalidFileCharacter(UChar c) { - // HFS+ basically allows anything but '/'. For sanity's sake we'll disallow - // control characters. + // HFS+ disallows '/' and Linux systems also disallow null. For sanity's sake we'll also + // disallow control characters. return c < ' ' || c == 0x7F || c == '/'; } -String ClipboardChromium::validateFileName(const String& title, ChromiumDataObject* dataObject) +void ClipboardChromium::validateFilename(String& name, String& extension) { // Remove any invalid file system characters, especially "/". - String result = title.removeCharacters(isInvalidFileCharacter); - String extension = dataObject->fileExtension().removeCharacters(&isInvalidFileCharacter); + name = name.removeCharacters(&isInvalidFileCharacter); + extension = extension.removeCharacters(&isInvalidFileCharacter); // Remove a ridiculously-long extension. - if (extension.length() >= MaxHFSFilenameLength) - extension = ""; - - // Truncate an overly-long filename. - int overflow = result.length() + extension.length() - MaxHFSFilenameLength; - if (overflow > 0) - result.remove(result.length() - overflow, overflow); - - dataObject->setFileExtension(extension); - return result; + if (extension.length() >= maxFilenameLength) + extension = String(); + + // Truncate an overly-long filename, reserving one character for a dot. + name.truncate(maxFilenameLength - extension.length() - 1); } -} // namespace WebCore +} // namespace WebCore diff --git a/Source/WebCore/platform/chromium/ClipboardChromiumWin.cpp b/Source/WebCore/platform/chromium/ClipboardChromiumWin.cpp index d9bbeb5dd..39b5806cd 100644 --- a/Source/WebCore/platform/chromium/ClipboardChromiumWin.cpp +++ b/Source/WebCore/platform/chromium/ClipboardChromiumWin.cpp @@ -27,12 +27,13 @@ #include "config.h" #include "ClipboardChromium.h" -#include "ChromiumDataObject.h" - #include <shlwapi.h> namespace WebCore { +// FAT32 and NTFS both limit filenames to a maximum of 255 characters. +static const unsigned maxFilenameLength = 255; + // Returns true if the specified character is not valid in a file name. This // is intended for use with removeCharacters. static bool isInvalidFileCharacter(UChar c) @@ -40,17 +41,17 @@ static bool isInvalidFileCharacter(UChar c) return (PathGetCharType(c) & (GCT_LFNCHAR | GCT_SHORTCHAR)) == 0; } -String ClipboardChromium::validateFileName(const String& title, ChromiumDataObject* dataObject) +void ClipboardChromium::validateFilename(String& name, String& extension) { // Remove any invalid file system characters. - String result = title.removeCharacters(&isInvalidFileCharacter); - if (result.length() + dataObject->fileExtension().length() + 1 >= MAX_PATH) { - if (dataObject->fileExtension().length() + 1 >= MAX_PATH) - dataObject->setFileExtension(""); - if (result.length() + dataObject->fileExtension().length() + 1 >= MAX_PATH) - result = result.substring(0, MAX_PATH - dataObject->fileExtension().length() - 1); - } - return result; + name = name.removeCharacters(&isInvalidFileCharacter); + extension = extension.removeCharacters(&isInvalidFileCharacter); + + if (extension.length() >= maxFilenameLength) + extension = String(); + + // Truncate overly-long filenames, reserving one character for a dot. + name.truncate(maxFilenameLength - extension.length() - 1); } } // namespace WebCore diff --git a/Source/WebCore/platform/chromium/DataTransferItemChromium.cpp b/Source/WebCore/platform/chromium/DataTransferItemChromium.cpp index a79ae85eb..696ee653e 100644 --- a/Source/WebCore/platform/chromium/DataTransferItemChromium.cpp +++ b/Source/WebCore/platform/chromium/DataTransferItemChromium.cpp @@ -38,6 +38,8 @@ #include "ClipboardChromium.h" #include "ClipboardMimeTypes.h" #include "ClipboardUtilitiesChromium.h" +#include "DataTransferItemListChromium.h" +#include "File.h" #include "PlatformSupport.h" #include "SharedBuffer.h" #include "StringCallback.h" @@ -47,7 +49,7 @@ namespace WebCore { PassRefPtr<DataTransferItemChromium> DataTransferItemChromium::createFromPasteboard(PassRefPtr<Clipboard> owner, ScriptExecutionContext* context, const String& type) { if (type == mimeTypeTextPlain || type == mimeTypeTextHTML) - return adoptRef(new DataTransferItemChromium(owner, context, PasteboardSource, DataTransferItem::kindString, type, "")); + return adoptRef(new DataTransferItemChromium(owner, context, PasteboardSource, DataTransferItem::kindString, type, String())); return adoptRef(new DataTransferItemChromium(owner, context, PasteboardSource, DataTransferItem::kindFile, type, "")); } @@ -56,29 +58,42 @@ PassRefPtr<DataTransferItemChromium> DataTransferItemChromium::create(PassRefPtr const String& data, const String& type) { - return adoptRef(new DataTransferItemChromium(owner, context, InternalSource, DataTransferItem::kindString, type, data)); + return adoptRef(new DataTransferItemChromium(owner, context, DataTransferItemChromium::InternalSource, kindString, type, data)); } -PassRefPtr<DataTransferItem> DataTransferItem::create(PassRefPtr<Clipboard> owner, - ScriptExecutionContext* context, - const String& data, - const String& type) +PassRefPtr<DataTransferItemChromium> DataTransferItemChromium::create(PassRefPtr<Clipboard> owner, + ScriptExecutionContext* context, + PassRefPtr<File> file) { - return DataTransferItemChromium::create(owner, context, data, type); + return adoptRef(new DataTransferItemChromium(owner, context, DataTransferItemChromium::InternalSource, file)); } DataTransferItemChromium::DataTransferItemChromium(PassRefPtr<Clipboard> owner, ScriptExecutionContext* context, DataSource source, const String& kind, const String& type, const String& data) - : DataTransferItem(owner, kind, type) - , m_context(context) + : m_context(context) + , m_owner(owner) + , m_kind(kind) + , m_type(type) , m_source(source) , m_data(data) { } -void DataTransferItemChromium::getAsString(PassRefPtr<StringCallback> callback) +DataTransferItemChromium::DataTransferItemChromium(PassRefPtr<Clipboard> owner, ScriptExecutionContext* context, DataSource source, PassRefPtr<File> file) + : m_context(context) + , m_owner(owner) + , m_kind(kindFile) + , m_type(file.get() ? file->type() : String()) + , m_source(source) + , m_file(file) +{ +} + +void DataTransferItemChromium::getAsString(PassRefPtr<StringCallback> callback) const { - if ((owner()->policy() != ClipboardReadable && owner()->policy() != ClipboardWritable) - || kind() != kindString) + if (kind() != kindString) + return; + + if (clipboardChromium()->storageHasUpdated()) return; if (m_source == InternalSource) { @@ -87,8 +102,6 @@ void DataTransferItemChromium::getAsString(PassRefPtr<StringCallback> callback) } ASSERT(m_source == PasteboardSource); - if (static_cast<ClipboardChromium*>(owner())->platformClipboardChanged()) - return; // This is ugly but there's no real alternative. if (type() == mimeTypeTextPlain) { @@ -106,13 +119,13 @@ void DataTransferItemChromium::getAsString(PassRefPtr<StringCallback> callback) ASSERT_NOT_REACHED(); } -PassRefPtr<Blob> DataTransferItemChromium::getAsFile() +PassRefPtr<Blob> DataTransferItemChromium::getAsFile() const { - if (m_source == InternalSource) + if (kind() != kindFile || clipboardChromium()->storageHasUpdated()) return 0; - if (static_cast<ClipboardChromium*>(owner())->platformClipboardChanged()) - return 0; + if (m_source == InternalSource) + return m_file; ASSERT(m_source == PasteboardSource); if (type() == mimeTypeImagePng) { @@ -136,6 +149,11 @@ PassRefPtr<Blob> DataTransferItemChromium::getAsFile() return 0; } +ClipboardChromium* DataTransferItemChromium::clipboardChromium() const +{ + return static_cast<ClipboardChromium*>(m_owner.get()); +} + } // namespace WebCore #endif // ENABLE(DATA_TRANSFER_ITEMS) diff --git a/Source/WebCore/platform/chromium/DataTransferItemChromium.h b/Source/WebCore/platform/chromium/DataTransferItemChromium.h index 144e40f7c..2a919006b 100644 --- a/Source/WebCore/platform/chromium/DataTransferItemChromium.h +++ b/Source/WebCore/platform/chromium/DataTransferItemChromium.h @@ -40,27 +40,41 @@ namespace WebCore { class Clipboard; +class ClipboardChromium; +class File; class ScriptExecutionContext; class DataTransferItemChromium : public DataTransferItem { public: - static PassRefPtr<DataTransferItemChromium> createFromPasteboard(PassRefPtr<Clipboard> owner, ScriptExecutionContext*, const String& type); static PassRefPtr<DataTransferItemChromium> create(PassRefPtr<Clipboard> owner, ScriptExecutionContext*, const String& data, const String& type); + static PassRefPtr<DataTransferItemChromium> create(PassRefPtr<Clipboard> owner, ScriptExecutionContext*, PassRefPtr<File>); + static PassRefPtr<DataTransferItemChromium> createFromPasteboard(PassRefPtr<Clipboard> owner, ScriptExecutionContext*, const String& type); - virtual void getAsString(PassRefPtr<StringCallback>); - virtual PassRefPtr<Blob> getAsFile(); + virtual String kind() const { return m_kind; } + virtual String type() const { return m_type; } + virtual void getAsString(PassRefPtr<StringCallback>) const; + virtual PassRefPtr<Blob> getAsFile() const; private: + friend class DataTransferItemListChromium; + enum DataSource { PasteboardSource, InternalSource, }; DataTransferItemChromium(PassRefPtr<Clipboard> owner, ScriptExecutionContext*, DataSource, const String& kind, const String& type, const String& data); + DataTransferItemChromium(PassRefPtr<Clipboard> owner, ScriptExecutionContext*, DataSource, PassRefPtr<File>); + + ClipboardChromium* clipboardChromium() const; ScriptExecutionContext* m_context; + const RefPtr<Clipboard> m_owner; + const String m_kind; + const String m_type; const DataSource m_source; const String m_data; + RefPtr<File> m_file; }; } // namespace WebCore diff --git a/Source/WebCore/platform/chromium/DataTransferItemListChromium.cpp b/Source/WebCore/platform/chromium/DataTransferItemListChromium.cpp index 320e74914..3a280fe3b 100644 --- a/Source/WebCore/platform/chromium/DataTransferItemListChromium.cpp +++ b/Source/WebCore/platform/chromium/DataTransferItemListChromium.cpp @@ -33,9 +33,17 @@ #if ENABLE(DATA_TRANSFER_ITEMS) -#include "Clipboard.h" +#include "BlobURL.h" +#include "ChromiumDataObject.h" +#include "ClipboardChromium.h" +#include "ClipboardMimeTypes.h" #include "DataTransferItemChromium.h" #include "ExceptionCode.h" +#include "File.h" +#include "KURL.h" +#include "ScriptExecutionContext.h" +#include "ThreadableBlobRegistry.h" +#include <wtf/text/StringBuilder.h> namespace WebCore { @@ -45,13 +53,116 @@ PassRefPtr<DataTransferItemListChromium> DataTransferItemListChromium::create(Pa } DataTransferItemListChromium::DataTransferItemListChromium(PassRefPtr<Clipboard> owner, ScriptExecutionContext* context) - : DataTransferItemList(owner, context) + : m_owner(owner) + , m_context(context) { } -void DataTransferItemListChromium::addPasteboardItem(const String& type) +size_t DataTransferItemListChromium::length() const { - m_items.append(DataTransferItemChromium::createFromPasteboard(m_owner, m_context, type)); + clipboardChromium()->mayUpdateItems(m_items); + return m_items.size(); +} + +PassRefPtr<DataTransferItem> DataTransferItemListChromium::item(unsigned long index) +{ + clipboardChromium()->mayUpdateItems(m_items); + if (index >= length()) + return 0; + return m_items[index]; +} + +void DataTransferItemListChromium::deleteItem(unsigned long index, ExceptionCode& ec) +{ + clipboardChromium()->mayUpdateItems(m_items); + if (index >= length()) + return; + RefPtr<DataTransferItem> item = m_items[index]; + + RefPtr<ChromiumDataObject> dataObject = clipboardChromium()->dataObject(); + if (!dataObject) + return; + + if (item->kind() == DataTransferItem::kindString) { + m_items.remove(index); + dataObject->clearData(item->type()); + return; + } + + ASSERT(item->kind() == DataTransferItem::kindFile); + RefPtr<Blob> blob = item->getAsFile(); + if (!blob || !blob->isFile()) + return; + + m_items.clear(); + const Vector<String>& filenames = dataObject->filenames(); + Vector<String> copiedFilenames; + for (size_t i = 0; i < filenames.size(); ++i) { + if (filenames[i] != static_cast<File*>(blob.get())->path()) + copiedFilenames.append(static_cast<File*>(blob.get())->path()); + } + dataObject->setFilenames(copiedFilenames); +} + +void DataTransferItemListChromium::clear() +{ + m_items.clear(); + clipboardChromium()->clearAllData(); +} + +void DataTransferItemListChromium::add(const String& data, const String& type, ExceptionCode& ec) +{ + RefPtr<ChromiumDataObject> dataObject = clipboardChromium()->dataObject(); + if (!dataObject) + return; + + bool success = false; + dataObject->getData(type, success); + if (success) { + // Adding data with the same type should fail with NOT_SUPPORTED_ERR. + ec = NOT_SUPPORTED_ERR; + return; + } + + m_items.clear(); + dataObject->setData(type, data); +} + +void DataTransferItemListChromium::add(PassRefPtr<File> file) +{ + if (!file) + return; + + RefPtr<ChromiumDataObject> dataObject = clipboardChromium()->dataObject(); + if (!dataObject) + return; + + m_items.clear(); + + // Updating dataObject's fileset so that we will be seeing the consistent list even if we reconstruct the items later. + dataObject->addFilename(file->path()); + + // FIXME: Allow multiple files to be dragged out at once if more than one file is added to the storage. For now we manually set up drag-out download URL only if it has not been set yet. + bool success = false; + dataObject->getData(mimeTypeDownloadURL, success); + if (success) + return; + + KURL urlForDownload = BlobURL::createPublicURL(m_context->securityOrigin()); + ThreadableBlobRegistry::registerBlobURL(urlForDownload, file->url()); + + StringBuilder downloadUrl; + downloadUrl.append(file->type()); + downloadUrl.append(":"); + downloadUrl.append(encodeWithURLEscapeSequences(file->name())); + downloadUrl.append(":"); + downloadUrl.append(urlForDownload.string()); + dataObject->setData(mimeTypeDownloadURL, downloadUrl.toString()); +} + +ClipboardChromium* DataTransferItemListChromium::clipboardChromium() const +{ + return static_cast<ClipboardChromium*>(m_owner.get()); } } // namespace WebCore diff --git a/Source/WebCore/platform/chromium/DataTransferItemListChromium.h b/Source/WebCore/platform/chromium/DataTransferItemListChromium.h index a3321b5ad..61bd167c7 100644 --- a/Source/WebCore/platform/chromium/DataTransferItemListChromium.h +++ b/Source/WebCore/platform/chromium/DataTransferItemListChromium.h @@ -40,7 +40,8 @@ namespace WebCore { class Clipboard; -class DataTransferItemChromium; +class ClipboardChromium; +class File; class ScriptExecutionContext; typedef int ExceptionCode; @@ -49,12 +50,23 @@ class DataTransferItemListChromium : public DataTransferItemList { public: static PassRefPtr<DataTransferItemListChromium> create(PassRefPtr<Clipboard>, ScriptExecutionContext*); -private: - friend class ClipboardChromium; + virtual size_t length() const; + virtual PassRefPtr<DataTransferItem> item(unsigned long index); + // FIXME: Implement V8DataTransferItemList::indexedPropertyDeleter to get this called. + virtual void deleteItem(unsigned long index, ExceptionCode&); + virtual void clear(); + virtual void add(const String& data, const String& type, ExceptionCode&); + virtual void add(PassRefPtr<File>); +private: DataTransferItemListChromium(PassRefPtr<Clipboard>, ScriptExecutionContext*); + ClipboardChromium* clipboardChromium() const; - virtual void addPasteboardItem(const String& type); + RefPtr<Clipboard> m_owner; + // Indirectly owned by our parent. + ScriptExecutionContext* m_context; + // FIXME: m_items should not be mutable. This will be fixed by https://bugs.webkit.org/show_bug.cgi?id=76598 + mutable Vector<RefPtr<DataTransferItem> > m_items; }; } // namespace WebCore @@ -62,4 +74,3 @@ private: #endif // ENABLE(DATA_TRANSFER_ITEMS) #endif // DataTransferItemListChromium_h - diff --git a/Source/WebCore/platform/chromium/DragDataChromium.cpp b/Source/WebCore/platform/chromium/DragDataChromium.cpp index 9c3838602..3d94a19b2 100644 --- a/Source/WebCore/platform/chromium/DragDataChromium.cpp +++ b/Source/WebCore/platform/chromium/DragDataChromium.cpp @@ -50,14 +50,14 @@ static bool containsHTML(const ChromiumDataObject* dropData) bool DragData::containsURL(Frame*, FilenameConversionPolicy filenamePolicy) const { - return m_platformDragData->types().contains(mimeTypeURL) + return m_platformDragData->types().contains(mimeTypeTextURIList) || (filenamePolicy == ConvertFilenames && m_platformDragData->containsFilenames()); } String DragData::asURL(Frame*, FilenameConversionPolicy filenamePolicy, String* title) const { String url; - if (m_platformDragData->types().contains(mimeTypeURL)) { + if (m_platformDragData->types().contains(mimeTypeTextURIList)) { bool ignoredSuccess; url = m_platformDragData->getData(mimeTypeURL, ignoredSuccess); if (title) @@ -109,7 +109,7 @@ bool DragData::canSmartReplace() const // ClipboardWin::writeRange is called). For example, dragging a link // should not result in a space being added. return m_platformDragData->types().contains(mimeTypeTextPlain) - && !m_platformDragData->types().contains(mimeTypeURL); + && !m_platformDragData->types().contains(mimeTypeTextURIList); } bool DragData::containsCompatibleContent() const diff --git a/Source/WebCore/platform/chromium/LanguageChromium.cpp b/Source/WebCore/platform/chromium/LanguageChromium.cpp index 93af1a946..d23f19cf1 100644 --- a/Source/WebCore/platform/chromium/LanguageChromium.cpp +++ b/Source/WebCore/platform/chromium/LanguageChromium.cpp @@ -33,10 +33,11 @@ #include "PlatformString.h" #include "PlatformSupport.h" +#include <wtf/Vector.h> namespace WebCore { -String platformDefaultLanguage() +static String platformLanguage() { DEFINE_STATIC_LOCAL(String, computedDefaultLanguage, ()); if (computedDefaultLanguage.isEmpty()) @@ -44,4 +45,11 @@ String platformDefaultLanguage() return computedDefaultLanguage; } +Vector<String> platformUserPreferredLanguages() +{ + Vector<String> userPreferredLanguages; + userPreferredLanguages.append(platformLanguage()); + return userPreferredLanguages; +} + } // namespace WebCore diff --git a/Source/WebCore/platform/chromium/PlatformScreenChromium.cpp b/Source/WebCore/platform/chromium/PlatformScreenChromium.cpp index 44df3213f..e0553b930 100644 --- a/Source/WebCore/platform/chromium/PlatformScreenChromium.cpp +++ b/Source/WebCore/platform/chromium/PlatformScreenChromium.cpp @@ -31,6 +31,7 @@ #include "config.h" #include "PlatformScreen.h" +#include "FrameView.h" #include "IntRect.h" #include "PlatformSupport.h" @@ -61,19 +62,14 @@ bool screenIsMonochrome(Widget* widget) return PlatformSupport::screenIsMonochrome(widget); } -FloatRect screenRect(Widget* widget) +FloatRect screenRect(FrameView* frameView) { - return PlatformSupport::screenRect(widget); + return PlatformSupport::screenRect(frameView); } -FloatRect screenAvailableRect(Widget* widget) +FloatRect screenAvailableRect(FrameView* frameView) { - return PlatformSupport::screenAvailableRect(widget); -} - -double screenRefreshRate(Widget* widget) -{ - return PlatformSupport::screenRefreshRate(widget); + return PlatformSupport::screenAvailableRect(frameView); } } // namespace WebCore diff --git a/Source/WebCore/platform/chromium/PlatformSupport.h b/Source/WebCore/platform/chromium/PlatformSupport.h index c8ded6e26..1f396c5d3 100644 --- a/Source/WebCore/platform/chromium/PlatformSupport.h +++ b/Source/WebCore/platform/chromium/PlatformSupport.h @@ -71,6 +71,7 @@ class Color; class Cursor; class Document; class Frame; +class FrameView; class GamepadList; class GeolocationServiceBridge; class GeolocationServiceChromium; @@ -245,9 +246,8 @@ public: static int screenDepth(Widget*); static int screenDepthPerComponent(Widget*); static bool screenIsMonochrome(Widget*); - static IntRect screenRect(Widget*); - static IntRect screenAvailableRect(Widget*); - static double screenRefreshRate(Widget*); + static IntRect screenRect(FrameView*); + static IntRect screenAvailableRect(FrameView*); // SharedTimers ------------------------------------------------------- static void setSharedTimerFiredFunction(void (*func)()); diff --git a/Source/WebCore/platform/efl/LanguageEfl.cpp b/Source/WebCore/platform/efl/LanguageEfl.cpp index efed862fb..e6c1a7259 100644 --- a/Source/WebCore/platform/efl/LanguageEfl.cpp +++ b/Source/WebCore/platform/efl/LanguageEfl.cpp @@ -32,10 +32,11 @@ #include "PlatformString.h" #include <locale.h> +#include <wtf/Vector.h> namespace WebCore { -String platformDefaultLanguage() +static String platformLanguage() { char* localeDefault = setlocale(LC_CTYPE, 0); @@ -50,4 +51,11 @@ String platformDefaultLanguage() return String(localeDefault); } +Vector<String> platformUserPreferredLanguages() +{ + Vector<String> userPreferredLanguages; + userPreferredLanguages.append(platformLanguage()); + return userPreferredLanguages; +} + } diff --git a/Source/WebCore/platform/efl/LocalizedStringsEfl.cpp b/Source/WebCore/platform/efl/LocalizedStringsEfl.cpp index ae530c1d9..27240e82b 100644 --- a/Source/WebCore/platform/efl/LocalizedStringsEfl.cpp +++ b/Source/WebCore/platform/efl/LocalizedStringsEfl.cpp @@ -113,6 +113,11 @@ String contextMenuItemTagCopyImageToClipboard() return String::fromUTF8("Copy Image"); } +String contextMenuItemTagCopyImageUrlToClipboard() +{ + return String::fromUTF8("Copy Image Address"); +} + String contextMenuItemTagOpenVideoInNewWindow() { return String::fromUTF8("Open Video in New Window"); diff --git a/Source/WebCore/platform/efl/PlatformScreenEfl.cpp b/Source/WebCore/platform/efl/PlatformScreenEfl.cpp index fac959723..f30d23da7 100644 --- a/Source/WebCore/platform/efl/PlatformScreenEfl.cpp +++ b/Source/WebCore/platform/efl/PlatformScreenEfl.cpp @@ -34,6 +34,7 @@ #include "config.h" #include "PlatformScreen.h" +#include "FrameView.h" #include "NotImplemented.h" #include "PlatformString.h" #include "Widget.h" @@ -73,23 +74,23 @@ bool screenIsMonochrome(Widget*) return false; } -FloatRect screenRect(Widget* widget) +FloatRect screenRect(FrameView* frameView) { - if (!widget) + if (!frameView) return FloatRect(); int x, y, w, h; - Evas* e = widget->evas(); + Evas* e = frameView->evas(); ecore_evas_screen_geometry_get(ecore_evas_ecore_evas_get(e), &x, &y, &w, &h); return FloatRect(x, y, w, h); } -FloatRect screenAvailableRect(Widget* widget) +FloatRect screenAvailableRect(FrameView* frameView) { notImplemented(); - return screenRect(widget); + return screenRect(frameView); } } diff --git a/Source/WebCore/platform/graphics/BitmapImage.h b/Source/WebCore/platform/graphics/BitmapImage.h index f4d50ce75..00802f69f 100644 --- a/Source/WebCore/platform/graphics/BitmapImage.h +++ b/Source/WebCore/platform/graphics/BitmapImage.h @@ -34,11 +34,7 @@ #if PLATFORM(MAC) #include <wtf/RetainPtr.h> -#ifdef __OBJC__ -@class NSImage; -#else -class NSImage; -#endif +OBJC_CLASS NSImage; #endif #if PLATFORM(WIN) diff --git a/Source/WebCore/platform/graphics/CrossfadeGeneratedImage.h b/Source/WebCore/platform/graphics/CrossfadeGeneratedImage.h index ade2e5bd7..eb06b6d8b 100644 --- a/Source/WebCore/platform/graphics/CrossfadeGeneratedImage.h +++ b/Source/WebCore/platform/graphics/CrossfadeGeneratedImage.h @@ -43,6 +43,13 @@ public: return adoptRef(new CrossfadeGeneratedImage(fromImage, toImage, percentage, crossfadeSize, size)); } + virtual void setContainerSize(const IntSize&) { } + virtual bool usesContainerSize() const { return false; } + virtual bool hasRelativeWidth() const { return false; } + virtual bool hasRelativeHeight() const { return false; } + + virtual IntSize size() const { return m_crossfadeSize; } + protected: virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& dstRect); diff --git a/Source/WebCore/platform/graphics/FloatRect.cpp b/Source/WebCore/platform/graphics/FloatRect.cpp index fa9045c0b..595af2a32 100644 --- a/Source/WebCore/platform/graphics/FloatRect.cpp +++ b/Source/WebCore/platform/graphics/FloatRect.cpp @@ -103,30 +103,30 @@ void FloatRect::unite(const FloatRect& other) return; } - float l = min(x(), other.x()); - float t = min(y(), other.y()); - float r = max(maxX(), other.maxX()); - float b = max(maxY(), other.maxY()); + uniteEvenIfEmpty(other); +} - setLocationAndSizeFromEdges(l, t, r, b); +void FloatRect::uniteEvenIfEmpty(const FloatRect& other) +{ + float minX = min(x(), other.x()); + float minY = min(y(), other.y()); + float maxX = max(this->maxX(), other.maxX()); + float maxY = max(this->maxY(), other.maxY()); + + setLocationAndSizeFromEdges(minX, minY, maxX, maxY); } void FloatRect::uniteIfNonZero(const FloatRect& other) { // Handle empty special cases first. - if (!other.width() && !other.height()) + if (other.isZero()) return; - if (!width() && !height()) { + if (isZero()) { *this = other; return; } - float left = min(x(), other.x()); - float top = min(y(), other.y()); - float right = max(maxX(), other.maxX()); - float bottom = max(maxY(), other.maxY()); - - setLocationAndSizeFromEdges(left, top, right, bottom); + uniteEvenIfEmpty(other); } void FloatRect::scale(float sx, float sy) @@ -218,6 +218,19 @@ IntRect enclosingIntRect(const FloatRect& rect) clampToInteger(width), clampToInteger(height)); } +IntRect enclosedIntRect(const FloatRect& rect) +{ + int x = clampToInteger(ceilf(rect.x())); + int y = clampToInteger(ceilf(rect.y())); + float maxX = clampToInteger(floorf(rect.maxX())); + float maxY = clampToInteger(floorf(rect.maxY())); + // A rect of width 0 should not become a rect of width -1 due to ceil/floor. + int width = max(clampToInteger(maxX - x), 0); + int height = max(clampToInteger(maxY - y), 0); + + return IntRect(x, y, width, height); +} + FloatRect mapRect(const FloatRect& r, const FloatRect& srcRect, const FloatRect& destRect) { if (srcRect.width() == 0 || srcRect.height() == 0) diff --git a/Source/WebCore/platform/graphics/FloatRect.h b/Source/WebCore/platform/graphics/FloatRect.h index ae6c23a7d..22c171c5a 100644 --- a/Source/WebCore/platform/graphics/FloatRect.h +++ b/Source/WebCore/platform/graphics/FloatRect.h @@ -152,6 +152,7 @@ public: void intersect(const FloatRect&); void unite(const FloatRect&); + void uniteEvenIfEmpty(const FloatRect&); void uniteIfNonZero(const FloatRect&); // Note, this doesn't match what IntRect::contains(IntPoint&) does; the int version @@ -269,6 +270,9 @@ inline bool operator!=(const FloatRect& a, const FloatRect& b) IntRect enclosingIntRect(const FloatRect&); +// Returns a valid IntRect contained within the given FloatRect. +IntRect enclosedIntRect(const FloatRect&); + // Map rect r from srcRect to an equivalent rect in destRect. FloatRect mapRect(const FloatRect& r, const FloatRect& srcRect, const FloatRect& destRect); diff --git a/Source/WebCore/platform/graphics/Font.h b/Source/WebCore/platform/graphics/Font.h index 9a7a86213..d15a77f3c 100644 --- a/Source/WebCore/platform/graphics/Font.h +++ b/Source/WebCore/platform/graphics/Font.h @@ -129,6 +129,17 @@ public: break; } + switch (m_fontDescription.commonLigaturesState()) { + case FontDescription::DisabledLigaturesState: + features &= ~Ligatures; + break; + case FontDescription::EnabledLigaturesState: + features |= Ligatures; + break; + case FontDescription::NormalLigaturesState: + break; + } + return features; } @@ -171,6 +182,7 @@ public: static bool shouldUseSmoothing(); enum CodePath { Auto, Simple, Complex, SimpleWithGlyphOverflow }; + CodePath codePath(const TextRun&) const; private: enum ForTextEmphasisOrNot { NotForTextEmphasis, ForTextEmphasis }; @@ -191,8 +203,6 @@ private: static bool canReturnFallbackFontsForComplexText(); static bool canExpandAroundIdeographsInComplexText(); - CodePath codePath(const TextRun&) const; - // Returns the initial in-stream advance. float getGlyphsAndAdvancesForComplexText(const TextRun&, int from, int to, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const; void drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; diff --git a/Source/WebCore/platform/graphics/FontDescription.h b/Source/WebCore/platform/graphics/FontDescription.h index 51a257b41..e8329763d 100644 --- a/Source/WebCore/platform/graphics/FontDescription.h +++ b/Source/WebCore/platform/graphics/FontDescription.h @@ -74,6 +74,8 @@ public: enum Kerning { AutoKerning, NormalKerning, NoneKerning }; + enum LigaturesState { NormalLigaturesState, DisabledLigaturesState, EnabledLigaturesState }; + FontDescription() : m_specifiedSize(0) , m_computedSize(0) @@ -88,6 +90,9 @@ public: , m_usePrinterFont(false) , m_renderingMode(NormalRenderingMode) , m_kerning(AutoKerning) + , m_commonLigaturesState(NormalLigaturesState) + , m_discretionaryLigaturesState(NormalLigaturesState) + , m_historicalLigaturesState(NormalLigaturesState) , m_keywordSize(0) , m_fontSmoothing(AutoSmoothing) , m_textRendering(AutoTextRendering) @@ -116,6 +121,9 @@ public: bool useFixedDefaultSize() const { return genericFamily() == MonospaceFamily && !family().next() && family().family() == monospaceFamily; } FontRenderingMode renderingMode() const { return static_cast<FontRenderingMode>(m_renderingMode); } Kerning kerning() const { return static_cast<Kerning>(m_kerning); } + LigaturesState commonLigaturesState() const { return static_cast<LigaturesState>(m_commonLigaturesState); } + LigaturesState discretionaryLigaturesState() const { return static_cast<LigaturesState>(m_discretionaryLigaturesState); } + LigaturesState historicalLigaturesState() const { return static_cast<LigaturesState>(m_historicalLigaturesState); } unsigned keywordSize() const { return m_keywordSize; } FontSmoothingMode fontSmoothing() const { return static_cast<FontSmoothingMode>(m_fontSmoothing); } TextRenderingMode textRenderingMode() const { return static_cast<TextRenderingMode>(m_textRendering); } @@ -146,6 +154,9 @@ public: #endif void setRenderingMode(FontRenderingMode mode) { m_renderingMode = mode; } void setKerning(Kerning kerning) { m_kerning = kerning; } + void setCommonLigaturesState(LigaturesState commonLigaturesState) { m_commonLigaturesState = commonLigaturesState; } + void setDiscretionaryLigaturesState(LigaturesState discretionaryLigaturesState) { m_discretionaryLigaturesState = discretionaryLigaturesState; } + void setHistoricalLigaturesState(LigaturesState historicalLigaturesState) { m_historicalLigaturesState = historicalLigaturesState; } void setKeywordSize(unsigned s) { m_keywordSize = s; } void setFontSmoothing(FontSmoothingMode smoothing) { m_fontSmoothing = smoothing; } void setTextRenderingMode(TextRenderingMode rendering) { m_textRendering = rendering; } @@ -180,6 +191,10 @@ private: unsigned m_renderingMode : 1; // Used to switch between CG and GDI text on Windows. unsigned m_kerning : 2; // Kerning + unsigned m_commonLigaturesState : 2; + unsigned m_discretionaryLigaturesState : 2; + unsigned m_historicalLigaturesState : 2; + unsigned m_keywordSize : 4; // We cache whether or not a font is currently represented by a CSS keyword (e.g., medium). If so, // then we can accurately translate across different generic families to adjust for different preference settings // (e.g., 13px monospace vs. 16px everything else). Sizes are 1-8 (like the HTML size values for <font>). @@ -203,6 +218,9 @@ inline bool FontDescription::operator==(const FontDescription& other) const && m_usePrinterFont == other.m_usePrinterFont && m_renderingMode == other.m_renderingMode && m_kerning == other.m_kerning + && m_commonLigaturesState == other.m_commonLigaturesState + && m_discretionaryLigaturesState == other.m_discretionaryLigaturesState + && m_historicalLigaturesState == other.m_historicalLigaturesState && m_keywordSize == other.m_keywordSize && m_fontSmoothing == other.m_fontSmoothing && m_textRendering == other.m_textRendering diff --git a/Source/WebCore/platform/graphics/FontFastPath.cpp b/Source/WebCore/platform/graphics/FontFastPath.cpp index 02b695b1c..3ae0ad581 100644 --- a/Source/WebCore/platform/graphics/FontFastPath.cpp +++ b/Source/WebCore/platform/graphics/FontFastPath.cpp @@ -379,6 +379,10 @@ void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRu void Font::drawGlyphBuffer(GraphicsContext* context, const TextRun& run, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const { +#if !ENABLE(SVG_FONTS) + UNUSED_PARAM(run); +#endif + // Draw each contiguous run of glyphs that use the same font data. const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); FloatSize offset = glyphBuffer.offsetAt(0); diff --git a/Source/WebCore/platform/graphics/FontPlatformData.h b/Source/WebCore/platform/graphics/FontPlatformData.h index 1fcba312f..705c58897 100644 --- a/Source/WebCore/platform/graphics/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/FontPlatformData.h @@ -55,11 +55,7 @@ #endif #if OS(DARWIN) -#ifdef __OBJC__ -@class NSFont; -#else -class NSFont; -#endif +OBJC_CLASS NSFont; typedef struct CGFont* CGFontRef; typedef const struct __CTFont* CTFontRef; diff --git a/Source/WebCore/platform/graphics/GraphicsContext3D.h b/Source/WebCore/platform/graphics/GraphicsContext3D.h index e4f69d8aa..34c549ab4 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext3D.h +++ b/Source/WebCore/platform/graphics/GraphicsContext3D.h @@ -50,13 +50,8 @@ #if PLATFORM(MAC) #include <OpenGL/OpenGL.h> #include <wtf/RetainPtr.h> -#ifdef __OBJC__ -@class CALayer; -@class WebGLLayer; -#else -class CALayer; -class WebGLLayer; -#endif +OBJC_CLASS CALayer; +OBJC_CLASS WebGLLayer; #elif PLATFORM(QT) QT_BEGIN_NAMESPACE class QPainter; @@ -459,7 +454,14 @@ public: virtual ~ContextLostCallback() {} }; + class ErrorMessageCallback { + public: + virtual void onErrorMessage(const String& message, GC3Dint id) = 0; + virtual ~ErrorMessageCallback() { } + }; + void setContextLostCallback(PassOwnPtr<ContextLostCallback>); + void setErrorMessageCallback(PassOwnPtr<ErrorMessageCallback>); static PassRefPtr<GraphicsContext3D> create(Attributes, HostWindow*, RenderStyle = RenderOffscreen); ~GraphicsContext3D(); diff --git a/Source/WebCore/platform/graphics/GraphicsLayer.cpp b/Source/WebCore/platform/graphics/GraphicsLayer.cpp index 3b884f546..c7a22755b 100644 --- a/Source/WebCore/platform/graphics/GraphicsLayer.cpp +++ b/Source/WebCore/platform/graphics/GraphicsLayer.cpp @@ -30,6 +30,8 @@ #include "GraphicsLayer.h" #include "FloatPoint.h" +#include "GraphicsContext.h" +#include "LayoutTypes.h" #include "RotateTransformOperation.h" #include "TextStream.h" #include <wtf/text/CString.h> @@ -261,6 +263,17 @@ void GraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer) m_replicaLayer = layer; } +void GraphicsLayer::setOffsetFromRenderer(const IntSize& offset) +{ + if (offset == m_offsetFromRenderer) + return; + + m_offsetFromRenderer = offset; + + // If the compositing layer offset changes, we need to repaint. + setNeedsDisplay(); +} + void GraphicsLayer::setBackgroundColor(const Color& color) { m_backgroundColor = color; @@ -278,8 +291,15 @@ void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const I #ifndef NDEBUG s_inPaintContents = true; #endif - if (m_client) - m_client->paintContents(this, context, m_paintingPhase, clip); + if (m_client) { + LayoutSize offset = offsetFromRenderer(); + context.translate(-offset); + + LayoutRect clipRect(clip); + clipRect.move(offset); + + m_client->paintContents(this, context, m_paintingPhase, clipRect); + } #ifndef NDEBUG s_inPaintContents = false; #endif @@ -306,7 +326,11 @@ void GraphicsLayer::updateDebugIndicators() { if (GraphicsLayer::showDebugBorders()) { if (drawsContent()) { - if (m_usingTiledLayer) + // FIXME: It's weird to ask the client if this layer is a tile cache layer. + // Maybe we should just cache that information inside GraphicsLayer? + if (m_client->shouldUseTileCache(this)) // tile cache layer: dark blue + setDebugBorder(Color(0, 0, 128, 128), 0.5); + else if (m_usingTiledLayer) setDebugBorder(Color(255, 128, 0, 128), 2); // tiled layer: orange else setDebugBorder(Color(0, 128, 32, 128), 2); // normal layer: green @@ -365,16 +389,14 @@ static inline const TransformOperations* operationsAt(const KeyframeValueList& v return static_cast<const TransformAnimationValue*>(valueList.at(index))->value(); } -void GraphicsLayer::fetchTransformOperationList(const KeyframeValueList& valueList, TransformOperationList& list, bool& isValid, bool& hasBigRotation) +int GraphicsLayer::validateTransformOperations(const KeyframeValueList& valueList, bool& hasBigRotation) { ASSERT(valueList.property() == AnimatedPropertyWebkitTransform); - list.clear(); - isValid = false; hasBigRotation = false; if (valueList.size() < 2) - return; + return -1; // Empty transforms match anything, so find the first non-empty entry as the reference. size_t firstIndex = 0; @@ -384,7 +406,7 @@ void GraphicsLayer::fetchTransformOperationList(const KeyframeValueList& valueLi } if (firstIndex >= valueList.size()) - return; + return -1; const TransformOperations* firstVal = operationsAt(valueList, firstIndex); @@ -397,19 +419,15 @@ void GraphicsLayer::fetchTransformOperationList(const KeyframeValueList& valueLi continue; if (!firstVal->operationsMatch(*val)) - return; + return -1; } - // Keyframes are valid, fill in the list. - isValid = true; - + // Keyframes are valid, check for big rotations. double lastRotAngle = 0.0; double maxRotAngle = -1.0; - list.resize(firstVal->operations().size()); for (size_t j = 0; j < firstVal->operations().size(); ++j) { TransformOperation::OperationType type = firstVal->operations().at(j)->getOperationType(); - list[j] = type; // if this is a rotation entry, we need to see if any angle differences are >= 180 deg if (type == TransformOperation::ROTATE_X || @@ -433,6 +451,8 @@ void GraphicsLayer::fetchTransformOperationList(const KeyframeValueList& valueLi } hasBigRotation = maxRotAngle >= 180.0; + + return firstIndex; } diff --git a/Source/WebCore/platform/graphics/GraphicsLayer.h b/Source/WebCore/platform/graphics/GraphicsLayer.h index 0b60be108..9f75624ff 100644 --- a/Source/WebCore/platform/graphics/GraphicsLayer.h +++ b/Source/WebCore/platform/graphics/GraphicsLayer.h @@ -44,11 +44,7 @@ #include <wtf/PassOwnPtr.h> #if PLATFORM(MAC) -#ifdef __OBJC__ -@class CALayer; -#else -class CALayer; -#endif +OBJC_CLASS CALayer; typedef CALayer PlatformLayer; #elif PLATFORM(WIN) typedef struct _CACFLayer PlatformLayer; @@ -258,7 +254,7 @@ public: // Offset is origin of the renderer minus origin of the graphics layer (so either zero or negative). IntSize offsetFromRenderer() const { return m_offsetFromRenderer; } - void setOffsetFromRenderer(const IntSize& offset) { m_offsetFromRenderer = offset; } + void setOffsetFromRenderer(const IntSize&); // The position of the layer (the location of its top-left corner in its parent) const FloatPoint& position() const { return m_position; } @@ -374,8 +370,8 @@ public: virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation) { m_contentsOrientation = orientation; } CompositingCoordinatesOrientation contentsOrientation() const { return m_contentsOrientation; } - bool showDebugBorders() const { return m_client ? m_client->showDebugBorders() : false; } - bool showRepaintCounter() const { return m_client ? m_client->showRepaintCounter() : false; } + bool showDebugBorders() const { return m_client ? m_client->showDebugBorders(this) : false; } + bool showRepaintCounter() const { return m_client ? m_client->showRepaintCounter(this) : false; } void updateDebugIndicators(); @@ -412,6 +408,9 @@ public: bool usingTiledLayer() const { return m_usingTiledLayer; } + // Called whenever the visible rect of the given GraphicsLayer changed. + virtual void visibleRectChanged() { } + #if PLATFORM(QT) || PLATFORM(GTK) // This allows several alternative GraphicsLayer implementations in the same port, // e.g. if a different GraphicsLayer implementation is needed in WebKit1 vs. WebKit2. @@ -420,11 +419,19 @@ public: #endif protected: +#if ENABLE(CSS_FILTERS) + // This method is used by platform GraphicsLayer classes to clear the filters + // when compositing is not done in hardware. It is not virtual, so the caller + // needs to notifiy the change to the platform layer as needed. + void clearFilters() { m_filters.clear(); } +#endif - typedef Vector<TransformOperation::OperationType> TransformOperationList; - // Given a list of TransformAnimationValues, return an array of transform operations. - // On return, if hasBigRotation is true, functions contain rotations of >= 180 degrees - static void fetchTransformOperationList(const KeyframeValueList&, TransformOperationList&, bool& isValid, bool& hasBigRotation); + // Given a list of TransformAnimationValues, see if all the operations for each keyframe match. If so + // return the index of the KeyframeValueList entry that has that list of operations (it may not be + // the first entry because some keyframes might have an empty transform and those match any list). + // If the lists don't match return -1. On return, if hasBigRotation is true, functions contain + // rotations of >= 180 degrees + static int validateTransformOperations(const KeyframeValueList&, bool& hasBigRotation); virtual void setOpacityInternal(float) { } diff --git a/Source/WebCore/platform/graphics/GraphicsLayerClient.h b/Source/WebCore/platform/graphics/GraphicsLayerClient.h index d9338265c..81272ddbe 100644 --- a/Source/WebCore/platform/graphics/GraphicsLayerClient.h +++ b/Source/WebCore/platform/graphics/GraphicsLayerClient.h @@ -71,8 +71,8 @@ public: // Page scale factor. virtual float pageScaleFactor() const { return 1; } - virtual bool showDebugBorders() const = 0; - virtual bool showRepaintCounter() const = 0; + virtual bool showDebugBorders(const GraphicsLayer*) const = 0; + virtual bool showRepaintCounter(const GraphicsLayer*) const = 0; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/GraphicsTypes.h b/Source/WebCore/platform/graphics/GraphicsTypes.h index 1a07f0083..e6596d95c 100644 --- a/Source/WebCore/platform/graphics/GraphicsTypes.h +++ b/Source/WebCore/platform/graphics/GraphicsTypes.h @@ -30,9 +30,6 @@ namespace WebCore { - // Note: These constants exactly match the NSCompositeOperator constants of - // AppKit on Mac OS X Tiger. If these ever change, we'll need to change the - // Mac OS X Tiger platform code to map one to the other. enum CompositeOperator { CompositeClear, CompositeCopy, @@ -46,7 +43,8 @@ namespace WebCore { CompositeDestinationAtop, CompositeXOR, CompositePlusDarker, - CompositePlusLighter + CompositePlusLighter, + CompositeDifference }; enum GradientSpreadMethod { diff --git a/Source/WebCore/platform/graphics/Icon.h b/Source/WebCore/platform/graphics/Icon.h index 279713331..781a08cb2 100644 --- a/Source/WebCore/platform/graphics/Icon.h +++ b/Source/WebCore/platform/graphics/Icon.h @@ -28,11 +28,7 @@ #if PLATFORM(MAC) #include <wtf/RetainPtr.h> -#ifdef __OBJC__ -@class NSImage; -#else -class NSImage; -#endif +OBJC_CLASS NSImage; #elif PLATFORM(WIN) typedef struct HICON__* HICON; #elif PLATFORM(QT) diff --git a/Source/WebCore/platform/graphics/Image.h b/Source/WebCore/platform/graphics/Image.h index 21b37d357..b78fc7d81 100644 --- a/Source/WebCore/platform/graphics/Image.h +++ b/Source/WebCore/platform/graphics/Image.h @@ -39,11 +39,7 @@ #include <wtf/text/WTFString.h> #if PLATFORM(MAC) -#ifdef __OBJC__ -@class NSImage; -#else -class NSImage; -#endif +OBJC_CLASS NSImage; #endif #if USE(CG) diff --git a/Source/WebCore/platform/graphics/ImageBuffer.h b/Source/WebCore/platform/graphics/ImageBuffer.h index 13070004c..ebc5bfa52 100644 --- a/Source/WebCore/platform/graphics/ImageBuffer.h +++ b/Source/WebCore/platform/graphics/ImageBuffer.h @@ -68,14 +68,19 @@ namespace WebCore { DontCopyBackingStore // Subsequent draws may affect the copy. }; + enum DeferralMode { + NonDeferred, + Deferred + }; + class ImageBuffer { WTF_MAKE_NONCOPYABLE(ImageBuffer); WTF_MAKE_FAST_ALLOCATED; public: // Will return a null pointer on allocation failure. - static PassOwnPtr<ImageBuffer> create(const IntSize& size, ColorSpace colorSpace = ColorSpaceDeviceRGB, RenderingMode renderingMode = Unaccelerated) + static PassOwnPtr<ImageBuffer> create(const IntSize& size, ColorSpace colorSpace = ColorSpaceDeviceRGB, RenderingMode renderingMode = Unaccelerated, DeferralMode deferralMode = NonDeferred) { bool success = false; - OwnPtr<ImageBuffer> buf = adoptPtr(new ImageBuffer(size, colorSpace, renderingMode, success)); + OwnPtr<ImageBuffer> buf = adoptPtr(new ImageBuffer(size, colorSpace, renderingMode, deferralMode, success)); if (success) return buf.release(); return nullptr; @@ -143,7 +148,7 @@ namespace WebCore { // This constructor will place its success into the given out-variable // so that create() knows when it should return failure. - ImageBuffer(const IntSize&, ColorSpace, RenderingMode, bool& success); + ImageBuffer(const IntSize&, ColorSpace, RenderingMode, DeferralMode, bool& success); }; #if USE(CG) || USE(SKIA) diff --git a/Source/WebCore/platform/graphics/MediaPlayer.cpp b/Source/WebCore/platform/graphics/MediaPlayer.cpp index 95ce0c553..54d7d7527 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.cpp +++ b/Source/WebCore/platform/graphics/MediaPlayer.cpp @@ -394,8 +394,10 @@ void MediaPlayer::loadWithNextMediaEngine(MediaPlayerFactory* current) m_private->load(m_url); else { m_private = createNullMediaPlayer(this); - if (m_mediaPlayerClient) + if (m_mediaPlayerClient) { m_mediaPlayerClient->mediaPlayerEngineUpdated(this); + m_mediaPlayerClient->mediaPlayerResourceNotSupported(this); + } } } diff --git a/Source/WebCore/platform/graphics/MediaPlayer.h b/Source/WebCore/platform/graphics/MediaPlayer.h index da53de152..26ca3aada 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.h +++ b/Source/WebCore/platform/graphics/MediaPlayer.h @@ -46,13 +46,9 @@ #include "GraphicsLayer.h" #endif -#ifdef __OBJC__ -@class AVPlayer; -@class QTMovie; -#else -class AVPlayer; -class QTMovie; -#endif +OBJC_CLASS AVPlayer; +OBJC_CLASS QTMovie; + class AVCFPlayer; class QTMovieGWorld; class QTMovieVisualContext; @@ -139,6 +135,9 @@ public: // element to an <embed> in standalone documents virtual void mediaPlayerSawUnsupportedTracks(MediaPlayer*) { } + // The MediaPlayer could not discover an engine which supports the requested resource. + virtual void mediaPlayerResourceNotSupported(MediaPlayer*) { } + // Presentation-related methods // a new frame of video is available virtual void mediaPlayerRepaint(MediaPlayer*) { } diff --git a/Source/WebCore/platform/graphics/Path.h b/Source/WebCore/platform/graphics/Path.h index d14d90879..69ba93ef6 100644 --- a/Source/WebCore/platform/graphics/Path.h +++ b/Source/WebCore/platform/graphics/Path.h @@ -146,9 +146,9 @@ namespace WebCore { void apply(void* info, PathApplierFunction) const; void transform(const AffineTransform&); - private: void addBeziersForRoundedRect(const FloatRect&, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius); + private: PlatformPathPtr m_path; }; diff --git a/Source/WebCore/platform/graphics/SVGGlyph.cpp b/Source/WebCore/platform/graphics/SVGGlyph.cpp index d5b7b9875..668134409 100644 --- a/Source/WebCore/platform/graphics/SVGGlyph.cpp +++ b/Source/WebCore/platform/graphics/SVGGlyph.cpp @@ -80,7 +80,7 @@ static inline SVGGlyph::ArabicForm processArabicFormDetection(const UChar& curCh return curForm; } -Vector<SVGGlyph::ArabicForm> charactersWithArabicForm(const String& input, bool mirror) +Vector<SVGGlyph::ArabicForm> charactersWithArabicForm(const String& input, bool rtl) { Vector<SVGGlyph::ArabicForm> forms; unsigned length = input.length(); @@ -99,7 +99,7 @@ Vector<SVGGlyph::ArabicForm> charactersWithArabicForm(const String& input, bool bool lastCharShapesRight = false; // Start identifying arabic forms - if (mirror) { + if (rtl) { for (int i = length - 1; i >= 0; --i) forms.prepend(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.first())); } else { diff --git a/Source/WebCore/platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp b/Source/WebCore/platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp index 29ebbeeac..32c85cd8f 100644 --- a/Source/WebCore/platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp +++ b/Source/WebCore/platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp @@ -160,6 +160,7 @@ private: virtual bool platformCALayerContentsOpaque() const { return false; } virtual bool platformCALayerDrawsContent() const { return false; } virtual void platformCALayerLayerDidDisplay(PlatformLayer*) { } + virtual void platformCALayerDidCreateTiles() { } AVFWrapper* m_parent; }; diff --git a/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h b/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h index 7fd2465dc..dcc046d07 100644 --- a/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h +++ b/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h @@ -30,20 +30,14 @@ #include "MediaPlayerPrivateAVFoundation.h" -#ifdef __OBJC__ -@class AVAsset; -@class AVPlayer; -@class AVPlayerItem; -@class AVPlayerLayer; -@class AVAssetImageGenerator; -@class WebCoreAVFMovieObserver; -#else -class AVAsset; -class AVPlayer; -class AVPlayerItem; -class AVPlayerLayer; -class AVAssetImageGenerator; -class WebCoreAVFMovieObserver; +OBJC_CLASS AVAsset; +OBJC_CLASS AVPlayer; +OBJC_CLASS AVPlayerItem; +OBJC_CLASS AVPlayerLayer; +OBJC_CLASS AVAssetImageGenerator; +OBJC_CLASS WebCoreAVFMovieObserver; + +#ifndef __OBJC__ typedef struct objc_object *id; #endif diff --git a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp index e73272ded..ad3ac04a2 100644 --- a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp +++ b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp @@ -569,12 +569,19 @@ void GraphicsLayerCA::setOpacity(float opacity) } #if ENABLE(CSS_FILTERS) -bool GraphicsLayerCA::setFilters(const FilterOperations& filters) +bool GraphicsLayerCA::setFilters(const FilterOperations& filterOperations) { - GraphicsLayer::setFilters(filters); - noteLayerPropertyChanged(FiltersChanged); - - return PlatformCALayer::filtersCanBeComposited(filters); + bool canCompositeFilters = PlatformCALayer::filtersCanBeComposited(filterOperations); + if (canCompositeFilters) { + GraphicsLayer::setFilters(filterOperations); + noteLayerPropertyChanged(FiltersChanged); + } else if (filters().size()) { + // In this case filters are rendered in software, so we need to remove any + // previously attached hardware filters. + clearFilters(); + noteLayerPropertyChanged(FiltersChanged); + } + return canCompositeFilters; } #endif @@ -836,6 +843,11 @@ void GraphicsLayerCA::syncCompositingStateForThisLayerOnly() commitLayerChangesAfterSublayers(); } +void GraphicsLayerCA::visibleRectChanged() +{ + m_layer->visibleRectChanged(); +} + void GraphicsLayerCA::recursiveCommitChanges(const TransformState& state, float pageScaleFactor, const FloatPoint& positionRelativeToBase, bool affectedByPageScale) { // Save the state before sending down to kids and restore it after @@ -921,6 +933,15 @@ void GraphicsLayerCA::platformCALayerPaintContents(GraphicsContext& context, con paintGraphicsLayerContents(context, clip); } +void GraphicsLayerCA::platformCALayerDidCreateTiles() +{ + ASSERT(m_layer->layerType() == PlatformCALayer::LayerTypeTileCacheLayer); + + // Ensure that the layout is up to date before any individual tiles are painted by telling the client + // that it needs to sync its layer state, which will end up scheduling the layer flusher. + client()->notifySyncRequired(this); +} + void GraphicsLayerCA::commitLayerChangesBeforeSublayers(float pageScaleFactor, const FloatPoint& positionRelativeToBase) { if (!m_uncommittedChanges) @@ -1749,9 +1770,9 @@ bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valu return true; } -bool GraphicsLayerCA::appendToUncommittedAnimations(const KeyframeValueList& valueList, const TransformOperationList& functionList, const Animation* animation, const String& animationName, const IntSize& boxSize, int animationIndex, double timeOffset, bool isMatrixAnimation) +bool GraphicsLayerCA::appendToUncommittedAnimations(const KeyframeValueList& valueList, const TransformOperations* operations, const Animation* animation, const String& animationName, const IntSize& boxSize, int animationIndex, double timeOffset, bool isMatrixAnimation) { - TransformOperation::OperationType transformOp = isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[animationIndex]; + TransformOperation::OperationType transformOp = isMatrixAnimation ? TransformOperation::MATRIX_3D : operations->operations().at(animationIndex)->getOperationType(); bool additive = animationIndex > 0; bool isKeyframe = valueList.size() > 2; @@ -1776,23 +1797,23 @@ bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValue { ASSERT(valueList.property() == AnimatedPropertyWebkitTransform); - TransformOperationList functionList; - bool listsMatch, hasBigRotation; - fetchTransformOperationList(valueList, functionList, listsMatch, hasBigRotation); + bool hasBigRotation; + int listIndex = validateTransformOperations(valueList, hasBigRotation); + const TransformOperations* operations = (listIndex >= 0) ? static_cast<const TransformAnimationValue*>(valueList.at(listIndex))->value() : 0; // We need to fall back to software animation if we don't have setValueFunction:, and // we would need to animate each incoming transform function separately. This is the // case if we have a rotation >= 180 or we have more than one transform function. - if ((hasBigRotation || functionList.size() > 1) && !PlatformCAAnimation::supportsValueFunction()) + if ((hasBigRotation || (operations && operations->size() > 1)) && !PlatformCAAnimation::supportsValueFunction()) return false; bool validMatrices = true; - // If functionLists don't match we do a matrix animation, otherwise we do a component hardware animation. + // If function lists don't match we do a matrix animation, otherwise we do a component hardware animation. // Also, we can't do component animation unless we have valueFunction, so we need to do matrix animation // if that's not true as well. - bool isMatrixAnimation = !listsMatch || !PlatformCAAnimation::supportsValueFunction(); - int numAnimations = isMatrixAnimation ? 1 : functionList.size(); + bool isMatrixAnimation = listIndex < 0 || !PlatformCAAnimation::supportsValueFunction(); + int numAnimations = isMatrixAnimation ? 1 : operations->size(); bool reverseAnimationList = true; #if !defined(BUILDING_ON_SNOW_LEOPARD) && !PLATFORM(WIN) @@ -1807,14 +1828,14 @@ bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValue #endif if (reverseAnimationList) { for (int animationIndex = numAnimations - 1; animationIndex >= 0; --animationIndex) { - if (!appendToUncommittedAnimations(valueList, functionList, animation, animationName, boxSize, animationIndex, timeOffset, isMatrixAnimation)) { + if (!appendToUncommittedAnimations(valueList, operations, animation, animationName, boxSize, animationIndex, timeOffset, isMatrixAnimation)) { validMatrices = false; break; } } } else { for (int animationIndex = 0; animationIndex < numAnimations; ++animationIndex) { - if (!appendToUncommittedAnimations(valueList, functionList, animation, animationName, boxSize, animationIndex, timeOffset, isMatrixAnimation)) { + if (!appendToUncommittedAnimations(valueList, operations, animation, animationName, boxSize, animationIndex, timeOffset, isMatrixAnimation)) { validMatrices = false; break; } diff --git a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h index 93e0e64cd..80b237641 100644 --- a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h +++ b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h @@ -134,6 +134,8 @@ public: virtual void syncCompositingState(const FloatRect&); virtual void syncCompositingStateForThisLayerOnly(); + virtual void visibleRectChanged() OVERRIDE; + bool allowTiledLayer() const { return m_allowTiledLayer; } virtual void setAllowTiledLayer(bool b); @@ -155,6 +157,7 @@ private: virtual bool platformCALayerContentsOpaque() const { return contentsOpaque(); } virtual bool platformCALayerDrawsContent() const { return drawsContent(); } virtual void platformCALayerLayerDidDisplay(PlatformLayer* layer) { return layerDidDisplay(layer); } + virtual void platformCALayerDidCreateTiles() OVERRIDE; void updateOpacityOnLayer(); @@ -321,7 +324,7 @@ private: static void moveOrCopyLayerAnimation(MoveOrCopy, const String& animationIdentifier, PlatformCALayer *fromLayer, PlatformCALayer *toLayer); void moveOrCopyAnimationsForProperty(MoveOrCopy, AnimatedPropertyID, PlatformCALayer * fromLayer, PlatformCALayer * toLayer); - bool appendToUncommittedAnimations(const KeyframeValueList&, const TransformOperationList&, const Animation*, const String& animationName, const IntSize& boxSize, int animationIndex, double timeOffset, bool isMatrixAnimation); + bool appendToUncommittedAnimations(const KeyframeValueList&, const TransformOperations*, const Animation*, const String& animationName, const IntSize& boxSize, int animationIndex, double timeOffset, bool isMatrixAnimation); enum LayerChange { NoChange = 0, diff --git a/Source/WebCore/platform/graphics/ca/LayerFlushScheduler.h b/Source/WebCore/platform/graphics/ca/LayerFlushScheduler.h index f59071e5d..36b60418f 100644 --- a/Source/WebCore/platform/graphics/ca/LayerFlushScheduler.h +++ b/Source/WebCore/platform/graphics/ca/LayerFlushScheduler.h @@ -46,6 +46,8 @@ public: void suspend(); void resume(); + bool isSuspended() const { return m_isSuspended; } + private: bool m_isSuspended; LayerFlushSchedulerClient* m_client; diff --git a/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h b/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h index bfd76c82a..b2d325956 100644 --- a/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h +++ b/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h @@ -36,11 +36,7 @@ #include <wtf/Vector.h> #if PLATFORM(MAC) -#ifdef __OBJC__ -@class CAPropertyAnimation; -#else -class CAPropertyAnimation; -#endif +OBJC_CLASS CAPropertyAnimation; typedef CAPropertyAnimation* PlatformAnimationRef; #elif PLATFORM(WIN) typedef struct _CACFAnimation* CACFAnimationRef; diff --git a/Source/WebCore/platform/graphics/ca/PlatformCALayer.h b/Source/WebCore/platform/graphics/ca/PlatformCALayer.h index 73661321a..582a0f74a 100644 --- a/Source/WebCore/platform/graphics/ca/PlatformCALayer.h +++ b/Source/WebCore/platform/graphics/ca/PlatformCALayer.h @@ -203,6 +203,8 @@ public: float contentsScale() const; void setContentsScale(float); + void visibleRectChanged(); + #if PLATFORM(WIN) HashMap<String, RefPtr<PlatformCAAnimation> >& animations() { return m_animations; } #endif diff --git a/Source/WebCore/platform/graphics/ca/PlatformCALayerClient.h b/Source/WebCore/platform/graphics/ca/PlatformCALayerClient.h index ae1815c0b..be8e459d8 100644 --- a/Source/WebCore/platform/graphics/ca/PlatformCALayerClient.h +++ b/Source/WebCore/platform/graphics/ca/PlatformCALayerClient.h @@ -59,6 +59,8 @@ public: virtual bool platformCALayerDrawsContent() const = 0; virtual void platformCALayerLayerDidDisplay(PlatformLayer*) = 0; + virtual void platformCALayerDidCreateTiles() = 0; + protected: virtual ~PlatformCALayerClient() {} }; diff --git a/Source/WebCore/platform/graphics/ca/mac/PlatformCALayerMac.mm b/Source/WebCore/platform/graphics/ca/mac/PlatformCALayerMac.mm index 34c9710d9..c52f20dd9 100644 --- a/Source/WebCore/platform/graphics/ca/mac/PlatformCALayerMac.mm +++ b/Source/WebCore/platform/graphics/ca/mac/PlatformCALayerMac.mm @@ -720,6 +720,8 @@ void PlatformCALayer::setFilters(const FilterOperations& filters) RetainPtr<NSMutableArray> array(AdoptNS, [[NSMutableArray alloc] init]); for (unsigned i = 0; i < filters.size(); ++i) { + String filterName = String::format("filter_%d", i); + const FilterOperation* filterOperation = filters.at(i); switch(filterOperation->getOperationType()) { case FilterOperation::DROP_SHADOW: { @@ -744,7 +746,7 @@ void PlatformCALayer::setFilters(const FilterOperations& filters) [caFilter setDefaults]; [caFilter setValue:[NSNumber numberWithFloat:op->amount()] forKey:@"inputIntensity"]; [caFilter setValue:[CIColor colorWithRed:1 green:1 blue:1] forKey:@"inputColor"]; - [caFilter setName:@"grayscaleFilter"]; + [caFilter setName:filterName]; [array.get() addObject:caFilter]; break; } @@ -762,7 +764,7 @@ void PlatformCALayer::setFilters(const FilterOperations& filters) [caFilter setValue:[CIVector vectorWithX:WebCore::blend(0.0, 0.272, t) Y:WebCore::blend(0.0, 0.534, t) Z:WebCore::blend(1.0, 0.131, t) W:0] forKey:@"inputBVector"]; [caFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:1] forKey:@"inputAVector"]; [caFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:0] forKey:@"inputBiasVector"]; - [caFilter setName:@"sepiaFilter"]; + [caFilter setName:filterName]; [array.get() addObject:caFilter]; break; } @@ -771,7 +773,7 @@ void PlatformCALayer::setFilters(const FilterOperations& filters) CIFilter* caFilter = [CIFilter filterWithName:@"CIColorControls"]; [caFilter setDefaults]; [caFilter setValue:[NSNumber numberWithFloat:op->amount()] forKey:@"inputSaturation"]; - [caFilter setName:@"saturateFilter"]; + [caFilter setName:filterName]; [array.get() addObject:caFilter]; break; } @@ -782,7 +784,7 @@ void PlatformCALayer::setFilters(const FilterOperations& filters) // The CIHueAdjust value is in radians [caFilter setValue:[NSNumber numberWithFloat:op->amount() * M_PI * 2 / 360] forKey:@"inputAngle"]; - [caFilter setName:@"hueRotateFilter"]; + [caFilter setName:filterName]; [array.get() addObject:caFilter]; break; } @@ -798,7 +800,7 @@ void PlatformCALayer::setFilters(const FilterOperations& filters) [caFilter setValue:[CIVector vectorWithX:0 Y:0 Z:multiplier W:0] forKey:@"inputBVector"]; [caFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:1] forKey:@"inputAVector"]; [caFilter setValue:[CIVector vectorWithX:op->amount() Y:op->amount() Z:op->amount() W:0] forKey:@"inputBiasVector"]; - [caFilter setName:@"invertFilter"]; + [caFilter setName:filterName]; [array.get() addObject:caFilter]; break; } @@ -812,7 +814,7 @@ void PlatformCALayer::setFilters(const FilterOperations& filters) [caFilter setValue:[CIVector vectorWithX:0 Y:0 Z:1 W:0] forKey:@"inputBVector"]; [caFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:op->amount()] forKey:@"inputAVector"]; [caFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:0] forKey:@"inputBiasVector"]; - [caFilter setName:@"opacityFilter"]; + [caFilter setName:filterName]; [array.get() addObject:caFilter]; break; } @@ -822,7 +824,25 @@ void PlatformCALayer::setFilters(const FilterOperations& filters) CIFilter* caFilter = [CIFilter filterWithName:@"CIGaussianBlur"]; [caFilter setDefaults]; [caFilter setValue:[NSNumber numberWithFloat:op->stdDeviation().calcFloatValue(0)] forKey:@"inputRadius"]; - [caFilter setName:@"blurFilter"]; + [caFilter setName:filterName]; + [array.get() addObject:caFilter]; + break; + } + case FilterOperation::CONTRAST: { + const BasicComponentTransferFilterOperation* op = static_cast<const BasicComponentTransferFilterOperation*>(filterOperation); + CIFilter* caFilter = [CIFilter filterWithName:@"CIColorControls"]; + [caFilter setDefaults]; + [caFilter setValue:[NSNumber numberWithFloat:op->amount()] forKey:@"inputContrast"]; + [caFilter setName:filterName]; + [array.get() addObject:caFilter]; + break; + } + case FilterOperation::BRIGHTNESS: { + const BasicComponentTransferFilterOperation* op = static_cast<const BasicComponentTransferFilterOperation*>(filterOperation); + CIFilter* caFilter = [CIFilter filterWithName:@"CIColorControls"]; + [caFilter setDefaults]; + [caFilter setValue:[NSNumber numberWithFloat:op->amount()] forKey:@"inputBrightness"]; + [caFilter setName:filterName]; [array.get() addObject:caFilter]; break; } @@ -936,6 +956,15 @@ void PlatformCALayer::setContentsScale(float value) #endif } +void PlatformCALayer::visibleRectChanged() +{ + if (m_layerType != LayerTypeTileCacheLayer) + return; + + WebTileCacheLayer *tileCacheLayer = static_cast<WebTileCacheLayer *>(m_layer.get()); + [tileCacheLayer visibleRectChanged]; +} + #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) void PlatformCALayer::synchronouslyDisplayTilesInRect(const FloatRect& rect) { diff --git a/Source/WebCore/platform/graphics/ca/mac/TileCache.h b/Source/WebCore/platform/graphics/ca/mac/TileCache.h index 5c788f9fb..2c290e500 100644 --- a/Source/WebCore/platform/graphics/ca/mac/TileCache.h +++ b/Source/WebCore/platform/graphics/ca/mac/TileCache.h @@ -26,23 +26,21 @@ #ifndef TileCache_h #define TileCache_h +#include "IntPointHash.h" #include "IntSize.h" +#include "Timer.h" +#include <wtf/HashMap.h> #include <wtf/Noncopyable.h> #include <wtf/PassOwnPtr.h> #include <wtf/RetainPtr.h> -#ifdef __OBJC__ -@class CALayer; -@class WebTileCacheLayer; -@class WebTileLayer; -#else -class CALayer; -class WebTileCacheLayer; -class WebTileLayer; -#endif +OBJC_CLASS CALayer; +OBJC_CLASS WebTileCacheLayer; +OBJC_CLASS WebTileLayer; namespace WebCore { +class FloatRect; class IntPoint; class IntRect; @@ -53,30 +51,55 @@ public: static PassOwnPtr<TileCache> create(WebTileCacheLayer*, const IntSize& tileSize); void tileCacheLayerBoundsChanged(); + + void setNeedsDisplay(); void setNeedsDisplayInRect(const IntRect&); void drawLayer(WebTileLayer*, CGContextRef); + bool acceleratesDrawing() const { return m_acceleratesDrawing; } + void setAcceleratesDrawing(bool); + CALayer *tileContainerLayer() const { return m_tileContainerLayer.get(); } + void visibleRectChanged(); + + float tileDebugBorderWidth() const { return m_tileDebugBorderWidth; } + void setTileDebugBorderWidth(float); + + CGColorRef tileDebugBorderColor() const { return m_tileDebugBorderColor.get(); } + void setTileDebugBorderColor(CGColorRef); private: + typedef IntPoint TileIndex; + TileCache(WebTileCacheLayer*, const IntSize& tileSize); + FloatRect visibleRect() const; IntRect bounds() const; - void getTileRangeForRect(const IntRect&, IntPoint& topLeft, IntPoint& bottomRight); - IntSize numTilesForGridSize(const IntSize&) const; - void resizeTileGrid(const IntSize& numTiles); + IntRect rectForTileIndex(const TileIndex&) const; + void getTileIndexRangeForRect(const IntRect&, TileIndex& topLeft, TileIndex& bottomRight); - WebTileLayer* tileLayerAtPosition(const IntPoint&) const; + void scheduleTileRevalidation(); + void tileRevalidationTimerFired(Timer<TileCache>*); + void revalidateTiles(); + + WebTileLayer* tileLayerAtIndex(const TileIndex&) const; RetainPtr<WebTileLayer> createTileLayer(); + bool shouldShowRepaintCounters() const; + WebTileCacheLayer* m_tileCacheLayer; + RetainPtr<CALayer> m_tileContainerLayer; const IntSize m_tileSize; - RetainPtr<CALayer> m_tileContainerLayer; + typedef HashMap<TileIndex, RetainPtr<WebTileLayer> > TileMap; + TileMap m_tiles; + Timer<TileCache> m_tileRevalidationTimer; + + bool m_acceleratesDrawing; - // Number of tiles in each dimension. - IntSize m_numTilesInGrid; + RetainPtr<CGColorRef> m_tileDebugBorderColor; + float m_tileDebugBorderWidth; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/ca/mac/TileCache.mm b/Source/WebCore/platform/graphics/ca/mac/TileCache.mm index dc791f836..2550b3dd6 100644 --- a/Source/WebCore/platform/graphics/ca/mac/TileCache.mm +++ b/Source/WebCore/platform/graphics/ca/mac/TileCache.mm @@ -35,6 +35,12 @@ using namespace std; +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) +@interface CALayer (WebCALayerDetails) +- (void)setAcceleratesDrawing:(BOOL)flag; +@end +#endif + namespace WebCore { PassOwnPtr<TileCache> TileCache::create(WebTileCacheLayer* tileCacheLayer, const IntSize& tileSize) @@ -44,8 +50,11 @@ PassOwnPtr<TileCache> TileCache::create(WebTileCacheLayer* tileCacheLayer, const TileCache::TileCache(WebTileCacheLayer* tileCacheLayer, const IntSize& tileSize) : m_tileCacheLayer(tileCacheLayer) - , m_tileSize(tileSize) , m_tileContainerLayer(adoptCF([[CALayer alloc] init])) + , m_tileSize(tileSize) + , m_tileRevalidationTimer(this, &TileCache::tileRevalidationTimerFired) + , m_acceleratesDrawing(false) + , m_tileDebugBorderWidth(0) { [CATransaction begin]; [CATransaction setDisableActions:YES]; @@ -55,31 +64,48 @@ TileCache::TileCache(WebTileCacheLayer* tileCacheLayer, const IntSize& tileSize) void TileCache::tileCacheLayerBoundsChanged() { - IntSize numTilesInGrid = numTilesForGridSize(bounds().size()); - if (numTilesInGrid == m_numTilesInGrid) + if (m_tiles.isEmpty()) { + // We must revalidate immediately instead of using a timer when there are + // no tiles to avoid a flash when transitioning from one page to another. + revalidateTiles(); return; + } - resizeTileGrid(numTilesInGrid); + scheduleTileRevalidation(); +} + +void TileCache::setNeedsDisplay() +{ + setNeedsDisplayInRect(IntRect(0, 0, std::numeric_limits<int>::max(), std::numeric_limits<int>::max())); } void TileCache::setNeedsDisplayInRect(const IntRect& rect) { - if (m_numTilesInGrid.isZero()) + if (m_tiles.isEmpty()) return; // Find the tiles that need to be invalidated. - IntPoint topLeft; - IntPoint bottomRight; - getTileRangeForRect(rect, topLeft, bottomRight); + TileIndex topLeft; + TileIndex bottomRight; + getTileIndexRangeForRect(rect, topLeft, bottomRight); for (int y = topLeft.y(); y <= bottomRight.y(); ++y) { for (int x = topLeft.x(); x <= bottomRight.x(); ++x) { - WebTileLayer* tileLayer = tileLayerAtPosition(IntPoint(x, y)); + WebTileLayer* tileLayer = tileLayerAtIndex(TileIndex(x, y)); + if (!tileLayer) + continue; CGRect tileRect = [m_tileCacheLayer convertRect:rect toLayer:tileLayer]; + if (CGRectIsEmpty(tileRect)) + continue; + + [tileLayer setNeedsDisplayInRect:tileRect]; - if (!CGRectIsEmpty(tileRect)) - [tileLayer setNeedsDisplayInRect:tileRect]; + if (shouldShowRepaintCounters()) { + CGRect bounds = [tileLayer bounds]; + CGRect indicatorRect = CGRectMake(bounds.origin.x, bounds.origin.y, 52, 27); + [tileLayer setNeedsDisplayInRect:indicatorRect]; + } } } } @@ -97,6 +123,99 @@ void TileCache::drawLayer(WebTileLayer* layer, CGContextRef context) drawLayerContents(context, layer, platformLayer); CGContextRestoreGState(context); + + unsigned repaintCount = [layer incrementRepaintCount]; + if (!shouldShowRepaintCounters()) + return; + + // FIXME: Some of this code could be shared with WebLayer. + char text[16]; // that's a lot of repaints + snprintf(text, sizeof(text), "%d", repaintCount); + + CGRect indicatorBox = [layer bounds]; + indicatorBox.size.width = 12 + 10 * strlen(text); + indicatorBox.size.height = 27; + CGContextSaveGState(context); + + CGContextSetAlpha(context, 0.5f); + CGContextBeginTransparencyLayerWithRect(context, indicatorBox, 0); + + CGContextSetFillColorWithColor(context, m_tileDebugBorderColor.get()); + CGContextFillRect(context, indicatorBox); + + if (platformLayer->acceleratesDrawing()) + CGContextSetRGBFillColor(context, 1, 0, 0, 1); + else + CGContextSetRGBFillColor(context, 1, 1, 1, 1); + + CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1, -1)); + CGContextSelectFont(context, "Helvetica", 22, kCGEncodingMacRoman); + CGContextShowTextAtPoint(context, indicatorBox.origin.x + 5, indicatorBox.origin.y + 22, text, strlen(text)); + + CGContextEndTransparencyLayer(context); + CGContextRestoreGState(context); +} + +void TileCache::setAcceleratesDrawing(bool acceleratesDrawing) +{ +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + if (m_acceleratesDrawing == acceleratesDrawing) + return; + + m_acceleratesDrawing = acceleratesDrawing; + + for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) + [it->second.get() setAcceleratesDrawing:m_acceleratesDrawing]; +#else + UNUSED_PARAM(acceleratesDrawing); +#endif +} + +void TileCache::visibleRectChanged() +{ + scheduleTileRevalidation(); +} + +void TileCache::setTileDebugBorderWidth(float borderWidth) +{ + if (m_tileDebugBorderWidth == borderWidth) + return; + + m_tileDebugBorderWidth = borderWidth; + for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) + [it->second.get() setBorderWidth:m_tileDebugBorderWidth]; +} + +void TileCache::setTileDebugBorderColor(CGColorRef borderColor) +{ + if (m_tileDebugBorderColor == borderColor) + return; + + m_tileDebugBorderColor = borderColor; + for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) + [it->second.get() setBorderColor:m_tileDebugBorderColor.get()]; +} + +FloatRect TileCache::visibleRect() const +{ + CGRect rect = [m_tileCacheLayer bounds]; + + CALayer *layer = m_tileCacheLayer; + CALayer *superlayer = [layer superlayer]; + + while (superlayer) { + CGRect rectInSuperlayerCoordinates = [superlayer convertRect:rect fromLayer:layer]; + + if ([superlayer masksToBounds]) + rect = CGRectIntersection([superlayer bounds], rectInSuperlayerCoordinates); + else + rect = rectInSuperlayerCoordinates; + + layer = superlayer; + superlayer = [layer superlayer]; + } + + return [m_tileCacheLayer convertRect:rect fromLayer:layer]; } IntRect TileCache::bounds() const @@ -104,60 +223,104 @@ IntRect TileCache::bounds() const return IntRect(IntPoint(), IntSize([m_tileCacheLayer bounds].size)); } -void TileCache::getTileRangeForRect(const IntRect& rect, IntPoint& topLeft, IntPoint& bottomRight) +IntRect TileCache::rectForTileIndex(const TileIndex& tileIndex) const { - topLeft.setX(max(rect.x() / m_tileSize.width(), 0)); - topLeft.setY(max(rect.y() / m_tileSize.height(), 0)); - bottomRight.setX(min(rect.maxX() / m_tileSize.width(), m_numTilesInGrid.width() - 1)); - bottomRight.setY(min(rect.maxY() / m_tileSize.height(), m_numTilesInGrid.height() - 1)); + return IntRect(IntPoint(tileIndex.x() * m_tileSize.width(), tileIndex.y() * m_tileSize.height()), m_tileSize); } -IntSize TileCache::numTilesForGridSize(const IntSize& gridSize) const +void TileCache::getTileIndexRangeForRect(const IntRect& rect, TileIndex& topLeft, TileIndex& bottomRight) { - int numXTiles = ceil(static_cast<double>(gridSize.width()) / m_tileSize.width()); - int numYTiles = ceil(static_cast<double>(gridSize.height()) / m_tileSize.height()); + IntRect clampedRect = intersection(rect, bounds()); - return IntSize(numXTiles, numYTiles); + topLeft.setX(max(clampedRect.x() / m_tileSize.width(), 0)); + topLeft.setY(max(clampedRect.y() / m_tileSize.height(), 0)); + bottomRight.setX(max(clampedRect.maxX() / m_tileSize.width(), 0)); + bottomRight.setY(max(clampedRect.maxY() / m_tileSize.height(), 0)); } -void TileCache::resizeTileGrid(const IntSize& numTilesInGrid) +void TileCache::scheduleTileRevalidation() { - [CATransaction begin]; - [CATransaction setDisableActions:YES]; + if (m_tileRevalidationTimer.isActive()) + return; + + m_tileRevalidationTimer.startOneShot(0); +} + +void TileCache::tileRevalidationTimerFired(Timer<TileCache>*) +{ + revalidateTiles(); +} + +void TileCache::revalidateTiles() +{ + IntRect tileCoverageRect = enclosingIntRect(visibleRect()); + if (tileCoverageRect.isEmpty()) + return; + + // Inflate the coverage rect so that it covers 2x of the visible width and 3x of the visible height. + // These values were chosen because it's more common to have tall pages and to scroll vertically, + // so we keep more tiles above and below the current area. + tileCoverageRect.inflateX(tileCoverageRect.width() / 2); + tileCoverageRect.inflateY(tileCoverageRect.height()); + + Vector<TileIndex> tilesToRemove; + + for (TileMap::iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) { + const TileIndex& tileIndex = it->first; + + WebTileLayer* tileLayer = it->second.get(); + + if (!rectForTileIndex(tileIndex).intersects(tileCoverageRect)) { + // Remove this layer. + [tileLayer removeFromSuperlayer]; + [tileLayer setTileCache:0]; - RetainPtr<NSMutableArray> newSublayers = adoptNS([[NSMutableArray alloc] initWithCapacity:numTilesInGrid.width() * numTilesInGrid.height()]); + tilesToRemove.append(tileIndex); + } + } + + // FIXME: Be more clever about which tiles to remove. We might not want to remove all + // the tiles that are outside the coverage rect. When we know that we're going to be scrolling up, + // we might want to remove the ones below the coverage rect but keep the ones above. + for (size_t i = 0; i < tilesToRemove.size(); ++i) + m_tiles.remove(tilesToRemove[i]); - for (int y = 0; y < numTilesInGrid.height(); ++y) { - for (int x = 0; x < numTilesInGrid.width(); ++x) { - RetainPtr<WebTileLayer> tileLayer; + TileIndex topLeft; + TileIndex bottomRight; + getTileIndexRangeForRect(tileCoverageRect, topLeft, bottomRight); - if (x < m_numTilesInGrid.width() && y < m_numTilesInGrid.height()) { - // We can reuse the tile layer at this position. - tileLayer = tileLayerAtPosition(IntPoint(x, y)); - } else { - tileLayer = createTileLayer(); + bool didCreateNewTiles = false; + + for (int y = topLeft.y(); y <= bottomRight.y(); ++y) { + for (int x = topLeft.x(); x <= bottomRight.x(); ++x) { + TileIndex tileIndex(x, y); + + RetainPtr<WebTileLayer>& tileLayer = m_tiles.add(tileIndex, 0).first->second; + if (tileLayer) { + // We already have a layer for this tile. + continue; } + didCreateNewTiles = true; + + tileLayer = createTileLayer(); + + [tileLayer.get() setNeedsDisplay]; [tileLayer.get() setPosition:CGPointMake(x * m_tileSize.width(), y * m_tileSize.height())]; - [newSublayers.get() addObject:tileLayer.get()]; + [m_tileContainerLayer.get() addSublayer:tileLayer.get()]; } } - // FIXME: Make sure to call setTileCache:0 on the layers that get thrown away here. - [m_tileContainerLayer.get() setSublayers:newSublayers.get()]; - m_numTilesInGrid = numTilesInGrid; + if (!didCreateNewTiles) + return; - [CATransaction commit]; + PlatformCALayer* platformLayer = PlatformCALayer::platformCALayer(m_tileCacheLayer); + platformLayer->owner()->platformCALayerDidCreateTiles(); } -WebTileLayer* TileCache::tileLayerAtPosition(const IntPoint& point) const +WebTileLayer* TileCache::tileLayerAtIndex(const TileIndex& index) const { - ASSERT(point.x() >= 0); - ASSERT(point.x() <= m_numTilesInGrid.width()); - ASSERT(point.y() >= 0); - ASSERT(point.y() <= m_numTilesInGrid.height()); - - return [[m_tileContainerLayer.get() sublayers] objectAtIndex:point.y() * m_numTilesInGrid.width() + point.x()]; + return m_tiles.get(index).get(); } RetainPtr<WebTileLayer> TileCache::createTileLayer() @@ -166,8 +329,28 @@ RetainPtr<WebTileLayer> TileCache::createTileLayer() [layer.get() setBounds:CGRectMake(0, 0, m_tileSize.width(), m_tileSize.height())]; [layer.get() setAnchorPoint:CGPointZero]; [layer.get() setTileCache:this]; + [layer.get() setBorderColor:m_tileDebugBorderColor.get()]; + [layer.get() setBorderWidth:m_tileDebugBorderWidth]; + +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + [layer.get() setAcceleratesDrawing:m_acceleratesDrawing]; +#endif return layer; } +bool TileCache::shouldShowRepaintCounters() const +{ + PlatformCALayer* platformLayer = PlatformCALayer::platformCALayer(m_tileCacheLayer); + if (!platformLayer) + return false; + + WebCore::PlatformCALayerClient* layerContents = platformLayer->owner(); + ASSERT(layerContents); + if (!layerContents) + return false; + + return layerContents->platformCALayerShowRepaintCounter(); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/ca/mac/WebTileCacheLayer.h b/Source/WebCore/platform/graphics/ca/mac/WebTileCacheLayer.h index 77126c0aa..5dc64983e 100644 --- a/Source/WebCore/platform/graphics/ca/mac/WebTileCacheLayer.h +++ b/Source/WebCore/platform/graphics/ca/mac/WebTileCacheLayer.h @@ -35,4 +35,6 @@ namespace WebCore { } - (CALayer *)tileContainerLayer; +- (void)visibleRectChanged; + @end diff --git a/Source/WebCore/platform/graphics/ca/mac/WebTileCacheLayer.mm b/Source/WebCore/platform/graphics/ca/mac/WebTileCacheLayer.mm index 3e292e9cf..059f1777c 100644 --- a/Source/WebCore/platform/graphics/ca/mac/WebTileCacheLayer.mm +++ b/Source/WebCore/platform/graphics/ca/mac/WebTileCacheLayer.mm @@ -52,14 +52,54 @@ using namespace WebCore; _tileCache->tileCacheLayerBoundsChanged(); } +- (void)setNeedsDisplay +{ + _tileCache->setNeedsDisplay(); +} + - (void)setNeedsDisplayInRect:(CGRect)rect { _tileCache->setNeedsDisplayInRect(enclosingIntRect(rect)); } +- (void)setAcceleratesDrawing:(BOOL)acceleratesDrawing +{ + _tileCache->setAcceleratesDrawing(acceleratesDrawing); +} + +- (BOOL)acceleratesDrawing +{ + return _tileCache->acceleratesDrawing(); +} + - (CALayer *)tileContainerLayer { return _tileCache->tileContainerLayer(); } +- (void)visibleRectChanged +{ + _tileCache->visibleRectChanged(); +} + +- (CGColorRef)borderColor +{ + return _tileCache->tileDebugBorderColor(); +} + +- (void)setBorderColor:(CGColorRef)borderColor +{ + _tileCache->setTileDebugBorderColor(borderColor); +} + +- (CGFloat)borderWidth +{ + return _tileCache->tileDebugBorderWidth(); +} + +- (void)setBorderWidth:(CGFloat)borderWidth +{ + _tileCache->setTileDebugBorderWidth(borderWidth); +} + @end diff --git a/Source/WebCore/platform/graphics/ca/mac/WebTileLayer.h b/Source/WebCore/platform/graphics/ca/mac/WebTileLayer.h index cb52c1cbd..577e34a39 100644 --- a/Source/WebCore/platform/graphics/ca/mac/WebTileLayer.h +++ b/Source/WebCore/platform/graphics/ca/mac/WebTileLayer.h @@ -32,8 +32,11 @@ namespace WebCore { @interface WebTileLayer : CALayer { WebCore::TileCache* _tileCache; + unsigned _repaintCount; } + - (void)setTileCache:(WebCore::TileCache*)tileCache; +- (unsigned)incrementRepaintCount; @end diff --git a/Source/WebCore/platform/graphics/ca/mac/WebTileLayer.mm b/Source/WebCore/platform/graphics/ca/mac/WebTileLayer.mm index ef42d7c67..6f7c85c08 100644 --- a/Source/WebCore/platform/graphics/ca/mac/WebTileLayer.mm +++ b/Source/WebCore/platform/graphics/ca/mac/WebTileLayer.mm @@ -52,5 +52,10 @@ using namespace WebCore; _tileCache = tileCache; } +- (unsigned)incrementRepaintCount +{ + return ++_repaintCount; +} + @end diff --git a/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp b/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp index 060f2490d..4a9a33599 100644 --- a/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp +++ b/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp @@ -620,6 +620,10 @@ void PlatformCALayer::setContentsScale(float) { } +void PlatformCALayer::visibleRectChanged() +{ +} + #ifndef NDEBUG static void printIndent(int indent) { diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp b/Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp index b5e1231d2..c85aab416 100644 --- a/Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp @@ -115,6 +115,10 @@ void GraphicsContext3D::setContextLostCallback(PassOwnPtr<ContextLostCallback>) { } +void GraphicsContext3D::setErrorMessageCallback(PassOwnPtr<ErrorMessageCallback>) +{ +} + #if USE(ACCELERATED_COMPOSITING) PlatformLayer* GraphicsContext3D::platformLayer() const { diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index 81c5ae47c..f4d2ea22c 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -54,7 +54,7 @@ ImageBufferData::ImageBufferData(const IntSize& size) { } -ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, DeferralMode, bool& success) : m_data(size) , m_size(size) { diff --git a/Source/WebCore/platform/graphics/cairo/OpenGLShims.cpp b/Source/WebCore/platform/graphics/cairo/OpenGLShims.cpp index 28316e0e4..2994cd2c9 100644 --- a/Source/WebCore/platform/graphics/cairo/OpenGLShims.cpp +++ b/Source/WebCore/platform/graphics/cairo/OpenGLShims.cpp @@ -42,7 +42,7 @@ OpenGLFunctionTable* openGLFunctionTable() #if PLATFORM(QT) static void* getProcAddress(const char* procName) { - return QGLContext::currentContext()->getProcAddress(QString::fromLatin1(procName)); + return reinterpret_cast<void*>(QGLContext::currentContext()->getProcAddress(QString::fromLatin1(procName))); } #else typedef void* (*glGetProcAddressType) (const char* procName); diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index 20ffba646..4b6192f16 100644 --- a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -630,9 +630,12 @@ void GraphicsContext::fillPath(const Path& path) if (m_state.fillGradient) { if (hasShadow()) { FloatRect rect = path.fastBoundingRect(); - CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(rect.width(), rect.height()), 0); + FloatSize layerSize = getCTM().mapSize(rect.size()); + + CGLayerRef layer = CGLayerCreateWithContext(context, layerSize, 0); CGContextRef layerContext = CGLayerGetContext(layer); + CGContextScaleCTM(layerContext, layerSize.width() / rect.width(), layerSize.height() / rect.height()); CGContextTranslateCTM(layerContext, -rect.x(), -rect.y()); CGContextBeginPath(layerContext); CGContextAddPath(layerContext, path.platformPath()); @@ -644,7 +647,7 @@ void GraphicsContext::fillPath(const Path& path) CGContextClip(layerContext); m_state.fillGradient->paint(layerContext); - CGContextDrawLayerAtPoint(context, CGPointMake(rect.x(), rect.y()), layer); + CGContextDrawLayerInRect(context, rect, layer); CGLayerRelease(layer); } else { CGContextBeginPath(context); @@ -687,10 +690,12 @@ void GraphicsContext::strokePath(const Path& path) FloatRect rect = path.fastBoundingRect(); float lineWidth = strokeThickness(); float doubleLineWidth = lineWidth * 2; - float layerWidth = ceilf(rect.width() + doubleLineWidth); - float layerHeight = ceilf(rect.height() + doubleLineWidth); + float adjustedWidth = ceilf(rect.width() + doubleLineWidth); + float adjustedHeight = ceilf(rect.height() + doubleLineWidth); + + FloatSize layerSize = getCTM().mapSize(FloatSize(adjustedWidth, adjustedHeight)); - CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(layerWidth, layerHeight), 0); + CGLayerRef layer = CGLayerCreateWithContext(context, layerSize, 0); CGContextRef layerContext = CGLayerGetContext(layer); CGContextSetLineWidth(layerContext, lineWidth); @@ -699,6 +704,7 @@ void GraphicsContext::strokePath(const Path& path) // the layer on the left and top sides. float translationX = lineWidth - rect.x(); float translationY = lineWidth - rect.y(); + CGContextScaleCTM(layerContext, layerSize.width() / adjustedWidth, layerSize.height() / adjustedHeight); CGContextTranslateCTM(layerContext, translationX, translationY); CGContextAddPath(layerContext, path.platformPath()); @@ -709,7 +715,7 @@ void GraphicsContext::strokePath(const Path& path) float destinationX = roundf(rect.x() - lineWidth); float destinationY = roundf(rect.y() - lineWidth); - CGContextDrawLayerAtPoint(context, CGPointMake(destinationX, destinationY), layer); + CGContextDrawLayerInRect(context, CGRectMake(destinationX, destinationY, adjustedWidth, adjustedHeight), layer); CGLayerRelease(layer); } else { CGContextSaveGState(context); @@ -747,16 +753,19 @@ void GraphicsContext::fillRect(const FloatRect& rect) if (m_state.fillGradient) { CGContextSaveGState(context); if (hasShadow()) { - CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(rect.width(), rect.height()), 0); + FloatSize layerSize = getCTM().mapSize(rect.size()); + + CGLayerRef layer = CGLayerCreateWithContext(context, layerSize, 0); CGContextRef layerContext = CGLayerGetContext(layer); + CGContextScaleCTM(layerContext, layerSize.width() / rect.width(), layerSize.height() / rect.height()); CGContextTranslateCTM(layerContext, -rect.x(), -rect.y()); CGContextAddRect(layerContext, rect); CGContextClip(layerContext); CGContextConcatCTM(layerContext, m_state.fillGradient->gradientSpaceTransform()); m_state.fillGradient->paint(layerContext); - CGContextDrawLayerAtPoint(context, CGPointMake(rect.x(), rect.y()), layer); + CGContextDrawLayerInRect(context, rect, layer); CGLayerRelease(layer); } else { CGContextClipToRect(context, rect); @@ -1027,6 +1036,7 @@ void GraphicsContext::setPlatformShadow(const FloatSize& offset, float blur, con blurRadius = min(blurRadius, narrowPrecisionToCGFloat(1000.0)); +#if defined(BUILDING_ON_SNOW_LEOPARD) || defined(BUILDING_ON_LION) if (!isAcceleratedContext()) { // Work around <rdar://problem/5539388> by ensuring that the offsets will get truncated // to the desired integer. Also see: <rdar://problem/10056277> @@ -1041,6 +1051,7 @@ void GraphicsContext::setPlatformShadow(const FloatSize& offset, float blur, con else if (yOffset < 0) yOffset -= extraShadowOffset; } +#endif // Check for an invalid color, as this means that the color was not set for the shadow // and we should therefore just use the default shadow color. @@ -1088,9 +1099,11 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) if (m_state.strokeGradient) { if (hasShadow()) { const float doubleLineWidth = lineWidth * 2; - const float layerWidth = ceilf(rect.width() + doubleLineWidth); - const float layerHeight = ceilf(rect.height() + doubleLineWidth); - CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(layerWidth, layerHeight), 0); + float adjustedWidth = ceilf(rect.width() + doubleLineWidth); + float adjustedHeight = ceilf(rect.height() + doubleLineWidth); + FloatSize layerSize = getCTM().mapSize(FloatSize(adjustedWidth, adjustedHeight)); + + CGLayerRef layer = CGLayerCreateWithContext(context, layerSize, 0); CGContextRef layerContext = CGLayerGetContext(layer); m_state.strokeThickness = lineWidth; @@ -1101,6 +1114,7 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) // the layer on the left and top sides. const float translationX = lineWidth - rect.x(); const float translationY = lineWidth - rect.y(); + CGContextScaleCTM(layerContext, layerSize.width() / adjustedWidth, layerSize.height() / adjustedHeight); CGContextTranslateCTM(layerContext, translationX, translationY); CGContextAddRect(layerContext, rect); @@ -1111,7 +1125,7 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) const float destinationX = roundf(rect.x() - lineWidth); const float destinationY = roundf(rect.y() - lineWidth); - CGContextDrawLayerAtPoint(context, CGPointMake(destinationX, destinationY), layer); + CGContextDrawLayerInRect(context, CGRectMake(destinationX, destinationY, adjustedWidth, adjustedHeight), layer); CGLayerRelease(layer); } else { CGContextSaveGState(context); @@ -1589,6 +1603,9 @@ void GraphicsContext::setPlatformCompositeOperation(CompositeOperator mode) case CompositePlusLighter: target = kCGBlendModePlusLighter; break; + case CompositeDifference: + target = kCGBlendModeDifference; + break; } CGContextSetBlendMode(platformContext(), target); } diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp index 355f475e2..02ba8cffd 100644 --- a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp @@ -38,7 +38,6 @@ #include <math.h> #include <wtf/Assertions.h> #include <wtf/CheckedArithmetic.h> -#include <wtf/CurrentTime.h> #include <wtf/MainThread.h> #include <wtf/OwnArrayPtr.h> #include <wtf/RetainPtr.h> @@ -53,6 +52,10 @@ #include <IOSurface/IOSurface.h> #endif +#if defined(BUILDING_ON_LION) +#include <wtf/CurrentTime.h> +#endif + using namespace std; namespace WebCore { @@ -104,7 +107,7 @@ static void releaseImageData(void*, const void* data, size_t) fastFree(const_cast<void*>(data)); } -ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, RenderingMode renderingMode, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, RenderingMode renderingMode, DeferralMode, bool& success) : m_data(size) , m_size(size) { @@ -169,7 +172,9 @@ ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, Render m_context->scale(FloatSize(1, -1)); m_context->translate(0, -height.unsafeGet()); m_context->setIsAcceleratedContext(accelerateRendering); +#if defined(BUILDING_ON_LION) m_data.m_lastFlushTime = currentTimeMS(); +#endif success = true; } @@ -184,6 +189,7 @@ size_t ImageBuffer::dataSize() const GraphicsContext* ImageBuffer::context() const { +#if defined(BUILDING_ON_LION) // Force a flush if last flush was more than 20ms ago if (m_context->isAcceleratedContext()) { double elapsedTime = currentTimeMS() - m_data.m_lastFlushTime; @@ -195,6 +201,7 @@ GraphicsContext* ImageBuffer::context() const m_data.m_lastFlushTime = currentTimeMS(); } } +#endif return m_context.get(); } @@ -228,7 +235,9 @@ NativeImagePtr ImageBuffer::copyNativeImage(BackingStoreCopy copyBehavior) const #if USE(IOSURFACE_CANVAS_BACKING_STORE) else { image = wkIOSurfaceContextCreateImage(context()->platformContext()); +#if defined(BUILDING_ON_LION) m_data.m_lastFlushTime = currentTimeMS(); +#endif } #endif @@ -241,7 +250,7 @@ void ImageBuffer::draw(GraphicsContext* destContext, ColorSpace styleColorSpace, ColorSpace colorSpace = (destContext == m_context) ? ColorSpaceDeviceRGB : styleColorSpace; RetainPtr<CGImageRef> image; - if (destContext == m_context) + if (destContext == m_context || destContext->isAcceleratedContext()) image.adoptCF(copyNativeImage(CopyBackingStore)); // Drawing into our own buffer, need to deep copy. else image.adoptCF(copyNativeImage(DontCopyBackingStore)); @@ -249,19 +258,19 @@ void ImageBuffer::draw(GraphicsContext* destContext, ColorSpace styleColorSpace, destContext->drawNativeImage(image.get(), m_size, colorSpace, destRect, srcRect, op); } -void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) +void ImageBuffer::drawPattern(GraphicsContext* destContext, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) { if (!m_context->isAcceleratedContext()) { - if (context == m_context) { + if (destContext == m_context || destContext->isAcceleratedContext()) { RefPtr<Image> copy = copyImage(CopyBackingStore); // Drawing into our own buffer, need to deep copy. - copy->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect); + copy->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect); } else { RefPtr<Image> imageForRendering = copyImage(DontCopyBackingStore); - imageForRendering->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect); + imageForRendering->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect); } } else { RefPtr<Image> copy = copyImage(CopyBackingStore); - copy->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect); + copy->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect); } } @@ -280,7 +289,9 @@ PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) { if (m_context->isAcceleratedContext()) { CGContextFlush(context()->platformContext()); +#if defined(BUILDING_ON_LION) m_data.m_lastFlushTime = currentTimeMS(); +#endif } return m_data.getData(rect, m_size, m_context->isAcceleratedContext(), true); } @@ -289,7 +300,9 @@ PassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect { if (m_context->isAcceleratedContext()) { CGContextFlush(context()->platformContext()); +#if defined(BUILDING_ON_LION) m_data.m_lastFlushTime = currentTimeMS(); +#endif } return m_data.getData(rect, m_size, m_context->isAcceleratedContext(), false); } @@ -298,7 +311,9 @@ void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sou { if (m_context->isAcceleratedContext()) { CGContextFlush(context()->platformContext()); +#if defined(BUILDING_ON_LION) m_data.m_lastFlushTime = currentTimeMS(); +#endif } m_data.putData(source, sourceSize, sourceRect, destPoint, m_size, m_context->isAcceleratedContext(), true); } @@ -307,7 +322,9 @@ void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& so { if (m_context->isAcceleratedContext()) { CGContextFlush(context()->platformContext()); +#if defined(BUILDING_ON_LION) m_data.m_lastFlushTime = currentTimeMS(); +#endif } m_data.putData(source, sourceSize, sourceRect, destPoint, m_size, m_context->isAcceleratedContext(), false); } diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h b/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h index 61d92ad0f..a148de6c2 100644 --- a/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h +++ b/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h @@ -54,7 +54,9 @@ public: Checked<unsigned, RecordOverflow> m_bytesPerRow; CGColorSpaceRef m_colorSpace; RetainPtr<IOSurfaceRef> m_surface; +#if defined(BUILDING_ON_LION) mutable double m_lastFlushTime; +#endif PassRefPtr<ByteArray> getData(const IntRect& rect, const IntSize& size, bool accelerateRendering, bool unmultiplied) const; void putData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool accelerateRendering, bool unmultiplied); diff --git a/Source/WebCore/platform/graphics/cg/PathCG.cpp b/Source/WebCore/platform/graphics/cg/PathCG.cpp index 93faf80f2..01f7ffe41 100644 --- a/Source/WebCore/platform/graphics/cg/PathCG.cpp +++ b/Source/WebCore/platform/graphics/cg/PathCG.cpp @@ -41,59 +41,6 @@ namespace WebCore { -// A class to provide an isEmpty test that considers a one-element path with only a MoveTo element -// to be empty. This behavior is consistent with other platforms in WebKit, and is needed to prevent -// incorrect (according to the spec) linecap stroking for zero length paths in SVG. -class PathIsEmptyOrSingleMoveTester { -public: - PathIsEmptyOrSingleMoveTester() : m_moveCount(0) { } - - bool isEmpty() const - { - return m_moveCount <= 1; - } - - static void testPathElement(void* info, const CGPathElement* element) - { - PathIsEmptyOrSingleMoveTester* tester = static_cast<PathIsEmptyOrSingleMoveTester*>(info); - if (element->type == kCGPathElementMoveToPoint) - ++tester->m_moveCount; - else { - // Any non move element implies a non-empty path; set the count to 2 to force - // isEmpty to return false. - tester->m_moveCount = 2; - } - } - -private: - // Any non-move-to element, or more than one move-to element, will make the count >= 2. - unsigned m_moveCount; -}; - -// Paths with only move-to elements do not draw under any circumstances, so their bound should -// be empty. Currently, CoreGraphics returns non-empty bounds for such paths. Radar 10450621 -// tracks this. This class reports paths that have only move-to elements, allowing the -// bounding box code to work around the CoreGraphics problem. -class PathHasOnlyMoveToTester { -public: - PathHasOnlyMoveToTester() : m_hasSeenOnlyMoveTo(true) { } - - bool hasOnlyMoveTo() const - { - return m_hasSeenOnlyMoveTo; - } - - static void testPathElement(void* info, const CGPathElement* element) - { - PathHasOnlyMoveToTester* tester = static_cast<PathHasOnlyMoveToTester*>(info); - if (tester->m_hasSeenOnlyMoveTo && element->type != kCGPathElementMoveToPoint) - tester->m_hasSeenOnlyMoveTo = false; - } - -private: - bool m_hasSeenOnlyMoveTo; -}; - static size_t putBytesNowhere(void*, const void*, size_t count) { return count; @@ -218,32 +165,20 @@ FloatRect Path::boundingRect() const { // CGPathGetBoundingBox includes the path's control points, CGPathGetPathBoundingBox // does not, but only exists on 10.6 and above. - // A bug in CoreGraphics leads to an incorrect bound on paths containing only move-to elements - // with a linecap style that is non-butt. All paths with only move-to elements (regardless of - // linecap) are effectively empty for bounding purposes and here we make it so. - PathHasOnlyMoveToTester tester; - CGPathApply(m_path, &tester, PathHasOnlyMoveToTester::testPathElement); - if (tester.hasOnlyMoveTo()) - return FloatRect(0, 0, 0, 0); + CGRect bound = CGRectZero; #if !defined(BUILDING_ON_LEOPARD) - return CGPathGetPathBoundingBox(m_path); + bound = CGPathGetPathBoundingBox(m_path); #else - return CGPathGetBoundingBox(m_path); + bound = CGPathGetBoundingBox(m_path); #endif + return CGRectIsNull(bound) ? CGRectZero : bound; } FloatRect Path::fastBoundingRect() const { - // A bug in CoreGraphics leads to an incorrect bound on paths containing only move-to elements - // with a linecap style that is non-butt. All paths with only move-to elements (regardless of - // linecap) are effectively empty for bounding purposes and here we make it so. - PathHasOnlyMoveToTester tester; - CGPathApply(m_path, &tester, PathHasOnlyMoveToTester::testPathElement); - if (tester.hasOnlyMoveTo()) - return FloatRect(0, 0, 0, 0); - - return CGPathGetBoundingBox(m_path); + CGRect bound = CGPathGetBoundingBox(m_path); + return CGRectIsNull(bound) ? CGRectZero : bound; } FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const @@ -263,7 +198,7 @@ FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const CGRect box = CGContextIsPathEmpty(context) ? CGRectZero : CGContextGetPathBoundingBox(context); CGContextRestoreGState(context); - return box; + return CGRectIsNull(box) ? CGRectZero : box; } void Path::moveTo(const FloatPoint& point) @@ -321,18 +256,12 @@ void Path::clear() bool Path::isEmpty() const { - // The SVG rendering code that uses this method relies on paths with a single move-to - // element, and nothing else, as being empty. Until that code is refactored to avoid - // the dependence on isEmpty, we match the behavior of other platforms. - // When the SVG code is refactored, we could use CGPathIsEmpty(m_path); - PathIsEmptyOrSingleMoveTester tester; - CGPathApply(m_path, &tester, PathIsEmptyOrSingleMoveTester::testPathElement); - return tester.isEmpty(); + return CGPathIsEmpty(m_path); } bool Path::hasCurrentPoint() const { - return !CGPathIsEmpty(m_path); + return !isEmpty(); } FloatPoint Path::currentPoint() const @@ -386,7 +315,7 @@ void Path::apply(void* info, PathApplierFunction function) const void Path::transform(const AffineTransform& transform) { - if (transform.isIdentity() || CGPathIsEmpty(m_path)) + if (transform.isIdentity() || isEmpty()) return; CGMutablePathRef path = CGPathCreateMutable(); diff --git a/Source/WebCore/platform/graphics/chromium/BitmapCanvasLayerTextureUpdater.cpp b/Source/WebCore/platform/graphics/chromium/BitmapCanvasLayerTextureUpdater.cpp index dd931913f..0d97e52ae 100644 --- a/Source/WebCore/platform/graphics/chromium/BitmapCanvasLayerTextureUpdater.cpp +++ b/Source/WebCore/platform/graphics/chromium/BitmapCanvasLayerTextureUpdater.cpp @@ -32,6 +32,7 @@ #include "LayerPainterChromium.h" #include "PlatformColor.h" +#include "PlatformContextSkia.h" namespace WebCore { @@ -77,10 +78,12 @@ LayerTextureUpdater::SampledTexelFormat BitmapCanvasLayerTextureUpdater::sampled LayerTextureUpdater::SampledTexelFormatRGBA : LayerTextureUpdater::SampledTexelFormatBGRA; } -void BitmapCanvasLayerTextureUpdater::prepareToUpdate(const IntRect& contentRect, const IntSize& tileSize, int borderTexels, float contentsScale) +void BitmapCanvasLayerTextureUpdater::prepareToUpdate(const IntRect& contentRect, const IntSize& tileSize, int borderTexels, float contentsScale, IntRect* resultingOpaqueRect) { m_texSubImage.setSubImageSize(tileSize); + bool layerIsOpaque = m_canvas.opaque(); + m_canvas.resize(contentRect.size()); // Assumption: if a tiler is using border texels, then it is because the // layer is likely to be filtered or transformed. Because of it might be @@ -88,7 +91,11 @@ void BitmapCanvasLayerTextureUpdater::prepareToUpdate(const IntRect& contentRect PlatformCanvas::Painter::TextOption textOption = borderTexels ? PlatformCanvas::Painter::GrayscaleText : PlatformCanvas::Painter::SubpixelText; PlatformCanvas::Painter canvasPainter(&m_canvas, textOption); + canvasPainter.skiaContext()->setTrackOpaqueRegion(!layerIsOpaque); paintContents(*canvasPainter.context(), contentRect, contentsScale); + + if (!layerIsOpaque) + *resultingOpaqueRect = canvasPainter.skiaContext()->opaqueRegion().asRect(); } void BitmapCanvasLayerTextureUpdater::updateTextureRect(GraphicsContext3D* context, TextureAllocator* allocator, ManagedTexture* texture, const IntRect& sourceRect, const IntRect& destRect) @@ -99,5 +106,10 @@ void BitmapCanvasLayerTextureUpdater::updateTextureRect(GraphicsContext3D* conte m_texSubImage.upload(locker.pixels(), contentRect(), sourceRect, destRect, texture->format(), context); } +void BitmapCanvasLayerTextureUpdater::setOpaque(bool opaque) +{ + m_canvas.setOpaque(opaque); +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/chromium/BitmapCanvasLayerTextureUpdater.h b/Source/WebCore/platform/graphics/chromium/BitmapCanvasLayerTextureUpdater.h index 153dd2c3c..4e162295b 100644 --- a/Source/WebCore/platform/graphics/chromium/BitmapCanvasLayerTextureUpdater.h +++ b/Source/WebCore/platform/graphics/chromium/BitmapCanvasLayerTextureUpdater.h @@ -60,9 +60,11 @@ public: virtual PassOwnPtr<LayerTextureUpdater::Texture> createTexture(TextureManager*); virtual SampledTexelFormat sampledTexelFormat(GC3Denum textureFormat); - virtual void prepareToUpdate(const IntRect& contentRect, const IntSize& tileSize, int borderTexels, float contentsScale); + virtual void prepareToUpdate(const IntRect& contentRect, const IntSize& tileSize, int borderTexels, float contentsScale, IntRect* resultingOpaqueRect); void updateTextureRect(GraphicsContext3D*, TextureAllocator*, ManagedTexture*, const IntRect& sourceRect, const IntRect& destRect); + virtual void setOpaque(bool); + private: BitmapCanvasLayerTextureUpdater(PassOwnPtr<LayerPainterChromium>, bool useMapTexSubImage); diff --git a/Source/WebCore/platform/graphics/chromium/BitmapSkPictureCanvasLayerTextureUpdater.cpp b/Source/WebCore/platform/graphics/chromium/BitmapSkPictureCanvasLayerTextureUpdater.cpp index 8221dd2e5..e2ab79838 100644 --- a/Source/WebCore/platform/graphics/chromium/BitmapSkPictureCanvasLayerTextureUpdater.cpp +++ b/Source/WebCore/platform/graphics/chromium/BitmapSkPictureCanvasLayerTextureUpdater.cpp @@ -86,10 +86,10 @@ LayerTextureUpdater::SampledTexelFormat BitmapSkPictureCanvasLayerTextureUpdater LayerTextureUpdater::SampledTexelFormatRGBA : LayerTextureUpdater::SampledTexelFormatBGRA; } -void BitmapSkPictureCanvasLayerTextureUpdater::prepareToUpdate(const IntRect& contentRect, const IntSize& tileSize, int borderTexels, float contentsScale) +void BitmapSkPictureCanvasLayerTextureUpdater::prepareToUpdate(const IntRect& contentRect, const IntSize& tileSize, int borderTexels, float contentsScale, IntRect* resultingOpaqueRect) { m_texSubImage.setSubImageSize(tileSize); - SkPictureCanvasLayerTextureUpdater::prepareToUpdate(contentRect, tileSize, borderTexels, contentsScale); + SkPictureCanvasLayerTextureUpdater::prepareToUpdate(contentRect, tileSize, borderTexels, contentsScale, resultingOpaqueRect); } void BitmapSkPictureCanvasLayerTextureUpdater::paintContentsRect(SkCanvas* canvas, const IntRect& sourceRect) diff --git a/Source/WebCore/platform/graphics/chromium/BitmapSkPictureCanvasLayerTextureUpdater.h b/Source/WebCore/platform/graphics/chromium/BitmapSkPictureCanvasLayerTextureUpdater.h index 6f2f10d9b..1c564cdc1 100644 --- a/Source/WebCore/platform/graphics/chromium/BitmapSkPictureCanvasLayerTextureUpdater.h +++ b/Source/WebCore/platform/graphics/chromium/BitmapSkPictureCanvasLayerTextureUpdater.h @@ -59,7 +59,7 @@ public: virtual PassOwnPtr<LayerTextureUpdater::Texture> createTexture(TextureManager*); virtual SampledTexelFormat sampledTexelFormat(GC3Denum textureFormat); - virtual void prepareToUpdate(const IntRect& contentRect, const IntSize& tileSize, int borderTexels, float contentsScale); + virtual void prepareToUpdate(const IntRect& contentRect, const IntSize& tileSize, int borderTexels, float contentsScale, IntRect* resultingOpaqueRect); void paintContentsRect(SkCanvas*, const IntRect& sourceRect); void updateTextureRect(GraphicsContext3D*, GC3Denum format, const IntRect& destRect, const uint8_t* pixels); diff --git a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp index 3408aa56b..6c778bf74 100644 --- a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp @@ -41,9 +41,9 @@ #include "GraphicsContext3D.h" #include "LayerRendererChromium.h" // For the GLC() macro -#if USE(SKIA) #include "GrContext.h" -#endif +#include "SkCanvas.h" +#include "SkDevice.h" namespace WebCore { @@ -53,12 +53,13 @@ PassRefPtr<Canvas2DLayerChromium> Canvas2DLayerChromium::create(GraphicsContext3 } Canvas2DLayerChromium::Canvas2DLayerChromium(GraphicsContext3D* context, const IntSize& size) - : CanvasLayerChromium(0) + : CanvasLayerChromium() , m_context(context) , m_size(size) , m_backTextureId(0) , m_fbo(0) , m_useDoubleBuffering(CCProxy::hasImplThread()) + , m_canvas(0) { if (m_useDoubleBuffering) GLC(m_context, m_fbo = m_context->createFramebuffer()); @@ -81,6 +82,7 @@ void Canvas2DLayerChromium::contentChanged() if (layerTreeHost()) layerTreeHost()->startRateLimiter(m_context); + m_updateRect = FloatRect(FloatPoint(), contentBounds()); setNeedsDisplay(); } @@ -90,7 +92,12 @@ bool Canvas2DLayerChromium::drawsContent() const && m_context && (m_context->getExtensions()->getGraphicsResetStatusARB() == GraphicsContext3D::NO_ERROR); } -void Canvas2DLayerChromium::paintContentsIfDirty() +void Canvas2DLayerChromium::setCanvas(SkCanvas* canvas) +{ + m_canvas = canvas; +} + +void Canvas2DLayerChromium::paintContentsIfDirty(const Region& /* occludedScreenSpace */) { if (!drawsContent()) return; @@ -106,11 +113,15 @@ void Canvas2DLayerChromium::paintContentsIfDirty() bool success = m_context->makeContextCurrent(); ASSERT_UNUSED(success, success); -#if USE(SKIA) + // FIXME: Replace this block of skia code with m_canvas->flush, when that + // API becomes available. + // https://bugs.webkit.org/show_bug.cgi?id=77463 + if (m_canvas) + m_canvas->getDevice()->accessRenderTarget(); // Triggers execution of pending draw operations. + GrContext* grContext = m_context->grContext(); if (grContext) grContext->flush(); -#endif m_context->flush(); } diff --git a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h index 83615a1f2..877224f41 100644 --- a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h @@ -37,9 +37,12 @@ #include "CanvasLayerChromium.h" #include "ManagedTexture.h" +class SkCanvas; + namespace WebCore { class GraphicsContext3D; +class Region; // A layer containing an accelerated 2d canvas class Canvas2DLayerChromium : public CanvasLayerChromium { @@ -52,7 +55,7 @@ public: virtual void contentChanged(); virtual bool drawsContent() const; - virtual void paintContentsIfDirty(); + virtual void paintContentsIfDirty(const Region& occludedScreenSpace); virtual void setLayerTreeHost(CCLayerTreeHost*); virtual void updateCompositorResources(GraphicsContext3D*, CCTextureUpdater&); @@ -60,6 +63,8 @@ public: virtual void unreserveContentsTexture(); virtual void cleanupResources(); + void setCanvas(SkCanvas*); + private: Canvas2DLayerChromium(GraphicsContext3D*, const IntSize&); @@ -76,6 +81,7 @@ private: // synchronize its draws with the canvas updates. bool m_useDoubleBuffering; OwnPtr<ManagedTexture> m_frontTexture; + SkCanvas* m_canvas; }; } diff --git a/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp index c51008cb4..181ba4e58 100644 --- a/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp @@ -40,8 +40,8 @@ namespace WebCore { -CanvasLayerChromium::CanvasLayerChromium(CCLayerDelegate* delegate) - : LayerChromium(delegate) +CanvasLayerChromium::CanvasLayerChromium() + : LayerChromium() { } diff --git a/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.h b/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.h index f4072f5d0..9e8ce7d8c 100644 --- a/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/CanvasLayerChromium.h @@ -44,7 +44,7 @@ public: virtual PassRefPtr<CCLayerImpl> createCCLayerImpl(); protected: - explicit CanvasLayerChromium(CCLayerDelegate*); + CanvasLayerChromium(); }; } diff --git a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp index ef105b53f..34303110f 100644 --- a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp @@ -48,7 +48,7 @@ namespace WebCore { class ContentLayerPainter : public LayerPainterChromium { WTF_MAKE_NONCOPYABLE(ContentLayerPainter); public: - static PassOwnPtr<ContentLayerPainter> create(CCLayerDelegate* delegate) + static PassOwnPtr<ContentLayerPainter> create(ContentLayerDelegate* delegate) { return adoptPtr(new ContentLayerPainter(delegate)); } @@ -65,21 +65,22 @@ public: PlatformSupport::histogramCustomCounts("Renderer4.AccelContentPaintMegapixPerSecond", pixelsPerSec / 1000000, 10, 210, 30); } private: - explicit ContentLayerPainter(CCLayerDelegate* delegate) + explicit ContentLayerPainter(ContentLayerDelegate* delegate) : m_delegate(delegate) { } - CCLayerDelegate* m_delegate; + ContentLayerDelegate* m_delegate; }; -PassRefPtr<ContentLayerChromium> ContentLayerChromium::create(CCLayerDelegate* delegate) +PassRefPtr<ContentLayerChromium> ContentLayerChromium::create(ContentLayerDelegate* delegate) { return adoptRef(new ContentLayerChromium(delegate)); } -ContentLayerChromium::ContentLayerChromium(CCLayerDelegate* delegate) - : TiledLayerChromium(delegate) +ContentLayerChromium::ContentLayerChromium(ContentLayerDelegate* delegate) + : TiledLayerChromium() + , m_delegate(delegate) { } @@ -87,7 +88,12 @@ ContentLayerChromium::~ContentLayerChromium() { } -void ContentLayerChromium::paintContentsIfDirty() +bool ContentLayerChromium::drawsContent() const +{ + return TiledLayerChromium::drawsContent() && m_delegate; +} + +void ContentLayerChromium::paintContentsIfDirty(const Region& /* occludedScreenSpace */) { updateTileSizeAndTilingOption(); @@ -119,18 +125,21 @@ void ContentLayerChromium::idlePaintContentsIfDirty() void ContentLayerChromium::createTextureUpdater(const CCLayerTreeHost* host) { #if USE(SKIA) - if (host->settings().acceleratePainting) { + if (host->settings().acceleratePainting) m_textureUpdater = FrameBufferSkPictureCanvasLayerTextureUpdater::create(ContentLayerPainter::create(m_delegate)); - return; - } - - if (host->settings().perTilePainting) { + else if (host->settings().perTilePainting) m_textureUpdater = BitmapSkPictureCanvasLayerTextureUpdater::create(ContentLayerPainter::create(m_delegate), host->layerRendererCapabilities().usingMapSub); - return; - } + else #endif // USE(SKIA) + m_textureUpdater = BitmapCanvasLayerTextureUpdater::create(ContentLayerPainter::create(m_delegate), host->layerRendererCapabilities().usingMapSub); + m_textureUpdater->setOpaque(opaque()); +} - m_textureUpdater = BitmapCanvasLayerTextureUpdater::create(ContentLayerPainter::create(m_delegate), host->layerRendererCapabilities().usingMapSub); +void ContentLayerChromium::setOpaque(bool opaque) +{ + LayerChromium::setOpaque(opaque); + if (m_textureUpdater) + m_textureUpdater->setOpaque(opaque); } } diff --git a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h index c3df1c20c..5eff6a3d6 100644 --- a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h @@ -41,24 +41,38 @@ namespace WebCore { class LayerTilerChromium; class LayerTextureUpdater; +class Region; + +class ContentLayerDelegate { +public: + virtual ~ContentLayerDelegate() { } + virtual void paintContents(GraphicsContext&, const IntRect& clip) = 0; +}; // A Layer that requires a GraphicsContext to render its contents. class ContentLayerChromium : public TiledLayerChromium { public: - static PassRefPtr<ContentLayerChromium> create(CCLayerDelegate*); + static PassRefPtr<ContentLayerChromium> create(ContentLayerDelegate*); virtual ~ContentLayerChromium(); - virtual void paintContentsIfDirty(); + void clearDelegate() { m_delegate = 0; } + + virtual bool drawsContent() const; + virtual void paintContentsIfDirty(const Region& occludedScreenSpace); virtual void idlePaintContentsIfDirty(); + virtual void setOpaque(bool); + protected: - explicit ContentLayerChromium(CCLayerDelegate*); + explicit ContentLayerChromium(ContentLayerDelegate*); + private: virtual void createTextureUpdater(const CCLayerTreeHost*); virtual LayerTextureUpdater* textureUpdater() const { return m_textureUpdater.get(); } + ContentLayerDelegate* m_delegate; RefPtr<LayerTextureUpdater> m_textureUpdater; }; diff --git a/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp b/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp index ead6aa3a2..551adf769 100644 --- a/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp @@ -143,7 +143,7 @@ void DrawingBuffer::publishToPlatformLayer() PlatformLayer* DrawingBuffer::platformLayer() { if (!m_platformLayer) { - m_platformLayer = WebGLLayerChromium::create(0); + m_platformLayer = WebGLLayerChromium::create(); m_platformLayer->setDrawingBuffer(this); m_platformLayer->setOpaque(!m_context->getContextAttributes().alpha); } diff --git a/Source/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp index 9f5bd4919..a50e6abc4 100644 --- a/Source/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2006, 2007 Apple Computer, Inc. - * Copyright (c) 2006, 2007, 2008, 2009 Google Inc. All rights reserved. + * Copyright (c) 2006, 2007, 2008, 2009, 2012 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 @@ -36,6 +36,7 @@ #include "FontUtilsChromiumWin.h" #include "HashMap.h" #include "HashSet.h" +#include "HWndDC.h" #include "PlatformSupport.h" #include "SimpleFontData.h" #include <unicode/uniset.h> @@ -241,7 +242,7 @@ static HFONT createFontIndirectAndGetWinName(const String& family, LOGFONT* winf if (!hfont) return 0; - HDC dc = GetDC(0); + HWndDC dc(0); HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont)); WCHAR name[LF_FACESIZE]; unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name); @@ -249,7 +250,6 @@ static HFONT createFontIndirectAndGetWinName(const String& family, LOGFONT* winf resultLength--; // ignore the null terminator SelectObject(dc, oldFont); - ReleaseDC(0, dc); *winName = String(name, resultLength); return hfont; } @@ -279,7 +279,7 @@ static bool fontContainsCharacter(const FontPlatformData* fontData, return it->second->contains(character); HFONT hfont = fontData->hfont(); - HDC hdc = GetDC(0); + HWndDC hdc(0); HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(hdc, hfont)); int count = GetFontUnicodeRanges(hdc, 0); if (!count && PlatformSupport::ensureFontLoaded(hfont)) @@ -287,7 +287,6 @@ static bool fontContainsCharacter(const FontPlatformData* fontData, if (!count) { LOG_ERROR("Unable to get the font unicode range after second attempt"); SelectObject(hdc, oldFont); - ReleaseDC(0, hdc); return true; } @@ -299,7 +298,6 @@ static bool fontContainsCharacter(const FontPlatformData* fontData, count = GetFontUnicodeRanges(hdc, glyphset); ASSERT(count > 0); SelectObject(hdc, oldFont); - ReleaseDC(0, hdc); // FIXME: consider doing either of the following two: // 1) port back ICU 4.0's faster look-up code for UnicodeSet @@ -571,11 +569,10 @@ SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& desc // both GetTextFace() and EnumFontFamilies() return the localized name. So, // FontCache::createFontPlatformData() does not filter out the fonts // returned by this EnumFontFamilies() call. - HDC dc = GetDC(0); + HWndDC dc(0); if (dc) { GetLastResortFallbackFontProcData procData(this, &description, shouldRetain, fallbackFontName); EnumFontFamilies(dc, 0, getLastResortFallbackFontProc, reinterpret_cast<LPARAM>(&procData)); - ReleaseDC(0, dc); if (procData.m_fontData) return procData.m_fontData; @@ -587,7 +584,7 @@ SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& desc void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) { - HDC hdc = GetDC(0); + HWndDC hdc(0); LOGFONT logFont; logFont.lfCharSet = DEFAULT_CHARSET; @@ -599,8 +596,6 @@ void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigne TraitsInFamilyProcData procData(familyName); EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0); copyToVector(procData.m_traitsMasks, traitsMasks); - - ReleaseDC(0, hdc); } FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) diff --git a/Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp index 46f9ecdad..a89a18232 100644 --- a/Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2006, 2007 Apple Computer, Inc. - * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved. + * Copyright (c) 2006, 2007, 2008, 2009, 2012 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 @@ -36,6 +36,7 @@ #include <objidl.h> #include <mlang.h> +#include "HWndDC.h" #include "PlatformSupport.h" #include "SkTypeface_win.h" #include "SkiaFontWin.h" @@ -161,7 +162,7 @@ SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties); if (result == E_PENDING) { - HDC dc = GetDC(0); + HWndDC dc(0); HGDIOBJ oldFont = SelectObject(dc, hfont()); HRESULT hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties); @@ -177,7 +178,6 @@ SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const } SelectObject(dc, oldFont); - ReleaseDC(0, dc); } } return m_scriptFontProperties; diff --git a/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp index a4798ddd5..711b896ac 100644 --- a/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2007, 2008, 2009, 2010, Google Inc. All rights reserved. + * Copyright (c) 2006, 2007, 2008, 2009, 2010, 2012 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 @@ -33,6 +33,7 @@ #include <limits> +#include "HWndDC.h" #include "PlatformString.h" #include "UniscribeHelper.h" #include <unicode/locid.h> @@ -50,14 +51,13 @@ bool isFontPresent(const UChar* fontName) fontName); if (!hfont) return false; - HDC dc = GetDC(0); + HWndDC dc(0); HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont)); WCHAR actualFontName[LF_FACESIZE]; GetTextFace(dc, LF_FACESIZE, actualFontName); actualFontName[LF_FACESIZE - 1] = 0; SelectObject(dc, oldFont); DeleteObject(hfont); - ReleaseDC(0, dc); // We don't have to worry about East Asian fonts with locale-dependent // names here for now. return !wcscmp(fontName, actualFontName); @@ -241,24 +241,22 @@ const int kUndefinedAscent = std::numeric_limits<int>::min(); // kUndefinedAscent is returned, instead. int getAscent(HFONT hfont) { - HDC dc = GetDC(0); + HWndDC dc(0); HGDIOBJ oldFont = SelectObject(dc, hfont); TEXTMETRIC tm; BOOL gotMetrics = GetTextMetrics(dc, &tm); SelectObject(dc, oldFont); - ReleaseDC(0, dc); return gotMetrics ? tm.tmAscent : kUndefinedAscent; } WORD getSpaceGlyph(HFONT hfont) { - HDC dc = GetDC(0); + HWndDC dc(0); HGDIOBJ oldFont = SelectObject(dc, hfont); WCHAR space = L' '; WORD spaceGlyph = 0; GetGlyphIndices(dc, &space, 1, &spaceGlyph, 0); SelectObject(dc, oldFont); - ReleaseDC(0, dc); return spaceGlyph; } diff --git a/Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp index f5ab22156..f5425b9df 100644 --- a/Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009 Google Inc. All rights reserved. + * Copyright (c) 2008, 2009, 2012 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 @@ -34,6 +34,7 @@ #include "Font.h" #include "GlyphPageTreeNode.h" +#include "HWndDC.h" #include "PlatformSupport.h" #include "SimpleFontData.h" #include "SystemInfo.h" @@ -49,15 +50,27 @@ static void fillEmptyGlyphs(GlyphPage* page) page->setGlyphDataForIndex(i, 0, 0); } -// Lazily initializes space glyph -static Glyph initSpaceGlyph(HDC dc, Glyph* spaceGlyph) +// Convert characters to glyph ids by GetGlyphIndices(), during which, we +// ensure the font is loaded in memory to make it work in a sandboxed process. +static bool getGlyphIndices(HFONT font, HDC dc, const UChar* characters, unsigned charactersLength, WORD* glyphBuffer, DWORD flag) { - if (*spaceGlyph) - return *spaceGlyph; + if (GetGlyphIndices(dc, characters, charactersLength, glyphBuffer, flag) != GDI_ERROR) + return true; + if (PlatformSupport::ensureFontLoaded(font)) { + if (GetGlyphIndices(dc, characters, charactersLength, glyphBuffer, flag) != GDI_ERROR) + return true; + // FIXME: Handle gracefully the error if this call also fails. + // See http://crbug.com/6401 + LOG_ERROR("Unable to get the glyph indices after second attempt"); + } + return false; +} +// Initializes space glyph +static bool initSpaceGlyph(HFONT font, HDC dc, Glyph* spaceGlyph) +{ static wchar_t space = ' '; - GetGlyphIndices(dc, &space, 1, spaceGlyph, 0); - return *spaceGlyph; + return getGlyphIndices(font, dc, &space, 1, spaceGlyph, 0); } // Fills |length| glyphs starting at |offset| in a |page| in the Basic @@ -68,27 +81,25 @@ static bool fillBMPGlyphs(unsigned offset, unsigned length, UChar* buffer, GlyphPage* page, - const SimpleFontData* fontData, - bool recurse) + const SimpleFontData* fontData) { - HDC dc = GetDC((HWND)0); + HWndDC dc(0); HGDIOBJ oldFont = SelectObject(dc, fontData->platformData().hfont()); TEXTMETRIC tm = {0}; if (!GetTextMetrics(dc, &tm)) { - SelectObject(dc, oldFont); - ReleaseDC(0, dc); + if (PlatformSupport::ensureFontLoaded(fontData->platformData().hfont())) { + if (!GetTextMetrics(dc, &tm)) { + // FIXME: Handle gracefully the error if this call also fails. + // See http://crbug.com/6401 + LOG_ERROR("Unable to get the text metrics after second attempt"); - if (recurse) { - if (PlatformSupport::ensureFontLoaded(fontData->platformData().hfont())) - return fillBMPGlyphs(offset, length, buffer, page, fontData, false); - - fillEmptyGlyphs(page); - return false; + SelectObject(dc, oldFont); + fillEmptyGlyphs(page); + return false; + } } else { - // FIXME: Handle gracefully the error if this call also fails. - // See http://crbug.com/6401 - LOG_ERROR("Unable to get the text metrics after second attempt"); + SelectObject(dc, oldFont); fillEmptyGlyphs(page); return false; } @@ -128,7 +139,11 @@ static bool fillBMPGlyphs(unsigned offset, // Also according to Jungshik and Hironori's suggestion and modification // we treat turetype and raster Font as different way when windows version // is less than Vista. - GetGlyphIndices(dc, buffer, length, localGlyphBuffer, GGI_MARK_NONEXISTING_GLYPHS); + if (!getGlyphIndices(fontData->platformData().hfont(), dc, buffer, length, localGlyphBuffer, GGI_MARK_NONEXISTING_GLYPHS)) { + SelectObject(dc, oldFont); + fillEmptyGlyphs(page); + return false; + } // Copy the output to the GlyphPage bool haveGlyphs = false; @@ -138,6 +153,7 @@ static bool fillBMPGlyphs(unsigned offset, invalidGlyph = 0x1F; Glyph spaceGlyph = 0; // Glyph for a space. Lazily filled. + bool spaceGlyphInitialized = false; for (unsigned i = 0; i < length; i++) { UChar c = buffer[i]; @@ -149,7 +165,12 @@ static bool fillBMPGlyphs(unsigned offset, if (Font::treatAsSpace(c)) { // Hard code the glyph indices for characters that should be // treated like spaces. - glyph = initSpaceGlyph(dc, &spaceGlyph); + if (!spaceGlyphInitialized) { + // If initSpaceGlyph fails, spaceGlyph stays 0 (= glyph is not present). + initSpaceGlyph(fontData->platformData().hfont(), dc, &spaceGlyph); + spaceGlyphInitialized = true; + } + glyph = spaceGlyph; } else if (glyph == invalidGlyph) { // WebKit expects both the glyph index and FontData // pointer to be 0 if the glyph is not present @@ -161,7 +182,6 @@ static bool fillBMPGlyphs(unsigned offset, } SelectObject(dc, oldFont); - ReleaseDC(0, dc); return haveGlyphs; } @@ -222,7 +242,7 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* characterBuffer, // FIXME: Add assertions to make sure that buffer is entirely in BMP // or entirely in non-BMP. if (bufferLength == length) - return fillBMPGlyphs(offset, length, characterBuffer, this, fontData, true); + return fillBMPGlyphs(offset, length, characterBuffer, this, fontData); if (bufferLength == 2 * length) { // A non-BMP input buffer will be twice as long as output glyph buffer diff --git a/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp index 67e05f8dc..31a5118ff 100644 --- a/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp @@ -82,17 +82,13 @@ GraphicsLayerChromium::GraphicsLayerChromium(GraphicsLayerClient* client) GraphicsLayerChromium::~GraphicsLayerChromium() { if (m_layer) { - m_layer->setDelegate(0); + m_layer->clearDelegate(); m_layer->clearRenderSurface(); } - if (m_contentsLayer) { - m_contentsLayer->setDelegate(0); + if (m_contentsLayer) m_contentsLayer->clearRenderSurface(); - } - if (m_transformLayer) { - m_transformLayer->setDelegate(0); + if (m_transformLayer) m_transformLayer->clearRenderSurface(); - } } void GraphicsLayerChromium::setName(const String& inName) @@ -327,7 +323,7 @@ void GraphicsLayerChromium::setContentsToImage(Image* image) bool childrenChanged = false; if (image) { if (!m_contentsLayer.get() || m_contentsLayerPurpose != ContentsLayerForImage) { - RefPtr<ImageLayerChromium> imageLayer = ImageLayerChromium::create(this); + RefPtr<ImageLayerChromium> imageLayer = ImageLayerChromium::create(); setupContentsLayer(imageLayer.get()); m_contentsLayerPurpose = ContentsLayerForImage; childrenChanged = true; @@ -353,7 +349,6 @@ void GraphicsLayerChromium::setContentsToCanvas(PlatformLayer* platformLayer) { bool childrenChanged = false; if (platformLayer) { - platformLayer->setDelegate(this); if (m_contentsLayer.get() != platformLayer) { setupContentsLayer(platformLayer); m_contentsLayerPurpose = ContentsLayerForCanvas; @@ -383,7 +378,6 @@ void GraphicsLayerChromium::setContentsToMedia(PlatformLayer* layer) m_contentsLayerPurpose = ContentsLayerForVideo; childrenChanged = true; } - layer->setDelegate(this); layer->setNeedsDisplay(); updateContentsRect(); } else { @@ -528,7 +522,7 @@ void GraphicsLayerChromium::updateLayerPreserves3D() { if (m_preserves3D && !m_transformLayer) { // Create the transform layer. - m_transformLayer = LayerChromium::create(this); + m_transformLayer = LayerChromium::create(); m_transformLayer->setPreserves3D(true); // Copy the position from this layer. diff --git a/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h index dfa109d3e..39b367b9d 100644 --- a/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h @@ -33,6 +33,7 @@ #if USE(ACCELERATED_COMPOSITING) +#include "ContentLayerChromium.h" #include "LayerChromium.h" #include "GraphicsContext.h" #include "GraphicsLayer.h" @@ -41,7 +42,7 @@ namespace WebCore { class LayerChromium; -class GraphicsLayerChromium : public GraphicsLayer, public CCLayerDelegate { +class GraphicsLayerChromium : public GraphicsLayer, public ContentLayerDelegate { public: GraphicsLayerChromium(GraphicsLayerClient*); virtual ~GraphicsLayerChromium(); @@ -97,7 +98,7 @@ public: virtual void setDebugBorder(const Color&, float borderWidth); virtual void deviceOrPageScaleFactorChanged(); - // The following functions implement the CCLayerDelegate interface. + // ContentLayerDelegate implementation. virtual void paintContents(GraphicsContext&, const IntRect& clip); // Exposed for tests. @@ -130,7 +131,7 @@ private: String m_nameBase; - RefPtr<LayerChromium> m_layer; + RefPtr<ContentLayerChromium> m_layer; RefPtr<LayerChromium> m_transformLayer; RefPtr<LayerChromium> m_contentsLayer; diff --git a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp index a0fb35f02..831cbe809 100644 --- a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp @@ -83,7 +83,7 @@ public: LayerTextureUpdater::SampledTexelFormatRGBA : LayerTextureUpdater::SampledTexelFormatBGRA; } - virtual void prepareToUpdate(const IntRect& contentRect, const IntSize& tileSize, int /* borderTexels */, float /* contentsScale */) + virtual void prepareToUpdate(const IntRect& contentRect, const IntSize& tileSize, int /* borderTexels */, float /* contentsScale */, IntRect* /* resultingOpaqueRect */) { m_texSubImage.setSubImageSize(tileSize); } @@ -129,13 +129,13 @@ private: LayerTextureSubImage m_texSubImage; }; -PassRefPtr<ImageLayerChromium> ImageLayerChromium::create(CCLayerDelegate* delegate) +PassRefPtr<ImageLayerChromium> ImageLayerChromium::create() { - return adoptRef(new ImageLayerChromium(delegate)); + return adoptRef(new ImageLayerChromium()); } -ImageLayerChromium::ImageLayerChromium(CCLayerDelegate* delegate) - : TiledLayerChromium(delegate) +ImageLayerChromium::ImageLayerChromium() + : TiledLayerChromium() , m_imageForCurrentFrame(0) { } @@ -158,7 +158,7 @@ void ImageLayerChromium::setContents(Image* contents) setNeedsDisplay(); } -void ImageLayerChromium::paintContentsIfDirty() +void ImageLayerChromium::paintContentsIfDirty(const Region& /* occludedScreenSpace */) { if (m_needsDisplay) { m_textureUpdater->updateFromImage(m_contents->nativeImageForCurrentFrame()); diff --git a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h index 1259a663c..ab5c1b27b 100644 --- a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h @@ -45,21 +45,22 @@ namespace WebCore { class Image; class ImageLayerTextureUpdater; +class Region; // A Layer that contains only an Image element. class ImageLayerChromium : public TiledLayerChromium { public: - static PassRefPtr<ImageLayerChromium> create(CCLayerDelegate*); + static PassRefPtr<ImageLayerChromium> create(); virtual ~ImageLayerChromium(); virtual bool drawsContent() const; - virtual void paintContentsIfDirty(); + virtual void paintContentsIfDirty(const Region& occludedScreenSpace); virtual bool needsContentsScale() const; void setContents(Image* image); private: - explicit ImageLayerChromium(CCLayerDelegate*); + ImageLayerChromium(); virtual void createTextureUpdater(const CCLayerTreeHost*); void setTilingOption(TilingOption); diff --git a/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp index 2df05b59c..b2f70141b 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp @@ -39,6 +39,7 @@ #include "NativeImageSkia.h" #include "PlatformContextSkia.h" #endif +#include "Region.h" #include "RenderLayerBacking.h" #include "TextStream.h" #include "skia/ext/platform_canvas.h" @@ -49,19 +50,19 @@ using namespace std; static int s_nextLayerId = 1; -PassRefPtr<LayerChromium> LayerChromium::create(CCLayerDelegate* delegate) +PassRefPtr<LayerChromium> LayerChromium::create() { - return adoptRef(new LayerChromium(delegate)); + return adoptRef(new LayerChromium()); } -LayerChromium::LayerChromium(CCLayerDelegate* delegate) - : m_delegate(delegate) - , m_needsDisplay(false) +LayerChromium::LayerChromium() + : m_needsDisplay(false) , m_layerId(s_nextLayerId++) , m_parent(0) , m_scrollable(false) , m_anchorPoint(0.5, 0.5) , m_backgroundColor(0, 0, 0, 0) + , m_backgroundCoversViewport(false) , m_debugBorderWidth(0) , m_opacity(1.0) , m_anchorPointZ(0) @@ -72,6 +73,7 @@ LayerChromium::LayerChromium(CCLayerDelegate* delegate) , m_usesLayerClipping(false) , m_isNonCompositedContent(false) , m_preserves3D(false) + , m_alwaysReserveTextures(false) , m_replicaLayer(0) , m_drawOpacity(0) , m_targetRenderSurface(0) @@ -94,19 +96,6 @@ void LayerChromium::cleanupResources() { } -void LayerChromium::cleanupResourcesRecursive() -{ - for (size_t i = 0; i < children().size(); ++i) - children()[i]->cleanupResourcesRecursive(); - - if (maskLayer()) - maskLayer()->cleanupResourcesRecursive(); - if (replicaLayer()) - replicaLayer()->cleanupResourcesRecursive(); - - cleanupResources(); -} - void LayerChromium::setIsNonCompositedContent(bool isNonCompositedContent) { m_isNonCompositedContent = isNonCompositedContent; @@ -285,6 +274,14 @@ void LayerChromium::setBackgroundColor(const Color& backgroundColor) setNeedsCommit(); } +void LayerChromium::setBackgroundCoversViewport(bool backgroundCoversViewport) +{ + if (m_backgroundCoversViewport == backgroundCoversViewport) + return; + m_backgroundCoversViewport = backgroundCoversViewport; + setNeedsCommit(); +} + void LayerChromium::setMasksToBounds(bool masksToBounds) { if (m_masksToBounds == masksToBounds) @@ -330,7 +327,7 @@ void LayerChromium::setOpaque(bool opaque) if (m_opaque == opaque) return; m_opaque = opaque; - setNeedsCommit(); + setNeedsDisplay(); } void LayerChromium::setPosition(const FloatPoint& position) @@ -416,6 +413,7 @@ void LayerChromium::pushPropertiesTo(CCLayerImpl* layer) layer->setAnchorPoint(m_anchorPoint); layer->setAnchorPointZ(m_anchorPointZ); layer->setBackgroundColor(m_backgroundColor); + layer->setBackgroundCoversViewport(m_backgroundCoversViewport); layer->setBounds(m_bounds); layer->setContentBounds(contentBounds()); layer->setDebugBorderColor(m_debugBorderColor); @@ -472,6 +470,35 @@ void LayerChromium::setContentsScale(float contentsScale) setNeedsDisplay(); } +TransformationMatrix LayerChromium::contentToScreenSpaceTransform() const +{ + IntSize boundsInLayerSpace = bounds(); + IntSize boundsInContentSpace = contentBounds(); + + TransformationMatrix transform = screenSpaceTransform(); + + // Scale from content space to layer space + transform.scaleNonUniform(boundsInLayerSpace.width() / static_cast<double>(boundsInContentSpace.width()), + boundsInLayerSpace.height() / static_cast<double>(boundsInContentSpace.height())); + + return transform; +} + +void LayerChromium::addSelfToOccludedScreenSpace(Region& occludedScreenSpace) +{ + if (!opaque() || drawOpacity() != 1 || !isPaintedAxisAlignedInScreen()) + return; + + FloatRect targetRect = contentToScreenSpaceTransform().mapRect(FloatRect(visibleLayerRect())); + occludedScreenSpace.unite(enclosedIntRect(targetRect)); +} + +bool LayerChromium::isPaintedAxisAlignedInScreen() const +{ + FloatQuad quad = contentToScreenSpaceTransform().mapQuad(FloatQuad(visibleLayerRect())); + return quad.isRectilinear(); +} + void LayerChromium::createRenderSurface() { ASSERT(!m_renderSurface); diff --git a/Source/WebCore/platform/graphics/chromium/LayerChromium.h b/Source/WebCore/platform/graphics/chromium/LayerChromium.h index 87f5056f3..764f73015 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/LayerChromium.h @@ -55,19 +55,14 @@ class CCLayerImpl; class CCLayerTreeHost; class CCTextureUpdater; class GraphicsContext3D; - -class CCLayerDelegate { -public: - virtual ~CCLayerDelegate() { } - virtual void paintContents(GraphicsContext&, const IntRect& clip) = 0; -}; +class Region; // Base class for composited layers. Special layer types are derived from // this class. class LayerChromium : public RefCounted<LayerChromium> { friend class LayerTilerChromium; public: - static PassRefPtr<LayerChromium> create(CCLayerDelegate*); + static PassRefPtr<LayerChromium> create(); virtual ~LayerChromium(); @@ -90,6 +85,9 @@ public: void setBackgroundColor(const Color&); Color backgroundColor() const { return m_backgroundColor; } + void setBackgroundCoversViewport(bool); + bool backgroundCoversViewport() const { return m_backgroundCoversViewport; } + void setBounds(const IntSize&); const IntSize& bounds() const { return m_bounds; } virtual IntSize contentBounds() const { return bounds(); } @@ -110,7 +108,7 @@ public: void setOpacity(float); float opacity() const { return m_opacity; } - void setOpaque(bool); + virtual void setOpaque(bool); bool opaque() const { return m_opaque; } void setPosition(const FloatPoint&); @@ -149,8 +147,6 @@ public: virtual void setLayerTreeHost(CCLayerTreeHost*); - void setDelegate(CCLayerDelegate* delegate) { m_delegate = delegate; } - void setIsDrawable(bool); void setReplicaLayer(LayerChromium*); @@ -158,7 +154,7 @@ public: // These methods typically need to be overwritten by derived classes. virtual bool drawsContent() const { return m_isDrawable; } - virtual void paintContentsIfDirty() { } + virtual void paintContentsIfDirty(const Region& /* occludedScreenSpace */) { } virtual void idlePaintContentsIfDirty() { } virtual void updateCompositorResources(GraphicsContext3D*, CCTextureUpdater&) { } virtual void setIsMask(bool) { } @@ -187,8 +183,10 @@ public: void setClipRect(const IntRect& clipRect) { m_clipRect = clipRect; } RenderSurfaceChromium* targetRenderSurface() const { return m_targetRenderSurface; } void setTargetRenderSurface(RenderSurfaceChromium* surface) { m_targetRenderSurface = surface; } + // This moves from layer space, with origin in the center to target space with origin in the top left const TransformationMatrix& drawTransform() const { return m_drawTransform; } void setDrawTransform(const TransformationMatrix& matrix) { m_drawTransform = matrix; } + // This moves from layer space, with origin the top left to screen space with origin in the top left const TransformationMatrix& screenSpaceTransform() const { return m_screenSpaceTransform; } void setScreenSpaceTransform(const TransformationMatrix& matrix) { m_screenSpaceTransform = matrix; } const IntRect& drawableContentRect() const { return m_drawableContentRect; } @@ -196,22 +194,33 @@ public: float contentsScale() const { return m_contentsScale; } void setContentsScale(float); + TransformationMatrix contentToScreenSpaceTransform() const; + + // Adds any opaque visible pixels to the occluded region. + virtual void addSelfToOccludedScreenSpace(Region& occludedScreenSpace); + // Returns true if any of the layer's descendants has content to draw. bool descendantDrawsContent(); virtual void contentChanged() { } CCLayerTreeHost* layerTreeHost() const { return m_layerTreeHost.get(); } - void cleanupResourcesRecursive(); + + // Reserve any textures needed for this layer. + virtual void reserveTextures() { } + + void setAlwaysReserveTextures(bool alwaysReserveTextures) { m_alwaysReserveTextures = alwaysReserveTextures; } + bool alwaysReserveTextures() const { return m_alwaysReserveTextures; } protected: - CCLayerDelegate* m_delegate; - explicit LayerChromium(CCLayerDelegate*); + LayerChromium(); // This is called to clean up resources being held in the same context as // layerRendererContext(). Subclasses should override this method if they // hold context-dependent resources such as textures. virtual void cleanupResources(); + bool isPaintedAxisAlignedInScreen() const; + void setNeedsCommit(); // This flag is set when layer need repainting/updating. @@ -220,6 +229,7 @@ protected: // The update rect is the region of the compositor resource that was actually updated by the compositor. // For layers that may do updating outside the compositor's control (i.e. plugin layers), this information // is not available and the update rect will remain empty. + // Note this rect is in layer space (not content space). FloatRect m_updateRect; RefPtr<LayerChromium> m_maskLayer; @@ -258,6 +268,7 @@ private: FloatPoint m_position; FloatPoint m_anchorPoint; Color m_backgroundColor; + bool m_backgroundCoversViewport; Color m_debugBorderColor; float m_debugBorderWidth; float m_opacity; @@ -269,6 +280,7 @@ private: bool m_usesLayerClipping; bool m_isNonCompositedContent; bool m_preserves3D; + bool m_alwaysReserveTextures; TransformationMatrix m_transform; TransformationMatrix m_sublayerTransform; diff --git a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp index 933e78253..4f76dd9a9 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp @@ -52,16 +52,18 @@ #include "TrackingTextureAllocator.h" #include "TreeSynchronizer.h" #include "WebGLLayerChromium.h" -#include "cc/CCCustomLayerDrawQuad.h" +#include "cc/CCCanvasDrawQuad.h" #include "cc/CCDamageTracker.h" #include "cc/CCDebugBorderDrawQuad.h" #include "cc/CCLayerImpl.h" #include "cc/CCLayerTreeHostCommon.h" +#include "cc/CCPluginDrawQuad.h" #include "cc/CCProxy.h" #include "cc/CCRenderPass.h" #include "cc/CCRenderSurfaceDrawQuad.h" #include "cc/CCSolidColorDrawQuad.h" #include "cc/CCTileDrawQuad.h" +#include "cc/CCVideoDrawQuad.h" #if USE(SKIA) #include "Extensions3D.h" #include "GrContext.h" @@ -161,10 +163,6 @@ private: PassOwnPtr<LayerRendererChromium> LayerRendererChromium::create(CCLayerTreeHostImpl* owner, PassRefPtr<GraphicsContext3D> context) { -#if USE(SKIA) - if (owner->settings().acceleratePainting && !contextSupportsAcceleratedPainting(context.get())) - return nullptr; -#endif OwnPtr<LayerRendererChromium> layerRenderer(adoptPtr(new LayerRendererChromium(owner, context))); if (!layerRenderer->initialize()) return nullptr; @@ -189,8 +187,10 @@ bool LayerRendererChromium::initialize() if (!m_context->makeContextCurrent()) return false; - if (settings().acceleratePainting) +#if USE(SKIA) + if (settings().acceleratePainting && contextSupportsAcceleratedPainting(m_context.get())) m_capabilities.usingAcceleratedPainting = true; +#endif WebCore::Extensions3D* extensions = m_context->getExtensions(); m_capabilities.contextHasCachedFrontBuffer = extensions->supports("GL_CHROMIUM_front_buffer_cached"); @@ -422,8 +422,14 @@ void LayerRendererChromium::drawQuad(const CCDrawQuad* quad, const FloatRect& su case CCDrawQuad::TiledContent: drawTileQuad(quad->toTileDrawQuad()); break; - case CCDrawQuad::CustomLayer: - drawCustomLayerQuad(quad->toCustomLayerDrawQuad()); + case CCDrawQuad::CanvasContent: + drawCanvasQuad(quad->toCanvasDrawQuad()); + break; + case CCDrawQuad::VideoContent: + drawVideoQuad(quad->toVideoDrawQuad()); + break; + case CCDrawQuad::PluginContent: + drawPluginQuad(quad->toPluginDrawQuad()); break; } } @@ -536,7 +542,7 @@ static void findTileProgramUniforms(LayerRendererChromium* layerRenderer, const void LayerRendererChromium::drawTileQuad(const CCTileDrawQuad* quad) { - const IntRect& tileRect = quad->quadRect(); + const IntRect& tileRect = quad->quadVisibleRect(); FloatRect clampRect(tileRect); // Clamp texture coordinates to avoid sampling outside the layer @@ -552,7 +558,8 @@ void LayerRendererChromium::drawTileQuad(const CCTileDrawQuad* quad) clampRect.inflateY(-clampY); FloatSize clampOffset = clampRect.minXMinYCorner() - FloatRect(tileRect).minXMinYCorner(); - FloatPoint textureOffset = quad->textureOffset() + clampOffset; + FloatPoint textureOffset = quad->textureOffset() + clampOffset + + IntPoint(quad->quadVisibleRect().location() - quad->quadRect().location()); // Map clamping rectangle to unit square. float vertexTexTranslateX = -clampRect.x() / clampRect.width(); @@ -615,13 +622,14 @@ void LayerRendererChromium::drawTileQuad(const CCTileDrawQuad* quad) CCLayerQuad::Edge topEdge(topLeft, topRight); CCLayerQuad::Edge rightEdge(topRight, bottomRight); - if (quad->topEdgeAA()) + // Only apply anti-aliasing to edges not clipped during culling. + if (quad->topEdgeAA() && quad->quadVisibleRect().y() == quad->quadRect().y()) topEdge = deviceLayerEdges.top(); - if (quad->leftEdgeAA()) + if (quad->leftEdgeAA() && quad->quadVisibleRect().x() == quad->quadRect().x()) leftEdge = deviceLayerEdges.left(); - if (quad->rightEdgeAA()) + if (quad->rightEdgeAA() && quad->quadVisibleRect().maxX() == quad->quadRect().maxX()) rightEdge = deviceLayerEdges.right(); - if (quad->bottomEdgeAA()) + if (quad->bottomEdgeAA() && quad->quadVisibleRect().maxY() == quad->quadRect().maxY()) bottomEdge = deviceLayerEdges.bottom(); float sign = FloatQuad(tileRect).isCounterclockwise() ? -1 : 1; @@ -659,7 +667,38 @@ void LayerRendererChromium::drawTileQuad(const CCTileDrawQuad* quad) drawTexturedQuad(quad->quadTransform(), tileRect.width(), tileRect.height(), quad->opacity(), localQuad, uniforms.matrixLocation, uniforms.alphaLocation, uniforms.pointLocation); } -void LayerRendererChromium::drawCustomLayerQuad(const CCCustomLayerDrawQuad* quad) +void LayerRendererChromium::drawCanvasQuad(const CCCanvasDrawQuad* quad) +{ + ASSERT(CCProxy::isImplThread()); + const CCCanvasLayerImpl::Program* program = canvasLayerProgram(); + ASSERT(program && program->initialized()); + GLC(context(), context()->activeTexture(GraphicsContext3D::TEXTURE0)); + GLC(context(), context()->bindTexture(GraphicsContext3D::TEXTURE_2D, quad->textureId())); + GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR)); + GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); + + if (quad->hasAlpha() && !quad->premultipliedAlpha()) + GLC(context(), context()->blendFunc(GraphicsContext3D::SRC_ALPHA, GraphicsContext3D::ONE_MINUS_SRC_ALPHA)); + + const IntSize& bounds = quad->quadRect().size(); + + GLC(context(), context()->useProgram(program->program())); + GLC(context(), context()->uniform1i(program->fragmentShader().samplerLocation(), 0)); + drawTexturedQuad(quad->layerTransform(), bounds.width(), bounds.height(), quad->opacity(), sharedGeometryQuad(), + program->vertexShader().matrixLocation(), + program->fragmentShader().alphaLocation(), + -1); + + GLC(m_context.get(), m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA)); +} + +void LayerRendererChromium::drawVideoQuad(const CCVideoDrawQuad* quad) +{ + CCLayerImpl* layer = quad->layer(); + layer->draw(this); +} + +void LayerRendererChromium::drawPluginQuad(const CCPluginDrawQuad* quad) { CCLayerImpl* layer = quad->layer(); layer->draw(this); diff --git a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h index 2bb0146ad..c896b1df2 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h +++ b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h @@ -167,7 +167,9 @@ private: void drawRenderSurfaceQuad(const CCRenderSurfaceDrawQuad*); void drawSolidColorQuad(const CCSolidColorDrawQuad*); void drawTileQuad(const CCTileDrawQuad*); - void drawCustomLayerQuad(const CCCustomLayerDrawQuad*); + void drawCanvasQuad(const CCCanvasDrawQuad*); + void drawVideoQuad(const CCVideoDrawQuad*); + void drawPluginQuad(const CCPluginDrawQuad*); ManagedTexture* getOffscreenLayerTexture(); void copyOffscreenTextureToDisplay(); diff --git a/Source/WebCore/platform/graphics/chromium/LayerTextureUpdater.h b/Source/WebCore/platform/graphics/chromium/LayerTextureUpdater.h index 34db72aa4..179fea6e1 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerTextureUpdater.h +++ b/Source/WebCore/platform/graphics/chromium/LayerTextureUpdater.h @@ -71,7 +71,13 @@ public: // This format specifies the component order in the sampled texel. // If the format is TexelFormatBGRA, vec4.x is blue and vec4.z is red. virtual SampledTexelFormat sampledTexelFormat(GC3Denum textureFormat) = 0; - virtual void prepareToUpdate(const IntRect& /* contentRect */, const IntSize& /* tileSize */, int /* borderTexels */, float /* contentsScale */) { } + // The |resultingOpaqueRect| gives back a region of the layer that was painted opaque. If the layer is marked opaque in the updater, + // then this region should be ignored in preference for the entire layer's area. + virtual void prepareToUpdate(const IntRect& /* contentRect */, const IntSize& /* tileSize */, int /* borderTexels */, float /* contentsScale */, + IntRect* /* resultingOpaqueRect */) { } + + // Set true by the layer when it is known that the entire output is going to be opaque. + virtual void setOpaque(bool) { } }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/ManagedTexture.cpp b/Source/WebCore/platform/graphics/chromium/ManagedTexture.cpp index 0c1e4b70d..5bb19fa87 100644 --- a/Source/WebCore/platform/graphics/chromium/ManagedTexture.cpp +++ b/Source/WebCore/platform/graphics/chromium/ManagedTexture.cpp @@ -41,6 +41,15 @@ ManagedTexture::ManagedTexture(TextureManager* manager) { } +ManagedTexture::ManagedTexture(TextureManager* manager, TextureToken token, IntSize size, unsigned format, unsigned textureId) + : m_textureManager(manager) + , m_token(token) + , m_size(size) + , m_format(format) + , m_textureId(textureId) +{ +} + ManagedTexture::~ManagedTexture() { if (m_token) @@ -99,6 +108,17 @@ void ManagedTexture::framebufferTexture2D(GraphicsContext3D* context, TextureAll context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_textureId, 0); } +PassOwnPtr<ManagedTexture> ManagedTexture::steal() +{ + OwnPtr<ManagedTexture> texture = adoptPtr(new ManagedTexture(m_textureManager, m_token, m_size, m_format, m_textureId)); + m_token = 0; + m_size = IntSize(); + m_format = 0; + m_textureId = 0; + return texture.release(); +} + + } #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/chromium/ManagedTexture.h b/Source/WebCore/platform/graphics/chromium/ManagedTexture.h index 1cc8bfa9a..76d62a8bb 100644 --- a/Source/WebCore/platform/graphics/chromium/ManagedTexture.h +++ b/Source/WebCore/platform/graphics/chromium/ManagedTexture.h @@ -63,8 +63,13 @@ public: unsigned format() const { return m_format; } unsigned textureId() const { return m_textureId; } + // Steal token and textureId by instantiates a new texture using existing + // member variables. + PassOwnPtr<ManagedTexture> steal(); + private: explicit ManagedTexture(TextureManager*); + ManagedTexture(TextureManager*, TextureToken, IntSize, unsigned format, unsigned textureId); TextureManager* m_textureManager; TextureToken m_token; diff --git a/Source/WebCore/platform/graphics/chromium/PlatformCanvas.cpp b/Source/WebCore/platform/graphics/chromium/PlatformCanvas.cpp index 1c3a20f57..a6b25c534 100644 --- a/Source/WebCore/platform/graphics/chromium/PlatformCanvas.cpp +++ b/Source/WebCore/platform/graphics/chromium/PlatformCanvas.cpp @@ -41,6 +41,7 @@ namespace WebCore { PlatformCanvas::PlatformCanvas() + : m_opaque(false) { } @@ -53,10 +54,27 @@ void PlatformCanvas::resize(const IntSize& size) if (m_size == size) return; m_size = size; + createBackingCanvas(); +} + +void PlatformCanvas::setOpaque(bool opaque) +{ + if (opaque == m_opaque) + return; + + m_opaque = opaque; + createBackingCanvas(); +} + +void PlatformCanvas::createBackingCanvas() +{ + if (m_size.isEmpty()) + return; + #if USE(SKIA) - m_skiaCanvas = adoptPtr(skia::CreateBitmapCanvas(size.width(), size.height(), false)); + m_skiaCanvas = adoptPtr(skia::CreateBitmapCanvas(m_size.width(), m_size.height(), m_opaque)); #elif USE(CG) - size_t bufferSize = size.width() * size.height() * 4; + size_t bufferSize = m_size.width() * m_size.height() * 4; m_pixelData = adoptArrayPtr(new uint8_t[bufferSize]); memset(m_pixelData.get(), 0, bufferSize); #endif diff --git a/Source/WebCore/platform/graphics/chromium/PlatformCanvas.h b/Source/WebCore/platform/graphics/chromium/PlatformCanvas.h index 14fe68798..fdee71b9f 100644 --- a/Source/WebCore/platform/graphics/chromium/PlatformCanvas.h +++ b/Source/WebCore/platform/graphics/chromium/PlatformCanvas.h @@ -85,6 +85,7 @@ public: ~Painter(); GraphicsContext* context() const { return m_context.get(); } + PlatformContextSkia* skiaContext() const { return m_skiaContext.get(); } private: OwnPtr<GraphicsContext> m_context; #if USE(SKIA) @@ -98,13 +99,19 @@ public: void resize(const IntSize&); IntSize size() const { return m_size; } + void setOpaque(bool); + bool opaque() const { return m_opaque; } + private: + void createBackingCanvas(); + #if USE(SKIA) OwnPtr<SkCanvas> m_skiaCanvas; #elif USE(CG) OwnArrayPtr<uint8_t> m_pixelData; #endif IntSize m_size; + bool m_opaque; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp index e3c5c48f7..079ad2ede 100644 --- a/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.cpp @@ -36,13 +36,13 @@ namespace WebCore { -PassRefPtr<PluginLayerChromium> PluginLayerChromium::create(CCLayerDelegate* delegate) +PassRefPtr<PluginLayerChromium> PluginLayerChromium::create() { - return adoptRef(new PluginLayerChromium(delegate)); + return adoptRef(new PluginLayerChromium); } -PluginLayerChromium::PluginLayerChromium(CCLayerDelegate* delegate) - : LayerChromium(delegate) +PluginLayerChromium::PluginLayerChromium() + : LayerChromium() , m_textureId(0) , m_flipped(true) , m_uvRect(0, 0, 1, 1) diff --git a/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.h b/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.h index 0f2f4be7f..84365695b 100644 --- a/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/PluginLayerChromium.h @@ -36,7 +36,7 @@ namespace WebCore { // A Layer containing a the rendered output of a plugin instance. class PluginLayerChromium : public LayerChromium { public: - static PassRefPtr<PluginLayerChromium> create(CCLayerDelegate* = 0); + static PassRefPtr<PluginLayerChromium> create(); virtual void updateCompositorResources(GraphicsContext3D*, CCTextureUpdater&); virtual PassRefPtr<CCLayerImpl> createCCLayerImpl(); @@ -58,7 +58,7 @@ public: void invalidateRect(const FloatRect& dirtyRect); protected: - explicit PluginLayerChromium(CCLayerDelegate*); + PluginLayerChromium(); private: unsigned m_textureId; diff --git a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h index 4e1822b31..bf4988c25 100644 --- a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h +++ b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h @@ -63,6 +63,8 @@ public: float drawOpacity() const { return m_drawOpacity; } void setDrawOpacity(float drawOpacity) { m_drawOpacity = drawOpacity; } + // This goes from content space with the origin in the center of the rect being transformed to the target space with the origin in the top left of the + // rect being transformed. Position the rect so that the origin is in the center of it before applying this transform. const TransformationMatrix& drawTransform() const { return m_drawTransform; } void setDrawTransform(const TransformationMatrix& drawTransform) { m_drawTransform = drawTransform; } diff --git a/Source/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp index 78ad56af9..a3dbd770a 100644 --- a/Source/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp @@ -36,6 +36,7 @@ #include "Font.h" #include "FontCache.h" #include "FontDescription.h" +#include "HWndDC.h" #include "PlatformSupport.h" #include <wtf/MathExtras.h> @@ -55,7 +56,7 @@ void SimpleFontData::platformInit() return; } - HDC dc = GetDC(0); + HWndDC dc(0); HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); TEXTMETRIC textMetric = {0}; @@ -95,7 +96,6 @@ void SimpleFontData::platformInit() m_fontMetrics.setLineSpacing(ascent + descent + lineGap); SelectObject(dc, oldFont); - ReleaseDC(0, dc); } void SimpleFontData::platformCharWidthInit() @@ -147,7 +147,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con void SimpleFontData::determinePitch() { // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that. - HDC dc = GetDC(0); + HWndDC dc(0); HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); // Yes, this looks backwards, but the fixed pitch bit is actually set if the font @@ -166,7 +166,6 @@ void SimpleFontData::determinePitch() m_treatAsFixedPitch = ((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0); SelectObject(dc, oldFont); - ReleaseDC(0, dc); } FloatRect SimpleFontData::platformBoundsForGlyph(Glyph) const @@ -179,7 +178,7 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const if (!m_platformData.size()) return 0; - HDC dc = GetDC(0); + HWndDC dc(0); HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); int width = 0; @@ -194,7 +193,6 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const } SelectObject(dc, oldFont); - ReleaseDC(0, dc); return static_cast<float>(width); } diff --git a/Source/WebCore/platform/graphics/chromium/SkPictureCanvasLayerTextureUpdater.cpp b/Source/WebCore/platform/graphics/chromium/SkPictureCanvasLayerTextureUpdater.cpp index 537e137e8..0d974fa63 100644 --- a/Source/WebCore/platform/graphics/chromium/SkPictureCanvasLayerTextureUpdater.cpp +++ b/Source/WebCore/platform/graphics/chromium/SkPictureCanvasLayerTextureUpdater.cpp @@ -41,6 +41,7 @@ namespace WebCore { SkPictureCanvasLayerTextureUpdater::SkPictureCanvasLayerTextureUpdater(PassOwnPtr<LayerPainterChromium> painter) : CanvasLayerTextureUpdater(painter) + , m_layerIsOpaque(false) { } @@ -48,14 +49,18 @@ SkPictureCanvasLayerTextureUpdater::~SkPictureCanvasLayerTextureUpdater() { } -void SkPictureCanvasLayerTextureUpdater::prepareToUpdate(const IntRect& contentRect, const IntSize& /* tileSize */, int /* borderTexels */, float contentsScale) +void SkPictureCanvasLayerTextureUpdater::prepareToUpdate(const IntRect& contentRect, const IntSize& /* tileSize */, int /* borderTexels */, float contentsScale, IntRect* resultingOpaqueRect) { SkCanvas* canvas = m_picture.beginRecording(contentRect.width(), contentRect.height()); PlatformContextSkia platformContext(canvas); platformContext.setDeferred(true); + platformContext.setTrackOpaqueRegion(!m_layerIsOpaque); GraphicsContext graphicsContext(&platformContext); paintContents(graphicsContext, contentRect, contentsScale); m_picture.endRecording(); + + if (!m_layerIsOpaque) + *resultingOpaqueRect = platformContext.opaqueRegion().asRect(); } void SkPictureCanvasLayerTextureUpdater::drawPicture(SkCanvas* canvas) @@ -64,6 +69,11 @@ void SkPictureCanvasLayerTextureUpdater::drawPicture(SkCanvas* canvas) canvas->drawPicture(m_picture); } +void SkPictureCanvasLayerTextureUpdater::setOpaque(bool opaque) +{ + m_layerIsOpaque = opaque; +} + } // namespace WebCore #endif // USE(SKIA) #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/chromium/SkPictureCanvasLayerTextureUpdater.h b/Source/WebCore/platform/graphics/chromium/SkPictureCanvasLayerTextureUpdater.h index 95b78c3b9..7fcc6059f 100644 --- a/Source/WebCore/platform/graphics/chromium/SkPictureCanvasLayerTextureUpdater.h +++ b/Source/WebCore/platform/graphics/chromium/SkPictureCanvasLayerTextureUpdater.h @@ -51,11 +51,16 @@ public: protected: explicit SkPictureCanvasLayerTextureUpdater(PassOwnPtr<LayerPainterChromium>); - virtual void prepareToUpdate(const IntRect& contentRect, const IntSize& tileSize, int borderTexels, float contentsScale); + virtual void prepareToUpdate(const IntRect& contentRect, const IntSize& tileSize, int borderTexels, float contentsScale, IntRect* resultingOpaqueRect); void drawPicture(SkCanvas*); + virtual void setOpaque(bool); + private: - SkPicture m_picture; // Recording canvas. + // Recording canvas. + SkPicture m_picture; + // True when it is known that all output pixels will be opaque. + bool m_layerIsOpaque; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/SolidColorLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/SolidColorLayerChromium.cpp new file mode 100644 index 000000000..ed13546ba --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/SolidColorLayerChromium.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 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" + +#if USE(ACCELERATED_COMPOSITING) + +#include "SolidColorLayerChromium.h" + +#include "cc/CCSolidColorLayerImpl.h" + +namespace WebCore { + +PassRefPtr<CCLayerImpl> SolidColorLayerChromium::createCCLayerImpl() +{ + return CCSolidColorLayerImpl::create(id()); +} + +PassRefPtr<SolidColorLayerChromium> SolidColorLayerChromium::create() +{ + return adoptRef(new SolidColorLayerChromium()); +} + +SolidColorLayerChromium::SolidColorLayerChromium() + : LayerChromium() +{ +} + +SolidColorLayerChromium::~SolidColorLayerChromium() +{ +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/chromium/SolidColorLayerChromium.h b/Source/WebCore/platform/graphics/chromium/SolidColorLayerChromium.h new file mode 100644 index 000000000..1d14890bd --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/SolidColorLayerChromium.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef SolidColorLayerChromium_h +#define SolidColorLayerChromium_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "LayerChromium.h" + +namespace WebCore { + +class LayerTilerChromium; + +// A Layer that renders a solid color. The color is specified by using +// setBackgroundColor() on the base class. +class SolidColorLayerChromium : public LayerChromium { +public: + virtual PassRefPtr<CCLayerImpl> createCCLayerImpl(); + static PassRefPtr<SolidColorLayerChromium> create(); + + virtual ~SolidColorLayerChromium(); + +protected: + SolidColorLayerChromium(); +}; + +} +#endif // USE(ACCELERATED_COMPOSITING) + +#endif + diff --git a/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp index ad2cb13fc..283aa8dd0 100644 --- a/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp @@ -59,16 +59,21 @@ public: ManagedTexture* managedTexture() { return m_texture->texture(); } bool isDirty() const { return !m_dirtyRect.isEmpty(); } - void clearDirty() { m_dirtyRect = IntRect(); } + void copyAndClearDirty() + { + m_updateRect = m_dirtyRect; + m_dirtyRect = IntRect(); + } IntRect m_dirtyRect; IntRect m_updateRect; + IntRect m_opaqueRect; private: OwnPtr<LayerTextureUpdater::Texture> m_texture; }; -TiledLayerChromium::TiledLayerChromium(CCLayerDelegate* delegate) - : LayerChromium(delegate) +TiledLayerChromium::TiledLayerChromium() + : LayerChromium() , m_textureFormat(GraphicsContext3D::INVALID_ENUM) , m_skipsDraw(false) , m_skipsIdlePaint(false) @@ -150,13 +155,13 @@ void TiledLayerChromium::setBorderTexelOption(CCLayerTilingData::BorderTexelOpti bool TiledLayerChromium::drawsContent() const { - if (!LayerChromium::drawsContent() || !m_delegate) + if (!LayerChromium::drawsContent()) return false; if (m_tilingOption == NeverTile && m_tiler->numTiles() > 1) return false; - return !m_skipsDraw; + return true; } bool TiledLayerChromium::needsContentsScale() const @@ -174,9 +179,6 @@ void TiledLayerChromium::setLayerTreeHost(CCLayerTreeHost* host) if (host == layerTreeHost()) return; - if (layerTreeHost()) - cleanupResources(); - LayerChromium::setLayerTreeHost(host); if (!host) @@ -236,7 +238,11 @@ void TiledLayerChromium::updateCompositorResources(GraphicsContext3D*, CCTexture } } + // The updateRect should be in layer space. So we have to convert the paintRect from content space to layer space. m_updateRect = FloatRect(m_paintRect); + float widthScale = bounds().width() / static_cast<float>(contentBounds().width()); + float heightScale = bounds().height() / static_cast<float>(contentBounds().height()); + m_updateRect.scale(widthScale, heightScale); } void TiledLayerChromium::setTilingOption(TilingOption tilingOption) @@ -268,7 +274,7 @@ void TiledLayerChromium::pushPropertiesTo(CCLayerImpl* layer) if (tile->isDirty()) continue; - tiledLayer->syncTextureId(i, j, tile->managedTexture()->textureId()); + tiledLayer->pushTileProperties(i, j, tile->managedTexture()->textureId(), tile->m_opaqueRect); } } @@ -366,7 +372,9 @@ void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int } // Create tiles as needed, expanding a dirty rect to contain all - // the dirty regions currently being drawn. + // the dirty regions currently being drawn. All dirty tiles that are to be painted + // get their m_updateRect set to m_dirtyRect and m_dirtyRect cleared. This way if + // invalidateRect is invoked during prepareToUpdate we don't lose the request. IntRect dirtyLayerRect; for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { @@ -374,19 +382,28 @@ void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int if (!tile) tile = createTile(i, j); + // Do post commit deletion of current texture when partial texture + // updates are not used. + if (tile->isDirty() && layerTreeHost() && !layerTreeHost()->settings().partialTextureUpdates) + layerTreeHost()->deleteTextureAfterCommit(tile->managedTexture()->steal()); + if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat)) tile->m_dirtyRect = m_tiler->tileRect(tile); if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat)) { m_skipsIdlePaint = true; if (!idle) { - m_skipsDraw = true; + // If the background covers the viewport, always draw this + // layer so that checkerboarded tiles will still draw. + if (!backgroundCoversViewport()) + m_skipsDraw = true; cleanupResources(); } return; } dirtyLayerRect.unite(tile->m_dirtyRect); + tile->copyAndClearDirty(); } } @@ -405,7 +422,8 @@ void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int // However, we can't free the memory backing the GraphicsContext until the paint finishes, // so we grab a local reference here to hold the updater alive until the paint completes. RefPtr<LayerTextureUpdater> protector(textureUpdater()); - textureUpdater()->prepareToUpdate(m_paintRect, m_tiler->tileSize(), m_tiler->hasBorderTexels(), contentsScale()); + IntRect paintedOpaqueRect; + textureUpdater()->prepareToUpdate(m_paintRect, m_tiler->tileSize(), m_tiler->hasBorderTexels(), contentsScale(), &paintedOpaqueRect); for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { UpdatableTile* tile = tileAt(i, j); @@ -414,19 +432,27 @@ void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int if (!tile) CRASH(); - if (!tile->isDirty()) + IntRect tileRect = m_tiler->tileBounds(i, j); + + // Save what was painted opaque in the tile. If everything painted in the tile was opaque, and the area is a subset of an + // already opaque area, keep the old area. + IntRect tilePaintedRect = intersection(tileRect, m_paintRect); + IntRect tilePaintedOpaqueRect = intersection(tileRect, paintedOpaqueRect); + if (tilePaintedOpaqueRect != tilePaintedRect || !tile->m_opaqueRect.contains(tilePaintedOpaqueRect)) + tile->m_opaqueRect = tilePaintedOpaqueRect; + + // Use m_updateRect as copyAndClearDirty above moved the existing dirty rect to m_updateRect. + const IntRect& dirtyRect = tile->m_updateRect; + if (dirtyRect.isEmpty()) continue; + // sourceRect starts as a full-sized tile with border texels included. IntRect sourceRect = m_tiler->tileRect(tile); - sourceRect.intersect(tile->m_dirtyRect); + sourceRect.intersect(dirtyRect); // Paint rect not guaranteed to line up on tile boundaries, so // make sure that sourceRect doesn't extend outside of it. sourceRect.intersect(m_paintRect); - // updateCompositorResources() uses m_updateRect to determine - // the tiles to update so we can clear the dirty rectangle here. - tile->clearDirty(); - tile->m_updateRect = sourceRect; if (sourceRect.isEmpty()) continue; @@ -436,6 +462,60 @@ void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int } } +void TiledLayerChromium::reserveTextures() +{ + updateBounds(); + + const IntRect& layerRect = visibleLayerRect(); + if (layerRect.isEmpty() || !m_tiler->numTiles()) + return; + + int left, top, right, bottom; + m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom); + + for (int j = top; j <= bottom; ++j) { + for (int i = left; i <= right; ++i) { + UpdatableTile* tile = tileAt(i, j); + if (!tile) + tile = createTile(i, j); + + if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat)) + tile->m_dirtyRect = m_tiler->tileRect(tile); + + if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat)) + return; + } + } +} + +void TiledLayerChromium::addSelfToOccludedScreenSpace(Region& occludedScreenSpace) +{ + if (m_skipsDraw || drawOpacity() != 1 || !isPaintedAxisAlignedInScreen()) + return; + + if (opaque()) { + LayerChromium::addSelfToOccludedScreenSpace(occludedScreenSpace); + return; + } + + IntRect visibleRect = visibleLayerRect(); + TransformationMatrix contentTransform = contentToScreenSpaceTransform(); + + // FIXME: Create/Use a FloatRegion for the occludedScreenSpace, instead of a Region based on ints, to avoid this step and get better accuracy between layers in target space. + Region tileRegion; + int left, top, right, bottom; + m_tiler->layerRectToTileIndices(visibleLayerRect(), left, top, right, bottom); + for (int j = top; j <= bottom; ++j) { + for (int i = left; i <= right; ++i) { + UpdatableTile* tile = tileAt(i, j); + if (tile) { + IntRect visibleTileOpaqueRect = intersection(visibleRect, tile->m_opaqueRect); + FloatRect screenRect = contentTransform.mapRect(FloatRect(visibleTileOpaqueRect)); + occludedScreenSpace.unite(enclosedIntRect(screenRect)); + } + } + } +} void TiledLayerChromium::prepareToUpdate(const IntRect& layerRect) { diff --git a/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.h b/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.h index f0ab057ef..3cbbbcbd7 100644 --- a/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/TiledLayerChromium.h @@ -35,6 +35,7 @@ namespace WebCore { class LayerTextureUpdater; +class Region; class UpdatableTile; class TiledLayerChromium : public LayerChromium { @@ -61,8 +62,12 @@ public: // recycled by the texture manager. void protectTileTextures(const IntRect& layerRect); + virtual void reserveTextures(); + + virtual void addSelfToOccludedScreenSpace(Region& occludedScreenSpace); + protected: - explicit TiledLayerChromium(CCLayerDelegate*); + TiledLayerChromium(); virtual void cleanupResources(); void updateTileSizeAndTilingOption(); @@ -88,6 +93,8 @@ protected: // After preparing an update, returns true if more pre-painting is needed. bool needsIdlePaint(const IntRect& layerRect); + bool skipsDraw() const { return m_skipsDraw; } + virtual void protectVisibleTileTextures(); virtual TextureManager* textureManager() const; diff --git a/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp b/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp index efca3d976..51b0c695f 100644 --- a/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp +++ b/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved. + * Copyright (c) 2006, 2007, 2008, 2009, 2012 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 @@ -33,6 +33,7 @@ #include "Font.h" #include "FontUtilsChromiumWin.h" +#include "HWndDC.h" #include "PlatformContextSkia.h" #include "SkiaFontWin.h" #include "SkPoint.h" @@ -786,13 +787,11 @@ void UniscribeHelper::EnsureCachedDCCreated() // Allocate a memory DC that is compatible with the Desktop DC since we don't have any window, // and we don't want to use the Desktop DC directly since it can have nasty side effects // as identified in Chrome Issue http://crbug.com/59315. - HDC screenDC = ::GetDC(0); + HWndDC screenDC(0); m_cachedDC = ::CreateCompatibleDC(screenDC); ASSERT(m_cachedDC); - - int result = ::ReleaseDC(0, screenDC); - ASSERT(result == 1); } + void UniscribeHelper::fillShapes() { m_shapes.resize(m_runs.size()); diff --git a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp index 0e0fcb665..ae2ae8c80 100644 --- a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp @@ -36,14 +36,13 @@ namespace WebCore { -PassRefPtr<VideoLayerChromium> VideoLayerChromium::create(CCLayerDelegate* delegate, - VideoFrameProvider* provider) +PassRefPtr<VideoLayerChromium> VideoLayerChromium::create(VideoFrameProvider* provider) { - return adoptRef(new VideoLayerChromium(delegate, provider)); + return adoptRef(new VideoLayerChromium(provider)); } -VideoLayerChromium::VideoLayerChromium(CCLayerDelegate* delegate, VideoFrameProvider* provider) - : LayerChromium(delegate) +VideoLayerChromium::VideoLayerChromium(VideoFrameProvider* provider) + : LayerChromium() , m_provider(provider) { ASSERT(m_provider); diff --git a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h index d3bed2b10..878806e26 100644 --- a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h @@ -45,14 +45,13 @@ class VideoFrameProvider; class VideoLayerChromium : public LayerChromium { public: - static PassRefPtr<VideoLayerChromium> create(CCLayerDelegate* = 0, - VideoFrameProvider* = 0); + static PassRefPtr<VideoLayerChromium> create(VideoFrameProvider* = 0); virtual ~VideoLayerChromium(); virtual PassRefPtr<CCLayerImpl> createCCLayerImpl(); private: - VideoLayerChromium(CCLayerDelegate*, VideoFrameProvider*); + explicit VideoLayerChromium(VideoFrameProvider*); // This pointer is only for passing to CCVideoLayerImpl's constructor. It should never be dereferenced by this class. VideoFrameProvider* m_provider; diff --git a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp index 7084d66ff..74db7f13e 100644 --- a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp @@ -42,13 +42,13 @@ namespace WebCore { -PassRefPtr<WebGLLayerChromium> WebGLLayerChromium::create(CCLayerDelegate* delegate) +PassRefPtr<WebGLLayerChromium> WebGLLayerChromium::create() { - return adoptRef(new WebGLLayerChromium(delegate)); + return adoptRef(new WebGLLayerChromium()); } -WebGLLayerChromium::WebGLLayerChromium(CCLayerDelegate* delegate) - : CanvasLayerChromium(delegate) +WebGLLayerChromium::WebGLLayerChromium() + : CanvasLayerChromium() , m_hasAlpha(true) , m_premultipliedAlpha(true) , m_textureId(0) diff --git a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h index eb5146eb7..4dc68a330 100644 --- a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h @@ -45,7 +45,7 @@ class WebGLLayerChromiumRateLimitTask; // A Layer containing a WebGL canvas class WebGLLayerChromium : public CanvasLayerChromium { public: - static PassRefPtr<WebGLLayerChromium> create(CCLayerDelegate* = 0); + static PassRefPtr<WebGLLayerChromium> create(); virtual ~WebGLLayerChromium(); @@ -63,7 +63,7 @@ public: void setDrawingBuffer(DrawingBuffer*); DrawingBuffer* drawingBuffer() const { return m_drawingBuffer; } private: - explicit WebGLLayerChromium(CCLayerDelegate*); + WebGLLayerChromium(); friend class WebGLLayerChromiumRateLimitTask; GraphicsContext3D* layerRendererContext(); diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCActiveAnimation.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCActiveAnimation.cpp new file mode 100644 index 000000000..21e6cc7a9 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCActiveAnimation.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2012 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "cc/CCActiveAnimation.h" + +#include "cc/CCAnimationCurve.h" + +#include <cmath> + +namespace WebCore { + +CCActiveAnimation::CCActiveAnimation(PassOwnPtr<CCAnimationCurve> curve, GroupID group, TargetProperty targetProperty) + : m_animationCurve(curve) + , m_group(group) + , m_targetProperty(targetProperty) + , m_runState(WaitingForTargetAvailability) + , m_iterations(1) + , m_startTime(0) + , m_pauseTime(0) + , m_totalPausedTime(0) +{ +} + +void CCActiveAnimation::setRunState(RunState runState, double now) +{ + if (runState == Running && m_runState == Paused) + m_totalPausedTime += now - m_pauseTime; + else if (runState == Paused) + m_pauseTime = now; + m_runState = runState; +} + +bool CCActiveAnimation::isFinishedAt(double time) const +{ + if (m_runState == Finished || m_runState == Aborted) + return true; + + return m_runState == Running + && m_iterations >= 0 + && m_iterations * m_animationCurve->duration() <= time - startTime() - m_totalPausedTime; +} + +double CCActiveAnimation::trimTimeToCurrentIteration(double now) const +{ + double trimmed = now; + + // If we're paused, time is 'stuck' at the pause time. + if (m_runState == Paused && trimmed > m_pauseTime) + trimmed = m_pauseTime; + + // Returned time should always be relative to the start time and should subtract + // all time spent paused. + trimmed -= m_startTime + m_totalPausedTime; + + // Zero is always the start of the animation. + if (trimmed <= 0) + return 0; + + // Always return zero if we have no iterations. + if (!m_iterations) + return 0; + + // If less than an iteration duration, just return trimmed. + if (trimmed < m_animationCurve->duration()) + return trimmed; + + // If greater than or equal to the total duration, return iteration duration. + if (m_iterations >= 0 && trimmed >= m_animationCurve->duration() * m_iterations) + return m_animationCurve->duration(); + + // Finally, return x where trimmed = x + n * m_animation->duration() for some positive integer n. + return fmod(trimmed, m_animationCurve->duration()); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCActiveAnimation.h b/Source/WebCore/platform/graphics/chromium/cc/CCActiveAnimation.h new file mode 100644 index 000000000..c22227941 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCActiveAnimation.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2012 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CCActiveAnimation_h +#define CCActiveAnimation_h + +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +class CCAnimationCurve; + +// A CCActiveAnimation, contains all the state required to play a CCAnimationCurve. +// Specifically, the affected property, the run state (paused, finished, etc.), +// loop count, last pause time, and the total time spent paused. +class CCActiveAnimation { +public: + // Animations that must be run together are called 'grouped' and have the same GroupID + // Grouped animations are guaranteed to start at the same time and no other animations + // may animate any of the group's target properties until all animations in the + // group have finished animating. Note: an active animation's group id and target + // property uniquely identify that animation. + typedef int GroupID; + + // Animations begin in one of the 'waiting' states. Animations waiting for the next tick + // will start the next time the controller animates. Animations waiting for target + // availibility will run as soon as their target property is free (and all the animations + // animating with it are also able to run). Animations waiting for their start time to + // come have be scheduled to run at a particular point in time. When this time arrives, + // the controller will move the animations into the Running state. Running animations + // may toggle between Running and Paused, and may be stopped by moving into either the + // Aborted or Finished states. A Finished animation was allowed to run to completion, but + // an Aborted animation was not. + enum RunState { + WaitingForNextTick = 1, + WaitingForTargetAvailability, + WaitingForStartTime, + Running, + Paused, + Finished, + Aborted + }; + + enum TargetProperty { + Transform = 1, + Opacity + }; + + static PassOwnPtr<CCActiveAnimation> create(PassOwnPtr<CCAnimationCurve> curve, GroupID group, TargetProperty targetProperty) + { + return adoptPtr(new CCActiveAnimation(curve, group, targetProperty)); + } + + virtual ~CCActiveAnimation() { } + + GroupID group() const { return m_group; } + TargetProperty targetProperty() const { return m_targetProperty; } + + RunState runState() const { return m_runState; } + void setRunState(RunState, double now); + + // This is the number of times that the animation will play. If this + // value is zero the animation will not play. If it is negative, then + // the animation will loop indefinitely. + int iterations() const { return m_iterations; } + void setIterations(int n) { m_iterations = n; } + + double startTime() const { return m_startTime; } + void setStartTime(double startTime) { m_startTime = startTime; } + + bool isFinishedAt(double time) const; + bool isFinished() const { return m_runState == Finished || m_runState == Aborted; } + + CCAnimationCurve* animationCurve() { return m_animationCurve.get(); } + const CCAnimationCurve* animationCurve() const { return m_animationCurve.get(); } + + // Takes the given absolute time, and using the start time and the number + // of iterations, returns the relative time in the current iteration. + double trimTimeToCurrentIteration(double now) const; + +private: + CCActiveAnimation(PassOwnPtr<CCAnimationCurve>, GroupID, TargetProperty); + + OwnPtr<CCAnimationCurve> m_animationCurve; + GroupID m_group; + TargetProperty m_targetProperty; + RunState m_runState; + int m_iterations; + double m_startTime; + + // These are used in trimTimeToCurrentIteration to account for time + // spent while paused. This is not included in AnimationState since it + // there is absolutely no need for clients of this controller to know + // about these values. + double m_pauseTime; + double m_totalPausedTime; +}; + +} // namespace WebCore + +#endif // CCActiveAnimation_h diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCAnimationCurve.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCAnimationCurve.cpp new file mode 100644 index 000000000..58cdc6ad6 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCAnimationCurve.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2012 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "cc/CCAnimationCurve.h" + +namespace WebCore { + +const CCFloatAnimationCurve* CCAnimationCurve::toFloatAnimationCurve() const +{ + ASSERT(type() == CCAnimationCurve::Float); + return static_cast<const CCFloatAnimationCurve*>(this); +} + +const CCTransformAnimationCurve* CCAnimationCurve::toTransformAnimationCurve() const +{ + ASSERT(type() == CCAnimationCurve::Transform); + return static_cast<const CCTransformAnimationCurve*>(this); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCAnimationCurve.h b/Source/WebCore/platform/graphics/chromium/cc/CCAnimationCurve.h new file mode 100644 index 000000000..de97e38c0 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCAnimationCurve.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2012 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CCAnimationCurve_h +#define CCAnimationCurve_h + +namespace WebCore { + +class CCFloatAnimationCurve; +class CCTransformAnimationCurve; +class TransformOperations; + +// An animation curve is a function that returns a value given a time. +// There are currently only two types of curve, float and transform. +class CCAnimationCurve { +public: + enum Type { Float, Transform }; + + virtual ~CCAnimationCurve() { } + + virtual double duration() const = 0; + virtual Type type() const = 0; + + const CCFloatAnimationCurve* toFloatAnimationCurve() const; + const CCTransformAnimationCurve* toTransformAnimationCurve() const; +}; + +class CCFloatAnimationCurve : public CCAnimationCurve { +public: + virtual ~CCFloatAnimationCurve() { } + + virtual float getValue(double t) const = 0; + + // Partial CCAnimation implementation. + virtual Type type() const { return Float; } +}; + +class CCTransformAnimationCurve : public CCAnimationCurve { +public: + virtual ~CCTransformAnimationCurve() { } + + virtual TransformOperations getValue(double t) const = 0; + + // Partial CCAnimation implementation. + virtual Type type() const { return Transform; } +}; + +} // namespace WebCore + +#endif // CCAnimation_h diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasDrawQuad.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasDrawQuad.cpp new file mode 100644 index 000000000..56f5083a5 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasDrawQuad.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 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 "cc/CCCanvasDrawQuad.h" + +namespace WebCore { + +PassOwnPtr<CCCanvasDrawQuad> CCCanvasDrawQuad::create(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, unsigned textureId, bool hasAlpha, bool premultipliedAlpha) +{ + return adoptPtr(new CCCanvasDrawQuad(sharedQuadState, quadRect, textureId, hasAlpha, premultipliedAlpha)); +} + +CCCanvasDrawQuad::CCCanvasDrawQuad(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, unsigned textureId, bool hasAlpha, bool premultipliedAlpha) + : CCDrawQuad(sharedQuadState, CCDrawQuad::CanvasContent, quadRect) + , m_textureId(textureId) + , m_hasAlpha(hasAlpha) + , m_premultipliedAlpha(premultipliedAlpha) +{ +} + +} diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasDrawQuad.h b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasDrawQuad.h new file mode 100644 index 000000000..aa85dbd13 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasDrawQuad.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012 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 CCCanvasDrawQuad_h +#define CCCanvasDrawQuad_h + +#include "cc/CCDrawQuad.h" +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +class CCLayerImpl; +class CCCanvasDrawQuad : public CCDrawQuad { + WTF_MAKE_NONCOPYABLE(CCCanvasDrawQuad); +public: + static PassOwnPtr<CCCanvasDrawQuad> create(const CCSharedQuadState*, const IntRect&, unsigned texture_id, bool hasAlpha, bool premultipliedAlpha); + + unsigned textureId() const { return m_textureId; } + bool hasAlpha() const { return m_hasAlpha; } + bool premultipliedAlpha() const { return m_premultipliedAlpha; } + +private: + CCCanvasDrawQuad(const CCSharedQuadState*, const IntRect&, unsigned texture_id, bool hasAlpha, bool premultipliedAlpha); + + unsigned m_textureId; + bool m_hasAlpha; + bool m_premultipliedAlpha; +}; + +} + +#endif diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp index 6ecdd90f2..2bb3eff22 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp @@ -31,6 +31,7 @@ #include "GraphicsContext3D.h" #include "LayerRendererChromium.h" +#include "cc/CCCanvasDrawQuad.h" #include "cc/CCProxy.h" #include <wtf/text/WTFString.h> @@ -48,36 +49,12 @@ CCCanvasLayerImpl::~CCCanvasLayerImpl() { } -void CCCanvasLayerImpl::draw(LayerRendererChromium* layerRenderer) +void CCCanvasLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState) { - ASSERT(CCProxy::isImplThread()); - const CCCanvasLayerImpl::Program* program = layerRenderer->canvasLayerProgram(); - ASSERT(program && program->initialized()); - GraphicsContext3D* context = layerRenderer->context(); - GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); - GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureId)); - GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR)); - GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); - - if (!m_hasAlpha) { - // Even though the WebGL layer's texture was likely allocated - // as GL_RGB, disable blending anyway for better robustness. - context->disable(GraphicsContext3D::BLEND); - } else { - GC3Denum sfactor = m_premultipliedAlpha ? GraphicsContext3D::ONE : GraphicsContext3D::SRC_ALPHA; - GLC(context, context->blendFunc(sfactor, GraphicsContext3D::ONE_MINUS_SRC_ALPHA)); - } - GLC(context, context->useProgram(program->program())); - GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0)); - layerRenderer->drawTexturedQuad(drawTransform(), bounds().width(), bounds().height(), drawOpacity(), layerRenderer->sharedGeometryQuad(), - program->vertexShader().matrixLocation(), - program->fragmentShader().alphaLocation(), - -1); - if (!m_hasAlpha) - context->enable(GraphicsContext3D::BLEND); + IntRect quadRect(IntPoint(), bounds()); + quadList.append(CCCanvasDrawQuad::create(sharedQuadState, quadRect, m_textureId, m_hasAlpha, m_premultipliedAlpha)); } - void CCCanvasLayerImpl::dumpLayerProperties(TextStream& ts, int indent) const { writeIndent(ts, indent); diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h index 275bf7ca8..9126a7d44 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h @@ -40,9 +40,9 @@ public: } virtual ~CCCanvasLayerImpl(); - typedef ProgramBinding<VertexShaderPosTex, FragmentShaderRGBATexFlipAlpha> Program; + virtual void appendQuads(CCQuadList&, const CCSharedQuadState*); - virtual void draw(LayerRendererChromium*); + typedef ProgramBinding<VertexShaderPosTex, FragmentShaderRGBATexFlipAlpha> Program; virtual void dumpLayerProperties(TextStream&, int indent) const; diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCDelayBasedTimeSource.h b/Source/WebCore/platform/graphics/chromium/cc/CCDelayBasedTimeSource.h index 6336b8849..a41aad4d8 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCDelayBasedTimeSource.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCDelayBasedTimeSource.h @@ -45,6 +45,7 @@ public: virtual void setClient(CCTimeSourceClient* client) { m_client = client; } virtual void setActive(bool); + virtual bool active() const { return m_state != STATE_INACTIVE; } // CCTimerClient implementation. virtual void onTimerFired(); diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCDrawQuad.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCDrawQuad.cpp index 8fcf449f0..708500267 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCDrawQuad.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCDrawQuad.cpp @@ -27,12 +27,14 @@ #include "cc/CCDrawQuad.h" -#include "cc/CCCustomLayerDrawQuad.h" +#include "cc/CCCanvasDrawQuad.h" #include "cc/CCDebugBorderDrawQuad.h" #include "cc/CCLayerImpl.h" +#include "cc/CCPluginDrawQuad.h" #include "cc/CCRenderSurfaceDrawQuad.h" #include "cc/CCSolidColorDrawQuad.h" #include "cc/CCTileDrawQuad.h" +#include "cc/CCVideoDrawQuad.h" namespace WebCore { @@ -40,6 +42,7 @@ CCDrawQuad::CCDrawQuad(const CCSharedQuadState* sharedQuadState, Material materi : m_sharedQuadState(sharedQuadState) , m_material(material) , m_quadRect(quadRect) + , m_quadVisibleRect(quadRect) , m_quadOpaque(true) , m_needsBlending(false) { @@ -47,6 +50,21 @@ CCDrawQuad::CCDrawQuad(const CCSharedQuadState* sharedQuadState, Material materi ASSERT(m_material != Invalid); } +IntRect CCDrawQuad::opaqueRect() const +{ + if (opacity() != 1) + return IntRect(); + if (m_sharedQuadState->isOpaque() && m_quadOpaque) + return m_quadRect; + return m_opaqueRect; +} + +void CCDrawQuad::setQuadVisibleRect(const IntRect& quadVisibleRect) +{ + m_quadVisibleRect = quadVisibleRect; + m_quadVisibleRect.intersect(m_quadRect); +} + const CCDebugBorderDrawQuad* CCDrawQuad::toDebugBorderDrawQuad() const { ASSERT(m_material == DebugBorder); @@ -71,10 +89,22 @@ const CCTileDrawQuad* CCDrawQuad::toTileDrawQuad() const return static_cast<const CCTileDrawQuad*>(this); } -const CCCustomLayerDrawQuad* CCDrawQuad::toCustomLayerDrawQuad() const +const CCCanvasDrawQuad* CCDrawQuad::toCanvasDrawQuad() const +{ + ASSERT(m_material == CanvasContent); + return static_cast<const CCCanvasDrawQuad*>(this); +} + +const CCVideoDrawQuad* CCDrawQuad::toVideoDrawQuad() const +{ + ASSERT(m_material == VideoContent); + return static_cast<const CCVideoDrawQuad*>(this); +} + +const CCPluginDrawQuad* CCDrawQuad::toPluginDrawQuad() const { - ASSERT(m_material == CustomLayer); - return static_cast<const CCCustomLayerDrawQuad*>(this); + ASSERT(m_material == PluginContent); + return static_cast<const CCPluginDrawQuad*>(this); } } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCDrawQuad.h b/Source/WebCore/platform/graphics/chromium/cc/CCDrawQuad.h index b56913b3c..1738b4b0e 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCDrawQuad.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCDrawQuad.h @@ -34,7 +34,9 @@ class CCDebugBorderDrawQuad; class CCRenderSurfaceDrawQuad; class CCSolidColorDrawQuad; class CCTileDrawQuad; -class CCCustomLayerDrawQuad; +class CCCanvasDrawQuad; +class CCVideoDrawQuad; +class CCPluginDrawQuad; // CCDrawQuad is a bag of data used for drawing a quad. Because different // materials need different bits of per-quad data to render, classes that derive @@ -49,20 +51,25 @@ public: const IntRect& layerRect() const { return m_sharedQuadState->layerRect(); } const IntRect& clipRect() const { return m_sharedQuadState->clipRect(); } float opacity() const { return m_sharedQuadState->opacity(); } - // For the purposes of culling, are the contents of this quad opaque? - bool drawsOpaque() const { return m_sharedQuadState->isOpaque() && m_quadOpaque && opacity() == 1; } - bool needsBlending() const { return !m_sharedQuadState->isOpaque() || m_needsBlending || opacity() != 1; } + // For the purposes of culling, what part of the contents of this quad are opaque? + IntRect opaqueRect() const; + bool needsBlending() const { return m_needsBlending || opaqueRect() != m_quadRect; } bool isLayerAxisAlignedIntRect() const { return m_sharedQuadState->isLayerAxisAlignedIntRect(); } + // Allows changing the rect that gets drawn to make it smaller. Parameter passed + // in will be clipped to quadRect(). + void setQuadVisibleRect(const IntRect&); + const IntRect& quadVisibleRect() const { return m_quadVisibleRect; } + enum Material { Invalid, DebugBorder, RenderSurface, SolidColor, TiledContent, - - // FIXME: remove this and add proper material types for all layer types - CustomLayer, + CanvasContent, + VideoContent, + PluginContent, }; Material material() const { return m_material; } @@ -71,7 +78,9 @@ public: const CCRenderSurfaceDrawQuad* toRenderSurfaceDrawQuad() const; const CCSolidColorDrawQuad* toSolidColorDrawQuad() const; const CCTileDrawQuad* toTileDrawQuad() const; - const CCCustomLayerDrawQuad* toCustomLayerDrawQuad() const; + const CCCanvasDrawQuad* toCanvasDrawQuad() const; + const CCVideoDrawQuad* toVideoDrawQuad() const; + const CCPluginDrawQuad* toPluginDrawQuad() const; protected: CCDrawQuad(const CCSharedQuadState*, Material, const IntRect&); @@ -80,12 +89,17 @@ protected: Material m_material; IntRect m_quadRect; + IntRect m_quadVisibleRect; // By default, the shared quad state determines whether or not this quad is // opaque or needs blending. Derived classes can override with these // variables. bool m_quadOpaque; bool m_needsBlending; + + // Be default, this rect is empty. It is used when the shared quad state and above + // variables determine that the quad is not fully opaque but may be partially opaque. + IntRect m_opaqueRect; }; } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCFrameRateController.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCFrameRateController.cpp index 5ac918658..55447ca59 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCFrameRateController.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCFrameRateController.cpp @@ -26,6 +26,7 @@ #include "cc/CCFrameRateController.h" +#include "TraceEvent.h" #include "cc/CCThread.h" #include "cc/CCThreadTask.h" @@ -62,6 +63,14 @@ CCFrameRateController::~CCFrameRateController() m_timeSource->setActive(false); } +void CCFrameRateController::setActive(bool active) +{ + if (m_timeSource->active() == active) + return; + TRACE_EVENT("CCFrameRateController::setActive", 0, (active ? "active" : "inactive")); + m_timeSource->setActive(active); +} + void CCFrameRateController::setMaxFramesPending(int maxFramesPending) { m_maxFramesPending = maxFramesPending; @@ -69,9 +78,13 @@ void CCFrameRateController::setMaxFramesPending(int maxFramesPending) void CCFrameRateController::onTimerTick() { + ASSERT(m_timeSource->active()); + // Don't forward the tick if we have too many frames in flight. - if (m_maxFramesPending && m_numFramesPending >= m_maxFramesPending) + if (m_maxFramesPending && m_numFramesPending >= m_maxFramesPending) { + TRACE_EVENT("CCFrameRateController::onTimerTickButMaxFramesPending", 0, 0); return; + } if (m_client) m_client->beginFrame(); diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCFrameRateController.h b/Source/WebCore/platform/graphics/chromium/cc/CCFrameRateController.h index b2281213d..a3eefe846 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCFrameRateController.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCFrameRateController.h @@ -50,9 +50,10 @@ public: void setClient(CCFrameRateControllerClient* client) { m_client = client; } - void setActive(bool active) { m_timeSource->setActive(active); } + void setActive(bool); void setMaxPendingFrames(int); + // Use the following methods to adjust target frame rate. // // Multiple frames can be in-progress, but for every didBeginFrame, a diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCInputHandler.h b/Source/WebCore/platform/graphics/chromium/cc/CCInputHandler.h index 1c25fb194..057d79b1a 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCInputHandler.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCInputHandler.h @@ -43,7 +43,6 @@ class IntSize; class CCInputHandlerClient { WTF_MAKE_NONCOPYABLE(CCInputHandlerClient); public: - virtual double currentTimeMs() const = 0; virtual void setNeedsRedraw() = 0; enum ScrollStatus { ScrollFailed, ScrollStarted, ScrollIgnored }; @@ -73,6 +72,7 @@ public: virtual void startPageScaleAnimation(const IntSize& targetPosition, bool anchorPoint, float pageScale, + double startTimeMs, double durationMs) = 0; protected: diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerAnimationControllerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCLayerAnimationControllerImpl.cpp new file mode 100644 index 000000000..bbca9cbd9 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerAnimationControllerImpl.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2012 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "cc/CCLayerAnimationControllerImpl.h" + +#include "TransformOperations.h" + +namespace WebCore { + +// A collection of properties. Used when deterimining if animations waiting for target +// availibility are able to run. +typedef HashSet<int> TargetProperties; + +PassOwnPtr<CCLayerAnimationControllerImpl> CCLayerAnimationControllerImpl::create(CCLayerAnimationControllerImplClient* client) +{ + return adoptPtr(new CCLayerAnimationControllerImpl(client)); +} + +CCLayerAnimationControllerImpl::CCLayerAnimationControllerImpl(CCLayerAnimationControllerImplClient* client) + : m_client(client) +{ +} + +void CCLayerAnimationControllerImpl::animate(double frameBeginTimeSecs) +{ + startAnimationsWaitingForNextTick(frameBeginTimeSecs); + startAnimationsWaitingForStartTime(frameBeginTimeSecs); + startAnimationsWaitingForTargetAvailability(frameBeginTimeSecs); + resolveConflicts(frameBeginTimeSecs); + tickAnimations(frameBeginTimeSecs); + purgeFinishedAnimations(); + startAnimationsWaitingForTargetAvailability(frameBeginTimeSecs); +} + +void CCLayerAnimationControllerImpl::add(PassOwnPtr<CCActiveAnimation> anim) +{ + m_activeAnimations.append(anim); + if (m_client) + m_client->animationControllerImplDidActivate(this); +} + +CCActiveAnimation* CCLayerAnimationControllerImpl::getActiveAnimation(CCActiveAnimation::GroupID group, CCActiveAnimation::TargetProperty property) +{ + for (size_t i = 0; i < m_activeAnimations.size(); ++i) { + if (m_activeAnimations[i]->group() == group && m_activeAnimations[i]->targetProperty() == property) + return m_activeAnimations[i].get(); + } + return 0; +} + +bool CCLayerAnimationControllerImpl::hasActiveAnimation() const +{ + for (size_t i = 0; i < m_activeAnimations.size(); ++i) { + if (m_activeAnimations[i]->runState() != CCActiveAnimation::Finished && m_activeAnimations[i]->runState() != CCActiveAnimation::Aborted) + return true; + } + return false; +} + +void CCLayerAnimationControllerImpl::startAnimationsWaitingForNextTick(double now) +{ + for (size_t i = 0; i < m_activeAnimations.size(); ++i) { + if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForNextTick) { + m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, now); + m_activeAnimations[i]->setStartTime(now); + } + } +} + +void CCLayerAnimationControllerImpl::startAnimationsWaitingForStartTime(double now) +{ + for (size_t i = 0; i < m_activeAnimations.size(); ++i) { + if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForStartTime && m_activeAnimations[i]->startTime() <= now) + m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, now); + } +} + +void CCLayerAnimationControllerImpl::startAnimationsWaitingForTargetAvailability(double now) +{ + // First collect running properties. + TargetProperties blockedProperties; + for (size_t i = 0; i < m_activeAnimations.size(); ++i) { + if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running || m_activeAnimations[i]->runState() == CCActiveAnimation::Finished) + blockedProperties.add(m_activeAnimations[i]->targetProperty()); + } + + for (size_t i = 0; i < m_activeAnimations.size(); ++i) { + if (m_activeAnimations[i]->runState() == CCActiveAnimation::WaitingForTargetAvailability) { + // Collect all properties for animations with the same group id (they should all also be in the list of animations). + TargetProperties enqueuedProperties; + enqueuedProperties.add(m_activeAnimations[i]->targetProperty()); + for (size_t j = i + 1; j < m_activeAnimations.size(); ++j) { + if (m_activeAnimations[i]->group() == m_activeAnimations[j]->group()) + enqueuedProperties.add(m_activeAnimations[j]->targetProperty()); + } + + // Check to see if intersection of the list of properties affected by the group and the list of currently + // blocked properties is null. In any case, the group's target properties need to be added to the list + // of blocked properties. + bool nullIntersection = true; + for (TargetProperties::iterator pIter = enqueuedProperties.begin(); pIter != enqueuedProperties.end(); ++pIter) { + if (!blockedProperties.add(*pIter).second) + nullIntersection = false; + } + + // If the intersection is null, then we are free to start the animations in the group. + if (nullIntersection) { + m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, now); + m_activeAnimations[i]->setStartTime(now); + for (size_t j = i + 1; j < m_activeAnimations.size(); ++j) { + if (m_activeAnimations[i]->group() == m_activeAnimations[j]->group()) { + m_activeAnimations[j]->setRunState(CCActiveAnimation::Running, now); + m_activeAnimations[j]->setStartTime(now); + } + } + } + } + } +} + +void CCLayerAnimationControllerImpl::resolveConflicts(double now) +{ + // Find any animations that are animating the same property and resolve the + // confict. We could eventually blend, but for now we'll just abort the + // previous animation (where 'previous' means: (1) has a prior start time or + // (2) has an equal start time, but was added to the queue earlier, i.e., + // has a lower index in m_activeAnimations). + for (size_t i = 0; i < m_activeAnimations.size(); ++i) { + if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running) { + for (size_t j = i + 1; j < m_activeAnimations.size(); ++j) { + if (m_activeAnimations[j]->runState() == CCActiveAnimation::Running && m_activeAnimations[i]->targetProperty() == m_activeAnimations[j]->targetProperty()) { + if (m_activeAnimations[i]->startTime() > m_activeAnimations[j]->startTime()) + m_activeAnimations[j]->setRunState(CCActiveAnimation::Aborted, now); + else + m_activeAnimations[i]->setRunState(CCActiveAnimation::Aborted, now); + } + } + } + } +} + +void CCLayerAnimationControllerImpl::purgeFinishedAnimations() +{ + // Each iteration, m_activeAnimations.size() decreases or i increments, + // guaranteeing progress towards loop termination. + size_t i = 0; + while (i < m_activeAnimations.size()) { + bool allAnimsWithSameIdAreFinished = false; + if (m_activeAnimations[i]->isFinished()) { + allAnimsWithSameIdAreFinished = true; + for (size_t j = i + 1; j < m_activeAnimations.size(); ++j) { + if (m_activeAnimations[i]->group() == m_activeAnimations[j]->group() && !m_activeAnimations[j]->isFinished()) { + allAnimsWithSameIdAreFinished = false; + break; + } + } + } + if (allAnimsWithSameIdAreFinished) + m_activeAnimations.remove(i); + else + i++; + } +} + +void CCLayerAnimationControllerImpl::tickAnimations(double now) +{ + for (size_t i = 0; i < m_activeAnimations.size(); ++i) { + if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running) { + double trimmed = m_activeAnimations[i]->trimTimeToCurrentIteration(now); + switch (m_activeAnimations[i]->targetProperty()) { + + case CCActiveAnimation::Transform: { + const CCTransformAnimationCurve* transformAnimationCurve = m_activeAnimations[i]->animationCurve()->toTransformAnimationCurve(); + const TransformOperations operations = transformAnimationCurve->getValue(trimmed); + if (m_activeAnimations[i]->isFinishedAt(now)) + m_activeAnimations[i]->setRunState(CCActiveAnimation::Finished, now); + + // Decide here if absolute or relative. Absolute for now. + TransformationMatrix toApply; + operations.apply(FloatSize(), toApply); + m_client->setTransform(toApply); + break; + } + + case CCActiveAnimation::Opacity: { + const CCFloatAnimationCurve* floatAnimationCurve = m_activeAnimations[i]->animationCurve()->toFloatAnimationCurve(); + const float opacity = floatAnimationCurve->getValue(trimmed); + if (m_activeAnimations[i]->isFinishedAt(now)) + m_activeAnimations[i]->setRunState(CCActiveAnimation::Finished, now); + + m_client->setOpacity(opacity); + break; + } + + } // switch + } // if running + } // for each animation +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerAnimationControllerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCLayerAnimationControllerImpl.h new file mode 100644 index 000000000..1ad223dba --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerAnimationControllerImpl.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2012 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CCLayerAnimationControllerImpl_h +#define CCLayerAnimationControllerImpl_h + +#include "cc/CCActiveAnimation.h" +#include "cc/CCAnimationCurve.h" + +#include <wtf/HashSet.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class CCLayerAnimationControllerImpl; +class IntSize; +class TransformationMatrix; +class TransformOperations; + +class CCLayerAnimationControllerImplClient { +public: + virtual ~CCLayerAnimationControllerImplClient() { } + + virtual float opacity() const = 0; + virtual void setOpacity(float) = 0; + virtual const TransformationMatrix& transform() const = 0; + virtual void setTransform(const TransformationMatrix&) = 0; + virtual void animationControllerImplDidActivate(CCLayerAnimationControllerImpl*) = 0; +}; + +class CCLayerAnimationControllerImpl { +public: + static PassOwnPtr<CCLayerAnimationControllerImpl> create(CCLayerAnimationControllerImplClient*); + + void animate(double frameBeginTimeSecs); + + void add(PassOwnPtr<CCActiveAnimation>); + + // Returns the active animation in the given group, animating the given property if such an + // animation exists. + CCActiveAnimation* getActiveAnimation(CCActiveAnimation::GroupID, CCActiveAnimation::TargetProperty); + + // Returns true if there are any animations that are neither finished nor aborted. + bool hasActiveAnimation() const; + +private: + // The animator is owned by the layer. + explicit CCLayerAnimationControllerImpl(CCLayerAnimationControllerImplClient*); + + void startAnimationsWaitingForNextTick(double now); + void startAnimationsWaitingForStartTime(double now); + void startAnimationsWaitingForTargetAvailability(double now); + void resolveConflicts(double now); + void purgeFinishedAnimations(); + + void tickAnimations(double now); + + CCLayerAnimationControllerImplClient* m_client; + Vector<OwnPtr<CCActiveAnimation> > m_activeAnimations; +}; + +} // namespace WebCore + +#endif // CCLayerAnimationControllerImpl_h + diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp index 6837f0a5c..81f9712e0 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp @@ -32,9 +32,9 @@ #include "GraphicsContext3D.h" #include "LayerChromium.h" #include "LayerRendererChromium.h" -#include "cc/CCCustomLayerDrawQuad.h" #include "cc/CCDebugBorderDrawQuad.h" #include "cc/CCLayerSorter.h" +#include "cc/CCSolidColorDrawQuad.h" #include <wtf/text/WTFString.h> namespace WebCore { @@ -45,6 +45,7 @@ CCLayerImpl::CCLayerImpl(int id) , m_anchorPoint(0.5, 0.5) , m_anchorPointZ(0) , m_scrollable(false) + , m_backgroundCoversViewport(false) , m_doubleSided(true) , m_layerPropertyChanged(false) , m_masksToBounds(false) @@ -129,8 +130,39 @@ PassOwnPtr<CCSharedQuadState> CCLayerImpl::createSharedQuadState() const void CCLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState) { - IntRect quadRect(IntPoint(), bounds()); - quadList.append(CCCustomLayerDrawQuad::create(sharedQuadState, quadRect, this)); + appendGutterQuads(quadList, sharedQuadState); +} + +void CCLayerImpl::appendGutterQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState) +{ + if (!backgroundCoversViewport() || !backgroundColor().isValid()) + return; + + const IntRect& layerRect = visibleLayerRect(); + IntRect clip = screenSpaceTransform().inverse().mapRect(clipRect()); + + if (layerRect.isEmpty()) { + quadList.append(CCSolidColorDrawQuad::create(sharedQuadState, clip, backgroundColor())); + return; + } + + IntRect gutterRects[4]; + for (int i = 0; i < 4; i++) + gutterRects[i] = clip; + gutterRects[0].shiftMaxYEdgeTo(layerRect.y()); + gutterRects[1].shiftYEdgeTo(layerRect.maxY()); + gutterRects[2].shiftMaxXEdgeTo(layerRect.x()); + gutterRects[3].shiftXEdgeTo(layerRect.maxX()); + + gutterRects[2].shiftYEdgeTo(layerRect.y()); + gutterRects[3].shiftYEdgeTo(layerRect.y()); + gutterRects[2].shiftMaxYEdgeTo(layerRect.maxY()); + gutterRects[3].shiftMaxYEdgeTo(layerRect.maxY()); + + for (int i = 0; i < 4; i++) { + if (!gutterRects[i].isEmpty()) + quadList.append(CCSolidColorDrawQuad::create(sharedQuadState, gutterRects[i], backgroundColor())); + } } void CCLayerImpl::appendDebugBorderQuad(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState) const @@ -138,7 +170,7 @@ void CCLayerImpl::appendDebugBorderQuad(CCQuadList& quadList, const CCSharedQuad if (!hasDebugBorders()) return; - IntRect layerRect(IntPoint(), bounds()); + IntRect layerRect(IntPoint(), contentBounds()); quadList.append(CCDebugBorderDrawQuad::create(sharedQuadState, layerRect, debugBorderColor(), debugBorderWidth())); } @@ -342,6 +374,15 @@ void CCLayerImpl::setBackgroundColor(const Color& backgroundColor) m_layerPropertyChanged = true; } +void CCLayerImpl::setBackgroundCoversViewport(bool backgroundCoversViewport) +{ + if (m_backgroundCoversViewport == backgroundCoversViewport) + return; + + m_backgroundCoversViewport = backgroundCoversViewport; + m_layerPropertyChanged = true; +} + void CCLayerImpl::setMasksToBounds(bool masksToBounds) { if (m_masksToBounds == masksToBounds) diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h index 0136b01f8..00e0adf8a 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h @@ -97,6 +97,9 @@ public: void setBackgroundColor(const Color&); Color backgroundColor() const { return m_backgroundColor; } + void setBackgroundCoversViewport(bool); + bool backgroundCoversViewport() const { return m_backgroundCoversViewport; } + void setMasksToBounds(bool); bool masksToBounds() const { return m_masksToBounds; } @@ -204,6 +207,8 @@ protected: // Transformation used to transform quads provided in appendQuads. virtual TransformationMatrix quadTransform() const; + void appendGutterQuads(CCQuadList&, const CCSharedQuadState*); + private: void setParent(CCLayerImpl* parent) { m_parent = parent; } friend class TreeSynchronizer; @@ -233,6 +238,7 @@ private: IntPoint m_scrollPosition; bool m_scrollable; Color m_backgroundColor; + bool m_backgroundCoversViewport; // Whether the "back" of this layer should draw. bool m_doubleSided; diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTilingData.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTilingData.cpp index 8b8622b78..92637fc83 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTilingData.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTilingData.cpp @@ -96,7 +96,6 @@ CCLayerTilingData::Tile* CCLayerTilingData::tileAt(int i, int j) const void CCLayerTilingData::reset() { m_tiles.clear(); - m_tilingData.setTotalSize(0, 0); } void CCLayerTilingData::layerRectToTileIndices(const IntRect& layerRect, int& left, int& top, int& right, int& bottom) const diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.cpp index 8663ec0ac..4ff8434b2 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.cpp @@ -29,6 +29,7 @@ #include "LayerChromium.h" #include "LayerPainterChromium.h" #include "LayerRendererChromium.h" +#include "Region.h" #include "TraceEvent.h" #include "TreeSynchronizer.h" #include "cc/CCLayerIterator.h" @@ -95,6 +96,9 @@ bool CCLayerTreeHost::initialize() // Update m_settings based on capabilities that we got back from the renderer. m_settings.acceleratePainting = m_proxy->layerRendererCapabilities().usingAcceleratedPainting; + // Update m_settings based on partial update capability. + m_settings.partialTextureUpdates = m_settings.partialTextureUpdates && m_proxy->partialTextureUpdateCapability(); + m_contentsTextureManager = TextureManager::create(TextureManager::highLimitBytes(viewportSize()), TextureManager::reclaimLimitBytes(viewportSize()), m_proxy->layerRendererCapabilities().maxTextureSize); @@ -165,6 +169,7 @@ void CCLayerTreeHost::finishCommitOnImplThread(CCLayerTreeHostImpl* hostImpl) void CCLayerTreeHost::commitComplete() { + m_deleteTextureAfterCommitList.clear(); clearPendingUpdate(); m_contentsTextureManager->unprotectAllTextures(); } @@ -181,10 +186,6 @@ PassOwnPtr<CCLayerTreeHostImpl> CCLayerTreeHost::createLayerTreeHostImpl(CCLayer void CCLayerTreeHost::didRecreateGraphicsContext(bool success) { - if (m_rootLayer) { - m_rootLayer->setLayerTreeHost(0); - m_rootLayer->setLayerTreeHost(this); - } m_client->didRecreateGraphicsContext(success); } @@ -379,6 +380,8 @@ void CCLayerTreeHost::updateLayers(LayerChromium* rootLayer) CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(rootLayer, rootLayer, identityMatrix, identityMatrix, m_updateList, rootRenderSurface->layerList(), layerRendererCapabilities().maxTextureSize); } + reserveTextures(); + paintLayerContents(m_updateList, PaintVisible); if (!m_triggerIdlePaints) return; @@ -397,13 +400,26 @@ void CCLayerTreeHost::updateLayers(LayerChromium* rootLayer) m_contentsTextureManager->setMaxMemoryLimitBytes(maxLimitBytes); } +void CCLayerTreeHost::reserveTextures() +{ + // Use BackToFront since it's cheap and this isn't order-dependent. + typedef CCLayerIterator<LayerChromium, RenderSurfaceChromium, CCLayerIteratorActions::BackToFront> CCLayerIteratorType; + + CCLayerIteratorType end = CCLayerIteratorType::end(&m_updateList); + for (CCLayerIteratorType it = CCLayerIteratorType::begin(&m_updateList); it != end; ++it) { + if (it.representsTargetRenderSurface() || !it->alwaysReserveTextures()) + continue; + it->reserveTextures(); + } +} + // static -void CCLayerTreeHost::paintContentsIfDirty(LayerChromium* layer, PaintType paintType) +void CCLayerTreeHost::paintContentsIfDirty(LayerChromium* layer, PaintType paintType, const Region& occludedScreenSpace) { ASSERT(layer); ASSERT(PaintVisible == paintType || PaintIdle == paintType); if (PaintVisible == paintType) - layer->paintContentsIfDirty(); + layer->paintContentsIfDirty(occludedScreenSpace); else layer->idlePaintContentsIfDirty(); } @@ -414,35 +430,93 @@ void CCLayerTreeHost::paintMaskAndReplicaForRenderSurface(LayerChromium* renderS // in code, we already know that at least something will be drawn into this render surface, so the // mask and replica should be painted. + // FIXME: If the surface has a replica, it should be painted with occlusion that excludes the current target surface subtree. + Region noOcclusion; + if (renderSurfaceLayer->maskLayer()) { renderSurfaceLayer->maskLayer()->setVisibleLayerRect(IntRect(IntPoint(), renderSurfaceLayer->contentBounds())); - paintContentsIfDirty(renderSurfaceLayer->maskLayer(), paintType); + paintContentsIfDirty(renderSurfaceLayer->maskLayer(), paintType, noOcclusion); } LayerChromium* replicaLayer = renderSurfaceLayer->replicaLayer(); if (replicaLayer) { - paintContentsIfDirty(replicaLayer, paintType); + paintContentsIfDirty(replicaLayer, paintType, noOcclusion); if (replicaLayer->maskLayer()) { replicaLayer->maskLayer()->setVisibleLayerRect(IntRect(IntPoint(), replicaLayer->maskLayer()->contentBounds())); - paintContentsIfDirty(replicaLayer->maskLayer(), paintType); + paintContentsIfDirty(replicaLayer->maskLayer(), paintType, noOcclusion); } } } +struct RenderSurfaceRegion { + RenderSurfaceChromium* surface; + Region occludedInScreen; +}; + +// Add the surface to the top of the stack and copy the occlusion from the old top of the stack to the new. +static void enterTargetRenderSurface(Vector<RenderSurfaceRegion>& stack, RenderSurfaceChromium* newTarget) +{ + if (stack.isEmpty()) { + stack.append(RenderSurfaceRegion()); + stack.last().surface = newTarget; + } else if (stack.last().surface != newTarget) { + const RenderSurfaceRegion& previous = stack.last(); + stack.append(RenderSurfaceRegion()); + stack.last().surface = newTarget; + stack.last().occludedInScreen = previous.occludedInScreen; + } +} + +// Pop the top of the stack off, push on the new surface, and merge the old top's occlusion into the new top surface. +static void leaveTargetRenderSurface(Vector<RenderSurfaceRegion>& stack, RenderSurfaceChromium* newTarget) +{ + int lastIndex = stack.size() - 1; + bool surfaceWillBeAtTopAfterPop = stack.size() > 1 && stack[lastIndex - 1].surface == newTarget; + + if (surfaceWillBeAtTopAfterPop) { + // Merge the top of the stack down. + stack[lastIndex - 1].occludedInScreen.unite(stack[lastIndex].occludedInScreen); + stack.removeLast(); + } else { + // Replace the top of the stack with the new pushed surface. Copy the occluded region to the top. + stack.last().surface = newTarget; + } +} + void CCLayerTreeHost::paintLayerContents(const LayerList& renderSurfaceLayerList, PaintType paintType) { // Use FrontToBack to allow for testing occlusion and performing culling during the tree walk. typedef CCLayerIterator<LayerChromium, RenderSurfaceChromium, CCLayerIteratorActions::FrontToBack> CCLayerIteratorType; + // The stack holds occluded regions for subtrees in the RenderSurface-Layer tree, so that when we leave a subtree we may + // apply a mask to it, but not to the parts outside the subtree. + // - The first time we see a new subtree under a target, we add that target to the top of the stack. This can happen as a layer representing itself, or as a target surface. + // - When we visit a target surface, we apply its mask to its subtree, which is at the top of the stack. + // - When we visit a layer representing itself, we add its occlusion to the current subtree, which is at the top of the stack. + // - When we visit a layer representing a contributing surface, the current target will never be the top of the stack since we just came from the contributing surface. + // We merge the occlusion at the top of the stack with the new current subtree. This new target is pushed onto the stack if not already there. + Vector<RenderSurfaceRegion> targetSurfaceStack; + CCLayerIteratorType end = CCLayerIteratorType::end(&renderSurfaceLayerList); for (CCLayerIteratorType it = CCLayerIteratorType::begin(&renderSurfaceLayerList); it != end; ++it) { if (it.representsTargetRenderSurface()) { ASSERT(it->renderSurface()->drawOpacity()); + + enterTargetRenderSurface(targetSurfaceStack, it->renderSurface()); paintMaskAndReplicaForRenderSurface(*it, paintType); + // FIXME: add the replica layer to the current occlusion + + if (it->maskLayer() || it->renderSurface()->drawOpacity() < 1) + targetSurfaceStack.last().occludedInScreen = Region(); } else if (it.representsItself()) { ASSERT(!it->bounds().isEmpty()); - paintContentsIfDirty(*it, paintType); + + enterTargetRenderSurface(targetSurfaceStack, it->targetRenderSurface()); + paintContentsIfDirty(*it, paintType, targetSurfaceStack.last().occludedInScreen); + it->addSelfToOccludedScreenSpace(targetSurfaceStack.last().occludedInScreen); + } else { + leaveTargetRenderSurface(targetSurfaceStack, it.targetRenderSurfaceLayer()->renderSurface()); } } } @@ -514,4 +588,9 @@ void CCLayerTreeHost::stopRateLimiter(GraphicsContext3D* context) } } +void CCLayerTreeHost::deleteTextureAfterCommit(PassOwnPtr<ManagedTexture> texture) +{ + m_deleteTextureAfterCommitList.append(texture); +} + } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.h b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.h index 2f989bcf6..f58203d15 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.h @@ -48,6 +48,7 @@ class CCLayerTreeHostImpl; class CCTextureUpdater; class GraphicsContext3D; class LayerPainterChromium; +class Region; class TextureAllocator; class TextureManager; @@ -76,7 +77,8 @@ struct CCSettings { , showPlatformLayerTree(false) , refreshRate(0) , perTilePainting(false) - , partialSwapEnabled(false) { } + , partialSwapEnabled(false) + , partialTextureUpdates(true) { } bool acceleratePainting; bool compositeOffscreen; @@ -85,6 +87,7 @@ struct CCSettings { double refreshRate; bool perTilePainting; bool partialSwapEnabled; + bool partialTextureUpdates; }; // Provides information on an Impl's rendering capabilities back to the CCLayerTreeHost @@ -192,19 +195,24 @@ public: void startRateLimiter(GraphicsContext3D*); void stopRateLimiter(GraphicsContext3D*); + void deleteTextureAfterCommit(PassOwnPtr<ManagedTexture>); + protected: CCLayerTreeHost(CCLayerTreeHostClient*, const CCSettings&); bool initialize(); private: typedef Vector<RefPtr<LayerChromium> > LayerList; + typedef Vector<OwnPtr<ManagedTexture> > TextureList; enum PaintType { PaintVisible, PaintIdle }; - static void paintContentsIfDirty(LayerChromium*, PaintType); + static void paintContentsIfDirty(LayerChromium*, PaintType, const Region& occludedScreenSpace); void paintLayerContents(const LayerList&, PaintType); void paintMaskAndReplicaForRenderSurface(LayerChromium*, PaintType); void updateLayers(LayerChromium*); + // Pre-reserve textures for any layer marked "always reserve textures" + void reserveTextures(); void clearPendingUpdate(); int m_compositorIdentifier; @@ -233,6 +241,8 @@ private: float m_pageScale; float m_minPageScale, m_maxPageScale; bool m_triggerIdlePaints; + + TextureList m_deleteTextureAfterCommitList; }; } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp index 02186caaf..1846d6c2e 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp @@ -114,7 +114,7 @@ void CCLayerTreeHostImpl::animate(double frameBeginTimeMs) } } -void CCLayerTreeHostImpl::startPageScaleAnimation(const IntSize& targetPosition, bool anchorPoint, float pageScale, double durationMs) +void CCLayerTreeHostImpl::startPageScaleAnimation(const IntSize& targetPosition, bool anchorPoint, float pageScale, double startTimeMs, double durationMs) { if (!m_scrollLayerImpl) return; @@ -122,10 +122,10 @@ void CCLayerTreeHostImpl::startPageScaleAnimation(const IntSize& targetPosition, IntSize scrollTotal = toSize(m_scrollLayerImpl->scrollPosition() + m_scrollLayerImpl->scrollDelta()); scrollTotal.scale(m_pageScaleDelta); float scaleTotal = m_pageScale * m_pageScaleDelta; - IntSize scaledContentSize = m_scrollLayerImpl->children()[0]->contentBounds(); + IntSize scaledContentSize = contentSize(); scaledContentSize.scale(m_pageScaleDelta); - m_pageScaleAnimation = CCPageScaleAnimation::create(scrollTotal, scaleTotal, m_viewportSize, scaledContentSize, currentTimeMs()); + m_pageScaleAnimation = CCPageScaleAnimation::create(scrollTotal, scaleTotal, m_viewportSize, scaledContentSize, startTimeMs); if (anchorPoint) { IntSize windowAnchor(targetPosition); @@ -244,6 +244,15 @@ void CCLayerTreeHostImpl::optimizeRenderPasses(CCRenderPassList& passes) passes[i]->optimizeQuads(); } +IntSize CCLayerTreeHostImpl::contentSize() const +{ + // TODO(aelias): Hardcoding the first child here is weird. Think of + // a cleaner way to get the contentBounds on the Impl side. + if (!m_scrollLayerImpl || m_scrollLayerImpl->children().isEmpty()) + return IntSize(); + return m_scrollLayerImpl->children()[0]->contentBounds(); +} + void CCLayerTreeHostImpl::drawLayers() { TRACE_EVENT("CCLayerTreeHostImpl::drawLayers", this, 0); @@ -346,14 +355,6 @@ bool CCLayerTreeHostImpl::initializeLayerRenderer(PassRefPtr<GraphicsContext3D> OwnPtr<LayerRendererChromium> layerRenderer; layerRenderer = LayerRendererChromium::create(this, context); - // If creation failed, and we had asked for accelerated painting, disable accelerated painting - // and try creating the renderer again. - if (!layerRenderer && m_settings.acceleratePainting) { - m_settings.acceleratePainting = false; - - layerRenderer = LayerRendererChromium::create(this, context); - } - if (m_layerRenderer) m_layerRenderer->close(); @@ -368,7 +369,9 @@ void CCLayerTreeHostImpl::setViewportSize(const IntSize& viewportSize) m_viewportSize = viewportSize; updateMaxScrollPosition(); - m_layerRenderer->viewportChanged(); + + if (m_layerRenderer) + m_layerRenderer->viewportChanged(); } void CCLayerTreeHostImpl::setPageScaleFactorAndLimits(float pageScale, float minPageScale, float maxPageScale) @@ -438,9 +441,7 @@ void CCLayerTreeHostImpl::updateMaxScrollPosition() FloatSize viewBounds = m_viewportSize; viewBounds.scale(1 / m_pageScaleDelta); - // TODO(aelias): Hardcoding the first child here is weird. Think of - // a cleaner way to get the contentBounds on the Impl side. - IntSize maxScroll = m_scrollLayerImpl->children()[0]->contentBounds() - expandedIntSize(viewBounds); + IntSize maxScroll = contentSize() - expandedIntSize(viewBounds); // The viewport may be larger than the contents in some cases, such as // having a vertical scrollbar but no horizontal overflow. maxScroll.clampNegativeToZero(); @@ -450,11 +451,6 @@ void CCLayerTreeHostImpl::updateMaxScrollPosition() // TODO(aelias): Also update sublayers. } -double CCLayerTreeHostImpl::currentTimeMs() const -{ - return monotonicallyIncreasingTime() * 1000.0; -} - void CCLayerTreeHostImpl::setNeedsRedraw() { m_client->setNeedsRedrawOnImplThread(); diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.h index e4d006d4f..a71adae67 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.h @@ -61,8 +61,7 @@ public: static PassOwnPtr<CCLayerTreeHostImpl> create(const CCSettings&, CCLayerTreeHostImplClient*); virtual ~CCLayerTreeHostImpl(); - // CCInputHandlerTarget implementation - virtual double currentTimeMs() const; + // CCInputHandlerClient implementation virtual void setNeedsRedraw(); virtual CCInputHandlerClient::ScrollStatus scrollBegin(const IntPoint&); virtual void scrollBy(const IntSize&); @@ -71,6 +70,7 @@ public: virtual void pinchGestureBegin(); virtual void pinchGestureUpdate(float, const IntPoint&); virtual void pinchGestureEnd(); + virtual void startPageScaleAnimation(const IntSize& targetPosition, bool anchorPoint, float pageScale, double startTimeMs, double durationMs); // Virtual for testing virtual void beginCommit(); @@ -113,8 +113,6 @@ public: void setPageScaleFactorAndLimits(float pageScale, float minPageScale, float maxPageScale); float pageScale() const { return m_pageScale; } - void startPageScaleAnimation(const IntSize& targetPosition, bool anchorPoint, float pageScale, double durationMs); - const CCSettings& settings() const { return m_settings; } PassOwnPtr<CCScrollAndScaleSet> processScrollDeltas(); @@ -135,6 +133,7 @@ private: void trackDamageForAllSurfaces(CCLayerImpl* rootDrawLayer, const CCLayerList& renderSurfaceLayerList); void calculateRenderPasses(CCRenderPassList&); void optimizeRenderPasses(CCRenderPassList&); + IntSize contentSize() const; OwnPtr<LayerRendererChromium> m_layerRenderer; RefPtr<CCLayerImpl> m_rootLayerImpl; diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCCustomLayerDrawQuad.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCPluginDrawQuad.cpp index 8580b10ed..fd2ae4b86 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCCustomLayerDrawQuad.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCPluginDrawQuad.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Google Inc. All rights reserved. + * Copyright (C) 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,17 +25,17 @@ #include "config.h" -#include "cc/CCCustomLayerDrawQuad.h" +#include "cc/CCPluginDrawQuad.h" namespace WebCore { -PassOwnPtr<CCCustomLayerDrawQuad> CCCustomLayerDrawQuad::create(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, CCLayerImpl* layer) +PassOwnPtr<CCPluginDrawQuad> CCPluginDrawQuad::create(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, CCLayerImpl* layer) { - return adoptPtr(new CCCustomLayerDrawQuad(sharedQuadState, quadRect, layer)); + return adoptPtr(new CCPluginDrawQuad(sharedQuadState, quadRect, layer)); } -CCCustomLayerDrawQuad::CCCustomLayerDrawQuad(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, CCLayerImpl* layer) - : CCDrawQuad(sharedQuadState, CCDrawQuad::CustomLayer, quadRect) +CCPluginDrawQuad::CCPluginDrawQuad(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, CCLayerImpl* layer) + : CCDrawQuad(sharedQuadState, CCDrawQuad::PluginContent, quadRect) , m_layer(layer) { ASSERT(m_layer); diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCCustomLayerDrawQuad.h b/Source/WebCore/platform/graphics/chromium/cc/CCPluginDrawQuad.h index a9bd46232..ca52abef4 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCCustomLayerDrawQuad.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCPluginDrawQuad.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Google Inc. All rights reserved. + * Copyright (C) 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,8 +23,8 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CCCustomLayerDrawQuad_h -#define CCCustomLayerDrawQuad_h +#ifndef CCPluginDrawQuad_h +#define CCPluginDrawQuad_h #include "cc/CCDrawQuad.h" #include <wtf/PassOwnPtr.h> @@ -33,18 +33,15 @@ namespace WebCore { class CCLayerImpl; -// FIXME: This class is a temporary way to access CCLayerImpl::draw. This class -// should be converted to a set of draw quads for each layer material type and -// then removed. -class CCCustomLayerDrawQuad : public CCDrawQuad { - WTF_MAKE_NONCOPYABLE(CCCustomLayerDrawQuad); +class CCPluginDrawQuad : public CCDrawQuad { + WTF_MAKE_NONCOPYABLE(CCPluginDrawQuad); public: - static PassOwnPtr<CCCustomLayerDrawQuad> create(const CCSharedQuadState*, const IntRect&, CCLayerImpl*); + static PassOwnPtr<CCPluginDrawQuad> create(const CCSharedQuadState*, const IntRect&, CCLayerImpl*); CCLayerImpl* layer() const { return m_layer; } private: - CCCustomLayerDrawQuad(const CCSharedQuadState*, const IntRect&, CCLayerImpl*); + CCPluginDrawQuad(const CCSharedQuadState*, const IntRect&, CCLayerImpl*); CCLayerImpl* m_layer; }; diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp index bc105bb4b..b20a2f518 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp @@ -32,6 +32,7 @@ #include "Extensions3DChromium.h" #include "GraphicsContext3D.h" #include "LayerRendererChromium.h" +#include "cc/CCPluginDrawQuad.h" #include "cc/CCProxy.h" #include <wtf/text/WTFString.h> @@ -176,6 +177,11 @@ void CCPluginLayerImpl::draw(LayerRendererChromium* layerRenderer) } } +void CCPluginLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState) +{ + IntRect quadRect(IntPoint(), bounds()); + quadList.append(CCPluginDrawQuad::create(sharedQuadState, quadRect, this)); +} void CCPluginLayerImpl::dumpLayerProperties(TextStream& ts, int indent) const { diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h index e09826a34..9b4d5a4d3 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h @@ -41,6 +41,8 @@ public: } virtual ~CCPluginLayerImpl(); + virtual void appendQuads(CCQuadList&, const CCSharedQuadState*); + typedef ProgramBinding<VertexShaderPosTexStretch, FragmentShaderRGBATexAlpha> Program; typedef ProgramBinding<VertexShaderPosTexStretch, FragmentShaderRGBATexFlipAlpha> ProgramFlip; typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderRGBATexRectAlpha> TexRectProgram; diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCProxy.h b/Source/WebCore/platform/graphics/chromium/cc/CCProxy.h index bb3780147..937c154ff 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCProxy.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCProxy.h @@ -79,6 +79,10 @@ public: virtual void start() = 0; // Must be called before using the proxy. virtual void stop() = 0; // Must be called before deleting the proxy. + // Whether sub-regions of textures can be updated or if complete texture + // updates are required. + virtual bool partialTextureUpdateCapability() const = 0; + // Debug hooks #ifndef NDEBUG static bool isMainThread(); diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCQuadCuller.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCQuadCuller.cpp index 4a8b85130..c8bd9b0f3 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCQuadCuller.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCQuadCuller.cpp @@ -31,11 +31,12 @@ #include "Region.h" #include "TransformationMatrix.h" -#include "cc/CCCustomLayerDrawQuad.h" #include "cc/CCLayerImpl.h" #include "cc/CCRenderPass.h" #include "cc/CCRenderSurfaceDrawQuad.h" +using namespace std; + namespace std { // Specialize for OwnPtr<CCDrawQuad> since Vector doesn't know how to reverse a Vector of OwnPtr<T> in general. @@ -49,16 +50,29 @@ void swap(OwnPtr<WebCore::CCDrawQuad>& a, OwnPtr<WebCore::CCDrawQuad>& b) namespace WebCore { -static bool regionContainsRect(const Region& region, const IntRect& rect) +// Determines what portion of rect, if any, is visible (not occluded by region). If +// the resulting visible region is not rectangular, we just return the original rect. +static IntRect rectSubtractRegion(const Region& region, const IntRect& rect) { Region rectRegion(rect); Region intersectRegion(intersect(region, rectRegion)); if (intersectRegion.isEmpty()) - return false; + return rect; + // Test if intersectRegion = rectRegion, if so return empty rect. rectRegion.subtract(intersectRegion); - return rectRegion.isEmpty(); + IntRect boundsRect = rectRegion.bounds(); + if (boundsRect.isEmpty()) + return boundsRect; + + // Test if rectRegion is still a rectangle. If it is, it will be identical to its bounds. + Region boundsRegion(boundsRect); + boundsRegion.subtract(rectRegion); + if (boundsRegion.isEmpty()) + return boundsRect; + + return rect; } void CCQuadCuller::cullOccludedQuads(CCQuadList& quadList) @@ -74,12 +88,23 @@ void CCQuadCuller::cullOccludedQuads(CCQuadList& quadList) for (int i = quadList.size() - 1; i >= 0; --i) { CCDrawQuad* drawQuad = quadList[i].get(); - IntRect quadRect(drawQuad->quadTransform().mapRect(drawQuad->quadRect())); + FloatRect floatTransformedRect = drawQuad->quadTransform().mapRect(FloatRect(drawQuad->quadRect())); + // Inflate rect to be tested to stay conservative. + IntRect transformedQuadRect(enclosingIntRect(floatTransformedRect)); + + IntRect transformedVisibleQuadRect = rectSubtractRegion(opaqueCoverageThusFar, transformedQuadRect); + bool keepQuad = !transformedVisibleQuadRect.isEmpty(); - bool keepQuad = !regionContainsRect(opaqueCoverageThusFar, quadRect); + // See if we can reduce the number of pixels to draw by reducing the size of the draw + // quad - we do this by changing its visible rect. + if (keepQuad && transformedVisibleQuadRect != transformedQuadRect && drawQuad->isLayerAxisAlignedIntRect()) + drawQuad->setQuadVisibleRect(drawQuad->quadTransform().inverse().mapRect(transformedVisibleQuadRect)); - if (keepQuad && drawQuad->drawsOpaque() && drawQuad->isLayerAxisAlignedIntRect()) - opaqueCoverageThusFar.unite(Region(quadRect)); + // When adding rect to opaque region, deflate it to stay conservative. + if (keepQuad && drawQuad->isLayerAxisAlignedIntRect()) { + FloatRect floatOpaqueRect = drawQuad->quadTransform().mapRect(FloatRect(drawQuad->opaqueRect())); + opaqueCoverageThusFar.unite(Region(enclosedIntRect(floatOpaqueRect))); + } if (keepQuad) culledList.append(quadList[i].release()); diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCScheduler.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCScheduler.cpp index 812a0c708..8580467f0 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCScheduler.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCScheduler.cpp @@ -36,9 +36,7 @@ CCScheduler::CCScheduler(CCSchedulerClient* client, PassOwnPtr<CCFrameRateContro { ASSERT(m_client); m_frameRateController->setClient(this); - - // FIXME: make the CCSchedulerStateMachine turn off FrameRateController it isn't needed. - m_frameRateController->setActive(true); + m_frameRateController->setActive(m_stateMachine.vsyncCallbackNeeded()); } CCScheduler::~CCScheduler() @@ -49,7 +47,9 @@ CCScheduler::~CCScheduler() void CCScheduler::setVisible(bool visible) { m_stateMachine.setVisible(visible); + processScheduledActions(); } + void CCScheduler::setNeedsCommit() { m_stateMachine.setNeedsCommit(); @@ -114,8 +114,10 @@ CCSchedulerStateMachine::Action CCScheduler::nextAction() void CCScheduler::processScheduledActions() { // Early out so we don't spam TRACE_EVENTS with useless processScheduledActions. - if (nextAction() == CCSchedulerStateMachine::ACTION_NONE) + if (nextAction() == CCSchedulerStateMachine::ACTION_NONE) { + m_frameRateController->setActive(m_stateMachine.vsyncCallbackNeeded()); return; + } // This function can re-enter itself. For example, draw may call // setNeedsCommit. Proceeed with caution. @@ -151,6 +153,9 @@ void CCScheduler::processScheduledActions() break; } } while (action != CCSchedulerStateMachine::ACTION_NONE); + + // Activate or deactivate the frame rate controller. + m_frameRateController->setActive(m_stateMachine.vsyncCallbackNeeded()); } } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCSchedulerStateMachine.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCSchedulerStateMachine.cpp index 05b4f6cb6..d1aa5ccdc 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCSchedulerStateMachine.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCSchedulerStateMachine.cpp @@ -118,6 +118,18 @@ void CCSchedulerStateMachine::updateState(Action action) } } +bool CCSchedulerStateMachine::vsyncCallbackNeeded() const +{ + if (!m_visible) { + if (m_needsForcedRedraw) + return true; + + return false; + } + + return m_needsRedraw || m_needsForcedRedraw || m_updateMoreResourcesPending; +} + void CCSchedulerStateMachine::didEnterVSync() { m_insideVSync = true; diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCSchedulerStateMachine.h b/Source/WebCore/platform/graphics/chromium/cc/CCSchedulerStateMachine.h index 2d7da7ee3..7de718846 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCSchedulerStateMachine.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCSchedulerStateMachine.h @@ -68,6 +68,10 @@ public: Action nextAction() const; void updateState(Action); + // Indicates whether the scheduler needs a vsync callback in order to make + // progress. + bool vsyncCallbackNeeded() const; + // Indicates that the system has entered and left a vsync callback. // The scheduler will not draw more than once in a given vsync callback. void didEnterVSync(); diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.h b/Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.h index 0d5a4a2d8..4faa22999 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCSingleThreadProxy.h @@ -54,6 +54,7 @@ public: virtual void setVisible(bool); virtual void start(); virtual void stop(); + virtual bool partialTextureUpdateCapability() const { return true; } // CCLayerTreeHostImplClient implementation virtual void onSwapBuffersCompleteOnImplThread() { ASSERT_NOT_REACHED(); } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCSolidColorDrawQuad.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCSolidColorDrawQuad.cpp index d1c729a41..7f6f98113 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCSolidColorDrawQuad.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCSolidColorDrawQuad.cpp @@ -38,8 +38,10 @@ CCSolidColorDrawQuad::CCSolidColorDrawQuad(const CCSharedQuadState* sharedQuadSt : CCDrawQuad(sharedQuadState, CCDrawQuad::SolidColor, quadRect) , m_color(color) { - if (m_color.alpha() != 1) + if (m_color.hasAlpha()) m_quadOpaque = false; + else + m_opaqueRect = quadRect; } } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCSolidColorLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCSolidColorLayerImpl.cpp new file mode 100644 index 000000000..864aff30a --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCSolidColorLayerImpl.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012 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" + +#if USE(ACCELERATED_COMPOSITING) + +#include "cc/CCSolidColorLayerImpl.h" + +#include "LayerRendererChromium.h" +#include "cc/CCSolidColorDrawQuad.h" +#include <wtf/MathExtras.h> +#include <wtf/text/WTFString.h> + +using namespace std; + +namespace WebCore { + +CCSolidColorLayerImpl::CCSolidColorLayerImpl(int id) + : CCLayerImpl(id) + , m_tileSize(256) +{ +} + +CCSolidColorLayerImpl::~CCSolidColorLayerImpl() +{ +} + +TransformationMatrix CCSolidColorLayerImpl::quadTransform() const +{ + TransformationMatrix solidColorTransform = drawTransform(); + solidColorTransform.translate(-bounds().width() / 2.0, -bounds().height() / 2.0); + + return solidColorTransform; +} + +void CCSolidColorLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState) +{ + // We create a series of smaller quads instead of just one large one so that the + // culler can reduce the total pixels drawn. + int width = bounds().width(); + int height = bounds().height(); + for (int x = 0; x < width; x += m_tileSize) { + for (int y = 0; y < height; y += m_tileSize) { + IntRect solidTileRect(x, y, min(width - x, m_tileSize), min(height - y, m_tileSize)); + quadList.append(CCSolidColorDrawQuad::create(sharedQuadState, solidTileRect, backgroundColor())); + } + } +} + +} // namespace WebCore +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCSolidColorLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCSolidColorLayerImpl.h new file mode 100644 index 000000000..c7edc18b2 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCSolidColorLayerImpl.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 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 CCSolidColorLayerImpl_h +#define CCSolidColorLayerImpl_h + +#include "TransformationMatrix.h" +#include "cc/CCLayerImpl.h" + +namespace WebCore { + +class LayerRendererChromium; + +class CCSolidColorLayerImpl : public CCLayerImpl { +public: + static PassRefPtr<CCSolidColorLayerImpl> create(int id) + { + return adoptRef(new CCSolidColorLayerImpl(id)); + } + virtual ~CCSolidColorLayerImpl(); + + virtual TransformationMatrix quadTransform() const; + virtual void appendQuads(CCQuadList&, const CCSharedQuadState*); + +protected: + explicit CCSolidColorLayerImpl(int id); + +private: + virtual const char* layerTypeAsString() const { return "SolidColorLayer"; } + + const int m_tileSize; +}; + +} + +#endif // CCSolidColorLayerImpl_h diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.cpp index 903313513..5e6a8f862 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.cpp @@ -41,6 +41,12 @@ using namespace WTF; +namespace { + +static const size_t textureUpdatesPerFrame = 0; + +} // anonymous namespace + namespace WebCore { PassOwnPtr<CCProxy> CCThreadProxy::create(CCLayerTreeHost* layerTreeHost) @@ -438,8 +444,7 @@ void CCThreadProxy::scheduledActionUpdateMoreResources() { TRACE_EVENT("CCThreadProxy::scheduledActionUpdateMoreResources", this, 0); ASSERT(m_currentTextureUpdaterOnImplThread); - static const int UpdatesPerFrame = 99999; - m_currentTextureUpdaterOnImplThread->update(m_layerTreeHostImpl->context(), UpdatesPerFrame); + m_currentTextureUpdaterOnImplThread->update(m_layerTreeHostImpl->context(), textureUpdatesPerFrame > 0 ? textureUpdatesPerFrame : 99999); } void CCThreadProxy::scheduledActionCommit() @@ -528,8 +533,7 @@ void CCThreadProxy::initializeImplOnImplThread(CCCompletionEvent* completion) TRACE_EVENT("CCThreadProxy::initializeImplOnImplThread", this, 0); ASSERT(isImplThread()); m_layerTreeHostImpl = m_layerTreeHost->createLayerTreeHostImpl(this); - ASSERT(m_layerTreeHostImpl->settings().refreshRate > 0); - const double displayRefreshIntervalMs = 1000.0 / m_layerTreeHostImpl->settings().refreshRate; + const double displayRefreshIntervalMs = 1000.0 / 60.0; OwnPtr<CCFrameRateController> frameRateController = adoptPtr(new CCFrameRateController(CCDelayBasedTimeSource::create(displayRefreshIntervalMs, CCProxy::implThread()))); m_schedulerOnImplThread = CCScheduler::create(this, frameRateController.release()); m_schedulerOnImplThread->setVisible(m_layerTreeHostImpl->visible()); @@ -565,4 +569,9 @@ void CCThreadProxy::layerTreeHostClosedOnImplThread(CCCompletionEvent* completio completion->signal(); } +bool CCThreadProxy::partialTextureUpdateCapability() const +{ + return !textureUpdatesPerFrame; +} + } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.h b/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.h index a41c0d564..a11b52785 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.h @@ -62,6 +62,7 @@ public: virtual void setVisible(bool); virtual void start(); virtual void stop(); + virtual bool partialTextureUpdateCapability() const; // CCLayerTreeHostImplClient implementation virtual void onSwapBuffersCompleteOnImplThread(); diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCTileDrawQuad.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCTileDrawQuad.cpp index df830508a..b35b6f69f 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCTileDrawQuad.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCTileDrawQuad.cpp @@ -29,12 +29,12 @@ namespace WebCore { -PassOwnPtr<CCTileDrawQuad> CCTileDrawQuad::create(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, Platform3DObject textureId, const IntPoint& textureOffset, const IntSize& textureSize, GC3Dint textureFilter, bool swizzleContents, bool leftEdgeAA, bool topEdgeAA, bool rightEdgeAA, bool bottomEdgeAA) +PassOwnPtr<CCTileDrawQuad> CCTileDrawQuad::create(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, const IntRect& opaqueRect, Platform3DObject textureId, const IntPoint& textureOffset, const IntSize& textureSize, GC3Dint textureFilter, bool swizzleContents, bool leftEdgeAA, bool topEdgeAA, bool rightEdgeAA, bool bottomEdgeAA) { - return adoptPtr(new CCTileDrawQuad(sharedQuadState, quadRect, textureId, textureOffset, textureSize, textureFilter, swizzleContents, leftEdgeAA, topEdgeAA, rightEdgeAA, bottomEdgeAA)); + return adoptPtr(new CCTileDrawQuad(sharedQuadState, quadRect, opaqueRect, textureId, textureOffset, textureSize, textureFilter, swizzleContents, leftEdgeAA, topEdgeAA, rightEdgeAA, bottomEdgeAA)); } -CCTileDrawQuad::CCTileDrawQuad(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, Platform3DObject textureId, const IntPoint& textureOffset, const IntSize& textureSize, GC3Dint textureFilter, bool swizzleContents, bool leftEdgeAA, bool topEdgeAA, bool rightEdgeAA, bool bottomEdgeAA) +CCTileDrawQuad::CCTileDrawQuad(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, const IntRect& opaqueRect, Platform3DObject textureId, const IntPoint& textureOffset, const IntSize& textureSize, GC3Dint textureFilter, bool swizzleContents, bool leftEdgeAA, bool topEdgeAA, bool rightEdgeAA, bool bottomEdgeAA) : CCDrawQuad(sharedQuadState, CCDrawQuad::TiledContent, quadRect) , m_textureId(textureId) , m_textureOffset(textureOffset) @@ -48,6 +48,7 @@ CCTileDrawQuad::CCTileDrawQuad(const CCSharedQuadState* sharedQuadState, const I { if (isAntialiased()) m_needsBlending = true; + m_opaqueRect = opaqueRect; } } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCTileDrawQuad.h b/Source/WebCore/platform/graphics/chromium/cc/CCTileDrawQuad.h index 12e53dbd2..33501a806 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCTileDrawQuad.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCTileDrawQuad.h @@ -35,7 +35,7 @@ namespace WebCore { class CCTileDrawQuad : public CCDrawQuad { WTF_MAKE_NONCOPYABLE(CCTileDrawQuad); public: - static PassOwnPtr<CCTileDrawQuad> create(const CCSharedQuadState*, const IntRect& quadRect, Platform3DObject textureId, const IntPoint& textureOffset, const IntSize& textureSize, GC3Dint textureFilter, bool swizzleContents, bool leftEdgeAA, bool topEdgeAA, bool rightEdgeAA, bool bottomEdgeAA); + static PassOwnPtr<CCTileDrawQuad> create(const CCSharedQuadState*, const IntRect& quadRect, const IntRect& opaqueRect, Platform3DObject textureId, const IntPoint& textureOffset, const IntSize& textureSize, GC3Dint textureFilter, bool swizzleContents, bool leftEdgeAA, bool topEdgeAA, bool rightEdgeAA, bool bottomEdgeAA); Platform3DObject textureId() const { return m_textureId; } IntPoint textureOffset() const { return m_textureOffset; } @@ -51,7 +51,7 @@ public: bool isAntialiased() const { return leftEdgeAA() || topEdgeAA() || rightEdgeAA() || bottomEdgeAA(); } private: - CCTileDrawQuad(const CCSharedQuadState*, const IntRect& quadRect, Platform3DObject textureId, const IntPoint& textureOffset, const IntSize& textureSize, GC3Dint textureFilter, bool swizzleContents, bool leftEdgeAA, bool topEdgeAA, bool rightEdgeAA, bool bottomEdgeAA); + CCTileDrawQuad(const CCSharedQuadState*, const IntRect& quadRect, const IntRect& opaqueRect, Platform3DObject textureId, const IntPoint& textureOffset, const IntSize& textureSize, GC3Dint textureFilter, bool swizzleContents, bool leftEdgeAA, bool topEdgeAA, bool rightEdgeAA, bool bottomEdgeAA); Platform3DObject m_textureId; IntPoint m_textureOffset; diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCTiledLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCTiledLayerImpl.cpp index 5849ef1eb..80a0435fd 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCTiledLayerImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCTiledLayerImpl.cpp @@ -51,8 +51,13 @@ public: Platform3DObject textureId() const { return m_textureId; } void setTextureId(Platform3DObject textureId) { m_textureId = textureId; } + + const IntRect& opaqueRect() const { return m_opaqueRect; } + void setOpaqueRect(const IntRect& opaqueRect) { m_opaqueRect = opaqueRect; } + private: Platform3DObject m_textureId; + IntRect m_opaqueRect; }; CCTiledLayerImpl::CCTiledLayerImpl(int id) @@ -122,7 +127,12 @@ void CCTiledLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState { const IntRect& layerRect = visibleLayerRect(); - if (m_skipsDraw || !m_tiler || m_tiler->isEmpty() || layerRect.isEmpty()) + if (m_skipsDraw) + return; + + appendGutterQuads(quadList, sharedQuadState); + + if (!m_tiler || !m_tiler->numTiles() || layerRect.isEmpty()) return; int left, top, right, bottom; @@ -143,6 +153,9 @@ void CCTiledLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState continue; } + IntRect tileOpaqueRect = tile->opaqueRect(); + tileOpaqueRect.intersect(layerRect); + // Keep track of how the top left has moved, so the texture can be // offset the same amount. IntSize displayOffset = tileRect.minXMinYCorner() - displayRect.minXMinYCorner(); @@ -159,7 +172,7 @@ void CCTiledLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState bool bottomEdgeAA = j == m_tiler->numTilesY() - 1 && useAA; const GC3Dint textureFilter = m_tiler->hasBorderTexels() ? GraphicsContext3D::LINEAR : GraphicsContext3D::NEAREST; - quadList.append(CCTileDrawQuad::create(sharedQuadState, tileRect, tile->textureId(), textureOffset, textureSize, textureFilter, contentsSwizzled(), leftEdgeAA, topEdgeAA, rightEdgeAA, bottomEdgeAA)); + quadList.append(CCTileDrawQuad::create(sharedQuadState, tileRect, tileOpaqueRect, tile->textureId(), textureOffset, textureSize, textureFilter, contentsSwizzled(), leftEdgeAA, topEdgeAA, rightEdgeAA, bottomEdgeAA)); if (hasDebugBorders()) { Color color(debugBorderColor().red(), debugBorderColor().green(), debugBorderColor().blue(), debugTileBorderAlpha); @@ -178,14 +191,15 @@ void CCTiledLayerImpl::setTilingData(const CCLayerTilingData& tiler) *m_tiler = tiler; } -void CCTiledLayerImpl::syncTextureId(int i, int j, Platform3DObject textureId) +void CCTiledLayerImpl::pushTileProperties(int i, int j, Platform3DObject textureId, const IntRect& opaqueRect) { DrawableTile* tile = tileAt(i, j); if (!tile) tile = createTile(i, j); tile->setTextureId(textureId); + tile->setOpaqueRect(opaqueRect); } -} +} // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCTiledLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCTiledLayerImpl.h index 478b03402..7ad71599b 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCTiledLayerImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCTiledLayerImpl.h @@ -51,7 +51,7 @@ public: void setSkipsDraw(bool skipsDraw) { m_skipsDraw = skipsDraw; } void setTilingData(const CCLayerTilingData& tiler); - void syncTextureId(int, int, Platform3DObject textureId); + void pushTileProperties(int, int, Platform3DObject textureId, const IntRect& opaqueRect); void setContentsSwizzled(bool contentsSwizzled) { m_contentsSwizzled = contentsSwizzled; } bool contentsSwizzled() const { return m_contentsSwizzled; } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCTimeSource.h b/Source/WebCore/platform/graphics/chromium/cc/CCTimeSource.h index ddb21f7b1..dccb470a6 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCTimeSource.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCTimeSource.h @@ -49,6 +49,7 @@ public: virtual ~CCTimeSource() { } virtual void setClient(CCTimeSourceClient*) = 0; virtual void setActive(bool) = 0; + virtual bool active() const = 0; }; } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCVideoDrawQuad.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCVideoDrawQuad.cpp new file mode 100644 index 000000000..3de38e90f --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCVideoDrawQuad.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012 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 "cc/CCVideoDrawQuad.h" + +namespace WebCore { + +PassOwnPtr<CCVideoDrawQuad> CCVideoDrawQuad::create(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, CCLayerImpl* layer) +{ + return adoptPtr(new CCVideoDrawQuad(sharedQuadState, quadRect, layer)); +} + +CCVideoDrawQuad::CCVideoDrawQuad(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, CCLayerImpl* layer) + : CCDrawQuad(sharedQuadState, CCDrawQuad::VideoContent, quadRect) + , m_layer(layer) +{ + ASSERT(m_layer); +} + +} diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCVideoDrawQuad.h b/Source/WebCore/platform/graphics/chromium/cc/CCVideoDrawQuad.h new file mode 100644 index 000000000..b18bc5541 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCVideoDrawQuad.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 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 CCVideoDrawQuad_h +#define CCVideoDrawQuad_h + +#include "cc/CCDrawQuad.h" +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +class CCLayerImpl; +class CCVideoDrawQuad : public CCDrawQuad { + WTF_MAKE_NONCOPYABLE(CCVideoDrawQuad); +public: + static PassOwnPtr<CCVideoDrawQuad> create(const CCSharedQuadState*, const IntRect&, CCLayerImpl*); + + CCLayerImpl* layer() const { return m_layer; } + +private: + CCVideoDrawQuad(const CCSharedQuadState*, const IntRect&, CCLayerImpl*); + + CCLayerImpl* m_layer; +}; + +} + +#endif diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp index 99e7e1174..09afb08d3 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp @@ -32,9 +32,10 @@ #include "Extensions3DChromium.h" #include "GraphicsContext3D.h" #include "LayerRendererChromium.h" -#include "ProgramBinding.h" #include "NotImplemented.h" +#include "ProgramBinding.h" #include "cc/CCProxy.h" +#include "cc/CCVideoDrawQuad.h" #include <wtf/text/WTFString.h> namespace WebCore { @@ -125,11 +126,15 @@ void CCVideoLayerImpl::draw(LayerRendererChromium* layerRenderer) return; GC3Denum format = convertVFCFormatToGC3DFormat(frame->format()); - if (format == GraphicsContext3D::INVALID_VALUE) + if (format == GraphicsContext3D::INVALID_VALUE) { + m_provider->putCurrentFrame(frame); return; + } - if (!copyFrameToTextures(frame, format, layerRenderer)) + if (!copyFrameToTextures(frame, format, layerRenderer)) { + m_provider->putCurrentFrame(frame); return; + } switch (format) { case GraphicsContext3D::LUMINANCE: @@ -150,6 +155,12 @@ void CCVideoLayerImpl::draw(LayerRendererChromium* layerRenderer) m_provider->putCurrentFrame(frame); } +void CCVideoLayerImpl::appendQuads(CCQuadList& quadList, const CCSharedQuadState* sharedQuadState) +{ + IntRect quadRect(IntPoint(), bounds()); + quadList.append(CCVideoDrawQuad::create(sharedQuadState, quadRect, this)); +} + bool CCVideoLayerImpl::copyFrameToTextures(const VideoFrameChromium* frame, GC3Denum format, LayerRendererChromium* layerRenderer) { if (frame->format() == VideoFrameChromium::NativeTexture) { diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h index cc4cc8232..182f7b582 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h @@ -46,6 +46,8 @@ public: } virtual ~CCVideoLayerImpl(); + virtual void appendQuads(CCQuadList&, const CCSharedQuadState*); + typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderRGBATexFlipAlpha> RGBAProgram; typedef ProgramBinding<VertexShaderPosTexYUVStretch, FragmentShaderYUVVideo> YUVProgram; typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderRGBATexFlipAlpha> NativeTextureProgram; diff --git a/Source/WebCore/platform/graphics/efl/GraphicsContext3DEfl.cpp b/Source/WebCore/platform/graphics/efl/GraphicsContext3DEfl.cpp index d45235e14..e3e82f998 100644 --- a/Source/WebCore/platform/graphics/efl/GraphicsContext3DEfl.cpp +++ b/Source/WebCore/platform/graphics/efl/GraphicsContext3DEfl.cpp @@ -836,6 +836,11 @@ void GraphicsContext3D::setContextLostCallback(PassOwnPtr<ContextLostCallback>) notImplemented(); } +void GraphicsContext3D::setErrorMessageCallback(PassOwnPtr<ErrorMessageCallback>) +{ + notImplemented(); +} + bool GraphicsContext3D::getImageData(Image* image, GC3Denum format, GC3Denum type, bool premultiplyAlpha, bool ignoreGammaAndColorProfile, Vector<uint8_t>& outputVector) { diff --git a/Source/WebCore/platform/graphics/efl/IntRectEfl.cpp b/Source/WebCore/platform/graphics/efl/IntRectEfl.cpp index 0c92f63b6..cfdfe221f 100644 --- a/Source/WebCore/platform/graphics/efl/IntRectEfl.cpp +++ b/Source/WebCore/platform/graphics/efl/IntRectEfl.cpp @@ -25,16 +25,16 @@ namespace WebCore { -IntRect::IntRect(const Eina_Rectangle& r) - : m_location(IntPoint(r.x, r.y)) - , m_size(r.w, r.h) +IntRect::IntRect(const Eina_Rectangle& rect) + : m_location(IntPoint(rect.x, rect.y)) + , m_size(rect.w, rect.h) { } IntRect::operator Eina_Rectangle() const { - Eina_Rectangle r = {x(), y(), width(), height()}; - return r; + Eina_Rectangle rect = {x(), y(), width(), height()}; + return rect; } } diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterNumberParameter.h b/Source/WebCore/platform/graphics/filters/CustomFilterNumberParameter.h new file mode 100644 index 000000000..36568d59a --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/CustomFilterNumberParameter.h @@ -0,0 +1,64 @@ +/* + * Copyright 2012 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER “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 HOLDER 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 CustomFilterNumberParameter_h +#define CustomFilterNumberParameter_h + +#if ENABLE(CSS_SHADERS) +#include "CustomFilterParameter.h" +#include <wtf/Vector.h> + +namespace WebCore { + +class CustomFilterNumberParameter : public CustomFilterParameter { +public: + static PassRefPtr<CustomFilterNumberParameter> create(const String& name) + { + return adoptRef(new CustomFilterNumberParameter(name)); + } + + unsigned size() const { return m_data.size(); } + double valueAt(unsigned index) const { return m_data.at(index); } + + void addValue(double value) { m_data.append(value); } + +private: + CustomFilterNumberParameter(const String& name) + : CustomFilterParameter(NUMBER, name) + { + } + + Vector<double, 4> m_data; +}; + +} // namespace WebCore + +#endif // ENABLE(CSS_SHADERS) + +#endif // CustomFilterNumberParameter_h diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterOperation.cpp b/Source/WebCore/platform/graphics/filters/CustomFilterOperation.cpp new file mode 100644 index 000000000..93af2b73a --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/CustomFilterOperation.cpp @@ -0,0 +1,74 @@ +/* + * Copyright 2012 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER “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 HOLDER 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(CSS_SHADERS) +#include "CustomFilterOperation.h" + +#include "CustomFilterParameter.h" +#include "CustomFilterProgram.h" +#include "FilterOperation.h" + +#include <wtf/text/StringHash.h> + +namespace WebCore { + +CustomFilterOperation::CustomFilterOperation(PassRefPtr<CustomFilterProgram> program, const CustomFilterParameterList& sortedParameters, unsigned meshRows, unsigned meshColumns, MeshBoxType meshBoxType, MeshType meshType) + : FilterOperation(CUSTOM) + , m_program(program) + , m_parameters(sortedParameters) + , m_meshRows(meshRows) + , m_meshColumns(meshColumns) + , m_meshBoxType(meshBoxType) + , m_meshType(meshType) +{ + // Make sure that the parameters are alwyas sorted by name. We use that to merge two CustomFilterOperations in animations. + ASSERT(hasSortedParameterList()); +} + +CustomFilterOperation::~CustomFilterOperation() +{ +} + +#ifndef NDEBUG +bool CustomFilterOperation::hasSortedParameterList() +{ + for (unsigned i = 1; i < m_parameters.size(); ++i) { + // Break for equal or not-sorted parameters. + if (!codePointCompareLessThan(m_parameters.at(i - i)->name(), m_parameters.at(i)->name())) + return false; + } + return true; +} +#endif + +} // namespace WebCore + +#endif // ENABLE(CSS_SHADERS) diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterOperation.h b/Source/WebCore/platform/graphics/filters/CustomFilterOperation.h new file mode 100644 index 000000000..66eb2c8b1 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/CustomFilterOperation.h @@ -0,0 +1,110 @@ +/* + * Copyright 2011 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER “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 HOLDER 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 CustomFilterOperation_h +#define CustomFilterOperation_h + +#if ENABLE(CSS_SHADERS) +#include "CustomFilterProgram.h" +#include "FilterOperation.h" + +#include <wtf/text/WTFString.h> + +namespace WebCore { + +// CSS Shaders + +class CustomFilterParameter; +typedef Vector<RefPtr<CustomFilterParameter> > CustomFilterParameterList; + +class CustomFilterOperation : public FilterOperation { +public: + enum MeshBoxType { + FILTER_BOX, + BORDER_BOX, + PADDING_BOX, + CONTENT_BOX + }; + + enum MeshType { + ATTACHED, + DETACHED + }; + + static PassRefPtr<CustomFilterOperation> create(PassRefPtr<CustomFilterProgram> program, const CustomFilterParameterList& sortedParameters, unsigned meshRows, unsigned meshColumns, MeshBoxType meshBoxType, MeshType meshType) + { + return adoptRef(new CustomFilterOperation(program, sortedParameters, meshRows, meshColumns, meshBoxType, meshType)); + } + + CustomFilterProgram* program() const { return m_program.get(); } + + const CustomFilterParameterList& parameters() { return m_parameters; } + + unsigned meshRows() const { return m_meshRows; } + unsigned meshColumns() const { return m_meshColumns; } + + MeshBoxType meshBoxType() const { return m_meshBoxType; } + MeshType meshType() const { return m_meshType; } + + virtual ~CustomFilterOperation(); + +private: + virtual bool operator==(const FilterOperation& o) const + { + if (!isSameType(o)) + return false; + + const CustomFilterOperation* other = static_cast<const CustomFilterOperation*>(&o); + return m_program.get() == other->m_program.get() + && m_meshRows == other->m_meshRows + && m_meshColumns == other->m_meshColumns + && m_meshBoxType == other->m_meshBoxType + && m_meshType == other->m_meshType; + } + + CustomFilterOperation(PassRefPtr<CustomFilterProgram>, const CustomFilterParameterList&, unsigned meshRows, unsigned meshColumns, MeshBoxType, MeshType); + +#ifndef NDEBUG + bool hasSortedParameterList(); +#endif + + RefPtr<CustomFilterProgram> m_program; + CustomFilterParameterList m_parameters; + + unsigned m_meshRows; + unsigned m_meshColumns; + MeshBoxType m_meshBoxType; + MeshType m_meshType; +}; + +} // namespace WebCore + +#endif // ENABLE(CSS_SHADERS) + +#endif // CustomFilterOperation_h diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterParameter.h b/Source/WebCore/platform/graphics/filters/CustomFilterParameter.h new file mode 100644 index 000000000..cd8cb8805 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/CustomFilterParameter.h @@ -0,0 +1,72 @@ +/* + * Copyright 2012 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER “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 HOLDER 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 CustomFilterParameter_h +#define CustomFilterParameter_h + +#if ENABLE(CSS_SHADERS) +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class CustomFilterParameter : public RefCounted<CustomFilterParameter> { +public: + // FIXME: Implement other parameters types: + // booleans: https://bugs.webkit.org/show_bug.cgi?id=76438 + // textures: https://bugs.webkit.org/show_bug.cgi?id=71442 + // 3d-transforms: https://bugs.webkit.org/show_bug.cgi?id=71443 + // mat2, mat3, mat4: https://bugs.webkit.org/show_bug.cgi?id=71444 + enum ParameterType { + NUMBER + }; + + virtual ~CustomFilterParameter() { } + + ParameterType parameterType() const { return m_type; } + const String& name() const { return m_name; } + +protected: + CustomFilterParameter(ParameterType type, const String& name) + : m_name(name) + , m_type(type) + { + } + +private: + String m_name; + ParameterType m_type; +}; + +} // namespace WebCore + +#endif // ENABLE(CSS_SHADERS) + +#endif // CustomFilterParameter_h diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterProgram.cpp b/Source/WebCore/platform/graphics/filters/CustomFilterProgram.cpp new file mode 100644 index 000000000..d257f3f83 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/CustomFilterProgram.cpp @@ -0,0 +1,92 @@ +/* + * Copyright 2012 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER “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 HOLDER 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(CSS_SHADERS) +#include "CustomFilterProgram.h" + +#include "CustomFilterProgramClient.h" +#include "CustomFilterShader.h" + +#if ENABLE(WEBGL) +#include "GraphicsContext3D.h" +#endif + +namespace WebCore { + +CustomFilterProgram::CustomFilterProgram() +{ + // Keep the constructor protected to prevent creating this object directly. +} + +CustomFilterProgram::~CustomFilterProgram() +{ + // All the clients should keep a reference to this object. + ASSERT(m_clients.isEmpty()); +} + +void CustomFilterProgram::addClient(CustomFilterProgramClient* client) +{ + if (m_clients.isEmpty()) { + // Notify the StyleCustomFilterProgram that we now have at least a client + // and the loading can begin. + // Note: If the shader is already cached the first client will be notified, + // even if the filter was already built. Add the client only after notifying + // the cache about them, so that we avoid a useless recreation of the filters chain. + willHaveClients(); + } + m_clients.add(client); +} + +void CustomFilterProgram::removeClient(CustomFilterProgramClient* client) +{ + m_clients.remove(client); + if (m_clients.isEmpty()) { + // We have no clients anymore, the cached resources can be purged from memory. + didRemoveLastClient(); + } +} + +void CustomFilterProgram::notifyClients() +{ + for (CustomFilterProgramClientList::iterator iter = m_clients.begin(), end = m_clients.end(); iter != end; ++iter) + iter->first->notifyCustomFilterProgramLoaded(this); +} + +#if ENABLE(WEBGL) +PassRefPtr<CustomFilterShader> CustomFilterProgram::createShaderWithContext(GraphicsContext3D* context) +{ + ASSERT(isLoaded()); + return CustomFilterShader::create(context, vertexShaderString(), fragmentShaderString()); +} +#endif + +} // namespace WebCore +#endif // ENABLE(CSS_SHADERS) diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterProgram.h b/Source/WebCore/platform/graphics/filters/CustomFilterProgram.h new file mode 100644 index 000000000..8c9056d39 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/CustomFilterProgram.h @@ -0,0 +1,82 @@ +/* + * Copyright 2012 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER “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 HOLDER 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 CustomFilterProgram_h +#define CustomFilterProgram_h + +#if ENABLE(CSS_SHADERS) + +#include <wtf/HashCountedSet.h> +#include <wtf/RefCounted.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class GraphicsContext3D; +class CustomFilterShader; +class CustomFilterProgramClient; + +// This is the base class for the StyleCustomFilterProgram class which knows how to keep +// references to the cached shaders. +class CustomFilterProgram: public RefCounted<CustomFilterProgram> { +public: + virtual ~CustomFilterProgram(); + + virtual bool isLoaded() const = 0; + + void addClient(CustomFilterProgramClient*); + void removeClient(CustomFilterProgramClient*); + +#if ENABLE(WEBGL) + PassRefPtr<CustomFilterShader> createShaderWithContext(GraphicsContext3D*); +#endif +protected: + // StyleCustomFilterProgram can notify the clients that the cached resources are + // loaded and it is ready to create CustomFilterShader objects. + void notifyClients(); + + virtual String vertexShaderString() const = 0; + virtual String fragmentShaderString() const = 0; + + virtual void willHaveClients() = 0; + virtual void didRemoveLastClient() = 0; + + // Keep the constructor protected to prevent creating this object directly. + CustomFilterProgram(); + +private: + typedef HashCountedSet<CustomFilterProgramClient*> CustomFilterProgramClientList; + CustomFilterProgramClientList m_clients; +}; + +} + +#endif // ENABLE(CSS_SHADERS) + +#endif diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterProgramClient.h b/Source/WebCore/platform/graphics/filters/CustomFilterProgramClient.h new file mode 100644 index 000000000..488247d9f --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/CustomFilterProgramClient.h @@ -0,0 +1,52 @@ +/* + * Copyright 2012 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER “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 HOLDER 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 CustomFilterProgramClient_h +#define CustomFilterProgramClient_h + +#if ENABLE(CSS_SHADERS) + +namespace WebCore { + +class CustomFilterProgram; + +class CustomFilterProgramClient { +public: + virtual ~CustomFilterProgramClient() + { + } + + virtual void notifyCustomFilterProgramLoaded(CustomFilterProgram*) = 0; +}; + +} + +#endif // ENABLE(CSS_SHADERS) + +#endif // CustomFilterProgramClient_h diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterShader.cpp b/Source/WebCore/platform/graphics/filters/CustomFilterShader.cpp index 6df78de97..cacfeb615 100644 --- a/Source/WebCore/platform/graphics/filters/CustomFilterShader.cpp +++ b/Source/WebCore/platform/graphics/filters/CustomFilterShader.cpp @@ -160,6 +160,13 @@ void CustomFilterShader::initializeParameterLocations() m_samplerSizeLocation = m_context->getUniformLocation(m_program, "s_textureSize"); m_contentSamplerLocation = m_context->getUniformLocation(m_program, "s_contentTexture"); } + +int CustomFilterShader::uniformLocationByName(const String& name) +{ + ASSERT(m_isInitialized); + // FIXME: Improve this by caching the uniform locations. + return m_context->getUniformLocation(m_program, name); +} CustomFilterShader::~CustomFilterShader() { diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterShader.h b/Source/WebCore/platform/graphics/filters/CustomFilterShader.h index 90602cb1e..6141c18c7 100644 --- a/Source/WebCore/platform/graphics/filters/CustomFilterShader.h +++ b/Source/WebCore/platform/graphics/filters/CustomFilterShader.h @@ -63,6 +63,8 @@ public: int samplerLocation() const { return m_samplerLocation; } int contentSamplerLocation() const { return m_contentSamplerLocation; } int samplerSizeLocation() const { return m_samplerSizeLocation; } + + int uniformLocationByName(const String&); bool isInitialized() const { return m_isInitialized; } diff --git a/Source/WebCore/platform/graphics/filters/FEColorMatrix.h b/Source/WebCore/platform/graphics/filters/FEColorMatrix.h index d03b6d376..27a4ac843 100644 --- a/Source/WebCore/platform/graphics/filters/FEColorMatrix.h +++ b/Source/WebCore/platform/graphics/filters/FEColorMatrix.h @@ -49,6 +49,9 @@ public: bool setValues(const Vector<float>&); virtual void platformApplySoftware(); +#if USE(SKIA) + virtual bool platformApplySkia(); +#endif virtual void dump(); virtual TextStream& externalRepresentation(TextStream&, int indention) const; diff --git a/Source/WebCore/platform/graphics/filters/FECustomFilter.cpp b/Source/WebCore/platform/graphics/filters/FECustomFilter.cpp index fb4270e47..95f51fc9b 100644 --- a/Source/WebCore/platform/graphics/filters/FECustomFilter.cpp +++ b/Source/WebCore/platform/graphics/filters/FECustomFilter.cpp @@ -34,6 +34,9 @@ #include "CachedShader.h" #include "CustomFilterMesh.h" +#include "CustomFilterNumberParameter.h" +#include "CustomFilterParameter.h" +#include "CustomFilterProgram.h" #include "CustomFilterShader.h" #include "Document.h" #include "DrawingBuffer.h" @@ -73,13 +76,13 @@ static void orthogonalProjectionMatrix(TransformationMatrix& matrix, float left, matrix.setM44(1.0f); } -FECustomFilter::FECustomFilter(Filter* filter, Document* document, const String& vertexShader, const String& fragmentShader, +FECustomFilter::FECustomFilter(Filter* filter, Document* document, PassRefPtr<CustomFilterProgram> program, const CustomFilterParameterList& parameters, unsigned meshRows, unsigned meshColumns, CustomFilterOperation::MeshBoxType meshBoxType, CustomFilterOperation::MeshType meshType) : FilterEffect(filter) , m_document(document) - , m_vertexShader(vertexShader) - , m_fragmentShader(fragmentShader) + , m_program(program) + , m_parameters(parameters) , m_meshRows(meshRows) , m_meshColumns(meshColumns) , m_meshBoxType(meshBoxType) @@ -87,11 +90,11 @@ FECustomFilter::FECustomFilter(Filter* filter, Document* document, const String& { } -PassRefPtr<FECustomFilter> FECustomFilter::create(Filter* filter, Document* document, const String& vertexShader, const String& fragmentShader, +PassRefPtr<FECustomFilter> FECustomFilter::create(Filter* filter, Document* document, PassRefPtr<CustomFilterProgram> program, const CustomFilterParameterList& parameters, unsigned meshRows, unsigned meshColumns, CustomFilterOperation::MeshBoxType meshBoxType, CustomFilterOperation::MeshType meshType) { - return adoptRef(new FECustomFilter(filter, document, vertexShader, fragmentShader, meshRows, meshColumns, meshBoxType, meshType)); + return adoptRef(new FECustomFilter(filter, document, program, parameters, meshRows, meshColumns, meshBoxType, meshType)); } void FECustomFilter::platformApplySoftware() @@ -116,6 +119,10 @@ void FECustomFilter::platformApplySoftware() if (m_inputTexture->tiles().numTiles() != 1) return; + // The shader had compiler errors. We cannot draw anything. + if (!m_shader->isInitialized()) + return; + m_context->clearColor(0, 0, 0, 0); m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT); @@ -137,10 +144,11 @@ void FECustomFilter::initializeContext(const IntSize& contextSize) attributes.preserveDrawingBuffer = true; attributes.premultipliedAlpha = false; + ASSERT(!m_context.get()); m_context = GraphicsContext3D::create(attributes, m_document->view()->root()->hostWindow(), GraphicsContext3D::RenderOffscreen); m_drawingBuffer = DrawingBuffer::create(m_context.get(), contextSize, !attributes.preserveDrawingBuffer); - m_shader = CustomFilterShader::create(m_context.get(), m_vertexShader, m_fragmentShader); + m_shader = m_program->createShaderWithContext(m_context.get()); m_mesh = CustomFilterMesh::create(m_context.get(), m_meshColumns, m_meshRows, FloatRect(0, 0, 1, 1), m_meshType); @@ -165,6 +173,46 @@ void FECustomFilter::bindVertexAttribute(int attributeLocation, unsigned size, u offset += size * sizeof(float); } +void FECustomFilter::bindProgramNumberParameters(int uniformLocation, CustomFilterNumberParameter* numberParameter) +{ + switch (numberParameter->size()) { + case 1: + m_context->uniform1f(uniformLocation, numberParameter->valueAt(0)); + break; + case 2: + m_context->uniform2f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1)); + break; + case 3: + m_context->uniform3f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1), numberParameter->valueAt(2)); + break; + case 4: + m_context->uniform4f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1), numberParameter->valueAt(2), numberParameter->valueAt(3)); + break; + default: + ASSERT_NOT_REACHED(); + } +} + +void FECustomFilter::bindProgramParameters() +{ + // FIXME: Find a way to reset uniforms that are not specified in CSS. This is needed to avoid using values + // set by other previous rendered filters. + // https://bugs.webkit.org/show_bug.cgi?id=76440 + + size_t parametersSize = m_parameters.size(); + for (size_t i = 0; i < parametersSize; ++i) { + CustomFilterParameter* parameter = m_parameters.at(i).get(); + int uniformLocation = m_shader->uniformLocationByName(parameter->name()); + if (uniformLocation == -1) + continue; + switch (parameter->parameterType()) { + case CustomFilterParameter::NUMBER: + bindProgramNumberParameters(uniformLocation, static_cast<CustomFilterNumberParameter*>(parameter)); + break; + } + } +} + void FECustomFilter::bindProgramAndBuffers(ByteArray* srcPixelArray) { m_context->useProgram(m_shader->program()); @@ -193,6 +241,8 @@ void FECustomFilter::bindProgramAndBuffers(ByteArray* srcPixelArray) bindVertexAttribute(m_shader->meshAttribLocation(), 2, offset); if (m_meshType == CustomFilterOperation::DETACHED) bindVertexAttribute(m_shader->triangleAttribLocation(), 3, offset); + + bindProgramParameters(); } void FECustomFilter::dump() diff --git a/Source/WebCore/platform/graphics/filters/FECustomFilter.h b/Source/WebCore/platform/graphics/filters/FECustomFilter.h index 2aaabf6ba..1fa2d292a 100644 --- a/Source/WebCore/platform/graphics/filters/FECustomFilter.h +++ b/Source/WebCore/platform/graphics/filters/FECustomFilter.h @@ -45,6 +45,8 @@ namespace WebCore { class CachedShader; class CustomFilterMesh; +class CustomFilterNumberParameter; +class CustomFilterProgram; class CustomFilterShader; class Document; class DrawingBuffer; @@ -54,7 +56,7 @@ class Texture; class FECustomFilter : public FilterEffect { public: - static PassRefPtr<FECustomFilter> create(Filter*, Document*, const String& vertexShader, const String& fragmentShader, + static PassRefPtr<FECustomFilter> create(Filter*, Document*, PassRefPtr<CustomFilterProgram>, const CustomFilterParameterList&, unsigned meshRows, unsigned meshColumns, CustomFilterOperation::MeshBoxType, CustomFilterOperation::MeshType); @@ -64,13 +66,15 @@ public: virtual TextStream& externalRepresentation(TextStream&, int indention) const; private: - FECustomFilter(Filter*, Document*, const String& vertexShader, const String& fragmentShader, + FECustomFilter(Filter*, Document*, PassRefPtr<CustomFilterProgram>, const CustomFilterParameterList&, unsigned meshRows, unsigned meshColumns, CustomFilterOperation::MeshBoxType, CustomFilterOperation::MeshType); void initializeContext(const IntSize& contextSize); void resizeContext(const IntSize& newContextSize); void bindVertexAttribute(int attributeLocation, unsigned size, unsigned& offset); + void bindProgramNumberParameters(int uniformLocation, CustomFilterNumberParameter*); + void bindProgramParameters(); void bindProgramAndBuffers(ByteArray* srcPixelArray); Document* m_document; @@ -81,9 +85,9 @@ private: RefPtr<CustomFilterShader> m_shader; RefPtr<CustomFilterMesh> m_mesh; IntSize m_contextSize; - - String m_vertexShader; - String m_fragmentShader; + + RefPtr<CustomFilterProgram> m_program; + CustomFilterParameterList m_parameters; unsigned m_meshRows; unsigned m_meshColumns; diff --git a/Source/WebCore/platform/graphics/filters/FETile.cpp b/Source/WebCore/platform/graphics/filters/FETile.cpp index a6e1da334..e4a9508ee 100644 --- a/Source/WebCore/platform/graphics/filters/FETile.cpp +++ b/Source/WebCore/platform/graphics/filters/FETile.cpp @@ -67,7 +67,7 @@ void FETile::platformApplySoftware() } OwnPtr<ImageBuffer> tileImage; - if (!SVGImageBufferTools::createImageBuffer(tileRect, tileRect, tileImage, ColorSpaceDeviceRGB, filter()->renderingMode())) + if (!SVGImageBufferTools::createImageBufferForPattern(tileRect, tileRect, tileImage, ColorSpaceDeviceRGB, filter()->renderingMode())) return; GraphicsContext* tileImageContext = tileImage->context(); diff --git a/Source/WebCore/platform/graphics/filters/FETurbulence.cpp b/Source/WebCore/platform/graphics/filters/FETurbulence.cpp index 3ca45717e..d5d64c130 100644 --- a/Source/WebCore/platform/graphics/filters/FETurbulence.cpp +++ b/Source/WebCore/platform/graphics/filters/FETurbulence.cpp @@ -148,16 +148,6 @@ bool FETurbulence::setStitchTiles(bool 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) - , filterSize(paintingSize) -{ -} - // Compute pseudo random number. inline long FETurbulence::PaintingData::random() { @@ -225,7 +215,7 @@ inline void checkNoise(int& noiseValue, int limitValue, int newValue) noiseValue -= newValue - 1; } -float FETurbulence::noise2D(int channel, PaintingData& paintingData, const FloatPoint& noiseVector) +float FETurbulence::noise2D(int channel, PaintingData& paintingData, StitchData& stitchData, const FloatPoint& noiseVector) { struct Noise { int noisePositionIntegerValue; @@ -246,8 +236,8 @@ float FETurbulence::noise2D(int channel, PaintingData& paintingData, const Float // If stitching, adjust lattice points accordingly. if (m_stitchTiles) { - checkNoise(noiseX.noisePositionIntegerValue, paintingData.wrapX, paintingData.width); - checkNoise(noiseY.noisePositionIntegerValue, paintingData.wrapY, paintingData.height); + checkNoise(noiseX.noisePositionIntegerValue, stitchData.wrapX, stitchData.width); + checkNoise(noiseY.noisePositionIntegerValue, stitchData.wrapY, stitchData.height); } noiseX.noisePositionIntegerValue &= s_blockMask; @@ -276,57 +266,58 @@ float FETurbulence::noise2D(int channel, PaintingData& paintingData, const Float return linearInterpolation(sy, a, b); } -unsigned char FETurbulence::calculateTurbulenceValueForPoint(int channel, PaintingData& paintingData, const FloatPoint& point) +unsigned char FETurbulence::calculateTurbulenceValueForPoint(int channel, PaintingData& paintingData, StitchData& stitchData, const FloatPoint& point) { float tileWidth = paintingData.filterSize.width(); - ASSERT(tileWidth > 0); float tileHeight = paintingData.filterSize.height(); - ASSERT(tileHeight > 0); + ASSERT(tileWidth > 0 && tileHeight > 0); + float baseFrequencyX = m_baseFrequencyX; + float baseFrequencyY = m_baseFrequencyY; // 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; + if (baseFrequencyX) { + float lowFrequency = floorf(tileWidth * baseFrequencyX) / tileWidth; + float highFrequency = ceilf(tileWidth * baseFrequencyX) / tileWidth; // BaseFrequency should be non-negative according to the standard. - if (m_baseFrequencyX / lowFrequency < highFrequency / m_baseFrequencyX) - m_baseFrequencyX = lowFrequency; + if (baseFrequencyX / lowFrequency < highFrequency / baseFrequencyX) + baseFrequencyX = lowFrequency; else - m_baseFrequencyX = highFrequency; + 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; + if (baseFrequencyY) { + float lowFrequency = floorf(tileHeight * baseFrequencyY) / tileHeight; + float highFrequency = ceilf(tileHeight * baseFrequencyY) / tileHeight; + if (baseFrequencyY / lowFrequency < highFrequency / baseFrequencyY) + baseFrequencyY = lowFrequency; else - m_baseFrequencyY = highFrequency; + 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; + stitchData.width = roundf(tileWidth * baseFrequencyX); + stitchData.wrapX = s_perlinNoise + stitchData.width; + stitchData.height = roundf(tileHeight * baseFrequencyY); + stitchData.wrapY = s_perlinNoise + stitchData.height; } float turbulenceFunctionResult = 0; - FloatPoint noiseVector(point.x() * m_baseFrequencyX, point.y() * m_baseFrequencyY); + FloatPoint noiseVector(point.x() * baseFrequencyX, point.y() * baseFrequencyY); float ratio = 1; for (int octave = 0; octave < m_numOctaves; ++octave) { if (m_type == FETURBULENCE_TYPE_FRACTALNOISE) - turbulenceFunctionResult += noise2D(channel, paintingData, noiseVector) / ratio; + turbulenceFunctionResult += noise2D(channel, paintingData, stitchData, noiseVector) / ratio; else - turbulenceFunctionResult += fabsf(noise2D(channel, paintingData, noiseVector)) / ratio; + turbulenceFunctionResult += fabsf(noise2D(channel, paintingData, stitchData, 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; + stitchData.width *= 2; + stitchData.wrapX = 2 * stitchData.wrapX - s_perlinNoise; + stitchData.height *= 2; + stitchData.wrapY = 2 * stitchData.wrapY - s_perlinNoise; } } @@ -345,6 +336,7 @@ inline void FETurbulence::fillRegion(ByteArray* pixelArray, PaintingData& painti IntPoint point(0, filterRegion.y() + startY); int indexOfPixelChannel = startY * (filterRegion.width() << 2); int channel; + StitchData stitchData; for (int y = startY; y < endY; ++y) { point.setY(point.y() + 1); @@ -352,7 +344,7 @@ inline void FETurbulence::fillRegion(ByteArray* pixelArray, PaintingData& painti for (int x = 0; x < filterRegion.width(); ++x) { point.setX(point.x() + 1); for (channel = 0; channel < 4; ++channel, ++indexOfPixelChannel) - pixelArray->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(channel, paintingData, filter()->mapAbsolutePointToLocalPoint(point))); + pixelArray->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(channel, paintingData, stitchData, filter()->mapAbsolutePointToLocalPoint(point))); } } } diff --git a/Source/WebCore/platform/graphics/filters/FETurbulence.h b/Source/WebCore/platform/graphics/filters/FETurbulence.h index 01d3c597a..59257d026 100644 --- a/Source/WebCore/platform/graphics/filters/FETurbulence.h +++ b/Source/WebCore/platform/graphics/filters/FETurbulence.h @@ -74,19 +74,35 @@ private: static const int s_minimalRectDimension = (100 * 100); // Empirical data limit for parallel jobs. struct PaintingData { + PaintingData(long paintingSeed, const IntSize& paintingSize) + : seed(paintingSeed) + , filterSize(paintingSize) + { + } + 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; IntSize filterSize; - PaintingData(long paintingSeed, const IntSize& paintingSize); inline long random(); }; + struct StitchData { + StitchData() + : width(0) + , wrapX(0) + , height(0) + , wrapY(0) + { + } + + int width; // How much to subtract to wrap for stitching. + int wrapX; // Minimum value to wrap. + int height; + int wrapY; + }; + template<typename Type> friend class ParallelJobs; @@ -103,8 +119,8 @@ private: FETurbulence(Filter*, TurbulenceType, float, float, int, float, bool); inline void initPaint(PaintingData&); - float noise2D(int channel, PaintingData&, const FloatPoint&); - unsigned char calculateTurbulenceValueForPoint(int channel, PaintingData&, const FloatPoint&); + float noise2D(int channel, PaintingData&, StitchData&, const FloatPoint&); + unsigned char calculateTurbulenceValueForPoint(int channel, PaintingData&, StitchData&, const FloatPoint&); inline void fillRegion(ByteArray*, PaintingData&, int, int); TurbulenceType m_type; diff --git a/Source/WebCore/platform/graphics/gtk/GraphicsContext3DPrivate.cpp b/Source/WebCore/platform/graphics/glx/GraphicsContext3DPrivate.cpp index 523bc7e36..a628a4bd6 100644 --- a/Source/WebCore/platform/graphics/gtk/GraphicsContext3DPrivate.cpp +++ b/Source/WebCore/platform/graphics/glx/GraphicsContext3DPrivate.cpp @@ -240,9 +240,8 @@ bool GraphicsContext3DPrivate::makeContextCurrent() return true; if (!m_context) return false; - if (m_pbuffer) { + if (m_pbuffer) return ::glXMakeCurrent(sharedDisplay(), m_pbuffer, m_context); - } ASSERT(m_glxPixmap); return ::glXMakeCurrent(sharedDisplay(), m_glxPixmap, m_context); diff --git a/Source/WebCore/platform/graphics/gtk/GraphicsContext3DPrivate.h b/Source/WebCore/platform/graphics/glx/GraphicsContext3DPrivate.h index 4134895b7..33a500d0a 100644 --- a/Source/WebCore/platform/graphics/gtk/GraphicsContext3DPrivate.h +++ b/Source/WebCore/platform/graphics/glx/GraphicsContext3DPrivate.h @@ -33,12 +33,12 @@ namespace WebCore { class GraphicsContext3D; class GraphicsContext3DPrivate { - public: +public: static PassOwnPtr<GraphicsContext3DPrivate> create(); ~GraphicsContext3DPrivate(); bool makeContextCurrent(); - private: +private: friend class GraphicsContext3D; static GraphicsContext3DPrivate* createPbufferContext(); static GraphicsContext3DPrivate* createPixmapContext(); diff --git a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp index d1d2cf2c3..9dd3b9de5 100644 --- a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp +++ b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp @@ -72,8 +72,10 @@ void DrawingBuffer::clear() return; m_context->makeContextCurrent(); - if (!m_size.isEmpty()) + if (!m_size.isEmpty()) { s_currentResourceUsePixels -= m_size.width() * m_size.height(); + m_size = IntSize(); + } if (m_colorBuffer) { m_context->deleteTexture(m_colorBuffer); diff --git a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp index fd5e977ce..ad4c24d82 100644 --- a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp @@ -18,6 +18,7 @@ #include "config.h" #include "WebKitWebSourceGStreamer.h" + #if ENABLE(VIDEO) && USE(GSTREAMER) #include "Document.h" @@ -31,9 +32,9 @@ #include "ResourceHandleInternal.h" #include "ResourceRequest.h" #include "ResourceResponse.h" -#include <wtf/text/CString.h> #include <gst/app/gstappsrc.h> #include <gst/pbutils/missing-plugins.h> +#include <wtf/text/CString.h> using namespace WebCore; @@ -106,22 +107,23 @@ static GstStaticPadTemplate srcTemplate = GST_STATIC_PAD_TEMPLATE("src", GST_DEBUG_CATEGORY_STATIC(webkit_web_src_debug); #define GST_CAT_DEFAULT webkit_web_src_debug -static void webKitWebSrcUriHandlerInit(gpointer gIface, - gpointer ifaceData); +static void webKitWebSrcUriHandlerInit(gpointer gIface, gpointer ifaceData); + +static void webKitWebSrcFinalize(GObject*); +static void webKitWebSrcSetProperty(GObject*, guint propertyID, const GValue*, GParamSpec*); +static void webKitWebSrcGetProperty(GObject*, guint propertyID, GValue*, GParamSpec*); +static GstStateChangeReturn webKitWebSrcChangeState(GstElement*, GstStateChange); -static void webKitWebSrcFinalize(GObject* object); -static void webKitWebSrcSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* pspec); -static void webKitWebSrcGetProperty(GObject* object, guint propID, GValue* value, GParamSpec* pspec); -static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStateChange transition); -static gboolean webKitWebSrcQuery(GstPad* pad, GstQuery* query); +static gboolean webKitWebSrcQueryWithParent(GstPad*, GstObject*, GstQuery*); +#ifndef GST_API_VERSION_1 +static gboolean webKitWebSrcQuery(GstPad*, GstQuery*); +#endif -static void webKitWebSrcNeedDataCb(GstAppSrc* appsrc, guint length, gpointer userData); -static void webKitWebSrcEnoughDataCb(GstAppSrc* appsrc, gpointer userData); -static gboolean webKitWebSrcSeekDataCb(GstAppSrc* appsrc, guint64 offset, gpointer userData); +static void webKitWebSrcNeedDataCb(GstAppSrc*, guint length, gpointer userData); +static void webKitWebSrcEnoughDataCb(GstAppSrc*, gpointer userData); +static gboolean webKitWebSrcSeekDataCb(GstAppSrc*, guint64 offset, gpointer userData); -static void webKitWebSrcStop(WebKitWebSrc* src, bool seeking); -static gboolean webKitWebSrcSetUri(GstURIHandler*, const gchar*); -static const gchar* webKitWebSrcGetUri(GstURIHandler*); +static void webKitWebSrcStop(WebKitWebSrc*, bool); static GstAppSrcCallbacks appsrcCallbacks = { webKitWebSrcNeedDataCb, @@ -148,7 +150,11 @@ static void webkit_web_src_class_init(WebKitWebSrcClass* klass) gst_element_class_add_pad_template(eklass, gst_static_pad_template_get(&srcTemplate)); +#ifdef GST_API_VERSION_1 + gst_element_class_set_metadata(eklass, +#else gst_element_class_set_details_simple(eklass, +#endif (gchar*) "WebKit Web source element", (gchar*) "Source", (gchar*) "Handles HTTP/HTTPS uris", @@ -235,7 +241,13 @@ static void webkit_web_src_init(WebKitWebSrc* src) priv->srcpad = gst_ghost_pad_new_from_template("src", targetPad.get(), padTemplate.get()); gst_element_add_pad(GST_ELEMENT(src), priv->srcpad); + +#ifdef GST_API_VERSION_1 + GST_OBJECT_FLAG_SET(priv->srcpad, GST_PAD_FLAG_NEED_PARENT); + gst_pad_set_query_function(priv->srcpad, webKitWebSrcQueryWithParent); +#else gst_pad_set_query_function(priv->srcpad, webKitWebSrcQuery); +#endif gst_app_src_set_callbacks(priv->appsrc, &appsrcCallbacks, src, 0); gst_app_src_set_emit_signals(priv->appsrc, FALSE); @@ -286,7 +298,11 @@ static void webKitWebSrcSetProperty(GObject* object, guint propID, const GValue* priv->iradioMode = g_value_get_boolean(value); break; case PROP_LOCATION: - webKitWebSrcSetUri(reinterpret_cast<GstURIHandler*>(src), g_value_get_string(value)); +#ifdef GST_API_VERSION_1 + gst_uri_handler_set_uri(reinterpret_cast<GstURIHandler*>(src), g_value_get_string(value), 0); +#else + gst_uri_handler_set_uri(reinterpret_cast<GstURIHandler*>(src), g_value_get_string(value)); +#endif break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, pspec); @@ -316,7 +332,7 @@ static void webKitWebSrcGetProperty(GObject* object, guint propID, GValue* value g_value_set_string(value, priv->iradioTitle); break; case PROP_LOCATION: - g_value_set_string(value, webKitWebSrcGetUri(reinterpret_cast<GstURIHandler*>(src))); + g_value_set_string(value, priv->uri); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, pspec); @@ -481,15 +497,13 @@ static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStat return ret; } -static gboolean webKitWebSrcQuery(GstPad* pad, GstQuery* query) +static gboolean webKitWebSrcQueryWithParent(GstPad* pad, GstObject* parent, GstQuery* query) { - GRefPtr<GstElement> src = adoptGRef(gst_pad_get_parent_element(pad)); - WebKitWebSrc* webkitSrc = WEBKIT_WEB_SRC(src.get()); + WebKitWebSrc* webkitSrc = WEBKIT_WEB_SRC(GST_ELEMENT(parent)); gboolean result = FALSE; switch (GST_QUERY_TYPE(query)) { - case GST_QUERY_DURATION: - { + case GST_QUERY_DURATION: { GstFormat format; gst_query_parse_duration(query, &format, NULL); @@ -501,24 +515,79 @@ static gboolean webKitWebSrcQuery(GstPad* pad, GstQuery* query) } break; } - case GST_QUERY_URI: - { + case GST_QUERY_URI: { gst_query_set_uri(query, webkitSrc->priv->uri); result = TRUE; break; } - default: + default: { + GRefPtr<GstPad> target = adoptGRef(gst_ghost_pad_get_target(GST_GHOST_PAD_CAST(pad))); + + // Forward the query to the proxy target pad. + if (target) + result = gst_pad_query(target.get(), query); break; } - - if (!result) - result = gst_pad_query_default(pad, query); + } return result; } +#ifndef GST_API_VERSION_1 +static gboolean webKitWebSrcQuery(GstPad* pad, GstQuery* query) +{ + GRefPtr<GstElement> src = adoptGRef(gst_pad_get_parent_element(pad)); + return webKitWebSrcQueryWithParent(pad, GST_OBJECT(src.get()), query); +} +#endif + // uri handler interface +#ifdef GST_API_VERSION_1 +static GstURIType webKitWebSrcUriGetType(GType) +{ + return GST_URI_SRC; +} + +const gchar* const* webKitWebSrcGetProtocols(GType) +{ + static const char* protocols[] = {"http", "https", 0 }; + return protocols; +} + +static gchar* webKitWebSrcGetUri(GstURIHandler* handler) +{ + return g_strdup(WEBKIT_WEB_SRC(handler)->priv->uri); +} + +static gboolean webKitWebSrcSetUri(GstURIHandler* handler, const gchar* uri, GError** error) +{ + WebKitWebSrc* src = WEBKIT_WEB_SRC(handler); + WebKitWebSrcPrivate* priv = src->priv; + + if (GST_STATE(src) >= GST_STATE_PAUSED) { + GST_ERROR_OBJECT(src, "URI can only be set in states < PAUSED"); + return FALSE; + } + + g_free(priv->uri); + priv->uri = 0; + + if (!uri) + return TRUE; + + KURL url(KURL(), uri); + + if (!url.isValid() || !url.protocolInHTTPFamily()) { + g_set_error(error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, "Invalid URI '%s'", uri); + return FALSE; + } + + priv->uri = g_strdup(url.string().utf8().data()); + return TRUE; +} + +#else static GstURIType webKitWebSrcUriGetType(void) { return GST_URI_SRC; @@ -527,16 +596,12 @@ static GstURIType webKitWebSrcUriGetType(void) static gchar** webKitWebSrcGetProtocols(void) { static gchar* protocols[] = {(gchar*) "http", (gchar*) "https", 0 }; - return protocols; } static const gchar* webKitWebSrcGetUri(GstURIHandler* handler) { - WebKitWebSrc* src = WEBKIT_WEB_SRC(handler); - WebKitWebSrcPrivate* priv = src->priv; - - return priv->uri; + return g_strdup(WEBKIT_WEB_SRC(handler)->priv->uri); } static gboolean webKitWebSrcSetUri(GstURIHandler* handler, const gchar* uri) @@ -565,6 +630,7 @@ static gboolean webKitWebSrcSetUri(GstURIHandler* handler, const gchar* uri) priv->uri = g_strdup(url.string().utf8().data()); return TRUE; } +#endif static void webKitWebSrcUriHandlerInit(gpointer gIface, gpointer ifaceData) { @@ -713,7 +779,13 @@ void StreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse length += priv->requestedOffset; gst_app_src_set_size(priv->appsrc, length); if (!priv->haveAppSrc27) { +#ifdef GST_API_VERSION_1 + GstSegment* segment = &GST_BASE_SRC(priv->appsrc)->segment; + segment->duration = length; + segment->format = GST_FORMAT_BYTES; +#else gst_segment_set_duration(&GST_BASE_SRC(priv->appsrc)->segment, GST_FORMAT_BYTES, length); +#endif gst_element_post_message(GST_ELEMENT(priv->appsrc), gst_message_new_duration(GST_OBJECT(priv->appsrc), GST_FORMAT_BYTES, length)); @@ -736,7 +808,11 @@ void StreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse } } +#ifdef GST_API_VERSION_1 + GstTagList* tags = gst_tag_list_new_empty(); +#else GstTagList* tags = gst_tag_list_new(); +#endif value = response.httpHeaderField("icy-name"); if (!value.isEmpty()) { g_free(priv->iradioName); @@ -769,7 +845,11 @@ void StreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse if (gst_tag_list_is_empty(tags)) gst_tag_list_free(tags); else +#ifdef GST_API_VERSION_1 + gst_pad_push_event(GST_PAD_CAST(m_src->priv->srcpad), gst_event_new_tag(tags)); +#else gst_element_found_tags_for_pad(GST_ELEMENT(m_src), m_src->priv->srcpad, tags); +#endif } void StreamingClient::didReceiveData(ResourceHandle* handle, const char* data, int length, int encodedDataLength) @@ -785,13 +865,21 @@ void StreamingClient::didReceiveData(ResourceHandle* handle, const char* data, i GstBuffer* buffer = gst_buffer_new_and_alloc(length); +#ifdef GST_API_VERSION_1 + gst_buffer_fill(buffer, 0, data, length); +#else memcpy(GST_BUFFER_DATA(buffer), data, length); +#endif GST_BUFFER_OFFSET(buffer) = priv->offset; priv->offset += length; GST_BUFFER_OFFSET_END(buffer) = priv->offset; GstFlowReturn ret = gst_app_src_push_buffer(priv->appsrc, buffer); +#ifdef GST_API_VERSION_1 + if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS) +#else if (ret != GST_FLOW_OK && ret != GST_FLOW_UNEXPECTED) +#endif GST_ELEMENT_ERROR(m_src, CORE, FAILED, (0), (0)); } diff --git a/Source/WebCore/platform/graphics/gtk/ImageGtk.cpp b/Source/WebCore/platform/graphics/gtk/ImageGtk.cpp index 9dd82a93a..6e81e33a3 100644 --- a/Source/WebCore/platform/graphics/gtk/ImageGtk.cpp +++ b/Source/WebCore/platform/graphics/gtk/ImageGtk.cpp @@ -48,36 +48,42 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) } } -static const char* getWebKitDataDirectory() +static char* getPathToImageResource(char* resource) { static char* dataDirectory = 0; - if (dataDirectory) - return dataDirectory; - - dataDirectory = new char[PATH_MAX]; - if (!GetModuleFileName(hmodule, static_cast<CHAR*>(dataDirectory), sizeof(dataDirectory) - 10)) - return DATA_DIR; - - // FIXME: This is pretty ugly. Ideally we should be using Windows API - // functions or GLib methods to calculate paths. - unsigned char *p; - p = _mbsrchr(static_cast<const unsigned char *>(dataDirectory), '\\'); - *p = '\0'; - p = _mbsrchr(static_cast<const unsigned char *>(dataDirectory), '\\'); - if (p) { - if (!stricmp((const char *) (p+1), "bin")) - *p = '\0'; + if (!dataDirectory) { + dataDirectory = new char[PATH_MAX]; + if (!GetModuleFileName(hmodule, static_cast<CHAR*>(dataDirectory), sizeof(dataDirectory) - 10)) + dataDirectory = DATA_DIR; + + // FIXME: This is pretty ugly. Ideally we should be using Windows API + // functions or GLib methods to calculate paths. + unsigned char *p; + p = _mbsrchr(static_cast<const unsigned char *>(dataDirectory), '\\'); + *p = '\0'; + p = _mbsrchr(static_cast<const unsigned char *>(dataDirectory), '\\'); + if (p) { + if (!stricmp((const char *) (p+1), "bin")) + *p = '\0'; + } + strcat(dataDirectory, "\\share\\webkitgtk-"WEBKITGTK_API_VERSION_STRING"\\images\\"); } - strcat(dataDirectory, "\\share"); - return dataDirectory; + char* imageResourcePath = new char[PATH_MAX]; + strcat(imageResourcePath, dataDirectory); + strcat(imageResourcePath, resource); + + return imageResourcePath; } #else -static const char* getWebKitDataDirectory() +static char* getPathToImageResource(char* resource) { - return DATA_DIR; + if (g_getenv("WEBKIT_TOP_LEVEL")) + return g_build_filename(g_getenv("WEBKIT_TOP_LEVEL"), "Source", "WebCore", "Resources", resource, NULL); + + return g_build_filename(DATA_DIR, "webkitgtk-"WEBKITGTK_API_VERSION_STRING, "images", resource, NULL); } #endif @@ -138,7 +144,7 @@ PassRefPtr<Image> Image::loadPlatformResource(const char* name) fileName = getThemeIconFileName(GTK_STOCK_MISSING_IMAGE, 16); if (fileName.isNull()) { GOwnPtr<gchar> imageName(g_strdup_printf("%s.png", name)); - GOwnPtr<gchar> glibFileName(g_build_filename(getWebKitDataDirectory(), "webkitgtk-"WEBKITGTK_API_VERSION_STRING, "images", imageName.get(), NULL)); + GOwnPtr<gchar> glibFileName(getPathToImageResource(imageName.get())); fileName = glibFileName.get(); } diff --git a/Source/WebCore/platform/graphics/mac/ColorMac.h b/Source/WebCore/platform/graphics/mac/ColorMac.h index b68b15763..2482b593b 100644 --- a/Source/WebCore/platform/graphics/mac/ColorMac.h +++ b/Source/WebCore/platform/graphics/mac/ColorMac.h @@ -31,11 +31,7 @@ #include "Color.h" -#ifdef __OBJC__ -@class NSColor; -#else -class NSColor; -#endif +OBJC_CLASS NSColor; namespace WebCore { diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp b/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp index 8ecc4b11b..6ed931f8c 100644 --- a/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp +++ b/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp @@ -204,9 +204,14 @@ static bool advanceByCombiningCharacterSequence(const UChar*& iterator, const UC } // Consume marks. - while (iterator < end && ((U_GET_GC_MASK(*iterator) & U_GC_M_MASK) || *iterator == zeroWidthJoiner || *iterator == zeroWidthNonJoiner)) { - iterator++; - markCount++; + while (iterator < end) { + UChar32 nextCharacter; + int markLength = 0; + U16_NEXT(iterator, markLength, end - iterator, nextCharacter); + if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK) && nextCharacter != zeroWidthJoiner && nextCharacter != zeroWidthNonJoiner) + break; + markCount += markLength; + iterator += markLength; } return true; diff --git a/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp b/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp index d07f4dc17..5aa23d38f 100644 --- a/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp +++ b/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp @@ -64,7 +64,8 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned b haveGlyphs = true; } } - } else if (wkGetVerticalGlyphsForCharacters(fontData->platformData().ctFont(), buffer, glyphs.data(), bufferLength)) { + } else if ((fontData->platformData().widthVariant() == RegularWidth) ? wkGetVerticalGlyphsForCharacters(fontData->platformData().ctFont(), buffer, glyphs.data(), bufferLength) + : CTFontGetGlyphsForCharacters(fontData->platformData().ctFont(), buffer, glyphs.data(), bufferLength)) { for (unsigned i = 0; i < length; ++i) { if (!glyphs[i]) setGlyphDataForIndex(offset + i, 0, 0); diff --git a/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm b/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm index e3c371a2c..a83e0de97 100644 --- a/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm +++ b/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm @@ -278,6 +278,10 @@ void GraphicsContext3D::setContextLostCallback(PassOwnPtr<ContextLostCallback>) { } +void GraphicsContext3D::setErrorMessageCallback(PassOwnPtr<ErrorMessageCallback>) +{ +} + } #endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h index 951dfff97..3089ae2d4 100644 --- a/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h +++ b/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h @@ -35,22 +35,18 @@ #ifdef __OBJC__ #import <QTKit/QTTime.h> -@class QTMovie; -@class QTMovieView; -@class QTMovieLayer; -@class QTVideoRendererWebKitOnly; -@class WebCoreMovieObserver; #else -class NSDictionary; -class NSMutableDictionary; -class QTMovie; -class QTMovieView; class QTTime; -class QTMovieLayer; -class QTVideoRendererWebKitOnly; -class WebCoreMovieObserver; #endif +OBJC_CLASS NSDictionary; +OBJC_CLASS NSMutableDictionary; +OBJC_CLASS QTMovie; +OBJC_CLASS QTMovieView; +OBJC_CLASS QTMovieLayer; +OBJC_CLASS QTVideoRendererWebKitOnly; +OBJC_CLASS WebCoreMovieObserver; + #ifndef DRAW_FRAME_RATE #define DRAW_FRAME_RATE 0 #endif diff --git a/Source/WebCore/platform/graphics/mac/MediaPlayerProxy.h b/Source/WebCore/platform/graphics/mac/MediaPlayerProxy.h index cc7ec9556..c586fb86f 100644 --- a/Source/WebCore/platform/graphics/mac/MediaPlayerProxy.h +++ b/Source/WebCore/platform/graphics/mac/MediaPlayerProxy.h @@ -26,11 +26,7 @@ #ifndef MediaPlayerProxy_h #define MediaPlayerProxy_h -#ifdef __OBJC__ -@class WebMediaPlayerProxy; -#else -class WebMediaPlayerProxy; -#endif +OBJC_CLASS WebMediaPlayerProxy; enum MediaPlayerProxyNotificationType { diff --git a/Source/WebCore/platform/graphics/mac/WebLayer.mm b/Source/WebCore/platform/graphics/mac/WebLayer.mm index 7c388d31f..277104148 100644 --- a/Source/WebCore/platform/graphics/mac/WebLayer.mm +++ b/Source/WebCore/platform/graphics/mac/WebLayer.mm @@ -85,7 +85,7 @@ void drawLayerContents(CGContextRef context, CALayer *layer, WebCore::PlatformCA // Re-fetch the layer owner, since <rdar://problem/9125151> indicates that it might have been destroyed during painting. layerContents = platformLayer->owner(); ASSERT(layerContents); - if (layerContents && layerContents->platformCALayerShowRepaintCounter()) { + if (platformLayer->layerType() != PlatformCALayer::LayerTypeTileCacheLayer && layerContents && layerContents->platformCALayerShowRepaintCounter()) { bool isTiledLayer = [layer isKindOfClass:[CATiledLayer class]]; char text[16]; // that's a lot of repaints diff --git a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp index 16a3b4a9c..47a41c6d0 100644 --- a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp @@ -29,22 +29,8 @@ #include "GraphicsContext3D.h" -#include "CanvasRenderingContext.h" #include "Extensions3DOpenGL.h" -#include "GraphicsContext.h" -#include "HTMLCanvasElement.h" -#include "ImageBuffer.h" -#include "ImageData.h" #include "NotImplemented.h" -#include "WebGLObject.h" -#include <cstring> -#include <wtf/ArrayBuffer.h> -#include <wtf/ArrayBufferView.h> -#include <wtf/Float32Array.h> -#include <wtf/Int32Array.h> -#include <wtf/Uint8Array.h> -#include <wtf/UnusedParam.h> -#include <wtf/text/CString.h> #if PLATFORM(MAC) #include <OpenGL/gl.h> @@ -57,30 +43,6 @@ namespace WebCore { -void GraphicsContext3D::validateAttributes() -{ - Extensions3D* extensions = getExtensions(); - if (m_attrs.stencil) { - if (extensions->supports("GL_EXT_packed_depth_stencil")) { - extensions->ensureEnabled("GL_EXT_packed_depth_stencil"); - // Force depth if stencil is true. - m_attrs.depth = true; - } else - m_attrs.stencil = false; - } - if (m_attrs.antialias) { - bool isValidVendor = true; - // Currently in Mac we only turn on antialias if vendor is NVIDIA. - const char* vendor = reinterpret_cast<const char*>(::glGetString(GL_VENDOR)); - if (!std::strstr(vendor, "NVIDIA")) - isValidVendor = false; - if (!isValidVendor || !extensions->supports("GL_ANGLE_framebuffer_multisample")) - m_attrs.antialias = false; - else - extensions->ensureEnabled("GL_ANGLE_framebuffer_multisample"); - } -} - void GraphicsContext3D::readRenderingResults(unsigned char *pixels, int pixelsSize) { if (pixelsSize < m_currentWidth * m_currentHeight * 4) @@ -119,66 +81,6 @@ void GraphicsContext3D::readRenderingResults(unsigned char *pixels, int pixelsSi ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO); } -bool GraphicsContext3D::isResourceSafe() -{ - return false; -} - -#if !PLATFORM(QT) -void GraphicsContext3D::paintRenderingResultsToCanvas(CanvasRenderingContext* context, DrawingBuffer*) -{ - HTMLCanvasElement* canvas = context->canvas(); - ImageBuffer* imageBuffer = canvas->buffer(); - - int rowBytes = m_currentWidth * 4; - int totalBytes = rowBytes * m_currentHeight; - - OwnArrayPtr<unsigned char> pixels = adoptArrayPtr(new unsigned char[totalBytes]); - if (!pixels) - return; - - readRenderingResults(pixels.get(), totalBytes); - - if (!m_attrs.premultipliedAlpha) { - for (int i = 0; i < totalBytes; i += 4) { - // Premultiply alpha - pixels[i + 0] = std::min(255, pixels[i + 0] * pixels[i + 3] / 255); - pixels[i + 1] = std::min(255, pixels[i + 1] * pixels[i + 3] / 255); - pixels[i + 2] = std::min(255, pixels[i + 2] * pixels[i + 3] / 255); - } - } - - paintToCanvas(pixels.get(), m_currentWidth, m_currentHeight, - canvas->width(), canvas->height(), imageBuffer->context()->platformContext()); -} -#endif - -bool GraphicsContext3D::paintCompositedResultsToCanvas(CanvasRenderingContext*) -{ - // Not needed at the moment, so return that nothing was done. - return false; -} - -PassRefPtr<ImageData> GraphicsContext3D::paintRenderingResultsToImageData(DrawingBuffer*) -{ - // Reading premultiplied alpha would involve unpremultiplying, which is - // lossy - if (m_attrs.premultipliedAlpha) - return 0; - - RefPtr<ImageData> imageData = ImageData::create(IntSize(m_currentWidth, m_currentHeight)); - unsigned char* pixels = imageData->data()->data()->data(); - int totalBytes = 4 * m_currentWidth * m_currentHeight; - - readRenderingResults(pixels, totalBytes); - - // Convert to RGBA - for (int i = 0; i < totalBytes; i += 4) - std::swap(pixels[i], pixels[i + 2]); - - return imageData.release(); -} - void GraphicsContext3D::reshape(int width, int height) { if (!platformGraphicsContext3D()) @@ -333,11 +235,6 @@ void GraphicsContext3D::reshape(int width, int height) ::glFlush(); } -IntSize GraphicsContext3D::getInternalFramebufferSize() const -{ - return IntSize(m_currentWidth, m_currentHeight); -} - void GraphicsContext3D::prepareTexture() { if (m_layerComposited) @@ -359,35 +256,6 @@ void GraphicsContext3D::prepareTexture() m_layerComposited = true; } -void GraphicsContext3D::activeTexture(GC3Denum texture) -{ - makeContextCurrent(); - m_activeTexture = texture; - ::glActiveTexture(texture); -} - -void GraphicsContext3D::attachShader(Platform3DObject program, Platform3DObject shader) -{ - ASSERT(program); - ASSERT(shader); - makeContextCurrent(); - ::glAttachShader(program, shader); -} - -void GraphicsContext3D::bindAttribLocation(Platform3DObject program, GC3Duint index, const String& name) -{ - ASSERT(program); - makeContextCurrent(); - ::glBindAttribLocation(program, index, name.utf8().data()); -} - -void GraphicsContext3D::bindBuffer(GC3Denum target, Platform3DObject buffer) -{ - makeContextCurrent(); - ::glBindBuffer(target, buffer); -} - - void GraphicsContext3D::bindFramebuffer(GC3Denum target, Platform3DObject buffer) { makeContextCurrent(); @@ -402,158 +270,6 @@ void GraphicsContext3D::bindFramebuffer(GC3Denum target, Platform3DObject buffer } } -void GraphicsContext3D::bindRenderbuffer(GC3Denum target, Platform3DObject renderbuffer) -{ - makeContextCurrent(); - ::glBindRenderbufferEXT(target, renderbuffer); -} - - -void GraphicsContext3D::bindTexture(GC3Denum target, Platform3DObject texture) -{ - makeContextCurrent(); - if (m_activeTexture && target == GL_TEXTURE_2D) - m_boundTexture0 = texture; - ::glBindTexture(target, texture); -} - -void GraphicsContext3D::blendColor(GC3Dclampf red, GC3Dclampf green, GC3Dclampf blue, GC3Dclampf alpha) -{ - makeContextCurrent(); - ::glBlendColor(red, green, blue, alpha); -} - -void GraphicsContext3D::blendEquation(GC3Denum mode) -{ - makeContextCurrent(); - ::glBlendEquation(mode); -} - -void GraphicsContext3D::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha) -{ - makeContextCurrent(); - ::glBlendEquationSeparate(modeRGB, modeAlpha); -} - - -void GraphicsContext3D::blendFunc(GC3Denum sfactor, GC3Denum dfactor) -{ - makeContextCurrent(); - ::glBlendFunc(sfactor, dfactor); -} - -void GraphicsContext3D::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha) -{ - makeContextCurrent(); - ::glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); -} - -void GraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage) -{ - makeContextCurrent(); - ::glBufferData(target, size, 0, usage); -} - -void GraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, const void* data, GC3Denum usage) -{ - makeContextCurrent(); - ::glBufferData(target, size, data, usage); -} - -void GraphicsContext3D::bufferSubData(GC3Denum target, GC3Dintptr offset, GC3Dsizeiptr size, const void* data) -{ - makeContextCurrent(); - ::glBufferSubData(target, offset, size, data); -} - -GC3Denum GraphicsContext3D::checkFramebufferStatus(GC3Denum target) -{ - makeContextCurrent(); - return ::glCheckFramebufferStatusEXT(target); -} - -void GraphicsContext3D::clearColor(GC3Dclampf r, GC3Dclampf g, GC3Dclampf b, GC3Dclampf a) -{ - makeContextCurrent(); - ::glClearColor(r, g, b, a); -} - -void GraphicsContext3D::clear(GC3Dbitfield mask) -{ - makeContextCurrent(); - ::glClear(mask); -} - -void GraphicsContext3D::clearDepth(GC3Dclampf depth) -{ - makeContextCurrent(); - ::glClearDepth(depth); -} - -void GraphicsContext3D::clearStencil(GC3Dint s) -{ - makeContextCurrent(); - ::glClearStencil(s); -} - -void GraphicsContext3D::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha) -{ - makeContextCurrent(); - ::glColorMask(red, green, blue, alpha); -} - -void GraphicsContext3D::compileShader(Platform3DObject shader) -{ - ASSERT(shader); - makeContextCurrent(); - - int GLshaderType; - ANGLEShaderType shaderType; - - glGetShaderiv(shader, SHADER_TYPE, &GLshaderType); - - if (GLshaderType == VERTEX_SHADER) - shaderType = SHADER_TYPE_VERTEX; - else if (GLshaderType == FRAGMENT_SHADER) - shaderType = SHADER_TYPE_FRAGMENT; - else - return; // Invalid shader type. - - HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader); - - if (result == m_shaderSourceMap.end()) - return; - - ShaderSourceEntry& entry = result->second; - - String translatedShaderSource; - String shaderInfoLog; - - bool isValid = m_compiler.validateShaderSource(entry.source.utf8().data(), shaderType, translatedShaderSource, shaderInfoLog); - - entry.log = shaderInfoLog; - entry.isValid = isValid; - - if (!isValid) - return; // Shader didn't validate, don't move forward with compiling translated source - - int translatedShaderLength = translatedShaderSource.length(); - - const CString& translatedShaderCString = translatedShaderSource.utf8(); - const char* translatedShaderPtr = translatedShaderCString.data(); - - ::glShaderSource(shader, 1, &translatedShaderPtr, &translatedShaderLength); - - ::glCompileShader(shader); - - int GLCompileSuccess; - - ::glGetShaderiv(shader, COMPILE_STATUS, &GLCompileSuccess); - - // ASSERT that ANGLE generated GLSL will be accepted by OpenGL - ASSERT(GLCompileSuccess == GL_TRUE); -} - void GraphicsContext3D::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border) { makeContextCurrent(); @@ -582,132 +298,6 @@ void GraphicsContext3D::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Din ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); } -void GraphicsContext3D::cullFace(GC3Denum mode) -{ - makeContextCurrent(); - ::glCullFace(mode); -} - -void GraphicsContext3D::depthFunc(GC3Denum func) -{ - makeContextCurrent(); - ::glDepthFunc(func); -} - -void GraphicsContext3D::depthMask(GC3Dboolean flag) -{ - makeContextCurrent(); - ::glDepthMask(flag); -} - -void GraphicsContext3D::depthRange(GC3Dclampf zNear, GC3Dclampf zFar) -{ - makeContextCurrent(); - ::glDepthRange(zNear, zFar); -} - -void GraphicsContext3D::detachShader(Platform3DObject program, Platform3DObject shader) -{ - ASSERT(program); - ASSERT(shader); - makeContextCurrent(); - ::glDetachShader(program, shader); -} - -void GraphicsContext3D::disable(GC3Denum cap) -{ - makeContextCurrent(); - ::glDisable(cap); -} - -void GraphicsContext3D::disableVertexAttribArray(GC3Duint index) -{ - makeContextCurrent(); - ::glDisableVertexAttribArray(index); -} - -void GraphicsContext3D::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count) -{ - makeContextCurrent(); - ::glDrawArrays(mode, first, count); -} - -void GraphicsContext3D::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset) -{ - makeContextCurrent(); - ::glDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset))); -} - -void GraphicsContext3D::enable(GC3Denum cap) -{ - makeContextCurrent(); - ::glEnable(cap); -} - -void GraphicsContext3D::enableVertexAttribArray(GC3Duint index) -{ - makeContextCurrent(); - ::glEnableVertexAttribArray(index); -} - -void GraphicsContext3D::finish() -{ - makeContextCurrent(); - ::glFinish(); -} - -void GraphicsContext3D::flush() -{ - makeContextCurrent(); - ::glFlush(); -} - -void GraphicsContext3D::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, Platform3DObject buffer) -{ - makeContextCurrent(); - ::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, buffer); -} - -void GraphicsContext3D::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, Platform3DObject texture, GC3Dint level) -{ - makeContextCurrent(); - ::glFramebufferTexture2DEXT(target, attachment, textarget, texture, level); -} - -void GraphicsContext3D::frontFace(GC3Denum mode) -{ - makeContextCurrent(); - ::glFrontFace(mode); -} - -void GraphicsContext3D::generateMipmap(GC3Denum target) -{ - makeContextCurrent(); - ::glGenerateMipmapEXT(target); -} - -bool GraphicsContext3D::getActiveAttrib(Platform3DObject program, GC3Duint index, ActiveInfo& info) -{ - if (!program) { - synthesizeGLError(INVALID_VALUE); - return false; - } - makeContextCurrent(); - GLint maxAttributeSize = 0; - ::glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttributeSize); - GLchar name[maxAttributeSize]; // GL_ACTIVE_ATTRIBUTE_MAX_LENGTH includes null termination - GLsizei nameLength = 0; - GLint size = 0; - GLenum type = 0; - ::glGetActiveAttrib(program, index, maxAttributeSize, &nameLength, &size, &type, name); - if (!nameLength) - return false; - info.name = String(name, nameLength); - info.type = type; - info.size = size; - return true; -} - bool GraphicsContext3D::getActiveUniform(Platform3DObject program, GC3Duint index, ActiveInfo& info) { if (!program) { @@ -730,139 +320,6 @@ bool GraphicsContext3D::getActiveUniform(Platform3DObject program, GC3Duint inde return true; } -void GraphicsContext3D::getAttachedShaders(Platform3DObject program, GC3Dsizei maxCount, GC3Dsizei* count, Platform3DObject* shaders) -{ - if (!program) { - synthesizeGLError(INVALID_VALUE); - return; - } - makeContextCurrent(); - ::glGetAttachedShaders(program, maxCount, count, shaders); -} - -int GraphicsContext3D::getAttribLocation(Platform3DObject program, const String& name) -{ - if (!program) - return -1; - - makeContextCurrent(); - return ::glGetAttribLocation(program, name.utf8().data()); -} - -GraphicsContext3D::Attributes GraphicsContext3D::getContextAttributes() -{ - return m_attrs; -} - -GC3Denum GraphicsContext3D::getError() -{ - if (m_syntheticErrors.size() > 0) { - ListHashSet<GC3Denum>::iterator iter = m_syntheticErrors.begin(); - GC3Denum err = *iter; - m_syntheticErrors.remove(iter); - return err; - } - - makeContextCurrent(); - return ::glGetError(); -} - -String GraphicsContext3D::getString(GC3Denum name) -{ - makeContextCurrent(); - return String(reinterpret_cast<const char*>(::glGetString(name))); -} - -void GraphicsContext3D::hint(GC3Denum target, GC3Denum mode) -{ - makeContextCurrent(); - ::glHint(target, mode); -} - -GC3Dboolean GraphicsContext3D::isBuffer(Platform3DObject buffer) -{ - if (!buffer) - return GL_FALSE; - - makeContextCurrent(); - return ::glIsBuffer(buffer); -} - -GC3Dboolean GraphicsContext3D::isEnabled(GC3Denum cap) -{ - makeContextCurrent(); - return ::glIsEnabled(cap); -} - -GC3Dboolean GraphicsContext3D::isFramebuffer(Platform3DObject framebuffer) -{ - if (!framebuffer) - return GL_FALSE; - - makeContextCurrent(); - return ::glIsFramebufferEXT(framebuffer); -} - -GC3Dboolean GraphicsContext3D::isProgram(Platform3DObject program) -{ - if (!program) - return GL_FALSE; - - makeContextCurrent(); - return ::glIsProgram(program); -} - -GC3Dboolean GraphicsContext3D::isRenderbuffer(Platform3DObject renderbuffer) -{ - if (!renderbuffer) - return GL_FALSE; - - makeContextCurrent(); - return ::glIsRenderbufferEXT(renderbuffer); -} - -GC3Dboolean GraphicsContext3D::isShader(Platform3DObject shader) -{ - if (!shader) - return GL_FALSE; - - makeContextCurrent(); - return ::glIsShader(shader); -} - -GC3Dboolean GraphicsContext3D::isTexture(Platform3DObject texture) -{ - if (!texture) - return GL_FALSE; - - makeContextCurrent(); - return ::glIsTexture(texture); -} - -void GraphicsContext3D::lineWidth(GC3Dfloat width) -{ - makeContextCurrent(); - ::glLineWidth(width); -} - -void GraphicsContext3D::linkProgram(Platform3DObject program) -{ - ASSERT(program); - makeContextCurrent(); - ::glLinkProgram(program); -} - -void GraphicsContext3D::pixelStorei(GC3Denum pname, GC3Dint param) -{ - makeContextCurrent(); - ::glPixelStorei(pname, param); -} - -void GraphicsContext3D::polygonOffset(GC3Dfloat factor, GC3Dfloat units) -{ - makeContextCurrent(); - ::glPolygonOffset(factor, units); -} void GraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data) { @@ -882,13 +339,6 @@ void GraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsi ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); } -void GraphicsContext3D::releaseShaderCompiler() -{ - // FIXME: This is not implemented on desktop OpenGL. We need to have ifdefs for the different GL variants. - makeContextCurrent(); - notImplemented(); -} - void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height) { makeContextCurrent(); @@ -910,302 +360,6 @@ void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalfo ::glRenderbufferStorageEXT(target, internalformat, width, height); } -void GraphicsContext3D::sampleCoverage(GC3Dclampf value, GC3Dboolean invert) -{ - makeContextCurrent(); - ::glSampleCoverage(value, invert); -} - -void GraphicsContext3D::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height) -{ - makeContextCurrent(); - ::glScissor(x, y, width, height); -} - -void GraphicsContext3D::shaderSource(Platform3DObject shader, const String& string) -{ - ASSERT(shader); - - makeContextCurrent(); - - ShaderSourceEntry entry; - - entry.source = string; - - m_shaderSourceMap.set(shader, entry); -} - -void GraphicsContext3D::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask) -{ - makeContextCurrent(); - ::glStencilFunc(func, ref, mask); -} - -void GraphicsContext3D::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask) -{ - makeContextCurrent(); - ::glStencilFuncSeparate(face, func, ref, mask); -} - -void GraphicsContext3D::stencilMask(GC3Duint mask) -{ - makeContextCurrent(); - ::glStencilMask(mask); -} - -void GraphicsContext3D::stencilMaskSeparate(GC3Denum face, GC3Duint mask) -{ - makeContextCurrent(); - ::glStencilMaskSeparate(face, mask); -} - -void GraphicsContext3D::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass) -{ - makeContextCurrent(); - ::glStencilOp(fail, zfail, zpass); -} - -void GraphicsContext3D::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass) -{ - makeContextCurrent(); - ::glStencilOpSeparate(face, fail, zfail, zpass); -} - -void GraphicsContext3D::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat value) -{ - makeContextCurrent(); - ::glTexParameterf(target, pname, value); -} - -void GraphicsContext3D::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint value) -{ - makeContextCurrent(); - ::glTexParameteri(target, pname, value); -} - -void GraphicsContext3D::uniform1f(GC3Dint location, GC3Dfloat v0) -{ - makeContextCurrent(); - ::glUniform1f(location, v0); -} - -void GraphicsContext3D::uniform1fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size) -{ - makeContextCurrent(); - ::glUniform1fv(location, size, array); -} - -void GraphicsContext3D::uniform2f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1) -{ - makeContextCurrent(); - ::glUniform2f(location, v0, v1); -} - -void GraphicsContext3D::uniform2fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size) -{ - // FIXME: length needs to be a multiple of 2 - makeContextCurrent(); - ::glUniform2fv(location, size, array); -} - -void GraphicsContext3D::uniform3f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2) -{ - makeContextCurrent(); - ::glUniform3f(location, v0, v1, v2); -} - -void GraphicsContext3D::uniform3fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size) -{ - // FIXME: length needs to be a multiple of 3 - makeContextCurrent(); - ::glUniform3fv(location, size, array); -} - -void GraphicsContext3D::uniform4f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3) -{ - makeContextCurrent(); - ::glUniform4f(location, v0, v1, v2, v3); -} - -void GraphicsContext3D::uniform4fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size) -{ - // FIXME: length needs to be a multiple of 4 - makeContextCurrent(); - ::glUniform4fv(location, size, array); -} - -void GraphicsContext3D::uniform1i(GC3Dint location, GC3Dint v0) -{ - makeContextCurrent(); - ::glUniform1i(location, v0); -} - -void GraphicsContext3D::uniform1iv(GC3Dint location, GC3Dint* array, GC3Dsizei size) -{ - makeContextCurrent(); - ::glUniform1iv(location, size, array); -} - -void GraphicsContext3D::uniform2i(GC3Dint location, GC3Dint v0, GC3Dint v1) -{ - makeContextCurrent(); - ::glUniform2i(location, v0, v1); -} - -void GraphicsContext3D::uniform2iv(GC3Dint location, GC3Dint* array, GC3Dsizei size) -{ - // FIXME: length needs to be a multiple of 2 - makeContextCurrent(); - ::glUniform2iv(location, size, array); -} - -void GraphicsContext3D::uniform3i(GC3Dint location, GC3Dint v0, GC3Dint v1, GC3Dint v2) -{ - makeContextCurrent(); - ::glUniform3i(location, v0, v1, v2); -} - -void GraphicsContext3D::uniform3iv(GC3Dint location, GC3Dint* array, GC3Dsizei size) -{ - // FIXME: length needs to be a multiple of 3 - makeContextCurrent(); - ::glUniform3iv(location, size, array); -} - -void GraphicsContext3D::uniform4i(GC3Dint location, GC3Dint v0, GC3Dint v1, GC3Dint v2, GC3Dint v3) -{ - makeContextCurrent(); - ::glUniform4i(location, v0, v1, v2, v3); -} - -void GraphicsContext3D::uniform4iv(GC3Dint location, GC3Dint* array, GC3Dsizei size) -{ - // FIXME: length needs to be a multiple of 4 - makeContextCurrent(); - ::glUniform4iv(location, size, array); -} - -void GraphicsContext3D::uniformMatrix2fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size) -{ - // FIXME: length needs to be a multiple of 4 - makeContextCurrent(); - ::glUniformMatrix2fv(location, size, transpose, array); -} - -void GraphicsContext3D::uniformMatrix3fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size) -{ - // FIXME: length needs to be a multiple of 9 - makeContextCurrent(); - ::glUniformMatrix3fv(location, size, transpose, array); -} - -void GraphicsContext3D::uniformMatrix4fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size) -{ - // FIXME: length needs to be a multiple of 16 - makeContextCurrent(); - ::glUniformMatrix4fv(location, size, transpose, array); -} - -void GraphicsContext3D::useProgram(Platform3DObject program) -{ - makeContextCurrent(); - ::glUseProgram(program); -} - -void GraphicsContext3D::validateProgram(Platform3DObject program) -{ - ASSERT(program); - - makeContextCurrent(); - ::glValidateProgram(program); -} - -void GraphicsContext3D::vertexAttrib1f(GC3Duint index, GC3Dfloat v0) -{ - makeContextCurrent(); - ::glVertexAttrib1f(index, v0); -} - -void GraphicsContext3D::vertexAttrib1fv(GC3Duint index, GC3Dfloat* array) -{ - makeContextCurrent(); - ::glVertexAttrib1fv(index, array); -} - -void GraphicsContext3D::vertexAttrib2f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1) -{ - makeContextCurrent(); - ::glVertexAttrib2f(index, v0, v1); -} - -void GraphicsContext3D::vertexAttrib2fv(GC3Duint index, GC3Dfloat* array) -{ - makeContextCurrent(); - ::glVertexAttrib2fv(index, array); -} - -void GraphicsContext3D::vertexAttrib3f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2) -{ - makeContextCurrent(); - ::glVertexAttrib3f(index, v0, v1, v2); -} - -void GraphicsContext3D::vertexAttrib3fv(GC3Duint index, GC3Dfloat* array) -{ - makeContextCurrent(); - ::glVertexAttrib3fv(index, array); -} - -void GraphicsContext3D::vertexAttrib4f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3) -{ - makeContextCurrent(); - ::glVertexAttrib4f(index, v0, v1, v2, v3); -} - -void GraphicsContext3D::vertexAttrib4fv(GC3Duint index, GC3Dfloat* array) -{ - makeContextCurrent(); - ::glVertexAttrib4fv(index, array); -} - -void GraphicsContext3D::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, GC3Dintptr offset) -{ - makeContextCurrent(); - ::glVertexAttribPointer(index, size, type, normalized, stride, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset))); -} - -void GraphicsContext3D::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height) -{ - makeContextCurrent(); - ::glViewport(x, y, width, height); -} - -void GraphicsContext3D::getBooleanv(GC3Denum pname, GC3Dboolean* value) -{ - makeContextCurrent(); - ::glGetBooleanv(pname, value); -} - -void GraphicsContext3D::getBufferParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value) -{ - makeContextCurrent(); - ::glGetBufferParameteriv(target, pname, value); -} - -void GraphicsContext3D::getFloatv(GC3Denum pname, GC3Dfloat* value) -{ - makeContextCurrent(); - ::glGetFloatv(pname, value); -} - -void GraphicsContext3D::getFramebufferAttachmentParameteriv(GC3Denum target, GC3Denum attachment, GC3Denum pname, GC3Dint* value) -{ - makeContextCurrent(); - if (attachment == DEPTH_STENCIL_ATTACHMENT) - attachment = DEPTH_ATTACHMENT; // Or STENCIL_ATTACHMENT, either works. - ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, value); -} - void GraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value) { // Need to emulate MAX_FRAGMENT/VERTEX_UNIFORM_VECTORS and MAX_VARYING_VECTORS @@ -1231,163 +385,6 @@ void GraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value) } } -void GraphicsContext3D::getProgramiv(Platform3DObject program, GC3Denum pname, GC3Dint* value) -{ - makeContextCurrent(); - ::glGetProgramiv(program, pname, value); -} - -String GraphicsContext3D::getProgramInfoLog(Platform3DObject program) -{ - ASSERT(program); - - makeContextCurrent(); - GLint length = 0; - ::glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); - if (!length) - return String(); - - GLsizei size = 0; - OwnArrayPtr<GLchar> info = adoptArrayPtr(new GLchar[length]); - ::glGetProgramInfoLog(program, length, &size, info.get()); - - return String(info.get()); -} - -void GraphicsContext3D::getRenderbufferParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value) -{ - makeContextCurrent(); - ::glGetRenderbufferParameterivEXT(target, pname, value); -} - -void GraphicsContext3D::getShaderiv(Platform3DObject shader, GC3Denum pname, GC3Dint* value) -{ - ASSERT(shader); - - makeContextCurrent(); - - HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader); - - switch (pname) { - case DELETE_STATUS: - case SHADER_TYPE: - ::glGetShaderiv(shader, pname, value); - break; - case COMPILE_STATUS: - if (result == m_shaderSourceMap.end()) { - *value = static_cast<int>(false); - return; - } - *value = static_cast<int>(result->second.isValid); - break; - case INFO_LOG_LENGTH: - if (result == m_shaderSourceMap.end()) { - *value = 0; - return; - } - *value = getShaderInfoLog(shader).length(); - break; - case SHADER_SOURCE_LENGTH: - *value = getShaderSource(shader).length(); - break; - default: - synthesizeGLError(INVALID_ENUM); - } -} - -String GraphicsContext3D::getShaderInfoLog(Platform3DObject shader) -{ - ASSERT(shader); - - makeContextCurrent(); - - HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader); - if (result == m_shaderSourceMap.end()) - return String(); - - ShaderSourceEntry entry = result->second; - if (!entry.isValid) - return entry.log; - - GLint length = 0; - ::glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); - if (!length) - return String(); - - GLsizei size = 0; - OwnArrayPtr<GLchar> info = adoptArrayPtr(new GLchar[length]); - ::glGetShaderInfoLog(shader, length, &size, info.get()); - - return String(info.get()); -} - -String GraphicsContext3D::getShaderSource(Platform3DObject shader) -{ - ASSERT(shader); - - makeContextCurrent(); - - HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader); - if (result == m_shaderSourceMap.end()) - return String(); - - return result->second.source; -} - - -void GraphicsContext3D::getTexParameterfv(GC3Denum target, GC3Denum pname, GC3Dfloat* value) -{ - makeContextCurrent(); - ::glGetTexParameterfv(target, pname, value); -} - -void GraphicsContext3D::getTexParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value) -{ - makeContextCurrent(); - ::glGetTexParameteriv(target, pname, value); -} - -void GraphicsContext3D::getUniformfv(Platform3DObject program, GC3Dint location, GC3Dfloat* value) -{ - makeContextCurrent(); - ::glGetUniformfv(program, location, value); -} - -void GraphicsContext3D::getUniformiv(Platform3DObject program, GC3Dint location, GC3Dint* value) -{ - makeContextCurrent(); - ::glGetUniformiv(program, location, value); -} - -GC3Dint GraphicsContext3D::getUniformLocation(Platform3DObject program, const String& name) -{ - ASSERT(program); - - makeContextCurrent(); - return ::glGetUniformLocation(program, name.utf8().data()); -} - -void GraphicsContext3D::getVertexAttribfv(GC3Duint index, GC3Denum pname, GC3Dfloat* value) -{ - makeContextCurrent(); - ::glGetVertexAttribfv(index, pname, value); -} - -void GraphicsContext3D::getVertexAttribiv(GC3Duint index, GC3Denum pname, GC3Dint* value) -{ - makeContextCurrent(); - ::glGetVertexAttribiv(index, pname, value); -} - -GC3Dsizeiptr GraphicsContext3D::getVertexAttribOffset(GC3Duint index, GC3Denum pname) -{ - makeContextCurrent(); - - GLvoid* pointer = 0; - ::glGetVertexAttribPointerv(index, pname, &pointer); - return static_cast<GC3Dsizeiptr>(reinterpret_cast<intptr_t>(pointer)); -} - bool GraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels) { if (width && height && !pixels) { @@ -1407,133 +404,6 @@ bool GraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum inte return true; } -void GraphicsContext3D::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoff, GC3Dint yoff, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, const void* pixels) -{ - makeContextCurrent(); - - // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size - ::glTexSubImage2D(target, level, xoff, yoff, width, height, format, type, pixels); -} - -void GraphicsContext3D::compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Dsizei imageSize, const void* data) -{ - makeContextCurrent(); - ::glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); -} - -void GraphicsContext3D::compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Dsizei imageSize, const void* data) -{ - makeContextCurrent(); - ::glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); -} - -Platform3DObject GraphicsContext3D::createBuffer() -{ - makeContextCurrent(); - GLuint o = 0; - glGenBuffers(1, &o); - return o; -} - -Platform3DObject GraphicsContext3D::createFramebuffer() -{ - makeContextCurrent(); - GLuint o = 0; - glGenFramebuffersEXT(1, &o); - return o; -} - -Platform3DObject GraphicsContext3D::createProgram() -{ - makeContextCurrent(); - return glCreateProgram(); -} - -Platform3DObject GraphicsContext3D::createRenderbuffer() -{ - makeContextCurrent(); - GLuint o = 0; - glGenRenderbuffersEXT(1, &o); - return o; -} - -Platform3DObject GraphicsContext3D::createShader(GC3Denum type) -{ - makeContextCurrent(); - return glCreateShader((type == FRAGMENT_SHADER) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER); -} - -Platform3DObject GraphicsContext3D::createTexture() -{ - makeContextCurrent(); - GLuint o = 0; - glGenTextures(1, &o); - return o; -} - -void GraphicsContext3D::deleteBuffer(Platform3DObject buffer) -{ - makeContextCurrent(); - glDeleteBuffers(1, &buffer); -} - -void GraphicsContext3D::deleteFramebuffer(Platform3DObject framebuffer) -{ - makeContextCurrent(); - glDeleteFramebuffersEXT(1, &framebuffer); -} - -void GraphicsContext3D::deleteProgram(Platform3DObject program) -{ - makeContextCurrent(); - glDeleteProgram(program); -} - -void GraphicsContext3D::deleteRenderbuffer(Platform3DObject renderbuffer) -{ - makeContextCurrent(); - glDeleteRenderbuffersEXT(1, &renderbuffer); -} - -void GraphicsContext3D::deleteShader(Platform3DObject shader) -{ - makeContextCurrent(); - glDeleteShader(shader); -} - -void GraphicsContext3D::deleteTexture(Platform3DObject texture) -{ - makeContextCurrent(); - glDeleteTextures(1, &texture); -} - -void GraphicsContext3D::synthesizeGLError(GC3Denum error) -{ - m_syntheticErrors.add(error); -} - -void GraphicsContext3D::markContextChanged() -{ - m_layerComposited = false; -} - -void GraphicsContext3D::markLayerComposited() -{ - m_layerComposited = true; -} - -bool GraphicsContext3D::layerComposited() const -{ - return m_layerComposited; -} - -Extensions3D* GraphicsContext3D::getExtensions() -{ - if (!m_extensions) - m_extensions = adoptPtr(new Extensions3DOpenGL(this)); - return m_extensions.get(); -} - } #endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp new file mode 100644 index 000000000..e68bba7fd --- /dev/null +++ b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp @@ -0,0 +1,1178 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEBGL) + +#include "GraphicsContext3D.h" + +#include "CanvasRenderingContext.h" +#include "Extensions3DOpenGL.h" +#include "GraphicsContext.h" +#include "HTMLCanvasElement.h" +#include "ImageBuffer.h" +#include "ImageData.h" +#include "NotImplemented.h" +#include "WebGLObject.h" +#include <cstring> +#include <wtf/ArrayBuffer.h> +#include <wtf/ArrayBufferView.h> +#include <wtf/Float32Array.h> +#include <wtf/Int32Array.h> +#include <wtf/Uint8Array.h> +#include <wtf/UnusedParam.h> +#include <wtf/text/CString.h> + +#if PLATFORM(MAC) +#include <OpenGL/gl.h> +#elif PLATFORM(GTK) +#include "OpenGLShims.h" +#elif PLATFORM(QT) +#include <QtGlobal> +#include <cairo/OpenGLShims.h> +#endif + +namespace WebCore { + +void GraphicsContext3D::validateAttributes() +{ + Extensions3D* extensions = getExtensions(); + if (m_attrs.stencil) { + if (extensions->supports("GL_EXT_packed_depth_stencil")) { + extensions->ensureEnabled("GL_EXT_packed_depth_stencil"); + // Force depth if stencil is true. + m_attrs.depth = true; + } else + m_attrs.stencil = false; + } + if (m_attrs.antialias) { + bool isValidVendor = true; + // Currently in Mac we only turn on antialias if vendor is NVIDIA. + const char* vendor = reinterpret_cast<const char*>(::glGetString(GL_VENDOR)); + if (!std::strstr(vendor, "NVIDIA")) + isValidVendor = false; + if (!isValidVendor || !extensions->supports("GL_ANGLE_framebuffer_multisample")) + m_attrs.antialias = false; + else + extensions->ensureEnabled("GL_ANGLE_framebuffer_multisample"); + } +} + +bool GraphicsContext3D::isResourceSafe() +{ + return false; +} + +#if !PLATFORM(QT) +void GraphicsContext3D::paintRenderingResultsToCanvas(CanvasRenderingContext* context, DrawingBuffer*) +{ + HTMLCanvasElement* canvas = context->canvas(); + ImageBuffer* imageBuffer = canvas->buffer(); + + int rowBytes = m_currentWidth * 4; + int totalBytes = rowBytes * m_currentHeight; + + OwnArrayPtr<unsigned char> pixels = adoptArrayPtr(new unsigned char[totalBytes]); + if (!pixels) + return; + + readRenderingResults(pixels.get(), totalBytes); + + if (!m_attrs.premultipliedAlpha) { + for (int i = 0; i < totalBytes; i += 4) { + // Premultiply alpha + pixels[i + 0] = std::min(255, pixels[i + 0] * pixels[i + 3] / 255); + pixels[i + 1] = std::min(255, pixels[i + 1] * pixels[i + 3] / 255); + pixels[i + 2] = std::min(255, pixels[i + 2] * pixels[i + 3] / 255); + } + } + + paintToCanvas(pixels.get(), m_currentWidth, m_currentHeight, + canvas->width(), canvas->height(), imageBuffer->context()->platformContext()); +} +#endif + +bool GraphicsContext3D::paintCompositedResultsToCanvas(CanvasRenderingContext*) +{ + // Not needed at the moment, so return that nothing was done. + return false; +} + +PassRefPtr<ImageData> GraphicsContext3D::paintRenderingResultsToImageData(DrawingBuffer*) +{ + // Reading premultiplied alpha would involve unpremultiplying, which is + // lossy + if (m_attrs.premultipliedAlpha) + return 0; + + RefPtr<ImageData> imageData = ImageData::create(IntSize(m_currentWidth, m_currentHeight)); + unsigned char* pixels = imageData->data()->data()->data(); + int totalBytes = 4 * m_currentWidth * m_currentHeight; + + readRenderingResults(pixels, totalBytes); + + // Convert to RGBA + for (int i = 0; i < totalBytes; i += 4) + std::swap(pixels[i], pixels[i + 2]); + + return imageData.release(); +} + +IntSize GraphicsContext3D::getInternalFramebufferSize() const +{ + return IntSize(m_currentWidth, m_currentHeight); +} + +void GraphicsContext3D::activeTexture(GC3Denum texture) +{ + makeContextCurrent(); + m_activeTexture = texture; + ::glActiveTexture(texture); +} + +void GraphicsContext3D::attachShader(Platform3DObject program, Platform3DObject shader) +{ + ASSERT(program); + ASSERT(shader); + makeContextCurrent(); + ::glAttachShader(program, shader); +} + +void GraphicsContext3D::bindAttribLocation(Platform3DObject program, GC3Duint index, const String& name) +{ + ASSERT(program); + makeContextCurrent(); + ::glBindAttribLocation(program, index, name.utf8().data()); +} + +void GraphicsContext3D::bindBuffer(GC3Denum target, Platform3DObject buffer) +{ + makeContextCurrent(); + ::glBindBuffer(target, buffer); +} + +void GraphicsContext3D::bindRenderbuffer(GC3Denum target, Platform3DObject renderbuffer) +{ + makeContextCurrent(); + ::glBindRenderbufferEXT(target, renderbuffer); +} + + +void GraphicsContext3D::bindTexture(GC3Denum target, Platform3DObject texture) +{ + makeContextCurrent(); + if (m_activeTexture && target == GL_TEXTURE_2D) + m_boundTexture0 = texture; + ::glBindTexture(target, texture); +} + +void GraphicsContext3D::blendColor(GC3Dclampf red, GC3Dclampf green, GC3Dclampf blue, GC3Dclampf alpha) +{ + makeContextCurrent(); + ::glBlendColor(red, green, blue, alpha); +} + +void GraphicsContext3D::blendEquation(GC3Denum mode) +{ + makeContextCurrent(); + ::glBlendEquation(mode); +} + +void GraphicsContext3D::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha) +{ + makeContextCurrent(); + ::glBlendEquationSeparate(modeRGB, modeAlpha); +} + + +void GraphicsContext3D::blendFunc(GC3Denum sfactor, GC3Denum dfactor) +{ + makeContextCurrent(); + ::glBlendFunc(sfactor, dfactor); +} + +void GraphicsContext3D::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha) +{ + makeContextCurrent(); + ::glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); +} + +void GraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage) +{ + makeContextCurrent(); + ::glBufferData(target, size, 0, usage); +} + +void GraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, const void* data, GC3Denum usage) +{ + makeContextCurrent(); + ::glBufferData(target, size, data, usage); +} + +void GraphicsContext3D::bufferSubData(GC3Denum target, GC3Dintptr offset, GC3Dsizeiptr size, const void* data) +{ + makeContextCurrent(); + ::glBufferSubData(target, offset, size, data); +} + +GC3Denum GraphicsContext3D::checkFramebufferStatus(GC3Denum target) +{ + makeContextCurrent(); + return ::glCheckFramebufferStatusEXT(target); +} + +void GraphicsContext3D::clearColor(GC3Dclampf r, GC3Dclampf g, GC3Dclampf b, GC3Dclampf a) +{ + makeContextCurrent(); + ::glClearColor(r, g, b, a); +} + +void GraphicsContext3D::clear(GC3Dbitfield mask) +{ + makeContextCurrent(); + ::glClear(mask); +} + +void GraphicsContext3D::clearDepth(GC3Dclampf depth) +{ + makeContextCurrent(); + ::glClearDepth(depth); +} + +void GraphicsContext3D::clearStencil(GC3Dint s) +{ + makeContextCurrent(); + ::glClearStencil(s); +} + +void GraphicsContext3D::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha) +{ + makeContextCurrent(); + ::glColorMask(red, green, blue, alpha); +} + +void GraphicsContext3D::compileShader(Platform3DObject shader) +{ + ASSERT(shader); + makeContextCurrent(); + + int GLshaderType; + ANGLEShaderType shaderType; + + glGetShaderiv(shader, SHADER_TYPE, &GLshaderType); + + if (GLshaderType == VERTEX_SHADER) + shaderType = SHADER_TYPE_VERTEX; + else if (GLshaderType == FRAGMENT_SHADER) + shaderType = SHADER_TYPE_FRAGMENT; + else + return; // Invalid shader type. + + HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader); + + if (result == m_shaderSourceMap.end()) + return; + + ShaderSourceEntry& entry = result->second; + + String translatedShaderSource; + String shaderInfoLog; + + bool isValid = m_compiler.validateShaderSource(entry.source.utf8().data(), shaderType, translatedShaderSource, shaderInfoLog); + + entry.log = shaderInfoLog; + entry.isValid = isValid; + + if (!isValid) + return; // Shader didn't validate, don't move forward with compiling translated source + + int translatedShaderLength = translatedShaderSource.length(); + + const CString& translatedShaderCString = translatedShaderSource.utf8(); + const char* translatedShaderPtr = translatedShaderCString.data(); + + ::glShaderSource(shader, 1, &translatedShaderPtr, &translatedShaderLength); + + ::glCompileShader(shader); + + int GLCompileSuccess; + + ::glGetShaderiv(shader, COMPILE_STATUS, &GLCompileSuccess); + + // ASSERT that ANGLE generated GLSL will be accepted by OpenGL + ASSERT(GLCompileSuccess == GL_TRUE); +} + +void GraphicsContext3D::cullFace(GC3Denum mode) +{ + makeContextCurrent(); + ::glCullFace(mode); +} + +void GraphicsContext3D::depthFunc(GC3Denum func) +{ + makeContextCurrent(); + ::glDepthFunc(func); +} + +void GraphicsContext3D::depthMask(GC3Dboolean flag) +{ + makeContextCurrent(); + ::glDepthMask(flag); +} + +void GraphicsContext3D::depthRange(GC3Dclampf zNear, GC3Dclampf zFar) +{ + makeContextCurrent(); + ::glDepthRange(zNear, zFar); +} + +void GraphicsContext3D::detachShader(Platform3DObject program, Platform3DObject shader) +{ + ASSERT(program); + ASSERT(shader); + makeContextCurrent(); + ::glDetachShader(program, shader); +} + +void GraphicsContext3D::disable(GC3Denum cap) +{ + makeContextCurrent(); + ::glDisable(cap); +} + +void GraphicsContext3D::disableVertexAttribArray(GC3Duint index) +{ + makeContextCurrent(); + ::glDisableVertexAttribArray(index); +} + +void GraphicsContext3D::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count) +{ + makeContextCurrent(); + ::glDrawArrays(mode, first, count); +} + +void GraphicsContext3D::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset) +{ + makeContextCurrent(); + ::glDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset))); +} + +void GraphicsContext3D::enable(GC3Denum cap) +{ + makeContextCurrent(); + ::glEnable(cap); +} + +void GraphicsContext3D::enableVertexAttribArray(GC3Duint index) +{ + makeContextCurrent(); + ::glEnableVertexAttribArray(index); +} + +void GraphicsContext3D::finish() +{ + makeContextCurrent(); + ::glFinish(); +} + +void GraphicsContext3D::flush() +{ + makeContextCurrent(); + ::glFlush(); +} + +void GraphicsContext3D::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, Platform3DObject buffer) +{ + makeContextCurrent(); + ::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, buffer); +} + +void GraphicsContext3D::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, Platform3DObject texture, GC3Dint level) +{ + makeContextCurrent(); + ::glFramebufferTexture2DEXT(target, attachment, textarget, texture, level); +} + +void GraphicsContext3D::frontFace(GC3Denum mode) +{ + makeContextCurrent(); + ::glFrontFace(mode); +} + +void GraphicsContext3D::generateMipmap(GC3Denum target) +{ + makeContextCurrent(); + ::glGenerateMipmapEXT(target); +} + +bool GraphicsContext3D::getActiveAttrib(Platform3DObject program, GC3Duint index, ActiveInfo& info) +{ + if (!program) { + synthesizeGLError(INVALID_VALUE); + return false; + } + makeContextCurrent(); + GLint maxAttributeSize = 0; + ::glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttributeSize); + GLchar name[maxAttributeSize]; // GL_ACTIVE_ATTRIBUTE_MAX_LENGTH includes null termination + GLsizei nameLength = 0; + GLint size = 0; + GLenum type = 0; + ::glGetActiveAttrib(program, index, maxAttributeSize, &nameLength, &size, &type, name); + if (!nameLength) + return false; + info.name = String(name, nameLength); + info.type = type; + info.size = size; + return true; +} + +void GraphicsContext3D::getAttachedShaders(Platform3DObject program, GC3Dsizei maxCount, GC3Dsizei* count, Platform3DObject* shaders) +{ + if (!program) { + synthesizeGLError(INVALID_VALUE); + return; + } + makeContextCurrent(); + ::glGetAttachedShaders(program, maxCount, count, shaders); +} + +int GraphicsContext3D::getAttribLocation(Platform3DObject program, const String& name) +{ + if (!program) + return -1; + + makeContextCurrent(); + return ::glGetAttribLocation(program, name.utf8().data()); +} + +GraphicsContext3D::Attributes GraphicsContext3D::getContextAttributes() +{ + return m_attrs; +} + +GC3Denum GraphicsContext3D::getError() +{ + if (m_syntheticErrors.size() > 0) { + ListHashSet<GC3Denum>::iterator iter = m_syntheticErrors.begin(); + GC3Denum err = *iter; + m_syntheticErrors.remove(iter); + return err; + } + + makeContextCurrent(); + return ::glGetError(); +} + +String GraphicsContext3D::getString(GC3Denum name) +{ + makeContextCurrent(); + return String(reinterpret_cast<const char*>(::glGetString(name))); +} + +void GraphicsContext3D::hint(GC3Denum target, GC3Denum mode) +{ + makeContextCurrent(); + ::glHint(target, mode); +} + +GC3Dboolean GraphicsContext3D::isBuffer(Platform3DObject buffer) +{ + if (!buffer) + return GL_FALSE; + + makeContextCurrent(); + return ::glIsBuffer(buffer); +} + +GC3Dboolean GraphicsContext3D::isEnabled(GC3Denum cap) +{ + makeContextCurrent(); + return ::glIsEnabled(cap); +} + +GC3Dboolean GraphicsContext3D::isFramebuffer(Platform3DObject framebuffer) +{ + if (!framebuffer) + return GL_FALSE; + + makeContextCurrent(); + return ::glIsFramebufferEXT(framebuffer); +} + +GC3Dboolean GraphicsContext3D::isProgram(Platform3DObject program) +{ + if (!program) + return GL_FALSE; + + makeContextCurrent(); + return ::glIsProgram(program); +} + +GC3Dboolean GraphicsContext3D::isRenderbuffer(Platform3DObject renderbuffer) +{ + if (!renderbuffer) + return GL_FALSE; + + makeContextCurrent(); + return ::glIsRenderbufferEXT(renderbuffer); +} + +GC3Dboolean GraphicsContext3D::isShader(Platform3DObject shader) +{ + if (!shader) + return GL_FALSE; + + makeContextCurrent(); + return ::glIsShader(shader); +} + +GC3Dboolean GraphicsContext3D::isTexture(Platform3DObject texture) +{ + if (!texture) + return GL_FALSE; + + makeContextCurrent(); + return ::glIsTexture(texture); +} + +void GraphicsContext3D::lineWidth(GC3Dfloat width) +{ + makeContextCurrent(); + ::glLineWidth(width); +} + +void GraphicsContext3D::linkProgram(Platform3DObject program) +{ + ASSERT(program); + makeContextCurrent(); + ::glLinkProgram(program); +} + +void GraphicsContext3D::pixelStorei(GC3Denum pname, GC3Dint param) +{ + makeContextCurrent(); + ::glPixelStorei(pname, param); +} + +void GraphicsContext3D::polygonOffset(GC3Dfloat factor, GC3Dfloat units) +{ + makeContextCurrent(); + ::glPolygonOffset(factor, units); +} + +void GraphicsContext3D::releaseShaderCompiler() +{ + // FIXME: This is not implemented on desktop OpenGL. We need to have ifdefs for the different GL variants. + makeContextCurrent(); + notImplemented(); +} + +void GraphicsContext3D::sampleCoverage(GC3Dclampf value, GC3Dboolean invert) +{ + makeContextCurrent(); + ::glSampleCoverage(value, invert); +} + +void GraphicsContext3D::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height) +{ + makeContextCurrent(); + ::glScissor(x, y, width, height); +} + +void GraphicsContext3D::shaderSource(Platform3DObject shader, const String& string) +{ + ASSERT(shader); + + makeContextCurrent(); + + ShaderSourceEntry entry; + + entry.source = string; + + m_shaderSourceMap.set(shader, entry); +} + +void GraphicsContext3D::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask) +{ + makeContextCurrent(); + ::glStencilFunc(func, ref, mask); +} + +void GraphicsContext3D::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask) +{ + makeContextCurrent(); + ::glStencilFuncSeparate(face, func, ref, mask); +} + +void GraphicsContext3D::stencilMask(GC3Duint mask) +{ + makeContextCurrent(); + ::glStencilMask(mask); +} + +void GraphicsContext3D::stencilMaskSeparate(GC3Denum face, GC3Duint mask) +{ + makeContextCurrent(); + ::glStencilMaskSeparate(face, mask); +} + +void GraphicsContext3D::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass) +{ + makeContextCurrent(); + ::glStencilOp(fail, zfail, zpass); +} + +void GraphicsContext3D::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass) +{ + makeContextCurrent(); + ::glStencilOpSeparate(face, fail, zfail, zpass); +} + +void GraphicsContext3D::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat value) +{ + makeContextCurrent(); + ::glTexParameterf(target, pname, value); +} + +void GraphicsContext3D::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint value) +{ + makeContextCurrent(); + ::glTexParameteri(target, pname, value); +} + +void GraphicsContext3D::uniform1f(GC3Dint location, GC3Dfloat v0) +{ + makeContextCurrent(); + ::glUniform1f(location, v0); +} + +void GraphicsContext3D::uniform1fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size) +{ + makeContextCurrent(); + ::glUniform1fv(location, size, array); +} + +void GraphicsContext3D::uniform2f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1) +{ + makeContextCurrent(); + ::glUniform2f(location, v0, v1); +} + +void GraphicsContext3D::uniform2fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size) +{ + // FIXME: length needs to be a multiple of 2 + makeContextCurrent(); + ::glUniform2fv(location, size, array); +} + +void GraphicsContext3D::uniform3f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2) +{ + makeContextCurrent(); + ::glUniform3f(location, v0, v1, v2); +} + +void GraphicsContext3D::uniform3fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size) +{ + // FIXME: length needs to be a multiple of 3 + makeContextCurrent(); + ::glUniform3fv(location, size, array); +} + +void GraphicsContext3D::uniform4f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3) +{ + makeContextCurrent(); + ::glUniform4f(location, v0, v1, v2, v3); +} + +void GraphicsContext3D::uniform4fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size) +{ + // FIXME: length needs to be a multiple of 4 + makeContextCurrent(); + ::glUniform4fv(location, size, array); +} + +void GraphicsContext3D::uniform1i(GC3Dint location, GC3Dint v0) +{ + makeContextCurrent(); + ::glUniform1i(location, v0); +} + +void GraphicsContext3D::uniform1iv(GC3Dint location, GC3Dint* array, GC3Dsizei size) +{ + makeContextCurrent(); + ::glUniform1iv(location, size, array); +} + +void GraphicsContext3D::uniform2i(GC3Dint location, GC3Dint v0, GC3Dint v1) +{ + makeContextCurrent(); + ::glUniform2i(location, v0, v1); +} + +void GraphicsContext3D::uniform2iv(GC3Dint location, GC3Dint* array, GC3Dsizei size) +{ + // FIXME: length needs to be a multiple of 2 + makeContextCurrent(); + ::glUniform2iv(location, size, array); +} + +void GraphicsContext3D::uniform3i(GC3Dint location, GC3Dint v0, GC3Dint v1, GC3Dint v2) +{ + makeContextCurrent(); + ::glUniform3i(location, v0, v1, v2); +} + +void GraphicsContext3D::uniform3iv(GC3Dint location, GC3Dint* array, GC3Dsizei size) +{ + // FIXME: length needs to be a multiple of 3 + makeContextCurrent(); + ::glUniform3iv(location, size, array); +} + +void GraphicsContext3D::uniform4i(GC3Dint location, GC3Dint v0, GC3Dint v1, GC3Dint v2, GC3Dint v3) +{ + makeContextCurrent(); + ::glUniform4i(location, v0, v1, v2, v3); +} + +void GraphicsContext3D::uniform4iv(GC3Dint location, GC3Dint* array, GC3Dsizei size) +{ + // FIXME: length needs to be a multiple of 4 + makeContextCurrent(); + ::glUniform4iv(location, size, array); +} + +void GraphicsContext3D::uniformMatrix2fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size) +{ + // FIXME: length needs to be a multiple of 4 + makeContextCurrent(); + ::glUniformMatrix2fv(location, size, transpose, array); +} + +void GraphicsContext3D::uniformMatrix3fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size) +{ + // FIXME: length needs to be a multiple of 9 + makeContextCurrent(); + ::glUniformMatrix3fv(location, size, transpose, array); +} + +void GraphicsContext3D::uniformMatrix4fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size) +{ + // FIXME: length needs to be a multiple of 16 + makeContextCurrent(); + ::glUniformMatrix4fv(location, size, transpose, array); +} + +void GraphicsContext3D::useProgram(Platform3DObject program) +{ + makeContextCurrent(); + ::glUseProgram(program); +} + +void GraphicsContext3D::validateProgram(Platform3DObject program) +{ + ASSERT(program); + + makeContextCurrent(); + ::glValidateProgram(program); +} + +void GraphicsContext3D::vertexAttrib1f(GC3Duint index, GC3Dfloat v0) +{ + makeContextCurrent(); + ::glVertexAttrib1f(index, v0); +} + +void GraphicsContext3D::vertexAttrib1fv(GC3Duint index, GC3Dfloat* array) +{ + makeContextCurrent(); + ::glVertexAttrib1fv(index, array); +} + +void GraphicsContext3D::vertexAttrib2f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1) +{ + makeContextCurrent(); + ::glVertexAttrib2f(index, v0, v1); +} + +void GraphicsContext3D::vertexAttrib2fv(GC3Duint index, GC3Dfloat* array) +{ + makeContextCurrent(); + ::glVertexAttrib2fv(index, array); +} + +void GraphicsContext3D::vertexAttrib3f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2) +{ + makeContextCurrent(); + ::glVertexAttrib3f(index, v0, v1, v2); +} + +void GraphicsContext3D::vertexAttrib3fv(GC3Duint index, GC3Dfloat* array) +{ + makeContextCurrent(); + ::glVertexAttrib3fv(index, array); +} + +void GraphicsContext3D::vertexAttrib4f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3) +{ + makeContextCurrent(); + ::glVertexAttrib4f(index, v0, v1, v2, v3); +} + +void GraphicsContext3D::vertexAttrib4fv(GC3Duint index, GC3Dfloat* array) +{ + makeContextCurrent(); + ::glVertexAttrib4fv(index, array); +} + +void GraphicsContext3D::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, GC3Dintptr offset) +{ + makeContextCurrent(); + ::glVertexAttribPointer(index, size, type, normalized, stride, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset))); +} + +void GraphicsContext3D::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height) +{ + makeContextCurrent(); + ::glViewport(x, y, width, height); +} + +void GraphicsContext3D::getBooleanv(GC3Denum pname, GC3Dboolean* value) +{ + makeContextCurrent(); + ::glGetBooleanv(pname, value); +} + +void GraphicsContext3D::getBufferParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value) +{ + makeContextCurrent(); + ::glGetBufferParameteriv(target, pname, value); +} + +void GraphicsContext3D::getFloatv(GC3Denum pname, GC3Dfloat* value) +{ + makeContextCurrent(); + ::glGetFloatv(pname, value); +} + +void GraphicsContext3D::getFramebufferAttachmentParameteriv(GC3Denum target, GC3Denum attachment, GC3Denum pname, GC3Dint* value) +{ + makeContextCurrent(); + if (attachment == DEPTH_STENCIL_ATTACHMENT) + attachment = DEPTH_ATTACHMENT; // Or STENCIL_ATTACHMENT, either works. + ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, value); +} + +void GraphicsContext3D::getProgramiv(Platform3DObject program, GC3Denum pname, GC3Dint* value) +{ + makeContextCurrent(); + ::glGetProgramiv(program, pname, value); +} + +String GraphicsContext3D::getProgramInfoLog(Platform3DObject program) +{ + ASSERT(program); + + makeContextCurrent(); + GLint length = 0; + ::glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); + if (!length) + return String(); + + GLsizei size = 0; + OwnArrayPtr<GLchar> info = adoptArrayPtr(new GLchar[length]); + ::glGetProgramInfoLog(program, length, &size, info.get()); + + return String(info.get()); +} + +void GraphicsContext3D::getRenderbufferParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value) +{ + makeContextCurrent(); + ::glGetRenderbufferParameterivEXT(target, pname, value); +} + +void GraphicsContext3D::getShaderiv(Platform3DObject shader, GC3Denum pname, GC3Dint* value) +{ + ASSERT(shader); + + makeContextCurrent(); + + HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader); + + switch (pname) { + case DELETE_STATUS: + case SHADER_TYPE: + ::glGetShaderiv(shader, pname, value); + break; + case COMPILE_STATUS: + if (result == m_shaderSourceMap.end()) { + *value = static_cast<int>(false); + return; + } + *value = static_cast<int>(result->second.isValid); + break; + case INFO_LOG_LENGTH: + if (result == m_shaderSourceMap.end()) { + *value = 0; + return; + } + *value = getShaderInfoLog(shader).length(); + break; + case SHADER_SOURCE_LENGTH: + *value = getShaderSource(shader).length(); + break; + default: + synthesizeGLError(INVALID_ENUM); + } +} + +String GraphicsContext3D::getShaderInfoLog(Platform3DObject shader) +{ + ASSERT(shader); + + makeContextCurrent(); + + HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader); + if (result == m_shaderSourceMap.end()) + return String(); + + ShaderSourceEntry entry = result->second; + if (!entry.isValid) + return entry.log; + + GLint length = 0; + ::glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); + if (!length) + return String(); + + GLsizei size = 0; + OwnArrayPtr<GLchar> info = adoptArrayPtr(new GLchar[length]); + ::glGetShaderInfoLog(shader, length, &size, info.get()); + + return String(info.get()); +} + +String GraphicsContext3D::getShaderSource(Platform3DObject shader) +{ + ASSERT(shader); + + makeContextCurrent(); + + HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader); + if (result == m_shaderSourceMap.end()) + return String(); + + return result->second.source; +} + + +void GraphicsContext3D::getTexParameterfv(GC3Denum target, GC3Denum pname, GC3Dfloat* value) +{ + makeContextCurrent(); + ::glGetTexParameterfv(target, pname, value); +} + +void GraphicsContext3D::getTexParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value) +{ + makeContextCurrent(); + ::glGetTexParameteriv(target, pname, value); +} + +void GraphicsContext3D::getUniformfv(Platform3DObject program, GC3Dint location, GC3Dfloat* value) +{ + makeContextCurrent(); + ::glGetUniformfv(program, location, value); +} + +void GraphicsContext3D::getUniformiv(Platform3DObject program, GC3Dint location, GC3Dint* value) +{ + makeContextCurrent(); + ::glGetUniformiv(program, location, value); +} + +GC3Dint GraphicsContext3D::getUniformLocation(Platform3DObject program, const String& name) +{ + ASSERT(program); + + makeContextCurrent(); + return ::glGetUniformLocation(program, name.utf8().data()); +} + +void GraphicsContext3D::getVertexAttribfv(GC3Duint index, GC3Denum pname, GC3Dfloat* value) +{ + makeContextCurrent(); + ::glGetVertexAttribfv(index, pname, value); +} + +void GraphicsContext3D::getVertexAttribiv(GC3Duint index, GC3Denum pname, GC3Dint* value) +{ + makeContextCurrent(); + ::glGetVertexAttribiv(index, pname, value); +} + +GC3Dsizeiptr GraphicsContext3D::getVertexAttribOffset(GC3Duint index, GC3Denum pname) +{ + makeContextCurrent(); + + GLvoid* pointer = 0; + ::glGetVertexAttribPointerv(index, pname, &pointer); + return static_cast<GC3Dsizeiptr>(reinterpret_cast<intptr_t>(pointer)); +} + +void GraphicsContext3D::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoff, GC3Dint yoff, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, const void* pixels) +{ + makeContextCurrent(); + + // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size + ::glTexSubImage2D(target, level, xoff, yoff, width, height, format, type, pixels); +} + +void GraphicsContext3D::compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Dsizei imageSize, const void* data) +{ + makeContextCurrent(); + ::glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); +} + +void GraphicsContext3D::compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Dsizei imageSize, const void* data) +{ + makeContextCurrent(); + ::glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); +} + +Platform3DObject GraphicsContext3D::createBuffer() +{ + makeContextCurrent(); + GLuint o = 0; + glGenBuffers(1, &o); + return o; +} + +Platform3DObject GraphicsContext3D::createFramebuffer() +{ + makeContextCurrent(); + GLuint o = 0; + glGenFramebuffersEXT(1, &o); + return o; +} + +Platform3DObject GraphicsContext3D::createProgram() +{ + makeContextCurrent(); + return glCreateProgram(); +} + +Platform3DObject GraphicsContext3D::createRenderbuffer() +{ + makeContextCurrent(); + GLuint o = 0; + glGenRenderbuffersEXT(1, &o); + return o; +} + +Platform3DObject GraphicsContext3D::createShader(GC3Denum type) +{ + makeContextCurrent(); + return glCreateShader((type == FRAGMENT_SHADER) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER); +} + +Platform3DObject GraphicsContext3D::createTexture() +{ + makeContextCurrent(); + GLuint o = 0; + glGenTextures(1, &o); + return o; +} + +void GraphicsContext3D::deleteBuffer(Platform3DObject buffer) +{ + makeContextCurrent(); + glDeleteBuffers(1, &buffer); +} + +void GraphicsContext3D::deleteFramebuffer(Platform3DObject framebuffer) +{ + makeContextCurrent(); + glDeleteFramebuffersEXT(1, &framebuffer); +} + +void GraphicsContext3D::deleteProgram(Platform3DObject program) +{ + makeContextCurrent(); + glDeleteProgram(program); +} + +void GraphicsContext3D::deleteRenderbuffer(Platform3DObject renderbuffer) +{ + makeContextCurrent(); + glDeleteRenderbuffersEXT(1, &renderbuffer); +} + +void GraphicsContext3D::deleteShader(Platform3DObject shader) +{ + makeContextCurrent(); + glDeleteShader(shader); +} + +void GraphicsContext3D::deleteTexture(Platform3DObject texture) +{ + makeContextCurrent(); + glDeleteTextures(1, &texture); +} + +void GraphicsContext3D::synthesizeGLError(GC3Denum error) +{ + m_syntheticErrors.add(error); +} + +void GraphicsContext3D::markContextChanged() +{ + m_layerComposited = false; +} + +void GraphicsContext3D::markLayerComposited() +{ + m_layerComposited = true; +} + +bool GraphicsContext3D::layerComposited() const +{ + return m_layerComposited; +} + +Extensions3D* GraphicsContext3D::getExtensions() +{ + if (!m_extensions) + m_extensions = adoptPtr(new Extensions3DOpenGL(this)); + return m_extensions.get(); +} + +} + +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLES.cpp b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLES.cpp new file mode 100644 index 000000000..90ff5a0a3 --- /dev/null +++ b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLES.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2012 ChangSeok Oh <shivamidow@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEBGL) + +#include "GraphicsContext3D.h" + +#include "NotImplemented.h" + +#if PLATFORM(GTK) +#include "OpenGLShims.h" +#endif + +namespace WebCore { + +void GraphicsContext3D::readRenderingResults(unsigned char *pixels, int pixelsSize) +{ + notImplemented(); +} + +void GraphicsContext3D::reshape(int width, int height) +{ + notImplemented(); +} + +void GraphicsContext3D::prepareTexture() +{ + notImplemented(); +} + +void GraphicsContext3D::bindFramebuffer(GC3Denum target, Platform3DObject buffer) +{ + notImplemented(); +} + +void GraphicsContext3D::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border) +{ + notImplemented(); +} + +void GraphicsContext3D::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height) +{ + notImplemented(); +} + +bool GraphicsContext3D::getActiveUniform(Platform3DObject program, GC3Duint index, ActiveInfo& info) +{ + notImplemented(); +} + + +void GraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data) +{ + notImplemented(); +} + +void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height) +{ + notImplemented(); +} + +void GraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value) +{ + notImplemented(); +} + +bool GraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels) +{ + notImplemented(); + return false; +} + +} + +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp index 0ff7022e3..ddff6051c 100644 --- a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp @@ -238,8 +238,10 @@ struct TextureMapperGLData { ProgramInfo programs[ProgramCount]; int stencilIndex; + Vector<IntRect> clipStack; - SharedGLData(GLContext glContext) : stencilIndex(1) + SharedGLData(GLContext glContext) + : stencilIndex(1) { glContextDataMap().add(glContext, this); initializeShaders(); @@ -321,12 +323,15 @@ struct TextureMapperGLData { TextureMapperGLData() : currentProgram(SharedGLData::NoProgram) + , previousProgram(0) + , previousScissorState(0) , m_sharedGLData(TextureMapperGLData::SharedGLData::currentSharedGLData()) { } TransformationMatrix projectionMatrix; int currentProgram; - int previousProgram; + GLint previousProgram; + GLint previousScissorState; RefPtr<SharedGLData> m_sharedGLData; }; @@ -347,6 +352,7 @@ public: void setTextureMapper(TextureMapperGL* texmap) { m_textureMapper = texmap; } void updateContents(PixelFormat, const IntRect&, void*); + void updateRawContents(const IntRect&, const void*); void pack() { // This is currently a stub. @@ -519,28 +525,40 @@ void TextureMapperGLData::SharedGLData::initializeShaders() void TextureMapperGL::beginPainting() { -#if PLATFORM(QT) + // Make sure that no GL error code stays from previous operations. + glGetError(); + if (!initializeOpenGLShims()) return; - glGetIntegerv(GL_CURRENT_PROGRAM, &m_data->previousProgram); + glGetIntegerv(GL_CURRENT_PROGRAM, &data().previousProgram); + data().previousScissorState = glIsEnabled(GL_SCISSOR_TEST); + + glEnable(GL_SCISSOR_TEST); +#if PLATFORM(QT) if (m_context) { QPainter* painter = m_context->platformContext(); painter->save(); painter->beginNativePainting(); } +#endif glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); bindSurface(0); -#endif } void TextureMapperGL::endPainting() { -#if PLATFORM(QT) glClearStencil(1); glClear(GL_STENCIL_BUFFER_BIT); - glUseProgram(m_data->previousProgram); + glUseProgram(data().previousProgram); + + if (data().previousScissorState) + glEnable(GL_SCISSOR_TEST); + else + glDisable(GL_SCISSOR_TEST); + +#if PLATFORM(QT) if (!m_context) return; QPainter* painter = m_context->platformContext(); @@ -619,6 +637,7 @@ void TextureMapperGL::drawTexture(uint32_t texture, bool opaque, const FloatSize } GL_CMD(glDisable(GL_DEPTH_TEST)) + GL_CMD(glDrawArrays(GL_TRIANGLE_FAN, 0, 4)) GL_CMD(glDisableVertexAttribArray(programInfo.vertexAttrib)) } @@ -737,6 +756,13 @@ void BitmapTextureGL::updateContents(PixelFormat pixelFormat, const IntRect& rec GL_CMD(glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), glFormat, GL_UNSIGNED_BYTE, bits)) } +void BitmapTextureGL::updateRawContents(const IntRect& rect, const void* bits) +{ + GL_CMD(glBindTexture(GL_TEXTURE_2D, m_id)) + GLuint glFormat = isOpaque() ? GL_RGB : GL_RGBA; + GL_CMD(glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), glFormat, GL_UNSIGNED_BYTE, bits)) +} + void BitmapTextureGL::setContentsToImage(Image* image) { ImageUID uid = image ? uidForImage(image) : 0; @@ -807,7 +833,6 @@ void BitmapTextureGL::bind() glStencilFunc(stencilIndex > 1 ? GL_GEQUAL : GL_ALWAYS, stencilIndex - 1, stencilIndex - 1); GL_CMD(glViewport(0, 0, size().width(), size().height())) m_textureMapper->data().projectionMatrix = createProjectionMatrix(size(), false); - glDisable(GL_SCISSOR_TEST); } void BitmapTextureGL::destroy() @@ -852,14 +877,58 @@ void TextureMapperGL::bindSurface(BitmapTexture *surfacePointer) GL_CMD(glStencilFunc(data().sharedGLData().stencilIndex > 1 ? GL_EQUAL : GL_ALWAYS, data().sharedGLData().stencilIndex - 1, data().sharedGLData().stencilIndex - 1)) GL_CMD(glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)) GL_CMD(glViewport(0, 0, viewportSize().width(), viewportSize().height())) + data().sharedGLData().clipStack.append(IntRect(IntPoint::zero(), viewportSize())); return; } surface->bind(); } +static void scissorClip(const IntRect& rect) +{ + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + glScissor(rect.x(), viewport[3] - rect.maxY(), rect.width(), rect.height()); +} + +bool TextureMapperGL::beginScissorClip(const TransformationMatrix& modelViewMatrix, const FloatRect& targetRect) +{ + FloatQuad quad = modelViewMatrix.projectQuad(targetRect); + IntRect rect = quad.enclosingBoundingBox(); + + // Only use scissors on rectilinear clips. + if (!quad.isRectilinear() || rect.isEmpty()) { + data().sharedGLData().clipStack.append(IntRect()); + return false; + } + + // Intersect with previous clip. + if (!data().sharedGLData().clipStack.isEmpty()) + rect.intersect(data().sharedGLData().clipStack.last()); + + scissorClip(rect); + data().sharedGLData().clipStack.append(rect); + + return true; +} + +bool TextureMapperGL::endScissorClip() +{ + data().sharedGLData().clipStack.removeLast(); + ASSERT(!data().sharedGLData().clipStack.isEmpty()); + + IntRect rect = data().sharedGLData().clipStack.last(); + if (rect.isEmpty()) + return false; + + scissorClip(rect); + return true; +} + void TextureMapperGL::beginClip(const TransformationMatrix& modelViewMatrix, const FloatRect& targetRect) { + if (beginScissorClip(modelViewMatrix, targetRect)) + return; TextureMapperGLData::SharedGLData::ShaderProgramIndex program = TextureMapperGLData::SharedGLData::ClipProgram; const TextureMapperGLData::SharedGLData::ProgramInfo& programInfo = data().sharedGLData().programs[program]; GL_CMD(glUseProgram(programInfo.id)) @@ -897,8 +966,16 @@ void TextureMapperGL::beginClip(const TransformationMatrix& modelViewMatrix, con void TextureMapperGL::endClip() { + if (endScissorClip()) + return; + data().sharedGLData().stencilIndex >>= 1; - glStencilFunc(data().sharedGLData().stencilIndex > 1 ? GL_EQUAL : GL_ALWAYS, data().sharedGLData().stencilIndex - 1, data().sharedGLData().stencilIndex - 1); + glStencilFunc(data().sharedGLData().stencilIndex > 1 ? GL_EQUAL : GL_ALWAYS, data().sharedGLData().stencilIndex - 1, data().sharedGLData().stencilIndex - 1); + + // After we've cleared the last non-rectalinear clip, we disable the stencil test. + if (data().sharedGLData().stencilIndex == 1) + GL_CMD(glDisable(GL_STENCIL_TEST)) + } PassRefPtr<BitmapTexture> TextureMapperGL::createTexture() diff --git a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.h b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.h index dd2e1a7c9..1b411857c 100644 --- a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.h +++ b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.h @@ -55,6 +55,8 @@ public: virtual bool isOpenGLBacked() const { return true; } private: + bool beginScissorClip(const TransformationMatrix&, const FloatRect&); + bool endScissorClip(); inline TextureMapperGLData& data() { return *m_data; } TextureMapperGLData* m_data; GraphicsContext* m_context; diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp index 9173a5dcc..495bcadd3 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp +++ b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp @@ -1639,6 +1639,10 @@ void GraphicsContext3D::setContextLostCallback(PassOwnPtr<ContextLostCallback>) { } +void GraphicsContext3D::setErrorMessageCallback(PassOwnPtr<ErrorMessageCallback>) +{ +} + } #endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp index 919cba368..e36ff85b1 100644 --- a/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp +++ b/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -94,7 +94,7 @@ QImage ImageBufferData::toQImage() const return image; } -ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, DeferralMode, bool& success) : m_data(size) , m_size(size) { diff --git a/Source/WebCore/platform/graphics/qt/TextureMapperQt.cpp b/Source/WebCore/platform/graphics/qt/TextureMapperQt.cpp index f41a4212d..44641ce63 100644 --- a/Source/WebCore/platform/graphics/qt/TextureMapperQt.cpp +++ b/Source/WebCore/platform/graphics/qt/TextureMapperQt.cpp @@ -76,7 +76,6 @@ void BitmapTextureQt::updateContents(PixelFormat pixelFormat, const IntRect& rec m_painter.end(); } - bool BitmapTextureQt::save(const String& path) { return m_pixmap.save(path, "PNG"); @@ -142,7 +141,7 @@ TextureMapperQt::TextureMapperQt() void TextureMapperQt::setGraphicsContext(GraphicsContext* context) { m_context = context; - m_painter = context->platformContext(); + m_painter = context ? context->platformContext() : 0; initialize(m_painter); } diff --git a/Source/WebCore/platform/graphics/qt/TextureMapperQt.h b/Source/WebCore/platform/graphics/qt/TextureMapperQt.h index de571974f..08fee03f1 100644 --- a/Source/WebCore/platform/graphics/qt/TextureMapperQt.h +++ b/Source/WebCore/platform/graphics/qt/TextureMapperQt.h @@ -70,7 +70,8 @@ public: static void initialize(QPainter* painter) { - painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false); + if (painter) + painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false); } static PassOwnPtr<TextureMapper> create() { return adoptPtr(new TextureMapperQt); } diff --git a/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index db343615f..355a6b5ef 100644 --- a/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -339,6 +339,7 @@ void GraphicsContext::clearRect(const FloatRect& rect) platformContext()->setupPaintForFilling(&paint); paint.setXfermodeMode(SkXfermode::kClear_Mode); platformContext()->canvas()->drawRect(r, paint); + platformContext()->didDrawRect(r, paint); } void GraphicsContext::clip(const FloatRect& rect) @@ -473,11 +474,13 @@ void GraphicsContext::drawConvexPolygon(size_t numPoints, platformContext()->setupPaintForFilling(&paint); paint.setAntiAlias(shouldAntialias); platformContext()->canvas()->drawPath(path, paint); + platformContext()->didDrawPath(path, paint); if (strokeStyle() != NoStroke) { paint.reset(); platformContext()->setupPaintForStroking(&paint, 0, 0); platformContext()->canvas()->drawPath(path, paint); + platformContext()->didDrawPath(path, paint); } } @@ -513,11 +516,13 @@ void GraphicsContext::drawEllipse(const IntRect& elipseRect) SkPaint paint; platformContext()->setupPaintForFilling(&paint); platformContext()->canvas()->drawOval(rect, paint); + platformContext()->didDrawBounded(rect, paint); if (strokeStyle() != NoStroke) { paint.reset(); platformContext()->setupPaintForStroking(&paint, &rect, 0); platformContext()->canvas()->drawOval(rect, paint); + platformContext()->didDrawBounded(rect, paint); } } @@ -526,7 +531,7 @@ void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, con // FIXME: implement } -static inline void drawOuterPath(SkCanvas* canvas, const SkPath& path, SkPaint& paint, int width) +static inline void drawOuterPath(PlatformContextSkia* context, const SkPath& path, SkPaint& paint, int width) { #if PLATFORM(CHROMIUM) && OS(DARWIN) paint.setAlpha(64); @@ -536,15 +541,17 @@ static inline void drawOuterPath(SkCanvas* canvas, const SkPath& path, SkPaint& paint.setStrokeWidth(1); paint.setPathEffect(new SkCornerPathEffect(1))->unref(); #endif - canvas->drawPath(path, paint); + context->canvas()->drawPath(path, paint); + context->didDrawPath(path, paint); } -static inline void drawInnerPath(SkCanvas* canvas, const SkPath& path, SkPaint& paint, int width) +static inline void drawInnerPath(PlatformContextSkia* context, const SkPath& path, SkPaint& paint, int width) { #if PLATFORM(CHROMIUM) && OS(DARWIN) paint.setAlpha(128); paint.setStrokeWidth(width * 0.5f); - canvas->drawPath(path, paint); + context->canvas()->drawPath(path, paint); + context->didDrawPath(path, paint); #endif } @@ -581,9 +588,8 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int paint.setColor(color.rgb()); focusRingRegion.getBoundaryPath(&path); - SkCanvas* canvas = platformContext()->canvas(); - drawOuterPath(canvas, path, paint, width); - drawInnerPath(canvas, path, paint, width); + drawOuterPath(platformContext(), path, paint, width); + drawInnerPath(platformContext(), path, paint, width); } // This is only used to draw borders. @@ -631,12 +637,15 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) fillPaint.setColor(paint.getColor()); platformContext()->canvas()->drawRect(r1, fillPaint); platformContext()->canvas()->drawRect(r2, fillPaint); + platformContext()->didDrawRect(r1, fillPaint); + platformContext()->didDrawRect(r2, fillPaint); } adjustLineToPixelBoundaries(p1, p2, width, penStyle); SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 }; platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint); + platformContext()->didDrawPoints(SkCanvas::kLines_PointMode, 2, pts, paint); } void GraphicsContext::drawLineForTextChecking(const FloatPoint& pt, float width, TextCheckingLineStyle style) @@ -647,17 +656,40 @@ void GraphicsContext::drawLineForTextChecking(const FloatPoint& pt, float width, // Create the pattern we'll use to draw the underline. static SkBitmap* misspellBitmap = 0; if (!misspellBitmap) { +#if PLATFORM(CHROMIUM) && OS(DARWIN) + // Match the artwork used by the Mac. + const int rowPixels = 4; + const int colPixels = 3; +#else // We use a 2-pixel-high misspelling indicator because that seems to be // what WebKit is designed for, and how much room there is in a typical // page for it. const int rowPixels = 32; // Must be multiple of 4 for pattern below. const int colPixels = 2; +#endif misspellBitmap = new SkBitmap; misspellBitmap->setConfig(SkBitmap::kARGB_8888_Config, rowPixels, colPixels); misspellBitmap->allocPixels(); misspellBitmap->eraseARGB(0, 0, 0, 0); +#if PLATFORM(CHROMIUM) && OS(DARWIN) + const uint32_t colors[] = { 0x2A2A0600, 0x57571000, // left half of 4x3 + 0xA8A81B00, 0xBFBF1F00, + 0x70701200, 0xE0E02400 }; + const uint32_t transparentColor = 0x00000000; + + // Pattern: a b a a b a + // c d c c d c + // e f e e f e + for (int x = 0; x < colPixels; ++x) { + uint32_t* row = misspellBitmap->getAddr32(0, x); + row[0] = colors[x * 2]; + row[1] = colors[x * 2 + 1]; + row[2] = colors[x * 2]; + row[3] = transparentColor; + } +#else const uint32_t lineColor = 0xFFFF0000; // Opaque red. const uint32_t antiColor = 0x60600000; // Semitransparent red. @@ -683,11 +715,16 @@ void GraphicsContext::drawLineForTextChecking(const FloatPoint& pt, float width, break; } } +#endif } - // Offset it vertically by 1 so that there's some space under the text. SkScalar originX = WebCoreFloatToSkScalar(pt.x()); +#if PLATFORM(CHROMIUM) && OS(DARWIN) + SkScalar originY = WebCoreFloatToSkScalar(pt.y()); +#else + // Offset it vertically by 1 so that there's some space under the text. SkScalar originY = WebCoreFloatToSkScalar(pt.y()) + 1; +#endif // Make a shader for the bitmap with an origin of the box we'll draw. This // shader is refcounted and will have an initial refcount of 1. @@ -712,6 +749,7 @@ void GraphicsContext::drawLineForTextChecking(const FloatPoint& pt, float width, originX + WebCoreFloatToSkScalar(width), originY + SkIntToScalar(misspellBitmap->height())); platformContext()->canvas()->drawRect(rect, paint); + platformContext()->didDrawRect(rect, paint); } void GraphicsContext::drawLineForText(const FloatPoint& pt, @@ -736,6 +774,7 @@ void GraphicsContext::drawLineForText(const FloatPoint& pt, // Text lines are drawn using the stroke color. paint.setColor(platformContext()->effectiveStrokeColor()); platformContext()->canvas()->drawRect(r, paint); + platformContext()->didDrawRect(r, paint); } // Draws a filled rectangle with a stroked border. @@ -770,6 +809,7 @@ void GraphicsContext::fillPath(const Path& pathToFill) platformContext()->setupPaintForFilling(&paint); platformContext()->canvas()->drawPath(path, paint); + platformContext()->didDrawPath(path, paint); } void GraphicsContext::fillRect(const FloatRect& rect) @@ -788,6 +828,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) SkPaint paint; platformContext()->setupPaintForFilling(&paint); platformContext()->canvas()->drawRect(r, paint); + platformContext()->didDrawRect(r, paint); platformContext()->restore(); } @@ -816,6 +857,7 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS platformContext()->setupPaintCommon(&paint); paint.setColor(color.rgb()); platformContext()->canvas()->drawRect(r, paint); + platformContext()->didDrawRect(r, paint); } void GraphicsContext::fillRoundedRect(const IntRect& rect, @@ -855,6 +897,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, platformContext()->setupPaintForFilling(&paint); paint.setColor(color.rgb()); platformContext()->canvas()->drawPath(path, paint); + platformContext()->didDrawPath(path, paint); } AffineTransform GraphicsContext::getCTM() const @@ -1139,6 +1182,7 @@ void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan) if (!isPathSkiaSafe(getCTM(), path)) return; platformContext()->canvas()->drawPath(path, paint); + platformContext()->didDrawPath(path, paint); } void GraphicsContext::strokePath(const Path& pathToStroke) @@ -1153,6 +1197,7 @@ void GraphicsContext::strokePath(const Path& pathToStroke) SkPaint paint; platformContext()->setupPaintForStroking(&paint, 0, 0); platformContext()->canvas()->drawPath(path, paint); + platformContext()->didDrawPath(path, paint); } void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) @@ -1173,9 +1218,10 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) bool validW = r.width() > 0; bool validH = r.height() > 0; SkCanvas* canvas = platformContext()->canvas(); - if (validW && validH) + if (validW && validH) { canvas->drawRect(r, paint); - else if (validW || validH) { + platformContext()->didDrawRect(r, paint); + } else if (validW || validH) { // we are expected to respect the lineJoin, so we can't just call // drawLine -- we have to create a path that doubles back on itself. SkPath path; @@ -1183,6 +1229,7 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) path.lineTo(r.fRight, r.fBottom); path.close(); canvas->drawPath(path, paint); + platformContext()->didDrawPath(path, paint); } } diff --git a/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index f96c5690d..eaa1d77b4 100644 --- a/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -46,6 +46,7 @@ #include "PlatformContextSkia.h" #include "SharedGraphicsContext3D.h" #include "SkColorPriv.h" +#include "SkDeferredCanvas.h" #include "SkGpuDevice.h" #include "SkiaUtils.h" #include "WEBPImageEncoder.h" @@ -65,7 +66,29 @@ ImageBufferData::ImageBufferData(const IntSize& size) { } -static SkCanvas* createAcceleratedCanvas(const IntSize& size, ImageBufferData* data) +class AcceleratedDeviceContext : public SkDeferredCanvas::DeviceContext { +public: + AcceleratedDeviceContext(GraphicsContext3D* context3D) + { + ASSERT(context3D); + m_context3D = context3D; + } + + virtual void prepareForDraw() + { + m_context3D->makeContextCurrent(); + } + + virtual void flush() + { + m_context3D->flush(); + } + +private: + GraphicsContext3D* m_context3D; +}; + +static SkCanvas* createAcceleratedCanvas(const IntSize& size, ImageBufferData* data, DeferralMode deferralMode) { GraphicsContext3D* context3D = SharedGraphicsContext3D::get(); if (!context3D) @@ -83,12 +106,18 @@ static SkCanvas* createAcceleratedCanvas(const IntSize& size, ImageBufferData* d SkAutoTUnref<GrTexture> texture(gr->createUncachedTexture(desc, 0, 0)); if (!texture.get()) return 0; - SkCanvas* canvas = new SkCanvas(); - canvas->setDevice(new SkGpuDevice(gr, texture.get()))->unref(); + SkCanvas* canvas; + SkAutoTUnref<SkDevice> device(new SkGpuDevice(gr, texture.get())); + if (deferralMode == Deferred) { + SkAutoTUnref<AcceleratedDeviceContext> deviceContext(new AcceleratedDeviceContext(context3D)); + canvas = new SkDeferredCanvas(device.get(), deviceContext.get()); + } else + canvas = new SkCanvas(device.get()); data->m_platformContext.setGraphicsContext3D(context3D); #if USE(ACCELERATED_COMPOSITING) data->m_platformLayer = Canvas2DLayerChromium::create(context3D, size); data->m_platformLayer->setTextureId(texture.get()->getTextureHandle()); + data->m_platformLayer->setCanvas(canvas); #endif return canvas; } @@ -100,14 +129,14 @@ static SkCanvas* createNonPlatformCanvas(const IntSize& size) return canvas; } -ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode renderingMode, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode renderingMode, DeferralMode deferralMode, bool& success) : m_data(size) , m_size(size) { OwnPtr<SkCanvas> canvas; if (renderingMode == Accelerated) - canvas = adoptPtr(createAcceleratedCanvas(size, &m_data)); + canvas = adoptPtr(createAcceleratedCanvas(size, &m_data, deferralMode)); else if (renderingMode == UnacceleratedNonPlatformBuffer) canvas = adoptPtr(createNonPlatformCanvas(size)); @@ -226,65 +255,18 @@ PassRefPtr<ByteArray> getImageData(const IntRect& rect, SkCanvas* canvas, || rect.maxY() > size.height()) memset(data, 0, result->length()); - int originX = rect.x(); - int destX = 0; - if (originX < 0) { - destX = -originX; - originX = 0; - } - int endX = rect.maxX(); - if (endX > size.width()) - endX = size.width(); - int numColumns = endX - originX; - - if (numColumns <= 0) - return result.release(); - - int originY = rect.y(); - int destY = 0; - if (originY < 0) { - destY = -originY; - originY = 0; - } - int endY = rect.maxY(); - if (endY > size.height()) - endY = size.height(); - int numRows = endY - originY; - - if (numRows <= 0) - return result.release(); - - SkBitmap srcBitmap; - if (!canvas->readPixels(SkIRect::MakeXYWH(originX, originY, numColumns, numRows), &srcBitmap)) - return result.release(); - unsigned destBytesPerRow = 4 * rect.width(); - unsigned char* destRow = data + destY * destBytesPerRow + destX * 4; - - // Do conversion of byte order and alpha divide (if necessary) - for (int y = 0; y < numRows; ++y) { - SkPMColor* srcBitmapRow = srcBitmap.getAddr32(0, y); - for (int x = 0; x < numColumns; ++x) { - SkPMColor srcPMColor = srcBitmapRow[x]; - unsigned char* destPixel = &destRow[x * 4]; - if (multiplied == Unmultiplied) { - unsigned char a = SkGetPackedA32(srcPMColor); - destPixel[0] = a ? SkGetPackedR32(srcPMColor) * 255 / a : 0; - destPixel[1] = a ? SkGetPackedG32(srcPMColor) * 255 / a : 0; - destPixel[2] = a ? SkGetPackedB32(srcPMColor) * 255 / a : 0; - destPixel[3] = a; - } else { - // Input and output are both pre-multiplied, we just need to re-arrange the - // bytes from the bitmap format to RGBA. - destPixel[0] = SkGetPackedR32(srcPMColor); - destPixel[1] = SkGetPackedG32(srcPMColor); - destPixel[2] = SkGetPackedB32(srcPMColor); - destPixel[3] = SkGetPackedA32(srcPMColor); - } - } - destRow += destBytesPerRow; - } + SkBitmap destBitmap; + destBitmap.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height(), destBytesPerRow); + destBitmap.setPixels(data); + + SkCanvas::Config8888 config8888; + if (multiplied == Premultiplied) + config8888 = SkCanvas::kRGBA_Premul_Config8888; + else + config8888 = SkCanvas::kRGBA_Unpremul_Config8888; + canvas->readPixels(&destBitmap, rect.x(), rect.y(), config8888); return result.release(); } diff --git a/Source/WebCore/platform/graphics/skia/ImageSkia.cpp b/Source/WebCore/platform/graphics/skia/ImageSkia.cpp index e66dbab43..1d5d9911b 100644 --- a/Source/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -248,6 +248,7 @@ static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImag // we don't send extra pixels. canvas->drawBitmapRect(bitmap.bitmap(), &srcRect, destRect, &paint); } + platformContext->didDrawRect(destRect, paint, &bitmap.bitmap()); } // Transforms the given dimensions with the given matrix. Used to see how big diff --git a/Source/WebCore/platform/graphics/skia/OpaqueRegionSkia.cpp b/Source/WebCore/platform/graphics/skia/OpaqueRegionSkia.cpp new file mode 100644 index 000000000..64a4ee4f3 --- /dev/null +++ b/Source/WebCore/platform/graphics/skia/OpaqueRegionSkia.cpp @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2012, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "OpaqueRegionSkia.h" + +#include "PlatformContextSkia.h" + +#include "SkShader.h" + +namespace WebCore { + +OpaqueRegionSkia::OpaqueRegionSkia() + : m_opaqueRect(SkRect::MakeEmpty()) +{ +} + +OpaqueRegionSkia::~OpaqueRegionSkia() +{ +} + +IntRect OpaqueRegionSkia::asRect() const +{ + // Returns the largest enclosed rect. + int left = SkScalarCeil(m_opaqueRect.fLeft); + int top = SkScalarCeil(m_opaqueRect.fTop); + int right = SkScalarFloor(m_opaqueRect.fRight); + int bottom = SkScalarFloor(m_opaqueRect.fBottom); + return IntRect(left, top, right-left, bottom-top); +} + +// Returns true if the xfermode will force the dst to be opaque, regardless of the current dst. +static inline bool xfermodeIsOpaque(const SkPaint& paint, bool srcIsOpaque) +{ + if (!srcIsOpaque) + return false; + + SkXfermode* xfermode = paint.getXfermode(); + if (!xfermode) + return true; // default to kSrcOver_Mode + SkXfermode::Mode mode; + if (!xfermode->asMode(&mode)) + return false; + + switch (mode) { + case SkXfermode::kSrc_Mode: // source + case SkXfermode::kSrcOver_Mode: // source + dest - source*dest + case SkXfermode::kDstOver_Mode: // source + dest - source*dest + case SkXfermode::kDstATop_Mode: // source + case SkXfermode::kPlus_Mode: // source+dest + default: // the rest are all source + dest - source*dest + return true; + case SkXfermode::kClear_Mode: // 0 + case SkXfermode::kDst_Mode: // dest + case SkXfermode::kSrcIn_Mode: // source * dest + case SkXfermode::kDstIn_Mode: // dest * source + case SkXfermode::kSrcOut_Mode: // source * (1-dest) + case SkXfermode::kDstOut_Mode: // dest * (1-source) + case SkXfermode::kSrcATop_Mode: // dest + case SkXfermode::kXor_Mode: // source + dest - 2*(source*dest) + return false; + } +} + +// Returns true if the xfermode will keep the dst opaque, assuming the dst is already opaque. +static inline bool xfermodePreservesOpaque(const SkPaint& paint, bool srcIsOpaque) +{ + SkXfermode* xfermode = paint.getXfermode(); + if (!xfermode) + return true; // default to kSrcOver_Mode + SkXfermode::Mode mode; + if (!xfermode->asMode(&mode)) + return false; + + switch (mode) { + case SkXfermode::kDst_Mode: // dest + case SkXfermode::kSrcOver_Mode: // source + dest - source*dest + case SkXfermode::kDstOver_Mode: // source + dest - source*dest + case SkXfermode::kSrcATop_Mode: // dest + case SkXfermode::kPlus_Mode: // source+dest + default: // the rest are all source + dest - source*dest + return true; + case SkXfermode::kClear_Mode: // 0 + case SkXfermode::kSrcOut_Mode: // source * (1-dest) + case SkXfermode::kDstOut_Mode: // dest * (1-source) + case SkXfermode::kXor_Mode: // source + dest - 2*(source*dest) + return false; + case SkXfermode::kSrc_Mode: // source + case SkXfermode::kSrcIn_Mode: // source * dest + case SkXfermode::kDstIn_Mode: // dest * source + case SkXfermode::kDstATop_Mode: // source + return srcIsOpaque; + } +} + +// Returns true if all pixels painted will be opaque. +static inline bool paintIsOpaque(const SkPaint& paint, const SkBitmap* bitmap = 0, bool checkFillOnly = false) +{ + if (paint.getAlpha() < 0xFF) + return false; + if (!checkFillOnly && paint.getStyle() != SkPaint::kFill_Style && paint.isAntiAlias()) + return false; + SkShader* shader = paint.getShader(); + if (shader && !shader->isOpaque()) + return false; + if (bitmap && !bitmap->isOpaque()) + return false; + return true; +} + +void OpaqueRegionSkia::didDrawRect(const PlatformContextSkia* context, const SkRect& fillRect, const SkPaint& paint, const SkBitmap* bitmap) +{ + // Any stroking may put alpha in pixels even if the filling part does not. + if (paint.getStyle() != SkPaint::kFill_Style) { + bool opaque = paintIsOpaque(paint, bitmap); + bool fillsBounds = false; + + if (!paint.canComputeFastBounds()) + didDrawUnbounded(paint, opaque); + else { + SkRect strokeRect; + strokeRect = paint.computeFastBounds(fillRect, &strokeRect); + didDraw(context, strokeRect, paint, opaque, fillsBounds); + } + } + + bool checkFillOnly = true; + bool opaque = paintIsOpaque(paint, bitmap, checkFillOnly); + bool fillsBounds = paint.getStyle() != SkPaint::kStroke_Style; + didDraw(context, fillRect, paint, opaque, fillsBounds); +} + +void OpaqueRegionSkia::didDrawPath(const PlatformContextSkia* context, const SkPath& path, const SkPaint& paint) +{ + SkRect rect; + if (path.isRect(&rect)) { + didDrawRect(context, rect, paint, 0); + return; + } + + bool opaque = paintIsOpaque(paint); + bool fillsBounds = false; + + if (!paint.canComputeFastBounds()) + didDrawUnbounded(paint, opaque); + else { + rect = paint.computeFastBounds(path.getBounds(), &rect); + didDraw(context, rect, paint, opaque, fillsBounds); + } +} + +void OpaqueRegionSkia::didDrawPoints(const PlatformContextSkia* context, SkCanvas::PointMode mode, int numPoints, const SkPoint points[], const SkPaint& paint) +{ + if (!numPoints) + return; + + SkRect rect; + rect.fLeft = points[0].fX; + rect.fRight = points[0].fX + 1; + rect.fTop = points[0].fY; + rect.fBottom = points[0].fY + 1; + + for (int i = 1; i < numPoints; ++i) { + rect.fLeft = std::min(rect.fLeft, points[i].fX); + rect.fRight = std::max(rect.fRight, points[i].fX + 1); + rect.fTop = std::min(rect.fTop, points[i].fY); + rect.fBottom = std::max(rect.fBottom, points[i].fY + 1); + } + + bool opaque = paintIsOpaque(paint); + bool fillsBounds = false; + + if (!paint.canComputeFastBounds()) + didDrawUnbounded(paint, opaque); + else { + rect = paint.computeFastBounds(rect, &rect); + didDraw(context, rect, paint, opaque, fillsBounds); + } +} + +void OpaqueRegionSkia::didDrawBounded(const PlatformContextSkia* context, const SkRect& bounds, const SkPaint& paint) +{ + bool opaque = paintIsOpaque(paint); + bool fillsBounds = false; + + if (!paint.canComputeFastBounds()) + didDrawUnbounded(paint, opaque); + else { + SkRect rect; + rect = paint.computeFastBounds(bounds, &rect); + didDraw(context, rect, paint, opaque, fillsBounds); + } +} + +void OpaqueRegionSkia::didDraw(const PlatformContextSkia* context, const SkRect& rect, const SkPaint& paint, bool drawsOpaque, bool fillsBounds) +{ + if (fillsBounds && xfermodeIsOpaque(paint, drawsOpaque)) + markRectAsOpaque(context, rect); + else if (SkRect::Intersects(rect, m_opaqueRect) && !xfermodePreservesOpaque(paint, drawsOpaque)) + markRectAsNonOpaque(rect); +} + +void OpaqueRegionSkia::didDrawUnbounded(const SkPaint& paint, bool drawsOpaque) +{ + if (!xfermodePreservesOpaque(paint, drawsOpaque)) { + // We don't know what was drawn on so just destroy the known opaque area. + m_opaqueRect = SkRect::MakeEmpty(); + } +} + +void OpaqueRegionSkia::markRectAsOpaque(const PlatformContextSkia* context, const SkRect& rect) +{ + // We want to keep track of an opaque region but bound its complexity at a constant size. + // We keep track of the largest rectangle seen by area. If we can add the new rect to this + // rectangle then we do that, as that is the cheapest way to increase the area returned + // without increasing the complexity. + + if (rect.isEmpty()) + return; + if (!context->clippedToImage().isOpaque()) + return; + if (m_opaqueRect.contains(rect)) + return; + if (rect.contains(m_opaqueRect)) { + m_opaqueRect = rect; + return; + } + + if (rect.fTop <= m_opaqueRect.fTop && rect.fBottom >= m_opaqueRect.fBottom) { + if (rect.fLeft < m_opaqueRect.fLeft && rect.fRight >= m_opaqueRect.fLeft) + m_opaqueRect.fLeft = rect.fLeft; + if (rect.fRight > m_opaqueRect.fRight && rect.fLeft <= m_opaqueRect.fRight) + m_opaqueRect.fRight = rect.fRight; + } else if (rect.fLeft <= m_opaqueRect.fLeft && rect.fRight >= m_opaqueRect.fRight) { + if (rect.fTop < m_opaqueRect.fTop && rect.fBottom >= m_opaqueRect.fTop) + m_opaqueRect.fTop = rect.fTop; + if (rect.fBottom > m_opaqueRect.fBottom && rect.fTop <= m_opaqueRect.fBottom) + m_opaqueRect.fBottom = rect.fBottom; + } + + long opaqueArea = (long)m_opaqueRect.width() * (long)m_opaqueRect.height(); + long area = (long)rect.width() * (long)rect.height(); + if (area > opaqueArea) + m_opaqueRect = rect; +} + +void OpaqueRegionSkia::markRectAsNonOpaque(const SkRect& rect) +{ + // We want to keep as much of the current opaque rectangle as we can, so find the one largest + // rectangle inside m_opaqueRect that does not intersect with |rect|. + + if (rect.contains(m_opaqueRect)) { + m_opaqueRect.setEmpty(); + return; + } + + int deltaLeft = rect.fLeft - m_opaqueRect.fLeft; + int deltaRight = m_opaqueRect.fRight - rect.fRight; + int deltaTop = rect.fTop - m_opaqueRect.fTop; + int deltaBottom = m_opaqueRect.fBottom - rect.fBottom; + + // horizontal is the larger of the two rectangles to the left or to the right of |rect| and inside m_opaqueRect. + // vertical is the larger of the two rectangles above or below |rect| and inside m_opaqueRect. + SkRect horizontal = m_opaqueRect; + if (deltaTop > deltaBottom) + horizontal.fBottom = rect.fTop; + else + horizontal.fTop = rect.fBottom; + SkRect vertical = m_opaqueRect; + if (deltaLeft > deltaRight) + vertical.fRight = rect.fLeft; + else + vertical.fLeft = rect.fRight; + + if ((long)horizontal.width() * (long)horizontal.height() > (long)vertical.width() * (long)vertical.height()) + m_opaqueRect = horizontal; + else + m_opaqueRect = vertical; +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/skia/OpaqueRegionSkia.h b/Source/WebCore/platform/graphics/skia/OpaqueRegionSkia.h new file mode 100644 index 000000000..93f2c5a1b --- /dev/null +++ b/Source/WebCore/platform/graphics/skia/OpaqueRegionSkia.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2012, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef OpaqueRegionSkia_h +#define OpaqueRegionSkia_h + +#include "IntRect.h" + +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkPoint.h" +#include "SkRect.h" + +namespace WebCore { +class PlatformContextSkia; + +// This class is an encapsulation of functionality for PlatformContextSkia, and its methods are mirrored +// there for the outside world. It tracks paints and computes what area will be opaque. +class OpaqueRegionSkia { +public: + OpaqueRegionSkia(); + virtual ~OpaqueRegionSkia(); + + // The resulting opaque region as a single rect. + IntRect asRect() const; + + void didDrawRect(const PlatformContextSkia*, const SkRect&, const SkPaint&, const SkBitmap*); + void didDrawPath(const PlatformContextSkia*, const SkPath&, const SkPaint&); + void didDrawPoints(const PlatformContextSkia*, SkCanvas::PointMode, int numPoints, const SkPoint[], const SkPaint&); + void didDrawBounded(const PlatformContextSkia*, const SkRect&, const SkPaint&); + +private: + void didDraw(const PlatformContextSkia*, const SkRect&, const SkPaint&, bool drawsOpaque, bool fillsBounds); + void didDrawUnbounded(const SkPaint&, bool drawsOpaque); + void markRectAsOpaque(const PlatformContextSkia*, const SkRect&); + void markRectAsNonOpaque(const SkRect&); + + SkRect m_opaqueRect; +}; + +} +#endif // OpaqueRegionSkia_h diff --git a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index a5e18680d..034c3319e 100644 --- a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -179,6 +179,7 @@ SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const // Danger: canvas can be NULL. PlatformContextSkia::PlatformContextSkia(SkCanvas* canvas) : m_canvas(canvas) + , m_trackOpaqueRegion(false) , m_printing(false) , m_deferred(false) , m_drawingToImageBuffer(false) @@ -266,6 +267,11 @@ void PlatformContextSkia::clipPathAntiAliased(const SkPath& clipPath) canvas()->clipPath(clipPath, SkRegion::kIntersect_Op, true); } +const SkBitmap& PlatformContextSkia::clippedToImage() const +{ + return m_state->m_imageBufferClip; +} + void PlatformContextSkia::restore() { if (!m_state->m_imageBufferClip.empty()) { @@ -287,6 +293,7 @@ void PlatformContextSkia::drawRect(SkRect rect) if (fillcolorNotTransparent) { setupPaintForFilling(&paint); canvas()->drawRect(rect, paint); + didDrawRect(rect, paint); } if (m_state->m_strokeStyle != NoStroke @@ -299,12 +306,16 @@ void PlatformContextSkia::drawRect(SkRect rect) SkRect topBorder = { rect.fLeft, rect.fTop, rect.fRight, rect.fTop + 1 }; canvas()->drawRect(topBorder, paint); + didDrawRect(topBorder, paint); SkRect bottomBorder = { rect.fLeft, rect.fBottom - 1, rect.fRight, rect.fBottom }; canvas()->drawRect(bottomBorder, paint); + didDrawRect(bottomBorder, paint); SkRect leftBorder = { rect.fLeft, rect.fTop + 1, rect.fLeft + 1, rect.fBottom - 1 }; canvas()->drawRect(leftBorder, paint); + didDrawRect(leftBorder, paint); SkRect rightBorder = { rect.fRight - 1, rect.fTop + 1, rect.fRight, rect.fBottom - 1 }; canvas()->drawRect(rightBorder, paint); + didDrawRect(rightBorder, paint); } } @@ -539,6 +550,7 @@ void PlatformContextSkia::paintSkPaint(const SkRect& rect, const SkPaint& paint) { m_canvas->drawRect(rect, paint); + didDrawRect(rect, paint); } const SkBitmap* PlatformContextSkia::bitmap() const @@ -597,4 +609,28 @@ void PlatformContextSkia::setGraphicsContext3D(GraphicsContext3D* context) m_gpuContext = context; } +void PlatformContextSkia::didDrawRect(const SkRect& rect, const SkPaint& paint, const SkBitmap* bitmap) +{ + if (m_trackOpaqueRegion) + m_opaqueRegion.didDrawRect(this, rect, paint, bitmap); +} + +void PlatformContextSkia::didDrawPath(const SkPath& path, const SkPaint& paint) +{ + if (m_trackOpaqueRegion) + m_opaqueRegion.didDrawPath(this, path, paint); +} + +void PlatformContextSkia::didDrawPoints(SkCanvas::PointMode mode, int numPoints, const SkPoint points[], const SkPaint& paint) +{ + if (m_trackOpaqueRegion) + m_opaqueRegion.didDrawPoints(this, mode, numPoints, points, paint); +} + +void PlatformContextSkia::didDrawBounded(const SkRect& rect, const SkPaint& paint) +{ + if (m_trackOpaqueRegion) + m_opaqueRegion.didDrawBounded(this, rect, paint); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h index 7dcfbe2e3..fe3abb6f5 100644 --- a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h +++ b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h @@ -33,6 +33,7 @@ #include "GraphicsContext.h" #include "Noncopyable.h" +#include "OpaqueRegionSkia.h" #include "SkCanvas.h" #include "SkDashPathEffect.h" @@ -98,6 +99,8 @@ public: // NOTE: |imageBuffer| may be deleted before the |restore| is invoked. void beginLayerClippedToImage(const FloatRect&, const ImageBuffer*); void clipPathAntiAliased(const SkPath&); + // If non-empty, the layer is clipped to the bitmap. + const SkBitmap& clippedToImage() const; // Sets up the common flags on a paint for antialiasing, effects, etc. // This is implicitly called by setupPaintFill and setupPaintStroke, but @@ -187,6 +190,18 @@ public: bool isDeferred() const { return m_deferred; } void setDeferred(bool deferred) { m_deferred = deferred; } + void setTrackOpaqueRegion(bool track) { m_trackOpaqueRegion = track; } + + // This will be an empty region unless tracking is enabled. + const OpaqueRegionSkia& opaqueRegion() const { return m_opaqueRegion; } + + // After drawing in the context's canvas, use these functions to notify the context so it can track the opaque region. + void didDrawRect(const SkRect&, const SkPaint&, const SkBitmap* = 0); + void didDrawPath(const SkPath&, const SkPaint&); + void didDrawPoints(SkCanvas::PointMode, int numPoints, const SkPoint[], const SkPaint&); + // For drawing operations that do not fill the entire rect. + void didDrawBounded(const SkRect&, const SkPaint&); + private: // Used when restoring and the state has an image clip. Only shows the pixels in // m_canvas that are also in imageBuffer. @@ -210,6 +225,10 @@ private: // mStateStack.back(). State* m_state; + // Tracks the region painted opaque via the GraphicsContext. + OpaqueRegionSkia m_opaqueRegion; + bool m_trackOpaqueRegion; + // Stores image sizes for a hint to compute image resampling modes. // Values are used in ImageSkia.cpp IntSize m_imageResamplingHintSrcSize; diff --git a/Source/WebCore/platform/graphics/harfbuzz/SimpleFontDataSkia.cpp b/Source/WebCore/platform/graphics/skia/SimpleFontDataSkia.cpp index 782b02fa9..782b02fa9 100644 --- a/Source/WebCore/platform/graphics/harfbuzz/SimpleFontDataSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/SimpleFontDataSkia.cpp diff --git a/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp b/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp index 8bed35454..1087cd0cb 100644 --- a/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp +++ b/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp @@ -205,12 +205,24 @@ static void setupPaintForFont(SkPaint* paint, PlatformContextSkia* pcs, textFlags &= getDefaultGDITextFlags(); // do this check after our switch on lfQuality - if (disableTextLCD(pcs)) + if (disableTextLCD(pcs)) { textFlags &= ~SkPaint::kLCDRenderText_Flag; + // If we *just* clear our request for LCD, then GDI seems to + // sometimes give us AA text, and sometimes give us BW text. Since the + // original intent was LCD, we want to force AA (rather than BW), so we + // add a special bit to tell Skia to do its best to avoid the BW: by + // drawing LCD offscreen and downsampling that to AA. + textFlags |= SkPaint::kGenA8FromLCD_Flag; + } + + static const uint32_t textFlagsMask = SkPaint::kAntiAlias_Flag | + SkPaint::kLCDRenderText_Flag | + SkPaint::kGenA8FromLCD_Flag; // now copy in just the text flags + SkASSERT(!(textFlags & ~textFlagsMask)); uint32_t flags = paint->getFlags(); - flags &= ~(SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag); + flags &= ~textFlagsMask; flags |= textFlags; paint->setFlags(flags); } diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp index 7ef9818ed..b521d1a21 100644 --- a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp +++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp @@ -365,59 +365,26 @@ bool GraphicsLayerTextureMapper::addAnimation(const KeyframeValueList& valueList if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2 || (valueList.property() != AnimatedPropertyWebkitTransform && valueList.property() != AnimatedPropertyOpacity)) return false; - for (size_t i = 0; i < m_animations.size(); ++i) { - // The same animation name can be used for two animations with different properties. - if (m_animations[i]->name != keyframesName || m_animations[i]->keyframes.property() != valueList.property()) - continue; - - // We already have a copy of this animation, that means that we're resuming it rather than adding it. - RefPtr<TextureMapperAnimation>& animation = m_animations[i]; - animation->animation = Animation::create(anim); - animation->paused = false; - animation->startTime = WTF::currentTime() - timeOffset; - notifyChange(TextureMapperNode::AnimationChange); - m_animationStartedTimer.startOneShot(0); - return true; - } + bool listsMatch = false; + bool hasBigRotation; - RefPtr<TextureMapperAnimation> animation = TextureMapperAnimation::create(valueList); - animation->boxSize = boxSize; - animation->name = keyframesName; - animation->animation = Animation::create(anim); - animation->paused = false; - animation->startTime = WTF::currentTime() - timeOffset; - - if (valueList.property() == AnimatedPropertyWebkitTransform) { - bool hasBigRotation; // Not used, but required as a pointer parameter for the function. - fetchTransformOperationList(valueList, animation->functionList, animation->listsMatch, hasBigRotation); - } + if (valueList.property() == AnimatedPropertyWebkitTransform) + listsMatch = validateTransformOperations(valueList, hasBigRotation) >= 0; - m_animations.append(animation); + m_animations.add(keyframesName, TextureMapperAnimation(valueList, boxSize, anim, timeOffset, listsMatch)); notifyChange(TextureMapperNode::AnimationChange); m_animationStartedTimer.startOneShot(0); - return true; } void GraphicsLayerTextureMapper::pauseAnimation(const String& animationName, double timeOffset) { - for (size_t i = 0; i < m_animations.size(); ++i) { - if (m_animations[i]->name != animationName) - continue; - m_animations[i]->paused = true; - notifyChange(TextureMapperNode::AnimationChange); - } + m_animations.pause(animationName, timeOffset); } void GraphicsLayerTextureMapper::removeAnimation(const String& animationName) { - for (int i = m_animations.size() - 1; i >= 0; --i) { - // The same animation name can be used for two animations with different properties. We should remove both. - if (m_animations[i]->name != animationName) - continue; - m_animations.remove(i); - notifyChange(TextureMapperNode::AnimationChange); - } + m_animations.remove(animationName); } void GraphicsLayerTextureMapper::animationStartedTimerFired(Timer<GraphicsLayerTextureMapper>*) diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h index ebb9b536d..172fdda24 100644 --- a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h +++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h @@ -95,7 +95,7 @@ private: bool m_syncQueued; int m_changeMask; TextureMapperNode::ContentData m_pendingContent; - Vector<RefPtr<TextureMapperAnimation> > m_animations; + TextureMapperAnimations m_animations; void animationStartedTimerFired(Timer<GraphicsLayerTextureMapper>*); Timer<GraphicsLayerTextureMapper> m_animationStartedTimer; }; diff --git a/Source/WebCore/platform/graphics/texmap/LayerTransform.cpp b/Source/WebCore/platform/graphics/texmap/LayerTransform.cpp new file mode 100644 index 000000000..1c3c02e57 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/LayerTransform.cpp @@ -0,0 +1,116 @@ +/* + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "LayerTransform.h" + +namespace WebCore { + +LayerTransform::LayerTransform() +: m_flattening(false) +, m_dirty(false) // false by default since all default values would be combined as the identity matrix +, m_childrenDirty(false) +{ +} + +void LayerTransform::setPosition(const FloatPoint& position) +{ + m_position = position; + m_dirty = true; +} + +void LayerTransform::setSize(const FloatSize& size) +{ + m_size = size; + m_dirty = true; +} + +void LayerTransform::setAnchorPoint(const FloatPoint3D& anchorPoint) +{ + m_anchorPoint = anchorPoint; + m_dirty = true; +} + +void LayerTransform::setFlattening(bool flattening) +{ + m_flattening = flattening; + m_dirty = true; +} + +void LayerTransform::setLocalTransform(const TransformationMatrix& transform) +{ + m_local = transform; + m_dirty = true; +} + +void LayerTransform::setChildrenTransform(const TransformationMatrix& transform) +{ + m_children = transform; + m_dirty = true; +} + +TransformationMatrix LayerTransform::combined() +{ + ASSERT(!m_dirty); + return m_combined; +} + +TransformationMatrix LayerTransform::combinedForChildren() +{ + ASSERT(!m_dirty); + if (m_childrenDirty) + combineTransformsForChildren(); + return m_combinedForChildren; +} + +void LayerTransform::combineTransforms(const TransformationMatrix& parentTransform) +{ + float originX = m_anchorPoint.x() * m_size.width(); + float originY = m_anchorPoint.y() * m_size.height(); + m_combined = + TransformationMatrix(parentTransform) + .translate3d(originX + m_position.x(), originY + m_position.y(), m_anchorPoint.z() ) + .multiply(m_local); + + // The children transform will take it from here, if it gets used. + m_combinedForChildren = m_combined; + m_combined.translate3d(-originX, -originY, -m_anchorPoint.z()); + + m_dirty = false; + m_childrenDirty = true; +} + +void LayerTransform::combineTransformsForChildren() +{ + ASSERT(!m_dirty); + ASSERT(m_childrenDirty); + + float originX = m_anchorPoint.x() * m_size.width(); + float originY = m_anchorPoint.y() * m_size.height(); + + // In case a parent had preserves3D and this layer has not, flatten our children. + if (m_flattening) + m_combinedForChildren = m_combinedForChildren.to2dTransform(); + m_combinedForChildren.multiply(m_children); + m_combinedForChildren.translate3d(-originX, -originY, -m_anchorPoint.z()); + + m_childrenDirty = false; +} + +} diff --git a/Source/WebCore/platform/graphics/texmap/LayerTransform.h b/Source/WebCore/platform/graphics/texmap/LayerTransform.h new file mode 100644 index 000000000..b73818501 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/LayerTransform.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef LayerTransform_h +#define LayerTransform_h + +#include "FloatPoint.h" +#include "FloatPoint3D.h" +#include "FloatSize.h" +#include "TransformationMatrix.h" + +namespace WebCore { + +class LayerTransform { +public: + LayerTransform(); + void setPosition(const FloatPoint&); + void setSize(const FloatSize&); + void setAnchorPoint(const FloatPoint3D&); + void setFlattening(bool); + void setLocalTransform(const TransformationMatrix&); + void setChildrenTransform(const TransformationMatrix&); + TransformationMatrix combined(); + TransformationMatrix combinedForChildren(); + + void combineTransforms(const TransformationMatrix& parentTransform); + +private: + void combineTransformsForChildren(); + + FloatPoint3D m_anchorPoint; + FloatPoint m_position; + FloatSize m_size; + bool m_flattening; + bool m_dirty; + bool m_childrenDirty; + + TransformationMatrix m_local; + TransformationMatrix m_children; + TransformationMatrix m_combined; + TransformationMatrix m_combinedForChildren; +}; + +} + +#endif // LayerTransform_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp index 2622d21ca..dd33f0d2a 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp @@ -26,18 +26,20 @@ namespace WebCore { PassRefPtr<BitmapTexture> TextureMapper::acquireTextureFromPool(const IntSize& size) { - if (m_texturePool.isEmpty()) { - RefPtr<BitmapTexture> selectedTexture = createTexture(); - selectedTexture->reset(size, false); - selectedTexture->lock(); - return selectedTexture; - } + RefPtr<BitmapTexture> selectedTexture; - size_t index = 0; - RefPtr<BitmapTexture> selectedTexture = m_texturePool[0]; + for (size_t i = 0; i < m_texturePool.size(); ++i) { + RefPtr<BitmapTexture>& texture = m_texturePool[i]; - for (size_t i = 1; i < m_texturePool.size(); ++i) { - RefPtr<BitmapTexture> texture = m_texturePool[i]; + // If the surface has only one reference (the one in m_texturePool), we can safely reuse it. + if (texture->refCount() > 1) + continue; + + // We default to the first available texture. + if (!selectedTexture) { + selectedTexture = texture; + continue; + } IntSize textureSize = texture->size(); IntSize selectedTextureSize = selectedTexture->size(); @@ -58,22 +60,16 @@ PassRefPtr<BitmapTexture> TextureMapper::acquireTextureFromPool(const IntSize& s continue; selectedTexture = texture; - index = i; } - m_texturePool.remove(index); + if (!selectedTexture) { + selectedTexture = createTexture(); + m_texturePool.append(selectedTexture); + } + selectedTexture->reset(size, false); - selectedTexture->lock(); return selectedTexture; } -void TextureMapper::releaseTextureToPool(BitmapTexture* texture) -{ - if (!texture) - return; - m_texturePool.append(texture); - texture->unlock(); -} - } #endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapper.h b/Source/WebCore/platform/graphics/texmap/TextureMapper.h index d81333daa..d66fe2fb4 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapper.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapper.h @@ -71,6 +71,7 @@ public: // For performance reasons, BitmapTexture might modify the bits directly (swizzle). // Thus, this method is only recommended for buffer update, such as used by WebKit2. virtual void updateContents(PixelFormat, const IntRect&, void* bits) = 0; + virtual void updateRawContents(const IntRect&, const void* bits) { } virtual PlatformGraphicsContext* beginPaintMedia() { return beginPaint(IntRect(0, 0, size().width(), size().height())); @@ -126,7 +127,7 @@ public: virtual void beginPainting() { } virtual void endPainting() { } - virtual void releaseTextureToPool(BitmapTexture* surface); + // A surface is released implicitly when dereferenced. virtual PassRefPtr<BitmapTexture> acquireTextureFromPool(const IntSize&); diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperAnimation.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperAnimation.cpp new file mode 100644 index 000000000..09714d909 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperAnimation.cpp @@ -0,0 +1,255 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "TextureMapperAnimation.h" + +#include "CurrentTime.h" +#include "UnitBezier.h" + +#if USE(TEXTURE_MAPPER) +namespace WebCore { + +static double normalizedAnimationValue(double runningTime, double duration, bool alternate) +{ + if (!duration) + return 0; + + const int loopCount = runningTime / duration; + const double lastFullLoop = duration * double(loopCount); + const double remainder = runningTime - lastFullLoop; + const double normalized = remainder / duration; + return (loopCount % 2 && alternate) ? (1 - normalized) : normalized; +} + +static float applyOpacityAnimation(float fromOpacity, float toOpacity, double progress) +{ + // Optimization: special case the edge values (0 and 1). + if (progress == 1.0) + return toOpacity; + + if (!progress) + return fromOpacity; + + return fromOpacity + progress * (toOpacity - fromOpacity); +} + +static inline double solveEpsilon(double duration) +{ + return 1.0 / (200.0 * duration); +} + +static inline double solveCubicBezierFunction(double p1x, double p1y, double p2x, double p2y, double t, double duration) +{ + return UnitBezier(p1x, p1y, p2x, p2y).solve(t, solveEpsilon(duration)); +} + +static inline double solveStepsFunction(int numSteps, bool stepAtStart, double t) +{ + if (stepAtStart) + return std::min(1.0, (floor(numSteps * t) + 1) / numSteps); + return floor(numSteps * t) / numSteps; +} + +static inline float applyTimingFunction(const TimingFunction* timingFunction, float progress, double duration) +{ + if (!timingFunction) + return progress; + + if (timingFunction->isCubicBezierTimingFunction()) { + const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(timingFunction); + return solveCubicBezierFunction(ctf->x1(), ctf->y1(), ctf->x2(), ctf->y2(), progress, duration); + } + + if (timingFunction->isStepsTimingFunction()) { + const StepsTimingFunction* stf = static_cast<const StepsTimingFunction*>(timingFunction); + return solveStepsFunction(stf->numberOfSteps(), stf->stepAtStart(), double(progress)); + } + + return progress; +} + +static TransformationMatrix applyTransformAnimation(const TransformOperations* from, const TransformOperations* to, double progress, const IntSize& boxSize, bool listsMatch) +{ + TransformationMatrix matrix; + + // First frame of an animation. + if (!progress) { + from->apply(boxSize, matrix); + return matrix; + } + + // Last frame of an animation. + if (progress == 1) { + to->apply(boxSize, matrix); + return matrix; + } + + // If we have incompatible operation lists, we blend the resulting matrices. + if (!listsMatch) { + TransformationMatrix fromMatrix; + to->apply(boxSize, matrix); + from->apply(boxSize, fromMatrix); + matrix.blend(fromMatrix, progress); + return matrix; + } + + // Animation to "-webkit-transform: none". + if (!to->size()) { + TransformOperations blended(*to); + for (size_t i = 0; i < blended.operations().size(); ++i) + blended.operations()[i]->blend(0, progress, true)->apply(matrix, boxSize); + return matrix; + } + + // Animation from "-webkit-transform: none". + if (!from->size()) { + TransformOperations blended(*from); + for (size_t i = 0; i < blended.operations().size(); ++i) + blended.operations()[i]->blend(0, 1. - progress, true)->apply(matrix, boxSize); + return matrix; + } + + // Normal animation with a matching operation list. + TransformOperations blended(*to); + for (size_t i = 0; i < blended.operations().size(); ++i) + blended.operations()[i]->blend(from->at(i), progress, !from->at(i))->apply(matrix, boxSize); + return matrix; +} + + +TextureMapperAnimation::TextureMapperAnimation(const KeyframeValueList& keyframes, const IntSize& boxSize, const Animation* animation, double timeOffset, bool listsMatch) + : m_keyframes(keyframes) + , m_boxSize(boxSize) + , m_animation(Animation::create(animation)) + , m_listsMatch(listsMatch) + , m_startTime(WTF::currentTime() - timeOffset) + , m_pauseTime(0) + , m_state(PlayingState) +{ +} + +void TextureMapperAnimation::applyInternal(TextureMapperAnimationClient* client, const AnimationValue* from, const AnimationValue* to, float progress) +{ + switch (m_keyframes.property()) { + case AnimatedPropertyOpacity: + client->setOpacity(applyOpacityAnimation((static_cast<const FloatAnimationValue*>(from)->value()), (static_cast<const FloatAnimationValue*>(to)->value()), progress)); + return; + case AnimatedPropertyWebkitTransform: + client->setTransform(applyTransformAnimation(static_cast<const TransformAnimationValue*>(from)->value(), static_cast<const TransformAnimationValue*>(to)->value(), progress, m_boxSize, m_listsMatch)); + return; + default: + ASSERT_NOT_REACHED(); + } +} + +bool TextureMapperAnimation::isActive() const +{ + if (state() != StoppedState) + return true; + + return m_animation->fillsForwards(); +} + +bool TextureMapperAnimations::hasActiveAnimationsOfType(AnimatedPropertyID type) const +{ + HashMap<String, TextureMapperAnimation>::const_iterator end = m_animations.end(); + for (HashMap<String, TextureMapperAnimation>::const_iterator it = m_animations.begin(); it != end; ++it) { + const TextureMapperAnimation& animation = it->second; + if (animation.isActive() && animation.property() == type) + return true; + } + return false; +} + +bool TextureMapperAnimations::hasRunningAnimations() const +{ + HashMap<String, TextureMapperAnimation>::const_iterator end = m_animations.end(); + for (HashMap<String, TextureMapperAnimation>::const_iterator it = m_animations.begin(); it != end; ++it) { + const TextureMapperAnimation& animation = it->second; + if (animation.state() == TextureMapperAnimation::PlayingState) + return true; + } + + return false; +} + +void TextureMapperAnimation::apply(TextureMapperAnimationClient* client) +{ + if (state() == StoppedState) + return; + + double totalRunningTime = m_state == PausedState ? m_pauseTime : WTF::currentTime() - m_startTime; + double normalizedValue = normalizedAnimationValue(totalRunningTime, m_animation->duration(), m_animation->direction()); + + if (m_animation->iterationCount() != Animation::IterationCountInfinite && totalRunningTime >= m_animation->duration() * m_animation->iterationCount()) + setState(StoppedState); + + if (!normalizedValue) { + applyInternal(client, m_keyframes.at(0), m_keyframes.at(1), 0); + return; + } + + if (normalizedValue == 1.0) { + applyInternal(client, m_keyframes.at(m_keyframes.size() - 2), m_keyframes.at(m_keyframes.size() - 1), 1); + return; + } + if (m_keyframes.size() == 2) { + normalizedValue = applyTimingFunction(m_animation->timingFunction().get(), normalizedValue, m_animation->duration()); + applyInternal(client, m_keyframes.at(0), m_keyframes.at(1), normalizedValue); + return; + } + + for (size_t i = 0; i < m_keyframes.size() - 1; ++i) { + const AnimationValue* from = m_keyframes.at(i); + const AnimationValue* to = m_keyframes.at(i + 1); + if (from->keyTime() > normalizedValue || to->keyTime() < normalizedValue) + continue; + + normalizedValue = (normalizedValue - from->keyTime()) / (to->keyTime() - from->keyTime()); + normalizedValue = applyTimingFunction(from->timingFunction(), normalizedValue, m_animation->duration()); + applyInternal(client, from, to, normalizedValue); + break; + } +} + +void TextureMapperAnimation::pause(double offset) +{ + // FIXME: should apply offset here. + setState(PausedState); + m_pauseTime = WTF::currentTime() - offset; +} + +void TextureMapperAnimations::pause(const String& name, double offset) +{ + HashMap<String, TextureMapperAnimation>::iterator it = m_animations.find(name); + if (it == m_animations.end()) + return; + it->second.pause(offset); +} + +void TextureMapperAnimations::apply(TextureMapperAnimationClient* client) +{ + HashMap<String, TextureMapperAnimation>::iterator end = m_animations.end(); + for (HashMap<String, TextureMapperAnimation>::iterator it = m_animations.begin(); it != end; ++it) + it->second.apply(client); +} + +} +#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperAnimation.h b/Source/WebCore/platform/graphics/texmap/TextureMapperAnimation.h new file mode 100644 index 000000000..a3f1ca60f --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperAnimation.h @@ -0,0 +1,85 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef TextureMapperAnimation_h +#define TextureMapperAnimation_h + +#include "GraphicsLayer.h" +#include "HashMap.h" +#include "TransformationMatrix.h" +#include <wtf/text/StringHash.h> + +#if USE(TEXTURE_MAPPER) +namespace WebCore { + +class TextureMapperAnimationClient { +public: + virtual void setTransform(const TransformationMatrix&) = 0; + virtual void setOpacity(float) = 0; +}; + +class TextureMapperAnimation { +public: + enum AnimationState { PlayingState, PausedState, StoppedState }; + + TextureMapperAnimation() + : m_keyframes(AnimatedPropertyInvalid) + { } + TextureMapperAnimation(const KeyframeValueList&, const IntSize&, const Animation*, double, bool); + void apply(TextureMapperAnimationClient*); + void pause(double); + AnimationState state() const { return m_state; } + void setState(AnimationState s) { m_state = s; } + AnimatedPropertyID property() const { return m_keyframes.property(); } + bool isActive() const; + +private: + void applyInternal(TextureMapperAnimationClient*, const AnimationValue* from, const AnimationValue* to, float progress); + KeyframeValueList m_keyframes; + IntSize m_boxSize; + RefPtr<Animation> m_animation; + String m_name; + bool m_listsMatch; + bool m_hasBigRotation; + double m_startTime; + double m_pauseTime; + AnimationState m_state; +}; + +class TextureMapperAnimations { +public: + TextureMapperAnimations() { } + + void add(const String& name, const TextureMapperAnimation& animation) { m_animations.add(name, animation); } + void remove(const String& name) { m_animations.remove(name); } + void pause(const String&, double); + void apply(TextureMapperAnimationClient*); + bool isEmpty() const { return m_animations.isEmpty(); } + + bool hasRunningAnimations() const; + bool hasActiveAnimationsOfType(AnimatedPropertyID type) const; + +private: + HashMap<String, TextureMapperAnimation> m_animations; +}; + +} +#endif // USE(TEXTURE_MAPPER) + +#endif // TextureMapperAnimation_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp index 15dff5aeb..ccf49bc98 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp @@ -47,95 +47,37 @@ TextureMapperNode* TextureMapperNode::rootLayer() void TextureMapperNode::setTransform(const TransformationMatrix& matrix) { - if (m_transforms.base == matrix) - return; - - m_transforms.base = matrix; -} - -void TextureMapperNode::computePerspectiveTransformIfNeeded() -{ - if (m_children.isEmpty() || m_state.childrenTransform.isIdentity()) - return; - - const FloatPoint centerPoint = FloatPoint(m_size.width() / 2, m_size.height() / 2); - m_transforms.perspective = TransformationMatrix() - .translate(centerPoint.x(), centerPoint.y()) - .multiply(m_state.childrenTransform) - .translate(-centerPoint.x(), -centerPoint.y()); -} - -int TextureMapperNode::countDescendantsWithContent() const -{ - if (!m_state.visible || (!m_size.width() && !m_size.height() && m_state.masksToBounds)) - return 0; - int count = (m_size.width() && m_size.height() && (m_state.drawsContent || m_currentContent.contentType != HTMLContentType)) ? 1 : 0; - for (size_t i = 0; i < m_children.size(); ++i) - count += m_children[i]->countDescendantsWithContent(); - - return count; + m_transform.setLocalTransform(matrix); } -void TextureMapperNode::computeOverlapsIfNeeded() -{ - m_state.mightHaveOverlaps = countDescendantsWithContent() > 1; -} - -void TextureMapperNode::computeReplicaTransformIfNeeded() -{ - if (!m_state.replicaLayer) - return; - - m_transforms.replica = - TransformationMatrix(m_transforms.target) - .multiply(m_state.replicaLayer->m_transforms.local) - .multiply(TransformationMatrix(m_transforms.target).inverse()); -} - -void TextureMapperNode::computeLocalTransformIfNeeded() -{ - float originX = m_state.anchorPoint.x() * m_size.width(); - float originY = m_state.anchorPoint.y() * m_size.height(); - m_transforms.local = - TransformationMatrix() - .translate3d(originX + m_state.pos.x(), originY + m_state.pos.y(), m_state.anchorPoint.z() ) - .multiply(m_transforms.base) - .translate3d(-originX, -originY, -m_state.anchorPoint.z()); -} - -void TextureMapperNode::computeAllTransforms() +void TextureMapperNode::computeTransformsRecursive() { if (m_size.isEmpty() && m_state.masksToBounds) return; - computeLocalTransformIfNeeded(); - computeReplicaTransformIfNeeded(); - computePerspectiveTransformIfNeeded(); - - m_transforms.target = TransformationMatrix(m_parent ? m_parent->m_transforms.forDescendants : TransformationMatrix()).multiply(m_transforms.local); + // Compute transforms recursively on the way down to leafs. + TransformationMatrix parentTransform; + if (m_parent) + parentTransform = m_parent->m_transform.combinedForChildren(); + else if (m_effectTarget) + parentTransform = m_effectTarget->m_transform.combined(); + m_transform.combineTransforms(parentTransform); - m_state.visible = m_state.backfaceVisibility || m_transforms.target.inverse().m33() >= 0; - if (!m_state.visible) - return; + m_state.visible = m_state.backfaceVisibility || m_transform.combined().inverse().m33() >= 0; - // This transform is only applied if using a two-pass for the replica, because the transform needs to be adjusted to the size of the intermediate surface, insteaf of the size of the content layer. if (m_parent && m_parent->m_state.preserves3D) - m_transforms.centerZ = m_transforms.target.mapPoint(FloatPoint3D(m_size.width() / 2, m_size.height() / 2, 0)).z(); - - if (!m_children.size()) - return; - - m_transforms.forDescendants = m_transforms.target; + m_centerZ = m_transform.combined().mapPoint(FloatPoint3D(m_size.width() / 2, m_size.height() / 2, 0)).z(); - if (!m_state.preserves3D) { - m_transforms.forDescendants = TransformationMatrix( - m_transforms.forDescendants.m11(), m_transforms.forDescendants.m12(), 0, m_transforms.forDescendants.m14(), - m_transforms.forDescendants.m21(), m_transforms.forDescendants.m22(), 0, m_transforms.forDescendants.m24(), - 0, 0, 1, 0, - m_transforms.forDescendants.m41(), m_transforms.forDescendants.m42(), 0, m_transforms.forDescendants.m44()); - } + if (m_state.maskLayer) + m_state.maskLayer->computeTransformsRecursive(); + if (m_state.replicaLayer) + m_state.replicaLayer->computeTransformsRecursive(); + for (int i = 0; i < m_children.size(); ++i) + m_children[i]->computeTransformsRecursive(); - m_transforms.forDescendants.multiply(m_transforms.perspective); + // Reorder children if needed on the way back up. + if (m_state.preserves3D) + sortByZOrder(m_children, 0, m_children.size()); } void TextureMapperNode::computeTiles() @@ -158,9 +100,6 @@ void TextureMapperNode::computeTiles() for (float x = 0; x < contentRect.width(); x += gTileDimension) { FloatRect tileRect(x, y, gTileDimension, gTileDimension); tileRect.intersect(contentRect); - FloatRect tileRectInRootCoordinates = tileRect; - tileRectInRootCoordinates.scale(1.0); - tileRectInRootCoordinates = m_transforms.target.mapRect(tileRectInRootCoordinates); tilesToAdd.append(tileRect); } } @@ -202,52 +141,6 @@ void TextureMapperNode::computeTiles() m_ownedTiles.remove(tilesToRemove[i]); } -#if USE(TILED_BACKING_STORE) -static void clampRect(IntRect& rect, int dimension) -{ - rect.shiftXEdgeTo(rect.x() - rect.x() % dimension); - rect.shiftYEdgeTo(rect.y() - rect.y() % dimension); - rect.shiftMaxXEdgeTo(rect.maxX() - rect.x() % dimension + dimension); - rect.shiftMaxYEdgeTo(rect.maxY() - rect.y() % dimension + dimension); -} - -bool TextureMapperNode::collectVisibleContentsRects(NodeRectMap& rectMap, const FloatRect& rootVisibleRect) -{ - if (!m_state.visible) - return false; - bool exists = false; - - for (int i = 0; i < m_children.size(); ++i) - exists = m_children[i]->collectVisibleContentsRects(rectMap, rootVisibleRect) || exists; - if (m_state.maskLayer) - exists = m_state.maskLayer->collectVisibleContentsRects(rectMap, rootVisibleRect) || exists; - if (m_state.replicaLayer) - exists = m_state.replicaLayer->collectVisibleContentsRects(rectMap, rootVisibleRect) || exists; - - // Non-invertible layers are not visible. - if (!m_transforms.target.isInvertible()) - return exists; - - static const int tilingThreshold = 256; - - IntRect visibleContentsRect(0, 0, m_size.width(), m_size.height()); - if (m_size.width() > tilingThreshold || m_size.height() > tilingThreshold) { - IntRect visibleRectInLocalCoordinates = enclosingIntRect(TransformationMatrix(m_transforms.target).inverse().mapRect(rootVisibleRect)); - if (!visibleRectInLocalCoordinates.isEmpty()) - clampRect(visibleRectInLocalCoordinates, gTileDimension); - visibleContentsRect.intersect(visibleRectInLocalCoordinates); - } - - if (visibleContentsRect.isEmpty() || visibleContentsRect == m_state.visibleRect) - return exists; - - m_state.visibleRect = visibleContentsRect; - rectMap.add(this, m_state.visibleRect); - - return true; -} -#endif - void TextureMapperNode::renderContent(TextureMapper* textureMapper, GraphicsLayer* layer) { #if USE(TILED_BACKING_STORE) @@ -312,6 +205,8 @@ void TextureMapperNode::paint() if (m_size.isEmpty()) return; + computeTransformsRecursive(); + TextureMapperPaintOptions opt; opt.textureMapper = m_textureMapper; opt.textureMapper->bindSurface(0); @@ -332,17 +227,16 @@ void TextureMapperNode::paintSelf(const TextureMapperPaintOptions& options) if (m_size.isEmpty() || (!m_state.drawsContent && m_currentContent.contentType == HTMLContentType)) return; - RefPtr<BitmapTexture> maskTexture; - RefPtr<BitmapTexture> replicaMaskTexture; - - if (m_state.maskLayer) - maskTexture = m_state.maskLayer->texture(); - if (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer) - replicaMaskTexture = m_state.replicaLayer->m_state.maskLayer->texture(); - - float opacity = options.isSurface ? 1 : options.opacity; + float opacity = options.opacity; + BitmapTexture* mask = options.mask; FloatRect targetRect = this->targetRect(); + // We apply the following transform to compensate for painting into a surface, and then apply the offset so that the painting fits in the target rect. + TransformationMatrix transform = + TransformationMatrix(options.transform) + .multiply(m_transform.combined()) + .translate(options.offset.width(), options.offset.height()); + #if USE(TILED_BACKING_STORE) Vector<ExternallyManagedTile> tilesToPaint; @@ -364,20 +258,11 @@ void TextureMapperNode::paintSelf(const TextureMapperPaintOptions& options) tiles.prepend(&it->second); } - TransformationMatrix replicaMatrix; for (int i = 0; i < tiles.size(); ++i) { ExternallyManagedTile& tile = *tiles[i]; FloatRect rect = tile.frontBuffer.targetRect; - - float replicaOpacity = 1.0; - if (m_state.replicaLayer) { - replicaMatrix = TransformationMatrix(m_transforms.target).scale(1.0 / tile.scale).multiply(m_state.replicaLayer->m_transforms.local); - replicaOpacity = opacity * m_state.replicaLayer->m_opacity; - } BitmapTexture& texture = *tile.frontBuffer.texture; - if (m_state.replicaLayer) - options.textureMapper->drawTexture(texture, rect, replicaMatrix, replicaOpacity, replicaMaskTexture ? replicaMaskTexture.get() : maskTexture.get()); - options.textureMapper->drawTexture(texture, rect, m_transforms.target, opacity, options.isSurface ? 0 : maskTexture.get()); + options.textureMapper->drawTexture(texture, rect, transform, opacity, mask); } return; } @@ -386,32 +271,19 @@ void TextureMapperNode::paintSelf(const TextureMapperPaintOptions& options) // Now we paint owned tiles, if we're in OwnedTileMode. for (size_t i = 0; i < m_ownedTiles.size(); ++i) { BitmapTexture* texture = m_ownedTiles[i].texture.get(); - if (m_state.replicaLayer && !options.isSurface) { - options.textureMapper->drawTexture(*texture, targetRectForTileRect(targetRect, m_ownedTiles[i].rect), - TransformationMatrix(m_transforms.target).multiply(m_state.replicaLayer->m_transforms.local), - opacity * m_state.replicaLayer->m_opacity, - replicaMaskTexture ? replicaMaskTexture.get() : maskTexture.get()); - } - const FloatRect rect = targetRectForTileRect(targetRect, m_ownedTiles[i].rect); - options.textureMapper->drawTexture(*texture, rect, m_transforms.target, opacity, options.isSurface ? 0 : maskTexture.get()); + options.textureMapper->drawTexture(*texture, rect, transform, opacity, mask); } - if (m_currentContent.contentType == MediaContentType && m_currentContent.media) { - if (m_state.replicaLayer && !options.isSurface) - m_currentContent.media->paintToTextureMapper(options.textureMapper, targetRect, - TransformationMatrix(m_transforms.target).multiply(m_state.replicaLayer->m_transforms.local), - opacity * m_state.replicaLayer->m_opacity, - replicaMaskTexture ? replicaMaskTexture.get() : maskTexture.get()); - m_currentContent.media->paintToTextureMapper(options.textureMapper, targetRect, m_transforms.target, opacity, options.isSurface ? 0 : maskTexture.get()); - } + if (m_currentContent.contentType == MediaContentType && m_currentContent.media) + m_currentContent.media->paintToTextureMapper(options.textureMapper, targetRect, transform, opacity, mask); } int TextureMapperNode::compareGraphicsLayersZValue(const void* a, const void* b) { TextureMapperNode* const* nodeA = static_cast<TextureMapperNode* const*>(a); TextureMapperNode* const* nodeB = static_cast<TextureMapperNode* const*>(b); - return int(((*nodeA)->m_transforms.centerZ - (*nodeB)->m_transforms.centerZ) * 1000); + return int(((*nodeA)->m_centerZ - (*nodeB)->m_centerZ) * 1000); } void TextureMapperNode::sortByZOrder(Vector<TextureMapperNode* >& array, int first, int last) @@ -419,139 +291,138 @@ void TextureMapperNode::sortByZOrder(Vector<TextureMapperNode* >& array, int fir qsort(array.data(), array.size(), sizeof(TextureMapperNode*), compareGraphicsLayersZValue); } -void TextureMapperNode::paintSelfAndChildren(const TextureMapperPaintOptions& options, TextureMapperPaintOptions& optionsForDescendants) +void TextureMapperNode::paintSelfAndChildren(const TextureMapperPaintOptions& options) { bool hasClip = m_state.masksToBounds && !m_children.isEmpty(); if (hasClip) - options.textureMapper->beginClip(m_transforms.forDescendants, FloatRect(0, 0, m_size.width(), m_size.height())); + options.textureMapper->beginClip(TransformationMatrix(options.transform).multiply(m_transform.combined()), FloatRect(0, 0, m_size.width(), m_size.height())); paintSelf(options); for (int i = 0; i < m_children.size(); ++i) - m_children[i]->paintRecursive(optionsForDescendants); + m_children[i]->paintRecursive(options); if (hasClip) options.textureMapper->endClip(); } -bool TextureMapperNode::paintReflection(const TextureMapperPaintOptions& options, BitmapTexture* contentSurface) +IntRect TextureMapperNode::intermediateSurfaceRect() { - if (!m_state.replicaLayer) - return false; + // FIXME: Add an inverse transform to LayerTransform. + return intermediateSurfaceRect(m_transform.combined().inverse()); +} - RefPtr<BitmapTexture> surface(contentSurface); - RefPtr<BitmapTexture> maskSurface; - RefPtr<BitmapTexture> replicaMaskSurface; - RefPtr<BitmapTexture> replicaMaskTexture; - - if (TextureMapperNode* replicaMask = m_state.replicaLayer->m_state.maskLayer) - replicaMaskTexture = replicaMask->texture(); - - RefPtr<BitmapTexture> maskTexture; - if (TextureMapperNode* mask = m_state.maskLayer) - maskTexture = mask->texture(); - - const IntSize viewportSize = options.textureMapper->viewportSize(); - const bool useIntermediateBufferForReplica = m_state.replicaLayer && options.opacity < 0.99; - const bool useIntermediateBufferForMask = maskTexture && replicaMaskTexture; - const FloatRect viewportRect(0, 0, viewportSize.width(), viewportSize.height()); - - // The mask has to be adjusted to target coordinates. - if (maskTexture) { - maskSurface = options.textureMapper->acquireTextureFromPool(options.textureMapper->viewportSize()); - options.textureMapper->bindSurface(maskSurface.get()); - options.textureMapper->drawTexture(*maskTexture.get(), entireRect(), m_transforms.target, 1, 0); - maskTexture = maskSurface; +IntRect TextureMapperNode::intermediateSurfaceRect(const TransformationMatrix& matrix) +{ + IntRect rect; + TransformationMatrix localTransform = TransformationMatrix(matrix).multiply(m_transform.combined()); + rect = enclosingIntRect(localTransform.mapRect(entireRect())); + if (!m_state.masksToBounds && !m_state.maskLayer) { + for (int i = 0; i < m_children.size(); ++i) + rect.unite(m_children[i]->intermediateSurfaceRect(matrix)); } - // The replica's mask has to be adjusted to target coordinates. - if (replicaMaskTexture) { - replicaMaskSurface = options.textureMapper->acquireTextureFromPool(options.textureMapper->viewportSize()); - options.textureMapper->bindSurface(replicaMaskSurface.get()); - options.textureMapper->drawTexture(*replicaMaskTexture.get(), entireRect(), m_transforms.target, 1, 0); - replicaMaskTexture = replicaMaskSurface; - } + if (m_state.replicaLayer) + rect.unite(m_state.replicaLayer->intermediateSurfaceRect(matrix)); - // We might need to apply the mask of the content layer before we draw the reflection, as there might be yet another mask for the reflection itself. - if (useIntermediateBufferForMask) { - RefPtr<BitmapTexture> maskSurface = options.textureMapper->acquireTextureFromPool(options.textureMapper->viewportSize()); - options.textureMapper->bindSurface(maskSurface.get()); - options.textureMapper->drawTexture(*surface.get(), viewportRect, TransformationMatrix(), 1, maskTexture.get()); - options.textureMapper->releaseTextureToPool(surface.get()); - surface = maskSurface; - maskTexture.clear(); - } + return rect; +} - // We blend the layer and its replica in an intermediate buffer before blending into the target surface. - if (useIntermediateBufferForReplica) { - RefPtr<BitmapTexture> replicaSurface = options.textureMapper->acquireTextureFromPool(options.textureMapper->viewportSize()); - options.textureMapper->bindSurface(replicaSurface.get()); - options.textureMapper->drawTexture(*surface.get(), viewportRect, m_transforms.replica, m_state.replicaLayer->m_opacity, replicaMaskTexture.get()); - options.textureMapper->drawTexture(*surface.get(), viewportRect, TransformationMatrix(), 1, maskTexture.get()); - options.textureMapper->releaseTextureToPool(surface.get()); - surface = replicaSurface; - } +bool TextureMapperNode::shouldPaintToIntermediateSurface() const +{ + bool hasOpacity = m_opacity < 0.99; + bool hasChildren = !m_children.isEmpty(); + bool hasReplica = !!m_state.replicaLayer; + bool hasMask = !!m_state.maskLayer; - options.textureMapper->bindSurface(options.surface); + // We don't use two-pass blending for preserves-3d, that's in sync with Safari. + if (m_state.preserves3D) + return false; - // Draw the reflection. - if (!useIntermediateBufferForReplica) - options.textureMapper->drawTexture(*surface.get(), viewportRect, m_transforms.replica, m_state.replicaLayer->m_opacity, replicaMaskTexture.get()); + // We should use an intermediate surface when blending several items with an ancestor opacity. + // Tested by compositing/reflections/reflection-opacity.html + if (hasOpacity && (hasChildren || hasReplica)) + return true; - // Draw the original. - options.textureMapper->drawTexture(*surface.get(), viewportRect, TransformationMatrix(), options.opacity, maskTexture.get()); + // We should use an intermediate surface with a masked ancestor. + // In the case of replicas the mask is applied before replicating. + // Tested by compositing/masks/masked-ancestor.html + if (hasMask && hasChildren && !hasReplica) + return true; - options.textureMapper->releaseTextureToPool(maskSurface.get()); - options.textureMapper->releaseTextureToPool(replicaMaskSurface.get()); + return false; +} +bool TextureMapperNode::isVisible() const +{ + if (m_size.isEmpty() && (m_state.masksToBounds || m_state.maskLayer || m_children.isEmpty())) + return false; + if (!m_state.visible || m_opacity < 0.01) + return false; return true; } -void TextureMapperNode::paintRecursive(TextureMapperPaintOptions options) +void TextureMapperNode::paintSelfAndChildrenWithReplica(const TextureMapperPaintOptions& options) { - if ((m_size.isEmpty() && (m_state.masksToBounds - || m_children.isEmpty())) || !m_state.visible || options.opacity < 0.01 || m_opacity < 0.01) - return; + if (m_state.replicaLayer) { + TextureMapperPaintOptions replicaOptions(options); + // We choose either the content's mask or the replica's mask. + // FIXME: blend the two if both exist. + if (m_state.replicaLayer->m_state.maskLayer) + replicaOptions.mask = m_state.replicaLayer->m_state.maskLayer->texture(); - options.opacity *= m_opacity; - RefPtr<BitmapTexture> surface; - const bool needsTwoPass = ((m_state.replicaLayer || m_state.maskLayer) && !m_children.isEmpty()) || (m_opacity < 0.99 && m_state.mightHaveOverlaps) || (m_opacity < 0.99 && m_state.replicaLayer); - const IntSize viewportSize = options.textureMapper->viewportSize(); - options.isSurface = false; + replicaOptions.transform + .multiply(m_state.replicaLayer->m_transform.combined()) + .multiply(m_transform.combined().inverse()); + paintSelfAndChildren(replicaOptions); + } - TextureMapperPaintOptions optionsForDescendants(options); + paintSelfAndChildren(options); +} - if (!needsTwoPass) { - paintSelfAndChildren(options, optionsForDescendants); +void TextureMapperNode::paintRecursive(const TextureMapperPaintOptions& options) +{ + if (!isVisible()) return; - } - FloatRect viewportRect(0, 0, viewportSize.width(), viewportSize.height()); + float opacity = options.opacity * m_opacity; + RefPtr<BitmapTexture> maskTexture = m_state.maskLayer ? m_state.maskLayer->texture() : 0; - RefPtr<BitmapTexture> maskSurface; + TextureMapperPaintOptions paintOptions(options); + paintOptions.mask = maskTexture.get(); + IntRect surfaceRect; - // The mask has to be adjusted to target coordinates. - if (m_state.maskLayer) { - maskSurface = options.textureMapper->acquireTextureFromPool(options.textureMapper->viewportSize()); - options.textureMapper->bindSurface(maskSurface.get()); - options.textureMapper->drawTexture(*m_state.maskLayer->texture(), entireRect(), m_transforms.target, 1.0, 0); + RefPtr<BitmapTexture> surface; + + if (!shouldPaintToIntermediateSurface()) { + paintOptions.opacity = opacity; + paintSelfAndChildrenWithReplica(paintOptions); + return; } - surface = options.textureMapper->acquireTextureFromPool(options.textureMapper->viewportSize()); - optionsForDescendants.surface = surface.get(); - options.isSurface = true; - optionsForDescendants.opacity = 1; + // Prepare a surface to paint into. + // We paint into the surface ignoring the opacity/transform of the current layer. + surfaceRect = intermediateSurfaceRect(); + surface = options.textureMapper->acquireTextureFromPool(surfaceRect.size()); options.textureMapper->bindSurface(surface.get()); + paintOptions.opacity = 1; - paintSelfAndChildren(options, optionsForDescendants); + // We have to use combinedForChildren() and not combined(), otherwise preserve-3D doesn't work. + paintOptions.transform = m_transform.combinedForChildren().inverse(); + paintOptions.offset = -IntSize(surfaceRect.x(), surfaceRect.y()); - if (!paintReflection(options, surface.get())) { - options.textureMapper->bindSurface(options.surface); - options.textureMapper->drawTexture(*surface.get(), viewportRect, TransformationMatrix(), options.opacity, 0); - } + paintSelfAndChildrenWithReplica(paintOptions); + + // If we painted the replica, the mask is already applied so we don't need to paint it again. + if (m_state.replicaLayer) + maskTexture = 0; - options.textureMapper->releaseTextureToPool(surface.get()); - options.textureMapper->releaseTextureToPool(maskSurface.get()); + options.textureMapper->bindSurface(options.surface); + TransformationMatrix targetTransform = + TransformationMatrix(options.transform) + .multiply(m_transform.combined()) + .translate(options.offset.width(), options.offset.height()); + options.textureMapper->drawTexture(*surface.get(), surfaceRect, targetTransform, opacity, maskTexture.get()); } TextureMapperNode::~TextureMapperNode() @@ -610,7 +481,7 @@ void TextureMapperNode::clearAllDirectlyCompositedImageTiles() } } -void TextureMapperNode::setContentsTileBackBuffer(int id, const IntRect& sourceRect, const IntRect& targetRect, void* bits, BitmapTexture::PixelFormat format) +void TextureMapperNode::setContentsTileBackBuffer(int id, const IntRect& sourceRect, const IntRect& targetRect, const void* bits) { ASSERT(m_textureMapper); @@ -627,7 +498,7 @@ void TextureMapperNode::setContentsTileBackBuffer(int id, const IntRect& sourceR if (!tile.backBuffer.texture) tile.backBuffer.texture = m_textureMapper->createTexture(); tile.backBuffer.texture->reset(sourceRect.size(), false); - tile.backBuffer.texture->updateContents(format, sourceRect, bits); + tile.backBuffer.texture->updateRawContents(sourceRect, bits); tile.isBackBufferUpdated = true; } @@ -714,11 +585,8 @@ void TextureMapperNode::syncCompositingStateSelf(GraphicsLayerTextureMapper* gra layer->m_effectTarget = this; } - if (changeMask & AnimationChange) { - m_animations.clear(); - for (size_t i = 0; i < graphicsLayer->m_animations.size(); ++i) - m_animations.append(graphicsLayer->m_animations[i]); - } + if (changeMask & AnimationChange) + m_animations = graphicsLayer->m_animations; m_state.maskLayer = toTextureMapperNode(graphicsLayer->maskLayer()); m_state.replicaLayer = toTextureMapperNode(graphicsLayer->replicaLayer()); @@ -735,6 +603,7 @@ void TextureMapperNode::syncCompositingStateSelf(GraphicsLayerTextureMapper* gra m_state.backfaceVisibility = graphicsLayer->backfaceVisibility(); m_state.childrenTransform = graphicsLayer->childrenTransform(); m_state.opacity = graphicsLayer->opacity(); + m_currentContent.contentType = pendingContent.contentType; m_currentContent.image = pendingContent.image; m_currentContent.media = pendingContent.media; @@ -742,18 +611,17 @@ void TextureMapperNode::syncCompositingStateSelf(GraphicsLayerTextureMapper* gra if (!m_currentContent.needsDisplay) m_currentContent.needsDisplayRect.unite(pendingContent.needsDisplayRect); - if (!hasOpacityAnimation()) - m_opacity = m_state.opacity; - if (!hasTransformAnimation()) - m_transforms.base = m_state.transform; + m_transform.setPosition(m_state.pos); + m_transform.setAnchorPoint(m_state.anchorPoint); + m_transform.setSize(m_state.size); + m_transform.setFlattening(!m_state.preserves3D); + m_transform.setChildrenTransform(m_state.childrenTransform); } bool TextureMapperNode::descendantsOrSelfHaveRunningAnimations() const { - for (size_t i = 0; i < m_animations.size(); ++i) { - if (!m_animations[i]->paused) - return true; - } + if (m_animations.hasRunningAnimations()) + return true; for (size_t i = 0; i < m_children.size(); ++i) { if (m_children[i]->descendantsOrSelfHaveRunningAnimations()) @@ -763,199 +631,18 @@ bool TextureMapperNode::descendantsOrSelfHaveRunningAnimations() const return false; } -static double normalizedAnimationValue(double runningTime, double duration, bool alternate) -{ - if (!duration) - return 0; - const int loopCount = runningTime / duration; - const double lastFullLoop = duration * double(loopCount); - const double remainder = runningTime - lastFullLoop; - const double normalized = remainder / duration; - return (loopCount % 2 && alternate) ? (1 - normalized) : normalized; -} - -void TextureMapperNode::applyOpacityAnimation(float fromOpacity, float toOpacity, double progress) -{ - // Optimization: special case the edge values (0 and 1). - if (progress == 1.0) - setOpacity(toOpacity); - else if (!progress) - setOpacity(fromOpacity); - else - setOpacity(fromOpacity + progress * (toOpacity - fromOpacity)); -} - -static inline double solveEpsilon(double duration) -{ - return 1.0 / (200.0 * duration); -} - -static inline double solveCubicBezierFunction(double p1x, double p1y, double p2x, double p2y, double t, double duration) -{ - UnitBezier bezier(p1x, p1y, p2x, p2y); - return bezier.solve(t, solveEpsilon(duration)); -} - -static inline double solveStepsFunction(int numSteps, bool stepAtStart, double t) -{ - if (stepAtStart) - return std::min(1.0, (floor(numSteps * t) + 1) / numSteps); - return floor(numSteps * t) / numSteps; -} - -static inline float applyTimingFunction(const TimingFunction* timingFunction, float progress, double duration) -{ - if (!timingFunction) - return progress; - - if (timingFunction->isCubicBezierTimingFunction()) { - const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(timingFunction); - return solveCubicBezierFunction(ctf->x1(), - ctf->y1(), - ctf->x2(), - ctf->y2(), - progress, duration); - } - - if (timingFunction->isStepsTimingFunction()) { - const StepsTimingFunction* stf = static_cast<const StepsTimingFunction*>(timingFunction); - return solveStepsFunction(stf->numberOfSteps(), stf->stepAtStart(), double(progress)); - } - - return progress; -} - -void TextureMapperNode::applyTransformAnimation(const TextureMapperAnimation& animation, const TransformOperations* from, const TransformOperations* to, double progress) -{ - // Optimization: special case the edge values (0 and 1). - if (progress == 1.0 || !progress) { - TransformationMatrix matrix; - const TransformOperations* ops = progress ? to : from; - ops->apply(animation.boxSize, matrix); - setTransform(matrix); - } - - if (!animation.listsMatch) { - TransformationMatrix toMatrix, fromMatrix; - to->apply(animation.boxSize, toMatrix); - from->apply(animation.boxSize, fromMatrix); - toMatrix.blend(fromMatrix, progress); - setTransform(toMatrix); - return; - } - - TransformationMatrix matrix; - - if (!to->size()) { - const TransformOperations* swap = to; - to = from; - from = swap; - } else if (!from->size()) - progress = 1.0 - progress; - - TransformOperations blended(*to); - for (size_t i = 0; i < animation.functionList.size(); ++i) - blended.operations()[i]->blend(from->at(i), progress, !from->at(i))->apply(matrix, animation.boxSize); - - setTransform(matrix); -} - -void TextureMapperNode::applyAnimationFrame(const TextureMapperAnimation& animation, const AnimationValue* from, const AnimationValue* to, float progress) -{ - switch (animation.keyframes.property()) { - case AnimatedPropertyOpacity: - applyOpacityAnimation((static_cast<const FloatAnimationValue*>(from)->value()), (static_cast<const FloatAnimationValue*>(to)->value()), progress); - return; - case AnimatedPropertyWebkitTransform: - applyTransformAnimation(animation, static_cast<const TransformAnimationValue*>(from)->value(), static_cast<const TransformAnimationValue*>(to)->value(), progress); - return; - default: - ASSERT_NOT_REACHED(); - } -} - -void TextureMapperNode::applyAnimation(const TextureMapperAnimation& animation, double normalizedValue) -{ - // Optimization: special case the edge values (0 and 1). - if (!normalizedValue) { - applyAnimationFrame(animation, animation.keyframes.at(0), animation.keyframes.at(1), 0); - return; - } - if (normalizedValue == 1.0) { - applyAnimationFrame(animation, animation.keyframes.at(animation.keyframes.size() - 2), animation.keyframes.at(animation.keyframes.size() - 1), 1); - return; - } - if (animation.keyframes.size() == 2) { - normalizedValue = applyTimingFunction(animation.animation->timingFunction().get(), normalizedValue, animation.animation->duration()); - applyAnimationFrame(animation, animation.keyframes.at(0), animation.keyframes.at(1), normalizedValue); - return; - } - - for (size_t i = 0; i < animation.keyframes.size() - 1; ++i) { - const AnimationValue* from = animation.keyframes.at(i); - const AnimationValue* to = animation.keyframes.at(i + 1); - if (from->keyTime() > normalizedValue || to->keyTime() < normalizedValue) - continue; - - normalizedValue = (normalizedValue - from->keyTime()) / (to->keyTime() - from->keyTime()); - normalizedValue = applyTimingFunction(from->timingFunction(), normalizedValue, animation.animation->duration()); - applyAnimationFrame(animation, from, to, normalizedValue); - break; - } -} - -bool TextureMapperNode::hasOpacityAnimation() const -{ - for (size_t i = 0; i < m_animations.size(); ++i) { - const TextureMapperAnimation& animation = *m_animations[i].get(); - if (animation.keyframes.property() == AnimatedPropertyOpacity) - return true; - } - return false; -} - -bool TextureMapperNode::hasTransformAnimation() const -{ - for (size_t i = 0; i < m_animations.size(); ++i) { - const TextureMapperAnimation& animation = *m_animations[i].get(); - if (animation.keyframes.property() == AnimatedPropertyWebkitTransform) - return true; - } - return false; -} - -void TextureMapperNode::syncAnimations(GraphicsLayerTextureMapper* layer) +void TextureMapperNode::syncAnimations() { - for (int i = m_animations.size() - 1; i >= 0; --i) { - RefPtr<TextureMapperAnimation> animation = m_animations[i]; - - double totalRunningTime = WTF::currentTime() - animation->startTime; - RefPtr<Animation> anim = animation->animation; - double normalizedValue = normalizedAnimationValue(totalRunningTime, anim->duration(), anim->direction()); - - if (anim->iterationCount() != Animation::IterationCountInfinite && totalRunningTime >= anim->duration() * anim->iterationCount()) { - // We apply an animation that very close to the edge, so that the final frame is applied, oterwise we might get, for example, an opacity of 0.01 which is still visible. - if (anim->fillsForwards()) { - if (animation->keyframes.property() == AnimatedPropertyWebkitTransform) - m_state.transform = m_transforms.base; - else if (animation->keyframes.property() == AnimatedPropertyOpacity) - m_opacity = m_state.opacity; - } - - m_animations.remove(i); - continue; - } - - if (!animation->paused) - applyAnimation(*animation.get(), normalizedValue); - } + m_animations.apply(this); + if (!m_animations.hasActiveAnimationsOfType(AnimatedPropertyWebkitTransform)) + setTransform(m_state.transform); + if (!m_animations.hasActiveAnimationsOfType(AnimatedPropertyOpacity)) + setOpacity(m_state.opacity); } void TextureMapperNode::syncAnimationsRecursively() { - syncAnimations(0); - - computeAllTransforms(); + syncAnimations(); for (int i = m_children.size() - 1; i >= 0; --i) m_children[i]->syncAnimationsRecursively(); @@ -979,11 +666,8 @@ void TextureMapperNode::syncCompositingState(GraphicsLayerTextureMapper* graphic if (m_state.replicaLayer) m_state.replicaLayer->syncCompositingState(toGraphicsLayerTextureMapper(graphicsLayer->replicaLayer()), textureMapper); - syncAnimations(graphicsLayer); - - computeAllTransforms(); + syncAnimations(); computeTiles(); - computeOverlapsIfNeeded(); if (graphicsLayer) renderContent(textureMapper, graphicsLayer); @@ -1003,16 +687,7 @@ void TextureMapperNode::syncCompositingState(GraphicsLayerTextureMapper* graphic for (int i = m_children.size() - 1; i >= 0; --i) m_children[i]->syncCompositingState(0, textureMapper, options); } - - if (m_state.preserves3D) - sortByZOrder(m_children, 0, m_children.size()); } -TextureMapperAnimation::TextureMapperAnimation(const KeyframeValueList& values) - : keyframes(values) -{ } - -} - #endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h index b40cd5d38..fe4b14c73 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h @@ -25,11 +25,11 @@ #include "GraphicsLayer.h" #include "Image.h" #include "IntPointHash.h" +#include "LayerTransform.h" #include "TextureMapper.h" +#include "TextureMapperAnimation.h" #include "Timer.h" #include "TransformOperations.h" -#include "TranslateTransformOperation.h" -#include "UnitBezier.h" #include <wtf/CurrentTime.h> #include <wtf/HashMap.h> #include <wtf/RefCounted.h> @@ -43,34 +43,20 @@ class GraphicsLayerTextureMapper; class TextureMapperPaintOptions { public: BitmapTexture* surface; - TextureMapper* textureMapper; - + BitmapTexture* mask; float opacity; - bool isSurface; + TransformationMatrix transform; + IntSize offset; + TextureMapper* textureMapper; TextureMapperPaintOptions() : surface(0) - , textureMapper(0) + , mask(0) , opacity(1) - , isSurface(false) + , textureMapper(0) { } }; -class TextureMapperAnimation : public RefCounted<TextureMapperAnimation> { -public: - String name; - KeyframeValueList keyframes; - IntSize boxSize; - RefPtr<Animation> animation; - bool paused; - Vector<TransformOperation::OperationType> functionList; - bool listsMatch; - bool hasBigRotation; - double startTime; - TextureMapperAnimation(const KeyframeValueList&); - static PassRefPtr<TextureMapperAnimation> create(const KeyframeValueList& values) { return adoptRef(new TextureMapperAnimation(values)); } -}; - -class TextureMapperNode { +class TextureMapperNode : public TextureMapperAnimationClient { public: // This set of flags help us defer which properties of the layer have been @@ -141,6 +127,7 @@ public: : m_parent(0) , m_effectTarget(0) , m_opacity(1) + , m_centerZ(0) , m_textureMapper(0) { } @@ -161,10 +148,9 @@ public: void setTileOwnership(TileOwnership ownership) { m_state.tileOwnership = ownership; } int createContentsTile(float scale); void removeContentsTile(int id); - void setContentsTileBackBuffer(int id, const IntRect& sourceRect, const IntRect& targetRect, void* bits, BitmapTexture::PixelFormat); + void setContentsTileBackBuffer(int id, const IntRect& sourceRect, const IntRect& targetRect, const void* bits); void setTileBackBufferTextureForDirectlyCompositedImage(int id, const IntRect& sourceRect, const FloatRect& targetRect, BitmapTexture*); void clearAllDirectlyCompositedImageTiles(); - bool collectVisibleContentsRects(NodeRectMap&, const FloatRect&); void purgeNodeTexturesRecursive(); #endif void setID(int id) { m_id = id; } @@ -174,15 +160,12 @@ public: private: TextureMapperNode* rootLayer(); - void computeAllTransforms(); - void computeVisibleRect(const FloatRect& rootVisibleRect); - void computePerspectiveTransformIfNeeded(); - void computeReplicaTransformIfNeeded(); + void computeTransformsRecursive(); void computeOverlapsIfNeeded(); - void computeLocalTransformIfNeeded(); void computeTiles(); + IntRect intermediateSurfaceRect(const TransformationMatrix&); + IntRect intermediateSurfaceRect(); void swapContentsBuffers(); - int countDescendantsWithContent() const; FloatRect targetRectForTileRect(const FloatRect& totalTargetRect, const FloatRect& tileRect) const; void invalidateViewport(const FloatRect&); void notifyChange(ChangeMask); @@ -193,32 +176,17 @@ private: BitmapTexture* texture() { return m_ownedTiles.isEmpty() ? 0 : m_ownedTiles[0].texture.get(); } - void paintRecursive(TextureMapperPaintOptions); - bool paintReflection(const TextureMapperPaintOptions&, BitmapTexture* surface); + void paintRecursive(const TextureMapperPaintOptions&); void paintSelf(const TextureMapperPaintOptions&); - void paintSelfAndChildren(const TextureMapperPaintOptions&, TextureMapperPaintOptions& optionsForDescendants); + void paintSelfAndChildren(const TextureMapperPaintOptions&); + void paintSelfAndChildrenWithReplica(const TextureMapperPaintOptions&); void renderContent(TextureMapper*, GraphicsLayer*); - void syncAnimations(GraphicsLayerTextureMapper*); - void applyAnimation(const TextureMapperAnimation&, double runningTime); - void applyAnimationFrame(const TextureMapperAnimation&, const AnimationValue* from, const AnimationValue* to, float progress); - void applyOpacityAnimation(float fromOpacity, float toOpacity, double); - void applyTransformAnimation(const TextureMapperAnimation&, const TransformOperations* start, const TransformOperations* end, double); - bool hasOpacityAnimation() const; - bool hasTransformAnimation() const; - - struct TransformData { - TransformationMatrix target; - TransformationMatrix replica; - TransformationMatrix forDescendants; - TransformationMatrix local; - TransformationMatrix base; - TransformationMatrix perspective; - float centerZ; - TransformData() { } - }; + void syncAnimations(); + bool isVisible() const; + bool shouldPaintToIntermediateSurface() const; - TransformData m_transforms; + LayerTransform m_transform; inline FloatRect targetRect() const { @@ -274,6 +242,7 @@ private: TextureMapperNode* m_effectTarget; FloatSize m_size; float m_opacity; + float m_centerZ; String m_name; int m_id; @@ -297,7 +266,6 @@ private: bool needsReset: 1; bool mightHaveOverlaps : 1; bool needsRepaint; - IntRect visibleRect; float contentScale; #if USE(TILED_BACKING_STORE) TileOwnership tileOwnership; @@ -325,8 +293,7 @@ private: State m_state; TextureMapper* m_textureMapper; - - Vector<RefPtr<TextureMapperAnimation> > m_animations; + TextureMapperAnimations m_animations; }; diff --git a/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp b/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp index 60c8df3ef..4131ca4c4 100644 --- a/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp +++ b/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp @@ -250,6 +250,22 @@ FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const return FloatPoint(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2)); } +IntSize AffineTransform::mapSize(const IntSize& size) const +{ + double width2 = size.width() * xScale(); + double height2 = size.height() * yScale(); + + return IntSize(lround(width2), lround(height2)); +} + +FloatSize AffineTransform::mapSize(const FloatSize& size) const +{ + double width2 = size.width() * xScale(); + double height2 = size.height() * yScale(); + + return FloatSize(narrowPrecisionToFloat(width2), narrowPrecisionToFloat(height2)); +} + IntRect AffineTransform::mapRect(const IntRect &rect) const { return enclosingIntRect(mapRect(FloatRect(rect))); diff --git a/Source/WebCore/platform/graphics/transforms/AffineTransform.h b/Source/WebCore/platform/graphics/transforms/AffineTransform.h index d3970da29..7d83f592f 100644 --- a/Source/WebCore/platform/graphics/transforms/AffineTransform.h +++ b/Source/WebCore/platform/graphics/transforms/AffineTransform.h @@ -76,6 +76,10 @@ public: FloatPoint mapPoint(const FloatPoint&) const; + IntSize mapSize(const IntSize&) const; + + FloatSize mapSize(const FloatSize&) const; + // Rounds the resulting mapped rectangle out. This is helpful for bounding // box computations but may not be what is wanted in other contexts. IntRect mapRect(const IntRect&) const; diff --git a/Source/WebCore/platform/graphics/win/FontCacheWin.cpp b/Source/WebCore/platform/graphics/win/FontCacheWin.cpp index 3eb7436ee..4d1b2cfd3 100644 --- a/Source/WebCore/platform/graphics/win/FontCacheWin.cpp +++ b/Source/WebCore/platform/graphics/win/FontCacheWin.cpp @@ -30,6 +30,7 @@ #include <winsock2.h> #include "FontCache.h" #include "Font.h" +#include "HWndDC.h" #include "SimpleFontData.h" #include "UnicodeRange.h" #include <mlang.h> @@ -189,7 +190,7 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, cons { UChar character = characters[0]; SimpleFontData* fontData = 0; - HDC hdc = GetDC(0); + HWndDC hdc(0); HFONT primaryFont = font.primaryFont()->fontDataForCharacter(character)->platformData().hfont(); HGDIOBJ oldFont = SelectObject(hdc, primaryFont); HFONT hfont = 0; @@ -292,7 +293,6 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, cons DeleteObject(hfont); } - ReleaseDC(0, hdc); return fontData; } @@ -447,7 +447,7 @@ static int CALLBACK matchImprovingEnumProc(CONST LOGFONT* candidate, CONST TEXTM static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool desiredItalic, int size, bool synthesizeItalic) { - HDC hdc = GetDC(0); + HWndDC hdc(0); LOGFONT logFont; logFont.lfCharSet = DEFAULT_CHARSET; @@ -459,8 +459,6 @@ static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool MatchImprovingProcData matchData(desiredWeight, desiredItalic); EnumFontFamiliesEx(hdc, &logFont, matchImprovingEnumProc, reinterpret_cast<LPARAM>(&matchData), 0); - ReleaseDC(0, hdc); - if (!matchData.m_hasMatched) return 0; @@ -486,13 +484,12 @@ static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool if (!result) return 0; - HDC dc = GetDC(0); + HWndDC dc(0); SaveDC(dc); SelectObject(dc, result); WCHAR actualName[LF_FACESIZE]; GetTextFace(dc, LF_FACESIZE, actualName); RestoreDC(dc, -1); - ReleaseDC(0, dc); if (wcsicmp(matchData.m_chosen.lfFaceName, actualName)) { DeleteObject(result); @@ -534,7 +531,7 @@ static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMET } void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) { - HDC hdc = GetDC(0); + HWndDC hdc(0); LOGFONT logFont; logFont.lfCharSet = DEFAULT_CHARSET; @@ -546,8 +543,6 @@ void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigne TraitsInFamilyProcData procData(familyName); EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0); copyToVector(procData.m_traitsMasks, traitsMasks); - - ReleaseDC(0, hdc); } FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) diff --git a/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp b/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp index d0b37bda3..9860df6a2 100644 --- a/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp +++ b/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp @@ -25,6 +25,7 @@ #include "config.h" #include "FontPlatformData.h" +#include "HWndDC.h" #include "PlatformString.h" #include <wtf/HashMap.h> #include <wtf/RetainPtr.h> @@ -51,7 +52,7 @@ FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool obliq , m_syntheticOblique(oblique) , m_useGDI(useGDI) { - HDC hdc = GetDC(0); + HWndDC hdc(0); SaveDC(hdc); SelectObject(hdc, font); @@ -71,7 +72,6 @@ FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool obliq } RestoreDC(hdc, -1); - ReleaseDC(0, hdc); } #ifndef NDEBUG diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp index e2e0c1027..d8be4f5f3 100644 --- a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp +++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp @@ -107,6 +107,7 @@ private: virtual bool platformCALayerContentsOpaque() const { return false; } virtual bool platformCALayerDrawsContent() const { return false; } virtual void platformCALayerLayerDidDisplay(PlatformLayer*) { } + virtual void platformCALayerDidCreateTiles() { } MediaPlayerPrivateQuickTimeVisualContext* m_parent; }; @@ -302,7 +303,8 @@ void MediaPlayerPrivateQuickTimeVisualContext::setUpCookiesForQuickTime(const St } else cookieURL = movieURL; - InternetSetCookieExW(cookieURL.charactersWithNullTermination(), 0, cookieBuilder.toString().charactersWithNullTermination(), 0, 0); + String string = cookieBuilder.toString(); + InternetSetCookieExW(cookieURL.charactersWithNullTermination(), 0, string.charactersWithNullTermination(), 0, 0); } } diff --git a/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp index 2d8f13e36..ad025b803 100644 --- a/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp +++ b/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp @@ -33,6 +33,7 @@ #include "FontCache.h" #include "FloatRect.h" #include "FontDescription.h" +#include "HWndDC.h" #include "PlatformString.h" #include <ApplicationServices/ApplicationServices.h> #include <WebKitSystemInterface/WebKitSystemInterface.h> @@ -55,7 +56,7 @@ void SimpleFontData::platformInit() m_isSystemFont = false; if (m_platformData.useGDI()) - return initGDIFont(); + return initGDIFont(); CGFontRef font = m_platformData.cgFont(); int iAscent = CGFontGetAscent(font); @@ -68,14 +69,13 @@ void SimpleFontData::platformInit() float fLineGap = scaleEmToUnits(iLineGap, unitsPerEm) * pointSize; if (!isCustomFont()) { - HDC dc = GetDC(0); + HWndDC dc(0); HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); int faceLength = GetTextFace(dc, 0, 0); Vector<WCHAR> faceName(faceLength); GetTextFace(dc, faceLength, faceName.data()); m_isSystemFont = !wcscmp(faceName.data(), L"Lucida Grande"); SelectObject(dc, oldFont); - ReleaseDC(0, dc); fAscent = ascentConsideringMacAscentHack(faceName.data(), fAscent, fDescent); } diff --git a/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp index de6687f5c..983c1bf92 100644 --- a/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp +++ b/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp @@ -33,6 +33,7 @@ #include "FontCache.h" #include "FloatRect.h" #include "FontDescription.h" +#include "HWndDC.h" #include <mlang.h> #include <unicode/uchar.h> #include <unicode/unorm.h> @@ -89,7 +90,7 @@ void SimpleFontData::initGDIFont() return; } - HDC hdc = GetDC(0); + HWndDC hdc(0); HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); OUTLINETEXTMETRIC metrics; GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics); @@ -115,9 +116,6 @@ void SimpleFontData::initGDIFont() m_fontMetrics.setUnitsPerEm(metrics.otmEMSquare); SelectObject(hdc, oldFont); - ReleaseDC(0, hdc); - - return; } void SimpleFontData::platformCharWidthInit() @@ -185,8 +183,8 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con if (!langFontLink) return false; - HDC dc = GetDC(0); - + HWndDC dc(0); + DWORD acpCodePages; langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages); @@ -203,8 +201,6 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con offset += numCharactersProcessed; } - ReleaseDC(0, dc); - return true; } @@ -216,7 +212,7 @@ void SimpleFontData::determinePitch() } // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that. - HDC dc = GetDC(0); + HWndDC dc(0); SaveDC(dc); SelectObject(dc, m_platformData.hfont()); @@ -227,12 +223,11 @@ void SimpleFontData::determinePitch() m_treatAsFixedPitch = ((tm.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0); RestoreDC(dc, -1); - ReleaseDC(0, dc); } FloatRect SimpleFontData::boundsForGDIGlyph(Glyph glyph) const { - HDC hdc = GetDC(0); + HWndDC hdc(0); SetGraphicsMode(hdc, GM_ADVANCED); HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); @@ -241,7 +236,6 @@ FloatRect SimpleFontData::boundsForGDIGlyph(Glyph glyph) const GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity); SelectObject(hdc, oldFont); - ReleaseDC(0, hdc); return FloatRect(gdiMetrics.gmptGlyphOrigin.x, -gdiMetrics.gmptGlyphOrigin.y, gdiMetrics.gmBlackBoxX + m_syntheticBoldOffset, gdiMetrics.gmBlackBoxY); @@ -249,7 +243,7 @@ FloatRect SimpleFontData::boundsForGDIGlyph(Glyph glyph) const float SimpleFontData::widthForGDIGlyph(Glyph glyph) const { - HDC hdc = GetDC(0); + HWndDC hdc(0); SetGraphicsMode(hdc, GM_ADVANCED); HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); @@ -258,7 +252,6 @@ float SimpleFontData::widthForGDIGlyph(Glyph glyph) const GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity); SelectObject(hdc, oldFont); - ReleaseDC(0, hdc); return gdiMetrics.gmCellIncX + m_syntheticBoldOffset; } @@ -271,12 +264,11 @@ SCRIPT_FONTPROPERTIES* SimpleFontData::scriptFontProperties() const m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES); HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties); if (result == E_PENDING) { - HDC dc = GetDC(0); + HWndDC dc(0); SaveDC(dc); SelectObject(dc, m_platformData.hfont()); ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties); RestoreDC(dc, -1); - ReleaseDC(0, dc); } } return m_scriptFontProperties; diff --git a/Source/WebCore/platform/graphics/win/UniscribeController.cpp b/Source/WebCore/platform/graphics/win/UniscribeController.cpp index 67e34a71d..336b4e642 100644 --- a/Source/WebCore/platform/graphics/win/UniscribeController.cpp +++ b/Source/WebCore/platform/graphics/win/UniscribeController.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "UniscribeController.h" #include "Font.h" +#include "HWndDC.h" #include "SimpleFontData.h" #include "TextRun.h" #include <wtf/MathExtras.h> @@ -248,13 +249,12 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const S if (placeResult == E_PENDING) { // The script cache isn't primed with enough info yet. We need to select our HFONT into // a DC and pass the DC in to ScriptPlace. - HDC hdc = GetDC(0); + HWndDC hdc(0); HFONT hfont = fontData->platformData().hfont(); HFONT oldFont = (HFONT)SelectObject(hdc, hfont); placeResult = ScriptPlace(hdc, fontData->scriptCache(), glyphs.data(), glyphs.size(), visualAttributes.data(), &item.a, advances.data(), offsets.data(), 0); SelectObject(hdc, oldFont); - ReleaseDC(0, hdc); } if (FAILED(placeResult) || glyphs.isEmpty()) @@ -380,7 +380,7 @@ bool UniscribeController::shape(const UChar* str, int len, SCRIPT_ITEM item, con Vector<WORD>& glyphs, Vector<WORD>& clusters, Vector<SCRIPT_VISATTR>& visualAttributes) { - HDC hdc = 0; + HWndDC hdc; HFONT oldFont = 0; HRESULT shapeResult = E_PENDING; int glyphCount = 0; @@ -391,7 +391,7 @@ bool UniscribeController::shape(const UChar* str, int len, SCRIPT_ITEM item, con // The script cache isn't primed with enough info yet. We need to select our HFONT into // a DC and pass the DC in to ScriptShape. ASSERT(!hdc); - hdc = GetDC(0); + hdc.setHWnd(0); HFONT hfont = fontData->platformData().hfont(); oldFont = (HFONT)SelectObject(hdc, hfont); } else if (shapeResult == E_OUTOFMEMORY) { @@ -401,10 +401,8 @@ bool UniscribeController::shape(const UChar* str, int len, SCRIPT_ITEM item, con } } while (shapeResult == E_PENDING || shapeResult == E_OUTOFMEMORY); - if (hdc) { + if (hdc) SelectObject(hdc, oldFont); - ReleaseDC(0, hdc); - } if (FAILED(shapeResult)) return false; diff --git a/Source/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp b/Source/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp index c1de965c4..39ef15503 100644 --- a/Source/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp +++ b/Source/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp @@ -72,7 +72,7 @@ ImageBufferData::ImageBufferData(const IntSize& size) m_bitmap->setHasAlpha(true); } -ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace colorSpace, RenderingMode, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace colorSpace, RenderingMode, DeferralMode, bool& success) : m_data(size) , m_size(size) { diff --git a/Source/WebCore/platform/graphics/wx/ImageBufferWx.cpp b/Source/WebCore/platform/graphics/wx/ImageBufferWx.cpp index d01391f6c..7c909b54d 100644 --- a/Source/WebCore/platform/graphics/wx/ImageBufferWx.cpp +++ b/Source/WebCore/platform/graphics/wx/ImageBufferWx.cpp @@ -37,7 +37,7 @@ ImageBufferData::ImageBufferData(const IntSize&) { } -ImageBuffer::ImageBuffer(const IntSize&, ColorSpace imageColorSpace, RenderingMode, bool& success) : +ImageBuffer::ImageBuffer(const IntSize&, ColorSpace imageColorSpace, RenderingMode, DeferralMode, bool& success) : m_data(IntSize()) { notImplemented(); diff --git a/Source/WebCore/platform/gtk/GtkUtilities.cpp b/Source/WebCore/platform/gtk/GtkUtilities.cpp index 2cf69c9d0..246687958 100644 --- a/Source/WebCore/platform/gtk/GtkUtilities.cpp +++ b/Source/WebCore/platform/gtk/GtkUtilities.cpp @@ -42,4 +42,9 @@ IntPoint convertWidgetPointToScreenPoint(GtkWidget* widget, const IntPoint& poin return IntPoint(windowOriginX + xInWindow, windowOriginY + yInWindow); } +bool widgetIsOnscreenToplevelWindow(GtkWidget* widget) +{ + return gtk_widget_is_toplevel(widget) && GTK_IS_WINDOW(widget) && !GTK_IS_OFFSCREEN_WINDOW(widget); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/gtk/GtkUtilities.h b/Source/WebCore/platform/gtk/GtkUtilities.h index a33858fa1..b9bdde659 100644 --- a/Source/WebCore/platform/gtk/GtkUtilities.h +++ b/Source/WebCore/platform/gtk/GtkUtilities.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, Igalia S.L. + * Copyright (C) 2011, 2012 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 @@ -24,6 +24,7 @@ namespace WebCore { class IntPoint; IntPoint convertWidgetPointToScreenPoint(GtkWidget*, const IntPoint&); +bool widgetIsOnscreenToplevelWindow(GtkWidget*); } // namespace WebCore diff --git a/Source/WebCore/platform/gtk/LanguageGtk.cpp b/Source/WebCore/platform/gtk/LanguageGtk.cpp index 7d7a66d2e..f0fae5300 100644 --- a/Source/WebCore/platform/gtk/LanguageGtk.cpp +++ b/Source/WebCore/platform/gtk/LanguageGtk.cpp @@ -22,6 +22,7 @@ #include "GOwnPtr.h" #include "PlatformString.h" +#include <wtf/Vector.h> #include <wtf/text/CString.h> #include <glib.h> @@ -32,7 +33,7 @@ namespace WebCore { // Using pango_language_get_default() here is not an option, because // it doesn't support changing the locale in runtime, so it returns // always the same value. -String platformDefaultLanguage() +static String platformLanguage() { char* localeDefault = setlocale(LC_CTYPE, NULL); @@ -53,4 +54,11 @@ String platformDefaultLanguage() return String(normalizedDefault.get()); } +Vector<String> platformUserPreferredLanguages() +{ + Vector<String> userPreferredLanguages; + userPreferredLanguages.append(platformLanguage()); + return userPreferredLanguages; +} + } diff --git a/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp b/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp index 0a3b486dc..74e4f18ca 100644 --- a/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp +++ b/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp @@ -31,6 +31,7 @@ #include "config.h" #include "PlatformScreen.h" +#include "FrameView.h" #include "GtkVersioning.h" #include "HostWindow.h" #include "NotImplemented.h" @@ -100,9 +101,9 @@ static GdkScreen* getScreen(GtkWidget* widget) return gtk_widget_has_screen(widget) ? gtk_widget_get_screen(widget) : gdk_screen_get_default(); } -FloatRect screenRect(Widget* widget) +FloatRect screenRect(FrameView* frameView) { - GtkWidget* container = widget ? GTK_WIDGET(widget->root()->hostWindow()->platformPageClient()) : 0; + GtkWidget* container = frameView ? GTK_WIDGET(frameView->root()->hostWindow()->platformPageClient()) : 0; if (container) container = getToplevel(container); @@ -118,11 +119,11 @@ FloatRect screenRect(Widget* widget) return FloatRect(geometry.x, geometry.y, geometry.width, geometry.height); } -FloatRect screenAvailableRect(Widget* widget) +FloatRect screenAvailableRect(FrameView* frameView) { - GtkWidget* container = widget ? GTK_WIDGET(widget->root()->hostWindow()->platformPageClient()) : 0; + GtkWidget* container = frameView ? GTK_WIDGET(frameView->root()->hostWindow()->platformPageClient()) : 0; if (container && !gtk_widget_get_realized(container)) - return screenRect(widget); + return screenRect(frameView); GdkScreen* screen = container ? getScreen(container) : gdk_screen_get_default(); if (!screen) diff --git a/Source/WebCore/platform/gtk/RenderThemeGtk.h b/Source/WebCore/platform/gtk/RenderThemeGtk.h index 408b05f8d..ea61674f4 100644 --- a/Source/WebCore/platform/gtk/RenderThemeGtk.h +++ b/Source/WebCore/platform/gtk/RenderThemeGtk.h @@ -82,6 +82,8 @@ public: virtual void systemFont(int propId, FontDescription&) const; virtual Color systemColor(int cssValueId) const; + virtual bool popsMenuBySpaceOrReturn() const OVERRIDE { return true; } + #if ENABLE(VIDEO) virtual String extraMediaControlsStyleSheet(); virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const; diff --git a/Source/WebCore/platform/gtk/RunLoopGtk.cpp b/Source/WebCore/platform/gtk/RunLoopGtk.cpp new file mode 100644 index 000000000..929a7b98e --- /dev/null +++ b/Source/WebCore/platform/gtk/RunLoopGtk.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Portions Copyright (c) 2010 Motorola Mobility, 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 INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RunLoop.h" + +#include <glib.h> + +namespace WebCore { + +RunLoop::RunLoop() +{ + m_runLoopContext = g_main_context_default(); + ASSERT(m_runLoopContext); + m_runLoopMain = g_main_loop_new(m_runLoopContext, FALSE); + ASSERT(m_runLoopMain); +} + +RunLoop::~RunLoop() +{ + if (m_runLoopMain) { + if (g_main_loop_is_running(m_runLoopMain)) + g_main_loop_quit(m_runLoopMain); + g_main_loop_unref(m_runLoopMain); + } + + if (m_runLoopContext) + g_main_context_unref(m_runLoopContext); +} + +void RunLoop::run() +{ + g_main_loop_run(RunLoop::main()->mainLoop()); +} + +GMainLoop* RunLoop::mainLoop() +{ + return m_runLoopMain; +} + +void RunLoop::stop() +{ + g_main_loop_quit(m_runLoopMain); +} + +gboolean RunLoop::queueWork(RunLoop* runLoop) +{ + runLoop->performWork(); + return FALSE; +} + +void RunLoop::wakeUp() +{ + GRefPtr<GSource> source = adoptGRef(g_idle_source_new()); + g_source_set_priority(source.get(), G_PRIORITY_DEFAULT); + g_source_set_callback(source.get(), reinterpret_cast<GSourceFunc>(&RunLoop::queueWork), this, 0); + g_source_attach(source.get(), m_runLoopContext); + + g_main_context_wakeup(m_runLoopContext); +} + +RunLoop::TimerBase::TimerBase(RunLoop* runLoop) + : m_runLoop(runLoop) + , m_timerSource(0) +{ +} + +RunLoop::TimerBase::~TimerBase() +{ + stop(); +} + +void RunLoop::TimerBase::clearTimerSource() +{ + m_timerSource = 0; +} + +gboolean RunLoop::TimerBase::timerFiredCallback(RunLoop::TimerBase* timer) +{ + GSource* currentTimerSource = timer->m_timerSource.get(); + bool isRepeating = timer->isRepeating(); + // This can change the timerSource by starting a new timer within the callback. + timer->fired(); + if (!isRepeating && currentTimerSource == timer->m_timerSource.get()) + timer->clearTimerSource(); + return isRepeating; +} + +void RunLoop::TimerBase::start(double fireInterval, bool repeat) +{ + if (m_timerSource) + stop(); + + m_timerSource = adoptGRef(g_timeout_source_new(static_cast<guint>(fireInterval * 1000))); + m_isRepeating = repeat; + g_source_set_callback(m_timerSource.get(), reinterpret_cast<GSourceFunc>(&RunLoop::TimerBase::timerFiredCallback), this, 0); + g_source_attach(m_timerSource.get(), m_runLoop->m_runLoopContext); +} + +void RunLoop::TimerBase::stop() +{ + if (!m_timerSource) + return; + + g_source_destroy(m_timerSource.get()); + clearTimerSource(); +} + +bool RunLoop::TimerBase::isActive() const +{ + return m_timerSource; +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp b/Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp index b5c5002a4..e99364f2a 100644 --- a/Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp +++ b/Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp @@ -97,6 +97,8 @@ IntRect ScrollbarThemeGtk::backButtonRect(Scrollbar* scrollbar, ScrollbarPart pa { if (part == BackButtonEndPart && !m_hasBackButtonEndPart) return IntRect(); + if (part == BackButtonStartPart && !m_hasBackButtonStartPart) + return IntRect(); int x = scrollbar->x() + m_troughBorderWidth; int y = scrollbar->y() + m_troughBorderWidth; @@ -116,6 +118,8 @@ IntRect ScrollbarThemeGtk::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart { if (part == ForwardButtonStartPart && !m_hasForwardButtonStartPart) return IntRect(); + if (part == ForwardButtonEndPart && !m_hasForwardButtonEndPart) + return IntRect(); IntSize size = buttonSize(scrollbar); if (scrollbar->orientation() == HorizontalScrollbar) { @@ -138,37 +142,42 @@ IntRect ScrollbarThemeGtk::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart IntRect ScrollbarThemeGtk::trackRect(Scrollbar* scrollbar, bool) { - // The padding along the thumb movement axis (from outside to in) - // is the size of trough border plus the size of the stepper (button) + // The padding along the thumb movement axis includes the trough border // plus the size of stepper spacing (the space between the stepper and // the place where the thumb stops). There is often no stepper spacing. - int movementAxisPadding = m_troughBorderWidth + m_stepperSize + m_stepperSpacing; + int movementAxisPadding = m_troughBorderWidth + m_stepperSpacing; // The fatness of the scrollbar on the non-movement axis. int thickness = scrollbarThickness(scrollbar->controlSize()); - int alternateButtonOffset = 0; - int alternateButtonWidth = 0; + int startButtonsOffset = 0; + int buttonsWidth = 0; if (m_hasForwardButtonStartPart) { - alternateButtonOffset += m_stepperSize; - alternateButtonWidth += m_stepperSize; + startButtonsOffset += m_stepperSize; + buttonsWidth += m_stepperSize; + } + if (m_hasBackButtonStartPart) { + startButtonsOffset += m_stepperSize; + buttonsWidth += m_stepperSize; } if (m_hasBackButtonEndPart) - alternateButtonWidth += m_stepperSize; + buttonsWidth += m_stepperSize; + if (m_hasForwardButtonEndPart) + buttonsWidth += m_stepperSize; if (scrollbar->orientation() == HorizontalScrollbar) { // Once the scrollbar becomes smaller than the natural size of the // two buttons, the track disappears. if (scrollbar->width() < 2 * thickness) return IntRect(); - return IntRect(scrollbar->x() + movementAxisPadding + alternateButtonOffset, scrollbar->y(), - scrollbar->width() - (2 * movementAxisPadding) - alternateButtonWidth, thickness); + return IntRect(scrollbar->x() + movementAxisPadding + startButtonsOffset, scrollbar->y(), + scrollbar->width() - (2 * movementAxisPadding) - buttonsWidth, thickness); } if (scrollbar->height() < 2 * thickness) return IntRect(); - return IntRect(scrollbar->x(), scrollbar->y() + movementAxisPadding + alternateButtonOffset, - thickness, scrollbar->height() - (2 * movementAxisPadding) - alternateButtonWidth); + return IntRect(scrollbar->x(), scrollbar->y() + movementAxisPadding + startButtonsOffset, + thickness, scrollbar->height() - (2 * movementAxisPadding) - buttonsWidth); } IntRect ScrollbarThemeGtk::thumbRect(Scrollbar* scrollbar, const IntRect& unconstrainedTrackRect) diff --git a/Source/WebCore/platform/gtk/ScrollbarThemeGtk.h b/Source/WebCore/platform/gtk/ScrollbarThemeGtk.h index 323d55442..45e093b1e 100644 --- a/Source/WebCore/platform/gtk/ScrollbarThemeGtk.h +++ b/Source/WebCore/platform/gtk/ScrollbarThemeGtk.h @@ -72,6 +72,8 @@ protected: int m_minThumbLength; gboolean m_troughUnderSteppers; gboolean m_hasForwardButtonStartPart; + gboolean m_hasForwardButtonEndPart; + gboolean m_hasBackButtonStartPart; gboolean m_hasBackButtonEndPart; }; diff --git a/Source/WebCore/platform/gtk/ScrollbarThemeGtk2.cpp b/Source/WebCore/platform/gtk/ScrollbarThemeGtk2.cpp index 1ab88504b..729bd124d 100644 --- a/Source/WebCore/platform/gtk/ScrollbarThemeGtk2.cpp +++ b/Source/WebCore/platform/gtk/ScrollbarThemeGtk2.cpp @@ -58,6 +58,8 @@ void ScrollbarThemeGtk::updateThemeProperties() "trough_border", &m_troughBorderWidth, "stepper-size", &m_stepperSize, "trough-under-steppers", &m_troughUnderSteppers, + "has-backward-stepper", &m_hasBackButtonStartPart, + "has-forward-stepper", &m_hasForwardButtonEndPart, "has-secondary-forward-stepper", &m_hasForwardButtonStartPart, "has-secondary-backward-stepper", &m_hasBackButtonEndPart, NULL); m_minThumbLength = gtk_range_get_min_slider_size(GTK_RANGE(scrollbar)); diff --git a/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp b/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp index e0e2e66ff..4c33e66db 100644 --- a/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp +++ b/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp @@ -58,6 +58,8 @@ void ScrollbarThemeGtk::updateThemeProperties() "stepper-size", &m_stepperSize, "stepper-spacing", &m_stepperSpacing, "trough-under-steppers", &m_troughUnderSteppers, + "has-backward-stepper", &m_hasBackButtonStartPart, + "has-forward-stepper", &m_hasForwardButtonEndPart, "has-secondary-backward-stepper", &m_hasBackButtonEndPart, "has-secondary-forward-stepper", &m_hasForwardButtonStartPart, NULL); diff --git a/Source/WebCore/platform/image-decoders/ImageDecoder.h b/Source/WebCore/platform/image-decoders/ImageDecoder.h index 95688e7a1..9d9b34f60 100644 --- a/Source/WebCore/platform/image-decoders/ImageDecoder.h +++ b/Source/WebCore/platform/image-decoders/ImageDecoder.h @@ -47,7 +47,6 @@ namespace WebCore { - // FIXME: Do we want better encapsulation? typedef Vector<char> ColorProfile; // ImageFrame represents the decoded image data. This buffer is what all @@ -301,6 +300,22 @@ namespace WebCore { void setIgnoreGammaAndColorProfile(bool flag) { m_ignoreGammaAndColorProfile = flag; } bool ignoresGammaAndColorProfile() const { return m_ignoreGammaAndColorProfile; } + enum { iccColorProfileHeaderLength = 128 }; + + static bool rgbColorProfile(const char* profileData, unsigned profileLength) + { + ASSERT(profileLength >= iccColorProfileHeaderLength); + + return !memcmp(&profileData[16], "RGB ", 4); + } + + static bool inputDeviceColorProfile(const char* profileData, unsigned profileLength) + { + ASSERT(profileLength >= iccColorProfileHeaderLength); + + return !memcmp(&profileData[12], "mntr", 4) || !memcmp(&profileData[12], "scnr", 4); + } + // Sets the "decode failure" flag. For caller convenience (since so // many callers want to return false after calling this), returns false // to enable easy tailcalling. Subclasses may override this to also diff --git a/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp index 0cbdd0453..5b42490ab 100644 --- a/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp +++ b/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp @@ -56,16 +56,12 @@ #endif extern "C" { - #include "jpeglib.h" - #if USE(ICCJPEG) #include "iccjpeg.h" #endif - -} - #include <setjmp.h> +} #if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) #define ASSUME_LITTLE_ENDIAN 0 @@ -73,12 +69,12 @@ extern "C" { #define ASSUME_LITTLE_ENDIAN 1 #endif -#if defined(JCS_EXTENSIONS) && ASSUME_LITTLE_ENDIAN +#if defined(JCS_ALPHA_EXTENSIONS) && ASSUME_LITTLE_ENDIAN #define TURBO_JPEG_RGB_SWIZZLE #if USE(SKIA) && (!SK_R32_SHIFT && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16) -inline J_COLOR_SPACE rgbOutputColorSpace() { return JCS_EXT_RGBX; } +inline J_COLOR_SPACE rgbOutputColorSpace() { return JCS_EXT_RGBA; } #else -inline J_COLOR_SPACE rgbOutputColorSpace() { return JCS_EXT_BGRX; } +inline J_COLOR_SPACE rgbOutputColorSpace() { return JCS_EXT_BGRA; } #endif inline bool turboSwizzled(J_COLOR_SPACE colorSpace) { return colorSpace == rgbOutputColorSpace(); } #else @@ -98,7 +94,7 @@ enum jstate { JPEG_DECOMPRESS_PROGRESSIVE, // Output progressive pixels JPEG_DECOMPRESS_SEQUENTIAL, // Output sequential pixels JPEG_DONE, - JPEG_ERROR + JPEG_ERROR }; void init_source(j_decompress_ptr jd); @@ -115,32 +111,6 @@ struct decoder_source_mgr { JPEGImageReader* decoder; }; -#if USE(ICCJPEG) - -#define iccProfileHeaderSize 128 - -static bool rgbColorProfile(const char* profileData, unsigned profileLength) -{ - ASSERT(profileLength >= iccProfileHeaderSize); - - if (!memcmp(&profileData[16], "RGB ", 4)) - return true; - return false; -} - -static bool inputDeviceColorProfile(const char* profileData, unsigned profileLength) -{ - ASSERT(profileLength >= iccProfileHeaderSize); - - if (!memcmp(&profileData[12], "mntr", 4)) - return true; - if (!memcmp(&profileData[12], "scnr", 4)) - return true; - return false; -} - -#endif - static ColorProfile readColorProfile(jpeg_decompress_struct* info) { #if USE(ICCJPEG) @@ -153,11 +123,11 @@ static ColorProfile readColorProfile(jpeg_decompress_struct* info) // Only accept RGB color profiles from input class devices. bool ignoreProfile = false; char* profileData = reinterpret_cast<char*>(profile); - if (profileLength < iccProfileHeaderSize) + if (profileLength < ImageDecoder::iccColorProfileHeaderLength) ignoreProfile = true; - else if (!rgbColorProfile(profileData, profileLength)) + else if (!ImageDecoder::rgbColorProfile(profileData, profileLength)) ignoreProfile = true; - else if (!inputDeviceColorProfile(profileData, profileLength)) + else if (!ImageDecoder::inputDeviceColorProfile(profileData, profileLength)) ignoreProfile = true; ColorProfile colorProfile; @@ -181,14 +151,14 @@ public: , m_samples(0) { memset(&m_info, 0, sizeof(jpeg_decompress_struct)); - + // We set up the normal JPEG error routines, then override error_exit. m_info.err = jpeg_std_error(&m_err.pub); m_err.pub.error_exit = error_exit; // Allocate and initialize JPEG decompression object. jpeg_create_decompress(&m_info); - + decoder_source_mgr* src = 0; if (!m_info.src) { src = (decoder_source_mgr*)fastCalloc(sizeof(decoder_source_mgr), 1); @@ -254,7 +224,7 @@ public: skipBytes(m_bytesToSkip); m_bufferLength = data.size(); - + // We need to do the setjmp here. Otherwise bad things will happen if (setjmp(m_err.setjmp_buffer)) return m_decoder->setFailed(); @@ -337,10 +307,10 @@ public: case JPEG_DECOMPRESS_SEQUENTIAL: if (m_state == JPEG_DECOMPRESS_SEQUENTIAL) { - + if (!m_decoder->outputScanlines()) return false; // I/O suspension. - + // If we've completed image output... ASSERT(m_info.output_scanline == m_info.output_height); m_state = JPEG_DONE; diff --git a/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp b/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp index fcef1335f..c50ebe957 100644 --- a/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp +++ b/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp @@ -227,8 +227,10 @@ bool PNGImageDecoder::setFailed() return ImageDecoder::setFailed(); } -static ColorProfile readColorProfile(png_structp png, png_infop info) +static void readColorProfile(png_structp png, png_infop info, ColorProfile& colorProfile) { + ASSERT(colorProfile.isEmpty()); + #ifdef PNG_iCCP_SUPPORTED char* profileName; int compressionType; @@ -238,13 +240,22 @@ static ColorProfile readColorProfile(png_structp png, png_infop info) png_bytep profile; #endif png_uint_32 profileLength; - if (png_get_iCCP(png, info, &profileName, &compressionType, &profile, &profileLength)) { - ColorProfile colorProfile; - colorProfile.append(profile, profileLength); - return colorProfile; - } + if (!png_get_iCCP(png, info, &profileName, &compressionType, &profile, &profileLength)) + return; + + // Only accept RGB color profiles from input class devices. + bool ignoreProfile = false; + char* profileData = reinterpret_cast<char*>(profile); + if (profileLength < ImageDecoder::iccColorProfileHeaderLength) + ignoreProfile = true; + else if (!ImageDecoder::rgbColorProfile(profileData, profileLength)) + ignoreProfile = true; + else if (!ImageDecoder::inputDeviceColorProfile(profileData, profileLength)) + ignoreProfile = true; + + if (!ignoreProfile) + colorProfile.append(profileData, profileLength); #endif - return ColorProfile(); } void PNGImageDecoder::headerAvailable() @@ -253,13 +264,13 @@ void PNGImageDecoder::headerAvailable() png_infop info = m_reader->infoPtr(); png_uint_32 width = png_get_image_width(png, info); png_uint_32 height = png_get_image_height(png, info); - + // Protect against large images. if (width > cMaxPNGSize || height > cMaxPNGSize) { longjmp(JMPBUF(png), 1); return; } - + // We can fill in the size now that the header is available. Avoid memory // corruption issues by neutering setFailed() during this call; if we don't // do this, failures will cause |m_reader| to be deleted, and our jmpbuf @@ -283,7 +294,7 @@ void PNGImageDecoder::headerAvailable() // don't similarly transform the color profile. We'd either need to transform // the color profile or we'd need to decode into a gray-scale image buffer and // hand that to CoreGraphics. - m_colorProfile = readColorProfile(png, info); + readColorProfile(png, info, m_colorProfile); } // The options we set here match what Mozilla does. @@ -291,7 +302,7 @@ void PNGImageDecoder::headerAvailable() // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. if (colorType == PNG_COLOR_TYPE_PALETTE || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)) png_set_expand(png); - + png_bytep trns = 0; int trnsCount = 0; if (png_get_valid(png, info, PNG_INFO_tRNS)) { diff --git a/Source/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp b/Source/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp index c7fcbd589..f3fd769cd 100644 --- a/Source/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp +++ b/Source/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp @@ -158,7 +158,9 @@ void ImageFrame::setStatus(FrameStatus status) if (m_status == FrameComplete) { m_bitmap.setDataComplete(); // Tell the bitmap it's done. #if PLATFORM(CHROMIUM) && OS(DARWIN) - if (m_colorProfile.isEmpty()) + // resolveColorSpace() and callees assume that the alpha channel is + // premultiplied, so don't apply the color profile if it isn't. + if (m_colorProfile.isEmpty() || (!m_premultiplyAlpha && hasAlpha())) return; RetainPtr<CGColorSpaceRef> cgColorSpace(AdoptCF, createColorSpace(m_colorProfile)); resolveColorSpace(m_bitmap.bitmap(), cgColorSpace.get()); diff --git a/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h b/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h index 3ccab2516..61ea13953 100644 --- a/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h +++ b/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h @@ -42,7 +42,7 @@ public: WEBPImageDecoder(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption); virtual ~WEBPImageDecoder(); - virtual String filenameExtension() const { return "vp8"; } + virtual String filenameExtension() const { return "webp"; } virtual bool isSizeAvailable(); virtual ImageFrame* frameBufferAtIndex(size_t index); diff --git a/Source/WebCore/platform/image-encoders/skia/WEBPImageEncoder.cpp b/Source/WebCore/platform/image-encoders/skia/WEBPImageEncoder.cpp index 631cf97cf..9cb24fc02 100644 --- a/Source/WebCore/platform/image-encoders/skia/WEBPImageEncoder.cpp +++ b/Source/WebCore/platform/image-encoders/skia/WEBPImageEncoder.cpp @@ -96,10 +96,10 @@ static bool encodePixels(IntSize imageSize, const unsigned char* pixels, bool pr return false; imageSize.clampNegativeToZero(); - if (!imageSize.width() || imageSize.width() > WEBPImageEncoder::MaximumImageDimension) + if (!imageSize.width() || imageSize.width() > WEBP_MAX_DIMENSION) return false; picture.width = imageSize.width(); - if (!imageSize.height() || imageSize.height() > WEBPImageEncoder::MaximumImageDimension) + if (!imageSize.height() || imageSize.height() > WEBP_MAX_DIMENSION) return false; picture.height = imageSize.height(); diff --git a/Source/WebCore/platform/image-encoders/skia/WEBPImageEncoder.h b/Source/WebCore/platform/image-encoders/skia/WEBPImageEncoder.h index ad786f606..4ec928e8d 100644 --- a/Source/WebCore/platform/image-encoders/skia/WEBPImageEncoder.h +++ b/Source/WebCore/platform/image-encoders/skia/WEBPImageEncoder.h @@ -49,9 +49,6 @@ public: // For callers: provide a reasonable compression quality default. enum Quality { DefaultCompressionQuality = 80 }; - - // Maximum image width or height allowed by the WEBP specification. - enum Dimension { MaximumImageDimension = 16383 }; }; } // namespace WebCore diff --git a/Source/WebCore/platform/mac/ClipboardMac.h b/Source/WebCore/platform/mac/ClipboardMac.h index 6c93ed5b9..24e9b8060 100644 --- a/Source/WebCore/platform/mac/ClipboardMac.h +++ b/Source/WebCore/platform/mac/ClipboardMac.h @@ -30,13 +30,8 @@ #include "Clipboard.h" #include <wtf/RetainPtr.h> -#ifdef __OBJC__ -@class NSImage; -@class NSPasteboard; -#else -class NSImage; -class NSPasteboard; -#endif +OBJC_CLASS NSImage; +OBJC_CLASS NSPasteboard; namespace WebCore { diff --git a/Source/WebCore/platform/mac/ClipboardMac.mm b/Source/WebCore/platform/mac/ClipboardMac.mm index ef759fb6b..2806fc625 100644 --- a/Source/WebCore/platform/mac/ClipboardMac.mm +++ b/Source/WebCore/platform/mac/ClipboardMac.mm @@ -68,13 +68,13 @@ bool ClipboardMac::hasData() static RetainPtr<NSString> cocoaTypeFromHTMLClipboardType(const String& type) { - String qType = type.stripWhiteSpace(); + // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dom-datatransfer-setdata + String qType = type.lower(); - // two special cases for IE compatibility - if (qType == "Text") - return NSStringPboardType; - if (qType == "URL") - return NSURLPboardType; + if (qType == "text") + qType = "text/plain"; + if (qType == "url") + qType = "text/uri-list"; // Ignore any trailing charset - JS strings are Unicode, which encapsulates the charset issue if (qType == "text/plain" || qType.startsWith("text/plain;")) @@ -82,7 +82,7 @@ static RetainPtr<NSString> cocoaTypeFromHTMLClipboardType(const String& type) if (qType == "text/uri-list") // special case because UTI doesn't work with Cocoa's URL type return NSURLPboardType; // note special case in getData to read NSFilenamesType - + // Try UTI now NSString *mimeType = qType; RetainPtr<CFStringRef> utiType(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (CFStringRef)mimeType, NULL)); @@ -218,8 +218,8 @@ String ClipboardMac::getData(const String& type, bool& success) const // Grab the value off the pasteboard corresponding to the cocoaType 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"); + // "url" and "text/url-list" both map to NSURLPboardType in cocoaTypeFromHTMLClipboardType(), "url" only wants the first URL + bool onlyFirstURL = (equalIgnoringCase(type, "url")); NSArray *absoluteURLs = absoluteURLsFromPasteboard(m_pasteboard.get(), onlyFirstURL); cocoaValue = [absoluteURLs componentsJoinedByString:@"\n"]; } else if ([cocoaType.get() isEqualToString:NSStringPboardType]) { @@ -367,19 +367,22 @@ void ClipboardMac::writeRange(Range* range, Frame* frame) { ASSERT(range); ASSERT(frame); - Pasteboard::writeSelection(m_pasteboard.get(), 0, range, frame->editor()->smartInsertDeleteEnabled() && frame->selection()->granularity() == WordGranularity, frame); + Pasteboard pasteboard([m_pasteboard.get() name]); + pasteboard.writeSelectionForTypes(nil, range, frame->editor()->smartInsertDeleteEnabled() && frame->selection()->granularity() == WordGranularity, frame); } void ClipboardMac::writePlainText(const String& text) { - Pasteboard::writePlainText(m_pasteboard.get(), text); + Pasteboard pasteboard([m_pasteboard.get() name]); + pasteboard.writePlainText(text); } void ClipboardMac::writeURL(const KURL& url, const String& title, Frame* frame) { ASSERT(frame); ASSERT(m_pasteboard); - Pasteboard::writeURL(m_pasteboard.get(), nil, url, title, frame); + Pasteboard pasteboard([m_pasteboard.get() name]); + pasteboard.writeURLForTypes(nil, url, title, frame); } #if ENABLE(DRAG_SUPPORT) diff --git a/Source/WebCore/platform/mac/DragDataMac.mm b/Source/WebCore/platform/mac/DragDataMac.mm index fd9f60a70..d6f4155c5 100644 --- a/Source/WebCore/platform/mac/DragDataMac.mm +++ b/Source/WebCore/platform/mac/DragDataMac.mm @@ -105,7 +105,7 @@ bool DragData::containsPlainText() const String DragData::asPlainText(Frame *frame) const { - Pasteboard pasteboard(m_pasteboard.get()); + Pasteboard pasteboard([m_pasteboard.get() name]); return pasteboard.plainText(frame); } @@ -157,13 +157,13 @@ String DragData::asURL(Frame* frame, FilenameConversionPolicy filenamePolicy, St if (NSString *URLTitleString = [m_pasteboard.get() stringForType:WebURLNamePboardType]) *title = URLTitleString; } - Pasteboard pasteboard(m_pasteboard.get()); + Pasteboard pasteboard([m_pasteboard.get() name]); return pasteboard.asURL(frame); } PassRefPtr<DocumentFragment> DragData::asFragment(Frame* frame, PassRefPtr<Range> range, bool allowPlainText, bool& chosePlainText) const { - Pasteboard pasteboard(m_pasteboard.get()); + Pasteboard pasteboard([m_pasteboard.get() name]); return pasteboard.documentFragment(frame, range, allowPlainText, chosePlainText); } diff --git a/Source/WebCore/platform/mac/HTMLConverter.mm b/Source/WebCore/platform/mac/HTMLConverter.mm index ef4ca3a24..5ce5446eb 100644 --- a/Source/WebCore/platform/mac/HTMLConverter.mm +++ b/Source/WebCore/platform/mac/HTMLConverter.mm @@ -1693,6 +1693,8 @@ static NSInteger _colCompare(id block1, id block2, void *) if (!renderer) continue; RenderStyle* style = renderer->style(); + if (style->textDecorationsInEffect() & UNDERLINE) + [attrs.get() setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName]; NSFont *font = style->font().primaryFont()->getNSFont(); [attrs.get() setObject:font forKey:NSFontAttributeName]; if (style->visitedDependentColor(CSSPropertyColor).alpha()) diff --git a/Source/WebCore/platform/mac/KURLMac.mm b/Source/WebCore/platform/mac/KURLMac.mm index bc20f3828..a5d15f5ea 100644 --- a/Source/WebCore/platform/mac/KURLMac.mm +++ b/Source/WebCore/platform/mac/KURLMac.mm @@ -42,22 +42,11 @@ KURL::KURL(NSURL *url) } CFIndex bytesLength = CFURLGetBytes(reinterpret_cast<CFURLRef>(url), 0, 0); - Vector<char, 512> buffer(bytesLength + 6); // 5 for "file:", 1 for null character to end C string - char* bytes = &buffer[5]; + Vector<char, 512> buffer(bytesLength + 1); + char* bytes = &buffer[0]; CFURLGetBytes(reinterpret_cast<CFURLRef>(url), reinterpret_cast<UInt8*>(bytes), bytesLength); bytes[bytesLength] = '\0'; - if (bytes[0] != '/') { - parse(bytes); - return; - } - - buffer[0] = 'f'; - buffer[1] = 'i'; - buffer[2] = 'l'; - buffer[3] = 'e'; - buffer[4] = ':'; - - parse(buffer.data()); + parse(bytes); } KURL::operator NSURL *() const diff --git a/Source/WebCore/platform/mac/Language.mm b/Source/WebCore/platform/mac/Language.mm index 8e01f06bc..78ff1dd31 100644 --- a/Source/WebCore/platform/mac/Language.mm +++ b/Source/WebCore/platform/mac/Language.mm @@ -30,11 +30,12 @@ #import "WebCoreSystemInterface.h" #import <wtf/Assertions.h> #import <wtf/MainThread.h> +#import <wtf/RetainPtr.h> #import <wtf/text/WTFString.h> using namespace WebCore; -static NSString *preferredLanguageCode; +static BOOL useCachedPreferredLanguages; @interface WebLanguageChangeObserver : NSObject { } @@ -46,8 +47,7 @@ static NSString *preferredLanguageCode; { ASSERT(isMainThread()); - [preferredLanguageCode release]; - preferredLanguageCode = nil; + useCachedPreferredLanguages = NO; languageDidChange(); } @@ -85,23 +85,28 @@ static NSString *createHTTPStyleLanguageCode(NSString *languageCode) return httpStyleLanguageCode; } -String platformDefaultLanguage() +Vector<String> platformUserPreferredLanguages() { + DEFINE_STATIC_LOCAL(Vector<String>, userPreferredLanguages, ()); + ASSERT(isMainThread()); BEGIN_BLOCK_OBJC_EXCEPTIONS; - if (!preferredLanguageCode) { - [[NSUserDefaults standardUserDefaults] synchronize]; - NSArray *languages = [[NSUserDefaults standardUserDefaults] stringArrayForKey:@"AppleLanguages"]; - if (![languages count]) - preferredLanguageCode = @"en"; - else - preferredLanguageCode = createHTTPStyleLanguageCode([languages objectAtIndex:0]); + if (!useCachedPreferredLanguages) { + useCachedPreferredLanguages = YES; + userPreferredLanguages.clear(); + + RetainPtr<CFArrayRef> languages(AdoptCF, CFLocaleCopyPreferredLanguages()); + CFIndex languageCount = CFArrayGetCount(languages.get()); + if (!languageCount) + userPreferredLanguages.append("en"); + else { + for (CFIndex i = 0; i < languageCount; i++) + userPreferredLanguages.append(createHTTPStyleLanguageCode((NSString *)CFArrayGetValueAtIndex(languages.get(), i))); + } } - NSString *code = [[preferredLanguageCode retain] autorelease]; - #if !PLATFORM(IOS) static bool languageChangeObserverAdded; if (!languageChangeObserverAdded) { @@ -112,11 +117,12 @@ String platformDefaultLanguage() languageChangeObserverAdded = true; } #endif // !PLATFORM(IOS) - - return code; + + return userPreferredLanguages; END_BLOCK_OBJC_EXCEPTIONS; - return String(); + + return Vector<String>(); } } diff --git a/Source/WebCore/platform/mac/LocalCurrentGraphicsContext.h b/Source/WebCore/platform/mac/LocalCurrentGraphicsContext.h index 0907fac52..d4df7e60e 100644 --- a/Source/WebCore/platform/mac/LocalCurrentGraphicsContext.h +++ b/Source/WebCore/platform/mac/LocalCurrentGraphicsContext.h @@ -24,11 +24,7 @@ #include "skia/ext/skia_utils_mac.h" #endif -#ifdef __OBJC__ -@class NSGraphicsContext; -#else -class NSGraphicsContext; -#endif +OBJC_CLASS NSGraphicsContext; namespace WebCore { diff --git a/Source/WebCore/platform/mac/LoggingMac.mm b/Source/WebCore/platform/mac/LoggingMac.mm index 7f2ee1fd0..45cf6e5a4 100644 --- a/Source/WebCore/platform/mac/LoggingMac.mm +++ b/Source/WebCore/platform/mac/LoggingMac.mm @@ -72,6 +72,7 @@ void initializeLoggingChannelsIfNecessary() initializeWithUserDefault(LogMedia); initializeWithUserDefault(LogPlugins); initializeWithUserDefault(LogArchives); + initializeWithUserDefault(LogWebAudio); } } diff --git a/Source/WebCore/platform/mac/MemoryPressureHandlerMac.mm b/Source/WebCore/platform/mac/MemoryPressureHandlerMac.mm index 838c12409..0e410d94f 100644 --- a/Source/WebCore/platform/mac/MemoryPressureHandlerMac.mm +++ b/Source/WebCore/platform/mac/MemoryPressureHandlerMac.mm @@ -32,7 +32,7 @@ #import <WebCore/PageCache.h> #import <wtf/FastMalloc.h> -#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) && !PLATFORM(IOS) #import "WebCoreSystemInterface.h" #import <notify.h> #endif @@ -41,6 +41,7 @@ namespace WebCore { #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) +#if !PLATFORM(IOS) static dispatch_source_t _cache_event_source = 0; static dispatch_source_t _timer_event_source = 0; static int _notifyToken; @@ -114,19 +115,25 @@ void MemoryPressureHandler::respondToMemoryPressure() { holdOff(s_secondsBetweenMemoryCleanup); + releaseMemory(false); +} +#endif // !PLATFORM(IOS) + +void MemoryPressureHandler::releaseMemory(bool critical) +{ int savedPageCacheCapacity = pageCache()->capacity(); - pageCache()->setCapacity(pageCache()->pageCount()/2); + pageCache()->setCapacity(critical ? 0 : pageCache()->pageCount() / 2); pageCache()->setCapacity(savedPageCacheCapacity); pageCache()->releaseAutoreleasedPagesNow(); NSURLCache *nsurlCache = [NSURLCache sharedURLCache]; NSUInteger savedNsurlCacheMemoryCapacity = [nsurlCache memoryCapacity]; - [nsurlCache setMemoryCapacity:[nsurlCache currentMemoryUsage]/2]; + [nsurlCache setMemoryCapacity:critical ? 0 : [nsurlCache currentMemoryUsage] / 2]; [nsurlCache setMemoryCapacity:savedNsurlCacheMemoryCapacity]; - + fontCache()->purgeInactiveFontData(); - memoryCache()->pruneToPercentage(0.5f); + memoryCache()->pruneToPercentage(critical ? 0 : 0.5f); gcController().garbageCollectNow(); diff --git a/Source/WebCore/platform/mac/NSScrollerImpDetails.h b/Source/WebCore/platform/mac/NSScrollerImpDetails.h index 7b3d14cfc..f06800c16 100644 --- a/Source/WebCore/platform/mac/NSScrollerImpDetails.h +++ b/Source/WebCore/platform/mac/NSScrollerImpDetails.h @@ -61,6 +61,7 @@ typedef NSInteger NSScrollerKnobStyle; - (void)setDoubleValue:(double)doubleValue; - (void)setKnobProportion:(CGFloat)proportion; - (void)setKnobStyle:(NSScrollerKnobStyle)knobStyle; +- (void)setExpanded:(BOOL)expanded; - (void)setDelegate:(id)delegate; - (void)setUiStateTransitionProgress:(CGFloat)uiStateTransitionProgress; - (BOOL)isHorizontal; diff --git a/Source/WebCore/platform/mac/PasteboardHelper.h b/Source/WebCore/platform/mac/PasteboardHelper.h index 7bd62e5fb..6c1e844ea 100644 --- a/Source/WebCore/platform/mac/PasteboardHelper.h +++ b/Source/WebCore/platform/mac/PasteboardHelper.h @@ -34,11 +34,7 @@ #import <wtf/Forward.h> -#ifdef __OBJC__ -@class DOMDocumentFragment; -#else -class DOMDocumentFragment; -#endif +OBJC_CLASS DOMDocumentFragment; namespace WebCore { diff --git a/Source/WebCore/platform/mac/PasteboardMac.mm b/Source/WebCore/platform/mac/PasteboardMac.mm index 852e17a96..cb501e512 100644 --- a/Source/WebCore/platform/mac/PasteboardMac.mm +++ b/Source/WebCore/platform/mac/PasteboardMac.mm @@ -113,13 +113,14 @@ static NSArray* writableTypesForImage() Pasteboard* Pasteboard::generalPasteboard() { - static Pasteboard* pasteboard = new Pasteboard([NSPasteboard generalPasteboard]); + static Pasteboard* pasteboard = new Pasteboard(NSGeneralPboard); return pasteboard; } -Pasteboard::Pasteboard(NSPasteboard* pboard) - : m_pasteboard(pboard) +Pasteboard::Pasteboard(const String& pasteboardName) + : m_pasteboard([NSPasteboard pasteboardWithName:pasteboardName]) { + ASSERT(pasteboardName); } void Pasteboard::clear() @@ -127,7 +128,7 @@ void Pasteboard::clear() [m_pasteboard.get() declareTypes:[NSArray array] owner:nil]; } -void Pasteboard::writeSelection(NSPasteboard* pasteboard, NSArray* pasteboardTypes, Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame) +void Pasteboard::writeSelectionForTypes(NSArray* pasteboardTypes, Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame) { if (!WebArchivePboardType) Pasteboard::generalPasteboard(); // Initializes pasteboard types. @@ -158,26 +159,26 @@ void Pasteboard::writeSelection(NSPasteboard* pasteboard, NSArray* pasteboardTyp #endif NSArray *types = pasteboardTypes ? pasteboardTypes : selectionPasteboardTypes(canSmartCopyOrDelete, [attributedString containsAttachments]); - [pasteboard declareTypes:types owner:nil]; + [m_pasteboard.get() declareTypes:types owner:nil]; frame->editor()->client()->didSetSelectionTypesForPasteboard(); // Put HTML on the pasteboard. if ([types containsObject:WebArchivePboardType]) { RefPtr<LegacyWebArchive> archive = LegacyWebArchive::createFromSelection(frame); RetainPtr<CFDataRef> data = archive ? archive->rawDataRepresentation() : 0; - [pasteboard setData:(NSData *)data.get() forType:WebArchivePboardType]; + [m_pasteboard.get() setData:(NSData *)data.get() forType:WebArchivePboardType]; } // Put the attributed string on the pasteboard (RTF/RTFD format). if ([types containsObject:NSRTFDPboardType]) { NSData *RTFDData = [attributedString RTFDFromRange:NSMakeRange(0, [attributedString length]) documentAttributes:nil]; - [pasteboard setData:RTFDData forType:NSRTFDPboardType]; + [m_pasteboard.get() setData:RTFDData forType:NSRTFDPboardType]; } if ([types containsObject:NSRTFPboardType]) { if ([attributedString containsAttachments]) attributedString = attributedStringByStrippingAttachmentCharacters(attributedString); NSData *RTFData = [attributedString RTFFromRange:NSMakeRange(0, [attributedString length]) documentAttributes:nil]; - [pasteboard setData:RTFData forType:NSRTFPboardType]; + [m_pasteboard.get() setData:RTFData forType:NSRTFPboardType]; } // Put plain string on the pasteboard. @@ -189,48 +190,34 @@ void Pasteboard::writeSelection(NSPasteboard* pasteboard, NSArray* pasteboardTyp NSString *NonBreakingSpaceString = [NSString stringWithCharacters:&noBreakSpace length:1]; [s replaceOccurrencesOfString:NonBreakingSpaceString withString:@" " options:0 range:NSMakeRange(0, [s length])]; - [pasteboard setString:s forType:NSStringPboardType]; + [m_pasteboard.get() setString:s forType:NSStringPboardType]; [s release]; } if ([types containsObject:WebSmartPastePboardType]) { - [pasteboard setData:nil forType:WebSmartPastePboardType]; + [m_pasteboard.get() setData:nil forType:WebSmartPastePboardType]; } } -void Pasteboard::writePlainText(NSPasteboard* pasteboard, const String& text) +void Pasteboard::writePlainText(const String& text) { - NSArray *types = [NSArray arrayWithObject:NSStringPboardType]; - [pasteboard declareTypes:types owner:nil]; - - [pasteboard setString:text forType:NSStringPboardType]; + [m_pasteboard.get() declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]; + [m_pasteboard.get() setString:text forType:NSStringPboardType]; } void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame) { - Pasteboard::writeSelection(m_pasteboard.get(), 0, selectedRange, canSmartCopyOrDelete, frame); -} - -void Pasteboard::writePlainText(const String& text) -{ - if (!WebArchivePboardType) - Pasteboard::generalPasteboard(); // Initializes pasteboard types. - - NSArray *types = [NSArray arrayWithObject:NSStringPboardType]; - NSPasteboard *pasteboard = m_pasteboard.get(); - [pasteboard declareTypes:types owner:nil]; - - [pasteboard setString:text forType:NSStringPboardType]; + writeSelectionForTypes(nil, selectedRange, canSmartCopyOrDelete, frame); } -void Pasteboard::writeURL(NSPasteboard* pasteboard, NSArray* types, const KURL& url, const String& titleStr, Frame* frame) +void Pasteboard::writeURLForTypes(NSArray* types, const KURL& url, const String& titleStr, Frame* frame) { if (!WebArchivePboardType) Pasteboard::generalPasteboard(); // Initializes pasteboard types. if (!types) { types = writableTypesForURL(); - [pasteboard declareTypes:types owner:nil]; + [m_pasteboard.get() declareTypes:types owner:nil]; } ASSERT(!url.isEmpty()); @@ -246,23 +233,23 @@ void Pasteboard::writeURL(NSPasteboard* pasteboard, NSArray* types, const KURL& } if ([types containsObject:WebURLsWithTitlesPboardType]) - [pasteboard setPropertyList:[NSArray arrayWithObjects:[NSArray arrayWithObject:userVisibleString], + [m_pasteboard.get() setPropertyList:[NSArray arrayWithObjects:[NSArray arrayWithObject:userVisibleString], [NSArray arrayWithObject:(NSString*)titleStr.stripWhiteSpace()], nil] forType:WebURLsWithTitlesPboardType]; if ([types containsObject:NSURLPboardType]) - [cocoaURL writeToPasteboard:pasteboard]; + [cocoaURL writeToPasteboard:m_pasteboard.get()]; if ([types containsObject:WebURLPboardType]) - [pasteboard setString:userVisibleString forType:WebURLPboardType]; + [m_pasteboard.get() setString:userVisibleString forType:WebURLPboardType]; if ([types containsObject:WebURLNamePboardType]) - [pasteboard setString:title forType:WebURLNamePboardType]; + [m_pasteboard.get() setString:title forType:WebURLNamePboardType]; if ([types containsObject:NSStringPboardType]) - [pasteboard setString:userVisibleString forType:NSStringPboardType]; + [m_pasteboard.get() setString:userVisibleString forType:NSStringPboardType]; } void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame) { - Pasteboard::writeURL(m_pasteboard.get(), nil, url, titleStr, frame); + writeURLForTypes(nil, url, titleStr, frame); } static NSFileWrapper* fileWrapperForImage(CachedResource* resource, NSURL *url) @@ -308,7 +295,7 @@ void Pasteboard::writeImage(Node* node, const KURL& url, const String& title) NSArray* types = writableTypesForImage(); [m_pasteboard.get() declareTypes:types owner:nil]; - writeURL(m_pasteboard.get(), types, cocoaURL, nsStringNilIfEmpty(title), frame); + writeURLForTypes(types, cocoaURL, nsStringNilIfEmpty(title), frame); Image* image = cachedImage->imageForRenderer(renderer); ASSERT(image); diff --git a/Source/WebCore/platform/mac/PlatformEventFactoryMac.h b/Source/WebCore/platform/mac/PlatformEventFactoryMac.h index 12ede1fab..8c186dafd 100644 --- a/Source/WebCore/platform/mac/PlatformEventFactoryMac.h +++ b/Source/WebCore/platform/mac/PlatformEventFactoryMac.h @@ -46,10 +46,14 @@ public: #endif }; -// FIXME: This doesn't really belong here. - #if PLATFORM(MAC) && defined(__OBJC__) +// FIXME: This doesn't really belong here. IntPoint globalPoint(const NSPoint& windowPoint, NSWindow *); + +// FIXME: WebKit2 has a lot of code copy/pasted from PlatformEventFactoryMac in WebEventFactory. It should be carefully shared with WebCore. +int windowsKeyCodeForKeyEvent(NSEvent*); +String keyIdentifierForKeyEvent(NSEvent*); + #endif } // namespace WebCore diff --git a/Source/WebCore/platform/mac/PlatformEventFactoryMac.mm b/Source/WebCore/platform/mac/PlatformEventFactoryMac.mm index 43623c712..f0ebf5cae 100644 --- a/Source/WebCore/platform/mac/PlatformEventFactoryMac.mm +++ b/Source/WebCore/platform/mac/PlatformEventFactoryMac.mm @@ -201,6 +201,11 @@ static PlatformWheelEventPhase phaseForEvent(NSEvent *event) phase |= PlatformWheelEventPhaseEnded; if ([event phase] & NSEventPhaseCancelled) phase |= PlatformWheelEventPhaseCancelled; +#if !defined(BUILDING_ON_LION) + if ([event momentumPhase] & NSEventPhaseMayBegin) + phase |= PlatformWheelEventPhaseMayBegin; +#endif + return static_cast<PlatformWheelEventPhase>(phase); #else UNUSED_PARAM(event); @@ -237,7 +242,7 @@ static inline String unmodifiedTextFromEvent(NSEvent* event) return String([event charactersIgnoringModifiers]); } -static String keyIdentifierForKeyEvent(NSEvent* event) +String keyIdentifierForKeyEvent(NSEvent* event) { if ([event type] == NSFlagsChanged) switch ([event keyCode]) { @@ -313,7 +318,7 @@ static bool isKeypadEvent(NSEvent* event) return false; } -static int windowsKeyCodeForKeyEvent(NSEvent* event) +int windowsKeyCodeForKeyEvent(NSEvent* event) { int code = 0; // There are several kinds of characters for which we produce key code from char code: diff --git a/Source/WebCore/platform/mac/PlatformScreenMac.mm b/Source/WebCore/platform/mac/PlatformScreenMac.mm index 9065854c6..f14f1e2e3 100644 --- a/Source/WebCore/platform/mac/PlatformScreenMac.mm +++ b/Source/WebCore/platform/mac/PlatformScreenMac.mm @@ -64,16 +64,16 @@ bool screenIsMonochrome(Widget*) // These functions scale between screen and page coordinates because JavaScript/DOM operations // assume that the screen and the page share the same coordinate system. -FloatRect screenRect(Widget* widget) +FloatRect screenRect(FrameView* frameView) { - NSWindow *window = widget ? [widget->platformWidget() window] : nil; - return toUserSpace([screenForWindow(window) frame], window); + NSWindow *window = frameView ? [frameView->platformWidget() window] : nil; + return toUserSpace([screenForWindow(window) frame], window, WebCore::deviceScaleFactor(frameView->frame())); } -FloatRect screenAvailableRect(Widget* widget) +FloatRect screenAvailableRect(FrameView* frameView) { - NSWindow *window = widget ? [widget->platformWidget() window] : nil; - return toUserSpace([screenForWindow(window) visibleFrame], window); + NSWindow *window = frameView ? [frameView->platformWidget() window] : nil; + return toUserSpace([screenForWindow(window) visibleFrame], window, WebCore::deviceScaleFactor(frameView->frame())); } NSScreen *screenForWindow(NSWindow *window) @@ -89,29 +89,18 @@ NSScreen *screenForWindow(NSWindow *window) return nil; } -static CGFloat windowScaleFactor(NSWindow *window) -{ -#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) - return [window backingScaleFactor]; -#else - return [window userSpaceScaleFactor]; -#endif -} - -FloatRect toUserSpace(const NSRect& rect, NSWindow *destination) +FloatRect toUserSpace(const NSRect& rect, NSWindow *destination, float deviceScaleFactor) { FloatRect userRect = rect; userRect.setY(NSMaxY([screenForWindow(destination) frame]) - (userRect.y() + userRect.height())); // flip - if (destination) - userRect.scale(1 / windowScaleFactor(destination)); // scale down + userRect.scale(1 / deviceScaleFactor); // scale down return userRect; } -NSRect toDeviceSpace(const FloatRect& rect, NSWindow *source) +NSRect toDeviceSpace(const FloatRect& rect, NSWindow *source, float deviceScaleFactor) { FloatRect deviceRect = rect; - if (source) - deviceRect.scale(windowScaleFactor(source)); // scale up + deviceRect.scale(deviceScaleFactor); // scale up deviceRect.setY(NSMaxY([screenForWindow(source) frame]) - (deviceRect.y() + deviceRect.height())); // flip return deviceRect; } diff --git a/Source/WebCore/platform/mac/PopupMenuMac.h b/Source/WebCore/platform/mac/PopupMenuMac.h index 8e21913a2..8dd6aff60 100644 --- a/Source/WebCore/platform/mac/PopupMenuMac.h +++ b/Source/WebCore/platform/mac/PopupMenuMac.h @@ -26,11 +26,7 @@ #include <wtf/RefCounted.h> #include <wtf/RetainPtr.h> -#ifdef __OBJC__ -@class NSPopUpButtonCell; -#else -class NSPopUpButtonCell; -#endif +OBJC_CLASS NSPopUpButtonCell; namespace WebCore { diff --git a/Source/WebCore/platform/mac/RunLoopMac.mm b/Source/WebCore/platform/mac/RunLoopMac.mm new file mode 100644 index 000000000..46fa4c2cb --- /dev/null +++ b/Source/WebCore/platform/mac/RunLoopMac.mm @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "RunLoop.h" + +#import <dispatch/dispatch.h> + +namespace WebCore { + +static RunLoop* s_mainRunLoop; + +void RunLoop::initializeMainRunLoop() +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + s_mainRunLoop = new RunLoop(CFRunLoopGetMain()); + }); +} + +RunLoop* RunLoop::current() +{ + if (pthread_main_np()) + return RunLoop::main(); + + DEFINE_STATIC_LOCAL(WTF::ThreadSpecific<RunLoop>, runLoopData, ()); + return &*runLoopData; +} + +RunLoop* RunLoop::main() +{ + ASSERT(s_mainRunLoop); + return s_mainRunLoop; +} + +void RunLoop::performWork(void* context) +{ + // Wrap main thread in an Autorelease pool. Sending messages can call + // into objc code and accumulate memory. + if (current() == main()) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + static_cast<RunLoop*>(context)->performWork(); + [pool drain]; + } else + static_cast<RunLoop*>(context)->performWork(); +} + +RunLoop::RunLoop() + : m_runLoop(CFRunLoopGetCurrent()) + , m_nestingLevel(0) +{ + CFRunLoopSourceContext context = { 0, this, 0, 0, 0, 0, 0, 0, 0, performWork }; + m_runLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context); + CFRunLoopAddSource(m_runLoop, m_runLoopSource, kCFRunLoopCommonModes); +} + +RunLoop::RunLoop(CFRunLoopRef runLoop) + : m_runLoop(runLoop) + , m_nestingLevel(0) +{ + CFRunLoopSourceContext context = { 0, this, 0, 0, 0, 0, 0, 0, 0, performWork }; + m_runLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context); + CFRunLoopAddSource(m_runLoop, m_runLoopSource, kCFRunLoopCommonModes); +} + +RunLoop::~RunLoop() +{ + // FIXME: Tear down the work item queue here. + CFRunLoopSourceInvalidate(m_runLoopSource); + CFRelease(m_runLoopSource); +} + +void RunLoop::run() +{ + current()->m_nestingLevel++; + if (current() == main() && current()->m_nestingLevel == 1) { + // Use -[NSApplication run] for the main run loop. + [NSApp run]; + } else { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + CFRunLoopRun(); + [pool drain]; + } + current()->m_nestingLevel--; +} + +void RunLoop::runForDuration(double duration) +{ + CFRunLoopRunInMode(kCFRunLoopDefaultMode, duration, true); +} + +void RunLoop::stop() +{ + ASSERT(m_runLoop == CFRunLoopGetCurrent()); + + if (m_runLoop == main()->m_runLoop && m_nestingLevel == 1) { + [NSApp stop:nil]; + NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined + location:NSMakePoint(0, 0) + modifierFlags:0 + timestamp:0.0 + windowNumber:0 + context:nil + subtype: 0 + data1:0 + data2:0]; + [NSApp postEvent:event atStart:true]; + } else + CFRunLoopStop(m_runLoop); +} + +void RunLoop::wakeUp() +{ + CFRunLoopSourceSignal(m_runLoopSource); + CFRunLoopWakeUp(m_runLoop); +} + +// RunLoop::Timer + +void RunLoop::TimerBase::timerFired(CFRunLoopTimerRef, void* context) +{ + TimerBase* timer = static_cast<TimerBase*>(context); + + // Wrap main thread in an Autorelease pool. The timer can call + // into objc code and accumulate memory outside of the main event loop. + if (current() == main()) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + timer->fired(); + [pool drain]; + } else + timer->fired(); +} + +RunLoop::TimerBase::TimerBase(RunLoop* runLoop) + : m_runLoop(runLoop) + , m_timer(0) +{ +} + +RunLoop::TimerBase::~TimerBase() +{ + stop(); +} + +void RunLoop::TimerBase::start(double nextFireInterval, bool repeat) +{ + if (m_timer) + stop(); + + CFRunLoopTimerContext context = { 0, this, 0, 0, 0 }; + CFTimeInterval repeatInterval = repeat ? nextFireInterval : 0; + m_timer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + nextFireInterval, repeatInterval, 0, 0, timerFired, &context); + CFRunLoopAddTimer(m_runLoop->m_runLoop, m_timer, kCFRunLoopCommonModes); +} + +void RunLoop::TimerBase::stop() +{ + if (!m_timer) + return; + + CFRunLoopTimerInvalidate(m_timer); + CFRelease(m_timer); + m_timer = 0; +} + +bool RunLoop::TimerBase::isActive() const +{ + return m_timer && CFRunLoopTimerIsValid(m_timer); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/mac/ScrollAnimatorMac.h b/Source/WebCore/platform/mac/ScrollAnimatorMac.h index 94383ca5e..c8d9b232a 100644 --- a/Source/WebCore/platform/mac/ScrollAnimatorMac.h +++ b/Source/WebCore/platform/mac/ScrollAnimatorMac.h @@ -36,15 +36,9 @@ #include "Timer.h" #include <wtf/RetainPtr.h> -#ifdef __OBJC__ -@class WebScrollAnimationHelperDelegate; -@class WebScrollbarPainterControllerDelegate; -@class WebScrollbarPainterDelegate; -#else -class WebScrollAnimationHelperDelegate; -class WebScrollbarPainterControllerDelegate; -class WebScrollbarPainterDelegate; -#endif +OBJC_CLASS WebScrollAnimationHelperDelegate; +OBJC_CLASS WebScrollbarPainterControllerDelegate; +OBJC_CLASS WebScrollbarPainterDelegate; typedef id ScrollbarPainterController; @@ -90,9 +84,6 @@ private: #if ENABLE(RUBBER_BANDING) virtual bool handleWheelEvent(const PlatformWheelEvent&) OVERRIDE; -#if ENABLE(GESTURE_EVENTS) - virtual void handleGestureEvent(const PlatformGestureEvent&); -#endif #endif virtual void cancelAnimations(); @@ -118,6 +109,8 @@ private: virtual void didAddHorizontalScrollbar(Scrollbar*); virtual void willRemoveHorizontalScrollbar(Scrollbar*); + virtual bool shouldScrollbarParticipateInHitTesting(Scrollbar*); + float adjustScrollXPositionIfNecessary(float) const; float adjustScrollYPositionIfNecessary(float) const; FloatPoint adjustScrollPositionIfNecessary(const FloatPoint&) const; @@ -127,31 +120,23 @@ private: #if ENABLE(RUBBER_BANDING) /// ScrollElasticityControllerClient member functions. virtual IntSize stretchAmount() OVERRIDE; + virtual bool allowsHorizontalStretching() OVERRIDE; + virtual bool allowsVerticalStretching() OVERRIDE; virtual bool pinnedInDirection(const FloatSize&) OVERRIDE; virtual bool canScrollHorizontally() OVERRIDE; virtual bool canScrollVertically() OVERRIDE; + virtual bool shouldRubberBandInDirection(ScrollDirection) OVERRIDE; virtual WebCore::IntPoint absoluteScrollPosition() OVERRIDE; virtual void immediateScrollByWithoutContentEdgeConstraints(const FloatSize&) OVERRIDE; virtual void immediateScrollBy(const FloatSize&) OVERRIDE; virtual void startSnapRubberbandTimer() OVERRIDE; virtual void stopSnapRubberbandTimer() OVERRIDE; - bool allowsVerticalStretching() const; - bool allowsHorizontalStretching() const; bool pinnedInDirection(float deltaX, float deltaY); - void snapRubberBand(); void snapRubberBandTimerFired(Timer<ScrollAnimatorMac>*); - bool smoothScrollWithEvent(const PlatformWheelEvent&); - void beginScrollGesture(); - void endScrollGesture(); ScrollElasticityController m_scrollElasticityController; Timer<ScrollAnimatorMac> m_snapRubberBandTimer; - - bool m_scrollerInitiallyPinnedOnLeft; - bool m_scrollerInitiallyPinnedOnRight; - int m_cumulativeHorizontalScroll; - bool m_didCumulativeHorizontalScrollEverSwitchToOppositeDirectionOfPin; #endif bool m_haveScrolledSincePageLoad; diff --git a/Source/WebCore/platform/mac/ScrollAnimatorMac.mm b/Source/WebCore/platform/mac/ScrollAnimatorMac.mm index 4011f33e8..7bed38f1b 100644 --- a/Source/WebCore/platform/mac/ScrollAnimatorMac.mm +++ b/Source/WebCore/platform/mac/ScrollAnimatorMac.mm @@ -40,20 +40,12 @@ #include "ScrollbarTheme.h" #include "ScrollbarThemeMac.h" #include "WebCoreSystemInterface.h" -#include <sys/time.h> -#include <sys/sysctl.h> #include <wtf/PassOwnPtr.h> #include <wtf/UnusedParam.h> using namespace WebCore; using namespace std; -#ifdef BUILDING_ON_LEOPARD -@interface NSProcessInfo (ScrollAnimatorMacExt) -- (NSTimeInterval)systemUptime; -@end -#endif - static bool supportsUIStateTransitionProgress() { // FIXME: This is temporary until all platforms that support ScrollbarPainter support this part of the API. @@ -75,31 +67,6 @@ static ScrollbarPainter scrollbarPainterForScrollbar(Scrollbar* scrollbar) return nil; } -#if ENABLE(RUBBER_BANDING) -static NSTimeInterval systemUptime() -{ - if ([[NSProcessInfo processInfo] respondsToSelector:@selector(systemUptime)]) - return [[NSProcessInfo processInfo] systemUptime]; - - // Get how long system has been up. Found by looking getting "boottime" from the kernel. - static struct timeval boottime = {0, 0}; - if (!boottime.tv_sec) { - int mib[2] = {CTL_KERN, KERN_BOOTTIME}; - size_t size = sizeof(boottime); - if (-1 == sysctl(mib, 2, &boottime, &size, 0, 0)) - boottime.tv_sec = 0; - } - struct timeval now; - if (boottime.tv_sec && -1 != gettimeofday(&now, 0)) { - struct timeval uptime; - timersub(&now, &boottime, &uptime); - NSTimeInterval result = uptime.tv_sec + (uptime.tv_usec / 1E+6); - return result; - } - return 0; -} -#endif - @interface NSObject (ScrollAnimationHelperDetails) - (id)initWithDelegate:(id)delegate; - (void)_stopRun; @@ -586,10 +553,6 @@ ScrollAnimatorMac::ScrollAnimatorMac(ScrollableArea* scrollableArea) #if ENABLE(RUBBER_BANDING) , m_scrollElasticityController(this) , m_snapRubberBandTimer(this, &ScrollAnimatorMac::snapRubberBandTimerFired) - , m_scrollerInitiallyPinnedOnLeft(false) - , m_scrollerInitiallyPinnedOnRight(false) - , m_cumulativeHorizontalScroll(0) - , m_didCumulativeHorizontalScrollEverSwitchToOppositeDirectionOfPin(false) #endif , m_haveScrolledSincePageLoad(false) , m_needsScrollerStyleUpdate(false) @@ -742,8 +705,13 @@ void ScrollAnimatorMac::mouseMovedInContentArea() const void ScrollAnimatorMac::mouseEnteredScrollbar(Scrollbar* scrollbar) const { + // At this time, only legacy scrollbars needs to send notifications here. + if (recommendedScrollerStyle() != NSScrollerStyleLegacy) + return; + if (!scrollableArea()->isOnActivePage()) return; + if (isScrollbarOverlayAPIAvailable()) { if (!supportsUIStateTransitionProgress()) return; @@ -754,8 +722,13 @@ void ScrollAnimatorMac::mouseEnteredScrollbar(Scrollbar* scrollbar) const void ScrollAnimatorMac::mouseExitedScrollbar(Scrollbar* scrollbar) const { + // At this time, only legacy scrollbars needs to send notifications here. + if (recommendedScrollerStyle() != NSScrollerStyleLegacy) + return; + if (!scrollableArea()->isOnActivePage()) return; + if (isScrollbarOverlayAPIAvailable()) { if (!supportsUIStateTransitionProgress()) return; @@ -886,6 +859,22 @@ void ScrollAnimatorMac::willRemoveHorizontalScrollbar(Scrollbar* scrollbar) } } +bool ScrollAnimatorMac::shouldScrollbarParticipateInHitTesting(Scrollbar* scrollbar) +{ + // Non-overlay scrollbars should always participate in hit testing. + if (recommendedScrollerStyle() != NSScrollerStyleOverlay) + return true; + + if (!isScrollbarOverlayAPIAvailable()) + return true; + + // Overlay scrollbars should participate in hit testing whenever they are at all visible. + ScrollbarPainter painter = scrollbarPainterForScrollbar(scrollbar); + if (!painter) + return false; + return [painter knobAlpha] > 0; +} + void ScrollAnimatorMac::cancelAnimations() { m_haveScrolledSincePageLoad = false; @@ -899,55 +888,6 @@ void ScrollAnimatorMac::cancelAnimations() } #if ENABLE(RUBBER_BANDING) - -static const float scrollVelocityZeroingTimeout = 0.10f; -static const float rubberbandStiffness = 20; -static const float rubberbandDirectionLockStretchRatio = 1; -static const float rubberbandMinimumRequiredDeltaBeforeStretch = 10; -static const float rubberbandAmplitude = 0.31f; -static const float rubberbandPeriod = 1.6f; - -static float elasticDeltaForTimeDelta(float initialPosition, float initialVelocity, float elapsedTime) -{ - float amplitude = rubberbandAmplitude; - float period = rubberbandPeriod; - float criticalDampeningFactor = expf((-elapsedTime * rubberbandStiffness) / period); - - return (initialPosition + (-initialVelocity * elapsedTime * amplitude)) * criticalDampeningFactor; -} - -static float elasticDeltaForReboundDelta(float delta) -{ - float stiffness = std::max(rubberbandStiffness, 1.0f); - return delta / stiffness; -} - -static float reboundDeltaForElasticDelta(float delta) -{ - return delta * rubberbandStiffness; -} - -static float scrollWheelMultiplier() -{ - static float multiplier = -1; - if (multiplier < 0) { - multiplier = [[NSUserDefaults standardUserDefaults] floatForKey:@"NSScrollWheelMultiplier"]; - if (multiplier <= 0) - multiplier = 1; - } - return multiplier; -} - -static inline bool isScrollingLeftAndShouldNotRubberBand(const PlatformWheelEvent& wheelEvent, ScrollableArea* scrollableArea) -{ - return wheelEvent.deltaX() > 0 && !scrollableArea->shouldRubberBandInDirection(ScrollLeft); -} - -static inline bool isScrollingRightAndShouldNotRubberBand(const PlatformWheelEvent& wheelEvent, ScrollableArea* scrollableArea) -{ - return wheelEvent.deltaX() < 0 && !scrollableArea->shouldRubberBandInDirection(ScrollRight); -} - bool ScrollAnimatorMac::handleWheelEvent(const PlatformWheelEvent& wheelEvent) { m_haveScrolledSincePageLoad = true; @@ -965,45 +905,18 @@ bool ScrollAnimatorMac::handleWheelEvent(const PlatformWheelEvent& wheelEvent) } else { if (!allowsHorizontalStretching()) return ScrollAnimator::handleWheelEvent(wheelEvent); - - if (m_scrollableArea->horizontalScrollbar()) { - // If there is a scrollbar, we aggregate the wheel events to get an - // overall trend of the scroll. If the direction of the scroll is ever - // in the opposite direction of the pin location, then we switch the - // boolean, and rubber band. That is, if we were pinned to the left, - // and we ended up scrolling to the right, we rubber band. - m_cumulativeHorizontalScroll += wheelEvent.deltaX(); - if (m_scrollerInitiallyPinnedOnLeft && m_cumulativeHorizontalScroll < 0) - m_didCumulativeHorizontalScrollEverSwitchToOppositeDirectionOfPin = true; - if (m_scrollerInitiallyPinnedOnRight && m_cumulativeHorizontalScroll > 0) - m_didCumulativeHorizontalScrollEverSwitchToOppositeDirectionOfPin = true; - } - - // After a gesture begins, we go through: - // 1+ PlatformWheelEventPhaseNone - // 0+ PlatformWheelEventPhaseChanged - // 1 PlatformWheelEventPhaseEnded if there was at least one changed event - if (wheelEvent.momentumPhase() == PlatformWheelEventPhaseNone && !m_didCumulativeHorizontalScrollEverSwitchToOppositeDirectionOfPin) { - if ((isScrollingLeftAndShouldNotRubberBand(wheelEvent, m_scrollableArea) && - m_scrollerInitiallyPinnedOnLeft && - m_scrollableArea->isHorizontalScrollerPinnedToMinimumPosition()) || - (isScrollingRightAndShouldNotRubberBand(wheelEvent, m_scrollableArea) && - m_scrollerInitiallyPinnedOnRight && - m_scrollableArea->isHorizontalScrollerPinnedToMaximumPosition())) { - return ScrollAnimator::handleWheelEvent(wheelEvent); - } - } } - return smoothScrollWithEvent(wheelEvent); -} + bool didHandleEvent = m_scrollElasticityController.handleWheelEvent(wheelEvent); -void ScrollAnimatorMac::handleGestureEvent(const PlatformGestureEvent& gestureEvent) -{ - if (gestureEvent.type() == PlatformEvent::GestureScrollBegin) - beginScrollGesture(); - else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd) - endScrollGesture(); + if (didHandleEvent) { + if (wheelEvent.phase() == PlatformWheelEventPhaseBegan) + didBeginScrollGesture(); + else if (wheelEvent.phase() == PlatformWheelEventPhaseEnded) + didEndScrollGesture(); + } + + return didHandleEvent; } bool ScrollAnimatorMac::pinnedInDirection(float deltaX, float deltaY) @@ -1032,6 +945,42 @@ bool ScrollAnimatorMac::pinnedInDirection(float deltaX, float deltaY) return false; } +bool ScrollAnimatorMac::allowsVerticalStretching() +{ + switch (m_scrollableArea->verticalScrollElasticity()) { + case ScrollElasticityAutomatic: { + Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); + Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); + return (((vScroller && vScroller->enabled()) || (!hScroller || !hScroller->enabled()))); + } + case ScrollElasticityNone: + return false; + case ScrollElasticityAllowed: + return true; + } + + ASSERT_NOT_REACHED(); + return false; +} + +bool ScrollAnimatorMac::allowsHorizontalStretching() +{ + switch (m_scrollableArea->horizontalScrollElasticity()) { + case ScrollElasticityAutomatic: { + Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); + Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); + return (((hScroller && hScroller->enabled()) || (!vScroller || !vScroller->enabled()))); + } + case ScrollElasticityNone: + return false; + case ScrollElasticityAllowed: + return true; + } + + ASSERT_NOT_REACHED(); + return false; +} + IntSize ScrollAnimatorMac::stretchAmount() { return m_scrollableArea->overhangAmount(); @@ -1058,6 +1007,11 @@ bool ScrollAnimatorMac::canScrollVertically() return scrollbar->enabled(); } +bool ScrollAnimatorMac::shouldRubberBandInDirection(ScrollDirection direction) +{ + return m_scrollableArea->shouldRubberBandInDirection(direction); +} + IntPoint ScrollAnimatorMac::absoluteScrollPosition() { return m_scrollableArea->visibleContentRect().location() + m_scrollableArea->scrollOrigin(); @@ -1093,313 +1047,9 @@ void ScrollAnimatorMac::stopSnapRubberbandTimer() m_snapRubberBandTimer.stop(); } -bool ScrollAnimatorMac::allowsVerticalStretching() const -{ - switch (m_scrollableArea->verticalScrollElasticity()) { - case ScrollElasticityAutomatic: { - Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); - Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); - return (((vScroller && vScroller->enabled()) || (!hScroller || !hScroller->enabled()))); - } - case ScrollElasticityNone: - return false; - case ScrollElasticityAllowed: - return true; - } - - ASSERT_NOT_REACHED(); - return false; -} - -bool ScrollAnimatorMac::allowsHorizontalStretching() const -{ - switch (m_scrollableArea->horizontalScrollElasticity()) { - case ScrollElasticityAutomatic: { - Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); - Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); - return (((hScroller && hScroller->enabled()) || (!vScroller || !vScroller->enabled()))); - } - case ScrollElasticityNone: - return false; - case ScrollElasticityAllowed: - return true; - } - - ASSERT_NOT_REACHED(); - return false; -} - -bool ScrollAnimatorMac::smoothScrollWithEvent(const PlatformWheelEvent& wheelEvent) -{ - bool isMomentumScrollEvent = (wheelEvent.momentumPhase() != PlatformWheelEventPhaseNone); - if (m_scrollElasticityController.m_ignoreMomentumScrolls && (isMomentumScrollEvent || m_scrollElasticityController.m_snapRubberbandTimerIsActive)) { - if (wheelEvent.momentumPhase() == PlatformWheelEventPhaseEnded) { - m_scrollElasticityController.m_ignoreMomentumScrolls = false; - return true; - } - return false; - } - - m_haveScrolledSincePageLoad = true; - - float deltaX = m_scrollElasticityController.m_overflowScrollDelta.width(); - float deltaY = m_scrollElasticityController.m_overflowScrollDelta.height(); - - // Reset overflow values because we may decide to remove delta at various points and put it into overflow. - m_scrollElasticityController.m_overflowScrollDelta = FloatSize(); - - float eventCoalescedDeltaX = -wheelEvent.deltaX(); - float eventCoalescedDeltaY = -wheelEvent.deltaY(); - - deltaX += eventCoalescedDeltaX; - deltaY += eventCoalescedDeltaY; - - // Slightly prefer scrolling vertically by applying the = case to deltaY - if (fabsf(deltaY) >= fabsf(deltaX)) - deltaX = 0; - else - deltaY = 0; - - bool isVerticallyStretched = false; - bool isHorizontallyStretched = false; - bool shouldStretch = false; - - IntSize stretchAmount = m_scrollElasticityController.m_client->stretchAmount(); - - isHorizontallyStretched = stretchAmount.width(); - isVerticallyStretched = stretchAmount.height(); - - PlatformWheelEventPhase phase = wheelEvent.momentumPhase(); - - // If we are starting momentum scrolling then do some setup. - if (!m_scrollElasticityController.m_momentumScrollInProgress && (phase == PlatformWheelEventPhaseBegan || phase == PlatformWheelEventPhaseChanged)) - m_scrollElasticityController.m_momentumScrollInProgress = true; - - CFTimeInterval timeDelta = wheelEvent.timestamp() - m_scrollElasticityController.m_lastMomentumScrollTimestamp; - if (m_scrollElasticityController.m_inScrollGesture || m_scrollElasticityController.m_momentumScrollInProgress) { - if (m_scrollElasticityController.m_lastMomentumScrollTimestamp && timeDelta > 0 && timeDelta < scrollVelocityZeroingTimeout) { - m_scrollElasticityController.m_momentumVelocity.setWidth(eventCoalescedDeltaX / (float)timeDelta); - m_scrollElasticityController.m_momentumVelocity.setHeight(eventCoalescedDeltaY / (float)timeDelta); - m_scrollElasticityController.m_lastMomentumScrollTimestamp = wheelEvent.timestamp(); - } else { - m_scrollElasticityController.m_lastMomentumScrollTimestamp = wheelEvent.timestamp(); - m_scrollElasticityController.m_momentumVelocity = FloatSize(); - } - - if (isVerticallyStretched) { - if (!isHorizontallyStretched && pinnedInDirection(deltaX, 0)) { - // Stretching only in the vertical. - if (deltaY != 0 && (fabsf(deltaX / deltaY) < rubberbandDirectionLockStretchRatio)) - deltaX = 0; - else if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStretch) { - m_scrollElasticityController.m_overflowScrollDelta.setWidth(m_scrollElasticityController.m_overflowScrollDelta.width() + deltaX); - deltaX = 0; - } else - m_scrollElasticityController.m_overflowScrollDelta.setWidth(m_scrollElasticityController.m_overflowScrollDelta.width() + deltaX); - } - } else if (isHorizontallyStretched) { - // Stretching only in the horizontal. - if (pinnedInDirection(0, deltaY)) { - if (deltaX != 0 && (fabsf(deltaY / deltaX) < rubberbandDirectionLockStretchRatio)) - deltaY = 0; - else if (fabsf(deltaY) < rubberbandMinimumRequiredDeltaBeforeStretch) { - m_scrollElasticityController.m_overflowScrollDelta.setHeight(m_scrollElasticityController.m_overflowScrollDelta.height() + deltaY); - deltaY = 0; - } else - m_scrollElasticityController.m_overflowScrollDelta.setHeight(m_scrollElasticityController.m_overflowScrollDelta.height() + deltaY); - } - } else { - // Not stretching at all yet. - if (pinnedInDirection(deltaX, deltaY)) { - if (fabsf(deltaY) >= fabsf(deltaX)) { - if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStretch) { - m_scrollElasticityController.m_overflowScrollDelta.setWidth(m_scrollElasticityController.m_overflowScrollDelta.width() + deltaX); - deltaX = 0; - } else - m_scrollElasticityController.m_overflowScrollDelta.setWidth(m_scrollElasticityController.m_overflowScrollDelta.width() + deltaX); - } - shouldStretch = true; - } - } - } - - if (deltaX != 0 || deltaY != 0) { - if (!(shouldStretch || isVerticallyStretched || isHorizontallyStretched)) { - if (deltaY != 0) { - deltaY *= scrollWheelMultiplier(); - m_scrollElasticityController.m_client->immediateScrollBy(FloatSize(0, deltaY)); - } - if (deltaX != 0) { - deltaX *= scrollWheelMultiplier(); - m_scrollElasticityController.m_client->immediateScrollBy(FloatSize(deltaX, 0)); - } - } else { - if (!allowsHorizontalStretching()) { - deltaX = 0; - eventCoalescedDeltaX = 0; - } else if ((deltaX != 0) && !isHorizontallyStretched && !pinnedInDirection(deltaX, 0)) { - deltaX *= scrollWheelMultiplier(); - - m_scrollElasticityController.m_client->immediateScrollByWithoutContentEdgeConstraints(FloatSize(deltaX, 0)); - deltaX = 0; - } - - if (!allowsVerticalStretching()) { - deltaY = 0; - eventCoalescedDeltaY = 0; - } else if ((deltaY != 0) && !isVerticallyStretched && !pinnedInDirection(0, deltaY)) { - deltaY *= scrollWheelMultiplier(); - - m_scrollElasticityController.m_client->immediateScrollByWithoutContentEdgeConstraints(FloatSize(0, deltaY)); - deltaY = 0; - } - - IntSize stretchAmount = m_scrollElasticityController.m_client->stretchAmount(); - - if (m_scrollElasticityController.m_momentumScrollInProgress) { - if ((pinnedInDirection(eventCoalescedDeltaX, eventCoalescedDeltaY) || (fabsf(eventCoalescedDeltaX) + fabsf(eventCoalescedDeltaY) <= 0)) && m_scrollElasticityController.m_lastMomentumScrollTimestamp) { - m_scrollElasticityController.m_ignoreMomentumScrolls = true; - m_scrollElasticityController.m_momentumScrollInProgress = false; - snapRubberBand(); - } - } - - m_scrollElasticityController.m_stretchScrollForce.setWidth(m_scrollElasticityController.m_stretchScrollForce.width() + deltaX); - m_scrollElasticityController.m_stretchScrollForce.setHeight(m_scrollElasticityController.m_stretchScrollForce.height() + deltaY); - - FloatSize dampedDelta(ceilf(elasticDeltaForReboundDelta(m_scrollElasticityController.m_stretchScrollForce.width())), ceilf(elasticDeltaForReboundDelta(m_scrollElasticityController.m_stretchScrollForce.height()))); - - m_scrollElasticityController.m_client->immediateScrollByWithoutContentEdgeConstraints(dampedDelta - stretchAmount); - } - } - - if (m_scrollElasticityController.m_momentumScrollInProgress && phase == PlatformWheelEventPhaseEnded) { - m_scrollElasticityController.m_momentumScrollInProgress = false; - m_scrollElasticityController.m_ignoreMomentumScrolls = false; - m_scrollElasticityController.m_lastMomentumScrollTimestamp = 0; - } - - return true; -} - -void ScrollAnimatorMac::beginScrollGesture() -{ - didBeginScrollGesture(); - - m_scrollerInitiallyPinnedOnLeft = m_scrollableArea->isHorizontalScrollerPinnedToMinimumPosition(); - m_scrollerInitiallyPinnedOnRight = m_scrollableArea->isHorizontalScrollerPinnedToMaximumPosition(); - m_haveScrolledSincePageLoad = true; - m_cumulativeHorizontalScroll = 0; - m_didCumulativeHorizontalScrollEverSwitchToOppositeDirectionOfPin = false; - - m_scrollElasticityController.beginScrollGesture(); -} - -void ScrollAnimatorMac::endScrollGesture() -{ - didEndScrollGesture(); - - snapRubberBand(); -} - -void ScrollAnimatorMac::snapRubberBand() -{ - CFTimeInterval timeDelta = systemUptime() - m_scrollElasticityController.m_lastMomentumScrollTimestamp; - if (m_scrollElasticityController.m_lastMomentumScrollTimestamp && timeDelta >= scrollVelocityZeroingTimeout) - m_scrollElasticityController.m_momentumVelocity = FloatSize(); - - m_scrollElasticityController.m_inScrollGesture = false; - - if (m_scrollElasticityController.m_snapRubberbandTimerIsActive) - return; - - m_scrollElasticityController.m_startTime = [NSDate timeIntervalSinceReferenceDate]; - m_scrollElasticityController.m_startStretch = FloatSize(); - m_scrollElasticityController.m_origOrigin = FloatPoint(); - m_scrollElasticityController.m_origVelocity = FloatSize(); - - m_scrollElasticityController.m_client->startSnapRubberbandTimer(); - m_scrollElasticityController.m_snapRubberbandTimerIsActive = true; -} - -static inline float roundTowardZero(float num) -{ - return num > 0 ? ceilf(num - 0.5f) : floorf(num + 0.5f); -} - -static inline float roundToDevicePixelTowardZero(float num) -{ - float roundedNum = roundf(num); - if (fabs(num - roundedNum) < 0.125) - num = roundedNum; - - return roundTowardZero(num); -} - void ScrollAnimatorMac::snapRubberBandTimerFired(Timer<ScrollAnimatorMac>*) { - if (!m_scrollElasticityController.m_momentumScrollInProgress || m_scrollElasticityController.m_ignoreMomentumScrolls) { - CFTimeInterval timeDelta = [NSDate timeIntervalSinceReferenceDate] - m_scrollElasticityController.m_startTime; - - if (m_scrollElasticityController.m_startStretch == FloatSize()) { - m_scrollElasticityController.m_startStretch = m_scrollElasticityController.m_client->stretchAmount(); - if (m_scrollElasticityController.m_startStretch == FloatSize()) { - m_scrollElasticityController.m_client->stopSnapRubberbandTimer(); - - m_scrollElasticityController.m_stretchScrollForce = FloatSize(); - m_scrollElasticityController.m_startTime = 0; - m_scrollElasticityController.m_startStretch = FloatSize(); - m_scrollElasticityController.m_origOrigin = FloatPoint(); - m_scrollElasticityController.m_origVelocity = FloatSize(); - m_scrollElasticityController.m_snapRubberbandTimerIsActive = false; - - return; - } - - m_scrollElasticityController.m_origOrigin = m_scrollElasticityController.m_client->absoluteScrollPosition() - m_scrollElasticityController.m_startStretch; - m_scrollElasticityController.m_origVelocity = m_scrollElasticityController.m_momentumVelocity; - - // Just like normal scrolling, prefer vertical rubberbanding - if (fabsf(m_scrollElasticityController.m_origVelocity.height()) >= fabsf(m_scrollElasticityController.m_origVelocity.width())) - m_scrollElasticityController.m_origVelocity.setWidth(0); - - // Don't rubber-band horizontally if it's not possible to scroll horizontally - if (!m_scrollElasticityController.m_client->canScrollHorizontally()) - m_scrollElasticityController.m_origVelocity.setWidth(0); - - // Don't rubber-band vertically if it's not possible to scroll vertically - if (!m_scrollElasticityController.m_client->canScrollVertically()) - m_scrollElasticityController.m_origVelocity.setHeight(0); - } - - FloatPoint delta(roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m_scrollElasticityController.m_startStretch.width(), -m_scrollElasticityController.m_origVelocity.width(), (float)timeDelta)), - roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m_scrollElasticityController.m_startStretch.height(), -m_scrollElasticityController.m_origVelocity.height(), (float)timeDelta))); - - if (fabs(delta.x()) >= 1 || fabs(delta.y()) >= 1) { - FloatPoint newOrigin = m_scrollElasticityController.m_origOrigin + delta; - - m_scrollElasticityController.m_client->immediateScrollByWithoutContentEdgeConstraints(FloatSize(delta.x(), delta.y()) - m_scrollElasticityController.m_client->stretchAmount()); - - FloatSize newStretch = m_scrollElasticityController.m_client->stretchAmount(); - - m_scrollElasticityController.m_stretchScrollForce.setWidth(reboundDeltaForElasticDelta(newStretch.width())); - m_scrollElasticityController.m_stretchScrollForce.setHeight(reboundDeltaForElasticDelta(newStretch.height())); - } else { - immediateScrollTo(m_scrollElasticityController.m_origOrigin); - - m_scrollElasticityController.m_client->stopSnapRubberbandTimer(); - - m_scrollElasticityController.m_stretchScrollForce = FloatSize(); - m_scrollElasticityController.m_startTime = 0; - m_scrollElasticityController.m_startStretch = FloatSize(); - m_scrollElasticityController.m_origOrigin = FloatPoint(); - m_scrollElasticityController.m_origVelocity = FloatSize(); - m_scrollElasticityController.m_snapRubberbandTimerIsActive = false; - } - } else { - m_scrollElasticityController.m_startTime = [NSDate timeIntervalSinceReferenceDate]; - m_scrollElasticityController.m_startStretch = FloatSize(); - } + m_scrollElasticityController.snapRubberBandTimerFired(); } #endif @@ -1440,8 +1090,8 @@ void ScrollAnimatorMac::updateScrollerStyle() controlSize:(NSControlSize)verticalScrollbar->controlSize() horizontal:NO replacingScrollerImp:oldVerticalPainter]; - macTheme->setNewPainterForScrollbar(verticalScrollbar, newVerticalPainter); [m_scrollbarPainterController.get() setVerticalScrollerImp:newVerticalPainter]; + macTheme->setNewPainterForScrollbar(verticalScrollbar, newVerticalPainter); // The different scrollbar styles have different thicknesses, so we must re-set the // frameRect to the new thickness, and the re-layout below will ensure the position @@ -1458,8 +1108,8 @@ void ScrollAnimatorMac::updateScrollerStyle() controlSize:(NSControlSize)horizontalScrollbar->controlSize() horizontal:YES replacingScrollerImp:oldHorizontalPainter]; - macTheme->setNewPainterForScrollbar(horizontalScrollbar, newHorizontalPainter); [m_scrollbarPainterController.get() setHorizontalScrollerImp:newHorizontalPainter]; + macTheme->setNewPainterForScrollbar(horizontalScrollbar, newHorizontalPainter); // The different scrollbar styles have different thicknesses, so we must re-set the // frameRect to the new thickness, and the re-layout below will ensure the position diff --git a/Source/WebCore/platform/mac/ScrollElasticityController.h b/Source/WebCore/platform/mac/ScrollElasticityController.h index 066184473..9f52443b8 100644 --- a/Source/WebCore/platform/mac/ScrollElasticityController.h +++ b/Source/WebCore/platform/mac/ScrollElasticityController.h @@ -30,19 +30,25 @@ #include "FloatPoint.h" #include "FloatSize.h" +#include "ScrollTypes.h" #include <wtf/Noncopyable.h> namespace WebCore { +class PlatformWheelEvent; + class ScrollElasticityControllerClient { protected: virtual ~ScrollElasticityControllerClient() { } public: + virtual bool allowsHorizontalStretching() = 0; + virtual bool allowsVerticalStretching() = 0; virtual IntSize stretchAmount() = 0; virtual bool pinnedInDirection(const FloatSize&) = 0; virtual bool canScrollHorizontally() = 0; virtual bool canScrollVertically() = 0; + virtual bool shouldRubberBandInDirection(ScrollDirection) = 0; // Return the absolute scroll position, not relative to the scroll origin. virtual WebCore::IntPoint absoluteScrollPosition() = 0; @@ -59,14 +65,15 @@ class ScrollElasticityController { public: explicit ScrollElasticityController(ScrollElasticityControllerClient*); - void beginScrollGesture(); + bool handleWheelEvent(const PlatformWheelEvent&); + void snapRubberBandTimerFired(); private: void stopSnapRubberbandTimer(); + void snapRubberBand(); + + bool shouldRubberBandInHorizontalDirection(const PlatformWheelEvent&); - // FIXME: These member variables should be private. They are currently public as a stop-gap measure, while - // the rubber-band related code from ScrollAnimatorMac is being moved over. -public: ScrollElasticityControllerClient* m_client; bool m_inScrollGesture; diff --git a/Source/WebCore/platform/mac/ScrollElasticityController.mm b/Source/WebCore/platform/mac/ScrollElasticityController.mm index fa841337e..d3247142b 100644 --- a/Source/WebCore/platform/mac/ScrollElasticityController.mm +++ b/Source/WebCore/platform/mac/ScrollElasticityController.mm @@ -26,17 +26,84 @@ #include "config.h" #include "ScrollElasticityController.h" +#include "PlatformWheelEvent.h" +#include <sys/time.h> +#include <sys/sysctl.h> + #if ENABLE(RUBBER_BANDING) +#ifdef BUILDING_ON_LEOPARD +@interface NSProcessInfo (ScrollAnimatorMacExt) +- (NSTimeInterval)systemUptime; +@end +#endif + +#if ENABLE(RUBBER_BANDING) +static NSTimeInterval systemUptime() +{ + if ([[NSProcessInfo processInfo] respondsToSelector:@selector(systemUptime)]) + return [[NSProcessInfo processInfo] systemUptime]; + + // Get how long system has been up. Found by looking getting "boottime" from the kernel. + static struct timeval boottime = {0, 0}; + if (!boottime.tv_sec) { + int mib[2] = {CTL_KERN, KERN_BOOTTIME}; + size_t size = sizeof(boottime); + if (-1 == sysctl(mib, 2, &boottime, &size, 0, 0)) + boottime.tv_sec = 0; + } + struct timeval now; + if (boottime.tv_sec && -1 != gettimeofday(&now, 0)) { + struct timeval uptime; + timersub(&now, &boottime, &uptime); + NSTimeInterval result = uptime.tv_sec + (uptime.tv_usec / 1E+6); + return result; + } + return 0; +} +#endif + + namespace WebCore { +static const float scrollVelocityZeroingTimeout = 0.10f; static const float rubberbandStiffness = 20; +static const float rubberbandDirectionLockStretchRatio = 1; +static const float rubberbandMinimumRequiredDeltaBeforeStretch = 10; +static const float rubberbandAmplitude = 0.31f; +static const float rubberbandPeriod = 1.6f; + +static float elasticDeltaForTimeDelta(float initialPosition, float initialVelocity, float elapsedTime) +{ + float amplitude = rubberbandAmplitude; + float period = rubberbandPeriod; + float criticalDampeningFactor = expf((-elapsedTime * rubberbandStiffness) / period); + + return (initialPosition + (-initialVelocity * elapsedTime * amplitude)) * criticalDampeningFactor; +} + +static float elasticDeltaForReboundDelta(float delta) +{ + float stiffness = std::max(rubberbandStiffness, 1.0f); + return delta / stiffness; +} static float reboundDeltaForElasticDelta(float delta) { return delta * rubberbandStiffness; } +static float scrollWheelMultiplier() +{ + static float multiplier = -1; + if (multiplier < 0) { + multiplier = [[NSUserDefaults standardUserDefaults] floatForKey:@"NSScrollWheelMultiplier"]; + if (multiplier <= 0) + multiplier = 1; + } + return multiplier; +} + ScrollElasticityController::ScrollElasticityController(ScrollElasticityControllerClient* client) : m_client(client) , m_inScrollGesture(false) @@ -48,21 +115,256 @@ ScrollElasticityController::ScrollElasticityController(ScrollElasticityControlle { } -void ScrollElasticityController::beginScrollGesture() +bool ScrollElasticityController::handleWheelEvent(const PlatformWheelEvent& wheelEvent) { - m_inScrollGesture = true; - m_momentumScrollInProgress = false; - m_ignoreMomentumScrolls = false; - m_lastMomentumScrollTimestamp = 0; - m_momentumVelocity = FloatSize(); - - IntSize stretchAmount = m_client->stretchAmount(); - m_stretchScrollForce.setWidth(reboundDeltaForElasticDelta(stretchAmount.width())); - m_stretchScrollForce.setHeight(reboundDeltaForElasticDelta(stretchAmount.height())); - + if (wheelEvent.phase() == PlatformWheelEventPhaseBegan) { + // First, check if we should rubber-band at all. + if (m_client->pinnedInDirection(FloatSize(-wheelEvent.deltaX(), 0)) && + !shouldRubberBandInHorizontalDirection(wheelEvent)) + return false; + + m_inScrollGesture = true; + m_momentumScrollInProgress = false; + m_ignoreMomentumScrolls = false; + m_lastMomentumScrollTimestamp = 0; + m_momentumVelocity = FloatSize(); + + IntSize stretchAmount = m_client->stretchAmount(); + m_stretchScrollForce.setWidth(reboundDeltaForElasticDelta(stretchAmount.width())); + m_stretchScrollForce.setHeight(reboundDeltaForElasticDelta(stretchAmount.height())); + m_overflowScrollDelta = FloatSize(); + + stopSnapRubberbandTimer(); + + return true; + } + + if (wheelEvent.phase() == PlatformWheelEventPhaseEnded) { + snapRubberBand(); + return true; + } + + bool isMomentumScrollEvent = (wheelEvent.momentumPhase() != PlatformWheelEventPhaseNone); + if (m_ignoreMomentumScrolls && (isMomentumScrollEvent || m_snapRubberbandTimerIsActive)) { + if (wheelEvent.momentumPhase() == PlatformWheelEventPhaseEnded) { + m_ignoreMomentumScrolls = false; + return true; + } + return false; + } + + float deltaX = m_overflowScrollDelta.width(); + float deltaY = m_overflowScrollDelta.height(); + + // Reset overflow values because we may decide to remove delta at various points and put it into overflow. m_overflowScrollDelta = FloatSize(); - stopSnapRubberbandTimer(); + float eventCoalescedDeltaX = -wheelEvent.deltaX(); + float eventCoalescedDeltaY = -wheelEvent.deltaY(); + + deltaX += eventCoalescedDeltaX; + deltaY += eventCoalescedDeltaY; + + // Slightly prefer scrolling vertically by applying the = case to deltaY + if (fabsf(deltaY) >= fabsf(deltaX)) + deltaX = 0; + else + deltaY = 0; + + bool isVerticallyStretched = false; + bool isHorizontallyStretched = false; + bool shouldStretch = false; + + IntSize stretchAmount = m_client->stretchAmount(); + + isHorizontallyStretched = stretchAmount.width(); + isVerticallyStretched = stretchAmount.height(); + + PlatformWheelEventPhase momentumPhase = wheelEvent.momentumPhase(); + + // If we are starting momentum scrolling then do some setup. + if (!m_momentumScrollInProgress && (momentumPhase == PlatformWheelEventPhaseBegan || momentumPhase == PlatformWheelEventPhaseChanged)) + m_momentumScrollInProgress = true; + + CFTimeInterval timeDelta = wheelEvent.timestamp() - m_lastMomentumScrollTimestamp; + if (m_inScrollGesture || m_momentumScrollInProgress) { + if (m_lastMomentumScrollTimestamp && timeDelta > 0 && timeDelta < scrollVelocityZeroingTimeout) { + m_momentumVelocity.setWidth(eventCoalescedDeltaX / (float)timeDelta); + m_momentumVelocity.setHeight(eventCoalescedDeltaY / (float)timeDelta); + m_lastMomentumScrollTimestamp = wheelEvent.timestamp(); + } else { + m_lastMomentumScrollTimestamp = wheelEvent.timestamp(); + m_momentumVelocity = FloatSize(); + } + + if (isVerticallyStretched) { + if (!isHorizontallyStretched && m_client->pinnedInDirection(FloatSize(deltaX, 0))) { + // Stretching only in the vertical. + if (deltaY != 0 && (fabsf(deltaX / deltaY) < rubberbandDirectionLockStretchRatio)) + deltaX = 0; + else if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStretch) { + m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); + deltaX = 0; + } else + m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); + } + } else if (isHorizontallyStretched) { + // Stretching only in the horizontal. + if (m_client->pinnedInDirection(FloatSize(0, deltaY))) { + if (deltaX != 0 && (fabsf(deltaY / deltaX) < rubberbandDirectionLockStretchRatio)) + deltaY = 0; + else if (fabsf(deltaY) < rubberbandMinimumRequiredDeltaBeforeStretch) { + m_overflowScrollDelta.setHeight(m_overflowScrollDelta.height() + deltaY); + deltaY = 0; + } else + m_overflowScrollDelta.setHeight(m_overflowScrollDelta.height() + deltaY); + } + } else { + // Not stretching at all yet. + if (m_client->pinnedInDirection(FloatSize(deltaX, deltaY))) { + if (fabsf(deltaY) >= fabsf(deltaX)) { + if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStretch) { + m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); + deltaX = 0; + } else + m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); + } + shouldStretch = true; + } + } + } + + if (deltaX != 0 || deltaY != 0) { + if (!(shouldStretch || isVerticallyStretched || isHorizontallyStretched)) { + if (deltaY != 0) { + deltaY *= scrollWheelMultiplier(); + m_client->immediateScrollBy(FloatSize(0, deltaY)); + } + if (deltaX != 0) { + deltaX *= scrollWheelMultiplier(); + m_client->immediateScrollBy(FloatSize(deltaX, 0)); + } + } else { + if (!m_client->allowsHorizontalStretching()) { + deltaX = 0; + eventCoalescedDeltaX = 0; + } else if ((deltaX != 0) && !isHorizontallyStretched && !m_client->pinnedInDirection(FloatSize(deltaX, 0))) { + deltaX *= scrollWheelMultiplier(); + + m_client->immediateScrollByWithoutContentEdgeConstraints(FloatSize(deltaX, 0)); + deltaX = 0; + } + + if (!m_client->allowsVerticalStretching()) { + deltaY = 0; + eventCoalescedDeltaY = 0; + } else if ((deltaY != 0) && !isVerticallyStretched && !m_client->pinnedInDirection(FloatSize(0, deltaY))) { + deltaY *= scrollWheelMultiplier(); + + m_client->immediateScrollByWithoutContentEdgeConstraints(FloatSize(0, deltaY)); + deltaY = 0; + } + + IntSize stretchAmount = m_client->stretchAmount(); + + if (m_momentumScrollInProgress) { + if ((m_client->pinnedInDirection(FloatSize(eventCoalescedDeltaX, eventCoalescedDeltaY)) || (fabsf(eventCoalescedDeltaX) + fabsf(eventCoalescedDeltaY) <= 0)) && m_lastMomentumScrollTimestamp) { + m_ignoreMomentumScrolls = true; + m_momentumScrollInProgress = false; + snapRubberBand(); + } + } + + m_stretchScrollForce.setWidth(m_stretchScrollForce.width() + deltaX); + m_stretchScrollForce.setHeight(m_stretchScrollForce.height() + deltaY); + + FloatSize dampedDelta(ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.width())), ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.height()))); + + m_client->immediateScrollByWithoutContentEdgeConstraints(dampedDelta - stretchAmount); + } + } + + if (m_momentumScrollInProgress && momentumPhase == PlatformWheelEventPhaseEnded) { + m_momentumScrollInProgress = false; + m_ignoreMomentumScrolls = false; + m_lastMomentumScrollTimestamp = 0; + } + + return true; +} + +static inline float roundTowardZero(float num) +{ + return num > 0 ? ceilf(num - 0.5f) : floorf(num + 0.5f); +} + +static inline float roundToDevicePixelTowardZero(float num) +{ + float roundedNum = roundf(num); + if (fabs(num - roundedNum) < 0.125) + num = roundedNum; + + return roundTowardZero(num); +} + +void ScrollElasticityController::snapRubberBandTimerFired() +{ + if (!m_momentumScrollInProgress || m_ignoreMomentumScrolls) { + CFTimeInterval timeDelta = [NSDate timeIntervalSinceReferenceDate] - m_startTime; + + if (m_startStretch == FloatSize()) { + m_startStretch = m_client->stretchAmount(); + if (m_startStretch == FloatSize()) { + stopSnapRubberbandTimer(); + + m_stretchScrollForce = FloatSize(); + m_startTime = 0; + m_startStretch = FloatSize(); + m_origOrigin = FloatPoint(); + m_origVelocity = FloatSize(); + return; + } + + m_origOrigin = m_client->absoluteScrollPosition() - m_startStretch; + m_origVelocity = m_momentumVelocity; + + // Just like normal scrolling, prefer vertical rubberbanding + if (fabsf(m_origVelocity.height()) >= fabsf(m_origVelocity.width())) + m_origVelocity.setWidth(0); + + // Don't rubber-band horizontally if it's not possible to scroll horizontally + if (!m_client->canScrollHorizontally()) + m_origVelocity.setWidth(0); + + // Don't rubber-band vertically if it's not possible to scroll vertically + if (!m_client->canScrollVertically()) + m_origVelocity.setHeight(0); + } + + FloatPoint delta(roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m_startStretch.width(), -m_origVelocity.width(), (float)timeDelta)), + roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m_startStretch.height(), -m_origVelocity.height(), (float)timeDelta))); + + if (fabs(delta.x()) >= 1 || fabs(delta.y()) >= 1) { + m_client->immediateScrollByWithoutContentEdgeConstraints(FloatSize(delta.x(), delta.y()) - m_client->stretchAmount()); + + FloatSize newStretch = m_client->stretchAmount(); + + m_stretchScrollForce.setWidth(reboundDeltaForElasticDelta(newStretch.width())); + m_stretchScrollForce.setHeight(reboundDeltaForElasticDelta(newStretch.height())); + } else { + m_client->immediateScrollBy(m_origOrigin - m_client->absoluteScrollPosition()); + + stopSnapRubberbandTimer(); + m_stretchScrollForce = FloatSize(); + m_startTime = 0; + m_startStretch = FloatSize(); + m_origOrigin = FloatPoint(); + m_origVelocity = FloatSize(); + } + } else { + m_startTime = [NSDate timeIntervalSinceReferenceDate]; + m_startStretch = FloatSize(); + } } void ScrollElasticityController::stopSnapRubberbandTimer() @@ -71,6 +373,36 @@ void ScrollElasticityController::stopSnapRubberbandTimer() m_snapRubberbandTimerIsActive = false; } +void ScrollElasticityController::snapRubberBand() +{ + CFTimeInterval timeDelta = systemUptime() - m_lastMomentumScrollTimestamp; + if (m_lastMomentumScrollTimestamp && timeDelta >= scrollVelocityZeroingTimeout) + m_momentumVelocity = FloatSize(); + + m_inScrollGesture = false; + + if (m_snapRubberbandTimerIsActive) + return; + + m_startTime = [NSDate timeIntervalSinceReferenceDate]; + m_startStretch = FloatSize(); + m_origOrigin = FloatPoint(); + m_origVelocity = FloatSize(); + + m_client->startSnapRubberbandTimer(); + m_snapRubberbandTimerIsActive = true; +} + +bool ScrollElasticityController::shouldRubberBandInHorizontalDirection(const PlatformWheelEvent& wheelEvent) +{ + if (wheelEvent.deltaX() > 0) + return m_client->shouldRubberBandInDirection(ScrollLeft); + if (wheelEvent.deltaX() < 0) + return m_client->shouldRubberBandInDirection(ScrollRight); + + return true; +} + } // namespace WebCore #endif // ENABLE(RUBBER_BANDING) diff --git a/Source/WebCore/platform/mac/ScrollbarThemeMac.mm b/Source/WebCore/platform/mac/ScrollbarThemeMac.mm index 0fe1c0d6f..85809244d 100644 --- a/Source/WebCore/platform/mac/ScrollbarThemeMac.mm +++ b/Source/WebCore/platform/mac/ScrollbarThemeMac.mm @@ -133,6 +133,13 @@ static bool gJumpOnTrackClick = false; static ScrollbarButtonsPlacement gButtonPlacement = ScrollbarButtonsDoubleEnd; +static bool supportsExpandedScrollbars() +{ + // FIXME: This is temporary until all platforms that support ScrollbarPainter support this part of the API. + static bool globalSupportsExpandedScrollbars = [NSClassFromString(@"NSScrollerImp") instancesRespondToSelector:@selector(isExpanded)]; + return globalSupportsExpandedScrollbars; +} + static void updateArrowPlacement() { if (isScrollbarOverlayAPIAvailable()) @@ -222,6 +229,8 @@ int ScrollbarThemeMac::scrollbarThickness(ScrollbarControlSize controlSize) { if (isScrollbarOverlayAPIAvailable()) { ScrollbarPainter scrollbarPainter = [NSClassFromString(@"NSScrollerImp") scrollerImpWithStyle:recommendedScrollerStyle() controlSize:controlSize horizontal:NO replacingScrollerImp:nil]; + if (supportsExpandedScrollbars()) + [scrollbarPainter setExpanded:YES]; return [scrollbarPainter trackBoxWidth]; } else return cScrollbarThickness[controlSize]; diff --git a/Source/WebCore/platform/mac/WebCoreSystemInterface.h b/Source/WebCore/platform/mac/WebCoreSystemInterface.h index beb36ca06..21eb94a18 100644 --- a/Source/WebCore/platform/mac/WebCoreSystemInterface.h +++ b/Source/WebCore/platform/mac/WebCoreSystemInterface.h @@ -77,56 +77,29 @@ typedef struct _CFURLRequest* CFMutableURLRequestRef; typedef const struct _CFURLRequest* CFURLRequestRef; #endif -#ifdef __OBJC__ -@class AVAsset; -@class NSArray; -@class NSButtonCell; -@class NSControl; -@class NSCursor; -@class NSData; -@class NSDate; -@class NSEvent; -@class NSFont; -@class NSHTTPCookie; -@class NSImage; -@class NSMenu; -@class NSMutableURLRequest; -@class NSString; -@class NSTextFieldCell; -@class NSURL; -@class NSURLConnection; -@class NSURLRequest; -@class NSURLResponse; -@class NSView; -@class NSWindow; -@class QTMovie; -@class QTMovieView; -#else -class AVAsset; -class NSArray; -class NSButtonCell; -class NSControl; -class NSCursor; -class NSData; -class NSDate; -class NSEvent; -class NSFont; -class NSHTTPCookie; -class NSImage; -class NSMenu; -class NSMutableArray; -class NSMutableURLRequest; -class NSURL; -class NSURLRequest; -class NSString; -class NSTextFieldCell; -class NSURLConnection; -class NSURLResponse; -class NSView; -class NSWindow; -class QTMovie; -class QTMovieView; -#endif +OBJC_CLASS AVAsset; +OBJC_CLASS NSArray; +OBJC_CLASS NSButtonCell; +OBJC_CLASS NSControl; +OBJC_CLASS NSCursor; +OBJC_CLASS NSData; +OBJC_CLASS NSDate; +OBJC_CLASS NSEvent; +OBJC_CLASS NSFont; +OBJC_CLASS NSHTTPCookie; +OBJC_CLASS NSImage; +OBJC_CLASS NSMenu; +OBJC_CLASS NSMutableURLRequest; +OBJC_CLASS NSString; +OBJC_CLASS NSTextFieldCell; +OBJC_CLASS NSURL; +OBJC_CLASS NSURLConnection; +OBJC_CLASS NSURLRequest; +OBJC_CLASS NSURLResponse; +OBJC_CLASS NSView; +OBJC_CLASS NSWindow; +OBJC_CLASS QTMovie; +OBJC_CLASS QTMovieView; extern "C" { @@ -255,8 +228,10 @@ extern CTLineRef (*wkCreateCTLineWithUniCharProvider)(const UniChar* (*provide)( extern CTTypesetterRef (*wkCreateCTTypesetterWithUniCharProviderAndOptions)(const UniChar* (*provide)(CFIndex stringIndex, CFIndex* charCount, CFDictionaryRef* attributes, void*), void (*dispose)(const UniChar* chars, void*), void*, CFDictionaryRef options); +#if PLATFORM(MAC) && USE(CA) extern CGContextRef (*wkIOSurfaceContextCreate)(IOSurfaceRef surface, unsigned width, unsigned height, CGColorSpaceRef colorSpace); extern CGImageRef (*wkIOSurfaceContextCreateImage)(CGContextRef context); +#endif extern int (*wkRecommendedScrollerStyle)(void); @@ -321,6 +296,7 @@ extern dispatch_source_t (*wkCreateVMPressureDispatchOnMainQueue)(void); #if !defined(BUILDING_ON_SNOW_LEOPARD) && !defined(BUILDING_ON_LION) extern NSString *(*wkGetMacOSXVersionString)(void); +extern bool (*wkExecutableWasLinkedOnOrBeforeLion)(void); #endif } diff --git a/Source/WebCore/platform/mac/WebCoreSystemInterface.mm b/Source/WebCore/platform/mac/WebCoreSystemInterface.mm index b4ca5407d..f01747d5f 100644 --- a/Source/WebCore/platform/mac/WebCoreSystemInterface.mm +++ b/Source/WebCore/platform/mac/WebCoreSystemInterface.mm @@ -179,4 +179,5 @@ dispatch_source_t (*wkCreateVMPressureDispatchOnMainQueue)(void); #if !defined(BUILDING_ON_SNOW_LEOPARD) && !defined(BUILDING_ON_LION) NSString *(*wkGetMacOSXVersionString)(void); +bool (*wkExecutableWasLinkedOnOrBeforeLion)(void); #endif diff --git a/Source/WebCore/platform/mediastream/MediaStreamCenter.cpp b/Source/WebCore/platform/mediastream/MediaStreamCenter.cpp index a484a2bc2..9203ce3ac 100644 --- a/Source/WebCore/platform/mediastream/MediaStreamCenter.cpp +++ b/Source/WebCore/platform/mediastream/MediaStreamCenter.cpp @@ -57,6 +57,7 @@ void MediaStreamCenter::endLocalMediaStream(MediaStreamDescriptor* streamDescrip // FIXME: remove when real implementations are available // Empty implementations for ports that build with MEDIA_STREAM enabled by default. + MediaStreamCenter::MediaStreamCenter() { } @@ -67,11 +68,11 @@ MediaStreamCenter::~MediaStreamCenter() void MediaStreamCenter::queryMediaStreamSources(PassRefPtr<MediaStreamSourcesQueryClient> client) { - MediaStreamSourceVector sources; - client->mediaStreamSourcesQueryCompleted(sources); + MediaStreamSourceVector audioSources, videoSources; + client->mediaStreamSourcesQueryCompleted(audioSources, videoSources); } -void MediaStreamCenter::didSetMediaStreamTrackEnabled(MediaStreamDescriptor*, unsigned) +void MediaStreamCenter::didSetMediaStreamTrackEnabled(MediaStreamDescriptor*, MediaStreamComponent*) { } @@ -79,6 +80,10 @@ void MediaStreamCenter::didStopLocalMediaStream(MediaStreamDescriptor*) { } +void MediaStreamCenter::didConstructMediaStream(MediaStreamDescriptor*) +{ +} + } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/MediaStreamCenter.h b/Source/WebCore/platform/mediastream/MediaStreamCenter.h index 8efc8b32f..7d98fc52d 100644 --- a/Source/WebCore/platform/mediastream/MediaStreamCenter.h +++ b/Source/WebCore/platform/mediastream/MediaStreamCenter.h @@ -38,6 +38,7 @@ namespace WebCore { +class MediaStreamComponent; class MediaStreamDescriptor; class MediaStreamSourcesQueryClient : public RefCounted<MediaStreamSourcesQueryClient> { @@ -47,7 +48,7 @@ public: virtual bool audio() const = 0; virtual bool video() const = 0; - virtual void mediaStreamSourcesQueryCompleted(const MediaStreamSourceVector&) = 0; + virtual void mediaStreamSourcesQueryCompleted(const MediaStreamSourceVector& audioSources, const MediaStreamSourceVector& videoSources) = 0; }; class MediaStreamCenter { @@ -63,8 +64,9 @@ public: // FIXME: add a way to mute a MediaStreamSource from the WebKit API layer // Calls from the DOM objects to notify the platform - void didSetMediaStreamTrackEnabled(MediaStreamDescriptor*, unsigned componentIndex); + void didSetMediaStreamTrackEnabled(MediaStreamDescriptor*, MediaStreamComponent*); void didStopLocalMediaStream(MediaStreamDescriptor*); + void didConstructMediaStream(MediaStreamDescriptor*); // Calls from the platform to update the DOM objects void endLocalMediaStream(MediaStreamDescriptor*); diff --git a/Source/WebCore/platform/mediastream/MediaStreamDescriptor.h b/Source/WebCore/platform/mediastream/MediaStreamDescriptor.h index a046d45fb..b3b273fa7 100644 --- a/Source/WebCore/platform/mediastream/MediaStreamDescriptor.h +++ b/Source/WebCore/platform/mediastream/MediaStreamDescriptor.h @@ -48,9 +48,9 @@ public: class MediaStreamDescriptor : public RefCounted<MediaStreamDescriptor> { public: - static PassRefPtr<MediaStreamDescriptor> create(const String& label, const MediaStreamSourceVector& sources) + static PassRefPtr<MediaStreamDescriptor> create(const String& label, const MediaStreamSourceVector& audioSources, const MediaStreamSourceVector& videoSources) { - return adoptRef(new MediaStreamDescriptor(label, sources)); + return adoptRef(new MediaStreamDescriptor(label, audioSources, videoSources)); } MediaStreamDescriptorOwner* owner() const { return m_owner; } @@ -58,25 +58,32 @@ public: String label() const { return m_label; } - MediaStreamComponent* component(unsigned index) const { return m_components[index].get(); } - unsigned numberOfComponents() const { return m_components.size(); } + unsigned numberOfAudioComponents() const { return m_audioComponents.size(); } + MediaStreamComponent* audioComponent(unsigned index) const { return m_audioComponents[index].get(); } + + unsigned numberOfVideoComponents() const { return m_videoComponents.size(); } + MediaStreamComponent* videoComponent(unsigned index) const { return m_videoComponents[index].get(); } bool ended() const { return m_ended; } void setEnded() { m_ended = true; } private: - MediaStreamDescriptor(const String& label, const MediaStreamSourceVector& sources) + MediaStreamDescriptor(const String& label, const MediaStreamSourceVector& audioSources, const MediaStreamSourceVector& videoSources) : m_owner(0) , m_label(label) , m_ended(false) { - for (size_t i = 0; i < sources.size(); i++) - m_components.append(MediaStreamComponent::create(sources[i])); + for (size_t i = 0; i < audioSources.size(); i++) + m_audioComponents.append(MediaStreamComponent::create(audioSources[i])); + + for (size_t i = 0; i < videoSources.size(); i++) + m_videoComponents.append(MediaStreamComponent::create(videoSources[i])); } MediaStreamDescriptorOwner* m_owner; String m_label; - Vector<RefPtr<MediaStreamComponent> > m_components; + Vector<RefPtr<MediaStreamComponent> > m_audioComponents; + Vector<RefPtr<MediaStreamComponent> > m_videoComponents; bool m_ended; }; diff --git a/Source/WebCore/platform/mock/SpeechInputClientMock.cpp b/Source/WebCore/platform/mock/SpeechInputClientMock.cpp deleted file mode 100644 index 9aa3113dc..000000000 --- a/Source/WebCore/platform/mock/SpeechInputClientMock.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "SpeechInputClientMock.h" - -#if ENABLE(INPUT_SPEECH) - -#include "SecurityOrigin.h" -#include "SpeechInputListener.h" - -namespace WebCore { - -SpeechInputClientMock::SpeechInputClientMock() - : m_recording(false) - , m_timer(this, &SpeechInputClientMock::timerFired) - , m_listener(0) - , m_requestId(0) -{ -} - -void SpeechInputClientMock::setListener(SpeechInputListener* listener) -{ - m_listener = listener; -} - -bool SpeechInputClientMock::startRecognition(int requestId, const IntRect& elementRect, const AtomicString& language, const String& grammar, SecurityOrigin* origin) -{ - if (m_timer.isActive()) - return false; - m_requestId = requestId; - m_recording = true; - m_language = language; - m_timer.startOneShot(0); - return true; -} - -void SpeechInputClientMock::stopRecording(int requestId) -{ - ASSERT(requestId == m_requestId); - if (m_timer.isActive() && m_recording) { - m_timer.stop(); - timerFired(&m_timer); - } -} - -void SpeechInputClientMock::cancelRecognition(int requestId) -{ - if (m_timer.isActive()) { - ASSERT(requestId == m_requestId); - m_timer.stop(); - m_recording = false; - m_listener->didCompleteRecognition(m_requestId); - m_requestId = 0; - } -} - -void SpeechInputClientMock::addRecognitionResult(const String& result, double confidence, const AtomicString& language) -{ - if (language.isEmpty()) - m_resultsForEmptyLanguage.append(SpeechInputResult::create(result, confidence)); - else { - if (!m_recognitionResults.contains(language)) - m_recognitionResults.set(language, SpeechInputResultArray()); - m_recognitionResults.find(language)->second.append(SpeechInputResult::create(result, confidence)); - } -} - -void SpeechInputClientMock::clearResults() -{ - m_resultsForEmptyLanguage.clear(); - m_recognitionResults.clear(); -} - -void SpeechInputClientMock::timerFired(WebCore::Timer<SpeechInputClientMock>*) -{ - if (m_recording) { - m_recording = false; - m_listener->didCompleteRecording(m_requestId); - m_timer.startOneShot(0); - } else { - bool noResultsFound = false; - - // We take a copy of the requestId here so that if scripts destroyed the input element - // inside one of the callbacks below, we'll still know what this session's requestId was. - int requestId = m_requestId; - m_requestId = 0; - - // Empty language case must be handled separately to avoid problems with HashMap and empty keys. - if (m_language.isEmpty()) { - if (!m_resultsForEmptyLanguage.isEmpty()) - m_listener->setRecognitionResult(requestId, m_resultsForEmptyLanguage); - else - noResultsFound = true; - } else { - if (m_recognitionResults.contains(m_language)) - m_listener->setRecognitionResult(requestId, m_recognitionResults.get(m_language)); - else - noResultsFound = true; - } - - if (noResultsFound) { - // Can't avoid setting a result even if no result was set for the given language. - // This would avoid generating the events used to check the results and the test would timeout. - String error("error: no result found for language '"); - error.append(m_language); - error.append("'"); - SpeechInputResultArray results; - results.append(SpeechInputResult::create(error, 1.0)); - m_listener->setRecognitionResult(requestId, results); - } - - m_listener->didCompleteRecognition(requestId); - } -} - -} // namespace WebCore - -#endif // ENABLE(INPUT_SPEECH) diff --git a/Source/WebCore/platform/network/HTTPParsers.cpp b/Source/WebCore/platform/network/HTTPParsers.cpp index 4ef54ef29..8cbd4ff14 100644 --- a/Source/WebCore/platform/network/HTTPParsers.cpp +++ b/Source/WebCore/platform/network/HTTPParsers.cpp @@ -73,28 +73,45 @@ static inline bool skipToken(const String& str, unsigned& pos, const char* token return true; } +// See RFC 2616, Section 2.2. +bool isRFC2616Token(const String& characters) +{ + if (characters.isEmpty()) + return false; + for (unsigned i = 0; i < characters.length(); ++i) { + UChar c = characters[i]; + if (c >= 0x80 || c <= 0x1F || c == 0x7F + || c == '(' || c == ')' || c == '<' || c == '>' || c == '@' + || c == ',' || c == ';' || c == ':' || c == '\\' || c == '"' + || c == '/' || c == '[' || c == ']' || c == '?' || c == '=' + || c == '{' || c == '}' || c == ' ' || c == '\t') + return false; + } + return true; +} + ContentDispositionType contentDispositionType(const String& contentDisposition) -{ +{ if (contentDisposition.isEmpty()) return ContentDispositionNone; - // Some broken sites just send - // Content-Disposition: ; filename="file" - // screen those out here. - if (contentDisposition.startsWith(";")) - return ContentDispositionNone; + Vector<String> parameters; + contentDisposition.split(';', parameters); - if (contentDisposition.startsWith("inline", false)) + String dispositionType = parameters[0]; + dispositionType.stripWhiteSpace(); + + if (equalIgnoringCase(dispositionType, "inline")) return ContentDispositionInline; - // Some broken sites just send - // Content-Disposition: filename="file" + // Some broken sites just send bogus headers like + // + // Content-Disposition: ; filename="file" + // Content-Disposition: filename="file" + // Content-Disposition: name="file" + // // without a disposition token... screen those out. - if (contentDisposition.startsWith("filename", false)) - return ContentDispositionNone; - - // Also in use is Content-Disposition: name="file" - if (contentDisposition.startsWith("name", false)) + if (!isRFC2616Token(dispositionType)) return ContentDispositionNone; // We have a content-disposition of "attachment" or unknown. @@ -167,6 +184,11 @@ double parseDate(const String& value) return parseDateFromNullTerminatedCharacters(value.utf8().data()); } +// FIXME: This function doesn't comply with RFC 6266. +// For example, this function doesn't handle the interaction between " and ; +// that arises from quoted-string, nor does this function properly unquote +// attribute values. Further this function appears to process parameter names +// in a case-sensitive manner. (There are likely other bugs as well.) String filenameFromHTTPContentDisposition(const String& value) { Vector<String> keyValuePairs; diff --git a/Source/WebCore/platform/network/HTTPParsers.h b/Source/WebCore/platform/network/HTTPParsers.h index 55b8c7b90..3c808af62 100644 --- a/Source/WebCore/platform/network/HTTPParsers.h +++ b/Source/WebCore/platform/network/HTTPParsers.h @@ -50,6 +50,7 @@ typedef enum { } ContentDispositionType; ContentDispositionType contentDispositionType(const String&); +bool isRFC2616Token(const String&); bool parseHTTPRefresh(const String& refresh, bool fromHttpEquivMeta, double& delay, String& url); double parseDate(const String&); String filenameFromHTTPContentDisposition(const String&); diff --git a/Source/WebCore/platform/network/ResourceHandle.h b/Source/WebCore/platform/network/ResourceHandle.h index a3633b25a..1b1eacc73 100644 --- a/Source/WebCore/platform/network/ResourceHandle.h +++ b/Source/WebCore/platform/network/ResourceHandle.h @@ -52,16 +52,11 @@ typedef LPVOID HINTERNET; #endif #if PLATFORM(MAC) -#ifdef __OBJC__ -@class NSData; -@class NSError; -@class NSURLConnection; -@class WebCoreResourceHandleAsDelegate; -#else -class NSData; -class NSError; -class NSURLConnection; -class WebCoreResourceHandleAsDelegate; +OBJC_CLASS NSData; +OBJC_CLASS NSError; +OBJC_CLASS NSURLConnection; +OBJC_CLASS WebCoreResourceHandleAsDelegate; +#ifndef __OBJC__ typedef struct objc_object *id; #endif #endif diff --git a/Source/WebCore/platform/network/ResourceHandleClient.h b/Source/WebCore/platform/network/ResourceHandleClient.h index a458b5da2..befbccfa0 100644 --- a/Source/WebCore/platform/network/ResourceHandleClient.h +++ b/Source/WebCore/platform/network/ResourceHandleClient.h @@ -40,11 +40,7 @@ #endif #if PLATFORM(MAC) -#ifdef __OBJC__ -@class NSCachedURLResponse; -#else -class NSCachedURLResponse; -#endif +OBJC_CLASS NSCachedURLResponse; #endif namespace WebCore { diff --git a/Source/WebCore/platform/network/ResourceHandleInternal.h b/Source/WebCore/platform/network/ResourceHandleInternal.h index cad38341a..877997963 100644 --- a/Source/WebCore/platform/network/ResourceHandleInternal.h +++ b/Source/WebCore/platform/network/ResourceHandleInternal.h @@ -61,13 +61,8 @@ class QNetworkReplyHandler; #endif #if PLATFORM(MAC) -#ifdef __OBJC__ -@class NSURLAuthenticationChallenge; -@class NSURLConnection; -#else -class NSURLAuthenticationChallenge; -class NSURLConnection; -#endif +OBJC_CLASS NSURLAuthenticationChallenge; +OBJC_CLASS NSURLConnection; #endif // The allocations and releases in ResourceHandleInternal are diff --git a/Source/WebCore/platform/network/ResourceRequestBase.cpp b/Source/WebCore/platform/network/ResourceRequestBase.cpp index c5bd30814..e1e96c409 100644 --- a/Source/WebCore/platform/network/ResourceRequestBase.cpp +++ b/Source/WebCore/platform/network/ResourceRequestBase.cpp @@ -57,7 +57,6 @@ PassOwnPtr<ResourceRequest> ResourceRequestBase::adopt(PassOwnPtr<CrossThreadRes request->updateResourceRequest(); request->m_httpHeaderFields.adopt(data->m_httpHeaders.release()); -#if PLATFORM(MAC) || PLATFORM(WIN) size_t encodingCount = data->m_responseContentDispositionEncodingFallbackArray.size(); if (encodingCount > 0) { String encoding1 = data->m_responseContentDispositionEncodingFallbackArray[0]; @@ -71,7 +70,6 @@ PassOwnPtr<ResourceRequest> ResourceRequestBase::adopt(PassOwnPtr<CrossThreadRes ASSERT(encodingCount <= 3); request->setResponseContentDispositionEncodingFallbackArray(encoding1, encoding2, encoding3); } -#endif request->setHTTPBody(data->m_httpBody); request->setAllowCookies(data->m_allowCookies); request->doPlatformAdopt(data); @@ -89,13 +87,11 @@ PassOwnPtr<CrossThreadResourceRequestData> ResourceRequestBase::copyData() const data->m_httpHeaders = httpHeaderFields().copyData(); data->m_priority = priority(); -#if PLATFORM(MAC) || PLATFORM(WIN) data->m_responseContentDispositionEncodingFallbackArray.reserveInitialCapacity(m_responseContentDispositionEncodingFallbackArray.size()); size_t encodingArraySize = m_responseContentDispositionEncodingFallbackArray.size(); for (size_t index = 0; index < encodingArraySize; ++index) { data->m_responseContentDispositionEncodingFallbackArray.append(m_responseContentDispositionEncodingFallbackArray[index].isolatedCopy()); } -#endif if (m_httpBody) data->m_httpBody = m_httpBody->deepCopy(); data->m_allowCookies = m_allowCookies; @@ -275,7 +271,6 @@ void ResourceRequestBase::clearHTTPOrigin() m_platformRequestUpdated = false; } -#if PLATFORM(MAC) || PLATFORM(WIN) void ResourceRequestBase::setResponseContentDispositionEncodingFallbackArray(const String& encoding1, const String& encoding2, const String& encoding3) { updateResourceRequest(); @@ -291,7 +286,6 @@ void ResourceRequestBase::setResponseContentDispositionEncodingFallbackArray(con if (url().protocolInHTTPFamily()) m_platformRequestUpdated = false; } -#endif FormData* ResourceRequestBase::httpBody() const { diff --git a/Source/WebCore/platform/network/ResourceRequestBase.h b/Source/WebCore/platform/network/ResourceRequestBase.h index b5dc11e4a..0b154d60f 100644 --- a/Source/WebCore/platform/network/ResourceRequestBase.h +++ b/Source/WebCore/platform/network/ResourceRequestBase.h @@ -103,11 +103,7 @@ namespace WebCore { String httpAccept() const { return httpHeaderField("Accept"); } void setHTTPAccept(const String& httpAccept) { setHTTPHeaderField("Accept", httpAccept); } -#if PLATFORM(MAC) || PLATFORM(WIN) - // FIXME: This state should either be moved to a CFNetwork-specific - // ResourceRequest or should be removed. void setResponseContentDispositionEncodingFallbackArray(const String& encoding1, const String& encoding2 = String(), const String& encoding3 = String()); -#endif FormData* httpBody() const; void setHTTPBody(PassRefPtr<FormData> httpBody); @@ -178,11 +174,7 @@ namespace WebCore { KURL m_firstPartyForCookies; String m_httpMethod; HTTPHeaderMap m_httpHeaderFields; -#if PLATFORM(MAC) || PLATFORM(WIN) - // FIXME: This state should either be moved to a CFNetwork-specific - // ResourceRequest or should be removed. Vector<String> m_responseContentDispositionEncodingFallbackArray; -#endif RefPtr<FormData> m_httpBody; bool m_allowCookies : 1; mutable bool m_resourceRequestUpdated : 1; @@ -215,9 +207,7 @@ namespace WebCore { String m_httpMethod; OwnPtr<CrossThreadHTTPHeaderMapData> m_httpHeaders; -#if PLATFORM(MAC) || PLATFORM(WIN) Vector<String> m_responseContentDispositionEncodingFallbackArray; -#endif RefPtr<FormData> m_httpBody; bool m_allowCookies; ResourceLoadPriority m_priority; diff --git a/Source/WebCore/platform/network/blackberry/CredentialBackingStore.cpp b/Source/WebCore/platform/network/blackberry/CredentialBackingStore.cpp index bbb2bfc5e..acacc3789 100644 --- a/Source/WebCore/platform/network/blackberry/CredentialBackingStore.cpp +++ b/Source/WebCore/platform/network/blackberry/CredentialBackingStore.cpp @@ -28,6 +28,12 @@ #include "SQLiteStatement.h" #include <wtf/UnusedParam.h> +#define HANDLE_SQL_EXEC_FAILURE(statement, returnValue, ...) \ + if (statement) { \ + LOG_ERROR(__VAR_ARGS__); \ + return returnValue; \ + } + namespace WebCore { CredentialBackingStore* CredentialBackingStore::instance() @@ -49,69 +55,212 @@ CredentialBackingStore::CredentialBackingStore() CredentialBackingStore::~CredentialBackingStore() { + if (m_database.isOpen()) + m_database.close(); } bool CredentialBackingStore::open(const String& dbPath) { - UNUSED_PARAM(dbPath); + ASSERT(!m_database.isOpen()); - notImplemented(); - return false; + HANDLE_SQL_EXEC_FAILURE(!m_database.open(dbPath), false, + "Failed to open database file %s for login database", dbPath.utf8().data()); + + if (!m_database.tableExists("logins")) { + HANDLE_SQL_EXEC_FAILURE(!m_database.executeCommand("CREATE TABLE logins (origin_url VARCHAR NOT NULL, host VARCHAR NOT NULL, port INTEGER, service_type INTEGER NOT NULL, realm VARCHAR, auth_scheme INTEGER NOT NULL, username VARCHAR, password BLOB) "), + false, "Failed to create table logins for login database"); + + // Create index for table logins. + HANDLE_SQL_EXEC_FAILURE(!m_database.executeCommand("CREATE INDEX logins_signon ON logins (host)"), + false, "Failed to create index for table logins"); + } else { // Initiate CredentialStorage. + SQLiteStatement query(m_database, "SELECT origin_url, host, port, service_type, realm, auth_scheme, username, password FROM logins"); + HANDLE_SQL_EXEC_FAILURE(query.prepare() != SQLResultOk, + false, "Failed to prepare query statement to initiate CredentialStorage"); + + int result = query.step(); + while (result == SQLResultRow) { + String strUrl = query.getColumnText(1); + String strHost = query.getColumnText(2); + int intPort = query.getColumnInt(3); + ProtectionSpaceServerType serviceType = static_cast<ProtectionSpaceServerType>(query.getColumnInt(4)); + String strRealm = query.getColumnText(5); + ProtectionSpaceAuthenticationScheme authScheme = static_cast<ProtectionSpaceAuthenticationScheme>(query.getColumnInt(6)); + String strUserName = query.getColumnText(7); + String strPassword = decryptedString(query.getColumnText(8)); + + KURL url(ParsedURLString, strUrl); + ProtectionSpace protectionSpace(strHost, intPort, serviceType, strRealm, authScheme); + Credential credential(strUserName, strPassword, CredentialPersistencePermanent); + CredentialStorage::set(credential, protectionSpace, url); + + result = query.step(); + } + } + + // Prepare the statements. + m_addStatement = new SQLiteStatement(m_database, "INSERT OR REPLACE INTO logins (origin_url, host, port, service_type, realm, auth_scheme, username, password) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); + HANDLE_SQL_EXEC_FAILURE(m_addStatement->prepare() != SQLResultOk, + false, "Failed to prepare addLogin statement"); + + m_updateStatement = new SQLiteStatement(m_database, "UPDATE logins SET username = ?, password = ? WHERE origin_url = ? AND host = ? AND port = ? AND service_type = ? AND realm = ? AND auth_scheme = ?"); + HANDLE_SQL_EXEC_FAILURE(m_updateStatement->prepare() != SQLResultOk, + false, "Failed to prepare updateLogin statement"); + + m_hasStatement = new SQLiteStatement(m_database, "SELECT COUNT(*) FROM logins WHERE host = ? AND port = ? AND service_type = ? AND realm = ? AND auth_scheme = ?"); + HANDLE_SQL_EXEC_FAILURE(m_hasStatement->prepare() != SQLResultOk, + false, "Failed to prepare hasLogin statement"); + + m_getStatement = new SQLiteStatement(m_database, "SELECT username, password FROM logins WHERE host = ? AND port = ? AND service_type = ? AND realm = ? AND auth_scheme = ?"); + HANDLE_SQL_EXEC_FAILURE(m_getStatement->prepare() != SQLResultOk, + false, "Failed to prepare getLogin statement"); + + m_removeStatement = new SQLiteStatement(m_database, "DELETE FROM logins WHERE host = ? AND port = ? AND service_type = ? AND realm = ? AND auth_scheme = ?"); + HANDLE_SQL_EXEC_FAILURE(m_removeStatement->prepare() != SQLResultOk, + false, "Failed to prepare removeLogin statement"); + + return true; } void CredentialBackingStore::close() { - notImplemented(); + delete m_addStatement; + m_addStatement = 0; + delete m_updateStatement; + m_updateStatement = 0; + delete m_hasStatement; + m_hasStatement = 0; + delete m_getStatement; + m_getStatement = 0; + delete m_removeStatement; + m_removeStatement = 0; + + if (m_database.isOpen()) + m_database.close(); } bool CredentialBackingStore::addLogin(const KURL& url, const ProtectionSpace& protectionSpace, const Credential& credential) { - UNUSED_PARAM(url); - UNUSED_PARAM(protectionSpace); - UNUSED_PARAM(credential); + ASSERT(m_database.isOpen()); + ASSERT(m_database.tableExists("logins")); - notImplemented(); - return false; + if (!m_addStatement) + return false; + + m_addStatement->bindText(1, url.string()); + m_addStatement->bindText(2, protectionSpace.host()); + m_addStatement->bindInt(3, protectionSpace.port()); + m_addStatement->bindInt(4, static_cast<int>(protectionSpace.serverType())); + m_addStatement->bindText(5, protectionSpace.realm()); + m_addStatement->bindInt(6, static_cast<int>(protectionSpace.authenticationScheme())); + m_addStatement->bindText(7, credential.user()); + m_addStatement->bindBlob(8, encryptedString(credential.password())); + + int result = m_addStatement->step(); + HANDLE_SQL_EXEC_FAILURE(result != SQLResultDone, false, + "Failed to add login info into table logins - %i", result); + + return true; } bool CredentialBackingStore::updateLogin(const KURL& url, const ProtectionSpace& protectionSpace, const Credential& credential) { - UNUSED_PARAM(url); - UNUSED_PARAM(protectionSpace); - UNUSED_PARAM(credential); + ASSERT(m_database.isOpen()); + ASSERT(m_database.tableExists("logins")); - notImplemented(); - return false; + if (!m_updateStatement) + return false; + + m_updateStatement->bindText(1, url.string()); + m_updateStatement->bindText(2, credential.user()); + m_updateStatement->bindBlob(3, encryptedString(credential.password())); + m_updateStatement->bindText(4, protectionSpace.host()); + m_updateStatement->bindInt(5, protectionSpace.port()); + m_updateStatement->bindInt(6, static_cast<int>(protectionSpace.serverType())); + m_updateStatement->bindText(7, protectionSpace.realm()); + m_updateStatement->bindInt(8, static_cast<int>(protectionSpace.authenticationScheme())); + + int result = m_updateStatement->step(); + HANDLE_SQL_EXEC_FAILURE(result != SQLResultDone, false, + "Failed to update login info in table logins - %i", result); + + return true; } bool CredentialBackingStore::hasLogin(const ProtectionSpace& protectionSpace) { - UNUSED_PARAM(protectionSpace); + ASSERT(m_database.isOpen()); + ASSERT(m_database.tableExists("logins")); - notImplemented(); + if (!m_hasStatement) + return false; + + m_hasStatement->bindText(1, protectionSpace.host()); + m_hasStatement->bindInt(2, protectionSpace.port()); + m_hasStatement->bindInt(3, static_cast<int>(protectionSpace.serverType())); + m_hasStatement->bindText(4, protectionSpace.realm()); + m_hasStatement->bindInt(5, static_cast<int>(protectionSpace.authenticationScheme())); + + int result = m_hasStatement->step(); + HANDLE_SQL_EXEC_FAILURE(result != SQLResultRow, false, + "Failed to execute select login info from table logins in hasLogin - %i", result); + + if (m_hasStatement->getColumnInt(0)) + return true; return false; } Credential CredentialBackingStore::getLogin(const ProtectionSpace& protectionSpace) { - UNUSED_PARAM(protectionSpace); + ASSERT(m_database.isOpen()); + ASSERT(m_database.tableExists("logins")); - notImplemented(); - return Credential(); + if (!m_getStatement) + return Credential(); + + m_getStatement->bindText(1, protectionSpace.host()); + m_getStatement->bindInt(2, protectionSpace.port()); + m_getStatement->bindInt(3, static_cast<int>(protectionSpace.serverType())); + m_getStatement->bindText(4, protectionSpace.realm()); + m_getStatement->bindInt(5, static_cast<int>(protectionSpace.authenticationScheme())); + + int result = m_getStatement->step(); + HANDLE_SQL_EXEC_FAILURE(result != SQLResultRow, Credential(), + "Failed to execute select login info from table logins in getLogin - %i", result); + + return Credential(m_getStatement->getColumnText(0), decryptedString(m_getStatement->getColumnText(1)), CredentialPersistencePermanent); } bool CredentialBackingStore::removeLogin(const ProtectionSpace& protectionSpace) { - UNUSED_PARAM(protectionSpace); + ASSERT(m_database.isOpen()); + ASSERT(m_database.tableExists("logins")); - notImplemented(); - return false; + if (!m_removeStatement) + return false; + + m_removeStatement->bindText(1, protectionSpace.host()); + m_removeStatement->bindInt(2, protectionSpace.port()); + m_removeStatement->bindInt(3, static_cast<int>(protectionSpace.serverType())); + m_removeStatement->bindText(4, protectionSpace.realm()); + m_removeStatement->bindInt(5, static_cast<int>(protectionSpace.authenticationScheme())); + + int result = m_removeStatement->step(); + HANDLE_SQL_EXEC_FAILURE(result != SQLResultDone, false, + "Failed to remove login info from table logins - %i", result); + + return true; } bool CredentialBackingStore::clear() { - notImplemented(); - return false; + ASSERT(m_database.isOpen()); + ASSERT(m_database.tableExists("logins")); + + HANDLE_SQL_EXEC_FAILURE(!m_database.executeCommand("DELETE * FROM logins"), + false, "Failed to clear table logins"); + + return true; } String CredentialBackingStore::encryptedString(const String& plainText) const diff --git a/Source/WebCore/platform/network/blackberry/NetworkJob.cpp b/Source/WebCore/platform/network/blackberry/NetworkJob.cpp index 2cf3d17df..fc7c416ee 100644 --- a/Source/WebCore/platform/network/blackberry/NetworkJob.cpp +++ b/Source/WebCore/platform/network/blackberry/NetworkJob.cpp @@ -316,7 +316,9 @@ void NetworkJob::handleNotifyHeaderReceived(const String& key, const String& val } if (lowerKey == "www-authenticate") - handleAuthHeader(value); + handleAuthHeader(ProtectionSpaceServerHTTP, value); + else if (lowerKey == "proxy-authenticate" && !BlackBerry::Platform::Client::get()->getProxyAddress().empty()) + handleAuthHeader(ProtectionSpaceProxyHTTP, value); if (equalIgnoringCase(key, BlackBerry::Platform::NetworkRequest::HEADER_BLACKBERRY_FTP)) handleFTPHeader(value); @@ -701,7 +703,7 @@ void NetworkJob::parseData() notifyClose(BlackBerry::Platform::FilterStream::StatusSuccess); } -bool NetworkJob::handleAuthHeader(const String& header) +bool NetworkJob::handleAuthHeader(const ProtectionSpaceServerType space, const String& header) { if (!m_handle) return false; @@ -713,12 +715,12 @@ bool NetworkJob::handleAuthHeader(const String& header) return false; if (equalIgnoringCase(header, "ntlm")) - sendRequestWithCredentials(ProtectionSpaceServerHTTP, ProtectionSpaceAuthenticationSchemeNTLM, "NTLM"); + sendRequestWithCredentials(space, ProtectionSpaceAuthenticationSchemeNTLM, "NTLM"); // Extract the auth scheme and realm from the header. size_t spacePos = header.find(' '); if (spacePos == notFound) { - LOG(Network, "WWW-Authenticate field '%s' badly formatted: missing scheme.", header.utf8().data()); + LOG(Network, "%s-Authenticate field '%s' badly formatted: missing scheme.", space == ProtectionSpaceServerHTTP ? "WWW" : "Proxy", header.utf8().data()); return false; } @@ -736,7 +738,7 @@ bool NetworkJob::handleAuthHeader(const String& header) size_t realmPos = header.findIgnoringCase("realm=", spacePos); if (realmPos == notFound) { - LOG(Network, "WWW-Authenticate field '%s' badly formatted: missing realm.", header.utf8().data()); + LOG(Network, "%s-Authenticate field '%s' badly formatted: missing realm.", space == ProtectionSpaceServerHTTP ? "WWW" : "Proxy", header.utf8().data()); return false; } size_t beginPos = realmPos + 6; @@ -745,14 +747,14 @@ bool NetworkJob::handleAuthHeader(const String& header) beginPos += 1; size_t endPos = header.find("\"", beginPos); if (endPos == notFound) { - LOG(Network, "WWW-Authenticate field '%s' badly formatted: invalid realm.", header.utf8().data()); + LOG(Network, "%s-Authenticate field '%s' badly formatted: invalid realm.", space == ProtectionSpaceServerHTTP ? "WWW" : "Proxy", header.utf8().data()); return false; } realm = header.substring(beginPos, endPos - beginPos); } // Get the user's credentials and resend the request. - sendRequestWithCredentials(ProtectionSpaceServerHTTP, protectionSpaceScheme, realm); + sendRequestWithCredentials(space, protectionSpaceScheme, realm); return true; } @@ -796,7 +798,15 @@ bool NetworkJob::sendRequestWithCredentials(ProtectionSpaceServerType type, Prot if (!newURL.isValid()) return false; - ProtectionSpace protectionSpace(m_response.url().host(), m_response.url().port(), type, realm, scheme); + int port = 0; + if (type == ProtectionSpaceProxyHTTP) { + std::stringstream toPort(BlackBerry::Platform::Client::get()->getProxyPort()); + toPort >> port; + } else + port = m_response.url().port(); + + ProtectionSpace protectionSpace((type == ProtectionSpaceProxyHTTP) ? BlackBerry::Platform::Client::get()->getProxyAddress().c_str() : m_response.url().host() + , port, type, realm, scheme); // We've got the scheme and realm. Now we need a username and password. // First search the CredentialStorage. diff --git a/Source/WebCore/platform/network/blackberry/NetworkJob.h b/Source/WebCore/platform/network/blackberry/NetworkJob.h index 3781610df..4d60a6aed 100644 --- a/Source/WebCore/platform/network/blackberry/NetworkJob.h +++ b/Source/WebCore/platform/network/blackberry/NetworkJob.h @@ -129,7 +129,7 @@ private: // The server needs authentication credentials. Search in the // CredentialStorage or prompt the user via dialog. - bool handleAuthHeader(const String& header); + bool handleAuthHeader(const ProtectionSpaceServerType, const String& header); bool handleFTPHeader(const String& header); diff --git a/Source/WebCore/platform/network/blackberry/NetworkManager.cpp b/Source/WebCore/platform/network/blackberry/NetworkManager.cpp index 38f09e618..077b4c219 100644 --- a/Source/WebCore/platform/network/blackberry/NetworkManager.cpp +++ b/Source/WebCore/platform/network/blackberry/NetworkManager.cpp @@ -104,6 +104,8 @@ bool NetworkManager::startJob(int playerId, const String& pageGroupName, PassRef } } else if (type == ProtectionSpaceServerFTP) authType = BlackBerry::Platform::NetworkRequest::AuthFTP; + else if (type == ProtectionSpaceProxyHTTP) + authType = BlackBerry::Platform::NetworkRequest::AuthProxy; if (authType != BlackBerry::Platform::NetworkRequest::AuthNone) platformRequest.setCredentials(username.utf8().data(), password.utf8().data(), authType); diff --git a/Source/WebCore/platform/network/blackberry/ResourceRequestBlackBerry.cpp b/Source/WebCore/platform/network/blackberry/ResourceRequestBlackBerry.cpp index 8416862f2..d86b88cf1 100644 --- a/Source/WebCore/platform/network/blackberry/ResourceRequestBlackBerry.cpp +++ b/Source/WebCore/platform/network/blackberry/ResourceRequestBlackBerry.cpp @@ -96,6 +96,8 @@ void ResourceRequest::initializePlatformRequest(NetworkRequest& platformRequest, platformTargetTypeForRequest(*this), timeoutInterval()); + platformRequest.setConditional(isConditional()); + if (httpBody() && !httpBody()->isEmpty()) { const Vector<FormDataElement>& elements = httpBody()->elements(); // Use setData for simple forms because it is slightly more efficient. diff --git a/Source/WebCore/platform/network/cf/AuthenticationChallenge.h b/Source/WebCore/platform/network/cf/AuthenticationChallenge.h index ca4a06c55..109ede81b 100644 --- a/Source/WebCore/platform/network/cf/AuthenticationChallenge.h +++ b/Source/WebCore/platform/network/cf/AuthenticationChallenge.h @@ -31,14 +31,17 @@ #include <wtf/RefPtr.h> #if USE(CFNETWORK) + typedef struct _CFURLAuthChallenge* CFURLAuthChallengeRef; + #else + #ifndef __OBJC__ typedef struct objc_object *id; -class NSURLAuthenticationChallenge; -#else -@class NSURLAuthenticationChallenge; #endif + +OBJC_CLASS NSURLAuthenticationChallenge; + #endif namespace WebCore { diff --git a/Source/WebCore/platform/network/cf/ResourceError.h b/Source/WebCore/platform/network/cf/ResourceError.h index 27c63ff5f..30e0a5ea0 100644 --- a/Source/WebCore/platform/network/cf/ResourceError.h +++ b/Source/WebCore/platform/network/cf/ResourceError.h @@ -37,10 +37,8 @@ #include <wincrypt.h> // windows.h must be included before wincrypt.h. #endif -#ifdef __OBJC__ -@class NSError; -#else -class NSError; +#if PLATFORM(MAC) +OBJC_CLASS NSError; #endif namespace WebCore { diff --git a/Source/WebCore/platform/network/cf/ResourceRequest.h b/Source/WebCore/platform/network/cf/ResourceRequest.h index 47b155b71..72522d9ed 100644 --- a/Source/WebCore/platform/network/cf/ResourceRequest.h +++ b/Source/WebCore/platform/network/cf/ResourceRequest.h @@ -34,11 +34,7 @@ typedef const struct _CFURLRequest* CFURLRequestRef; #endif -#ifdef __OBJC__ -@class NSURLRequest; -#else -class NSURLRequest; -#endif +OBJC_CLASS NSURLRequest; #if USE(CFURLSTORAGESESSIONS) && (defined(BUILDING_ON_SNOW_LEOPARD) || defined(BUILDING_ON_LEOPARD)) typedef struct __CFURLStorageSession* CFURLStorageSessionRef; diff --git a/Source/WebCore/platform/network/cf/ResourceResponse.h b/Source/WebCore/platform/network/cf/ResourceResponse.h index 946eee083..d83a6610f 100644 --- a/Source/WebCore/platform/network/cf/ResourceResponse.h +++ b/Source/WebCore/platform/network/cf/ResourceResponse.h @@ -33,11 +33,7 @@ typedef struct _CFURLResponse* CFURLResponseRef; #endif -#ifdef __OBJC__ -@class NSURLResponse; -#else -class NSURLResponse; -#endif +OBJC_CLASS NSURLResponse; namespace WebCore { diff --git a/Source/WebCore/platform/network/soup/ResourceResponse.h b/Source/WebCore/platform/network/soup/ResourceResponse.h index 6ebba8b55..8624c0591 100644 --- a/Source/WebCore/platform/network/soup/ResourceResponse.h +++ b/Source/WebCore/platform/network/soup/ResourceResponse.h @@ -42,6 +42,7 @@ public: ResourceResponse(const KURL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename) : ResourceResponseBase(url, mimeType, expectedLength, textEncodingName, filename) + , m_soupFlags(static_cast<SoupMessageFlags>(0)) { } diff --git a/Source/WebCore/platform/qt/DataTransferItemListQt.cpp b/Source/WebCore/platform/qt/DataTransferItemListQt.cpp index 45fb6bc76..1806a7f6f 100644 --- a/Source/WebCore/platform/qt/DataTransferItemListQt.cpp +++ b/Source/WebCore/platform/qt/DataTransferItemListQt.cpp @@ -40,10 +40,73 @@ PassRefPtr<DataTransferItemListQt> DataTransferItemListQt::create(PassRefPtr<Cli } DataTransferItemListQt::DataTransferItemListQt(PassRefPtr<Clipboard> owner, ScriptExecutionContext* context) - : DataTransferItemList(owner, context) + : m_owner(clipboard) + , m_context(context) { } +size_t DataTransferItemListQt::length() const +{ + if (m_owner->policy() == ClipboardNumb) + return 0; + + return m_items.size(); +} + +PassRefPtr<DataTransferItem> DataTransferItemListQt::item(unsigned long index) +{ + if (m_owner->policy() == ClipboardNumb || index >= length()) + return 0; + + return m_items[index]; +} + +void DataTransferItemListQt::deleteItem(unsigned long index, ExceptionCode& ec) +{ + if (m_owner->policy() != ClipboardWritable) { + ec = INVALID_STATE_ERR; + return; + } + + if (index >= length()) + return; + + m_items.remove(index); +} + +void DataTransferItemListQt::clear() +{ + if (m_owner->policy() != ClipboardWritable) + return; + + m_items.clear(); + +} + +void DataTransferItemListQt::add(const String& data, const String& type, ExceptionCode& ec) +{ + if (m_owner->policy() != ClipboardWritable) + return; + + // Only one 'string' item with a given type is allowed in the collection. + for (size_t i = 0; i < m_items.size(); ++i) { + if (m_items[i]->type() == type && m_items[i]->kind() == DataTransferItem::kindString) { + ec = NOT_SUPPORTED_ERR; + return; + } + } + + m_items.append(DataTransferItem::create(m_owner, m_context, data, type)); +} + +void DataTransferItemListQt::add(PassRefPtr<File> file) +{ + if (m_owner->policy() != ClipboardWritable || !file) + return; + + m_items.append(DataTransferItem::create(m_owner, m_context, file)); +} + void DataTransferItemListQt::addPasteboardItem(const String& type) { m_items.append(DataTransferItemQt::createFromPasteboard(m_owner, m_context, type)); diff --git a/Source/WebCore/platform/qt/DataTransferItemListQt.h b/Source/WebCore/platform/qt/DataTransferItemListQt.h index 1442563ee..d5c39a4a5 100644 --- a/Source/WebCore/platform/qt/DataTransferItemListQt.h +++ b/Source/WebCore/platform/qt/DataTransferItemListQt.h @@ -42,11 +42,24 @@ class DataTransferItemListQt : public DataTransferItemList { public: static PassRefPtr<DataTransferItemListQt> create(PassRefPtr<Clipboard>, ScriptExecutionContext*); + virtual size_t length() const; + virtual PassRefPtr<DataTransferItem> item(unsigned long index); + virtual void deleteItem(unsigned long index, ExceptionCode&); + virtual void clear(); + virtual void add(const String& data, const String& type, ExceptionCode&); + virtual void add(PassRefPtr<File>); + + friend class ClipboardQt; private: DataTransferItemListQt(PassRefPtr<Clipboard>, ScriptExecutionContext*); virtual void addPasteboardItem(const String& type); + + RefPtr<Clipboard> m_owner; + // Indirectly owned by our parent. + ScriptExecutionContext* m_context; + Vector<RefPtr<DataTransferItem> > m_items; }; } diff --git a/Source/WebCore/platform/qt/DataTransferItemQt.cpp b/Source/WebCore/platform/qt/DataTransferItemQt.cpp index b277bef04..9ff621ef4 100644 --- a/Source/WebCore/platform/qt/DataTransferItemQt.cpp +++ b/Source/WebCore/platform/qt/DataTransferItemQt.cpp @@ -31,6 +31,7 @@ #include "Blob.h" #include "Clipboard.h" +#include "File.h" #include "NotImplemented.h" #include "StringCallback.h" #include <QApplication> @@ -40,12 +41,19 @@ namespace WebCore { -PassRefPtr<DataTransferItem> DataTransferItem::create(PassRefPtr<Clipboard> owner, - ScriptExecutionContext* context, - const String& data, - const String& type) +PassRefPtr<DataTransferItemQt> DataTransferItemQt::create(PassRefPtr<Clipboard> owner, + ScriptExecutionContext* context, + const String& data, + const String& type) +{ + return adoptRef(new DataTransferItemQt(owner, context, DataTransferItemQt::InternalSource, kindString, type, data)); +} + +PassRefPtr<DataTransferItemQt> DataTransferItemQt::create(PassRefPtr<Clipboard> owner, + ScriptExecutionContext* context, + PassRefPtr<File> file) { - return DataTransferItemQt::create(owner, context, type, data); + return adoptRef(new DataTransferItemQt(owner, context, DataTransferItemQt::InternalSource, file)); } PassRefPtr<DataTransferItemQt> DataTransferItemQt::createFromPasteboard(PassRefPtr<Clipboard> owner, @@ -58,27 +66,34 @@ PassRefPtr<DataTransferItemQt> DataTransferItemQt::createFromPasteboard(PassRefP return adoptRef(new DataTransferItemQt(owner, context, PasteboardSource, DataTransferItem::kindFile, type, "")); } -PassRefPtr<DataTransferItemQt> DataTransferItemQt::create(PassRefPtr<Clipboard> owner, - ScriptExecutionContext* context, - const String& type, - const String& data) -{ - return adoptRef(new DataTransferItemQt(owner, context, InternalSource, DataTransferItem::kindString, type, data)); -} - DataTransferItemQt::DataTransferItemQt(PassRefPtr<Clipboard> owner, ScriptExecutionContext* context, DataSource source, const String& kind, const String& type, const String& data) - : DataTransferItem(owner, kind, type) + : m_owner(owner) , m_context(context) + , m_kind(kind) + , m_type(type) , m_dataSource(source) , m_data(data) { } -void DataTransferItemQt::getAsString(PassRefPtr<StringCallback> callback) +DataTransferItemQt::DataTransferItemQt(PassRefPtr<Clipboard> owner, + ScriptExecutionContext* context, + DataSource source, + PassRefPtr<File> file) + : m_owner(owner) + , m_context(context) + , m_kind(kindFile) + , m_type(file.get() ? file->type() : ""); + , m_source(source) + , m_file(file) +{ +} + +void DataTransferItemQt::getAsString(PassRefPtr<StringCallback> callback) const { if ((owner()->policy() != ClipboardReadable && owner()->policy() != ClipboardWritable) || kind() != kindString) @@ -106,9 +121,11 @@ void DataTransferItemQt::getAsString(PassRefPtr<StringCallback> callback) callback->scheduleCallback(m_context, data); } -PassRefPtr<Blob> DataTransferItemQt::getAsFile() +PassRefPtr<Blob> DataTransferItemQt::getAsFile() const { - notImplemented(); + if (kind() == kindFile && m_dataSource == InternalSource) + return m_file; + return 0; } diff --git a/Source/WebCore/platform/qt/DataTransferItemQt.h b/Source/WebCore/platform/qt/DataTransferItemQt.h index 025ba4161..de88b8ad2 100644 --- a/Source/WebCore/platform/qt/DataTransferItemQt.h +++ b/Source/WebCore/platform/qt/DataTransferItemQt.h @@ -34,22 +34,25 @@ namespace WebCore { class Clipboard; +class File; class ScriptExecutionContext; class DataTransferItemQt : public DataTransferItem { public: + static PassRefPtr<DataTransferItemQt> create(PassRefPtr<Clipboard> owner, ScriptExecutionContext*, const String& data, const String& type); + static PassRefPtr<DataTransferItemQt> create(PassRefPtr<Clipboard> owner, ScriptExecutionContext*, PassRefPtr<File>); static PassRefPtr<DataTransferItemQt> createFromPasteboard(PassRefPtr<Clipboard> owner, ScriptExecutionContext*, const String&); - static PassRefPtr<DataTransferItemQt> create(PassRefPtr<Clipboard> owner, - ScriptExecutionContext*, - const String&, - const String&); - virtual void getAsString(PassRefPtr<StringCallback>); - virtual PassRefPtr<Blob> getAsFile(); + virtual String kind() const { return m_kind; } + virtual String type() const { return m_type; } + virtual void getAsString(PassRefPtr<StringCallback>) const; + virtual PassRefPtr<Blob> getAsFile() const; private: + friend class DataTransferItemListQt; + enum DataSource { PasteboardSource, InternalSource @@ -59,10 +62,18 @@ private: ScriptExecutionContext*, DataSource, const String&, const String&, const String&); + DataTransferItemQt(PassRefPtr<Clipboard> owner, + ScriptExecutionContext*, + DataSource, + PassRefPtr<File>); + const RefPtr<Clipboard> m_owner; ScriptExecutionContext* m_context; + const String m_kind; + const String m_type; const DataSource m_dataSource; const String m_data; + RefPtr<File> m_file; }; } diff --git a/Source/WebCore/platform/qt/LanguageQt.cpp b/Source/WebCore/platform/qt/LanguageQt.cpp index 5a1d70721..bdccfcd5e 100644 --- a/Source/WebCore/platform/qt/LanguageQt.cpp +++ b/Source/WebCore/platform/qt/LanguageQt.cpp @@ -29,13 +29,21 @@ #include "PlatformString.h" #include <QLocale> +#include <wtf/Vector.h> namespace WebCore { -String platformDefaultLanguage() +static String platformLanguage() { QLocale locale; return locale.name().replace(QLatin1Char('_'), QLatin1Char('-')); } +Vector<String> platformUserPreferredLanguages() +{ + Vector<String> userPreferredLanguages; + userPreferredLanguages.append(platformLanguage()); + return userPreferredLanguages; +} + } diff --git a/Source/WebCore/platform/qt/PlatformScreenQt.cpp b/Source/WebCore/platform/qt/PlatformScreenQt.cpp index 7a267fc6c..846f0b8a4 100644 --- a/Source/WebCore/platform/qt/PlatformScreenQt.cpp +++ b/Source/WebCore/platform/qt/PlatformScreenQt.cpp @@ -102,15 +102,15 @@ bool screenIsMonochrome(Widget* w) return QApplication::desktop()->screen(screenNumber(w))->colorCount() == 2; } -FloatRect screenRect(Widget* w) +FloatRect screenRect(FrameView* frameView) { - QRect r = QApplication::desktop()->screenGeometry(screenNumber(w)); + QRect r = QApplication::desktop()->screenGeometry(screenNumber(frameView)); return FloatRect(r.x(), r.y(), r.width(), r.height()); } -FloatRect screenAvailableRect(Widget* w) +FloatRect screenAvailableRect(FrameView* frameView) { - QRect r = QApplication::desktop()->availableGeometry(screenNumber(w)); + QRect r = QApplication::desktop()->availableGeometry(screenNumber(frameView)); return FloatRect(r.x(), r.y(), r.width(), r.height()); } diff --git a/Source/WebCore/platform/qt/PlatformTouchPointQt.cpp b/Source/WebCore/platform/qt/PlatformTouchPointQt.cpp index c2932129c..ee5e56df7 100644 --- a/Source/WebCore/platform/qt/PlatformTouchPointQt.cpp +++ b/Source/WebCore/platform/qt/PlatformTouchPointQt.cpp @@ -1,7 +1,7 @@ /* * This file is part of the WebKit project. * - * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2009,2012 Nokia Corporation and/or its subsidiary(-ies) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -28,17 +28,29 @@ namespace WebCore { PlatformTouchPoint::PlatformTouchPoint(const QTouchEvent::TouchPoint& point) -{ // The QTouchEvent::TouchPoint API states that ids will be >= 0. - m_id = static_cast<unsigned>(point.id()); + : m_id(point.id()) + , m_screenPos(point.screenPos().toPoint()) + , m_pos(point.pos().toPoint()) +{ switch (point.state()) { case Qt::TouchPointReleased: m_state = TouchReleased; break; case Qt::TouchPointMoved: m_state = TouchMoved; break; case Qt::TouchPointPressed: m_state = TouchPressed; break; case Qt::TouchPointStationary: m_state = TouchStationary; break; } - m_screenPos = point.screenPos().toPoint(); - m_pos = point.pos().toPoint(); + // Qt reports touch point size as rectangles, but we will pretend it is an oval. + QRect touchRect = point.rect().toAlignedRect(); + if (touchRect.isValid()) { + m_radiusX = point.rect().width() / 2; + m_radiusY = point.rect().height() / 2; + } else { + // http://www.w3.org/TR/2011/WD-touch-events-20110505: 1 if no value is known. + m_radiusX = 1; + m_radiusY = 1; + } + m_force = point.pressure(); + // FIXME: Support m_rotationAngle if QTouchEvent at some point supports it. } } diff --git a/Source/WebCore/platform/qt/RenderThemeQtMobile.cpp b/Source/WebCore/platform/qt/RenderThemeQtMobile.cpp index ca47cf93d..c2f4228b0 100644 --- a/Source/WebCore/platform/qt/RenderThemeQtMobile.cpp +++ b/Source/WebCore/platform/qt/RenderThemeQtMobile.cpp @@ -63,6 +63,7 @@ static const int radioWidth = 21; static const int sliderSize = 19; static const int buttonHeightRatio = 1.5; +static const float multipleComboDotsOffsetFactor = 1.8; static const float buttonPaddingLeft = 18; static const float buttonPaddingRight = 18; static const float buttonPaddingTop = 2; @@ -80,6 +81,18 @@ static const QColor highlightColor(16, 128, 221); static const QColor buttonGradientBottom(245, 245, 245); static const QColor shadowColor(80, 80, 80, 160); +static QHash<KeyIdentifier, CacheKey> cacheKeys; + +uint qHash(const KeyIdentifier& id) +{ + const quint32 value = id.trait1 + (id.trait2 << 1) + (uint(id.type) << 2) + (id.height << 5) + (id.width << 14) + (id.trait3 << 25); + const unsigned char* p = reinterpret_cast<const unsigned char*>(&value); + uint hash = 0; + for (int i = 0; i < 4; ++i) + hash ^= (hash << 5) + (hash >> 2) + p[i]; + return hash; +} + static void drawControlBackground(QPainter* painter, const QPen& pen, const QRect& rect, const QBrush& brush) { QPen oldPen = painter->pen(); @@ -150,6 +163,28 @@ StylePainterMobile::~StylePainterMobile() painter->setRenderHints(QPainter::SmoothPixmapTransform, m_previousSmoothPixmapTransform); } +bool StylePainterMobile::findCachedControl(const KeyIdentifier& keyId, QPixmap* result) +{ + static CacheKey emptyKey; + CacheKey key = cacheKeys.value(keyId, emptyKey); + if (key == emptyKey) + return false; + const bool ret = QPixmapCache::find(key, result); + if (!ret) + cacheKeys.remove(keyId); + return ret; +} + +void StylePainterMobile::insertIntoCache(const KeyIdentifier& keyId, const QPixmap& pixmap) +{ + ASSERT(keyId.type); + const int sizeInKiloBytes = pixmap.width() * pixmap.height() * pixmap.depth() / (8 * 1024); + // Don't cache pixmaps over 512 KB; + if (sizeInKiloBytes > 512) + return; + cacheKeys.insert(keyId, QPixmapCache::insert(pixmap)); +} + void StylePainterMobile::drawCheckableBackground(QPainter* painter, const QRect& rect, bool checked, bool enabled) const { QBrush brush; @@ -196,10 +231,12 @@ QPixmap StylePainterMobile::findCheckBox(const QSize& size, bool checked, bool e { ASSERT(size.width() == size.height()); QPixmap result; - static const QString prefix = QLatin1String("$qt-webkit-mobile-theme-checkbox-"); - QString key = prefix + QString::number(size.width()) + QLatin1String("-") + (enabled ? QLatin1String("on") : QLatin1String("off")) - + (checked ? QLatin1String("-checked") : QString()); - if (!QPixmapCache::find(key, result)) { + KeyIdentifier id; + id.type = KeyIdentifier::CheckBox; + id.height = size.height(); + id.trait1 = enabled; + id.trait2 = checked; + if (!findCachedControl(id, &result)) { result = QPixmap(size); result.fill(Qt::transparent); QPainter cachePainter(&result); @@ -207,14 +244,13 @@ QPixmap StylePainterMobile::findCheckBox(const QSize& size, bool checked, bool e drawCheckableBackground(&cachePainter, rect, checked, enabled); if (checked || !enabled) drawChecker(&cachePainter, rect, enabled ? Qt::white : Qt::gray); - QPixmapCache::insert(key, result); + insertIntoCache(id, result); } return result; } void StylePainterMobile::drawRadio(QPainter* painter, const QSize& size, bool checked, bool enabled) const { - ASSERT(size.width() == size.height()); QRect rect(QPoint(0, 0), size); drawCheckableBackground(painter, rect, checked, enabled); @@ -225,21 +261,24 @@ void StylePainterMobile::drawRadio(QPainter* painter, const QSize& size, bool ch QPixmap StylePainterMobile::findRadio(const QSize& size, bool checked, bool enabled) const { + ASSERT(size.width() == size.height()); QPixmap result; - static const QString prefix = QLatin1String("$qt-webkit-mobile-theme-radio-"); - QString key = prefix + QString::number(size.width()) + QLatin1String("-") + (enabled ? QLatin1String("on") : QLatin1String("off")) - + (checked ? QLatin1String("-checked") : QString()); - if (!QPixmapCache::find(key, result)) { + KeyIdentifier id; + id.type = KeyIdentifier::Radio; + id.height = size.height(); + id.trait1 = enabled; + id.trait2 = checked; + if (!findCachedControl(id, &result)) { result = QPixmap(size); result.fill(Qt::transparent); QPainter cachePainter(&result); drawRadio(&cachePainter, size, checked, enabled); - QPixmapCache::insert(key, result); + insertIntoCache(id, result); } return result; } -void StylePainterMobile::drawMultipleComboButton(QPainter* painter, const QSize& size, const QColor& color) const +void StylePainterMobile::drawMultipleComboButton(QPainter* painter, const QSizeF& size, const QColor& color) const { const qreal dotDiameter = size.height(); const qreal dotRadii = dotDiameter / 2; @@ -248,59 +287,66 @@ void StylePainterMobile::drawMultipleComboButton(QPainter* painter, const QSize& painter->setPen(color); painter->setBrush(color); - const qreal offsetFactor = 1.8; for (int i = 0; i < 3; ++i) { - QPointF center(offsetFactor * dotRadii + i * offsetFactor * dotDiameter, dotRadii); + QPointF center(dotRadii + i * multipleComboDotsOffsetFactor * dotDiameter, dotRadii); painter->drawEllipse(center, dotRadii, dotRadii); } } -void StylePainterMobile::drawSimpleComboButton(QPainter* painter, const QSize& size, const QColor& color) const +void StylePainterMobile::drawSimpleComboButton(QPainter* painter, const QSizeF& size, const QColor& color) const { - const int gap = (size.height() - 1) / 5; - const int arrowHeight = 2 * gap; - const int right = arrowHeight * 2; - const int bottomBaseline = arrowHeight + gap + 1; - QPolygon upArrow, downArrow; - upArrow << QPoint(0, arrowHeight) << QPoint(arrowHeight, 0) << QPoint(right, arrowHeight); - downArrow << QPoint(0, bottomBaseline) << QPoint(arrowHeight, bottomBaseline + arrowHeight) - << QPoint(right, bottomBaseline); + const qreal gap = size.height() / 5.0; + const qreal arrowHeight = (size.height() - gap) / 2.0; + const qreal right = arrowHeight * 2; + const qreal bottomBaseline = size.height() - arrowHeight; + QPolygonF upArrow, downArrow; + upArrow << QPointF(0, arrowHeight) << QPointF(arrowHeight, 0) << QPointF(right, arrowHeight); + downArrow << QPointF(0, bottomBaseline) << QPointF(arrowHeight, bottomBaseline + arrowHeight) + << QPointF(right, bottomBaseline); - painter->setPen(color); + painter->setPen(Qt::NoPen); painter->setBrush(color); painter->drawPolygon(upArrow); painter->drawPolygon(downArrow); } -QSize StylePainterMobile::getButtonImageSize(int buttonHeight, bool multiple) const +QSizeF StylePainterMobile::getButtonImageSize(int buttonHeight, bool multiple) const { if (multiple) - return QSize(buttonHeight / 2, buttonHeight / 10); + return QSizeF(qreal(2 + buttonHeight * 3 * multipleComboDotsOffsetFactor/ 10.0) + , qreal(2 + buttonHeight / 10.0)); - const int height = buttonHeight / 2.5; - const int width = 4 * height / 5; - return QSize(width, height); + const qreal height = buttonHeight / 2.5; + const qreal width = 4 * height / 5.0; + return QSizeF(2 + width, 2 + height); } QPixmap StylePainterMobile::findComboButton(const QSize& size, bool multiple, bool enabled) const { if (size.isNull()) return QPixmap(); - static const QString prefix = QLatin1String("$qt-webkit-mobile-theme-combo-"); QPixmap result; - QString key = prefix + (multiple ? QLatin1String("multiple-") : QLatin1String("simple-")) - + QString::number(size.width()) + QLatin1String("-") + QString::number(size.height()) - + QLatin1String("-") + (enabled ? QLatin1String("on") : QLatin1String("off")); - - if (!QPixmapCache::find(key, result)) { + KeyIdentifier id; + id.type = KeyIdentifier::ComboButton; + id.width = size.width(); + id.height = size.height(); + id.trait1 = multiple; + id.trait2 = enabled; + + if (!findCachedControl(id, &result)) { result = QPixmap(size); + const qreal border = painterScale(painter); + const QSizeF padding(2 * border, 2 * border); + const QSizeF innerSize = size - padding; + ASSERT(innerSize.isValid()); result.fill(Qt::transparent); QPainter cachePainter(&result); + cachePainter.translate(border, border); if (multiple) - drawMultipleComboButton(&cachePainter, size, enabled ? darkColor : Qt::lightGray); + drawMultipleComboButton(&cachePainter, innerSize, enabled ? darkColor : Qt::lightGray); else - drawSimpleComboButton(&cachePainter, size, enabled ? darkColor : Qt::lightGray); - QPixmapCache::insert(key, result); + drawSimpleComboButton(&cachePainter, innerSize, enabled ? darkColor : Qt::lightGray); + insertIntoCache(id, result); } return result; } @@ -317,10 +363,13 @@ void StylePainterMobile::drawLineEdit(const QRect& rect, bool focused, bool enab QPixmap StylePainterMobile::findLineEdit(const QSize & size, bool focused) const { QPixmap result; - static const QString prefix = QLatin1String("$qt-webkit-mobile-theme-lineEdit-"); - QString key = prefix + QString::number(size.width()) + QLatin1String("x") + QString::number(size.height()) - + (focused ? QLatin1String("-focused") : QString()); - if (!QPixmapCache::find(key, result)) { + KeyIdentifier id; + id.type = KeyIdentifier::LineEdit; + id.width = size.width(); + id.height = size.height(); + id.trait1 = focused; + + if (!findCachedControl(id, &result)) { const int focusFrame = painterScale(painter); result = QPixmap(size + QSize(2 * focusFrame, 2 * focusFrame)); result.fill(Qt::transparent); @@ -332,7 +381,7 @@ QPixmap StylePainterMobile::findLineEdit(const QSize & size, bool focused) const QPen focusPen(highlightColor, focusFrame, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); drawControlBackground(&cachePainter, focusPen, rect, Qt::NoBrush); } - QPixmapCache::insert(key, result); + insertIntoCache(id, result); } return result; } @@ -366,10 +415,13 @@ void StylePainterMobile::drawPushButton(const QRect& rect, bool sunken, bool ena QPixmap StylePainterMobile::findPushButton(const QSize& size, bool sunken, bool enabled) const { QPixmap result; - static const QString prefix = QLatin1String("$qt-webkit-mobile-theme-pushButton-"); - QString key = prefix + QString::number(size.width()) + QLatin1String("x") + QString::number(size.height()) - + (sunken ? QLatin1String("-sunken") : QString()) + (enabled ? QLatin1String("-on") : QString()); - if (!QPixmapCache::find(key, result)) { + KeyIdentifier id; + id.type = KeyIdentifier::PushButton; + id.width = size.width(); + id.height = size.height(); + id.trait1 = sunken; + id.trait2 = enabled; + if (!findCachedControl(id, &result)) { const qreal dropShadowSize = painterScale(painter); result = QPixmap(size); result.fill(Qt::transparent); @@ -396,7 +448,7 @@ QPixmap StylePainterMobile::findPushButton(const QSize& size, bool sunken, bool brush = linearGradient; } drawControlBackground(&cachePainter, borderPen(painter), rect, brush); - QPixmapCache::insert(key, result); + insertIntoCache(id, result); } return result; } @@ -407,28 +459,31 @@ void StylePainterMobile::drawComboBox(const QRect& rect, bool multiple, bool ena if (pushButton.isNull()) return; painter->drawPixmap(rect, pushButton); - QRect targetRect(QPoint(0, 0), getButtonImageSize(rect.height() - 1, multiple)); - const QPoint buttonCenter(rect.right() - arrowBoxWidth / 2, rect.height() / 2 - 1); + QRectF targetRect(QPointF(0, 0), getButtonImageSize(rect.height() - 1, multiple)); + const QPointF buttonCenter(rect.right() - arrowBoxWidth / 2, rect.top() + (rect.height() - 1) / 2); targetRect.moveCenter(buttonCenter); - QPixmap pic = findComboButton(sizeForPainterScale(targetRect), multiple, enabled); + QPixmap pic = findComboButton(sizeForPainterScale(targetRect.toRect()), multiple, enabled); if (pic.isNull()) return; - painter->drawPixmap(targetRect, pic); + painter->drawPixmap(targetRect.toRect(), pic); } void StylePainterMobile::drawProgress(const QRect& rect, double progress, bool leftToRight, bool animated) const { - static const QString prefix = QLatin1String("$qt-webkit-mobile-theme-progress-"); const int border = rect.height() / 4; const QRect targetRect = rect.adjusted(0, border, 0, -border); QPixmap result; const QSize imageSize = sizeForPainterScale(targetRect); - QString key = prefix + QString::number(imageSize.width()) + QLatin1String("-") + QString::number(imageSize.height()) - + QLatin1String("-") + QString::number(progress, 'f', 3) + (animated? QLatin1String("-anim") : QString()) - + ((!animated && !leftToRight) ? QLatin1String("-rtl") : QString()); - if (!QPixmapCache::find(key, result)) { + KeyIdentifier id; + id.type = KeyIdentifier::Progress; + id.width = imageSize.width(); + id.height = imageSize.height(); + id.trait1 = animated; + id.trait2 = (!animated && !leftToRight); + id.trait3 = progress * 100; + if (!findCachedControl(id, &result)) { if (imageSize.isNull()) return; result = QPixmap(imageSize); @@ -463,25 +518,28 @@ void StylePainterMobile::drawProgress(const QRect& rect, double progress, bool l radius = radiusFactor * progressRect.height(); painter.drawRoundedRect(progressRect, radius, radius); } - QPixmapCache::insert(key, result); + insertIntoCache(id, result); } painter->drawPixmap(targetRect, result); } void StylePainterMobile::drawSliderThumb(const QRect & rect, bool pressed) const { - static const QString prefix = QLatin1String("$qt-webkit-mobile-theme-slider-thumb-"); QPixmap result; const QSize size = sizeForPainterScale(rect); - const QString key = prefix + QString::number(size.width()); - if (!QPixmapCache::find(key, &result)) { + KeyIdentifier id; + id.type = KeyIdentifier::SliderThumb; + id.width = size.width(); + id.height = size.height(); + id.trait1 = pressed; + if (!findCachedControl(id, &result)) { if (size.isNull()) return; result = QPixmap(size); result.fill(Qt::transparent); QPainter cachePainter(&result); drawControlBackground(&cachePainter, borderPen(painter), QRect(QPoint(0, 0), size), pressed? Qt::lightGray : buttonGradientBottom); - QPixmapCache::insert(key, result); + insertIntoCache(id, result); } painter->drawPixmap(rect, result); } @@ -661,6 +719,8 @@ bool RenderThemeQtMobile::paintTextField(RenderObject* o, const PaintInfo& i, co // Now paint the text field. if (appearance == TextAreaPart) { + const bool previousAntialiasing = p.painter->testRenderHint(QPainter::Antialiasing); + p.painter->setRenderHint(QPainter::Antialiasing); p.painter->setPen(borderPen()); p.painter->setBrush(Qt::white); const int radius = checkBoxWidth * radiusFactor; @@ -672,7 +732,7 @@ bool RenderThemeQtMobile::paintTextField(RenderObject* o, const PaintInfo& i, co p.painter->setBrush(Qt::NoBrush); p.painter->drawRoundedRect(r, radius, radius); } - + p.painter->setRenderHint(QPainter::Antialiasing, previousAntialiasing); } else p.drawLineEdit(r, isFocused(o), isEnabled(o)); return false; @@ -702,12 +762,7 @@ bool RenderThemeQtMobile::paintMenuList(RenderObject* o, const PaintInfo& i, con if (!p.isValid()) return true; - const QPoint topLeft = r.location(); - p.painter->translate(topLeft); - const QRect rect(QPoint(0, 0), r.size()); - - p.drawComboBox(rect, checkMultiple(o), isEnabled(o)); - p.painter->translate(-topLeft); + p.drawComboBox(r, checkMultiple(o), isEnabled(o)); return false; } diff --git a/Source/WebCore/platform/qt/RenderThemeQtMobile.h b/Source/WebCore/platform/qt/RenderThemeQtMobile.h index 9e9b8143e..c57a18029 100644 --- a/Source/WebCore/platform/qt/RenderThemeQtMobile.h +++ b/Source/WebCore/platform/qt/RenderThemeQtMobile.h @@ -25,13 +25,16 @@ #include "RenderThemeQt.h" #include <QBrush> +#include <QHash> +#include <QPixmapCache> QT_BEGIN_NAMESPACE class QColor; -class QPixmap; class QSize; QT_END_NAMESPACE +typedef QPixmapCache::Key CacheKey; + namespace WebCore { class RenderThemeQtMobile : public RenderThemeQt { @@ -83,6 +86,44 @@ private: void setPaletteFromPageClientIfExists(QPalette&) const; }; +struct KeyIdentifier { + + KeyIdentifier() + : type(Undefined) + , width(0) + , height(0) + , trait1(0) + , trait2(0) + , trait3(0) + { + } + + enum ControlType { + Undefined, + CheckBox, + Radio, + ComboButton, + LineEdit, + PushButton, + Progress, + SliderThumb + }; + + ControlType type : 3; + uint width : 11; + uint height : 9; + uint trait1 : 1; + uint trait2 : 1; + uint trait3 : 7; + + inline bool operator==(const KeyIdentifier& other) const + { + return (type == other.type && width == other.width + && height == other.height && trait1 == other.trait1 + && trait2 == other.trait2 && trait3 == other.trait3); + } +}; + class StylePainterMobile : public StylePainter { public: @@ -105,9 +146,9 @@ private: void drawRadio(QPainter*, const QSize&, bool checked, bool enabled) const; QPixmap findRadio(const QSize&, bool checked, bool enabled) const; - QSize getButtonImageSize(int , bool multiple) const; - void drawSimpleComboButton(QPainter*, const QSize&, const QColor&) const; - void drawMultipleComboButton(QPainter*, const QSize&, const QColor&) const; + QSizeF getButtonImageSize(int , bool multiple) const; + void drawSimpleComboButton(QPainter*, const QSizeF&, const QColor&) const; + void drawMultipleComboButton(QPainter*, const QSizeF&, const QColor&) const; QPixmap findComboButton(const QSize&, bool multiple, bool enabled) const; QPixmap findLineEdit(const QSize&, bool focused) const; @@ -115,9 +156,12 @@ private: QSize sizeForPainterScale(const QRect&) const; + static bool findCachedControl(const KeyIdentifier&, QPixmap*); + static void insertIntoCache(const KeyIdentifier&, const QPixmap&); + bool m_previousSmoothPixmapTransform; - Q_DISABLE_COPY(StylePainterMobile); + Q_DISABLE_COPY(StylePainterMobile) }; } diff --git a/Source/WebCore/platform/qt/RunLoopQt.cpp b/Source/WebCore/platform/qt/RunLoopQt.cpp new file mode 100644 index 000000000..2a87e2fc8 --- /dev/null +++ b/Source/WebCore/platform/qt/RunLoopQt.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RunLoop.h" + +#include <QAbstractEventDispatcher> +#include <QCoreApplication> +#include <QMetaMethod> +#include <QMetaObject> +#include <QObject> +#include <QTimerEvent> + +namespace WebCore { + +class RunLoop::TimerObject : public QObject { + Q_OBJECT +public: + TimerObject(RunLoop* runLoop) : m_runLoop(runLoop) + { + int methodIndex = metaObject()->indexOfMethod("performWork()"); + m_method = metaObject()->method(methodIndex); + } + + Q_SLOT void performWork() { m_runLoop->performWork(); } + inline void wakeUp() { m_method.invoke(this, Qt::QueuedConnection); } + +protected: + virtual void timerEvent(QTimerEvent* event) + { + RunLoop::TimerBase::timerFired(m_runLoop, event->timerId()); + } + +private: + RunLoop* m_runLoop; + QMetaMethod m_method; +}; + +static QEventLoop* currentEventLoop; + +void RunLoop::run() +{ + static bool mainEventLoopIsRunning = false; + if (!mainEventLoopIsRunning) { + mainEventLoopIsRunning = true; + QCoreApplication::exec(); + mainEventLoopIsRunning = false; + } else { + QEventLoop eventLoop; + + QEventLoop* previousEventLoop = currentEventLoop; + currentEventLoop = &eventLoop; + + eventLoop.exec(); + + currentEventLoop = previousEventLoop; + } +} + +void RunLoop::stop() +{ + if (currentEventLoop) + currentEventLoop->exit(); + else + QCoreApplication::exit(); +} + +RunLoop::RunLoop() + : m_timerObject(new TimerObject(this)) +{ +} + +RunLoop::~RunLoop() +{ + delete m_timerObject; +} + +void RunLoop::wakeUp() +{ + m_timerObject->wakeUp(); +} + +// RunLoop::Timer + +void RunLoop::TimerBase::timerFired(RunLoop* runLoop, int ID) +{ + TimerMap::iterator it = runLoop->m_activeTimers.find(ID); + ASSERT(it != runLoop->m_activeTimers.end()); + TimerBase* timer = it->second; + + if (!timer->m_isRepeating) { + // Stop the timer (calling stop would need another hash table lookup). + runLoop->m_activeTimers.remove(it); + runLoop->m_timerObject->killTimer(timer->m_ID); + timer->m_ID = 0; + } + + timer->fired(); +} + +RunLoop::TimerBase::TimerBase(RunLoop* runLoop) + : m_runLoop(runLoop) + , m_ID(0) + , m_isRepeating(false) +{ +} + +RunLoop::TimerBase::~TimerBase() +{ + stop(); +} + +void RunLoop::TimerBase::start(double nextFireInterval, bool repeat) +{ + stop(); + int millis = static_cast<int>(nextFireInterval * 1000); + m_isRepeating = repeat; + m_ID = m_runLoop->m_timerObject->startTimer(millis); + ASSERT(m_ID); + m_runLoop->m_activeTimers.set(m_ID, this); +} + +void RunLoop::TimerBase::stop() +{ + if (!m_ID) + return; + TimerMap::iterator it = m_runLoop->m_activeTimers.find(m_ID); + if (it == m_runLoop->m_activeTimers.end()) + return; + + m_runLoop->m_activeTimers.remove(it); + m_runLoop->m_timerObject->killTimer(m_ID); + m_ID = 0; +} + +bool RunLoop::TimerBase::isActive() const +{ + return m_ID; +} + +#include "RunLoopQt.moc" + +} // namespace WebCore diff --git a/Source/WebCore/platform/text/DecodeEscapeSequences.h b/Source/WebCore/platform/text/DecodeEscapeSequences.h index a795698db..22a47ac14 100644 --- a/Source/WebCore/platform/text/DecodeEscapeSequences.h +++ b/Source/WebCore/platform/text/DecodeEscapeSequences.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2011 Daniel Bates (dbates@intudata.com). All Rights Reserved. + * Copyright (c) 2012 Google, inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -9,6 +10,9 @@ * 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 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 APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -36,52 +40,81 @@ namespace WebCore { // See <http://en.wikipedia.org/wiki/Percent-encoding#Non-standard_implementations>. struct Unicode16BitEscapeSequence { - enum { size = 6 }; // e.g. %u26C4 - static size_t findInString(const String& string, unsigned start = 0) { return string.find("%u", start); } - static bool matchStringPrefix(const String& string, unsigned start = 0) + enum { sequenceSize = 6 }; // e.g. %u26C4 + static size_t findInString(const String& string, size_t startPosition) { return string.find("%u", startPosition); } + static size_t findEndOfRun(const String& string, size_t startPosition, size_t endPosition) { - if (string.length() - start < size) - return false; - return string[start] == '%' && string[start + 1] == 'u' - && isASCIIHexDigit(string[start + 2]) && isASCIIHexDigit(string[start + 3]) - && isASCIIHexDigit(string[start + 4]) && isASCIIHexDigit(string[start + 5]); + size_t runEnd = startPosition; + while (endPosition - runEnd >= sequenceSize && string[runEnd] == '%' && string[runEnd + 1] == 'u' + && isASCIIHexDigit(string[runEnd + 2]) && isASCIIHexDigit(string[runEnd + 3]) + && isASCIIHexDigit(string[runEnd + 4]) && isASCIIHexDigit(string[runEnd + 5])) { + runEnd += sequenceSize; + } + return runEnd; } static String decodeRun(const UChar* run, size_t runLength, const TextEncoding&) { // Each %u-escape sequence represents a UTF-16 code unit. // See <http://www.w3.org/International/iri-edit/draft-duerst-iri.html#anchor29>. - size_t numberOfSequences = runLength / size; + // For 16-bit escape sequences, we know that findEndOfRun() has given us a contiguous run of sequences + // without any intervening characters, so decode the run without additional checks. + size_t numberOfSequences = runLength / sequenceSize; StringBuilder builder; builder.reserveCapacity(numberOfSequences); while (numberOfSequences--) { UChar codeUnit = (toASCIIHexValue(run[2]) << 12) | (toASCIIHexValue(run[3]) << 8) | (toASCIIHexValue(run[4]) << 4) | toASCIIHexValue(run[5]); builder.append(codeUnit); - run += size; + run += sequenceSize; } return builder.toString(); } }; struct URLEscapeSequence { - enum { size = 3 }; // e.g. %41 - static size_t findInString(const String& string, unsigned start = 0) { return string.find('%', start); } - static bool matchStringPrefix(const String& string, unsigned start = 0) + enum { sequenceSize = 3 }; // e.g. %41 + static size_t findInString(const String& string, size_t startPosition) { return string.find('%', startPosition); } + static size_t findEndOfRun(const String& string, size_t startPosition, size_t endPosition) { - if (string.length() - start < size) - return false; - return string[start] == '%' && isASCIIHexDigit(string[start + 1]) && isASCIIHexDigit(string[start + 2]); + // Make the simplifying assumption that supported encodings may have up to two unescaped characters + // in the range 0x40 - 0x7F as the trailing bytes of their sequences which need to be passed into the + // decoder as part of the run. In other words, we end the run at the first value outside of the + // 0x40 - 0x7F range, after two values in this range, or at a %-sign that does not introduce a valid + // escape sequence. + size_t runEnd = startPosition; + int numberOfTrailingCharacters = 0; + while (runEnd < endPosition) { + if (string[runEnd] == '%') { + if (endPosition - runEnd >= sequenceSize && isASCIIHexDigit(string[runEnd + 1]) && isASCIIHexDigit(string[runEnd + 2])) { + runEnd += sequenceSize; + numberOfTrailingCharacters = 0; + } else + break; + } else if (string[runEnd] >= 0x40 && string[runEnd] <= 0x7F && numberOfTrailingCharacters < 2) { + runEnd += 1; + numberOfTrailingCharacters += 1; + } else + break; + } + return runEnd; } static String decodeRun(const UChar* run, size_t runLength, const TextEncoding& encoding) { - size_t numberOfSequences = runLength / size; + // For URL escape sequences, we know that findEndOfRun() has given us a run where every %-sign introduces + // a valid escape sequence, but there may be characters between the sequences. Vector<char, 512> buffer; - buffer.resize(numberOfSequences); + buffer.resize(runLength); // Unescaping hex sequences only makes the length smaller. char* p = buffer.data(); - while (numberOfSequences--) { - *p++ = (toASCIIHexValue(run[1]) << 4) | toASCIIHexValue(run[2]); - run += size; + const UChar* runEnd = run + runLength; + while (run < runEnd) { + if (run[0] == '%') { + *p++ = (toASCIIHexValue(run[1]) << 4) | toASCIIHexValue(run[2]); + run += sequenceSize; + } else { + *p++ = run[0]; + run += 1; + } } - ASSERT(buffer.size() == static_cast<size_t>(p - buffer.data())); + ASSERT(buffer.size() >= static_cast<size_t>(p - buffer.data())); // Prove buffer not overrun. return (encoding.isValid() ? encoding : UTF8Encoding()).decode(buffer.data(), p - buffer.data()); } }; @@ -95,9 +128,7 @@ String decodeEscapeSequences(const String& string, const TextEncoding& encoding) size_t searchPosition = 0; size_t encodedRunPosition; while ((encodedRunPosition = EscapeSequence::findInString(string, searchPosition)) != notFound) { - unsigned encodedRunEnd = encodedRunPosition; - while (length - encodedRunEnd >= EscapeSequence::size && EscapeSequence::matchStringPrefix(string, encodedRunEnd)) - encodedRunEnd += EscapeSequence::size; + size_t encodedRunEnd = EscapeSequence::findEndOfRun(string, encodedRunPosition, length); searchPosition = encodedRunEnd; if (encodedRunEnd == encodedRunPosition) { ++searchPosition; @@ -108,11 +139,11 @@ String decodeEscapeSequences(const String& string, const TextEncoding& encoding) if (decoded.isEmpty()) continue; - result.append(string.characters() + decodedPosition, encodedRunPosition - decodedPosition); + result.append(string, decodedPosition, encodedRunPosition - decodedPosition); result.append(decoded); decodedPosition = encodedRunEnd; } - result.append(string.characters() + decodedPosition, length - decodedPosition); + result.append(string, decodedPosition, length - decodedPosition); return result.toString(); } diff --git a/Source/WebCore/platform/text/LocalizedNumber.h b/Source/WebCore/platform/text/LocalizedNumber.h index 01d2553ef..350dac0db 100644 --- a/Source/WebCore/platform/text/LocalizedNumber.h +++ b/Source/WebCore/platform/text/LocalizedNumber.h @@ -35,21 +35,20 @@ namespace WebCore { -// Parses a string representation of a floating point number localized -// for the browser's current locale. If the input string is not valid -// or an implementation doesn't support localized numbers, this -// function returns NaN. This function doesn't need to support -// scientific notation, NaN, +Infinity and -Infinity, and doesn't need -// to support the standard representations of ECMAScript and HTML5. -double parseLocalizedNumber(const String&); +// Converts the specified number string to another number string +// localized for the browser's current locale. The input string must +// conform to HTML floating-point numbers, and is not empty. The +// fractionDigits argument is deprecated. The function implementaion +// should not use the argument. +String convertToLocalizedNumber(const String&, unsigned fractionDigits); -// Serializes the specified floating point number for the browser's -// current locale. If an implementation doesn't support localized -// numbers or the input value is NaN or Infinitiy, the function should -// return an empty string. -// fractionDigits is the maximum length of the fractional parts of the -// resultant string. -String formatLocalizedNumber(double, unsigned fractionDigits); +// Converts the specified localized number string to a number string +// in the HTML floating-point number format. The input string is +// provided by a end user, and might not be a number string. It's ok +// that the function returns a string which is not conforms to the +// HTML floating-point number format, callers of this function are +// responsible to check the format of the resultant string. +String convertFromLocalizedNumber(const String&); } // namespace WebCore diff --git a/Source/WebCore/platform/text/LocalizedNumberICU.cpp b/Source/WebCore/platform/text/LocalizedNumberICU.cpp index dc226df12..03db4d546 100644 --- a/Source/WebCore/platform/text/LocalizedNumberICU.cpp +++ b/Source/WebCore/platform/text/LocalizedNumberICU.cpp @@ -37,6 +37,7 @@ #include <wtf/MainThread.h> #include <wtf/MathExtras.h> #include <wtf/PassOwnPtr.h> +#include <wtf/dtoa.h> using namespace icu; using namespace std; @@ -76,7 +77,7 @@ static NumberFormat* numberFormatterForDisplay() return formatter; } -double parseLocalizedNumber(const String& numberString) +static double parseLocalizedNumber(const String& numberString) { if (numberString.isEmpty()) return numeric_limits<double>::quiet_NaN(); @@ -94,7 +95,7 @@ double parseLocalizedNumber(const String& numberString) return U_SUCCESS(status) ? numericResult : numeric_limits<double>::quiet_NaN(); } -String formatLocalizedNumber(double number, unsigned fractionDigits) +static String formatLocalizedNumber(double number, unsigned fractionDigits) { NumberFormat* formatter = numberFormatterForDisplay(); if (!formatter) @@ -105,4 +106,30 @@ String formatLocalizedNumber(double number, unsigned fractionDigits) return String(result.getBuffer(), result.length()); } +String convertToLocalizedNumber(const String& canonicalNumberString, unsigned fractionDigits) +{ + // FIXME: We should not do parse-then-format. It makes some + // problems such as removing leading zeros, changing trailing + // digits to zeros. + // FIXME: We should not use the fractionDigits argument. + + double doubleValue = canonicalNumberString.toDouble(); + // The input string must be valid. + return formatLocalizedNumber(doubleValue, fractionDigits); + +} + +String convertFromLocalizedNumber(const String& localizedNumberString) +{ + // FIXME: We should not do parse-then-format. It makes some + // problems such as removing leading zeros, changing trailing + // digits to zeros. + + double doubleValue = parseLocalizedNumber(localizedNumberString); + if (!isfinite(doubleValue)) + return localizedNumberString; + NumberToStringBuffer buffer; + return String(numberToString(doubleValue, buffer)); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/text/LocalizedNumberNone.cpp b/Source/WebCore/platform/text/LocalizedNumberNone.cpp index c7a8ed274..a1400855d 100644 --- a/Source/WebCore/platform/text/LocalizedNumberNone.cpp +++ b/Source/WebCore/platform/text/LocalizedNumberNone.cpp @@ -37,14 +37,14 @@ using namespace std; namespace WebCore { -double parseLocalizedNumber(const String&) +String convertToLocalizedNumber(const String& canonicalNumberString, unsigned) { - return numeric_limits<double>::quiet_NaN(); + return canonicalNumberString; } -String formatLocalizedNumber(double, unsigned) +String convertFromLocalizedNumber(const String& localizedNumberString) { - return String(); + return localizedNumberString; } } // namespace WebCore diff --git a/Source/WebCore/platform/text/mac/LocalizedNumberMac.mm b/Source/WebCore/platform/text/mac/LocalizedNumberMac.mm index ac6e70990..c2a7ea013 100644 --- a/Source/WebCore/platform/text/mac/LocalizedNumberMac.mm +++ b/Source/WebCore/platform/text/mac/LocalizedNumberMac.mm @@ -33,7 +33,9 @@ #import <Foundation/NSNumberFormatter.h> #import <limits> +#import <wtf/dtoa.h> #import <wtf/MainThread.h> +#import <wtf/MathExtras.h> #import <wtf/RetainPtr.h> #import <wtf/text/CString.h> @@ -70,7 +72,7 @@ static NSNumberFormatter *numberFormatterForDisplay() return formatter; } -double parseLocalizedNumber(const String& numberString) +static double parseLocalizedNumber(const String& numberString) { if (numberString.isEmpty()) return numeric_limits<double>::quiet_NaN(); @@ -80,7 +82,7 @@ double parseLocalizedNumber(const String& numberString) return [number doubleValue]; } -String formatLocalizedNumber(double inputNumber, unsigned fractionDigits) +static String formatLocalizedNumber(double inputNumber, unsigned fractionDigits) { RetainPtr<NSNumber> number(AdoptNS, [[NSNumber alloc] initWithDouble:inputNumber]); RetainPtr<NSNumberFormatter> formatter = numberFormatterForDisplay(); @@ -88,5 +90,31 @@ String formatLocalizedNumber(double inputNumber, unsigned fractionDigits) return String([formatter.get() stringFromNumber:number.get()]); } +String convertToLocalizedNumber(const String& canonicalNumberString, unsigned fractionDigits) +{ + // FIXME: We should not do parse-then-format. It makes some + // problems such as removing leading zeros, changing trailing + // digits to zeros. + // FIXME: We should not use the fractionDigits argument. + + double doubleValue = canonicalNumberString.toDouble(); + // The input string must be valid. + return formatLocalizedNumber(doubleValue, fractionDigits); + +} + +String convertFromLocalizedNumber(const String& localizedNumberString) +{ + // FIXME: We should not do parse-then-format. It makes some + // problems such as removing leading zeros, changing trailing + // digits to zeros. + + double doubleValue = parseLocalizedNumber(localizedNumberString); + if (!isfinite(doubleValue)) + return localizedNumberString; + NumberToStringBuffer buffer; + return String(numberToString(doubleValue, buffer)); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/win/CursorWin.cpp b/Source/WebCore/platform/win/CursorWin.cpp index 544b9a77b..ce4d58fb4 100644 --- a/Source/WebCore/platform/win/CursorWin.cpp +++ b/Source/WebCore/platform/win/CursorWin.cpp @@ -28,6 +28,7 @@ #include "Cursor.h" #include "BitmapInfo.h" +#include "HWndDC.h" #include "Image.h" #include "IntPoint.h" #include "SystemInfo.h" @@ -49,7 +50,7 @@ static PassRefPtr<SharedCursor> createSharedCursor(Image* img, const IntPoint& h static bool doAlpha = windowsVersion() >= WindowsXP; BitmapInfo cursorImage = BitmapInfo::create(IntSize(img->width(), img->height())); - HDC dc = GetDC(0); + HWndDC dc(0); HDC workingDC = CreateCompatibleDC(dc); if (doAlpha) { OwnPtr<HBITMAP> hCursor = adoptPtr(CreateDIBSection(dc, (BITMAPINFO *)&cursorImage, DIB_RGB_COLORS, 0, 0, 0)); @@ -112,7 +113,6 @@ static PassRefPtr<SharedCursor> createSharedCursor(Image* img, const IntPoint& h DeleteDC(andMaskDC); } DeleteDC(workingDC); - ReleaseDC(0, dc); return impl.release(); } diff --git a/Source/WebCore/platform/win/DragImageCGWin.cpp b/Source/WebCore/platform/win/DragImageCGWin.cpp index bc45e22c3..741016846 100644 --- a/Source/WebCore/platform/win/DragImageCGWin.cpp +++ b/Source/WebCore/platform/win/DragImageCGWin.cpp @@ -29,6 +29,7 @@ #include "BitmapInfo.h" #include "CachedImage.h" #include "GraphicsContextCG.h" +#include "HWndDC.h" #include "Image.h" #include "RetainPtr.h" @@ -89,7 +90,7 @@ DragImageRef scaleDragImage(DragImageRef image, FloatSize scale) IntSize srcSize = dragImageSize(image); IntSize dstSize(static_cast<int>(srcSize.width() * scale.width()), static_cast<int>(srcSize.height() * scale.height())); HBITMAP hbmp = 0; - HDC dc = GetDC(0); + HWndDC dc(0); HDC dstDC = CreateCompatibleDC(dc); if (!dstDC) goto exit; @@ -116,14 +117,13 @@ exit: hbmp = image; if (dstDC) DeleteDC(dstDC); - ReleaseDC(0, dc); return hbmp; } DragImageRef createDragImageFromImage(Image* img) { HBITMAP hbmp = 0; - HDC dc = GetDC(0); + HWndDC dc(0); HDC workingDC = CreateCompatibleDC(dc); CGContextRef drawContext = 0; if (!workingDC) @@ -155,7 +155,6 @@ DragImageRef createDragImageFromImage(Image* img) exit: if (workingDC) DeleteDC(workingDC); - ReleaseDC(0, dc); return hbmp; } diff --git a/Source/WebCore/platform/win/DragImageWin.cpp b/Source/WebCore/platform/win/DragImageWin.cpp index f858b07f1..1f6b73e89 100644 --- a/Source/WebCore/platform/win/DragImageWin.cpp +++ b/Source/WebCore/platform/win/DragImageWin.cpp @@ -33,6 +33,7 @@ #include "FontSelector.h" #include "Frame.h" #include "GraphicsContext.h" +#include "HWndDC.h" #include "Image.h" #include "RetainPtr.h" #include "Settings.h" @@ -183,18 +184,15 @@ DragImageRef createDragImageForLink(KURL& url, const String& inLabel, Frame* fra // We now know how big the image needs to be, so we create and // fill the background HBITMAP image = 0; - HDC dc = GetDC(0); + HWndDC dc(0); HDC workingDC = CreateCompatibleDC(dc); - if (!workingDC) { - ReleaseDC(0, dc); + if (!workingDC) return 0; - } PlatformGraphicsContext* contextRef; image = allocImage(workingDC, imageSize, &contextRef); if (!image) { DeleteDC(workingDC); - ReleaseDC(0, dc); return 0; } @@ -225,7 +223,6 @@ DragImageRef createDragImageForLink(KURL& url, const String& inLabel, Frame* fra deallocContext(contextRef); DeleteDC(workingDC); - ReleaseDC(0, dc); return image; } diff --git a/Source/WebCore/platform/efl/CookieJarEfl.cpp b/Source/WebCore/platform/win/HWndDC.h index 261ab233a..2eaecaddc 100644 --- a/Source/WebCore/platform/efl/CookieJarEfl.cpp +++ b/Source/WebCore/platform/win/HWndDC.h @@ -1,7 +1,5 @@ /* - * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2009-2010 ProFUSION embedded systems - * Copyright (C) 2009-2010 Samsung Electronics + * Copyright (C) 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,46 +23,67 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" -#include "CookieJar.h" +#ifndef HWndDC_h +#define HWndDC_h -#include "KURL.h" -#include "PlatformString.h" -#include <wtf/HashMap.h> -#include <wtf/text/StringHash.h> +#include <windows.h> +#include <wtf/NonCopyable.h> namespace WebCore { -static HashMap<String, String> cookieJar; +class HWndDC { + WTF_MAKE_NONCOPYABLE(HWndDC); +public: + HWndDC() + : m_hwnd(0) + , m_hdc(0) + { + } -void setCookies(Document* document, const KURL& url, const KURL& policyURL, const String& value) -{ - cookieJar.set(url.string(), value); -} + explicit HWndDC(HWND hwnd) + : m_hwnd(hwnd) + , m_hdc(::GetDC(hwnd)) + { + } -String cookies(const Document* document, const KURL& url) -{ - return cookieJar.get(url.string()); -} + HWndDC(HWND hwnd, HRGN hrgnClip, DWORD flags) + : m_hwnd(hwnd) + , m_hdc(::GetDCEx(hwnd, hrgnClip, flags)) + { + } -bool cookiesEnabled(const Document* document) -{ - return true; -} + ~HWndDC() + { + clear(); + } -void getHostnamesWithCookies(HashSet<String>& hostnames) -{ - // FIXME: Not yet implemented -} + HDC setHWnd(HWND hwnd) + { + clear(); + m_hwnd = hwnd; + m_hdc = ::GetDC(hwnd); + return m_hdc; + } -void deleteCookiesForHostname(const String& hostname) -{ - // FIXME: Not yet implemented -} + void clear() + { + if (!m_hdc) + return; + ::ReleaseDC(m_hwnd, m_hdc); + m_hwnd = 0; + m_hdc = 0; + } -void deleteAllCookies() -{ - // FIXME: Not yet implemented -} + operator HDC() + { + return m_hdc; + } -} +private: + HWND m_hwnd; + HDC m_hdc; +}; + +} // namespace WebCore + +#endif // HWndDC_h diff --git a/Source/WebCore/platform/win/LanguageWin.cpp b/Source/WebCore/platform/win/LanguageWin.cpp index aa050a78e..006dc1051 100644 --- a/Source/WebCore/platform/win/LanguageWin.cpp +++ b/Source/WebCore/platform/win/LanguageWin.cpp @@ -27,6 +27,7 @@ #include "Language.h" #include <windows.h> +#include <wtf/Vector.h> #include <wtf/text/WTFString.h> namespace WebCore { @@ -49,7 +50,7 @@ static String localeInfo(LCTYPE localeType, const String& fallback) return localeName; } -String platformDefaultLanguage() +static String platformLanguage() { static String computedDefaultLanguage; if (!computedDefaultLanguage.isEmpty()) @@ -66,4 +67,11 @@ String platformDefaultLanguage() return computedDefaultLanguage; } +Vector<String> platformUserPreferredLanguages() +{ + Vector<String> userPreferredLanguages; + userPreferredLanguages.append(platformLanguage()); + return userPreferredLanguages; +} + } diff --git a/Source/WebCore/platform/win/PasteboardWin.cpp b/Source/WebCore/platform/win/PasteboardWin.cpp index d768a3d53..887fc912c 100644 --- a/Source/WebCore/platform/win/PasteboardWin.cpp +++ b/Source/WebCore/platform/win/PasteboardWin.cpp @@ -32,6 +32,7 @@ #include "DocumentFragment.h" #include "Element.h" #include "Frame.h" +#include "HWndDC.h" #include "HitTestResult.h" #include "Image.h" #include "KURL.h" @@ -223,7 +224,7 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String&) clear(); - HDC dc = GetDC(0); + HWndDC dc(0); HDC compatibleDC = CreateCompatibleDC(0); HDC sourceDC = CreateCompatibleDC(0); OwnPtr<HBITMAP> resultBitmap = adoptPtr(CreateCompatibleBitmap(dc, image->width(), image->height())); @@ -243,7 +244,6 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String&) SelectObject(compatibleDC, oldBitmap); DeleteDC(sourceDC); DeleteDC(compatibleDC); - ReleaseDC(0, dc); if (::OpenClipboard(m_owner)) { ::SetClipboardData(CF_BITMAP, resultBitmap.leakPtr()); diff --git a/Source/WebCore/platform/win/PlatformScreenWin.cpp b/Source/WebCore/platform/win/PlatformScreenWin.cpp index caadde943..936f8a747 100644 --- a/Source/WebCore/platform/win/PlatformScreenWin.cpp +++ b/Source/WebCore/platform/win/PlatformScreenWin.cpp @@ -106,15 +106,15 @@ bool screenIsMonochrome(Widget* widget) #endif } -FloatRect screenRect(Widget* widget) +FloatRect screenRect(FrameView* frameView) { - MONITORINFOEX monitorInfo = monitorInfoForWidget(widget); + MONITORINFOEX monitorInfo = monitorInfoForWidget(frameView); return monitorInfo.rcMonitor; } -FloatRect screenAvailableRect(Widget* widget) +FloatRect screenAvailableRect(FrameView* frameView) { - MONITORINFOEX monitorInfo = monitorInfoForWidget(widget); + MONITORINFOEX monitorInfo = monitorInfoForWidget(frameView); return monitorInfo.rcWork; } diff --git a/Source/WebCore/platform/win/PopupMenuWin.cpp b/Source/WebCore/platform/win/PopupMenuWin.cpp index 097fc8231..d0b3ec940 100644 --- a/Source/WebCore/platform/win/PopupMenuWin.cpp +++ b/Source/WebCore/platform/win/PopupMenuWin.cpp @@ -31,6 +31,7 @@ #include "FrameView.h" #include "GraphicsContext.h" #include "HTMLNames.h" +#include "HWndDC.h" #include "HostWindow.h" #include "Page.h" #include "PlatformMouseEvent.h" @@ -42,6 +43,7 @@ #include "SimpleFontData.h" #include "TextRun.h" #include "WebCoreInstanceHandle.h" + #include <windows.h> #include <windowsx.h> #if OS(WINCE) @@ -566,7 +568,7 @@ void PopupMenuWin::paint(const IntRect& damageRect, HDC hdc) return; if (!m_DC) { - m_DC = ::CreateCompatibleDC(::GetDC(m_popup)); + m_DC = ::CreateCompatibleDC(HWndDC(m_popup)); if (!m_DC) return; } @@ -660,12 +662,10 @@ void PopupMenuWin::paint(const IntRect& damageRect, HDC hdc) if (m_scrollbar) m_scrollbar->paint(&context, damageRect); - HDC localDC = hdc ? hdc : ::GetDC(m_popup); + HWndDC hWndDC; + HDC localDC = hdc ? hdc : hWndDC.setHWnd(m_popup); ::BitBlt(localDC, damageRect.x(), damageRect.y(), damageRect.width(), damageRect.height(), m_DC, damageRect.x(), damageRect.y(), SRCCOPY); - - if (!hdc) - ::ReleaseDC(m_popup, localDC); } int PopupMenuWin::scrollSize(ScrollbarOrientation orientation) const diff --git a/Source/WebCore/platform/win/RunLoopWin.cpp b/Source/WebCore/platform/win/RunLoopWin.cpp new file mode 100644 index 000000000..120c252a6 --- /dev/null +++ b/Source/WebCore/platform/win/RunLoopWin.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RunLoop.h" + +#include <wtf/CurrentTime.h> + +using namespace std; + +namespace WebCore { + +static const UINT PerformWorkMessage = WM_USER + 1; +static const LPWSTR kRunLoopMessageWindowClassName = L"RunLoopMessageWindow"; + +LRESULT CALLBACK RunLoop::RunLoopWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + LONG_PTR longPtr = ::GetWindowLongPtr(hWnd, 0); + + if (RunLoop* runLoop = reinterpret_cast<RunLoop*>(longPtr)) + return runLoop->wndProc(hWnd, message, wParam, lParam); + + if (message == WM_CREATE) { + LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam); + + // Associate the RunLoop with the window. + ::SetWindowLongPtr(hWnd, 0, (LONG_PTR)createStruct->lpCreateParams); + return 0; + } + + return ::DefWindowProc(hWnd, message, wParam, lParam); +} + +LRESULT RunLoop::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case PerformWorkMessage: + performWork(); + return 0; + case WM_TIMER: + RunLoop::TimerBase::timerFired(this, wParam); + return 0; + } + + return ::DefWindowProc(hWnd, message, wParam, lParam); +} + +void RunLoop::run() +{ + MSG message; + while (BOOL result = ::GetMessage(&message, 0, 0, 0)) { + if (result == -1) + break; + ::TranslateMessage(&message); + ::DispatchMessage(&message); + } +} + +void RunLoop::stop() +{ + ::PostQuitMessage(0); +} + +bool RunLoop::registerRunLoopMessageWindowClass() +{ + // FIXME: This really only needs to be called once. + + WNDCLASSEX windowClass = { 0 }; + windowClass.cbSize = sizeof(windowClass); + windowClass.lpfnWndProc = RunLoop::RunLoopWndProc; + windowClass.cbWndExtra = sizeof(RunLoop*); + windowClass.lpszClassName = kRunLoopMessageWindowClassName; + + return !!::RegisterClassEx(&windowClass); +} + +RunLoop::RunLoop() +{ + registerRunLoopMessageWindowClass(); + + m_runLoopMessageWindow = ::CreateWindow(kRunLoopMessageWindowClassName, 0, 0, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, + HWND_MESSAGE, 0, 0, this); + ASSERT(::IsWindow(m_runLoopMessageWindow)); +} + +RunLoop::~RunLoop() +{ + // FIXME: Tear down the work item queue here. +} + +void RunLoop::wakeUp() +{ + // FIXME: No need to wake up the run loop if we've already called dispatch + // before the run loop has had the time to respond. + ::PostMessage(m_runLoopMessageWindow, PerformWorkMessage, reinterpret_cast<WPARAM>(this), 0); +} + +// RunLoop::Timer + +void RunLoop::TimerBase::timerFired(RunLoop* runLoop, uint64_t ID) +{ + TimerMap::iterator it = runLoop->m_activeTimers.find(ID); + if (it == runLoop->m_activeTimers.end()) { + // The timer must have been stopped after the WM_TIMER message was posted to the message queue. + return; + } + + TimerBase* timer = it->second; + + if (!timer->m_isRepeating) { + runLoop->m_activeTimers.remove(it); + ::KillTimer(runLoop->m_runLoopMessageWindow, ID); + } + + timer->fired(); +} + +static uint64_t generateTimerID() +{ + static uint64_t uniqueTimerID = 1; + return uniqueTimerID++; +} + +RunLoop::TimerBase::TimerBase(RunLoop* runLoop) + : m_runLoop(runLoop) + , m_ID(generateTimerID()) + , m_isRepeating(false) +{ +} + +RunLoop::TimerBase::~TimerBase() +{ + stop(); +} + +void RunLoop::TimerBase::start(double nextFireInterval, bool repeat) +{ + m_isRepeating = repeat; + m_runLoop->m_activeTimers.set(m_ID, this); + ::SetTimer(m_runLoop->m_runLoopMessageWindow, m_ID, nextFireInterval * 1000, 0); +} + +void RunLoop::TimerBase::stop() +{ + TimerMap::iterator it = m_runLoop->m_activeTimers.find(m_ID); + if (it == m_runLoop->m_activeTimers.end()) + return; + + m_runLoop->m_activeTimers.remove(it); + ::KillTimer(m_runLoop->m_runLoopMessageWindow, m_ID); +} + +bool RunLoop::TimerBase::isActive() const +{ + return m_runLoop->m_activeTimers.contains(m_ID); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/wx/KeyboardEventWx.cpp b/Source/WebCore/platform/wx/KeyboardEventWx.cpp index ce85ffa10..963b56350 100644 --- a/Source/WebCore/platform/wx/KeyboardEventWx.cpp +++ b/Source/WebCore/platform/wx/KeyboardEventWx.cpp @@ -364,10 +364,20 @@ PlatformKeyboardEvent::PlatformKeyboardEvent(wxKeyEvent& event) m_windowsVirtualKeyCode = windowsKeyCodeForKeyEvent(event.GetKeyCode()); m_nativeVirtualKeyCode = event.GetKeyCode(); m_isKeypad = (event.GetKeyCode() >= WXK_NUMPAD_SPACE) && (event.GetKeyCode() <= WXK_NUMPAD_DIVIDE); - m_shiftKey = event.ShiftDown(); - m_ctrlKey = event.CmdDown(); - m_altKey = event.AltDown(); - m_metaKey = event.MetaDown(); + + m_modifiers = 0; + if (event.ShiftDown()) + m_modifiers |= ShiftKey; + + if (event.CmdDown()) + m_modifiers |= CtrlKey; + + if (event.AltDown()) + m_modifiers |= AltKey; + + if (event.MetaDown()) + m_modifiers |= MetaKey; + m_timestamp = WTF::currentTime(); } diff --git a/Source/WebCore/platform/chromium/ClipboardChromiumLinux.cpp b/Source/WebCore/platform/wx/LanguageWx.cpp index 2c89f6e8e..d66b29974 100644 --- a/Source/WebCore/platform/chromium/ClipboardChromiumLinux.cpp +++ b/Source/WebCore/platform/wx/LanguageWx.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. - * Copyright (C) 2009 Google Inc. + * Copyright (C) 2012 Kevin Ollivier <kevino@theolliviers.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,17 +24,24 @@ */ #include "config.h" -#include "ClipboardChromium.h" +#include "Language.h" -#include "ChromiumDataObject.h" #include "NotImplemented.h" +#include "PlatformString.h" namespace WebCore { -String ClipboardChromium::validateFileName(const String& title, ChromiumDataObject* dataObject) +static String platformLanguage() { notImplemented(); - return title; + return String(); } -} // namespace WebCore +Vector<String> platformUserPreferredLanguages() +{ + notImplemented(); + Vector<String> userPreferredLanguages; + return userPreferredLanguages; +} + +} diff --git a/Source/WebCore/platform/wx/RunLoopWx.cpp b/Source/WebCore/platform/wx/RunLoopWx.cpp new file mode 100644 index 000000000..bd14dd545 --- /dev/null +++ b/Source/WebCore/platform/wx/RunLoopWx.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 Kevin Ollivier <kevino@theolliviers.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RunLoop.h" + +#include "NotImplemented.h" + +namespace WebCore { + +void RunLoop::run() +{ + notImplemented(); +} + +void RunLoop::stop() +{ + notImplemented(); +} + +RunLoop::RunLoop() +{ + notImplemented(); +} + +RunLoop::~RunLoop() +{ +} + +void RunLoop::wakeUp() +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/wx/ScreenWx.cpp b/Source/WebCore/platform/wx/ScreenWx.cpp index 41edf1561..779d4fdf5 100644 --- a/Source/WebCore/platform/wx/ScreenWx.cpp +++ b/Source/WebCore/platform/wx/ScreenWx.cpp @@ -28,6 +28,7 @@ #include "Screen.h" #include "IntRect.h" #include "FloatRect.h" +#include "FrameView.h" #include "NotImplemented.h" #include "Widget.h" @@ -48,7 +49,7 @@ int screenVerticalDPI(Widget*) return 0; } -FloatRect screenRect(Widget* widget) +FloatRect screenRect(FrameView* frameView) { /* int displayNum; @@ -77,7 +78,7 @@ bool screenIsMonochrome(Widget* widget) return wxColourDisplay(); } -FloatRect screenAvailableRect(Widget* widget) +FloatRect screenAvailableRect(FrameView* frameView) { /* Widget* widget = widget->widget(); |