diff options
Diffstat (limited to 'WebCore/platform')
285 files changed, 9862 insertions, 4216 deletions
diff --git a/WebCore/platform/ContextMenu.cpp b/WebCore/platform/ContextMenu.cpp index ee6aa4e..771798a 100644 --- a/WebCore/platform/ContextMenu.cpp +++ b/WebCore/platform/ContextMenu.cpp @@ -40,6 +40,7 @@ #include "Editor.h" #include "Frame.h" #include "FrameLoader.h" +#include "InspectorController.h" #include "KURL.h" #include "LocalizedStrings.h" #include "Node.h" @@ -779,6 +780,7 @@ void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const #if ENABLE(INSPECTOR) case ContextMenuItemTagInspectElement: #endif + case ContextMenuItemBaseCustomTag: case ContextMenuItemBaseApplicationTag: break; } diff --git a/WebCore/platform/ContextMenu.h b/WebCore/platform/ContextMenu.h index dc484b2..77843dc 100644 --- a/WebCore/platform/ContextMenu.h +++ b/WebCore/platform/ContextMenu.h @@ -78,6 +78,8 @@ namespace WebCore { RetainPtr<NSMutableArray> m_platformDescription; #elif PLATFORM(QT) QList<ContextMenuItem> m_items; +#elif PLATFORM(CHROMIUM) + Vector<ContextMenuItem> m_items; #else PlatformMenuDescription m_platformDescription; #endif diff --git a/WebCore/platform/ContextMenuItem.h b/WebCore/platform/ContextMenuItem.h index 6b9d0a9..b4c97a5 100644 --- a/WebCore/platform/ContextMenuItem.h +++ b/WebCore/platform/ContextMenuItem.h @@ -143,6 +143,7 @@ namespace WebCore { ContextMenuItemTagCapitalize, ContextMenuItemTagChangeBack, #endif + ContextMenuItemBaseCustomTag = 5000, ContextMenuItemBaseApplicationTag = 10000 }; @@ -210,11 +211,24 @@ namespace WebCore { }; #elif PLATFORM(HAIKU) typedef BMenuItem* PlatformMenuItemDescription; +#elif PLATFORM(CHROMIUM) + struct PlatformMenuItemDescription { + PlatformMenuItemDescription() + : type(ActionType) + , action(ContextMenuItemTagNoAction) + , checked(false) + , enabled(true) { } + ContextMenuItemType type; + ContextMenuAction action; + String title; + bool checked; + bool enabled; + }; #else typedef void* PlatformMenuItemDescription; #endif - class ContextMenuItem { + class ContextMenuItem : public FastAllocBase { public: ContextMenuItem(PlatformMenuItemDescription); ContextMenuItem(ContextMenu* subMenu = 0); @@ -239,7 +253,8 @@ namespace WebCore { void setSubMenu(ContextMenu*); void setChecked(bool = true); - + bool checked() const; + void setEnabled(bool = true); bool enabled() const; diff --git a/WebCore/platform/CrossThreadCopier.h b/WebCore/platform/CrossThreadCopier.h index 178e056..2bdf57d 100644 --- a/WebCore/platform/CrossThreadCopier.h +++ b/WebCore/platform/CrossThreadCopier.h @@ -41,7 +41,7 @@ namespace WebCore { class ResourceError; - struct ResourceRequest; + class ResourceRequest; class ResourceResponse; class String; struct CrossThreadResourceResponseData; diff --git a/WebCore/platform/DeprecatedPtrList.h b/WebCore/platform/DeprecatedPtrList.h index 67161af..47cd538 100644 --- a/WebCore/platform/DeprecatedPtrList.h +++ b/WebCore/platform/DeprecatedPtrList.h @@ -27,12 +27,13 @@ #define DeprecatedPtrList_h #include "DeprecatedPtrListImpl.h" +#include <wtf/FastAllocBase.h> namespace WebCore { template <class T> class DeprecatedPtrListIterator; -template <class T> class DeprecatedPtrList { +template <class T> class DeprecatedPtrList : public FastAllocBase { public: DeprecatedPtrList() : impl(deleteFunc), del_item(false) { } ~DeprecatedPtrList() { impl.clear(del_item); } diff --git a/WebCore/platform/DeprecatedPtrListImpl.cpp b/WebCore/platform/DeprecatedPtrListImpl.cpp index 6d6112e..96fd513 100644 --- a/WebCore/platform/DeprecatedPtrListImpl.cpp +++ b/WebCore/platform/DeprecatedPtrListImpl.cpp @@ -29,10 +29,11 @@ #include <cstddef> #include <algorithm> #include <wtf/Assertions.h> +#include <wtf/Noncopyable.h> namespace WebCore { -class DeprecatedListNode +class DeprecatedListNode : public Noncopyable { public: DeprecatedListNode(void *d) : data(d), next(0), prev(0) { } diff --git a/WebCore/platform/FileChooser.cpp b/WebCore/platform/FileChooser.cpp index 739181d..9fad392 100644 --- a/WebCore/platform/FileChooser.cpp +++ b/WebCore/platform/FileChooser.cpp @@ -37,16 +37,16 @@ FileChooserClient::~FileChooserClient() { } -inline FileChooser::FileChooser(FileChooserClient* client, const String& filename) +inline FileChooser::FileChooser(FileChooserClient* client, const Vector<String>& initialFilenames) : m_client(client) - , m_icon(chooseIcon(filename)) + , m_icon(Icon::createIconForFiles(initialFilenames)) { - m_filenames.append(filename); + m_filenames = initialFilenames; } -PassRefPtr<FileChooser> FileChooser::create(FileChooserClient* client, const String& filename) +PassRefPtr<FileChooser> FileChooser::create(FileChooserClient* client, const Vector<String>& initialFilenames) { - return adoptRef(new FileChooser(client, filename)); + return adoptRef(new FileChooser(client, initialFilenames)); } FileChooser::~FileChooser() @@ -61,13 +61,9 @@ void FileChooser::clear() void FileChooser::chooseFile(const String& filename) { - if (m_filenames.size() == 1 && m_filenames[0] == filename) - return; - m_filenames.clear(); - m_filenames.append(filename); - m_icon = chooseIcon(filename); - if (m_client) - m_client->valueChanged(); + Vector<String> filenames; + filenames.append(filename); + chooseFiles(filenames); } void FileChooser::chooseFiles(const Vector<String>& filenames) @@ -75,23 +71,9 @@ void FileChooser::chooseFiles(const Vector<String>& filenames) if (m_filenames == filenames) return; m_filenames = filenames; - m_icon = chooseIcon(filenames); + m_icon = Icon::createIconForFiles(filenames); if (m_client) m_client->valueChanged(); } -PassRefPtr<Icon> FileChooser::chooseIcon(const String& filename) -{ - return Icon::createIconForFile(filename); -} - -PassRefPtr<Icon> FileChooser::chooseIcon(Vector<String> filenames) -{ - if (filenames.isEmpty()) - return 0; - if (filenames.size() == 1) - return Icon::createIconForFile(filenames[0]); - return Icon::createIconForFiles(filenames); -} - } diff --git a/WebCore/platform/FileChooser.h b/WebCore/platform/FileChooser.h index 8192fe8..1d4e970 100644 --- a/WebCore/platform/FileChooser.h +++ b/WebCore/platform/FileChooser.h @@ -47,7 +47,7 @@ public: class FileChooser : public RefCounted<FileChooser> { public: - static PassRefPtr<FileChooser> create(FileChooserClient*, const String& initialFilename); + static PassRefPtr<FileChooser> create(FileChooserClient*, const Vector<String>& initialFilenames); ~FileChooser(); void disconnectClient() { m_client = 0; } @@ -66,9 +66,7 @@ public: bool allowsMultipleFiles() const { return m_client ? m_client->allowsMultipleFiles() : false; } private: - FileChooser(FileChooserClient*, const String& initialfilename); - static PassRefPtr<Icon> chooseIcon(const String& filename); - static PassRefPtr<Icon> chooseIcon(Vector<String> filenames); + FileChooser(FileChooserClient*, const Vector<String>& initialFilenames); FileChooserClient* m_client; Vector<String> m_filenames; diff --git a/WebCore/platform/FileSystem.h b/WebCore/platform/FileSystem.h index 9952b39..3220d51 100644 --- a/WebCore/platform/FileSystem.h +++ b/WebCore/platform/FileSystem.h @@ -39,9 +39,10 @@ #if defined(Q_OS_WIN32) #include <windows.h> #endif -#if defined(Q_WS_MAC) -#include <CoreFoundation/CFBundle.h> #endif + +#if PLATFORM(CF) || (PLATFORM(QT) && defined(Q_WS_MAC)) +#include <CoreFoundation/CFBundle.h> #endif #include <time.h> @@ -76,6 +77,8 @@ typedef QLibrary* PlatformModule; #endif // defined(Q_WS_MAC) #elif PLATFORM(GTK) typedef GModule* PlatformModule; +#elif PLATFORM(CF) +typedef CFBundleRef PlatformModule; #else typedef void* PlatformModule; #endif diff --git a/WebCore/platform/KURL.cpp b/WebCore/platform/KURL.cpp index ffacc19..a8f7969 100644 --- a/WebCore/platform/KURL.cpp +++ b/WebCore/platform/KURL.cpp @@ -30,7 +30,7 @@ #include "KURL.h" #include "CString.h" -#include "PlatformString.h" +#include "StringHash.h" #include "TextEncoding.h" #include <wtf/StdLibExtras.h> @@ -102,7 +102,7 @@ static const unsigned char characterClassTable[256] = { /* 42 * */ UserInfoChar, /* 43 + */ SchemeChar | UserInfoChar, /* 44 , */ UserInfoChar, /* 45 - */ SchemeChar | UserInfoChar | HostnameChar, - /* 46 . */ SchemeChar | UserInfoChar | HostnameChar, + /* 46 . */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char, /* 47 / */ PathSegmentEndChar, /* 48 0 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char, /* 49 1 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char, @@ -633,7 +633,7 @@ bool KURL::protocolIs(const char* protocol) const // JavaScript URLs are "valid" and should be executed even if KURL decides they are invalid. // The free function protocolIsJavaScript() should be used instead. - ASSERT(strcmp(protocol, "javascript") != 0); + ASSERT(!equalIgnoringCase(protocol, String("javascript"))); if (!m_isValid) return false; @@ -685,18 +685,22 @@ void KURL::setHost(const String& s) parse(m_string.left(hostStart()) + (slashSlashNeeded ? "//" : "") + s + m_string.substring(m_hostEnd)); } +void KURL::removePort() +{ + if (m_hostEnd == m_portEnd) + return; + parse(m_string.left(m_hostEnd) + m_string.substring(m_portEnd)); +} + void KURL::setPort(unsigned short i) { if (!m_isValid) return; - if (i) { - bool colonNeeded = m_portEnd == m_hostEnd; - int portStart = (colonNeeded ? m_hostEnd : m_hostEnd + 1); + bool colonNeeded = m_portEnd == m_hostEnd; + int portStart = (colonNeeded ? m_hostEnd : m_hostEnd + 1); - parse(m_string.left(portStart) + (colonNeeded ? ":" : "") + String::number(i) + m_string.substring(m_portEnd)); - } else - parse(m_string.left(m_hostEnd) + m_string.substring(m_portEnd)); + parse(m_string.left(portStart) + (colonNeeded ? ":" : "") + String::number(i) + m_string.substring(m_portEnd)); } void KURL::setHostAndPort(const String& hostAndPort) @@ -819,7 +823,7 @@ String KURL::prettyURL() const authority.append('@'); } append(authority, host()); - if (port() != 0) { + if (hasPort()) { authority.append(':'); append(authority, String::number(port())); } @@ -1269,8 +1273,8 @@ void KURL::parse(const char* url, const String* originalString) m_userStart = m_userEnd = m_passwordEnd = m_hostEnd = m_portEnd = p - buffer.data(); // For canonicalization, ensure we have a '/' for no path. - // Only do this for http and https. - if (m_protocolInHTTPFamily && pathEnd - pathStart == 0) + // Do this only for hierarchical URL with protocol http or https. + if (m_protocolInHTTPFamily && hierarchical && pathEnd == pathStart) *p++ = '/'; // add path, escaping bad characters @@ -1624,6 +1628,132 @@ bool protocolIsJavaScript(const String& url) return protocolIs(url, "javascript"); } +bool isValidProtocol(const String& protocol) +{ + if (!isSchemeFirstChar(protocol[0])) + return false; + unsigned protocolLength = protocol.length(); + for (unsigned i = 1; i < protocolLength; i++) { + if (!isSchemeChar(protocol[i])) + return false; + } + return true; +} + +bool isDefaultPortForProtocol(unsigned short port, const String& protocol) +{ + if (protocol.isEmpty()) + return false; + + typedef HashMap<String, unsigned, CaseFoldingHash> DefaultPortsMap; + DEFINE_STATIC_LOCAL(DefaultPortsMap, defaultPorts, ()); + if (defaultPorts.isEmpty()) { + defaultPorts.set("http", 80); + defaultPorts.set("https", 443); + defaultPorts.set("ftp", 21); + defaultPorts.set("ftps", 990); + } + return defaultPorts.get(protocol) == port; +} + +bool portAllowed(const KURL& url) +{ + unsigned short port = url.port(); + + // Since most URLs don't have a port, return early for the "no port" case. + if (!port) + return true; + + // This blocked port list matches the port blocking that Mozilla implements. + // See http://www.mozilla.org/projects/netlib/PortBanning.html for more information. + static const unsigned short blockedPortList[] = { + 1, // tcpmux + 7, // echo + 9, // discard + 11, // systat + 13, // daytime + 15, // netstat + 17, // qotd + 19, // chargen + 20, // FTP-data + 21, // FTP-control + 22, // SSH + 23, // telnet + 25, // SMTP + 37, // time + 42, // name + 43, // nicname + 53, // domain + 77, // priv-rjs + 79, // finger + 87, // ttylink + 95, // supdup + 101, // hostriame + 102, // iso-tsap + 103, // gppitnp + 104, // acr-nema + 109, // POP2 + 110, // POP3 + 111, // sunrpc + 113, // auth + 115, // SFTP + 117, // uucp-path + 119, // nntp + 123, // NTP + 135, // loc-srv / epmap + 139, // netbios + 143, // IMAP2 + 179, // BGP + 389, // LDAP + 465, // SMTP+SSL + 512, // print / exec + 513, // login + 514, // shell + 515, // printer + 526, // tempo + 530, // courier + 531, // Chat + 532, // netnews + 540, // UUCP + 556, // remotefs + 563, // NNTP+SSL + 587, // ESMTP + 601, // syslog-conn + 636, // LDAP+SSL + 993, // IMAP+SSL + 995, // POP3+SSL + 2049, // NFS + 3659, // apple-sasl / PasswordServer [Apple addition] + 4045, // lockd + 6000, // X11 + }; + const unsigned short* const blockedPortListEnd = blockedPortList + sizeof(blockedPortList) / sizeof(blockedPortList[0]); + +#ifndef NDEBUG + // The port list must be sorted for binary_search to work. + static bool checkedPortList = false; + if (!checkedPortList) { + for (const unsigned short* p = blockedPortList; p != blockedPortListEnd - 1; ++p) + ASSERT(*p < *(p + 1)); + checkedPortList = true; + } +#endif + + // If the port is not in the blocked port list, allow it. + if (!binary_search(blockedPortList, blockedPortListEnd, port)) + return true; + + // Allow ports 21 and 22 for FTP URLs, as Mozilla does. + if ((port == 21 || port == 22) && url.protocolIs("ftp")) + return true; + + // Allow any port number in a file URL, since the port number is ignored. + if (url.protocolIs("file")) + return true; + + return false; +} + String mimeTypeFromDataURL(const String& url) { ASSERT(protocolIs(url, "data")); diff --git a/WebCore/platform/KURL.h b/WebCore/platform/KURL.h index 73fadd1..647330d 100644 --- a/WebCore/platform/KURL.h +++ b/WebCore/platform/KURL.h @@ -78,6 +78,7 @@ public: KURL(const KURL& base, const String& relative); KURL(const KURL& base, const String& relative, const TextEncoding&); + #if USE(GOOGLEURL) // For conversions for other structures that have already parsed and // canonicalized the URL. The input must be exactly what KURL would have @@ -104,6 +105,12 @@ public: // non-hierarchical (like "javascript:") URLs will have no path. bool hasPath() const; + // Returns true if you can set the host and port for the URL. + // Non-hierarchical URLs don't have a host and port. + bool canSetHostOrPort() const { return isHierarchical(); } + + bool canSetPathname() const { return isHierarchical(); } + #if USE(GOOGLEURL) const String& string() const { return m_url.string(); } #else @@ -113,6 +120,7 @@ public: String protocol() const; String host() const; unsigned short port() const; + bool hasPort() const; String user() const; String pass() const; String path() const; @@ -135,7 +143,7 @@ public: void setProtocol(const String&); void setHost(const String&); - // Setting the port to 0 will clear any port from the URL. + void removePort(); void setPort(unsigned short); // Input is like "foo.com" or "foo.com:8000". @@ -254,6 +262,10 @@ const KURL& blankURL(); bool protocolIs(const String& url, const char* protocol); bool protocolIsJavaScript(const String& url); +bool isValidProtocol(const String& protocol); + +bool isDefaultPortForProtocol(unsigned short port, const String& protocol); +bool portAllowed(const KURL&); // Blacklist ports that should never be used for Web resources. String mimeTypeFromDataURL(const String& url); @@ -317,6 +329,11 @@ inline bool KURL::isValid() const return m_isValid; } +inline bool KURL::hasPort() const +{ + return m_hostEnd < m_portEnd; +} + inline bool KURL::protocolInHTTPFamily() const { return m_protocolInHTTPFamily; diff --git a/WebCore/platform/KURLGoogle.cpp b/WebCore/platform/KURLGoogle.cpp index d0aae0c..76b5612 100644 --- a/WebCore/platform/KURLGoogle.cpp +++ b/WebCore/platform/KURLGoogle.cpp @@ -38,16 +38,21 @@ #include <stdio.h> #endif +#include <algorithm> + #include "CString.h" +#include "StringHash.h" #include "NotImplemented.h" #include "TextEncoding.h" #include <wtf/Vector.h> +#include <wtf/StdLibExtras.h> #include <googleurl/src/url_canon_internal.h> #include <googleurl/src/url_util.h> using WTF::isASCIILower; using WTF::toASCIILower; +using std::binary_search; namespace WebCore { @@ -116,6 +121,16 @@ static bool lowerCaseEqualsASCII(const char* begin, const char* end, const char* return begin == end && !*str; } +static inline bool isSchemeFirstChar(char c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +static inline bool isSchemeChar(char c) +{ + return isSchemeFirstChar(c) || (c >= '0' && c <= '9') || c == '.' || c == '-' || c == '*'; +} + // KURLGooglePrivate ----------------------------------------------------------- @@ -426,6 +441,11 @@ bool KURL::isValid() const return m_url.m_isValid; } +bool KURL::hasPort() const +{ + return hostEnd() < pathStart(); +} + bool KURL::protocolInHTTPFamily() const { return m_url.m_protocolInHTTPFamily; @@ -537,7 +557,10 @@ String KURL::query() const // Bug: https://bugs.webkit.org/show_bug.cgi?id=21015 this function returns // an empty string when the query is empty rather than a null (not sure // which is right). - return String("", 0); + // Returns a null if the query is not specified, instead of empty. + if (m_url.m_parsed.query.is_valid()) + return String("", 0); + return String(); } String KURL::path() const @@ -562,24 +585,36 @@ void KURL::setHost(const String& host) m_url.replaceComponents(replacements); } -// This function is used only in the JSC build. void KURL::setHostAndPort(const String& s) { - String newhost = s.left(s.find(":")); - String newport = s.substring(s.find(":") + 1); + String host = s; + String port; + int hostEnd = s.find(":"); + if (hostEnd != -1) { + host = s.left(hostEnd); + port = s.substring(hostEnd + 1); + } KURLGooglePrivate::Replacements replacements; // Host can't be removed, so we always set. - replacements.SetHost(CharactersOrEmpty(newhost), - url_parse::Component(0, newhost.length())); + replacements.SetHost(CharactersOrEmpty(host), + url_parse::Component(0, host.length())); - if (newport.isEmpty()) // Port may be removed, so we support clearing. + if (port.isEmpty()) // Port may be removed, so we support clearing. replacements.ClearPort(); else - replacements.SetPort(CharactersOrEmpty(newport), url_parse::Component(0, newport.length())); + replacements.SetPort(CharactersOrEmpty(port), url_parse::Component(0, port.length())); m_url.replaceComponents(replacements); } +void KURL::removePort() +{ + if (hasPort()) { + String urlWithoutPort = m_url.string().left(hostEnd()) + m_url.string().substring(pathStart()); + m_url.setUtf8(urlWithoutPort.utf8()); + } +} + void KURL::setPort(unsigned short i) { KURLGooglePrivate::Replacements replacements; @@ -698,6 +733,142 @@ bool protocolIsJavaScript(const String& url) return protocolIs(url, "javascript"); } +bool isValidProtocol(const String& protocol) +{ + if (!isSchemeFirstChar(protocol[0])) + return false; + unsigned protocolLength = protocol.length(); + for (unsigned i = 1; i < protocolLength; i++) { + if (!isSchemeChar(protocol[i])) + return false; + } + return true; +} + +// We copied the KURL version here on Dec 4, 2009 while doing a WebKit +// merge. +// +// FIXME Somehow share this with KURL? Like we'd theoretically merge with +// decodeURLEscapeSequences below? +bool isDefaultPortForProtocol(unsigned short port, const String& protocol) +{ + if (protocol.isEmpty()) + return false; + + typedef HashMap<String, unsigned, CaseFoldingHash> DefaultPortsMap; + DEFINE_STATIC_LOCAL(DefaultPortsMap, defaultPorts, ()); + if (defaultPorts.isEmpty()) { + defaultPorts.set("http", 80); + defaultPorts.set("https", 443); + defaultPorts.set("ftp", 21); + defaultPorts.set("ftps", 990); + } + return defaultPorts.get(protocol) == port; +} + +// We copied the KURL version here on Dec 4, 2009 while doing a WebKit +// merge. +// +// FIXME Somehow share this with KURL? Like we'd theoretically merge with +// decodeURLEscapeSequences below? +bool portAllowed(const KURL& url) +{ + unsigned short port = url.port(); + + // Since most URLs don't have a port, return early for the "no port" case. + if (!port) + return true; + + // This blocked port list matches the port blocking that Mozilla implements. + // See http://www.mozilla.org/projects/netlib/PortBanning.html for more information. + static const unsigned short blockedPortList[] = { + 1, // tcpmux + 7, // echo + 9, // discard + 11, // systat + 13, // daytime + 15, // netstat + 17, // qotd + 19, // chargen + 20, // FTP-data + 21, // FTP-control + 22, // SSH + 23, // telnet + 25, // SMTP + 37, // time + 42, // name + 43, // nicname + 53, // domain + 77, // priv-rjs + 79, // finger + 87, // ttylink + 95, // supdup + 101, // hostriame + 102, // iso-tsap + 103, // gppitnp + 104, // acr-nema + 109, // POP2 + 110, // POP3 + 111, // sunrpc + 113, // auth + 115, // SFTP + 117, // uucp-path + 119, // nntp + 123, // NTP + 135, // loc-srv / epmap + 139, // netbios + 143, // IMAP2 + 179, // BGP + 389, // LDAP + 465, // SMTP+SSL + 512, // print / exec + 513, // login + 514, // shell + 515, // printer + 526, // tempo + 530, // courier + 531, // Chat + 532, // netnews + 540, // UUCP + 556, // remotefs + 563, // NNTP+SSL + 587, // ESMTP + 601, // syslog-conn + 636, // LDAP+SSL + 993, // IMAP+SSL + 995, // POP3+SSL + 2049, // NFS + 3659, // apple-sasl / PasswordServer [Apple addition] + 4045, // lockd + 6000, // X11 + }; + const unsigned short* const blockedPortListEnd = blockedPortList + sizeof(blockedPortList) / sizeof(blockedPortList[0]); + +#ifndef NDEBUG + // The port list must be sorted for binary_search to work. + static bool checkedPortList = false; + if (!checkedPortList) { + for (const unsigned short* p = blockedPortList; p != blockedPortListEnd - 1; ++p) + ASSERT(*p < *(p + 1)); + checkedPortList = true; + } +#endif + + // If the port is not in the blocked port list, allow it. + if (!binary_search(blockedPortList, blockedPortListEnd, port)) + return true; + + // Allow ports 21 and 22 for FTP URLs, as Mozilla does. + if ((port == 21 || port == 22) && url.protocolIs("ftp")) + return true; + + // Allow any port number in a file URL, since the port number is ignored. + if (url.protocolIs("file")) + return true; + + return false; +} + // We copied the KURL version here on Sept 12, 2008 while doing a WebKit // merge. // diff --git a/WebCore/platform/Length.h b/WebCore/platform/Length.h index b4497b6..4f36577 100644 --- a/WebCore/platform/Length.h +++ b/WebCore/platform/Length.h @@ -22,6 +22,7 @@ #define Length_h #include <wtf/Assertions.h> +#include <wtf/FastAllocBase.h> #include <wtf/MathExtras.h> namespace WebCore { @@ -33,7 +34,7 @@ const int percentScaleFactor = 128; enum LengthType { Auto, Relative, Percent, Fixed, Static, Intrinsic, MinIntrinsic }; -struct Length { +struct Length : FastAllocBase { Length() : m_value(0) { diff --git a/WebCore/platform/LocalizedStrings.h b/WebCore/platform/LocalizedStrings.h index 0fa9f71..f7a6fa6 100644 --- a/WebCore/platform/LocalizedStrings.h +++ b/WebCore/platform/LocalizedStrings.h @@ -141,6 +141,15 @@ namespace WebCore { String localizedMediaControlElementString(const String&); String localizedMediaControlElementHelpText(const String&); String localizedMediaTimeDescription(float); + + String validationMessageValueMissingText(); + String validationMessageTypeMismatchText(); + String validationMessagePatternMismatchText(); + String validationMessageTooLongText(); + String validationMessageRangeUnderflowText(); + String validationMessageRangeOverflowText(); + String validationMessageStepMismatchText(); + } #endif diff --git a/WebCore/platform/MIMETypeRegistry.cpp b/WebCore/platform/MIMETypeRegistry.cpp index 32dd3f6..978a611 100644 --- a/WebCore/platform/MIMETypeRegistry.cpp +++ b/WebCore/platform/MIMETypeRegistry.cpp @@ -261,8 +261,8 @@ static void initializeMediaTypeMaps() static const TypeExtensionPair pairs[] = { // Ogg - { "application/ogg", "ogg" }, { "application/ogg", "ogx" }, + { "audio/ogg", "ogg" }, { "audio/ogg", "oga" }, { "video/ogg", "ogv" }, diff --git a/WebCore/platform/PlatformKeyboardEvent.h b/WebCore/platform/PlatformKeyboardEvent.h index b5c2e95..cbbb48d 100644 --- a/WebCore/platform/PlatformKeyboardEvent.h +++ b/WebCore/platform/PlatformKeyboardEvent.h @@ -65,7 +65,7 @@ class BMessage; namespace WebCore { - class PlatformKeyboardEvent { + class PlatformKeyboardEvent : public FastAllocBase { public: enum Type { // KeyDown is sent by platforms such as Mac OS X, gtk and Qt, and has information about both physical pressed key, and its translation. diff --git a/WebCore/platform/ScrollView.cpp b/WebCore/platform/ScrollView.cpp index 1c9b5ce..6df462a 100644 --- a/WebCore/platform/ScrollView.cpp +++ b/WebCore/platform/ScrollView.cpp @@ -50,6 +50,7 @@ ScrollView::ScrollView() , m_updateScrollbarsPass(0) , m_drawPanScrollIcon(false) , m_useFixedLayout(false) + , m_paintsEntireContents(false) { platformInit(); } @@ -169,6 +170,11 @@ bool ScrollView::canBlitOnScroll() const return m_canBlitOnScroll; } +void ScrollView::setPaintsEntireContents(bool paintsEntireContents) +{ + m_paintsEntireContents = paintsEntireContents; +} + #if !PLATFORM(GTK) IntRect ScrollView::visibleContentRect(bool includeScrollbars) const { @@ -712,6 +718,7 @@ void ScrollView::frameRectsChanged() void ScrollView::repaintContentRectangle(const IntRect& rect, bool now) { +<<<<<<< HEAD:WebCore/platform/ScrollView.cpp IntRect visibleContent = visibleContentRect(); #ifdef ANDROID_CAPTURE_OFFSCREEN_PAINTS IntRect fullVis = visibleContent; @@ -722,14 +729,20 @@ void ScrollView::repaintContentRectangle(const IntRect& rect, bool now) platformOffscreenContentRectangle(fullVis, rect); #endif if (visibleContent.isEmpty()) +======= + IntRect paintRect = rect; + if (!paintsEntireContents()) + paintRect.intersect(visibleContentRect()); + if (paintRect.isEmpty()) +>>>>>>> webkit.org at r51976:WebCore/platform/ScrollView.cpp return; if (platformWidget()) { - platformRepaintContentRectangle(visibleContent, now); + platformRepaintContentRectangle(paintRect, now); return; } if (hostWindow()) - hostWindow()->repaint(contentsToWindow(visibleContent), true, now); + hostWindow()->repaint(contentsToWindow(paintRect), true, now); } IntRect ScrollView::scrollCornerRect() const @@ -775,7 +788,7 @@ void ScrollView::paintScrollbars(GraphicsContext* context, const IntRect& rect) void ScrollView::paintPanScrollIcon(GraphicsContext* context) { DEFINE_STATIC_LOCAL(Image*, panScrollIcon, (Image::loadPlatformResource("panIcon").releaseRef())); - context->drawImage(panScrollIcon, m_panScrollIconPoint); + context->drawImage(panScrollIcon, DeviceColorSpace, m_panScrollIconPoint); } void ScrollView::paint(GraphicsContext* context, const IntRect& rect) @@ -970,7 +983,7 @@ void ScrollView::platformDestroy() #endif -#if !PLATFORM(WX) && !PLATFORM(GTK) && !PLATFORM(QT) && !PLATFORM(MAC) +#if (!PLATFORM(WX) && !PLATFORM(GTK) && !PLATFORM(QT) && !PLATFORM(MAC)) || ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) void ScrollView::platformAddChild(Widget*) { @@ -982,7 +995,7 @@ void ScrollView::platformRemoveChild(Widget*) #endif -#if !PLATFORM(MAC) +#if !PLATFORM(MAC) || ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) void ScrollView::platformSetScrollbarsSuppressed(bool repaintOnUnsuppress) { @@ -990,7 +1003,7 @@ void ScrollView::platformSetScrollbarsSuppressed(bool repaintOnUnsuppress) #endif -#if !PLATFORM(MAC) && !PLATFORM(WX) +#if (!PLATFORM(MAC) && !PLATFORM(WX)) || ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) void ScrollView::platformSetScrollbarModes() { @@ -1052,8 +1065,12 @@ bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity) return true; } +<<<<<<< HEAD:WebCore/platform/ScrollView.cpp #if !PLATFORM(ANDROID) void ScrollView::platformRepaintContentRectangle(const IntRect&, bool now) +======= +void ScrollView::platformRepaintContentRectangle(const IntRect&, bool /*now*/) +>>>>>>> webkit.org at r51976:WebCore/platform/ScrollView.cpp { } diff --git a/WebCore/platform/ScrollView.h b/WebCore/platform/ScrollView.h index 2844ace..ac0e42f 100644 --- a/WebCore/platform/ScrollView.h +++ b/WebCore/platform/ScrollView.h @@ -89,9 +89,14 @@ public: void scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& verticalMode) const; ScrollbarMode horizontalScrollbarMode() const { ScrollbarMode horizontal, vertical; scrollbarModes(horizontal, vertical); return horizontal; } ScrollbarMode verticalScrollbarMode() const { ScrollbarMode horizontal, vertical; scrollbarModes(horizontal, vertical); return vertical; } - void setCanHaveScrollbars(bool flag); + virtual void setCanHaveScrollbars(bool); bool canHaveScrollbars() const { return horizontalScrollbarMode() != ScrollbarAlwaysOff || verticalScrollbarMode() != ScrollbarAlwaysOff; } + // By default you only receive paint events for the area that is visible. In the case of using a + // tiled backing store, this method can be set, so that the view paints the entire contents. + bool paintsEntireContents() const { return m_paintsEntireContents; } + void setPaintsEntireContents(bool); + // Overridden by FrameView to create custom CSS scrollbars if applicable. virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarOrientation); @@ -272,6 +277,8 @@ private: bool m_drawPanScrollIcon; bool m_useFixedLayout; + bool m_paintsEntireContents; + void init(); void destroy(); diff --git a/WebCore/platform/ScrollbarTheme.h b/WebCore/platform/ScrollbarTheme.h index 9327dc6..01229e1 100644 --- a/WebCore/platform/ScrollbarTheme.h +++ b/WebCore/platform/ScrollbarTheme.h @@ -36,7 +36,7 @@ class PlatformMouseEvent; class Scrollbar; class ScrollView; -class ScrollbarTheme { +class ScrollbarTheme : public Noncopyable { public: virtual ~ScrollbarTheme() {}; @@ -73,7 +73,7 @@ public: virtual void invalidatePart(Scrollbar*, ScrollbarPart) {} - virtual void paintScrollCorner(ScrollView*, GraphicsContext* context, const IntRect& cornerRect) { context->fillRect(cornerRect, Color::white); } + virtual void paintScrollCorner(ScrollView*, GraphicsContext* context, const IntRect& cornerRect) { context->fillRect(cornerRect, Color::white, DeviceColorSpace); } virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&) { return false; } virtual bool shouldSnapBackToDragOrigin(Scrollbar*, const PlatformMouseEvent&) { return false; } diff --git a/WebCore/platform/ScrollbarThemeComposite.cpp b/WebCore/platform/ScrollbarThemeComposite.cpp index ab5e16b..74bfae3 100644 --- a/WebCore/platform/ScrollbarThemeComposite.cpp +++ b/WebCore/platform/ScrollbarThemeComposite.cpp @@ -297,7 +297,7 @@ void ScrollbarThemeComposite::paintScrollCorner(ScrollView* view, GraphicsContex Page* page = frameView->frame() ? frameView->frame()->page() : 0; if (page && page->settings()->shouldPaintCustomScrollbars()) { if (!page->chrome()->client()->paintCustomScrollCorner(context, cornerRect)) - context->fillRect(cornerRect, Color::white); + context->fillRect(cornerRect, Color::white, DeviceColorSpace); } } diff --git a/WebCore/platform/SharedTimer.h b/WebCore/platform/SharedTimer.h index a005add..5b5cd14 100644 --- a/WebCore/platform/SharedTimer.h +++ b/WebCore/platform/SharedTimer.h @@ -26,12 +26,14 @@ #ifndef SharedTimer_h #define SharedTimer_h +#include <wtf/Noncopyable.h> + namespace WebCore { // Each thread has its own single instance of shared timer, which implements this interface. // This instance is shared by all timers in the thread. // Not intended to be used directly; use the Timer class instead. - class SharedTimer { + class SharedTimer : public Noncopyable { public: virtual ~SharedTimer() {} virtual void setFiredFunction(void (*)()) = 0; diff --git a/WebCore/platform/StaticConstructors.h b/WebCore/platform/StaticConstructors.h index 5bc792c..c0a9a53 100644 --- a/WebCore/platform/StaticConstructors.h +++ b/WebCore/platform/StaticConstructors.h @@ -1,6 +1,4 @@ /* - * This file is part of the DOM implementation for KDE. - * * Copyright (C) 2006 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or diff --git a/WebCore/platform/ThemeTypes.h b/WebCore/platform/ThemeTypes.h index e132313..439a3b1 100644 --- a/WebCore/platform/ThemeTypes.h +++ b/WebCore/platform/ThemeTypes.h @@ -48,7 +48,7 @@ enum ControlPart { NoControlPart, CheckboxPart, RadioPart, PushButtonPart, SquareButtonPart, ButtonPart, ButtonBevelPart, DefaultButtonPart, ListButtonPart, ListboxPart, ListItemPart, MediaFullscreenButtonPart, MediaMuteButtonPart, MediaPlayButtonPart, MediaSeekBackButtonPart, - MediaSeekForwardButtonPart, MediaRewindButtonPart, MediaReturnToRealtimeButtonPart, + MediaSeekForwardButtonPart, MediaRewindButtonPart, MediaReturnToRealtimeButtonPart, MediaToggleClosedCaptionsButtonPart, MediaSliderPart, MediaSliderThumbPart, MediaVolumeSliderContainerPart, MediaVolumeSliderPart, MediaVolumeSliderThumbPart, MediaControlsBackgroundPart, MediaCurrentTimePart, MediaTimeRemainingPart, MenulistPart, MenulistButtonPart, MenulistTextPart, MenulistTextFieldPart, diff --git a/WebCore/platform/ThreadGlobalData.cpp b/WebCore/platform/ThreadGlobalData.cpp index a43e9bd..26a9728 100644 --- a/WebCore/platform/ThreadGlobalData.cpp +++ b/WebCore/platform/ThreadGlobalData.cpp @@ -32,7 +32,7 @@ #include "ThreadTimers.h" #include <wtf/UnusedParam.h> -#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) +#if USE(ICU_UNICODE) #include "TextCodecICU.h" #endif @@ -75,7 +75,7 @@ ThreadGlobalData::ThreadGlobalData() #ifndef NDEBUG , m_isMainThread(isMainThread()) #endif -#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) +#if USE(ICU_UNICODE) , m_cachedConverterICU(new ICUConverterWrapper) #endif #if PLATFORM(MAC) @@ -89,7 +89,7 @@ ThreadGlobalData::~ThreadGlobalData() #if PLATFORM(MAC) delete m_cachedConverterTEC; #endif -#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) +#if USE(ICU_UNICODE) delete m_cachedConverterICU; #endif diff --git a/WebCore/platform/TreeShared.h b/WebCore/platform/TreeShared.h index 02728ff..a60ad0d 100644 --- a/WebCore/platform/TreeShared.h +++ b/WebCore/platform/TreeShared.h @@ -23,6 +23,9 @@ #include <wtf/Assertions.h> #include <wtf/Noncopyable.h> +#ifndef NDEBUG +#include <wtf/Threading.h> +#endif namespace WebCore { @@ -32,6 +35,7 @@ public: : m_refCount(initialRefCount) , m_parent(0) { + ASSERT(isMainThread()); #ifndef NDEBUG m_deletionHasBegun = false; m_inRemovedLastRefFunction = false; @@ -39,11 +43,13 @@ public: } virtual ~TreeShared() { + ASSERT(isMainThread()); ASSERT(m_deletionHasBegun); } void ref() { + ASSERT(isMainThread()); ASSERT(!m_deletionHasBegun); ASSERT(!m_inRemovedLastRefFunction); ++m_refCount; @@ -51,6 +57,7 @@ public: void deref() { + ASSERT(isMainThread()); ASSERT(!m_deletionHasBegun); ASSERT(!m_inRemovedLastRefFunction); if (--m_refCount <= 0 && !m_parent) { @@ -73,8 +80,17 @@ public: return m_refCount; } - void setParent(T* parent) { m_parent = parent; } - T* parent() const { return m_parent; } + void setParent(T* parent) + { + ASSERT(isMainThread()); + m_parent = parent; + } + + T* parent() const + { + ASSERT(isMainThread()); + return m_parent; + } #ifndef NDEBUG bool m_deletionHasBegun; diff --git a/WebCore/platform/Widget.cpp b/WebCore/platform/Widget.cpp index 23e5de8..2213a11 100644 --- a/WebCore/platform/Widget.cpp +++ b/WebCore/platform/Widget.cpp @@ -105,7 +105,7 @@ IntPoint Widget::convertToContainingWindow(const IntPoint& localPoint) const return convertFromRootToContainingWindow(this, localPoint); } -#if !PLATFORM(MAC) +#if !PLATFORM(MAC) || ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) IntRect Widget::convertFromRootToContainingWindow(const Widget*, const IntRect& rect) { return rect; @@ -127,7 +127,11 @@ IntPoint Widget::convertFromContainingWindowToRoot(const Widget*, const IntPoint } #endif +<<<<<<< HEAD:WebCore/platform/Widget.cpp #if !PLATFORM(MAC) && !PLATFORM(GTK) && !PLATFORM(ANDROID) +======= +#if (!PLATFORM(MAC) && !PLATFORM(GTK)) || ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) +>>>>>>> webkit.org at r51976:WebCore/platform/Widget.cpp void Widget::releasePlatformWidget() { } diff --git a/WebCore/platform/Widget.h b/WebCore/platform/Widget.h index cbbc427..a449d58 100644 --- a/WebCore/platform/Widget.h +++ b/WebCore/platform/Widget.h @@ -189,7 +189,7 @@ public: virtual void frameRectsChanged() {} -#if PLATFORM(MAC) +#if PLATFORM(MAC) && !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) NSView* getOuterView() const; static void beforeMouseDown(NSView*, Widget*); @@ -226,7 +226,7 @@ private: IntRect m_frame; // Not used when a native widget exists. -#if PLATFORM(MAC) +#if PLATFORM(MAC) && !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) WidgetPrivate* m_data; #endif #if PLATFORM(ANDROID) diff --git a/WebCore/platform/animation/AnimationList.h b/WebCore/platform/animation/AnimationList.h index 9901424..afad422 100644 --- a/WebCore/platform/animation/AnimationList.h +++ b/WebCore/platform/animation/AnimationList.h @@ -31,7 +31,7 @@ namespace WebCore { -class AnimationList { +class AnimationList : public FastAllocBase { public: void fillUnsetProperties(); bool operator==(const AnimationList& o) const; diff --git a/WebCore/platform/cf/BinaryPropertyList.h b/WebCore/platform/cf/BinaryPropertyList.h index 598aaa7..a930b43 100644 --- a/WebCore/platform/cf/BinaryPropertyList.h +++ b/WebCore/platform/cf/BinaryPropertyList.h @@ -26,6 +26,8 @@ #ifndef BinaryPropertyList_h #define BinaryPropertyList_h +#include <CoreFoundation/CoreFoundation.h> + #include <wtf/Vector.h> namespace WebCore { diff --git a/WebCore/platform/chromium/ChromiumBridge.h b/WebCore/platform/chromium/ChromiumBridge.h index 0c80636..3709f7c 100644 --- a/WebCore/platform/chromium/ChromiumBridge.h +++ b/WebCore/platform/chromium/ChromiumBridge.h @@ -37,6 +37,8 @@ #include "PassRefPtr.h" #include "PasteboardPrivate.h" +#include <wtf/Vector.h> + typedef struct NPObject NPObject; typedef struct _NPP NPP_t; typedef NPP_t* NPP; @@ -58,6 +60,7 @@ namespace WebCore { class String; class Widget; + struct Cookie; struct PluginInfo; // An interface to the embedding layer, which has the ability to answer @@ -82,6 +85,8 @@ namespace WebCore { // Cookies ------------------------------------------------------------ static void setCookies(const KURL& url, const KURL& firstPartyForCookies, const String& value); static String cookies(const KURL& url, const KURL& firstPartyForCookies); + static bool rawCookies(const KURL& url, const KURL& firstPartyForCookies, Vector<Cookie>*); + static void deleteCookie(const KURL& url, const String& cookieName); // DNS ---------------------------------------------------------------- static void prefetchDNS(const String& hostname); @@ -113,13 +118,13 @@ namespace WebCore { // HTML5 DB ----------------------------------------------------------- #if ENABLE(DATABASE) // Returns a handle to the DB file and ooptionally a handle to its containing directory - static PlatformFileHandle databaseOpenFile(const String& fileName, int desiredFlags, PlatformFileHandle* dirHandle = 0); + static PlatformFileHandle databaseOpenFile(const String& vfsFleName, int desiredFlags, PlatformFileHandle* dirHandle = 0); // Returns a SQLite code (SQLITE_OK = 0, on success) - static int databaseDeleteFile(const String& fileName, bool syncDir = false); + static int databaseDeleteFile(const String& vfsFileName, bool syncDir = false); // Returns the attributes of the DB file - static long databaseGetFileAttributes(const String& fileName); + static long databaseGetFileAttributes(const String& vfsFileName); // Returns the size of the DB file - static long long databaseGetFileSize(const String& fileName); + static long long databaseGetFileSize(const String& vfsFileName); #endif // JavaScript --------------------------------------------------------- @@ -135,6 +140,11 @@ namespace WebCore { // LayoutTestMode ----------------------------------------------------- static bool layoutTestMode(); + // Memory ------------------------------------------------------------- + // Returns the current space allocated for the pagefile, in MB. + // That is committed size for Windows and virtual memory size for POSIX + static int memoryUsageMB(); + // MimeType ----------------------------------------------------------- static bool isSupportedImageMIMEType(const String& mimeType); static bool isSupportedJavaScriptMIMEType(const String& mimeType); @@ -148,9 +158,6 @@ namespace WebCore { static NPObject* pluginScriptableObject(Widget*); static bool popupsAllowed(NPP); - // Protocol ----------------------------------------------------------- - static String uiResourceProtocol(); // deprecated - // Resources ---------------------------------------------------------- static PassRefPtr<Image> loadPlatformImageResource(const char* name); diff --git a/WebCore/platform/chromium/ClipboardChromium.cpp b/WebCore/platform/chromium/ClipboardChromium.cpp index d330d3b..1a2caa4 100644 --- a/WebCore/platform/chromium/ClipboardChromium.cpp +++ b/WebCore/platform/chromium/ClipboardChromium.cpp @@ -354,7 +354,7 @@ void ClipboardChromium::writeRange(Range* selectedRange, Frame* frame) m_dataObject->textHtml = createMarkup(selectedRange, 0, AnnotateForInterchange); #if PLATFORM(DARWIN) - m_dataObject->textHtml = String("<meta charset='utf-8'>") + m_dataObject->textHtml; + m_dataObject->textHtml = String("<meta charset='utf-8' id='webkit-interchange-charset'>") + m_dataObject->textHtml; #endif m_dataObject->htmlBaseUrl = frame->document()->url(); diff --git a/WebCore/platform/chromium/ContextMenuChromium.cpp b/WebCore/platform/chromium/ContextMenuChromium.cpp index 0614e3e..93c0ec4 100644 --- a/WebCore/platform/chromium/ContextMenuChromium.cpp +++ b/WebCore/platform/chromium/ContextMenuChromium.cpp @@ -38,13 +38,11 @@ namespace WebCore { ContextMenu::ContextMenu(const HitTestResult& result) : m_hitTestResult(result) - , m_platformDescription(0) { } ContextMenu::ContextMenu(const HitTestResult& result, const PlatformMenuDescription menu) : m_hitTestResult(result) - , m_platformDescription(0) { } @@ -54,25 +52,31 @@ ContextMenu::~ContextMenu() unsigned ContextMenu::itemCount() const { - return 0; + return m_items.size(); } void ContextMenu::insertItem(unsigned position, ContextMenuItem& item) { + m_items.insert(position, item); } void ContextMenu::appendItem(ContextMenuItem& item) { + m_items.append(item); } ContextMenuItem* ContextMenu::itemWithAction(unsigned action) { + for (size_t i = 0; i < m_items.size(); ++i) { + if (m_items[i].action() == static_cast<ContextMenuAction>(action)) + return &m_items[i]; + } return 0; } ContextMenuItem* ContextMenu::itemAtIndex(unsigned index, const PlatformMenuDescription platformDescription) { - return 0; + return &m_items[index]; } void ContextMenu::setPlatformDescription(PlatformMenuDescription menu) @@ -81,7 +85,7 @@ void ContextMenu::setPlatformDescription(PlatformMenuDescription menu) PlatformMenuDescription ContextMenu::platformDescription() const { - return m_platformDescription; + return 0; } PlatformMenuDescription ContextMenu::releasePlatformDescription() diff --git a/WebCore/platform/chromium/ContextMenuItemChromium.cpp b/WebCore/platform/chromium/ContextMenuItemChromium.cpp index f34ea23..6a0d657 100644 --- a/WebCore/platform/chromium/ContextMenuItemChromium.cpp +++ b/WebCore/platform/chromium/ContextMenuItemChromium.cpp @@ -46,6 +46,9 @@ ContextMenuItem::ContextMenuItem(ContextMenu* subMenu) ContextMenuItem::ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, const String& title, ContextMenu* subMenu) { + m_platformDescription.type = type; + m_platformDescription.action = action; + m_platformDescription.title = title; } ContextMenuItem::~ContextMenuItem() @@ -54,22 +57,32 @@ ContextMenuItem::~ContextMenuItem() PlatformMenuItemDescription ContextMenuItem::releasePlatformDescription() { - return PlatformMenuItemDescription(); + return m_platformDescription; } ContextMenuItemType ContextMenuItem::type() const { - return ContextMenuItemType(); + return m_platformDescription.type; } ContextMenuAction ContextMenuItem::action() const { - return ContextMenuAction(); + return m_platformDescription.action; } String ContextMenuItem::title() const { - return String(); + return m_platformDescription.title; +} + +bool ContextMenuItem::checked() const +{ + return m_platformDescription.checked; +} + +bool ContextMenuItem::enabled() const +{ + return m_platformDescription.enabled; } PlatformMenuDescription ContextMenuItem::platformSubMenu() const @@ -79,14 +92,17 @@ PlatformMenuDescription ContextMenuItem::platformSubMenu() const void ContextMenuItem::setType(ContextMenuItemType type) { + m_platformDescription.type = type; } void ContextMenuItem::setAction(ContextMenuAction action) { + m_platformDescription.action = action; } void ContextMenuItem::setTitle(const String& title) { + m_platformDescription.title = title; } void ContextMenuItem::setSubMenu(ContextMenu* subMenu) @@ -95,15 +111,12 @@ void ContextMenuItem::setSubMenu(ContextMenu* subMenu) void ContextMenuItem::setChecked(bool checked) { + m_platformDescription.checked = checked; } void ContextMenuItem::setEnabled(bool enabled) { -} - -bool ContextMenuItem::enabled() const -{ - return false; + m_platformDescription.enabled = enabled; } } // namespace WebCore diff --git a/WebCore/platform/chromium/GeolocationServiceChromium.cpp b/WebCore/platform/chromium/GeolocationServiceChromium.cpp new file mode 100644 index 0000000..65886b0 --- /dev/null +++ b/WebCore/platform/chromium/GeolocationServiceChromium.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * 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 "GeolocationService.h" + +namespace WebCore { + +class GeolocationServiceChromium : public GeolocationService { +public: + GeolocationServiceChromium(GeolocationServiceClient* c) + : GeolocationService(c) + { + } + // FIXME: Implement. https://bugs.webkit.org/show_bug.cgi?id=32068 +}; + +// This guard is the counterpart of the one in WebCore/platform/GeolocationService.cpp +#if ENABLE(GEOLOCATION) +static GeolocationService* createGeolocationService(GeolocationServiceClient* c) +{ + return new GeolocationServiceChromium(c); +} + +GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &createGeolocationService; +#endif + +} // namespace WebCore diff --git a/WebCore/platform/chromium/MIMETypeRegistryChromium.cpp b/WebCore/platform/chromium/MIMETypeRegistryChromium.cpp index 51bff80..ff0be82 100644 --- a/WebCore/platform/chromium/MIMETypeRegistryChromium.cpp +++ b/WebCore/platform/chromium/MIMETypeRegistryChromium.cpp @@ -34,6 +34,7 @@ #include "ChromiumBridge.h" #include "CString.h" #include "MediaPlayer.h" +#include "PluginDataChromium.h" // NOTE: Unlike other ports, we don't use the shared implementation bits in // MIMETypeRegistry.cpp. Instead, we need to route most functions via the @@ -41,11 +42,6 @@ namespace WebCore { -// Checks if any of the plugins handle this extension, and if so returns the -// plugin's mime type for this extension. Otherwise returns an empty string. -// See PluginsChromium.cpp for the implementation of this function. -String getPluginMimeTypeFromExtension(const String& extension); - String MIMETypeRegistry::getMIMETypeForExtension(const String &ext) { return ChromiumBridge::mimeTypeForExtension(ext); diff --git a/WebCore/platform/chromium/PasteboardChromium.cpp b/WebCore/platform/chromium/PasteboardChromium.cpp index 4929eb8..ce06e55 100644 --- a/WebCore/platform/chromium/PasteboardChromium.cpp +++ b/WebCore/platform/chromium/PasteboardChromium.cpp @@ -83,7 +83,7 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, { String html = createMarkup(selectedRange, 0, AnnotateForInterchange); #if PLATFORM(DARWIN) - html = String("<meta charset='utf-8'>") + html; + html = String("<meta charset='utf-8' id='webkit-interchange-charset'>") + html; #endif ExceptionCode ec = 0; KURL url = selectedRange->startContainer(ec)->document()->url(); @@ -170,6 +170,11 @@ PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefP String markup; KURL srcURL; ChromiumBridge::clipboardReadHTML(buffer, &markup, &srcURL); +#if PLATFORM(DARWIN) + DEFINE_STATIC_LOCAL(const String, forceUtf8String, ("<meta charset='utf-8' id='webkit-interchange-charset'>")); + if (markup.startsWith(forceUtf8String)) + markup = markup.substring(forceUtf8String.length()); +#endif RefPtr<DocumentFragment> fragment = createFragmentFromMarkup(frame->document(), markup, srcURL); diff --git a/WebCore/platform/chromium/PopupMenuChromium.cpp b/WebCore/platform/chromium/PopupMenuChromium.cpp index d6f895d..5abd364 100644 --- a/WebCore/platform/chromium/PopupMenuChromium.cpp +++ b/WebCore/platform/chromium/PopupMenuChromium.cpp @@ -370,6 +370,12 @@ void PopupContainer::showExternal(const IntRect& rect, FrameView* v, int index) ChromeClientChromium* client = static_cast<ChromeClientChromium*>( v->frame()->page()->chrome()->client()); client->popupOpened(this, popupRect, true, true); + + // The popup sends its "closed" notification through its parent. Set the + // parent, even though external popups have no real on-screen widget but a + // native menu (see |PopupListBox::hidePopup()|); + if (!m_listBox->parent()) + addChild(m_listBox.get()); } void PopupContainer::hidePopup() @@ -446,7 +452,7 @@ void PopupContainer::paintBorder(GraphicsContext* gc, const IntRect& rect) Color borderColor(127, 157, 185); gc->setStrokeStyle(NoStroke); - gc->setFillColor(borderColor); + gc->setFillColor(borderColor, DeviceColorSpace); int tx = x(); int ty = y(); @@ -772,7 +778,7 @@ void PopupListBox::paint(GraphicsContext* gc, const IntRect& rect) // Special case for an empty popup. if (numItems() == 0) - gc->fillRect(r, Color::white); + gc->fillRect(r, Color::white, DeviceColorSpace); gc->restore(); @@ -805,23 +811,23 @@ void PopupListBox::paintRow(GraphicsContext* gc, const IntRect& rect, int rowInd // If we have a transparent background, make sure it has a color to blend // against. if (backColor.hasAlpha()) - gc->fillRect(rowRect, Color::white); + gc->fillRect(rowRect, Color::white, DeviceColorSpace); - gc->fillRect(rowRect, backColor); + gc->fillRect(rowRect, backColor, DeviceColorSpace); if (m_popupClient->itemIsSeparator(rowIndex)) { IntRect separatorRect( rowRect.x() + separatorPadding, rowRect.y() + (rowRect.height() - separatorHeight) / 2, rowRect.width() - 2 * separatorPadding, separatorHeight); - gc->fillRect(separatorRect, textColor); + gc->fillRect(separatorRect, textColor, DeviceColorSpace); return; } if (!style.isVisible()) return; - gc->setFillColor(textColor); + gc->setFillColor(textColor, DeviceColorSpace); Font itemFont = getRowFont(rowIndex); // FIXME: http://crbug.com/19872 We should get the padding of individual option diff --git a/WebCore/platform/chromium/ScrollbarThemeChromium.cpp b/WebCore/platform/chromium/ScrollbarThemeChromium.cpp index 725de10..a6720a1 100644 --- a/WebCore/platform/chromium/ScrollbarThemeChromium.cpp +++ b/WebCore/platform/chromium/ScrollbarThemeChromium.cpp @@ -113,7 +113,7 @@ void ScrollbarThemeChromium::paintTickmarks(GraphicsContext* context, Scrollbar* const int yPos = rect.topLeft().y() + (rect.height() * percent); IntPoint tick(scrollbar->x(), yPos); - context->drawImage(dash.get(), tick); + context->drawImage(dash.get(), DeviceColorSpace, tick); } context->restore(); diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp index 64f58c4..3a1a652 100644 --- a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp +++ b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp @@ -33,6 +33,8 @@ #include "PlatformContextSkia.h" #include "PlatformMouseEvent.h" +#include "RenderTheme.h" +#include "RenderThemeChromiumLinux.h" #include "Scrollbar.h" #include "TransformationMatrix.h" @@ -73,6 +75,60 @@ static void drawBox(SkCanvas* canvas, const IntRect& rect, const SkPaint& paint) drawVertLine(canvas, rect.x(), rect.y(), bottom, paint); } +static SkScalar clamp(SkScalar value, SkScalar min, SkScalar max) +{ + return std::min(std::max(value, min), max); +} + +static SkColor saturateAndBrighten(SkScalar* hsv, + SkScalar saturateAmount, + SkScalar brightenAmount) +{ + SkScalar color[3]; + color[0] = hsv[0]; + color[1] = clamp(hsv[1] + saturateAmount, 0.0, 1.0); + color[2] = clamp(hsv[2] + brightenAmount, 0.0, 1.0); + return SkHSVToColor(color); +} + +static SkColor outlineColor(SkScalar* hsv1, SkScalar* hsv2) +{ + // GTK Theme engines have way too much control over the layout of + // the scrollbar. We might be able to more closely approximate its + // look-and-feel, if we sent whole images instead of just colors + // from the browser to the renderer. But even then, some themes + // would just break. + // + // So, instead, we don't even try to 100% replicate the look of + // the native scrollbar. We render our own version, but we make + // sure to pick colors that blend in nicely with the system GTK + // theme. In most cases, we can just sample a couple of pixels + // from the system scrollbar and use those colors to draw our + // scrollbar. + // + // This works fine for the track color and the overall thumb + // color. But it fails spectacularly for the outline color used + // around the thumb piece. Not all themes have a clearly defined + // outline. For some of them it is partially transparent, and for + // others the thickness is very unpredictable. + // + // So, instead of trying to approximate the system theme, we + // instead try to compute a reasonable looking choice based on the + // known color of the track and the thumb piece. This is difficult + // when trying to deal both with high- and low-contrast themes, + // and both with positive and inverted themes. + // + // The following code has been tested to look OK with all of the + // default GTK themes. + SkScalar minDiff = clamp((hsv1[1] + hsv2[1]) * 1.2, 0.2, 0.5); + SkScalar diff = clamp(fabs(hsv1[2] - hsv2[2]) / 2, minDiff, 0.5); + + if (hsv1[2] + hsv2[2] > 1.0) + diff = -diff; + + return saturateAndBrighten(hsv2, -0.2, diff); +} + IntRect ScrollbarThemeChromium::trackRect(Scrollbar* scrollbar, bool) { IntSize bs = buttonSize(scrollbar); @@ -89,10 +145,16 @@ void ScrollbarThemeChromiumLinux::paintTrackPiece(GraphicsContext* gc, Scrollbar SkIRect skrect; skrect.set(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height()); - paint.setARGB(0xff, 0xe3, 0xdd, 0xd8); + SkScalar track_hsv[3]; + SkColorToHSV(RenderThemeChromiumLinux::trackColor(), track_hsv); + paint.setColor(saturateAndBrighten(track_hsv, 0, 0)); canvas->drawIRect(skrect, paint); - paint.setARGB(0xff, 0xc5, 0xba, 0xb0); + SkScalar thumb_hsv[3]; + SkColorToHSV(RenderThemeChromiumLinux::thumbInactiveColor(), + thumb_hsv); + + paint.setColor(outlineColor(track_hsv, thumb_hsv)); drawBox(canvas, rect, paint); } @@ -109,11 +171,14 @@ void ScrollbarThemeChromiumLinux::paintThumb(GraphicsContext* gc, Scrollbar* scr const bool vertical = scrollbar->orientation() == VerticalScrollbar; SkCanvas* const canvas = gc->platformContext()->canvas(); + SkScalar thumb[3]; + SkColorToHSV(hovered + ? RenderThemeChromiumLinux::thumbActiveColor() + : RenderThemeChromiumLinux::thumbInactiveColor(), + thumb); + SkPaint paint; - if (hovered) - paint.setARGB(0xff, 0xff, 0xff, 0xff); - else - paint.setARGB(0xff, 0xf4, 0xf2, 0xef); + paint.setColor(saturateAndBrighten(thumb, 0, 0.02)); SkIRect skrect; if (vertical) @@ -123,10 +188,7 @@ void ScrollbarThemeChromiumLinux::paintThumb(GraphicsContext* gc, Scrollbar* scr canvas->drawIRect(skrect, paint); - if (hovered) - paint.setARGB(0xff, 0xf4, 0xf2, 0xef); - else - paint.setARGB(0xff, 0xea, 0xe5, 0xe0); + paint.setColor(saturateAndBrighten(thumb, 0, -0.02)); if (vertical) skrect.set(midx + 1, rect.y(), rect.x() + rect.width(), rect.y() + rect.height()); @@ -135,11 +197,12 @@ void ScrollbarThemeChromiumLinux::paintThumb(GraphicsContext* gc, Scrollbar* scr canvas->drawIRect(skrect, paint); - paint.setARGB(0xff, 0x9d, 0x96, 0x8e); + SkScalar track[3]; + SkColorToHSV(RenderThemeChromiumLinux::trackColor(), track); + paint.setColor(outlineColor(track, thumb)); drawBox(canvas, rect, paint); if (rect.height() > 10 && rect.width() > 10) { - paint.setARGB(0xff, 0x9d, 0x96, 0x8e); const int grippyHalfWidth = 2; const int interGrippyOffset = 3; if (vertical) { diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumMac.h b/WebCore/platform/chromium/ScrollbarThemeChromiumMac.h new file mode 100644 index 0000000..1ab2f18 --- /dev/null +++ b/WebCore/platform/chromium/ScrollbarThemeChromiumMac.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Google Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 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. ``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 + * 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 ScrollbarThemeChromiumMac_h +#define ScrollbarThemeChromiumMac_h + +#include "ScrollbarThemeComposite.h" + +// This file (and its associated .mm file) is a clone of ScrollbarThemeMac.h. +// See the .mm file for details. + +namespace WebCore { + +class ScrollbarThemeChromiumMac : public ScrollbarThemeComposite { +public: + ScrollbarThemeChromiumMac(); + virtual ~ScrollbarThemeChromiumMac(); + + virtual bool paint(Scrollbar*, GraphicsContext* context, const IntRect& damageRect); + + virtual int scrollbarThickness(ScrollbarControlSize = RegularScrollbar); + + virtual bool supportsControlTints() const { return true; } + + virtual double initialAutoscrollTimerDelay(); + virtual double autoscrollTimerDelay(); + + virtual ScrollbarButtonsPlacement buttonsPlacement() const; + + virtual void registerScrollbar(Scrollbar*); + virtual void unregisterScrollbar(Scrollbar*); + +protected: + virtual bool hasButtons(Scrollbar*); + virtual bool hasThumb(Scrollbar*); + + virtual IntRect backButtonRect(Scrollbar*, ScrollbarPart, bool painting = false); + virtual IntRect forwardButtonRect(Scrollbar*, ScrollbarPart, bool painting = false); + virtual IntRect trackRect(Scrollbar*, bool painting = false); + + virtual int minimumThumbLength(Scrollbar*); + + virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&); + +public: + void preferencesChanged(); +}; + +} + +#endif // ScrollbarThemeChromiumMac_h diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumMac.mm b/WebCore/platform/chromium/ScrollbarThemeChromiumMac.mm new file mode 100644 index 0000000..b4ebaf6 --- /dev/null +++ b/WebCore/platform/chromium/ScrollbarThemeChromiumMac.mm @@ -0,0 +1,463 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Google Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 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. ``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 + * 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 "ScrollbarThemeChromiumMac.h" + +#include "ImageBuffer.h" +#include "PlatformMouseEvent.h" +#include "ScrollView.h" +#include <Carbon/Carbon.h> +#include <wtf/StdLibExtras.h> +#include <wtf/UnusedParam.h> + +// FIXME: There are repainting problems due to Aqua scroll bar buttons' visual overflow. + +using namespace std; +using namespace WebCore; + +// This file (and its associated .h file) is a clone of ScrollbarThemeMac.mm. +// Because we want to draw tickmarks in the scrollbar, we must maintain a fork. +// Please maintain this file by performing parallel changes to it. +// +// The only changes from ScrollbarThemeMac should be: +// - The classname change from ScrollbarThemeMac to ScrollbarThemeChromiumMac. +// - In paint() the code to paint the track, tickmarks, and thumb separately. +// +// For all other differences, if it was introduced in this file, then the +// maintainer forgot to include it in the list; otherwise it is an update that +// should have been applied to this file but was not. + +static HashSet<Scrollbar*>* gScrollbars; + +@interface ScrollbarPrefsObserver : NSObject +{ + +} + ++ (void)registerAsObserver; ++ (void)appearancePrefsChanged:(NSNotification*)theNotification; ++ (void)behaviorPrefsChanged:(NSNotification*)theNotification; + +@end + +@implementation ScrollbarPrefsObserver + ++ (void)appearancePrefsChanged:(NSNotification*)unusedNotification +{ + UNUSED_PARAM(unusedNotification); + + static_cast<ScrollbarThemeChromiumMac*>(ScrollbarTheme::nativeTheme())->preferencesChanged(); + if (!gScrollbars) + return; + HashSet<Scrollbar*>::iterator end = gScrollbars->end(); + for (HashSet<Scrollbar*>::iterator it = gScrollbars->begin(); it != end; ++it) { + (*it)->styleChanged(); + (*it)->invalidate(); + } +} + ++ (void)behaviorPrefsChanged:(NSNotification*)unusedNotification +{ + UNUSED_PARAM(unusedNotification); + + static_cast<ScrollbarThemeChromiumMac*>(ScrollbarTheme::nativeTheme())->preferencesChanged(); +} + ++ (void)registerAsObserver +{ + [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(appearancePrefsChanged:) name:@"AppleAquaScrollBarVariantChanged" object:nil suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately]; + [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(behaviorPrefsChanged:) name:@"AppleNoRedisplayAppearancePreferenceChanged" object:nil suspensionBehavior:NSNotificationSuspensionBehaviorCoalesce]; +} + +@end + +namespace WebCore { + +ScrollbarTheme* ScrollbarTheme::nativeTheme() +{ + DEFINE_STATIC_LOCAL(ScrollbarThemeChromiumMac, theme, ()); + return &theme; +} + +// FIXME: Get these numbers from CoreUI. +static int cScrollbarThickness[] = { 15, 11 }; +static int cRealButtonLength[] = { 28, 21 }; +static int cButtonInset[] = { 14, 11 }; +static int cButtonHitInset[] = { 3, 2 }; +// cRealButtonLength - cButtonInset +static int cButtonLength[] = { 14, 10 }; +static int cThumbMinLength[] = { 26, 20 }; + +static int cOuterButtonLength[] = { 16, 14 }; // The outer button in a double button pair is a bit bigger. +static int cOuterButtonOverlap = 2; + +static float gInitialButtonDelay = 0.5f; +static float gAutoscrollButtonDelay = 0.05f; +static bool gJumpOnTrackClick = false; +static ScrollbarButtonsPlacement gButtonPlacement = ScrollbarButtonsDoubleEnd; + +static void updateArrowPlacement() +{ + NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"]; + if ([buttonPlacement isEqualToString:@"Single"]) + gButtonPlacement = ScrollbarButtonsSingle; + else if ([buttonPlacement isEqualToString:@"DoubleMin"]) + gButtonPlacement = ScrollbarButtonsDoubleStart; + else if ([buttonPlacement isEqualToString:@"DoubleBoth"]) + gButtonPlacement = ScrollbarButtonsDoubleBoth; + else + gButtonPlacement = ScrollbarButtonsDoubleEnd; // The default is ScrollbarButtonsDoubleEnd. +} + +void ScrollbarThemeChromiumMac::registerScrollbar(Scrollbar* scrollbar) +{ + if (!gScrollbars) + gScrollbars = new HashSet<Scrollbar*>; + gScrollbars->add(scrollbar); +} + +void ScrollbarThemeChromiumMac::unregisterScrollbar(Scrollbar* scrollbar) +{ + gScrollbars->remove(scrollbar); + if (gScrollbars->isEmpty()) { + delete gScrollbars; + gScrollbars = 0; + } +} + +ScrollbarThemeChromiumMac::ScrollbarThemeChromiumMac() +{ + static bool initialized; + if (!initialized) { + initialized = true; + [ScrollbarPrefsObserver registerAsObserver]; + preferencesChanged(); + } +} + +ScrollbarThemeChromiumMac::~ScrollbarThemeChromiumMac() +{ +} + +void ScrollbarThemeChromiumMac::preferencesChanged() +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults synchronize]; + updateArrowPlacement(); + gInitialButtonDelay = [defaults floatForKey:@"NSScrollerButtonDelay"]; + gAutoscrollButtonDelay = [defaults floatForKey:@"NSScrollerButtonPeriod"]; + gJumpOnTrackClick = [defaults boolForKey:@"AppleScrollerPagingBehavior"]; +} + +int ScrollbarThemeChromiumMac::scrollbarThickness(ScrollbarControlSize controlSize) +{ + return cScrollbarThickness[controlSize]; +} + +double ScrollbarThemeChromiumMac::initialAutoscrollTimerDelay() +{ + return gInitialButtonDelay; +} + +double ScrollbarThemeChromiumMac::autoscrollTimerDelay() +{ + return gAutoscrollButtonDelay; +} + +ScrollbarButtonsPlacement ScrollbarThemeChromiumMac::buttonsPlacement() const +{ + return gButtonPlacement; +} + +bool ScrollbarThemeChromiumMac::hasButtons(Scrollbar* scrollbar) +{ + return scrollbar->enabled() && (scrollbar->orientation() == HorizontalScrollbar ? + scrollbar->width() : + scrollbar->height()) >= 2 * (cRealButtonLength[scrollbar->controlSize()] - cButtonHitInset[scrollbar->controlSize()]); +} + +bool ScrollbarThemeChromiumMac::hasThumb(Scrollbar* scrollbar) +{ + return scrollbar->enabled() && (scrollbar->orientation() == HorizontalScrollbar ? + scrollbar->width() : + scrollbar->height()) >= 2 * cButtonInset[scrollbar->controlSize()] + cThumbMinLength[scrollbar->controlSize()] + 1; +} + +static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize, bool start) +{ + IntRect paintRect(buttonRect); + if (orientation == HorizontalScrollbar) { + paintRect.setWidth(cRealButtonLength[controlSize]); + if (!start) + paintRect.setX(buttonRect.x() - (cRealButtonLength[controlSize] - buttonRect.width())); + } else { + paintRect.setHeight(cRealButtonLength[controlSize]); + if (!start) + paintRect.setY(buttonRect.y() - (cRealButtonLength[controlSize] - buttonRect.height())); + } + + return paintRect; +} + +IntRect ScrollbarThemeChromiumMac::backButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool painting) +{ + IntRect result; + + if (part == BackButtonStartPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleEnd)) + return result; + + if (part == BackButtonEndPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleStart || buttonsPlacement() == ScrollbarButtonsSingle)) + return result; + + int thickness = scrollbarThickness(scrollbar->controlSize()); + bool outerButton = part == BackButtonStartPart && (buttonsPlacement() == ScrollbarButtonsDoubleStart || buttonsPlacement() == ScrollbarButtonsDoubleBoth); + if (outerButton) { + if (scrollbar->orientation() == HorizontalScrollbar) + result = IntRect(scrollbar->x(), scrollbar->y(), cOuterButtonLength[scrollbar->controlSize()] + painting ? cOuterButtonOverlap : 0, thickness); + else + result = IntRect(scrollbar->x(), scrollbar->y(), thickness, cOuterButtonLength[scrollbar->controlSize()] + painting ? cOuterButtonOverlap : 0); + return result; + } + + // Our repaint rect is slightly larger, since we are a button that is adjacent to the track. + if (scrollbar->orientation() == HorizontalScrollbar) { + int start = part == BackButtonStartPart ? scrollbar->x() : scrollbar->x() + scrollbar->width() - cOuterButtonLength[scrollbar->controlSize()] - cButtonLength[scrollbar->controlSize()]; + result = IntRect(start, scrollbar->y(), cButtonLength[scrollbar->controlSize()], thickness); + } else { + int start = part == BackButtonStartPart ? scrollbar->y() : scrollbar->y() + scrollbar->height() - cOuterButtonLength[scrollbar->controlSize()] - cButtonLength[scrollbar->controlSize()]; + result = IntRect(scrollbar->x(), start, thickness, cButtonLength[scrollbar->controlSize()]); + } + + if (painting) + return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->controlSize(), part == BackButtonStartPart); + return result; +} + +IntRect ScrollbarThemeChromiumMac::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool painting) +{ + IntRect result; + + if (part == ForwardButtonEndPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleStart)) + return result; + + if (part == ForwardButtonStartPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleEnd || buttonsPlacement() == ScrollbarButtonsSingle)) + return result; + + int thickness = scrollbarThickness(scrollbar->controlSize()); + int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()]; + int buttonLength = cButtonLength[scrollbar->controlSize()]; + + bool outerButton = part == ForwardButtonEndPart && (buttonsPlacement() == ScrollbarButtonsDoubleEnd || buttonsPlacement() == ScrollbarButtonsDoubleBoth); + if (outerButton) { + if (scrollbar->orientation() == HorizontalScrollbar) { + result = IntRect(scrollbar->x() + scrollbar->width() - outerButtonLength, scrollbar->y(), outerButtonLength, thickness); + if (painting) + result.inflateX(cOuterButtonOverlap); + } else { + result = IntRect(scrollbar->x(), scrollbar->y() + scrollbar->height() - outerButtonLength, thickness, outerButtonLength); + if (painting) + result.inflateY(cOuterButtonOverlap); + } + return result; + } + + if (scrollbar->orientation() == HorizontalScrollbar) { + int start = part == ForwardButtonEndPart ? scrollbar->x() + scrollbar->width() - buttonLength : scrollbar->x() + outerButtonLength; + result = IntRect(start, scrollbar->y(), buttonLength, thickness); + } else { + int start = part == ForwardButtonEndPart ? scrollbar->y() + scrollbar->height() - buttonLength : scrollbar->y() + outerButtonLength; + result = IntRect(scrollbar->x(), start, thickness, buttonLength); + } + if (painting) + return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->controlSize(), part == ForwardButtonStartPart); + return result; +} + +IntRect ScrollbarThemeChromiumMac::trackRect(Scrollbar* scrollbar, bool painting) +{ + if (painting || !hasButtons(scrollbar)) + return scrollbar->frameRect(); + + IntRect result; + int thickness = scrollbarThickness(scrollbar->controlSize()); + int startWidth = 0; + int endWidth = 0; + int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()]; + int buttonLength = cButtonLength[scrollbar->controlSize()]; + int doubleButtonLength = outerButtonLength + buttonLength; + switch (buttonsPlacement()) { + case ScrollbarButtonsSingle: + startWidth = buttonLength; + endWidth = buttonLength; + break; + case ScrollbarButtonsDoubleStart: + startWidth = doubleButtonLength; + break; + case ScrollbarButtonsDoubleEnd: + endWidth = doubleButtonLength; + break; + case ScrollbarButtonsDoubleBoth: + startWidth = doubleButtonLength; + endWidth = doubleButtonLength; + break; + default: + break; + } + + int totalWidth = startWidth + endWidth; + if (scrollbar->orientation() == HorizontalScrollbar) + return IntRect(scrollbar->x() + startWidth, scrollbar->y(), scrollbar->width() - totalWidth, thickness); + return IntRect(scrollbar->x(), scrollbar->y() + startWidth, thickness, scrollbar->height() - totalWidth); +} + +int ScrollbarThemeChromiumMac::minimumThumbLength(Scrollbar* scrollbar) +{ + return cThumbMinLength[scrollbar->controlSize()]; +} + +bool ScrollbarThemeChromiumMac::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt) +{ + if (evt.button() != LeftButton) + return false; + if (gJumpOnTrackClick) + return !evt.altKey(); + return evt.altKey(); +} + +static int scrollbarPartToHIPressedState(ScrollbarPart part) +{ + switch (part) { + case BackButtonStartPart: + return kThemeTopOutsideArrowPressed; + case BackButtonEndPart: + return kThemeTopOutsideArrowPressed; // This does not make much sense. For some reason the outside constant is required. + case ForwardButtonStartPart: + return kThemeTopInsideArrowPressed; + case ForwardButtonEndPart: + return kThemeBottomOutsideArrowPressed; + case ThumbPart: + return kThemeThumbPressed; + default: + return 0; + } +} + +bool ScrollbarThemeChromiumMac::paint(Scrollbar* scrollbar, GraphicsContext* context, const IntRect& damageRect) +{ + HIThemeTrackDrawInfo trackInfo; + trackInfo.version = 0; + trackInfo.kind = scrollbar->controlSize() == RegularScrollbar ? kThemeMediumScrollBar : kThemeSmallScrollBar; + trackInfo.bounds = scrollbar->frameRect(); + trackInfo.min = 0; + trackInfo.max = scrollbar->maximum(); + trackInfo.value = scrollbar->currentPos(); + trackInfo.trackInfo.scrollbar.viewsize = scrollbar->pageStep(); + trackInfo.attributes = 0; + if (scrollbar->orientation() == HorizontalScrollbar) + trackInfo.attributes |= kThemeTrackHorizontal; + + if (!scrollbar->enabled()) + trackInfo.enableState = kThemeTrackDisabled; + else + trackInfo.enableState = scrollbar->client()->isActive() ? kThemeTrackActive : kThemeTrackInactive; + + if (!hasButtons(scrollbar)) + trackInfo.enableState = kThemeTrackNothingToScroll; + trackInfo.trackInfo.scrollbar.pressState = scrollbarPartToHIPressedState(scrollbar->pressedPart()); + + CGAffineTransform currentCTM = CGContextGetCTM(context->platformContext()); + + // The Aqua scrollbar is buggy when rotated and scaled. We will just draw into a bitmap if we detect a scale or rotation. + bool canDrawDirectly = currentCTM.a == 1.0f && currentCTM.b == 0.0f && currentCTM.c == 0.0f && (currentCTM.d == 1.0f || currentCTM.d == -1.0f); + GraphicsContext* drawingContext = context; + OwnPtr<ImageBuffer> imageBuffer; + if (!canDrawDirectly) { + trackInfo.bounds = IntRect(IntPoint(), scrollbar->frameRect().size()); + + IntRect bufferRect(scrollbar->frameRect()); + bufferRect.intersect(damageRect); + bufferRect.move(-scrollbar->frameRect().x(), -scrollbar->frameRect().y()); + + imageBuffer = ImageBuffer::create(bufferRect.size()); + if (!imageBuffer) + return true; + + drawingContext = imageBuffer->context(); + } + + // Draw thumbless. + HIThemeDrawTrack(&trackInfo, 0, drawingContext->platformContext(), kHIThemeOrientationNormal); + + Vector<IntRect> tickmarks; + scrollbar->client()->getTickmarks(tickmarks); + if (scrollbar->orientation() == VerticalScrollbar && tickmarks.size()) { + drawingContext->save(); + drawingContext->setShouldAntialias(false); + drawingContext->setStrokeColor(Color(0xCC, 0xAA, 0x00, 0xFF), DeviceColorSpace); + drawingContext->setFillColor(Color(0xFF, 0xDD, 0x00, 0xFF), DeviceColorSpace); + + IntRect thumbArea = trackRect(scrollbar, false); + if (!canDrawDirectly) { + thumbArea.setX(0); + thumbArea.setY(0); + } + // The ends are rounded and the thumb doesn't go there. + thumbArea.inflateY(-thumbArea.width()); + + for (Vector<IntRect>::const_iterator i = tickmarks.begin(); i != tickmarks.end(); ++i) { + // Calculate how far down (in %) the tick-mark should appear. + const float percent = static_cast<float>(i->y()) / scrollbar->totalSize(); + if (percent < 0.0 || percent > 1.0) + continue; + + // Calculate how far down (in pixels) the tick-mark should appear. + const int yPos = static_cast<int>((thumbArea.topLeft().y() + (thumbArea.height() * percent))) & ~1; + + // Paint. + const int indent = 2; + FloatRect tickRect(thumbArea.topLeft().x() + indent, yPos, thumbArea.width() - 2 * indent - 1, 2); + drawingContext->fillRect(tickRect); + drawingContext->strokeRect(tickRect, 1); + } + + drawingContext->restore(); + } + + if (hasThumb(scrollbar)) { + trackInfo.attributes |= (kThemeTrackShowThumb | kThemeTrackHideTrack); + HIThemeDrawTrack(&trackInfo, 0, drawingContext->platformContext(), kHIThemeOrientationNormal); + } + + if (!canDrawDirectly) { + context->drawImage(imageBuffer->image(), DeviceColorSpace, scrollbar->frameRect().location()); + } + + return true; +} + +} + diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h index 13641d2..a07daf2 100644 --- a/WebCore/platform/graphics/BitmapImage.h +++ b/WebCore/platform/graphics/BitmapImage.h @@ -140,8 +140,10 @@ public: virtual CGImageRef getCGImageRef(); #endif -#if PLATFORM(WIN) +#if PLATFORM(WIN) || (PLATFORM(QT) && PLATFORM(WIN_OS)) static PassRefPtr<BitmapImage> create(HBITMAP); +#endif +#if PLATFORM(WIN) virtual bool getHBITMAP(HBITMAP); virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE); #endif @@ -167,13 +169,13 @@ protected: BitmapImage(ImageObserver* = 0); #if PLATFORM(WIN) - virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator); + virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator); #endif - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); #if PLATFORM(WX) || (PLATFORM(WINCE) && !PLATFORM(QT)) virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect); #endif #if PLATFORM(HAIKU) diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h index 8e51b95..c348166 100644 --- a/WebCore/platform/graphics/Color.h +++ b/WebCore/platform/graphics/Color.h @@ -26,6 +26,7 @@ #ifndef Color_h #define Color_h +#include <wtf/FastAllocBase.h> #include <wtf/Platform.h> #if PLATFORM(CG) @@ -68,7 +69,7 @@ RGBA32 makeRGBAFromCMYKA(float c, float m, float y, float k, float a); int differenceSquared(const Color&, const Color&); -class Color { +class Color : public FastAllocBase { public: Color() : m_color(0), m_valid(false) { } Color(RGBA32 col) : m_color(col), m_valid(true) { } diff --git a/WebCore/platform/graphics/ColorSpace.h b/WebCore/platform/graphics/ColorSpace.h new file mode 100644 index 0000000..1bad58c --- /dev/null +++ b/WebCore/platform/graphics/ColorSpace.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 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. ``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 + * 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 ColorSpace_h +#define ColorSpace_h + +namespace WebCore { + + enum ColorSpace { DeviceColorSpace, sRGBColorSpace }; + +} // namespace WebCore + +#endif // ColorSpace_h diff --git a/WebCore/platform/graphics/FloatRect.cpp b/WebCore/platform/graphics/FloatRect.cpp index 532f719..7a54f21 100644 --- a/WebCore/platform/graphics/FloatRect.cpp +++ b/WebCore/platform/graphics/FloatRect.cpp @@ -102,12 +102,12 @@ void FloatRect::unite(const FloatRect& other) m_size.setHeight(b - t); } -void FloatRect::scale(float s) +void FloatRect::scale(float sx, float sy) { - m_location.setX(x() * s); - m_location.setY(y() * s); - m_size.setWidth(width() * s); - m_size.setHeight(height() * s); + m_location.setX(x() * sx); + m_location.setY(y() * sy); + m_size.setWidth(width() * sx); + m_size.setHeight(height() * sy); } IntRect enclosingIntRect(const FloatRect& rect) diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h index 50cb095..4b4694f 100644 --- a/WebCore/platform/graphics/FloatRect.h +++ b/WebCore/platform/graphics/FloatRect.h @@ -120,7 +120,8 @@ public: m_size.setHeight(m_size.height() + dy + dy); } void inflate(float d) { inflateX(d); inflateY(d); } - void scale(float s); + void scale(float s) { scale(s, s); } + void scale(float sx, float sy); #if PLATFORM(CG) FloatRect(const CGRect&); diff --git a/WebCore/platform/graphics/FontCache.h b/WebCore/platform/graphics/FontCache.h index b88305f..4a6222b 100644 --- a/WebCore/platform/graphics/FontCache.h +++ b/WebCore/platform/graphics/FontCache.h @@ -50,7 +50,7 @@ class FontDescription; class FontSelector; class SimpleFontData; -class FontCache { +class FontCache : public Noncopyable { public: friend FontCache* fontCache(); diff --git a/WebCore/platform/graphics/GeneratedImage.cpp b/WebCore/platform/graphics/GeneratedImage.cpp index bac9da0..eec7ffb 100644 --- a/WebCore/platform/graphics/GeneratedImage.cpp +++ b/WebCore/platform/graphics/GeneratedImage.cpp @@ -34,7 +34,7 @@ using namespace std; namespace WebCore { -void GeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp) +void GeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace, CompositeOperator compositeOp) { context->save(); context->setCompositeOperation(compositeOp); @@ -48,7 +48,7 @@ void GeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, co } void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator compositeOp, const FloatRect& destRect) + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator compositeOp, const FloatRect& destRect) { // Create a BitmapImage and call drawPattern on it. OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(m_size); @@ -62,7 +62,7 @@ void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcR Image* bitmap = imageBuffer->image(); // Now just call drawTiled on that image. - bitmap->drawPattern(context, srcRect, patternTransform, phase, compositeOp, destRect); + bitmap->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, compositeOp, destRect); } } diff --git a/WebCore/platform/graphics/GeneratedImage.h b/WebCore/platform/graphics/GeneratedImage.h index dea0c54..a4583e3 100644 --- a/WebCore/platform/graphics/GeneratedImage.h +++ b/WebCore/platform/graphics/GeneratedImage.h @@ -57,9 +57,9 @@ public: virtual unsigned decodedSize() const { return 0; } protected: - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect); GeneratedImage(PassRefPtr<Generator> generator, const IntSize& size) : m_generator(generator) diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp index ccdce08..fee05ee 100644 --- a/WebCore/platform/graphics/GraphicsContext.cpp +++ b/WebCore/platform/graphics/GraphicsContext.cpp @@ -120,24 +120,21 @@ void GraphicsContext::setStrokeStyle(const StrokeStyle& style) setPlatformStrokeStyle(style); } -void GraphicsContext::setStrokeColor(const Color& color) +void GraphicsContext::setStrokeColor(const Color& color, ColorSpace colorSpace) { - m_common->state.strokeColorSpace = SolidColorSpace; m_common->state.strokeColor = color; - setPlatformStrokeColor(color); + m_common->state.strokeColorSpace = colorSpace; + m_common->state.strokeGradient.clear(); + m_common->state.strokePattern.clear(); + setPlatformStrokeColor(color, colorSpace); } -ColorSpace GraphicsContext::strokeColorSpace() const -{ - return m_common->state.strokeColorSpace; -} - -void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color) +void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color, ColorSpace colorSpace) { m_common->state.shadowSize = size; m_common->state.shadowBlur = blur; m_common->state.shadowColor = color; - setPlatformShadow(size, blur, color); + setPlatformShadow(size, blur, color, colorSpace); } void GraphicsContext::clearShadow() @@ -172,6 +169,11 @@ Color GraphicsContext::strokeColor() const return m_common->state.strokeColor; } +ColorSpace GraphicsContext::strokeColorSpace() const +{ + return m_common->state.strokeColorSpace; +} + WindRule GraphicsContext::fillRule() const { return m_common->state.fillRule; @@ -182,11 +184,13 @@ void GraphicsContext::setFillRule(WindRule fillRule) m_common->state.fillRule = fillRule; } -void GraphicsContext::setFillColor(const Color& color) +void GraphicsContext::setFillColor(const Color& color, ColorSpace colorSpace) { - m_common->state.fillColorSpace = SolidColorSpace; m_common->state.fillColor = color; - setPlatformFillColor(color); + m_common->state.fillColorSpace = colorSpace; + m_common->state.fillGradient.clear(); + m_common->state.fillPattern.clear(); + setPlatformFillColor(color, colorSpace); } Color GraphicsContext::fillColor() const @@ -194,6 +198,11 @@ Color GraphicsContext::fillColor() const return m_common->state.fillColor; } +ColorSpace GraphicsContext::fillColorSpace() const +{ + return m_common->state.fillColorSpace; +} + void GraphicsContext::setShouldAntialias(bool b) { m_common->state.shouldAntialias = b; @@ -209,10 +218,10 @@ void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern) { ASSERT(pattern); if (!pattern) { - setStrokeColor(Color::black); + setStrokeColor(Color::black, DeviceColorSpace); return; } - m_common->state.strokeColorSpace = PatternColorSpace; + m_common->state.strokeGradient.clear(); m_common->state.strokePattern = pattern; setPlatformStrokePattern(m_common->state.strokePattern.get()); } @@ -221,10 +230,10 @@ void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern) { ASSERT(pattern); if (!pattern) { - setFillColor(Color::black); + setFillColor(Color::black, DeviceColorSpace); return; } - m_common->state.fillColorSpace = PatternColorSpace; + m_common->state.fillGradient.clear(); m_common->state.fillPattern = pattern; setPlatformFillPattern(m_common->state.fillPattern.get()); } @@ -233,11 +242,11 @@ void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient) { ASSERT(gradient); if (!gradient) { - setStrokeColor(Color::black); + setStrokeColor(Color::black, DeviceColorSpace); return; } - m_common->state.strokeColorSpace = GradientColorSpace; m_common->state.strokeGradient = gradient; + m_common->state.strokePattern.clear(); setPlatformStrokeGradient(m_common->state.strokeGradient.get()); } @@ -245,11 +254,11 @@ void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient) { ASSERT(gradient); if (!gradient) { - setFillColor(Color::black); + setFillColor(Color::black, DeviceColorSpace); return; } - m_common->state.fillColorSpace = GradientColorSpace; m_common->state.fillGradient = gradient; + m_common->state.fillPattern.clear(); setPlatformFillGradient(m_common->state.fillGradient.get()); } @@ -258,11 +267,6 @@ Gradient* GraphicsContext::fillGradient() const return m_common->state.fillGradient.get(); } -ColorSpace GraphicsContext::fillColorSpace() const -{ - return m_common->state.fillColorSpace; -} - Gradient* GraphicsContext::strokeGradient() const { return m_common->state.strokeGradient.get(); @@ -304,24 +308,24 @@ bool GraphicsContext::paintingDisabled() const return m_common->state.paintingDisabled; } -void GraphicsContext::drawImage(Image* image, const IntPoint& p, CompositeOperator op) +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op) { - drawImage(image, p, IntRect(0, 0, -1, -1), op); + drawImage(image, styleColorSpace, p, IntRect(0, 0, -1, -1), op); } -void GraphicsContext::drawImage(Image* image, const IntRect& r, CompositeOperator op, bool useLowQualityScale) +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, bool useLowQualityScale) { - drawImage(image, r, IntRect(0, 0, -1, -1), op, useLowQualityScale); + drawImage(image, styleColorSpace, r, IntRect(0, 0, -1, -1), op, useLowQualityScale); } -void GraphicsContext::drawImage(Image* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op) +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op) { - drawImage(image, IntRect(dest, srcRect.size()), srcRect, op); + drawImage(image, styleColorSpace, IntRect(dest, srcRect.size()), srcRect, op); } -void GraphicsContext::drawImage(Image* image, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale) +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale) { - drawImage(image, FloatRect(dest), srcRect, op, useLowQualityScale); + drawImage(image, styleColorSpace, FloatRect(dest), srcRect, op, useLowQualityScale); } #if !PLATFORM(WINCE) || PLATFORM(QT) @@ -370,12 +374,12 @@ void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const F bidiResolver.deleteRuns(); } -void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const IntPoint& point, int h, const Color& backgroundColor, int from, int to) +void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const IntPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to) { if (paintingDisabled()) return; - fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor); + fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor, colorSpace); } void GraphicsContext::initFocusRing(int width, int offset) @@ -427,7 +431,7 @@ const Vector<IntRect>& GraphicsContext::focusRingRects() const return m_common->m_focusRingRects; } -void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale) +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale) { if (paintingDisabled() || !image) return; @@ -451,29 +455,29 @@ void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const Float save(); setImageInterpolationQuality(InterpolationNone); } - image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op); + image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), styleColorSpace, op); if (useLowQualityScale) restore(); } -void GraphicsContext::drawTiledImage(Image* image, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op) +void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op) { if (paintingDisabled() || !image) return; - image->drawTiled(this, rect, srcPoint, tileSize, op); + image->drawTiled(this, rect, srcPoint, tileSize, styleColorSpace, op); } -void GraphicsContext::drawTiledImage(Image* image, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op) +void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op) { if (paintingDisabled() || !image) return; if (hRule == Image::StretchTile && vRule == Image::StretchTile) // Just do a scale. - return drawImage(image, dest, srcRect, op); + return drawImage(image, styleColorSpace, dest, srcRect, op); - image->drawTiled(this, dest, srcRect, hRule, vRule, op); + image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op); } void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h index 3ffc211..96a6221 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008-2009 Torch Mobile, Inc. * * Redistribution and use in source and binary forms, with or without @@ -27,6 +27,7 @@ #ifndef GraphicsContext_h #define GraphicsContext_h +#include "ColorSpace.h" #include "DashArray.h" #include "FloatRect.h" #include "Image.h" @@ -111,17 +112,17 @@ namespace WebCore { const int cMisspellingLinePatternWidth = 4; const int cMisspellingLinePatternGapWidth = 1; - class TransformationMatrix; class Font; class Generator; class Gradient; - class GraphicsContextPrivate; class GraphicsContextPlatformPrivate; + class GraphicsContextPrivate; class ImageBuffer; class KURL; class Path; class Pattern; class TextRun; + class TransformationMatrix; // These bits can be ORed together for a total of 8 possible text drawing modes. const int cTextInvisible = 0; @@ -136,18 +137,6 @@ namespace WebCore { DashedStroke }; - // FIXME: This is a place-holder until we decide to add - // real color space support to WebCore. At that time, ColorSpace will be a - // class and instances will be held off of Colors. There will be - // special singleton Gradient and Pattern color spaces to mark when - // a fill or stroke is using a gradient or pattern instead of a solid color. - // https://bugs.webkit.org/show_bug.cgi?id=20558 - enum ColorSpace { - SolidColorSpace, - PatternColorSpace, - GradientColorSpace - }; - enum InterpolationQuality { InterpolationDefault, InterpolationNone, @@ -170,9 +159,8 @@ namespace WebCore { StrokeStyle strokeStyle() const; void setStrokeStyle(const StrokeStyle& style); Color strokeColor() const; - void setStrokeColor(const Color&); - ColorSpace strokeColorSpace() const; + void setStrokeColor(const Color&, ColorSpace); void setStrokePattern(PassRefPtr<Pattern>); Pattern* strokePattern() const; @@ -183,7 +171,8 @@ namespace WebCore { WindRule fillRule() const; void setFillRule(WindRule); Color fillColor() const; - void setFillColor(const Color&); + ColorSpace fillColorSpace() const; + void setFillColor(const Color&, ColorSpace); void setFillPattern(PassRefPtr<Pattern>); Pattern* fillPattern() const; @@ -191,8 +180,6 @@ namespace WebCore { void setFillGradient(PassRefPtr<Gradient>); Gradient* fillGradient() const; - ColorSpace fillColorSpace() const; - void setShadowsIgnoreTransforms(bool); void setShouldAntialias(bool); @@ -250,24 +237,24 @@ namespace WebCore { void strokeArc(const IntRect&, int startAngle, int angleSpan); void fillRect(const FloatRect&); - void fillRect(const FloatRect&, const Color&); + void fillRect(const FloatRect&, const Color&, ColorSpace); void fillRect(const FloatRect&, Generator&); - void fillRoundedRect(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color&); + void fillRoundedRect(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color&, ColorSpace); void clearRect(const FloatRect&); void strokeRect(const FloatRect&); void strokeRect(const FloatRect&, float lineWidth); - void drawImage(Image*, const IntPoint&, CompositeOperator = CompositeSourceOver); - void drawImage(Image*, const IntRect&, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); - void drawImage(Image*, const IntPoint& destPoint, const IntRect& srcRect, CompositeOperator = CompositeSourceOver); - void drawImage(Image*, const IntRect& destRect, const IntRect& srcRect, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); - void drawImage(Image*, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1), + void drawImage(Image*, ColorSpace styleColorSpace, const IntPoint&, CompositeOperator = CompositeSourceOver); + void drawImage(Image*, ColorSpace styleColorSpace, const IntRect&, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); + void drawImage(Image*, ColorSpace styleColorSpace, const IntPoint& destPoint, const IntRect& srcRect, CompositeOperator = CompositeSourceOver); + void drawImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntRect& srcRect, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); + void drawImage(Image*, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1), CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); - void drawTiledImage(Image*, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, + void drawTiledImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator = CompositeSourceOver); - void drawTiledImage(Image*, const IntRect& destRect, const IntRect& srcRect, + void drawTiledImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntRect& srcRect, Image::TileRule hRule = Image::StretchTile, Image::TileRule vRule = Image::StretchTile, CompositeOperator = CompositeSourceOver); @@ -288,7 +275,7 @@ namespace WebCore { void drawText(const Font&, const TextRun&, const IntPoint&, int from = 0, int to = -1); void drawBidiText(const Font&, const TextRun&, const FloatPoint&); - void drawHighlightForText(const Font&, const TextRun&, const IntPoint&, int h, const Color& backgroundColor, int from = 0, int to = -1); + void drawHighlightForText(const Font&, const TextRun&, const IntPoint&, int h, const Color& backgroundColor, ColorSpace, int from = 0, int to = -1); FloatRect roundToDevicePixels(const FloatRect&); @@ -304,7 +291,7 @@ namespace WebCore { void beginTransparencyLayer(float opacity); void endTransparencyLayer(); - void setShadow(const IntSize&, int blur, const Color&); + void setShadow(const IntSize&, int blur, const Color&, ColorSpace); bool getShadow(IntSize&, int&, Color&) const; void clearShadow(); @@ -322,6 +309,8 @@ namespace WebCore { void setAlpha(float); #if PLATFORM(CAIRO) float getAlpha(); + void createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float kernelSize); + static void calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& kernelSize, const FloatRect& sourceRect, const IntSize& shadowSize, int shadowBlur); #endif void setCompositeOperation(CompositeOperator); @@ -405,12 +394,16 @@ namespace WebCore { void drawWindowsBitmap(WindowsBitmap*, const IntPoint&); #endif -#if PLATFORM(QT) && defined(Q_WS_WIN) +#if (PLATFORM(QT) && defined(Q_WS_WIN)) || (PLATFORM(WX) && PLATFORM(WIN_OS)) HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); bool shouldIncludeChildWindows() const { return false; } #endif +#if PLATFORM(WX) + bool inTransparencyLayer() const { return false; } +#endif + #if PLATFORM(QT) bool inTransparencyLayer() const; PlatformPath* currentPath(); @@ -434,19 +427,19 @@ namespace WebCore { void setPlatformTextDrawingMode(int); void setPlatformFont(const Font& font); - void setPlatformStrokeColor(const Color&); + void setPlatformStrokeColor(const Color&, ColorSpace); void setPlatformStrokeStyle(const StrokeStyle&); void setPlatformStrokeThickness(float); void setPlatformStrokeGradient(Gradient*); void setPlatformStrokePattern(Pattern*); - void setPlatformFillColor(const Color&); + void setPlatformFillColor(const Color&, ColorSpace); void setPlatformFillGradient(Gradient*); void setPlatformFillPattern(Pattern*); void setPlatformShouldAntialias(bool b); - void setPlatformShadow(const IntSize&, int blur, const Color&); + void setPlatformShadow(const IntSize&, int blur, const Color&, ColorSpace); void clearPlatformShadow(); static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, const StrokeStyle&); diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h index 07ec04d..aad8dd4 100644 --- a/WebCore/platform/graphics/GraphicsContext3D.h +++ b/WebCore/platform/graphics/GraphicsContext3D.h @@ -28,9 +28,15 @@ #include "PlatformString.h" +#include <wtf/ListHashSet.h> #include <wtf/Noncopyable.h> #include <wtf/PassOwnPtr.h> +// FIXME: Find a better way to avoid the name confliction for NO_ERROR. +#if PLATFORM(CHROMIUM) && PLATFORM(WIN_OS) +#undef NO_ERROR +#endif + #if PLATFORM(MAC) #include <OpenGL/OpenGL.h> @@ -46,20 +52,19 @@ const Platform3DObject NullPlatform3DObject = 0; #endif namespace WebCore { - class CanvasActiveInfo; - class CanvasArray; - class CanvasBuffer; - class CanvasUnsignedByteArray; - class CanvasFloatArray; - class CanvasFramebuffer; - class CanvasIntArray; - class CanvasProgram; - class CanvasRenderbuffer; - class CanvasRenderingContext3D; - class CanvasShader; - class CanvasTexture; - class HTMLCanvasElement; - class HTMLImageElement; + class WebGLActiveInfo; + class WebGLArray; + class WebGLBuffer; + class WebGLUnsignedByteArray; + class WebGLFloatArray; + class WebGLFramebuffer; + class WebGLIntArray; + class WebGLProgram; + class WebGLRenderbuffer; + class WebGLRenderingContext; + class WebGLShader; + class WebGLTexture; + class Image; class HTMLVideoElement; class ImageData; class WebKitCSSMatrix; @@ -77,8 +82,309 @@ namespace WebCore { class GraphicsContext3D : public Noncopyable { public: - enum ShaderType { FRAGMENT_SHADER, VERTEX_SHADER }; - + enum WebGLEnumType { + DEPTH_BUFFER_BIT = 0x00000100, + STENCIL_BUFFER_BIT = 0x00000400, + COLOR_BUFFER_BIT = 0x00004000, + POINTS = 0x0000, + LINES = 0x0001, + LINE_LOOP = 0x0002, + LINE_STRIP = 0x0003, + TRIANGLES = 0x0004, + TRIANGLE_STRIP = 0x0005, + TRIANGLE_FAN = 0x0006, + ZERO = 0, + ONE = 1, + SRC_COLOR = 0x0300, + ONE_MINUS_SRC_COLOR = 0x0301, + SRC_ALPHA = 0x0302, + ONE_MINUS_SRC_ALPHA = 0x0303, + DST_ALPHA = 0x0304, + ONE_MINUS_DST_ALPHA = 0x0305, + DST_COLOR = 0x0306, + ONE_MINUS_DST_COLOR = 0x0307, + SRC_ALPHA_SATURATE = 0x0308, + FUNC_ADD = 0x8006, + BLEND_EQUATION = 0x8009, + BLEND_EQUATION_RGB = 0x8009, + BLEND_EQUATION_ALPHA = 0x883D, + FUNC_SUBTRACT = 0x800A, + FUNC_REVERSE_SUBTRACT = 0x800B, + BLEND_DST_RGB = 0x80C8, + BLEND_SRC_RGB = 0x80C9, + BLEND_DST_ALPHA = 0x80CA, + BLEND_SRC_ALPHA = 0x80CB, + CONSTANT_COLOR = 0x8001, + ONE_MINUS_CONSTANT_COLOR = 0x8002, + CONSTANT_ALPHA = 0x8003, + ONE_MINUS_CONSTANT_ALPHA = 0x8004, + BLEND_COLOR = 0x8005, + ARRAY_BUFFER = 0x8892, + ELEMENT_ARRAY_BUFFER = 0x8893, + ARRAY_BUFFER_BINDING = 0x8894, + ELEMENT_ARRAY_BUFFER_BINDING = 0x8895, + STREAM_DRAW = 0x88E0, + STATIC_DRAW = 0x88E4, + DYNAMIC_DRAW = 0x88E8, + BUFFER_SIZE = 0x8764, + BUFFER_USAGE = 0x8765, + CURRENT_VERTEX_ATTRIB = 0x8626, + FRONT = 0x0404, + BACK = 0x0405, + FRONT_AND_BACK = 0x0408, + TEXTURE_2D = 0x0DE1, + CULL_FACE = 0x0B44, + BLEND = 0x0BE2, + DITHER = 0x0BD0, + STENCIL_TEST = 0x0B90, + DEPTH_TEST = 0x0B71, + SCISSOR_TEST = 0x0C11, + POLYGON_OFFSET_FILL = 0x8037, + SAMPLE_ALPHA_TO_COVERAGE = 0x809E, + SAMPLE_COVERAGE = 0x80A0, + NO_ERROR = 0, + INVALID_ENUM = 0x0500, + INVALID_VALUE = 0x0501, + INVALID_OPERATION = 0x0502, + OUT_OF_MEMORY = 0x0505, + CW = 0x0900, + CCW = 0x0901, + LINE_WIDTH = 0x0B21, + ALIASED_POINT_SIZE_RANGE = 0x846D, + ALIASED_LINE_WIDTH_RANGE = 0x846E, + CULL_FACE_MODE = 0x0B45, + FRONT_FACE = 0x0B46, + DEPTH_RANGE = 0x0B70, + DEPTH_WRITEMASK = 0x0B72, + DEPTH_CLEAR_VALUE = 0x0B73, + DEPTH_FUNC = 0x0B74, + STENCIL_CLEAR_VALUE = 0x0B91, + STENCIL_FUNC = 0x0B92, + STENCIL_FAIL = 0x0B94, + STENCIL_PASS_DEPTH_FAIL = 0x0B95, + STENCIL_PASS_DEPTH_PASS = 0x0B96, + STENCIL_REF = 0x0B97, + STENCIL_VALUE_MASK = 0x0B93, + STENCIL_WRITEMASK = 0x0B98, + STENCIL_BACK_FUNC = 0x8800, + STENCIL_BACK_FAIL = 0x8801, + STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802, + STENCIL_BACK_PASS_DEPTH_PASS = 0x8803, + STENCIL_BACK_REF = 0x8CA3, + STENCIL_BACK_VALUE_MASK = 0x8CA4, + STENCIL_BACK_WRITEMASK = 0x8CA5, + VIEWPORT = 0x0BA2, + SCISSOR_BOX = 0x0C10, + COLOR_CLEAR_VALUE = 0x0C22, + COLOR_WRITEMASK = 0x0C23, + UNPACK_ALIGNMENT = 0x0CF5, + PACK_ALIGNMENT = 0x0D05, + MAX_TEXTURE_SIZE = 0x0D33, + MAX_VIEWPORT_DIMS = 0x0D3A, + SUBPIXEL_BITS = 0x0D50, + RED_BITS = 0x0D52, + GREEN_BITS = 0x0D53, + BLUE_BITS = 0x0D54, + ALPHA_BITS = 0x0D55, + DEPTH_BITS = 0x0D56, + STENCIL_BITS = 0x0D57, + POLYGON_OFFSET_UNITS = 0x2A00, + POLYGON_OFFSET_FACTOR = 0x8038, + TEXTURE_BINDING_2D = 0x8069, + SAMPLE_BUFFERS = 0x80A8, + SAMPLES = 0x80A9, + SAMPLE_COVERAGE_VALUE = 0x80AA, + SAMPLE_COVERAGE_INVERT = 0x80AB, + NUM_COMPRESSED_TEXTURE_FORMATS = 0x86A2, + COMPRESSED_TEXTURE_FORMATS = 0x86A3, + DONT_CARE = 0x1100, + FASTEST = 0x1101, + NICEST = 0x1102, + GENERATE_MIPMAP_HINT = 0x8192, + BYTE = 0x1400, + UNSIGNED_BYTE = 0x1401, + SHORT = 0x1402, + UNSIGNED_SHORT = 0x1403, + INT = 0x1404, + UNSIGNED_INT = 0x1405, + FLOAT = 0x1406, + FIXED = 0x140C, + DEPTH_COMPONENT = 0x1902, + ALPHA = 0x1906, + RGB = 0x1907, + RGBA = 0x1908, + LUMINANCE = 0x1909, + LUMINANCE_ALPHA = 0x190A, + UNSIGNED_SHORT_4_4_4_4 = 0x8033, + UNSIGNED_SHORT_5_5_5_1 = 0x8034, + UNSIGNED_SHORT_5_6_5 = 0x8363, + FRAGMENT_SHADER = 0x8B30, + VERTEX_SHADER = 0x8B31, + MAX_VERTEX_ATTRIBS = 0x8869, + MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB, + MAX_VARYING_VECTORS = 0x8DFC, + MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D, + MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C, + MAX_TEXTURE_IMAGE_UNITS = 0x8872, + MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD, + SHADER_TYPE = 0x8B4F, + DELETE_STATUS = 0x8B80, + LINK_STATUS = 0x8B82, + VALIDATE_STATUS = 0x8B83, + ATTACHED_SHADERS = 0x8B85, + ACTIVE_UNIFORMS = 0x8B86, + ACTIVE_UNIFORM_MAX_LENGTH = 0x8B87, + ACTIVE_ATTRIBUTES = 0x8B89, + ACTIVE_ATTRIBUTE_MAX_LENGTH = 0x8B8A, + SHADING_LANGUAGE_VERSION = 0x8B8C, + CURRENT_PROGRAM = 0x8B8D, + NEVER = 0x0200, + LESS = 0x0201, + EQUAL = 0x0202, + LEQUAL = 0x0203, + GREATER = 0x0204, + NOTEQUAL = 0x0205, + GEQUAL = 0x0206, + ALWAYS = 0x0207, + KEEP = 0x1E00, + REPLACE = 0x1E01, + INCR = 0x1E02, + DECR = 0x1E03, + INVERT = 0x150A, + INCR_WRAP = 0x8507, + DECR_WRAP = 0x8508, + VENDOR = 0x1F00, + RENDERER = 0x1F01, + VERSION = 0x1F02, + EXTENSIONS = 0x1F03, + NEAREST = 0x2600, + LINEAR = 0x2601, + NEAREST_MIPMAP_NEAREST = 0x2700, + LINEAR_MIPMAP_NEAREST = 0x2701, + NEAREST_MIPMAP_LINEAR = 0x2702, + LINEAR_MIPMAP_LINEAR = 0x2703, + TEXTURE_MAG_FILTER = 0x2800, + TEXTURE_MIN_FILTER = 0x2801, + TEXTURE_WRAP_S = 0x2802, + TEXTURE_WRAP_T = 0x2803, + TEXTURE = 0x1702, + TEXTURE_CUBE_MAP = 0x8513, + TEXTURE_BINDING_CUBE_MAP = 0x8514, + TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515, + TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516, + TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517, + TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518, + TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519, + TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A, + MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C, + TEXTURE0 = 0x84C0, + TEXTURE1 = 0x84C1, + TEXTURE2 = 0x84C2, + TEXTURE3 = 0x84C3, + TEXTURE4 = 0x84C4, + TEXTURE5 = 0x84C5, + TEXTURE6 = 0x84C6, + TEXTURE7 = 0x84C7, + TEXTURE8 = 0x84C8, + TEXTURE9 = 0x84C9, + TEXTURE10 = 0x84CA, + TEXTURE11 = 0x84CB, + TEXTURE12 = 0x84CC, + TEXTURE13 = 0x84CD, + TEXTURE14 = 0x84CE, + TEXTURE15 = 0x84CF, + TEXTURE16 = 0x84D0, + TEXTURE17 = 0x84D1, + TEXTURE18 = 0x84D2, + TEXTURE19 = 0x84D3, + TEXTURE20 = 0x84D4, + TEXTURE21 = 0x84D5, + TEXTURE22 = 0x84D6, + TEXTURE23 = 0x84D7, + TEXTURE24 = 0x84D8, + TEXTURE25 = 0x84D9, + TEXTURE26 = 0x84DA, + TEXTURE27 = 0x84DB, + TEXTURE28 = 0x84DC, + TEXTURE29 = 0x84DD, + TEXTURE30 = 0x84DE, + TEXTURE31 = 0x84DF, + ACTIVE_TEXTURE = 0x84E0, + REPEAT = 0x2901, + CLAMP_TO_EDGE = 0x812F, + MIRRORED_REPEAT = 0x8370, + FLOAT_VEC2 = 0x8B50, + FLOAT_VEC3 = 0x8B51, + FLOAT_VEC4 = 0x8B52, + INT_VEC2 = 0x8B53, + INT_VEC3 = 0x8B54, + INT_VEC4 = 0x8B55, + BOOL = 0x8B56, + BOOL_VEC2 = 0x8B57, + BOOL_VEC3 = 0x8B58, + BOOL_VEC4 = 0x8B59, + FLOAT_MAT2 = 0x8B5A, + FLOAT_MAT3 = 0x8B5B, + FLOAT_MAT4 = 0x8B5C, + SAMPLER_2D = 0x8B5E, + SAMPLER_CUBE = 0x8B60, + VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622, + VERTEX_ATTRIB_ARRAY_SIZE = 0x8623, + VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624, + VERTEX_ATTRIB_ARRAY_TYPE = 0x8625, + VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A, + VERTEX_ATTRIB_ARRAY_POINTER = 0x8645, + VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F, + IMPLEMENTATION_COLOR_READ_TYPE = 0x8B9A, + IMPLEMENTATION_COLOR_READ_FORMAT = 0x8B9B, + COMPILE_STATUS = 0x8B81, + INFO_LOG_LENGTH = 0x8B84, + SHADER_SOURCE_LENGTH = 0x8B88, + SHADER_COMPILER = 0x8DFA, + SHADER_BINARY_FORMATS = 0x8DF8, + NUM_SHADER_BINARY_FORMATS = 0x8DF9, + LOW_FLOAT = 0x8DF0, + MEDIUM_FLOAT = 0x8DF1, + HIGH_FLOAT = 0x8DF2, + LOW_INT = 0x8DF3, + MEDIUM_INT = 0x8DF4, + HIGH_INT = 0x8DF5, + FRAMEBUFFER = 0x8D40, + RENDERBUFFER = 0x8D41, + RGBA4 = 0x8056, + RGB5_A1 = 0x8057, + RGB565 = 0x8D62, + DEPTH_COMPONENT16 = 0x81A5, + STENCIL_INDEX = 0x1901, + STENCIL_INDEX8 = 0x8D48, + RENDERBUFFER_WIDTH = 0x8D42, + RENDERBUFFER_HEIGHT = 0x8D43, + RENDERBUFFER_INTERNAL_FORMAT = 0x8D44, + RENDERBUFFER_RED_SIZE = 0x8D50, + RENDERBUFFER_GREEN_SIZE = 0x8D51, + RENDERBUFFER_BLUE_SIZE = 0x8D52, + RENDERBUFFER_ALPHA_SIZE = 0x8D53, + RENDERBUFFER_DEPTH_SIZE = 0x8D54, + RENDERBUFFER_STENCIL_SIZE = 0x8D55, + FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0, + FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1, + FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2, + FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3, + COLOR_ATTACHMENT0 = 0x8CE0, + DEPTH_ATTACHMENT = 0x8D00, + STENCIL_ATTACHMENT = 0x8D20, + NONE = 0, + FRAMEBUFFER_COMPLETE = 0x8CD5, + FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6, + FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7, + FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9, + FRAMEBUFFER_UNSUPPORTED = 0x8CDD, + FRAMEBUFFER_BINDING = 0x8CA6, + RENDERBUFFER_BINDING = 0x8CA7, + MAX_RENDERBUFFER_SIZE = 0x84E8, + INVALID_FRAMEBUFFER_OPERATION = 0x0506 + }; + static PassOwnPtr<GraphicsContext3D> create(); virtual ~GraphicsContext3D(); @@ -92,7 +398,6 @@ namespace WebCore { PlatformGraphicsContext3D platformGraphicsContext3D() const { return NullPlatformGraphicsContext3D; } Platform3DObject platformTexture() const { return NullPlatform3DObject; } #endif - void checkError() const; void makeContextCurrent(); // Helper to return the size in bytes of OpenGL data types @@ -100,12 +405,12 @@ namespace WebCore { int sizeInBytes(int type); void activeTexture(unsigned long texture); - void attachShader(CanvasProgram* program, CanvasShader* shader); - void bindAttribLocation(CanvasProgram*, unsigned long index, const String& name); - void bindBuffer(unsigned long target, CanvasBuffer*); - void bindFramebuffer(unsigned long target, CanvasFramebuffer*); - void bindRenderbuffer(unsigned long target, CanvasRenderbuffer*); - void bindTexture(unsigned long target, CanvasTexture* texture); + void attachShader(WebGLProgram* program, WebGLShader* shader); + void bindAttribLocation(WebGLProgram*, unsigned long index, const String& name); + void bindBuffer(unsigned long target, WebGLBuffer*); + void bindFramebuffer(unsigned long target, WebGLFramebuffer*); + void bindRenderbuffer(unsigned long target, WebGLRenderbuffer*); + void bindTexture(unsigned long target, WebGLTexture* texture); void blendColor(double red, double green, double blue, double alpha); void blendEquation(unsigned long mode); void blendEquationSeparate(unsigned long modeRGB, unsigned long modeAlpha); @@ -113,8 +418,8 @@ namespace WebCore { void blendFuncSeparate(unsigned long srcRGB, unsigned long dstRGB, unsigned long srcAlpha, unsigned long dstAlpha); void bufferData(unsigned long target, int size, unsigned long usage); - void bufferData(unsigned long target, CanvasArray* data, unsigned long usage); - void bufferSubData(unsigned long target, long offset, CanvasArray* data); + void bufferData(unsigned long target, WebGLArray* data, unsigned long usage); + void bufferSubData(unsigned long target, long offset, WebGLArray* data); unsigned long checkFramebufferStatus(unsigned long target); void clear(unsigned long mask); @@ -122,7 +427,7 @@ namespace WebCore { void clearDepth(double depth); void clearStencil(long s); void colorMask(bool red, bool green, bool blue, bool alpha); - void compileShader(CanvasShader*); + void compileShader(WebGLShader*); //void compressedTexImage2D(unsigned long target, long level, unsigned long internalformat, unsigned long width, unsigned long height, long border, unsigned long imageSize, const void* data); //void compressedTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, unsigned long width, unsigned long height, unsigned long format, unsigned long imageSize, const void* data); @@ -133,7 +438,7 @@ namespace WebCore { void depthFunc(unsigned long func); void depthMask(bool flag); void depthRange(double zNear, double zFar); - void detachShader(CanvasProgram*, CanvasShader*); + void detachShader(WebGLProgram*, WebGLShader*); void disable(unsigned long cap); void disableVertexAttribArray(unsigned long index); void drawArrays(unsigned long mode, long first, long count); @@ -143,84 +448,77 @@ namespace WebCore { void enableVertexAttribArray(unsigned long index); void finish(); void flush(); - void framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, CanvasRenderbuffer*); - void framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, CanvasTexture*, long level); + void framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, WebGLRenderbuffer*); + void framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, WebGLTexture*, long level); void frontFace(unsigned long mode); void generateMipmap(unsigned long target); - bool getActiveAttrib(CanvasProgram* program, unsigned long index, ActiveInfo&); - bool getActiveUniform(CanvasProgram* program, unsigned long index, ActiveInfo&); + bool getActiveAttrib(WebGLProgram* program, unsigned long index, ActiveInfo&); + bool getActiveUniform(WebGLProgram* program, unsigned long index, ActiveInfo&); - int getAttribLocation(CanvasProgram*, const String& name); + int getAttribLocation(WebGLProgram*, const String& name); - bool getBoolean(unsigned long pname); - PassRefPtr<CanvasUnsignedByteArray> getBooleanv(unsigned long pname); - int getBufferParameteri(unsigned long target, unsigned long pname); - PassRefPtr<CanvasIntArray> getBufferParameteriv(unsigned long target, unsigned long pname); + void getBooleanv(unsigned long pname, unsigned char* value); + + void getBufferParameteriv(unsigned long target, unsigned long pname, int* value); unsigned long getError(); - float getFloat(unsigned long pname); - PassRefPtr<CanvasFloatArray> getFloatv(unsigned long pname); - int getFramebufferAttachmentParameteri(unsigned long target, unsigned long attachment, unsigned long pname); - PassRefPtr<CanvasIntArray> getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname); - int getInteger(unsigned long pname); - PassRefPtr<CanvasIntArray> getIntegerv(unsigned long pname); - int getProgrami(CanvasProgram*, unsigned long pname); - PassRefPtr<CanvasIntArray> getProgramiv(CanvasProgram*, unsigned long pname); - String getProgramInfoLog(CanvasProgram*); - int getRenderbufferParameteri(unsigned long target, unsigned long pname); - PassRefPtr<CanvasIntArray> getRenderbufferParameteriv(unsigned long target, unsigned long pname); - int getShaderi(CanvasShader*, unsigned long pname); - PassRefPtr<CanvasIntArray> getShaderiv(CanvasShader*, unsigned long pname); - - String getShaderInfoLog(CanvasShader*); + void getFloatv(unsigned long pname, float* value); + + void getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname, int* value); + + void getIntegerv(unsigned long pname, int* value); + + void getProgramiv(WebGLProgram* program, unsigned long pname, int* value); + + String getProgramInfoLog(WebGLProgram*); + + void getRenderbufferParameteriv(unsigned long target, unsigned long pname, int* value); + + void getShaderiv(WebGLShader*, unsigned long pname, int* value); + + String getShaderInfoLog(WebGLShader*); // TBD // void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); - String getShaderSource(CanvasShader*); + String getShaderSource(WebGLShader*); String getString(unsigned long name); - - float getTexParameterf(unsigned long target, unsigned long pname); - PassRefPtr<CanvasFloatArray> getTexParameterfv(unsigned long target, unsigned long pname); - int getTexParameteri(unsigned long target, unsigned long pname); - PassRefPtr<CanvasIntArray> getTexParameteriv(unsigned long target, unsigned long pname); - - float getUniformf(CanvasProgram* program, long location); - PassRefPtr<CanvasFloatArray> getUniformfv(CanvasProgram* program, long location); - int getUniformi(CanvasProgram* program, long location); - PassRefPtr<CanvasIntArray> getUniformiv(CanvasProgram* program, long location); - - long getUniformLocation(CanvasProgram*, const String& name); - - float getVertexAttribf(unsigned long index, unsigned long pname); - PassRefPtr<CanvasFloatArray> getVertexAttribfv(unsigned long index, unsigned long pname); - int getVertexAttribi(unsigned long index, unsigned long pname); - PassRefPtr<CanvasIntArray> getVertexAttribiv(unsigned long index, unsigned long pname); - + + void getTexParameterfv(unsigned long target, unsigned long pname, float* value); + void getTexParameteriv(unsigned long target, unsigned long pname, int* value); + + void getUniformfv(WebGLProgram* program, long location, float* value); + void getUniformiv(WebGLProgram* program, long location, int* value); + + long getUniformLocation(WebGLProgram*, const String& name); + + void getVertexAttribfv(unsigned long index, unsigned long pname, float* value); + void getVertexAttribiv(unsigned long index, unsigned long pname, int* value); + long getVertexAttribOffset(unsigned long index, unsigned long pname); void hint(unsigned long target, unsigned long mode); - bool isBuffer(CanvasBuffer*); + bool isBuffer(WebGLBuffer*); bool isEnabled(unsigned long cap); - bool isFramebuffer(CanvasFramebuffer*); - bool isProgram(CanvasProgram*); - bool isRenderbuffer(CanvasRenderbuffer*); - bool isShader(CanvasShader*); - bool isTexture(CanvasTexture*); + bool isFramebuffer(WebGLFramebuffer*); + bool isProgram(WebGLProgram*); + bool isRenderbuffer(WebGLRenderbuffer*); + bool isShader(WebGLShader*); + bool isTexture(WebGLTexture*); void lineWidth(double); - void linkProgram(CanvasProgram*); + void linkProgram(WebGLProgram*); void pixelStorei(unsigned long pname, long param); void polygonOffset(double factor, double units); - PassRefPtr<CanvasArray> readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type); + PassRefPtr<WebGLArray> readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type); void releaseShaderCompiler(); void renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height); void sampleCoverage(double value, bool invert); void scissor(long x, long y, unsigned long width, unsigned long height); - void shaderSource(CanvasShader*, const String& string); + void shaderSource(WebGLShader*, const String& string); void stencilFunc(unsigned long func, long ref, unsigned long mask); void stencilFuncSeparate(unsigned long face, unsigned long func, long ref, unsigned long mask); void stencilMask(unsigned long mask); @@ -232,13 +530,11 @@ namespace WebCore { // Currently they return -1 on any error. int texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, - unsigned format, unsigned type, CanvasArray* pixels); + unsigned format, unsigned type, WebGLArray* pixels); int texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, ImageData* pixels); - int texImage2D(unsigned target, unsigned level, HTMLImageElement* image, - bool flipY, bool premultiplyAlpha); - int texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas, + int texImage2D(unsigned target, unsigned level, Image* image, bool flipY, bool premultiplyAlpha); int texImage2D(unsigned target, unsigned level, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha); @@ -248,15 +544,12 @@ namespace WebCore { int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, unsigned width, unsigned height, - unsigned format, unsigned type, CanvasArray* pixels); + unsigned format, unsigned type, WebGLArray* pixels); int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, unsigned width, unsigned height, unsigned format, unsigned type, ImageData* pixels); int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, - unsigned width, unsigned height, HTMLImageElement* image, - bool flipY, bool premultiplyAlpha); - int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, - unsigned width, unsigned height, HTMLCanvasElement* canvas, + unsigned width, unsigned height, Image* image, bool flipY, bool premultiplyAlpha); int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, unsigned width, unsigned height, HTMLVideoElement* video, @@ -282,8 +575,8 @@ namespace WebCore { void uniformMatrix3fv(long location, bool transpose, float* value, int size); void uniformMatrix4fv(long location, bool transpose, float* value, int size); - void useProgram(CanvasProgram*); - void validateProgram(CanvasProgram*); + void useProgram(WebGLProgram*); + void validateProgram(WebGLProgram*); void vertexAttrib1f(unsigned long indx, float x); void vertexAttrib1fv(unsigned long indx, float* values); @@ -301,7 +594,7 @@ namespace WebCore { void reshape(int width, int height); // Helpers for notification about paint events - void beginPaint(CanvasRenderingContext3D* context); + void beginPaint(WebGLRenderingContext* context); void endPaint(); // Support for buffer creation and deletion @@ -309,7 +602,7 @@ namespace WebCore { unsigned createFramebuffer(); unsigned createProgram(); unsigned createRenderbuffer(); - unsigned createShader(ShaderType); + unsigned createShader(unsigned long); unsigned createTexture(); void deleteBuffer(unsigned); @@ -319,6 +612,16 @@ namespace WebCore { void deleteShader(unsigned); void deleteTexture(unsigned); + // Synthesizes an OpenGL error which will be returned from a + // later call to getError. This is used to emulate OpenGL ES + // 2.0 behavior on the desktop and to enforce additional error + // checking mandated by WebGL. + // + // Per the behavior of glGetError, this stores at most one + // instance of any given error, and returns them from calls to + // getError in the order they were added. + void synthesizeGLError(unsigned long error); + private: GraphicsContext3D(); @@ -331,6 +634,8 @@ namespace WebCore { GLuint m_texture; GLuint m_fbo; GLuint m_depthBuffer; + // Errors raised by synthesizeGLError(). + ListHashSet<unsigned long> m_syntheticErrors; #endif // FIXME: ideally this would be used on all platforms. @@ -343,4 +648,3 @@ namespace WebCore { } // namespace WebCore #endif // GraphicsContext3D_h - diff --git a/WebCore/platform/graphics/GraphicsContextPrivate.h b/WebCore/platform/graphics/GraphicsContextPrivate.h index 98baab1..c532162 100644 --- a/WebCore/platform/graphics/GraphicsContextPrivate.h +++ b/WebCore/platform/graphics/GraphicsContextPrivate.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,10 +26,10 @@ #ifndef GraphicsContextPrivate_h #define GraphicsContextPrivate_h -#include "TransformationMatrix.h" #include "Gradient.h" #include "GraphicsContext.h" #include "Pattern.h" +#include "TransformationMatrix.h" namespace WebCore { @@ -38,18 +38,18 @@ namespace WebCore { : textDrawingMode(cTextFill) , strokeStyle(SolidStroke) , strokeThickness(0) -#if PLATFORM(CAIRO) - , globalAlpha(1.0f) -#endif - , strokeColorSpace(SolidColorSpace) , strokeColor(Color::black) + , strokeColorSpace(DeviceColorSpace) , fillRule(RULE_NONZERO) - , fillColorSpace(SolidColorSpace) , fillColor(Color::black) + , fillColorSpace(DeviceColorSpace) , shouldAntialias(true) , paintingDisabled(false) , shadowBlur(0) , shadowsIgnoreTransforms(false) +#if PLATFORM(CAIRO) + , globalAlpha(1.0f) +#endif { } @@ -57,19 +57,14 @@ namespace WebCore { StrokeStyle strokeStyle; float strokeThickness; -#if PLATFORM(CAIRO) - float globalAlpha; -#elif PLATFORM(QT) - TransformationMatrix pathTransform; -#endif - ColorSpace strokeColorSpace; Color strokeColor; + ColorSpace strokeColorSpace; RefPtr<Gradient> strokeGradient; RefPtr<Pattern> strokePattern; WindRule fillRule; - ColorSpace fillColorSpace; Color fillColor; + ColorSpace fillColorSpace; RefPtr<Gradient> fillGradient; RefPtr<Pattern> fillPattern; @@ -82,9 +77,14 @@ namespace WebCore { Color shadowColor; bool shadowsIgnoreTransforms; +#if PLATFORM(CAIRO) + float globalAlpha; +#elif PLATFORM(QT) + TransformationMatrix pathTransform; +#endif }; - class GraphicsContextPrivate { + class GraphicsContextPrivate : public Noncopyable { public: GraphicsContextPrivate() : m_focusRingWidth(0) diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp index c8582bb..e215097 100644 --- a/WebCore/platform/graphics/GraphicsLayer.cpp +++ b/WebCore/platform/graphics/GraphicsLayer.cpp @@ -92,6 +92,21 @@ bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const return false; } +bool GraphicsLayer::setChildren(const Vector<GraphicsLayer*>& newChildren) +{ + // If the contents of the arrays are the same, nothing to do. + if (newChildren == m_children) + return false; + + removeAllChildren(); + + size_t listSize = newChildren.size(); + for (size_t i = 0; i < listSize; ++i) + addChild(newChildren[i]); + + return true; +} + void GraphicsLayer::addChild(GraphicsLayer* childLayer) { ASSERT(childLayer != this); diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h index 85eace0..0456bad 100644 --- a/WebCore/platform/graphics/GraphicsLayer.h +++ b/WebCore/platform/graphics/GraphicsLayer.h @@ -53,6 +53,12 @@ typedef CALayer* NativeLayer; typedef void* PlatformLayer; typedef void* NativeLayer; #endif +#elif PLATFORM(WIN) +namespace WebCore { +class WKCACFLayer; +typedef WKCACFLayer PlatformLayer; +typedef void* NativeLayer; +} #else typedef void* PlatformLayer; typedef void* NativeLayer; @@ -176,6 +182,8 @@ public: bool hasAncestor(GraphicsLayer*) const; const Vector<GraphicsLayer*>& children() const { return m_children; } + // Returns true if the child list changed. + virtual bool setChildren(const Vector<GraphicsLayer*>&); // Add child layers. If the child is already parented, it will be removed from its old parent. virtual void addChild(GraphicsLayer*); @@ -292,8 +300,8 @@ public: virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation) { m_contentsOrientation = orientation; } CompositingCoordinatesOrientation contentsOrientation() const { return m_contentsOrientation; } - static bool showDebugBorders(); - static bool showRepaintCounter(); + bool showDebugBorders() { return m_client ? m_client->showDebugBorders() : false; } + bool showRepaintCounter() { return m_client ? m_client->showRepaintCounter() : false; } void updateDebugIndicators(); diff --git a/WebCore/platform/graphics/GraphicsLayerClient.h b/WebCore/platform/graphics/GraphicsLayerClient.h index 5facc94..afb297d 100644 --- a/WebCore/platform/graphics/GraphicsLayerClient.h +++ b/WebCore/platform/graphics/GraphicsLayerClient.h @@ -62,6 +62,9 @@ public: virtual void notifySyncRequired(const GraphicsLayer*) = 0; virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) = 0; + + virtual bool showDebugBorders() const = 0; + virtual bool showRepaintCounter() const = 0; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/Icon.h b/WebCore/platform/graphics/Icon.h index 444c67c..d7d694a 100644 --- a/WebCore/platform/graphics/Icon.h +++ b/WebCore/platform/graphics/Icon.h @@ -51,7 +51,6 @@ class String; class Icon : public RefCounted<Icon> { public: - static PassRefPtr<Icon> createIconForFile(const String& filename); static PassRefPtr<Icon> createIconForFiles(const Vector<String>& filenames); ~Icon(); diff --git a/WebCore/platform/graphics/Image.cpp b/WebCore/platform/graphics/Image.cpp index 80b5457..611216a 100644 --- a/WebCore/platform/graphics/Image.cpp +++ b/WebCore/platform/graphics/Image.cpp @@ -75,14 +75,14 @@ bool Image::setData(PassRefPtr<SharedBuffer> data, bool allDataReceived) return dataChanged(allDataReceived); } -void Image::fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, CompositeOperator op) +void Image::fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, ColorSpace styleColorSpace, CompositeOperator op) { if (color.alpha() <= 0) return; ctxt->save(); ctxt->setCompositeOperation(!color.hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); - ctxt->fillRect(dstRect, color); + ctxt->fillRect(dstRect, color, styleColorSpace); ctxt->restore(); } @@ -104,10 +104,10 @@ static inline FloatSize calculatePatternScale(const FloatRect& dstRect, const Fl } -void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, CompositeOperator op) +void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, ColorSpace styleColorSpace, CompositeOperator op) { if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, destRect, solidColor(), op); + fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, op); return; } @@ -132,22 +132,22 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const Fl visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height()); visibleSrcRect.setWidth(destRect.width() / scale.width()); visibleSrcRect.setHeight(destRect.height() / scale.height()); - draw(ctxt, destRect, visibleSrcRect, op); + draw(ctxt, destRect, visibleSrcRect, styleColorSpace, op); return; } TransformationMatrix patternTransform = TransformationMatrix().scaleNonUniform(scale.width(), scale.height()); FloatRect tileRect(FloatPoint(), intrinsicTileSize); - drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), op, destRect); + drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), styleColorSpace, op, destRect); startAnimation(); } // FIXME: Merge with the other drawTiled eventually, since we need a combination of both for some things. -void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, CompositeOperator op) +void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, ColorSpace styleColorSpace, CompositeOperator op) { if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, dstRect, solidColor(), op); + fillWithSolidColor(ctxt, dstRect, solidColor(), styleColorSpace, op); return; } @@ -170,7 +170,7 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const Flo vPhase -= fmodf(dstRect.height(), scale.height() * srcRect.height()) / 2.0f; FloatPoint patternPhase(dstRect.x() - hPhase, dstRect.y() - vPhase); - drawPattern(ctxt, srcRect, patternTransform, patternPhase, op, dstRect); + drawPattern(ctxt, srcRect, patternTransform, patternPhase, styleColorSpace, op, dstRect); startAnimation(); } diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h index 294ddf6..aef6577 100644 --- a/WebCore/platform/graphics/Image.h +++ b/WebCore/platform/graphics/Image.h @@ -28,6 +28,7 @@ #define Image_h #include "Color.h" +#include "ColorSpace.h" #include "GraphicsTypes.h" #include "ImageSource.h" #include "IntRect.h" @@ -158,21 +159,22 @@ public: protected: Image(ImageObserver* = 0); - static void fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, CompositeOperator op); + static void fillWithSolidColor(GraphicsContext*, const FloatRect& dstRect, const Color&, ColorSpace styleColorSpace, CompositeOperator); + // The ColorSpace parameter will only be used for untagged images. #if PLATFORM(WIN) - virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator) { } + virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator) { } #endif - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator) = 0; - void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatPoint& srcPoint, const FloatSize& tileSize, CompositeOperator); - void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator) = 0; + void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatPoint& srcPoint, const FloatSize& tileSize, ColorSpace styleColorSpace, CompositeOperator); + void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, ColorSpace styleColorSpace, CompositeOperator); // Supporting tiled drawing virtual bool mayFillWithSolidColor() { return false; } virtual Color solidColor() const { return Color(); } virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect); private: RefPtr<SharedBuffer> m_data; // The encoded raw data for the image. diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp index b64f82b..4c66c50 100644 --- a/WebCore/platform/graphics/MediaPlayer.cpp +++ b/WebCore/platform/graphics/MediaPlayer.cpp @@ -91,6 +91,9 @@ public: virtual void setVolume(float) { } + virtual bool hasClosedCaptions() const { return false; } + virtual void setClosedCaptionsVisible(bool) { }; + virtual MediaPlayer::NetworkState networkState() const { return MediaPlayer::Empty; } virtual MediaPlayer::ReadyState readyState() const { return MediaPlayer::HaveNothing; } @@ -126,7 +129,7 @@ static MediaPlayerPrivateInterface* createNullMediaPlayer(MediaPlayer* player) // engine support -struct MediaPlayerFactory { +struct MediaPlayerFactory : Noncopyable { MediaPlayerFactory(CreateMediaEnginePlayer constructor, MediaEngineSupportedTypes getSupportedTypes, MediaEngineSupportsType supportsTypeAndCodecs) : constructor(constructor) , getSupportedTypes(getSupportedTypes) @@ -377,6 +380,16 @@ void MediaPlayer::setVolume(float volume) m_private->setVolume(volume); } +bool MediaPlayer::hasClosedCaptions() const +{ + return m_private->hasClosedCaptions(); +} + +void MediaPlayer::setClosedCaptionsVisible(bool closedCaptionsVisible) +{ + m_private->setClosedCaptionsVisible(closedCaptionsVisible); +} + float MediaPlayer::rate() const { return m_rate; diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h index 4cc6476..ec8ac33 100644 --- a/WebCore/platform/graphics/MediaPlayer.h +++ b/WebCore/platform/graphics/MediaPlayer.h @@ -37,6 +37,7 @@ #include <wtf/HashSet.h> #include <wtf/OwnPtr.h> #include <wtf/Noncopyable.h> +#include <wtf/PassOwnPtr.h> #ifdef __OBJC__ @class QTMovie; @@ -115,7 +116,11 @@ public: class MediaPlayer : public Noncopyable { public: - MediaPlayer(MediaPlayerClient*); + + static PassOwnPtr<MediaPlayer> create(MediaPlayerClient* client) + { + return new MediaPlayer(client); + } virtual ~MediaPlayer(); // media engine support @@ -175,7 +180,10 @@ public: float volume() const; void setVolume(float); - + + bool hasClosedCaptions() const; + void setClosedCaptionsVisible(bool closedCaptionsVisible); + int dataRate() const; bool autobuffer() const; @@ -223,6 +231,8 @@ public: bool hasSingleSecurityOrigin() const; private: + MediaPlayer(MediaPlayerClient*); + static void initializeMediaEngines(); MediaPlayerClient* m_mediaPlayerClient; diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h index f5687b3..03906bd 100644 --- a/WebCore/platform/graphics/MediaPlayerPrivate.h +++ b/WebCore/platform/graphics/MediaPlayerPrivate.h @@ -36,7 +36,7 @@ class IntRect; class IntSize; class String; -class MediaPlayerPrivateInterface { +class MediaPlayerPrivateInterface : public Noncopyable { public: virtual ~MediaPlayerPrivateInterface() { } @@ -76,6 +76,9 @@ public: virtual void setVolume(float) = 0; + virtual bool hasClosedCaptions() const { return false; } + virtual void setClosedCaptionsVisible(bool) { } + virtual MediaPlayer::NetworkState networkState() const = 0; virtual MediaPlayer::ReadyState readyState() const = 0; diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h index 6b617a0..fef5ad2 100644 --- a/WebCore/platform/graphics/Path.h +++ b/WebCore/platform/graphics/Path.h @@ -29,6 +29,7 @@ #define Path_h #include <algorithm> +#include <wtf/FastAllocBase.h> #if PLATFORM(CG) typedef struct CGPath PlatformPath; @@ -93,7 +94,7 @@ namespace WebCore { typedef void (*PathApplierFunction)(void* info, const PathElement*); - class Path { + class Path : public FastAllocBase { public: Path(); ~Path(); diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp index 1a951c2..3bfa8f3 100644 --- a/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -32,6 +32,7 @@ #include "GlyphBuffer.h" #include "Gradient.h" #include "GraphicsContext.h" +#include "ImageBuffer.h" #include "Pattern.h" #include "SimpleFontData.h" #include "TransformationMatrix.h" @@ -85,6 +86,34 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons shadowFillColor.getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha); +#if ENABLE(FILTERS) + cairo_text_extents_t extents; + cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents); + + FloatRect rect(FloatPoint(), FloatSize(extents.width, extents.height)); + IntSize shadowBufferSize; + FloatRect shadowRect; + float kernelSize = 0.f; + GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur); + + // Draw shadow into a new ImageBuffer + OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); + GraphicsContext* shadowContext = shadowBuffer->context(); + cairo_t* shadowCr = shadowContext->platformContext(); + + cairo_translate(shadowCr, kernelSize, extents.height + kernelSize); + + cairo_set_scaled_font(shadowCr, font->platformData().scaledFont()); + cairo_show_glyphs(shadowCr, glyphs, numGlyphs); + if (font->syntheticBoldOffset()) { + cairo_save(shadowCr); + cairo_translate(shadowCr, font->syntheticBoldOffset(), 0); + cairo_show_glyphs(shadowCr, glyphs, numGlyphs); + cairo_restore(shadowCr); + } + cairo_translate(cr, 0.0, -extents.height); + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); +#else cairo_translate(cr, shadowSize.width(), shadowSize.height()); cairo_show_glyphs(cr, glyphs, numGlyphs); if (font->syntheticBoldOffset()) { @@ -93,6 +122,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons cairo_show_glyphs(cr, glyphs, numGlyphs); cairo_restore(cr); } +#endif cairo_restore(cr); } @@ -156,7 +186,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons // Re-enable the platform shadow we disabled earlier if (hasShadow) - context->setShadow(shadowSize, shadowBlur, shadowColor); + context->setShadow(shadowSize, shadowBlur, shadowColor, DeviceColorSpace); cairo_restore(cr); } diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 8741c5e..14034fd 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -1,8 +1,9 @@ /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. * Copyright (C) 2007 Alp Toker <alp@atoker.com> - * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de> + * Copyright (C) 2008, 2009 Dirk Schulze <krit@webkit.org> * Copyright (C) 2008 Nuanti Ltd. + * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,14 +33,17 @@ #if PLATFORM(CAIRO) #include "CairoPath.h" +#include "FEGaussianBlur.h" #include "FloatRect.h" #include "Font.h" #include "ImageBuffer.h" +#include "ImageBufferFilter.h" #include "IntRect.h" #include "NotImplemented.h" #include "Path.h" #include "Pattern.h" #include "SimpleFontData.h" +#include "SourceGraphic.h" #include "TransformationMatrix.h" #include <cairo.h> @@ -69,6 +73,42 @@ static inline void setColor(cairo_t* cr, const Color& col) cairo_set_source_rgba(cr, red, green, blue, alpha); } +static inline void setPlatformFill(GraphicsContext* context, cairo_t* cr, GraphicsContextPrivate* gcp) +{ + cairo_save(cr); + if (gcp->state.fillPattern) { + TransformationMatrix affine; + cairo_set_source(cr, gcp->state.fillPattern->createPlatformPattern(affine)); + } else if (gcp->state.fillGradient) + cairo_set_source(cr, gcp->state.fillGradient->platformGradient()); + else + setColor(cr, context->fillColor()); + cairo_clip_preserve(cr); + cairo_paint_with_alpha(cr, gcp->state.globalAlpha); + cairo_restore(cr); +} + +static inline void setPlatformStroke(GraphicsContext* context, cairo_t* cr, GraphicsContextPrivate* gcp) +{ + cairo_save(cr); + if (gcp->state.strokePattern) { + TransformationMatrix affine; + cairo_set_source(cr, gcp->state.strokePattern->createPlatformPattern(affine)); + } else if (gcp->state.strokeGradient) + cairo_set_source(cr, gcp->state.strokeGradient->platformGradient()); + else { + Color strokeColor = colorWithOverrideAlpha(context->strokeColor().rgb(), context->strokeColor().alpha() / 255.f * gcp->state.globalAlpha); + setColor(cr, strokeColor); + } + if (gcp->state.globalAlpha < 1.0f && (gcp->state.strokePattern || gcp->state.strokeGradient)) { + cairo_push_group(cr); + cairo_paint_with_alpha(cr, gcp->state.globalAlpha); + cairo_pop_group_to_source(cr); + } + cairo_stroke_preserve(cr); + cairo_restore(cr); +} + // A fillRect helper static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const Color& col) { @@ -78,6 +118,81 @@ static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const cairo_fill(cr); } +static inline void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr) +{ + cairo_set_antialias(dstCr, cairo_get_antialias(srcCr)); + + size_t dashCount = cairo_get_dash_count(srcCr); + Vector<double> dashes(dashCount); + + double offset; + cairo_get_dash(srcCr, dashes.data(), &offset); + cairo_set_dash(dstCr, dashes.data(), dashCount, offset); + cairo_set_line_cap(dstCr, cairo_get_line_cap(srcCr)); + cairo_set_line_join(dstCr, cairo_get_line_join(srcCr)); + cairo_set_line_width(dstCr, cairo_get_line_width(srcCr)); + cairo_set_miter_limit(dstCr, cairo_get_miter_limit(srcCr)); + cairo_set_fill_rule(dstCr, cairo_get_fill_rule(srcCr)); +} + +void GraphicsContext::calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& kernelSize, const FloatRect& sourceRect, const IntSize& shadowSize, int shadowBlur) +{ +#if ENABLE(FILTERS) + // calculate the kernel size according to the HTML5 canvas shadow specification + kernelSize = (shadowBlur < 8 ? shadowBlur / 2.f : sqrt(shadowBlur * 2.f)); + int blurRadius = ceil(kernelSize); + + shadowBufferSize = IntSize(sourceRect.width() + blurRadius * 2, sourceRect.height() + blurRadius * 2); + + // determine dimensions of shadow rect + shadowRect = FloatRect(sourceRect.location(), shadowBufferSize); + shadowRect.move(shadowSize.width() - kernelSize, shadowSize.height() - kernelSize); +#endif +} + +static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPrivate* gcp, bool fillShadow, bool strokeShadow) +{ +#if ENABLE(FILTERS) + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (!context->getShadow(shadowSize, shadowBlur, shadowColor)) + return; + + // Calculate filter values to create appropriate shadow. + cairo_t* cr = context->platformContext(); + cairo_path_t* path = cairo_copy_path(cr); + double x0, x1, y0, y1; + if (strokeShadow) + cairo_stroke_extents(cr, &x0, &y0, &x1, &y1); + else + cairo_fill_extents(cr, &x0, &y0, &x1, &y1); + FloatRect rect(x0, y0, x1 - x0, y1 - y0); + + IntSize shadowBufferSize; + FloatRect shadowRect; + float kernelSize = 0; + GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur); + + // Create suitably-sized ImageBuffer to hold the shadow. + OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); + + // Draw shadow into a new ImageBuffer. + cairo_t* shadowContext = shadowBuffer->context()->platformContext(); + copyContextProperties(cr, shadowContext); + cairo_translate(shadowContext, -rect.x() + kernelSize, -rect.y() + kernelSize); + cairo_new_path(shadowContext); + cairo_append_path(shadowContext, path); + + if (fillShadow) + setPlatformFill(context, shadowContext, gcp); + if (strokeShadow) + setPlatformStroke(context, shadowContext, gcp); + + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); +#endif +} + GraphicsContext::GraphicsContext(PlatformGraphicsContext* cr) : m_common(createGraphicsContextPrivate()) , m_data(new GraphicsContextPlatformPrivate) @@ -387,30 +502,12 @@ void GraphicsContext::fillPath() return; cairo_t* cr = m_data->cr; - cairo_save(cr); cairo_set_fill_rule(cr, fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - setColor(cr, fillColor()); - cairo_clip(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - break; - case PatternColorSpace: { - TransformationMatrix affine; - cairo_set_source(cr, m_common->state.fillPattern->createPlatformPattern(affine)); - cairo_clip(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - break; - } - case GradientColorSpace: - cairo_pattern_t* pattern = m_common->state.fillGradient->platformGradient(); - cairo_set_source(cr, pattern); - cairo_clip(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - break; - } - cairo_restore(cr); + drawPathShadow(this, m_common, true, false); + + setPlatformFill(this, cr, m_common); + cairo_new_path(cr); } void GraphicsContext::strokePath() @@ -419,45 +516,26 @@ void GraphicsContext::strokePath() return; cairo_t* cr = m_data->cr; - cairo_save(cr); - switch (m_common->state.strokeColorSpace) { - case SolidColorSpace: - float red, green, blue, alpha; - strokeColor().getRGBA(red, green, blue, alpha); - if (m_common->state.globalAlpha < 1.0f) - alpha *= m_common->state.globalAlpha; - cairo_set_source_rgba(cr, red, green, blue, alpha); - cairo_stroke(cr); - break; - case PatternColorSpace: { - TransformationMatrix affine; - cairo_set_source(cr, m_common->state.strokePattern->createPlatformPattern(affine)); - if (m_common->state.globalAlpha < 1.0f) { - cairo_push_group(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - cairo_pop_group_to_source(cr); - } - cairo_stroke(cr); - break; - } - case GradientColorSpace: - cairo_pattern_t* pattern = m_common->state.strokeGradient->platformGradient(); - cairo_set_source(cr, pattern); - if (m_common->state.globalAlpha < 1.0f) { - cairo_push_group(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - cairo_pop_group_to_source(cr); - } - cairo_stroke(cr); - break; - } - cairo_restore(cr); + drawPathShadow(this, m_common, false, true); + + setPlatformStroke(this, cr, m_common); + cairo_new_path(cr); + } void GraphicsContext::drawPath() { - fillPath(); - strokePath(); + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + + cairo_set_fill_rule(cr, fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); + drawPathShadow(this, m_common, true, true); + + setPlatformFill(this, cr, m_common); + setPlatformStroke(this, cr, m_common); + cairo_new_path(cr); } void GraphicsContext::fillRect(const FloatRect& rect) @@ -470,11 +548,36 @@ void GraphicsContext::fillRect(const FloatRect& rect) fillPath(); } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +static void drawBorderlessRectShadow(GraphicsContext* context, const FloatRect& rect, const Color& rectColor) +{ +#if ENABLE(FILTERS) + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + + if (!context->getShadow(shadowSize, shadowBlur, shadowColor)) + return; + + IntSize shadowBufferSize; + FloatRect shadowRect; + float kernelSize = 0; + GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur); + + // Draw shadow into a new ImageBuffer + OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); + GraphicsContext* shadowContext = shadowBuffer->context(); + shadowContext->fillRect(FloatRect(FloatPoint(kernelSize, kernelSize), rect.size()), rectColor, DeviceColorSpace); + + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); +#endif +} + +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; + drawBorderlessRectShadow(this, rect, color); if (color.alpha()) fillRectSourceOver(m_data->cr, rect, color); } @@ -634,13 +737,13 @@ IntPoint GraphicsContext::origin() return IntPoint(static_cast<int>(matrix.x0), static_cast<int>(matrix.y0)); } -void GraphicsContext::setPlatformFillColor(const Color& col) +void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace) { // Cairo contexts can't hold separate fill and stroke colors // so we set them just before we actually fill or stroke } -void GraphicsContext::setPlatformStrokeColor(const Color& col) +void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace) { // Cairo contexts can't hold separate fill and stroke colors // so we set them just before we actually fill or stroke @@ -726,9 +829,48 @@ void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer notImplemented(); } -void GraphicsContext::setPlatformShadow(IntSize const&, int, Color const&) +void GraphicsContext::setPlatformShadow(IntSize const& size, int, Color const&, ColorSpace) { - notImplemented(); + // Cairo doesn't support shadows natively, they are drawn manually in the draw* + // functions + + if (m_common->state.shadowsIgnoreTransforms) { + // Meaning that this graphics context is associated with a CanvasRenderingContext + // We flip the height since CG and HTML5 Canvas have opposite Y axis + m_common->state.shadowSize = IntSize(size.width(), -size.height()); + } +} + +void GraphicsContext::createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float kernelSize) +{ +#if ENABLE(FILTERS) + cairo_t* cr = m_data->cr; + + // draw the shadow without blurring, if kernelSize is zero + if (!kernelSize) { + setColor(cr, shadowColor); + cairo_mask_surface(cr, buffer->image()->nativeImageForCurrentFrame(), shadowRect.x(), shadowRect.y()); + return; + } + + // limit kernel size to 1000, this is what CG is doing. + kernelSize = std::min(1000.f, kernelSize); + + // create filter + RefPtr<Filter> filter = ImageBufferFilter::create(); + filter->setSourceImage(buffer.release()); + RefPtr<FilterEffect> source = SourceGraphic::create(); + source->setScaledSubRegion(FloatRect(FloatPoint(), shadowRect.size())); + source->setIsAlphaImage(true); + RefPtr<FilterEffect> blur = FEGaussianBlur::create(source.get(), kernelSize, kernelSize); + blur->setScaledSubRegion(FloatRect(FloatPoint(), shadowRect.size())); + blur->apply(filter.get()); + + // Mask the filter with the shadow color and draw it to the context. + // Masking makes it possible to just blur the alpha channel. + setColor(cr, shadowColor); + cairo_mask_surface(cr, blur->resultImage()->image()->nativeImageForCurrentFrame(), shadowRect.x(), shadowRect.y()); +#endif } void GraphicsContext::clearPlatformShadow() @@ -941,7 +1083,6 @@ void GraphicsContext::clipOut(const Path& path) if (paintingDisabled()) return; -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,4,0) cairo_t* cr = m_data->cr; double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); @@ -952,9 +1093,6 @@ void GraphicsContext::clipOut(const Path& path) cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_clip(cr); cairo_set_fill_rule(cr, savedFillRule); -#else - notImplemented(); -#endif } void GraphicsContext::rotate(float radians) @@ -980,19 +1118,15 @@ void GraphicsContext::clipOut(const IntRect& r) if (paintingDisabled()) return; -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,4,0) cairo_t* cr = m_data->cr; double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); - cairo_rectangle(cr, x1, x2, x2 - x1, y2 - y1); + cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1); cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height()); cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_clip(cr); cairo_set_fill_rule(cr, savedFillRule); -#else - notImplemented(); -#endif } void GraphicsContext::clipOutEllipseInRect(const IntRect& r) @@ -1005,7 +1139,7 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& r) clipOut(p); } -void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -1015,6 +1149,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, beginPath(); addPath(Path::createRoundedRectangle(r, topLeft, topRight, bottomLeft, bottomRight)); setColor(cr, color); + drawPathShadow(this, m_common, true, false); cairo_fill(cr); cairo_restore(cr); } diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index 0213944..d991c80 100644 --- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -136,6 +136,7 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) *pixel = premultipliedARGBFromColor(pixelColor); } } + cairo_surface_mark_dirty_rectangle (m_data.m_surface, 0, 0, m_size.width(), m_size.height()); } template <Multiply multiplied> @@ -260,6 +261,9 @@ void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& } srcRows += srcBytesPerRow; } + cairo_surface_mark_dirty_rectangle (data.m_surface, + destx, desty, + numColumns, numRows); } void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp index c8c992e..92e36fc 100644 --- a/WebCore/platform/graphics/cairo/ImageCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp @@ -89,7 +89,7 @@ BitmapImage::BitmapImage(cairo_surface_t* surface, ImageObserver* observer) checkForSolidColor(); } -void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, CompositeOperator op) +void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { FloatRect srcRect(src); FloatRect dstRect(dst); @@ -105,7 +105,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo return; if (mayFillWithSolidColor()) { - fillWithSolidColor(context, dstRect, solidColor(), op); + fillWithSolidColor(context, dstRect, solidColor(), styleColorSpace, op); return; } @@ -125,17 +125,37 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); - // To avoid the unwanted gradient effect (#14017) we use - // CAIRO_FILTER_NEAREST now, but the real fix will be to have - // CAIRO_EXTEND_PAD implemented for surfaces in Cairo allowing us to still - // use bilinear filtering - cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST); + cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD); float scaleX = srcRect.width() / dstRect.width(); float scaleY = srcRect.height() / dstRect.height(); cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, srcRect.x(), srcRect.y() }; cairo_pattern_set_matrix(pattern, &matrix); + // Draw the shadow +#if ENABLE(FILTERS) + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (context->getShadow(shadowSize, shadowBlur, shadowColor)) { + IntSize shadowBufferSize; + FloatRect shadowRect; + float kernelSize (0.0); + GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, dstRect, shadowSize, shadowBlur); + shadowColor = colorWithOverrideAlpha(shadowColor.rgb(), (shadowColor.alpha() * context->getAlpha()) / 255.f); + + //draw shadow into a new ImageBuffer + OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); + cairo_t* shadowContext = shadowBuffer->context()->platformContext(); + cairo_set_source(shadowContext, pattern); + cairo_translate(shadowContext, -dstRect.x(), -dstRect.y()); + cairo_rectangle(shadowContext, 0, 0, dstRect.width(), dstRect.height()); + cairo_fill(shadowContext); + + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); + } +#endif + // Draw the image. cairo_translate(cr, dstRect.x(), dstRect.y()); cairo_set_source(cr, pattern); @@ -151,7 +171,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo } void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) + const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect) { cairo_surface_t* image = nativeImageForCurrentFrame(); if (!image) // If it's too early we won't have an image yet. @@ -180,9 +200,6 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, con cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); - // Workaround to avoid the unwanted gradient effect (#14017) - cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST); - cairo_matrix_t pattern_matrix = cairo_matrix_t(patternTransform); cairo_matrix_t phase_matrix = {1, 0, 0, 1, phase.x() + tileRect.x() * patternTransform.a(), phase.y() + tileRect.y() * patternTransform.d()}; cairo_matrix_t combined; diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp index 75681bd..8bde57e 100644 --- a/WebCore/platform/graphics/cairo/PathCairo.cpp +++ b/WebCore/platform/graphics/cairo/PathCairo.cpp @@ -78,15 +78,7 @@ void Path::clear() bool Path::isEmpty() const { - cairo_t* cr = platformPath()->m_cr; -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,5,10) - return !cairo_has_current_point(cr); -#else - cairo_path_t* p = cairo_copy_path(cr); - bool hasData = p->num_data; - cairo_path_destroy(p); - return !hasData; -#endif + return !cairo_has_current_point(platformPath()->m_cr); } bool Path::hasCurrentPoint() const @@ -256,11 +248,7 @@ FloatRect Path::boundingRect() const { cairo_t* cr = platformPath()->m_cr; double x0, x1, y0, y1; -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 6, 0) cairo_path_extents(cr, &x0, &y0, &x1, &y1); -#else - cairo_stroke_extents(cr, &x0, &y0, &x1, &y1); -#endif return FloatRect(x0, y0, x1 - x0, y1 - y0); } diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index 1350bd3..39f06a6 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -43,26 +43,78 @@ #include <wtf/OwnArrayPtr.h> #include <wtf/RetainPtr.h> -#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +// Building on 10.6 or later: kCGInterpolationMedium is defined in the CGInterpolationQuality enum. #define HAVE_CG_INTERPOLATION_MEDIUM 1 #endif +#if !defined(TARGETING_TIGER) && !defined(TARGETING_LEOPARD) +// Targeting 10.6 or later: use kCGInterpolationMedium. +#define WTF_USE_CG_INTERPOLATION_MEDIUM 1 +#endif + +#endif + using namespace std; namespace WebCore { -static void setCGFillColor(CGContextRef context, const Color& color) +static CGColorRef createCGColorWithColorSpace(const Color& color, ColorSpace colorSpace) { - CGFloat red, green, blue, alpha; - color.getRGBA(red, green, blue, alpha); - CGContextSetRGBFillColor(context, red, green, blue, alpha); + CGFloat components[4]; + color.getRGBA(components[0], components[1], components[2], components[3]); + + CGColorRef cgColor = 0; + if (colorSpace == sRGBColorSpace) + cgColor = CGColorCreate(sRGBColorSpaceRef(), components); + else + cgColor = CGColorCreate(deviceRGBColorSpaceRef(), components); + + return cgColor; } -static void setCGStrokeColor(CGContextRef context, const Color& color) +static void setCGFillColor(CGContextRef context, const Color& color, ColorSpace colorSpace) { - CGFloat red, green, blue, alpha; - color.getRGBA(red, green, blue, alpha); - CGContextSetRGBStrokeColor(context, red, green, blue, alpha); + CGColorRef cgColor = createCGColorWithColorSpace(color, colorSpace); + CGContextSetFillColorWithColor(context, cgColor); + CFRelease(cgColor); +} + +static void setCGStrokeColor(CGContextRef context, const Color& color, ColorSpace colorSpace) +{ + CGColorRef cgColor = createCGColorWithColorSpace(color, colorSpace); + CGContextSetStrokeColorWithColor(context, cgColor); + CFRelease(cgColor); +} + +static void setCGFillColorSpace(CGContextRef context, ColorSpace colorSpace) +{ + switch (colorSpace) { + case DeviceColorSpace: + break; + case sRGBColorSpace: + CGContextSetFillColorSpace(context, sRGBColorSpaceRef()); + break; + default: + ASSERT_NOT_REACHED(); + break; + } +} + +static void setCGStrokeColorSpace(CGContextRef context, ColorSpace colorSpace) +{ + switch (colorSpace) { + case DeviceColorSpace: + break; + case sRGBColorSpace: + CGContextSetStrokeColorSpace(context, sRGBColorSpaceRef()); + break; + default: + ASSERT_NOT_REACHED(); + break; + } } GraphicsContext::GraphicsContext(CGContextRef cgContext) @@ -72,8 +124,8 @@ GraphicsContext::GraphicsContext(CGContextRef cgContext) setPaintingDisabled(!cgContext); if (cgContext) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), fillColorSpace()); + setPlatformStrokeColor(strokeColor(), strokeColorSpace()); } } @@ -123,7 +175,7 @@ void GraphicsContext::drawRect(const IntRect& rect) // We do a fill of four rects to simulate the stroke of a border. Color oldFillColor = fillColor(); if (oldFillColor != strokeColor()) - setCGFillColor(context, strokeColor()); + setCGFillColor(context, strokeColor(), strokeColorSpace()); CGRect rects[4] = { FloatRect(rect.x(), rect.y(), rect.width(), 1), FloatRect(rect.x(), rect.bottom() - 1, rect.width(), 1), @@ -132,7 +184,7 @@ void GraphicsContext::drawRect(const IntRect& rect) }; CGContextFillRects(context, rects, 4); if (oldFillColor != strokeColor()) - setCGFillColor(context, oldFillColor); + setCGFillColor(context, oldFillColor, fillColorSpace()); } } @@ -200,7 +252,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) // Do a rect fill of our endpoints. This ensures we always have the // appearance of being a border. We then draw the actual dotted/dashed line. - setCGFillColor(context, strokeColor()); // The save/restore make it safe to mutate the fill color here without setting it back to the old color. + setCGFillColor(context, strokeColor(), strokeColorSpace()); // The save/restore make it safe to mutate the fill color here without setting it back to the old color. if (isVerticalLine) { CGContextFillRect(context, FloatRect(p1.x() - width / 2, p1.y() - width, width, width)); CGContextFillRect(context, FloatRect(p2.x() - width / 2, p2.y(), width, width)); @@ -392,7 +444,7 @@ void GraphicsContext::applyStrokePattern() { CGContextRef cgContext = platformContext(); - RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_common->state.strokePattern.get()->createPlatformPattern(getCTM())); + RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_common->state.strokePattern->createPlatformPattern(getCTM())); if (!platformPattern) return; @@ -407,7 +459,7 @@ void GraphicsContext::applyFillPattern() { CGContextRef cgContext = platformContext(); - RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_common->state.fillPattern.get()->createPlatformPattern(getCTM())); + RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_common->state.fillPattern->createPlatformPattern(getCTM())); if (!platformPattern) return; @@ -420,8 +472,8 @@ void GraphicsContext::applyFillPattern() static inline bool calculateDrawingMode(const GraphicsContextState& state, CGPathDrawingMode& mode) { - bool shouldFill = state.fillColorSpace == PatternColorSpace || state.fillColor.alpha(); - bool shouldStroke = state.strokeColorSpace == PatternColorSpace || (state.strokeStyle != NoStroke && state.strokeColor.alpha()); + bool shouldFill = state.fillPattern || state.fillColor.alpha(); + bool shouldStroke = state.strokePattern || (state.strokeStyle != NoStroke && state.strokeColor.alpha()); bool useEOFill = state.fillRule == RULE_EVENODD; if (shouldFill) { @@ -453,16 +505,16 @@ void GraphicsContext::drawPath() CGContextRef context = platformContext(); const GraphicsContextState& state = m_common->state; - if (state.fillColorSpace == GradientColorSpace || state.strokeColorSpace == GradientColorSpace) { + if (state.fillGradient || state.strokeGradient) { // We don't have any optimized way to fill & stroke a path using gradients fillPath(); strokePath(); return; } - if (state.fillColorSpace == PatternColorSpace) + if (state.fillPattern) applyFillPattern(); - if (state.strokeColorSpace == PatternColorSpace) + if (state.strokePattern) applyStrokePattern(); CGPathDrawingMode drawingMode; @@ -484,15 +536,11 @@ void GraphicsContext::fillPath() return; CGContextRef context = platformContext(); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - fillPathWithFillRule(context, fillRule()); - break; - case PatternColorSpace: - applyFillPattern(); - fillPathWithFillRule(context, fillRule()); - break; - case GradientColorSpace: + + // FIXME: Is this helpful and correct in the fillPattern and fillGradient cases? + setCGFillColorSpace(context, m_common->state.fillColorSpace); + + if (m_common->state.fillGradient) { CGContextSaveGState(context); if (fillRule() == RULE_EVENODD) CGContextEOClip(context); @@ -501,8 +549,12 @@ void GraphicsContext::fillPath() CGContextConcatCTM(context, m_common->state.fillGradient->gradientSpaceTransform()); CGContextDrawShading(context, m_common->state.fillGradient->platformGradient()); CGContextRestoreGState(context); - break; + return; } + + if (m_common->state.fillPattern) + applyFillPattern(); + fillPathWithFillRule(context, fillRule()); } void GraphicsContext::strokePath() @@ -511,76 +563,83 @@ void GraphicsContext::strokePath() return; CGContextRef context = platformContext(); - switch (m_common->state.strokeColorSpace) { - case SolidColorSpace: - CGContextStrokePath(context); - break; - case PatternColorSpace: - applyStrokePattern(); - CGContextStrokePath(context); - break; - case GradientColorSpace: + + // FIXME: Is this helpful and correct in the strokePattern and strokeGradient cases? + setCGStrokeColorSpace(context, m_common->state.strokeColorSpace); + + if (m_common->state.strokeGradient) { CGContextSaveGState(context); CGContextReplacePathWithStrokedPath(context); CGContextClip(context); CGContextConcatCTM(context, m_common->state.strokeGradient->gradientSpaceTransform()); CGContextDrawShading(context, m_common->state.strokeGradient->platformGradient()); CGContextRestoreGState(context); - break; + return; } + + if (m_common->state.strokePattern) + applyStrokePattern(); + CGContextStrokePath(context); } void GraphicsContext::fillRect(const FloatRect& rect) { if (paintingDisabled()) return; + CGContextRef context = platformContext(); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - CGContextFillRect(context, rect); - break; - case PatternColorSpace: - applyFillPattern(); - CGContextFillRect(context, rect); - break; - case GradientColorSpace: + + // FIXME: Is this helpful and correct in the fillPattern and fillGradient cases? + setCGFillColorSpace(context, m_common->state.fillColorSpace); + + if (m_common->state.fillGradient) { CGContextSaveGState(context); CGContextClipToRect(context, rect); CGContextConcatCTM(context, m_common->state.fillGradient->gradientSpaceTransform()); CGContextDrawShading(context, m_common->state.fillGradient->platformGradient()); CGContextRestoreGState(context); - break; + return; } + + if (m_common->state.fillPattern) + applyFillPattern(); + CGContextFillRect(context, rect); } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; CGContextRef context = platformContext(); Color oldFillColor = fillColor(); - if (oldFillColor != color) - setCGFillColor(context, color); + ColorSpace oldColorSpace = fillColorSpace(); + + if (oldFillColor != color || oldColorSpace != colorSpace) + setCGFillColor(context, color, colorSpace); + CGContextFillRect(context, rect); - if (oldFillColor != color) - setCGFillColor(context, oldFillColor); + + if (oldFillColor != color || oldColorSpace != colorSpace) + setCGFillColor(context, oldFillColor, oldColorSpace); } -void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; CGContextRef context = platformContext(); Color oldFillColor = fillColor(); - if (oldFillColor != color) - setCGFillColor(context, color); + ColorSpace oldColorSpace = fillColorSpace(); + + if (oldFillColor != color || oldColorSpace != colorSpace) + setCGFillColor(context, color, colorSpace); addPath(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight)); fillPath(); - if (oldFillColor != color) - setCGFillColor(context, oldFillColor); + if (oldFillColor != color || oldColorSpace != colorSpace) + setCGFillColor(context, oldFillColor, oldColorSpace); } void GraphicsContext::clip(const FloatRect& rect) @@ -680,7 +739,7 @@ void GraphicsContext::endTransparencyLayer() m_data->m_userToDeviceTransformKnownToBeIdentity = false; } -void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color) +void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -727,7 +786,7 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Col if (!color.isValid()) CGContextSetShadow(context, CGSizeMake(width, height), blurRadius); else { - RetainPtr<CGColorRef> colorCG(AdoptCF, createCGColor(color)); + RetainPtr<CGColorRef> colorCG(AdoptCF, createCGColorWithColorSpace(color, colorSpace)); CGContextSetShadowWithColor(context, CGSizeMake(width, height), blurRadius, @@ -769,15 +828,11 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth) return; CGContextRef context = platformContext(); - switch (m_common->state.strokeColorSpace) { - case SolidColorSpace: - CGContextStrokeRectWithWidth(context, r, lineWidth); - break; - case PatternColorSpace: - applyStrokePattern(); - CGContextStrokeRectWithWidth(context, r, lineWidth); - break; - case GradientColorSpace: + + // FIXME: Is this helpful and correct in the strokePattern and strokeGradient cases? + setCGStrokeColorSpace(context, m_common->state.strokeColorSpace); + + if (m_common->state.strokeGradient) { CGContextSaveGState(context); setStrokeThickness(lineWidth); CGContextAddRect(context, r); @@ -785,8 +840,12 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth) CGContextClip(context); CGContextDrawShading(context, m_common->state.strokeGradient->platformGradient()); CGContextRestoreGState(context); - break; + return; } + + if (m_common->state.strokePattern) + applyStrokePattern(); + CGContextStrokeRectWithWidth(context, r, lineWidth); } void GraphicsContext::setLineCap(LineCap cap) @@ -986,10 +1045,10 @@ void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool pri } if (fillColor() != strokeColor()) - setCGFillColor(platformContext(), strokeColor()); + setCGFillColor(platformContext(), strokeColor(), strokeColorSpace()); CGContextFillRect(platformContext(), CGRectMake(x, y, lineLength, thickness)); if (fillColor() != strokeColor()) - setCGFillColor(platformContext(), fillColor()); + setCGFillColor(platformContext(), fillColor(), fillColorSpace()); if (restoreAntialiasMode) CGContextSetShouldAntialias(platformContext(), true); @@ -1034,9 +1093,9 @@ void GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode) quality = kCGInterpolationLow; break; - // Fall through to InterpolationHigh if kCGInterpolationMedium is not available + // Fall through to InterpolationHigh if kCGInterpolationMedium is not usable. case InterpolationMedium: -#if HAVE(CG_INTERPOLATION_MEDIUM) +#if USE(CG_INTERPOLATION_MEDIUM) quality = kCGInterpolationMedium; break; #endif @@ -1061,9 +1120,15 @@ InterpolationQuality GraphicsContext::imageInterpolationQuality() const case kCGInterpolationLow: return InterpolationLow; #if HAVE(CG_INTERPOLATION_MEDIUM) + // kCGInterpolationMedium is known to be present in the CGInterpolationQuality enum. case kCGInterpolationMedium: +#if USE(CG_INTERPOLATION_MEDIUM) + // Only map to InterpolationMedium if targeting a system that understands it. return InterpolationMedium; -#endif +#else + return InterpolationDefault; +#endif // USE(CG_INTERPOLATION_MEDIUM) +#endif // HAVE(CG_INTERPOLATION_MEDIUM) case kCGInterpolationHigh: return InterpolationHigh; } @@ -1107,11 +1172,11 @@ void GraphicsContext::setPlatformTextDrawingMode(int mode) } } -void GraphicsContext::setPlatformStrokeColor(const Color& color) +void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; - setCGStrokeColor(platformContext(), color); + setCGStrokeColor(platformContext(), color, colorSpace); } void GraphicsContext::setPlatformStrokeThickness(float thickness) @@ -1121,11 +1186,11 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness) CGContextSetLineWidth(platformContext(), thickness); } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; - setCGFillColor(platformContext(), color); + setCGFillColor(platformContext(), color, colorSpace); } void GraphicsContext::setPlatformShouldAntialias(bool enable) diff --git a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h index 38c5506..ff1816f 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h +++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h @@ -27,6 +27,25 @@ namespace WebCore { +// FIXME: This would be in GraphicsContextCG.h if that existed. +inline CGColorSpaceRef deviceRGBColorSpaceRef() +{ + static CGColorSpaceRef deviceSpace = CGColorSpaceCreateDeviceRGB(); + return deviceSpace; +} + +// FIXME: This would be in GraphicsContextCG.h if that existed. +inline CGColorSpaceRef sRGBColorSpaceRef() +{ + // FIXME: Windows should be able to use kCGColorSpaceSRGB, this is tracked by http://webkit.org/b/31363. +#if PLATFORM(WIN) || defined(BUILDING_ON_TIGER) + return deviceRGBColorSpaceRef(); +#else + static CGColorSpaceRef sRGBSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); + return sRGBSpace; +#endif +} + class GraphicsContextPlatformPrivate { public: GraphicsContextPlatformPrivate(CGContextRef cgContext) diff --git a/WebCore/platform/graphics/cg/ImageCG.cpp b/WebCore/platform/graphics/cg/ImageCG.cpp index 4da7018..2e372e2 100644 --- a/WebCore/platform/graphics/cg/ImageCG.cpp +++ b/WebCore/platform/graphics/cg/ImageCG.cpp @@ -32,6 +32,7 @@ #include "FloatConversion.h" #include "FloatRect.h" #include "GraphicsContext.h" +#include "GraphicsContextPlatformPrivateCG.h" #include "ImageObserver.h" #include "PDFDocumentImage.h" #include "PlatformString.h" @@ -127,25 +128,46 @@ void BitmapImage::checkForSolidColor() } } +static RetainPtr<CGImageRef> imageWithColorSpace(CGImageRef originalImage, ColorSpace colorSpace) +{ + CGColorSpaceRef originalColorSpace = CGImageGetColorSpace(originalImage); + + // If the image already has a (non-device) color space, we don't want to + // override it, so return. + if (!originalColorSpace || !CFEqual(originalColorSpace, deviceRGBColorSpaceRef())) + return originalImage; + + switch (colorSpace) { + case DeviceColorSpace: + return originalImage; + case sRGBColorSpace: + return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateCopyWithColorSpace(originalImage, + sRGBColorSpaceRef())); + } + + ASSERT_NOT_REACHED(); + return originalImage; +} + CGImageRef BitmapImage::getCGImageRef() { return frameAtIndex(0); } -void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator compositeOp) +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp) { startAnimation(); - CGImageRef image = frameAtIndex(m_currentFrame); + RetainPtr<CGImageRef> image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, destRect, solidColor(), compositeOp); + fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp); return; } - float currHeight = CGImageGetHeight(image); + float currHeight = CGImageGetHeight(image.get()); if (currHeight <= srcRect.y()) return; @@ -181,10 +203,10 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F subimageRect.setHeight(ceilf(subimageRect.height() + topPadding)); adjustedDestRect.setHeight(subimageRect.height() / yScale); - image = CGImageCreateWithImageInRect(image, subimageRect); + image.adoptCF(CGImageCreateWithImageInRect(image.get(), subimageRect)); if (currHeight < srcRect.bottom()) { - ASSERT(CGImageGetHeight(image) == currHeight - CGRectIntegral(srcRect).origin.y); - adjustedDestRect.setHeight(CGImageGetHeight(image) / yScale); + ASSERT(CGImageGetHeight(image.get()) == currHeight - CGRectIntegral(srcRect).origin.y); + adjustedDestRect.setHeight(CGImageGetHeight(image.get()) / yScale); } } else { adjustedDestRect.setLocation(FloatPoint(destRect.x() - srcRect.x() / xScale, destRect.y() - srcRect.y() / yScale)); @@ -204,11 +226,11 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F CGContextScaleCTM(context, 1, -1); adjustedDestRect.setY(-adjustedDestRect.bottom()); - // Draw the image. - CGContextDrawImage(context, adjustedDestRect, image); + // Adjust the color space. + image = imageWithColorSpace(image.get(), styleColorSpace); - if (shouldUseSubimage) - CGImageRelease(image); + // Draw the image. + CGContextDrawImage(context, adjustedDestRect, image.get()); ctxt->restore(); @@ -223,7 +245,7 @@ static void drawPatternCallback(void* info, CGContextRef context) } void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) { if (!nativeImageForCurrentFrame()) return; @@ -260,6 +282,9 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const ASSERT(h == height()); subImage.adoptCF(CGImageCreateWithImageInRect(tileImage, tileRect)); } + + // Adjust the color space. + subImage = imageWithColorSpace(subImage.get(), styleColorSpace); #ifndef BUILDING_ON_TIGER // Leopard has an optimized call for the tiling of image patterns, but we can only use it if the image has been decoded enough that diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp index 66246fe..2b2c6b0 100644 --- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp +++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -35,12 +35,27 @@ #include <ApplicationServices/ApplicationServices.h> #include <wtf/UnusedParam.h> +using namespace std; + namespace WebCore { static const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32"); #if !PLATFORM(MAC) -static void sharedBufferDerefCallback(void*, void* info) +size_t sharedBufferGetBytesAtPosition(void* info, void* buffer, off_t position, size_t count) +{ + SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info); + size_t sourceSize = sharedBuffer->size(); + if (position >= sourceSize) + return 0; + + const char* source = sharedBuffer->data() + position; + size_t amount = min<size_t>(count, sourceSize - position); + memcpy(buffer, source, amount); + return amount; +} + +void sharedBufferRelease(void* info) { SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info); sharedBuffer->deref(); @@ -110,15 +125,17 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived) // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer. RetainPtr<CFDataRef> cfData(AdoptCF, data->createCFData()); + CGImageSourceUpdateData(m_decoder, cfData.get(), allDataReceived); #else - // If no NSData is available, then we know SharedBuffer will always just be a vector. That means no secret changes can occur to it behind the - // scenes. We use CFDataCreateWithBytesNoCopy in that case. Ensure that the SharedBuffer lives as long as the CFDataRef. + // Create a CGDataProvider to wrap the SharedBuffer. data->ref(); - CFAllocatorContext context = {0, data, 0, 0, 0, 0, 0, &sharedBufferDerefCallback, 0}; - RetainPtr<CFAllocatorRef> derefAllocator(AdoptCF, CFAllocatorCreate(kCFAllocatorDefault, &context)); - RetainPtr<CFDataRef> cfData(AdoptCF, CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data->data()), data->size(), derefAllocator.get())); + // We use the GetBytesAtPosition callback rather than the GetBytePointer one because SharedBuffer + // does not provide a way to lock down the byte pointer and guarantee that it won't move, which + // is a requirement for using the GetBytePointer callback. + CGDataProviderDirectCallbacks providerCallbacks = { 0, 0, 0, sharedBufferGetBytesAtPosition, sharedBufferRelease }; + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateDirect(data, data->size(), &providerCallbacks)); + CGImageSourceUpdateDataProvider(m_decoder, dataProvider.get(), allDataReceived); #endif - CGImageSourceUpdateData(m_decoder, cfData.get(), allDataReceived); } String ImageSource::filenameExtension() const diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.h b/WebCore/platform/graphics/cg/ImageSourceCG.h index d5b4b5a..76b4160 100644 --- a/WebCore/platform/graphics/cg/ImageSourceCG.h +++ b/WebCore/platform/graphics/cg/ImageSourceCG.h @@ -36,6 +36,10 @@ String preferredExtensionForImageSourceType(const String& type); String MIMETypeForImageSourceType(const String& type); +#if !PLATFORM(MAC) +size_t sharedBufferGetBytesAtPosition(void* info, void* buffer, off_t position, size_t count); +#endif + } #endif // ImageSourceCG_h diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp index 2f5c15e..67333ae 100644 --- a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp +++ b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp @@ -33,6 +33,10 @@ #include "ImageObserver.h" #include <wtf/MathExtras.h> +#if !PLATFORM(MAC) +#include "ImageSourceCG.h" +#endif + using namespace std; namespace WebCore { @@ -69,12 +73,15 @@ bool PDFDocumentImage::dataChanged(bool allDataReceived) // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer. RetainPtr<CFDataRef> data(AdoptCF, this->data()->createCFData()); + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(data.get())); #else - // If no NSData is available, then we know SharedBuffer will always just be a vector. That means no secret changes can occur to it behind the - // scenes. We use CFDataCreateWithBytesNoCopy in that case. - RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(this->data()->data()), this->data()->size(), kCFAllocatorNull)); + // Create a CGDataProvider to wrap the SharedBuffer. + // We use the GetBytesAtPosition callback rather than the GetBytePointer one because SharedBuffer + // does not provide a way to lock down the byte pointer and guarantee that it won't move, which + // is a requirement for using the GetBytePointer callback. + CGDataProviderDirectCallbacks providerCallbacks = { 0, 0, 0, sharedBufferGetBytesAtPosition, 0 }; + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateDirect(this->data(), this->data()->size(), &providerCallbacks)); #endif - RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(data.get())); m_document = CGPDFDocumentCreateWithProvider(dataProvider.get()); setCurrentPage(0); } @@ -139,7 +146,7 @@ int PDFDocumentImage::pageCount() const return m_document ? CGPDFDocumentGetNumberOfPages(m_document) : 0; } -void PDFDocumentImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator op) +void PDFDocumentImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace, CompositeOperator op) { if (!m_document || m_currentPage == -1) return; diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.h b/WebCore/platform/graphics/cg/PDFDocumentImage.h index 130c12c..12ab46c 100644 --- a/WebCore/platform/graphics/cg/PDFDocumentImage.h +++ b/WebCore/platform/graphics/cg/PDFDocumentImage.h @@ -58,7 +58,7 @@ namespace WebCore { virtual IntSize size() const; PDFDocumentImage(); - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); void setCurrentPage(int); int pageCount() const; diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp index 229188e..9f8f354 100644 --- a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -112,12 +112,16 @@ void TransparencyAwareFontPainter::init() void TransparencyAwareFontPainter::initializeForGDI() { + m_graphicsContext->save(); SkColor color = m_platformContext->effectiveFillColor(); + // Used only when m_createdTransparencyLayer is true. + float layerAlpha = 0.0f; if (SkColorGetA(color) != 0xFF) { // When the font has some transparency, apply it by creating a new - // transparency layer with that opacity applied. + // transparency layer with that opacity applied. We'll actually create + // a new transparency layer after we calculate the bounding box. m_createdTransparencyLayer = true; - m_graphicsContext->beginTransparencyLayer(SkColorGetA(color) / 255.0f); + layerAlpha = SkColorGetA(color) / 255.0f; // The color should be opaque now. color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); } @@ -131,16 +135,22 @@ void TransparencyAwareFontPainter::initializeForGDI() // and we could do ClearType in that case. layerMode = TransparencyWin::TextComposite; layerRect = estimateTextBounds(); + m_graphicsContext->clip(layerRect); + if (m_createdTransparencyLayer) + m_graphicsContext->beginTransparencyLayer(layerAlpha); // The transparency helper requires that we draw text in black in // this mode and it will apply the color. m_transparency.setTextCompositeColor(color); color = SkColorSetRGB(0, 0, 0); - } else if (canvasHasMultipleLayers(m_platformContext->canvas())) { + } else if (m_createdTransparencyLayer || canvasHasMultipleLayers(m_platformContext->canvas())) { // When we're drawing a web page, we know the background is opaque, // but if we're drawing to a layer, we still need extra work. layerMode = TransparencyWin::OpaqueCompositeLayer; layerRect = estimateTextBounds(); + m_graphicsContext->clip(layerRect); + if (m_createdTransparencyLayer) + m_graphicsContext->beginTransparencyLayer(layerAlpha); } else { // Common case of drawing onto the bottom layer of a web page: we // know everything is opaque so don't need to do anything special. @@ -167,6 +177,7 @@ TransparencyAwareFontPainter::~TransparencyAwareFontPainter() m_transparency.composite(); if (m_createdTransparencyLayer) m_graphicsContext->endTransparencyLayer(); + m_graphicsContext->restore(); m_platformContext->canvas()->endPlatformPaint(); } diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp index 88035d5..6bd7d7c 100644 --- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp @@ -42,12 +42,11 @@ #include "FontPlatformData.h" #include "NotImplemented.h" +#include "OpenTypeSanitizer.h" #include "SharedBuffer.h" #if PLATFORM(WIN_OS) #include <objbase.h> -#include <t2embapi.h> -#pragma comment(lib, "t2embed") #elif PLATFORM(LINUX) #include <cstring> #endif @@ -57,13 +56,8 @@ namespace WebCore { FontCustomPlatformData::~FontCustomPlatformData() { #if PLATFORM(WIN_OS) - if (m_fontReference) { - if (m_name.isNull()) { - ULONG status; - TTDeleteEmbeddedFont(m_fontReference, 0, &status); - } else - RemoveFontMemResourceEx(m_fontReference); - } + if (m_fontReference) + RemoveFontMemResourceEx(m_fontReference); #elif PLATFORM(LINUX) if (m_fontReference) m_fontReference->unref(); @@ -76,19 +70,15 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b ASSERT(m_fontReference); LOGFONT logFont; - if (m_name.isNull()) - TTGetNewFontName(&m_fontReference, logFont.lfFaceName, LF_FACESIZE, 0, 0); - else { - // m_name comes from createUniqueFontName, which, in turn, gets - // it from base64-encoded uuid (128-bit). So, m_name - // can never be longer than LF_FACESIZE (32). - if (m_name.length() + 1 >= LF_FACESIZE) { - ASSERT_NOT_REACHED(); - return FontPlatformData(); - } - memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(), - sizeof(logFont.lfFaceName[0]) * (1 + m_name.length())); + // m_name comes from createUniqueFontName, which, in turn, gets + // it from base64-encoded uuid (128-bit). So, m_name + // can never be longer than LF_FACESIZE (32). + if (m_name.length() + 1 >= LF_FACESIZE) { + ASSERT_NOT_REACHED(); + return FontPlatformData(); } + memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(), + sizeof(logFont.lfFaceName[0]) * (1 + m_name.length())); // FIXME: almost identical to FillLogFont in FontCacheWin.cpp. // Need to refactor. @@ -119,69 +109,6 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b } #if PLATFORM(WIN_OS) -// FIXME: EOTStream class and static functions in this #if block are -// duplicated from platform/graphics/win/FontCustomPlatformData.cpp -// and need to be shared. - -// Streams the concatenation of a header and font data. -class EOTStream { -public: - EOTStream(const EOTHeader& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength) - : m_eotHeader(eotHeader) - , m_fontData(fontData) - , m_overlayDst(overlayDst) - , m_overlaySrc(overlaySrc) - , m_overlayLength(overlayLength) - , m_offset(0) - , m_inHeader(true) - { - } - - size_t read(void* buffer, size_t count); - -private: - const EOTHeader& m_eotHeader; - const SharedBuffer* m_fontData; - size_t m_overlayDst; - size_t m_overlaySrc; - size_t m_overlayLength; - size_t m_offset; - bool m_inHeader; -}; - -size_t EOTStream::read(void* buffer, size_t count) -{ - size_t bytesToRead = count; - if (m_inHeader) { - size_t bytesFromHeader = std::min(m_eotHeader.size() - m_offset, count); - memcpy(buffer, m_eotHeader.data() + m_offset, bytesFromHeader); - m_offset += bytesFromHeader; - bytesToRead -= bytesFromHeader; - if (m_offset == m_eotHeader.size()) { - m_inHeader = false; - m_offset = 0; - } - } - if (bytesToRead && !m_inHeader) { - size_t bytesFromData = std::min(m_fontData->size() - m_offset, bytesToRead); - memcpy(buffer, m_fontData->data() + m_offset, bytesFromData); - if (m_offset < m_overlayDst + m_overlayLength && m_offset + bytesFromData >= m_overlayDst) { - size_t dstOffset = std::max<int>(m_overlayDst - m_offset, 0); - size_t srcOffset = std::max<int>(0, m_offset - m_overlayDst); - size_t bytesToCopy = std::min(bytesFromData - dstOffset, m_overlayLength - srcOffset); - memcpy(reinterpret_cast<char*>(buffer) + dstOffset, m_fontData->data() + m_overlaySrc + srcOffset, bytesToCopy); - } - m_offset += bytesFromData; - bytesToRead -= bytesFromData; - } - return count - bytesToRead; -} - -static unsigned long WINAPIV readEmbedProc(void* stream, void* buffer, unsigned long length) -{ - return static_cast<EOTStream*>(stream)->read(buffer, length); -} - // Creates a unique and unpredictable font name, in order to avoid collisions and to // not allow access from CSS. static String createUniqueFontName() @@ -245,38 +172,22 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) { ASSERT_ARG(buffer, buffer); +#if ENABLE(OPENTYPE_SANITIZER) + OpenTypeSanitizer sanitizer(buffer); + RefPtr<SharedBuffer> transcodeBuffer = sanitizer.sanitize(); + if (!transcodeBuffer) + return 0; // validation failed. + buffer = transcodeBuffer.get(); +#endif + #if PLATFORM(WIN_OS) - // Introduce the font to GDI. AddFontMemResourceEx cannot be used, because it will pollute the process's + // Introduce the font to GDI. AddFontMemResourceEx should be used with care, because it will pollute the process's // font namespace (Windows has no API for creating an HFONT from data without exposing the font to the - // entire process first). TTLoadEmbeddedFont lets us override the font family name, so using a unique name - // we avoid namespace collisions. - + // entire process first). String fontName = createUniqueFontName(); - - // TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data, - // so we need to create an EOT header and prepend it to the font data. - EOTHeader eotHeader; - size_t overlayDst; - size_t overlaySrc; - size_t overlayLength; - - if (!getEOTHeader(buffer, eotHeader, overlayDst, overlaySrc, overlayLength)) + HANDLE fontReference = renameAndActivateFont(buffer, fontName); + if (!fontReference) return 0; - - HANDLE fontReference; - ULONG privStatus; - ULONG status; - EOTStream eotStream(eotHeader, buffer, overlayDst, overlaySrc, overlayLength); - - LONG loadEmbeddedFontResult = TTLoadEmbeddedFont(&fontReference, TTLOAD_PRIVATE, &privStatus, LICENSE_PREVIEWPRINT, &status, readEmbedProc, &eotStream, const_cast<LPWSTR>(fontName.charactersWithNullTermination()), 0, 0); - if (loadEmbeddedFontResult == E_NONE) - fontName = String(); - else { - fontReference = renameAndActivateFont(buffer, fontName); - if (!fontReference) - return 0; - } - return new FontCustomPlatformData(fontReference, fontName); #elif PLATFORM(LINUX) RemoteFontStream stream(buffer); diff --git a/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp b/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp index a5a6e1f..1386163 100644 --- a/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp +++ b/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp @@ -46,12 +46,6 @@ Icon::~Icon() { } -PassRefPtr<Icon> Icon::createIconForFile(const String&) -{ - notImplemented(); - return 0; -} - PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) { notImplemented(); diff --git a/WebCore/platform/graphics/chromium/IconChromiumMac.cpp b/WebCore/platform/graphics/chromium/IconChromiumMac.cpp index 93e36ba..23ca698 100644 --- a/WebCore/platform/graphics/chromium/IconChromiumMac.cpp +++ b/WebCore/platform/graphics/chromium/IconChromiumMac.cpp @@ -39,11 +39,6 @@ namespace WebCore { -PassRefPtr<Icon> Icon::createIconForFile(const String&) -{ - return 0; -} - PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) { return 0; diff --git a/WebCore/platform/graphics/chromium/IconChromiumWin.cpp b/WebCore/platform/graphics/chromium/IconChromiumWin.cpp index b419e6f..b0145f8 100644 --- a/WebCore/platform/graphics/chromium/IconChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/IconChromiumWin.cpp @@ -52,26 +52,11 @@ Icon::~Icon() DestroyIcon(m_icon); } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) -{ - SHFILEINFO sfi; - memset(&sfi, 0, sizeof(sfi)); - - String tmpFilename = filename; - if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON)) - return 0; - - return adoptRef(new Icon(sfi.hIcon)); -} - PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { - // FIXME: support multiple files. + // FIXME: We can't access icons directly from renderer processes. // http://code.google.com/p/chromium/issues/detail?id=4092 - if (!filenames.size()) - return 0; - - return createIconForFile(filenames[0]); + return 0; } void Icon::paint(GraphicsContext* context, const IntRect& rect) diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/WebCore/platform/graphics/chromium/TransparencyWin.cpp index 7957d5a..6dcd595 100644 --- a/WebCore/platform/graphics/chromium/TransparencyWin.cpp +++ b/WebCore/platform/graphics/chromium/TransparencyWin.cpp @@ -275,7 +275,7 @@ void TransparencyWin::setupLayerForWhiteLayer() if (!m_validLayer) return; - m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white); + m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white, DeviceColorSpace); // Layer rect represents the part of the original layer. } diff --git a/WebCore/platform/graphics/filters/FEBlend.cpp b/WebCore/platform/graphics/filters/FEBlend.cpp index 2364cc4..f362148 100644 --- a/WebCore/platform/graphics/filters/FEBlend.cpp +++ b/WebCore/platform/graphics/filters/FEBlend.cpp @@ -111,10 +111,10 @@ void FEBlend::apply(Filter* filter) if (!getEffectContext()) return; - IntRect effectADrawingRect = calculateDrawingIntRect(m_in->subRegion()); + IntRect effectADrawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); RefPtr<CanvasPixelArray> srcPixelArrayA(m_in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); - IntRect effectBDrawingRect = calculateDrawingIntRect(m_in2->subRegion()); + IntRect effectBDrawingRect = calculateDrawingIntRect(m_in2->scaledSubRegion()); RefPtr<CanvasPixelArray> srcPixelArrayB(m_in2->resultImage()->getPremultipliedImageData(effectBDrawingRect)->data()); IntRect imageRect(IntPoint(), resultImage()->size()); diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp index a2ed9bd..f422157 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp +++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp @@ -164,7 +164,7 @@ void FEColorMatrix::apply(Filter* filter) if (!filterContext) return; - filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion())); IntRect imageRect(IntPoint(), resultImage()->size()); PassRefPtr<ImageData> imageData(resultImage()->getUnmultipliedImageData(imageRect)); diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp index 0d76d8d..1d9cfff 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp @@ -165,7 +165,7 @@ void FEComponentTransfer::apply(Filter* filter) for (unsigned channel = 0; channel < 4; channel++) (*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]); - IntRect drawingRect = calculateDrawingIntRect(m_in->subRegion()); + IntRect drawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); RefPtr<ImageData> imageData(m_in->resultImage()->getUnmultipliedImageData(drawingRect)); CanvasPixelArray* srcPixelArray(imageData->data()); diff --git a/WebCore/platform/graphics/filters/FEComposite.cpp b/WebCore/platform/graphics/filters/FEComposite.cpp index 1b41165..c540cb7 100644 --- a/WebCore/platform/graphics/filters/FEComposite.cpp +++ b/WebCore/platform/graphics/filters/FEComposite.cpp @@ -133,32 +133,32 @@ void FEComposite::apply(Filter* filter) FloatRect srcRect = FloatRect(0.f, 0.f, -1.f, -1.f); switch (m_type) { case FECOMPOSITE_OPERATOR_OVER: - filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion())); - filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); + filterContext->drawImage(m_in2->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in2->scaledSubRegion())); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion())); break; case FECOMPOSITE_OPERATOR_IN: filterContext->save(); - filterContext->clipToImageBuffer(calculateDrawingRect(m_in2->subRegion()), m_in2->resultImage()); - filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); + filterContext->clipToImageBuffer(calculateDrawingRect(m_in2->scaledSubRegion()), m_in2->resultImage()); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion())); filterContext->restore(); break; case FECOMPOSITE_OPERATOR_OUT: - filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); - filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion()), srcRect, CompositeDestinationOut); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion())); + filterContext->drawImage(m_in2->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in2->scaledSubRegion()), srcRect, CompositeDestinationOut); break; case FECOMPOSITE_OPERATOR_ATOP: - filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion())); - filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion()), srcRect, CompositeSourceAtop); + filterContext->drawImage(m_in2->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in2->scaledSubRegion())); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion()), srcRect, CompositeSourceAtop); break; case FECOMPOSITE_OPERATOR_XOR: - filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion())); - filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion()), srcRect, CompositeXOR); + filterContext->drawImage(m_in2->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in2->scaledSubRegion())); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion()), srcRect, CompositeXOR); break; case FECOMPOSITE_OPERATOR_ARITHMETIC: { - IntRect effectADrawingRect = calculateDrawingIntRect(m_in->subRegion()); + IntRect effectADrawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); RefPtr<CanvasPixelArray> srcPixelArrayA(m_in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); - IntRect effectBDrawingRect = calculateDrawingIntRect(m_in2->subRegion()); + IntRect effectBDrawingRect = calculateDrawingIntRect(m_in2->scaledSubRegion()); RefPtr<ImageData> imageData(m_in2->resultImage()->getPremultipliedImageData(effectBDrawingRect)); CanvasPixelArray* srcPixelArrayB(imageData->data()); diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp index f480f10..0b97e39 100644 --- a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp @@ -32,6 +32,8 @@ #include <math.h> #include <wtf/MathExtras.h> +using std::max; + namespace WebCore { FEGaussianBlur::FEGaussianBlur(FilterEffect* in, const float& x, const float& y) @@ -111,10 +113,12 @@ void FEGaussianBlur::apply(Filter* filter) if (m_x == 0 || m_y == 0) return; - unsigned sdx = static_cast<unsigned>(floor(m_x * 3 * sqrt(2 * piDouble) / 4.f + 0.5f)); - unsigned sdy = static_cast<unsigned>(floor(m_y * 3 * sqrt(2 * piDouble) / 4.f + 0.5f)); + unsigned sdx = static_cast<unsigned>(floor(m_x * filter->filterResolution().width() * 3 * sqrt(2 * piDouble) / 4.f + 0.5f)); + unsigned sdy = static_cast<unsigned>(floor(m_y * filter->filterResolution().height() * 3 * sqrt(2 * piDouble) / 4.f + 0.5f)); + sdx = max(sdx, static_cast<unsigned>(1)); + sdy = max(sdy, static_cast<unsigned>(1)); - IntRect effectDrawingRect = calculateDrawingIntRect(m_in->subRegion()); + IntRect effectDrawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); RefPtr<ImageData> srcImageData(m_in->resultImage()->getPremultipliedImageData(effectDrawingRect)); CanvasPixelArray* srcPixelArray(srcImageData->data()); diff --git a/WebCore/platform/graphics/filters/Filter.h b/WebCore/platform/graphics/filters/Filter.h index ee97afc..8924b94 100644 --- a/WebCore/platform/graphics/filters/Filter.h +++ b/WebCore/platform/graphics/filters/Filter.h @@ -22,6 +22,7 @@ #if ENABLE(FILTERS) #include "FloatRect.h" +#include "FloatSize.h" #include "ImageBuffer.h" #include "StringHash.h" @@ -40,15 +41,21 @@ namespace WebCore { void setSourceImage(PassOwnPtr<ImageBuffer> sourceImage) { m_sourceImage = sourceImage; } ImageBuffer* sourceImage() { return m_sourceImage.get(); } - virtual FloatRect sourceImageRect() = 0; - virtual FloatRect filterRegion() = 0; + FloatSize filterResolution() const { return m_filterResolution; } + void setFilterResolution(const FloatSize& filterResolution) { m_filterResolution = filterResolution; } + + virtual FloatRect sourceImageRect() const = 0; + virtual FloatRect filterRegion() const = 0; // SVG specific - virtual void calculateEffectSubRegion(FilterEffect*) = 0; - virtual bool effectBoundingBoxMode() = 0; + virtual void calculateEffectSubRegion(FilterEffect*) { } + + virtual FloatSize maxImageSize() const = 0; + virtual bool effectBoundingBoxMode() const = 0; private: OwnPtr<ImageBuffer> m_sourceImage; + FloatSize m_filterResolution; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp index 68900b5..5583813 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.cpp +++ b/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -58,21 +58,21 @@ FloatRect FilterEffect::calculateEffectRect(Filter* filter) IntRect FilterEffect::calculateDrawingIntRect(const FloatRect& effectRect) { - IntPoint location = roundedIntPoint(FloatPoint(subRegion().x() - effectRect.x(), - subRegion().y() - effectRect.y())); + IntPoint location = roundedIntPoint(FloatPoint(scaledSubRegion().x() - effectRect.x(), + scaledSubRegion().y() - effectRect.y())); return IntRect(location, resultImage()->size()); } FloatRect FilterEffect::calculateDrawingRect(const FloatRect& srcRect) { - FloatPoint startPoint = FloatPoint(srcRect.x() - subRegion().x(), srcRect.y() - subRegion().y()); + FloatPoint startPoint = FloatPoint(srcRect.x() - scaledSubRegion().x(), srcRect.y() - scaledSubRegion().y()); FloatRect drawingRect = FloatRect(startPoint, srcRect.size()); return drawingRect; } GraphicsContext* FilterEffect::getEffectContext() { - IntRect bufferRect = enclosingIntRect(subRegion()); + IntRect bufferRect = enclosingIntRect(scaledSubRegion()); m_effectBuffer = ImageBuffer::create(bufferRect.size(), LinearRGB); return m_effectBuffer->context(); } diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h index b30e513..a46d795 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.h +++ b/WebCore/platform/graphics/filters/FilterEffect.h @@ -44,6 +44,12 @@ namespace WebCore { FloatRect subRegion() const { return m_subRegion; } void setSubRegion(const FloatRect& subRegion) { m_subRegion = subRegion; } + FloatRect scaledSubRegion() const { return m_scaledSubRegion; } + void setScaledSubRegion(const FloatRect& scaledSubRegion) { m_scaledSubRegion = scaledSubRegion; } + + FloatRect effectBoundaries() const { return m_effectBoundaries; } + void setEffectBoundaries(const FloatRect& effectBoundaries) { m_effectBoundaries = effectBoundaries; } + bool hasX() { return m_hasX; } void setHasX(bool value) { m_hasX = value; } @@ -96,7 +102,9 @@ namespace WebCore { bool m_alphaImage; + FloatRect m_effectBoundaries; FloatRect m_subRegion; + FloatRect m_scaledSubRegion; FloatRect m_unionOfChildEffectSubregions; mutable OwnPtr<ImageBuffer> m_effectBuffer; diff --git a/WebCore/platform/graphics/filters/ImageBufferFilter.cpp b/WebCore/platform/graphics/filters/ImageBufferFilter.cpp new file mode 100644 index 0000000..33953d6 --- /dev/null +++ b/WebCore/platform/graphics/filters/ImageBufferFilter.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * aint with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "ImageBufferFilter.h" + +#include "FloatSize.h" + +namespace WebCore { + +ImageBufferFilter::ImageBufferFilter() + : Filter() +{ + setFilterResolution(FloatSize(1.f, 1.f)); +} + +PassRefPtr<ImageBufferFilter> ImageBufferFilter::create() +{ + return adoptRef(new ImageBufferFilter()); +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/ImageBufferFilter.h b/WebCore/platform/graphics/filters/ImageBufferFilter.h new file mode 100644 index 0000000..a2775ea --- /dev/null +++ b/WebCore/platform/graphics/filters/ImageBufferFilter.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * aint with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef ImageBufferFilter_h +#define ImageBufferFilter_h + +#if ENABLE(FILTERS) +#include "Filter.h" +#include "FilterEffect.h" +#include "FloatRect.h" +#include "FloatSize.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class ImageBufferFilter : public Filter { +public: + static PassRefPtr<ImageBufferFilter> create(); + + virtual FloatRect filterRegion() const { return FloatRect(); } + virtual FloatRect sourceImageRect() const { return FloatRect(); } + + // SVG specific + virtual bool effectBoundingBoxMode() const { return false; } + + virtual FloatSize maxImageSize() const { return FloatSize(); } + virtual void calculateEffectSubRegion(FilterEffect*) { } + +private: + ImageBufferFilter(); +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // ImageBufferFilter_h diff --git a/WebCore/platform/graphics/filters/SourceAlpha.cpp b/WebCore/platform/graphics/filters/SourceAlpha.cpp index 1b6309b..539bb44 100644 --- a/WebCore/platform/graphics/filters/SourceAlpha.cpp +++ b/WebCore/platform/graphics/filters/SourceAlpha.cpp @@ -50,6 +50,8 @@ FloatRect SourceAlpha::calculateEffectRect(Filter* filter) if (filter->sourceImageRect().y() < filter->filterRegion().y()) clippedSourceRect.setY(filter->filterRegion().y()); setSubRegion(clippedSourceRect); + clippedSourceRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); + setScaledSubRegion(clippedSourceRect); return filter->filterRegion(); } @@ -64,7 +66,7 @@ void SourceAlpha::apply(Filter* filter) FloatRect imageRect(FloatPoint(), filter->sourceImage()->image()->size()); filterContext->save(); filterContext->clipToImageBuffer(imageRect, filter->sourceImage()); - filterContext->fillRect(imageRect, Color::black); + filterContext->fillRect(imageRect, Color::black, DeviceColorSpace); filterContext->restore(); } diff --git a/WebCore/platform/graphics/filters/SourceGraphic.cpp b/WebCore/platform/graphics/filters/SourceGraphic.cpp index 023eeac..cc55618 100644 --- a/WebCore/platform/graphics/filters/SourceGraphic.cpp +++ b/WebCore/platform/graphics/filters/SourceGraphic.cpp @@ -49,6 +49,8 @@ FloatRect SourceGraphic::calculateEffectRect(Filter* filter) if (filter->sourceImageRect().y() < filter->filterRegion().y()) clippedSourceRect.setY(filter->filterRegion().y()); setSubRegion(clippedSourceRect); + clippedSourceRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); + setScaledSubRegion(clippedSourceRect); return filter->filterRegion(); } @@ -58,7 +60,7 @@ void SourceGraphic::apply(Filter* filter) if (!filterContext) return; - filterContext->drawImage(filter->sourceImage()->image(), IntPoint()); + filterContext->drawImage(filter->sourceImage()->image(), DeviceColorSpace, IntPoint()); } void SourceGraphic::dump() diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp index ee86f96..5c320e0 100644 --- a/WebCore/platform/graphics/gtk/FontGtk.cpp +++ b/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -259,7 +259,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F // Re-enable the platform shadow we disabled earlier if (hasShadow) - context->setShadow(shadowSize, shadowBlur, shadowColor); + context->setShadow(shadowSize, shadowBlur, shadowColor, DeviceColorSpace); // Pango sometimes leaves behind paths we don't want cairo_new_path(cr); diff --git a/WebCore/platform/graphics/gtk/IconGtk.cpp b/WebCore/platform/graphics/gtk/IconGtk.cpp index e08c1ab..3563a59 100644 --- a/WebCore/platform/graphics/gtk/IconGtk.cpp +++ b/WebCore/platform/graphics/gtk/IconGtk.cpp @@ -87,23 +87,25 @@ static String lookupIconName(String MIMEType) return GTK_STOCK_FILE; } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { - if (!g_path_skip_root(filename.utf8().data())) + if (filenames.isEmpty()) return 0; - String MIMEType = MIMETypeRegistry::getMIMETypeForPath(filename); - String iconName = lookupIconName(MIMEType); + if (filenames.size() == 1) { + if (!g_path_skip_root(filenames[0].utf8().data())) + return 0; - RefPtr<Icon> icon = adoptRef(new Icon); - icon->m_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), iconName.utf8().data(), 16, GTK_ICON_LOOKUP_USE_BUILTIN, NULL); - if (!icon->m_icon) - return 0; - return icon.release(); -} + String MIMEType = MIMETypeRegistry::getMIMETypeForPath(filenames[0]); + String iconName = lookupIconName(MIMEType); + + RefPtr<Icon> icon = adoptRef(new Icon); + icon->m_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), iconName.utf8().data(), 16, GTK_ICON_LOOKUP_USE_BUILTIN, 0); + if (!icon->m_icon) + return 0; + return icon.release(); + } -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) -{ //FIXME: Implement this return 0; } diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp index 8d1d261..a023dae 100644 --- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp @@ -46,7 +46,7 @@ #include <gst/video/video.h> #include <limits> #include <math.h> -#include <wtf/GOwnPtr.h> +#include <wtf/gtk/GOwnPtr.h> using namespace std; @@ -66,11 +66,15 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); error = MediaPlayer::Empty; - if (err->domain == GST_CORE_ERROR || err->domain == GST_LIBRARY_ERROR) - error = MediaPlayer::DecodeError; - else if (err->domain == GST_RESOURCE_ERROR) + if (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND + || err->code == GST_STREAM_ERROR_WRONG_TYPE + || err->code == GST_STREAM_ERROR_FAILED + || err->code == GST_CORE_ERROR_MISSING_PLUGIN + || err->code == GST_RESOURCE_ERROR_NOT_FOUND) error = MediaPlayer::FormatError; else if (err->domain == GST_STREAM_ERROR) + error = MediaPlayer::DecodeError; + else if (err->domain == GST_RESOURCE_ERROR) error = MediaPlayer::NetworkError; if (mp) @@ -95,6 +99,33 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo return true; } +static float playbackPosition(GstElement* playbin) +{ + + float ret = 0.0; + + GstQuery* query = gst_query_new_position(GST_FORMAT_TIME); + if (!gst_element_query(playbin, query)) { + LOG_VERBOSE(Media, "Position query failed..."); + gst_query_unref(query); + return ret; + } + + gint64 position; + gst_query_parse_position(query, 0, &position); + + // Position is available only if the pipeline is not in NULL or + // READY state. + if (position != static_cast<gint64>(GST_CLOCK_TIME_NONE)) + ret = static_cast<float>(position) / static_cast<float>(GST_SECOND); + + LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); + + gst_query_unref(query); + + return ret; +} + void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivate* playerPrivate) { g_return_if_fail(GST_IS_BUFFER(buffer)); @@ -115,16 +146,34 @@ void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) static bool gstInitialized = false; -static void do_gst_init() +static bool do_gst_init() { // FIXME: We should pass the arguments from the command line if (!gstInitialized) { - gst_init(0, 0); - gstInitialized = true; - gst_element_register(0, "webkitmediasrc", GST_RANK_PRIMARY, - WEBKIT_TYPE_DATA_SRC); + GOwnPtr<GError> error; + gstInitialized = gst_init_check(0, 0, &error.outPtr()); + if (!gstInitialized) + LOG_VERBOSE(Media, "Could not initialize GStreamer: %s", + error ? error->message : "unknown error occurred"); + else + gst_element_register(0, "webkitmediasrc", GST_RANK_PRIMARY, + WEBKIT_TYPE_DATA_SRC); } + return gstInitialized; +} + +bool MediaPlayerPrivate::isAvailable() +{ + if (!do_gst_init()) + return false; + + GstElementFactory* factory = gst_element_factory_find("playbin2"); + if (factory) { + gst_object_unref(GST_OBJECT(factory)); + return true; + } + return false; } MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) @@ -132,6 +181,8 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_playBin(0) , m_videoSink(0) , m_source(0) + , m_seekTime(0) + , m_changingRate(false) , m_endTime(numeric_limits<float>::infinity()) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::HaveNothing) @@ -181,14 +232,26 @@ void MediaPlayerPrivate::load(const String& url) void MediaPlayerPrivate::play() { - LOG_VERBOSE(Media, "Play"); - gst_element_set_state(m_playBin, GST_STATE_PLAYING); + GstState state; + GstState pending; + + gst_element_get_state(m_playBin, &state, &pending, 0); + if (state != GST_STATE_PLAYING && pending != GST_STATE_PLAYING) { + LOG_VERBOSE(Media, "Play"); + gst_element_set_state(m_playBin, GST_STATE_PLAYING); + } } void MediaPlayerPrivate::pause() { - LOG_VERBOSE(Media, "Pause"); - gst_element_set_state(m_playBin, GST_STATE_PAUSED); + GstState state; + GstState pending; + + gst_element_get_state(m_playBin, &state, &pending, 0); + if (state != GST_STATE_PAUSED && pending != GST_STATE_PAUSED) { + LOG_VERBOSE(Media, "Pause"); + gst_element_set_state(m_playBin, GST_STATE_PAUSED); + } } float MediaPlayerPrivate::duration() const @@ -202,7 +265,7 @@ float MediaPlayerPrivate::duration() const GstFormat timeFormat = GST_FORMAT_TIME; gint64 timeLength = 0; - if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeFormat != GST_FORMAT_TIME || timeLength == GST_CLOCK_TIME_NONE) { + if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeFormat != GST_FORMAT_TIME || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE) { LOG_VERBOSE(Media, "Time duration query failed."); return numeric_limits<float>::infinity(); } @@ -221,23 +284,11 @@ float MediaPlayerPrivate::currentTime() const if (m_errorOccured) return 0; - float ret = 0.0; + if (m_seeking) + return m_seekTime; - GstQuery* query = gst_query_new_position(GST_FORMAT_TIME); - if (!gst_element_query(m_playBin, query)) { - LOG_VERBOSE(Media, "Position query failed..."); - gst_query_unref(query); - return ret; - } + return playbackPosition(m_playBin); - gint64 position; - gst_query_parse_position(query, 0, &position); - ret = (float) (position / 1000000000.0); - LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); - - gst_query_unref(query); - - return ret; } void MediaPlayerPrivate::seek(float time) @@ -260,8 +311,10 @@ void MediaPlayerPrivate::seek(float time) GST_SEEK_TYPE_SET, sec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) LOG_VERBOSE(Media, "Seek to %f failed", time); - else + else { m_seeking = true; + m_seekTime = sec; + } } void MediaPlayerPrivate::setEndTime(float time) @@ -310,10 +363,10 @@ IntSize MediaPlayerPrivate::naturalSize() const gfloat pixelAspectRatio; gint pixelAspectRatioNumerator, pixelAspectRatioDenominator; - if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps) || - !gst_video_format_parse_caps(caps, NULL, &width, &height) || - !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, - &pixelAspectRatioDenominator)) { + if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps) + || !gst_video_format_parse_caps(caps, 0, &width, &height) + || !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, + &pixelAspectRatioDenominator)) { gst_object_unref(GST_OBJECT(pad)); return IntSize(); } @@ -353,16 +406,50 @@ void MediaPlayerPrivate::setVolume(float volume) void MediaPlayerPrivate::setRate(float rate) { - if (rate == 0.0) { - gst_element_set_state(m_playBin, GST_STATE_PAUSED); + GstState state; + GstState pending; + + gst_element_get_state(m_playBin, &state, &pending, 0); + if ((state != GST_STATE_PLAYING && state != GST_STATE_PAUSED) + || (pending == GST_STATE_PAUSED)) return; - } if (m_isStreaming) return; + m_changingRate = true; + float currentPosition = playbackPosition(m_playBin) * GST_SECOND; + GstSeekFlags flags = (GstSeekFlags)(GST_SEEK_FLAG_FLUSH); + gint64 start, end; + bool mute = false; + LOG_VERBOSE(Media, "Set Rate to %f", rate); - seek(currentTime()); + if (rate >= 0) { + // Mute the sound if the playback rate is too extreme. + // TODO: in other cases we should perform pitch adjustments. + mute = (bool) (rate < 0.8 || rate > 2); + start = currentPosition; + end = GST_CLOCK_TIME_NONE; + } else { + start = 0; + mute = true; + + // If we are at beginning of media, start from the end to + // avoid immediate EOS. + if (currentPosition <= 0) + end = duration() * GST_SECOND; + else + end = currentPosition; + } + + LOG_VERBOSE(Media, "Need to mute audio: %d", (int) mute); + + if (!gst_element_seek(m_playBin, rate, GST_FORMAT_TIME, flags, + GST_SEEK_TYPE_SET, start, + GST_SEEK_TYPE_SET, end)) + LOG_VERBOSE(Media, "Set rate to %f failed", rate); + else + g_object_set(m_playBin, "mute", mute, NULL); } int MediaPlayerPrivate::dataRate() const @@ -497,6 +584,11 @@ void MediaPlayerPrivate::updateStates() } else m_paused = true; + if (m_changingRate) { + m_player->rateChanged(); + m_changingRate = false; + } + if (m_seeking) { shouldUpdateAfterSeek = true; m_seeking = false; @@ -560,11 +652,6 @@ void MediaPlayerPrivate::loadStateChanged() updateStates(); } -void MediaPlayerPrivate::rateChanged() -{ - updateStates(); -} - void MediaPlayerPrivate::sizeChanged() { notImplemented(); @@ -624,54 +711,36 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) return; int width = 0, height = 0; - int pixelAspectRatioNumerator = 0; - int pixelAspectRatioDenominator = 0; - double doublePixelAspectRatioNumerator = 0; - double doublePixelAspectRatioDenominator = 0; - double displayWidth; - double displayHeight; - double scale, gapHeight, gapWidth; - GstCaps *caps = gst_buffer_get_caps(m_buffer); + GstVideoFormat format; - if (!gst_video_format_parse_caps(caps, NULL, &width, &height) || - !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, &pixelAspectRatioDenominator)) { + if (!gst_video_format_parse_caps(caps, &format, &width, &height)) { gst_caps_unref(caps); return; } - displayWidth = width; - displayHeight = height; - doublePixelAspectRatioNumerator = pixelAspectRatioNumerator; - doublePixelAspectRatioDenominator = pixelAspectRatioDenominator; + cairo_format_t cairoFormat; + if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA) + cairoFormat = CAIRO_FORMAT_ARGB32; + else + cairoFormat = CAIRO_FORMAT_RGB24; cairo_t* cr = context->platformContext(); cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(m_buffer), - CAIRO_FORMAT_RGB24, + cairoFormat, width, height, 4 * width); cairo_save(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - - displayWidth *= doublePixelAspectRatioNumerator / doublePixelAspectRatioDenominator; - displayHeight *= doublePixelAspectRatioDenominator / doublePixelAspectRatioNumerator; - scale = MIN (rect.width () / displayWidth, rect.height () / displayHeight); - displayWidth *= scale; - displayHeight *= scale; + // translate and scale the context to correct size + cairo_translate(cr, rect.x(), rect.y()); + cairo_scale(cr, static_cast<double>(rect.width()) / width, static_cast<double>(rect.height()) / height); - // Calculate gap between border an picture - gapWidth = (rect.width() - displayWidth) / 2.0; - gapHeight = (rect.height() - displayHeight) / 2.0; - - // paint the rectangle on the context and draw the surface inside. - cairo_translate(cr, rect.x() + gapWidth, rect.y() + gapHeight); - cairo_rectangle(cr, 0, 0, rect.width(), rect.height()); - cairo_scale(cr, doublePixelAspectRatioNumerator / doublePixelAspectRatioDenominator, - doublePixelAspectRatioDenominator / doublePixelAspectRatioNumerator); - cairo_scale(cr, scale, scale); + // And paint it. cairo_set_source_surface(cr, src, 0, 0); + cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_PAD); + cairo_rectangle(cr, 0, 0, width, height); cairo_fill(cr); cairo_restore(cr); @@ -688,76 +757,91 @@ static HashSet<String> mimeTypeCache() static bool typeListInitialized = false; if (!typeListInitialized) { - // These subtypes are already beeing supported by WebKit itself - HashSet<String> ignoredApplicationSubtypes; - ignoredApplicationSubtypes.add(String("javascript")); - ignoredApplicationSubtypes.add(String("ecmascript")); - ignoredApplicationSubtypes.add(String("x-javascript")); - ignoredApplicationSubtypes.add(String("xml")); - ignoredApplicationSubtypes.add(String("xhtml+xml")); - ignoredApplicationSubtypes.add(String("rss+xml")); - ignoredApplicationSubtypes.add(String("atom+xml")); - ignoredApplicationSubtypes.add(String("x-ftp-directory")); - ignoredApplicationSubtypes.add(String("x-java-applet")); - ignoredApplicationSubtypes.add(String("x-java-bean")); - ignoredApplicationSubtypes.add(String("x-java-vm")); - ignoredApplicationSubtypes.add(String("x-shockwave-flash")); + // Build a whitelist of mime-types known to be supported by + // GStreamer. + HashSet<String> handledApplicationSubtypes; + handledApplicationSubtypes.add(String("ogg")); + handledApplicationSubtypes.add(String("x-3gp")); + handledApplicationSubtypes.add(String("vnd.rn-realmedia")); + handledApplicationSubtypes.add(String("x-pn-realaudio")); GList* factories = gst_type_find_factory_get_list(); for (GList* iterator = factories; iterator; iterator = iterator->next) { GstTypeFindFactory* factory = GST_TYPE_FIND_FACTORY(iterator->data); GstCaps* caps = gst_type_find_factory_get_caps(factory); - // Splitting the capability by comma and taking the first part - // as capability can be something like "audio/x-wavpack, framed=(boolean)false" - GOwnPtr<gchar> capabilityString(gst_caps_to_string(caps)); - gchar** capability = g_strsplit(capabilityString.get(), ",", 2); - gchar** mimetype = g_strsplit(capability[0], "/", 2); - - // GStreamer plugins can be capable of supporting types which WebKit supports - // by default. In that case, we should not consider these types supportable by GStreamer. - // Examples of what GStreamer can support but should not be added: - // text/plain, text/html, image/jpeg, application/xml - if (g_str_equal(mimetype[0], "audio") || - g_str_equal(mimetype[0], "video") || - (g_str_equal(mimetype[0], "application") && - !ignoredApplicationSubtypes.contains(String(mimetype[1])))) { - cache.add(String(capability[0])); - - // These formats are supported by GStreamer, but not correctly advertised - if (g_str_equal(capability[0], "video/x-h264") || - g_str_equal(capability[0], "audio/x-m4a")) { + if (!caps) + continue; + + for (guint structureIndex = 0; structureIndex < gst_caps_get_size(caps); structureIndex++) { + GstStructure* structure = gst_caps_get_structure(caps, structureIndex); + const gchar* name = gst_structure_get_name(structure); + bool cached = false; + + // These formats are supported by GStreamer, but not + // correctly advertised. + if (g_str_equal(name, "video/x-h264") + || g_str_equal(name, "audio/x-m4a")) { cache.add(String("video/mp4")); cache.add(String("audio/aac")); + cached = true; } - if (g_str_equal(capability[0], "video/x-theora")) + if (g_str_equal(name, "video/x-theora")) { cache.add(String("video/ogg")); + cached = true; + } - if (g_str_equal(capability[0], "audio/x-wav")) - cache.add(String("audio/wav")); + if (g_str_equal(name, "audio/x-vorbis")) { + cache.add(String("audio/ogg")); + cached = true; + } - if (g_str_equal(capability[0], "audio/mpeg")) { - // This is what we are handling: mpegversion=(int)1, layer=(int)[ 1, 3 ] - gchar** versionAndLayer = g_strsplit(capability[1], ",", 2); + if (g_str_equal(name, "audio/x-wav")) { + cache.add(String("audio/wav")); + cached = true; + } - if (g_str_has_suffix (versionAndLayer[0], "(int)1")) { - for (int i = 0; versionAndLayer[1][i] != '\0'; i++) { - if (versionAndLayer[1][i] == '1') + if (g_str_equal(name, "audio/mpeg")) { + cache.add(String(name)); + cached = true; + + // This is what we are handling: + // mpegversion=(int)1, layer=(int)[ 1, 3 ] + gint mpegVersion = 0; + if (gst_structure_get_int(structure, "mpegversion", &mpegVersion) && (mpegVersion == 1)) { + const GValue* layer = gst_structure_get_value(structure, "layer"); + if (G_VALUE_TYPE(layer) == GST_TYPE_INT_RANGE) { + gint minLayer = gst_value_get_int_range_min(layer); + gint maxLayer = gst_value_get_int_range_max(layer); + if (minLayer <= 1 <= maxLayer) cache.add(String("audio/mp1")); - else if (versionAndLayer[1][i] == '2') + if (minLayer <= 2 <= maxLayer) cache.add(String("audio/mp2")); - else if (versionAndLayer[1][i] == '3') + if (minLayer <= 3 <= maxLayer) cache.add(String("audio/mp3")); } } + } - g_strfreev(versionAndLayer); + if (!cached) { + // GStreamer plugins can be capable of supporting + // types which WebKit supports by default. In that + // case, we should not consider these types + // supportable by GStreamer. Examples of what + // GStreamer can support but should not be added: + // text/plain, text/html, image/jpeg, + // application/xml + gchar** mimetype = g_strsplit(name, "/", 2); + if (g_str_equal(mimetype[0], "audio") + || g_str_equal(mimetype[0], "video") + || (g_str_equal(mimetype[0], "application") + && handledApplicationSubtypes.contains(String(mimetype[1])))) + cache.add(String(name)); + + g_strfreev(mimetype); } } - - g_strfreev(capability); - g_strfreev(mimetype); } gst_plugin_feature_list_free(factories); diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h index 54da420..6ab8edb 100644 --- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h @@ -29,6 +29,7 @@ #include <cairo.h> #include <glib.h> +#include <gst/gst.h> typedef struct _WebKitVideoSink WebKitVideoSink; typedef struct _GstBuffer GstBuffer; @@ -89,7 +90,6 @@ namespace WebCore { void setSize(const IntSize&); void loadStateChanged(); - void rateChanged(); void sizeChanged(); void timeChanged(); void volumeChanged(); @@ -109,7 +109,7 @@ namespace WebCore { static void getSupportedTypes(HashSet<String>&); static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); - static bool isAvailable() { return true; } + static bool isAvailable(); void updateStates(); void cancelSeek(); @@ -124,6 +124,8 @@ namespace WebCore { GstElement* m_playBin; GstElement* m_videoSink; GstElement* m_source; + GstClockTime m_seekTime; + bool m_changingRate; float m_endTime; bool m_isEndReached; MediaPlayer::NetworkState m_networkState; diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp index 9a616f4..df25393 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp +++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp @@ -39,8 +39,6 @@ #include "FontDescription.h" #include "GlyphBuffer.h" #include <cairo.h> -#include <unicode/uchar.h> -#include <unicode/unorm.h> #include <wtf/MathExtras.h> namespace WebCore { diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp index b5e1a8b..5e0f8e2 100644 --- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp +++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp @@ -37,21 +37,15 @@ static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, // CAIRO_FORMAT_RGB24 used to render the video buffers is little/big endian dependant. #if G_BYTE_ORDER == G_LITTLE_ENDIAN - GST_STATIC_CAPS(GST_VIDEO_CAPS_BGRx) + GST_STATIC_CAPS(GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_BGRA) #else - GST_STATIC_CAPS(GST_VIDEO_CAPS_xRGB) + GST_STATIC_CAPS(GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_ARGB) #endif ); GST_DEBUG_CATEGORY_STATIC(webkit_video_sink_debug); #define GST_CAT_DEFAULT webkit_video_sink_debug -static GstElementDetails webkit_video_sink_details = - GST_ELEMENT_DETAILS((gchar*) "WebKit video sink", - (gchar*) "Sink/Video", - (gchar*) "Sends video data from a GStreamer pipeline to a Cairo surface", - (gchar*) "Alp Toker <alp@atoker.com>"); - enum { REPAINT_REQUESTED, LAST_SIGNAL @@ -98,7 +92,9 @@ webkit_video_sink_base_init(gpointer g_class) GstElementClass* element_class = GST_ELEMENT_CLASS(g_class); gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sinktemplate)); - gst_element_class_set_details(element_class, &webkit_video_sink_details); + gst_element_class_set_details_simple(element_class, "WebKit video sink", + "Sink/Video", "Sends video data from a GStreamer pipeline to a Cairo surface", + "Alp Toker <alp@atoker.com>"); } static void @@ -129,11 +125,6 @@ webkit_video_sink_timeout_func(gpointer data) return FALSE; } - if (G_UNLIKELY(!GST_BUFFER_CAPS(buffer))) { - buffer = gst_buffer_make_metadata_writable(buffer); - gst_buffer_set_caps(buffer, GST_PAD_CAPS(GST_BASE_SINK_PAD(sink))); - } - g_signal_emit(sink, webkit_video_sink_signals[REPAINT_REQUESTED], 0, buffer); gst_buffer_unref(buffer); g_cond_signal(priv->data_cond); @@ -157,6 +148,71 @@ webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer) priv->buffer = gst_buffer_ref(buffer); + // For the unlikely case where the buffer has no caps, the caps + // are implicitely the caps of the pad. This shouldn't happen. + if (G_UNLIKELY(!GST_BUFFER_CAPS(buffer))) { + buffer = priv->buffer = gst_buffer_make_metadata_writable(priv->buffer); + gst_buffer_set_caps(priv->buffer, GST_PAD_CAPS(GST_BASE_SINK_PAD(bsink))); + } + + GstCaps *caps = GST_BUFFER_CAPS(buffer); + GstVideoFormat format; + int width, height; + if (G_UNLIKELY(!gst_video_format_parse_caps(caps, &format, &width, &height))) { + gst_buffer_unref(buffer); + g_mutex_unlock(priv->buffer_mutex); + return GST_FLOW_ERROR; + } + + // Cairo's ARGB has pre-multiplied alpha while GStreamer's doesn't. + // Here we convert to Cairo's ARGB. + if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA) { + // Because GstBaseSink::render() only owns the buffer reference in the + // method scope we can't use gst_buffer_make_writable() here. Also + // The buffer content should not be changed here because the same buffer + // could be passed multiple times to this method (in theory) + GstBuffer *newBuffer = gst_buffer_try_new_and_alloc(GST_BUFFER_SIZE(buffer)); + + // Check if allocation failed + if (G_UNLIKELY(!newBuffer)) { + gst_buffer_unref(buffer); + g_mutex_unlock(priv->buffer_mutex); + return GST_FLOW_ERROR; + } + + gst_buffer_copy_metadata(newBuffer, buffer, (GstBufferCopyFlags) GST_BUFFER_COPY_ALL); + + // We don't use Color::premultipliedARGBFromColor() here because + // one function call per video pixel is just too expensive: + // For 720p/PAL for example this means 1280*720*25=23040000 + // function calls per second! + unsigned short alpha; + const guint8 *source = GST_BUFFER_DATA(buffer); + guint8 *destination = GST_BUFFER_DATA(newBuffer); + + for (int x = 0; x < height; x++) { + for (int y = 0; y < width; y++) { +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + alpha = source[3]; + destination[0] = (source[0] * alpha + 128) / 255; + destination[1] = (source[1] * alpha + 128) / 255; + destination[2] = (source[2] * alpha + 128) / 255; + destination[3] = alpha; +#else + alpha = source[0]; + destination[0] = alpha; + destination[1] = (source[1] * alpha + 128) / 255; + destination[2] = (source[2] * alpha + 128) / 255; + destination[3] = (source[3] * alpha + 128) / 255; +#endif + source += 4; + destination += 4; + } + } + gst_buffer_unref(buffer); + buffer = priv->buffer = newBuffer; + } + // Use HIGH_IDLE+20 priority, like Gtk+ for redrawing operations. priv->timeout_id = g_timeout_add_full(G_PRIORITY_HIGH_IDLE + 20, 0, webkit_video_sink_timeout_func, diff --git a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp index c23b8a9..4728d56 100644 --- a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp +++ b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp @@ -152,7 +152,7 @@ void GraphicsContext::drawConvexPolygon(size_t pointsLength, const FloatPoint* p m_data->m_view->StrokePolygon(bPoints, pointsLength, true, getHaikuStrokeStyle()); } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -169,7 +169,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) return; } -void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) { if (paintingDisabled() || !color.alpha()) return; @@ -477,7 +477,7 @@ void GraphicsContext::setPlatformFont(const Font& font) m_data->m_view->SetFont(font.primaryFont()->platformData().font()); } -void GraphicsContext::setPlatformStrokeColor(const Color& color) +void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -519,7 +519,7 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness) m_data->m_view->SetPenSize(thickness); } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -532,7 +532,7 @@ void GraphicsContext::clearPlatformShadow() notImplemented(); } -void GraphicsContext::setPlatformShadow(IntSize const&, int, Color const&) +void GraphicsContext::setPlatformShadow(IntSize const&, int, Color const&, ColorSpace) { notImplemented(); } diff --git a/WebCore/platform/graphics/haiku/IconHaiku.cpp b/WebCore/platform/graphics/haiku/IconHaiku.cpp index dccac4a..3663ee2 100644 --- a/WebCore/platform/graphics/haiku/IconHaiku.cpp +++ b/WebCore/platform/graphics/haiku/IconHaiku.cpp @@ -36,12 +36,6 @@ Icon::~Icon() notImplemented(); } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) -{ - notImplemented(); - return 0; -} - PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { notImplemented(); diff --git a/WebCore/platform/graphics/haiku/ImageHaiku.cpp b/WebCore/platform/graphics/haiku/ImageHaiku.cpp index 323d6ab..df08822 100644 --- a/WebCore/platform/graphics/haiku/ImageHaiku.cpp +++ b/WebCore/platform/graphics/haiku/ImageHaiku.cpp @@ -83,7 +83,7 @@ void BitmapImage::invalidatePlatformData() } // Drawing Routines -void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, CompositeOperator op) +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { startAnimation(); @@ -92,7 +92,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR return; if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, dst, solidColor(), op); + fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op); return; } @@ -109,7 +109,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR ctxt->restore(); } -void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const TransformationMatrix& patternTransform, const FloatPoint& srcPoint, CompositeOperator op, const FloatRect& dstRect) +void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const TransformationMatrix& patternTransform, const FloatPoint& srcPoint, ColorSpace, CompositeOperator op, const FloatRect& dstRect) { // FIXME: finish this to support also phased position (srcPoint) startAnimation(); diff --git a/WebCore/platform/graphics/mac/CoreTextController.cpp b/WebCore/platform/graphics/mac/ComplexTextController.cpp index b2682e4..265b2c3 100644 --- a/WebCore/platform/graphics/mac/CoreTextController.cpp +++ b/WebCore/platform/graphics/mac/ComplexTextController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,30 +10,24 @@ * 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. ``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 - * 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. + * 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 "CoreTextController.h" - -#if USE(CORE_TEXT) +#include "ComplexTextController.h" #include "CharacterNames.h" #include "Font.h" -#include "FontCache.h" -#include "SimpleFontData.h" #include "TextBreakIterator.h" -#include <wtf/MathExtras.h> using namespace std; @@ -53,54 +47,7 @@ static inline CGFloat ceilCGFloat(CGFloat f) return static_cast<CGFloat>(ceil(f)); } -CoreTextController::CoreTextRun::CoreTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength) - : m_CTRun(ctRun) - , m_fontData(fontData) - , m_characters(characters) - , m_stringLocation(stringLocation) - , m_stringLength(stringLength) -{ - m_glyphCount = CTRunGetGlyphCount(ctRun); - m_indices = CTRunGetStringIndicesPtr(ctRun); - if (!m_indices) { - m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); - CFDataIncreaseLength(m_indicesData.get(), m_glyphCount * sizeof(CFIndex)); - m_indices = reinterpret_cast<const CFIndex*>(CFDataGetMutableBytePtr(m_indicesData.get())); - CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), const_cast<CFIndex*>(m_indices)); - } -} - -// Missing glyphs run constructor. Core Text will not generate a run of missing glyphs, instead falling back on -// glyphs from LastResort. We want to use the primary font's missing glyph in order to match the fast text code path. -CoreTextController::CoreTextRun::CoreTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) - : m_fontData(fontData) - , m_characters(characters) - , m_stringLocation(stringLocation) - , m_stringLength(stringLength) -{ - Vector<CFIndex, 16> indices; - unsigned r = 0; - while (r < stringLength) { - indices.append(r); - if (U_IS_SURROGATE(characters[r])) { - ASSERT(r + 1 < stringLength); - ASSERT(U_IS_SURROGATE_LEAD(characters[r])); - ASSERT(U_IS_TRAIL(characters[r + 1])); - r += 2; - } else - r++; - } - m_glyphCount = indices.size(); - if (!ltr) { - for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end) - std::swap(indices[r], indices[end]); - } - m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); - CFDataAppendBytes(m_indicesData.get(), reinterpret_cast<const UInt8*>(indices.data()), m_glyphCount * sizeof(CFIndex)); - m_indices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_indicesData.get())); -} - -CoreTextController::CoreTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts) +ComplexTextController::ComplexTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts) : m_font(*font) , m_run(run) , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection) @@ -111,6 +58,7 @@ CoreTextController::CoreTextController(const Font* font, const TextRun& run, boo , m_numGlyphsSoFar(0) , m_currentRun(0) , m_glyphInCurrentRun(0) + , m_characterInCurrentGlyph(0) , m_finalRoundingWidth(0) , m_fallbackFonts(fallbackFonts) , m_lastRoundingGlyph(0) @@ -130,16 +78,12 @@ CoreTextController::CoreTextController(const Font* font, const TextRun& run, boo m_padPerSpace = ceilf(m_run.padding() / numSpaces); } - collectCoreTextRuns(); + collectComplexTextRuns(); adjustGlyphsAndAdvances(); } -int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) +int ComplexTextController::offsetForPosition(int h, bool includePartialGlyphs) { - // FIXME: For positions occurring within a ligature, we should return the closest "ligature caret" or - // approximate it by dividing the width of the ligature by the number of characters it encompasses. - // However, Core Text does not expose a low-level API for directly finding - // out how many characters a ligature encompasses (the "attachment count"). if (h >= m_totalWidth) return m_run.ltr() ? m_end : 0; if (h < 0) @@ -147,17 +91,27 @@ int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) CGFloat x = h; - size_t runCount = m_coreTextRuns.size(); + size_t runCount = m_complexTextRuns.size(); size_t offsetIntoAdjustedGlyphs = 0; for (size_t r = 0; r < runCount; ++r) { - const CoreTextRun& coreTextRun = m_coreTextRuns[r]; - for (unsigned j = 0; j < coreTextRun.glyphCount(); ++j) { + const ComplexTextRun& complexTextRun = *m_complexTextRuns[r]; + for (unsigned j = 0; j < complexTextRun.glyphCount(); ++j) { CGFloat adjustedAdvance = m_adjustedAdvances[offsetIntoAdjustedGlyphs + j].width; - if (x <= adjustedAdvance) { - CFIndex hitIndex = coreTextRun.indexAt(j); - int stringLength = coreTextRun.stringLength(); - TextBreakIterator* cursorPositionIterator = cursorMovementIterator(coreTextRun.characters(), stringLength); + if (x < adjustedAdvance) { + CFIndex hitGlyphStart = complexTextRun.indexAt(j); + CFIndex hitGlyphEnd; + if (m_run.ltr()) + hitGlyphEnd = max<CFIndex>(hitGlyphStart, j + 1 < complexTextRun.glyphCount() ? complexTextRun.indexAt(j + 1) : complexTextRun.stringLength()); + else + hitGlyphEnd = max<CFIndex>(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : complexTextRun.stringLength()); + + // FIXME: Instead of dividing the glyph's advance equially between the characters, this + // could use the glyph's "ligature carets". However, there is no Core Text API to get the + // ligature carets. + CFIndex hitIndex = hitGlyphStart + (hitGlyphEnd - hitGlyphStart) * (m_run.ltr() ? x / adjustedAdvance : 1 - x / adjustedAdvance); + int stringLength = complexTextRun.stringLength(); + TextBreakIterator* cursorPositionIterator = cursorMovementIterator(complexTextRun.characters(), stringLength); int clusterStart; if (isTextBreak(cursorPositionIterator, hitIndex)) clusterStart = hitIndex; @@ -168,45 +122,49 @@ int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) } if (!includePartialGlyphs) - return coreTextRun.stringLocation() + clusterStart; + return complexTextRun.stringLocation() + clusterStart; int clusterEnd = textBreakFollowing(cursorPositionIterator, hitIndex); if (clusterEnd == TextBreakDone) clusterEnd = stringLength; - CGFloat clusterWidth = adjustedAdvance; - // FIXME: The search stops at the boundaries of coreTextRun. In theory, it should go on into neighboring CoreTextRuns + CGFloat clusterWidth; + // FIXME: The search stops at the boundaries of complexTextRun. In theory, it should go on into neighboring ComplexTextRuns // derived from the same CTLine. In practice, we do not expect there to be more than one CTRun in a CTLine, as no // reordering and on font fallback should occur within a CTLine. if (clusterEnd - clusterStart > 1) { + clusterWidth = adjustedAdvance; int firstGlyphBeforeCluster = j - 1; - while (firstGlyphBeforeCluster >= 0 && coreTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) { + while (firstGlyphBeforeCluster >= 0 && complexTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) { CGFloat width = m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width; clusterWidth += width; x += width; firstGlyphBeforeCluster--; } unsigned firstGlyphAfterCluster = j + 1; - while (firstGlyphAfterCluster < coreTextRun.glyphCount() && coreTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) { + while (firstGlyphAfterCluster < complexTextRun.glyphCount() && complexTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) { clusterWidth += m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width; firstGlyphAfterCluster++; } + } else { + clusterWidth = adjustedAdvance / (hitGlyphEnd - hitGlyphStart); + x -= clusterWidth * (m_run.ltr() ? hitIndex - hitGlyphStart : hitGlyphEnd - hitIndex - 1); } if (x <= clusterWidth / 2) - return coreTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd); + return complexTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd); else - return coreTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart); + return complexTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart); } x -= adjustedAdvance; } - offsetIntoAdjustedGlyphs += coreTextRun.glyphCount(); + offsetIntoAdjustedGlyphs += complexTextRun.glyphCount(); } ASSERT_NOT_REACHED(); return 0; } -void CoreTextController::collectCoreTextRuns() +void ComplexTextController::collectComplexTextRuns() { if (!m_end) return; @@ -227,7 +185,7 @@ void CoreTextController::collectCoreTextRuns() static const UChar hyphen = '-'; if (hasTrailingSoftHyphen && m_run.rtl()) { - collectCoreTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); + collectComplexTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); indexOfFontTransition--; curr--; } @@ -290,7 +248,7 @@ void CoreTextController::collectCoreTextRuns() if (nextGlyphData.fontData != glyphData.fontData || nextIsSmallCaps != isSmallCaps || !nextGlyphData.glyph != !glyphData.glyph) { int itemStart = m_run.rtl() ? index + 1 : indexOfFontTransition; int itemLength = m_run.rtl() ? indexOfFontTransition - index : index - indexOfFontTransition; - collectCoreTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, glyphData.glyph ? glyphData.fontData : 0); + collectComplexTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, glyphData.glyph ? glyphData.fontData : 0); indexOfFontTransition = index; } } @@ -298,19 +256,15 @@ void CoreTextController::collectCoreTextRuns() int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : m_end - indexOfFontTransition - (hasTrailingSoftHyphen ? 1 : 0); if (itemLength) { int itemStart = m_run.rtl() ? 0 : indexOfFontTransition; - collectCoreTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, nextGlyphData.glyph ? nextGlyphData.fontData : 0); + collectComplexTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, nextGlyphData.glyph ? nextGlyphData.fontData : 0); } if (hasTrailingSoftHyphen && m_run.ltr()) - collectCoreTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); + collectComplexTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); } -void CoreTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) +void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) { - // FIXME: For offsets falling inside a ligature, we should advance only as far as the appropriate "ligature caret" - // or divide the width of the ligature by the number of offsets it encompasses and make an advance proportional - // to the offsets into the ligature. However, Core Text does not expose a low-level API for - // directly finding out how many characters a ligature encompasses (the "attachment count"). if (static_cast<int>(offset) > m_end) offset = m_end; @@ -319,24 +273,44 @@ void CoreTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) m_currentCharacter = offset; - size_t runCount = m_coreTextRuns.size(); + size_t runCount = m_complexTextRuns.size(); bool ltr = m_run.ltr(); unsigned k = ltr ? m_numGlyphsSoFar : m_adjustedGlyphs.size() - 1 - m_numGlyphsSoFar; while (m_currentRun < runCount) { - const CoreTextRun& coreTextRun = m_coreTextRuns[ltr ? m_currentRun : runCount - 1 - m_currentRun]; - size_t glyphCount = coreTextRun.glyphCount(); + const ComplexTextRun& complexTextRun = *m_complexTextRuns[ltr ? m_currentRun : runCount - 1 - m_currentRun]; + size_t glyphCount = complexTextRun.glyphCount(); unsigned g = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun; while (m_glyphInCurrentRun < glyphCount) { - if (coreTextRun.indexAt(g) + coreTextRun.stringLocation() >= m_currentCharacter) - return; + unsigned glyphStartOffset = complexTextRun.indexAt(g); + unsigned glyphEndOffset; + if (ltr) + glyphEndOffset = max<unsigned>(glyphStartOffset, g + 1 < glyphCount ? complexTextRun.indexAt(g + 1) : complexTextRun.stringLength()); + else + glyphEndOffset = max<unsigned>(glyphStartOffset, g > 0 ? complexTextRun.indexAt(g - 1) : complexTextRun.stringLength()); + CGSize adjustedAdvance = m_adjustedAdvances[k]; - if (glyphBuffer) - glyphBuffer->add(m_adjustedGlyphs[k], coreTextRun.fontData(), adjustedAdvance); - m_runWidthSoFar += adjustedAdvance.width; + + if (glyphStartOffset + complexTextRun.stringLocation() >= m_currentCharacter) + return; + + if (glyphBuffer && !m_characterInCurrentGlyph) + glyphBuffer->add(m_adjustedGlyphs[k], complexTextRun.fontData(), adjustedAdvance); + + unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph; + m_characterInCurrentGlyph = min(m_currentCharacter - complexTextRun.stringLocation(), glyphEndOffset) - glyphStartOffset; + // FIXME: Instead of dividing the glyph's advance equially between the characters, this + // could use the glyph's "ligature carets". However, there is no Core Text API to get the + // ligature carets. + m_runWidthSoFar += adjustedAdvance.width * (m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset); + + if (glyphEndOffset + complexTextRun.stringLocation() > m_currentCharacter) + return; + m_numGlyphsSoFar++; m_glyphInCurrentRun++; + m_characterInCurrentGlyph = 0; if (ltr) { g++; k++; @@ -352,100 +326,35 @@ void CoreTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) m_runWidthSoFar += m_finalRoundingWidth; } -void CoreTextController::collectCoreTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData) -{ - if (!fontData) { - // Create a run of missing glyphs from the primary font. - m_coreTextRuns.append(CoreTextRun(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr())); - return; - } - - if (m_fallbackFonts && fontData != m_font.primaryFont()) - m_fallbackFonts->add(fontData); - - RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull)); - - RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes(m_font.fontDescription().textRenderingMode()))); - - RetainPtr<CTTypesetterRef> typesetter; - - if (!m_mayUseNaturalWritingDirection || m_run.directionalOverride()) { - static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel }; - static const void* ltrOptionValues[] = { kCFBooleanFalse }; - static const void* rtlOptionValues[] = { kCFBooleanTrue }; - static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - typesetter.adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions)); - } else - typesetter.adoptCF(CTTypesetterCreateWithAttributedString(attributedString.get())); - - RetainPtr<CTLineRef> line(AdoptCF, CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0))); - - CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); - - CFIndex runCount = CFArrayGetCount(runArray); - - for (CFIndex r = 0; r < runCount; r++) { - CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r)); - ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID()); - m_coreTextRuns.append(CoreTextRun(ctRun, fontData, cp, stringLocation, length)); - } -} - -void CoreTextController::adjustGlyphsAndAdvances() +void ComplexTextController::adjustGlyphsAndAdvances() { - size_t runCount = m_coreTextRuns.size(); + size_t runCount = m_complexTextRuns.size(); for (size_t r = 0; r < runCount; ++r) { - const CoreTextRun& coreTextRun = m_coreTextRuns[r]; - unsigned glyphCount = coreTextRun.glyphCount(); - const SimpleFontData* fontData = coreTextRun.fontData(); - - Vector<CGGlyph, 256> glyphsVector; - const CGGlyph* glyphs; - - Vector<CGSize, 256> advancesVector; - const CGSize* advances; - - if (coreTextRun.ctRun()) { - glyphs = CTRunGetGlyphsPtr(coreTextRun.ctRun()); - if (!glyphs) { - glyphsVector.grow(glyphCount); - CTRunGetGlyphs(coreTextRun.ctRun(), CFRangeMake(0, 0), glyphsVector.data()); - glyphs = glyphsVector.data(); - } + const ComplexTextRun& complexTextRun = *m_complexTextRuns[r]; + unsigned glyphCount = complexTextRun.glyphCount(); + const SimpleFontData* fontData = complexTextRun.fontData(); - advances = CTRunGetAdvancesPtr(coreTextRun.ctRun()); - if (!advances) { - advancesVector.grow(glyphCount); - CTRunGetAdvances(coreTextRun.ctRun(), CFRangeMake(0, 0), advancesVector.data()); - advances = advancesVector.data(); - } - } else { - // Synthesize a run of missing glyphs. - glyphsVector.fill(0, glyphCount); - glyphs = glyphsVector.data(); - advancesVector.fill(CGSizeMake(fontData->widthForGlyph(0), 0), glyphCount); - advances = advancesVector.data(); - } + const CGGlyph* glyphs = complexTextRun.glyphs(); + const CGSize* advances = complexTextRun.advances(); bool lastRun = r + 1 == runCount; - const UChar* cp = coreTextRun.characters(); + const UChar* cp = complexTextRun.characters(); CGFloat roundedSpaceWidth = roundCGFloat(fontData->spaceWidth()); bool roundsAdvances = !m_font.isPrinterFont() && fontData->platformData().roundsGlyphAdvances(); bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_padding) && !m_run.spacingDisabled(); for (unsigned i = 0; i < glyphCount; i++) { - CFIndex characterIndex = coreTextRun.indexAt(i); + CFIndex characterIndex = complexTextRun.indexAt(i); UChar ch = *(cp + characterIndex); bool lastGlyph = lastRun && i + 1 == glyphCount; UChar nextCh; if (lastGlyph) nextCh = ' '; else if (i + 1 < glyphCount) - nextCh = *(cp + coreTextRun.indexAt(i + 1)); + nextCh = *(cp + complexTextRun.indexAt(i + 1)); else - nextCh = *(m_coreTextRuns[r + 1].characters() + m_coreTextRuns[r + 1].indexAt(0)); + nextCh = *(m_complexTextRuns[r + 1]->characters() + m_complexTextRuns[r + 1]->indexAt(0)); bool treatAsSpace = Font::treatAsSpace(ch); CGGlyph glyph = treatAsSpace ? fontData->spaceGlyph() : glyphs[i]; @@ -533,5 +442,3 @@ void CoreTextController::adjustGlyphsAndAdvances() } } // namespace WebCore - -#endif // USE(CORE_TEXT) diff --git a/WebCore/platform/graphics/mac/ComplexTextController.h b/WebCore/platform/graphics/mac/ComplexTextController.h new file mode 100644 index 0000000..7a915e2 --- /dev/null +++ b/WebCore/platform/graphics/mac/ComplexTextController.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2007, 2008, 2009 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. + */ + +#ifndef ComplexTextController_h +#define ComplexTextController_h + +#include "GlyphBuffer.h" +#include <wtf/HashSet.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RetainPtr.h> +#include <wtf/Vector.h> +#include <wtf/unicode/Unicode.h> + +namespace WebCore { + +class Font; +class SimpleFontData; +class TextRun; + +class ComplexTextController { +public: + ComplexTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const SimpleFontData*>* fallbackFonts = 0); + + // Advance and emit glyphs up to the specified character. + void advance(unsigned to, GlyphBuffer* = 0); + + // Compute the character offset for a given x coordinate. + int offsetForPosition(int x, bool includePartialGlyphs); + + // Returns the width of everything we've consumed so far. + float runWidthSoFar() const { return m_runWidthSoFar; } + + float totalWidth() const { return m_totalWidth; } + + // Extra width to the left of the leftmost glyph. + float finalRoundingWidth() const { return m_finalRoundingWidth; } + +private: + class ComplexTextRun : public RefCounted<ComplexTextRun> { + public: +#if USE(CORE_TEXT) + static PassRefPtr<ComplexTextRun> create(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength) + { + return adoptRef(new ComplexTextRun(ctRun, fontData, characters, stringLocation, stringLength)); + } +#elif USE(ATSUI) + static PassRefPtr<ComplexTextRun> create(ATSUTextLayout atsuTextLayout, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride) + { + return adoptRef(new ComplexTextRun(atsuTextLayout, fontData, characters, stringLocation, stringLength, ltr, directionalOverride)); + } +#endif + static PassRefPtr<ComplexTextRun> create(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) + { + return adoptRef(new ComplexTextRun(fontData, characters, stringLocation, stringLength, ltr)); + } + + unsigned glyphCount() const { return m_glyphCount; } + const SimpleFontData* fontData() const { return m_fontData; } + const UChar* characters() const { return m_characters; } + unsigned stringLocation() const { return m_stringLocation; } + size_t stringLength() const { return m_stringLength; } + CFIndex indexAt(size_t i) const { return m_indices[i]; } + const CGGlyph* glyphs() const { return m_glyphs; } + const CGSize* advances() const { return m_advances; } + + private: +#if USE(CORE_TEXT) + ComplexTextRun(CTRunRef, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength); +#elif USE(ATSUI) + ComplexTextRun(ATSUTextLayout, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride); +#endif + ComplexTextRun(const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr); + +#if USE(ATSUI) +#ifdef BUILDING_ON_TIGER + typedef UInt32 URefCon; +#endif + static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef, URefCon, void*, ATSULayoutOperationCallbackStatus*); +#endif + +#if USE(CORE_TEXT) + RetainPtr<CTRunRef> m_CTRun; +#endif + unsigned m_glyphCount; + const SimpleFontData* m_fontData; + const UChar* m_characters; + unsigned m_stringLocation; + size_t m_stringLength; +#if USE(CORE_TEXT) + RetainPtr<CFMutableDataRef> m_indicesData; + const CFIndex* m_indices; +#elif USE(ATSUI) + Vector<CFIndex, 64> m_indices; +#endif + Vector<CGGlyph, 64> m_glyphsVector; + const CGGlyph* m_glyphs; + Vector<CGSize, 64> m_advancesVector; + const CGSize* m_advances; +#if USE(ATSUI) + bool m_ltr; + bool m_directionalOverride; +#endif + }; + + void collectComplexTextRuns(); + void collectComplexTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*); + void adjustGlyphsAndAdvances(); + + const Font& m_font; + const TextRun& m_run; + bool m_mayUseNaturalWritingDirection; + + Vector<UChar, 256> m_smallCapsBuffer; + + Vector<RefPtr<ComplexTextRun>, 16> m_complexTextRuns; + Vector<CGSize, 256> m_adjustedAdvances; + Vector<CGGlyph, 256> m_adjustedGlyphs; + + unsigned m_currentCharacter; + int m_end; + + CGFloat m_totalWidth; + + float m_runWidthSoFar; + unsigned m_numGlyphsSoFar; + size_t m_currentRun; + unsigned m_glyphInCurrentRun; + unsigned m_characterInCurrentGlyph; + float m_finalRoundingWidth; + float m_padding; + float m_padPerSpace; + + HashSet<const SimpleFontData*>* m_fallbackFonts; + + unsigned m_lastRoundingGlyph; +}; + +} // namespace WebCore + +#endif // ComplexTextController_h diff --git a/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp b/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp new file mode 100644 index 0000000..78c588f --- /dev/null +++ b/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp @@ -0,0 +1,341 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "ComplexTextController.h" + +#if USE(ATSUI) + +#include "CharacterNames.h" +#include "Font.h" +#include "ShapeArabic.h" + +#ifdef __LP64__ +// ATSUTextInserted() is SPI in 64-bit. +extern "C" { +OSStatus ATSUTextInserted(ATSUTextLayout iTextLayout, UniCharArrayOffset iInsertionLocation, UniCharCount iInsertionLength); +} +#endif + +using namespace WTF::Unicode; + +namespace WebCore { + +OSStatus ComplexTextController::ComplexTextRun::overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef atsuLineRef, URefCon refCon, void*, ATSULayoutOperationCallbackStatus* callbackStatus) +{ + ComplexTextRun* complexTextRun = reinterpret_cast<ComplexTextRun*>(refCon); + OSStatus status; + ItemCount count; + ATSLayoutRecord *layoutRecords; + + status = ATSUDirectGetLayoutDataArrayPtrFromLineRef(atsuLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, true, reinterpret_cast<void**>(&layoutRecords), &count); + if (status != noErr) { + *callbackStatus = kATSULayoutOperationCallbackStatusContinue; + return status; + } + + count--; + ItemCount j = 0; + CFIndex indexOffset = 0; + + if (complexTextRun->m_directionalOverride) { + j++; + count -= 2; + indexOffset = -1; + } + + complexTextRun->m_glyphCount = count; + complexTextRun->m_glyphsVector.reserveCapacity(count); + complexTextRun->m_advancesVector.reserveCapacity(count); + complexTextRun->m_indices.reserveCapacity(count); + + bool atBeginning = true; + CGFloat lastX = 0; + + for (ItemCount i = 0; i < count; ++i, ++j) { + if (layoutRecords[j].glyphID == kATSDeletedGlyphcode) { + complexTextRun->m_glyphCount--; + continue; + } + complexTextRun->m_glyphsVector.uncheckedAppend(layoutRecords[j].glyphID); + complexTextRun->m_indices.uncheckedAppend(layoutRecords[j].originalOffset / 2 + indexOffset); + CGFloat x = FixedToFloat(layoutRecords[j].realPos); + if (!atBeginning) + complexTextRun->m_advancesVector.uncheckedAppend(CGSizeMake(x - lastX, 0)); + lastX = x; + atBeginning = false; + } + + complexTextRun->m_advancesVector.uncheckedAppend(CGSizeMake(FixedToFloat(layoutRecords[j].realPos) - lastX, 0)); + + complexTextRun->m_glyphs = complexTextRun->m_glyphsVector.data(); + complexTextRun->m_advances = complexTextRun->m_advancesVector.data(); + + status = ATSUDirectReleaseLayoutDataArrayPtr(atsuLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, reinterpret_cast<void**>(&layoutRecords)); + *callbackStatus = kATSULayoutOperationCallbackStatusContinue; + return noErr; +} + +static inline bool isArabicLamWithAlefLigature(UChar c) +{ + return c >= 0xfef5 && c <= 0xfefc; +} + +static void shapeArabic(const UChar* source, UChar* dest, unsigned totalLength) +{ + unsigned shapingStart = 0; + while (shapingStart < totalLength) { + unsigned shapingEnd; + // We do not want to pass a Lam with Alef ligature followed by a space to the shaper, + // since we want to be able to identify this sequence as the result of shaping a Lam + // followed by an Alef and padding with a space. + bool foundLigatureSpace = false; + for (shapingEnd = shapingStart; !foundLigatureSpace && shapingEnd < totalLength - 1; ++shapingEnd) + foundLigatureSpace = isArabicLamWithAlefLigature(source[shapingEnd]) && source[shapingEnd + 1] == ' '; + shapingEnd++; + + UErrorCode shapingError = U_ZERO_ERROR; + unsigned charsWritten = shapeArabic(source + shapingStart, shapingEnd - shapingStart, dest + shapingStart, shapingEnd - shapingStart, U_SHAPE_LETTERS_SHAPE | U_SHAPE_LENGTH_FIXED_SPACES_NEAR, &shapingError); + + if (U_SUCCESS(shapingError) && charsWritten == shapingEnd - shapingStart) { + for (unsigned j = shapingStart; j < shapingEnd - 1; ++j) { + if (isArabicLamWithAlefLigature(dest[j]) && dest[j + 1] == ' ') + dest[++j] = zeroWidthSpace; + } + if (foundLigatureSpace) { + dest[shapingEnd] = ' '; + shapingEnd++; + } else if (isArabicLamWithAlefLigature(dest[shapingEnd - 1])) { + // u_shapeArabic quirk: if the last two characters in the source string are a Lam and an Alef, + // the space is put at the beginning of the string, despite U_SHAPE_LENGTH_FIXED_SPACES_NEAR. + ASSERT(dest[shapingStart] == ' '); + dest[shapingStart] = zeroWidthSpace; + } + } else { + // Something went wrong. Abandon shaping and just copy the rest of the buffer. + LOG_ERROR("u_shapeArabic failed(%d)", shapingError); + shapingEnd = totalLength; + memcpy(dest + shapingStart, source + shapingStart, (shapingEnd - shapingStart) * sizeof(UChar)); + } + shapingStart = shapingEnd; + } +} + +ComplexTextController::ComplexTextRun::ComplexTextRun(ATSUTextLayout atsuTextLayout, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride) + : m_fontData(fontData) + , m_characters(characters) + , m_stringLocation(stringLocation) + , m_stringLength(stringLength) + , m_ltr(ltr) + , m_directionalOverride(directionalOverride) +{ + OSStatus status; + + status = ATSUSetTextLayoutRefCon(atsuTextLayout, reinterpret_cast<URefCon>(this)); + + ATSLineLayoutOptions lineLayoutOptions = kATSLineKeepSpacesOutOfMargin | kATSLineHasNoHangers; + + Boolean rtl = !ltr; + + Vector<UChar, 256> substituteCharacters; + bool shouldCheckForMirroring = !ltr && !fontData->m_ATSUMirrors; + bool shouldCheckForArabic = !fontData->shapesArabic(); + bool shouldShapeArabic = false; + + bool mirrored = false; + for (size_t i = 0; i < stringLength; ++i) { + if (shouldCheckForMirroring) { + UChar mirroredChar = u_charMirror(characters[i]); + if (mirroredChar != characters[i]) { + if (!mirrored) { + mirrored = true; + substituteCharacters.grow(stringLength); + memcpy(substituteCharacters.data(), characters, stringLength * sizeof(UChar)); + ATSUTextMoved(atsuTextLayout, substituteCharacters.data()); + } + substituteCharacters[i] = mirroredChar; + } + } + if (shouldCheckForArabic && isArabicChar(characters[i])) { + shouldCheckForArabic = false; + shouldShapeArabic = true; + } + } + + if (shouldShapeArabic) { + Vector<UChar, 256> shapedArabic(stringLength); + shapeArabic(substituteCharacters.isEmpty() ? characters : substituteCharacters.data(), shapedArabic.data(), stringLength); + substituteCharacters.swap(shapedArabic); + ATSUTextMoved(atsuTextLayout, substituteCharacters.data()); + } + + if (directionalOverride) { + UChar override = ltr ? leftToRightOverride : rightToLeftOverride; + if (substituteCharacters.isEmpty()) { + substituteCharacters.grow(stringLength + 2); + substituteCharacters[0] = override; + memcpy(substituteCharacters.data() + 1, characters, stringLength * sizeof(UChar)); + substituteCharacters[stringLength + 1] = popDirectionalFormatting; + ATSUTextMoved(atsuTextLayout, substituteCharacters.data()); + } else { + substituteCharacters.prepend(override); + substituteCharacters.append(popDirectionalFormatting); + } + ATSUTextInserted(atsuTextLayout, 0, 2); + } + + ATSULayoutOperationOverrideSpecifier overrideSpecifier; + overrideSpecifier.operationSelector = kATSULayoutOperationPostLayoutAdjustment; + overrideSpecifier.overrideUPP = overrideLayoutOperation; + + ATSUAttributeTag tags[] = { kATSULineLayoutOptionsTag, kATSULineDirectionTag, kATSULayoutOperationOverrideTag }; + ByteCount sizes[] = { sizeof(ATSLineLayoutOptions), sizeof(Boolean), sizeof(ATSULayoutOperationOverrideSpecifier) }; + ATSUAttributeValuePtr values[] = { &lineLayoutOptions, &rtl, &overrideSpecifier }; + + status = ATSUSetLayoutControls(atsuTextLayout, 3, tags, sizes, values); + + ItemCount boundsCount; + status = ATSUGetGlyphBounds(atsuTextLayout, 0, 0, 0, m_stringLength, kATSUseFractionalOrigins, 0, 0, &boundsCount); + + status = ATSUDisposeTextLayout(atsuTextLayout); +} + +ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) + : m_fontData(fontData) + , m_characters(characters) + , m_stringLocation(stringLocation) + , m_stringLength(stringLength) +{ + m_indices.reserveCapacity(stringLength); + unsigned r = 0; + while (r < stringLength) { + m_indices.uncheckedAppend(r); + if (U_IS_SURROGATE(characters[r])) { + ASSERT(r + 1 < stringLength); + ASSERT(U_IS_SURROGATE_LEAD(characters[r])); + ASSERT(U_IS_TRAIL(characters[r + 1])); + r += 2; + } else + r++; + } + m_glyphCount = m_indices.size(); + if (!ltr) { + for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end) + std::swap(m_indices[r], m_indices[end]); + } + + m_glyphsVector.fill(0, m_glyphCount); + m_glyphs = m_glyphsVector.data(); + m_advancesVector.fill(CGSizeMake(fontData->widthForGlyph(0), 0), m_glyphCount); + m_advances = m_advancesVector.data(); +} + +static bool fontHasMirroringInfo(ATSUFontID fontID) +{ + ByteCount propTableSize; + OSStatus status = ATSFontGetTable(fontID, 'prop', 0, 0, 0, &propTableSize); + if (status == noErr) // naively assume that if a 'prop' table exists then it contains mirroring info + return true; + else if (status != kATSInvalidFontTableAccess) // anything other than a missing table is logged as an error + LOG_ERROR("ATSFontGetTable failed (%d)", static_cast<int>(status)); + + return false; +} + +static void disableLigatures(const SimpleFontData* fontData, TextRenderingMode textMode) +{ + // Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are + // in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example. + // See bugzilla 5166. + if (textMode == OptimizeLegibility || textMode == GeometricPrecision || fontData->platformData().allowsLigatures()) + return; + + ATSUFontFeatureType featureTypes[] = { kLigaturesType }; + ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector }; + OSStatus status = ATSUSetFontFeatures(fontData->m_ATSUStyle, 1, featureTypes, featureSelectors); + if (status != noErr) + LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", static_cast<int>(status)); +} + +static void initializeATSUStyle(const SimpleFontData* fontData, TextRenderingMode textMode) +{ + if (fontData->m_ATSUStyleInitialized) + return; + + ATSUFontID fontID = fontData->platformData().m_atsuFontID; + if (!fontID) { + LOG_ERROR("unable to get ATSUFontID for %p", fontData->platformData().font()); + return; + } + + OSStatus status = ATSUCreateStyle(&fontData->m_ATSUStyle); + if (status != noErr) + LOG_ERROR("ATSUCreateStyle failed (%d)", static_cast<int>(status)); + + Fixed fontSize = FloatToFixed(fontData->platformData().m_size); + Fract kerningInhibitFactor = FloatToFract(1); + static CGAffineTransform verticalFlip = CGAffineTransformMakeScale(1, -1); + + ByteCount styleSizes[4] = { sizeof(fontSize), sizeof(fontID), sizeof(verticalFlip), sizeof(kerningInhibitFactor) }; + ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag }; + ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &verticalFlip, &kerningInhibitFactor }; + + bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision; + status = ATSUSetAttributes(fontData->m_ATSUStyle, allowKerning ? 3 : 4, styleTags, styleSizes, styleValues); + if (status != noErr) + LOG_ERROR("ATSUSetAttributes failed (%d)", static_cast<int>(status)); + + fontData->m_ATSUMirrors = fontHasMirroringInfo(fontID); + + disableLigatures(fontData, textMode); + + fontData->m_ATSUStyleInitialized = true; +} + +void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData) +{ + if (!fontData) { + // Create a run of missing glyphs from the primary font. + m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr())); + return; + } + + if (m_fallbackFonts && fontData != m_font.primaryFont()) + m_fallbackFonts->add(fontData); + + initializeATSUStyle(fontData, m_font.fontDescription().textRenderingMode()); + + OSStatus status; + ATSUTextLayout atsuTextLayout; + UniCharCount runLength = length; + + status = ATSUCreateTextLayoutWithTextPtr(cp, 0, length, length, 1, &runLength, &fontData->m_ATSUStyle, &atsuTextLayout); + if (status != noErr) { + LOG_ERROR("ATSUCreateTextLayoutWithTextPtr failed with error %d", static_cast<int>(status)); + return; + } + m_complexTextRuns.append(ComplexTextRun::create(atsuTextLayout, fontData, cp, stringLocation, length, m_run.ltr(), m_run.directionalOverride())); +} + +} // namespace WebCore + +#endif // USE(ATSUI) diff --git a/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp b/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp new file mode 100644 index 0000000..c9daf84 --- /dev/null +++ b/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2007, 2008, 2009 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 "ComplexTextController.h" + +#if USE(CORE_TEXT) + +#include "Font.h" + +namespace WebCore { + +ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength) + : m_CTRun(ctRun) + , m_fontData(fontData) + , m_characters(characters) + , m_stringLocation(stringLocation) + , m_stringLength(stringLength) +{ + m_glyphCount = CTRunGetGlyphCount(m_CTRun.get()); + m_indices = CTRunGetStringIndicesPtr(m_CTRun.get()); + if (!m_indices) { + m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); + CFDataIncreaseLength(m_indicesData.get(), m_glyphCount * sizeof(CFIndex)); + m_indices = reinterpret_cast<const CFIndex*>(CFDataGetMutableBytePtr(m_indicesData.get())); + CTRunGetStringIndices(m_CTRun.get(), CFRangeMake(0, 0), const_cast<CFIndex*>(m_indices)); + } + + m_glyphs = CTRunGetGlyphsPtr(m_CTRun.get()); + if (!m_glyphs) { + m_glyphsVector.grow(m_glyphCount); + CTRunGetGlyphs(m_CTRun.get(), CFRangeMake(0, 0), m_glyphsVector.data()); + m_glyphs = m_glyphsVector.data(); + } + + m_advances = CTRunGetAdvancesPtr(m_CTRun.get()); + if (!m_advances) { + m_advancesVector.grow(m_glyphCount); + CTRunGetAdvances(m_CTRun.get(), CFRangeMake(0, 0), m_advancesVector.data()); + m_advances = m_advancesVector.data(); + } + +} + +// Missing glyphs run constructor. Core Text will not generate a run of missing glyphs, instead falling back on +// glyphs from LastResort. We want to use the primary font's missing glyph in order to match the fast text code path. +ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) + : m_fontData(fontData) + , m_characters(characters) + , m_stringLocation(stringLocation) + , m_stringLength(stringLength) +{ + Vector<CFIndex, 16> indices; + unsigned r = 0; + while (r < stringLength) { + indices.append(r); + if (U_IS_SURROGATE(characters[r])) { + ASSERT(r + 1 < stringLength); + ASSERT(U_IS_SURROGATE_LEAD(characters[r])); + ASSERT(U_IS_TRAIL(characters[r + 1])); + r += 2; + } else + r++; + } + m_glyphCount = indices.size(); + if (!ltr) { + for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end) + std::swap(indices[r], indices[end]); + } + m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); + CFDataAppendBytes(m_indicesData.get(), reinterpret_cast<const UInt8*>(indices.data()), m_glyphCount * sizeof(CFIndex)); + m_indices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_indicesData.get())); + + // Synthesize a run of missing glyphs. + m_glyphsVector.fill(0, m_glyphCount); + m_glyphs = m_glyphsVector.data(); + m_advancesVector.fill(CGSizeMake(m_fontData->widthForGlyph(0), 0), m_glyphCount); + m_advances = m_advancesVector.data(); +} + +void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData) +{ + if (!fontData) { + // Create a run of missing glyphs from the primary font. + m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr())); + return; + } + + if (m_fallbackFonts && fontData != m_font.primaryFont()) + m_fallbackFonts->add(fontData); + + RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull)); + + RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes(m_font.fontDescription().textRenderingMode()))); + + RetainPtr<CTTypesetterRef> typesetter; + + if (!m_mayUseNaturalWritingDirection || m_run.directionalOverride()) { + static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel }; + static const void* ltrOptionValues[] = { kCFBooleanFalse }; + static const void* rtlOptionValues[] = { kCFBooleanTrue }; + static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + typesetter.adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions)); + } else + typesetter.adoptCF(CTTypesetterCreateWithAttributedString(attributedString.get())); + + RetainPtr<CTLineRef> line(AdoptCF, CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0))); + + CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); + + CFIndex runCount = CFArrayGetCount(runArray); + + for (CFIndex r = 0; r < runCount; r++) { + CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r)); + ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID()); + m_complexTextRuns.append(ComplexTextRun::create(ctRun, fontData, cp, stringLocation, length)); + } +} + +} // namespace WebCore + +#endif // USE(CORE_TEXT) diff --git a/WebCore/platform/graphics/mac/CoreTextController.h b/WebCore/platform/graphics/mac/CoreTextController.h deleted file mode 100644 index 4dd6f93..0000000 --- a/WebCore/platform/graphics/mac/CoreTextController.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2007, 2008 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. ``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 - * 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 CoreTextController_h -#define CoreTextController_h - -#if USE(CORE_TEXT) - -#include "Font.h" -#include "GlyphBuffer.h" -#include <wtf/RetainPtr.h> -#include <wtf/Vector.h> - -namespace WebCore { - -class CoreTextController { -public: - CoreTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const SimpleFontData*>* fallbackFonts = 0); - - // Advance and emit glyphs up to the specified character. - void advance(unsigned to, GlyphBuffer* = 0); - - // Compute the character offset for a given x coordinate. - int offsetForPosition(int x, bool includePartialGlyphs); - - // Returns the width of everything we've consumed so far. - float runWidthSoFar() const { return m_runWidthSoFar; } - - float totalWidth() const { return m_totalWidth; } - - // Extra width to the left of the leftmost glyph. - float finalRoundingWidth() const { return m_finalRoundingWidth; } - -private: - class CoreTextRun { - public: - CoreTextRun(CTRunRef, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength); - CoreTextRun(const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr); - - CTRunRef ctRun() const { return m_CTRun.get(); } - unsigned glyphCount() const { return m_glyphCount; } - const SimpleFontData* fontData() const { return m_fontData; } - const UChar* characters() const { return m_characters; } - unsigned stringLocation() const { return m_stringLocation; } - size_t stringLength() const { return m_stringLength; } - CFIndex indexAt(size_t i) const { return m_indices[i]; } - - private: - RetainPtr<CTRunRef> m_CTRun; - unsigned m_glyphCount; - const SimpleFontData* m_fontData; - const UChar* m_characters; - unsigned m_stringLocation; - size_t m_stringLength; - const CFIndex* m_indices; - // Used only if CTRunGet*Ptr fails or if this is a missing glyphs run. - RetainPtr<CFMutableDataRef> m_indicesData; - }; - - void collectCoreTextRuns(); - void collectCoreTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*); - void adjustGlyphsAndAdvances(); - - const Font& m_font; - const TextRun& m_run; - bool m_mayUseNaturalWritingDirection; - - Vector<UChar, 256> m_smallCapsBuffer; - - Vector<CoreTextRun, 16> m_coreTextRuns; - Vector<CGSize, 256> m_adjustedAdvances; - Vector<CGGlyph, 256> m_adjustedGlyphs; - - unsigned m_currentCharacter; - int m_end; - - CGFloat m_totalWidth; - - float m_runWidthSoFar; - unsigned m_numGlyphsSoFar; - size_t m_currentRun; - unsigned m_glyphInCurrentRun; - float m_finalRoundingWidth; - float m_padding; - float m_padPerSpace; - - HashSet<const SimpleFontData*>* m_fallbackFonts; - - unsigned m_lastRoundingGlyph; -}; - -} // namespace WebCore -#endif // USE(CORE_TEXT) -#endif // CoreTextController_h diff --git a/WebCore/platform/graphics/mac/FontMacCoreText.cpp b/WebCore/platform/graphics/mac/FontComplexTextMac.cpp index 9dffc7a..0db2601 100644 --- a/WebCore/platform/graphics/mac/FontMacCoreText.cpp +++ b/WebCore/platform/graphics/mac/FontComplexTextMac.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,25 +10,22 @@ * 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. + * 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 "Font.h" -#if USE(CORE_TEXT) - -#include "CoreTextController.h" +#include "ComplexTextController.h" #include "FontFallbackList.h" #include "GlyphBuffer.h" #include "GraphicsContext.h" @@ -41,7 +38,7 @@ namespace WebCore { FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const { - CoreTextController controller(this, run); + ComplexTextController controller(this, run); controller.advance(from); float beforeWidth = controller.runWidthSoFar(); controller.advance(to); @@ -63,7 +60,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F GlyphBuffer glyphBuffer; float startX = point.x(); - CoreTextController controller(this, run); + ComplexTextController controller(this, run); controller.advance(from); float beforeWidth = controller.runWidthSoFar(); controller.advance(to, &glyphBuffer); @@ -88,15 +85,14 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const { - CoreTextController controller(this, run, true, fallbackFonts); + ComplexTextController controller(this, run, true, fallbackFonts); return controller.totalWidth(); } int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const { - CoreTextController controller(this, run); + ComplexTextController controller(this, run); return controller.offsetForPosition(x, includePartialGlyphs); } -} -#endif // USE(CORE_TEXT) +} // namespace WebCore diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp index 5e72101..256b5a4 100644 --- a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp @@ -24,6 +24,7 @@ #include <ApplicationServices/ApplicationServices.h> #include "SharedBuffer.h" #include "FontPlatformData.h" +#include "OpenTypeSanitizer.h" namespace WebCore { @@ -43,6 +44,14 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) { ASSERT_ARG(buffer, buffer); +#if ENABLE(OPENTYPE_SANITIZER) + OpenTypeSanitizer sanitizer(buffer); + RefPtr<SharedBuffer> transcodeBuffer = sanitizer.sanitize(); + if (!transcodeBuffer) + return 0; // validation failed. + buffer = transcodeBuffer.get(); +#endif + ATSFontContainerRef containerRef = 0; ATSFontRef fontRef = 0; diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm index b2b9a5c..bb9561e 100644 --- a/WebCore/platform/graphics/mac/FontMac.mm +++ b/WebCore/platform/graphics/mac/FontMac.mm @@ -115,6 +115,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons IntSize shadowSize; int shadowBlur; Color shadowColor; + ColorSpace fillColorSpace = context->fillColorSpace(); context->getShadow(shadowSize, shadowBlur, shadowColor); bool hasSimpleShadow = context->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur; @@ -123,14 +124,14 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons context->clearShadow(); Color fillColor = context->fillColor(); Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); - context->setFillColor(shadowFillColor); + context->setFillColor(shadowFillColor, fillColorSpace); CGContextSetTextPosition(cgContext, point.x() + shadowSize.width(), point.y() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->syntheticBoldOffset()) { CGContextSetTextPosition(cgContext, point.x() + shadowSize.width() + font->syntheticBoldOffset(), point.y() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } - context->setFillColor(fillColor); + context->setFillColor(fillColor, fillColorSpace); } CGContextSetTextPosition(cgContext, point.x(), point.y()); @@ -141,7 +142,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons } if (hasSimpleShadow) - context->setShadow(shadowSize, shadowBlur, shadowColor); + context->setShadow(shadowSize, shadowBlur, shadowColor, fillColorSpace); if (originalShouldUseFontSmoothing != newShouldUseFontSmoothing) CGContextSetShouldSmoothFonts(cgContext, originalShouldUseFontSmoothing); diff --git a/WebCore/platform/graphics/mac/FontMacATSUI.mm b/WebCore/platform/graphics/mac/FontMacATSUI.mm deleted file mode 100644 index 409bda4..0000000 --- a/WebCore/platform/graphics/mac/FontMacATSUI.mm +++ /dev/null @@ -1,635 +0,0 @@ -/* - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2006 Apple Computer, Inc. - * - * 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. - */ - -#import "config.h" -#import "Font.h" - -#if USE(ATSUI) - -#import "CharacterNames.h" -#import "GraphicsContext.h" -#import "Logging.h" -#import "ShapeArabic.h" -#import "SimpleFontData.h" -#import <AppKit/NSGraphicsContext.h> -#import <wtf/OwnArrayPtr.h> - -#define SYNTHETIC_OBLIQUE_ANGLE 14 - -#ifdef __LP64__ -#define URefCon void* -#else -#define URefCon UInt32 -#endif - -using namespace std; - -namespace WebCore { - -struct ATSULayoutParameters : Noncopyable -{ - ATSULayoutParameters(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts = 0) - : m_run(run) - , m_font(0) - , m_hasSyntheticBold(false) - , m_syntheticBoldPass(false) - , m_padPerSpace(0) - , m_fallbackFonts(fallbackFonts) - { - } - - ~ATSULayoutParameters() - { - ATSUDisposeTextLayout(m_layout); - } - - void initialize(const Font*, const GraphicsContext* = 0); - - const TextRun& m_run; - - const Font* m_font; - - ATSUTextLayout m_layout; - OwnArrayPtr<const SimpleFontData*> m_fonts; - - OwnArrayPtr<UChar> m_charBuffer; - bool m_hasSyntheticBold; - bool m_syntheticBoldPass; - float m_padPerSpace; - HashSet<const SimpleFontData*>* m_fallbackFonts; -}; - -static TextRun copyRunForDirectionalOverrideIfNecessary(const TextRun& run, OwnArrayPtr<UChar>& charactersWithOverride) -{ - if (!run.directionalOverride()) - return run; - - charactersWithOverride.set(new UChar[run.length() + 2]); - charactersWithOverride[0] = run.rtl() ? rightToLeftOverride : leftToRightOverride; - memcpy(&charactersWithOverride[1], run.data(0), sizeof(UChar) * run.length()); - charactersWithOverride[run.length() + 1] = popDirectionalFormatting; - - TextRun result = run; - result.setText(charactersWithOverride.get(), run.length() + 2); - return result; -} - -static bool fontHasMirroringInfo(ATSUFontID fontID) -{ - ByteCount propTableSize; - OSStatus status = ATSFontGetTable(fontID, 'prop', 0, 0, 0, &propTableSize); - if (status == noErr) // naively assume that if a 'prop' table exists then it contains mirroring info - return true; - else if (status != kATSInvalidFontTableAccess) // anything other than a missing table is logged as an error - LOG_ERROR("ATSFontGetTable failed (%d)", status); - - return false; -} - -static void disableLigatures(const SimpleFontData* fontData, TextRenderingMode textMode) -{ - // Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are - // in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example. - // See bugzilla 5166. - if (textMode == OptimizeLegibility || textMode == GeometricPrecision || fontData->platformData().allowsLigatures()) - return; - - ATSUFontFeatureType featureTypes[] = { kLigaturesType }; - ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector }; - OSStatus status = ATSUSetFontFeatures(fontData->m_ATSUStyle, 1, featureTypes, featureSelectors); - if (status != noErr) - LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", status); -} - -static void initializeATSUStyle(const SimpleFontData* fontData, TextRenderingMode textMode) -{ - if (fontData->m_ATSUStyleInitialized) - return; - - ATSUFontID fontID = fontData->platformData().m_atsuFontID; - if (!fontID) { - LOG_ERROR("unable to get ATSUFontID for %@", fontData->platformData().font()); - return; - } - - OSStatus status = ATSUCreateStyle(&fontData->m_ATSUStyle); - if (status != noErr) - // Who knows how many ATSU functions will crash when passed a NULL style... - LOG_ERROR("ATSUCreateStyle failed (%d)", status); - - CGAffineTransform transform = CGAffineTransformMakeScale(1, -1); - if (fontData->platformData().m_syntheticOblique) - transform = CGAffineTransformConcat(transform, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0)); - Fixed fontSize = FloatToFixed(fontData->platformData().m_size); - ByteCount styleSizes[4] = { sizeof(Fixed), sizeof(ATSUFontID), sizeof(CGAffineTransform), sizeof(Fract) }; - - bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision; - if (!allowKerning) { - // Turn off automatic kerning until it is supported in the CG code path (bug 6136) - Fract kerningInhibitFactor = FloatToFract(1.0); - ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag }; - ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &transform, &kerningInhibitFactor }; - status = ATSUSetAttributes(fontData->m_ATSUStyle, 4, styleTags, styleSizes, styleValues); - if (status != noErr) - LOG_ERROR("ATSUSetAttributes failed (%d)", status); - } else { - ATSUAttributeTag styleTags[3] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag }; - ATSUAttributeValuePtr styleValues[3] = { &fontSize, &fontID, &transform, }; - status = ATSUSetAttributes(fontData->m_ATSUStyle, 3, styleTags, styleSizes, styleValues); - if (status != noErr) - LOG_ERROR("ATSUSetAttributes failed (%d)", status); - } - - fontData->m_ATSUMirrors = fontHasMirroringInfo(fontID); - - // Turn off ligatures such as 'fi' to match the CG code path's behavior, until bug 6135 is fixed. - disableLigatures(fontData, textMode); - - fontData->m_ATSUStyleInitialized = true; -} - -static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef iLineRef, URefCon iRefCon, void*, ATSULayoutOperationCallbackStatus* oCallbackStatus) -{ - ATSULayoutParameters* params = reinterpret_cast<ATSULayoutParameters*>(iRefCon); - OSStatus status; - ItemCount count; - ATSLayoutRecord *layoutRecords; - - if (params->m_run.applyWordRounding()) { - status = ATSUDirectGetLayoutDataArrayPtrFromLineRef(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, true, (void **)&layoutRecords, &count); - if (status != noErr) { - *oCallbackStatus = kATSULayoutOperationCallbackStatusContinue; - return status; - } - - Fixed lastNativePos = 0; - float lastAdjustedPos = 0; - const UChar* characters = params->m_charBuffer ? params->m_charBuffer.get() : params->m_run.characters(); - const SimpleFontData** renderers = params->m_fonts.get(); - const SimpleFontData* renderer; - const SimpleFontData* lastRenderer = 0; - ByteCount offset = layoutRecords[0].originalOffset; - UChar nextCh = *(UChar *)(((char *)characters)+offset); - bool shouldRound = false; - bool syntheticBoldPass = params->m_syntheticBoldPass; - Fixed syntheticBoldOffset = 0; - bool hasExtraSpacing = (params->m_font->letterSpacing() || params->m_font->wordSpacing() || params->m_run.padding()) && !params->m_run.spacingDisabled(); - float padding = params->m_run.padding(); - // In the CoreGraphics code path, the rounding hack is applied in logical order. - // Here it is applied in visual left-to-right order, which may be better. - ItemCount lastRoundingChar = 0; - ItemCount i; - for (i = 1; i < count; i++) { - bool isLastChar = i == count - 1; - renderer = renderers[offset / 2]; - float width; - if (nextCh == zeroWidthSpace || Font::treatAsZeroWidthSpace(nextCh) && !Font::treatAsSpace(nextCh)) { - width = 0; - layoutRecords[i-1].glyphID = renderer->spaceGlyph(); - } else { - width = FixedToFloat(layoutRecords[i].realPos - lastNativePos); - if (renderer != lastRenderer && width) { - lastRenderer = renderer; - // The CoreGraphics interpretation of NSFontAntialiasedIntegerAdvancementsRenderingMode seems - // to be "round each glyph's width to the nearest integer". This is not the same as ATSUI - // does in any of its device-metrics modes. - shouldRound = renderer->platformData().roundsGlyphAdvances(); - if (syntheticBoldPass) - syntheticBoldOffset = FloatToFixed(renderer->syntheticBoldOffset()); - if (params->m_fallbackFonts && renderer != params->m_font->primaryFont()) - params->m_fallbackFonts->add(renderer); - } - if (shouldRound) - width = roundf(width); - width += renderer->syntheticBoldOffset(); - if (renderer->pitch() == FixedPitch ? width == renderer->spaceWidth() : (layoutRecords[i-1].flags & kATSGlyphInfoIsWhiteSpace)) - width = renderer->adjustedSpaceWidth(); - } - lastNativePos = layoutRecords[i].realPos; - - if (hasExtraSpacing) { - if (width && params->m_font->letterSpacing()) - width +=params->m_font->letterSpacing(); - if (Font::treatAsSpace(nextCh)) { - if (params->m_run.padding()) { - if (padding < params->m_padPerSpace) { - width += padding; - padding = 0; - } else { - width += params->m_padPerSpace; - padding -= params->m_padPerSpace; - } - } - if (offset != 0 && !Font::treatAsSpace(*((UChar *)(((char *)characters)+offset) - 1)) && params->m_font->wordSpacing()) - width += params->m_font->wordSpacing(); - } - } - - UChar ch = nextCh; - offset = layoutRecords[i].originalOffset; - // Use space for nextCh at the end of the loop so that we get inside the rounding hack code. - // We won't actually round unless the other conditions are satisfied. - nextCh = isLastChar ? ' ' : *(UChar *)(((char *)characters)+offset); - - if (Font::isRoundingHackCharacter(ch)) - width = ceilf(width); - lastAdjustedPos = lastAdjustedPos + width; - if (Font::isRoundingHackCharacter(nextCh) && (!isLastChar || params->m_run.applyRunRounding())){ - if (params->m_run.ltr()) - lastAdjustedPos = ceilf(lastAdjustedPos); - else { - float roundingWidth = ceilf(lastAdjustedPos) - lastAdjustedPos; - Fixed rw = FloatToFixed(roundingWidth); - ItemCount j; - for (j = lastRoundingChar; j < i; j++) - layoutRecords[j].realPos += rw; - lastRoundingChar = i; - lastAdjustedPos += roundingWidth; - } - } - if (syntheticBoldPass) { - if (syntheticBoldOffset) - layoutRecords[i-1].realPos += syntheticBoldOffset; - else - layoutRecords[i-1].glyphID = renderer->spaceGlyph(); - } - layoutRecords[i].realPos = FloatToFixed(lastAdjustedPos); - } - - status = ATSUDirectReleaseLayoutDataArrayPtr(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void **)&layoutRecords); - } - *oCallbackStatus = kATSULayoutOperationCallbackStatusHandled; - return noErr; -} - -static inline bool isArabicLamWithAlefLigature(UChar c) -{ - return c >= 0xfef5 && c <= 0xfefc; -} - -static void shapeArabic(const UChar* source, UChar* dest, unsigned totalLength, unsigned shapingStart) -{ - while (shapingStart < totalLength) { - unsigned shapingEnd; - // We do not want to pass a Lam with Alef ligature followed by a space to the shaper, - // since we want to be able to identify this sequence as the result of shaping a Lam - // followed by an Alef and padding with a space. - bool foundLigatureSpace = false; - for (shapingEnd = shapingStart; !foundLigatureSpace && shapingEnd < totalLength - 1; ++shapingEnd) - foundLigatureSpace = isArabicLamWithAlefLigature(source[shapingEnd]) && source[shapingEnd + 1] == ' '; - shapingEnd++; - - UErrorCode shapingError = U_ZERO_ERROR; - unsigned charsWritten = shapeArabic(source + shapingStart, shapingEnd - shapingStart, dest + shapingStart, shapingEnd - shapingStart, U_SHAPE_LETTERS_SHAPE | U_SHAPE_LENGTH_FIXED_SPACES_NEAR, &shapingError); - - if (U_SUCCESS(shapingError) && charsWritten == shapingEnd - shapingStart) { - for (unsigned j = shapingStart; j < shapingEnd - 1; ++j) { - if (isArabicLamWithAlefLigature(dest[j]) && dest[j + 1] == ' ') - dest[++j] = zeroWidthSpace; - } - if (foundLigatureSpace) { - dest[shapingEnd] = ' '; - shapingEnd++; - } else if (isArabicLamWithAlefLigature(dest[shapingEnd - 1])) { - // u_shapeArabic quirk: if the last two characters in the source string are a Lam and an Alef, - // the space is put at the beginning of the string, despite U_SHAPE_LENGTH_FIXED_SPACES_NEAR. - ASSERT(dest[shapingStart] == ' '); - dest[shapingStart] = zeroWidthSpace; - } - } else { - // Something went wrong. Abandon shaping and just copy the rest of the buffer. - LOG_ERROR("u_shapeArabic failed(%d)", shapingError); - shapingEnd = totalLength; - memcpy(dest + shapingStart, source + shapingStart, (shapingEnd - shapingStart) * sizeof(UChar)); - } - shapingStart = shapingEnd; - } -} - -void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* graphicsContext) -{ - m_font = font; - - const SimpleFontData* fontData = font->primaryFont(); - m_fonts.set(new const SimpleFontData*[m_run.length()]); - if (font->isSmallCaps()) - m_charBuffer.set(new UChar[m_run.length()]); - - ATSUTextLayout layout; - OSStatus status; - ATSULayoutOperationOverrideSpecifier overrideSpecifier; - - initializeATSUStyle(fontData, m_font->fontDescription().textRenderingMode()); - - // FIXME: This is currently missing the following required features that the CoreGraphics code path has: - // - \n, \t, and nonbreaking space render as a space. - - UniCharCount runLength = m_run.length(); - - if (m_charBuffer) - memcpy(m_charBuffer.get(), m_run.characters(), runLength * sizeof(UChar)); - - status = ATSUCreateTextLayoutWithTextPtr( - (m_charBuffer ? m_charBuffer.get() : m_run.characters()), - 0, // offset - runLength, // length - runLength, // total length - 1, // styleRunCount - &runLength, // length of style run - &fontData->m_ATSUStyle, - &layout); - if (status != noErr) - LOG_ERROR("ATSUCreateTextLayoutWithTextPtr failed(%d)", status); - m_layout = layout; - ATSUSetTextLayoutRefCon(m_layout, (URefCon)this); - - // FIXME: There are certain times when this method is called, when we don't have access to a GraphicsContext - // measuring text runs with floatWidthForComplexText is one example. - // ATSUI requires that we pass a valid CGContextRef to it when specifying kATSUCGContextTag (crashes when passed 0) - // ATSUI disables sub-pixel rendering if kATSUCGContextTag is not specified! So we're in a bind. - // Sometimes [[NSGraphicsContext currentContext] graphicsPort] may return the wrong (or no!) context. Nothing we can do about it (yet). - CGContextRef cgContext = graphicsContext ? graphicsContext->platformContext() : (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; - - ATSLineLayoutOptions lineLayoutOptions = kATSLineKeepSpacesOutOfMargin | kATSLineHasNoHangers; - Boolean rtl = m_run.rtl(); - overrideSpecifier.operationSelector = kATSULayoutOperationPostLayoutAdjustment; - overrideSpecifier.overrideUPP = overrideLayoutOperation; - ATSUAttributeTag tags[] = { kATSUCGContextTag, kATSULineLayoutOptionsTag, kATSULineDirectionTag, kATSULayoutOperationOverrideTag }; - ByteCount sizes[] = { sizeof(CGContextRef), sizeof(ATSLineLayoutOptions), sizeof(Boolean), sizeof(ATSULayoutOperationOverrideSpecifier) }; - ATSUAttributeValuePtr values[] = { &cgContext, &lineLayoutOptions, &rtl, &overrideSpecifier }; - - status = ATSUSetLayoutControls(layout, (m_run.applyWordRounding() ? 4 : 3), tags, sizes, values); - if (status != noErr) - LOG_ERROR("ATSUSetLayoutControls failed(%d)", status); - - status = ATSUSetTransientFontMatching(layout, YES); - if (status != noErr) - LOG_ERROR("ATSUSetTransientFontMatching failed(%d)", status); - - m_hasSyntheticBold = false; - ATSUFontID ATSUSubstituteFont; - UniCharArrayOffset substituteOffset = 0; - UniCharCount substituteLength; - UniCharArrayOffset lastOffset; - const SimpleFontData* substituteFontData = 0; - - while (substituteOffset < runLength) { - // FIXME: Using ATSUMatchFontsToText() here results in several problems: the CSS font family list is not necessarily followed for the 2nd - // and onwards unmatched characters; segmented fonts do not work correctly; behavior does not match the simple text and Uniscribe code - // paths. Change this function to use Font::glyphDataForCharacter() for each character instead. - lastOffset = substituteOffset; - status = ATSUMatchFontsToText(layout, substituteOffset, kATSUToTextEnd, &ATSUSubstituteFont, &substituteOffset, &substituteLength); - if (status == kATSUFontsMatched || status == kATSUFontsNotMatched) { - const FontData* fallbackFontData = m_font->fontDataForCharacters(m_run.characters() + substituteOffset, substituteLength); - substituteFontData = fallbackFontData ? fallbackFontData->fontDataForCharacter(m_run[0]) : 0; - if (substituteFontData) { - initializeATSUStyle(substituteFontData, m_font->fontDescription().textRenderingMode()); - if (substituteFontData->m_ATSUStyle) - ATSUSetRunStyle(layout, substituteFontData->m_ATSUStyle, substituteOffset, substituteLength); - } else - substituteFontData = fontData; - } else { - substituteOffset = runLength; - substituteLength = 0; - } - - bool shapedArabic = false; - bool isSmallCap = false; - UniCharArrayOffset firstSmallCap = 0; - const SimpleFontData *r = fontData; - UniCharArrayOffset i; - for (i = lastOffset; ; i++) { - if (i == substituteOffset || i == substituteOffset + substituteLength) { - if (isSmallCap) { - isSmallCap = false; - initializeATSUStyle(r->smallCapsFontData(m_font->fontDescription()), m_font->fontDescription().textRenderingMode()); - ATSUSetRunStyle(layout, r->smallCapsFontData(m_font->fontDescription())->m_ATSUStyle, firstSmallCap, i - firstSmallCap); - } - if (i == substituteOffset && substituteLength > 0) - r = substituteFontData; - else - break; - } - if (!shapedArabic && WTF::Unicode::isArabicChar(m_run[i]) && !r->shapesArabic()) { - shapedArabic = true; - if (!m_charBuffer) { - m_charBuffer.set(new UChar[runLength]); - memcpy(m_charBuffer.get(), m_run.characters(), i * sizeof(UChar)); - ATSUTextMoved(layout, m_charBuffer.get()); - } - shapeArabic(m_run.characters(), m_charBuffer.get(), runLength, i); - } - if (m_run.rtl() && !r->m_ATSUMirrors) { - UChar mirroredChar = u_charMirror(m_run[i]); - if (mirroredChar != m_run[i]) { - if (!m_charBuffer) { - m_charBuffer.set(new UChar[runLength]); - memcpy(m_charBuffer.get(), m_run.characters(), runLength * sizeof(UChar)); - ATSUTextMoved(layout, m_charBuffer.get()); - } - m_charBuffer[i] = mirroredChar; - } - } - if (m_font->isSmallCaps()) { - const SimpleFontData* smallCapsData = r->smallCapsFontData(m_font->fontDescription()); - UChar c = m_charBuffer[i]; - UChar newC; - if (U_GET_GC_MASK(c) & U_GC_M_MASK) - m_fonts[i] = isSmallCap ? smallCapsData : r; - else if (!u_isUUppercase(c) && (newC = u_toupper(c)) != c) { - m_charBuffer[i] = newC; - if (!isSmallCap) { - isSmallCap = true; - firstSmallCap = i; - } - m_fonts[i] = smallCapsData; - } else { - if (isSmallCap) { - isSmallCap = false; - initializeATSUStyle(smallCapsData, m_font->fontDescription().textRenderingMode()); - ATSUSetRunStyle(layout, smallCapsData->m_ATSUStyle, firstSmallCap, i - firstSmallCap); - } - m_fonts[i] = r; - } - } else - m_fonts[i] = r; - if (m_fonts[i]->syntheticBoldOffset()) - m_hasSyntheticBold = true; - } - substituteOffset += substituteLength; - } - if (m_run.padding()) { - float numSpaces = 0; - unsigned k; - for (k = 0; k < runLength; k++) - if (Font::treatAsSpace(m_run[k])) - numSpaces++; - - if (numSpaces == 0) - m_padPerSpace = 0; - else - m_padPerSpace = ceilf(m_run.padding() / numSpaces); - } else - m_padPerSpace = 0; -} - -FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const -{ - OwnArrayPtr<UChar> charactersWithOverride; - TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride); - if (run.directionalOverride()) { - from++; - to++; - } - - ATSULayoutParameters params(adjustedRun); - params.initialize(this); - - ATSTrapezoid firstGlyphBounds; - ItemCount actualNumBounds; - - OSStatus status = ATSUGetGlyphBounds(params.m_layout, 0, 0, from, to - from, kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds); - if (status != noErr || actualNumBounds != 1) { - static ATSTrapezoid zeroTrapezoid = { {0, 0}, {0, 0}, {0, 0}, {0, 0} }; - firstGlyphBounds = zeroTrapezoid; - } - - float beforeWidth = min(FixedToFloat(firstGlyphBounds.lowerLeft.x), FixedToFloat(firstGlyphBounds.upperLeft.x)); - float afterWidth = max(FixedToFloat(firstGlyphBounds.lowerRight.x), FixedToFloat(firstGlyphBounds.upperRight.x)); - - FloatRect rect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h); - - return rect; -} - -void Font::drawComplexText(GraphicsContext* graphicsContext, const TextRun& run, const FloatPoint& point, int from, int to) const -{ - OSStatus status; - - int drawPortionLength = to - from; - OwnArrayPtr<UChar> charactersWithOverride; - TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride); - if (run.directionalOverride()) - from++; - - ATSULayoutParameters params(adjustedRun); - params.initialize(this, graphicsContext); - - // ATSUI can't draw beyond -32768 to +32767 so we translate the CTM and tell ATSUI to draw at (0, 0). - CGContextRef context = graphicsContext->platformContext(); - CGContextTranslateCTM(context, point.x(), point.y()); - - IntSize shadowSize; - int shadowBlur; - Color shadowColor; - graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor); - - bool hasSimpleShadow = graphicsContext->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur; - if (hasSimpleShadow) { - // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing. - graphicsContext->clearShadow(); - Color fillColor = graphicsContext->fillColor(); - Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); - graphicsContext->setFillColor(shadowFillColor); - CGContextTranslateCTM(context, shadowSize.width(), shadowSize.height()); - status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0); - if (status == noErr && params.m_hasSyntheticBold) { - // Force relayout for the bold pass - ATSUClearLayoutCache(params.m_layout, 0); - params.m_syntheticBoldPass = true; - status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0); - // Force relayout for the next pass - ATSUClearLayoutCache(params.m_layout, 0); - params.m_syntheticBoldPass = false; - } - CGContextTranslateCTM(context, -shadowSize.width(), -shadowSize.height()); - graphicsContext->setFillColor(fillColor); - } - - status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0); - if (status == noErr && params.m_hasSyntheticBold) { - // Force relayout for the bold pass - ATSUClearLayoutCache(params.m_layout, 0); - params.m_syntheticBoldPass = true; - status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0); - } - CGContextTranslateCTM(context, -point.x(), -point.y()); - - if (status != noErr) - // Nothing to do but report the error (dev build only). - LOG_ERROR("ATSUDrawText() failed(%d)", status); - - if (hasSimpleShadow) - graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor); -} - -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const -{ - if (run.length() == 0) - return 0; - - ATSULayoutParameters params(run, fallbackFonts); - params.initialize(this); - - OSStatus status; - - ATSTrapezoid firstGlyphBounds; - ItemCount actualNumBounds; - status = ATSUGetGlyphBounds(params.m_layout, 0, 0, 0, run.length(), kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds); - if (status != noErr) - LOG_ERROR("ATSUGetGlyphBounds() failed(%d)", status); - if (actualNumBounds != 1) - LOG_ERROR("unexpected result from ATSUGetGlyphBounds(): actualNumBounds(%d) != 1", actualNumBounds); - - return max(FixedToFloat(firstGlyphBounds.upperRight.x), FixedToFloat(firstGlyphBounds.lowerRight.x)) - - min(FixedToFloat(firstGlyphBounds.upperLeft.x), FixedToFloat(firstGlyphBounds.lowerLeft.x)); -} - -int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool /*includePartialGlyphs*/) const -{ - OwnArrayPtr<UChar> charactersWithOverride; - TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride); - - ATSULayoutParameters params(adjustedRun); - params.initialize(this); - - UniCharArrayOffset primaryOffset = 0; - - // FIXME: No idea how to avoid including partial glyphs. - // Not even sure if that's the behavior this yields now. - Boolean isLeading; - UniCharArrayOffset secondaryOffset = 0; - OSStatus status = ATSUPositionToOffset(params.m_layout, FloatToFixed(x), FloatToFixed(-1), &primaryOffset, &isLeading, &secondaryOffset); - unsigned offset; - if (status == noErr) { - offset = (unsigned)primaryOffset; - if (run.directionalOverride() && offset > 0) - offset--; - } else - // Failed to find offset! Return 0 offset. - offset = 0; - - return offset; -} - -} -#endif // USE(ATSUI) diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp index 47617d8..41f63a9 100644 --- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp +++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp @@ -30,18 +30,18 @@ #include "GraphicsContext3D.h" #include "CachedImage.h" -#include "CanvasActiveInfo.h" -#include "CanvasArray.h" -#include "CanvasBuffer.h" -#include "CanvasFramebuffer.h" -#include "CanvasFloatArray.h" -#include "CanvasIntArray.h" +#include "WebGLActiveInfo.h" +#include "WebGLArray.h" +#include "WebGLBuffer.h" +#include "WebGLFramebuffer.h" +#include "WebGLFloatArray.h" +#include "WebGLIntArray.h" #include "CanvasObject.h" -#include "CanvasProgram.h" -#include "CanvasRenderbuffer.h" -#include "CanvasShader.h" -#include "CanvasTexture.h" -#include "CanvasUnsignedByteArray.h" +#include "WebGLProgram.h" +#include "WebGLRenderbuffer.h" +#include "WebGLShader.h" +#include "WebGLTexture.h" +#include "WebGLUnsignedByteArray.h" #include "CString.h" #include "HTMLCanvasElement.h" #include "HTMLImageElement.h" @@ -175,21 +175,12 @@ GraphicsContext3D::~GraphicsContext3D() } } -void GraphicsContext3D::checkError() const -{ - // FIXME: This needs to only be done in the debug context. It will probably throw an exception - // on error and print the error message to the debug console - GLenum error = ::glGetError(); - if (error != GL_NO_ERROR) - notImplemented(); -} - void GraphicsContext3D::makeContextCurrent() { CGLSetCurrentContext(m_contextObj); } -void GraphicsContext3D::beginPaint(CanvasRenderingContext3D* context) +void GraphicsContext3D::beginPaint(WebGLRenderingContext* context) { UNUSED_PARAM(context); } @@ -246,43 +237,42 @@ void GraphicsContext3D::activeTexture(unsigned long texture) ::glActiveTexture(texture); } -void GraphicsContext3D::attachShader(CanvasProgram* program, CanvasShader* shader) +void GraphicsContext3D::attachShader(WebGLProgram* program, WebGLShader* shader) { - if (!program || !shader) - return; + ASSERT(program); + ASSERT(shader); ensureContext(m_contextObj); ::glAttachShader((GLuint) program->object(), (GLuint) shader->object()); } -void GraphicsContext3D::bindAttribLocation(CanvasProgram* program, unsigned long index, const String& name) +void GraphicsContext3D::bindAttribLocation(WebGLProgram* program, unsigned long index, const String& name) { - if (!program) - return; + ASSERT(program); ensureContext(m_contextObj); ::glBindAttribLocation((GLuint) program->object(), index, name.utf8().data()); } -void GraphicsContext3D::bindBuffer(unsigned long target, CanvasBuffer* buffer) +void GraphicsContext3D::bindBuffer(unsigned long target, WebGLBuffer* buffer) { ensureContext(m_contextObj); ::glBindBuffer(target, buffer ? (GLuint) buffer->object() : 0); } -void GraphicsContext3D::bindFramebuffer(unsigned long target, CanvasFramebuffer* buffer) +void GraphicsContext3D::bindFramebuffer(unsigned long target, WebGLFramebuffer* buffer) { ensureContext(m_contextObj); ::glBindFramebufferEXT(target, buffer ? (GLuint) buffer->object() : m_fbo); } -void GraphicsContext3D::bindRenderbuffer(unsigned long target, CanvasRenderbuffer* renderbuffer) +void GraphicsContext3D::bindRenderbuffer(unsigned long target, WebGLRenderbuffer* renderbuffer) { ensureContext(m_contextObj); - ::glBindBuffer(target, renderbuffer ? (GLuint) renderbuffer->object() : 0); + ::glBindRenderbufferEXT(target, renderbuffer ? (GLuint) renderbuffer->object() : 0); } -void GraphicsContext3D::bindTexture(unsigned long target, CanvasTexture* texture) +void GraphicsContext3D::bindTexture(unsigned long target, WebGLTexture* texture) { ensureContext(m_contextObj); ::glBindTexture(target, texture ? (GLuint) texture->object() : 0); @@ -324,22 +314,22 @@ void GraphicsContext3D::bufferData(unsigned long target, int size, unsigned long ensureContext(m_contextObj); ::glBufferData(target, size, 0, usage); } -void GraphicsContext3D::bufferData(unsigned long target, CanvasArray* array, unsigned long usage) +void GraphicsContext3D::bufferData(unsigned long target, WebGLArray* array, unsigned long usage) { if (!array || !array->length()) return; ensureContext(m_contextObj); - ::glBufferData(target, array->sizeInBytes(), array->baseAddress(), usage); + ::glBufferData(target, array->byteLength(), array->baseAddress(), usage); } -void GraphicsContext3D::bufferSubData(unsigned long target, long offset, CanvasArray* array) +void GraphicsContext3D::bufferSubData(unsigned long target, long offset, WebGLArray* array) { if (!array || !array->length()) return; ensureContext(m_contextObj); - ::glBufferSubData(target, offset, array->sizeInBytes(), array->baseAddress()); + ::glBufferSubData(target, offset, array->byteLength(), array->baseAddress()); } unsigned long GraphicsContext3D::checkFramebufferStatus(unsigned long target) @@ -378,11 +368,9 @@ void GraphicsContext3D::colorMask(bool red, bool green, bool blue, bool alpha) ::glColorMask(red, green, blue, alpha); } -void GraphicsContext3D::compileShader(CanvasShader* shader) +void GraphicsContext3D::compileShader(WebGLShader* shader) { - if (!shader) - return; - + ASSERT(shader); ensureContext(m_contextObj); ::glCompileShader((GLuint) shader->object()); } @@ -423,11 +411,10 @@ void GraphicsContext3D::depthRange(double zNear, double zFar) ::glDepthRange(zNear, zFar); } -void GraphicsContext3D::detachShader(CanvasProgram* program, CanvasShader* shader) +void GraphicsContext3D::detachShader(WebGLProgram* program, WebGLShader* shader) { - if (!program || !shader) - return; - + ASSERT(program); + ASSERT(shader); ensureContext(m_contextObj); ::glDetachShader((GLuint) program->object(), (GLuint) shader->object()); } @@ -480,22 +467,16 @@ void GraphicsContext3D::flush() ::glFlush(); } -void GraphicsContext3D::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, CanvasRenderbuffer* buffer) +void GraphicsContext3D::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, WebGLRenderbuffer* buffer) { - if (!buffer) - return; - ensureContext(m_contextObj); - ::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, (GLuint) buffer->object()); + ::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, buffer ? (GLuint) buffer->object() : 0); } -void GraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, CanvasTexture* texture, long level) +void GraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, WebGLTexture* texture, long level) { - if (!texture) - return; - ensureContext(m_contextObj); - ::glFramebufferTexture2DEXT(target, attachment, textarget, (GLuint) texture->object(), level); + ::glFramebufferTexture2DEXT(target, attachment, textarget, texture ? (GLuint) texture->object() : 0, level); } void GraphicsContext3D::frontFace(unsigned long mode) @@ -510,10 +491,12 @@ void GraphicsContext3D::generateMipmap(unsigned long target) ::glGenerateMipmapEXT(target); } -bool GraphicsContext3D::getActiveAttrib(CanvasProgram* program, unsigned long index, ActiveInfo& info) +bool GraphicsContext3D::getActiveAttrib(WebGLProgram* program, unsigned long index, ActiveInfo& info) { - if (!program->object()) + if (!program->object()) { + synthesizeGLError(INVALID_VALUE); return false; + } ensureContext(m_contextObj); GLint maxAttributeSize = 0; ::glGetProgramiv(static_cast<GLuint>(program->object()), GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttributeSize); @@ -530,10 +513,12 @@ bool GraphicsContext3D::getActiveAttrib(CanvasProgram* program, unsigned long in return true; } -bool GraphicsContext3D::getActiveUniform(CanvasProgram* program, unsigned long index, ActiveInfo& info) +bool GraphicsContext3D::getActiveUniform(WebGLProgram* program, unsigned long index, ActiveInfo& info) { - if (!program->object()) + if (!program->object()) { + synthesizeGLError(INVALID_VALUE); return false; + } ensureContext(m_contextObj); GLint maxUniformSize = 0; ::glGetProgramiv(static_cast<GLuint>(program->object()), GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformSize); @@ -550,7 +535,7 @@ bool GraphicsContext3D::getActiveUniform(CanvasProgram* program, unsigned long i return true; } -int GraphicsContext3D::getAttribLocation(CanvasProgram* program, const String& name) +int GraphicsContext3D::getAttribLocation(WebGLProgram* program, const String& name) { if (!program) return -1; @@ -561,6 +546,13 @@ int GraphicsContext3D::getAttribLocation(CanvasProgram* program, const String& n unsigned long GraphicsContext3D::getError() { + if (m_syntheticErrors.size() > 0) { + ListHashSet<unsigned long>::iterator iter = m_syntheticErrors.begin(); + unsigned long err = *iter; + m_syntheticErrors.remove(iter); + return err; + } + ensureContext(m_contextObj); return ::glGetError(); } @@ -577,7 +569,7 @@ void GraphicsContext3D::hint(unsigned long target, unsigned long mode) ::glHint(target, mode); } -bool GraphicsContext3D::isBuffer(CanvasBuffer* buffer) +bool GraphicsContext3D::isBuffer(WebGLBuffer* buffer) { if (!buffer) return false; @@ -592,7 +584,7 @@ bool GraphicsContext3D::isEnabled(unsigned long cap) return ::glIsEnabled(cap); } -bool GraphicsContext3D::isFramebuffer(CanvasFramebuffer* framebuffer) +bool GraphicsContext3D::isFramebuffer(WebGLFramebuffer* framebuffer) { if (!framebuffer) return false; @@ -601,7 +593,7 @@ bool GraphicsContext3D::isFramebuffer(CanvasFramebuffer* framebuffer) return ::glIsFramebufferEXT((GLuint) framebuffer->object()); } -bool GraphicsContext3D::isProgram(CanvasProgram* program) +bool GraphicsContext3D::isProgram(WebGLProgram* program) { if (!program) return false; @@ -610,7 +602,7 @@ bool GraphicsContext3D::isProgram(CanvasProgram* program) return ::glIsProgram((GLuint) program->object()); } -bool GraphicsContext3D::isRenderbuffer(CanvasRenderbuffer* renderbuffer) +bool GraphicsContext3D::isRenderbuffer(WebGLRenderbuffer* renderbuffer) { if (!renderbuffer) return false; @@ -619,7 +611,7 @@ bool GraphicsContext3D::isRenderbuffer(CanvasRenderbuffer* renderbuffer) return ::glIsRenderbufferEXT((GLuint) renderbuffer->object()); } -bool GraphicsContext3D::isShader(CanvasShader* shader) +bool GraphicsContext3D::isShader(WebGLShader* shader) { if (!shader) return false; @@ -628,7 +620,7 @@ bool GraphicsContext3D::isShader(CanvasShader* shader) return ::glIsShader((GLuint) shader->object()); } -bool GraphicsContext3D::isTexture(CanvasTexture* texture) +bool GraphicsContext3D::isTexture(WebGLTexture* texture) { if (!texture) return false; @@ -643,11 +635,9 @@ void GraphicsContext3D::lineWidth(double width) ::glLineWidth(static_cast<float>(width)); } -void GraphicsContext3D::linkProgram(CanvasProgram* program) +void GraphicsContext3D::linkProgram(WebGLProgram* program) { - if (!program) - return; - + ASSERT(program); ensureContext(m_contextObj); ::glLinkProgram((GLuint) program->object()); } @@ -664,7 +654,7 @@ void GraphicsContext3D::polygonOffset(double factor, double units) ::glPolygonOffset(static_cast<float>(factor), static_cast<float>(units)); } -PassRefPtr<CanvasArray> GraphicsContext3D::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type) +PassRefPtr<WebGLArray> GraphicsContext3D::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type) { ensureContext(m_contextObj); @@ -675,7 +665,7 @@ PassRefPtr<CanvasArray> GraphicsContext3D::readPixels(long x, long y, unsigned l if (type != GL_UNSIGNED_BYTE || format != GL_RGBA) return 0; - RefPtr<CanvasUnsignedByteArray> array = CanvasUnsignedByteArray::create(width * height * 4); + RefPtr<WebGLUnsignedByteArray> array = WebGLUnsignedByteArray::create(width * height * 4); ::glReadPixels(x, y, width, height, format, type, (GLvoid*) array->data()); return array; } @@ -705,10 +695,9 @@ void GraphicsContext3D::scissor(long x, long y, unsigned long width, unsigned lo ::glScissor(x, y, width, height); } -void GraphicsContext3D::shaderSource(CanvasShader* shader, const String& string) +void GraphicsContext3D::shaderSource(WebGLShader* shader, const String& string) { - if (!shader) - return; + ASSERT(shader); ensureContext(m_contextObj); const CString& cs = string.utf8(); @@ -889,19 +878,17 @@ void GraphicsContext3D::uniformMatrix4fv(long location, bool transpose, float* a ::glUniformMatrix4fv(location, size, transpose, array); } -void GraphicsContext3D::useProgram(CanvasProgram* program) +void GraphicsContext3D::useProgram(WebGLProgram* program) { - if (!program) - return; + ASSERT(program); ensureContext(m_contextObj); ::glUseProgram((GLuint) program->object()); } -void GraphicsContext3D::validateProgram(CanvasProgram* program) +void GraphicsContext3D::validateProgram(WebGLProgram* program) { - if (!program) - return; + ASSERT(program); ensureContext(m_contextObj); ::glValidateProgram((GLuint) program->object()); @@ -967,567 +954,156 @@ void GraphicsContext3D::viewport(long x, long y, unsigned long width, unsigned l ::glViewport(static_cast<GLint>(x), static_cast<GLint>(y), static_cast<GLsizei>(width), static_cast<GLsizei>(height)); } -static int sizeForGetParam(unsigned long pname) -{ - switch(pname) { - case GL_ACTIVE_TEXTURE: return 1; - case GL_ALIASED_LINE_WIDTH_RANGE: return 2; - case GL_ALIASED_POINT_SIZE_RANGE: return 2; - case GL_ALPHA_BITS: return 1; - case GL_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*) - case GL_BLEND: return 1; - case GL_BLEND_COLOR: return 4; - case GL_BLEND_DST_ALPHA: return 1; - case GL_BLEND_DST_RGB: return 1; - case GL_BLEND_EQUATION_ALPHA: return 1; - case GL_BLEND_EQUATION_RGB: return 1; - case GL_BLEND_SRC_ALPHA: return 1; - case GL_BLEND_SRC_RGB: return 1; - case GL_BLUE_BITS: return 1; - case GL_COLOR_CLEAR_VALUE: return 4; - case GL_COLOR_WRITEMASK: return 4; - case GL_COMPRESSED_TEXTURE_FORMATS: return GL_NUM_COMPRESSED_TEXTURE_FORMATS; - case GL_CULL_FACE: return 1; - case GL_CULL_FACE_MODE: return 1; - case GL_CURRENT_PROGRAM: return 1; // (* actually a CanvasProgram*) - case GL_DEPTH_BITS: return 1; - case GL_DEPTH_CLEAR_VALUE: return 1; - case GL_DEPTH_FUNC: return 1; - case GL_DEPTH_RANGE: return 2; - case GL_DEPTH_TEST: return 1; - case GL_DEPTH_WRITEMASK: return 1; - case GL_DITHER: return 1; - case GL_ELEMENT_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*) - case GL_FRAMEBUFFER_BINDING_EXT: return 1; // (* actually a CanvasFramebuffer*) - case GL_FRONT_FACE: return 1; - case GL_GENERATE_MIPMAP_HINT: return 1; - case GL_GREEN_BITS: return 1; - //case GL_IMPLEMENTATION_COLOR_READ_FORMAT:return 1; - //case GL_IMPLEMENTATION_COLOR_READ_TYPE: return 1; - case GL_LINE_WIDTH: return 1; - case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:return 1; - case GL_MAX_CUBE_MAP_TEXTURE_SIZE: return 1; - //case GL_MAX_FRAGMENT_UNIFORM_VECTORS: return 1; - case GL_MAX_RENDERBUFFER_SIZE_EXT: return 1; - case GL_MAX_TEXTURE_IMAGE_UNITS: return 1; - case GL_MAX_TEXTURE_SIZE: return 1; - //case GL_MAX_VARYING_VECTORS: return 1; - case GL_MAX_VERTEX_ATTRIBS: return 1; - case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: return 1; - //case GL_MAX_VERTEX_UNIFORM_VECTORS: return 1; - case GL_MAX_VIEWPORT_DIMS: return 2; - case GL_NUM_COMPRESSED_TEXTURE_FORMATS: return 1; - //case GL_NUM_SHADER_BINARY_FORMATS: return 1; - case GL_PACK_ALIGNMENT: return 1; - case GL_POLYGON_OFFSET_FACTOR: return 1; - case GL_POLYGON_OFFSET_FILL: return 1; - case GL_POLYGON_OFFSET_UNITS: return 1; - case GL_RED_BITS: return 1; - case GL_RENDERBUFFER_BINDING_EXT: return 1; // (* actually a CanvasRenderbuffer*) - case GL_SAMPLE_BUFFERS: return 1; - case GL_SAMPLE_COVERAGE_INVERT: return 1; - case GL_SAMPLE_COVERAGE_VALUE: return 1; - case GL_SAMPLES: return 1; - case GL_SCISSOR_BOX: return 4; - case GL_SCISSOR_TEST: return 1; - //case GL_SHADER_BINARY_FORMATS: return GL_NUM_SHADER_BINARY_FORMATS; - //case GL_SHADER_COMPILER: return 1; - case GL_STENCIL_BACK_FAIL: return 1; - case GL_STENCIL_BACK_FUNC: return 1; - case GL_STENCIL_BACK_PASS_DEPTH_FAIL: return 1; - case GL_STENCIL_BACK_PASS_DEPTH_PASS: return 1; - case GL_STENCIL_BACK_REF: return 1; - case GL_STENCIL_BACK_VALUE_MASK: return 1; - case GL_STENCIL_BACK_WRITEMASK: return 1; - case GL_STENCIL_BITS: return 1; - case GL_STENCIL_CLEAR_VALUE: return 1; - case GL_STENCIL_FAIL: return 1; - case GL_STENCIL_FUNC: return 1; - case GL_STENCIL_PASS_DEPTH_FAIL: return 1; - case GL_STENCIL_PASS_DEPTH_PASS: return 1; - case GL_STENCIL_REF: return 1; - case GL_STENCIL_TEST: return 1; - case GL_STENCIL_VALUE_MASK: return 1; - case GL_STENCIL_WRITEMASK: return 1; - case GL_SUBPIXEL_BITS: return 1; - case GL_TEXTURE_BINDING_2D: return 1; // (* actually a CanvasTexture*) - case GL_TEXTURE_BINDING_CUBE_MAP: return 1; // (* actually a CanvasTexture*) - case GL_UNPACK_ALIGNMENT: return 1; - case GL_VIEWPORT: return 4; - } - - return -1; -} - -bool GraphicsContext3D::getBoolean(unsigned long pname) -{ - int size = sizeForGetParam(pname); - if (size < 1) - return 0; - - ensureContext(m_contextObj); - - bool isAlloced = false; - GLboolean buf[4]; - GLboolean* pbuf = buf; - - if (size > 4) { - pbuf = (GLboolean*) malloc(size * sizeof(GLboolean)); - isAlloced = true; - } - - ::glGetBooleanv(pname, pbuf); - - bool value = pbuf[0]; - - if (isAlloced) - free(pbuf); - - return value; -} - -PassRefPtr<CanvasUnsignedByteArray> GraphicsContext3D::getBooleanv(unsigned long pname) -{ - int size = sizeForGetParam(pname); - if (size < 1) - return 0; - - ensureContext(m_contextObj); - - RefPtr<CanvasUnsignedByteArray> array = CanvasUnsignedByteArray::create(size); - bool isAlloced = false; - GLboolean buf[4]; - GLboolean* pbuf = buf; - - if (size > 4) { - pbuf = (GLboolean*) malloc(size * sizeof(GLboolean)); - isAlloced = true; - } - - ::glGetBooleanv(pname, pbuf); - - for (int i = 0; i < size; ++i) - array->set(i, static_cast<unsigned char>(pbuf[i])); - - if (isAlloced) - free(pbuf); - - return array; -} - -float GraphicsContext3D::getFloat(unsigned long pname) +void GraphicsContext3D::getBooleanv(unsigned long pname, unsigned char* value) { - int size = sizeForGetParam(pname); - if (size < 1) - return 0; - ensureContext(m_contextObj); - - bool isAlloced = false; - GLfloat buf[4]; - GLfloat* pbuf = buf; - - if (size > 4) { - pbuf = (GLfloat*) malloc(size * sizeof(GLfloat)); - isAlloced = true; - } - - ::glGetFloatv(pname, pbuf); - - float value = pbuf[0]; - - if (isAlloced) - free(pbuf); - - return value; + ::glGetBooleanv(pname, value); } -PassRefPtr<CanvasFloatArray> GraphicsContext3D::getFloatv(unsigned long pname) +void GraphicsContext3D::getBufferParameteriv(unsigned long target, unsigned long pname, int* value) { - int size = sizeForGetParam(pname); - if (size < 1) - return 0; - ensureContext(m_contextObj); - - RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(size); - bool isAlloced = false; - GLfloat buf[4]; - GLfloat* pbuf = buf; - - if (size > 4) { - pbuf = (GLfloat*) malloc(size * sizeof(GLfloat)); - isAlloced = true; - } - - ::glGetFloatv(pname, pbuf); - - for (int i = 0; i < size; ++i) - array->set(i, static_cast<float>(pbuf[i])); - - if (isAlloced) - free(pbuf); - - return array; + ::glGetBufferParameteriv(target, pname, value); } -int GraphicsContext3D::getInteger(unsigned long pname) +void GraphicsContext3D::getFloatv(unsigned long pname, float* value) { - int size = sizeForGetParam(pname); - if (size < 1) - return 0; - ensureContext(m_contextObj); - - bool isAlloced = false; - GLint buf[4]; - GLint* pbuf = buf; - - if (size > 4) { - pbuf = (GLint*) malloc(size * sizeof(GLint)); - isAlloced = true; - } - - ::glGetIntegerv(pname, pbuf); - - int value = pbuf[0]; - - if (isAlloced) - free(pbuf); - - return value; + ::glGetFloatv(pname, value); } -PassRefPtr<CanvasIntArray> GraphicsContext3D::getIntegerv(unsigned long pname) +void GraphicsContext3D::getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname, int* value) { - int size = sizeForGetParam(pname); - if (size < 1) - return 0; - ensureContext(m_contextObj); - - RefPtr<CanvasIntArray> array = CanvasIntArray::create(size); - bool isAlloced = false; - GLint buf[4]; - GLint* pbuf = buf; - - if (size > 4) { - pbuf = (GLint*) malloc(size * sizeof(GLint)); - isAlloced = true; - } - - ::glGetIntegerv(pname, pbuf); - - for (int i = 0; i < size; ++i) - array->set(i, static_cast<int>(pbuf[i])); - - if (isAlloced) - free(pbuf); - - return array; + ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, value); } -int GraphicsContext3D::getBufferParameteri(unsigned long target, unsigned long pname) +void GraphicsContext3D::getIntegerv(unsigned long pname, int* value) { ensureContext(m_contextObj); - GLint data; - ::glGetBufferParameteriv(target, pname, &data); - return data; + ::glGetIntegerv(pname, value); } -PassRefPtr<CanvasIntArray> GraphicsContext3D::getBufferParameteriv(unsigned long target, unsigned long pname) +void GraphicsContext3D::getProgramiv(WebGLProgram* program, unsigned long pname, int* value) { ensureContext(m_contextObj); - RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); - GLint data; - ::glGetBufferParameteriv(target, pname, &data); - array->set(0, static_cast<int>(data)); - - return array; + ::glGetProgramiv((GLuint) program->object(), pname, value); } -int GraphicsContext3D::getFramebufferAttachmentParameteri(unsigned long target, unsigned long attachment, unsigned long pname) +String GraphicsContext3D::getProgramInfoLog(WebGLProgram* program) { - ensureContext(m_contextObj); - GLint data; - ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, &data); - return data; -} - -PassRefPtr<CanvasIntArray> GraphicsContext3D::getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname) -{ - ensureContext(m_contextObj); - RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); - GLint data; - ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, &data); - array->set(0, static_cast<int>(data)); - - return array; -} - -int GraphicsContext3D::getProgrami(CanvasProgram* program, unsigned long pname) -{ - ensureContext(m_contextObj); - GLint data; - ::glGetProgramiv((GLuint) program->object(), pname, &data); - return data; -} - -PassRefPtr<CanvasIntArray> GraphicsContext3D::getProgramiv(CanvasProgram* program, unsigned long pname) -{ - ensureContext(m_contextObj); - RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); - GLint data; - ::glGetProgramiv((GLuint) program->object(), pname, &data); - array->set(0, static_cast<int>(data)); - - return array; -} - -String GraphicsContext3D::getProgramInfoLog(CanvasProgram* program) -{ - if (!program) - return String(); + ASSERT(program); ensureContext(m_contextObj); GLint length; ::glGetProgramiv((GLuint) program->object(), GL_INFO_LOG_LENGTH, &length); GLsizei size; - GLchar* info = (GLchar*) malloc(length); + GLchar* info = (GLchar*) fastMalloc(length); + if (!info) + return ""; + ::glGetProgramInfoLog((GLuint) program->object(), length, &size, info); String s(info); - free(info); + fastFree(info); return s; } -int GraphicsContext3D::getRenderbufferParameteri(unsigned long target, unsigned long pname) -{ - ensureContext(m_contextObj); - GLint data; - ::glGetBufferParameteriv(target, pname, &data); - return data; -} - -PassRefPtr<CanvasIntArray> GraphicsContext3D::getRenderbufferParameteriv(unsigned long target, unsigned long pname) +void GraphicsContext3D::getRenderbufferParameteriv(unsigned long target, unsigned long pname, int* value) { ensureContext(m_contextObj); - RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); - GLint data; - ::glGetBufferParameteriv(target, pname, &data); - array->set(0, static_cast<int>(data)); - - return array; + ::glGetRenderbufferParameterivEXT(target, pname, value); } -int GraphicsContext3D::getShaderi(CanvasShader* shader, unsigned long pname) +void GraphicsContext3D::getShaderiv(WebGLShader* shader, unsigned long pname, int* value) { - if (!shader) - return 0; - - ensureContext(m_contextObj); - GLint data; - ::glGetShaderiv((GLuint) shader->object(), pname, &data); - return data; -} - -PassRefPtr<CanvasIntArray> GraphicsContext3D::getShaderiv(CanvasShader* shader, unsigned long pname) -{ - if (!shader) - return 0; + ASSERT(shader); ensureContext(m_contextObj); - RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); - GLint data; - ::glGetShaderiv((GLuint) shader->object(), pname, &data); - array->set(0, static_cast<int>(data)); - - return array; + ::glGetShaderiv((GLuint) shader->object(), pname, value); } -String GraphicsContext3D::getShaderInfoLog(CanvasShader* shader) +String GraphicsContext3D::getShaderInfoLog(WebGLShader* shader) { - if (!shader) - return String(); + ASSERT(shader); ensureContext(m_contextObj); GLint length; ::glGetShaderiv((GLuint) shader->object(), GL_INFO_LOG_LENGTH, &length); GLsizei size; - GLchar* info = (GLchar*) malloc(length); + GLchar* info = (GLchar*) fastMalloc(length); + if (!info) + return ""; + ::glGetShaderInfoLog((GLuint) shader->object(), length, &size, info); String s(info); - free(info); + fastFree(info); return s; } -String GraphicsContext3D::getShaderSource(CanvasShader* shader) +String GraphicsContext3D::getShaderSource(WebGLShader* shader) { - if (!shader) - return String(); - + ASSERT(shader); + ensureContext(m_contextObj); GLint length; ::glGetShaderiv((GLuint) shader->object(), GL_SHADER_SOURCE_LENGTH, &length); GLsizei size; - GLchar* info = (GLchar*) malloc(length); + GLchar* info = (GLchar*) fastMalloc(length); + if (!info) + return ""; + ::glGetShaderSource((GLuint) shader->object(), length, &size, info); String s(info); - free(info); + fastFree(info); return s; } -float GraphicsContext3D::getTexParameterf(unsigned long target, unsigned long pname) +void GraphicsContext3D::getTexParameterfv(unsigned long target, unsigned long pname, float* value) { ensureContext(m_contextObj); - GLfloat data; - ::glGetTexParameterfv(target, pname, &data); - return data; + ::glGetTexParameterfv(target, pname, value); } -PassRefPtr<CanvasFloatArray> GraphicsContext3D::getTexParameterfv(unsigned long target, unsigned long pname) +void GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long pname, int* value) { ensureContext(m_contextObj); - RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(1); - GLfloat data; - ::glGetTexParameterfv(target, pname, &data); - array->set(0, static_cast<float>(data)); - - return array; + ::glGetTexParameteriv(target, pname, value); } -int GraphicsContext3D::getTexParameteri(unsigned long target, unsigned long pname) +void GraphicsContext3D::getUniformfv(WebGLProgram* program, long location, float* value) { ensureContext(m_contextObj); - GLint data; - ::glGetTexParameteriv(target, pname, &data); - return data; + ::glGetUniformfv((GLuint) program->object(), location, value); } -PassRefPtr<CanvasIntArray> GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long pname) +void GraphicsContext3D::getUniformiv(WebGLProgram* program, long location, int* value) { ensureContext(m_contextObj); - RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); - GLint data; - ::glGetTexParameteriv(target, pname, &data); - array->set(0, static_cast<int>(data)); - - return array; -} - -float GraphicsContext3D::getUniformf(CanvasProgram* program, long location) -{ - // FIXME: We need to query glGetUniformLocation to determine the size needed - UNUSED_PARAM(program); - UNUSED_PARAM(location); - notImplemented(); - return 0; + ::glGetUniformiv((GLuint) program->object(), location, value); } -PassRefPtr<CanvasFloatArray> GraphicsContext3D::getUniformfv(CanvasProgram* program, long location) +long GraphicsContext3D::getUniformLocation(WebGLProgram* program, const String& name) { - // FIXME: We need to query glGetUniformLocation to determine the size needed - UNUSED_PARAM(program); - UNUSED_PARAM(location); - notImplemented(); - return 0; -} - -int GraphicsContext3D::getUniformi(CanvasProgram* program, long location) -{ - // FIXME: We need to query glGetUniformLocation to determine the size needed - UNUSED_PARAM(program); - UNUSED_PARAM(location); - notImplemented(); - return 0; -} - -PassRefPtr<CanvasIntArray> GraphicsContext3D::getUniformiv(CanvasProgram* program, long location) -{ - // FIXME: We need to query glGetUniformLocation to determine the size needed - UNUSED_PARAM(program); - UNUSED_PARAM(location); - notImplemented(); - return 0; -} - -long GraphicsContext3D::getUniformLocation(CanvasProgram* program, const String& name) -{ - if (!program) - return -1; + ASSERT(program); ensureContext(m_contextObj); return ::glGetUniformLocation((GLuint) program->object(), name.utf8().data()); } -static int sizeForGetVertexAttribParam(unsigned long pname) -{ - switch(pname) { - case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*) - case GL_VERTEX_ATTRIB_ARRAY_ENABLED: return 1; - case GL_VERTEX_ATTRIB_ARRAY_SIZE: return 1; - case GL_VERTEX_ATTRIB_ARRAY_STRIDE: return 1; - case GL_VERTEX_ATTRIB_ARRAY_TYPE: return 1; - case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: return 1; - case GL_CURRENT_VERTEX_ATTRIB: return 4; - } - - return -1; -} - -float GraphicsContext3D::getVertexAttribf(unsigned long index, unsigned long pname) -{ - ensureContext(m_contextObj); - GLfloat buf[4]; - ::glGetVertexAttribfv(index, pname, buf); - return buf[0]; -} - -PassRefPtr<CanvasFloatArray> GraphicsContext3D::getVertexAttribfv(unsigned long index, unsigned long pname) -{ - int size = sizeForGetVertexAttribParam(pname); - if (size < 1) - return 0; - - ensureContext(m_contextObj); - - RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(size); - GLfloat buf[4]; - ::glGetVertexAttribfv(index, pname, buf); - - for (int i = 0; i < size; ++i) - array->set(i, static_cast<float>(buf[i])); - - return array; -} - -int GraphicsContext3D::getVertexAttribi(unsigned long index, unsigned long pname) +void GraphicsContext3D::getVertexAttribfv(unsigned long index, unsigned long pname, float* value) { ensureContext(m_contextObj); - GLint buf[4]; - ::glGetVertexAttribiv(index, pname, buf); - return buf[0]; + ::glGetVertexAttribfv(index, pname, value); } -PassRefPtr<CanvasIntArray> GraphicsContext3D::getVertexAttribiv(unsigned long index, unsigned long pname) +void GraphicsContext3D::getVertexAttribiv(unsigned long index, unsigned long pname, int* value) { - int size = sizeForGetVertexAttribParam(pname); - if (size < 1) - return 0; - ensureContext(m_contextObj); - - RefPtr<CanvasIntArray> array = CanvasIntArray::create(size); - GLint buf[4]; - ::glGetVertexAttribiv(index, pname, buf); - - for (int i = 0; i < size; ++i) - array->set(i, static_cast<int>(buf[i])); - - return array; + ::glGetVertexAttribiv(index, pname, value); } long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long pname) @@ -1552,18 +1128,21 @@ static void imageToTexture(Image* image, unsigned target, unsigned level) size_t textureWidth = CGImageGetWidth(textureImage); size_t textureHeight = CGImageGetHeight(textureImage); - GLubyte* textureData = (GLubyte*) malloc(textureWidth * textureHeight * 4); + GLubyte* textureData = (GLubyte*) fastMalloc(textureWidth * textureHeight * 4); + if (!textureData) + return; + CGContextRef textureContext = CGBitmapContextCreate(textureData, textureWidth, textureHeight, 8, textureWidth * 4, CGImageGetColorSpace(textureImage), kCGImageAlphaPremultipliedLast); - + CGContextSetBlendMode(textureContext, kCGBlendModeCopy); CGContextDrawImage(textureContext, CGRectMake(0, 0, (CGFloat)textureWidth, (CGFloat)textureHeight), textureImage); CGContextRelease(textureContext); ::glTexImage2D(target, level, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData); - free(textureData); + fastFree(textureData); } -int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, CanvasArray* pixels) +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, WebGLArray* pixels) { // FIXME: Need to do bounds checking on the buffer here. ::glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels->baseAddress()); @@ -1585,39 +1164,15 @@ int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned inte return -1; } -int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLImageElement* image, bool flipY, bool premultiplyAlpha) +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, Image* image, bool flipY, bool premultiplyAlpha) { // FIXME: need to support flipY and premultiplyAlpha UNUSED_PARAM(flipY); UNUSED_PARAM(premultiplyAlpha); - - if (!image) - return -1; + ASSERT(image); ensureContext(m_contextObj); - CachedImage* cachedImage = image->cachedImage(); - if (!cachedImage) - return -1; - - imageToTexture(cachedImage->image(), target, level); - return 0; -} - -int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas, bool flipY, bool premultiplyAlpha) -{ - // FIXME: need to support flipY and premultiplyAlpha - UNUSED_PARAM(flipY); - UNUSED_PARAM(premultiplyAlpha); - - if (!canvas) - return -1; - - ensureContext(m_contextObj); - ImageBuffer* buffer = canvas->buffer(); - if (!buffer) - return -1; - - imageToTexture(buffer->image(), target, level); + imageToTexture(image, target, level); return 0; } @@ -1634,7 +1189,7 @@ int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLVideoElem return -1; } -int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, CanvasArray* pixels) +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, WebGLArray* pixels) { // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size UNUSED_PARAM(target); @@ -1664,7 +1219,7 @@ int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned x return -1; } -int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLImageElement* image, bool flipY, bool premultiplyAlpha) +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, Image* image, bool flipY, bool premultiplyAlpha) { // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size UNUSED_PARAM(target); @@ -1681,23 +1236,6 @@ int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned x return -1; } -int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLCanvasElement* canvas, bool flipY, bool premultiplyAlpha) -{ - // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size - UNUSED_PARAM(target); - UNUSED_PARAM(level); - UNUSED_PARAM(xoff); - UNUSED_PARAM(yoff); - UNUSED_PARAM(width); - UNUSED_PARAM(height); - UNUSED_PARAM(canvas); - - // FIXME: need to support flipY and premultiplyAlpha - UNUSED_PARAM(flipY); - UNUSED_PARAM(premultiplyAlpha); - return -1; -} - int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha) { // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size @@ -1745,7 +1283,7 @@ unsigned GraphicsContext3D::createRenderbuffer() return o; } -unsigned GraphicsContext3D::createShader(ShaderType type) +unsigned GraphicsContext3D::createShader(unsigned long type) { ensureContext(m_contextObj); return glCreateShader((type == FRAGMENT_SHADER) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER); @@ -1817,6 +1355,11 @@ int GraphicsContext3D::sizeInBytes(int type) } } +void GraphicsContext3D::synthesizeGLError(unsigned long error) +{ + m_syntheticErrors.add(error); +} + } #endif // ENABLE(3D_CANVAS) diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h index 8cf51b4..8024091 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h @@ -54,6 +54,7 @@ public: // for hosting this GraphicsLayer in a native layer hierarchy virtual NativeLayer nativeLayer() const; + virtual bool setChildren(const Vector<GraphicsLayer*>&); virtual void addChild(GraphicsLayer*); virtual void addChildAtIndex(GraphicsLayer*, int index); virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling); diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm index b351956..dea6bfc 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -47,6 +47,7 @@ #import "WebLayer.h" #import "WebTiledLayer.h" #import <limits.h> +#import <objc/objc-auto.h> #import <wtf/CurrentTime.h> #import <wtf/UnusedParam.h> #import <wtf/RetainPtr.h> @@ -298,6 +299,18 @@ static void clearLayerBackgroundColor(PlatformLayer* layer) [layer setBackgroundColor:0]; } +static void safeSetSublayers(CALayer* layer, NSArray* sublayers) +{ + // Workaround for <rdar://problem/7390716>: -[CALayer setSublayers:] crashes if sublayers is an empty array, or nil, under GC. + if (objc_collectingEnabled() && ![sublayers count]) { + while ([[layer sublayers] count]) + [[[layer sublayers] objectAtIndex:0] removeFromSuperlayer]; + return; + } + + [layer setSublayers:sublayers]; +} + static bool caValueFunctionSupported() { static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)]; @@ -315,18 +328,6 @@ GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoord return CompositingCoordinatesBottomUp; } -bool GraphicsLayer::showDebugBorders() -{ - static bool showDebugBorders = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerBorders"]; - return showDebugBorders; -} - -bool GraphicsLayer::showRepaintCounter() -{ - static bool showRepaintCounter = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerRepaintCounter"]; - return showRepaintCounter; -} - static NSDictionary* nullActionsDictionary() { NSNull* nullValue = [NSNull null]; @@ -352,13 +353,13 @@ PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) } GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client) -: GraphicsLayer(client) -, m_contentsLayerPurpose(NoContentsLayer) -, m_contentsLayerHasBackgroundColor(false) -, m_uncommittedChanges(NoChange) + : GraphicsLayer(client) + , m_contentsLayerPurpose(NoContentsLayer) + , m_contentsLayerHasBackgroundColor(false) + , m_uncommittedChanges(NoChange) #if ENABLE(3D_CANVAS) -, m_platformGraphicsContext3D(NullPlatformGraphicsContext3D) -, m_platformTexture(NullPlatform3DObject) + , m_platformGraphicsContext3D(NullPlatformGraphicsContext3D) + , m_platformTexture(NullPlatform3DObject) #endif { BEGIN_BLOCK_OBJC_EXCEPTIONS @@ -409,6 +410,15 @@ NativeLayer GraphicsLayerCA::nativeLayer() const return m_layer.get(); } +bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children) +{ + bool childrenChanged = GraphicsLayer::setChildren(children); + if (childrenChanged) + noteLayerPropertyChanged(ChildrenChanged); + + return childrenChanged; +} + void GraphicsLayerCA::addChild(GraphicsLayer* childLayer) { GraphicsLayer::addChild(childLayer); @@ -882,17 +892,16 @@ void GraphicsLayerCA::updateSublayerList() [newSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]; if (m_transformLayer) { - [m_transformLayer.get() setSublayers:newSublayers]; + safeSetSublayers(m_transformLayer.get(), newSublayers); if (m_contentsLayer) { // If we have a transform layer, then the contents layer is parented in the // primary layer (which is itself a child of the transform layer). - [m_layer.get() setSublayers:nil]; + safeSetSublayers(m_layer.get(), nil); [m_layer.get() addSublayer:m_contentsLayer.get()]; } - } else { - [m_layer.get() setSublayers:newSublayers]; - } + } else + safeSetSublayers(m_layer.get(), newSublayers); [newSublayers release]; } @@ -1757,7 +1766,7 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer) } [m_layer.get() setLayerOwner:this]; - [m_layer.get() setSublayers:[oldLayer.get() sublayers]]; + safeSetSublayers(m_layer.get(), [oldLayer.get() sublayers]); [[oldLayer.get() superlayer] replaceSublayer:oldLayer.get() with:m_layer.get()]; diff --git a/WebCore/platform/graphics/mac/IconMac.mm b/WebCore/platform/graphics/mac/IconMac.mm index 63abe59..aee7234 100644 --- a/WebCore/platform/graphics/mac/IconMac.mm +++ b/WebCore/platform/graphics/mac/IconMac.mm @@ -39,27 +39,32 @@ Icon::~Icon() { } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { - // Don't pass relative filenames -- we don't want a result that depends on the current directory. - // Need 0U here to disambiguate String::operator[] from operator(NSString*, int)[] - if (filename.isEmpty() || filename[0U] != '/') + if (filenames.isEmpty()) return 0; - NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile:filename]; - if (!image) - return 0; + bool useIconFromFirstFile; +#ifdef BUILDING_ON_TIGER + // FIXME: find a better image for multiple files to use on Tiger. + useIconFromFirstFile = true; +#else + useIconFromFirstFile = filenames.size() == 1; +#endif + if (useIconFromFirstFile) { + // Don't pass relative filenames -- we don't want a result that depends on the current directory. + // Need 0U here to disambiguate String::operator[] from operator(NSString*, int)[] + if (filenames[0].isEmpty() || filenames[0][0U] != '/') + return 0; - return adoptRef(new Icon(image)); -} + NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile:filenames[0]]; + if (!image) + return 0; -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) -{ - if (filenames.isEmpty()) - return 0; + return adoptRef(new Icon(image)); + } #ifdef BUILDING_ON_TIGER - // FIXME: find a better image to use on Tiger. - return createIconForFile(filenames[0]); + return 0; #else NSImage* image = [NSImage imageNamed:NSImageNameMultipleDocuments]; if (!image) diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h index 0a63626..7aaf95d 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h @@ -101,6 +101,9 @@ private: void setVolume(float); void setPreservesPitch(bool); + bool hasClosedCaptions() const; + void setClosedCaptionsVisible(bool); + void setEndTime(float time); int dataRate() const; diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm index 30d0c82..dfb5958 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -736,8 +736,13 @@ bool MediaPlayerPrivate::hasAudio() const } bool MediaPlayerPrivate::supportsFullscreen() const -{ +{ +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) return true; +#else + // See <rdar://problem/7389945> + return false; +#endif } void MediaPlayerPrivate::setVolume(float volume) @@ -746,6 +751,27 @@ void MediaPlayerPrivate::setVolume(float volume) [m_qtMovie.get() setVolume:volume]; } +bool MediaPlayerPrivate::hasClosedCaptions() const +{ + if (!metaDataAvailable()) + return false; + return wkQTMovieHasClosedCaptions(m_qtMovie.get()); +} + +void MediaPlayerPrivate::setClosedCaptionsVisible(bool closedCaptionsVisible) +{ + if (metaDataAvailable()) { + wkQTMovieSetShowClosedCaptions(m_qtMovie.get(), closedCaptionsVisible); + +#if USE(ACCELERATED_COMPOSITING) && (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) + if (closedCaptionsVisible && m_qtVideoLayer) { + // Captions will be rendered upsided down unless we flag the movie as flipped (again). See <rdar://7408440>. + [m_qtVideoLayer.get() setGeometryFlipped:YES]; + } +#endif + } +} + void MediaPlayerPrivate::setRate(float rate) { if (m_qtMovie) @@ -1158,10 +1184,10 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r) TextRun textRun(text.characters(), text.length()); const Color color(255, 0, 0); context->scale(FloatSize(1.0f, -1.0f)); - context->setStrokeColor(color); + context->setStrokeColor(color, styleToUse->colorSpace()); context->setStrokeStyle(SolidStroke); context->setStrokeThickness(1.0f); - context->setFillColor(color); + context->setFillColor(color, styleToUse->colorSpace()); context->drawText(styleToUse->font(), textRun, IntPoint(2, -3)); } } diff --git a/WebCore/platform/graphics/opentype/OpenTypeSanitizer.cpp b/WebCore/platform/graphics/opentype/OpenTypeSanitizer.cpp new file mode 100644 index 0000000..b4cdb09 --- /dev/null +++ b/WebCore/platform/graphics/opentype/OpenTypeSanitizer.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#if ENABLE(OPENTYPE_SANITIZER) +#include "OpenTypeSanitizer.h" + +#include "SharedBuffer.h" +#include "opentype-sanitiser.h" +#include "ots-memory-stream.h" +#include <wtf/OwnArrayPtr.h> + +namespace WebCore { + +PassRefPtr<SharedBuffer> OpenTypeSanitizer::sanitize() +{ + if (!m_buffer) + return 0; + + // This is the largest web font size which we'll try to transcode. + static const size_t maxWebFontSize = 30 * 1024 * 1024; // 30 MB + if (m_buffer->size() > maxWebFontSize) + return 0; + + // A transcoded font is usually smaller than an original font. + // However, it can be slightly bigger than the original one due to + // name table replacement and/or padding for glyf table. + static const size_t padLen = 20 * 1024; // 20 kB + + OwnArrayPtr<unsigned char> transcodeRawBuffer(new unsigned char[m_buffer->size() + padLen]); + ots::MemoryStream output(transcodeRawBuffer.get(), m_buffer->size() + padLen); + if (!ots::Process(&output, reinterpret_cast<const uint8_t*>(m_buffer->data()), m_buffer->size())) + return 0; + + const size_t transcodeLen = output.Tell(); + return SharedBuffer::create(transcodeRawBuffer.get(), transcodeLen); +} + +} // namespace WebCore + +#endif // ENABLE(OPENTYPE_SANITIZER) diff --git a/WebCore/platform/graphics/opentype/OpenTypeSanitizer.h b/WebCore/platform/graphics/opentype/OpenTypeSanitizer.h new file mode 100644 index 0000000..3f93448 --- /dev/null +++ b/WebCore/platform/graphics/opentype/OpenTypeSanitizer.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * 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 OpenTypeSanitizer_h +#define OpenTypeSanitizer_h + +#if ENABLE(OPENTYPE_SANITIZER) +#include <wtf/Forward.h> + +namespace WebCore { + +class SharedBuffer; + +class OpenTypeSanitizer { +public: + explicit OpenTypeSanitizer(SharedBuffer* buffer) + : m_buffer(buffer) + { + } + + PassRefPtr<SharedBuffer> sanitize(); + +private: + SharedBuffer* const m_buffer; +}; + +} // namespace WebCore + +#endif // ENABLE(OPENTYPE_SANITIZER) +#endif // OpenTypeSanitizer_h diff --git a/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp index b2e3d92..3a60160 100644 --- a/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp +++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp @@ -435,7 +435,7 @@ HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName) DWORD numFonts = 0; HANDLE fontHandle = AddFontMemResourceEx(rewrittenFontData.data(), fontData->size() + nameTableSize, 0, &numFonts); - if (fontHandle && numFonts != 1) { + if (fontHandle && numFonts < 1) { RemoveFontMemResourceEx(fontHandle); return 0; } diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp index 1113eae..82fb709 100644 --- a/WebCore/platform/graphics/qt/FontCacheQt.cpp +++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp @@ -34,260 +34,39 @@ #include <wtf/ListHashSet.h> #include <wtf/StdLibExtras.h> +#include <QFont> + using namespace WTF; namespace WebCore { -FontCache* fontCache() +void FontCache::platformInit() { - DEFINE_STATIC_LOCAL(FontCache, globalFontCache, ()); - return &globalFontCache; } -FontCache::FontCache() -{ -} - -void FontCache::getTraitsInFamily(const AtomicString&, Vector<unsigned>&) -{ -} - -// This type must be consistent with FontPlatformData's ctor - the one which -// gets FontDescription as it's parameter. -class FontPlatformDataCacheKey { -public: - FontPlatformDataCacheKey(const FontDescription& description) - : m_familyName() - , m_size(description.computedPixelSize()) - , m_bold(false) - , m_italic(description.italic()) - , m_smallCaps(description.smallCaps()) - , m_hash(0) - { - // FIXME: Map all FontWeight values to QFont weights in FontPlatformData's ctor and follow it here - if (FontPlatformData::toQFontWeight(description.weight()) > QFont::Normal) - m_bold = true; - - const FontFamily* family = &description.family(); - while (family) { - m_familyName.append(family->family()); - family = family->next(); - if (family) - m_familyName.append(','); - } - - computeHash(); - } - - FontPlatformDataCacheKey(const FontPlatformData& fontData) - : m_familyName(static_cast<String>(fontData.family())) - , m_size(fontData.pixelSize()) - , m_bold(fontData.bold()) - , m_italic(fontData.italic()) - , m_smallCaps(fontData.smallCaps()) - , m_hash(0) - { - computeHash(); - } - - FontPlatformDataCacheKey(HashTableDeletedValueType) : m_size(hashTableDeletedSize()) { } - bool isHashTableDeletedValue() const { return m_size == hashTableDeletedSize(); } - - enum HashTableEmptyValueType { HashTableEmptyValue }; - - FontPlatformDataCacheKey(HashTableEmptyValueType) - : m_familyName() - , m_size(0) - , m_bold(false) - , m_italic(false) - , m_smallCaps(false) - , m_hash(0) - { - } - - bool operator==(const FontPlatformDataCacheKey& other) const - { - if (m_hash != other.m_hash) - return false; - - return equalIgnoringCase(m_familyName, other.m_familyName) && m_size == other.m_size && - m_bold == other.m_bold && m_italic == other.m_italic && m_smallCaps == other.m_smallCaps; - } - - unsigned hash() const - { - return m_hash; - } - - void computeHash() - { - unsigned hashCodes[] = { - CaseFoldingHash::hash(m_familyName), - m_size | static_cast<unsigned>(m_bold << sizeof(unsigned) * 8 - 1) - | static_cast<unsigned>(m_italic) << sizeof(unsigned) *8 - 2 - | static_cast<unsigned>(m_smallCaps) << sizeof(unsigned) * 8 - 3 - }; - m_hash = StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); - } - -private: - String m_familyName; - int m_size; - bool m_bold; - bool m_italic; - bool m_smallCaps; - unsigned m_hash; - - static unsigned hashTableDeletedSize() { return 0xFFFFFFFFU; } -}; - -struct FontPlatformDataCacheKeyHash { - static unsigned hash(const FontPlatformDataCacheKey& key) - { - return key.hash(); - } - - static bool equal(const FontPlatformDataCacheKey& a, const FontPlatformDataCacheKey& b) - { - return a == b; - } - - static const bool safeToCompareToEmptyOrDeleted = true; -}; - -struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataCacheKey> { - static const bool needsDestruction = true; - static const FontPlatformDataCacheKey& emptyValue() - { - DEFINE_STATIC_LOCAL(FontPlatformDataCacheKey, key, (FontPlatformDataCacheKey::HashTableEmptyValue)); - return key; - } - static void constructDeletedValue(FontPlatformDataCacheKey& slot) - { - new (&slot) FontPlatformDataCacheKey(HashTableDeletedValue); - } - static bool isDeletedValue(const FontPlatformDataCacheKey& value) - { - return value.isHashTableDeletedValue(); - } -}; - -typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontPlatformDataCache; - -// using Q_GLOBAL_STATIC leads to crash. TODO investigate the way to fix this. -static FontPlatformDataCache* gFontPlatformDataCache = 0; - -FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& description, const AtomicString&, bool) -{ - if (!gFontPlatformDataCache) - gFontPlatformDataCache = new FontPlatformDataCache; - - FontPlatformDataCacheKey key(description); - FontPlatformData* platformData = gFontPlatformDataCache->get(key); - if (!platformData) { - platformData = new FontPlatformData(description); - gFontPlatformDataCache->add(key, platformData); - } - return platformData; -} - -typedef HashMap<FontPlatformDataCacheKey, std::pair<SimpleFontData*, unsigned>, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontDataCache; - -static FontDataCache* gFontDataCache = 0; - -static const int cMaxInactiveFontData = 40; -static const int cTargetInactiveFontData = 32; - -static ListHashSet<const SimpleFontData*>* gInactiveFontDataSet = 0; - -SimpleFontData* FontCache::getCachedFontData(const FontPlatformData* fontPlatformData) -{ - if (!gFontDataCache) { - gFontDataCache = new FontDataCache; - gInactiveFontDataSet = new ListHashSet<const SimpleFontData*>; - } - - FontPlatformDataCacheKey key(*fontPlatformData); - FontDataCache::iterator it = gFontDataCache->find(key); - if (it == gFontDataCache->end()) { - SimpleFontData* fontData = new SimpleFontData(*fontPlatformData); - gFontDataCache->add(key, std::pair<SimpleFontData*, unsigned>(fontData, 1)); - return fontData; - } - if (!it->second.second++) { - ASSERT(gInactiveFontDataSet->contains(it->second.first)); - gInactiveFontDataSet->remove(it->second.first); - } - return it->second.first; -} - -FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription&) +const SimpleFontData* FontCache::getFontDataForCharacters(const Font&, const UChar*, int) { return 0; } -void FontCache::releaseFontData(const WebCore::SimpleFontData* fontData) +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) { - ASSERT(gFontDataCache); - ASSERT(!fontData->isCustomFont()); - - FontPlatformDataCacheKey key(fontData->platformData()); - FontDataCache::iterator it = gFontDataCache->find(key); - ASSERT(it != gFontDataCache->end()); - if (!--it->second.second) { - gInactiveFontDataSet->add(it->second.first); - if (gInactiveFontDataSet->size() > cMaxInactiveFontData) - purgeInactiveFontData(gInactiveFontDataSet->size() - cTargetInactiveFontData); - } -} - -void FontCache::purgeInactiveFontData(int count) -{ - static bool isPurging; // Guard against reentry when e.g. a deleted FontData releases its small caps FontData. - if (isPurging) - return; - - isPurging = true; - - ListHashSet<const SimpleFontData*>::iterator it = gInactiveFontDataSet->begin(); - ListHashSet<const SimpleFontData*>::iterator end = gInactiveFontDataSet->end(); - for (int i = 0; i < count && it != end; ++i, ++it) { - FontPlatformDataCacheKey key = (*it)->platformData(); - pair<SimpleFontData*, unsigned> fontDataPair = gFontDataCache->take(key); - ASSERT(fontDataPair.first != 0); - ASSERT(!fontDataPair.second); - delete fontDataPair.first; - - FontPlatformData* platformData = gFontPlatformDataCache->take(key); - if (platformData) - delete platformData; - } - - if (it == end) { - // Removed everything - gInactiveFontDataSet->clear(); - } else { - for (int i = 0; i < count; ++i) - gInactiveFontDataSet->remove(gInactiveFontDataSet->begin()); - } - - isPurging = false; + return 0; } -void FontCache::addClient(FontSelector*) +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription) { + const AtomicString fallbackFamily = QFont(fontDescription.family().family()).lastResortFont(); + return new FontPlatformData(fontDescription, fallbackFamily); } -void FontCache::removeClient(FontSelector*) +void FontCache::getTraitsInFamily(const AtomicString&, Vector<unsigned>&) { } -void FontCache::invalidate() +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName) { - if (!gFontPlatformDataCache || !gFontDataCache) - return; - - purgeInactiveFontData(); + return new FontPlatformData(fontDescription, familyName); } } // namespace WebCore diff --git a/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp index a19464e..6e9d053 100644 --- a/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp @@ -43,7 +43,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b font.setWeight(QFont::Bold); font.setItalic(italic); - return FontPlatformData(font, bold); + return FontPlatformData(font); } FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) diff --git a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp deleted file mode 100644 index 8e1e4f6..0000000 --- a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - Copyright (C) 2008 Holger Hans Peter Freyther - - 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. - - Replacement of the stock FontFallbackList as Qt is going to find us a - replacement font, will do caching and the other stuff we implement in - WebKit. -*/ - -#include "config.h" -#include "FontFallbackList.h" - -#include "Font.h" -#include "FontCache.h" -#include "SegmentedFontData.h" - -#include <QDebug> - -namespace WebCore { - -FontFallbackList::FontFallbackList() - : m_pageZero(0) - , m_cachedPrimarySimpleFontData(0) - , m_fontSelector(0) - , m_familyIndex(0) - , m_pitch(UnknownPitch) - , m_loadingCustomFonts(false) - , m_generation(0) -{ -} - -void FontFallbackList::invalidate(WTF::PassRefPtr<WebCore::FontSelector> fontSelector) -{ - releaseFontData(); - m_fontList.clear(); - m_pageZero = 0; - m_pages.clear(); - m_cachedPrimarySimpleFontData = 0; - m_familyIndex = 0; - m_pitch = UnknownPitch; - m_loadingCustomFonts = false; - m_fontSelector = fontSelector; - m_generation = 0; -} - -void FontFallbackList::releaseFontData() -{ - unsigned numFonts = m_fontList.size(); - for (unsigned i = 0; i < numFonts; ++i) { - if (m_fontList[i].second) - delete m_fontList[i].first; - else { - ASSERT(!m_fontList[i].first->isSegmented()); - fontCache()->releaseFontData(static_cast<const SimpleFontData*>(m_fontList[i].first)); - } - } -} - -void FontFallbackList::determinePitch(const WebCore::Font* font) const -{ - const FontData* fontData = primaryFontData(font); - if (!fontData->isSegmented()) - m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch(); - else { - const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData); - unsigned numRanges = segmentedFontData->numRanges(); - if (numRanges == 1) - m_pitch = segmentedFontData->rangeAt(0).fontData()->pitch(); - else - m_pitch = VariablePitch; - } -} - -const FontData* FontFallbackList::fontDataAt(const WebCore::Font* _font, unsigned index) const -{ - if (index != 0) - return 0; - - // Search for the WebCore font that is already in the list - for (int i = m_fontList.size() - 1; i >= 0; --i) { - pair<const FontData*, bool> item = m_fontList[i]; - // item.second means that the item was created locally or not - if (!item.second) - return item.first; - } - - // Use the FontSelector to get a WebCore font and then fallback to Qt - const FontDescription& description = _font->fontDescription(); - const FontFamily* family = &description.family(); - while (family) { - if (m_fontSelector) { - FontData* data = m_fontSelector->getFontData(description, family->family()); - if (data) { - if (data->isLoading()) - m_loadingCustomFonts = true; - if (!data->isCustomFont()) { - // Custom fonts can be freed anytime so we must not hold them - m_fontList.append(pair<const FontData*, bool>(data, false)); - } - return data; - } - } - family = family->next(); - } - - if (m_fontList.size()) - return m_fontList[0].first; - - const FontData* result = new SimpleFontData(FontPlatformData(description, _font->wordSpacing(), _font->letterSpacing()), true); - m_fontList.append(pair<const FontData*, bool>(result, true)); - return result; -} - -const FontData* FontFallbackList::fontDataForCharacters(const WebCore::Font* font, const UChar*, int) const -{ - return primaryFontData(font); -} - -void FontFallbackList::setPlatformFont(const WebCore::FontPlatformData&) -{ - m_familyIndex = cAllFamiliesScanned; -} - -} diff --git a/WebCore/platform/graphics/qt/FontPlatformData.h b/WebCore/platform/graphics/qt/FontPlatformData.h index 92219fd..4a3f8bc 100644 --- a/WebCore/platform/graphics/qt/FontPlatformData.h +++ b/WebCore/platform/graphics/qt/FontPlatformData.h @@ -26,20 +26,62 @@ #include "FontDescription.h" #include <QFont> +#include <QHash> namespace WebCore { class String; +class FontPlatformDataPrivate { +public: + FontPlatformDataPrivate() + : refCount(1) + , size(font.pointSizeF()) + , bold(font.bold()) + , oblique(false) + {} + FontPlatformDataPrivate(const float size, const bool bold, const bool oblique) + : refCount(1) + , size(size) + , bold(bold) + , oblique(oblique) + {} + FontPlatformDataPrivate(const QFont& font) + : refCount(1) + , font(font) + , size(font.pointSizeF()) + , bold(font.bold()) + , oblique(false) + {} + unsigned refCount; + QFont font; + float size; + bool bold : 1; + bool oblique : 1; +}; + + -class FontPlatformData -{ +class FontPlatformData : public FastAllocBase { public: -#if ENABLE(SVG_FONTS) FontPlatformData(float size, bool bold, bool oblique); -#endif - FontPlatformData(); - FontPlatformData(const FontDescription&, int wordSpacing = 0, int letterSpacing = 0); - FontPlatformData(const QFont&, bool bold); + FontPlatformData(const FontPlatformData &); + FontPlatformData(const FontDescription&, const AtomicString& familyName, int wordSpacing = 0, int letterSpacing = 0); + FontPlatformData(const QFont& font) + : m_data(new FontPlatformDataPrivate(font)) + {} + FontPlatformData(WTF::HashTableDeletedValueType) + : m_data(reinterpret_cast<FontPlatformDataPrivate*>(-1)) + {} + + ~FontPlatformData(); + + FontPlatformData& operator=(const FontPlatformData&); + bool operator==(const FontPlatformData&) const; + + bool isHashTableDeletedValue() const + { + return m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1); + } static inline QFont::Weight toQFontWeight(FontWeight fontWeight) { @@ -62,22 +104,62 @@ public: } } - QFont font() const { return m_font; } - float size() const { return m_size; } - QString family() const { return m_font.family(); } - bool bold() const { return m_bold; } - bool italic() const { return m_font.italic(); } - bool smallCaps() const { return m_font.capitalization() == QFont::SmallCaps; } - int pixelSize() const { return m_font.pixelSize(); } + QFont font() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font; + return QFont(); + } + float size() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->size; + return 0.0f; + } + QString family() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font.family(); + return QString(); + } + bool bold() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->bold; + return false; + } + bool italic() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font.italic(); + return false; + } + bool smallCaps() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font.capitalization() == QFont::SmallCaps; + return false; + } + int pixelSize() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font.pixelSize(); + return 0; + } + unsigned hash() const; #ifndef NDEBUG String description() const; #endif - - float m_size; - bool m_bold; - bool m_oblique; - QFont m_font; +private: + FontPlatformDataPrivate* m_data; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp index 7709be6..2cc2fc6 100644 --- a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp +++ b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp @@ -26,56 +26,104 @@ namespace WebCore { -FontPlatformData::FontPlatformData(const FontDescription& description, int wordSpacing, int letterSpacing) - : m_size(0.0f) - , m_bold(false) - , m_oblique(false) +static inline bool isEmtpyValue(const float size, const bool bold, const bool oblique) { - QString familyName; + // this is the empty value by definition of the trait FontDataCacheKeyTraits + return !bold && !oblique && size == 0.f; +} + +FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) +{ + if (isEmtpyValue(size, bold, oblique)) + m_data = 0; + else + m_data = new FontPlatformDataPrivate(size, bold, oblique); +} + +FontPlatformData::FontPlatformData(const FontPlatformData &other) : m_data(other.m_data) +{ + if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)) + ++m_data->refCount; +} + +FontPlatformData::FontPlatformData(const FontDescription& description, const AtomicString& familyName, int wordSpacing, int letterSpacing) + : m_data(new FontPlatformDataPrivate()) +{ + QString familyNames(familyName); + if (!familyName.isEmpty()) + familyNames += QLatin1Char(','); + const FontFamily* family = &description.family(); while (family) { - familyName += family->family(); + familyNames += family->family(); family = family->next(); if (family) - familyName += QLatin1Char(','); + familyNames += QLatin1Char(','); } + QFont& font = m_data->font; + font.setFamily(familyName); + font.setPixelSize(qRound(description.computedSize())); + font.setItalic(description.italic()); + font.setWeight(toQFontWeight(description.weight())); + font.setWordSpacing(wordSpacing); + font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing); + const bool smallCaps = description.smallCaps(); + font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase); + + m_data->bold = font.bold(); + m_data->size = font.pointSizeF(); +} - m_font.setFamily(familyName); - m_font.setPixelSize(qRound(description.computedSize())); - m_font.setItalic(description.italic()); - - m_font.setWeight(toQFontWeight(description.weight())); - m_bold = m_font.bold(); - - bool smallCaps = description.smallCaps(); - m_font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase); - m_font.setWordSpacing(wordSpacing); - m_font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing); - m_size = m_font.pointSize(); +FontPlatformData::~FontPlatformData() +{ + if (!m_data || m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1)) + return; + --m_data->refCount; + if (!m_data->refCount) + delete m_data; } -FontPlatformData::FontPlatformData(const QFont& font, bool bold) - : m_size(font.pointSize()) - , m_bold(bold) - , m_oblique(false) - , m_font(font) +FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other) { + if (m_data == other.m_data) + return *this; + if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)) { + --m_data->refCount; + if (!m_data->refCount) + delete m_data; + } + m_data = other.m_data; + if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)) + ++m_data->refCount; + return *this; } -#if ENABLE(SVG_FONTS) -FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) - : m_size(size) - , m_bold(bold) - , m_oblique(oblique) +bool FontPlatformData::operator==(const FontPlatformData& other) const { + if (m_data == other.m_data) + return true; + + if (!m_data || !other.m_data + || m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1) || other.m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1)) + return false; + + const bool equals = (m_data->size == other.m_data->size + && m_data->bold == other.m_data->bold + && m_data->oblique == other.m_data->oblique + && m_data->font == other.m_data->font); + return equals; } -#endif -FontPlatformData::FontPlatformData() - : m_size(0.0f) - , m_bold(false) - , m_oblique(false) +unsigned FontPlatformData::hash() const { + if (!m_data) + return 0; + if (m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1)) + return 1; + return qHash(m_data->font.toString()) + ^ qHash(*reinterpret_cast<quint32*>(&m_data->size)) + ^ qHash(m_data->bold) + ^ qHash(m_data->oblique); } #ifndef NDEBUG diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp index c5960ac..1e44626 100644 --- a/WebCore/platform/graphics/qt/FontQt.cpp +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -42,7 +42,6 @@ #include <limits.h> -#if QT_VERSION >= 0x040400 namespace WebCore { static const QString qstring(const TextRun& run) @@ -229,5 +228,3 @@ QFont Font::font() const } -#endif - diff --git a/WebCore/platform/graphics/qt/FontQt43.cpp b/WebCore/platform/graphics/qt/FontQt43.cpp deleted file mode 100644 index 45bf05d..0000000 --- a/WebCore/platform/graphics/qt/FontQt43.cpp +++ /dev/null @@ -1,354 +0,0 @@ -/* - Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) - Copyright (C) 2008 Holger Hans Peter Freyther - - 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 "Font.h" -#include "FontDescription.h" -#include "FontFallbackList.h" -#include "FontSelector.h" - -#include "GraphicsContext.h" -#include <QTextLayout> -#include <QPainter> -#include <QFontMetrics> -#include <QFontInfo> -#include <qalgorithms.h> -#include <qdebug.h> - -#include <limits.h> - -#if QT_VERSION < 0x040400 - -namespace WebCore { - -struct TextRunComponent { - TextRunComponent() : font(0) {} - TextRunComponent(const UChar *start, int length, bool rtl, const QFont *font, int offset, bool sc = false); - TextRunComponent(int spaces, bool rtl, const QFont *font, int offset); - - inline bool isSpace() const { return spaces != 0; } - - QString string; - const QFont *font; - int width; - int offset; - int spaces; -}; - -TextRunComponent::TextRunComponent(const UChar *start, int length, bool rtl, const QFont *f, int o, bool sc) - : string(reinterpret_cast<const QChar*>(start), length) - , font(f) - , offset(o) - , spaces(0) -{ - if (sc) - string = string.toUpper(); - string.prepend(rtl ? QChar(0x202e) : QChar(0x202d)); - width = QFontMetrics(*font).width(string); -} - -TextRunComponent::TextRunComponent(int s, bool rtl, const QFont *f, int o) - : string(s, QLatin1Char(' ')) - , font(f) - , offset(o) - , spaces(s) -{ - string.prepend(rtl ? QChar(0x202e) : QChar(0x202d)); - width = spaces * QFontMetrics(*font).width(QLatin1Char(' ')); -} - - -static int generateComponents(Vector<TextRunComponent, 1024>* components, const Font &font, const TextRun &run) -{ -// qDebug() << "generateComponents" << QString((const QChar *)run.characters(), run.length()); - int letterSpacing = font.letterSpacing(); - int wordSpacing = font.wordSpacing(); - bool smallCaps = font.fontDescription().smallCaps(); - int padding = run.padding(); - int numSpaces = 0; - if (padding) { - for (int i = 0; i < run.length(); i++) - if (Font::treatAsSpace(run[i])) - ++numSpaces; - } - - int offset = 0; - const QFont *f = &font.font(); - if (letterSpacing || smallCaps) { - // need to draw every letter on it's own - int start = 0; - if (Font::treatAsSpace(run[0])) { - int add = 0; - if (numSpaces) { - add = padding/numSpaces; - padding -= add; - --numSpaces; - } - components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); - offset += add + letterSpacing + components->last().width; - start = 1; -// qDebug() << "space at 0" << offset; - } else if (smallCaps) - f = (QChar::category(run[0]) == QChar::Letter_Lowercase ? &font.scFont() : &font.font()); - - for (int i = 1; i < run.length(); ++i) { - uint ch = run[i]; - if (QChar(ch).isHighSurrogate() && QChar(run[i-1]).isLowSurrogate()) - ch = QChar::surrogateToUcs4(ch, run[i-1]); - if (QChar(ch).isLowSurrogate() || QChar::category(ch) == QChar::Mark_NonSpacing) - continue; - if (Font::treatAsSpace(run[i])) { - int add = 0; -// qDebug() << " treatAsSpace:" << i << start; - if (i - start > 0) { - components->append(TextRunComponent(run.characters() + start, i - start, - run.rtl(), - f, offset, f == &font.scFont())); - offset += components->last().width + letterSpacing; -// qDebug() << " appending(1) " << components->last().string << components->last().width; - } - if (numSpaces) { - add = padding/numSpaces; - padding -= add; - --numSpaces; - } - components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); - offset += wordSpacing + add + components->last().width + letterSpacing; - start = i + 1; - continue; - } else if (!letterSpacing) { -// qDebug() << i << char(run[i]) << (QChar::category(ch) == QChar::Letter_Lowercase) << -// QFontInfo(*f).pointSizeF(); - if (QChar::category(ch) == QChar::Letter_Lowercase) { - if (f == &font.scFont()) - continue; - } else { - if (f == &font.font()) - continue; - } - } - if (i - start > 0) { - components->append(TextRunComponent(run.characters() + start, i - start, - run.rtl(), - f, offset, f == &font.scFont())); - offset += components->last().width + letterSpacing; -// qDebug() << " appending(2) " << components->last().string << components->last().width; - } - if (smallCaps) - f = (QChar::category(ch) == QChar::Letter_Lowercase ? &font.scFont() : &font.font()); - start = i; - } - if (run.length() - start > 0) { - components->append(TextRunComponent(run.characters() + start, run.length() - start, - run.rtl(), - f, offset, f == &font.scFont())); - offset += components->last().width; -// qDebug() << " appending(3) " << components->last().string << components->last().width; - } - offset += letterSpacing; - } else { - int start = 0; - for (int i = 0; i < run.length(); ++i) { - if (Font::treatAsSpace(run[i])) { - if (i - start > 0) { - components->append(TextRunComponent(run.characters() + start, i - start, - run.rtl(), - f, offset)); - offset += components->last().width; - } - int add = 0; - if (numSpaces) { - add = padding/numSpaces; - padding -= add; - --numSpaces; - } - components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); - offset += add + components->last().width; - if (i) - offset += wordSpacing; - start = i + 1; - } - } - if (run.length() - start > 0) { - components->append(TextRunComponent(run.characters() + start, run.length() - start, - run.rtl(), - f, offset)); - offset += components->last().width; - } - } - return offset; -} - -void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const -{ - if (to < 0) - to = run.length(); - - QPainter *p = ctx->platformContext(); - Color color = ctx->fillColor(); - p->setPen(QColor(color)); - - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - if (from > 0 || to < run.length()) { - FloatRect clip = selectionRectForComplexText(run, - IntPoint(qRound(point.x()), qRound(point.y())), - QFontMetrics(font()).height(), from, to); - QRectF rect(clip.x(), clip.y() - ascent(), clip.width(), clip.height()); - p->save(); - p->setClipRect(rect.toRect()); - } - - if (run.rtl()) { - for (int i = 0; i < components.size(); ++i) { - if (!components.at(i).isSpace()) { - p->setFont(*components.at(i).font); - QPointF pt(point.x() + w - components.at(i).offset - components.at(i).width, point.y()); - p->drawText(pt, components.at(i).string); - } - } - } else { - for (int i = 0; i < components.size(); ++i) { - if (!components.at(i).isSpace()) { - p->setFont(*components.at(i).font); - QPointF pt(point.x() + components.at(i).offset, point.y()); - p->drawText(pt, components.at(i).string); - } - } - } - if (from > 0 || to < run.length()) - p->restore(); -} - -float Font::floatWidthForComplexText(const TextRun& run) const -{ - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - return w; -} - -int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const -{ - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - int offset = 0; - if (run.rtl()) { - for (int i = 0; i < components.size(); ++i) { - int xe = w - components.at(i).offset; - int xs = xe - components.at(i).width; - if (position >= xs) { - QTextLayout layout(components.at(i).string, *components.at(i).font); - layout.beginLayout(); - QTextLine l = layout.createLine(); - if (!l.isValid()) - return offset; - - l.setLineWidth(INT_MAX / 256); - layout.endLayout(); - - if (position - xs >= l.width()) - return offset; - int cursor = l.xToCursor(position - xs); - if (cursor > 1) - --cursor; - return offset + cursor; - } else - offset += components.at(i).string.length() - 1; - } - } else { - for (int i = 0; i < components.size(); ++i) { - int xs = components.at(i).offset; - int xe = xs + components.at(i).width; - if (position <= xe) { - QTextLayout layout(components.at(i).string, *components.at(i).font); - layout.beginLayout(); - QTextLine l = layout.createLine(); - if (!l.isValid()) - return offset; - - l.setLineWidth(INT_MAX / 256); - layout.endLayout(); - - if (position - xs >= l.width()) - return offset + components.at(i).string.length() - 1; - int cursor = l.xToCursor(position - xs); - if (cursor > 1) - --cursor; - return offset + cursor; - } else - offset += components.at(i).string.length() - 1; - } - } - return run.length(); -} - -static float cursorToX(const Vector<TextRunComponent, 1024>& components, int width, bool rtl, int cursor) -{ - int start = 0; - for (int i = 0; i < components.size(); ++i) { - if (start + components.at(i).string.length() - 1 < cursor) { - start += components.at(i).string.length() - 1; - continue; - } - int xs = components.at(i).offset; - if (rtl) - xs = width - xs - components.at(i).width; - QTextLayout layout(components.at(i).string, *components.at(i).font); - layout.beginLayout(); - QTextLine l = layout.createLine(); - if (!l.isValid()) - return 0; - - l.setLineWidth(INT_MAX / 256); - layout.endLayout(); - - return xs + l.cursorToX(cursor - start + 1); - } - return width; -} - -FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& pt, - int h, int from, int to) const -{ - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - if (from == 0 && to == run.length()) - return FloatRect(pt.x(), pt.y(), w, h); - - float x1 = cursorToX(components, w, run.rtl(), from); - float x2 = cursorToX(components, w, run.rtl(), to); - if (x2 < x1) - qSwap(x1, x2); - - return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h); -} - -int Font::lineGap() const -{ - return QFontMetrics(m_font).leading(); -} - -} - -#endif diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index 57a481a..a095476 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -256,8 +256,8 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) setPaintingDisabled(!context); if (context) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), DeviceColorSpace); + setPlatformStrokeColor(strokeColor(), DeviceColorSpace); } } @@ -639,24 +639,18 @@ void GraphicsContext::fillPath() QPainterPath path = m_data->currentPath; path.setFillRule(toQtFillRule(fillRule())); - if ((m_common->state.fillColorSpace != SolidColorSpace) - || (fillColor().alpha())) { + if (m_common->state.fillPattern || m_common->state.fillGradient || fillColor().alpha()) { drawFilledShadowPath(this, p, &path); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - if (fillColor().alpha()) - p->fillPath(path, p->brush()); - break; - case PatternColorSpace: { + if (m_common->state.fillPattern) { TransformationMatrix affine; p->fillPath(path, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); - break; - } - case GradientColorSpace: + } else if (m_common->state.fillGradient) { QBrush brush(*m_common->state.fillGradient->platformGradient()); brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); p->fillPath(path, brush); - break; + } else { + if (fillColor().alpha()) + p->fillPath(path, p->brush()); } } m_data->currentPath = QPainterPath(); @@ -672,8 +666,7 @@ void GraphicsContext::strokePath() QPainterPath path = m_data->currentPath; path.setFillRule(toQtFillRule(fillRule())); - if ((m_common->state.strokeColorSpace != SolidColorSpace) - || (strokeColor().alpha())) { + if (m_common->state.strokePattern || m_common->state.strokeGradient || strokeColor().alpha()) { IntSize shadowSize; int shadowBlur; Color shadowColor; @@ -685,26 +678,20 @@ void GraphicsContext::strokePath() p->strokePath(path, shadowPen); p->setWorldTransform(t); } - switch (m_common->state.strokeColorSpace) { - case SolidColorSpace: - if (strokeColor().alpha()) - p->strokePath(path, pen); - break; - case PatternColorSpace: { + if (m_common->state.strokePattern) { TransformationMatrix affine; pen.setBrush(QBrush(m_common->state.strokePattern->createPlatformPattern(affine))); p->setPen(pen); p->strokePath(path, pen); - break; - } - case GradientColorSpace: { + } else if (m_common->state.strokeGradient) { QBrush brush(*m_common->state.strokeGradient->platformGradient()); brush.setTransform(m_common->state.strokeGradient->gradientSpaceTransform()); pen.setBrush(brush); p->setPen(pen); p->strokePath(path, pen); - break; - } + } else { + if (strokeColor().alpha()) + p->strokePath(path, pen); } } m_data->currentPath = QPainterPath(); @@ -729,29 +716,23 @@ void GraphicsContext::fillRect(const FloatRect& rect) QPainter* p = m_data->p(); - if ((m_common->state.fillColorSpace != SolidColorSpace) - || (fillColor().alpha())) { + if (m_common->state.fillPattern || m_common->state.fillGradient || fillColor().alpha()) { drawBorderlessRectShadow(this, p, rect); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - if (fillColor().alpha()) - p->fillRect(rect, p->brush()); - break; - case PatternColorSpace: { + if (m_common->state.fillPattern) { TransformationMatrix affine; p->fillRect(rect, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); - break; - } - case GradientColorSpace: + } else if (m_common->state.fillGradient) { QBrush brush(*m_common->state.fillGradient->platformGradient()); brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); p->fillRect(rect, brush); - break; + } else { + if (fillColor().alpha()) + p->fillRect(rect, p->brush()); } } } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& c) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& c, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -762,7 +743,7 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& c) p->fillRect(rect, m_data->solidColor); } -void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) { if (paintingDisabled() || !color.alpha()) return; @@ -886,7 +867,7 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) return FloatRect(QRectF(result)); } -void GraphicsContext::setPlatformShadow(const IntSize& size, int, const Color&) +void GraphicsContext::setPlatformShadow(const IntSize& size, int, const Color&, ColorSpace) { // Qt doesn't support shadows natively, they are drawn manually in the draw* // functions @@ -1225,7 +1206,7 @@ void GraphicsContext::setURLForRect(const KURL&, const IntRect&) notImplemented(); } -void GraphicsContext::setPlatformStrokeColor(const Color& color) +void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -1255,7 +1236,7 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness) p->setPen(newPen); } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; diff --git a/WebCore/platform/graphics/qt/IconQt.cpp b/WebCore/platform/graphics/qt/IconQt.cpp index 98f4606..a9870fc 100644 --- a/WebCore/platform/graphics/qt/IconQt.cpp +++ b/WebCore/platform/graphics/qt/IconQt.cpp @@ -40,15 +40,17 @@ Icon::~Icon() { } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { - RefPtr<Icon> i = adoptRef(new Icon); - i->m_icon = QIcon(filename); - return i.release(); -} + if (filenames.isEmpty()) + return 0; + + if (filenames.size() == 1) { + RefPtr<Icon> i = adoptRef(new Icon); + i->m_icon = QIcon(filenames[0]); + return i.release(); + } -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) -{ //FIXME: Implement this return 0; } diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index f8403b7..b6823dd 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -145,16 +145,8 @@ RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index) return &frame; } -void ImageDecoderQt::clearFrameBufferCache(size_t index) +void ImageDecoderQt::clearFrameBufferCache(size_t /*index*/) { - // Currently QImageReader will be asked to read everything. This - // might change when we read gif images on demand. For now we - // can have a rather simple implementation. - if (index > m_frameBufferCache.size()) - return; - - for (size_t i = 0; i < index; ++index) - m_frameBufferCache[index].clear(); } void ImageDecoderQt::internalDecodeSize() diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp index da6ddac..9a82911 100644 --- a/WebCore/platform/graphics/qt/ImageQt.cpp +++ b/WebCore/platform/graphics/qt/ImageQt.cpp @@ -44,9 +44,7 @@ #include <QPainter> #include <QImage> #include <QImageReader> -#if QT_VERSION >= 0x040300 #include <QTransform> -#endif #include <QDebug> @@ -64,6 +62,8 @@ static QPixmap loadResourcePixmap(const char *name) pixmap = QWebSettings::webGraphic(QWebSettings::DefaultFrameIconGraphic); else if (qstrcmp(name, "textAreaResizeCorner") == 0) pixmap = QWebSettings::webGraphic(QWebSettings::TextAreaSizeGripCornerGraphic); + else if (qstrcmp(name, "deleteButton") == 0) + pixmap = QWebSettings::webGraphic(QWebSettings::DeleteButtonGraphic); return pixmap; } @@ -94,7 +94,7 @@ PassRefPtr<Image> Image::loadPlatformResource(const char* name) } void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) + const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect) { QPixmap* framePixmap = nativeImageForCurrentFrame(); if (!framePixmap) // If it's too early we won't have an image yet. @@ -120,6 +120,38 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const imageObserver()->didDraw(this); } +BitmapImage::BitmapImage(QPixmap* pixmap, ImageObserver* observer) + : Image(observer) + , m_currentFrame(0) + , m_frames(0) + , m_frameTimer(0) + , m_repetitionCount(cAnimationNone) + , m_repetitionCountStatus(Unknown) + , m_repetitionsComplete(0) + , m_isSolidColor(false) + , m_checkedForSolidColor(false) + , m_animationFinished(true) + , m_allDataReceived(true) + , m_haveSize(true) + , m_sizeAvailable(true) + , m_decodedSize(0) + , m_haveFrameCount(true) + , m_frameCount(1) +{ + initPlatformData(); + + int width = pixmap->width(); + int height = pixmap->height(); + m_decodedSize = width * height * 4; + m_size = IntSize(width, height); + + m_frames.grow(1); + m_frames[0].m_frame = pixmap; + m_frames[0].m_hasAlpha = pixmap->hasAlpha(); + m_frames[0].m_haveMetadata = true; + checkForSolidColor(); +} + void BitmapImage::initPlatformData() { } @@ -130,7 +162,7 @@ void BitmapImage::invalidatePlatformData() // Drawing Routines void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, - const FloatRect& src, CompositeOperator op) + const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { startAnimation(); @@ -139,7 +171,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, return; if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, dst, solidColor(), op); + fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op); return; } @@ -181,6 +213,13 @@ void BitmapImage::checkForSolidColor() m_solidColor = QColor::fromRgba(framePixmap->toImage().pixel(0, 0)); } +#if PLATFORM(WIN_OS) +PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap) +{ + return BitmapImage::create(new QPixmap(QPixmap::fromWinHBITMAP(hBitmap))); +} +#endif + } diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp index 7078d16..f446755 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp @@ -101,15 +101,15 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) foreach (QWidget* widget, qFindChildren<QWidget*>(m_videoWidget)) widget->installEventFilter(this); - connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), - this, SLOT(stateChanged(Phonon::State, Phonon::State))); + connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)), + this, SLOT(stateChanged(Phonon::State,Phonon::State))); connect(m_mediaObject, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged())); connect(m_mediaObject, SIGNAL(seekableChanged(bool)), this, SLOT(seekableChanged(bool))); connect(m_mediaObject, SIGNAL(hasVideoChanged(bool)), this, SLOT(hasVideoChanged(bool))); connect(m_mediaObject, SIGNAL(bufferStatus(int)), this, SLOT(bufferStatus(int))); connect(m_mediaObject, SIGNAL(finished()), this, SLOT(finished())); - connect(m_mediaObject, SIGNAL(currentSourceChanged(const Phonon::MediaSource&)), - this, SLOT(currentSourceChanged(const Phonon::MediaSource&))); + connect(m_mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)), + this, SLOT(currentSourceChanged(Phonon::MediaSource))); connect(m_mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish())); connect(m_mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64))); } diff --git a/WebCore/platform/graphics/qt/StillImageQt.cpp b/WebCore/platform/graphics/qt/StillImageQt.cpp index 95b3bc8..1db04a7 100644 --- a/WebCore/platform/graphics/qt/StillImageQt.cpp +++ b/WebCore/platform/graphics/qt/StillImageQt.cpp @@ -50,7 +50,7 @@ NativeImagePtr StillImage::nativeImageForCurrentFrame() } void StillImage::draw(GraphicsContext* ctxt, const FloatRect& dst, - const FloatRect& src, CompositeOperator op) + const FloatRect& src, ColorSpace, CompositeOperator op) { if (m_pixmap.isNull()) return; diff --git a/WebCore/platform/graphics/qt/StillImageQt.h b/WebCore/platform/graphics/qt/StillImageQt.h index 6c417b1..7be9136 100644 --- a/WebCore/platform/graphics/qt/StillImageQt.h +++ b/WebCore/platform/graphics/qt/StillImageQt.h @@ -46,7 +46,7 @@ namespace WebCore { virtual IntSize size() const; virtual NativeImagePtr nativeImageForCurrentFrame(); - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); private: StillImage(const QPixmap& pixmap); diff --git a/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h b/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h index 5d85652..9fb6a8b 100644 --- a/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h +++ b/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h @@ -72,7 +72,7 @@ public: } protected: - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); private: NativeImageSkia m_nativeImage; diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index 889c41b..f1536a6 100644 --- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -293,7 +293,10 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness path.addOval(r, SkPath::kCW_Direction); // only perform the inset if we won't invert r if (2 * thickness < rect.width() && 2 * thickness < rect.height()) { - r.inset(SkIntToScalar(thickness), SkIntToScalar(thickness)); + // Adding one to the thickness doesn't make the border too thick as + // it's painted over afterwards. But without this adjustment the + // border appears a little anemic after anti-aliasing. + r.inset(SkIntToScalar(thickness + 1), SkIntToScalar(thickness + 1)); path.addOval(r, SkPath::kCCW_Direction); } platformContext()->clipPathAntiAliased(path); @@ -704,8 +707,6 @@ void GraphicsContext::fillPath() return; const GraphicsContextState& state = m_common->state; - ColorSpace colorSpace = state.fillColorSpace; - path.setFillType(state.fillRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); @@ -727,14 +728,13 @@ void GraphicsContext::fillRect(const FloatRect& rect) } const GraphicsContextState& state = m_common->state; - ColorSpace colorSpace = state.fillColorSpace; SkPaint paint; platformContext()->setupPaintForFilling(&paint); platformContext()->canvas()->drawRect(r, paint); } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -765,7 +765,8 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, - const Color& color) + const Color& color, + ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -782,7 +783,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, // Not all the radii fit, return a rect. This matches the behavior of // Path::createRoundedRectangle. Without this we attempt to draw a round // shadow for a square box. - fillRect(rect, color); + fillRect(rect, color, colorSpace); return; } @@ -950,7 +951,7 @@ void GraphicsContext::setMiterLimit(float limit) platformContext()->setMiterLimit(limit); } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -977,7 +978,8 @@ void GraphicsContext::setPlatformFillPattern(Pattern* pattern) void GraphicsContext::setPlatformShadow(const IntSize& size, int blurInt, - const Color& color) + const Color& color, + ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -1019,7 +1021,7 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, dl->unref(); } -void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor) +void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -1118,7 +1120,6 @@ void GraphicsContext::strokePath() return; const GraphicsContextState& state = m_common->state; - ColorSpace colorSpace = state.strokeColorSpace; SkPaint paint; platformContext()->setupPaintForStroking(&paint, 0, 0); @@ -1135,7 +1136,6 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) return; const GraphicsContextState& state = m_common->state; - ColorSpace colorSpace = state.strokeColorSpace; SkPaint paint; platformContext()->setupPaintForStroking(&paint, 0, 0); diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index a5c8926..c36f1ce 100644 --- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -105,13 +105,16 @@ Image* ImageBuffer::image() const void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) { const SkBitmap& bitmap = *context()->platformContext()->bitmap(); + if (bitmap.isNull()) + return; + ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); SkAutoLockPixels bitmapLock(bitmap); for (int y = 0; y < m_size.height(); ++y) { uint32_t* srcRow = bitmap.getAddr32(0, y); for (int x = 0; x < m_size.width(); ++x) { SkColor color = SkPMColorToColor(srcRow[x]); - srcRow[x] = SkPreMultiplyARGB(lookUpTable[SkColorGetA(color)], + srcRow[x] = SkPreMultiplyARGB(SkColorGetA(color), lookUpTable[SkColorGetR(color)], lookUpTable[SkColorGetG(color)], lookUpTable[SkColorGetB(color)]); @@ -164,11 +167,12 @@ PassRefPtr<ImageData> getImageData(const IntRect& rect, const SkBitmap& bitmap, for (int x = 0; x < numColumns; ++x) { unsigned char* destPixel = &destRow[x * 4]; if (multiplied == Unmultiplied) { - SkColor color = SkPMColorToColor(srcRow[x]); - destPixel[0] = SkColorGetR(color); - destPixel[1] = SkColorGetG(color); - destPixel[2] = SkColorGetB(color); - destPixel[3] = SkColorGetA(color); + SkColor color = srcRow[x]; + unsigned a = SkColorGetA(color); + destPixel[0] = a ? SkColorGetR(color) * 255 / a : 0; + destPixel[1] = a ? SkColorGetG(color) * 255 / a : 0; + destPixel[2] = a ? SkColorGetB(color) * 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. diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp index ecab364..6d8ed22 100644 --- a/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -302,6 +302,7 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& floatSrcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, + ColorSpace styleColorSpace, CompositeOperator compositeOp, const FloatRect& destRect) { @@ -405,7 +406,7 @@ void BitmapImage::checkForSolidColor() } void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, - const FloatRect& srcRect, CompositeOperator compositeOp) + const FloatRect& srcRect, ColorSpace, CompositeOperator compositeOp) { if (!m_source.initialized()) return; @@ -437,6 +438,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, + ColorSpace styleColorSpace, CompositeOperator compositeOp) { FloatRect normDstRect = normalizeRect(dstRect); diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index a079da0..dfffa0d 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -343,6 +343,15 @@ void PlatformContextSkia::setupPaintForFilling(SkPaint* paint) const paint->setShader(m_state->m_fillShader); } +static SkScalar scalarBound(SkScalar v, SkScalar min, SkScalar max) +{ + if (v < min) + return min; + if (v > max) + return max; + return v; +} + float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const { setupPaintCommon(paint); @@ -351,10 +360,13 @@ float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, i paint->setColor(m_state->applyAlpha(m_state->m_strokeColor)); paint->setShader(m_state->m_strokeShader); paint->setStyle(SkPaint::kStroke_Style); - paint->setStrokeWidth(SkFloatToScalar(width)); + // The limits here (512 and 256) were made up but are hopefully large + // enough to be reasonable. They are, empirically, small enough not to + // cause overflows in Skia. + paint->setStrokeWidth(scalarBound(SkFloatToScalar(width), 0, 512)); paint->setStrokeCap(m_state->m_lineCap); paint->setStrokeJoin(m_state->m_lineJoin); - paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit)); + paint->setStrokeMiter(scalarBound(SkFloatToScalar(m_state->m_miterLimit), 0, 256)); if (m_state->m_dash) paint->setPathEffect(m_state->m_dash); diff --git a/WebCore/platform/graphics/transforms/TransformOperations.h b/WebCore/platform/graphics/transforms/TransformOperations.h index dd56408..08efd23 100644 --- a/WebCore/platform/graphics/transforms/TransformOperations.h +++ b/WebCore/platform/graphics/transforms/TransformOperations.h @@ -31,7 +31,7 @@ namespace WebCore { -class TransformOperations { +class TransformOperations : public FastAllocBase { public: TransformOperations(bool makeIdentity = false); diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.h b/WebCore/platform/graphics/transforms/TransformationMatrix.h index a7fbb3d..33f9afe 100644 --- a/WebCore/platform/graphics/transforms/TransformationMatrix.h +++ b/WebCore/platform/graphics/transforms/TransformationMatrix.h @@ -29,6 +29,7 @@ #include "FloatPoint.h" #include "IntPoint.h" #include <string.h> //for memcpy +#include <wtf/FastAllocBase.h> #if PLATFORM(CG) #include <CoreGraphics/CGAffineTransform.h> @@ -49,7 +50,7 @@ class FloatPoint3D; class FloatRect; class FloatQuad; -class TransformationMatrix { +class TransformationMatrix : public FastAllocBase { public: typedef double Matrix4[4][4]; diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp index e2ed130..e901669 100644 --- a/WebCore/platform/graphics/win/FontCGWin.cpp +++ b/WebCore/platform/graphics/win/FontCGWin.cpp @@ -362,14 +362,14 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo graphicsContext->clearShadow(); Color fillColor = graphicsContext->fillColor(); Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); - graphicsContext->setFillColor(shadowFillColor); + graphicsContext->setFillColor(shadowFillColor, DeviceColorSpace); CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width(), point.y() + translation.height() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->syntheticBoldOffset()) { CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width() + font->syntheticBoldOffset(), point.y() + translation.height() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } - graphicsContext->setFillColor(fillColor); + graphicsContext->setFillColor(fillColor, DeviceColorSpace); } CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height()); @@ -380,7 +380,7 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo } if (hasSimpleShadow) - graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor); + graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor, DeviceColorSpace); wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle); } diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp index 1923ecc..137b914 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp @@ -70,8 +70,8 @@ GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha) setPaintingDisabled(!m_data->m_cgContext); if (m_data->m_cgContext) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), DeviceColorSpace); + setPlatformStrokeColor(strokeColor(), DeviceColorSpace); } } diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp index 2489e02..61ae76c 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp @@ -74,8 +74,8 @@ GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha) if (m_data->cr) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), fillColorSpace()); + setPlatformStrokeColor(strokeColor(), strokeColorSpace()); } } diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp new file mode 100644 index 0000000..22faeb8 --- /dev/null +++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp @@ -0,0 +1,721 @@ +/* + * Copyright (C) 2009 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. ``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 USE(ACCELERATED_COMPOSITING) + +#include "GraphicsLayerCACF.h" + +#include "CString.h" +#include "FloatConversion.h" +#include "FloatRect.h" +#include "Image.h" +#include "PlatformString.h" +#include "SystemTime.h" +#include "WKCACFLayer.h" +#include <wtf/CurrentTime.h> +#include <wtf/StringExtras.h> + +using namespace std; + +namespace WebCore { + +static inline void copyTransform(CATransform3D& toT3D, const TransformationMatrix& t) +{ + toT3D.m11 = narrowPrecisionToFloat(t.m11()); + toT3D.m12 = narrowPrecisionToFloat(t.m12()); + toT3D.m13 = narrowPrecisionToFloat(t.m13()); + toT3D.m14 = narrowPrecisionToFloat(t.m14()); + toT3D.m21 = narrowPrecisionToFloat(t.m21()); + toT3D.m22 = narrowPrecisionToFloat(t.m22()); + toT3D.m23 = narrowPrecisionToFloat(t.m23()); + toT3D.m24 = narrowPrecisionToFloat(t.m24()); + toT3D.m31 = narrowPrecisionToFloat(t.m31()); + toT3D.m32 = narrowPrecisionToFloat(t.m32()); + toT3D.m33 = narrowPrecisionToFloat(t.m33()); + toT3D.m34 = narrowPrecisionToFloat(t.m34()); + toT3D.m41 = narrowPrecisionToFloat(t.m41()); + toT3D.m42 = narrowPrecisionToFloat(t.m42()); + toT3D.m43 = narrowPrecisionToFloat(t.m43()); + toT3D.m44 = narrowPrecisionToFloat(t.m44()); +} + +TransformationMatrix CAToTransform3D(const CATransform3D& fromT3D) +{ + return TransformationMatrix( + fromT3D.m11, + fromT3D.m12, + fromT3D.m13, + fromT3D.m14, + fromT3D.m21, + fromT3D.m22, + fromT3D.m23, + fromT3D.m24, + fromT3D.m31, + fromT3D.m32, + fromT3D.m33, + fromT3D.m34, + fromT3D.m41, + fromT3D.m42, + fromT3D.m43, + fromT3D.m44); +} + +static void setLayerBorderColor(WKCACFLayer* layer, const Color& color) +{ + CGColorRef borderColor = createCGColor(color); + layer->setBorderColor(borderColor); + CGColorRelease(borderColor); +} + +static void clearBorderColor(WKCACFLayer* layer) +{ + layer->setBorderColor(0); +} + +static void setLayerBackgroundColor(WKCACFLayer* layer, const Color& color) +{ + CGColorRef bgColor = createCGColor(color); + layer->setBackgroundColor(bgColor); + CGColorRelease(bgColor); +} + +static void clearLayerBackgroundColor(WKCACFLayer* layer) +{ + layer->setBackgroundColor(0); +} + +GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoordinatesOrientation() +{ + return CompositingCoordinatesBottomUp; +} + +PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) +{ + return new GraphicsLayerCACF(client); +} + +GraphicsLayerCACF::GraphicsLayerCACF(GraphicsLayerClient* client) + : GraphicsLayer(client) + , m_contentsLayerPurpose(NoContentsLayer) + , m_contentsLayerHasBackgroundColor(false) +{ + m_layer = WKCACFLayer::create(kCACFLayer, this); + + updateDebugIndicators(); +} + +GraphicsLayerCACF::~GraphicsLayerCACF() +{ + // clean up the WK layer + if (m_layer) + m_layer->removeFromSuperlayer(); + + if (m_transformLayer) + m_transformLayer->removeFromSuperlayer(); +} + +void GraphicsLayerCACF::setName(const String& inName) +{ + String name = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + inName; + GraphicsLayer::setName(name); + + m_layer->setName(inName); +} + +NativeLayer GraphicsLayerCACF::nativeLayer() const +{ + return m_layer.get(); +} + +bool GraphicsLayerCACF::setChildren(const Vector<GraphicsLayer*>& children) +{ + bool childrenChanged = GraphicsLayer::setChildren(children); + // FIXME: GraphicsLayer::setChildren calls addChild() for each sublayer, which + // will end up calling updateSublayerList() N times. + if (childrenChanged) + updateSublayerList(); + + return childrenChanged; +} + +void GraphicsLayerCACF::addChild(GraphicsLayer* childLayer) +{ + GraphicsLayer::addChild(childLayer); + updateSublayerList(); +} + +void GraphicsLayerCACF::addChildAtIndex(GraphicsLayer* childLayer, int index) +{ + GraphicsLayer::addChildAtIndex(childLayer, index); + updateSublayerList(); +} + +void GraphicsLayerCACF::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling) +{ + GraphicsLayer::addChildBelow(childLayer, sibling); + updateSublayerList(); +} + +void GraphicsLayerCACF::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer *sibling) +{ + GraphicsLayer::addChildAbove(childLayer, sibling); + updateSublayerList(); +} + +bool GraphicsLayerCACF::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) +{ + if (GraphicsLayer::replaceChild(oldChild, newChild)) { + updateSublayerList(); + return true; + } + return false; +} + +void GraphicsLayerCACF::removeFromParent() +{ + GraphicsLayer::removeFromParent(); + layerForSuperlayer()->removeFromSuperlayer(); +} + +void GraphicsLayerCACF::setPosition(const FloatPoint& point) +{ + GraphicsLayer::setPosition(point); + updateLayerPosition(); +} + +void GraphicsLayerCACF::setAnchorPoint(const FloatPoint3D& point) +{ + if (point == m_anchorPoint) + return; + + GraphicsLayer::setAnchorPoint(point); + updateAnchorPoint(); +} + +void GraphicsLayerCACF::setSize(const FloatSize& size) +{ + if (size == m_size) + return; + + GraphicsLayer::setSize(size); + updateLayerSize(); +} + +void GraphicsLayerCACF::setTransform(const TransformationMatrix& t) +{ + if (t == m_transform) + return; + + GraphicsLayer::setTransform(t); + updateTransform(); +} + +void GraphicsLayerCACF::setChildrenTransform(const TransformationMatrix& t) +{ + if (t == m_childrenTransform) + return; + + GraphicsLayer::setChildrenTransform(t); + updateChildrenTransform(); +} + +void GraphicsLayerCACF::setPreserves3D(bool preserves3D) +{ + if (preserves3D == m_preserves3D) + return; + + GraphicsLayer::setPreserves3D(preserves3D); + updateLayerPreserves3D(); +} + +void GraphicsLayerCACF::setMasksToBounds(bool masksToBounds) +{ + if (masksToBounds == m_masksToBounds) + return; + + GraphicsLayer::setMasksToBounds(masksToBounds); + updateMasksToBounds(); +} + +void GraphicsLayerCACF::setDrawsContent(bool drawsContent) +{ + if (drawsContent == m_drawsContent) + return; + + GraphicsLayer::setDrawsContent(drawsContent); + updateLayerDrawsContent(); +} + +void GraphicsLayerCACF::setBackgroundColor(const Color& color) +{ + if (m_backgroundColorSet && m_backgroundColor == color) + return; + + GraphicsLayer::setBackgroundColor(color); + + m_contentsLayerHasBackgroundColor = true; + updateLayerBackgroundColor(); +} + +void GraphicsLayerCACF::clearBackgroundColor() +{ + if (!m_backgroundColorSet) + return; + + GraphicsLayer::clearBackgroundColor(); + clearLayerBackgroundColor(m_contentsLayer.get()); +} + +void GraphicsLayerCACF::setContentsOpaque(bool opaque) +{ + if (m_contentsOpaque == opaque) + return; + + GraphicsLayer::setContentsOpaque(opaque); + updateContentsOpaque(); +} + +void GraphicsLayerCACF::setBackfaceVisibility(bool visible) +{ + if (m_backfaceVisibility == visible) + return; + + GraphicsLayer::setBackfaceVisibility(visible); + updateBackfaceVisibility(); +} + +void GraphicsLayerCACF::setOpacity(float opacity) +{ + float clampedOpacity = max(min(opacity, 1.0f), 0.0f); + + if (m_opacity == clampedOpacity) + return; + + GraphicsLayer::setOpacity(clampedOpacity); + primaryLayer()->setOpacity(opacity); +} + +void GraphicsLayerCACF::setNeedsDisplay() +{ + if (drawsContent()) + m_layer->setNeedsDisplay(); +} + +void GraphicsLayerCACF::setNeedsDisplayInRect(const FloatRect& rect) +{ + if (drawsContent()) + m_layer->setNeedsDisplay(rect); +} + +void GraphicsLayerCACF::setContentsRect(const IntRect& rect) +{ + if (rect == m_contentsRect) + return; + + GraphicsLayer::setContentsRect(rect); + updateContentsRect(); +} + +void GraphicsLayerCACF::setContentsToImage(Image* image) +{ + bool childrenChanged = false; + + if (image) { + m_pendingContentsImage = image->nativeImageForCurrentFrame(); + m_contentsLayerPurpose = ContentsLayerForImage; + if (!m_contentsLayer) + childrenChanged = true; + } else { + m_pendingContentsImage = 0; + m_contentsLayerPurpose = NoContentsLayer; + if (m_contentsLayer) + childrenChanged = true; + } + + updateContentsImage(); + + // This has to happen after updateContentsImage + if (childrenChanged) + updateSublayerList(); +} + +void GraphicsLayerCACF::setContentsToVideo(PlatformLayer* videoLayer) +{ + bool childrenChanged = false; + + if (videoLayer != m_contentsLayer.get()) + childrenChanged = true; + + m_contentsLayer = videoLayer; + m_contentsLayerPurpose = videoLayer ? ContentsLayerForVideo : NoContentsLayer; + + updateContentsVideo(); + + // This has to happen after updateContentsVideo + if (childrenChanged) + updateSublayerList(); +} + +void GraphicsLayerCACF::setGeometryOrientation(CompositingCoordinatesOrientation orientation) +{ + if (orientation == m_geometryOrientation) + return; + + GraphicsLayer::setGeometryOrientation(orientation); + updateGeometryOrientation(); +} + +PlatformLayer* GraphicsLayerCACF::hostLayerForSublayers() const +{ + return m_transformLayer ? m_transformLayer.get() : m_layer.get(); +} + +PlatformLayer* GraphicsLayerCACF::layerForSuperlayer() const +{ + return m_transformLayer ? m_transformLayer.get() : m_layer.get(); +} + +PlatformLayer* GraphicsLayerCACF::platformLayer() const +{ + return primaryLayer(); +} + +void GraphicsLayerCACF::setDebugBackgroundColor(const Color& color) +{ + if (color.isValid()) + setLayerBackgroundColor(m_layer.get(), color); + else + clearLayerBackgroundColor(m_layer.get()); +} + +void GraphicsLayerCACF::setDebugBorder(const Color& color, float borderWidth) +{ + if (color.isValid()) { + setLayerBorderColor(m_layer.get(), color); + m_layer->setBorderWidth(borderWidth); + } else { + clearBorderColor(m_layer.get()); + m_layer->setBorderWidth(0); + } +} + +GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerCACF::defaultContentsOrientation() const +{ + return CompositingCoordinatesTopDown; +} + +void GraphicsLayerCACF::updateSublayerList() +{ + Vector<RefPtr<WKCACFLayer> > newSublayers; + + if (m_transformLayer) { + // Add the primary layer first. Even if we have negative z-order children, the primary layer always comes behind. + newSublayers.append(m_layer.get()); + } else if (m_contentsLayer) { + // FIXME: add the contents layer in the correct order with negative z-order children. + // This does not cause visible rendering issues because currently contents layers are only used + // for replaced elements that don't have children. + newSublayers.append(m_contentsLayer.get()); + } + + const Vector<GraphicsLayer*>& childLayers = children(); + size_t numChildren = childLayers.size(); + for (size_t i = 0; i < numChildren; ++i) { + GraphicsLayerCACF* curChild = static_cast<GraphicsLayerCACF*>(childLayers[i]); + + WKCACFLayer* childLayer = curChild->layerForSuperlayer(); + newSublayers.append(childLayer); + } + + for (int i = 0; i < newSublayers.size(); ++i) + newSublayers[i]->removeFromSuperlayer(); + + if (m_transformLayer) { + m_transformLayer->setSublayers(newSublayers); + + if (m_contentsLayer) { + // If we have a transform layer, then the contents layer is parented in the + // primary layer (which is itself a child of the transform layer). + m_layer->removeAllSublayers(); + m_layer->addSublayer(m_contentsLayer); + } + } else + m_layer->setSublayers(newSublayers); +} + +void GraphicsLayerCACF::updateLayerPosition() +{ + // Position is offset on the layer by the layer anchor point. + CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(), + m_position.y() + m_anchorPoint.y() * m_size.height()); + + primaryLayer()->setPosition(posPoint); +} + +void GraphicsLayerCACF::updateLayerSize() +{ + CGRect rect = CGRectMake(0, 0, m_size.width(), m_size.height()); + if (m_transformLayer) { + m_transformLayer->setBounds(rect); + // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative. + CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); + m_layer->setPosition(centerPoint); + } + + m_layer->setBounds(rect); + + // Note that we don't resize m_contentsLayer. It's up the caller to do that. + + // if we've changed the bounds, we need to recalculate the position + // of the layer, taking anchor point into account. + updateLayerPosition(); +} + +void GraphicsLayerCACF::updateAnchorPoint() +{ + primaryLayer()->setAnchorPoint(FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())); + primaryLayer()->setAnchorPointZ(m_anchorPoint.z()); + updateLayerPosition(); +} + +void GraphicsLayerCACF::updateTransform() +{ + CATransform3D transform; + copyTransform(transform, m_transform); + primaryLayer()->setTransform(transform); +} + +void GraphicsLayerCACF::updateChildrenTransform() +{ + CATransform3D transform; + copyTransform(transform, m_childrenTransform); + primaryLayer()->setSublayerTransform(transform); +} + +void GraphicsLayerCACF::updateMasksToBounds() +{ + m_layer->setMasksToBounds(m_masksToBounds); + updateDebugIndicators(); +} + +void GraphicsLayerCACF::updateContentsOpaque() +{ + m_layer->setOpaque(m_contentsOpaque); +} + +void GraphicsLayerCACF::updateBackfaceVisibility() +{ + m_layer->setDoubleSided(m_backfaceVisibility); +} + +void GraphicsLayerCACF::updateLayerPreserves3D() +{ + if (m_preserves3D && !m_transformLayer) { + // Create the transform layer. + m_transformLayer = WKCACFLayer::create(kCACFTransformLayer, this); + +#ifndef NDEBUG + m_transformLayer->setName(String().format("Transform Layer CATransformLayer(%p) GraphicsLayer(%p)", m_transformLayer.get(), this)); +#endif + // Copy the position from this layer. + updateLayerPosition(); + updateLayerSize(); + updateAnchorPoint(); + updateTransform(); + updateChildrenTransform(); + + CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); + m_layer->setPosition(point); + + m_layer->setAnchorPoint(CGPointMake(0.5f, 0.5f)); + m_layer->setTransform(CATransform3DIdentity); + + // Set the old layer to opacity of 1. Further down we will set the opacity on the transform layer. + m_layer->setOpacity(1); + + // Move this layer to be a child of the transform layer. + if (m_layer->superlayer()) + m_layer->superlayer()->replaceSublayer(m_layer.get(), m_transformLayer.get()); + m_transformLayer->addSublayer(m_layer.get()); + + updateSublayerList(); + } else if (!m_preserves3D && m_transformLayer) { + // Relace the transformLayer in the parent with this layer. + m_layer->removeFromSuperlayer(); + m_transformLayer->superlayer()->replaceSublayer(m_transformLayer.get(), m_layer.get()); + + // Release the transform layer. + m_transformLayer = 0; + + updateLayerPosition(); + updateLayerSize(); + updateAnchorPoint(); + updateTransform(); + updateChildrenTransform(); + + updateSublayerList(); + } + + updateOpacityOnLayer(); +} + +void GraphicsLayerCACF::updateLayerDrawsContent() +{ + if (m_drawsContent) + m_layer->setNeedsDisplay(); + else + m_layer->setContents(nil); + + updateDebugIndicators(); +} + +void GraphicsLayerCACF::updateLayerBackgroundColor() +{ + if (!m_contentsLayer) + return; + + // We never create the contents layer just for background color yet. + if (m_backgroundColorSet) + setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor); + else + clearLayerBackgroundColor(m_contentsLayer.get()); +} + +void GraphicsLayerCACF::updateContentsImage() +{ + if (m_pendingContentsImage) { + if (!m_contentsLayer.get()) { + RefPtr<WKCACFLayer> imageLayer = WKCACFLayer::create(kCACFLayer, this); +#ifndef NDEBUG + imageLayer->setName("Image Layer"); +#endif + setupContentsLayer(imageLayer.get()); + m_contentsLayer = imageLayer; + // m_contentsLayer will be parented by updateSublayerList + } + + // FIXME: maybe only do trilinear if the image is being scaled down, + // but then what if the layer size changes? + m_contentsLayer->setMinificationFilter(kCACFFilterTrilinear); + m_contentsLayer->setContents(m_pendingContentsImage.get()); + m_pendingContentsImage = 0; + + updateContentsRect(); + } else { + // No image. + // m_contentsLayer will be removed via updateSublayerList. + m_contentsLayer = 0; + } +} + +void GraphicsLayerCACF::updateContentsVideo() +{ + // Video layer was set as m_contentsLayer, and will get parented in updateSublayerList(). + if (m_contentsLayer) { + setupContentsLayer(m_contentsLayer.get()); + updateContentsRect(); + } +} + +void GraphicsLayerCACF::updateContentsRect() +{ + if (!m_contentsLayer) + return; + + CGPoint point = CGPointMake(m_contentsRect.x(), + m_contentsRect.y()); + CGRect rect = CGRectMake(0.0f, + 0.0f, + m_contentsRect.width(), + m_contentsRect.height()); + + m_contentsLayer->setPosition(point); + m_contentsLayer->setBounds(rect); +} + +void GraphicsLayerCACF::updateGeometryOrientation() +{ + switch (geometryOrientation()) { + case CompositingCoordinatesTopDown: + m_layer->setGeometryFlipped(false); + break; + + case CompositingCoordinatesBottomUp: + m_layer->setGeometryFlipped(true); + break; + } + // Geometry orientation is mapped onto children transform in older QuartzCores, + // so is handled via setGeometryOrientation(). +} + +void GraphicsLayerCACF::setupContentsLayer(WKCACFLayer* contentsLayer) +{ + if (contentsLayer == m_contentsLayer) + return; + + if (m_contentsLayer) { + m_contentsLayer->removeFromSuperlayer(); + m_contentsLayer = 0; + } + + if (contentsLayer) { + m_contentsLayer = contentsLayer; + + if (defaultContentsOrientation() == CompositingCoordinatesBottomUp) { + CATransform3D flipper = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + m_contentsLayer->setTransform(flipper); + m_contentsLayer->setAnchorPoint(CGPointMake(0.0f, 1.0f)); + } else + m_contentsLayer->setAnchorPoint(CGPointMake(0.0f, 0.0f)); + + // Insert the content layer first. Video elements require this, because they have + // shadow content that must display in front of the video. + m_layer->insertSublayer(m_contentsLayer.get(), 0); + + updateContentsRect(); + + if (showDebugBorders()) { + setLayerBorderColor(m_contentsLayer.get(), Color(0, 0, 128, 180)); + m_contentsLayer->setBorderWidth(1.0f); + } + } + updateDebugIndicators(); +} + +// This function simply mimics the operation of GraphicsLayerCA +void GraphicsLayerCACF::updateOpacityOnLayer() +{ + primaryLayer()->setOpacity(m_opacity); +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.h b/WebCore/platform/graphics/win/GraphicsLayerCACF.h new file mode 100644 index 0000000..93ddf25 --- /dev/null +++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2009 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. ``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. + */ + +#ifndef GraphicsLayerCACF_h_ +#define GraphicsLayerCACF_h_ + +#if USE(ACCELERATED_COMPOSITING) + +#include "GraphicsLayer.h" +#include "GraphicsContext.h" +#include <wtf/RetainPtr.h> + +namespace WebCore { + +class WKCACFLayer; + +class GraphicsLayerCACF : public GraphicsLayer { +public: + + GraphicsLayerCACF(GraphicsLayerClient*); + virtual ~GraphicsLayerCACF(); + + virtual void setName(const String& inName); + + // for hosting this GraphicsLayer in a native layer hierarchy + virtual NativeLayer nativeLayer() const; + + virtual bool setChildren(const Vector<GraphicsLayer*>&); + virtual void addChild(GraphicsLayer *layer); + virtual void addChildAtIndex(GraphicsLayer *layer, int index); + virtual void addChildAbove(GraphicsLayer *layer, GraphicsLayer *sibling); + virtual void addChildBelow(GraphicsLayer *layer, GraphicsLayer *sibling); + virtual bool replaceChild(GraphicsLayer *oldChild, GraphicsLayer *newChild); + + virtual void removeFromParent(); + + virtual void setPosition(const FloatPoint& inPoint); + virtual void setAnchorPoint(const FloatPoint3D& inPoint); + virtual void setSize(const FloatSize& inSize); + + virtual void setTransform(const TransformationMatrix&); + + virtual void setChildrenTransform(const TransformationMatrix&); + + virtual void setPreserves3D(bool); + virtual void setMasksToBounds(bool); + virtual void setDrawsContent(bool); + + virtual void setBackgroundColor(const Color&); + virtual void clearBackgroundColor(); + + virtual void setContentsOpaque(bool); + virtual void setBackfaceVisibility(bool); + + virtual void setOpacity(float opacity); + + virtual void setNeedsDisplay(); + virtual void setNeedsDisplayInRect(const FloatRect&); + + virtual void setContentsRect(const IntRect&); + + virtual void setContentsToImage(Image*); + virtual void setContentsToVideo(PlatformLayer*); + + virtual PlatformLayer* platformLayer() const; + + virtual void setDebugBackgroundColor(const Color&); + virtual void setDebugBorder(const Color&, float borderWidth); + + virtual void setGeometryOrientation(CompositingCoordinatesOrientation); + + void notifySyncRequired() { if (m_client) m_client->notifySyncRequired(this); } + +private: + void updateOpacityOnLayer(); + + WKCACFLayer* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); } + WKCACFLayer* hostLayerForSublayers() const; + WKCACFLayer* layerForSuperlayer() const; + + CompositingCoordinatesOrientation defaultContentsOrientation() const; + void updateSublayerList(); + void updateLayerPosition(); + void updateLayerSize(); + void updateAnchorPoint(); + void updateTransform(); + void updateChildrenTransform(); + void updateMasksToBounds(); + void updateContentsOpaque(); + void updateBackfaceVisibility(); + void updateLayerPreserves3D(); + void updateLayerDrawsContent(); + void updateLayerBackgroundColor(); + + void updateContentsImage(); + void updateContentsVideo(); + void updateContentsRect(); + void updateGeometryOrientation(); + + void setupContentsLayer(WKCACFLayer*); + WKCACFLayer* contentsLayer() const { return m_contentsLayer.get(); } + + RefPtr<WKCACFLayer> m_layer; + RefPtr<WKCACFLayer> m_transformLayer; + RefPtr<WKCACFLayer> m_contentsLayer; + + enum ContentsLayerPurpose { + NoContentsLayer = 0, + ContentsLayerForImage, + ContentsLayerForVideo + }; + + ContentsLayerPurpose m_contentsLayerPurpose; + bool m_contentsLayerHasBackgroundColor : 1; + RetainPtr<CGImageRef> m_pendingContentsImage; +}; + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // GraphicsLayerCACF_h_ diff --git a/WebCore/platform/graphics/win/IconWin.cpp b/WebCore/platform/graphics/win/IconWin.cpp index 61f1fd3..d71ca00 100644 --- a/WebCore/platform/graphics/win/IconWin.cpp +++ b/WebCore/platform/graphics/win/IconWin.cpp @@ -47,20 +47,22 @@ Icon::~Icon() DestroyIcon(m_hIcon); } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { - SHFILEINFO sfi; - memset(&sfi, 0, sizeof(sfi)); - - String tmpFilename = filename; - if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON)) + if (filenames.isEmpty()) return 0; - return adoptRef(new Icon(sfi.hIcon)); -} + if (filenames.size() == 1) { + SHFILEINFO sfi; + memset(&sfi, 0, sizeof(sfi)); + + String tmpFilename = filenames[0]; + if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON)) + return 0; + + return adoptRef(new Icon(sfi.hIcon)); + } -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) -{ #if PLATFORM(WINCE) return 0; #else diff --git a/WebCore/platform/graphics/win/ImageCGWin.cpp b/WebCore/platform/graphics/win/ImageCGWin.cpp index 285fb71..2c6d41d 100644 --- a/WebCore/platform/graphics/win/ImageCGWin.cpp +++ b/WebCore/platform/graphics/win/ImageCGWin.cpp @@ -77,9 +77,9 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) IntSize imageSize = BitmapImage::size(); if (size) - drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), CompositeCopy); + drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), DeviceColorSpace, CompositeCopy); else - draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy); + draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), DeviceColorSpace, CompositeCopy); // Do cleanup CGContextRelease(cgContext); @@ -88,7 +88,7 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) return true; } -void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp) +void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator compositeOp) { size_t frames = frameCount(); for (size_t i = 0; i < frames; ++i) { @@ -96,7 +96,7 @@ void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const Float if (CGImageGetHeight(image) == static_cast<size_t>(srcSize.height()) && CGImageGetWidth(image) == static_cast<size_t>(srcSize.width())) { size_t currentFrame = m_currentFrame; m_currentFrame = i; - draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), compositeOp); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), styleColorSpace, compositeOp); m_currentFrame = currentFrame; return; } @@ -104,7 +104,7 @@ void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const Float // No image of the correct size was found, fallback to drawing the current frame IntSize imageSize = BitmapImage::size(); - draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), compositeOp); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), styleColorSpace, compositeOp); } } // namespace WebCore diff --git a/WebCore/platform/graphics/win/ImageCairoWin.cpp b/WebCore/platform/graphics/win/ImageCairoWin.cpp index 0b27438..e3c5ea0 100644 --- a/WebCore/platform/graphics/win/ImageCairoWin.cpp +++ b/WebCore/platform/graphics/win/ImageCairoWin.cpp @@ -82,9 +82,9 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) IntSize imageSize = BitmapImage::size(); if (size) - drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), CompositeCopy); + drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), DeviceColorSpace, CompositeCopy); else - draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy); + draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), DeviceColorSpace, CompositeCopy); // Do cleanup cairo_destroy(targetRef); @@ -92,7 +92,7 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) return true; } -void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp) +void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator compositeOp) { size_t frames = frameCount(); for (size_t i = 0; i < frames; ++i) { @@ -100,7 +100,7 @@ void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const Float if (cairo_image_surface_get_height(image) == static_cast<size_t>(srcSize.height()) && cairo_image_surface_get_width(image) == static_cast<size_t>(srcSize.width())) { size_t currentFrame = m_currentFrame; m_currentFrame = i; - draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), compositeOp); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), DeviceColorSpace, compositeOp); m_currentFrame = currentFrame; return; } @@ -108,7 +108,7 @@ void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const Float // No image of the correct size was found, fallback to drawing the current frame IntSize imageSize = BitmapImage::size(); - draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), compositeOp); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), DeviceColorSpace, compositeOp); } } // namespace WebCore diff --git a/WebCore/platform/graphics/win/IntPointWin.cpp b/WebCore/platform/graphics/win/IntPointWin.cpp index a6ce0bb..73db199 100644 --- a/WebCore/platform/graphics/win/IntPointWin.cpp +++ b/WebCore/platform/graphics/win/IntPointWin.cpp @@ -23,6 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "IntPoint.h" #include <windows.h> diff --git a/WebCore/platform/graphics/win/IntRectWin.cpp b/WebCore/platform/graphics/win/IntRectWin.cpp index 6228be8..fe25a7f 100644 --- a/WebCore/platform/graphics/win/IntRectWin.cpp +++ b/WebCore/platform/graphics/win/IntRectWin.cpp @@ -1,3 +1,4 @@ + /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. * @@ -23,6 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "IntRect.h" #include <windows.h> diff --git a/WebCore/platform/graphics/win/IntSizeWin.cpp b/WebCore/platform/graphics/win/IntSizeWin.cpp index 8a27cdb..26e68da 100644 --- a/WebCore/platform/graphics/win/IntSizeWin.cpp +++ b/WebCore/platform/graphics/win/IntSizeWin.cpp @@ -23,6 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "IntSize.h" #include <windows.h> diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp index 15e1001..a5beea1 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp @@ -318,6 +318,20 @@ void MediaPlayerPrivate::setPreservesPitch(bool preservesPitch) m_qtMovie->setPreservesPitch(preservesPitch); } +bool MediaPlayerPrivate::hasClosedCaptions() const +{ + if (!m_qtMovie) + return false; + return m_qtMovie->hasClosedCaptions(); +} + +void MediaPlayerPrivate::setClosedCaptionsVisible(bool visible) +{ + if (!m_qtMovie) + return; + m_qtMovie->setClosedCaptionsVisible(visible); +} + int MediaPlayerPrivate::dataRate() const { // This is not used at the moment diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h index 4a3a28e..2bccbbf 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h @@ -49,7 +49,10 @@ public: static void registerMediaEngine(MediaEngineRegistrar); ~MediaPlayerPrivate(); - + +private: + MediaPlayerPrivate(MediaPlayer*); + IntSize naturalSize() const; bool hasVideo() const; bool hasAudio() const; @@ -93,8 +96,8 @@ public: bool hasSingleSecurityOrigin() const; -private: - MediaPlayerPrivate(MediaPlayer*); + bool hasClosedCaptions() const; + void setClosedCaptionsVisible(bool); void updateStates(); void doSeek(); diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp index 56f3d0b..2d4c2ea 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.cpp +++ b/WebCore/platform/graphics/win/QTMovieWin.cpp @@ -45,6 +45,12 @@ using namespace std; static const long minimumQuickTimeVersion = 0x07300000; // 7.3 +static const long closedCaptionTrackType = 'clcp'; +static const long subTitleTrackType = 'sbtl'; +static const long mpeg4ObjectDescriptionTrackType = 'odsm'; +static const long mpeg4SceneDescriptionTrackType = 'sdsm'; +static const long closedCaptionDisplayPropertyID = 'disp'; + // Resizing GWorlds is slow, give them a minimum size so size of small // videos can be animated smoothly static const int cGWorldMinWidth = 640; @@ -757,10 +763,10 @@ void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& allowedTrackTypes->add(SoundMediaType); allowedTrackTypes->add(TextMediaType); allowedTrackTypes->add(BaseMediaType); - allowedTrackTypes->add('clcp'); // Closed caption - allowedTrackTypes->add('sbtl'); // Subtitle - allowedTrackTypes->add('odsm'); // MPEG-4 object descriptor stream - allowedTrackTypes->add('sdsm'); // MPEG-4 scene description stream + allowedTrackTypes->add(closedCaptionTrackType); + allowedTrackTypes->add(subTitleTrackType); + allowedTrackTypes->add(mpeg4ObjectDescriptionTrackType); + allowedTrackTypes->add(mpeg4SceneDescriptionTrackType); allowedTrackTypes->add(TimeCodeMediaType); allowedTrackTypes->add(TimeCode64MediaType); } @@ -877,6 +883,27 @@ bool QTMovieWin::hasAudio() const return (GetMovieIndTrackType(m_private->m_movie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly)); } + +bool QTMovieWin::hasClosedCaptions() const +{ + if (!m_private->m_movie) + return false; + return GetMovieIndTrackType(m_private->m_movie, 1, closedCaptionTrackType, movieTrackMediaType); +} + +void QTMovieWin::setClosedCaptionsVisible(bool visible) +{ + if (!m_private->m_movie) + return; + + Track ccTrack = GetMovieIndTrackType(m_private->m_movie, 1, closedCaptionTrackType, movieTrackMediaType); + if (!ccTrack) + return; + + Boolean doDisplay = visible; + QTSetTrackProperty(ccTrack, closedCaptionTrackType, closedCaptionDisplayPropertyID, sizeof(doDisplay), &doDisplay); +} + pascal OSErr movieDrawingCompleteProc(Movie movie, long data) { UppParam param; diff --git a/WebCore/platform/graphics/win/QTMovieWin.h b/WebCore/platform/graphics/win/QTMovieWin.h index d178eb8..778f9aa 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.h +++ b/WebCore/platform/graphics/win/QTMovieWin.h @@ -98,6 +98,9 @@ public: bool hasVideo() const; bool hasAudio() const; + bool hasClosedCaptions() const; + void setClosedCaptionsVisible(bool); + static unsigned countSupportedTypes(); static void getSupportedType(unsigned index, const UChar*& str, unsigned& len); diff --git a/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp b/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp new file mode 100644 index 0000000..e97b530 --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2009 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. ``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 USE(ACCELERATED_COMPOSITING) + +#include "WKCACFContextFlusher.h" + +#include <wtf/StdLibExtras.h> +#include <QuartzCore/CACFContext.h> + +namespace WebCore { + +WKCACFContextFlusher& WKCACFContextFlusher::shared() +{ + DEFINE_STATIC_LOCAL(WKCACFContextFlusher, flusher, ()); + return flusher; +} + +WKCACFContextFlusher::WKCACFContextFlusher() +{ +} + +WKCACFContextFlusher::~WKCACFContextFlusher() +{ +} + +void WKCACFContextFlusher::addContext(CACFContextRef context) +{ + ASSERT(context); + + m_contexts.add(context); + CFRetain(context); +} + +void WKCACFContextFlusher::removeContext(CACFContextRef context) +{ + ASSERT(context); + + ContextSet::iterator found = m_contexts.find(context); + if (found == m_contexts.end()) + return; + + CFRelease(*found); + m_contexts.remove(found); +} + +void WKCACFContextFlusher::flushAllContexts() +{ + // addContext might get called beneath CACFContextFlush, and we don't want m_contexts to change while + // we're iterating over it, so we move the contexts into a local ContextSet and iterate over that instead. + ContextSet contextsToFlush; + contextsToFlush.swap(m_contexts); + + ContextSet::const_iterator end = contextsToFlush.end(); + for (ContextSet::const_iterator it = contextsToFlush.begin(); it != end; ++it) { + CACFContextRef context = *it; + CACFContextFlush(context); + CFRelease(context); + } +} + +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/WKCACFContextFlusher.h b/WebCore/platform/graphics/win/WKCACFContextFlusher.h new file mode 100644 index 0000000..9ce76aa --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFContextFlusher.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009 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. ``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. + */ + +#ifndef WKCACFContextFlusher_h +#define WKCACFContextFlusher_h + +#if USE(ACCELERATED_COMPOSITING) + +#include <wtf/Noncopyable.h> + +#include <wtf/HashSet.h> + +typedef struct _CACFContext* CACFContextRef; + +namespace WebCore { + +class WKCACFContextFlusher : public Noncopyable { +public: + static WKCACFContextFlusher& shared(); + + void addContext(CACFContextRef); + void removeContext(CACFContextRef); + + void flushAllContexts(); + +private: + WKCACFContextFlusher(); + ~WKCACFContextFlusher(); + + typedef HashSet<CACFContextRef> ContextSet; + ContextSet m_contexts; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // WKCACFContextFlusher_h diff --git a/WebCore/platform/graphics/win/WKCACFLayer.cpp b/WebCore/platform/graphics/win/WKCACFLayer.cpp new file mode 100644 index 0000000..21e010d --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFLayer.cpp @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2009 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. ``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 USE(ACCELERATED_COMPOSITING) + +#include "WKCACFLayer.h" + +#include "WKCACFContextFlusher.h" + +#include <stdio.h> +#include <QuartzCore/CACFContext.h> +#include <QuartzCore/CARender.h> + +#pragma comment(lib, "QuartzCore")
+ +namespace WebCore { + +using namespace std; + +static void displayInContext(CACFLayerRef layer, CGContextRef context) +{ + ASSERT_ARG(layer, WKCACFLayer::layer(layer)); + WKCACFLayer::layer(layer)->display(context); +} + +// FIXME: It might be good to have a way of ensuring that all WKCACFLayers eventually +// get destroyed in debug builds. A static counter could accomplish this pretty easily. + +WKCACFLayer::WKCACFLayer(CFStringRef className, GraphicsLayerCACF* owner) + : m_layer(AdoptCF, CACFLayerCreate(className)) + , m_needsDisplayOnBoundsChange(false) + , m_owner(owner) +{ + CACFLayerSetUserData(layer(), this); + CACFLayerSetDisplayCallback(layer(), displayInContext); +} + +WKCACFLayer::~WKCACFLayer() +{ + // Our superlayer should be holding a reference to us, so there should be no way for us to be destroyed while we still have a superlayer. + ASSERT(!superlayer()); + + CACFLayerSetUserData(layer(), 0); + CACFLayerSetDisplayCallback(layer(), 0); +} + +void WKCACFLayer::display(PlatformGraphicsContext* context) +{ + if (!m_owner) + return; + + CGContextSaveGState(context); + + CGRect layerBounds = bounds(); + if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) { + CGContextScaleCTM(context, 1, -1); + CGContextTranslateCTM(context, 0, -layerBounds.size.height); + } + + if (m_owner->client()) { + GraphicsContext graphicsContext(context); + + // It's important to get the clip from the context, because it may be significantly + // smaller than the layer bounds (e.g. tiled layers) + CGRect clipBounds = CGContextGetClipBoundingBox(context); + IntRect clip(enclosingIntRect(clipBounds)); + m_owner->paintGraphicsLayerContents(graphicsContext, clip); + } +#ifndef NDEBUG + else { + ASSERT_NOT_REACHED(); + + // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color, + // so CA never makes backing store for it (which is what -setNeedsDisplay will do above). + CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f); + CGContextFillRect(context, layerBounds); + } +#endif + + if (m_owner->showRepaintCounter()) { + char text[16]; // that's a lot of repaints + _snprintf(text, sizeof(text), "%d", m_owner->incrementRepaintCount()); + + CGContextSaveGState(context); + CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f); + + CGRect aBounds = layerBounds; + + aBounds.size.width = 10 + 12 * strlen(text); + aBounds.size.height = 25; + CGContextFillRect(context, aBounds); + + CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 1.0f); + + CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f)); + CGContextSelectFont(context, "Helvetica", 25, kCGEncodingMacRoman); + CGContextShowTextAtPoint(context, aBounds.origin.x + 3.0f, aBounds.origin.y + 20.0f, text, strlen(text)); + + CGContextRestoreGState(context); + } + + CGContextRestoreGState(context); +} + +void WKCACFLayer::becomeRootLayerForContext(CACFContextRef context) +{ + CACFContextSetLayer(context, layer()); + setNeedsCommit(); +} + +void WKCACFLayer::setNeedsCommit() +{ + CACFContextRef context = CACFLayerGetContext(rootLayer()->layer()); + + // The context might now be set yet. This happens if a property gets set + // before placing the layer in the tree. In this case we don't need to + // worry about remembering the context because we will when the layer is + // added to the tree. + if (context) + WKCACFContextFlusher::shared().addContext(context); + + // Call notifySyncRequired(), which in this implementation plumbs through to + // call setRootLayerNeedsDisplay() on the WebView, which causes the CACFRenderer + // to render a frame. + if (m_owner) + m_owner->notifySyncRequired(); +} + +void WKCACFLayer::addSublayer(PassRefPtr<WKCACFLayer> sublayer) +{ + insertSublayer(sublayer, numSublayers()); +} + +void WKCACFLayer::insertSublayer(PassRefPtr<WKCACFLayer> sublayer, size_t index) +{ + index = min(index, numSublayers()); + CACFLayerInsertSublayer(layer(), sublayer->layer(), index); + setNeedsCommit(); +} + +void WKCACFLayer::insertSublayerAboveLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference) +{ + if (!reference) { + insertSublayer(sublayer, 0); + return; + } + + int referenceIndex = indexOfSublayer(reference); + if (referenceIndex == -1) { + addSublayer(sublayer); + return; + } + + insertSublayer(sublayer, referenceIndex + 1); +} + +void WKCACFLayer::insertSublayerBelowLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference) +{ + if (!reference) { + insertSublayer(sublayer, 0); + return; + } + + int referenceIndex = indexOfSublayer(reference); + if (referenceIndex == -1) { + addSublayer(sublayer); + return; + } + + insertSublayer(sublayer, referenceIndex); +} + +void WKCACFLayer::replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer> newLayer) +{ + ASSERT_ARG(reference, reference); + ASSERT_ARG(reference, reference->superlayer() == this); + + if (reference == newLayer) + return; + + if (!newLayer) { + removeSublayer(reference); + return; + } + + newLayer->removeFromSuperlayer(); + + int referenceIndex = indexOfSublayer(reference); + ASSERT(referenceIndex != -1); + if (referenceIndex == -1) + return; + + // FIXME: Can we make this more efficient? The current CACF API doesn't seem to give us a way to do so. + reference->removeFromSuperlayer(); + insertSublayer(newLayer, referenceIndex); +} + +void WKCACFLayer::removeFromSuperlayer() +{ + WKCACFLayer* superlayer = this->superlayer(); + if (!superlayer) + return; + + superlayer->removeSublayer(this); + CACFLayerRemoveFromSuperlayer(layer()); + superlayer->setNeedsCommit(); +} + +void WKCACFLayer::removeSublayer(const WKCACFLayer* sublayer) +{ + int foundIndex = indexOfSublayer(sublayer); + if (foundIndex == -1) + return; + + CACFLayerRemoveFromSuperlayer(sublayer->layer()); + setNeedsCommit(); +} + +int WKCACFLayer::indexOfSublayer(const WKCACFLayer* reference) +{ + CACFLayerRef ref = reference->layer(); + if (!ref) + return -1; + + CFArrayRef sublayers = CACFLayerGetSublayers(layer()); + size_t n = CFArrayGetCount(sublayers); + + for (size_t i = 0; i < n; ++i) + if (CFArrayGetValueAtIndex(sublayers, i) == ref) + return i; + + return -1; +} + +WKCACFLayer* WKCACFLayer::ancestorOrSelfWithSuperlayer(WKCACFLayer* superlayer) const +{ + WKCACFLayer* layer = const_cast<WKCACFLayer*>(this); + for (WKCACFLayer* ancestor = this->superlayer(); ancestor; layer = ancestor, ancestor = ancestor->superlayer()) { + if (ancestor == superlayer) + return layer; + } + return 0; +} + +void WKCACFLayer::setBounds(const CGRect& rect) +{ + if (CGRectEqualToRect(rect, bounds())) + return; + + CACFLayerSetBounds(layer(), rect); + setNeedsCommit(); + + if (m_needsDisplayOnBoundsChange) + setNeedsDisplay(); +} + +void WKCACFLayer::setFrame(const CGRect& rect) +{ + CGRect oldFrame = frame(); + if (CGRectEqualToRect(rect, oldFrame)) + return; + + CACFLayerSetFrame(layer(), rect); + setNeedsCommit(); + + if (m_needsDisplayOnBoundsChange) + setNeedsDisplay(); +} + +WKCACFLayer* WKCACFLayer::rootLayer() const +{ + WKCACFLayer* layer = const_cast<WKCACFLayer*>(this); + for (WKCACFLayer* superlayer = layer->superlayer(); superlayer; layer = superlayer, superlayer = superlayer->superlayer()) { } + return layer; +} + +void WKCACFLayer::removeAllSublayers() +{ + CACFLayerSetSublayers(layer(), 0); + setNeedsCommit(); +} + +void WKCACFLayer::setSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers) +{ + if (sublayers.isEmpty()) + CACFLayerSetSublayers(layer(), 0); + else { + // Create a vector of CACFLayers. + Vector<const void*> layers; + for (size_t i = 0; i < sublayers.size(); i++) + layers.append(sublayers[i]->layer()); + + RetainPtr<CFArrayRef> layersArray(AdoptCF, CFArrayCreate(0, layers.data(), layers.size(), 0)); + CACFLayerSetSublayers(layer(), layersArray.get()); + } + + setNeedsCommit(); +} + +void WKCACFLayer::moveSublayers(WKCACFLayer* fromLayer, WKCACFLayer* toLayer) +{ + if (!fromLayer || !toLayer) + return; + + CACFLayerSetSublayers(toLayer->layer(), CACFLayerGetSublayers(fromLayer->layer())); + fromLayer->setNeedsCommit(); + toLayer->setNeedsCommit(); +} + +WKCACFLayer* WKCACFLayer::superlayer() const +{ + CACFLayerRef super = CACFLayerGetSuperlayer(layer()); + if (!super) + return 0; + return WKCACFLayer::layer(super); +} + +void WKCACFLayer::setNeedsDisplay(const CGRect& dirtyRect) +{ + if (m_owner) + CACFLayerSetNeedsDisplay(layer(), &dirtyRect); + setNeedsCommit(); +} + +void WKCACFLayer::setNeedsDisplay() +{ + if (m_owner) + CACFLayerSetNeedsDisplay(layer(), 0); + setNeedsCommit(); +} + + +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/WKCACFLayer.h b/WebCore/platform/graphics/win/WKCACFLayer.h new file mode 100644 index 0000000..6655f7a --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFLayer.h @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2009 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. ``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. + */ + +#ifndef WKCACFLayer_h +#define WKCACFLayer_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "StringHash.h" + +#include <wtf/RefCounted.h> + +#include <QuartzCore/CACFLayer.h> +#include <QuartzCore/CACFVector.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RetainPtr.h> +#include <wtf/Vector.h> + +#include "GraphicsContext.h" +#include "GraphicsLayerCACF.h" +#include "PlatformString.h" +#include "TransformationMatrix.h" + +namespace WebCore { + +class WKCACFAnimation; +class WKCACFTimingFunction; + +class WKCACFLayer : public RefCounted<WKCACFLayer> { +public: + static PassRefPtr<WKCACFLayer> create(CFStringRef className, GraphicsLayerCACF* owner = 0) { return adoptRef(new WKCACFLayer(className, owner)); } + static WKCACFLayer* layer(CACFLayerRef layer) { return static_cast<WKCACFLayer*>(CACFLayerGetUserData(layer)); } + + ~WKCACFLayer(); + + // Makes this layer the root when the passed context is rendered + void becomeRootLayerForContext(CACFContextRef); + + static RetainPtr<CFTypeRef> cfValue(float value) { return RetainPtr<CFTypeRef>(AdoptCF, CFNumberCreate(0, kCFNumberFloat32Type, &value)); } + static RetainPtr<CFTypeRef> cfValue(const TransformationMatrix& value) + { + CATransform3D t; + t.m11 = value.m11(); + t.m12 = value.m12(); + t.m13 = value.m13(); + t.m14 = value.m14(); + t.m21 = value.m21(); + t.m22 = value.m22(); + t.m23 = value.m23(); + t.m24 = value.m24(); + t.m31 = value.m31(); + t.m32 = value.m32(); + t.m33 = value.m33(); + t.m34 = value.m34(); + t.m41 = value.m41(); + t.m42 = value.m42(); + t.m43 = value.m43(); + t.m44 = value.m44(); + return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreateTransform(t)); + } + static RetainPtr<CFTypeRef> cfValue(const FloatPoint& value) + { + CGPoint p; + p.x = value.x(); p.y = value.y(); + return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreatePoint(p)); + } + static RetainPtr<CFTypeRef> cfValue(const FloatRect& rect) + { + CGRect r; + r.origin.x = rect.x(); + r.origin.y = rect.y(); + r.size.width = rect.width(); + r.size.height = rect.height(); + CGFloat v[4] = { CGRectGetMinX(r), CGRectGetMinY(r), CGRectGetMaxX(r), CGRectGetMaxY(r) }; + return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreate(4, v)); + } + static RetainPtr<CFTypeRef> cfValue(const Color& color) + { + return RetainPtr<CFTypeRef>(AdoptCF, CGColorCreateGenericRGB(color.red(), color.green(), color.blue(), color.alpha())); + } + + void display(PlatformGraphicsContext*); + + bool isTransformLayer() const { return CACFLayerGetClass(layer()) == kCACFTransformLayer; } + + void addSublayer(PassRefPtr<WKCACFLayer> sublayer); + void insertSublayer(PassRefPtr<WKCACFLayer>, size_t index); + void insertSublayerAboveLayer(PassRefPtr<WKCACFLayer>, const WKCACFLayer* reference); + void insertSublayerBelowLayer(PassRefPtr<WKCACFLayer>, const WKCACFLayer* reference); + void replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer>); + void removeFromSuperlayer(); + static void moveSublayers(WKCACFLayer* fromLayer, WKCACFLayer* toLayer); + + WKCACFLayer* ancestorOrSelfWithSuperlayer(WKCACFLayer*) const; + + void setAnchorPoint(const CGPoint& p) { CACFLayerSetAnchorPoint(layer(), p); setNeedsCommit(); } + CGPoint anchorPoint() const { return CACFLayerGetAnchorPoint(layer()); } + + void setAnchorPointZ(CGFloat z) { CACFLayerSetAnchorPointZ(layer(), z); setNeedsCommit(); } + CGFloat anchorPointZ() const { return CACFLayerGetAnchorPointZ(layer()); } + + void setBackgroundColor(CGColorRef color) { CACFLayerSetBackgroundColor(layer(), color); setNeedsCommit(); } + CGColorRef backgroundColor() const { return CACFLayerGetBackgroundColor(layer()); } + + void setBorderColor(CGColorRef color) { CACFLayerSetBorderColor(layer(), color); setNeedsCommit(); } + CGColorRef borderColor() const { return CACFLayerGetBorderColor(layer()); } + + void setBorderWidth(CGFloat width) { CACFLayerSetBorderWidth(layer(), width); setNeedsCommit(); } + CGFloat borderWidth() const { return CACFLayerGetBorderWidth(layer()); } + + void setBounds(const CGRect&); + CGRect bounds() const { return CACFLayerGetBounds(layer()); } + + void setClearsContext(bool clears) { CACFLayerSetClearsContext(layer(), clears); setNeedsCommit(); } + bool clearsContext() const { return CACFLayerGetClearsContext(layer()); } + + void setContents(CGImageRef contents) { CACFLayerSetContents(layer(), contents); setNeedsCommit(); } + CGImageRef contents() const { return static_cast<CGImageRef>(const_cast<void*>(CACFLayerGetContents(layer()))); } + + void setContentsRect(const CGRect& contentsRect) { CACFLayerSetContentsRect(layer(), contentsRect); setNeedsCommit(); } + CGRect contentsRect() const { return CACFLayerGetContentsRect(layer()); } + + void setContentsGravity(CFStringRef str) { CACFLayerSetContentsGravity(layer(), str); setNeedsCommit(); } + CFStringRef contentsGravity() const { return CACFLayerGetContentsGravity(layer()); } + + void setDoubleSided(bool b) { CACFLayerSetDoubleSided(layer(), b); setNeedsCommit(); } + bool doubleSided() const { return CACFLayerIsDoubleSided(layer()); } + + void setEdgeAntialiasingMask(uint32_t mask) { CACFLayerSetEdgeAntialiasingMask(layer(), mask); setNeedsCommit(); } + uint32_t edgeAntialiasingMask() const { return CACFLayerGetEdgeAntialiasingMask(layer()); } + + void setFilters(CFArrayRef filters) { CACFLayerSetFilters(layer(), filters); setNeedsCommit(); } + CFArrayRef filters() const { return CACFLayerGetFilters(layer()); } + + void setFrame(const CGRect&); + CGRect frame() const { return CACFLayerGetFrame(layer()); } + + void setHidden(bool hidden) { CACFLayerSetHidden(layer(), hidden); setNeedsCommit(); } + bool isHidden() const { return CACFLayerIsHidden(layer()); } + + void setMasksToBounds(bool b) { CACFLayerSetMasksToBounds(layer(), b); } + bool masksToBounds() const { return CACFLayerGetMasksToBounds(layer()); } + + void setMagnificationFilter(const String& string) { CACFLayerSetMagnificationFilter(layer(), RetainPtr<CFStringRef>(AdoptCF, string.createCFString()).get()); } + String magnificationFilter() const { return CACFLayerGetMagnificationFilter(layer()); } + + void setMinificationFilter(const String& string) { CACFLayerSetMinificationFilter(layer(), RetainPtr<CFStringRef>(AdoptCF, string.createCFString()).get()); } + String minificationFilter() const { return CACFLayerGetMinificationFilter(layer()); } + + void setMinificationFilterBias(float bias) { CACFLayerSetMinificationFilterBias(layer(), bias); } + float minificationFilterBias() const { return CACFLayerGetMinificationFilterBias(layer()); } + + void setName(const String& name) { CACFLayerSetName(layer(), RetainPtr<CFStringRef>(AdoptCF, name.createCFString()).get()); } + String name() const { return CACFLayerGetName(layer()); } + + void setNeedsDisplay(const CGRect& dirtyRect); + void setNeedsDisplay(); + + void setNeedsDisplayOnBoundsChange(bool needsDisplay) { m_needsDisplayOnBoundsChange = needsDisplay; } + + void setOpacity(float opacity) { CACFLayerSetOpacity(layer(), opacity); setNeedsCommit(); } + float opacity() const { return CACFLayerGetOpacity(layer()); } + + void setOpaque(bool b) { CACFLayerSetOpaque(layer(), b); setNeedsCommit(); } + bool opaque() const { return CACFLayerIsOpaque(layer()); } + + void setPosition(const CGPoint& position) { CACFLayerSetPosition(layer(), position); setNeedsCommit(); } + CGPoint position() const { return CACFLayerGetPosition(layer()); } + + void setZPosition(CGFloat position) { CACFLayerSetZPosition(layer(), position); setNeedsCommit(); } + CGFloat zPosition() const { return CACFLayerGetZPosition(layer()); } + + void setSpeed(float speed) { CACFLayerSetSpeed(layer(), speed); } + CFTimeInterval speed() const { CACFLayerGetSpeed(layer()); } + + void setTimeOffset(CFTimeInterval t) { CACFLayerSetTimeOffset(layer(), t); } + CFTimeInterval timeOffset() const { CACFLayerGetTimeOffset(layer()); } + + WKCACFLayer* rootLayer() const; + + void setSortsSublayers(bool sorts) { CACFLayerSetSortsSublayers(layer(), sorts); setNeedsCommit(); } + bool sortsSublayers() const { return CACFLayerGetSortsSublayers(layer()); } + + void removeAllSublayers(); + + void setSublayers(const Vector<RefPtr<WKCACFLayer> >&); + + void setSublayerTransform(const CATransform3D& transform) { CACFLayerSetSublayerTransform(layer(), transform); setNeedsCommit(); } + CATransform3D sublayerTransform() const { return CACFLayerGetSublayerTransform(layer()); } + + WKCACFLayer* superlayer() const; + + void setTransform(const CATransform3D& transform) { CACFLayerSetTransform(layer(), transform); setNeedsCommit(); } + CATransform3D transform() const { return CACFLayerGetTransform(layer()); } + + void setGeometryFlipped(bool flipped) { CACFLayerSetGeometryFlipped(layer(), flipped); setNeedsCommit(); } + bool geometryFlipped() const { return CACFLayerIsGeometryFlipped(layer()); } + + WKCACFLayer(CFStringRef className, GraphicsLayerCACF* owner); + +private: + void setNeedsCommit(); + CACFLayerRef layer() const { return m_layer.get(); } + size_t numSublayers() const + { + CFArrayRef sublayers = CACFLayerGetSublayers(layer()); + return sublayers ? CFArrayGetCount(sublayers) : 0; + } + + // Returns the index of the passed layer in this layer's sublayers list + // or -1 if not found + int indexOfSublayer(const WKCACFLayer*); + + // This should only be called from removeFromSuperlayer. + void removeSublayer(const WKCACFLayer*); + + RetainPtr<CACFLayerRef> m_layer; + bool m_needsDisplayOnBoundsChange; + GraphicsLayerCACF* m_owner; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // WKCACFLayer_h diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp new file mode 100644 index 0000000..9fbd0fc --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2009 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. ``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 USE(ACCELERATED_COMPOSITING) + +#include "WKCACFLayerRenderer.h" + +#include "WKCACFContextFlusher.h" +#include "WKCACFLayer.h" +#include <CoreGraphics/CGSRegion.h> +#include <QuartzCore/CACFContext.h> +#include <QuartzCore/CARenderOGL.h> +#include <wtf/HashMap.h> +#include <wtf/OwnArrayPtr.h> +#include <d3d9.h> +#include <d3dx9.h> +#include <dxerr9.h> + +#pragma comment(lib, "d3d9")
+#pragma comment(lib, "d3dx9")
+#pragma comment(lib, "QuartzCore")
+ +static IDirect3D9* s_d3d = 0; +static IDirect3D9* d3d() +{ + if (s_d3d) + return s_d3d; + + if (!LoadLibrary(TEXT("d3d9.dll"))) + return 0; + + s_d3d = Direct3DCreate9(D3D_SDK_VERSION); + + return s_d3d; +} + +inline static CGRect winRectToCGRect(RECT rc) +{ + return CGRectMake(rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top)); +} + +inline static CGRect winRectToCGRect(RECT rc, RECT relativeToRect) +{ + return CGRectMake(rc.left, (relativeToRect.bottom-rc.bottom), (rc.right - rc.left), (rc.bottom - rc.top)); +} + +namespace WebCore { + +typedef HashMap<CACFContextRef, WKCACFLayerRenderer*> ContextToWindowMap; + +static ContextToWindowMap& windowsForContexts() +{ + DEFINE_STATIC_LOCAL(ContextToWindowMap, map, ()); + return map; +} + +static D3DPRESENT_PARAMETERS initialPresentationParameters() +{ + D3DPRESENT_PARAMETERS parameters = {0}; + parameters.Windowed = TRUE; + parameters.SwapEffect = D3DSWAPEFFECT_COPY; + parameters.BackBufferCount = 1; + parameters.BackBufferFormat = D3DFMT_A8R8G8B8; + parameters.MultiSampleType = D3DMULTISAMPLE_NONE; + + return parameters; +} + +bool WKCACFLayerRenderer::acceleratedCompositingAvailable()
+{
+ static bool available;
+ static bool tested;
+
+ if (tested)
+ return available;
+
+ tested = true;
+ HMODULE library = LoadLibrary(TEXT("d3d9.dll"));
+ if (!library)
+ return false;
+
+ FreeLibrary(library);
+ library = LoadLibrary(TEXT("QuartzCore.dll"));
+ if (!library)
+ return false;
+
+ FreeLibrary(library);
+ available = true;
+ return available;
+}
+
+void WKCACFLayerRenderer::didFlushContext(CACFContextRef context) +{ + WKCACFLayerRenderer* window = windowsForContexts().get(context); + if (!window) + return; + + window->renderSoon(); +} + +PassOwnPtr<WKCACFLayerRenderer> WKCACFLayerRenderer::create() +{ + if (!acceleratedCompositingAvailable()) + return 0; + return new WKCACFLayerRenderer; +} + +WKCACFLayerRenderer::WKCACFLayerRenderer() + : m_triedToCreateD3DRenderer(false) + , m_renderContext(0) + , m_renderer(0) + , m_hostWindow(0) + , m_renderTimer(this, &WKCACFLayerRenderer::renderTimerFired) + , m_scrollFrameWidth(1) // Default to 1 to avoid 0 size frames + , m_scrollFrameHeight(1) // Default to 1 to avoid 0 size frames +{ +} + +WKCACFLayerRenderer::~WKCACFLayerRenderer() +{ + destroyRenderer(); +} + +void WKCACFLayerRenderer::setScrollFrame(int width, int height, int scrollX, int scrollY) +{ + m_scrollFrameWidth = width; + m_scrollFrameHeight = height; + + CGRect contentsRect = CGRectMake(scrollX, scrollY, width, height); + m_scrollLayer->setFrame(contentsRect); + + if (m_rootChildLayer) { + contentsRect.origin.x = 0; + contentsRect.origin.y = 0; + m_rootChildLayer->setFrame(contentsRect); + } +} + +void WKCACFLayerRenderer::setRootContents(CGImageRef image) +{ + ASSERT(m_rootLayer); + m_rootLayer->setContents(image); + renderSoon(); +} + +void WKCACFLayerRenderer::setRootChildLayer(WebCore::PlatformLayer* layer) +{ + if (!m_scrollLayer) + return; + + m_scrollLayer->removeAllSublayers(); + if (layer) { + m_scrollLayer->addSublayer(layer); + + // Set the frame + layer->setFrame(CGRectMake(0, 0, m_scrollFrameWidth, m_scrollFrameHeight)); + } + + m_rootChildLayer = layer; + +} + +void WKCACFLayerRenderer::setNeedsDisplay() +{ + ASSERT(m_rootLayer); + m_rootLayer->setNeedsDisplay(); + renderSoon(); +} + +void WKCACFLayerRenderer::createRenderer() +{ + if (m_triedToCreateD3DRenderer) + return; + + m_triedToCreateD3DRenderer = true; + D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); + + if (!d3d() || !::IsWindow(m_hostWindow)) + return; + + // D3D doesn't like to make back buffers for 0 size windows. We skirt this problem if we make the + // passed backbuffer width and height non-zero. The window will necessarily get set to a non-zero + // size eventually, and then the backbuffer size will get reset. + RECT rect; + GetClientRect(m_hostWindow, &rect); + + if (rect.left-rect.right == 0 || rect.bottom-rect.top == 0) { + parameters.BackBufferWidth = 1; + parameters.BackBufferHeight = 1; + } + + if (FAILED(d3d()->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hostWindow, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, ¶meters, &m_d3dDevice))) + return; + + D3DXMATRIXA16 projection; + D3DXMatrixOrthoOffCenterRH(&projection, rect.left, rect.right, rect.top, rect.bottom, -1.0f, 1.0f); + + m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection); + + m_context.adoptCF(CACFContextCreate(0)); + windowsForContexts().set(m_context.get(), this); + + m_renderContext = static_cast<CARenderContext*>(CACFContextGetRenderContext(m_context.get())); + m_renderer = CARenderOGLNew(&kCARenderDX9Callbacks, m_d3dDevice.get(), 0); + + // Create the root hierarchy + m_rootLayer = WKCACFLayer::create(kCACFLayer); + m_scrollLayer = WKCACFLayer::create(kCACFLayer); + + m_rootLayer->addSublayer(m_scrollLayer); + m_scrollLayer->setMasksToBounds(true); + +#ifndef NDEBUG + CGColorRef debugColor = createCGColor(Color(255, 0, 0, 204)); + m_rootLayer->setBackgroundColor(debugColor); + CGColorRelease(debugColor); +#endif + + if (IsWindow(m_hostWindow)) { + m_rootLayer->setFrame(bounds()); + + // For now this will include the scroll bars. Later in the setScrollFrame + // we will fix it + m_scrollLayer->setFrame(bounds()); + } + + if (m_context) + m_rootLayer->becomeRootLayerForContext(m_context.get()); +} + +void WKCACFLayerRenderer::destroyRenderer() +{ + if (m_context) { + windowsForContexts().remove(m_context.get()); + WKCACFContextFlusher::shared().removeContext(m_context.get()); + } + + if (m_renderer) + CARenderOGLDestroy(m_renderer); + m_renderer = 0; + m_d3dDevice = 0; + if (s_d3d) + s_d3d->Release(); + + s_d3d = 0; + m_rootLayer = 0; + m_scrollLayer = 0; + m_rootChildLayer = 0; + + m_triedToCreateD3DRenderer = false; +} + +void WKCACFLayerRenderer::resize() +{ + if (!m_d3dDevice) + return; + + resetDevice(); + + if (m_rootLayer) { + m_rootLayer->setFrame(bounds()); + WKCACFContextFlusher::shared().flushAllContexts(); + } +} + +static void getDirtyRects(HWND window, Vector<CGRect>& outRects) +{ + ASSERT_ARG(outRects, outRects.isEmpty()); + + RECT clientRect; + if (!GetClientRect(window, &clientRect)) + return; + + HRGN region = CreateRectRgn(0, 0, 0, 0); + int regionType = GetUpdateRgn(window, region, false); + if (regionType != COMPLEXREGION) { + RECT dirtyRect; + if (GetUpdateRect(window, &dirtyRect, false)) + outRects.append(winRectToCGRect(dirtyRect, clientRect)); + return; + } + + DWORD dataSize = GetRegionData(region, 0, 0); + OwnArrayPtr<unsigned char> regionDataBuffer(new unsigned char[dataSize]); + RGNDATA* regionData = reinterpret_cast<RGNDATA*>(regionDataBuffer.get()); + if (!GetRegionData(region, dataSize, regionData)) + return; + + outRects.resize(regionData->rdh.nCount); + + RECT* rect = reinterpret_cast<RECT*>(regionData->Buffer); + for (size_t i = 0; i < outRects.size(); ++i, ++rect) + outRects[i] = winRectToCGRect(*rect, clientRect); + + DeleteObject(region); +} + +void WKCACFLayerRenderer::renderTimerFired(Timer<WKCACFLayerRenderer>*) +{ + paint(); +} + +void WKCACFLayerRenderer::paint() +{ + if (!m_d3dDevice) + return; + + Vector<CGRect> dirtyRects; + getDirtyRects(m_hostWindow, dirtyRects); + render(dirtyRects); +} + +void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects) +{ + ASSERT(m_d3dDevice); + + // Flush the root layer to the render tree. + WKCACFContextFlusher::shared().flushAllContexts(); + + CGRect bounds = this->bounds(); + + CFTimeInterval t = CACurrentMediaTime(); + + // Give the renderer some space to use. This needs to be valid until the + // CARenderUpdateFinish() call below. + char space[4096]; + CARenderUpdate* u = CARenderUpdateBegin(space, sizeof(space), t, 0, 0, &bounds); + if (!u) + return; + + CARenderContextLock(m_renderContext); + CARenderUpdateAddContext(u, m_renderContext); + CARenderContextUnlock(m_renderContext); + + for (size_t i = 0; i < dirtyRects.size(); ++i) + CARenderUpdateAddRect(u, &dirtyRects[i]); + + HRESULT err = S_OK; + do { + CGSRegionObj rgn = CARenderUpdateCopyRegion(u); + + if (!rgn) + break; + + // FIXME: don't need to clear dirty region if layer tree is opaque. + + Vector<D3DRECT, 64> rects; + CGSRegionEnumeratorObj e = CGSRegionEnumerator(rgn); + for (const CGRect* r = CGSNextRect(e); r; r = CGSNextRect(e)) { + D3DRECT rect; + rect.x1 = r->origin.x; + rect.x2 = rect.x1 + r->size.width; + rect.y1 = bounds.origin.y + bounds.size.height - (r->origin.y + r->size.height); + rect.y2 = rect.y1 + r->size.height; + + rects.append(rect); + } + CGSReleaseRegionEnumerator(e); + CGSReleaseRegion(rgn); + + if (rects.isEmpty()) + break; + + m_d3dDevice->Clear(rects.size(), rects.data(), D3DCLEAR_TARGET, 0, 1.0f, 0); + + m_d3dDevice->BeginScene(); + CARenderOGLRender(m_renderer, u); + m_d3dDevice->EndScene(); + + err = m_d3dDevice->Present(0, 0, 0, 0); + + if (err == D3DERR_DEVICELOST) { + // Lost device situation. + CARenderOGLPurge(m_renderer); + resetDevice(); + CARenderUpdateAddRect(u, &bounds); + } + } while (err == D3DERR_DEVICELOST); + + CARenderUpdateFinish(u); +} + +void WKCACFLayerRenderer::renderSoon() +{ + if (!m_renderTimer.isActive()) + m_renderTimer.startOneShot(0); +} + +CGRect WKCACFLayerRenderer::bounds() const +{ + RECT clientRect; + GetClientRect(m_hostWindow, &clientRect); + + return winRectToCGRect(clientRect); +} + +void WKCACFLayerRenderer::initD3DGeometry() +{ + ASSERT(m_d3dDevice); + + CGRect bounds = this->bounds(); + + float x0 = bounds.origin.x; + float y0 = bounds.origin.y; + float x1 = x0 + bounds.size.width; + float y1 = y0 + bounds.size.height; + + D3DXMATRIXA16 projection; + D3DXMatrixOrthoOffCenterRH(&projection, x0, x1, y0, y1, -1.0f, 1.0f); + + m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection); +} + +void WKCACFLayerRenderer::resetDevice() +{ + ASSERT(m_d3dDevice); + + D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); + m_d3dDevice->Reset(¶meters); + initD3DGeometry(); +} + +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h new file mode 100644 index 0000000..12cde48 --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2009 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. ``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. + */ + +#ifndef WKCACFLayerRenderer_h +#define WKCACFLayerRenderer_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "COMPtr.h" +#include "Timer.h" +#include "WKCACFLayer.h" + +#include <wtf/Noncopyable.h> + +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/RetainPtr.h> + +#include <CoreGraphics/CGGeometry.h> + +interface IDirect3DDevice9; +typedef struct _CACFContext* CACFContextRef; +typedef struct _CARenderContext CARenderContext; +typedef struct _CARenderOGLContext CARenderOGLContext; + +namespace WebCore { + +// FIXME: Currently there is a WKCACFLayerRenderer for each WebView and each +// has its own CARenderOGLContext and Direct3DDevice9, which is inefficient. +// (https://bugs.webkit.org/show_bug.cgi?id=31855) +class WKCACFLayerRenderer : public Noncopyable { +public: + static PassOwnPtr<WKCACFLayerRenderer> create(); + ~WKCACFLayerRenderer(); + + static bool acceleratedCompositingAvailable(); + static void didFlushContext(CACFContextRef); + + void setScrollFrame(int width, int height, int scrollX, int scrollY); + void setRootContents(CGImageRef); + void setRootChildLayer(WebCore::PlatformLayer* layer); + void setNeedsDisplay(); + void setHostWindow(HWND window) { m_hostWindow = window; createRenderer(); } + + void createRenderer(); + void destroyRenderer(); + void resize(); + void renderSoon(); + +protected: + WKCACFLayer* rootLayer() const { return m_rootLayer.get(); } + +private: + WKCACFLayerRenderer(); + + void renderTimerFired(Timer<WKCACFLayerRenderer>*); + + CGRect bounds() const; + + void initD3DGeometry(); + void resetDevice(); + + void render(const Vector<CGRect>& dirtyRects = Vector<CGRect>()); + void paint(); + + bool m_triedToCreateD3DRenderer; + COMPtr<IDirect3DDevice9> m_d3dDevice; + RefPtr<WKCACFLayer> m_rootLayer; + RefPtr<WKCACFLayer> m_viewLayer; + RefPtr<WKCACFLayer> m_scrollLayer; + RefPtr<WKCACFLayer> m_rootChildLayer; + RetainPtr<CACFContextRef> m_context; + CARenderContext* m_renderContext; + CARenderOGLContext* m_renderer; + HWND m_hostWindow; + Timer<WKCACFLayerRenderer> m_renderTimer; + int m_scrollFrameWidth, m_scrollFrameHeight; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // WKCACFLayerRenderer_h diff --git a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp index f308840..f22e6c9 100644 --- a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp +++ b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp @@ -947,7 +947,7 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points } } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled() || !m_data->m_opacity) return; @@ -1051,12 +1051,12 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int wi notImplemented(); } -void GraphicsContext::setPlatformFillColor(const Color& col) +void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace) { notImplemented(); } -void GraphicsContext::setPlatformStrokeColor(const Color& col) +void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace) { notImplemented(); } @@ -1088,7 +1088,7 @@ void GraphicsContext::clearRect(const FloatRect& rect) return; } - fillRect(rect, Color(Color::white)); + fillRect(rect, Color(Color::white), DeviceColorSpace); } void GraphicsContext::strokeRect(const FloatRect& rect, float width) @@ -1238,7 +1238,7 @@ static inline IntPoint rectCenterPoint(const RECT& rect) { return IntPoint(rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2); } -void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& c) +void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& c, ColorSpace colorSpace) { ScopeDCProvider dcProvider(m_data); if (!m_data->m_dc) @@ -1355,7 +1355,7 @@ Color gradientAverageColor(const Gradient* gradient) void GraphicsContext::fillPath() { - Color c = m_common->state.fillColorSpace == GradientColorSpace && m_common->state.fillGradient + Color c = m_common->state.fillGradient ? gradientAverageColor(m_common->state.fillGradient.get()) : fillColor(); @@ -1449,7 +1449,7 @@ void GraphicsContext::fillRect(const FloatRect& r, const Gradient* gradient) if (numStops == 1) { const Gradient::ColorStop& stop = stops.first(); Color color(stop.red, stop.green, stop.blue, stop.alpha); - fillRect(r, color); + fillRect(r, color, DeviceColorSpace); return; } @@ -1539,13 +1539,13 @@ void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) void GraphicsContext::fillRect(const FloatRect& rect) { - if (m_common->state.fillColorSpace == GradientColorSpace && m_common->state.fillGradient) + if (m_common->state.fillGradient) fillRect(rect, m_common->state.fillGradient.get()); else - fillRect(rect, fillColor()); + fillRect(rect, fillColor(), DeviceColorSpace); } -void GraphicsContext::setPlatformShadow(const IntSize&, int, const Color&) +void GraphicsContext::setPlatformShadow(const IntSize&, int, const Color&, ColorSpace) { notImplemented(); } diff --git a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp index de92fcd..fd3322f 100644 --- a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp +++ b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp @@ -111,7 +111,7 @@ unsigned FontPlatformData::computeHash() const { // a font whose properties are equal should generate the same hash uintptr_t hashCodes[6] = { thisFont->GetPointSize(), thisFont->GetFamily(), thisFont->GetStyle(), thisFont->GetWeight(), thisFont->GetUnderlined(), - StringImpl::computeHash(thisFont->GetFaceName().mb_str(wxConvUTF8)) }; + StringImpl::computeHash(thisFont->GetFaceName().utf8_str()) }; return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); } diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp index 39f14f4..9c05ce5 100644 --- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp +++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp @@ -119,8 +119,8 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) setPaintingDisabled(!context); if (context) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), DeviceColorSpace); + setPlatformStrokeColor(strokeColor(), DeviceColorSpace); } #if USE(WXGC) m_data->context = (wxGCDC*)context; @@ -252,7 +252,7 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points delete [] polygon; } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -262,7 +262,7 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height()); } -void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -438,7 +438,7 @@ void GraphicsContext::addPath(const Path& path) notImplemented(); } -void GraphicsContext::setPlatformStrokeColor(const Color& color) +void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -457,7 +457,7 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness) } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -511,7 +511,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) return; } -void GraphicsContext::setPlatformShadow(IntSize const&,int,Color const&) +void GraphicsContext::setPlatformShadow(IntSize const&,int,Color const&, ColorSpace) { notImplemented(); } @@ -566,4 +566,72 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness notImplemented(); } +#if PLATFORM(WIN_OS) +HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) +{ + if (dstRect.isEmpty()) + return 0; + + // Create a bitmap DC in which to draw. + BITMAPINFO bitmapInfo; + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = dstRect.width(); + bitmapInfo.bmiHeader.biHeight = dstRect.height(); + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = 0; + bitmapInfo.bmiHeader.biXPelsPerMeter = 0; + bitmapInfo.bmiHeader.biYPelsPerMeter = 0; + bitmapInfo.bmiHeader.biClrUsed = 0; + bitmapInfo.bmiHeader.biClrImportant = 0; + + void* pixels = 0; + HBITMAP bitmap = ::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0); + if (!bitmap) + return 0; + + HDC displayDC = ::GetDC(0); + HDC bitmapDC = ::CreateCompatibleDC(displayDC); + ::ReleaseDC(0, displayDC); + + ::SelectObject(bitmapDC, bitmap); + + // Fill our buffer with clear if we're going to alpha blend. + if (supportAlphaBlend) { + BITMAP bmpInfo; + GetObject(bitmap, sizeof(bmpInfo), &bmpInfo); + int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; + memset(bmpInfo.bmBits, 0, bufferSize); + } + return bitmapDC; +} + +void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) +{ + if (hdc) { + + if (!dstRect.isEmpty()) { + + HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + BITMAP info; + GetObject(bitmap, sizeof(info), &info); + ASSERT(info.bmBitsPixel == 32); + + wxBitmap bmp; + bmp.SetHBITMAP(bitmap); +#if !wxCHECK_VERSION(2,9,0) + if (supportAlphaBlend) + bmp.UseAlpha(); +#endif + m_data->context->DrawBitmap(bmp, dstRect.x(), dstRect.y(), supportAlphaBlend); + + ::DeleteObject(bitmap); + } + + ::DeleteDC(hdc); + } +} +#endif + } diff --git a/WebCore/platform/graphics/wx/IconWx.cpp b/WebCore/platform/graphics/wx/IconWx.cpp index e82091e..d3cc961 100644 --- a/WebCore/platform/graphics/wx/IconWx.cpp +++ b/WebCore/platform/graphics/wx/IconWx.cpp @@ -32,12 +32,6 @@ Icon::~Icon() { } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) -{ - notImplemented(); - return 0; -} - PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { notImplemented(); diff --git a/WebCore/platform/graphics/wx/ImageWx.cpp b/WebCore/platform/graphics/wx/ImageWx.cpp index bd129cf..ff60d6f 100644 --- a/WebCore/platform/graphics/wx/ImageWx.cpp +++ b/WebCore/platform/graphics/wx/ImageWx.cpp @@ -86,13 +86,13 @@ void BitmapImage::initPlatformData() // Drawing Routines -void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, CompositeOperator op) +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { if (!m_source.initialized()) return; if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, dst, solidColor(), op); + fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op); return; } @@ -176,7 +176,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR observer->didDraw(this); } -void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& dstRect) +void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, ColorSpace, CompositeOperator, const FloatRect& dstRect) { if (!m_source.initialized()) return; @@ -261,7 +261,7 @@ void BitmapImage::invalidatePlatformData() } -void Image::drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& destRect) +void Image::drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, ColorSpace, CompositeOperator, const FloatRect& destRect) { notImplemented(); } diff --git a/WebCore/platform/gtk/GeolocationServiceGtk.cpp b/WebCore/platform/gtk/GeolocationServiceGtk.cpp index cf35346..edb8d10 100644 --- a/WebCore/platform/gtk/GeolocationServiceGtk.cpp +++ b/WebCore/platform/gtk/GeolocationServiceGtk.cpp @@ -86,7 +86,7 @@ bool GeolocationServiceGtk::startUpdating(PositionOptions* options) g_object_unref(master); if (!client) { - setError(PositionError::UNKNOWN_ERROR, "Could not connect to location provider."); + setError(PositionError::POSITION_UNAVAILABLE, "Could not connect to location provider."); return false; } @@ -101,14 +101,14 @@ bool GeolocationServiceGtk::startUpdating(PositionOptions* options) true, GEOCLUE_RESOURCE_ALL, &error.outPtr()); if (!result) { - setError(PositionError::UNKNOWN_ERROR, error->message); + setError(PositionError::POSITION_UNAVAILABLE, error->message); g_object_unref(client); return false; } m_geocluePosition = geoclue_master_client_create_position(client, &error.outPtr()); if (!m_geocluePosition) { - setError(PositionError::UNKNOWN_ERROR, error->message); + setError(PositionError::POSITION_UNAVAILABLE, error->message); g_object_unref(client); return false; } diff --git a/WebCore/platform/gtk/KeyEventGtk.cpp b/WebCore/platform/gtk/KeyEventGtk.cpp index 3931eff..11ea956 100644 --- a/WebCore/platform/gtk/KeyEventGtk.cpp +++ b/WebCore/platform/gtk/KeyEventGtk.cpp @@ -507,6 +507,8 @@ static String singleCharacterString(guint val) return String("\r"); case GDK_BackSpace: return String("\x8"); + case GDK_Tab: + return String("\t"); default: gunichar c = gdk_keyval_to_unicode(val); glong nwc; diff --git a/WebCore/platform/gtk/Language.cpp b/WebCore/platform/gtk/Language.cpp index fea2df6..577d7d8 100644 --- a/WebCore/platform/gtk/Language.cpp +++ b/WebCore/platform/gtk/Language.cpp @@ -43,12 +43,12 @@ String defaultLanguage() GOwnPtr<gchar> normalizedDefault(g_ascii_strdown(localeDefault, -1)); char* ptr = strchr(normalizedDefault.get(), '_'); - if(ptr) + if (ptr) *ptr = '-'; ptr = strchr(normalizedDefault.get(), '.'); - if(ptr) + if (ptr) *ptr = '\0'; return String(normalizedDefault.get()); diff --git a/WebCore/platform/gtk/LocalizedStringsGtk.cpp b/WebCore/platform/gtk/LocalizedStringsGtk.cpp index 85e071b..5809e47 100644 --- a/WebCore/platform/gtk/LocalizedStringsGtk.cpp +++ b/WebCore/platform/gtk/LocalizedStringsGtk.cpp @@ -392,6 +392,10 @@ String localizedMediaControlElementString(const String& name) return String::fromUTF8(_("fast forward")); if (name == "SeekBackButton") return String::fromUTF8(_("fast reverse")); + if (name == "ShowClosedCaptionsButton") + return String::fromUTF8(_("show closed captions")); + if (name == "HideClosedCaptionsButton") + return String::fromUTF8(_("hide closed captions")); ASSERT_NOT_REACHED(); return String(); @@ -431,6 +435,10 @@ String localizedMediaControlElementHelpText(const String& name) return String::fromUTF8(_("seek quickly forward")); if (name == "FullscreenButton") return String::fromUTF8(_("Play movie in fullscreen mode")); + if (name == "ShowClosedCaptionsButton") + return String::fromUTF8(_("start displaying closed captions")); + if (name == "HideClosedCaptionsButton") + return String::fromUTF8(_("stop displaying closed captions")); ASSERT_NOT_REACHED(); return String(); @@ -467,4 +475,40 @@ String localizedMediaTimeDescription(float time) } #endif // ENABLE(VIDEO) +String validationMessageValueMissingText() +{ + return String::fromUTF8(_("value missing")); +} + +String validationMessageTypeMismatchText() +{ + notImplemented(); + return String::fromUTF8(_("type mismatch")); +} + +String validationMessagePatternMismatchText() +{ + return String::fromUTF8(_("pattern mismatch")); +} + +String validationMessageTooLongText() +{ + return String::fromUTF8(_("too long")); +} + +String validationMessageRangeUnderflowText() +{ + return String::fromUTF8(_("range underflow")); +} + +String validationMessageRangeOverflowText() +{ + return String::fromUTF8(_("range overflow")); +} + +String validationMessageStepMismatchText() +{ + return String::fromUTF8(_("step mismatch")); +} + } diff --git a/WebCore/platform/gtk/PasteboardGtk.cpp b/WebCore/platform/gtk/PasteboardGtk.cpp index 0ff26f7..ee95a38 100644 --- a/WebCore/platform/gtk/PasteboardGtk.cpp +++ b/WebCore/platform/gtk/PasteboardGtk.cpp @@ -102,7 +102,7 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, PasteboardSelectionData* data = new PasteboardSelectionData(text, markup); gint n_targets; - GtkTargetEntry* targets = gtk_target_table_new_from_list(m_helper->getCopyTargetList(frame), &n_targets); + GtkTargetEntry* targets = gtk_target_table_new_from_list(m_helper->targetList(), &n_targets); gtk_clipboard_set_with_data(clipboard, targets, n_targets, clipboard_get_contents_cb, clipboard_clear_contents_cb, data); gtk_target_table_free(targets, n_targets); diff --git a/WebCore/platform/gtk/PasteboardHelper.h b/WebCore/platform/gtk/PasteboardHelper.h index 8e67127..e589f24 100644 --- a/WebCore/platform/gtk/PasteboardHelper.h +++ b/WebCore/platform/gtk/PasteboardHelper.h @@ -41,8 +41,7 @@ public: virtual GtkClipboard* getCurrentTarget(Frame*) const = 0; virtual GtkClipboard* getClipboard(Frame*) const = 0; virtual GtkClipboard* getPrimary(Frame*) const = 0; - virtual GtkTargetList* getCopyTargetList(Frame*) const = 0; - virtual GtkTargetList* getPasteTargetList(Frame*) const = 0; + virtual GtkTargetList* targetList() const = 0; virtual gint getWebViewTargetInfoHtml() const = 0; }; diff --git a/WebCore/platform/gtk/RenderThemeGtk.cpp b/WebCore/platform/gtk/RenderThemeGtk.cpp index fdef9c2..4842d68 100644 --- a/WebCore/platform/gtk/RenderThemeGtk.cpp +++ b/WebCore/platform/gtk/RenderThemeGtk.cpp @@ -188,7 +188,6 @@ static bool paintMozWidget(RenderTheme* theme, GtkThemeWidgetType type, RenderOb GdkRectangle gdkRect = IntRect(pos.x(), pos.y(), rect.width(), rect.height()); GtkTextDirection direction = gtkTextDirection(o->style()->direction()); -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,4,0) // Find the clip rectangle cairo_t *cr = i.context->platformContext(); double clipX1, clipX2, clipY1, clipY2; @@ -202,9 +201,6 @@ static bool paintMozWidget(RenderTheme* theme, GtkThemeWidgetType type, RenderOb gdkClipRect.y = clipPos.y(); gdk_rectangle_intersect(&gdkRect, &gdkClipRect, &gdkClipRect); -#else - GdkRectangle gdkClipRect = gdkRect; -#endif return moz_gtk_widget_paint(type, i.context->gdkDrawable(), &gdkRect, &gdkClipRect, &mozState, flags, direction) != MOZ_GTK_SUCCESS; } diff --git a/WebCore/platform/haiku/FileChooserHaiku.cpp b/WebCore/platform/haiku/FileChooserHaiku.cpp index b0e42b6..f56e02b 100644 --- a/WebCore/platform/haiku/FileChooserHaiku.cpp +++ b/WebCore/platform/haiku/FileChooserHaiku.cpp @@ -28,14 +28,6 @@ namespace WebCore { -FileChooser::FileChooser(FileChooserClient* client, const String& filename) - : m_client(client) - , m_filenames() - , m_icon(chooseIcon(filename)) -{ - m_filenames.append(filename); -} - String FileChooser::basenameForWidth(const Font&, int width) const { notImplemented(); diff --git a/WebCore/platform/haiku/LocalizedStringsHaiku.cpp b/WebCore/platform/haiku/LocalizedStringsHaiku.cpp index a37ffcc..9bb4c3e 100644 --- a/WebCore/platform/haiku/LocalizedStringsHaiku.cpp +++ b/WebCore/platform/haiku/LocalizedStringsHaiku.cpp @@ -342,5 +342,47 @@ String AXDefinitionListDefinitionText() return String(); } +String validationMessageValueMissingText() +{ + notImplemented(); + return String(); +} + +String validationMessageTypeMismatchText() +{ + notImplemented(); + return String(); +} + +String validationMessagePatternMismatchText() +{ + notImplemented(); + return String(); +} + +String validationMessageTooLongText() +{ + notImplemented(); + return String(); +} + +String validationMessageRangeUnderflowText() +{ + notImplemented(); + return String(); +} + +String validationMessageRangeOverflowText() +{ + notImplemented(); + return String(); +} + +String validationMessageStepMismatchText() +{ + notImplemented(); + return String(); +} + } // namespace WebCore diff --git a/WebCore/platform/image-decoders/ImageDecoder.h b/WebCore/platform/image-decoders/ImageDecoder.h index 8c9b7f1..08f4aa2 100644 --- a/WebCore/platform/image-decoders/ImageDecoder.h +++ b/WebCore/platform/image-decoders/ImageDecoder.h @@ -197,7 +197,7 @@ namespace WebCore { // The ImageDecoder class represents a base class for specific image format decoders // (e.g., GIF, JPG, PNG, ICO) to derive from. All decoders decode into RGBA32 format // and the base class manages the RGBA32 frame cache. - class ImageDecoder { + class ImageDecoder : public Noncopyable { public: // ENABLE(IMAGE_DECODER_DOWN_SAMPLING) allows image decoders to write directly to // scaled output buffers by down sampling. Call setMaxNumPixels() to specify the diff --git a/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp b/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp index da6ab38..5e9b527 100644 --- a/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp +++ b/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp @@ -34,9 +34,9 @@ namespace WebCore { RGBA32Buffer::RGBA32Buffer() - : m_status(FrameEmpty) - , m_hasAlpha(false) + : m_hasAlpha(false) , m_size() + , m_status(FrameEmpty) , m_duration(0) , m_disposalMethod(DisposeNotSpecified) { diff --git a/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp b/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp index 3cadf1c..e6e45b7 100644 --- a/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp +++ b/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp @@ -40,35 +40,41 @@ namespace WebCore { NativeImagePtr RGBA32Buffer::asNewNativeImage() const { wxBitmap* bmp = new wxBitmap(width(), height(), 32); - typedef wxPixelData<wxBitmap, wxAlphaPixelFormat> WxPixelData; - WxPixelData data(*bmp); - - // NB: It appears that the data is in BGRA format instead of RGBA format. - // This code works properly on both ppc and intel, meaning the issue is - // likely not an issue of byte order getting mixed up on different archs. - const unsigned char* bytes = (const unsigned char*)m_bytes.data(); - int rowCounter = 0; - long pixelCounter = 0; - WxPixelData::Iterator p(data); - WxPixelData::Iterator rowStart = p; - for (size_t i = 0; i < m_bytes.size() * sizeof(PixelData); i += sizeof(PixelData)) { - p.Red() = bytes[i+2]; - p.Green() = bytes[i+1]; - p.Blue() = bytes[i+0]; - p.Alpha() = bytes[i+3]; + + { + typedef wxPixelData<wxBitmap, wxAlphaPixelFormat> WxPixelData; + WxPixelData data(*bmp); - p++; + // NB: It appears that the data is in BGRA format instead of RGBA format. + // This code works properly on both ppc and intel, meaning the issue is + // likely not an issue of byte order getting mixed up on different archs. + const unsigned char* bytes = (const unsigned char*)m_bytes.data(); + int rowCounter = 0; + long pixelCounter = 0; + WxPixelData::Iterator p(data); + WxPixelData::Iterator rowStart = p; + for (size_t i = 0; i < m_bytes.size() * sizeof(PixelData); i += sizeof(PixelData)) { + p.Red() = bytes[i + 2]; + p.Green() = bytes[i + 1]; + p.Blue() = bytes[i + 0]; + p.Alpha() = bytes[i + 3]; + + p++; - pixelCounter++; - if ((pixelCounter % width()) == 0) { - rowCounter++; - p = rowStart; - p.MoveTo(data, 0, rowCounter); + pixelCounter++; + if ((pixelCounter % width()) == 0) { + rowCounter++; + p = rowStart; + p.MoveTo(data, 0, rowCounter); + } } - } #if !wxCHECK_VERSION(2,9,0) - bmp->UseAlpha(); + bmp->UseAlpha(); #endif + } // ensure that WxPixelData is destroyed as it unlocks the bitmap data in + // its dtor and we can't access it (notably in CreateBitmap() below) + // before this is done + ASSERT(bmp->IsOk()); #if USE(WXGC) diff --git a/WebCore/platform/mac/LocalizedStringsMac.mm b/WebCore/platform/mac/LocalizedStringsMac.mm index 261347f..c438d6b 100644 --- a/WebCore/platform/mac/LocalizedStringsMac.mm +++ b/WebCore/platform/mac/LocalizedStringsMac.mm @@ -747,5 +747,60 @@ String localizedMediaTimeDescription(float time) return String(); } +String validationMessageValueMissingText() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] validationMessageValueMissingText]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String validationMessageTypeMismatchText() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] validationMessageTypeMismatchText]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String validationMessagePatternMismatchText() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] validationMessagePatternMismatchText]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String validationMessageTooLongText() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] validationMessageTooLongText]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String validationMessageRangeUnderflowText() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] validationMessageRangeUnderflowText]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String validationMessageRangeOverflowText() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] validationMessageRangeOverflowText]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String validationMessageStepMismatchText() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] validationMessageStepMismatchText]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} } diff --git a/WebCore/platform/mac/ScrollViewMac.mm b/WebCore/platform/mac/ScrollViewMac.mm index 202d49e..f31b301 100644 --- a/WebCore/platform/mac/ScrollViewMac.mm +++ b/WebCore/platform/mac/ScrollViewMac.mm @@ -57,6 +57,8 @@ NSView *ScrollView::documentView() const return nil; } +#if !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) + void ScrollView::platformAddChild(Widget* child) { BEGIN_BLOCK_OBJC_EXCEPTIONS; @@ -203,4 +205,6 @@ bool ScrollView::platformIsOffscreen() const return ![platformWidget() window] || ![[platformWidget() window] isVisible]; } -} +#endif // !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) + +} // namespace WebCore diff --git a/WebCore/platform/mac/ScrollbarThemeMac.mm b/WebCore/platform/mac/ScrollbarThemeMac.mm index 0a20e2f..b4b8f62 100644 --- a/WebCore/platform/mac/ScrollbarThemeMac.mm +++ b/WebCore/platform/mac/ScrollbarThemeMac.mm @@ -396,7 +396,7 @@ bool ScrollbarThemeMac::paint(Scrollbar* scrollbar, GraphicsContext* context, co return true; HIThemeDrawTrack(&trackInfo, 0, imageBuffer->context()->platformContext(), kHIThemeOrientationNormal); - context->drawImage(imageBuffer->image(), scrollbar->frameRect().location()); + context->drawImage(imageBuffer->image(), DeviceColorSpace, scrollbar->frameRect().location()); } return true; diff --git a/WebCore/platform/mac/ThemeMac.mm b/WebCore/platform/mac/ThemeMac.mm index fd2f944..a95fee4 100644 --- a/WebCore/platform/mac/ThemeMac.mm +++ b/WebCore/platform/mac/ThemeMac.mm @@ -173,9 +173,9 @@ static LengthSize checkboxSize(const Font& font, const LengthSize& zoomedSize, f return sizeFromFont(font, zoomedSize, zoomFactor, checkboxSizes()); } -static NSButtonCell* checkbox(ControlStates states, const IntRect& zoomedRect, float zoomFactor) +static NSButtonCell *checkbox(ControlStates states, const IntRect& zoomedRect, float zoomFactor) { - static NSButtonCell* checkboxCell; + static NSButtonCell *checkboxCell; if (!checkboxCell) { checkboxCell = [[NSButtonCell alloc] init]; [checkboxCell setButtonType:NSSwitchButton]; @@ -199,7 +199,7 @@ static void paintCheckbox(ControlStates states, GraphicsContext* context, const BEGIN_BLOCK_OBJC_EXCEPTIONS // Determine the width and height needed for the control and prepare the cell for painting. - NSButtonCell* checkboxCell = checkbox(states, zoomedRect, zoomFactor); + NSButtonCell *checkboxCell = checkbox(states, zoomedRect, zoomFactor); context->save(); @@ -254,9 +254,9 @@ static LengthSize radioSize(const Font& font, const LengthSize& zoomedSize, floa return sizeFromFont(font, zoomedSize, zoomFactor, radioSizes()); } -static NSButtonCell* radio(ControlStates states, const IntRect& zoomedRect, float zoomFactor) +static NSButtonCell *radio(ControlStates states, const IntRect& zoomedRect, float zoomFactor) { - static NSButtonCell* radioCell; + static NSButtonCell *radioCell; if (!radioCell) { radioCell = [[NSButtonCell alloc] init]; [radioCell setButtonType:NSRadioButton]; @@ -276,7 +276,7 @@ static NSButtonCell* radio(ControlStates states, const IntRect& zoomedRect, floa static void paintRadio(ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView) { // Determine the width and height needed for the control and prepare the cell for painting. - NSButtonCell* radioCell = radio(states, zoomedRect, zoomFactor); + NSButtonCell *radioCell = radio(states, zoomedRect, zoomFactor); context->save(); @@ -330,14 +330,14 @@ static const int* buttonMargins(NSControlSize controlSize) return margins[controlSize]; } -static NSButtonCell* button(ControlPart part, ControlStates states, const IntRect& zoomedRect, float zoomFactor) +static void setupButtonCell(NSButtonCell *&buttonCell, ControlPart part, ControlStates states, const IntRect& zoomedRect, float zoomFactor) { - static NSButtonCell *buttonCell; - static bool defaultButton; if (!buttonCell) { buttonCell = [[NSButtonCell alloc] init]; [buttonCell setTitle:nil]; [buttonCell setButtonType:NSMomentaryPushInButton]; + if (states & DefaultState) + [buttonCell setKeyEquivalent:@"\r"]; } // Set the control size based off the rectangle we're painting into. @@ -357,15 +357,16 @@ static NSButtonCell* button(ControlPart part, ControlStates states, const IntRec setControlSize(buttonCell, buttonSizes(), zoomedRect.size(), zoomFactor); - if (defaultButton != (states & DefaultState)) { - defaultButton = !defaultButton; - [buttonCell setKeyEquivalent:(defaultButton ? @"\r" : @"")]; - } - // Update the various states we respond to. updateStates(buttonCell, states); +} - return buttonCell; +static NSButtonCell *button(ControlPart part, ControlStates states, const IntRect& zoomedRect, float zoomFactor) +{ + bool isDefault = states & DefaultState; + static NSButtonCell *cells[2]; + setupButtonCell(cells[isDefault], part, states, zoomedRect, zoomFactor); + return cells[isDefault]; } static void paintButton(ControlPart part, ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView) @@ -408,7 +409,7 @@ static void paintButton(ControlPart part, ControlStates states, GraphicsContext* NSWindow *window = [view window]; NSButtonCell *previousDefaultButtonCell = [window defaultButtonCell]; - if ((states & DefaultState) && [window isKeyWindow]) { + if (states & DefaultState) { [window setDefaultButtonCell:buttonCell]; wkAdvanceDefaultButtonPulseAnimation(buttonCell); } else if ([previousDefaultButtonCell isEqual:buttonCell]) diff --git a/WebCore/platform/mac/WebCoreSystemInterface.h b/WebCore/platform/mac/WebCoreSystemInterface.h index 768899e..917ab0b 100644 --- a/WebCore/platform/mac/WebCoreSystemInterface.h +++ b/WebCore/platform/mac/WebCoreSystemInterface.h @@ -117,6 +117,7 @@ extern BOOL (*wkGetNSURLResponseMustRevalidate)(NSURLResponse *response); extern void (*wkGetWheelEventDeltas)(NSEvent*, float* deltaX, float* deltaY, BOOL* continuous); extern BOOL (*wkHitTestMediaUIPart)(int part, int themeStyle, CGRect bounds, CGPoint point); extern void (*wkMeasureMediaUIPart)(int part, int themeStyle, CGRect *bounds, CGSize *naturalSize); +extern BOOL (*wkMediaControllerThemeAvailable)(int themeStyle); extern void (*wkPopupMenu)(NSMenu*, NSPoint location, float width, NSView*, int selectedItem, NSFont*); extern unsigned (*wkQTIncludeOnlyModernMediaFileTypes)(void); extern int (*wkQTMovieDataRate)(QTMovie*); @@ -124,6 +125,8 @@ extern float (*wkQTMovieMaxTimeLoaded)(QTMovie*); extern NSString *(*wkQTMovieMaxTimeLoadedChangeNotification)(void); extern float (*wkQTMovieMaxTimeSeekable)(QTMovie*); extern int (*wkQTMovieGetType)(QTMovie* movie); +extern BOOL (*wkQTMovieHasClosedCaptions)(QTMovie* movie); +extern void (*wkQTMovieSetShowClosedCaptions)(QTMovie* movie, BOOL showClosedCaptions); extern void (*wkQTMovieViewSetDrawSynchronously)(QTMovieView*, BOOL); extern void (*wkSetCGFontRenderingMode)(CGContextRef, NSFont*); extern void (*wkSetDragImage)(NSImage*, NSPoint offset); @@ -136,6 +139,9 @@ extern void (*wkSignalCFReadStreamEnd)(CFReadStreamRef stream); extern void (*wkSignalCFReadStreamError)(CFReadStreamRef stream, CFStreamError *error); extern void (*wkSignalCFReadStreamHasBytes)(CFReadStreamRef stream); extern unsigned (*wkInitializeMaximumHTTPConnectionCountPerHost)(unsigned preferredConnectionCount); +extern void (*wkSetCONNECTProxyForStream)(CFReadStreamRef, CFStringRef proxyHost, CFNumberRef proxyPort); +extern void (*wkSetCONNECTProxyAuthorizationForStream)(CFReadStreamRef, CFStringRef proxyAuthorizationString); +extern CFHTTPMessageRef (*wkCopyCONNECTProxyResponse)(CFReadStreamRef, CFURLRef responseURL); extern BOOL (*wkIsLatchingWheelEvent)(NSEvent *); #ifndef BUILDING_ON_TIGER diff --git a/WebCore/platform/mac/WebCoreSystemInterface.mm b/WebCore/platform/mac/WebCoreSystemInterface.mm index d0e276f..3a9c011 100644 --- a/WebCore/platform/mac/WebCoreSystemInterface.mm +++ b/WebCore/platform/mac/WebCoreSystemInterface.mm @@ -44,6 +44,7 @@ void (*wkDrawMediaSliderTrack)(int themeStyle, CGContextRef context, CGRect rect BOOL (*wkHitTestMediaUIPart)(int part, int themeStyle, CGRect bounds, CGPoint point); void (*wkDrawMediaUIPart)(int part, int themeStyle, CGContextRef context, CGRect rect, unsigned state); void (*wkMeasureMediaUIPart)(int part, int themeStyle, CGRect *bounds, CGSize *naturalSize); +BOOL (*wkMediaControllerThemeAvailable)(int themeStyle); NSString* (*wkGetPreferredExtensionForMIMEType)(NSString*); NSArray* (*wkGetExtensionsForMIMEType)(NSString*); NSString* (*wkGetMIMETypeForExtension)(NSString*); @@ -58,6 +59,8 @@ float (*wkQTMovieMaxTimeLoaded)(QTMovie*); NSString *(*wkQTMovieMaxTimeLoadedChangeNotification)(void); float (*wkQTMovieMaxTimeSeekable)(QTMovie*); int (*wkQTMovieGetType)(QTMovie* movie); +BOOL (*wkQTMovieHasClosedCaptions)(QTMovie* movie); +void (*wkQTMovieSetShowClosedCaptions)(QTMovie* movie, BOOL showClosedCaptions); void (*wkQTMovieViewSetDrawSynchronously)(QTMovieView*, BOOL); void (*wkSetCGFontRenderingMode)(CGContextRef, NSFont*); void (*wkSetDragImage)(NSImage*, NSPoint offset); @@ -80,6 +83,9 @@ void (*wkSetNSURLConnectionDefersCallbacks)(NSURLConnection *, BOOL); void (*wkSetNSURLRequestShouldContentSniff)(NSMutableURLRequest *, BOOL); id (*wkCreateNSURLConnectionDelegateProxy)(void); unsigned (*wkInitializeMaximumHTTPConnectionCountPerHost)(unsigned preferredConnectionCount); +void (*wkSetCONNECTProxyForStream)(CFReadStreamRef, CFStringRef proxyHost, CFNumberRef proxyPort); +void (*wkSetCONNECTProxyAuthorizationForStream)(CFReadStreamRef, CFStringRef proxyAuthorizationString); +CFHTTPMessageRef (*wkCopyCONNECTProxyResponse)(CFReadStreamRef, CFURLRef responseURL); BOOL (*wkIsLatchingWheelEvent)(NSEvent *); #ifndef BUILDING_ON_TIGER diff --git a/WebCore/platform/mac/WidgetMac.mm b/WebCore/platform/mac/WidgetMac.mm index 8653a03..ebb47dc 100644 --- a/WebCore/platform/mac/WidgetMac.mm +++ b/WebCore/platform/mac/WidgetMac.mm @@ -44,6 +44,8 @@ #import "WebCoreView.h" #import <wtf/RetainPtr.h> +#if !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) + @interface NSWindow (WebWindowDetails) - (BOOL)_needsToResetDragMargins; - (void)_setNeedsToResetDragMargins:(BOOL)needs; @@ -54,8 +56,12 @@ - (void)webPlugInSetIsSelected:(BOOL)isSelected; @end +#endif + namespace WebCore { +#if !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) + class WidgetPrivate { public: bool mustStayInWindow; @@ -78,7 +84,7 @@ static void safeRemoveFromSuperview(NSView *view) [window _setNeedsToResetDragMargins:resetDragMargins]; } -Widget::Widget(NSView* view) +Widget::Widget(NSView *view) : m_data(new WidgetPrivate) { init(view); @@ -341,5 +347,54 @@ void Widget::retainPlatformWidget() HardRetain(m_widget); } +#else // ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) + +Widget::Widget(PlatformWidget widget) +{ + init(widget); +} + +Widget::~Widget() +{ + ASSERT(!parent()); +} + +void Widget::show() +{ +} + +void Widget::hide() +{ } +void Widget::setCursor(const Cursor&) +{ + notImplemented(); +} + +void Widget::paint(GraphicsContext*, const IntRect&) +{ +} + +void Widget::setFocus() +{ +} + +void Widget::setIsSelected(bool) +{ +} + +IntRect Widget::frameRect() const +{ + return m_frame; +} + +void Widget::setFrameRect(const IntRect& rect) +{ + m_frame = rect; +} + +#endif + +} // namespace WebCore + diff --git a/WebCore/platform/network/AuthenticationClient.h b/WebCore/platform/network/AuthenticationClient.h new file mode 100644 index 0000000..1e17910 --- /dev/null +++ b/WebCore/platform/network/AuthenticationClient.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2009 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. + */ + +#ifndef AuthenticationClient_h +#define AuthenticationClient_h + +namespace WebCore { + +class AuthenticationChallenge; +class Credential; + +class AuthenticationClient { +public: + virtual void receivedCredential(const AuthenticationChallenge&, const Credential&) = 0; + virtual void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&) = 0; + virtual void receivedCancellation(const AuthenticationChallenge&) = 0; + + void ref() { refAuthenticationClient(); } + void deref() { derefAuthenticationClient(); } + +protected: + virtual ~AuthenticationClient() { } + +private: + virtual void refAuthenticationClient() = 0; + virtual void derefAuthenticationClient() = 0; +}; + +} + +#endif diff --git a/WebCore/platform/network/Credential.cpp b/WebCore/platform/network/Credential.cpp index f905743..87cd7ff 100644 --- a/WebCore/platform/network/Credential.cpp +++ b/WebCore/platform/network/Credential.cpp @@ -33,6 +33,9 @@ Credential::Credential() : m_user("") , m_password("") , m_persistence(CredentialPersistenceNone) +#if CERTIFICATE_CREDENTIALS_SUPPORTED + , m_type(CredentialTypePassword) +#endif { } @@ -42,11 +45,31 @@ Credential::Credential(const String& user, const String& password, CredentialPer : m_user(user.length() ? user : "") , m_password(password.length() ? password : "") , m_persistence(persistence) +#if CERTIFICATE_CREDENTIALS_SUPPORTED + , m_type(CredentialTypePassword) +#endif +{ +} + +Credential::Credential(const Credential& original, CredentialPersistence persistence) + : m_user(original.user()) + , m_password(original.password()) + , m_persistence(persistence) +#if CERTIFICATE_CREDENTIALS_SUPPORTED + , m_identity(original.identity()) + , m_certificates(original.certificates()) + , m_type(original.type()) +#endif { } bool Credential::isEmpty() const { +#if CERTIFICATE_CREDENTIALS_SUPPORTED + if (m_type == CredentialTypeClientCertificate && (m_identity || m_certificates)) + return false; +#endif + return m_user.isEmpty() && m_password.isEmpty(); } @@ -69,15 +92,68 @@ CredentialPersistence Credential::persistence() const { return m_persistence; } + +#if CERTIFICATE_CREDENTIALS_SUPPORTED +Credential::Credential(SecIdentityRef identity, CFArrayRef certificates, CredentialPersistence persistence) + : m_user("") + , m_password("") + , m_persistence(persistence) + , m_identity(identity) + , m_certificates(certificates) + , m_type(CredentialTypeClientCertificate) +{ +} + +SecIdentityRef Credential::identity() const +{ + return m_identity.get(); +} + +CFArrayRef Credential::certificates() const +{ + return m_certificates.get(); +} + +const CredentialType Credential::type() const +{ + return m_type; +} +#endif bool operator==(const Credential& a, const Credential& b) { + // Check persistence first since all credential types + // have the persistence property. + if (a.persistence() != b.persistence()) + return false; + +#if CERTIFICATE_CREDENTIALS_SUPPORTED + CredentialType aType = a.type(); + if (aType != b.type()) + return false; + + // Comparing identity and certificate chain pointers is valid only + // for client certificate type credentials. + // + // FIXME: Is pointer comparison of the identity and certificates properties sufficient? + if (aType == CredentialTypeClientCertificate) { + if (a.identity() != b.identity()) + return false; + if (a.certificates() != b.certificates()) + return false; + + // We only need to check identity and certificates to compare + // client certificate based credentials. + return true; + } + + ASSERT(a.type() == CredentialTypePassword && b.type() == CredentialTypePassword); +#endif + if (a.user() != b.user()) return false; if (a.password() != b.password()) return false; - if (a.persistence() != b.persistence()) - return false; return true; } diff --git a/WebCore/platform/network/Credential.h b/WebCore/platform/network/Credential.h index 0471fbc..199817c 100644 --- a/WebCore/platform/network/Credential.h +++ b/WebCore/platform/network/Credential.h @@ -27,6 +27,13 @@ #include "PlatformString.h" +#define CERTIFICATE_CREDENTIALS_SUPPORTED ((PLATFORM(MAC) || PLATFORM(IPHONE)) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) + +#if CERTIFICATE_CREDENTIALS_SUPPORTED +#include <Security/SecBase.h> +#include <wtf/RetainPtr.h> +#endif + namespace WebCore { enum CredentialPersistence { @@ -34,12 +41,23 @@ enum CredentialPersistence { CredentialPersistenceForSession, CredentialPersistencePermanent }; - + +#if CERTIFICATE_CREDENTIALS_SUPPORTED +enum CredentialType { + CredentialTypePassword, + CredentialTypeClientCertificate +}; +#endif + class Credential { public: Credential(); Credential(const String& user, const String& password, CredentialPersistence); + Credential(const Credential& original, CredentialPersistence); +#if CERTIFICATE_CREDENTIALS_SUPPORTED + Credential(SecIdentityRef identity, CFArrayRef certificates, CredentialPersistence); +#endif bool isEmpty() const; @@ -48,10 +66,21 @@ public: bool hasPassword() const; CredentialPersistence persistence() const; +#if CERTIFICATE_CREDENTIALS_SUPPORTED + SecIdentityRef identity() const; + CFArrayRef certificates() const; + const CredentialType type() const; +#endif + private: String m_user; String m_password; CredentialPersistence m_persistence; +#if CERTIFICATE_CREDENTIALS_SUPPORTED + RetainPtr<SecIdentityRef> m_identity; + RetainPtr<CFArrayRef> m_certificates; + CredentialType m_type; +#endif }; bool operator==(const Credential& a, const Credential& b); diff --git a/WebCore/platform/network/CredentialStorage.cpp b/WebCore/platform/network/CredentialStorage.cpp index ec78372..a401751 100644 --- a/WebCore/platform/network/CredentialStorage.cpp +++ b/WebCore/platform/network/CredentialStorage.cpp @@ -85,16 +85,18 @@ static String protectionSpaceMapKeyFromURL(const KURL& url) void CredentialStorage::set(const Credential& credential, const ProtectionSpace& protectionSpace, const KURL& url) { - ASSERT(url.protocolInHTTPFamily()); - ASSERT(url.isValid()); + ASSERT(protectionSpace.isProxy() || url.protocolInHTTPFamily()); + ASSERT(protectionSpace.isProxy() || url.isValid()); protectionSpaceToCredentialMap().set(protectionSpace, credential); - originsWithCredentials().add(originStringFromURL(url)); - - ProtectionSpaceAuthenticationScheme scheme = protectionSpace.authenticationScheme(); - if (scheme == ProtectionSpaceAuthenticationSchemeHTTPBasic || scheme == ProtectionSpaceAuthenticationSchemeDefault) { - // The map can contain both a path and its subpath - while redundant, this makes lookups faster. - pathToDefaultProtectionSpaceMap().set(protectionSpaceMapKeyFromURL(url), protectionSpace); + if (!protectionSpace.isProxy()) { + originsWithCredentials().add(originStringFromURL(url)); + + ProtectionSpaceAuthenticationScheme scheme = protectionSpace.authenticationScheme(); + if (scheme == ProtectionSpaceAuthenticationSchemeHTTPBasic || scheme == ProtectionSpaceAuthenticationSchemeDefault) { + // The map can contain both a path and its subpath - while redundant, this makes lookups faster. + pathToDefaultProtectionSpaceMap().set(protectionSpaceMapKeyFromURL(url), protectionSpace); + } } } diff --git a/WebCore/platform/network/CredentialStorage.h b/WebCore/platform/network/CredentialStorage.h index 5086f69..21fcbad 100644 --- a/WebCore/platform/network/CredentialStorage.h +++ b/WebCore/platform/network/CredentialStorage.h @@ -34,9 +34,13 @@ class ProtectionSpace; class CredentialStorage { public: + // WebCore session credential storage. static void set(const Credential&, const ProtectionSpace&, const KURL&); static Credential get(const ProtectionSpace&); + // OS persistent storage. + static Credential getFromPersistentStorage(const ProtectionSpace&); + // These methods work for authentication schemes that support sending credentials without waiting for a request. E.g., for HTTP Basic authentication scheme // a client should assume that all paths at or deeper than the depth of a known protected resource share are within the same protection space. static bool set(const Credential&, const KURL&); // Returns true if the URL corresponds to a known protection space, so credentials could be updated. diff --git a/WebCore/platform/network/FormDataBuilder.cpp b/WebCore/platform/network/FormDataBuilder.cpp index 04c7527..52f62f3 100644 --- a/WebCore/platform/network/FormDataBuilder.cpp +++ b/WebCore/platform/network/FormDataBuilder.cpp @@ -127,9 +127,6 @@ static void appendQuotedString(Vector<char>& buffer, const CString& string) case '"': append(buffer, "%22"); break; - case '%': - append(buffer, "%25"); - break; default: append(buffer, c); } @@ -143,7 +140,10 @@ Vector<char> FormDataBuilder::generateUniqueBoundaryString() // The RFC 2046 spec says the alphanumeric characters plus the // following characters are legal for boundaries: '()+_,-./:=? // However the following characters, though legal, cause some sites - // to fail: (),./:= (http://bugs.webkit.org/show_bug.cgi?id=13352) + // to fail: (),./:=+ + // Note that our algorithm makes it twice as much likely for 'A' or 'B' + // to appear in the boundary string, because 0x41 and 0x42 are present in + // the below array twice. static const char alphaNumericEncodingMap[64] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, @@ -152,18 +152,7 @@ Vector<char> FormDataBuilder::generateUniqueBoundaryString() 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x41 - // FIXME <rdar://problem/5252577> gmail does not accept legal characters in the form boundary - // As stated above, some legal characters cause, sites to fail. Specifically - // the / character which was the last character in the above array. I have - // replaced the last character with another character already in the array - // (notice the first and last values are both 0x41, A). Instead of picking - // another unique legal character for boundary strings that, because it has - // never been tested, may or may not break other sites, I simply - // replaced / with A. This means A is twice as likely to occur in our boundary - // strings than any other character but I think this is fine for the time being. - // The FIXME here is about restoring the / character once the aforementioned - // radar has been resolved. + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42 }; // Start with an informative prefix. diff --git a/WebCore/platform/network/HTTPHeaderMap.cpp b/WebCore/platform/network/HTTPHeaderMap.cpp index 07c66e8..413fb7b 100644 --- a/WebCore/platform/network/HTTPHeaderMap.cpp +++ b/WebCore/platform/network/HTTPHeaderMap.cpp @@ -59,5 +59,41 @@ void HTTPHeaderMap::adopt(auto_ptr<CrossThreadHTTPHeaderMapData> data) set(header.first, header.second); } } + +// Adapter that allows the HashMap to take C strings as keys. +struct CaseFoldingCStringTranslator { + static unsigned hash(const char* cString) + { + return CaseFoldingHash::hash(cString, strlen(cString)); + } + + static bool equal(const AtomicString& key, const char* cString) + { + return equalIgnoringCase(key, cString); + } + + static void translate(AtomicString& location, const char* cString, unsigned /*hash*/) + { + location = AtomicString(cString); + } +}; + +String HTTPHeaderMap::get(const char* name) const +{ + const_iterator i = find<const char*, CaseFoldingCStringTranslator>(name); + if (i == end()) + return String(); + return i->second; +} + +bool HTTPHeaderMap::contains(const char* name) const +{ + return find<const char*, CaseFoldingCStringTranslator>(name) != end(); +} + +pair<HTTPHeaderMap::iterator, bool> HTTPHeaderMap::add(const char* name, const String& value) +{ + return HashMap<AtomicString, String, CaseFoldingHash>::add<const char*, CaseFoldingCStringTranslator>(name, value); +} } // namespace WebCore diff --git a/WebCore/platform/network/HTTPHeaderMap.h b/WebCore/platform/network/HTTPHeaderMap.h index 6da1b90..dfde974 100644 --- a/WebCore/platform/network/HTTPHeaderMap.h +++ b/WebCore/platform/network/HTTPHeaderMap.h @@ -45,6 +45,22 @@ namespace WebCore { std::auto_ptr<CrossThreadHTTPHeaderMapData> copyData() const; void adopt(std::auto_ptr<CrossThreadHTTPHeaderMapData>); + + String get(const AtomicString& name) const + { + return HashMap<AtomicString, String, CaseFoldingHash>::get(name); + } + + pair<iterator, bool> add(const AtomicString& name, const String& value) + { + return HashMap<AtomicString, String, CaseFoldingHash>::add(name, value); + } + + // Alternate accessors that are faster than converting the char* to AtomicString first. + bool contains(const char*) const; + String get(const char*) const; + pair<iterator, bool> add(const char* name, const String& value); + }; } // namespace WebCore diff --git a/WebCore/platform/network/NetworkStateNotifier.h b/WebCore/platform/network/NetworkStateNotifier.h index f918be6..a630ccd 100644 --- a/WebCore/platform/network/NetworkStateNotifier.h +++ b/WebCore/platform/network/NetworkStateNotifier.h @@ -26,6 +26,8 @@ #ifndef NetworkStateNotifier_h #define NetworkStateNotifier_h +#include <wtf/Noncopyable.h> + #if PLATFORM(MAC) #include <wtf/RetainPtr.h> @@ -46,7 +48,7 @@ typedef const struct __SCDynamicStore * SCDynamicStoreRef; namespace WebCore { -class NetworkStateNotifier { +class NetworkStateNotifier : public Noncopyable { public: NetworkStateNotifier(); void setNetworkStateChangedFunction(void (*)()); diff --git a/WebCore/platform/network/ProtectionSpace.cpp b/WebCore/platform/network/ProtectionSpace.cpp index d04bcbe..26c258f 100644 --- a/WebCore/platform/network/ProtectionSpace.cpp +++ b/WebCore/platform/network/ProtectionSpace.cpp @@ -111,7 +111,8 @@ bool operator==(const ProtectionSpace& a, const ProtectionSpace& b) return false; if (a.serverType() != b.serverType()) return false; - if (a.realm() != b.realm()) + // Ignore realm for proxies + if (!a.isProxy() && a.realm() != b.realm()) return false; if (a.authenticationScheme() != b.authenticationScheme()) return false; diff --git a/WebCore/platform/network/ProtectionSpaceHash.h b/WebCore/platform/network/ProtectionSpaceHash.h index 6f68b5b..f8c84e8 100644 --- a/WebCore/platform/network/ProtectionSpaceHash.h +++ b/WebCore/platform/network/ProtectionSpaceHash.h @@ -37,11 +37,15 @@ struct ProtectionSpaceHash { protectionSpace.host().impl() ? protectionSpace.host().impl()->hash() : 0, protectionSpace.port(), protectionSpace.serverType(), - protectionSpace.realm().impl() ? protectionSpace.realm().impl()->hash() : 0, - protectionSpace.authenticationScheme() + protectionSpace.authenticationScheme(), + protectionSpace.realm().impl() ? protectionSpace.realm().impl()->hash() : 0 }; - return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); + unsigned codeCount = sizeof(hashCodes) / sizeof(UChar); + // Ignore realm for proxies. + if (protectionSpace.isProxy()) + codeCount -= sizeof(hashCodes[0]) / sizeof(UChar); + return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), codeCount); } static bool equal(const ProtectionSpace& a, const ProtectionSpace& b) { return a == b; } diff --git a/WebCore/platform/network/ResourceHandle.cpp b/WebCore/platform/network/ResourceHandle.cpp index 5a40b21..7c20561 100644 --- a/WebCore/platform/network/ResourceHandle.cpp +++ b/WebCore/platform/network/ResourceHandle.cpp @@ -36,8 +36,6 @@ namespace WebCore { static bool shouldForceContentSniffing; -static bool portAllowed(const ResourceRequest&); - ResourceHandle::ResourceHandle(const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff, bool mightDownloadFromHandle) : d(new ResourceHandleInternal(this, request, client, defersLoading, shouldContentSniff, mightDownloadFromHandle)) @@ -57,7 +55,7 @@ PassRefPtr<ResourceHandle> ResourceHandle::create(const ResourceRequest& request return newHandle.release(); } - if (!portAllowed(request)) { + if (!portAllowed(request.url())) { newHandle->scheduleFailure(BlockedFailure); return newHandle.release(); } @@ -110,100 +108,9 @@ void ResourceHandle::clearAuthentication() { #if PLATFORM(MAC) d->m_currentMacChallenge = nil; -#elif USE(CFNETWORK) - d->m_currentCFChallenge = 0; #endif d->m_currentWebChallenge.nullify(); } - -static bool portAllowed(const ResourceRequest& request) -{ - unsigned short port = request.url().port(); - - // Since most URLs don't have a port, return early for the "no port" case. - if (!port) - return true; - - // This blocked port list matches the port blocking that Mozilla implements. - // See http://www.mozilla.org/projects/netlib/PortBanning.html for more information. - static const unsigned short blockedPortList[] = { - 1, // tcpmux - 7, // echo - 9, // discard - 11, // systat - 13, // daytime - 15, // netstat - 17, // qotd - 19, // chargen - 20, // FTP-data - 21, // FTP-control - 22, // SSH - 23, // telnet - 25, // SMTP - 37, // time - 42, // name - 43, // nicname - 53, // domain - 77, // priv-rjs - 79, // finger - 87, // ttylink - 95, // supdup - 101, // hostriame - 102, // iso-tsap - 103, // gppitnp - 104, // acr-nema - 109, // POP2 - 110, // POP3 - 111, // sunrpc - 113, // auth - 115, // SFTP - 117, // uucp-path - 119, // nntp - 123, // NTP - 135, // loc-srv / epmap - 139, // netbios - 143, // IMAP2 - 179, // BGP - 389, // LDAP - 465, // SMTP+SSL - 512, // print / exec - 513, // login - 514, // shell - 515, // printer - 526, // tempo - 530, // courier - 531, // Chat - 532, // netnews - 540, // UUCP - 556, // remotefs - 563, // NNTP+SSL - 587, // ESMTP - 601, // syslog-conn - 636, // LDAP+SSL - 993, // IMAP+SSL - 995, // POP3+SSL - 2049, // NFS - 3659, // apple-sasl / PasswordServer [Apple addition] - 4045, // lockd - 6000, // X11 - }; - const unsigned short* const blockedPortListEnd = blockedPortList - + sizeof(blockedPortList) / sizeof(blockedPortList[0]); - - // If the port is not in the blocked port list, allow it. - if (!std::binary_search(blockedPortList, blockedPortListEnd, port)) - return true; - - // Allow ports 21 and 22 for FTP URLs, as Mozilla does. - if ((port == 21 || port == 22) && request.url().protocolIs("ftp")) - return true; - - // Allow any port number in a file URL, since the port number is ignored. - if (request.url().protocolIs("file")) - return true; - - return false; -} bool ResourceHandle::shouldContentSniff() const { diff --git a/WebCore/platform/network/ResourceHandle.h b/WebCore/platform/network/ResourceHandle.h index e82e13b..e7f6092 100644 --- a/WebCore/platform/network/ResourceHandle.h +++ b/WebCore/platform/network/ResourceHandle.h @@ -27,6 +27,7 @@ #define ResourceHandle_h #include "AuthenticationChallenge.h" +#include "AuthenticationClient.h" #include "HTTPHeaderMap.h" #include "ThreadableLoader.h" #include <wtf/OwnPtr.h> @@ -84,14 +85,18 @@ class KURL; class ResourceError; class ResourceHandleClient; class ResourceHandleInternal; -struct ResourceRequest; +class ResourceRequest; class ResourceResponse; class SchedulePair; class SharedBuffer; template <typename T> class Timer; -class ResourceHandle : public RefCounted<ResourceHandle> { +class ResourceHandle : public RefCounted<ResourceHandle> +#if PLATFORM(MAC) || USE(CFNETWORK) || USE(CURL) + , public AuthenticationClient +#endif + { private: ResourceHandle(const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff, bool mightDownloadFromHandle); @@ -110,7 +115,7 @@ public: static bool didSendBodyDataDelegateExists(); #endif - ~ResourceHandle(); + virtual ~ResourceHandle(); #if PLATFORM(MAC) || USE(CFNETWORK) void willSendRequest(ResourceRequest&, const ResourceResponse& redirectResponse); @@ -118,9 +123,9 @@ public: #endif #if PLATFORM(MAC) || USE(CFNETWORK) || USE(CURL) void didReceiveAuthenticationChallenge(const AuthenticationChallenge&); - void receivedCredential(const AuthenticationChallenge&, const Credential&); - void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&); - void receivedCancellation(const AuthenticationChallenge&); + virtual void receivedCredential(const AuthenticationChallenge&, const Credential&); + virtual void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&); + virtual void receivedCancellation(const AuthenticationChallenge&); #endif #if PLATFORM(MAC) @@ -133,7 +138,6 @@ public: void schedule(SchedulePair*); void unschedule(SchedulePair*); #elif USE(CFNETWORK) - static CFRunLoopRef loaderRunLoop(); CFURLConnectionRef connection() const; CFURLConnectionRef releaseConnectionForDownload(); static void setHostAllowsAnyHTTPSCertificate(const String&); @@ -190,11 +194,17 @@ public: void fireFailure(Timer<ResourceHandle>*); + using RefCounted<ResourceHandle>::ref; + using RefCounted<ResourceHandle>::deref; + private: void scheduleFailure(FailureType); bool start(Frame*); + virtual void refAuthenticationClient() { ref(); } + virtual void derefAuthenticationClient() { deref(); } + friend class ResourceHandleInternal; OwnPtr<ResourceHandleInternal> d; }; diff --git a/WebCore/platform/network/ResourceHandleClient.h b/WebCore/platform/network/ResourceHandleClient.h index c99be54..b5efaed 100644 --- a/WebCore/platform/network/ResourceHandleClient.h +++ b/WebCore/platform/network/ResourceHandleClient.h @@ -50,7 +50,7 @@ namespace WebCore { class KURL; class ResourceHandle; class ResourceError; - struct ResourceRequest; + class ResourceRequest; class ResourceResponse; enum CacheStoragePolicy { diff --git a/WebCore/platform/network/ResourceHandleInternal.h b/WebCore/platform/network/ResourceHandleInternal.h index fa939db..8313560 100644 --- a/WebCore/platform/network/ResourceHandleInternal.h +++ b/WebCore/platform/network/ResourceHandleInternal.h @@ -132,8 +132,6 @@ namespace WebCore { , m_startWhenScheduled(false) , m_needsSiteSpecificQuirks(false) , m_currentMacChallenge(nil) -#elif USE(CFNETWORK) - , m_currentCFChallenge(0) #endif #if PLATFORM(ANDROID) , m_loader(0) @@ -211,24 +209,24 @@ namespace WebCore { Frame* m_frame; #endif #if PLATFORM(QT) -#if QT_VERSION < 0x040400 - QWebNetworkJob* m_job; -#else QNetworkReplyHandler* m_job; -#endif QWebFrame* m_frame; #endif - // FIXME: The platform challenge is almost identical to the one stored in m_currentWebChallenge, but it has a different sender. We only need to store a sender reference here. #if PLATFORM(MAC) + // We need to keep a reference to the original challenge to be able to cancel it. + // It is almost identical to m_currentWebChallenge.nsURLAuthenticationChallenge(), but has a different sender. NSURLAuthenticationChallenge *m_currentMacChallenge; #endif +<<<<<<< HEAD:WebCore/platform/network/ResourceHandleInternal.h #if USE(CFNETWORK) CFURLAuthChallengeRef m_currentCFChallenge; #endif #if PLATFORM(ANDROID) RefPtr<ResourceLoaderAndroid> m_loader; #endif +======= +>>>>>>> webkit.org at r51976:WebCore/platform/network/ResourceHandleInternal.h AuthenticationChallenge m_currentWebChallenge; ResourceHandle::FailureType m_failureType; diff --git a/WebCore/platform/network/ResourceRequestBase.cpp b/WebCore/platform/network/ResourceRequestBase.cpp index 936f26b..41afb92 100644 --- a/WebCore/platform/network/ResourceRequestBase.cpp +++ b/WebCore/platform/network/ResourceRequestBase.cpp @@ -208,6 +208,13 @@ String ResourceRequestBase::httpHeaderField(const AtomicString& name) const return m_httpHeaderFields.get(name); } +String ResourceRequestBase::httpHeaderField(const char* name) const +{ + updateResourceRequest(); + + return m_httpHeaderFields.get(name); +} + void ResourceRequestBase::setHTTPHeaderField(const AtomicString& name, const String& value) { updateResourceRequest(); @@ -218,6 +225,11 @@ void ResourceRequestBase::setHTTPHeaderField(const AtomicString& name, const Str m_platformRequestUpdated = false; } +void ResourceRequestBase::setHTTPHeaderField(const char* name, const String& value) +{ + setHTTPHeaderField(AtomicString(name), value); +} + void ResourceRequestBase::clearHTTPReferrer() { updateResourceRequest(); diff --git a/WebCore/platform/network/ResourceRequestBase.h b/WebCore/platform/network/ResourceRequestBase.h index 84a7bd0..931a9de 100644 --- a/WebCore/platform/network/ResourceRequestBase.h +++ b/WebCore/platform/network/ResourceRequestBase.h @@ -46,12 +46,25 @@ namespace WebCore { const int unspecifiedTimeoutInterval = INT_MAX; - struct ResourceRequest; + class ResourceRequest; struct CrossThreadResourceRequestData; // Do not use this type directly. Use ResourceRequest instead. class ResourceRequestBase { public: + // The type of this ResourceRequest, based on how the resource will be used. + enum TargetType { + TargetIsMainFrame, + TargetIsSubframe, + TargetIsSubresource, // Resource is a generic subresource. (Generally a specific type should be specified) + TargetIsStyleSheet, + TargetIsScript, + TargetIsFontResource, + TargetIsImage, + TargetIsObject, + TargetIsMedia + }; + static std::auto_ptr<ResourceRequest> adopt(std::auto_ptr<CrossThreadResourceRequestData>); // Gets a copy of the data suitable for passing to another thread. @@ -79,7 +92,9 @@ namespace WebCore { const HTTPHeaderMap& httpHeaderFields() const; String httpHeaderField(const AtomicString& name) const; + String httpHeaderField(const char* name) const; void setHTTPHeaderField(const AtomicString& name, const String& value); + void setHTTPHeaderField(const char* name, const String& value); void addHTTPHeaderField(const AtomicString& name, const String& value); void addHTTPHeaderFields(const HTTPHeaderMap& headerFields); @@ -115,12 +130,17 @@ namespace WebCore { bool reportUploadProgress() const { return m_reportUploadProgress; } void setReportUploadProgress(bool reportUploadProgress) { m_reportUploadProgress = reportUploadProgress; } + // What this request is for. + TargetType targetType() const { return m_targetType; } + void setTargetType(TargetType type) { m_targetType = type; } + protected: // Used when ResourceRequest is initialized from a platform representation of the request ResourceRequestBase() : m_resourceRequestUpdated(false) , m_platformRequestUpdated(true) , m_reportUploadProgress(false) + , m_targetType(TargetIsSubresource) { } @@ -133,6 +153,7 @@ namespace WebCore { , m_resourceRequestUpdated(true) , m_platformRequestUpdated(false) , m_reportUploadProgress(false) + , m_targetType(TargetIsSubresource) { } @@ -152,6 +173,7 @@ namespace WebCore { mutable bool m_resourceRequestUpdated; mutable bool m_platformRequestUpdated; bool m_reportUploadProgress; + TargetType m_targetType; private: const ResourceRequest& asResourceRequest() const; @@ -162,7 +184,7 @@ namespace WebCore { bool operator==(const ResourceRequestBase&, const ResourceRequestBase&); inline bool operator!=(ResourceRequestBase& a, const ResourceRequestBase& b) { return !(a == b); } - struct CrossThreadResourceRequestData { + struct CrossThreadResourceRequestData : Noncopyable { KURL m_url; ResourceRequestCachePolicy m_cachePolicy; diff --git a/WebCore/platform/network/ResourceResponseBase.cpp b/WebCore/platform/network/ResourceResponseBase.cpp index fd44225..f9cd271 100644 --- a/WebCore/platform/network/ResourceResponseBase.cpp +++ b/WebCore/platform/network/ResourceResponseBase.cpp @@ -239,6 +239,13 @@ String ResourceResponseBase::httpHeaderField(const AtomicString& name) const return m_httpHeaderFields.get(name); } +String ResourceResponseBase::httpHeaderField(const char* name) const +{ + lazyInit(); + + return m_httpHeaderFields.get(name); +} + void ResourceResponseBase::setHTTPHeaderField(const AtomicString& name, const String& value) { lazyInit(); diff --git a/WebCore/platform/network/ResourceResponseBase.h b/WebCore/platform/network/ResourceResponseBase.h index 7594c09..e06c6f8 100644 --- a/WebCore/platform/network/ResourceResponseBase.h +++ b/WebCore/platform/network/ResourceResponseBase.h @@ -71,6 +71,7 @@ public: void setHTTPStatusText(const String&); String httpHeaderField(const AtomicString& name) const; + String httpHeaderField(const char* name) const; void setHTTPHeaderField(const AtomicString& name, const String& value); const HTTPHeaderMap& httpHeaderFields() const; diff --git a/WebCore/platform/network/SocketStreamHandleBase.cpp b/WebCore/platform/network/SocketStreamHandleBase.cpp index 875c248..8472713 100644 --- a/WebCore/platform/network/SocketStreamHandleBase.cpp +++ b/WebCore/platform/network/SocketStreamHandleBase.cpp @@ -31,6 +31,7 @@ #include "config.h" #include "SocketStreamHandleBase.h" +#include "SocketStreamHandle.h" #include "SocketStreamHandleClient.h" namespace WebCore { @@ -64,7 +65,7 @@ bool SocketStreamHandleBase::send(const char* data, int length) int bytesWritten = 0; if (m_state == Open) bytesWritten = platformSend(data, length); - if (bytesWritten <= 0) + if (bytesWritten < 0) return false; if (m_buffer.size() + length - bytesWritten > bufferSize) { // FIXME: report error to indicate that buffer has no more space. @@ -77,6 +78,8 @@ bool SocketStreamHandleBase::send(const char* data, int length) void SocketStreamHandleBase::close() { + RefPtr<SocketStreamHandle> protect(static_cast<SocketStreamHandle*>(this)); // platformClose calls the client, which may make the handle get deallocated immediately. + platformClose(); m_state = Closed; } diff --git a/WebCore/platform/network/SocketStreamHandleClient.h b/WebCore/platform/network/SocketStreamHandleClient.h index 04c744e..5d97ec0 100644 --- a/WebCore/platform/network/SocketStreamHandleClient.h +++ b/WebCore/platform/network/SocketStreamHandleClient.h @@ -43,18 +43,15 @@ namespace WebCore { public: virtual ~SocketStreamHandleClient() { } - virtual void willOpenStream(SocketStreamHandle*, const KURL&) { } - virtual void willSendData(SocketStreamHandle*, const char* /*data*/, int /*length*/) { } - virtual void didOpen(SocketStreamHandle*) { } virtual void didClose(SocketStreamHandle*) { } virtual void didReceiveData(SocketStreamHandle*, const char* /*data*/, int /*length*/) { } virtual void didFail(SocketStreamHandle*, const SocketStreamError&) { } + // No authentication for streams per se, but proxy may ask for credentials. virtual void didReceiveAuthenticationChallenge(SocketStreamHandle*, const AuthenticationChallenge&) { } virtual void didCancelAuthenticationChallenge(SocketStreamHandle*, const AuthenticationChallenge&) { } - virtual void receivedCancellation(SocketStreamHandle*, const AuthenticationChallenge&) { } }; } // namespace WebCore diff --git a/WebCore/platform/network/cf/AuthenticationCF.cpp b/WebCore/platform/network/cf/AuthenticationCF.cpp index bb05a39..93b62a8 100644 --- a/WebCore/platform/network/cf/AuthenticationCF.cpp +++ b/WebCore/platform/network/cf/AuthenticationCF.cpp @@ -27,9 +27,9 @@ #include "AuthenticationCF.h" #include "AuthenticationChallenge.h" +#include "AuthenticationClient.h" #include "Credential.h" #include "ProtectionSpace.h" -#include "ResourceHandle.h" #include <CFNetwork/CFURLAuthChallengePriv.h> #include <CFNetwork/CFURLCredentialPriv.h> @@ -51,20 +51,20 @@ AuthenticationChallenge::AuthenticationChallenge(const ProtectionSpace& protecti } AuthenticationChallenge::AuthenticationChallenge(CFURLAuthChallengeRef cfChallenge, - ResourceHandle* sourceHandle) + AuthenticationClient* authenticationClient) : AuthenticationChallengeBase(core(CFURLAuthChallengeGetProtectionSpace(cfChallenge)), core(CFURLAuthChallengeGetProposedCredential(cfChallenge)), CFURLAuthChallengeGetPreviousFailureCount(cfChallenge), (CFURLResponseRef)CFURLAuthChallengeGetFailureResponse(cfChallenge), CFURLAuthChallengeGetError(cfChallenge)) - , m_sourceHandle(sourceHandle) + , m_authenticationClient(authenticationClient) , m_cfChallenge(cfChallenge) { } bool AuthenticationChallenge::platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b) { - if (a.sourceHandle() != b.sourceHandle()) + if (a.authenticationClient() != b.authenticationClient()) return false; if (a.cfURLAuthChallengeRef() != b.cfURLAuthChallengeRef()) diff --git a/WebCore/platform/network/cf/AuthenticationChallenge.h b/WebCore/platform/network/cf/AuthenticationChallenge.h index 9697d7e..58fb836 100644 --- a/WebCore/platform/network/cf/AuthenticationChallenge.h +++ b/WebCore/platform/network/cf/AuthenticationChallenge.h @@ -26,29 +26,29 @@ #define AuthenticationChallenge_h #include "AuthenticationChallengeBase.h" -#include "ResourceHandle.h" +#include "AuthenticationClient.h" #include <wtf/RefPtr.h> typedef struct _CFURLAuthChallenge* CFURLAuthChallengeRef; namespace WebCore { -class ResourceHandle; - class AuthenticationChallenge : public AuthenticationChallengeBase { public: AuthenticationChallenge() {} AuthenticationChallenge(const ProtectionSpace& protectionSpace, const Credential& proposedCredential, unsigned previousFailureCount, const ResourceResponse& response, const ResourceError& error); - AuthenticationChallenge(CFURLAuthChallengeRef, ResourceHandle* sourceHandle); + AuthenticationChallenge(CFURLAuthChallengeRef, AuthenticationClient*); + + AuthenticationClient* authenticationClient() const { return m_authenticationClient.get(); } + void setAuthenticationClient(AuthenticationClient* client) { m_authenticationClient = client; } - ResourceHandle* sourceHandle() const { return m_sourceHandle.get(); } CFURLAuthChallengeRef cfURLAuthChallengeRef() const { return m_cfChallenge.get(); } private: friend class AuthenticationChallengeBase; static bool platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b); - RefPtr<ResourceHandle> m_sourceHandle; + RefPtr<AuthenticationClient> m_authenticationClient; RetainPtr<CFURLAuthChallengeRef> m_cfChallenge; }; diff --git a/WebCore/platform/network/cf/CredentialStorageCFNet.cpp b/WebCore/platform/network/cf/CredentialStorageCFNet.cpp new file mode 100644 index 0000000..0a9e36f --- /dev/null +++ b/WebCore/platform/network/cf/CredentialStorageCFNet.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 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 "CredentialStorage.h" + +#include "AuthenticationCF.h" +#include "Credential.h" +#include "ProtectionSpace.h" +#include <WebKitSystemInterface/WebKitSystemInterface.h> +#include <wtf/RetainPtr.h> + +namespace WebCore { + +Credential CredentialStorage::getFromPersistentStorage(const ProtectionSpace& protectionSpace) +{ + RetainPtr<CFURLProtectionSpaceRef> protectionSpaceCF(AdoptCF, createCF(protectionSpace)); + RetainPtr<CFURLCredentialRef> credentialCF(AdoptCF, wkCopyCredentialFromCFPersistentStorage(protectionSpaceCF.get())); + return core(credentialCF.get()); +} + +} // namespace WebCore diff --git a/WebCore/platform/network/cf/DNSCFNet.cpp b/WebCore/platform/network/cf/DNSCFNet.cpp index 381dff2..6311baf 100644 --- a/WebCore/platform/network/cf/DNSCFNet.cpp +++ b/WebCore/platform/network/cf/DNSCFNet.cpp @@ -33,7 +33,7 @@ #include <wtf/StdLibExtras.h> #if PLATFORM(WIN) -#include "ResourceHandle.h" // for loaderRunLoop() +#include "LoaderRunLoopCF.h" #endif #ifdef BUILDING_ON_TIGER @@ -137,7 +137,7 @@ void DNSResolveQueue::resolve(const String& hostname) CFHostScheduleWithRunLoop(host.get(), CFRunLoopGetMain(), kCFRunLoopCommonModes); #else // On Windows, we run a separate thread with CFRunLoop, which is where clientCallback will be called. - CFHostScheduleWithRunLoop(host.get(), ResourceHandle::loaderRunLoop(), kCFRunLoopDefaultMode); + CFHostScheduleWithRunLoop(host.get(), loaderRunLoop(), kCFRunLoopDefaultMode); #endif CFHostStartInfoResolution(host.get(), kCFHostAddresses, 0); host.releaseRef(); // The host will be released from clientCallback(). diff --git a/WebCore/platform/network/cf/LoaderRunLoopCF.cpp b/WebCore/platform/network/cf/LoaderRunLoopCF.cpp new file mode 100644 index 0000000..aa68916 --- /dev/null +++ b/WebCore/platform/network/cf/LoaderRunLoopCF.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2009 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 "LoaderRunLoopCF.h" + +#include <wtf/Threading.h> + +namespace WebCore { + +static CFRunLoopRef loaderRunLoopObject = 0; + +static void emptyPerform(void*) +{ +} + +static void* runLoaderThread(void*) +{ + loaderRunLoopObject = CFRunLoopGetCurrent(); + + // Must add a source to the run loop to prevent CFRunLoopRun() from exiting. + CFRunLoopSourceContext ctxt = {0, (void*)1 /*must be non-NULL*/, 0, 0, 0, 0, 0, 0, 0, emptyPerform}; + CFRunLoopSourceRef bogusSource = CFRunLoopSourceCreate(0, 0, &ctxt); + CFRunLoopAddSource(loaderRunLoopObject, bogusSource, kCFRunLoopDefaultMode); + + CFRunLoopRun(); + + return 0; +} + +CFRunLoopRef loaderRunLoop() +{ + ASSERT(isMainThread()); + if (!loaderRunLoopObject) { + createThread(runLoaderThread, 0, "WebCore: CFNetwork Loader"); + while (!loaderRunLoopObject) { + // FIXME: Sleep 10? that can't be right... + Sleep(10); + } + } + return loaderRunLoopObject; +} + +} diff --git a/WebCore/platform/network/cf/LoaderRunLoopCF.h b/WebCore/platform/network/cf/LoaderRunLoopCF.h new file mode 100644 index 0000000..20e4c29 --- /dev/null +++ b/WebCore/platform/network/cf/LoaderRunLoopCF.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2009 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. + */ + +#ifndef LoaderRunLoopCF_h +#define LoaderRunLoopCF_h + +#if !PLATFORM(WIN) +#error This code is not needed on platforms other than Windows, because main thread's CFRunLoop can be used. +#endif + +namespace WebCore { + +CFRunLoopRef loaderRunLoop(); + +} + +#endif // LoaderRunLoop_h diff --git a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp index 38a9705..8cc5022 100644 --- a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp @@ -39,6 +39,7 @@ #include "FormDataStreamCFNet.h" #include "Frame.h" #include "FrameLoader.h" +#include "LoaderRunLoopCF.h" #include "Logging.h" #include "MIMETypeRegistry.h" #include "ResourceError.h" @@ -322,37 +323,6 @@ CFArrayRef arrayFromFormData(const FormData& d) return a; } -void emptyPerform(void* unused) -{ -} - -static CFRunLoopRef loaderRL = 0; -void* runLoaderThread(void *unused) -{ - loaderRL = CFRunLoopGetCurrent(); - - // Must add a source to the run loop to prevent CFRunLoopRun() from exiting - CFRunLoopSourceContext ctxt = {0, (void *)1 /*must be non-NULL*/, 0, 0, 0, 0, 0, 0, 0, emptyPerform}; - CFRunLoopSourceRef bogusSource = CFRunLoopSourceCreate(0, 0, &ctxt); - CFRunLoopAddSource(loaderRL, bogusSource,kCFRunLoopDefaultMode); - - CFRunLoopRun(); - - return 0; -} - -CFRunLoopRef ResourceHandle::loaderRunLoop() -{ - if (!loaderRL) { - createThread(runLoaderThread, 0, "WebCore: CFNetwork Loader"); - while (loaderRL == 0) { - // FIXME: sleep 10? that can't be right... - Sleep(10); - } - } - return loaderRL; -} - static CFURLRequestRef makeFinalRequest(const ResourceRequest& request, bool shouldContentSniff) { CFMutableURLRequestRef newRequest = CFURLRequestCreateMutableCopy(kCFAllocatorDefault, request.cfURLRequest()); @@ -479,11 +449,11 @@ bool ResourceHandle::shouldUseCredentialStorage() void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge) { LOG(Network, "CFNet - didReceiveAuthenticationChallenge()"); - ASSERT(!d->m_currentCFChallenge); ASSERT(d->m_currentWebChallenge.isNull()); // Since CFURLConnection networking relies on keeping a reference to the original CFURLAuthChallengeRef, // we make sure that is actually present ASSERT(challenge.cfURLAuthChallengeRef()); + ASSERT(challenge.authenticationClient() == this); // Should be already set. if (!d->m_user.isNull() && !d->m_pass.isNull()) { RetainPtr<CFStringRef> user(AdoptCF, d->m_user.createCFString()); @@ -513,8 +483,7 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall } } - d->m_currentCFChallenge = challenge.cfURLAuthChallengeRef(); - d->m_currentWebChallenge = AuthenticationChallenge(d->m_currentCFChallenge, this); + d->m_currentWebChallenge = challenge; if (client()) client()->didReceiveAuthenticationChallenge(this, d->m_currentWebChallenge); diff --git a/WebCore/platform/network/cf/ResourceRequest.h b/WebCore/platform/network/cf/ResourceRequest.h index 8ead412..e361af5 100644 --- a/WebCore/platform/network/cf/ResourceRequest.h +++ b/WebCore/platform/network/cf/ResourceRequest.h @@ -34,8 +34,8 @@ typedef const struct _CFURLRequest* CFURLRequestRef; namespace WebCore { - struct ResourceRequest : ResourceRequestBase { - + class ResourceRequest : public ResourceRequestBase { + public: ResourceRequest(const String& url) : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) { @@ -64,7 +64,7 @@ namespace WebCore { CFURLRequestRef cfURLRequest() const; private: - friend struct ResourceRequestBase; + friend class ResourceRequestBase; void doUpdatePlatformRequest(); void doUpdateResourceRequest(); diff --git a/WebCore/platform/network/cf/ResourceRequestCFNet.h b/WebCore/platform/network/cf/ResourceRequestCFNet.h index d26072d..e9ebe76 100644 --- a/WebCore/platform/network/cf/ResourceRequestCFNet.h +++ b/WebCore/platform/network/cf/ResourceRequestCFNet.h @@ -30,7 +30,7 @@ typedef const struct _CFURLRequest* CFURLRequestRef; namespace WebCore { - struct ResourceRequest; + class ResourceRequest; void getResourceRequest(ResourceRequest&, CFURLRequestRef); CFURLRequestRef cfURLRequest(const ResourceRequest&); diff --git a/WebCore/platform/network/cf/SocketStreamHandle.h b/WebCore/platform/network/cf/SocketStreamHandle.h index 64139e5..63bf9a7 100644 --- a/WebCore/platform/network/cf/SocketStreamHandle.h +++ b/WebCore/platform/network/cf/SocketStreamHandle.h @@ -32,10 +32,9 @@ #ifndef SocketStreamHandle_h #define SocketStreamHandle_h +#include "AuthenticationClient.h" #include "SocketStreamHandleBase.h" - -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> +#include <wtf/RetainPtr.h> namespace WebCore { @@ -43,24 +42,69 @@ namespace WebCore { class Credential; class SocketStreamHandleClient; - class SocketStreamHandle : public RefCounted<SocketStreamHandle>, public SocketStreamHandleBase { + class SocketStreamHandle : public RefCounted<SocketStreamHandle>, public SocketStreamHandleBase, public AuthenticationClient { public: static PassRefPtr<SocketStreamHandle> create(const KURL& url, SocketStreamHandleClient* client) { return adoptRef(new SocketStreamHandle(url, client)); } virtual ~SocketStreamHandle(); - protected: + using RefCounted<SocketStreamHandle>::ref; + using RefCounted<SocketStreamHandle>::deref; + + private: virtual int platformSend(const char* data, int length); virtual void platformClose(); - private: SocketStreamHandle(const KURL&, SocketStreamHandleClient*); + void createStreams(); + void scheduleStreams(); + void chooseProxy(); +#ifndef BUILDING_ON_TIGER + void chooseProxyFromArray(CFArrayRef); + void executePACFileURL(CFURLRef); + void removePACRunLoopSource(); + RetainPtr<CFRunLoopSourceRef> m_pacRunLoopSource; + static void pacExecutionCallback(void* client, CFArrayRef proxyList, CFErrorRef error); + static void pacExecutionCallbackMainThread(void*); + static CFStringRef copyPACExecutionDescription(void*); +#endif + + bool shouldUseSSL() const { return m_url.protocolIs("wss"); } + + void addCONNECTCredentials(CFHTTPMessageRef response); + + static CFStringRef copyCFStreamDescription(void* ); + static void readStreamCallback(CFReadStreamRef, CFStreamEventType, void*); + static void writeStreamCallback(CFWriteStreamRef, CFStreamEventType, void*); +#if PLATFORM(WIN) + static void readStreamCallbackMainThread(void*); + static void writeStreamCallbackMainThread(void*); +#endif + void readStreamCallback(CFStreamEventType); + void writeStreamCallback(CFStreamEventType); // No authentication for streams per se, but proxy may ask for credentials. - void didReceiveAuthenticationChallenge(const AuthenticationChallenge&); - void receivedCredential(const AuthenticationChallenge&, const Credential&); - void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&); - void receivedCancellation(const AuthenticationChallenge&); + virtual void receivedCredential(const AuthenticationChallenge&, const Credential&); + virtual void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&); + virtual void receivedCancellation(const AuthenticationChallenge&); + + virtual void refAuthenticationClient() { ref(); } + virtual void derefAuthenticationClient() { deref(); } + + enum ConnectingSubstate { New, ExecutingPACFile, WaitingForCredentials, WaitingForConnect, Connected }; + ConnectingSubstate m_connectingSubstate; + + enum ConnectionType { Unknown, Direct, SOCKSProxy, CONNECTProxy }; + ConnectionType m_connectionType; + RetainPtr<CFStringRef> m_proxyHost; + RetainPtr<CFNumberRef> m_proxyPort; + + RetainPtr<CFHTTPMessageRef> m_proxyResponseMessage; + bool m_sentStoredCredentials; + RetainPtr<CFReadStreamRef> m_readStream; + RetainPtr<CFWriteStreamRef> m_writeStream; + + RetainPtr<CFURLRef> m_httpsURL; // ws(s): replaced with https: }; } // namespace WebCore diff --git a/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp b/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp index 6aa33fc..e7e64da 100644 --- a/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp +++ b/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp @@ -1,4 +1,5 @@ /* + * Copyright (C) 2009 Apple Inc. All rights reserved. * Copyright (C) 2009 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,58 +32,608 @@ #include "config.h" #include "SocketStreamHandle.h" -#include "KURL.h" +#include "Credential.h" +#include "CredentialStorage.h" #include "Logging.h" -#include "NotImplemented.h" +#include "ProtectionSpace.h" +#include "SocketStreamError.h" #include "SocketStreamHandleClient.h" +#include <wtf/MainThread.h> + +#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) +#include <SystemConfiguration/SystemConfiguration.h> +#endif + +#if PLATFORM(WIN) +#include "LoaderRunLoopCF.h" +#include <WebKitSystemInterface/WebKitSystemInterface.h> +#else +#include "WebCoreSystemInterface.h" +#endif + +#ifdef BUILDING_ON_TIGER +#define CFN_EXPORT extern +#endif namespace WebCore { SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client) : SocketStreamHandleBase(url, client) + , m_connectingSubstate(New) + , m_connectionType(Unknown) + , m_sentStoredCredentials(false) { LOG(Network, "SocketStreamHandle %p new client %p", this, m_client); - notImplemented(); + + ASSERT(url.protocolIs("ws") || url.protocolIs("wss")); + + if (!m_url.port()) + m_url.setPort(shouldUseSSL() ? 443 : 80); + + KURL httpsURL(KURL(), "https://" + m_url.host()); + m_httpsURL.adoptCF(httpsURL.createCFURL()); + + createStreams(); + ASSERT(!m_readStream == !m_writeStream); + if (!m_readStream) // Doing asynchronous PAC file processing, streams will be created later. + return; + + scheduleStreams(); +} + +void SocketStreamHandle::scheduleStreams() +{ + ASSERT(m_readStream); + ASSERT(m_writeStream); + + CFStreamClientContext clientContext = { 0, this, 0, 0, copyCFStreamDescription }; + // FIXME: Pass specific events we're interested in instead of -1. + CFReadStreamSetClient(m_readStream.get(), static_cast<CFOptionFlags>(-1), readStreamCallback, &clientContext); + CFWriteStreamSetClient(m_writeStream.get(), static_cast<CFOptionFlags>(-1), writeStreamCallback, &clientContext); + +#if PLATFORM(WIN) + CFReadStreamScheduleWithRunLoop(m_readStream.get(), loaderRunLoop(), kCFRunLoopDefaultMode); + CFWriteStreamScheduleWithRunLoop(m_writeStream.get(), loaderRunLoop(), kCFRunLoopDefaultMode); +#else + CFReadStreamScheduleWithRunLoop(m_readStream.get(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes); + CFWriteStreamScheduleWithRunLoop(m_writeStream.get(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes); +#endif + + CFReadStreamOpen(m_readStream.get()); + CFWriteStreamOpen(m_writeStream.get()); + +#ifndef BUILDING_ON_TIGER + if (m_pacRunLoopSource) + removePACRunLoopSource(); +#endif + + m_connectingSubstate = WaitingForConnect; +} + +#ifndef BUILDING_ON_TIGER +CFStringRef SocketStreamHandle::copyPACExecutionDescription(void*) +{ + return CFSTR("WebSocket proxy PAC file execution"); +} + +struct MainThreadPACCallbackInfo { + MainThreadPACCallbackInfo(SocketStreamHandle* handle, CFArrayRef proxyList) : handle(handle), proxyList(proxyList) { } + SocketStreamHandle* handle; + CFArrayRef proxyList; +}; + +void SocketStreamHandle::pacExecutionCallback(void* client, CFArrayRef proxyList, CFErrorRef) +{ + SocketStreamHandle* handle = static_cast<SocketStreamHandle*>(client); + MainThreadPACCallbackInfo info(handle, proxyList); + // If we're already on main thread (e.g. on Mac), callOnMainThreadAndWait() will be just a function call. + callOnMainThreadAndWait(pacExecutionCallbackMainThread, &info); +} + +void SocketStreamHandle::pacExecutionCallbackMainThread(void* invocation) +{ + MainThreadPACCallbackInfo* info = static_cast<MainThreadPACCallbackInfo*>(invocation); + ASSERT(info->handle->m_connectingSubstate == ExecutingPACFile); + // This time, the array won't have PAC as a first entry. + info->handle->chooseProxyFromArray(info->proxyList); + info->handle->createStreams(); + info->handle->scheduleStreams(); +} + +void SocketStreamHandle::executePACFileURL(CFURLRef pacFileURL) +{ + // CFNetwork returns an empty proxy array for WebScoket schemes, so use m_httpsURL. + CFStreamClientContext clientContext = { 0, this, 0, 0, copyPACExecutionDescription }; + m_pacRunLoopSource.adoptCF(CFNetworkExecuteProxyAutoConfigurationURL(pacFileURL, m_httpsURL.get(), pacExecutionCallback, &clientContext)); +#if PLATFORM(WIN) + CFRunLoopAddSource(loaderRunLoop(), m_pacRunLoopSource.get(), kCFRunLoopDefaultMode); +#else + CFRunLoopAddSource(CFRunLoopGetCurrent(), m_pacRunLoopSource.get(), kCFRunLoopCommonModes); +#endif + m_connectingSubstate = ExecutingPACFile; +} + +void SocketStreamHandle::removePACRunLoopSource() +{ + ASSERT(m_pacRunLoopSource); + + CFRunLoopSourceInvalidate(m_pacRunLoopSource.get()); +#if PLATFORM(WIN) + CFRunLoopRemoveSource(loaderRunLoop(), m_pacRunLoopSource.get(), kCFRunLoopDefaultMode); +#else + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_pacRunLoopSource.get(), kCFRunLoopCommonModes); +#endif + m_pacRunLoopSource = 0; +} + +void SocketStreamHandle::chooseProxy() +{ +#ifndef BUILDING_ON_LEOPARD + RetainPtr<CFDictionaryRef> proxyDictionary(AdoptCF, CFNetworkCopySystemProxySettings()); +#else + // We don't need proxy information often, so there is no need to set up a permanent dynamic store session. + RetainPtr<CFDictionaryRef> proxyDictionary(AdoptCF, SCDynamicStoreCopyProxies(0)); +#endif + + // SOCKS or HTTPS (AKA CONNECT) proxies are supported. + // WebSocket protocol relies on handshake being transferred unchanged, so we need a proxy that will not modify headers. + // Since HTTP proxies must add Via headers, they are highly unlikely to work. + // Many CONNECT proxies limit connectivity to port 443, so we prefer SOCKS, if configured. + + if (!proxyDictionary) { + m_connectionType = Direct; + return; + } + + // CFNetworkCopyProxiesForURL doesn't know about WebSocket schemes, so pretend to use http. + // Always use "https" to get HTTPS proxies in result - we'll try to use those for ws:// even though many are configured to reject connections to ports other than 443. + RetainPtr<CFArrayRef> proxyArray(AdoptCF, CFNetworkCopyProxiesForURL(m_httpsURL.get(), proxyDictionary.get())); + + chooseProxyFromArray(proxyArray.get()); +} + +void SocketStreamHandle::chooseProxyFromArray(CFArrayRef proxyArray) +{ + if (!proxyArray) + m_connectionType = Direct; + + CFIndex proxyArrayCount = CFArrayGetCount(proxyArray); + + // PAC is always the first entry, if present. + if (proxyArrayCount) { + CFDictionaryRef proxyInfo = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(proxyArray, 0)); + CFTypeRef proxyType = CFDictionaryGetValue(proxyInfo, kCFProxyTypeKey); + if (proxyType && CFGetTypeID(proxyType) == CFStringGetTypeID()) { + if (CFEqual(proxyType, kCFProxyTypeAutoConfigurationURL)) { + CFTypeRef pacFileURL = CFDictionaryGetValue(proxyInfo, kCFProxyAutoConfigurationURLKey); + if (pacFileURL && CFGetTypeID(pacFileURL) == CFURLGetTypeID()) { + executePACFileURL(static_cast<CFURLRef>(pacFileURL)); + return; + } + } + } + } + + CFDictionaryRef chosenProxy = 0; + for (CFIndex i = 0; i < proxyArrayCount; ++i) { + CFDictionaryRef proxyInfo = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(proxyArray, i)); + CFTypeRef proxyType = CFDictionaryGetValue(proxyInfo, kCFProxyTypeKey); + if (proxyType && CFGetTypeID(proxyType) == CFStringGetTypeID()) { + if (CFEqual(proxyType, kCFProxyTypeSOCKS)) { + m_connectionType = SOCKSProxy; + chosenProxy = proxyInfo; + break; + } + if (CFEqual(proxyType, kCFProxyTypeHTTPS)) { + m_connectionType = CONNECTProxy; + chosenProxy = proxyInfo; + // Keep looking for proxies, as a SOCKS one is preferable. + } + } + } + + if (chosenProxy) { + ASSERT(m_connectionType != Unknown); + ASSERT(m_connectionType != Direct); + + CFTypeRef proxyHost = CFDictionaryGetValue(chosenProxy, kCFProxyHostNameKey); + CFTypeRef proxyPort = CFDictionaryGetValue(chosenProxy, kCFProxyPortNumberKey); + + if (proxyHost && CFGetTypeID(proxyHost) == CFStringGetTypeID() && proxyPort && CFGetTypeID(proxyPort) == CFNumberGetTypeID()) { + m_proxyHost = static_cast<CFStringRef>(proxyHost); + m_proxyPort = static_cast<CFNumberRef>(proxyPort); + return; + } + } + + m_connectionType = Direct; +} + +#else // BUILDING_ON_TIGER + +void SocketStreamHandle::chooseProxy() +{ + // We don't need proxy information often, so there is no need to set up a permanent dynamic store session. + RetainPtr<CFDictionaryRef> proxyDictionary(AdoptCF, SCDynamicStoreCopyProxies(0)); + + // SOCKS or HTTPS (AKA CONNECT) proxies are supported. + // WebSocket protocol relies on handshake being transferred unchanged, so we need a proxy that will not modify headers. + // Since HTTP proxies must add Via headers, they are highly unlikely to work. + // Many CONNECT proxies limit connectivity to port 443, so we prefer SOCKS, if configured. + + if (!proxyDictionary) { + m_connectionType = Direct; + return; + } + + // FIXME: check proxy bypass list and ExcludeSimpleHostnames. + // FIXME: Support PAC files. + + CFTypeRef socksEnableCF = CFDictionaryGetValue(proxyDictionary.get(), kSCPropNetProxiesSOCKSEnable); + int socksEnable; + if (socksEnableCF && CFGetTypeID(socksEnableCF) == CFNumberGetTypeID() && CFNumberGetValue(static_cast<CFNumberRef>(socksEnableCF), kCFNumberIntType, &socksEnable) && socksEnable) { + CFTypeRef proxyHost = CFDictionaryGetValue(proxyDictionary.get(), kSCPropNetProxiesSOCKSProxy); + CFTypeRef proxyPort = CFDictionaryGetValue(proxyDictionary.get(), kSCPropNetProxiesSOCKSPort); + if (proxyHost && CFGetTypeID(proxyHost) == CFStringGetTypeID() && proxyPort && CFGetTypeID(proxyPort) == CFNumberGetTypeID()) { + m_proxyHost = static_cast<CFStringRef>(proxyHost); + m_proxyPort = static_cast<CFNumberRef>(proxyPort); + m_connectionType = SOCKSProxy; + return; + } + } + + CFTypeRef httpsEnableCF = CFDictionaryGetValue(proxyDictionary.get(), kSCPropNetProxiesHTTPSEnable); + int httpsEnable; + if (httpsEnableCF && CFGetTypeID(httpsEnableCF) == CFNumberGetTypeID() && CFNumberGetValue(static_cast<CFNumberRef>(httpsEnableCF), kCFNumberIntType, &httpsEnable) && httpsEnable) { + CFTypeRef proxyHost = CFDictionaryGetValue(proxyDictionary.get(), kSCPropNetProxiesHTTPSProxy); + CFTypeRef proxyPort = CFDictionaryGetValue(proxyDictionary.get(), kSCPropNetProxiesHTTPSPort); + + if (proxyHost && CFGetTypeID(proxyHost) == CFStringGetTypeID() && proxyPort && CFGetTypeID(proxyPort) == CFNumberGetTypeID()) { + m_proxyHost = static_cast<CFStringRef>(proxyHost); + m_proxyPort = static_cast<CFNumberRef>(proxyPort); + m_connectionType = CONNECTProxy; + return; + } + } + + m_connectionType = Direct; +} +#endif // BUILDING_ON_TIGER + +void SocketStreamHandle::createStreams() +{ + if (m_connectionType == Unknown) + chooseProxy(); + + // If it's still unknown, then we're resolving a PAC file asynchronously. + if (m_connectionType == Unknown) + return; + + RetainPtr<CFStringRef> host(AdoptCF, m_url.host().createCFString()); + + // Creating streams to final destination, not to proxy. + CFReadStreamRef readStream = 0; + CFWriteStreamRef writeStream = 0; + CFStreamCreatePairWithSocketToHost(0, host.get(), m_url.port(), &readStream, &writeStream); + + m_readStream.adoptCF(readStream); + m_writeStream.adoptCF(writeStream); + + switch (m_connectionType) { + case Unknown: + ASSERT_NOT_REACHED(); + break; + case Direct: + break; + case SOCKSProxy: { + // FIXME: SOCKS5 doesn't do challenge-response, should we try to apply credentials from Keychain right away? + // But SOCKS5 credentials don't work at the time of this writing anyway, see <rdar://6776698>. + const void* proxyKeys[] = { kCFStreamPropertySOCKSProxyHost, kCFStreamPropertySOCKSProxyPort }; + const void* proxyValues[] = { m_proxyHost.get(), m_proxyPort.get() }; + RetainPtr<CFDictionaryRef> connectDictionary(AdoptCF, CFDictionaryCreate(0, proxyKeys, proxyValues, sizeof(proxyKeys) / sizeof(*proxyKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + CFReadStreamSetProperty(m_readStream.get(), kCFStreamPropertySOCKSProxy, connectDictionary.get()); + break; + } + case CONNECTProxy: + wkSetCONNECTProxyForStream(m_readStream.get(), m_proxyHost.get(), m_proxyPort.get()); + break; + } + + if (shouldUseSSL()) { + const void* keys[] = { kCFStreamSSLPeerName, kCFStreamSSLLevel }; + const void* values[] = { host.get(), kCFStreamSocketSecurityLevelNegotiatedSSL }; + RetainPtr<CFDictionaryRef> settings(AdoptCF, CFDictionaryCreate(0, keys, values, sizeof(keys) / sizeof(*keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + CFReadStreamSetProperty(m_readStream.get(), kCFStreamPropertySSLSettings, settings.get()); + CFWriteStreamSetProperty(m_writeStream.get(), kCFStreamPropertySSLSettings, settings.get()); + } +} + +static bool getStoredCONNECTProxyCredentials(const ProtectionSpace& protectionSpace, String& login, String& password) +{ + // Try system credential storage first, matching HTTP behavior (CFNetwork only asks the client for password if it couldn't find it in Keychain). + Credential storedCredential = CredentialStorage::getFromPersistentStorage(protectionSpace); + if (storedCredential.isEmpty()) + storedCredential = CredentialStorage::get(protectionSpace); + + if (storedCredential.isEmpty()) + return false; + + login = storedCredential.user(); + password = storedCredential.password(); + + return true; +} + +static ProtectionSpaceAuthenticationScheme authenticationSchemeFromAuthenticationMethod(CFStringRef method) +{ + if (CFEqual(method, kCFHTTPAuthenticationSchemeBasic)) + return ProtectionSpaceAuthenticationSchemeHTTPBasic; + if (CFEqual(method, kCFHTTPAuthenticationSchemeDigest)) + return ProtectionSpaceAuthenticationSchemeHTTPDigest; +#ifndef BUILDING_ON_TIGER + if (CFEqual(method, kCFHTTPAuthenticationSchemeNTLM)) + return ProtectionSpaceAuthenticationSchemeNTLM; + if (CFEqual(method, kCFHTTPAuthenticationSchemeNegotiate)) + return ProtectionSpaceAuthenticationSchemeNegotiate; +#endif + ASSERT_NOT_REACHED(); + return ProtectionSpaceAuthenticationSchemeDefault; +} + +void SocketStreamHandle::addCONNECTCredentials(CFHTTPMessageRef proxyResponse) +{ + RetainPtr<CFHTTPAuthenticationRef> authentication(AdoptCF, CFHTTPAuthenticationCreateFromResponse(0, proxyResponse)); + + if (!CFHTTPAuthenticationRequiresUserNameAndPassword(authentication.get())) { + // That's all we can offer... + m_client->didFail(this, SocketStreamError()); // FIXME: Provide a sensible error. + return; + } + + int port = 0; + CFNumberGetValue(m_proxyPort.get(), kCFNumberIntType, &port); + RetainPtr<CFStringRef> methodCF(AdoptCF, CFHTTPAuthenticationCopyMethod(authentication.get())); + RetainPtr<CFStringRef> realmCF(AdoptCF, CFHTTPAuthenticationCopyRealm(authentication.get())); + ProtectionSpace protectionSpace(String(m_proxyHost.get()), port, ProtectionSpaceProxyHTTPS, String(realmCF.get()), authenticationSchemeFromAuthenticationMethod(methodCF.get())); + String login; + String password; + if (!m_sentStoredCredentials && getStoredCONNECTProxyCredentials(protectionSpace, login, password)) { + // Try to apply stored credentials, if we haven't tried those already. + RetainPtr<CFStringRef> loginCF(AdoptCF, login.createCFString()); + RetainPtr<CFStringRef> passwordCF(AdoptCF, password.createCFString()); + // Creating a temporary request to make CFNetwork apply credentials to it. Unfortunately, this cannot work with NTLM authentication. + RetainPtr<CFHTTPMessageRef> dummyRequest(AdoptCF, CFHTTPMessageCreateRequest(0, CFSTR("GET"), m_httpsURL.get(), kCFHTTPVersion1_1)); + + Boolean appliedCredentials = CFHTTPMessageApplyCredentials(dummyRequest.get(), authentication.get(), loginCF.get(), passwordCF.get(), 0); + ASSERT_UNUSED(appliedCredentials, appliedCredentials); + + RetainPtr<CFStringRef> proxyAuthorizationString(AdoptCF, CFHTTPMessageCopyHeaderFieldValue(dummyRequest.get(), CFSTR("Proxy-Authorization"))); + + if (!proxyAuthorizationString) { + // Fails e.g. for NTLM auth. + m_client->didFail(this, SocketStreamError()); // FIXME: Provide a sensible error. + return; + } + + // Setting the authorization results in a new connection attempt. + wkSetCONNECTProxyAuthorizationForStream(m_readStream.get(), proxyAuthorizationString.get()); + m_sentStoredCredentials = true; + return; + } + + // FIXME: Ask the client if credentials could not be found. + + m_client->didFail(this, SocketStreamError()); // FIXME: Provide a sensible error. +} + +CFStringRef SocketStreamHandle::copyCFStreamDescription(void* info) +{ + SocketStreamHandle* handle = static_cast<SocketStreamHandle*>(info); + return ("WebKit socket stream, " + handle->m_url.string()).createCFString(); +} + +struct MainThreadEventCallbackInfo { + MainThreadEventCallbackInfo(CFStreamEventType type, SocketStreamHandle* handle) : type(type), handle(handle) { } + CFStreamEventType type; + SocketStreamHandle* handle; +}; + +void SocketStreamHandle::readStreamCallback(CFReadStreamRef stream, CFStreamEventType type, void* clientCallBackInfo) +{ + SocketStreamHandle* handle = static_cast<SocketStreamHandle*>(clientCallBackInfo); + ASSERT_UNUSED(stream, stream == handle->m_readStream.get()); +#if PLATFORM(WIN) + MainThreadEventCallbackInfo info(type, handle); + callOnMainThreadAndWait(readStreamCallbackMainThread, &info); +#else + ASSERT(isMainThread()); + handle->readStreamCallback(type); +#endif +} + +void SocketStreamHandle::writeStreamCallback(CFWriteStreamRef stream, CFStreamEventType type, void* clientCallBackInfo) +{ + SocketStreamHandle* handle = static_cast<SocketStreamHandle*>(clientCallBackInfo); + ASSERT_UNUSED(stream, stream == handle->m_writeStream.get()); +#if PLATFORM(WIN) + MainThreadEventCallbackInfo info(type, handle); + callOnMainThreadAndWait(writeStreamCallbackMainThread, &info); +#else + ASSERT(isMainThread()); + handle->writeStreamCallback(type); +#endif +} + +#if PLATFORM(WIN) +void SocketStreamHandle::readStreamCallbackMainThread(void* invocation) +{ + MainThreadEventCallbackInfo* info = static_cast<MainThreadEventCallbackInfo*>(invocation); + info->handle->readStreamCallback(info->type); +} + +void SocketStreamHandle::writeStreamCallbackMainThread(void* invocation) +{ + MainThreadEventCallbackInfo* info = static_cast<MainThreadEventCallbackInfo*>(invocation); + info->handle->writeStreamCallback(info->type); +} +#endif // PLATFORM(WIN) + +void SocketStreamHandle::readStreamCallback(CFStreamEventType type) +{ + switch(type) { + case kCFStreamEventNone: + break; + case kCFStreamEventOpenCompleted: + break; + case kCFStreamEventHasBytesAvailable: { + if (m_connectingSubstate == WaitingForConnect) { + if (m_connectionType == CONNECTProxy) { + RetainPtr<CFHTTPMessageRef> proxyResponse(AdoptCF, wkCopyCONNECTProxyResponse(m_readStream.get(), m_httpsURL.get())); + if (proxyResponse && (407 == CFHTTPMessageGetResponseStatusCode(proxyResponse.get()))) { + addCONNECTCredentials(proxyResponse.get()); + return; + } + } + } else if (m_connectingSubstate == WaitingForCredentials) + break; + + if (m_connectingSubstate == WaitingForConnect) { + m_connectingSubstate = Connected; + m_state = Open; + + RefPtr<SocketStreamHandle> protect(this); // The client can close the handle, potentially removing the last reference. + m_client->didOpen(this); + if (m_state == Closed) + break; + // Fall through. + } else if (m_state == Closed) + break; + + ASSERT(m_state == Open); + ASSERT(m_connectingSubstate == Connected); + + CFIndex length; + UInt8 localBuffer[1024]; // Used if CFReadStreamGetBuffer couldn't return anything. + const UInt8* ptr = CFReadStreamGetBuffer(m_readStream.get(), 0, &length); + if (!ptr) { + length = CFReadStreamRead(m_readStream.get(), localBuffer, sizeof(localBuffer)); + ptr = localBuffer; + } + + m_client->didReceiveData(this, reinterpret_cast<const char*>(ptr), length); + + break; + } + case kCFStreamEventCanAcceptBytes: + ASSERT_NOT_REACHED(); + break; + case kCFStreamEventErrorOccurred: { + CFStreamError error = CFReadStreamGetError(m_readStream.get()); + m_client->didFail(this, SocketStreamError(error.error)); // FIXME: Provide a sensible error. + break; + } + case kCFStreamEventEndEncountered: + platformClose(); + break; + } +} + +void SocketStreamHandle::writeStreamCallback(CFStreamEventType type) +{ + switch(type) { + case kCFStreamEventNone: + break; + case kCFStreamEventOpenCompleted: + break; + case kCFStreamEventHasBytesAvailable: + ASSERT_NOT_REACHED(); + break; + case kCFStreamEventCanAcceptBytes: { + // Possibly, a spurious event from CONNECT handshake. + if (!CFWriteStreamCanAcceptBytes(m_writeStream.get())) + return; + + if (m_connectingSubstate == WaitingForCredentials) + break; + + if (m_connectingSubstate == WaitingForConnect) { + m_connectingSubstate = Connected; + m_state = Open; + + RefPtr<SocketStreamHandle> protect(this); // The client can close the handle, potentially removing the last reference. + m_client->didOpen(this); + break; + } + + ASSERT(m_state = Open); + ASSERT(m_connectingSubstate == Connected); + + sendPendingData(); + break; + } + case kCFStreamEventErrorOccurred: { + CFStreamError error = CFWriteStreamGetError(m_writeStream.get()); + m_client->didFail(this, SocketStreamError(error.error)); // FIXME: Provide a sensible error. + break; + } + case kCFStreamEventEndEncountered: + // FIXME: Currently, we handle closing in read callback, but these can come independently (e.g. a server can stop listening, but keep sending data). + break; + } } SocketStreamHandle::~SocketStreamHandle() { - LOG(Network, "SocketStreamHandle %p delete", this); - setClient(0); - notImplemented(); + LOG(Network, "SocketStreamHandle %p dtor", this); + +#ifndef BUILDING_ON_TIGER + ASSERT(!m_pacRunLoopSource); +#endif } -int SocketStreamHandle::platformSend(const char*, int) +int SocketStreamHandle::platformSend(const char* data, int length) { - LOG(Network, "SocketStreamHandle %p platformSend", this); - notImplemented(); - return 0; + if (!CFWriteStreamCanAcceptBytes(m_writeStream.get())) + return 0; + + return CFWriteStreamWrite(m_writeStream.get(), reinterpret_cast<const UInt8*>(data), length); } void SocketStreamHandle::platformClose() { LOG(Network, "SocketStreamHandle %p platformClose", this); - notImplemented(); -} -void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&) -{ - notImplemented(); +#ifndef BUILDING_ON_TIGER + if (m_pacRunLoopSource) + removePACRunLoopSource(); +#endif + + ASSERT(!m_readStream == !m_writeStream); + if (!m_readStream) + return; + + CFReadStreamUnscheduleFromRunLoop(m_readStream.get(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes); + CFWriteStreamUnscheduleFromRunLoop(m_writeStream.get(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes); + + CFReadStreamClose(m_readStream.get()); + CFWriteStreamClose(m_writeStream.get()); + + m_readStream = 0; + m_writeStream = 0; + + m_client->didClose(this); } void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&) { - notImplemented(); } void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&) { - notImplemented(); } void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&) { - notImplemented(); } } // namespace WebCore diff --git a/WebCore/platform/network/chromium/AuthenticationChallenge.h b/WebCore/platform/network/chromium/AuthenticationChallenge.h index cd1b430..e2d1f42 100644 --- a/WebCore/platform/network/chromium/AuthenticationChallenge.h +++ b/WebCore/platform/network/chromium/AuthenticationChallenge.h @@ -28,25 +28,23 @@ #define AuthenticationChallenge_h #include "AuthenticationChallengeBase.h" -#include "ResourceHandle.h" +#include "AuthenticationClient.h" #include <wtf/RefPtr.h> namespace WebCore { - class ResourceHandle; - class AuthenticationChallenge : public AuthenticationChallengeBase { public: AuthenticationChallenge() {} AuthenticationChallenge(const ProtectionSpace&, const Credential& proposedCredential, unsigned previousFailureCount, const ResourceResponse&, const ResourceError&); - ResourceHandle* sourceHandle() const { return m_sourceHandle.get(); } + AuthenticationClient* authenticationClient() const { return m_authenticationClient.get(); } private: friend class AuthenticationChallengeBase; static bool platformCompare(const AuthenticationChallenge&, const AuthenticationChallenge&); - RefPtr<ResourceHandle> m_sourceHandle; + RefPtr<AuthenticationClient> m_authenticationClient; }; } // namespace WebCore diff --git a/WebCore/platform/network/chromium/CookieJarChromium.cpp b/WebCore/platform/network/chromium/CookieJarChromium.cpp index 7862cc3..279d9b0 100644 --- a/WebCore/platform/network/chromium/CookieJarChromium.cpp +++ b/WebCore/platform/network/chromium/CookieJarChromium.cpp @@ -53,16 +53,14 @@ bool cookiesEnabled(const Document*) return true; } -bool getRawCookies(const Document*, const KURL&, Vector<Cookie>& rawCookies) +bool getRawCookies(const Document* document, const KURL& url, Vector<Cookie>& rawCookies) { - // FIXME: Not yet implemented - rawCookies.clear(); - return false; // return true when implemented + return ChromiumBridge::rawCookies(url, document->firstPartyForCookies(), &rawCookies); } -void deleteCookie(const Document*, const KURL&, const String&) +void deleteCookie(const Document*, const KURL& url, const String& cookieName) { - // FIXME: Not yet implemented + return ChromiumBridge::deleteCookie(url, cookieName); } } // namespace WebCore diff --git a/WebCore/platform/network/chromium/ResourceRequest.cpp b/WebCore/platform/network/chromium/ResourceRequest.cpp index 76d1288..5b27c1b 100644 --- a/WebCore/platform/network/chromium/ResourceRequest.cpp +++ b/WebCore/platform/network/chromium/ResourceRequest.cpp @@ -23,6 +23,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" +#include "ResourceRequest.h" + namespace WebCore { // This is used by the loader to control the number of issued parallel load requests. diff --git a/WebCore/platform/network/chromium/ResourceRequest.h b/WebCore/platform/network/chromium/ResourceRequest.h index 48ff1e7..176f923 100644 --- a/WebCore/platform/network/chromium/ResourceRequest.h +++ b/WebCore/platform/network/chromium/ResourceRequest.h @@ -35,22 +35,13 @@ namespace WebCore { class Frame; - struct ResourceRequest : public ResourceRequestBase { + class ResourceRequest : public ResourceRequestBase { public: - enum TargetType { - TargetIsMainFrame, - TargetIsSubFrame, - TargetIsSubResource, - TargetIsObject, - TargetIsMedia - }; - ResourceRequest(const String& url) : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) , m_requestorID(0) , m_requestorProcessID(0) , m_appCacheHostID(0) - , m_targetType(TargetIsSubResource) { } @@ -59,7 +50,6 @@ namespace WebCore { , m_requestorID(0) , m_requestorProcessID(0) , m_appCacheHostID(0) - , m_targetType(TargetIsSubResource) , m_securityInfo(securityInfo) { } @@ -69,7 +59,6 @@ namespace WebCore { , m_requestorID(0) , m_requestorProcessID(0) , m_appCacheHostID(0) - , m_targetType(TargetIsSubResource) { } @@ -78,7 +67,6 @@ namespace WebCore { , m_requestorID(0) , m_requestorProcessID(0) , m_appCacheHostID(0) - , m_targetType(TargetIsSubResource) { setHTTPReferrer(referrer); } @@ -88,7 +76,6 @@ namespace WebCore { , m_requestorID(0) , m_requestorProcessID(0) , m_appCacheHostID(0) - , m_targetType(TargetIsSubResource) { } @@ -96,10 +83,6 @@ namespace WebCore { int requestorID() const { return m_requestorID; } void setRequestorID(int requestorID) { m_requestorID = requestorID; } - // What this request is for. - TargetType targetType() const { return m_targetType; } - void setTargetType(TargetType type) { m_targetType = type; } - // The process id of the process from which this request originated. In // the case of out-of-process plugins, this allows to link back the // request to the plugin process (as it is processed through a render @@ -129,7 +112,6 @@ namespace WebCore { int m_requestorID; int m_requestorProcessID; int m_appCacheHostID; - TargetType m_targetType; CString m_securityInfo; }; diff --git a/WebCore/platform/network/curl/AuthenticationChallenge.h b/WebCore/platform/network/curl/AuthenticationChallenge.h index a64d575..7ace096 100644 --- a/WebCore/platform/network/curl/AuthenticationChallenge.h +++ b/WebCore/platform/network/curl/AuthenticationChallenge.h @@ -26,13 +26,11 @@ #define AuthenticationChallenge_h #include "AuthenticationChallengeBase.h" -#include "ResourceHandle.h" +#include "AuthenticationClient.h" #include <wtf/RefPtr.h> namespace WebCore { -class ResourceHandle; - class AuthenticationChallenge : public AuthenticationChallengeBase { public: AuthenticationChallenge() @@ -44,9 +42,9 @@ public: { } - ResourceHandle* sourceHandle() const { return m_sourceHandle.get(); } + AuthenticationClient* authenticationClient() const { return m_authenticationClient.get(); } - RefPtr<ResourceHandle> m_sourceHandle; + RefPtr<AuthenticationClient> m_authenticationClient; }; } diff --git a/WebCore/platform/network/curl/ResourceHandleManager.cpp b/WebCore/platform/network/curl/ResourceHandleManager.cpp index d8a812f..a006a14 100644 --- a/WebCore/platform/network/curl/ResourceHandleManager.cpp +++ b/WebCore/platform/network/curl/ResourceHandleManager.cpp @@ -49,6 +49,11 @@ #include <wtf/Threading.h> #include <wtf/Vector.h> +#if !PLATFORM(WIN_OS) +#include <sys/param.h> +#define MAX_PATH MAXPATHLEN +#endif + namespace WebCore { const int selectTimeoutMS = 5; diff --git a/WebCore/platform/network/curl/ResourceRequest.h b/WebCore/platform/network/curl/ResourceRequest.h index 3fa2795..40e1e8f 100644 --- a/WebCore/platform/network/curl/ResourceRequest.h +++ b/WebCore/platform/network/curl/ResourceRequest.h @@ -33,8 +33,8 @@ typedef const struct _CFURLRequest* CFURLRequestRef; namespace WebCore { - struct ResourceRequest : ResourceRequestBase { - + class ResourceRequest : public ResourceRequestBase { + public: ResourceRequest(const String& url) : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) { diff --git a/WebCore/platform/network/mac/AuthenticationChallenge.h b/WebCore/platform/network/mac/AuthenticationChallenge.h index e8f3a2d..d74a92c 100644 --- a/WebCore/platform/network/mac/AuthenticationChallenge.h +++ b/WebCore/platform/network/mac/AuthenticationChallenge.h @@ -37,21 +37,25 @@ class NSURLAuthenticationChallenge; namespace WebCore { +class AuthenticationClient; + class AuthenticationChallenge : public AuthenticationChallengeBase { public: - AuthenticationChallenge() {} + AuthenticationChallenge() { } AuthenticationChallenge(const ProtectionSpace& protectionSpace, const Credential& proposedCredential, unsigned previousFailureCount, const ResourceResponse& response, const ResourceError& error); AuthenticationChallenge(NSURLAuthenticationChallenge *); id sender() const { return m_sender.get(); } - NSURLAuthenticationChallenge *nsURLAuthenticationChallenge() const { return m_macChallenge.get(); } + NSURLAuthenticationChallenge *nsURLAuthenticationChallenge() const { return m_nsChallenge.get(); } + + void setAuthenticationClient(AuthenticationClient*); // Changes sender to one that invokes client methods. private: friend class AuthenticationChallengeBase; static bool platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b); - RetainPtr<id> m_sender; - RetainPtr<NSURLAuthenticationChallenge *> m_macChallenge; + RetainPtr<id> m_sender; // Always the same as [m_macChallenge.get() sender], cached here for performance. + RetainPtr<NSURLAuthenticationChallenge *> m_nsChallenge; }; } diff --git a/WebCore/platform/network/mac/AuthenticationMac.mm b/WebCore/platform/network/mac/AuthenticationMac.mm index 93725d5..ea06ecd 100644 --- a/WebCore/platform/network/mac/AuthenticationMac.mm +++ b/WebCore/platform/network/mac/AuthenticationMac.mm @@ -26,6 +26,7 @@ #import "AuthenticationMac.h" #import "AuthenticationChallenge.h" +#import "AuthenticationClient.h" #import "Credential.h" #import "ProtectionSpace.h" @@ -33,6 +34,51 @@ #import <Foundation/NSURLCredential.h> #import <Foundation/NSURLProtectionSpace.h> +using namespace WebCore; + +@interface WebCoreAuthenticationClientAsChallengeSender : NSObject <NSURLAuthenticationChallengeSender> +{ + AuthenticationClient* m_client; +} +- (id)initWithAuthenticationClient:(AuthenticationClient*)client; +- (void)detachClient; +@end + +@implementation WebCoreAuthenticationClientAsChallengeSender + +- (id)initWithAuthenticationClient:(AuthenticationClient*)client +{ + self = [self init]; + if (!self) + return nil; + m_client = client; + return self; +} + +- (void)detachClient +{ + m_client = 0; +} + +- (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + if (m_client) + m_client->receivedCredential(core(challenge), core(credential)); +} + +- (void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + if (m_client) + m_client->receivedRequestToContinueWithoutCredential(core(challenge)); +} + +- (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + if (m_client) + m_client->receivedCancellation(core(challenge)); +} + +@end namespace WebCore { @@ -49,17 +95,28 @@ AuthenticationChallenge::AuthenticationChallenge(const ProtectionSpace& protecti { } -AuthenticationChallenge::AuthenticationChallenge(NSURLAuthenticationChallenge *macChallenge) - : AuthenticationChallengeBase(core([macChallenge protectionSpace]), - core([macChallenge proposedCredential]), - [macChallenge previousFailureCount], - [macChallenge failureResponse], - [macChallenge error]) - , m_sender([macChallenge sender]) - , m_macChallenge(macChallenge) +AuthenticationChallenge::AuthenticationChallenge(NSURLAuthenticationChallenge *challenge) + : AuthenticationChallengeBase(core([challenge protectionSpace]), + core([challenge proposedCredential]), + [challenge previousFailureCount], + [challenge failureResponse], + [challenge error]) + , m_sender([challenge sender]) + , m_nsChallenge(challenge) { } +void AuthenticationChallenge::setAuthenticationClient(AuthenticationClient* client) +{ + if (client) { + m_sender.adoptNS([[WebCoreAuthenticationClientAsChallengeSender alloc] initWithAuthenticationClient:client]); + m_nsChallenge.adoptNS([[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:m_nsChallenge.get() sender:m_sender.get()]); + } else { + if ([m_sender.get() isMemberOfClass:[WebCoreAuthenticationClientAsChallengeSender class]]) + [(WebCoreAuthenticationClientAsChallengeSender *)m_sender.get() detachClient]; + } +} + bool AuthenticationChallenge::platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b) { if (a.sender() != b.sender()) @@ -131,6 +188,11 @@ NSURLProtectionSpace *mac(const ProtectionSpace& coreSpace) case ProtectionSpaceAuthenticationSchemeHTMLForm: method = NSURLAuthenticationMethodHTMLForm; break; +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + case ProtectionSpaceAuthenticationSchemeNTLM: + method = NSURLAuthenticationMethodNTLM; + break; +#endif default: ASSERT_NOT_REACHED(); } @@ -167,6 +229,15 @@ NSURLCredential *mac(const Credential& coreCredential) ASSERT_NOT_REACHED(); } +#if CERTIFICATE_CREDENTIALS_SUPPORTED + if (coreCredential.type() == CredentialTypeClientCertificate) { + return [[[NSURLCredential alloc] initWithIdentity:coreCredential.identity() + certificates:(NSArray *)coreCredential.certificates() + persistence:persistence] + autorelease]; + } +#endif + return [[[NSURLCredential alloc] initWithUser:coreCredential.user() password:coreCredential.password() persistence:persistence] @@ -218,6 +289,10 @@ ProtectionSpace core(NSURLProtectionSpace *macSpace) scheme = ProtectionSpaceAuthenticationSchemeHTTPDigest; else if ([method isEqualToString:NSURLAuthenticationMethodHTMLForm]) scheme = ProtectionSpaceAuthenticationSchemeHTMLForm; +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + else if ([method isEqualToString:NSURLAuthenticationMethodNTLM]) + scheme = ProtectionSpaceAuthenticationSchemeNTLM; +#endif else ASSERT_NOT_REACHED(); @@ -240,6 +315,12 @@ Credential core(NSURLCredential *macCredential) default: ASSERT_NOT_REACHED(); } + +#if CERTIFICATE_CREDENTIALS_SUPPORTED + SecIdentityRef identity = [macCredential identity]; + if (identity) + return Credential(identity, (CFArrayRef)[macCredential certificates], persistence); +#endif return Credential([macCredential user], [macCredential password], persistence); } diff --git a/WebCore/platform/network/mac/CredentialStorageMac.mm b/WebCore/platform/network/mac/CredentialStorageMac.mm new file mode 100644 index 0000000..66e94e9 --- /dev/null +++ b/WebCore/platform/network/mac/CredentialStorageMac.mm @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2009 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 "CredentialStorage.h" + +#include "AuthenticationMac.h" +#include "Credential.h" + +namespace WebCore { + +Credential CredentialStorage::getFromPersistentStorage(const ProtectionSpace& protectionSpace) +{ + NSURLCredential *credential = [[NSURLCredentialStorage sharedCredentialStorage] defaultCredentialForProtectionSpace:mac(protectionSpace)]; + return credential ? core(credential) : Credential(); +} + +} // namespace WebCore diff --git a/WebCore/platform/network/mac/NetworkStateNotifierMac.cpp b/WebCore/platform/network/mac/NetworkStateNotifierMac.cpp index c0918a4..2045eb3 100644 --- a/WebCore/platform/network/mac/NetworkStateNotifierMac.cpp +++ b/WebCore/platform/network/mac/NetworkStateNotifierMac.cpp @@ -28,10 +28,10 @@ #include <SystemConfiguration/SystemConfiguration.h> -#ifdef BUILDING_ON_TIGER -// This function is available on Tiger, but not declared in the CFRunLoop.h header on Tiger. -extern "C" CFRunLoopRef CFRunLoopGetMain(); -#endif +#ifdef BUILDING_ON_TIGER +// This function is available on Tiger, but not declared in the CFRunLoop.h header on Tiger. +extern "C" CFRunLoopRef CFRunLoopGetMain(); +#endif namespace WebCore { diff --git a/WebCore/platform/network/mac/ResourceHandleMac.mm b/WebCore/platform/network/mac/ResourceHandleMac.mm index 3630b30..360425e 100644 --- a/WebCore/platform/network/mac/ResourceHandleMac.mm +++ b/WebCore/platform/network/mac/ResourceHandleMac.mm @@ -55,7 +55,7 @@ typedef int NSInteger; using namespace WebCore; -@interface WebCoreResourceHandleAsDelegate : NSObject <NSURLAuthenticationChallengeSender> +@interface WebCoreResourceHandleAsDelegate : NSObject { ResourceHandle* m_handle; } @@ -138,6 +138,7 @@ ResourceHandleInternal::~ResourceHandleInternal() ResourceHandle::~ResourceHandle() { releaseDelegate(); + d->m_currentWebChallenge.setAuthenticationClient(0); LOG(Network, "Handle %p destroyed", this); } @@ -511,10 +512,8 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall #endif d->m_currentMacChallenge = challenge.nsURLAuthenticationChallenge(); - NSURLAuthenticationChallenge *webChallenge = [[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:d->m_currentMacChallenge - sender:(id<NSURLAuthenticationChallengeSender>)delegate()]; - d->m_currentWebChallenge = core(webChallenge); - [webChallenge release]; + d->m_currentWebChallenge = core(d->m_currentMacChallenge); + d->m_currentWebChallenge.setAuthenticationClient(this); if (client()) client()->didReceiveAuthenticationChallenge(this, d->m_currentWebChallenge); @@ -523,8 +522,8 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall void ResourceHandle::didCancelAuthenticationChallenge(const AuthenticationChallenge& challenge) { ASSERT(d->m_currentMacChallenge); + ASSERT(d->m_currentMacChallenge == challenge.nsURLAuthenticationChallenge()); ASSERT(!d->m_currentWebChallenge.isNull()); - ASSERT(d->m_currentWebChallenge == challenge); if (client()) client()->didCancelAuthenticationChallenge(this, challenge); @@ -547,7 +546,7 @@ void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge // Manage per-session credentials internally, because once NSURLCredentialPersistenceForSession is used, there is no way // to ignore it for a particular request (short of removing it altogether). // <rdar://problem/6867598> gallery.me.com is temporarily whitelisted, so that QuickTime plug-in could see the credentials. - Credential webCredential(credential.user(), credential.password(), CredentialPersistenceNone); + Credential webCredential(credential, CredentialPersistenceNone); KURL urlToStore; if (challenge.failureResponse().httpStatusCode() == 401) urlToStore = d->m_request.url(); @@ -868,27 +867,6 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen return newResponse; } -- (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge -{ - if (!m_handle) - return; - m_handle->receivedCredential(core(challenge), core(credential)); -} - -- (void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge -{ - if (!m_handle) - return; - m_handle->receivedRequestToContinueWithoutCredential(core(challenge)); -} - -- (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge -{ - if (!m_handle) - return; - m_handle->receivedCancellation(core(challenge)); -} - @end #ifndef BUILDING_ON_TIGER diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index ed5e024..f7bbb9d 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -21,8 +21,6 @@ #include "config.h" #include "QNetworkReplyHandler.h" -#if QT_VERSION >= 0x040400 - #include "HTTPParsers.h" #include "MIMETypeRegistry.h" #include "ResourceHandle.h" @@ -140,10 +138,14 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load m_method = QNetworkAccessManager::PostOperation; else if (r.httpMethod() == "PUT") m_method = QNetworkAccessManager::PutOperation; +#if QT_VERSION >= 0x040600 + else if (r.httpMethod() == "DELETE") + m_method = QNetworkAccessManager::DeleteOperation; +#endif else m_method = QNetworkAccessManager::UnknownOperation; - m_request = r.toNetworkRequest(); + m_request = r.toNetworkRequest(m_resourceHandle->getInternal()->m_frame); if (m_loadMode == LoadNormal) start(); @@ -255,7 +257,7 @@ void QNetworkReplyHandler::sendResponseIfNeeded() if (m_shouldSendResponse) return; - if (m_reply->error()) + if (m_reply->error() && !ignoreHttpError(m_reply, m_responseDataSent)) return; if (m_responseSent || !m_resourceHandle) @@ -305,9 +307,15 @@ void QNetworkReplyHandler::sendResponseIfNeeded() response.setHTTPStatusText(m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData()); // Add remaining headers. +#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) + foreach (const QNetworkReply::RawHeaderPair& pair, m_reply->rawHeaderPairs()) { + response.setHTTPHeaderField(QString::fromAscii(pair.first), QString::fromAscii(pair.second)); + } +#else foreach (const QByteArray& headerName, m_reply->rawHeaderList()) { response.setHTTPHeaderField(QString::fromAscii(headerName), QString::fromAscii(m_reply->rawHeader(headerName))); } +#endif } QUrl redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); @@ -321,12 +329,13 @@ void QNetworkReplyHandler::sendResponseIfNeeded() newRequest.setHTTPMethod("GET"); } + // Should not set Referer after a redirect from a secure resource to non-secure one. + if (!newRequest.url().protocolIs("https") && protocolIs(newRequest.httpReferrer(), "https")) + newRequest.clearHTTPReferrer(); + client->willSendRequest(m_resourceHandle, newRequest, response); m_redirected = true; - m_request = newRequest.toNetworkRequest(); - - ResourceHandleInternal* d = m_resourceHandle->getInternal(); - emit d->m_frame->page()->networkRequestStarted(d->m_frame, &m_request); + m_request = newRequest.toNetworkRequest(m_resourceHandle->getInternal()->m_frame); return; } @@ -368,8 +377,6 @@ void QNetworkReplyHandler::start() QNetworkAccessManager* manager = d->m_frame->page()->networkAccessManager(); - emit d->m_frame->page()->networkRequestStarted(d->m_frame, &m_request); - const QUrl url = m_request.url(); const QString scheme = url.scheme(); // Post requests on files and data don't really make sense, but for @@ -398,6 +405,12 @@ void QNetworkReplyHandler::start() putDevice->setParent(m_reply); break; } +#if QT_VERSION >= 0x040600 + case QNetworkAccessManager::DeleteOperation: { + m_reply = manager->deleteResource(m_request); + break; + } +#endif case QNetworkAccessManager::UnknownOperation: { m_reply = 0; ResourceHandleClient* client = m_resourceHandle->client(); @@ -461,5 +474,3 @@ void QNetworkReplyHandler::sendQueuedItems() } #include "moc_QNetworkReplyHandler.cpp" - -#endif diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.h b/WebCore/platform/network/qt/QNetworkReplyHandler.h index fccc4a6..2171083 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.h +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.h @@ -21,8 +21,6 @@ #include <QObject> -#if QT_VERSION >= 0x040400 - #include <QNetworkRequest> #include <QNetworkAccessManager> @@ -113,6 +111,4 @@ private: } -#endif - #endif // QNETWORKREPLYHANDLER_H diff --git a/WebCore/platform/network/qt/ResourceHandleQt.cpp b/WebCore/platform/network/qt/ResourceHandleQt.cpp index f4c30c9..09cdefd 100644 --- a/WebCore/platform/network/qt/ResourceHandleQt.cpp +++ b/WebCore/platform/network/qt/ResourceHandleQt.cpp @@ -48,13 +48,9 @@ #endif #include <QCoreApplication> #include <QUrl> -#if QT_VERSION >= 0x040400 #include <QNetworkAccessManager> #include <QNetworkRequest> #include <QNetworkReply> -#else -#include "qwebnetworkinterface_p.h" -#endif namespace WebCore { @@ -131,24 +127,25 @@ bool ResourceHandle::start(Frame* frame) if (!page) return false; + if (!(d->m_user.isEmpty() || d->m_pass.isEmpty())) { + // If credentials were specified for this request, add them to the url, + // so that they will be passed to QNetworkRequest. + KURL urlWithCredentials(d->m_request.url()); + urlWithCredentials.setUser(d->m_user); + urlWithCredentials.setPass(d->m_pass); + d->m_request.setURL(urlWithCredentials); + } + getInternal()->m_frame = static_cast<FrameLoaderClientQt*>(frame->loader()->client())->webFrame(); -#if QT_VERSION < 0x040400 - return QWebNetworkManager::self()->add(this, getInternal()->m_frame->page()->d->networkInterface); -#else ResourceHandleInternal *d = getInternal(); d->m_job = new QNetworkReplyHandler(this, QNetworkReplyHandler::LoadMode(d->m_defersLoading)); return true; -#endif } void ResourceHandle::cancel() { -#if QT_VERSION < 0x040400 - QWebNetworkManager::self()->cancel(this); -#else if (d->m_job) d->m_job->abort(); -#endif } bool ResourceHandle::loadsBlocked() @@ -196,17 +193,17 @@ void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, S WebCoreSynchronousLoader syncLoader; ResourceHandle handle(request, &syncLoader, true, false, true); -#if QT_VERSION < 0x040400 - if (!QWebNetworkManager::self()->add(&handle, QWebNetworkInterface::defaultInterface(), QWebNetworkManager::SynchronousJob)) { - // FIXME Create a sane ResourceError - error = ResourceError(String(), -1, String(), String()); - return; - } -#else ResourceHandleInternal *d = handle.getInternal(); + if (!(d->m_user.isEmpty() || d->m_pass.isEmpty())) { + // If credentials were specified for this request, add them to the url, + // so that they will be passed to QNetworkRequest. + KURL urlWithCredentials(d->m_request.url()); + urlWithCredentials.setUser(d->m_user); + urlWithCredentials.setPass(d->m_pass); + d->m_request.setURL(urlWithCredentials); + } d->m_frame = static_cast<FrameLoaderClientQt*>(frame->loader()->client())->webFrame(); d->m_job = new QNetworkReplyHandler(&handle, QNetworkReplyHandler::LoadNormal); -#endif syncLoader.waitForCompletion(); error = syncLoader.resourceError(); @@ -219,10 +216,8 @@ void ResourceHandle::setDefersLoading(bool defers) { d->m_defersLoading = defers; -#if QT_VERSION >= 0x040400 if (d->m_job) d->m_job->setLoadMode(QNetworkReplyHandler::LoadMode(defers)); -#endif } } // namespace WebCore diff --git a/WebCore/platform/network/qt/ResourceRequest.h b/WebCore/platform/network/qt/ResourceRequest.h index 93dacf3..fb69326 100644 --- a/WebCore/platform/network/qt/ResourceRequest.h +++ b/WebCore/platform/network/qt/ResourceRequest.h @@ -31,12 +31,13 @@ QT_BEGIN_NAMESPACE class QNetworkRequest; +class QObject; QT_END_NAMESPACE namespace WebCore { - struct ResourceRequest : ResourceRequestBase { - + class ResourceRequest : public ResourceRequestBase { + public: ResourceRequest(const String& url) : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) { @@ -58,9 +59,7 @@ namespace WebCore { { } -#if QT_VERSION >= 0x040400 - QNetworkRequest toNetworkRequest() const; -#endif + QNetworkRequest toNetworkRequest(QObject* originatingObject) const; private: friend class ResourceRequestBase; diff --git a/WebCore/platform/network/qt/ResourceRequestQt.cpp b/WebCore/platform/network/qt/ResourceRequestQt.cpp index c8f6ad5..752abfe 100644 --- a/WebCore/platform/network/qt/ResourceRequestQt.cpp +++ b/WebCore/platform/network/qt/ResourceRequestQt.cpp @@ -21,24 +21,31 @@ #include "ResourceRequest.h" #include <qglobal.h> -#if QT_VERSION >= 0x040400 #include <QNetworkRequest> #include <QUrl> namespace WebCore { -QNetworkRequest ResourceRequest::toNetworkRequest() const +QNetworkRequest ResourceRequest::toNetworkRequest(QObject* originatingFrame) const { QNetworkRequest request; request.setUrl(url()); +#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) + request.setOriginatingObject(originatingFrame); +#endif const HTTPHeaderMap &headers = httpHeaderFields(); for (HTTPHeaderMap::const_iterator it = headers.begin(), end = headers.end(); it != end; ++it) { QByteArray name = QString(it->first).toAscii(); QByteArray value = QString(it->second).toAscii(); - request.setRawHeader(name, value); + // QNetworkRequest::setRawHeader() would remove the header if the value is null + // Make sure to set an empty header instead of null header. + if (!value.isNull()) + request.setRawHeader(name, value); + else + request.setRawHeader(name, ""); } switch (cachePolicy()) { @@ -62,4 +69,3 @@ QNetworkRequest ResourceRequest::toNetworkRequest() const } -#endif diff --git a/WebCore/platform/network/soup/DNSSoup.cpp b/WebCore/platform/network/soup/DNSSoup.cpp index 1ffe1a0..ce55143 100644 --- a/WebCore/platform/network/soup/DNSSoup.cpp +++ b/WebCore/platform/network/soup/DNSSoup.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2009 Igalia S.L. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,13 +27,19 @@ #include "config.h" #include "DNS.h" -#include "NotImplemented.h" +#include "CString.h" +#include "ResourceHandle.h" namespace WebCore { void prefetchDNS(const String& hostname) { - notImplemented(); + #ifdef HAVE_LIBSOUP_2_29_3 + String uri = "http://"+hostname; + SoupURI* soupUri = soup_uri_new(uri.utf8().data()); + soup_session_prepare_for_uri(ResourceHandle::defaultSession(), soupUri); + soup_uri_free(soupUri); + #endif } } diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp index 2177bd2..6367a3e 100644 --- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp +++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp @@ -200,6 +200,13 @@ static void restartedCallback(SoupMessage* msg, gpointer data) request.setURL(newURL); request.setHTTPMethod(msg->method); fillResponseFromMessage(msg, &response); + + // Should not set Referer after a redirect from a secure resource to non-secure one. + if (!request.url().protocolIs("https") && protocolIs(request.httpReferrer(), "https")) { + request.clearHTTPReferrer(); + soup_message_headers_remove(msg->request_headers, "Referer"); + } + if (d->client()) d->client()->willSendRequest(handle, request, response); } @@ -686,6 +693,13 @@ static void closeCallback(GObject* source, GAsyncResult* res, gpointer) g_input_stream_close_finish(d->m_inputStream, res, 0); cleanupGioOperation(handle.get()); + + // The load may have been cancelled, the client may have been + // destroyed already. In such cases calling didFinishLoading is a + // bad idea. + if (d->m_cancelled || !client) + return; + client->didFinishLoading(handle.get()); } @@ -866,7 +880,7 @@ static bool startGio(ResourceHandle* handle, KURL url) // using GIO internally, and providing URIs instead of file paths url.removeFragmentIdentifier(); url.setQuery(String()); - url.setPort(0); + url.removePort(); #if !PLATFORM(WIN_OS) // we avoid the escaping for local files, because diff --git a/WebCore/platform/network/soup/ResourceRequest.h b/WebCore/platform/network/soup/ResourceRequest.h index 42b7baa..8270863 100644 --- a/WebCore/platform/network/soup/ResourceRequest.h +++ b/WebCore/platform/network/soup/ResourceRequest.h @@ -33,8 +33,8 @@ namespace WebCore { - struct ResourceRequest : ResourceRequestBase { - + class ResourceRequest : public ResourceRequestBase { + public: ResourceRequest(const String& url) : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) { @@ -66,7 +66,7 @@ namespace WebCore { void updateFromSoupMessage(SoupMessage* soupMessage); private: - friend struct ResourceRequestBase; + friend class ResourceRequestBase; void doUpdatePlatformRequest() {}; void doUpdateResourceRequest() {}; diff --git a/WebCore/platform/network/soup/ResourceResponse.h b/WebCore/platform/network/soup/ResourceResponse.h index 5fa31a0..ecd9f21 100644 --- a/WebCore/platform/network/soup/ResourceResponse.h +++ b/WebCore/platform/network/soup/ResourceResponse.h @@ -44,7 +44,14 @@ public: { } + ResourceResponse(SoupMessage* soupMessage) + : ResourceResponseBase() + { + updateFromSoupMessage(soupMessage); + } + SoupMessage* toSoupMessage() const; + void updateFromSoupMessage(SoupMessage* soupMessage); private: friend class ResourceResponseBase; diff --git a/WebCore/platform/network/soup/ResourceResponseSoup.cpp b/WebCore/platform/network/soup/ResourceResponseSoup.cpp index 293577f..caf0b31 100644 --- a/WebCore/platform/network/soup/ResourceResponseSoup.cpp +++ b/WebCore/platform/network/soup/ResourceResponseSoup.cpp @@ -22,6 +22,7 @@ #include "ResourceResponse.h" #include "CString.h" +#include "GOwnPtr.h" #include "PlatformString.h" using namespace std; @@ -49,4 +50,21 @@ SoupMessage* ResourceResponse::toSoupMessage() const return soupMessage; } +void ResourceResponse::updateFromSoupMessage(SoupMessage* soupMessage) +{ + SoupURI* soupURI = soup_message_get_uri(soupMessage); + GOwnPtr<gchar> uri(soup_uri_to_string(soupURI, FALSE)); + m_url = KURL(KURL(), String::fromUTF8(uri.get())); + + m_httpStatusCode = soupMessage->status_code; + + SoupMessageHeadersIter headersIter; + const char* headerName; + const char* headerValue; + + soup_message_headers_iter_init(&headersIter, soupMessage->response_headers); + while (soup_message_headers_iter_next(&headersIter, &headerName, &headerValue)) + m_httpHeaderFields.set(String::fromUTF8(headerName), String::fromUTF8(headerValue)); +} + } diff --git a/WebCore/platform/qt/ClipboardQt.cpp b/WebCore/platform/qt/ClipboardQt.cpp index 9d2c452..f9940a6 100644 --- a/WebCore/platform/qt/ClipboardQt.cpp +++ b/WebCore/platform/qt/ClipboardQt.cpp @@ -95,21 +95,7 @@ void ClipboardQt::clearData(const String& type) return; if (m_writableData) { -#if QT_VERSION >= 0x040400 m_writableData->removeFormat(type); -#else - const QString toClearType = type; - QMap<QString, QByteArray> formats; - foreach (QString format, m_writableData->formats()) { - if (format != toClearType) - formats[format] = m_writableData->data(format); - } - - m_writableData->clear(); - QMap<QString, QByteArray>::const_iterator it, end = formats.constEnd(); - for (it = formats.begin(); it != end; ++it) - m_writableData->setData(it.key(), it.value()); -#endif if (m_writableData->formats().isEmpty()) { if (isForDragging()) delete m_writableData; diff --git a/WebCore/platform/qt/CookieJarQt.cpp b/WebCore/platform/qt/CookieJarQt.cpp index a27a06e..b621e7e 100644 --- a/WebCore/platform/qt/CookieJarQt.cpp +++ b/WebCore/platform/qt/CookieJarQt.cpp @@ -33,19 +33,14 @@ #include "KURL.h" #include "PlatformString.h" -#if QT_VERSION >= 0x040400 #include "qwebpage.h" #include "qwebframe.h" #include "FrameLoaderClientQt.h" #include <QNetworkAccessManager> #include <QNetworkCookie> -#else -#include <qcookiejar.h> -#endif namespace WebCore { -#if QT_VERSION >= 0x040400 static QNetworkCookieJar *cookieJar(const Document *document) { if (!document) @@ -62,13 +57,11 @@ static QNetworkCookieJar *cookieJar(const Document *document) QNetworkCookieJar* jar = manager->cookieJar(); return jar; } -#endif void setCookies(Document* document, const KURL& url, const String& value) { QUrl u(url); QUrl p(document->firstPartyForCookies()); -#if QT_VERSION >= 0x040400 QNetworkCookieJar* jar = cookieJar(document); if (!jar) return; @@ -84,15 +77,11 @@ void setCookies(Document* document, const KURL& url, const String& value) } #endif jar->setCookiesFromUrl(cookies, u); -#else - QCookieJar::cookieJar()->setCookies(u, p, (QString)value); -#endif } String cookies(const Document* document, const KURL& url) { QUrl u(url); -#if QT_VERSION >= 0x040400 QNetworkCookieJar* jar = cookieJar(document); if (!jar) return String(); @@ -112,23 +101,12 @@ String cookies(const Document* document, const KURL& url) } return resultCookies.join(QLatin1String("; ")); -#else - QString cookies = QCookieJar::cookieJar()->cookies(u); - int idx = cookies.indexOf(QLatin1Char(';')); - if (idx > 0) - cookies = cookies.left(idx); - return cookies; -#endif } bool cookiesEnabled(const Document* document) { -#if QT_VERSION >= 0x040400 QNetworkCookieJar* jar = cookieJar(document); return (jar != 0); -#else - return QCookieJar::cookieJar()->isEnabled(); -#endif } bool getRawCookies(const Document*, const KURL&, Vector<Cookie>& rawCookies) diff --git a/WebCore/platform/qt/CursorQt.cpp b/WebCore/platform/qt/CursorQt.cpp index 3fc83f9..87f4fce 100644 --- a/WebCore/platform/qt/CursorQt.cpp +++ b/WebCore/platform/qt/CursorQt.cpp @@ -73,7 +73,7 @@ Cursor& Cursor::operator=(const Cursor& other) namespace { // FIXME: static deleter -class Cursors { +class Cursors : public Noncopyable { protected: Cursors() #ifndef QT_NO_CURSOR diff --git a/WebCore/platform/qt/Localizations.cpp b/WebCore/platform/qt/Localizations.cpp index ca3ca9d..1768502 100644 --- a/WebCore/platform/qt/Localizations.cpp +++ b/WebCore/platform/qt/Localizations.cpp @@ -30,6 +30,7 @@ #include "IntSize.h" #include "LocalizedStrings.h" +#include "NotImplemented.h" #include "PlatformString.h" #include <QCoreApplication> @@ -470,5 +471,47 @@ String localizedMediaTimeDescription(float time) } #endif // ENABLE(VIDEO) +String validationMessageValueMissingText() +{ + notImplemented(); + return String(); +} + +String validationMessageTypeMismatchText() +{ + notImplemented(); + return String(); +} + +String validationMessagePatternMismatchText() +{ + notImplemented(); + return String(); +} + +String validationMessageTooLongText() +{ + notImplemented(); + return String(); +} + +String validationMessageRangeUnderflowText() +{ + notImplemented(); + return String(); +} + +String validationMessageRangeOverflowText() +{ + notImplemented(); + return String(); +} + +String validationMessageStepMismatchText() +{ + notImplemented(); + return String(); +} + } // vim: ts=4 sw=4 et diff --git a/WebCore/platform/qt/PlatformKeyboardEventQt.cpp b/WebCore/platform/qt/PlatformKeyboardEventQt.cpp index 37ea681..f78c7d7 100644 --- a/WebCore/platform/qt/PlatformKeyboardEventQt.cpp +++ b/WebCore/platform/qt/PlatformKeyboardEventQt.cpp @@ -52,10 +52,8 @@ static String keyIdentifierForQtKeyCode(int keyCode) case Qt::Key_Return: case Qt::Key_Enter: return "Enter"; -#if QT_VERSION >= 0x040200 case Qt::Key_Execute: return "Execute"; -#endif case Qt::Key_F1: return "F1"; case Qt::Key_F2: @@ -290,10 +288,8 @@ static int windowsKeyCodeForKeyEvent(unsigned int keycode, bool isKeypad = false return VK_SELECT; // (29) SELECT key case Qt::Key_Print: return VK_PRINT; // (2A) PRINT key -#if QT_VERSION >= 0x040200 case Qt::Key_Execute: return VK_EXECUTE;// (2B) EXECUTE key -#endif //dunno on this //case Qt::Key_PrintScreen: // return VK_SNAPSHOT; // (2C) PRINT SCREEN key diff --git a/WebCore/platform/qt/QWebPageClient.h b/WebCore/platform/qt/QWebPageClient.h index 28ef724..b510736 100644 --- a/WebCore/platform/qt/QWebPageClient.h +++ b/WebCore/platform/qt/QWebPageClient.h @@ -26,13 +26,19 @@ #ifndef QWebPageClient_h #define QWebPageClient_h +#ifndef QT_NO_CURSOR +#include <QCursor> +#endif #include <QRect> class QWebPageClient { public: + virtual ~QWebPageClient() { } + virtual void scroll(int dx, int dy, const QRect&) = 0; virtual void update(const QRect&) = 0; virtual void setInputMethodEnabled(bool enable) = 0; + virtual bool inputMethodEnabled() const = 0; #if QT_VERSION >= 0x040600 virtual void setInputMethodHint(Qt::InputMethodHint hint, bool enable) = 0; #endif diff --git a/WebCore/platform/qt/RenderThemeQt.cpp b/WebCore/platform/qt/RenderThemeQt.cpp index b61d356..501a28b 100644 --- a/WebCore/platform/qt/RenderThemeQt.cpp +++ b/WebCore/platform/qt/RenderThemeQt.cpp @@ -45,6 +45,7 @@ #include "RenderBox.h" #include "RenderTheme.h" #include "UserAgentStyleSheets.h" +#include "QWebPageClient.h" #include "qwebpage.h" #include <QApplication> @@ -757,12 +758,13 @@ ControlPart RenderThemeQt::applyTheme(QStyleOption& option, RenderObject* o) con if (result == RadioPart || result == CheckboxPart) option.state |= (isChecked(o) ? QStyle::State_On : QStyle::State_Off); - // If the webview has a custom palette, use it + // If the owner widget has a custom palette, use it Page* page = o->document()->page(); if (page) { - QWidget* view = static_cast<ChromeClientQt*>(page->chrome()->client())->m_webPage->view(); - if (view) - option.palette = view->palette(); + ChromeClient* client = page->chrome()->client(); + QWebPageClient* pageClient = client->platformPageClient(); + if (pageClient) + option.palette = pageClient->palette(); } return result; diff --git a/WebCore/platform/qt/WheelEventQt.cpp b/WebCore/platform/qt/WheelEventQt.cpp index 9cc27ab..162a4f2 100644 --- a/WebCore/platform/qt/WheelEventQt.cpp +++ b/WebCore/platform/qt/WheelEventQt.cpp @@ -45,8 +45,10 @@ void PlatformWheelEvent::applyDelta(int delta, Qt::Orientation orientation) // Use the same single scroll step as QTextEdit // (in QTextEditPrivate::init [h,v]bar->setSingleStep) static const float cDefaultQtScrollStep = 20.f; +#ifndef QT_NO_WHEELEVENT m_deltaX *= QApplication::wheelScrollLines() * cDefaultQtScrollStep; m_deltaY *= QApplication::wheelScrollLines() * cDefaultQtScrollStep; +#endif } PlatformWheelEvent::PlatformWheelEvent(QGraphicsSceneWheelEvent* e) diff --git a/WebCore/platform/qt/WidgetQt.cpp b/WebCore/platform/qt/WidgetQt.cpp index e9c99a4..252bdb4 100644 --- a/WebCore/platform/qt/WidgetQt.cpp +++ b/WebCore/platform/qt/WidgetQt.cpp @@ -91,13 +91,17 @@ void Widget::setCursor(const Cursor& cursor) void Widget::show() { - if (platformWidget()) + setSelfVisible(true); + + if (isParentVisible() && platformWidget()) platformWidget()->show(); } void Widget::hide() { - if (platformWidget()) + setSelfVisible(false); + + if (isParentVisible() && platformWidget()) platformWidget()->hide(); } diff --git a/WebCore/platform/sql/chromium/SQLiteFileSystemChromium.cpp b/WebCore/platform/sql/chromium/SQLiteFileSystemChromium.cpp index 3cf961f..752c613 100644 --- a/WebCore/platform/sql/chromium/SQLiteFileSystemChromium.cpp +++ b/WebCore/platform/sql/chromium/SQLiteFileSystemChromium.cpp @@ -58,7 +58,8 @@ int SQLiteFileSystem::openDatabase(const String& fileName, sqlite3** database) // open databases using the default VFS // in renderers, it should be Chromium's VFS; in the browser process it should be SQLite's default VFS return sqlite3_open_v2(fileName.utf8().data(), database, - SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, 0); + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, + "chromium_vfs"); } String SQLiteFileSystem::getFileNameForNewDatabase( diff --git a/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp b/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp index 2960a5f..0050a43 100644 --- a/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp +++ b/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp @@ -42,8 +42,11 @@ using namespace WebCore; // Defined in Chromium's codebase in third_party/sqlite/src/os_unix.c extern "C" { -void initUnixFile(sqlite3_file* file); -int fillInUnixFile(sqlite3_vfs* vfs, int fd, int dirfd, sqlite3_file* file, const char* fileName, int noLock); +void chromium_sqlite3_initialize_unix_sqlite3_file(sqlite3_file* file); +int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* vfs, int fd, int dirfd, sqlite3_file* file, const char* fileName, int noLock); +int chromium_sqlite3_get_reusable_file_handle(sqlite3_file* file, const char* fileName, int flags, int* fd); +void chromium_sqlite3_update_reusable_file_handle(sqlite3_file* file, int fd, int flags); +void chromium_sqlite3_destroy_reusable_file_handle(sqlite3_file* file); } // Chromium's Posix implementation of SQLite VFS @@ -59,18 +62,28 @@ namespace { int chromiumOpen(sqlite3_vfs* vfs, const char* fileName, sqlite3_file* id, int desiredFlags, int* usedFlags) { - initUnixFile(id); + chromium_sqlite3_initialize_unix_sqlite3_file(id); + int fd = -1; int dirfd = -1; - int fd = ChromiumBridge::databaseOpenFile(fileName, desiredFlags, &dirfd); + int result = chromium_sqlite3_get_reusable_file_handle(id, fileName, desiredFlags, &fd); + if (result != SQLITE_OK) + return result; + if (fd < 0) { - if (desiredFlags & SQLITE_OPEN_READWRITE) { + fd = ChromiumBridge::databaseOpenFile(fileName, desiredFlags, &dirfd); + if ((fd < 0) && (desiredFlags & SQLITE_OPEN_READWRITE)) { int newFlags = (desiredFlags & ~(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)) | SQLITE_OPEN_READONLY; - return chromiumOpen(vfs, fileName, id, newFlags, usedFlags); - } else - return SQLITE_CANTOPEN; + fd = ChromiumBridge::databaseOpenFile(fileName, newFlags, &dirfd); + } + } + if (fd < 0) { + chromium_sqlite3_destroy_reusable_file_handle(id); + return SQLITE_CANTOPEN; } + if (usedFlags) *usedFlags = desiredFlags; + chromium_sqlite3_update_reusable_file_handle(id, fd, desiredFlags); fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); if (dirfd >= 0) @@ -79,7 +92,10 @@ int chromiumOpen(sqlite3_vfs* vfs, const char* fileName, // The mask 0x00007F00 gives us the 7 bits that determine the type of the file SQLite is trying to open. int fileType = desiredFlags & 0x00007F00; int noLock = (fileType != SQLITE_OPEN_MAIN_DB); - return fillInUnixFile(vfs, fd, dirfd, id, fileName, noLock); + result = chromium_sqlite3_fill_in_unix_sqlite3_file(vfs, fd, dirfd, id, fileName, noLock); + if (result != SQLITE_OK) + chromium_sqlite3_destroy_reusable_file_handle(id); + return result; } // Deletes the given file. @@ -184,7 +200,7 @@ void SQLiteFileSystem::registerSQLiteVFS() unix_vfs->xCurrentTime, unix_vfs->xGetLastError }; - sqlite3_vfs_register(&chromium_vfs, 1); + sqlite3_vfs_register(&chromium_vfs, 0); } } // namespace WebCore diff --git a/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumWin.cpp b/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumWin.cpp index 153793b..7b57db1 100644 --- a/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumWin.cpp +++ b/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumWin.cpp @@ -169,7 +169,7 @@ void SQLiteFileSystem::registerSQLiteVFS() win32_vfs->xCurrentTime, win32_vfs->xGetLastError }; - sqlite3_vfs_register(&chromium_vfs, 1); + sqlite3_vfs_register(&chromium_vfs, 0); } } // namespace WebCore diff --git a/WebCore/platform/text/AtomicString.h b/WebCore/platform/text/AtomicString.h index 8805f4c..47d07c5 100644 --- a/WebCore/platform/text/AtomicString.h +++ b/WebCore/platform/text/AtomicString.h @@ -24,6 +24,14 @@ #include "AtomicStringImpl.h" #include "PlatformString.h" +// Define 'NO_IMPLICIT_ATOMICSTRING' before including this header, +// to disallow (expensive) implicit String-->AtomicString conversions. +#ifdef NO_IMPLICIT_ATOMICSTRING +#define ATOMICSTRING_CONVERSION explicit +#else +#define ATOMICSTRING_CONVERSION +#endif + namespace WebCore { struct AtomicStringHash; @@ -40,9 +48,9 @@ public: AtomicString(const JSC::UString& s) : m_string(add(s)) { } AtomicString(const JSC::Identifier& s) : m_string(add(s)) { } #endif - AtomicString(StringImpl* imp) : m_string(add(imp)) { } + ATOMICSTRING_CONVERSION AtomicString(StringImpl* imp) : m_string(add(imp)) { } AtomicString(AtomicStringImpl* imp) : m_string(imp) { } - AtomicString(const String& s) : m_string(add(s.impl())) { } + ATOMICSTRING_CONVERSION AtomicString(const String& s) : m_string(add(s.impl())) { } // Hash table deleted values, which are only constructed and never copied or destroyed. AtomicString(WTF::HashTableDeletedValueType) : m_string(WTF::HashTableDeletedValue) { } @@ -96,7 +104,7 @@ public: static void remove(StringImpl*); -#if PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN)) +#if PLATFORM(CF) AtomicString(CFStringRef s) : m_string(add(String(s).impl())) { } CFStringRef createCFString() const { return m_string.createCFString(); } #endif diff --git a/WebCore/platform/text/AtomicStringImpl.h b/WebCore/platform/text/AtomicStringImpl.h index d905afc..ba1c72c 100644 --- a/WebCore/platform/text/AtomicStringImpl.h +++ b/WebCore/platform/text/AtomicStringImpl.h @@ -1,6 +1,4 @@ /* - * This file is part of the DOM implementation for KDE. - * * Copyright (C) 2006 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or diff --git a/WebCore/platform/text/BidiContext.cpp b/WebCore/platform/text/BidiContext.cpp index 546571e..59db7bd 100644 --- a/WebCore/platform/text/BidiContext.cpp +++ b/WebCore/platform/text/BidiContext.cpp @@ -30,7 +30,7 @@ using namespace WTF::Unicode; PassRefPtr<BidiContext> BidiContext::create(unsigned char level, Direction direction, bool override, BidiContext* parent) { - ASSERT(direction == level % 2 ? RightToLeft : LeftToRight); + ASSERT(direction == (level % 2 ? RightToLeft : LeftToRight)); if (parent) return adoptRef(new BidiContext(level, direction, override, parent)); diff --git a/WebCore/platform/text/PlatformString.h b/WebCore/platform/text/PlatformString.h index 8d19c17..247536a 100644 --- a/WebCore/platform/text/PlatformString.h +++ b/WebCore/platform/text/PlatformString.h @@ -41,7 +41,7 @@ #include <wtf/OwnPtr.h> #endif -#if PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN)) +#if PLATFORM(CF) typedef const struct __CFString * CFStringRef; #endif @@ -206,7 +206,7 @@ public: StringImpl* impl() const { return m_impl.get(); } -#if PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN)) +#if PLATFORM(CF) String(CFStringRef); CFStringRef createCFString() const; #endif @@ -286,6 +286,11 @@ inline bool equalIgnoringCase(const String& a, const String& b) { return equalIg inline bool equalIgnoringCase(const String& a, const char* b) { return equalIgnoringCase(a.impl(), b); } inline bool equalIgnoringCase(const char* a, const String& b) { return equalIgnoringCase(a, b.impl()); } +inline bool equalPossiblyIgnoringCase(const String& a, const String& b, bool ignoreCase) +{ + return ignoreCase ? equalIgnoringCase(a, b) : (a == b); +} + inline bool equalIgnoringNullity(const String& a, const String& b) { return equalIgnoringNullity(a.impl(), b.impl()); } inline bool operator!(const String& str) { return str.isNull(); } diff --git a/WebCore/platform/text/RegularExpression.h b/WebCore/platform/text/RegularExpression.h index 3254067..f1611e5 100644 --- a/WebCore/platform/text/RegularExpression.h +++ b/WebCore/platform/text/RegularExpression.h @@ -30,7 +30,7 @@ namespace WebCore { -class RegularExpression { +class RegularExpression : public FastAllocBase { public: RegularExpression(const String&, TextCaseSensitivity); ~RegularExpression(); diff --git a/WebCore/platform/text/String.cpp b/WebCore/platform/text/String.cpp index 44582a9..24659a4 100644 --- a/WebCore/platform/text/String.cpp +++ b/WebCore/platform/text/String.cpp @@ -81,6 +81,9 @@ String::String(const char* str, unsigned length) void String::append(const String& str) { + if (str.isEmpty()) + return; + // FIXME: This is extremely inefficient. So much so that we might want to take this // out of String's API. We can make it better by optimizing the case where exactly // one String is pointing at this StringImpl, but even then it's going to require a diff --git a/WebCore/platform/text/StringHash.h b/WebCore/platform/text/StringHash.h index fc6cb3c..21a478e 100644 --- a/WebCore/platform/text/StringHash.h +++ b/WebCore/platform/text/StringHash.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved + * Copyright (C) Research In Motion Limited 2009. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -29,6 +30,10 @@ namespace WebCore { + // The hash() functions on StringHash and CaseFoldingHash do not support + // null strings. get(), contains(), and add() on HashMap<String,..., StringHash> + // cause a null-pointer dereference when passed null strings. + // FIXME: We should really figure out a way to put the computeHash function that's // currently a member function of StringImpl into this file so we can be a little // closer to having all the nearly-identical hash functions in one place. diff --git a/WebCore/platform/text/StringImpl.h b/WebCore/platform/text/StringImpl.h index dac25b2..5155fa5 100644 --- a/WebCore/platform/text/StringImpl.h +++ b/WebCore/platform/text/StringImpl.h @@ -37,7 +37,7 @@ #include <runtime/UString.h> #endif -#if PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN)) +#if PLATFORM(CF) typedef const struct __CFString * CFStringRef; #endif @@ -168,7 +168,7 @@ public: WTF::Unicode::Direction defaultWritingDirection(); -#if PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN)) +#if PLATFORM(CF) CFStringRef createCFString(); #endif #ifdef __OBJC__ diff --git a/WebCore/platform/text/TextBoundariesICU.cpp b/WebCore/platform/text/TextBoundaries.cpp index b1e8ee2..2455f6d 100644 --- a/WebCore/platform/text/TextBoundariesICU.cpp +++ b/WebCore/platform/text/TextBoundaries.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2009 Dominik Röttsches <dominik.roettsches@access-company.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,39 +27,40 @@ #include "config.h" #include "TextBoundaries.h" -#include <unicode/ubrk.h> -#include <unicode/uchar.h> - #include "StringImpl.h" #include "TextBreakIterator.h" +#include <wtf/unicode/Unicode.h> + +using namespace WTF; +using namespace Unicode; namespace WebCore { int findNextWordFromIndex(const UChar* chars, int len, int position, bool forward) { - UBreakIterator* it = wordBreakIterator(chars, len); + TextBreakIterator* it = wordBreakIterator(chars, len); if (forward) { - position = ubrk_following(it, position); - while (position != UBRK_DONE) { + position = textBreakFollowing(it, position); + while (position != TextBreakDone) { // We stop searching when the character preceeding the break // is alphanumeric. - if (position < len && u_isalnum(chars[position - 1])) + if (position < len && isAlphanumeric(chars[position - 1])) return position; - position = ubrk_following(it, position); + position = textBreakFollowing(it, position); } return len; } else { - position = ubrk_preceding(it, position); - while (position != UBRK_DONE) { + position = textBreakPreceding(it, position); + while (position != TextBreakDone) { // We stop searching when the character following the break // is alphanumeric. - if (position > 0 && u_isalnum(chars[position])) + if (position > 0 && isAlphanumeric(chars[position])) return position; - position = ubrk_preceding(it, position); + position = textBreakPreceding(it, position); } return 0; @@ -67,11 +69,11 @@ int findNextWordFromIndex(const UChar* chars, int len, int position, bool forwar void findWordBoundary(const UChar* chars, int len, int position, int* start, int* end) { - UBreakIterator* it = wordBreakIterator(chars, len); - *end = ubrk_following(it, position); + TextBreakIterator* it = wordBreakIterator(chars, len); + *end = textBreakFollowing(it, position); if (*end < 0) - *end = ubrk_last(it); - *start = ubrk_previous(it); + *end = textBreakLast(it); + *start = textBreakPrevious(it); } } // namespace WebCore diff --git a/WebCore/platform/text/TextBreakIterator.h b/WebCore/platform/text/TextBreakIterator.h index 7b3b963..17cf5f0 100644 --- a/WebCore/platform/text/TextBreakIterator.h +++ b/WebCore/platform/text/TextBreakIterator.h @@ -47,7 +47,9 @@ namespace WebCore { TextBreakIterator* sentenceBreakIterator(const UChar*, int length); int textBreakFirst(TextBreakIterator*); + int textBreakLast(TextBreakIterator*); int textBreakNext(TextBreakIterator*); + int textBreakPrevious(TextBreakIterator*); int textBreakCurrent(TextBreakIterator*); int textBreakPreceding(TextBreakIterator*, int); int textBreakFollowing(TextBreakIterator*, int); diff --git a/WebCore/platform/text/TextBreakIteratorICU.cpp b/WebCore/platform/text/TextBreakIteratorICU.cpp index c922fbc..44423c0 100644 --- a/WebCore/platform/text/TextBreakIteratorICU.cpp +++ b/WebCore/platform/text/TextBreakIteratorICU.cpp @@ -90,11 +90,21 @@ int textBreakFirst(TextBreakIterator* bi) return ubrk_first(bi); } +int textBreakLast(TextBreakIterator* bi) +{ + return ubrk_last(bi); +} + int textBreakNext(TextBreakIterator* bi) { return ubrk_next(bi); } +int textBreakPrevious(TextBreakIterator* bi) +{ + return ubrk_previous(bi); +} + int textBreakPreceding(TextBreakIterator* bi, int pos) { return ubrk_preceding(bi, pos); diff --git a/WebCore/platform/text/TextEncoding.cpp b/WebCore/platform/text/TextEncoding.cpp index c5c8cfd..ec9a8b0 100644 --- a/WebCore/platform/text/TextEncoding.cpp +++ b/WebCore/platform/text/TextEncoding.cpp @@ -32,10 +32,13 @@ #include "PlatformString.h" #include "TextCodec.h" #include "TextEncodingRegistry.h" -#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) +#if USE(ICU_UNICODE) #include <unicode/unorm.h> #elif USE(QT4_UNICODE) #include <QString> +#elif USE(GLIB_UNICODE) +#include <glib.h> +#include <wtf/gtk/GOwnPtr.h> #endif #include <wtf/HashSet.h> #include <wtf/OwnPtr.h> @@ -84,7 +87,7 @@ CString TextEncoding::encode(const UChar* characters, size_t length, Unencodable if (!length) return ""; -#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) +#if USE(ICU_UNICODE) // FIXME: What's the right place to do normalization? // It's a little strange to do it inside the encode function. // Perhaps normalization should be an explicit step done before calling encode. @@ -114,6 +117,18 @@ CString TextEncoding::encode(const UChar* characters, size_t length, Unencodable QString str(reinterpret_cast<const QChar*>(characters), length); str = str.normalized(QString::NormalizationForm_C); return newTextCodec(*this)->encode(reinterpret_cast<const UChar *>(str.utf16()), str.length(), handling); +#elif USE(GLIB_UNICODE) + GOwnPtr<char> UTF8Source; + UTF8Source.set(g_utf16_to_utf8(characters, length, 0, 0, 0)); + + GOwnPtr<char> UTF8Normalized; + UTF8Normalized.set(g_utf8_normalize(UTF8Source.get(), -1, G_NORMALIZE_NFC)); + + long UTF16Length; + GOwnPtr<UChar> UTF16Normalized; + UTF16Normalized.set(g_utf8_to_utf16(UTF8Normalized.get(), -1, 0, &UTF16Length, 0)); + + return newTextCodec(*this)->encode(UTF16Normalized.get(), UTF16Length, handling); #elif PLATFORM(WINCE) // normalization will be done by Windows CE API OwnPtr<TextCodec> textCodec = newTextCodec(*this); diff --git a/WebCore/platform/text/TextEncodingRegistry.cpp b/WebCore/platform/text/TextEncodingRegistry.cpp index d3e2965..a4be520 100644 --- a/WebCore/platform/text/TextEncodingRegistry.cpp +++ b/WebCore/platform/text/TextEncodingRegistry.cpp @@ -39,7 +39,7 @@ #include <wtf/StringExtras.h> #include <wtf/Threading.h> -#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) +#if USE(ICU_UNICODE) #include "TextCodecICU.h" #endif #if PLATFORM(MAC) @@ -48,6 +48,9 @@ #if PLATFORM(QT) #include "qt/TextCodecQt.h" #endif +#if USE(GLIB_UNICODE) +#include "gtk/TextCodecGtk.h" +#endif #if PLATFORM(WINCE) && !PLATFORM(QT) #include "TextCodecWince.h" #endif @@ -217,11 +220,16 @@ static void buildBaseTextCodecMaps() TextCodecUserDefined::registerEncodingNames(addToTextEncodingNameMap); TextCodecUserDefined::registerCodecs(addToTextCodecMap); -#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) +#if USE(ICU_UNICODE) TextCodecICU::registerBaseEncodingNames(addToTextEncodingNameMap); TextCodecICU::registerBaseCodecs(addToTextCodecMap); #endif +#if USE(GLIB_UNICODE) + TextCodecGtk::registerBaseEncodingNames(addToTextEncodingNameMap); + TextCodecGtk::registerBaseCodecs(addToTextCodecMap); +#endif + #if PLATFORM(WINCE) && !PLATFORM(QT) TextCodecWince::registerBaseEncodingNames(addToTextEncodingNameMap); TextCodecWince::registerBaseCodecs(addToTextCodecMap); @@ -230,7 +238,7 @@ static void buildBaseTextCodecMaps() static void extendTextCodecMaps() { -#if USE(ICU_UNICODE) || USE(GLIB_ICU_UNICODE_HYBRID) +#if USE(ICU_UNICODE) TextCodecICU::registerExtendedEncodingNames(addToTextEncodingNameMap); TextCodecICU::registerExtendedCodecs(addToTextCodecMap); #endif @@ -245,6 +253,11 @@ static void extendTextCodecMaps() TextCodecMac::registerCodecs(addToTextCodecMap); #endif +#if USE(GLIB_UNICODE) + TextCodecGtk::registerExtendedEncodingNames(addToTextEncodingNameMap); + TextCodecGtk::registerExtendedCodecs(addToTextCodecMap); +#endif + #if PLATFORM(WINCE) && !PLATFORM(QT) TextCodecWince::registerExtendedEncodingNames(addToTextEncodingNameMap); TextCodecWince::registerExtendedCodecs(addToTextCodecMap); diff --git a/WebCore/platform/text/cf/StringCF.cpp b/WebCore/platform/text/cf/StringCF.cpp index b770d0e..97691e5 100644 --- a/WebCore/platform/text/cf/StringCF.cpp +++ b/WebCore/platform/text/cf/StringCF.cpp @@ -21,7 +21,7 @@ #include "config.h" #include "PlatformString.h" -#if PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN)) +#if PLATFORM(CF) #include <CoreFoundation/CoreFoundation.h> @@ -52,4 +52,4 @@ CFStringRef String::createCFString() const } -#endif // PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN)) +#endif // PLATFORM(CF) diff --git a/WebCore/platform/text/cf/StringImplCF.cpp b/WebCore/platform/text/cf/StringImplCF.cpp index 8a2ae79..aff45b3 100644 --- a/WebCore/platform/text/cf/StringImplCF.cpp +++ b/WebCore/platform/text/cf/StringImplCF.cpp @@ -21,7 +21,7 @@ #include "config.h" #include "StringImpl.h" -#if PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN)) +#if PLATFORM(CF) #include <CoreFoundation/CoreFoundation.h> #include <wtf/MainThread.h> @@ -159,4 +159,4 @@ CFStringRef StringImpl::createCFString() } -#endif // PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN)) +#endif // PLATFORM(CF) diff --git a/WebCore/platform/text/gtk/TextBreakIteratorGtk.cpp b/WebCore/platform/text/gtk/TextBreakIteratorGtk.cpp new file mode 100644 index 0000000..7a10b41 --- /dev/null +++ b/WebCore/platform/text/gtk/TextBreakIteratorGtk.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2006 Lars Knoll <lars@trolltech.com> + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008 Jürg Billeter <j@bitron.ch> + * Copyright (C) 2008 Dominik Röttsches <dominik.roettsches@access-company.com> + * + * 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 "TextBreakIterator.h" + +#include <pango/pango.h> +#include <wtf/gtk/GOwnPtr.h> + +namespace WebCore { + +enum UBreakIteratorType { + UBRK_CHARACTER, + UBRK_WORD, + UBRK_LINE, + UBRK_SENTENCE +}; + +class TextBreakIterator { +public: + UBreakIteratorType m_type; + int m_length; + PangoLogAttr* m_logAttrs; + int m_index; +}; + +static TextBreakIterator* setUpIterator(bool& createdIterator, TextBreakIterator*& iterator, + UBreakIteratorType type, const UChar* string, int length) +{ + if (!string) + return 0; + + if (!createdIterator) { + iterator = new TextBreakIterator(); + createdIterator = true; + } + if (!iterator) + return 0; + + long utf8len; + GOwnPtr<char> utf8; + utf8.set(g_utf16_to_utf8(string, length, 0, &utf8len, 0)); + + // FIXME: assumes no surrogate pairs + + iterator->m_type = type; + iterator->m_length = length; + if (createdIterator) + g_free(iterator->m_logAttrs); + iterator->m_logAttrs = g_new0(PangoLogAttr, length + 1); + iterator->m_index = -1; + pango_get_log_attrs(utf8.get(), utf8len, -1, 0, iterator->m_logAttrs, length + 1); + + return iterator; +} + +TextBreakIterator* characterBreakIterator(const UChar* string, int length) +{ + static bool createdCharacterBreakIterator = false; + static TextBreakIterator* staticCharacterBreakIterator; + return setUpIterator(createdCharacterBreakIterator, staticCharacterBreakIterator, UBRK_CHARACTER, string, length); +} + +TextBreakIterator* cursorMovementIterator(const UChar* string, int length) +{ + // FIXME: This needs closer inspection to achieve behaviour identical to the ICU version. + return characterBreakIterator(string, length); +} + +TextBreakIterator* wordBreakIterator(const UChar* string, int length) +{ + static bool createdWordBreakIterator = false; + static TextBreakIterator* staticWordBreakIterator; + return setUpIterator(createdWordBreakIterator, staticWordBreakIterator, UBRK_WORD, string, length); +} + +TextBreakIterator* lineBreakIterator(const UChar* string, int length) +{ + static bool createdLineBreakIterator = false; + static TextBreakIterator* staticLineBreakIterator; + return setUpIterator(createdLineBreakIterator, staticLineBreakIterator, UBRK_LINE, string, length); +} + +TextBreakIterator* sentenceBreakIterator(const UChar* string, int length) +{ + static bool createdSentenceBreakIterator = false; + static TextBreakIterator* staticSentenceBreakIterator; + return setUpIterator(createdSentenceBreakIterator, staticSentenceBreakIterator, UBRK_SENTENCE, string, length); +} + +int textBreakFirst(TextBreakIterator* bi) +{ + // see textBreakLast + + int firstCursorPosition = -1; + int pos = 0; + while (pos <= bi->m_length && (firstCursorPosition < 0)) { + if (bi->m_logAttrs[pos].is_cursor_position) + firstCursorPosition = pos; + } + bi->m_index = firstCursorPosition; + return firstCursorPosition; +} + +int textBreakLast(TextBreakIterator* bi) +{ + // TextBreakLast is not meant to find just any break according to bi->m_type + // but really the one near the last character. + // (cmp ICU documentation for ubrk_first and ubrk_last) + // From ICU docs for ubrk_last: + // "Determine the index immediately beyond the last character in the text being scanned." + + // So we should advance or traverse back based on bi->m_logAttrs cursor positions. + // If last character position in the original string is a whitespace, + // traverse to the left until the first non-white character position is found + // and return the position of the first white-space char after this one. + // Otherwise return m_length, as "the first character beyond the last" is outside our string. + + bool whiteSpaceAtTheEnd = true; + int nextWhiteSpacePos = bi->m_length; + + int pos = bi->m_length; + while (pos >= 0 && whiteSpaceAtTheEnd) { + if (bi->m_logAttrs[pos].is_cursor_position) { + if (whiteSpaceAtTheEnd = bi->m_logAttrs[pos].is_white) + nextWhiteSpacePos = pos; + } + pos--; + } + bi->m_index = nextWhiteSpacePos; + return nextWhiteSpacePos; +} + +int textBreakNext(TextBreakIterator* bi) +{ + for (int i = bi->m_index + 1; i <= bi->m_length; i++) { + + // FIXME: UBRK_WORD case: Single multibyte characters (i.e. white space around them), such as the euro symbol €, + // are not marked as word_start & word_end as opposed to the way ICU does it. + // This leads to - for example - different word selection behaviour when right clicking. + + if ((bi->m_type == UBRK_LINE && bi->m_logAttrs[i].is_line_break) + || (bi->m_type == UBRK_WORD && (bi->m_logAttrs[i].is_word_start || bi->m_logAttrs[i].is_word_end)) + || (bi->m_type == UBRK_CHARACTER && bi->m_logAttrs[i].is_cursor_position) + || (bi->m_type == UBRK_SENTENCE && (bi->m_logAttrs[i].is_sentence_start || bi->m_logAttrs[i].is_sentence_end)) ) { + bi->m_index = i; + return i; + } + } + return TextBreakDone; +} + +int textBreakPrevious(TextBreakIterator* bi) +{ + for (int i = bi->m_index - 1; i >= 0; i--) { + if ((bi->m_type == UBRK_LINE && bi->m_logAttrs[i].is_line_break) + || (bi->m_type == UBRK_WORD && (bi->m_logAttrs[i].is_word_start || bi->m_logAttrs[i].is_word_end)) + || (bi->m_type == UBRK_CHARACTER && bi->m_logAttrs[i].is_cursor_position) + || (bi->m_type == UBRK_SENTENCE && (bi->m_logAttrs[i].is_sentence_start || bi->m_logAttrs[i].is_sentence_end)) ) { + bi->m_index = i; + return i; + } + } + return textBreakFirst(bi); +} + +int textBreakPreceding(TextBreakIterator* bi, int pos) +{ + bi->m_index = pos; + return textBreakPrevious(bi); +} + +int textBreakFollowing(TextBreakIterator* bi, int pos) +{ + if (pos < 0) + pos = -1; + bi->m_index = pos; + return textBreakNext(bi); +} + +int textBreakCurrent(TextBreakIterator* bi) +{ + return bi->m_index; +} + +bool isTextBreak(TextBreakIterator* bi, int pos) +{ + if (bi->m_index < 0) + return false; + + return ((bi->m_type == UBRK_LINE && bi->m_logAttrs[bi->m_index].is_line_break) + || (bi->m_type == UBRK_WORD && bi->m_logAttrs[bi->m_index].is_word_end) + || (bi->m_type == UBRK_CHARACTER && bi->m_logAttrs[bi->m_index].is_char_break) + || (bi->m_type == UBRK_SENTENCE && bi->m_logAttrs[bi->m_index].is_sentence_end) ); +} + +} diff --git a/WebCore/platform/text/gtk/TextCodecGtk.cpp b/WebCore/platform/text/gtk/TextCodecGtk.cpp new file mode 100644 index 0000000..31da3b7 --- /dev/null +++ b/WebCore/platform/text/gtk/TextCodecGtk.cpp @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2004, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com> + * Copyright (C) 2008 Jürg Billeter <j@bitron.ch> + * Copyright (C) 2009 Dominik Röttsches <dominik.roettsches@access-company.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" +#include "TextCodecGtk.h" + +#include "CString.h" +#include "PlatformString.h" +#include <wtf/Assertions.h> +#include <wtf/HashMap.h> +#include <wtf/gtk/GOwnPtr.h> +#include "Logging.h" + +using std::min; + +namespace WebCore { + +// TextCodec's appendOmittingBOM() is gone (http://trac.webkit.org/changeset/33380). +// That's why we need to avoid generating extra BOM's for the conversion result. +// This can be achieved by specifying the UTF-16 codecs' endianness explicitly when initializing GLib. + +#if (G_BYTE_ORDER == G_BIG_ENDIAN) + const gchar* WebCore::TextCodecGtk::m_internalEncodingName = "UTF-16BE"; +#else + const gchar* WebCore::TextCodecGtk::m_internalEncodingName = "UTF-16LE"; +#endif + + +// We're specifying the list of text codecs and their aliases here. +// For each codec the first entry is the canonical name, remaining ones are used as aliases. +// Each alias list must be terminated by a 0. + +// Unicode +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_UTF_8 = { "UTF-8", 0 }; + +// Western +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_ISO_8859_1 = { "ISO-8859-1", "CP819", "IBM819", "ISO-IR-100", "ISO8859-1", "ISO_8859-1", "ISO_8859-1:1987", "L1", "LATIN1", "CSISOLATIN1", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_MACROMAN = { "MACROMAN", "MAC", "MACINTOSH", "CSMACINTOSH", 0 }; + +// Japanese +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_SHIFT_JIS = { "Shift_JIS", "MS_KANJI", "SHIFT-JIS", "SJIS", "CSSHIFTJIS", 0 }; + TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_EUC_JP = { "EUC-JP", "EUC_JP", "EUCJP", "EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE", "CSEUCPKDFMTJAPANESE", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_ISO_2022_JP = { "ISO-2022-JP", 0 }; + +// Traditional Chinese +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_BIG5 = { "BIG5", "BIG-5", "BIG-FIVE", "BIG5", "BIGFIVE", "CN-BIG5", "CSBIG5", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_BIG5_HKSCS = { "BIG5-HKSCS", "BIG5-HKSCS:2004", "BIG5HKSCS", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_CP950 = { "CP950", 0 }; + +// Korean +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_ISO_2022_KR = { "ISO-2022-KR", "CSISO2022KR", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_CP949 = { "CP949", "UHC", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_EUC_KR = { "EUC-KR", "CSEUCKR", 0 }; + +// Arabic +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_ISO_8859_6 = { "ISO-8859-6", "ARABIC", "ASMO-708", "ECMA-114", "ISO-IR-127", "ISO8859-6", "ISO_8859-6", "ISO_8859-6:1987", "CSISOLATINARABIC", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_CP1256 = { "windows-1256", "CP1256", "MS-ARAB", 0 }; // rearranged, windows-1256 now declared the canonical name and put to lowercase to fix /fast/encoding/ahram-org-eg.html test case + +// Hebrew +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_ISO_8859_8 = { "ISO-8859-8", "HEBREW", "ISO-8859-8", "ISO-IR-138", "ISO8859-8", "ISO_8859-8", "ISO_8859-8:1988", "CSISOLATINHEBREW", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_CP1255 = { "windows-1255", "CP1255", "MS-HEBR", 0 }; // rearranged, moved windows-1255 as canonical and lowercased, fixing /fast/encoding/meta-charset.html + +// Greek +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_ISO_8859_7 = { "ISO-8859-7", "ECMA-118", "ELOT_928", "GREEK", "GREEK8", "ISO-IR-126", "ISO8859-7", "ISO_8859-7", "ISO_8859-7:1987", "ISO_8859-7:2003", "CSI", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_CP869 = { "CP869", "869", "CP-GR", "IBM869", "CSIBM869", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_WINDOWS_1253 = { "WINDOWS-1253", 0 }; + +// Cyrillic +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_ISO_8859_5 = { "ISO-8859-5", "CYRILLIC", "ISO-IR-144", "ISO8859-5", "ISO_8859-5", "ISO_8859-5:1988", "CSISOLATINCYRILLIC", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_KOI8_R = { "KOI8-R", "CSKOI8R", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_CP866 = { "CP866", "866", "IBM866", "CSIBM866", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_KOI8_U = { "KOI8-U", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_WINDOWS_1251 = { "windows-1251", "CP1251", 0 }; // CP1251 added to pass /fast/encoding/charset-cp1251.html +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_MACCYRILLIC = { "mac-cyrillic", "MACCYRILLIC", "x-mac-cyrillic", 0 }; + +// Thai +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_CP874 = { "CP874", "WINDOWS-874", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_TIS_620 = { "TIS-620", 0 }; + +// Simplified Chinese +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_GBK = { "GBK", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_HZ = { "HZ", "HZ-GB-2312", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_GB18030 = { "GB18030", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_EUC_CN = { "EUC-CN", "EUCCN", "GB2312", "CN-GB", "CSGB2312", "EUC_CN", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_2312_80 = { "GB_2312-80", "CHINESE", "csISO58GB231280", "GB2312.1980-0", "ISO-IR-58" }; + +// Central European +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_ISO_8859_2 = { "ISO-8859-2", "ISO-IR-101", "ISO8859-2", "ISO_8859-2", "ISO_8859-2:1987", "L2", "LATIN2", "CSISOLATIN2", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_CP1250 = { "CP1250", "MS-EE", "WINDOWS-1250", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_MACCENTRALEUROPE = { "MAC-CENTRALEUROPE", 0 }; + +// Vietnamese +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_CP1258 = { "CP1258", "WINDOWS-1258", 0 }; + +// Turkish +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_CP1254 = { "CP1254", "MS-TURK", "WINDOWS-1254", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_ISO_8859_9 = { "ISO-8859-9", "ISO-IR-148", "ISO8859-9", "ISO_8859-9", "ISO_8859-9:1989", "L5", "LATIN5", "CSISOLATIN5", 0 }; + +// Baltic +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_CP1257 = { "CP1257", "WINBALTRIM", "WINDOWS-1257", 0 }; +TextCodecGtk::codecAliasList TextCodecGtk::m_codecAliases_ISO_8859_4 = { "ISO-8859-4", "ISO-IR-110", "ISO8859-4", "ISO_8859-4", "ISO_8859-4:1988", "L4", "LATIN4", "CSISOLATIN4", 0 }; + +gconstpointer const TextCodecGtk::m_iconvBaseCodecList[] = { + // Unicode + &m_codecAliases_UTF_8, + + // Western + &m_codecAliases_ISO_8859_1 +}; + +gconstpointer const TextCodecGtk::m_iconvExtendedCodecList[] = +{ + // Western + &m_codecAliases_MACROMAN, + + // Japanese + &m_codecAliases_SHIFT_JIS, + &m_codecAliases_EUC_JP, + &m_codecAliases_ISO_2022_JP, + + // Simplified Chinese + &m_codecAliases_BIG5, + &m_codecAliases_BIG5_HKSCS, + &m_codecAliases_CP950, + + // Korean + &m_codecAliases_ISO_2022_KR, + &m_codecAliases_CP949, + &m_codecAliases_EUC_KR, + + // Arabic + &m_codecAliases_ISO_8859_6, + &m_codecAliases_CP1256, + + // Hebrew + &m_codecAliases_ISO_8859_8, + &m_codecAliases_CP1255, + + // Greek + &m_codecAliases_ISO_8859_7, + &m_codecAliases_CP869, + &m_codecAliases_WINDOWS_1253, + + // Cyrillic + &m_codecAliases_ISO_8859_5, + &m_codecAliases_KOI8_R, + &m_codecAliases_CP866, + &m_codecAliases_KOI8_U, + &m_codecAliases_WINDOWS_1251, + &m_codecAliases_MACCYRILLIC, + + // Thai + &m_codecAliases_CP874, + &m_codecAliases_TIS_620, + + // Traditional Chinese + &m_codecAliases_GBK, + &m_codecAliases_HZ, + &m_codecAliases_GB18030, + &m_codecAliases_EUC_CN, + &m_codecAliases_2312_80, + + // Central European + &m_codecAliases_ISO_8859_2, + &m_codecAliases_CP1250, + &m_codecAliases_MACCENTRALEUROPE, + + // Vietnamese + &m_codecAliases_CP1258, + + // Turkish + &m_codecAliases_CP1254, + &m_codecAliases_ISO_8859_9, + + // Baltic + &m_codecAliases_CP1257, + &m_codecAliases_ISO_8859_4 +}; + + +const size_t ConversionBufferSize = 16384; + + +static PassOwnPtr<TextCodec> newTextCodecGtk(const TextEncoding& encoding, const void*) +{ + return new TextCodecGtk(encoding); +} + +gboolean TextCodecGtk::isEncodingAvailable(const gchar* encName) +{ + GIConv tester; + // test decoding + tester = g_iconv_open(m_internalEncodingName, encName); + if (tester == reinterpret_cast<GIConv>(-1)) { + return false; + } else { + g_iconv_close(tester); + // test encoding + tester = g_iconv_open(encName, m_internalEncodingName); + if (tester == reinterpret_cast<GIConv>(-1)) { + return false; + } else { + g_iconv_close(tester); + return true; + } + } +} + +void TextCodecGtk::registerEncodingNames(EncodingNameRegistrar registrar, bool extended) +{ + const void* const* encodingList; + unsigned int listLength = 0; + if (extended) { + encodingList = m_iconvExtendedCodecList; + listLength = sizeof(m_iconvExtendedCodecList)/sizeof(gpointer); + } else { + encodingList = m_iconvBaseCodecList; + listLength = sizeof(m_iconvBaseCodecList)/sizeof(gpointer); + } + + for (unsigned int i = 0; i < listLength; ++i) { + codecAliasList *codecAliases = static_cast<codecAliasList*>(encodingList[i]); + + // Our convention is, the first entry in codecAliases is the canonical name, + // see above in the list of declarations. + // Probe GLib for this one first. If it's not available, we skip the whole group of aliases. + + int codecCount = 0; + const char *canonicalName; + canonicalName = (*codecAliases)[codecCount]; + + if(!isEncodingAvailable(canonicalName)) { + LOG(TextConversion, "Canonical encoding %s not available, skipping.", canonicalName); + continue; + } + registrar(canonicalName, canonicalName); + + const char *currentAlias; + while ((currentAlias = (*codecAliases)[++codecCount])) { + if (isEncodingAvailable(currentAlias)) { + LOG(TextConversion, "Registering encoding name alias %s to canonical %s", currentAlias, canonicalName); + registrar(currentAlias, canonicalName); + } + } + + } +} + +void TextCodecGtk::registerCodecs(TextCodecRegistrar registrar, bool extended) +{ + const void* const* encodingList; + unsigned int listLength = 0; + if (extended) { + encodingList = m_iconvExtendedCodecList; + listLength = sizeof(m_iconvExtendedCodecList)/sizeof(gpointer); + } else { + encodingList = m_iconvBaseCodecList; + listLength = sizeof(m_iconvBaseCodecList)/sizeof(gpointer); + } + + for (unsigned int i = 0; i < listLength; ++i) { + codecAliasList *codecAliases = static_cast<codecAliasList*>(encodingList[i]); + // by convention, the first "alias" should be the canonical name, see the definition of the alias lists + const gchar *codecName = (*codecAliases)[0]; + if (isEncodingAvailable(codecName)) + registrar(codecName, newTextCodecGtk, 0); + } +} + +void TextCodecGtk::registerBaseEncodingNames(EncodingNameRegistrar registrar) +{ + registerEncodingNames(registrar, false); +} + +void TextCodecGtk::registerBaseCodecs(TextCodecRegistrar registrar) +{ + registerCodecs(registrar, false); +} + +void TextCodecGtk::registerExtendedEncodingNames(EncodingNameRegistrar registrar) +{ + registerEncodingNames(registrar, true); +} + +void TextCodecGtk::registerExtendedCodecs(TextCodecRegistrar registrar) +{ + registerCodecs(registrar, true); +} + +TextCodecGtk::TextCodecGtk(const TextEncoding& encoding) + : m_encoding(encoding) + , m_numBufferedBytes(0) + , m_iconvDecoder(reinterpret_cast<GIConv>(-1)) + , m_iconvEncoder(reinterpret_cast<GIConv>(-1)) +{ +} + +TextCodecGtk::~TextCodecGtk() +{ + if (m_iconvDecoder != reinterpret_cast<GIConv>(-1)) { + g_iconv_close(m_iconvDecoder); + m_iconvDecoder = reinterpret_cast<GIConv>(-1); + } + if (m_iconvEncoder != reinterpret_cast<GIConv>(-1)) { + g_iconv_close(m_iconvEncoder); + m_iconvEncoder = reinterpret_cast<GIConv>(-1); + } +} + +void TextCodecGtk::createIConvDecoder() const +{ + ASSERT(m_iconvDecoder == reinterpret_cast<GIConv>(-1)); + + m_iconvDecoder = g_iconv_open(m_internalEncodingName, m_encoding.name()); +} + +void TextCodecGtk::createIConvEncoder() const +{ + ASSERT(m_iconvDecoder == reinterpret_cast<GIConv>(-1)); + + m_iconvEncoder = g_iconv_open(m_encoding.name(), m_internalEncodingName); +} + +String TextCodecGtk::decode(const char* bytes, size_t length, bool flush, bool stopOnError, bool& sawError) +{ + // Get a converter for the passed-in encoding. + if (m_iconvDecoder == reinterpret_cast<GIConv>(-1)) { + createIConvDecoder(); + ASSERT(m_iconvDecoder != reinterpret_cast<GIConv>(-1)); + if (m_iconvDecoder == reinterpret_cast<GIConv>(-1)) { + LOG_ERROR("Error creating IConv encoder even though encoding was in table."); + return String(); + } + } + + size_t countWritten, countRead, conversionLength; + const char* conversionBytes; + char* prefixedBytes = 0; + + if (m_numBufferedBytes) { + conversionLength = length + m_numBufferedBytes; + prefixedBytes = static_cast<char*>(fastMalloc(conversionLength)); + memcpy(prefixedBytes, m_bufferedBytes, m_numBufferedBytes); + memcpy(prefixedBytes + m_numBufferedBytes, bytes, length); + + conversionBytes = prefixedBytes; + + // all buffered bytes are consumed now + m_numBufferedBytes = 0; + } else { + // no previously buffered partial data, + // just convert the data that was passed in + conversionBytes = bytes; + conversionLength = length; + } + + GOwnPtr<GError> err; + GOwnPtr<UChar> buffer; + + buffer.outPtr() = reinterpret_cast<UChar*>(g_convert_with_iconv(conversionBytes, conversionLength, m_iconvDecoder, &countRead, &countWritten, &err.outPtr())); + + + if (err) { + LOG_ERROR("GIConv conversion error, Code %d: \"%s\"", err->code, err->message); + m_numBufferedBytes = 0; // reset state for subsequent calls to decode + fastFree(prefixedBytes); + sawError = true; + return String(); + } + + // Partial input at the end of the string may not result in an error being raised. + // From the gnome library documentation on g_convert_with_iconv: + // "Even if the conversion was successful, this may be less than len if there were partial characters at the end of the input." + // That's why we need to compare conversionLength against countRead + + m_numBufferedBytes = conversionLength - countRead; + if (m_numBufferedBytes > 0) { + if (flush) { + LOG_ERROR("Partial bytes at end of input while flush requested."); + m_numBufferedBytes = 0; // reset state for subsequent calls to decode + fastFree(prefixedBytes); + sawError = true; + return String(); + } + memcpy(m_bufferedBytes, conversionBytes + countRead, m_numBufferedBytes); + } + + fastFree(prefixedBytes); + + Vector<UChar> result; + + result.append(buffer.get(), countWritten / sizeof(UChar)); + + return String::adopt(result); +} + +CString TextCodecGtk::encode(const UChar* characters, size_t length, UnencodableHandling handling) +{ + if (!length) + return ""; + + if (m_iconvEncoder == reinterpret_cast<GIConv>(-1)) + createIConvEncoder(); + if (m_iconvEncoder == reinterpret_cast<GIConv>(-1)) + return CString(); + + size_t count; + + GOwnPtr<GError> err; + GOwnPtr<char> buffer; + + buffer.outPtr() = g_convert_with_iconv(reinterpret_cast<const char*>(characters), length * sizeof(UChar), m_iconvEncoder, 0, &count, &err.outPtr()); + if (err) { + LOG_ERROR("GIConv conversion error, Code %d: \"%s\"", err->code, err->message); + return CString(); + } + + return CString(buffer.get(), count); +} + +} // namespace WebCore diff --git a/WebCore/platform/text/gtk/TextCodecGtk.h b/WebCore/platform/text/gtk/TextCodecGtk.h new file mode 100644 index 0000000..a8af752 --- /dev/null +++ b/WebCore/platform/text/gtk/TextCodecGtk.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com> + * Copyright (C) 2008 Jürg Billeter <j@bitron.ch> + * Copyright (C) 2009 Dominik Röttsches <dominik.roettsches@access-company.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. + */ + +#ifndef TextCodecGTK_h +#define TextCodecGTK_h + +#include <glib.h> +#include "TextCodec.h" +#include "TextEncoding.h" + +namespace WebCore { + + class TextCodecGtk : public TextCodec { + public: + static void registerBaseEncodingNames(EncodingNameRegistrar); + static void registerBaseCodecs(TextCodecRegistrar); + + static void registerExtendedEncodingNames(EncodingNameRegistrar); + static void registerExtendedCodecs(TextCodecRegistrar); + + TextCodecGtk(const TextEncoding&); + virtual ~TextCodecGtk(); + + virtual String decode(const char*, size_t length, bool flush, bool stopOnError, bool& sawError); + virtual CString encode(const UChar*, size_t length, UnencodableHandling); + + private: + void createIConvDecoder() const; + void createIConvEncoder() const; + + static void registerEncodingNames(EncodingNameRegistrar registrar, bool extended); + static void registerCodecs(TextCodecRegistrar registrar, bool extended); + static gboolean isEncodingAvailable(const gchar*); + + TextEncoding m_encoding; + size_t m_numBufferedBytes; + unsigned char m_bufferedBytes[16]; // bigger than any single multi-byte character + mutable GIConv m_iconvDecoder; + mutable GIConv m_iconvEncoder; + + static const gchar* m_internalEncodingName; + + typedef const gchar* const codecAliasList[]; + + // Unicode + static codecAliasList m_codecAliases_UTF_8; + + // Western + static codecAliasList m_codecAliases_ISO_8859_1; + static codecAliasList m_codecAliases_MACROMAN; + + // Japanese + static codecAliasList m_codecAliases_SHIFT_JIS; + static codecAliasList m_codecAliases_EUC_JP; + static codecAliasList m_codecAliases_ISO_2022_JP; + + // Traditional Chinese + static codecAliasList m_codecAliases_BIG5; + static codecAliasList m_codecAliases_BIG5_HKSCS; + static codecAliasList m_codecAliases_CP950; + + // Korean + static codecAliasList m_codecAliases_ISO_2022_KR; + static codecAliasList m_codecAliases_CP949; + static codecAliasList m_codecAliases_EUC_KR; + + // Arabic + static codecAliasList m_codecAliases_ISO_8859_6; + static codecAliasList m_codecAliases_CP1256; + + // Hebrew + static codecAliasList m_codecAliases_ISO_8859_8; + static codecAliasList m_codecAliases_CP1255; + + // Greek + static codecAliasList m_codecAliases_ISO_8859_7; + static codecAliasList m_codecAliases_CP869; + static codecAliasList m_codecAliases_WINDOWS_1253; + + // Cyrillic + static codecAliasList m_codecAliases_ISO_8859_5; + static codecAliasList m_codecAliases_KOI8_R; + static codecAliasList m_codecAliases_CP866; + static codecAliasList m_codecAliases_KOI8_U; + static codecAliasList m_codecAliases_WINDOWS_1251; + static codecAliasList m_codecAliases_MACCYRILLIC; + + // Thai + static codecAliasList m_codecAliases_CP874; + static codecAliasList m_codecAliases_TIS_620; + + // Simplified Chinese + static codecAliasList m_codecAliases_GBK; + static codecAliasList m_codecAliases_HZ; + static codecAliasList m_codecAliases_GB18030; + static codecAliasList m_codecAliases_EUC_CN; + static codecAliasList m_codecAliases_2312_80; + + // Central European + static codecAliasList m_codecAliases_ISO_8859_2; + static codecAliasList m_codecAliases_CP1250; + static codecAliasList m_codecAliases_MACCENTRALEUROPE; + + // Vietnamese + static codecAliasList m_codecAliases_CP1258; + + // Turkish + static codecAliasList m_codecAliases_CP1254; + static codecAliasList m_codecAliases_ISO_8859_9; + + // Baltic + static codecAliasList m_codecAliases_CP1257; + static codecAliasList m_codecAliases_ISO_8859_4; + + static gconstpointer const m_iconvBaseCodecList[]; + static gconstpointer const m_iconvExtendedCodecList[]; + + }; + +} // namespace WebCore + +#endif // TextCodecGTK_h diff --git a/WebCore/platform/text/qt/TextBoundaries.cpp b/WebCore/platform/text/qt/TextBoundariesQt.cpp index ffc4c44..a354ca6 100644 --- a/WebCore/platform/text/qt/TextBoundaries.cpp +++ b/WebCore/platform/text/qt/TextBoundariesQt.cpp @@ -36,7 +36,6 @@ #include <QDebug> #include <stdio.h> -#if QT_VERSION >= 0x040400 #include <qtextboundaryfinder.h> namespace WebCore { @@ -76,48 +75,3 @@ void findWordBoundary(UChar const* buffer, int len, int position, int* start, in } -#else -namespace WebCore { - -int findNextWordFromIndex(UChar const* buffer, int len, int position, bool forward) -{ - QString str(reinterpret_cast<QChar const*>(buffer), len); - notImplemented(); - return 0; -} - -void findWordBoundary(UChar const* buffer, int len, int position, int* start, int* end) -{ - QString str(reinterpret_cast<QChar const*>(buffer), len); - - if (position > str.length()) { - *start = 0; - *end = 0; - return; - } - - int currentPosition = position - 1; - QString foundWord; - while (currentPosition >= 0 && - str[currentPosition].isLetter()) { - foundWord.prepend(str[currentPosition]); - --currentPosition; - } - - // currentPosition == 0 means the first char is not letter - // currentPosition == -1 means we reached the beginning - int startPos = (currentPosition < 0) ? 0 : ++currentPosition; - currentPosition = position; - if (str[currentPosition].isLetter()) { - while (str[currentPosition].isLetter()) { - foundWord.append(str[currentPosition]); - ++currentPosition; - } - } - - *start = startPos; - *end = currentPosition; -} - -} -#endif diff --git a/WebCore/platform/text/qt/TextBreakIteratorQt.cpp b/WebCore/platform/text/qt/TextBreakIteratorQt.cpp index d80e270..101947c 100644 --- a/WebCore/platform/text/qt/TextBreakIteratorQt.cpp +++ b/WebCore/platform/text/qt/TextBreakIteratorQt.cpp @@ -1,6 +1,4 @@ /* - * This file is part of the DOM implementation for KDE. - * * Copyright (C) 2006 Lars Knoll <lars@trolltech.com> * * This library is free software; you can redistribute it and/or @@ -23,7 +21,6 @@ #include "config.h" #include "TextBreakIterator.h" -#if QT_VERSION >= 0x040400 #include <QtCore/qtextboundaryfinder.h> #include <qdebug.h> @@ -132,183 +129,3 @@ namespace WebCore { } } -#else -#include <qtextlayout.h> - -namespace WebCore { - - class TextBreakIterator { - public: - virtual int first() = 0; - virtual int next() = 0; - virtual int previous() = 0; - inline int following(int pos) - { - currentPos = pos; - return next(); - } - inline int preceding(int pos) - { - currentPos = pos; - return previous(); - } - int currentPos; - const UChar *string; - int length; - }; - - class WordBreakIteratorQt : public TextBreakIterator { - public: - virtual int first(); - virtual int next(); - virtual int previous(); - }; - - class CharBreakIteratorQt : public TextBreakIterator { - public: - virtual int first(); - virtual int next(); - virtual int previous(); - QTextLayout layout; - }; - - int WordBreakIteratorQt::first() - { - currentPos = 0; - return currentPos; - } - - int WordBreakIteratorQt::next() - { - if (currentPos >= length) { - currentPos = -1; - return currentPos; - } - bool haveSpace = false; - while (currentPos < length) { - if (haveSpace && !QChar(string[currentPos]).isSpace()) - break; - if (QChar(string[currentPos]).isSpace()) - haveSpace = true; - ++currentPos; - } - return currentPos; - } - - int WordBreakIteratorQt::previous() - { - if (currentPos <= 0) { - currentPos = -1; - return currentPos; - } - bool haveSpace = false; - while (currentPos > 0) { - if (haveSpace && !QChar(string[currentPos]).isSpace()) - break; - if (QChar(string[currentPos]).isSpace()) - haveSpace = true; - --currentPos; - } - return currentPos; - } - - int CharBreakIteratorQt::first() - { - currentPos = 0; - return currentPos; - } - - int CharBreakIteratorQt::next() - { - if (currentPos >= length) - return -1; - currentPos = layout.nextCursorPosition(currentPos); - return currentPos; - } - - int CharBreakIteratorQt::previous() - { - if (currentPos <= 0) - return -1; - currentPos = layout.previousCursorPosition(currentPos); - return currentPos; - } - - -TextBreakIterator* wordBreakIterator(const UChar* string, int length) -{ - static WordBreakIteratorQt *iterator = 0; - if (!iterator) - iterator = new WordBreakIteratorQt; - - iterator->string = string; - iterator->length = length; - iterator->currentPos = 0; - - return iterator; -} - -TextBreakIterator* characterBreakIterator(const UChar* string, int length) -{ - static CharBreakIteratorQt *iterator = 0; - if (!iterator) - iterator = new CharBreakIteratorQt; - - iterator->string = string; - iterator->length = length; - iterator->currentPos = 0; - iterator->layout.setText(QString(reinterpret_cast<const QChar*>(string), length)); - - return iterator; -} - -TextBreakIterator* cursorMovementIterator(const UChar* string, int length) -{ - return characterBreakIterator(string, length); -} - -TextBreakIterator* lineBreakIterator(const UChar*, int) -{ - // not yet implemented - return 0; -} - -TextBreakIterator* sentenceBreakIterator(const UChar*, int) -{ - // not yet implemented - return 0; -} - -int textBreakFirst(TextBreakIterator* bi) -{ - return bi->first(); -} - -int textBreakNext(TextBreakIterator* bi) -{ - return bi->next(); -} - -int textBreakPreceding(TextBreakIterator* bi, int pos) -{ - return bi->preceding(pos); -} - -int textBreakFollowing(TextBreakIterator* bi, int pos) -{ - return bi->following(pos); -} - -int textBreakCurrent(TextBreakIterator* bi) -{ - return bi->currentPos; -} - -bool isTextBreak(TextBreakIterator*, int) -{ - return true; -} - -} - -#endif diff --git a/WebCore/platform/text/wince/TextBoundariesWince.cpp b/WebCore/platform/text/wince/TextBoundariesWince.cpp new file mode 100644 index 0000000..df6f757 --- /dev/null +++ b/WebCore/platform/text/wince/TextBoundariesWince.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * Copyright (C) 2007-2009 Torch Mobile, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TextBoundaries.h" + +#include "NotImplemented.h" +#include "PlatformString.h" + +using namespace WTF::Unicode; + +namespace WebCore { + +int findNextWordFromIndex(const UChar * buffer, int len, int position, bool forward) +{ + notImplemented(); + return 0; +} + +void findWordBoundary(const UChar * buffer, int len, int position, int* start, int* end) +{ + if (position > len) { + *start = 0; + *end = 0; + return; + } + + String str(buffer, len); + + int currentPosition = position - 1; + String foundWord; + while (currentPosition >= 0 && isLetter(str[currentPosition])) { + UChar c = str[currentPosition]; + foundWord.insert(&c, 1, 0); + --currentPosition; + } + + // currentPosition == 0 means the first char is not letter + // currentPosition == -1 means we reached the beginning + int startPos = (currentPosition < 0) ? 0 : ++currentPosition; + currentPosition = position; + while (isLetter(str[currentPosition])) { + foundWord.append(str[currentPosition]); + ++currentPosition; + } + + *start = startPos; + *end = currentPosition; +} + + +} diff --git a/WebCore/platform/text/wince/TextBreakIteratorWince.cpp b/WebCore/platform/text/wince/TextBreakIteratorWince.cpp new file mode 100644 index 0000000..26a5be2 --- /dev/null +++ b/WebCore/platform/text/wince/TextBreakIteratorWince.cpp @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2006 Lars Knoll <lars@trolltech.com> + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" +#include "TextBreakIterator.h" + +#include "PlatformString.h" +#include <wtf/unicode/Unicode.h> + +using namespace WTF::Unicode; + +namespace WebCore { + +// Hack, not entirely correct +static inline bool isCharStop(UChar c) +{ + CharCategory charCategory = category(c); + return charCategory != Mark_NonSpacing && (charCategory != Other_Surrogate || (c < 0xd800 || c >= 0xdc00)); +} + +static inline bool isLineStop(UChar c) +{ + return category(c) != Separator_Line; +} + +static inline bool isSentenceStop(UChar c) +{ + return isPunct(c); +} + +class TextBreakIterator { +public: + void reset(const UChar* str, int len) + { + string = str; + length = len; + currentPos = 0; + } + virtual int first() = 0; + virtual int next() = 0; + virtual int previous() = 0; + int following(int position) + { + currentPos = position; + return next(); + } + int preceding(int position) + { + currentPos = position; + return previous(); + } + + int currentPos; + const UChar* string; + int length; +}; + +struct WordBreakIterator: TextBreakIterator { + virtual int first(); + virtual int next(); + virtual int previous(); +}; + +struct CharBreakIterator: TextBreakIterator { + virtual int first(); + virtual int next(); + virtual int previous(); +}; + +struct LineBreakIterator: TextBreakIterator { + virtual int first(); + virtual int next(); + virtual int previous(); +}; + +struct SentenceBreakIterator : TextBreakIterator { + virtual int first(); + virtual int next(); + virtual int previous(); +}; + +int WordBreakIterator::first() +{ + currentPos = 0; + return currentPos; +} + +int WordBreakIterator::next() +{ + if (currentPos == length) { + currentPos = -1; + return currentPos; + } + bool haveSpace = false; + while (currentPos < length) { + if (haveSpace && !isSpace(string[currentPos])) + break; + if (isSpace(string[currentPos])) + haveSpace = true; + ++currentPos; + } + return currentPos; +} + +int WordBreakIterator::previous() +{ + if (!currentPos) { + currentPos = -1; + return currentPos; + } + bool haveSpace = false; + while (currentPos > 0) { + if (haveSpace && !isSpace(string[currentPos])) + break; + if (isSpace(string[currentPos])) + haveSpace = true; + --currentPos; + } + return currentPos; +} + +int CharBreakIterator::first() +{ + currentPos = 0; + return currentPos; +} + +int CharBreakIterator::next() +{ + if (currentPos >= length) + return -1; + ++currentPos; + while (currentPos < length && !isCharStop(string[currentPos])) + ++currentPos; + return currentPos; +} + +int CharBreakIterator::previous() +{ + if (currentPos <= 0) + return -1; + if (currentPos > length) + currentPos = length; + --currentPos; + while (currentPos > 0 && !isCharStop(string[currentPos])) + --currentPos; + return currentPos; +} + +int LineBreakIterator::first() +{ + currentPos = 0; + return currentPos; +} + +int LineBreakIterator::next() +{ + if (currentPos == length) { + currentPos = -1; + return currentPos; + } + bool haveSpace = false; + while (currentPos < length) { + if (haveSpace && !isLineStop(string[currentPos])) + break; + if (isLineStop(string[currentPos])) + haveSpace = true; + ++currentPos; + } + return currentPos; +} + +int LineBreakIterator::previous() +{ + if (!currentPos) { + currentPos = -1; + return currentPos; + } + bool haveSpace = false; + while (currentPos > 0) { + if (haveSpace && !isLineStop(string[currentPos])) + break; + if (isLineStop(string[currentPos])) + haveSpace = true; + --currentPos; + } + return currentPos; +} + +int SentenceBreakIterator::first() +{ + currentPos = 0; + return currentPos; +} + +int SentenceBreakIterator::next() +{ + if (currentPos == length) { + currentPos = -1; + return currentPos; + } + bool haveSpace = false; + while (currentPos < length) { + if (haveSpace && !isSentenceStop(string[currentPos])) + break; + if (isSentenceStop(string[currentPos])) + haveSpace = true; + ++currentPos; + } + return currentPos; +} + +int SentenceBreakIterator::previous() +{ + if (!currentPos) { + currentPos = -1; + return currentPos; + } + bool haveSpace = false; + while (currentPos > 0) { + if (haveSpace && !isSentenceStop(string[currentPos])) + break; + if (isSentenceStop(string[currentPos])) + haveSpace = true; + --currentPos; + } + return currentPos; +} + +TextBreakIterator* wordBreakIterator(const UChar* string, int length) +{ + DEFINE_STATIC_LOCAL(WordBreakIterator, iterator, ()); + iterator.reset(string, length); + return &iterator; +} + +TextBreakIterator* characterBreakIterator(const UChar* string, int length) +{ + DEFINE_STATIC_LOCAL(CharBreakIterator, iterator, ()); + iterator.reset(string, length); + return &iterator; +} + +TextBreakIterator* lineBreakIterator(const UChar* string, int length) +{ + DEFINE_STATIC_LOCAL(LineBreakIterator , iterator, ()); + iterator.reset(string, length); + return &iterator; +} + +TextBreakIterator* sentenceBreakIterator(const UChar* string, int length) +{ + DEFINE_STATIC_LOCAL(SentenceBreakIterator, iterator, ()); + iterator.reset(string, length); + return &iterator; +} + +int textBreakFirst(TextBreakIterator* breakIterator) +{ + return breakIterator->first(); +} + +int textBreakNext(TextBreakIterator* breakIterator) +{ + return breakIterator->next(); +} + +int textBreakPreceding(TextBreakIterator* breakIterator, int position) +{ + return breakIterator->preceding(position); +} + +int textBreakFollowing(TextBreakIterator* breakIterator, int position) +{ + return breakIterator->following(position); +} + +int textBreakCurrent(TextBreakIterator* breakIterator) +{ + return breakIterator->currentPos; +} + +bool isTextBreak(TextBreakIterator*, int) +{ + return true; +} + +TextBreakIterator* cursorMovementIterator(const UChar* string, int length) +{ + return characterBreakIterator(string, length); +} + +} diff --git a/WebCore/platform/win/PlatformMouseEventWin.cpp b/WebCore/platform/win/PlatformMouseEventWin.cpp index e9c0e3e..dc4dd2f 100644 --- a/WebCore/platform/win/PlatformMouseEventWin.cpp +++ b/WebCore/platform/win/PlatformMouseEventWin.cpp @@ -24,6 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "PlatformMouseEvent.h" #include <wtf/Assertions.h> diff --git a/WebCore/platform/win/PopupMenuWin.cpp b/WebCore/platform/win/PopupMenuWin.cpp index 1d9eb71..7d8c8d5 100644 --- a/WebCore/platform/win/PopupMenuWin.cpp +++ b/WebCore/platform/win/PopupMenuWin.cpp @@ -617,11 +617,11 @@ void PopupMenu::paint(const IntRect& damageRect, HDC hdc) // Draw the background for this menu item if (itemStyle.isVisible()) - context.fillRect(itemRect, optionBackgroundColor); + context.fillRect(itemRect, optionBackgroundColor, DeviceColorSpace); if (client()->itemIsSeparator(index)) { IntRect separatorRect(itemRect.x() + separatorPadding, itemRect.y() + (itemRect.height() - separatorHeight) / 2, itemRect.width() - 2 * separatorPadding, separatorHeight); - context.fillRect(separatorRect, optionTextColor); + context.fillRect(separatorRect, optionTextColor, DeviceColorSpace); continue; } @@ -631,7 +631,7 @@ void PopupMenu::paint(const IntRect& damageRect, HDC hdc) const UChar* string = itemText.characters(); TextRun textRun(string, length, false, 0, 0, itemText.defaultWritingDirection() == WTF::Unicode::RightToLeft); - context.setFillColor(optionTextColor); + context.setFillColor(optionTextColor, DeviceColorSpace); Font itemFont = client()->menuStyle().font(); if (client()->itemIsLabel(index)) { diff --git a/WebCore/platform/win/WebCoreTextRenderer.cpp b/WebCore/platform/win/WebCoreTextRenderer.cpp index affeb9d..f771e00 100644 --- a/WebCore/platform/win/WebCoreTextRenderer.cpp +++ b/WebCore/platform/win/WebCoreTextRenderer.cpp @@ -49,7 +49,7 @@ static void doDrawTextAtPoint(GraphicsContext& context, const String& text, cons { TextRun run(text.characters(), text.length()); - context.setFillColor(color); + context.setFillColor(color, DeviceColorSpace); if (isOneLeftToRightRun(run)) font.drawText(&context, run, point); else @@ -71,7 +71,7 @@ static void doDrawTextAtPoint(GraphicsContext& context, const String& text, cons IntPoint underlinePoint(point); underlinePoint.move(beforeWidth, 1); - context.setStrokeColor(color); + context.setStrokeColor(color, DeviceColorSpace); context.drawLineForText(underlinePoint, underlinedWidth, false); } } diff --git a/WebCore/platform/wx/FileSystemWx.cpp b/WebCore/platform/wx/FileSystemWx.cpp index 109278f..1ee87ae 100644 --- a/WebCore/platform/wx/FileSystemWx.cpp +++ b/WebCore/platform/wx/FileSystemWx.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2007 Kevin Ollivier * Copyright (C) 2008 Collabora, Ltd. + * Copyright (C) 2009 Peter Laufenberg @ Inhance Digital Corp * * All rights reserved. * @@ -34,13 +35,23 @@ #include "PlatformString.h" #include <wx/wx.h> +#include <wx/datetime.h> +#include <wx/dir.h> +#include <wx/dynlib.h> +#include <wx/file.h> +#include <wx/filefn.h> #include <wx/filename.h> +#if PLATFORM(DARWIN) +#include <CoreFoundation/CoreFoundation.h> +#endif + namespace WebCore { bool fileExists(const String& path) { - return wxFileName::FileExists(path); + // NOTE: This is called for directory paths too so we need to check both. + return wxFileName::FileExists(path) || wxFileName::DirExists(path); } bool deleteFile(const String& path) @@ -114,16 +125,71 @@ int writeToFile(PlatformFileHandle, const char* data, int length) return 0; } -bool unloadModule(PlatformModule) +bool unloadModule(PlatformModule mod) { - notImplemented(); - return false; +#if PLATFORM(WIN_OS) + return ::FreeLibrary(mod); +#elif PLATFORM(DARWIN) + CFRelease(mod); + return true; +#else + wxASSERT(mod); + delete mod; + return true; +#endif } + +class wxDirTraverserNonRecursive : public wxDirTraverser { +public: + wxDirTraverserNonRecursive(wxString basePath, wxArrayString& files) : m_basePath(basePath), m_files(files) { } + + virtual wxDirTraverseResult OnFile(const wxString& filename) + { + wxFileName afile(filename); + afile.MakeRelativeTo(m_basePath); + if (afile.GetFullPath().Find(afile.GetPathSeparator()) == wxNOT_FOUND) + m_files.push_back(filename); + + return wxDIR_CONTINUE; + } + + virtual wxDirTraverseResult OnDir(const wxString& dirname) + { + wxFileName dirfile(dirname); + dirfile.MakeRelativeTo(m_basePath); + if (dirfile.GetFullPath().Find(dirfile.GetPathSeparator()) == wxNOT_FOUND) + m_files.push_back(dirname); + + return wxDIR_CONTINUE; + } + +private: + wxString m_basePath; + wxArrayString& m_files; + + DECLARE_NO_COPY_CLASS(wxDirTraverserNonRecursive) +}; + Vector<String> listDirectory(const String& path, const String& filter) { + wxArrayString file_paths; + // wxDir::GetAllFiles recurses and for platforms like Mac where + // a .plugin or .bundle can be a dir wx will recurse into the bundle + // and list the files rather than just returning the plugin name, so + // we write a special traverser that works around that issue. + wxDirTraverserNonRecursive traverser(path, file_paths); + + wxDir dir(path); + dir.Traverse(traverser, _T(""), wxDIR_FILES | wxDIR_DIRS); + Vector<String> entries; - notImplemented(); + + for (int i = 0; i < file_paths.GetCount(); i++) + { + entries.append(file_paths[i]); + } + return entries; } diff --git a/WebCore/platform/wx/LocalizedStringsWx.cpp b/WebCore/platform/wx/LocalizedStringsWx.cpp index 5bede52..6a389f2 100644 --- a/WebCore/platform/wx/LocalizedStringsWx.cpp +++ b/WebCore/platform/wx/LocalizedStringsWx.cpp @@ -27,6 +27,7 @@ #include "config.h" #include "LocalizedStrings.h" +#include "NotImplemented.h" #include "PlatformString.h" namespace WebCore { @@ -323,4 +324,46 @@ String AXDefinitionListDefinitionText() return String(); } +String validationMessageValueMissingText() +{ + notImplemented(); + return String(); +} + +String validationMessageTypeMismatchText() +{ + notImplemented(); + return String(); +} + +String validationMessagePatternMismatchText() +{ + notImplemented(); + return String(); +} + +String validationMessageTooLongText() +{ + notImplemented(); + return String(); +} + +String validationMessageRangeUnderflowText() +{ + notImplemented(); + return String(); +} + +String validationMessageRangeOverflowText() +{ + notImplemented(); + return String(); +} + +String validationMessageStepMismatchText() +{ + notImplemented(); + return String(); +} + } // namespace WebCore diff --git a/WebCore/platform/wx/ScrollbarThemeWx.cpp b/WebCore/platform/wx/ScrollbarThemeWx.cpp index 6904f41..82e4a15 100644 --- a/WebCore/platform/wx/ScrollbarThemeWx.cpp +++ b/WebCore/platform/wx/ScrollbarThemeWx.cpp @@ -28,6 +28,7 @@ #include "HostWindow.h" #include "NotImplemented.h" +#include "PlatformMouseEvent.h" #include "Scrollbar.h" #include "ScrollbarClient.h" #include "scrollbar_render.h" @@ -70,6 +71,11 @@ bool ScrollbarThemeWx::hasThumb(Scrollbar* scrollbar) return thumbLength(scrollbar) > 0; } +int ScrollbarThemeWx::minimumThumbLength(Scrollbar* scrollbar) +{ + return 20; +} + IntSize ScrollbarThemeWx::buttonSize(Scrollbar*) { #ifdef __WXMAC__ @@ -79,6 +85,22 @@ IntSize ScrollbarThemeWx::buttonSize(Scrollbar*) #endif } +void ScrollbarThemeWx::splitTrack(Scrollbar* scrollbar, const IntRect& unconstrainedTrackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& afterThumbRect) +{ + ScrollbarThemeComposite::splitTrack(scrollbar, unconstrainedTrackRect, beforeThumbRect, thumbRect, afterThumbRect); +#ifdef __WXMAC__ + // on Mac, there are a few pixels drawn above the actual track and so adjust + // the hit testing rects accordingly + int trackStart = 10; + if (scrollbar->orientation() == HorizontalScrollbar) { + thumbRect.setX(thumbRect.x() + trackStart); + afterThumbRect.setX(afterThumbRect.x() - trackStart); + } else { + thumbRect.setY(thumbRect.y() + trackStart); + afterThumbRect.setY(afterThumbRect.y() - trackStart); + } +#endif +} IntRect ScrollbarThemeWx::backButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool) { @@ -111,10 +133,16 @@ IntRect ScrollbarThemeWx::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart IntSize size = buttonSize(scrollbar); int x, y; if (scrollbar->orientation() == HorizontalScrollbar) { +#ifdef __WXMAC__ + size.setWidth(size.width() + cMacButtonOverlap); +#endif x = scrollbar->x() + scrollbar->width() - size.width(); y = scrollbar->y(); } else { x = scrollbar->x(); +#ifdef __WXMAC__ + size.setHeight(size.height() + cMacButtonOverlap); +#endif y = scrollbar->y() + scrollbar->height() - size.height(); } return IntRect(x, y, size.width(), size.height()); diff --git a/WebCore/platform/wx/ScrollbarThemeWx.h b/WebCore/platform/wx/ScrollbarThemeWx.h index 2b3bff0..79b10b3 100644 --- a/WebCore/platform/wx/ScrollbarThemeWx.h +++ b/WebCore/platform/wx/ScrollbarThemeWx.h @@ -48,6 +48,10 @@ protected: virtual IntRect backButtonRect(Scrollbar*, ScrollbarPart, bool painting = false); virtual IntRect forwardButtonRect(Scrollbar*, ScrollbarPart, bool painting = false); virtual IntRect trackRect(Scrollbar*, bool painting = false); + + virtual void splitTrack(Scrollbar*, const IntRect& track, IntRect& startTrack, IntRect& thumb, IntRect& endTrack); + + virtual int minimumThumbLength(Scrollbar*); }; } diff --git a/WebCore/platform/wx/wxcode/gtk/scrollbar_render.cpp b/WebCore/platform/wx/wxcode/gtk/scrollbar_render.cpp index f74b076..3b4daa8 100644 --- a/WebCore/platform/wx/wxcode/gtk/scrollbar_render.cpp +++ b/WebCore/platform/wx/wxcode/gtk/scrollbar_render.cpp @@ -116,9 +116,18 @@ void wxRenderer_DrawScrollbar(wxWindow* window, wxDC& dc, const wxRect& rect, wx dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW))); dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height); + // when going from Cairo -> Gdk, any Cairo context transformations are lost + // so we need to alter the coordinates to reflect their transformed point. + double xtrans = 0; + double ytrans = 0; + + wxGCDC* gcdc = wxDynamicCast(&dc, wxGCDC); + wxGraphicsContext* gc = gcdc->GetGraphicsContext(); + gc->GetTransform().TransformPoint(&xtrans, &ytrans); + wxRendererNative& renderer = wxRendererNative::Get(); - int x = rect.x; - int y = rect.y; + int x = rect.x + (int)xtrans; + int y = rect.y + (int)ytrans; int buttonLength = 16; @@ -138,13 +147,15 @@ void wxRenderer_DrawScrollbar(wxWindow* window, wxDC& dc, const wxRect& rect, wx physicalLength -= buttonLength*2; int thumbStart = 0; int thumbLength = 0; - calcThumbStartAndLength(physicalLength, max + step, current, step, &thumbStart, &thumbLength); + calcThumbStartAndLength(physicalLength, max, current, step, &thumbStart, &thumbLength); if (horiz) { - buttonRect.x = thumbStart + buttonLength; + buttonRect.x = x + thumbStart + buttonLength; + buttonRect.y = y; buttonRect.width = thumbLength; } else { - buttonRect.y = thumbStart + buttonLength; + buttonRect.x = x; + buttonRect.y = y + thumbStart + buttonLength; buttonRect.height = thumbLength; } diff --git a/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp b/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp index c4c4d48..47eb1f8 100644 --- a/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp +++ b/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp @@ -56,7 +56,7 @@ void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext()); wxFont* wxfont = font->getWxFont(); - graphicsContext->setFillColor(graphicsContext->fillColor()); + graphicsContext->setFillColor(graphicsContext->fillColor(), DeviceColorSpace); CGContextRef cgContext = static_cast<CGContextRef>(dc->GetGraphicsContext()->GetNativeContext()); diff --git a/WebCore/platform/wx/wxcode/scrollbar_render.h b/WebCore/platform/wx/wxcode/scrollbar_render.h index 7a0ba1c..5e0ea8e 100644 --- a/WebCore/platform/wx/wxcode/scrollbar_render.h +++ b/WebCore/platform/wx/wxcode/scrollbar_render.h @@ -50,16 +50,17 @@ void wxRenderer_DrawScrollbar(wxWindow* window, wxDC& dc, int current, wxScrollbarPart focusPart, wxScrollbarPart hoverPart, int max, int step, int flags=0); -inline void calcThumbStartAndLength(int physicalLength, int virtualLength, int current, +inline void calcThumbStartAndLength(int physicalLength, int max, int current, int step, int *thumbStart, int *thumbLength) { - float proportion = (float)physicalLength / virtualLength; - float scale = (float)virtualLength / physicalLength; - int thumbSize = proportion * physicalLength; - int currentPos = current / scale; - + float proportion = ((float)physicalLength - 8)/ (max + step); + float thumbSize = proportion * (float)physicalLength; + if (thumbSize < 20) + thumbSize = 20; + + float thumbPos = ((float)current / (float)max) * ((float)physicalLength - thumbSize); if (thumbStart) - *thumbStart = currentPos; + *thumbStart = thumbPos; if (thumbLength) *thumbLength = thumbSize; diff --git a/WebCore/platform/wx/wxcode/win/scrollbar_render.cpp b/WebCore/platform/wx/wxcode/win/scrollbar_render.cpp index 4d6bbc0..890db00 100644 --- a/WebCore/platform/wx/wxcode/win/scrollbar_render.cpp +++ b/WebCore/platform/wx/wxcode/win/scrollbar_render.cpp @@ -30,6 +30,8 @@ #include <wx/defs.h> #include <wx/dc.h> +#include <wx/dcgraph.h> +#include <wx/graphics.h> #include <wx/renderer.h> #include <wx/window.h> @@ -131,8 +133,24 @@ void wxRenderer_DrawScrollbar(wxWindow* window, wxDC& dc, part = SP_TRACKENDVERT; int xpState = TS_NORMAL; + wxRect transRect = rect; + +#if USE(WXGC) + // when going from GdiPlus -> Gdi, any GdiPlus transformations are lost + // so we need to alter the coordinates to reflect their transformed point. + double xtrans = 0; + double ytrans = 0; + + wxGCDC* gcdc = wxDynamicCast(&dc, wxGCDC); + wxGraphicsContext* gc = gcdc->GetGraphicsContext(); + gc->GetTransform().TransformPoint(&xtrans, &ytrans); + + transRect.x += (int)xtrans; + transRect.y += (int)ytrans; +#endif + RECT r; - wxCopyRectToRECT(rect, r); + wxCopyRectToRECT(transRect, r); // Unlike Mac, on MSW you draw the scrollbar piece by piece. // so we draw the track first, then the buttons @@ -163,14 +181,14 @@ void wxRenderer_DrawScrollbar(wxWindow* window, wxDC& dc, physicalLength -= buttonSize*2; int thumbStart = 0; int thumbLength = 0; - calcThumbStartAndLength(physicalLength, max + step, + calcThumbStartAndLength(physicalLength, max, current, step, &thumbStart, &thumbLength); buttonRect = r; if (horiz) { - buttonRect.left = thumbStart + buttonSize; + buttonRect.left = buttonRect.left + thumbStart + buttonSize; buttonRect.right = buttonRect.left + thumbLength; } else { - buttonRect.top = thumbStart + buttonSize; + buttonRect.top = buttonRect.top + thumbStart + buttonSize; buttonRect.bottom = buttonRect.top + thumbLength; } |